diff --git a/HelpSource/Classes/XiiLang.schelp b/HelpSource/Classes/XiiLang.schelp new file mode 100644 index 0000000..1abe247 --- /dev/null +++ b/HelpSource/Classes/XiiLang.schelp @@ -0,0 +1,806 @@ +TITLE:: XiiLang +summary:: a live coding language interpreter +categories:: ixilang + +DESCRIPTION:: +The ixi lang live coding environment is a simple visual system presenting a high entry-level control over synth definitions and samples in SuperCollider. The core idea is to represent events in a spatial layout, thus merging musical code and musical scores. The score of an ixi lang agent is reactive, i.e., if a method is performed upon the score, it changes in real time. + + +NOTE:: The interpreter uses a different key command for evaluating ixi lang code, namely alt+arrows. +:: + +This allows for coding in both sc lang and ixi lang in the same document without confusing interpreters. + + +Further explanation below, but videos can be found on www.vimeo.com/ixi + +A paper on ixi lang for the 2011 ICMC conference can be found here www.ixi-audio.net/thor + +For more information and feedback contact: thor@ixi-audio.net and updates on ixi lang (+ other stuff) here http://www.twitter.com/thormagnusson + + + +subsection:: Folder structure of ixi lang: + + +The ixi lang app (or your SuperCollider app) will have a folder called "ixilang" next to it. In there you keep your projects. The project name is the name you give the folder inside the ixilang folder. Each project will have the following items: + + +LIST:: +## colors.ixi (a file storing the color values of your coding envrionment); + +## keyMapping.ixi (a document storing the mapping between keys and samples); + +## recordings folder (where recordings will appear if you use the "rec" button); + +## samples folder (where you keep your short samples that you map to the keys of the keyboard); + +## scores folder (where scores are saved); sessions folder (where environments are stored); + +## synthdefs.scd file where you can put synth definitions that will appear in the key mapping GUI). + +## livesamples folder (where samples are recorded in a live situation) +:: + +Each project (or do you want to call it a "piece"?) can therefore have its own colour code, samples and key mappings. + + + +subsection:: Having Problems? Here is a quick troubleshooting: + + +You need to make sure you're evaluating the code with alt+arrow keys (and not the SuperCollider default - read about that below). Don't use TABs when coding, only spaces. Do you have a "samples" folder within a "default" folder next to your SuperCollider.app (i.e., ixilang/default/samples )? Put some short sounds into that folder. When you've figured this out, you can start to create your own project folders, not using the "default" anymore. + +Finally, if you get a message saying samplerate 44100 != 48000 or the like, go into your Audio MIDI Setup.app and set the input and output sample rate to 44100 Hz. + + + +subsection:: The three modes of ixi lang: + + +The ixi lang presents three different modes in ixi lang: melodic mode, rhythmic mode and concrète mode. + +code:: +agentname -> marimba[1 4 3 2 ] // square brackets indicate melodic score (synthesis or samples) + +agentname -> |o x o s x | // the "|" symbol indicates percussive score (samples or synthesis) + +agentname -> sndname{0 1 2 8 } // curly brackets indicate concrète score (samples) +:: + +NOTE: for non-programmers the "|" symbol is a vertical bar, often called a pipe and should not be confused with a lowercase "L". For programmers, it's the symbol you use for OR (or "\|\|"). + + +In general, when running a command use one space between words. Good practice is the following: + +code:: +future 4:12 >> swap agentname +:: + +subsection:: Creation of ixi lang: + + + *new (project name, key) + + + + project name - The name of your project. Represents a folder name. Default value is "default". + + key - The key of the session (important if playing with other instrumentalists). Default value is "C". + + +code:: + // inline example + + XiiLang(); + + or + + XiiLang.new("yourprojectname", "E"); +:: + + +subsection:: Getting help in ixi lang (type command and ixi evaluate): + +definitionlist:: + + ## remind + || Opens a document with instructions of what ixi lang has in store. + + ## tonality + || Opens a document listing available scales and tunings. + + ## instruments + || Listing all registered instruments (although any synthdef on the system can be used). + + ## help + || Opens this document. +:: + +subsection:: Operators of ixi lang: + +definitionlist:: + ## -> +|| Assignment operator: it assigns a score to an agent (see example below) + + ## >> +|| Route agent through an effect. (see example below) + + ## << +|| Remove effect from an agent. (see example below) + + ## )) +|| Increase the amplitude of an agent. (see example below) + + ## (( + || Reduce the amplitude of an agent. (see example below) +:: + +subsection:: The three score modes of ixi lang: + +subsection:: [ ... ] Melodic score + Here notes are played in a scale from 1 to 9, where 1 is the tonic. + + Spaces (or full stops - new in v3) represent silence. Additional arguments are + + ! for inserting a silence after the score + + + or - for transposition in pitch + + * or / for increasing or decreasing the timing as multiplied or divided by an integer + + ^^ for accents (volume of each note, e.g. ^1418^) + + () for note sustain (duration of each note (wholenote = 1, halfnote = 2, quarternote = 4, etc) + + <> for panning (1 being the left speaker, 5 middle and 9 the right speaker, e.g, <15289>) + + + Melodic scores can use any Pattern-ready synthdef on your system, or samples that have + + been loaded into XiiLangInstr (see class). A special case is the "midi" instrument, i.e., it is + + not a synth definition, but sends MIDI messages out on a specific MIDI channel. + + +subsection:: | ... | Percussive score + Here samples (or synthdefs) are mapped to keyboard keys + + (see keyMappings.ixi). Spaces (or full stops - new in v3) represent silence. + + Additional arguments are + + ! for inserting a silence after the score + + + or - for transposition in pitch + + * or / for increasing or decreasing the timing as multiplied or divided by an integer + + ^^ for accents (volume of each note, e.g. ^1418^) + + () for note sustain (duration of each note (wholenote = 1, halfnote = 2, quarternote = 4, etc) + + <> for panning (1 being the left speaker, 5 middle and 9 the right speaker, e.g, <15289>) + + + The percussive score can create various types of timbral transitions between the sonic events in + + the score. The available transitions are: morph, fade, wipe, minus, common, binwipe, copy, mul, + + subtract, rand, smear, comb, low, band. Those can be used with the sound looping or playing + + only once, using the % symbol. + + (e.g., ringo -> morph|a b c d | (not looping) or ringo -> fade%|a b c d |) + + + +subsection:: { ... } Concrete score + Here longer samples can be played and their amplitude controlled. + + Spaces (or full stops - new in v3) do not represent silence. Additional arguments are + + ! for inserting a silence after the score + + * or / for changing the scores duration. + + <> for panning (1 being the left speaker, 5 middle and 9 the right speaker, e.g, <15289>) + + + +subsection:: Meta agents (new in version 4) + + + ~ ... ~ Meta agents. Here agents (and groups or other meta agents) can be sequenced. An argument + + is provided for how many times it is repeated. Example: mymeta -> ~ agA 2 agB 4 ~ + + + + + +subsection:: Post-score operators in ixi lang: + +definitionlist:: + ## ! + || Will create a silent part in the score according to the argument given. (e.g., !16 is sixteen silent notes) + + + + ## + + || Transpose the score in MIDI notes. (for example +7 will be a fifth higher than the note written, and -12 will be an octave lower). + + + + ## * + || Will multiply the duration of the array (not note lengths in the array). + + + + ## / + || Will divide the duration of the array (not note lengths in the array). + + + ## () + || Arguments in brackets are note sustain. (1 is one beat, 2 is half, 4 quarter and 8 is eight). Can be multiplied with the _ symbol, so (1_4) is a whole note in a 4/4 time signature. + + + + ## ^ + || Arguments in caret symbols are accents (9 is highest amplitude, 0 is silence). This is relative to the agent's general amplitude. + + +## <> + || Arguments between arrows are panning (1 is left, 5 is centre, 9 is right ). + + + ## @ + || Number of times the agent will play. Example: oo -> wood[1 3 2 4 ]@4 + +:: + +subsection:: Methods of ixi lang (put in front of agents, as in verb-noun-adjective): + +definitionlist:: +## doze || Set the agent to sleep +## perk || Wake the agent, if sleeping +## nap || Sleep for a N number of seconds. If 2nd argument, then this is repeated N2 times. (e.g., nap miles 2:4 ) +## shake || Shake the score of an agent, practically scrambling all items +## swap || Swap items in the score of an agent +## replace || Replace new items into the score of an agent (in place) +## insert || Insert new items into the score of an agent (not in place) +## remove || Remove items from the score of an agent +## slide || Slide the score with a certain windowlength (1st argument) and stepsize (2nd argument) +## >shift || Right shift the score by N number of places (e.g., >shift jimi 6 ) +## > )) paul ). +## (( || Decrease volume. Can be used with future. +:: + +NOTE:: The post score operators (above) can also be used in the syntax of these methods (in ixi lang "verbs") for example: < ringo 1253742 (which reads like "pan ringo to these locations") +:: + + + + +subsection:: Commands in ixi lang: + +definitionlist:: +## tonic || Set the tonic of the performance (as MIDI note value) +## scale || Set the scale of the performance (for all agents evaluated after this event) +## scalepush || Set the scale of the performance (for all agents, also those playing) +## tuning || Set the tuning of the performance (for all agents evaluated after this event - type "tonality" to see tunings - see below) +## tuningpush || Set the tuning of the performance (for all agents, also those playing) +## tempo || Set the tempo of performance ( destination tempo: n seconds) (e.g., tempo 120:2 ) +## future || Schedule event in the future (in sec:times or bars:times) (e.g., future 2:2 >> shake jimi or future 2b:2 >> shake jimi). To remove the scheduling use: future << jimi. +## grid || Draw a grid with n spaces (e.g., grid 8 ) +## kill || Stop all sounds and future tasks of this window +## remind || Get a document listing the functions of ixi lang +## help || Get this document +## instruments || Get a list of instruments +## tonality || Get a list of scales and tunings +## group || Group together, under one name, various agents. This is handy for control. +## sequence || Sequence agents linearly. This will create a new agent, but not stop running agents. +## snapshot || Take a snapshot of the agent's scores and instruments for recalling later. +## suicide || Live dangerously! Allow ixi lang to crash in your live coding session. +## hotline || In case you change your mind with regards to the suicide. +## midiclients || Get a list of the MIDI clients (ports) available on your system. +## midiout || Set the MIDI port (as in midiclient 2) and initiate a MIDI clock on that port (can slave other software, such as Ableton). +## coder || Opens up a new ixi lang window where all keystrokes result in sounds. +## autocode || Will write and evaluate N number of lines of code. Now check email on stage? +## matrix || Opens up a matrix window. A dynamic state machine that can be adopted in real time (hit fn+key to get to code) +## store || Stores the environment of a session (with agents, groups, snapshots and effects) to be loaded up later +## load || Load a stored session and start playing as you left the system +## savescore || Record your session (from start) to be played back later (different from store/load) +## playscore|| Playback a session (do you want to listen to how your live gig sounded?). You can also play it back asking for a new variation (where the algorithmic decisions taken throughout the piece are different from the score you recorded). eg. [playscore myscore myvariation] +## newrec || Eraze all memory of the performance, if you use "savescore" it will record everything from the time you issued this command +## new || Open up a GUI window to start a new project or create a new key mapping. +## gui || Same as new. + +:: + +subsection:: Available Audio Effects in ixi lang (w/ hardcoded parameters): + +definitionlist:: +## reverb || A decent space reverb +## reverbS || A small space reverb +## reverbL || A large space reverb +## delay || A decent delay +## distort || A decent distortion +## cyberpunk || A good healthy effect +## bitcrush || A jolly sounding effect +## techno || An old trick of sweeping filter +## antique || A lowpass and some vinyl scratches +## lowpass || What it says on the tin +## tremolo || Amplitude variation +## vibrato || Pitch variation + +:: + +subsection:: Creating agents in ixi lang + + +By creating an agent (agentname -> .... ), you create a space where a score can be performed. The agent can play any type of score (melodic, percussive or concrète). The agent name is then used when assigning effects or applying methods. + + +The agent is assigned a score by hitting alt + arrow keys. Any arrow can be used, with ONE exception, where command + left arrow on an agent line will kill that agent (and turn the text red). It will not wake up with a perk command, but has to be reevaluated with commend + right. + + + +subsection:: Real time recording of sounds into keys + + +By hitting "fn" and Return, a window opens up that tells you to press any key to record a new sound "into it". You simply hold down the key and it records until you release the key. The sounds will be stored in the "livesamples" folder, so if you want to use them at a later stage, you move them into the samples folder and map them to the key you want. + + + +subsection:: Tempo tapping + + +You can set the tempo of ixi lang by tapping on the keyboard. Just hold down ctrl and then start tapping on the "," key until you want to stop and then indicate that with the "." key (on a UK keyboard thesa are also the "<" and ">" keys). The tempo will then be calculated and set. + + + +subsection:: On XiiLangInstr + + +See: XiiLangInstr (highlight and hit alt+y to view) + + +The ixi lang instruments class stores the available instruments. Synthdefs are added when the class is run, but you can use any pattern-ready synth definition you have on your system. Synth Definitions are mapped onto keys on the keyboard, and when the language is run it creates synth definitions with the same names as your samples. This mapping is random unless a special keyMapping.ixi file is present in the sample folder where keys are mapped to the NAME of the sound. Mono and short sounds are ideal. + + +Use the command "new" go get the GUI where you can create your keymapping file. + + +If you want to use specific synth definitions for your project and map to the keys, you can create a synthdefs.scd file in your project folder. Make sure you add your synthdefs with the name of the project (e.g., SynthDef(\myDef, {bla bla}).add(\myProject), if you want to be able to map your synthdefs to keys using the keymapping GUI. + + + +subsection:: ixi lang Sattellites: + + +subsection:: The Coder: + + + +Opens up an ixi lang coding file, just as normally, except every keystroke is "sounded" as per key mapping. This makes it possible to live code in more "real-time" than when there is a delay between writing a score and executing it. + + +subsection:: The Matrix: + + +The Matrix is a sequencer where you can place samples, notes or SuperCollider code. Write letters into the matrix and those are containers of a function (which can be to trigger a sound or to run SuperCollider code). To control the cell the key combination of "fn" + the key value you want is used. Hit the TAB to start an actor and hit delete to remove it. + + +The following variables are available as globals and make it possible to create complex patterns. + +code:: + ~instr = \string; // set the instrument to string + + ~note = 60; // the note value of the instrument + + ~amp = 0.5; // amplitude + + ~wait = 0.25; // how long the agent waits on this cell + + ~nextX = 3; // which X (horizontal column to enter next) + + ~nextY = 1; // which Y (vertical row to enter next) +:: + +In the sccode: field, this can be coded using the SC lang (the language of SuperCollider): + + +code:: +~nextX = 5.rand; +:: + +The Matrix is a bit of a riddle. You have to explore it yourself! + + +subsection::: Example of a ixi lang session with comments: + +code:: +// remove comments and run this line in an EMPTY document and the ixi lang interpreter is launched (here you use SHIFT + RETURN) + +// or better use the demosession.scd file within the ixi lang folder + + +XiiLang(txt:true) + + +tuning just // choose a tuning (remember to use the ixi lang evaluation (Alt + right arrow) + +scale minor // set the scale + + + +// melodic score + +jimi -> string[1 2 6 2 ] // here we have an agent called jimi, playing four notes + + +jimi -> string[1 2 6 2 ]+12 // same as above but transposed up an octave (MIDI notes) + + +jimi -> string[1 2 6 2 ]!16 // ! 16 makes silence for 16 notes before playing again + + +jimi -> string[1 2 6 2 ]+12!16(12) // this can be combined - and alternating between whole and half notes + + +jimi -> string[1 2 6 2 ]+12(12~8) // alternating between whole and half notes but note sustain is multiplied by 8 + + +midiclients // want to send midi out to another app? + + +midiout 2 // send out on bus 2 + + +jarret -> midi[1 4 2 1 ]+12 // sending out midi on channel 1 + + +jarret -> midi[1 4 2 1 ]c5 // sending out midi info on channel 5 + + +a -> (135) // a chord can be defined in brackets and assigned to a character (one letter only) + + +jarret -> piano[1 3 5 a ] // the chord is then played inside the score + + +a -> $16 // 16 semitones above the fundamental + + +b -> $24 // two octaves above + + +c -> (158ab) // a chord with a tonic, a fifth, an octave, a third, and two octave above + + +bb -> piano[1 2 3 a b c c ] + + +// or as here below, jack a minor chord into a major scale + +scale major + +a -> $3 + +c -> (1a5) + +d -> (135) + +bb -> piano[1 2 a 3 4 5 c d ](1) + + + +// percussive score + +ringo -> |o x o x | // here o is mapped to a bass drum and x to a snare drum + + +ringo2 -> | ii s n | (1148) // here the notes get durations (two whole notes, a quarter and ab eigth) + + +ringo3 -> |c c c c |!2^1219^ // expanded by two and the accents are of amplitude 1 2 1 and 9 (relative to general amp) + + +ringo4 -> | o o d sd |!12 // ! 12 inserts silence for 12 beats + + + +// concrète score + +pierre -> water{0 2 8 4 1 0 } // numbers are amplitude + + +henry -> water{0 2 8 }!14 // last amp value is extended by 14 beats + + +schaeffer -> water{0 2 8 }*4!14 // duration is multiplied by 4 and same as above + + + + +jimi )) // increase the volume of jimi + + +jimi >> delay // add one effect to jimi's output + + +jimi >> distort >> reverb // put jimi through distortion and reverb effects + + +jimi << distort // remove distortion but not the reverb effect + + +jimi << // remove all effects + + +shake jimi // scramble jimi's score + + +future 2:4 >> swap jimi // in 2 seconds time, swap jimi's score. Do this 4 times + + +future 2b:4 >> swap jimi // every 2 bars, swap jimi's score. Do this 4 times + + +tempo 60 // set the tempo + + +tempo 120:10 // set the tempo to 120 in 10 seconds + + +group funnyband -> ringo jimi // create a new group + + +doze band // make the band stop + + +perk band // restart the bandmembers + + +sequence drumbo -> ringo ringo2 // create a new sequence of two sequences + + +snapshot -> one // take a snapshot of the agent states + + +snapshot one // recall the snapshot + + +swap jimi // swap jimi's score + + ++ jimi 12 // add 12 as an argument to the score (transposing octave up) + + +^ jimi 1842 // setting the amplitude arguments of jimi + + +future 2b:12 >> + jimi 7 12 0 // every 2 bars, transpose jimi's score to the tailing arguments + + +snapshot -> two // take a snapshot of the agent states + + +snapshot two // recall the snapshot + + +future 3:12 >> snapshot // recall a random snapshot every 3 seconds (12 times) + + +autocode 4 // create four lines of automatic code writing + + +save mysession // save a session with a unique name + + +load mysession // load that session at a later time + + +help // get this file + + +/// Experimental + + +Using ixi lang in normal SC code: + + +// when creating an agent, the string has to go in + +"aa -> xylo[2 3 4 ]".ixilang(0, newagent:true) // 1st arg: document nr, 2nd arg: new agent + +"axa -> xylo[2 3 4 8 3 ]".ixilang( newagent:true) + + +// if doc number is nil, a new window is created. + + +// then one can give it any ixi lang action: + +"doze axa".ixilang(0) + +"perk axa".ixilang(0) + +:: + +CLASSMETHODS:: + +METHOD:: new +argument:: project +argument:: keyarg +argument:: txt +argument:: newdoc +argument:: language +argument:: dicts +argument:: score +argument:: numChannels + + +INSTANCEMETHODS:: + +METHOD:: opInterpreter +argument:: string +argument:: return + +METHOD:: parseScoreMode0 +argument:: string +argument:: return +argument:: snapshot + +METHOD:: initEffect +argument:: string + +METHOD:: makeEffectDict + +METHOD:: addixiMenu + +METHOD:: playScoreMode1 +argument:: agent +argument:: notearr +argument:: durarr +argument:: sustainarr +argument:: attackarr +argument:: panarr +argument:: instrument +argument:: quantphase +argument:: newInstrFlag +argument:: midichannel +argument:: repeats +argument:: return +argument:: snapshot + +METHOD:: playScore +argument:: score + +METHOD:: initXiiLang +argument:: project +argument:: keyarg +argument:: txt +argument:: newdoc +argument:: lang +argument:: dicts +argument:: score +argument:: numChannels + +METHOD:: parseChord +argument:: string +argument:: mode + +METHOD:: swapString +argument:: doc +argument:: pureagentname +argument:: newscore +argument:: modearray +argument:: newarg +argument:: return + +METHOD:: inbus + +METHOD:: findStringStartEnd +argument:: doc +argument:: pureagentname + +METHOD:: parseMethod +argument:: string +argument:: return + +METHOD:: getMethodsList + +METHOD:: interpret +argument:: cmd + +METHOD:: decreaseAmp +argument:: string + +METHOD:: freeAgent +argument:: string + +METHOD:: parseScoreMode1 +argument:: string +argument:: return +argument:: snapshot + +METHOD:: parseScoreMode2 +argument:: string +argument:: return +argument:: snapshot + +METHOD:: playScoreMode2 +argument:: agent +argument:: pitch +argument:: amparr +argument:: durarr +argument:: panarr +argument:: instrument +argument:: quantphase +argument:: newInstrFlag +argument:: repeats +argument:: return +argument:: snapshot + +METHOD:: removeEffect +argument:: string + +METHOD:: updateInstrDict +argument:: char + +METHOD:: oncolor + +METHOD:: playScoreMode0 +argument:: agent +argument:: notearr +argument:: durarr +argument:: instrarr +argument:: sustainarr +argument:: attackarr +argument:: panarr +argument:: quantphase +argument:: newInstrFlag +argument:: morphmode +argument:: repeats +argument:: return +argument:: snapshot + +METHOD:: increaseAmp +argument:: string + +METHOD:: envirSetup +argument:: txt +argument:: newdoc +argument:: project + +METHOD:: createMetaAgent +argument:: string + +METHOD:: doccolor + +METHOD:: doc + +METHOD:: parsePostfixArgs +argument:: postfixstring + +METHOD:: parseSnapshot +argument:: string + +METHOD:: getInstrumentsList + + +EXAMPLES:: + +code:: +_some_example_code_ +:: \ No newline at end of file diff --git a/XiiLang.sc b/XiiLang.sc index 6963a0e..55f779c 100644 --- a/XiiLang.sc +++ b/XiiLang.sc @@ -1,4 +1,13 @@ +/* +possible changes: +effectDict should be global and initialized by *initClass, does not need to be evaluated on CmdPeriod + +implement *all to replace XiiLangSingletone + +eliminate number from nodeproxy naming + +*/ // use "~/Documents/ixilang".standardizePath as the path for projects @@ -125,9 +134,9 @@ ma2 -> ~ ag1 1 ma1 1 ~ XiiLang { - classvar globaldocnum; - var <>doc, docnum, useHomeDir = false; + var <>doc, ", "))", "((", "|", "[", "{", "~", ")", - "$", ">>", "<<", "tempo", "scale", "scalepush", "tuning", "tuningpush", "remind", "help", - "tonality", "instr", "tonic", "grid", "kill", "doze", "perk", "nap", "shake", "swap", "replace", - "insert", "remove", ">shift", ">", "<<", "tempo", "scale", "scalepush", "tuning", "tuningpush", "remind", "help", + "tonality", "instr", "tonic", "grid", "kill", "doze", "perk", "nap", "shake", "swap", "replace", + "insert", "remove", ">shift", " |asdf| -matrix 8 -oxo -> |Sdfsdf| \n\n\n") }); + if(txt == false, { doc.string_(" +use (alt/option)-(arrow right) to evaluate ixilang text. +help +remind +instr +agent1 -> string[1 2 3 4] +agent2 -> |abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ| +agent3 -> d{9 8 2 1}@1\n\n\n") }, + { + doc.string_(txt); + } + ); doc.setProperty(\styleSheet, "color:white"); // set the cursor to white doc.setStringColor(oncolor, 0, 100000); // then set the text color to whatever the user has specified doc.keyDownAction_({|doc, char, mod, unicode, keycode | var string; - //keycode.postln; - // evaluating code (the next line will use .isAlt, when that is available - if(((mod == 524288) || (mod == 2621440))&& ((keycode==124)||(keycode==123)||(keycode==125)||(keycode==126)||(keycode==111)||(keycode==113)||(keycode==114)||(keycode==116)), { // alt + left or up or right or down arrow keys - "eval".postln; - //linenr = doc.string[..doc.selectionStart-1].split($\n).size; - //doc.selectLine(linenr); - string = doc.selectedString; // ++ "\n"; - - (string.size < 1).if({"Hilight some text!".warn}); - if(keycode==123, { // not 124, 125, - this.freeAgent(string); - }, { - this.opInterpreter(string); - }); + var returnVal = nil; + var altArrow, altLeft, altPlus, altMinus; + //[mod, keycode, unicode].postln; + + altArrow = Platform.case( + \osx, { ((keycode==124)||(keycode==123)||(keycode==125) + ||(keycode==126)||(keycode==111)||(keycode==113)|| + (keycode==114)||(keycode==116)||(keycode==37)|| + (keycode==38)||(keycode==39)||(keycode==40)) + }, + \linux, {((keycode>=65361) && (keycode <=65364))}, + \windows, // I don't know, so this is a copy of the mac: + { ((keycode==124)||(keycode==123)||(keycode==125) + ||(keycode==126)||(keycode==111)||(keycode==113)|| + (keycode==114)||(keycode==116)||(keycode==37)|| + (keycode==38)||(keycode==39)||(keycode==40)) + } + ); + + altLeft = Platform.case( + \osx, {((keycode==123) || (keycode==37))}, + \linux,{(keycode==65361)}, + \windows, // I don't know, so here's a copy of osx + {((keycode==123) || (keycode==37))} + ); + + if( mod.isAlt && altArrow.value, + { // alt + left or up or right or down arrow keys + "eval".postln; + //linenr = doc.string[..doc.selectionStart-1].split($\n).size; + //doc.selectLine(linenr); + string = doc.selectedString; // ++ "\n"; + + (string.size < 1).if({"Hilight some text!".warn}); + + // alt + left + if(altLeft.value, { // not 124, 125, + this.freeAgent(string); + }, { + this.opInterpreter(string); + }); + returnVal = true; }); - // create a live sampler doc (fn+Enter) - if((mod == 8388864) && (unicode == 3), { + // create a live sampler doc (fn+Enter or alt+Enter) + if((mod.isFun || mod.isAlt) && (unicode == 3), { ixiInstr.createRecorderDoc(this, numChan); + returnVal = true; }); // tempo tap function (ctrl+, for starting and ctrl+. for stopping (the < and > keys)) - if(((mod == 262145)||(mod==262401)) && (unicode == 44), { + if((mod.isCtrl || mod.isAlt) && (unicode == 44), { if(tapping == false, { time = Main.elapsedTime; tapping = true; }); tapcount = tapcount + 1; }); - if(((mod == 262145)||(mod==262401)) && (unicode == 46), { - time = Main.elapsedTime - time; - tempo = tapcount / time; - tapping = false; - tapcount = 0; - " ---> ixi lang Tempo : set to % BPM\n".postf(tempo*60); - TempoClock.default.tempo = tempo; + if((mod.isCtrl || mod.isAlt) && (unicode == 46), { + if( (time.isNil || tapping.not), { + "Tap with the comma key first".warn; + }, { + time = Main.elapsedTime - time; + tempo = tapcount / time; + tapping = false; + tapcount = 0; + " ---> ixi lang Tempo : set to % BPM\n".postf(tempo*60); + TempoClock.default.tempo = tempo; + }); + }); + // Change font size + if(mod.isCtrl && (unicode==43), { + var font; + font = doc. font; + font.size = font.size + 1; + doc.font = font; + //"bigger".postln; + returnVal = true; + }); + if(mod.isCtrl && (unicode==45), { + var font; + font = doc. font; + font.size = font.size - 1; + doc.font = font; + + returnVal = true; }); + returnVal }); doc.keyUpAction_({|doc, char, mod, unicode, keycode | - if(mod == 8388864, { + if(mod.isFun, { recdoc.close; }); }); @@ -378,35 +456,32 @@ oxo -> |Sdfsdf| \n\n\n") }); snapshotDict[\futures].stop; }); // these two folders are created if the user is downloading from github and hasn't created the ixilang folder in their SC folder - if((Platform.userAppSupportDir ++"/ixilang").pathMatch==[], { - //("mkdir -p" + (Platform.userAppSupportDir ++"/ixilang")).unixCmd; // create the scores folder - File.mkdir(Platform.userAppSupportDir ++"/ixilang"); - "ixi-lang NOTE: an ixi lang folder was not found in your SuperCollider directory (in ~Library/Application Support) - It was created".postln; - }); - if((Platform.userAppSupportDir ++"/ixilang/default").pathMatch==[], { - File.mkdir(Platform.userAppSupportDir ++"/ixilang/default"); - //("mkdir -p" + (Platform.userAppSupportDir ++"/ixilang/default")).unixCmd; // create the scores folder - "ixi-lang NOTE: an ixi lang default folder was not found in your ixi lang directory - It was created".postln; - }); + if((path = XiiLang.ixiDir).pathMatch==[]) { + File.mkdir(path); + ("ixi-lang NOTE: an ixi lang folder was not found" + path + "was created").postln; + }; + if((path = XiiLang.ixiDir++ "/default").pathMatch==[]) { + File.mkdir(path); + ("ixi-lang NOTE: an ixi lang default folder was not found." + path + "was created").postln; + }; // just make sure that all folders are in place - if((Platform.userAppSupportDir ++"/ixilang/"++project++"/scores").pathMatch==[], { - File.mkdir(Platform.userAppSupportDir ++"/ixilang/"++project++"/scores"); - //("mkdir -p" + (Platform.userAppSupportDir ++"/ixilang/"++project++"/scores")).unixCmd; // create the scores folder + if((this.projectDir++"/scores").pathMatch==[], { + File.mkdir(this.projectDir++"/scores"); "ixi-lang NOTE: a scores folder was not found for saving scores - It was created".postln; }); - if((Platform.userAppSupportDir ++"/ixilang/"++project++"/recordings").pathMatch==[], { - File.mkdir(Platform.userAppSupportDir ++"/ixilang/"++project++"/recordings"); - // ("mkdir -p" + (Platform.userAppSupportDir ++"/ixilang/"++project++"/recordings")).unixCmd; // create the recordings folder + if((this.projectDir++"/recordings").pathMatch==[], { + File.mkdir(this.projectDir++"/recordings"); + // ("mkdir -p" + (this.projectDir++"/recordings")).unixCmd; // create the recordings folder "ixi-lang NOTE: a recordings folder was not found for saving scores - It was created".postln; }); - if((Platform.userAppSupportDir ++"/ixilang/"++project++"/sessions").pathMatch==[], { - File.mkdir(Platform.userAppSupportDir ++"/ixilang/"++project++"/sessions"); - // ("mkdir -p" + (Platform.userAppSupportDir ++"/ixilang/"++project++"/sessions")).unixCmd; // create the sessions folder + if((this.projectDir++"/sessions").pathMatch==[], { + File.mkdir(this.projectDir++"/sessions"); + // ("mkdir -p" + (this.projectDir++"/sessions")).unixCmd; // create the sessions folder "ixi-lang NOTE: a sessions folder was not found for saving scores - It was created".postln; }); - if((Platform.userAppSupportDir ++"/ixilang/"++project++"/samples").pathMatch==[], { - File.mkdir(Platform.userAppSupportDir ++"/ixilang/"++project++"/samples"); - //("mkdir -p" + (Platform.userAppSupportDir ++"/ixilang/"++project++"/samples")).unixCmd; // create the samples folder + if((this.projectDir++"/samples").pathMatch==[], { + File.mkdir(this.projectDir++"/samples"); + //("mkdir -p" + (this.projectDir++"/samples")).unixCmd; // create the samples folder "ixi-lang NOTE: a samples folder was not found for saving scores - It was created".postln; }); } @@ -447,857 +522,870 @@ oxo -> |Sdfsdf| \n\n\n") }); }); switch(operator) - {"dict"}{ // TEMP: only used for debugging - "-- Groups : ".postln; - Post << groups; "\n".postln; + {"dict"}{ // TEMP: only used for debugging + "-- Groups : ".postln; + Post << groups; "\n".postln; - "-- agentDicts : ".postln; - Post << agentDict.keys; "\n".postln; - Post << agentDict; "\n".postln; + "-- agentDicts : ".postln; + Post << agentDict.keys; "\n".postln; + Post << agentDict; "\n".postln; - "-- snapshotDicts : ".postln; - Post << snapshotDict; "\n".postln; + "-- snapshotDicts : ".postln; + Post << snapshotDict; "\n".postln; - "-- proxyspace : ".postln; - Post << proxyspace; "\n".postln; + "-- proxyspace : ".postln; + Post << proxyspace; "\n".postln; - "-- metaAgentDict : ".postln; - Post << metaAgentDict; "\n".postln; + "-- metaAgentDict : ".postln; + Post << metaAgentDict; "\n".postln; - // "-- scoreArray : ".postln; - // Post << scoreArray; "\n".postln; + // "-- scoreArray : ".postln; + // Post << scoreArray; "\n".postln; - // "-- buffers : ".postln; - // Post << ixiInstr.returnBufferDict; "\n".postln; + // "-- buffers : ".postln; + // Post << ixiInstr.returnBufferDict; "\n".postln; - } - {"store"}{ - var sessionstart, sessionend, session; - string = string.replace(" ", " "); - string = string.replace(" ", " "); - string = string.replace(" ", " "); - string = string++" "; // add a space in order to find end of agent (if no argument) - sessionstart = string.findAll(" ")[0]; - sessionend = string.findAll(" ")[1]; - session = string[sessionstart+1..sessionend-1]; - [projectname, key, language, doc.string, agentDict, snapshotDict, groups, docnum].writeArchive(Platform.userAppSupportDir ++"/ixilang/"++projectname++"/sessions/"++session++".ils"); - } - {"load"}{ - var sessionstart, sessionend, session, key, language, project; - var tempAgentDict, tempSnapshotDict; - string = string.replace(" ", " "); - string = string.replace(" ", " "); - string = string.replace(" ", " "); - string = string++" "; // add a space in order to find end of agent (if no argument) - sessionstart = string.findAll(" ")[0]; - sessionend = string.findAll(" ")[1]; - session = string[sessionstart+1..sessionend-1]; - doc.onClose; // call this to end all agents and groups in this particular doc if it has been running agents - #project, key, language, string, agentDict, snapshotDict, groups, docnum = Object.readArchive(Platform.userAppSupportDir ++"/ixilang/"++projectname++"/sessions/"++session++".ils"); - doc.string = string; - XiiLang.new( project, key, true, false, language, [agentDict, snapshotDict, groups, docnum]); - } - {"snapshot"}{ - this.parseSnapshot(string); - } - {"->"}{ - var mode; - mode = block{|break| - ["|", "[", "{", ")", "$", "~"].do({arg op, i; - var c = string.find(op); - if(c.isNil.not, {break.value(i)}); - }); - }; + } + {"store"}{ + var sessionstart, sessionend, session; + string = string.replace(" ", " "); + string = string.replace(" ", " "); + string = string.replace(" ", " "); + string = string++" "; // add a space in order to find end of agent (if no argument) + sessionstart = string.findAll(" ")[0]; + sessionend = string.findAll(" ")[1]; + session = string[sessionstart+1..sessionend-1]; + [projectname, key, language, doc.string, agentDict, snapshotDict, groups, docnum].writeArchive(this.projectDirname++"/sessions/"++session++".ils"); + } + {"load"}{ + var sessionstart, sessionend, session, key, language, project; + var tempAgentDict, tempSnapshotDict; + string = string.replace(" ", " "); + string = string.replace(" ", " "); + string = string.replace(" ", " "); + string = string++" "; // add a space in order to find end of agent (if no argument) + sessionstart = string.findAll(" ")[0]; + sessionend = string.findAll(" ")[1]; + session = string[sessionstart+1..sessionend-1]; + doc.onClose; // call this to end all agents and groups in this particular doc if it has been running agents + #project, key, language, string, agentDict, snapshotDict, groups, docnum = Object.readArchive(this.projectDirname++"/sessions/"++session++".ils"); + doc.string = string; + XiiLang.new( project, key, true, false, language, [agentDict, snapshotDict, groups, docnum]); + } + {"snapshot"}{ + this.parseSnapshot(string); + } + {"->"}{ + var mode; + mode = block{|break| + ["|", "[", "{", ")", "$", "~"].do({arg op, i; + var c = string.find(op); + if(c.isNil.not, {break.value(i)}); + }); + }; [\mode, mode].postln; - switch(mode) - {0} { ^this.parseScoreMode0(string, return) } - {1} { ^this.parseScoreMode1(string, return) } - {2} { ^this.parseScoreMode2(string, return) } - {3} { this.parseChord(string, \c) } - {4} { this.parseChord(string, \n) } - {5} { this.createMetaAgent(string) }; - } - {"future"}{ - // future 8:4 >> swap thor // every 8 SECONDS the action is performed (here 4 times) - // future 4b:4 >> swap thor // every 8 BARS the action is performed (here 4 times) - // future << thor // cancel the scheduling - var command, commandstart, colon, seconds, times, agent, pureagent, agentstart, agentend, argument; - var cursorPos, testcond, snapshot, barmode, argumentarray, tempstring; - - string = string.reject({ |c| c.ascii == 10 }); // get rid of char return - // allow for some sloppyness in style - string = string++" "; // add a space in order to find end of agent (if no argument) - string = string.replace(" ", " "); - string = string.replace(" ", " "); - string = string.replace(" ", " "); - - if(string.contains(">>"), { // setting future event(s) - commandstart = string.find(">"); - colon = string.find(":"); - if(string[6..colon-1].contains("b") || string[6..colon-1].contains("B"), { - barmode = true; - seconds = string[6..colon-1].tr($b, \).asFloat; // remove the b and get the beats - },{ - barmode = false; // is the future working in seconds or bars ? - seconds = string[6..colon-1].asFloat; - }); - times = string[colon+1..commandstart-1].asInteger; - if(string[commandstart+3..commandstart+10] == "snapshot", { // it's the "choose snapshot" future - if(snapshotDict.size > 1, { + switch(mode) + {0} { ^this.parseScoreMode0(string, return) } + {1} { ^this.parseScoreMode1(string, return) } + {2} { ^this.parseScoreMode2(string, return) } + {3} { this.parseChord(string, \c) } + {4} { this.parseChord(string, \n) } + {5} { this.createMetaAgent(string) }; + } + {"future"}{ + // future 8:4 >> swap thor // every 8 SECONDS the action is performed (here 4 times) + // future 4b:4 >> swap thor // every 8 BARS the action is performed (here 4 times) + // future << thor // cancel the scheduling + var command, commandstart, colon, seconds, times, agent, pureagent, agentstart, agentend, argument; + var cursorPos, testcond, snapshot, barmode, argumentarray, tempstring; + + string = string.reject({ |c| c.ascii == 10 }); // get rid of char return + // allow for some sloppyness in style + string = string++" "; // add a space in order to find end of agent (if no argument) + string = string.replace(" ", " "); + string = string.replace(" ", " "); + string = string.replace(" ", " "); + + if(string.contains(">>"), { // setting future event(s) + commandstart = string.find(">"); + colon = string.find(":"); + if(string[6..colon-1].contains("b") || string[6..colon-1].contains("B"), { + barmode = true; + seconds = string[6..colon-1].tr($b, \).asFloat; // remove the b and get the beats + },{ + barmode = false; // is the future working in seconds or bars ? + seconds = string[6..colon-1].asFloat; + }); + times = string[colon+1..commandstart-1].asInteger; + if(string[commandstart+3..commandstart+10] == "snapshot", { // it's the "choose snapshot" future + if(snapshotDict.size > 1, { snapshotDict[\futures].stop; // futures is when future is choosing a random snapshot snapshotDict[\futures] = // don't need to store the name, just a unique name - { - times.do({arg i; - seconds.wait; - testcond = false; - while({ testcond.not }, { - snapshot = snapshotDict.keys.choose; - if(snapshot != \futures, { testcond = true }); - }); - { + { + times.do({arg i; + seconds.wait; + testcond = false; + while({ testcond.not }, { + snapshot = snapshotDict.keys.choose; + if(snapshot != \futures, { testcond = true }); + }); + { cursorPos = doc.selectionStart; // get cursor pos this.parseSnapshot("snapshot " ++ snapshot.asString); //doc.selectRange(cursorPos); // set cursor pos again doc.select(cursorPos,0); // xxx - }.defer; - }) - }.fork(TempoClock.new) // not using default clock, since new tempo affects wait (strange?/bug?) - }, { - " ---> ixi lang: you haven't stored more than one snapshot!".postln; - }); + }.defer; + }) + }.fork(TempoClock.new) // not using default clock, since new tempo affects wait (strange?/bug?) }, { - agentstart = string.findAll(" ")[3]; - agentend = string.findAll(" ")[4]; - pureagent = string[agentstart+1..agentend-1]; - agent = (docnum.asString++pureagent).asSymbol; - command = string[commandstart+3..agentstart-1]; - argument = string[agentend..string.size-1]; - argumentarray = []; - tempstring = ""; - argument.do({arg item; - if(item.isAlphaNum || (item == $_), { - tempstring = tempstring ++ item; - }, { - if(tempstring != "", {argumentarray = argumentarray.add(tempstring)}); // removed .asInteger here XXX !!! could cause bugs - tempstring =""; - }); + " ---> ixi lang: you haven't stored more than one snapshot!".postln; + }); + }, { + agentstart = string.findAll(" ")[3]; + agentend = string.findAll(" ")[4]; + pureagent = string[agentstart+1..agentend-1]; + agent = (this.agentPrefix++pureagent).asSymbol; // !!! + command = string[commandstart+3..agentstart-1]; + argument = string[agentend..string.size-1]; + argumentarray = []; + tempstring = ""; + argument.do({arg item; + if(item.isAlphaNum || (item == $_), { + tempstring = tempstring ++ item; + }, { + if(tempstring != "", {argumentarray = argumentarray.add(tempstring)}); // removed .asInteger here XXX !!! could cause bugs + tempstring =""; }); - if(argumentarray == [], {argumentarray = [argument]}); // removed .asInteger here XXX !!! could cause bugs + }); + if(argumentarray == [], {argumentarray = [argument]}); // removed .asInteger here XXX !!! could cause bugs - //if future argument contains many args then put them into a list that will be wrappedAt in the future task + //if future argument contains many args then put them into a list that will be wrappedAt in the future task - if(groups.at(agent).isNil.not, { // the "agent" is a group so we need to set routine to each of the agents in the group - groups.at(agent).do({arg agentx, i; - { var agent; // this var and the value statement is needed to individualise the agents in the future - agent = (docnum.asString++agentx).asSymbol; + if(groups.at(agent).isNil.not, { // the "agent" is a group so we need to set routine to each of the agents in the group + groups.at(agent).do({arg agentx, i; + { var agent; // this var and the value statement is needed to individualise the agents in the future + agent = (this.agentPrefix++agentx).asSymbol; agentDict[agent][2] = agentDict[agent][2].add( - { - times.do({arg i; - if(barmode, { - ((seconds*agentDict[agent][1].durarr.sum)/TempoClock.default.tempo).wait; - },{ - seconds.wait; - }); - { + { + times.do({arg i; + if(barmode, { + ((seconds*agentDict[agent][1].durarr.sum)/TempoClock.default.tempo).wait; + },{ + seconds.wait; + }); + { scoreArray = scoreArray.add([Main.elapsedTime, command+agentx+argumentarray.wrapAt(i).asString]); this.parseMethod(command+agentx+argumentarray.wrapAt(i).asString); // do command - }.defer; - }); - }.fork(TempoClock.new) - ); - }.value; - }); - }, { // it is a real agent, not a group, then we ADD - agentDict[agent][2] = agentDict[agent][2].add( - { - times.do({arg i; - if(barmode, { - ((seconds*agentDict[agent][1].durarr.sum)/TempoClock.default.tempo).wait; - },{ - seconds.wait; + }.defer; }); - { + }.fork(TempoClock.new) + ); + }.value; + }); + }, { // it is a real agent, not a group, then we ADD + agentDict[agent][2] = agentDict[agent][2].add( + { + times.do({arg i; + if(barmode, { + ((seconds*agentDict[agent][1].durarr.sum)/TempoClock.default.tempo).wait; + },{ + seconds.wait; + }); + { scoreArray = scoreArray.add([Main.elapsedTime, command+pureagent+argumentarray.wrapAt(i).asString]); this.parseMethod(command+pureagent+argumentarray.wrapAt(i).asString); // do command - }.defer; - }); - // agentDict[agent][2] = nil; // set it back to nil after routine is finished - }.fork(TempoClock.new) - ); - }); + }.defer; + }); + // agentDict[agent][2] = nil; // set it back to nil after routine is finished + }.fork(TempoClock.new) + ); }); - }, { // removing future scheduling (syntax: future << agent) - agentstart = string.findAll(" ")[1]; - agentend = string.findAll(" ")[2]; - agent = string[agentstart+1..agentend-1]; - agent = (docnum.asString++agent).asSymbol; - if(groups.at(agent).isNil.not, { // the "agent" is a group so we need to set routine to each of the agents in the group - groups.at(agent).do({arg agentx, i; - agent = (docnum.asString++agentx).asSymbol; - agentDict[agent][2].do({arg routine; routine.stop}); - agentDict[agent][2] = []; - }); - },{ + }); + }, { // removing future scheduling (syntax: future << agent) + agentstart = string.findAll(" ")[1]; + agentend = string.findAll(" ")[2]; + agent = string[agentstart+1..agentend-1]; + agent = (this.agentPrefix++agent).asSymbol; + if(groups.at(agent).isNil.not, { // the "agent" is a group so we need to set routine to each of the agents in the group + groups.at(agent).do({arg agentx, i; + agent = (this.agentPrefix++agentx).asSymbol; agentDict[agent][2].do({arg routine; routine.stop}); agentDict[agent][2] = []; }); + },{ + agentDict[agent][2].do({arg routine; routine.stop}); + agentDict[agent][2] = []; }); - } - {">>"}{ - this.initEffect(string); - } - {"<<"}{ - this.removeEffect(string); - } - {"))"}{ - this.increaseAmp(string); - } - {"(("}{ - this.decreaseAmp(string); - } - {"tempo"}{ - var newtemp, time, op; - var nrstart = string.find("o")+1; - if(string.contains(":"), { - string = string.tr($ , \); - op = string.find(":"); - newtemp = string[nrstart..op].asInteger/60; - time = string[op+1..string.size-1].asInteger; - TempoClock.default.sync(newtemp, time); - }, { - newtemp = string[nrstart+1..string.size-1].asInteger / 60; - TempoClock.default.tempo = newtemp; - }); - "---> Setting tempo to : ".post; (newtemp*60).postln; - } - {"scale"}{ - var agent, firstarg; - string = string++" "; - firstarg = string[string.findAll(" ")[0]+1..(string.findAll(" ")[1])-1]; - agent = (docnum.asString++firstarg).asSymbol; - if(agentDict.keys.includes(agent), { - this.parseMethod(string); // since future will use this, I need to parse the method - }, { - chosenscale = ("Scale."++firstarg).interpret; - chosenscale.tuning_(tuning.asSymbol); - scale = chosenscale.semitones.copy.add(12); // used to be degrees, but that doesn't support tuning - }); - } - {"scalepush"}{ - var scalestart, scalestr; - var dictscore, mode; - scalestart = string.find("h"); - scalestr = string.tr($ , \); - scalestr = scalestr[scalestart+1..scalestr.size-1]; - chosenscale = ("Scale."++scalestr).interpret; + }); + } + {">>"}{ + this.initEffect(string); + } + {"<<"}{ + this.removeEffect(string); + } + {"))"}{ + this.increaseAmp(string); + } + {"(("}{ + this.decreaseAmp(string); + } + {"tempo"}{ + var newtemp, time, op; + var nrstart = string.find("o")+1; + if(string.contains(":"), { + string = string.tr($ , \); + op = string.find(":"); + newtemp = string[nrstart..op].asInteger/60; + time = string[op+1..string.size-1].asInteger; + TempoClock.default.sync(newtemp, time); + }, { + newtemp = string[nrstart+1..string.size-1].asInteger / 60; + TempoClock.default.tempo = newtemp; + }); + "---> Setting tempo to : ".post; (newtemp*60).postln; + } + {"scale"}{ + var agent, firstarg; + string = string++" "; + firstarg = string[string.findAll(" ")[0]+1..(string.findAll(" ")[1])-1]; + agent = (this.agentPrefix++firstarg).asSymbol; + if(agentDict.keys.includes(agent), { + this.parseMethod(string); // since future will use this, I need to parse the method + }, { + chosenscale = ("Scale."++firstarg).interpret; chosenscale.tuning_(tuning.asSymbol); scale = chosenscale.semitones.copy.add(12); // used to be degrees, but that doesn't support tuning - agentDict.do({arg agent; - dictscore = agent[1].scorestring; - dictscore = dictscore.reject({ |c| c.ascii == 34 }); // get rid of quotation marks - mode = block{|break| - ["|", "[", "{", ")"].do({arg op, i; var c = dictscore.find(op); - if(c.isNil.not, {break.value(i)}); - }); - }; - switch(mode) - {0} { this.parseScoreMode0(dictscore, false) } - {1} { this.parseScoreMode1(dictscore, false) }; - // {2} { this.parseScoreMode2(dictscore) }; // not relevant - if(agent[1].playstate == true, { - proxyspace[agent].play; + }); + } + {"scalepush"}{ + var scalestart, scalestr; + var dictscore, mode; + scalestart = string.find("h"); + scalestr = string.tr($ , \); + scalestr = scalestr[scalestart+1..scalestr.size-1]; + chosenscale = ("Scale."++scalestr).interpret; + chosenscale.tuning_(tuning.asSymbol); + scale = chosenscale.semitones.copy.add(12); // used to be degrees, but that doesn't support tuning + agentDict.do({arg agent; + dictscore = agent[1].scorestring; + dictscore = dictscore.reject({ |c| c.ascii == 34 }); // get rid of quotation marks + mode = block{|break| + ["|", "[", "{", ")"].do({arg op, i; var c = dictscore.find(op); + if(c.isNil.not, {break.value(i)}); }); + }; + switch(mode) + {0} { this.parseScoreMode0(dictscore, false) } + {1} { this.parseScoreMode1(dictscore, false) }; + // {2} { this.parseScoreMode2(dictscore) }; // not relevant + if(agent[1].playstate == true, { + proxyspace[agent].play; }); - } - {"tuning"}{ - var tuningstart, tuningstr; - tuningstart = string.find("g"); - tuningstr = string.tr($ , \); - tuning = tuningstr[tuningstart+1..tuningstr.size-1]; - tuning = tuning.reject({ |c| c.ascii == 10 }); // get rid of char return - chosenscale.tuning_(tuning.asSymbol); - scale = chosenscale.semitones.copy.add(12); - } - {"tuningpush"}{ - var tuningstart, tuningstr; - var dictscore, mode; - tuningstart = string.find("g"); - tuningstr = string.tr($ , \); - tuning = tuningstr[tuningstart+1..tuningstr.size-1]; - tuning = tuning.reject({ |c| c.ascii == 10 }); // get rid of char return - chosenscale.tuning_(tuning.asSymbol); - scale = chosenscale.semitones.copy.add(12); - agentDict.do({arg agent; - dictscore = agent[1].scorestring; - dictscore = dictscore.reject({ |c| c.ascii == 34 }); // get rid of quotation marks - mode = block{|break| - ["|", "[", "{", ")"].do({arg op, i; var c = dictscore.find(op); - if(c.isNil.not, {break.value(i)}); - }); - }; - switch(mode) - {0} { this.parseScoreMode0(dictscore, false) } - {1} { this.parseScoreMode1(dictscore, false) }; - // {2} { this.parseScoreMode2(dictscore) }; // not relevant - if(agent[1].playstate == true, { - proxyspace[agent].play; + }); + } + {"tuning"}{ + var tuningstart, tuningstr; + tuningstart = string.find("g"); + tuningstr = string.tr($ , \); + tuning = tuningstr[tuningstart+1..tuningstr.size-1]; + tuning = tuning.reject({ |c| c.ascii == 10 }); // get rid of char return + chosenscale.tuning_(tuning.asSymbol); + scale = chosenscale.semitones.copy.add(12); + } + {"tuningpush"}{ + var tuningstart, tuningstr; + var dictscore, mode; + tuningstart = string.find("g"); + tuningstr = string.tr($ , \); + tuning = tuningstr[tuningstart+1..tuningstr.size-1]; + tuning = tuning.reject({ |c| c.ascii == 10 }); // get rid of char return + chosenscale.tuning_(tuning.asSymbol); + scale = chosenscale.semitones.copy.add(12); + agentDict.do({arg agent; + dictscore = agent[1].scorestring; + dictscore = dictscore.reject({ |c| c.ascii == 34 }); // get rid of quotation marks + mode = block{|break| + ["|", "[", "{", ")"].do({arg op, i; var c = dictscore.find(op); + if(c.isNil.not, {break.value(i)}); }); + }; + switch(mode) + {0} { this.parseScoreMode0(dictscore, false) } + {1} { this.parseScoreMode1(dictscore, false) }; + // {2} { this.parseScoreMode2(dictscore) }; // not relevant + if(agent[1].playstate == true, { + proxyspace[agent].play; }); - } - {"remind"}{ - this.getMethodsList; - } - {"help"}{ - //XiiLang.openHelpFile; // ixi lang doesn't have the new helpfile format - //(XiiLang.filenameSymbol.asString.dirname++"/XiiLang.html").openTextFile; - WebView.new(Window.new("", Rect(100, 100, 600, 700)).front, Rect(0, 0, 600, 700)).resize_(5).url_(XiiLang.filenameSymbol.asString.dirname++"/XiiLang.html").enterInterpretsSelection_(true); - - } - {"tonality"}{ - var doc; - doc = Document.new; - doc.name_("scales"); - doc.promptToSave_(false); - doc.background_(Color.black); - doc.setStringColor(Color.green, 0, 1000000); - doc.bounds_(Rect(10, 500, 500, 800)); - doc.font_(Font("Monaco",16)); - doc.string_("Scales: " + ScaleInfo.scales.keys.asArray.sort.asCompileString + }); + } + {"remind"}{ + this.getMethodsList; + } + {"help"}{ + XiiLang.openHelpFile; + } + {"tonality"}{ + var doc; + doc = Document.new; + doc.name_("scales"); + doc.promptToSave_(false); + doc.background_(Color.black); + doc.setStringColor(Color.green, 0, 1000000); + doc.bounds_(Rect(10, 500, 500, 800)); + doc.font_(Font("Monaco",16)); + doc.string_("Scales: " + ScaleInfo.scales.keys.asArray.sort.asCompileString +"\n\n Tunings: "+ "et12, pythagorean, just, sept1, sept2, mean4, mean5, mean6, kirnberger, werkmeister, vallotti, young, reinhard, wcHarm, wcSJ"); - } - {"instr"}{ - this.getInstrumentsList; - } - {"tonic"}{ - var tonicstart, tstring, tonicstr; - tonicstart = string.find("c"); - tstring = string.tr($ , \); - tonicstr = tstring[tonicstart+1..tstring.size-1]; - tonicstr = tonicstr.reject({ |c| c.ascii == 10 }); // get rid of char return - if(tonicstr.asInteger == 0, { // it's a string - tonic = 60 + [\C, \CS, \D, \DS, \E, \F, \FS, \G, \GS, \A, \AS, \B].indexOf(tonicstr.toUpper.asSymbol); // midinote 60 is the default - }, { - tonic = tonicstr.asInteger; - }); - } - {"grid"}{ - var cursorPos, gridstring, meter, grids, gridstart; - cursorPos = doc.selectionStart; // get cursor pos - meter = string[string.find(" ")..string.size-1].asInteger; - if(meter == "grid", {meter = 1}); - gridstring = ""; - 50.do({arg i; gridstring = gridstring++if((i%meter)==0, {"|"}, {" "}) }); - doc.string_(doc.string.replace(string, gridstring++"\n")); - } - {"kill"}{ - proxyspace.end; - proxyspace = ProxySpace.new.know_(true); - snapshotDict[\futures].stop; // ooo not working - agentDict.do({arg agent; - agent[2].do({arg routine; routine.stop}); - }); - agentDict.do({arg agent; - agent[2].stop; - agent[2] = nil; - }); - } - {"group"}{ - var spaces, groupname, op, groupitems; - // allow for some sloppyness in style - string = string.replace(" ", " "); - string = string.replace(" ", " "); - string = string++" "; // add an extra space at the end - string = string.replace(" ", " "); - string = string.reject({ |c| c.ascii == 10 }); // get rid of char return - spaces = string.findAll(" "); - groupname = string[spaces[0]+1..spaces[1]-1]; - " ---> ixi lang : MAKING A GROUP : ".post; groupname.postln; - groupname = (docnum.asString++groupname).asSymbol; // multidoc support - op = string.find("->"); - groupitems = []; - (spaces.size-1).do({arg i; - if(spaces[i] > op, { groupitems = groupitems.add( string[spaces[i]+1..spaces[i+1]-1].asSymbol ) }) - }); - groups.add(groupname -> groupitems); - } - {"sequence"}{ - var spaces, sequenceagent, op, seqagents, typecheck, firsttype, sa, originalstring, originalagents, fullscore; - var notearr, durarr, sustainarr, instrarr, attackarr, amparr, panarr, score, instrument, quantphase, newInstrFlag = false; - typecheck = 0; - notearr = []; - durarr = []; - sustainarr = []; - attackarr = []; - amparr = []; - panarr = []; - instrarr = []; - score = ""; - originalstring = string; - " ---> ixi lang : MAKING A SEQUENCE : ".postln; - // allow for some sloppyness in style - string = string.replace(" ", " "); - string = string.replace(" ", " "); - string = string.replace(" ", " "); - string = string++" "; // add an extra space at the end - string = string.reject({ |c| c.ascii == 10 }); // get rid of char return - spaces = string.findAll(" "); - sequenceagent = string[spaces[0]+1..spaces[1]-1]; - sa = sequenceagent; - sequenceagent = (docnum.asString++sequenceagent).asSymbol; // multidoc support - op = string.find("->"); - seqagents = []; - originalagents = []; - - (spaces.size-1).do({arg i; - if(spaces[i] > op, { - seqagents = seqagents.add((docnum.asString++string[spaces[i]+1..spaces[i+1]-1]).asSymbol); - originalagents = originalagents.add(string[spaces[i]+1..spaces[i+1]-1]); - }); + } + {"instr"}{ + this.getInstrumentsList; + } + {"tonic"}{ + var tonicstart, tstring, tonicstr; + tonicstart = string.find("c"); + tstring = string.tr($ , \); + tonicstr = tstring[tonicstart+1..tstring.size-1]; + tonicstr = tonicstr.reject({ |c| c.ascii == 10 }); // get rid of char return + if(tonicstr.asInteger == 0, { // it's a string + tonic = 60 + [\C, \CS, \D, \DS, \E, \F, \FS, \G, \GS, \A, \AS, \B].indexOf(tonicstr.toUpper.asSymbol); // midinote 60 is the default + }, { + tonic = tonicstr.asInteger; + }); + } + {"grid"}{ + var cursorPos, gridstring, meter, grids, gridstart; + cursorPos = doc.selectionStart; // get cursor pos + meter = string[string.find(" ")..string.size-1].asInteger; + if(meter == "grid", {meter = 1}); + gridstring = ""; + 50.do({arg i; gridstring = gridstring++if((i%meter)==0, {"|"}, {" "}) }); + doc.string_(doc.string.replace(string, gridstring++"\n")); + } + {"kill"}{ + proxyspace.end; + proxyspace = ProxySpace.new.know_(true); + snapshotDict[\futures].stop; // ooo not working + agentDict.do({arg agent; + agent[2].do({arg routine; routine.stop}); + }); + agentDict.do({arg agent; + agent[2].stop; + agent[2] = nil; + }); + } + {"group"}{ + var spaces, groupname, op, groupitems; + // allow for some sloppyness in style + string = string.replace(" ", " "); + string = string.replace(" ", " "); + string = string++" "; // add an extra space at the end + string = string.replace(" ", " "); + string = string.reject({ |c| c.ascii == 10 }); // get rid of char return + spaces = string.findAll(" "); + groupname = string[spaces[0]+1..spaces[1]-1]; + " ---> ixi lang : MAKING A GROUP : ".post; groupname.postln; + groupname = (this.agentPrefix++groupname).asSymbol; // multidoc support + op = string.find("->"); + groupitems = []; + (spaces.size-1).do({arg i; + if(spaces[i] > op, { groupitems = groupitems.add( string[spaces[i]+1..spaces[i+1]-1].asSymbol ) }) + }); + groups.add(groupname -> groupitems); + } + {"sequence"}{ + var spaces, sequenceagent, op, seqagents, typecheck, firsttype, sa, originalstring, originalagents, fullscore; + var notearr, durarr, sustainarr, instrarr, attackarr, amparr, panarr, score, instrument, quantphase, newInstrFlag = false; + typecheck = 0; + notearr = []; + durarr = []; + sustainarr = []; + attackarr = []; + amparr = []; + panarr = []; + instrarr = []; + score = ""; + originalstring = string; + " ---> ixi lang : MAKING A SEQUENCE : ".postln; + // allow for some sloppyness in style + string = string.replace(" ", " "); + string = string.replace(" ", " "); + string = string.replace(" ", " "); + string = string++" "; // add an extra space at the end + string = string.reject({ |c| c.ascii == 10 }); // get rid of char return + spaces = string.findAll(" "); + sequenceagent = string[spaces[0]+1..spaces[1]-1]; + sa = sequenceagent; + sequenceagent = (this.agentPrefix++sequenceagent).asSymbol; // multidoc support + op = string.find("->"); + seqagents = []; + originalagents = []; + + (spaces.size-1).do({arg i; + if(spaces[i] > op, { + seqagents = seqagents.add((this.agentPrefix++string[spaces[i]+1..spaces[i+1]-1]).asSymbol); + originalagents = originalagents.add(string[spaces[i]+1..spaces[i+1]-1]); }); - // check if all items are of same type - firsttype = agentDict[seqagents[0]][1].mode; - seqagents.do({arg agent; typecheck = typecheck + agentDict[agent][1].mode; }); - - // then merge their score into one string (see below the dict idea) - if((typecheck/seqagents.size) != firsttype, { - " ---> ixi lang: ERROR! You are trying to mix playmodes".postln; - }, { - switch(firsttype) - {0} { - seqagents.do({arg agent, i; - notearr = agentDict[agent][1].notearr; - durarr = durarr ++ agentDict[agent][1].durarr; - sustainarr = sustainarr ++ agentDict[agent][1].sustainarr; - instrarr = instrarr ++ agentDict[agent][1].instrarr; - attackarr = attackarr ++ agentDict[agent][1].attackarr; - panarr = panarr ++ agentDict[agent][1].panarr; - score = score ++ agentDict[agent][1].score; // just for creating the score in the doc - }); + }); + // check if all items are of same type + firsttype = agentDict[seqagents[0]][1].mode; + seqagents.do({arg agent; typecheck = typecheck + agentDict[agent][1].mode; }); - fullscore = (sa++" -> |"++score++"|"); - if(agentDict[sequenceagent].isNil, { - agentDict[sequenceagent] = [ (), ().add(\amp->0.3), nil]; - }, { - if(agentDict[sequenceagent][1].scorestring.contains("{"), {newInstrFlag = true }); // free if { instr (Pmono is always on) - }); // 1st = effectRegistryDict, 2nd = scoreInfoDict, 3rd = placeholder for a routine - quantphase = agentDict[seqagents[0]][1].quantphase; - agentDict[sequenceagent][1].scorestring = fullscore.asCompileString; - agentDict[sequenceagent][1].instrument = "rhythmtrack"; - agentDict[sequenceagent][1].durarr = durarr; - agentDict[sequenceagent][1].notearr = notearr; - agentDict[sequenceagent][1].sustainarr = sustainarr; - agentDict[sequenceagent][1].instrarr = instrarr; - agentDict[sequenceagent][1].attackarr = attackarr; - agentDict[sequenceagent][1].panarr = panarr; - agentDict[sequenceagent][1].score = score; - agentDict[sequenceagent][1].quantphase = quantphase; - doc.string_(doc.string.replace(originalstring, fullscore++"\n")); - this.playScoreMode0(sequenceagent, notearr, durarr, instrarr, sustainarr, attackarr, panarr, quantphase, newInstrFlag, agentDict[sequenceagent][1].morphmode, agentDict[sequenceagent][1].repeats, false); - } - {1} { - - seqagents.do({arg agent, i; - durarr = durarr ++ agentDict[agent][1].durarr; - sustainarr = sustainarr ++ agentDict[agent][1].sustainarr; - notearr = notearr ++ agentDict[agent][1].notearr; - attackarr = attackarr ++ agentDict[agent][1].attackarr; - score = score ++ agentDict[agent][1].score; // just for creating the score in the doc - }); + // then merge their score into one string (see below the dict idea) + if((typecheck/seqagents.size) != firsttype, { + " ---> ixi lang: ERROR! You are trying to mix playmodes".postln; + }, { + switch(firsttype) + {0} { + seqagents.do({arg agent, i; + notearr = agentDict[agent][1].notearr; + durarr = durarr ++ agentDict[agent][1].durarr; + sustainarr = sustainarr ++ agentDict[agent][1].sustainarr; + instrarr = instrarr ++ agentDict[agent][1].instrarr; + attackarr = attackarr ++ agentDict[agent][1].attackarr; + panarr = panarr ++ agentDict[agent][1].panarr; + score = score ++ agentDict[agent][1].score; // just for creating the score in the doc + }); - quantphase = agentDict[seqagents[0]][1].quantphase; - instrument = agentDict[seqagents[0]][1].instrument; - fullscore = (sa++" -> "++ instrument ++"["++score++"]"); - if(agentDict[sequenceagent].isNil, { - agentDict[sequenceagent] = [ (), ().add(\amp->0.3), nil]; - }, { - if(agentDict[sequenceagent][1].scorestring.contains("{"), {newInstrFlag = true }); // free if { instr (Pmono is always on) - }); // 1st = effectRegistryDict, 2nd = scoreInfoDict, 3rd = placeholder for a routine - - agentDict[sequenceagent][1].scorestring = fullscore.asCompileString; - agentDict[sequenceagent][1].instrument = instrument; - agentDict[sequenceagent][1].durarr = durarr; - agentDict[sequenceagent][1].sustainarr = sustainarr; - agentDict[sequenceagent][1].notearr = notearr; - agentDict[sequenceagent][1].attackarr = attackarr; - agentDict[sequenceagent][1].panarr = panarr; - agentDict[sequenceagent][1].score = score; - agentDict[sequenceagent][1].quantphase = quantphase; - - doc.string_(doc.string.replace(originalstring, fullscore++"\n")); - this.playScoreMode1(sequenceagent, notearr, durarr, sustainarr, attackarr, panarr, instrument, quantphase, newInstrFlag, agentDict[sequenceagent][1].repeats, false); - } - {2} { - seqagents.do({arg agent, i; - durarr = durarr ++ agentDict[agent][1].durarr; - amparr = notearr ++ agentDict[agent][1].amparr; - attackarr = attackarr ++ agentDict[agent][1].attackarr; - score = score ++ agentDict[agent][1].score; // just for creating the score in the doc - }); - quantphase = agentDict[seqagents[0]][1].quantphase; - instrument = agentDict[seqagents[0]][1].instrument; - fullscore = (sa++" -> "++ instrument ++"{"++score++"}"); - if(agentDict[sequenceagent].isNil, { - agentDict[sequenceagent] = [ (), ().add(\amp->0.3), nil]; - }, { - if(agentDict[sequenceagent][1].scorestring.contains("{"), {newInstrFlag = true }); // free if { instr (Pmono is always on) - }); // 1st = effectRegistryDict, 2nd = scoreInfoDict, 3rd = placeholder for a routine - agentDict[sequenceagent][1].scorestring = fullscore.asCompileString; - agentDict[sequenceagent][1].instrument = instrument; - agentDict[sequenceagent][1].durarr = durarr; - agentDict[sequenceagent][1].amparr = amparr; - agentDict[sequenceagent][1].panarr = panarr; - agentDict[sequenceagent][1].score = score; - agentDict[sequenceagent][1].quantphase = quantphase; - doc.string_(doc.string.replace(originalstring, fullscore++"\n")); - this.playScoreMode2(sequenceagent, amparr, durarr, panarr, instrument, quantphase, newInstrFlag, agentDict[sequenceagent][1].repeats, false); - }; - }); - } + fullscore = (sa++" -> |"++score++"|"); + if(agentDict[sequenceagent].isNil, { + agentDict[sequenceagent] = [ (), ().add(\amp->0.3), nil]; + }, { + if(agentDict[sequenceagent][1].scorestring.contains("{"), {newInstrFlag = true }); // free if { instr (Pmono is always on) + }); // 1st = effectRegistryDict, 2nd = scoreInfoDict, 3rd = placeholder for a routine + quantphase = agentDict[seqagents[0]][1].quantphase; + agentDict[sequenceagent][1].scorestring = fullscore.asCompileString; + agentDict[sequenceagent][1].instrument = "rhythmtrack"; + agentDict[sequenceagent][1].durarr = durarr; + agentDict[sequenceagent][1].notearr = notearr; + agentDict[sequenceagent][1].sustainarr = sustainarr; + agentDict[sequenceagent][1].instrarr = instrarr; + agentDict[sequenceagent][1].attackarr = attackarr; + agentDict[sequenceagent][1].panarr = panarr; + agentDict[sequenceagent][1].score = score; + agentDict[sequenceagent][1].quantphase = quantphase; + doc.string_(doc.string.replace(originalstring, fullscore++"\n")); + this.playScoreMode0(sequenceagent, notearr, durarr, instrarr, sustainarr, attackarr, panarr, quantphase, newInstrFlag, agentDict[sequenceagent][1].morphmode, agentDict[sequenceagent][1].repeats, false); + } + {1} { - // methods (called verbs in ixi lang) dealt with in the parsMethod below (these change string in doc) - {"doze"} { - this.parseMethod(string); - } - {"perk"}{ - this.parseMethod(string); - } - {"nap"}{ - this.parseMethod(string); - } - {"shake"}{ - this.parseMethod(string); - } - {"swap"}{ - this.parseMethod(string); - } - {"replace"}{ - this.parseMethod(string); - } - {"insert"}{ - this.parseMethod(string); - } - {"remove"}{ - this.parseMethod(string); - } - {">shift"}{ - this.parseMethod(string); - } - {" You set the MIDI out to : ".post; MIDIClient.destinations[destination].postln; - MIDIClockOut(destination).play; // XXX experimental - } - {"matrix"}{ - var spaces, size=8, direction=\x; - spaces = string.findAll(" "); - if(spaces.size > 0, { size = string[spaces[0]..spaces[1]].asInteger; }); - if(spaces.size > 1, { - direction = string[spaces[1]+1..string.size-1].tr($ , \).asSymbol; - }); - matrixArray = matrixArray.add( XiiLangMatrix.new(size, direction, instrDict, doccolor, oncolor) ); - } - {"coder"}{ - var xiilang, tempstring, scorestring, coderarraysum, quantspaces, quant; - - xiilang = XiiLang.new(initargs[0], initargs[1], initargs[2], true, initargs[4], numChannels: numChan); - xiilang.doc.name_("ixi lang coder"); - xiilang.doc.keyDownAction_({| thisdoc, char, mod, unicode, keycode | - var linenr, string; - if((mod & 524288 == 524288) && ((keycode==124)||(keycode==123)||(keycode==125)||(keycode==126)), { - linenr = thisdoc.string[..thisdoc.selectionStart-1].split($\n).size; - thisdoc.selectLine(linenr); - string = thisdoc.selectedString; - if(keycode==123, { // not 124, 125, - xiilang.freeAgent(string); - }, { - xiilang.opInterpreter(string); - }); + seqagents.do({arg agent, i; + durarr = durarr ++ agentDict[agent][1].durarr; + sustainarr = sustainarr ++ agentDict[agent][1].sustainarr; + notearr = notearr ++ agentDict[agent][1].notearr; + attackarr = attackarr ++ agentDict[agent][1].attackarr; + score = score ++ agentDict[agent][1].score; // just for creating the score in the doc }); - // here adding what the coder is about - if(char.isAlpha, { - Synth(instrDict[char.asSymbol], [\freq, 60.midicps]); // original - }); - }); - } - {"twitter"}{ - var xiilang, tweetDict, getTweets, currentLine, newLines, routine; - xiilang = XiiLang.new(initargs[0], initargs[1], initargs[2], true, initargs[4]); - xiilang.doc.name_("ixi lang twitter client"); - xiilang.doc.string_("// this window evaluates your #ixilang twitter messages"); - tweetDict = (); - currentLine = 1; // one empty line at the top - newLines = 0; - // TODO: unixCmd to start moai main.lua - - getTweets = { - var file, string, allLineBreaks, newdocstring; - file = File("/Users/thor/quaziir/mobilecoding/moai-sdk/thor/ixiTwitter/ixitweets","r"); - string = file.readAllString; - file.close; - string = string.replace("#ixilang", ""); - //string = string.replace(" ",""); - allLineBreaks = string.findAll("\n"); - newdocstring = xiilang.doc.string; - newLines = 0; - allLineBreaks.do({arg thisLineBreak, i; - var prevLineBreak, line, id, msg; - prevLineBreak = allLineBreaks[i-1]; - if(prevLineBreak.isNil, { prevLineBreak = 0 }); - line = string[prevLineBreak..thisLineBreak]; - id = line[1..line.findAll(",")[0]-1]; - if(tweetDict[id.asSymbol].isNil, { - msg = line[line.findAll(",")[0]+3..line.findAll(",")[1]-1]; - tweetDict[id.asSymbol] = msg; - newdocstring = newdocstring ++ "\n" ++ msg; - newLines = newLines + 1; - }); + quantphase = agentDict[seqagents[0]][1].quantphase; + instrument = agentDict[seqagents[0]][1].instrument; + fullscore = (sa++" -> "++ instrument ++"["++score++"]"); + if(agentDict[sequenceagent].isNil, { + agentDict[sequenceagent] = [ (), ().add(\amp->0.3), nil]; + }, { + if(agentDict[sequenceagent][1].scorestring.contains("{"), {newInstrFlag = true }); // free if { instr (Pmono is always on) + }); // 1st = effectRegistryDict, 2nd = scoreInfoDict, 3rd = placeholder for a routine + + agentDict[sequenceagent][1].scorestring = fullscore.asCompileString; + agentDict[sequenceagent][1].instrument = instrument; + agentDict[sequenceagent][1].durarr = durarr; + agentDict[sequenceagent][1].sustainarr = sustainarr; + agentDict[sequenceagent][1].notearr = notearr; + agentDict[sequenceagent][1].attackarr = attackarr; + agentDict[sequenceagent][1].panarr = panarr; + agentDict[sequenceagent][1].score = score; + agentDict[sequenceagent][1].quantphase = quantphase; + + doc.string_(doc.string.replace(originalstring, fullscore++"\n")); + this.playScoreMode1(sequenceagent, notearr, durarr, sustainarr, attackarr, panarr, instrument, quantphase, newInstrFlag, agentDict[sequenceagent][1].repeats, false); + } + {2} { + seqagents.do({arg agent, i; + durarr = durarr ++ agentDict[agent][1].durarr; + amparr = notearr ++ agentDict[agent][1].amparr; + attackarr = attackarr ++ agentDict[agent][1].attackarr; + score = score ++ agentDict[agent][1].score; // just for creating the score in the doc + }); + quantphase = agentDict[seqagents[0]][1].quantphase; + instrument = agentDict[seqagents[0]][1].instrument; + fullscore = (sa++" -> "++ instrument ++"{"++score++"}"); + if(agentDict[sequenceagent].isNil, { + agentDict[sequenceagent] = [ (), ().add(\amp->0.3), nil]; + }, { + if(agentDict[sequenceagent][1].scorestring.contains("{"), {newInstrFlag = true }); // free if { instr (Pmono is always on) + }); // 1st = effectRegistryDict, 2nd = scoreInfoDict, 3rd = placeholder for a routine + agentDict[sequenceagent][1].scorestring = fullscore.asCompileString; + agentDict[sequenceagent][1].instrument = instrument; + agentDict[sequenceagent][1].durarr = durarr; + agentDict[sequenceagent][1].amparr = amparr; + agentDict[sequenceagent][1].panarr = panarr; + agentDict[sequenceagent][1].score = score; + agentDict[sequenceagent][1].quantphase = quantphase; + doc.string_(doc.string.replace(originalstring, fullscore++"\n")); + this.playScoreMode2(sequenceagent, amparr, durarr, panarr, instrument, quantphase, newInstrFlag, agentDict[sequenceagent][1].repeats, false); + }; + }); + } + + // methods (called verbs in ixi lang) dealt with in the parsMethod below (these change string in doc) + {"doze"} { + this.parseMethod(string); + } + {"perk"}{ + this.parseMethod(string); + } + {"nap"}{ + this.parseMethod(string); + } + {"shake"}{ + this.parseMethod(string); + } + {"swap"}{ + this.parseMethod(string); + } + {"replace"}{ + this.parseMethod(string); + } + {"insert"}{ + this.parseMethod(string); + } + {"remove"}{ + this.parseMethod(string); + } + {">shift"}{ + this.parseMethod(string); + } + {" You set the MIDI out to : ".post; MIDIClient.destinations[destination].postln; + MIDIClockOut(destination).play; // XXX experimental + } + {"matrix"}{ + var spaces, size=8, direction=\x; + spaces = string.findAll(" "); + if(spaces.size > 0, { size = string[spaces[0]..spaces[1]].asInteger; }); + if(spaces.size > 1, { + direction = string[spaces[1]+1..string.size-1].tr($ , \).asSymbol; + }); + matrixArray = matrixArray.add( XiiLangMatrix.new(size, direction, instrDict, doccolor, oncolor) ); + } + {"coder"}{ + var xiilang, tempstring, scorestring, coderarraysum, quantspaces, quant; + + xiilang = XiiLang(initargs[0], initargs[1], initargs[2], true, initargs[4], numChannels: numChan); + xiilang.doc.name_("ixi lang coder"); + xiilang.doc.keyDownAction_({| thisdoc, char, mod, unicode, keycode | + var linenr, string; + //TODO if((mod & 524288 == 524288) && ((keycode==124)||(keycode==123)||(keycode==125)||(keycode==126)), { + // linenr = thisdoc.string[..thisdoc.selectionStart-1].split($\n).size; + // thisdoc.selectLine(linenr); + // string = thisdoc.selectedString; + // if(keycode==123, { // not 124, 125, + // xiilang.freeAgent(string); + // }, { + // xiilang.opInterpreter(string); + // }); + // }); + // here adding what the coder is about + if(char.isAlpha, { + Synth(instrDict[char.asSymbol], [\freq, 60.midicps]); // original + }); + }); + } + {"twitter"}{ + var xiilang, tweetDict, getTweets, currentLine, newLines, routine; + xiilang = XiiLang(initargs[0], initargs[1], initargs[2], true, initargs[4]); + xiilang.doc.name_("ixi lang twitter client"); + xiilang.doc.string_("// this window evaluates your #ixilang twitter messages"); + tweetDict = (); + currentLine = 1; // one empty line at the top + newLines = 0; + + // TODO: unixCmd to start moai main.lua + + getTweets = { + var file, string, allLineBreaks, newdocstring; + file = File("/Users/thor/quaziir/mobilecoding/moai-sdk/thor/ixiTwitter/ixitweets","r"); + string = file.readAllString; + file.close; + string = string.replace("#ixilang", ""); + //string = string.replace(" ",""); + allLineBreaks = string.findAll("\n"); + newdocstring = xiilang.doc.string; + newLines = 0; + allLineBreaks.do({arg thisLineBreak, i; + var prevLineBreak, line, id, msg; + prevLineBreak = allLineBreaks[i-1]; + if(prevLineBreak.isNil, { prevLineBreak = 0 }); + line = string[prevLineBreak..thisLineBreak]; + id = line[1..line.findAll(",")[0]-1]; + if(tweetDict[id.asSymbol].isNil, { + msg = line[line.findAll(",")[0]+3..line.findAll(",")[1]-1]; + tweetDict[id.asSymbol] = msg; + newdocstring = newdocstring ++ "\n" ++ msg; + newLines = newLines + 1; + }); + }); + xiilang.doc.string = newdocstring; + { + newLines.do({arg i; + var xiistring; + "running newlines".postln; + currentLine = currentLine + 1; + xiilang.doc.selectLine(currentLine); + xiistring = xiilang.doc.selectedString; + try{this.opInterpreter(xiistring)}; + + 0.5.wait; + }); + }.fork(AppClock); + //Post << tweetDict; + }; - routine = {{ - getTweets.value; - 5.wait; - }.loop}.fork(AppClock); + routine = {{ + getTweets.value; + 5.wait; + }.loop}.fork(AppClock); - } - {"autocode"}{ - var agent, mode, instrument, score, line, charloc, cursorPos, density, lines, spaces, nextline; - - string = string.replace(" ", " "); - string = string.replace(" ", " "); - string = string.replace(" ", " "); - string = string++" "; // add a space in order to find end of agent (if no argument) -// [\firstspace, string.findAll(" ")[0]].postln; -// [\endspace, string.findAll(" ")[1]].postln; -// charloc = doc.selectedRangeLocation; - spaces = doc.string.findAll(" "); + } + {"autocode"}{ + var agent, mode, instrument, score, line, charloc, cursorPos, density, lines, spaces, nextline, found, i; + + string = string.replace(" ", " "); + string = string.replace(" ", " "); + string = string.replace(" ", " "); + string = string++" "; // add a space in order to find end of agent (if no argument) + // [\firstspace, string.findAll(" ")[0]].postln; + // [\endspace, string.findAll(" ")[1]].postln; + // charloc = doc.selectedRangeLocation; + spaces = doc.string.findAll(" "); // nextline = if(spaces.indexOfGreaterThan(charloc).isNil, { -// charloc; -// },{ -// spaces[spaces.indexOfGreaterThan(charloc)]; -// }); -// charloc = nextline; -// + // charloc; + // },{ + // spaces[spaces.indexOfGreaterThan(charloc)]; + // }); + // charloc = nextline; + // // charloc = spaces[spaces.indexOfGreaterThan(charloc)-1]; - charloc = doc.selectionStart; + charloc = doc.selectionStart; - //charloc = string.findAll(" ")[1]+1; - {doc.insertTextRange("\n", charloc, 0)}.defer; - lines = ""; - string.collect({arg char; if(char.isDecDigit, { lines = lines++char }) }); - lines = lines.asInteger; - { - lines.do({ + //charloc = string.findAll(" ")[1]+1; + {doc.setString("\n", charloc, 0)}.defer; + lines = ""; + string.collect({arg char; if(char.isDecDigit, { lines = lines++char }) }); + lines = lines.asInteger; + { + lines.do({ + if(( ixiInstr.returnPercussiveInstr.size > 0), { mode = [0,1,2].wchoose([0.5, 0.35, 0.15]); - agent = "abcdefghijklmnopqrstuvxyzaeyiuxz".scramble[0..(2+(4.rand))]; - density = rrand(0.15, 0.45); - switch(mode) - {0}{ - score = ""; - [16, 20, 24].choose.do({arg char; - score = score ++ if(density.coin, { - "abcdefghijklmnopqrstuvxABCDEFGHIJKLMNOPQRSTUVXYZ".scramble.choose; - }, {" "}); - }); - score = "|"++score++"|"; - line = agent+"->"+score+"\n"; - } - {1}{ - instrument = (ixiInstr.returnMelodicInstr++ - ixiInstr.returnMelodicInstr++ixiInstr.returnMelodicInstr++ - ixiInstr.returnMelodicInstr++ixiInstr.returnPercussiveInstr).choose; - score = ""; - [16, 20, 24].choose.do({ - score = score ++ if(density.coin, {10.rand}, {" "}); - }); - score = instrument++"["++score++"]"; - line = agent+"->"+score+"\n"; - } - {2}{ - instrument = ixiInstr.returnPercussiveInstr.choose; - score = ""; - [16, 20, 24].choose.do({ - score = score ++ if(density.coin, {10.rand}, {" "}); - }); - score = instrument++"{"++score++"}"; - line = agent+"->"+score+"\n"; - }; - line.do({arg char, i; - charloc = charloc + 1; - {doc.insertTextRange(char.asString, charloc, 0)}.defer; - [0.1, 0.05, 0.5].wchoose([0.5, 0.4, 0.1]).wait; + }, { + mode = [0,1].wchoose([0.5, 0.35]); + }); + + agent = "abcdefghijklmnopqrstuvxyzaeyiuxz".scramble[0..(2+(4.rand))]; + density = rrand(0.15, 0.45); + switch(mode) + {0}{ + score = ""; + [16, 20, 24].choose.do({arg char; + score = score ++ if(density.coin, { + "abcdefghijklmnopqrstuvxABCDEFGHIJKLMNOPQRSTUVXYZ".scramble.choose; + }, {" "}); + }); + score = "|"++score++"|"; + line = agent+"->"+score+"\n"; + } + {1}{ + instrument = (ixiInstr.returnMelodicInstr++ + ixiInstr.returnMelodicInstr++ixiInstr.returnMelodicInstr++ + ixiInstr.returnMelodicInstr++ixiInstr.returnPercussiveInstr).choose; + score = ""; + [16, 20, 24].choose.do({ + score = score ++ if(density.coin, {10.rand}, {" "}); + }); + score = instrument++"["++score++"]"; + line = agent+"->"+score+"\n"; + } + {2}{ + found = false; + i = 0; + {( i < 3) && found.not }.while({ + instrument = ixiInstr.returnPercussiveInstr.choose; + found = instrument.notNil; + if(found, { + found = (instrument.asString != "nil"); + }); + i = i+1; + }); + score = ""; + [16, 20, 24].choose.do({ + score = score ++ if(density.coin, {10.rand}, {" "}); }); - 1.wait; - this.opInterpreter(line); + score = instrument++"{"++score++"}"; + if(found, { + line = agent+"->"+score+"\n"; + }); + }; + line.do({arg char, i; + charloc = charloc + 1; + {doc.setString(char.asString, charloc, 0)}.defer; + [0.1, 0.05, 0.5].wchoose([0.5, 0.4, 0.1]).wait; }); - }.fork(TempoClock.new); - } - {"new"}{ - XiiLangGUI.new(projectname, numChannels: numChan); - } - {"gui"}{ - XiiLangGUI.new(projectname, numChannels: numChan); - } - {"savescore"}{ - var sessionstart, sessionend, session; - var offsettime; - - string = string.replace(" ", " "); - string = string.replace(" ", " "); - string = string.replace(" ", " "); - string = string++" "; // add a space in order to find end of agent (if no argument) - sessionstart = string.findAll(" ")[0]; - sessionend = string.findAll(" ")[1]; - session = string[sessionstart+1..sessionend-1]; - offsettime = scoreArray[0][0]; - scoreArray = scoreArray.collect({arg event; [event[0]-offsettime, event[1]]}); - [randomseed, scoreArray.copy].writeArchive(Platform.userAppSupportDir ++"/ixilang/"++projectname++"/scores/"++session++".scr"); - } - {"playscore"}{ - var sessionstart, sessionend, session, variation, varstart, varend, score, offsettime; - variation = nil; - string = string.replace(" ", " "); - string = string.replace(" ", " "); - string = string.replace(" ", " "); - string = string++" "; // add a space in order to find end of agent (if no argument) - sessionstart = string.findAll(" ")[0]; - sessionend = string.findAll(" ")[1]; - session = string[sessionstart+1..sessionend-1]; - if(string.findAll(" ")[2].isNil.not, { - varstart = string.findAll(" ")[1]; - varend = string.findAll(" ")[2]; - variation = string[varstart+1..varend-1]; + 1.wait; + {this.opInterpreter(line)}.defer; }); - //doc.onClose; // call this to end all agents and groups in this particular doc if it has been running agents - #randomseed, score = Object.readArchive(Platform.userAppSupportDir ++"/ixilang/"++projectname++"/scores/"++session++".scr"); - if(variation.isNil.not, { randomseed = variation.ascii.pyramid.pyramid.sum; "playing variation: %".postf(variation) }); // overwrite the orig seed to get a variation - XiiLang.new( projectname, key, true, false, language, nil, [randomseed, score]); - } - {"newrec"}{ - " ---> ixi lang: clearing score array".postln; - scoreArray = []; - scoreArray = scoreArray.add([Main.elapsedTime, string]); // recording the performance - } - ; + }.fork(TempoClock.new); + } + {"new"}{ + XiiLangGUI.new(projectname, numChannels: numChan); + } + {"gui"}{ + XiiLangGUI.new(projectname, numChannels: numChan); + } + {"savescore"}{ + var sessionstart, sessionend, session; + var offsettime; + + string = string.replace(" ", " "); + string = string.replace(" ", " "); + string = string.replace(" ", " "); + string = string++" "; // add a space in order to find end of agent (if no argument) + sessionstart = string.findAll(" ")[0]; + sessionend = string.findAll(" ")[1]; + session = string[sessionstart+1..sessionend-1]; + offsettime = scoreArray[0][0]; + scoreArray = scoreArray.collect({arg event; [event[0]-offsettime, event[1]]}); + [randomseed, scoreArray.copy].writeArchive(this.projectDirname++"/scores/"++session++".scr"); + } + {"playscore"}{ + var sessionstart, sessionend, session, variation, varstart, varend, score, offsettime; + variation = nil; + string = string.replace(" ", " "); + string = string.replace(" ", " "); + string = string.replace(" ", " "); + string = string++" "; // add a space in order to find end of agent (if no argument) + sessionstart = string.findAll(" ")[0]; + sessionend = string.findAll(" ")[1]; + session = string[sessionstart+1..sessionend-1]; + if(string.findAll(" ")[2].isNil.not, { + varstart = string.findAll(" ")[1]; + varend = string.findAll(" ")[2]; + variation = string[varstart+1..varend-1]; + }); + //doc.onClose; // call this to end all agents and groups in this particular doc if it has been running agents + #randomseed, score = Object.readArchive(this.projectDirname++"/scores/"++session++".scr"); + if(variation.isNil.not, { randomseed = variation.ascii.pyramid.pyramid.sum; "playing variation: %".postf(variation) }); // overwrite the orig seed to get a variation + XiiLang.new( projectname, key, true, false, language, nil, [randomseed, score]); + } + {"newrec"}{ + " ---> ixi lang: clearing score array".postln; + scoreArray = []; + scoreArray = scoreArray.add([Main.elapsedTime, string]); // recording the performance } + ; + } playScore{ arg score; var offsettime; @@ -1305,7 +1393,7 @@ oxo -> |Sdfsdf| \n\n\n") }); doc.string = ""; win.onClose; { - // thisThread.randSeed = randomseed; + // thisThread.randSeed = randomseed; score.do({ arg event; (event[0]-offsettime).wait; //(1).wait; @@ -1313,8 +1401,8 @@ oxo -> |Sdfsdf| \n\n\n") }); event[1].contains("snapshot").not && event[1].contains("suicide").not && event[1].contains("savescore").not, { - doc.string_(doc.string++"\n"++event[1]); - this.opInterpreter(event[1]); + doc.string_(doc.string++"\n"++event[1]); + this.opInterpreter(event[1]); }); offsettime = event[0]; }); @@ -1330,7 +1418,7 @@ oxo -> |Sdfsdf| \n\n\n") }); string = string.tr($ , \); splitloc = string.find("->"); pureagentname = string[0..splitloc-1]; // get the name of the agent - agent = (docnum.asString++pureagentname).asSymbol; + agent = (this.agentPrefix++pureagentname).asSymbol; [\pureagentnameX, pureagentname].postln; #stringstart, stringend = this.findStringStartEnd(doc, pureagentname); @@ -1338,17 +1426,17 @@ oxo -> |Sdfsdf| \n\n\n") }); [pureagentname, stringstart, stringend].postln; recursionfunc = {arg subagent; - if(groups[subagent].isNil.not, { - // "---- The subagent is a group. Name : ".post; subagent.postln; - groups[subagent].do({arg agent; - // "GROUP AGENT recursing : ".post; agent.postln; - recursionfunc.value((docnum.asString++agent).asSymbol); // recursion - }); - }, { - // "FREEING AGENT : ".post; subagent.postln; - proxyspace[subagent.asSymbol].clear; - agentDict[subagent.asSymbol][1].playstate = false; + if(groups[subagent].isNil.not, { + // "---- The subagent is a group. Name : ".post; subagent.postln; + groups[subagent].do({arg agent; + // "GROUP AGENT recursing : ".post; agent.postln; + recursionfunc.value((this.agentPrefix++agent).asSymbol); // recursion }); + }, { + // "FREEING AGENT : ".post; subagent.postln; + proxyspace[subagent.asSymbol].clear; + agentDict[subagent.asSymbol][1].playstate = false; + }); }; if(metaAgentDict[agent].isNil.not, { @@ -1358,7 +1446,7 @@ oxo -> |Sdfsdf| \n\n\n") }); if(groups[subagent].isNil.not, { recursionfunc.value(subagent); }, { - // "FREEING AGENT __ : ".post; subagent.postln; + // "FREEING AGENT __ : ".post; subagent.postln; proxyspace[subagent].clear; agentDict[subagent][1].playstate = false; }); @@ -1368,9 +1456,9 @@ oxo -> |Sdfsdf| \n\n\n") }); proxyspace[agent].clear; agentDict[agent] = nil; metaAgentDict[agent] = nil; - //\deb.postln; + //\deb.postln; {doc.setStringColor(deadcolor, stringstart, stringend-stringstart)}.defer; - // {doc.setStringColor(deadcolor, doc.selectionStart, doc.selectionSize)}.defer(0.1); // killed code is red + // {doc.setStringColor(deadcolor, doc.selectionStart, doc.selectionSize)}.defer(0.1); // killed code is red } interpret { arg cmd; @@ -1414,12 +1502,12 @@ oxo -> |Sdfsdf| \n\n\n") }); Pdef(agent).stop; // new proxyspace[agent].stop; // proxyspace[agent].objects[0].array[0].mute; - allreturns = doc.string.findAll("\n") ++ doc.string.findAll(""++13.asAscii); + allreturns = doc.string.findAll("\n") ++ doc.string.findAll(""++13.asAscii); // the following checks if it's exactly the same agent name (and not confusing joe and joel) #stringstart, stringend = this.findStringStartEnd(doc, pureagentname); - (stringend.notNil && stringstart.notNil).if({ - doc.setStringColor(offcolor, stringstart, stringend-stringstart); - }); + (stringend.notNil && stringstart.notNil).if({ + doc.setStringColor(offcolor, stringstart, stringend-stringstart); + }); }); }); // then run the agents in the snapshot and replace strings in doc @@ -1440,15 +1528,15 @@ oxo -> |Sdfsdf| \n\n\n") }); // -- 2) Swap the string in the doc // either with the simple swap - (stringend.notNil && stringstart.notNil).if({ - doc.string_( dictscore, stringstart, stringend-stringstart); // this one keeps text colour - doc.setStringColor(oncolor, stringstart, stringend-stringstart); - }); + (stringend.notNil && stringstart.notNil).if({ + doc.string_( dictscore, stringstart, stringend-stringstart); // this one keeps text colour + doc.setStringColor(oncolor, stringstart, stringend-stringstart); + }); // -- 3) Run the code (parse it) - IF playstate is true (in case it's been dozed) try{ // try, because if loading from "load", then there will be no proxyspace yet if(proxyspace[keyagentname].objects[0].array[0].muteCount == 1, { - proxyspace[keyagentname].objects[0].array[0].unmute; - }); + proxyspace[keyagentname].objects[0].array[0].unmute; + }); }; mode = block{|break| @@ -1458,10 +1546,10 @@ oxo -> |Sdfsdf| \n\n\n") }); }; switch(mode) - {0} { proxyspace[keyagentname].play; this.parseScoreMode0(dictscore, false, true) } - {1} { proxyspace[keyagentname].play; this.parseScoreMode1(dictscore, false, true) } - {2} { proxyspace[keyagentname].play; this.parseScoreMode2(dictscore, false, true) } - {3} { proxyspace[keyagentname].play; this.opInterpreter( dictscore, false, true ) }; + {0} { proxyspace[keyagentname].play; this.parseScoreMode0(dictscore, false, true) } + {1} { proxyspace[keyagentname].play; this.parseScoreMode1(dictscore, false, true) } + {2} { proxyspace[keyagentname].play; this.parseScoreMode2(dictscore, false, true) } + {3} { proxyspace[keyagentname].play; this.opInterpreter( dictscore, false, true ) }; //proxyspace[keyagentname].play; scoreArray = scoreArray.add([Main.elapsedTime, dictscore]); @@ -1478,9 +1566,9 @@ oxo -> |Sdfsdf| \n\n\n") }); Pdef(keyagentname).stop; // new proxyspace[keyagentname].stop; #stringstart, stringend = this.findStringStartEnd(doc, pureagentname); - (stringend.notNil && stringstart.notNil).if({ - doc.setStringColor(offcolor, stringstart, stringend-stringstart); - }) + (stringend.notNil && stringstart.notNil).if({ + doc.setStringColor(offcolor, stringstart, stringend-stringstart); + }) }); }); }); @@ -1577,7 +1665,7 @@ oxo -> |Sdfsdf| \n\n\n") }); }); attackstring.do({arg att; attackarr = attackarr.add(att.asString.asInteger/9); // values range from 0 to 1.0 - }); + }); argDict.add(\attackarr -> attackarr); // -- panning -- @@ -1595,7 +1683,7 @@ oxo -> |Sdfsdf| \n\n\n") }); }, { panarr = panarr.add(pan.asString.asInteger.linlin(1, 9, 0, 2 - (2/numChan))); // 1 to 9 are mapped to panning of 0 - (2 - (2/numChan)) (PanAz) }); - }); + }); argDict.add(\panarr -> panarr); ^argDict; } @@ -1637,13 +1725,14 @@ oxo -> |Sdfsdf| \n\n\n") }); notearr = [60+transposition]; score = score[0..endchar-1]; // get rid of the function marker - agent = (docnum.asString++agent).asSymbol; + agent = (this.agentPrefix++agent).asSymbol; // -- create a new agent if needed if(agentDict[agent].isNil, { agentDict[agent] = [(), ().add(\amp->0.5), []]; }, { - if(agentDict[agent][1].scorestring.contains("{"), { newInstrFlag = true }); // trick to free if the agent was { instr (Pmono is always on) + if(agentDict[agent][1].scorestring.contains("{"), { newInstrFlag = true }); + // trick to free if the agent was { instr (Pmono is always on) }); // 1st = effectRegistryDict, 2nd = scoreInfoDict, 3rd = placeholder for a routine // ------------- the instrument ------------------- @@ -1694,12 +1783,12 @@ oxo -> |Sdfsdf| \n\n\n") }); agentDict[agent][1].instrument = "rhythmtrack"; {doc.setStringColor(oncolor, stringstart, stringend-stringstart)}.defer; -// {doc.setStringColor(oncolor, doc.selectionStart, doc.selectionSize)}.defer(0.1); // if code is green (sleeping) + // {doc.setStringColor(oncolor, doc.selectionStart, doc.selectionSize)}.defer(0.1); // if code is green (sleeping) "------ ixi lang: Created Percussive Agent : ".post; pureagent.postln; agentDict[agent].postln; ^this.playScoreMode0(agent, notearr, durarr, instrarr, sustainarr, attackarr, panarr, quantphase, newInstrFlag, morphmode, repeats, return, snapshot); } - // MELODIC MODE + // MELODIC MODE, rjk parseScoreMode1 {arg string, return, snapshot=false; var agent, pureagent, score, scorestartloc, splitloc, endchar, agentstring, instrument, instrstring, timestretch=1, transposition=0; var prestring, silenceicon, silences, postfixargs, newInstrFlag = false; @@ -1711,19 +1800,20 @@ oxo -> |Sdfsdf| \n\n\n") }); var postfixArgDict, stringstart, stringend; channelicon = 0; - scorestartloc = string.find("["); prestring = string[0..scorestartloc-1].tr($ , \); // get rid of spaces until score splitloc = prestring.find("->"); if(splitloc.isNil, { // no assignment operator - agent = prestring[0..prestring.size]; // get the name of the agent + // agent = prestring[0..prestring.size]; // get the name of the agent RJK bug! + agent = prestring; // get the name of the agent instrument = agent; }, { agent = prestring[0..splitloc-1]; // get the name of the agent - instrument = prestring[splitloc+2..prestring.size]; + instrument = prestring[splitloc+2..prestring.size - 1]; }); pureagent = agent; - agent = (docnum.asString++agent).asSymbol; + agent = (this.agentPrefix++pureagent).asSymbol; //rjk + #stringstart, stringend = this.findStringStartEnd(doc, pureagent); score = string[scorestartloc+1..string.size-1]; @@ -1801,6 +1891,7 @@ oxo -> |Sdfsdf| \n\n\n") }); durarr = durarr/4; durarr = durarr*timestretch; // duration is stretched by timestretch var + agentDict[agent][1].mode = 1; agentDict[agent][1].quantphase = quantphase; agentDict[agent][1].durarr = durarr; @@ -1817,6 +1908,7 @@ oxo -> |Sdfsdf| \n\n\n") }); {doc.setStringColor(oncolor, stringstart, stringend-stringstart)}.defer; //{doc.setStringColor(oncolor, doc.selectionStart, doc.selectionSize)}.defer(0.1); // if code is green (sleeping) "------ ixi lang: Created Melodic Agent : ".post; pureagent.postln; agentDict[agent].postln; + ^this.playScoreMode1(agent, notearr, durarr, sustainarr, attackarr, panarr, instrument, quantphase, newInstrFlag, midichannel, repeats, return, snapshot); // this has to be below the playscore method } @@ -1837,11 +1929,11 @@ oxo -> |Sdfsdf| \n\n\n") }); instrument = agent; }, { agent = prestring[0..splitloc-1]; // get the name of the agent - instrument = prestring[splitloc+2..prestring.size]; + instrument = prestring[splitloc+2..prestring.size-1]; }); pureagent = agent; #stringstart, stringend = this.findStringStartEnd(doc, pureagent); - agent = (docnum.asString++agent).asSymbol; + agent = (this.agentPrefix++agent).asSymbol; score = string[scorestartloc+1..string.size-1]; endchar = score.find("}"); // the index (int) of the end op in the string @@ -1863,7 +1955,7 @@ oxo -> |Sdfsdf| \n\n\n") }); if(agentDict[agent][1].instrument != instrument, { newInstrFlag = true; }, { - newInstrFlag = false; + newInstrFlag = false; }); }); // 1st = effectRegistryDict, 2nd = scoreInfoDict, 3rd = placeholder for a routine @@ -1915,7 +2007,7 @@ oxo -> |Sdfsdf| \n\n\n") }); {doc.setStringColor(oncolor, stringstart, stringend-stringstart)}.defer; -// {doc.setStringColor(oncolor, doc.selectionStart, doc.selectionSize)}.defer(0.1); // if code is green (sleeping) + // {doc.setStringColor(oncolor, doc.selectionStart, doc.selectionSize)}.defer(0.1); // if code is green (sleeping) "------ ixi lang: Created Concrete Agent : ".post; pureagent.postln; agentDict[agent].postln; ^this.playScoreMode2(agent, pitch, amparr, durarr, panarr, instrument, quantphase, newInstrFlag, repeats, return, snapshot); // this has to be below the playscore method @@ -1929,11 +2021,11 @@ oxo -> |Sdfsdf| \n\n\n") }); splitloc = string.find("->"); varname = string[0..splitloc-1]; // get the name of the var -// if(mode == \c, { -// chordstartloc = string.find("("); -// },{ -// chordstartloc = string.find("�"); -// }); + // if(mode == \c, { + // chordstartloc = string.find("("); + // },{ + // chordstartloc = string.find("�"); + // }); if(varname.interpret.isInteger, { // PERCUSSIVE MODE ------------ NOT WORKING - Pseq(\instrument does not expand) chordstring = string[splitloc+3..string.size-3]; chord = []; @@ -1968,7 +2060,7 @@ oxo -> |Sdfsdf| \n\n\n") }); splitloc = string.find("->"); agentname = string[0..splitloc-1]; // get the name of the var agentname = agentname.tr($ , \); - agent = (docnum.asString++agentname).asSymbol; + agent = (this.agentPrefix++agentname).asSymbol; patternstring = string[splitloc+3..string.size-2].tr($ , $-); agentarray = []; tempstring = ""; @@ -1995,17 +2087,17 @@ oxo -> |Sdfsdf| \n\n\n") }); groupitems = []; (agentarray.size/2).do({arg i; - var subagent = (docnum.asString++agentarray[i*2].asString).asSymbol; // not the new meta agent but its contents + var subagent = (this.agentPrefix++agentarray[i*2].asString).asSymbol; // not the new meta agent but its contents // activeAgentArray = activeAgentArray.add(agentname); activeAgentArray = activeAgentArray.add(subagent); - // what kind of agent is it? a) agent (mode 0-2), b) meta agent (mode 3), c) a group (mode 4) + // what kind of agent is it? a) agent (mode 0-2), b) meta agent (mode 3), c) a group (mode 4) try{ switch(agentDict[subagent][1].mode) - {0} {quant = agentDict[subagent][1].durarr.sum; mode = 0 } - {1} {quant = agentDict[subagent][1].durarr.sum; mode = 1 } - {2} {quant = agentDict[subagent][1].durarr.sum; mode = 2 } - {3} {quant = metaAgentDict[subagent].quant; mode = 3 } // it's a meta agent (will play sequentially) + {0} {quant = agentDict[subagent][1].durarr.sum; mode = 0 } + {1} {quant = agentDict[subagent][1].durarr.sum; mode = 1 } + {2} {quant = agentDict[subagent][1].durarr.sum; mode = 2 } + {3} {quant = metaAgentDict[subagent].quant; mode = 3 } // it's a meta agent (will play sequentially) } {quant = 0; /* TEMP - do I need to set quant? */ mode = 4 }; // it's a group (not meta agent) and will play synchronously) groupitems = groupitems.add(agentarray[i*2].asString); @@ -2036,9 +2128,9 @@ oxo -> |Sdfsdf| \n\n\n") }); var durarrReady = false; var groupPpars = []; groups[subagent].do({arg subsubagent; - if(durarrReady.not, {durarrReady = true; durarr = agentDict[(docnum.asString++subsubagent).asSymbol][1].durarr }); + if(durarrReady.not, {durarrReady = true; durarr = agentDict[(this.agentPrefix++subsubagent).asSymbol][1].durarr }); this.opInterpreter("@" + subsubagent + agentarray[(i*2)+1], true); - groupPpars = groupPpars.add(this.opInterpreter( agentDict[(docnum.asString++subsubagent).asSymbol][1].scorestring.tr($",\ ), true )); + groupPpars = groupPpars.add(this.opInterpreter( agentDict[(this.agentPrefix++subsubagent).asSymbol][1].scorestring.tr($",\ ), true )); }); Pdef(subagent, Ppar(groupPpars, 1)); //.quant = [quant, 0]; }; @@ -2048,9 +2140,9 @@ oxo -> |Sdfsdf| \n\n\n") }); groups.add(agent -> groupitems); // -- set the general quant argument (from the first agent in a metaagent) -// if(metaAgentDict.quant.isNil, { -// metaAgentDict.add(\quant -> quant); -// }); + // if(metaAgentDict.quant.isNil, { + // metaAgentDict.add(\quant -> quant); + // }); // -- create a new agent if needed if(agentDict[agent].isNil, { @@ -2062,7 +2154,7 @@ oxo -> |Sdfsdf| \n\n\n") }); }); agentDict[agent][1].mode = 3; - // agentDict[agent][1].durarr = agentDict[(docnum.asString++agentarray[0].asString).asSymbol][1].durarr; + // agentDict[agent][1].durarr = agentDict[(this.agentPrefix++agentarray[0].asString).asSymbol][1].durarr; agentDict[agent][1].durarr = durarr; agentDict[agent][1].instrument = "metatrack"; agentDict[agent][1].scorestring = string; @@ -2081,16 +2173,16 @@ oxo -> |Sdfsdf| \n\n\n") }); playNow = return.not; // if returning, then don't play if(snapshot.not, { - metaAgentDict.do({arg metaagent; - // if the agent is part of a metaAgent it is not played (so we can do "shake ringo", etc. without it being played) - try{metaagent.agents.do({arg agentindict; if(agentindict == agent, {playNow = false }) })}; - }); + metaAgentDict.do({arg metaagent; + // if the agent is part of a metaAgent it is not played (so we can do "shake ringo", etc. without it being played) + try{metaagent.agents.do({arg agentindict; if(agentindict == agent, {playNow = false }) })}; + }); - // experimental -// groups.do({arg group; -// // if the agent is part of a metaAgent it is not played (so we can do "shake ringo", etc. without it being played) -// try{group.do({arg agentname; "agentName ".post; if((docnum.asString++agentname.asString).asSymbol == agent, { playNow = false }) })}; -// }); + // experimental + // groups.do({arg group; + // // if the agent is part of a metaAgent it is not played (so we can do "shake ringo", etc. without it being played) + // try{group.do({arg agentname; "agentName ".post; if((this.agentPrefix++agentname.asString).asSymbol == agent, { playNow = false }) })}; + // }); }); if(snapshot, { playNow = true }); @@ -2102,29 +2194,29 @@ oxo -> |Sdfsdf| \n\n\n") }); 10.do({arg i; proxyspace[agent][i+1] = nil }); // oh dear. Proxyspace forces this, as one might want to put an effect again on a repeat pat agentDict[agent][0].clear; // clear the effect references pdef = Pdef(agent, Pbind( - \instrument, Pseq(instrarr, inf), - \midinote, Pseq(notearr, inf), - \dur, Pseq(durarr, repeats), - \amp, Pseq(attackarr*agentDict[agent][1].amp, inf), - \sustain, Pseq(sustainarr, inf), - \pan, Pseq(panarr, inf) + \instrument, Pseq(instrarr, inf), + \midinote, Pseq(notearr, inf), + \dur, Pseq(durarr, repeats), + \amp, Pseq(attackarr*agentDict[agent][1].amp, inf), + \sustain, Pseq(sustainarr, inf), + \pan, Pseq(panarr, inf) )); if(playNow, { {proxyspace[agent].quant = [durarr.sum, quantphase, 0, 1]; - proxyspace[agent].defineBus(numChannels: numChan); - proxyspace[agent] = Pdef(agent); - proxyspace[agent].play;}.defer(0.5); + proxyspace[agent].defineBus(numChannels: numChan); + proxyspace[agent] = Pdef(agent); + proxyspace[agent].play;}.defer(0.5); }); },{ if(newInstrFlag, { // only if instrument was {, where Pmono bufferplayer synthdef needs to be shut down (similar to above, but no freeing of effects) proxyspace[agent].free; // needed in order to swap instrument in Pmono pdef = Pdef(agent, Pbind( - \instrument, Pseq(instrarr, inf), - \midinote, Pseq(notearr, inf), - \dur, Pseq(durarr, repeats), - \amp, Pseq(attackarr*agentDict[agent][1].amp, inf), - \sustain, Pseq(sustainarr, inf), - \pan, Pseq(panarr, inf) + \instrument, Pseq(instrarr, inf), + \midinote, Pseq(notearr, inf), + \dur, Pseq(durarr, repeats), + \amp, Pseq(attackarr*agentDict[agent][1].amp, inf), + \sustain, Pseq(sustainarr, inf), + \pan, Pseq(panarr, inf) )).quant = [durarr.sum, quantphase]; if(playNow, { { proxyspace[agent].play }.defer(0.5); // defer needed as the free above and play immediately doesn't work @@ -2132,12 +2224,12 @@ oxo -> |Sdfsdf| \n\n\n") }); }, { // default behavior pdef = Pdef(agent, Pbind( - \instrument, Pseq(instrarr, inf), - \midinote, Pseq(notearr, inf), - \dur, Pseq(durarr, repeats), - \amp, Pseq(attackarr*agentDict[agent][1].amp, inf), - \sustain, Pseq(sustainarr, inf), - \pan, Pseq(panarr, inf) + \instrument, Pseq(instrarr, inf), + \midinote, Pseq(notearr, inf), + \dur, Pseq(durarr, repeats), + \amp, Pseq(attackarr*agentDict[agent][1].amp, inf), + \sustain, Pseq(sustainarr, inf), + \pan, Pseq(panarr, inf) )).quant = [durarr.sum, quantphase]; if(playNow, { if(agentDict[agent][1].playstate == false, { @@ -2161,57 +2253,57 @@ oxo -> |Sdfsdf| \n\n\n") }); 10.do({arg i; proxyspace[agent][i+1] = nil }); // oh dear. Proxyspace forces this, as one might want to put an effect again on a repeat pat agentDict[agent][0].clear; // clear the effect references pdef = Pdef(agent, Pbind( - \instrument, morphmode.asSymbol, - \loop, loop, - \buf1, Pseq(instrarr, inf), - \buf2, Pseq(instrarr.rotate(-1), inf), - \midinote, Pseq(notearr, inf), - \dur, Pseq(durarr, repeats), - \amp, Pseq(attackarr*agentDict[agent][1].amp, inf), - \morphtime, Pseq(durarr/TempoClock.default.tempo, inf), - //\sustain, Pseq(sustainarr, inf), - \panFrom, Pseq(panarr, inf), - \panTo, Pseq(panarr.rotate(-1), inf) + \instrument, morphmode.asSymbol, + \loop, loop, + \buf1, Pseq(instrarr, inf), + \buf2, Pseq(instrarr.rotate(-1), inf), + \midinote, Pseq(notearr, inf), + \dur, Pseq(durarr, repeats), + \amp, Pseq(attackarr*agentDict[agent][1].amp, inf), + \morphtime, Pseq(durarr/TempoClock.default.tempo, inf), + //\sustain, Pseq(sustainarr, inf), + \panFrom, Pseq(panarr, inf), + \panTo, Pseq(panarr.rotate(-1), inf) )); if(playNow, { {proxyspace[agent].quant = [durarr.sum, quantphase, 0, 1]; - proxyspace[agent].defineBus(numChannels: numChan); - proxyspace[agent] = Pdef(agent); - proxyspace[agent].play;}.defer(0.5); + proxyspace[agent].defineBus(numChannels: numChan); + proxyspace[agent] = Pdef(agent); + proxyspace[agent].play;}.defer(0.5); }); },{ if(newInstrFlag, { // only if instrument was {, where Pmono bufferplayer synthdef needs to be shut down (similar to above, but no freeing of effects) proxyspace[agent].free; // needed in order to swap instrument in Pmono pdef = Pdef(agent, Pbind( - \instrument, morphmode.asSymbol, - \loop, loop, - \buf1, Pseq(instrarr, inf), - \buf2, Pseq(instrarr.rotate(-1), inf), - \midinote, Pseq(notearr, inf), - \dur, Pseq(durarr, repeats), - \amp, Pseq(attackarr*agentDict[agent][1].amp, inf), - \morphtime, Pseq(durarr/TempoClock.default.tempo, inf), - //\sustain, Pseq(sustainarr, inf), - //\pan, Pseq(panarr, inf) - \panFrom, Pseq(panarr, inf), - \panTo, Pseq(panarr.rotate(-1), inf) + \instrument, morphmode.asSymbol, + \loop, loop, + \buf1, Pseq(instrarr, inf), + \buf2, Pseq(instrarr.rotate(-1), inf), + \midinote, Pseq(notearr, inf), + \dur, Pseq(durarr, repeats), + \amp, Pseq(attackarr*agentDict[agent][1].amp, inf), + \morphtime, Pseq(durarr/TempoClock.default.tempo, inf), + //\sustain, Pseq(sustainarr, inf), + //\pan, Pseq(panarr, inf) + \panFrom, Pseq(panarr, inf), + \panTo, Pseq(panarr.rotate(-1), inf) )).quant = [durarr.sum, quantphase, 0, 1]; if(playNow, { { proxyspace[agent].play }.defer(0.5); // defer needed as the free above and play immediately doesn't work }); }, { // default behavior pdef = Pdef(agent, Pbind( - \instrument, morphmode.asSymbol, - \loop, loop, - \buf1, Pseq(instrarr, inf), - \buf2, Pseq(instrarr.rotate(-1), inf), - \midinote, Pseq(notearr, inf), - \dur, Pseq(durarr, repeats), - \amp, Pseq(attackarr*agentDict[agent][1].amp, inf), - \morphtime, Pseq(durarr/TempoClock.default.tempo, inf), - //\sustain, Pseq(sustainarr, inf), - \panFrom, Pseq(panarr, inf), - \panTo, Pseq(panarr.rotate(-1), inf) + \instrument, morphmode.asSymbol, + \loop, loop, + \buf1, Pseq(instrarr, inf), + \buf2, Pseq(instrarr.rotate(-1), inf), + \midinote, Pseq(notearr, inf), + \dur, Pseq(durarr, repeats), + \amp, Pseq(attackarr*agentDict[agent][1].amp, inf), + \morphtime, Pseq(durarr/TempoClock.default.tempo, inf), + //\sustain, Pseq(sustainarr, inf), + \panFrom, Pseq(panarr, inf), + \panTo, Pseq(panarr.rotate(-1), inf) )).quant = [durarr.sum, quantphase, 0, 1]; //proxyspace[agent].play; // this would build up synths on server on commands such as yoyo agent if(playNow, { @@ -2230,15 +2322,15 @@ oxo -> |Sdfsdf| \n\n\n") }); var pdef, playNow; playNow = return.not; // if returning, then don't play if(snapshot.not, { - metaAgentDict.do({arg metaagent; - // if the agent is part of a metaAgent it is not played (so we can do "shake ringo", etc. without it being played) - try{metaagent.agents.do({arg agentindict; if(agentindict == agent, {playNow = false }) })}; - }); - // experimental -// groups.do({arg group; -// // if the agent is part of a metaAgent it is not played (so we can do "shake ringo", etc. without it being played) -// try{group.do({arg agentname; "agentName ".post; if((docnum.asString++agentname.asString).asSymbol == agent, { playNow = false }) })}; -// }); + metaAgentDict.do({arg metaagent; + // if the agent is part of a metaAgent it is not played (so we can do "shake ringo", etc. without it being played) + try{metaagent.agents.do({arg agentindict; if(agentindict == agent, {playNow = false }) })}; + }); + // experimental + // groups.do({arg group; + // // if the agent is part of a metaAgent it is not played (so we can do "shake ringo", etc. without it being played) + // try{group.do({arg agentname; "agentName ".post; if((this.agentPrefix++agentname.asString).asSymbol == agent, { playNow = false }) })}; + // }); }); if(snapshot, { playNow = true }); if(instrument.asString=="midi", { eventtype = \midi }, { eventtype = \note }); @@ -2249,35 +2341,35 @@ oxo -> |Sdfsdf| \n\n\n") }); 10.do({arg i; proxyspace[agent][i+1] = nil }); // oh dear. Proxyspace forces this, as one might want to put an effect again on a repeat pat agentDict[agent][0].clear; // clear the effect references pdef = Pdef(agent, Pbind( - \instrument, instrument, - \type, eventtype, - \midiout, midiclient, - \chan, midichannel, - \midinote, Pseq(notearr, inf), - \dur, Pseq(durarr, repeats), - \sustain, Pseq(sustainarr, inf), - \amp, Pseq(attackarr*agentDict[agent][1].amp, inf), - \pan, Pseq(panarr, inf) + \instrument, instrument, + \type, eventtype, + \midiout, midiclient, + \chan, midichannel, + \midinote, Pseq(notearr, inf), + \dur, Pseq(durarr, repeats), + \sustain, Pseq(sustainarr, inf), + \amp, Pseq(attackarr*agentDict[agent][1].amp, inf), + \pan, Pseq(panarr, inf) )); if(playNow, { {proxyspace[agent].quant = [durarr.sum, quantphase, 0, 1]; - proxyspace[agent].defineBus(numChannels: numChan); - proxyspace[agent] = Pdef(agent); - proxyspace[agent].play;}.defer(0.5); + proxyspace[agent].defineBus(numChannels: numChan); + proxyspace[agent] = Pdef(agent); + proxyspace[agent].play;}.defer(0.5); }); },{ if(newInstrFlag, { // only if instrument was {, where Pmono bufferplayer synthdef needs to be shut down (similar to above, but no freeing of effects) proxyspace[agent].free; // needed in order to swap instrument in Pmono pdef = Pdef(agent, Pbind( - \instrument, instrument, - \type, eventtype, - \midiout, midiclient, - \chan, midichannel, - \midinote, Pseq(notearr, inf), - \dur, Pseq(durarr, repeats), - \sustain, Pseq(sustainarr, inf), - \amp, Pseq(attackarr*agentDict[agent][1].amp, inf), - \pan, Pseq(panarr, inf) + \instrument, instrument, + \type, eventtype, + \midiout, midiclient, + \chan, midichannel, + \midinote, Pseq(notearr, inf), + \dur, Pseq(durarr, repeats), + \sustain, Pseq(sustainarr, inf), + \amp, Pseq(attackarr*agentDict[agent][1].amp, inf), + \pan, Pseq(panarr, inf) )).quant = [durarr.sum, quantphase, 0, 1]; if(playNow, { proxyspace[agent].defineBus(numChannels: numChan); @@ -2286,17 +2378,17 @@ oxo -> |Sdfsdf| \n\n\n") }); }, { // default behavior pdef = Pdef(agent, Pbind( - \instrument, instrument, - \type, eventtype, - \midiout, midiclient, - \chan, midichannel, - \midinote, Pseq(notearr, inf), - \dur, Pseq(durarr, repeats), - \sustain, Pseq(sustainarr, inf), - \amp, Pseq(attackarr*agentDict[agent][1].amp, inf), - \pan, Pseq(panarr, inf) + \instrument, instrument, + \type, eventtype, + \midiout, midiclient, + \chan, midichannel, + \midinote, Pseq(notearr, inf), + \dur, Pseq(durarr, repeats), + \sustain, Pseq(sustainarr, inf), + \amp, Pseq(attackarr*agentDict[agent][1].amp, inf), + \pan, Pseq(panarr, inf) )).quant = [durarr.sum, quantphase, 0, 1]; - //proxyspace[agent].play; // this would build up synths on server on commands such as yoyo agent + //proxyspace[agent].play; // this would build up synths on server on commands such as yoyo agent if(playNow, { if(agentDict[agent][1].playstate == false, { proxyspace[agent].defineBus(numChannels: numChan); @@ -2313,15 +2405,15 @@ oxo -> |Sdfsdf| \n\n\n") }); var pdef, playNow; playNow = return.not; // if returning, then don't play if(snapshot.not, { - metaAgentDict.do({arg metaagent; - // if the agent is part of a metaAgent it is not played (so we can do "shake ringo", etc. without it being played) - try{metaagent.agents.do({arg agentindict; if(agentindict == agent, {playNow = false }) })}; - }); - // experimental -// groups.do({arg group; -// // if the agent is part of a metaAgent it is not played (so we can do "shake ringo", etc. without it being played) -// try{group.do({arg agentname; "agentName ".post; if((docnum.asString++agentname.asString).asSymbol == agent, { playNow = false }) })}; -// }); + metaAgentDict.do({arg metaagent; + // if the agent is part of a metaAgent it is not played (so we can do "shake ringo", etc. without it being played) + try{metaagent.agents.do({arg agentindict; if(agentindict == agent, {playNow = false }) })}; + }); + // experimental + // groups.do({arg group; + // // if the agent is part of a metaAgent it is not played (so we can do "shake ringo", etc. without it being played) + // try{group.do({arg agentname; "agentName ".post; if((this.agentPrefix++agentname.asString).asSymbol == agent, { playNow = false }) })}; + // }); }); @@ -2335,34 +2427,34 @@ oxo -> |Sdfsdf| \n\n\n") }); Pdefn((agent++"durarray").asSymbol, Pseq(durarr, repeats)); Pdefn((agent++"amparray").asSymbol, Pseq(amparr, repeats)); pdef = Pdef(agent, Pmono(instrument, - \dur, Pdefn((agent++"durarray").asSymbol), - \freq, pitch.midicps, - \noteamp, Pdefn((agent++"amparray").asSymbol), - \pan, Pseq(panarr, inf) + \dur, Pdefn((agent++"durarray").asSymbol), + \freq, pitch.midicps, + \noteamp, Pdefn((agent++"amparray").asSymbol), + \pan, Pseq(panarr, inf) )); if(playNow, { {proxyspace[agent].quant = [durarr.sum, quantphase, 0, 1]; - proxyspace[agent].defineBus(numChannels: numChan); - proxyspace[agent] = Pdef(agent); - proxyspace[agent].play }.defer(0.5); + proxyspace[agent].defineBus(numChannels: numChan); + proxyspace[agent] = Pdef(agent); + proxyspace[agent].play }.defer(0.5); }); },{ Pdefn((agent++"durarray").asSymbol, Pseq(durarr, repeats)).quant = [durarr.sum, quantphase, 0, 1]; Pdefn((agent++"amparray").asSymbol, Pseq(amparr, repeats)).quant = [durarr.sum, quantphase, 0, 1]; //if(newInstrFlag, { // removed temp for repeat functionality - proxyspace[agent].free; // needed in order to swap instrument in Pmono - pdef = Pdef(agent, Pmono(instrument, - \dur, Pdefn((agent++"durarray").asSymbol), - \freq, pitch.midicps, - \noteamp, Pdefn((agent++"amparray").asSymbol), - \pan, Pseq(panarr, inf) - )); - if(playNow, { - { + proxyspace[agent].free; // needed in order to swap instrument in Pmono + pdef = Pdef(agent, Pmono(instrument, + \dur, Pdefn((agent++"durarray").asSymbol), + \freq, pitch.midicps, + \noteamp, Pdefn((agent++"amparray").asSymbol), + \pan, Pseq(panarr, inf) + )); + if(playNow, { + { proxyspace[agent].defineBus(numChannels: numChan); proxyspace[agent] = Pdef(agent); proxyspace[agent].play }.defer(0.5); // defer needed as the free above and play immediately doesn't work - }); + }); //}); }); Pdef(agent).set(\amp, agentDict[agent][1].amp); // proxyspace quirk: amp set from outside @@ -2378,7 +2470,7 @@ oxo -> |Sdfsdf| \n\n\n") }); splitloc = string.findAll(">>"); agent = string[0..splitloc[0]-1]; pureagent = agent; - agent = (docnum.asString++agent).asSymbol; + agent = (this.agentPrefix++agent).asSymbol; string = string++$ ; endchar = string.find(" "); splitloc = splitloc.add(endchar); @@ -2420,10 +2512,10 @@ oxo -> |Sdfsdf| \n\n\n") }); effectFoundFlag = false; string = string.tr($ , \); // get rid of spaces string = string.reject({ |c| c.ascii == 10 }); - splitloc = string.findAll("<<"); + splitloc = string.findAll("<<"); agent = string[0..splitloc[0]-1]; pureagent = agent; - agent = (docnum.asString++agent).asSymbol; + agent = (this.agentPrefix++agent).asSymbol; string = string++$ ; endchar = string.find(" "); splitloc = splitloc.add(endchar); @@ -2473,7 +2565,7 @@ oxo -> |Sdfsdf| \n\n\n") }); splitloc = string.find("))"); agentstring = string[0..splitloc-1]; // get the name of the agent agent = agentstring[0..agentstring.size-1]; - agent = (docnum.asString++agent).asSymbol; + agent = (this.agentPrefix++agent).asSymbol; dict = agentDict[agent][1]; if(groups[agent].isNil.not, { // the "agent" is a group groups[agent].do({arg agentx, i; @@ -2485,11 +2577,11 @@ oxo -> |Sdfsdf| \n\n\n") }); (" ---> ixi lang : AMP in agent "++agent.asString++" : ").post; amp.postln; agentDict[agent][1].amp = amp; switch(agentDict[agent][1].mode) - {0} { this.playScoreMode0(agent, dict.notearr, dict.durarr, dict.instrarr, dict.sustainarr, dict.attackarr, dict.panarr, - dict.quantphase, false, dict.morphmode, dict.repeats, false, false); } - {1} { this.playScoreMode1(agent, dict.notearr, dict.durarr, dict.sustainarr, dict.attackarr, dict.panarr, dict.instrument, - dict.quantphase, false, dict.midichannel, dict.repeats, false, false); } - {2} { Pdef(agent).set(\amp, amp) }; + {0} { this.playScoreMode0(agent, dict.notearr, dict.durarr, dict.instrarr, dict.sustainarr, dict.attackarr, dict.panarr, + dict.quantphase, false, dict.morphmode, dict.repeats, false, false); } + {1} { this.playScoreMode1(agent, dict.notearr, dict.durarr, dict.sustainarr, dict.attackarr, dict.panarr, dict.instrument, + dict.quantphase, false, dict.midichannel, dict.repeats, false, false); } + {2} { Pdef(agent).set(\amp, amp) }; }); } @@ -2501,7 +2593,7 @@ oxo -> |Sdfsdf| \n\n\n") }); splitloc = string.find("(("); agentstring = string[0..splitloc-1]; // get the name of the agent agent = agentstring[0..agentstring.size-1]; - agent = (docnum.asString++agent).asSymbol; + agent = (this.agentPrefix++agent).asSymbol; dict = agentDict[agent][1]; if(groups[agent].isNil.not, { // the "agent" is a group groups[agent].do({arg agentx, i; @@ -2513,18 +2605,18 @@ oxo -> |Sdfsdf| \n\n\n") }); (" ---> ixi lang : AMP in agent "++agent.asString++" : ").post; amp.postln; agentDict[agent][1].amp = amp; switch(agentDict[agent][1].mode) - {0} { this.playScoreMode0(agent, dict.notearr, dict.durarr, dict.instrarr, dict.sustainarr, dict.attackarr, dict.panarr, - dict.quantphase, false, dict.morphmode, dict.repeats, false, false); } - {1} { this.playScoreMode1(agent, dict.notearr, dict.durarr, dict.sustainarr, dict.attackarr, dict.panarr, dict.instrument, - dict.quantphase, false, dict.midichannel, dict.repeats, false, false); } - {2} { Pdef(agent).set(\amp, amp) }; + {0} { this.playScoreMode0(agent, dict.notearr, dict.durarr, dict.instrarr, dict.sustainarr, dict.attackarr, dict.panarr, + dict.quantphase, false, dict.morphmode, dict.repeats, false, false); } + {1} { this.playScoreMode1(agent, dict.notearr, dict.durarr, dict.sustainarr, dict.attackarr, dict.panarr, dict.instrument, + dict.quantphase, false, dict.midichannel, dict.repeats, false, false); } + {2} { Pdef(agent).set(\amp, amp) }; }); } findStringStartEnd {arg doc, pureagentname; var allreturns, stringstart, stringend, tempstringstart; var docstring = doc.string ++ "\n"; // added in Qt as the last line wasn't working -// allreturns = doc.string.findAll("\n") ++ doc.string.findAll(""++13.asAscii); + // allreturns = doc.string.findAll("\n") ++ doc.string.findAll(""++13.asAscii); allreturns = docstring.findAll("\n") ++ docstring.findAll(""++13.asAscii); allreturns.notNil.if({ try{block{ | break | @@ -2535,7 +2627,7 @@ oxo -> |Sdfsdf| \n\n\n") }); if(pureagentname == doc.string[tempstringstart..doc.string.findAll("->")[doc.string.findAll("->").indexOfGreaterThan(tempstringstart+1)]-1].tr($ , \), { // the line below will check if it's the same agent in the dict and on the doc. if so, it changes it (in case there are many with same name) //stringend.isNil.if({stringend = 0}); - if(agentDict[(docnum.asString++pureagentname.asString).asSymbol][1].scorestring == doc.string[loc..stringend-1].asCompileString, { + if(agentDict[(this.agentPrefix++pureagentname.asString).asSymbol][1].scorestring == doc.string[loc..stringend-1].asCompileString, { stringstart = tempstringstart; break.value; // exact match found and we break loop, leaving stringstart and stringend with correct values }); @@ -2612,22 +2704,22 @@ oxo -> |Sdfsdf| \n\n\n") }); }); },{ switch(newarg[0]) - {"^"} { - thisline = thisline++newarg[0]++newarg[1]++newarg[0]; // no need to replace an operator, just add to the end - } - {"("} { - thisline = thisline++newarg[0]++newarg[1]++")"; // no need to replace an operator, just add to the end - } - {"<"} { - thisline = thisline++newarg[0]++newarg[1]++">"; // no need to replace an operator, just add to the end - } - { - thisline = thisline++newarg[0]++newarg[1]; // no need to replace an operator, just add to the end - }; + {"^"} { + thisline = thisline++newarg[0]++newarg[1]++newarg[0]; // no need to replace an operator, just add to the end + } + {"("} { + thisline = thisline++newarg[0]++newarg[1]++")"; // no need to replace an operator, just add to the end + } + {"<"} { + thisline = thisline++newarg[0]++newarg[1]++">"; // no need to replace an operator, just add to the end + } + { + thisline = thisline++newarg[0]++newarg[1]; // no need to replace an operator, just add to the end + }; }); }); - agent = (docnum.asString++pureagentname).asSymbol; + agent = (this.agentPrefix++pureagentname).asSymbol; if(agentDict.keys.includes(agent), { if(thisline.find("|").isNil.not, { @@ -2654,13 +2746,13 @@ oxo -> |Sdfsdf| \n\n\n") }); scorerange = thisline.findAll("~"); argsuffix = thisline[scorerange[1]+1..thisline.size-1]; // if arguments are added scoremode = 3; - { // make agent white again - cursorPos = doc.selectionStart; // get cursor pos - #stringstart, stringend = this.findStringStartEnd(doc, pureagentname); // this will cause error since the agent string will have changed - // -- doc.setStringColor(oncolor, stringstart, stringend-stringstart); - //doc.selectRange(cursorPos); // set cursor pos again + { // make agent white again + cursorPos = doc.selectionStart; // get cursor pos + #stringstart, stringend = this.findStringStartEnd(doc, pureagentname); // this will cause error since the agent string will have changed + // -- doc.setStringColor(oncolor, stringstart, stringend-stringstart); + //doc.selectRange(cursorPos); // set cursor pos again doc.select(cursorPos, 0); - }.defer; + }.defer; }); if(modearray[scoremode], { // if this scoremode supports the operation (no need to yoyo a melodic score for example) @@ -2697,15 +2789,15 @@ oxo -> |Sdfsdf| \n\n\n") }); // for methods that change string sizes, it's good to do the below so cursor is placed correctly // if cursorPos < stringend, then the same location, else calcultate new location cf. new string size if(cursorPos |Sdfsdf| \n\n\n") }); "ixi lang ERROR: Action not applicable in this mode".postln; }); },{ - "ixi lang ERROR: Agent with this name not found!!!".postln; + "ixi lang ERROR: Agent with this name not found!!!".postln; }); } @@ -2743,7 +2835,7 @@ oxo -> |Sdfsdf| \n\n\n") }); spaces = string.findAll(" "); agent = string[splitloc+1..spaces[1]-1]; pureagentname = agent; // the name of the agent is different in code (0john) and in doc (john) (for multidoc support) - agent = (docnum.asString++agent).asSymbol; + agent = (this.agentPrefix++agent).asSymbol; if( spaces.size > 1, { argument = string[spaces[1]..spaces[spaces.size-1]] }); // is there an argument? @@ -2757,68 +2849,68 @@ oxo -> |Sdfsdf| \n\n\n") }); // the rest of the methods apply to the sub-agents #stringstart, stringend = this.findStringStartEnd(doc, pureagentname); switch(method) - {"doze"} {// pause stream - if(agentDict[agent][1].playstate == true, { - agentDict[agent][1].playstate = false; - proxyspace[agent].stop; + {"doze"} {// pause stream + if(agentDict[agent][1].playstate == true, { + agentDict[agent][1].playstate = false; + proxyspace[agent].stop; (stringend.notNil && stringstart.notNil).if({ doc.setStringColor(offcolor, stringstart, stringend-stringstart); }); - }); - } - {"perk"} { // restart stream - if(agentDict[agent][1].playstate == false, { - agentDict[agent][1].playstate = true; - proxyspace[agent].play; + }); + } + {"perk"} { // restart stream + if(agentDict[agent][1].playstate == false, { + agentDict[agent][1].playstate = true; + proxyspace[agent].play; (stringend.notNil && stringstart.notNil).if({ - doc.setStringColor(oncolor, stringstart, stringend-stringstart); - }); + doc.setStringColor(oncolor, stringstart, stringend-stringstart); }); - } - {"nap"} { // pause for either n secs or n secs:number of times - var napdur, separator, times, on, barmode; - on = true; - separator = argument.find(":"); - - if(separator.isNil.not, { // it contains a on/off order - napdur = argument[0..separator-1].asFloat; - // round to even, so it doesn't leave the stream off - times = argument[separator+1..argument.size-1].asInteger.round(2); - { - (times*2).do({ // times two as the interface is that it should nap twice - if(on, { - proxyspace[agent].objects[0].array[0].mute; - agentDict[agent][1].playstate = false; + }); + } + {"nap"} { // pause for either n secs or n secs:number of times + var napdur, separator, times, on, barmode; + on = true; + separator = argument.find(":"); + + if(separator.isNil.not, { // it contains a on/off order + napdur = argument[0..separator-1].asFloat; + // round to even, so it doesn't leave the stream off + times = argument[separator+1..argument.size-1].asInteger.round(2); + { + (times*2).do({ // times two as the interface is that it should nap twice + if(on, { + proxyspace[agent].objects[0].array[0].mute; + agentDict[agent][1].playstate = false; (stringend.notNil && stringstart.notNil).if({ - {doc.setStringColor(offcolor, stringstart, stringend-stringstart)}.defer; + {doc.setStringColor(offcolor, stringstart, stringend-stringstart)}.defer; }); - on = false; - }, { - proxyspace[agent].objects[0].array[0].unmute; - agentDict[agent][1].playstate = true; - (stringend.notNil && stringstart.notNil).if({ - {doc.setStringColor(oncolor, stringstart, stringend-stringstart)}.defer; - }); - on = true; - }); - napdur.wait; - }); - }.fork(TempoClock.new); - }, { // it is just a nap for n seconds and then reawake - { - napdur = argument.asFloat; - proxyspace[agent].objects[0].array[0].mute; - (stringend.notNil && stringstart.notNil).if({ - {doc.setStringColor(offcolor, stringstart, stringend-stringstart)}.defer; + on = false; + }, { + proxyspace[agent].objects[0].array[0].unmute; + agentDict[agent][1].playstate = true; + (stringend.notNil && stringstart.notNil).if({ + {doc.setStringColor(oncolor, stringstart, stringend-stringstart)}.defer; + }); + on = true; }); napdur.wait; - proxyspace[agent].objects[0].array[0].unmute; - (stringend.notNil && stringstart.notNil).if({ - {doc.setStringColor(oncolor, stringstart, stringend-stringstart)}.defer; - }); - }.fork(TempoClock.new); - }); - }; + }); + }.fork(TempoClock.new); + }, { // it is just a nap for n seconds and then reawake + { + napdur = argument.asFloat; + proxyspace[agent].objects[0].array[0].mute; + (stringend.notNil && stringstart.notNil).if({ + {doc.setStringColor(offcolor, stringstart, stringend-stringstart)}.defer; + }); + napdur.wait; + proxyspace[agent].objects[0].array[0].unmute; + (stringend.notNil && stringstart.notNil).if({ + {doc.setStringColor(oncolor, stringstart, stringend-stringstart)}.defer; + }); + }.fork(TempoClock.new); + }); + }; }); }, { // it is a real agent, not a group @@ -2855,350 +2947,350 @@ oxo -> |Sdfsdf| \n\n\n") }); // ------------- Perform methods - the ixi lang verbs switch(method) - {"doze"} {// pause stream - if(agentDict[agent][1].playstate == true, { - agentDict[agent][1].playstate = false; - //if(agentDict[agent][1].mode == 2, { // mode 2 would not mute/unmute - //Pdef(agent).stop; - proxyspace[agent].stop; - //}); - //proxyspace[agent].objects[0].array[0].mute; - (stringend.notNil && stringstart.notNil).if({ - doc.setStringColor(offcolor, stringstart, stringend-stringstart); - }); + {"doze"} {// pause stream + if(agentDict[agent][1].playstate == true, { + agentDict[agent][1].playstate = false; + //if(agentDict[agent][1].mode == 2, { // mode 2 would not mute/unmute + //Pdef(agent).stop; + proxyspace[agent].stop; + //}); + //proxyspace[agent].objects[0].array[0].mute; + (stringend.notNil && stringstart.notNil).if({ + doc.setStringColor(offcolor, stringstart, stringend-stringstart); }); - } - {"perk"} { // restart stream - if(agentDict[agent][1].playstate == false, { - agentDict[agent][1].playstate = true; - //if(agentDict[agent][1].mode == 2, { // mode 2 would not mute/unmute - //Pdef(agent).play; - proxyspace[agent].play; - //}); - //proxyspace[agent].objects[0].array[0].unmute; - (stringend.notNil && stringstart.notNil).if({ - doc.setStringColor(oncolor, stringstart, stringend-stringstart); - }); + }); + } + {"perk"} { // restart stream + if(agentDict[agent][1].playstate == false, { + agentDict[agent][1].playstate = true; + //if(agentDict[agent][1].mode == 2, { // mode 2 would not mute/unmute + //Pdef(agent).play; + proxyspace[agent].play; + //}); + //proxyspace[agent].objects[0].array[0].unmute; + (stringend.notNil && stringstart.notNil).if({ + doc.setStringColor(oncolor, stringstart, stringend-stringstart); }); - } - {"nap"} { // pause for either n secs or n secs:number of times - var napdur, separator, times, on, barmode; - on = true; - separator = argument.find(":"); + }); + } + {"nap"} { // pause for either n secs or n secs:number of times + var napdur, separator, times, on, barmode; + on = true; + separator = argument.find(":"); - if(separator.isNil.not, { // it contains a on/off order + if(separator.isNil.not, { // it contains a on/off order + if(argument.contains("b") || argument.contains("B"), { + barmode = true; + napdur = argument[0..separator-1].tr($b, \).asFloat; + },{ + barmode = false; // is the future working in seconds or bars ? + napdur = argument[0..separator-1].asFloat; + }); + //napdur = argument[0..separator-1].asInteger; + // round to even, so it doesn't leave the stream off + times = argument[separator+1..argument.size-1].asInteger.round(2); + { + (times*2).do({ // times two as the interface is that it should nap twice + if(on, { + if(agentDict[agent][1].mode == 2, { // mode 2 would not mute/unmute + proxyspace[agent].stop; + }); + try{proxyspace[agent].objects[0].array[0].mute}; // inside try, as metaagents have to nap as well + agentDict[agent][1].playstate = false; + (stringend.notNil && stringstart.notNil).if({ + {doc.setStringColor(offcolor, stringstart, stringend-stringstart)}.defer; + }); + on = false; + }, { + if(agentDict[agent][1].mode == 2, { // mode 2 would not mute/unmute + proxyspace[agent].play; + }); + try{proxyspace[agent].objects[0].array[0].unmute}; // inside try, as metaagents have to nap as well + agentDict[agent][1].playstate = true; + (stringend.notNil && stringstart.notNil).if({ + {doc.setStringColor(oncolor, stringstart, stringend-stringstart)}.defer; + }); + on = true; + }); + + if(barmode, { + ((napdur*agentDict[agent][1].durarr.sum)/TempoClock.default.tempo).wait; + },{ + napdur.wait; + }); + }); + }.fork(TempoClock.new); + }, { // it is just a nap for n seconds and then reawake + { + // argument = argument.asInteger; if(argument.contains("b") || argument.contains("B"), { barmode = true; - napdur = argument[0..separator-1].tr($b, \).asFloat; + napdur = argument.tr($b, \).asFloat; },{ barmode = false; // is the future working in seconds or bars ? - napdur = argument[0..separator-1].asFloat; + napdur = argument.asFloat; + }); + if(agentDict[agent][1].mode == 2, { // mode 2 would not mute/unmute + proxyspace[agent].stop; }); - //napdur = argument[0..separator-1].asInteger; - // round to even, so it doesn't leave the stream off - times = argument[separator+1..argument.size-1].asInteger.round(2); - { - (times*2).do({ // times two as the interface is that it should nap twice - if(on, { - if(agentDict[agent][1].mode == 2, { // mode 2 would not mute/unmute - proxyspace[agent].stop; - }); - try{proxyspace[agent].objects[0].array[0].mute}; // inside try, as metaagents have to nap as well - agentDict[agent][1].playstate = false; - (stringend.notNil && stringstart.notNil).if({ - {doc.setStringColor(offcolor, stringstart, stringend-stringstart)}.defer; - }); - on = false; - }, { - if(agentDict[agent][1].mode == 2, { // mode 2 would not mute/unmute - proxyspace[agent].play; - }); - try{proxyspace[agent].objects[0].array[0].unmute}; // inside try, as metaagents have to nap as well - agentDict[agent][1].playstate = true; - (stringend.notNil && stringstart.notNil).if({ - {doc.setStringColor(oncolor, stringstart, stringend-stringstart)}.defer; - }); - on = true; - }); - - if(barmode, { - ((napdur*agentDict[agent][1].durarr.sum)/TempoClock.default.tempo).wait; - },{ - napdur.wait; - }); - }); - }.fork(TempoClock.new); - }, { // it is just a nap for n seconds and then reawake - { -// argument = argument.asInteger; - if(argument.contains("b") || argument.contains("B"), { - barmode = true; - napdur = argument.tr($b, \).asFloat; - },{ - barmode = false; // is the future working in seconds or bars ? - napdur = argument.asFloat; - }); - if(agentDict[agent][1].mode == 2, { // mode 2 would not mute/unmute - proxyspace[agent].stop; - }); - try{proxyspace[agent].objects[0].array[0].mute}; - (stringend.notNil && stringstart.notNil).if({ + try{proxyspace[agent].objects[0].array[0].mute}; + (stringend.notNil && stringstart.notNil).if({ {doc.setStringColor(offcolor, stringstart, stringend-stringstart)}.defer; - }); - if(barmode, { - ((napdur*agentDict[agent][1].durarr.sum)/TempoClock.default.tempo).wait; - },{ - napdur.wait; - }); - if(agentDict[agent][1].mode == 2, { // mode 2 would not mute/unmute - proxyspace[agent].play; - }); - try{proxyspace[agent].objects[0].array[0].unmute}; - (stringend.notNil && stringstart.notNil).if({ + }); + if(barmode, { + ((napdur*agentDict[agent][1].durarr.sum)/TempoClock.default.tempo).wait; + },{ + napdur.wait; + }); + if(agentDict[agent][1].mode == 2, { // mode 2 would not mute/unmute + proxyspace[agent].play; + }); + try{proxyspace[agent].objects[0].array[0].unmute}; + (stringend.notNil && stringstart.notNil).if({ {doc.setStringColor(oncolor, stringstart, stringend-stringstart)}.defer; - }) - }.fork(TempoClock.new); - }); - } - {"shake"} { - // -------- perform the method ----------- - score = score.scramble; - // -------- put it back in place ---------- - this.swapString(doc, pureagentname, score, [true, true, true]); - } - {"replace"} { - var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; - // -------- perform the method ----------- - if(scoremode == 0, { - if(argument.contains("down"), { - score = score.collect({arg char; if(char != Char.space, {chars[26..51].choose}, {char})}); + }) + }.fork(TempoClock.new); + }); + } + {"shake"} { + // -------- perform the method ----------- + score = score.scramble; + // -------- put it back in place ---------- + this.swapString(doc, pureagentname, score, [true, true, true]); + } + {"replace"} { + var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + // -------- perform the method ----------- + if(scoremode == 0, { + if(argument.contains("down"), { + score = score.collect({arg char; if(char != Char.space, {chars[26..51].choose}, {char})}); + }, { + if(argument.contains("up"), { + score = score.collect({arg char; if(char != Char.space, {chars[0..26].choose}, {char})}); }, { - if(argument.contains("up"), { - score = score.collect({arg char; if(char != Char.space, {chars[0..26].choose}, {char})}); - }, { - score = score.collect({arg char; if(char != Char.space, {chars.choose}, {char})}); - }); + score = score.collect({arg char; if(char != Char.space, {chars.choose}, {char})}); }); - }, { - score = score.collect({arg char; if(char.isAlphaNum, {9.rand}, {char})}); - }); - // -------- put it back in place ---------- - this.swapString(doc, pureagentname, score, [true, true, true]); - } - {"insert"} { - var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; - // -------- perform the method ----------- - if(scoremode == 0, { - score = score.collect({arg char; if((char == Char.space) && 0.5.coin, {chars.choose}, {char})}); - }, { - score = score.collect({arg char; if((char == Char.space) && 0.5.coin, {9.rand}, {char})}); }); - // -------- put it back in place ---------- - this.swapString(doc, pureagentname, score, [true, true, true]); - } - {"remove"} { - // -------- perform the method ----------- - if(scoremode == 0, { - score = score.collect({arg char; if((char != Char.space) && 0.5.coin, {Char.space}, {char}) }); - }, { - score = score.collect({arg char; if((char != Char.space) && 0.5.coin, {Char.space}, {char}) }); - }); - // -------- put it back in place ---------- - this.swapString(doc, pureagentname, score, [true, true, true]); - } - {"swap"} { - var instruments; - // -------- perform the method ----------- - instruments = score.reject({arg c; c==$ }).scramble; - score = score.collect({arg char; if(char!=$ , {instruments.pop}, {" "}) }); - - this.swapString(doc, pureagentname, score, [true, true, true]); - } - {">shift"} { - argument = argument.asInteger; - // -------- perform the method ----------- - score = score.rotate(if((argument==0) || (argument=="") || (argument==" "), {1}, {argument})); - this.swapString(doc, pureagentname, score, [true, true, true]); - } - {"shift"} { + argument = argument.asInteger; + // -------- perform the method ----------- + score = score.rotate(if((argument==0) || (argument=="") || (argument==" "), {1}, {argument})); + this.swapString(doc, pureagentname, score, [true, true, true]); + } + {" |Sdfsdf| \n\n\n") }); //instrDict = dict; } + getMethodsList { - var doc, str; + // var doc, str; //doc = Document.new; //doc.name_("ixi lang lingo"); //doc.promptToSave_(false); @@ -3217,175 +3310,155 @@ oxo -> |Sdfsdf| \n\n\n") }); //doc.bounds_(Rect(10, 500, 650, 800)); //doc.font_(Font("Monaco",16)); //doc.string_(" - str = " - -- ixi lang lingo -- - - ----------- score modes ----------- - [ : melodic score - | : percussive score - { : concrete score (samples) - - ----------- operators ----------- - -> : score assigned to an agent - >> : set effect - << : delete effect - )) : increase amplitude - (( : decrease amplitude - tonic : set the tonic - - ------------ arguments --------- - ! : insert silence (!16 is silence for 16 beats) - + : transpose in melodic mode - - : transpose in melodic mode - * : expand the score in all modes - / : contract the score in all modes - () : control note length (1 is whole note, 2 is half, etc. - ~ will multiply the lenghts with n) - ^^ : control note accent (1 is quiet, 9 is loud) - <> : panning (1 is left, 9 right) - - ----------- methods ----------- - doze : pause agent - perk : resume agent - nap : pause agent for n seconds : n times - shake : randomise the score - swap : swap instruments in score - replace : replace instruments or notes in the score (in place) - >shift : right shift array n slot(s) - : store current state as a snapshot (snapshot -> mySnap) - snapshot mySnap : recall the snapshot - suicide : allow the language to kill itself sometime in the future - hotline : if you change your mind wrgt the suicide - midiclients : post the available midiclients - midiout : set the port to the midiclient - store : store the environmental setup of the session - load : load the environment of a stored - savescore : save the session - playscore : play a saved session (exactly the same, unless you name a variation) - newrec : start a new recording and ignore all that has been typed and evaluated before - autocode : autocode some agents and scores - - ----------- effects ----------- - reverb - reverbS - reverbL - delay - distort - cyberpunk - bitcrush - techno - technosaw - antique - lowpass - tremolo - vibrato - "//); - ; - str.postln; - } - - getInstrumentsList { - var doc; - doc = TextView.new(Window.new("", Rect(100, 100, 600, 700)).front, Rect(0, 0, 600, 700)) - .resize_(5) - .name_("ixi lang instruments") - .background_(doccolor) - .setProperty(\styleSheet, "color:white") // set the cursor to white - .setStringColor(oncolor, 0, 100000) // then set the text color to whatever the user has specified - .font_(Font("Monaco",16)) - .string_(" - - -- ixi lang instruments -- - - ------ synthesis instruments ------\n\n"++ -"project synthdefs:\n\n" ++ - -ixiInstr.getProjectSynthesisSynthdefs // calling an XiiLangInstr instance - -++ "\n\nixi lang synthdefs:\n\n" ++ - -ixiInstr.getXiiLangSynthesisSynthdefs // calling an XiiLangInstr instance - -++ + var w, m, str = " +----------- score modes ----------- +[ : melodic score +| : percussive score +{ : concrete score (samples) + +----------- operators ----------- +-> : score assigned to an agent +>> : set effect +<< : delete effect +)) : increase amplitude +(( : decrease amplitude +tonic : set the tonic + +examples: (@ sets repetition count) +name score expression +agent1 -> piano[123456787654321]@1 +agent2 -> |abcdefghijklmonp|@1 +agent3 -> snow{9 }@1 + +agent1 33 reverb +------------ arguments --------- +! : insert silence (!16 is silence for 16 beats) +@ : set the number of repetitions ++ : transpose in melodic mode, value can be multi-digit +- : transpose in melodic mode, value can be multi-digit +* : expand the score in all modes, value can be multi-digit +/ : contract the score in all modes, value can be multi-digit +(..) : duration divisors ( 1 - 9) durations can be scaled +: (1244_8) makes the durations 8 times larger, scaling value can be multi-digit +^..^ : control note accent (1 is quiet, 9 is loud) +<..> : panning (1 is left, 9 right) +~ agent reps... ~ :sequence agents, repeating each one the specified time +:MUST have spaces between tildes and argument +----------- methods ----------- +doze : pause agent +perk : resume agent +nap : pause agent for n seconds : n times +shake : randomise the score +swap : swap instruments in score +replace : replace instruments or notes in the score (in place) +>shift : right shift array n slot(s) + : store current state as a snapshot (snapshot -> mySnap) +snapshot mySnap : recall the snapshot +suicide : allow the language to kill itself sometime in the future +hotline : if you change your mind wrgt the suicide +midiclients : post the available midiclients +midiout : set the port to the midiclient +store : store the environmental setup of the session +load : load the environment of a stored +savescore : save the session +playscore : play a saved session (exactly the same, unless you name a variation) +newrec : start a new recording and ignore all that has been typed and evaluated before +autocode : autocode some agents and scores +"; + str.split(Char.nl); + + w = Window.new("ixi Lang Lingo", Rect(Window.screenBounds.width - 650, 100, 650, 350), scroll: false); + w.front; + // ListView(w, Rect(10, 10, 630, 330)) + // .items_(str.split(Char.nl)) + TextView(w, Rect(10, 10, 630, 330)) + .string_(str) + .resize_(5); + } -"\n\n ------ sample instruments ------\n\n" -++ + getInstrumentsList { + var m,t,u,e,f, w, r; + r = Rect(Window.screenBounds.width - 650, Window.screenBounds.height - 500, 650, 500); + w = Window.new("Xii Sounds, Scales, Tunings", r, scroll: false).front; + + // scales + + StaticText(w, Rect(10, 0, 119, 20)).string_("synths").align_(\center); + m = ListView(w, Rect(10, 20, 119, 490)).resize_(4); + m.items = ixiInstr.getProjectSynthesisSynthdefs.sort ++ ["-----------"] ++ + SynthDescLib.getLib(\xiilang).synthDescs.keys.asArray.sort[1..]; + + StaticText(w, Rect(130, 0, 119, 20)).string_("effects").align_(\center); + t = ListView(w, Rect(130, 20, 119, 490)).resize_(4); + t.items = effectDict.keys.asArray.sort.collect({ | k | (k.asString) }); + + // sample mappings - project specific + StaticText(w, Rect(260, 0, 119, 20)).string_("sample mappings").align_(\center); + u = ListView(w, Rect(260, 20, 119, 490)).resize_(4); + u.items = instrDict.keys.asArray.sort.collect({ | k | (k.asString + instrDict[k]) }); + + // effects - project specific, sort of + StaticText(w, Rect(390, 0, 119, 20)).string_("scales").align_(\center); + e = ListView(w, Rect(390, 20, 119, 490)).resize_(4); + if( Scale.respondsTo(\all)) { + e.items = Scale.all.parent.keys.asArray.sort.collect(_.asString); + } { + e.items = ScaleInfo.scales.keys.asArray.sort.collect(_.asString); + }; -ixiInstr.getSamplesSynthdefs - //); - ).postln; + StaticText(w, Rect(520, 0, 119, 20)).string_("tunings").align_(\center); + f = ListView(w, Rect(520, 20, 119, 490)).resize_(4); + if( Tuning.respondsTo(\all)) { + f.items = Tuning.all.parent.keys.asArray.sort.collect(_.asString); + } { + f.items = TuningInfo.tunings.keys.asArray.sort.collect(_.asString); + }; } - addixiMenu { - /* - var a; - CocoaMenuItem.clearCustomItems; - a = SCMenuGroup(nil, "ixi", 10); - - SCMenuItem(a, "Feedback") - .action_({ - "open http://www.ixi-audio.net/ixilang/ixilang_feedback.html".unixCmd; - }); - SCMenuSeparator(a, 1); // add a separator - - SCMenuItem(a, "Survey") - .action_({ - "open http://www.ixi-audio.net/ixilang/survey".unixCmd; - }); - SCMenuSeparator(a, 3); // add a separator - - SCMenuItem(a, "Check for Update") - .action_({ - var latestversion, pipe; - // check if user is online: (will return a 4 digit number if not) - a = "curl http://www.ixi-audio.net/ixilang/version.txt".systemCmd; - // then get the version number (from a textfile with only one number in it) - if(a==0, { - pipe = Pipe.new("curl http://www.ixi-audio.net/ixilang/version.txt", "r"); - latestversion = pipe.getLine; - pipe.close; - [\latestversion, latestversion, \thisversion, thisversion].postln; - if(latestversion.asFloat > thisversion, { - XiiAlert.new("New version (version "++latestversion++") is available on the ixi website"); - {"open http://www.ixi-audio.net".unixCmd}.defer(2.5); // allow for time to read - }, { - XiiAlert.new("You have got the latest version of ixi lang"); - }); - }); - }); - */ + agentPrefix { + ^docnum.asString; + // ^""; } - - } +/* +eval +[ mode, 1 ] +------ ixi lang: Created Melodic Agent : test +[ ( ), ( 'instrument': string, 'mode': 1, 'notearr': [ 60, 62, 64 ], 'amp': 0.5, + +a = s.waitForBoot { a = XiiLang(txt: true); }; +a.agentDict['1test'] +a.agentDict.keys +*/ XiiLangSingleton { classvar <>windowsList; @@ -3423,8 +3496,8 @@ XiiLangSingleton { XiiLangSingleton.windowsList[window].opInterpreter(this); if(newagent, { { - XiiLangSingleton.windowsList[window].doc.string = XiiLangSingleton.windowsList[window].doc.string ++ "\n" ++ this ++ "\n"; + XiiLangSingleton.windowsList[window].doc.string = XiiLangSingleton.windowsList[window].doc.string ++ "\n" ++ this ++ "\n"; }.defer(0.3); }); } -} +} \ No newline at end of file diff --git a/XiiLangGUI.sc b/XiiLangGUI.sc index 313ae0a..3afaef4 100644 --- a/XiiLangGUI.sc +++ b/XiiLangGUI.sc @@ -16,9 +16,9 @@ XiiLangGUI { thisversion = 3; // this.addixiMenu; - projectsList = "ixilang/*".pathMatch.collect({arg n; n.basename}); + projectsList = (Platform.userAppSupportDir +/+ "ixilang/*").pathMatch.collect({arg n; n.basename}); projectname = projectnamearg ? projectsList[0]; - projectpath = "ixilang/"++projectname; + projectpath = Platform.userAppSupportDir +/+ "ixilang/"++projectname; filenames = (projectpath++"/samples/*").pathMatch; filenames = filenames.collect({arg file; file.basename}); filenames = filenames.reject({ |file| file.splitext[1] == "scd" }); // not including the keymapping files @@ -44,8 +44,8 @@ XiiLangGUI { .value_(projectsList.indexOfEqual(projectname)) .action_({arg view; projectname = projectsList[view.value] ; - projectpath = "ixilang/*".pathMatch[view.value]; - projectsList = "ixilang/*".pathMatch.collect({arg n; n.basename}); + projectpath = (Platform.userAppSupportDir +/+ "ixilang/*").pathMatch[view.value]; + projectsList = (Platform.userAppSupportDir +/+ "ixilang/*").pathMatch.collect({arg n; n.basename}); filenames = (projectpath++"/samples/*").pathMatch; filenames = filenames.collect({arg file; file.basename}); filenames = filenames.reject({ |file| file.splitext[1] == "scd" }); // not including the keymapping files @@ -136,7 +136,7 @@ XiiLangGUI { var ixiLangInstr; synthdesclib = SynthDescLib(projectname.asSymbol); - ("ixilang/"++projectname++"/synthdefs.scd").load; + (Platform.userAppSupportDir +/+ "ixilang/"++projectname++"/synthdefs.scd").load; SynthDescLib.read; synthdefnames = SynthDescLib.getLib(projectname.asSymbol).synthDescs.keys.asArray; if(Object.readArchive(projectpath++"/keyMapping.ixi").isNil, { diff --git a/XiiLangInstr.sc b/XiiLangInstr.sc index f8be453..4e4c51f 100644 --- a/XiiLangInstr.sc +++ b/XiiLangInstr.sc @@ -1,7 +1,7 @@ XiiLangInstr { - classvar instrDict; + classvar ("ixilang/"++project++"/synthdefs.scd").loadPath; // ---------------------------------------------------------------------------------- // --------------------------- unique project synthdefs ---------------------------- // ---------------------------------------------------------------------------------- synthdesclib = SynthDescLib(project.asSymbol); - ("ixilang/"++project++"/synthdefs.scd").load; // instead of loadPath + (XiiLang.ixiDir +/+project++"/synthdefs.scd").load; // instead of loadPath - // thisProcess.interpreter.executeFile("ixilang/"++project++"/synthdefs.scd"); - // was - > ("ixilang/"++project++"/synthdefs.scd").loadPath; + // thisProcess.interpreter.executeFile(XiiLang.ixiDir +/+project++"/synthdefs.scd"); + // was - > (XiiLang.ixiDir +/+project++"/synthdefs.scd").loadPath; @@ -59,7 +48,7 @@ XiiLangInstr { // ---------------------- sample based instruments ----------------------------- if(loadsamples, { - samplePaths = ("ixilang/"++project++"/samples/*").pathMatch; + samplePaths = (XiiLang.ixiDir +/+project++"/samples/*").pathMatch; //samplePaths = samplePaths.reject({ |path| path.basename.splitext[1] == "scd" }); // not including the keymapping files //samplePaths = samplePaths.reject({ |path| path.basename.splitext[1] == "ixi" }); // not including the keymapping files sampleNames = samplePaths.collect({ |path| path.basename.splitext[0]}); @@ -934,10 +923,10 @@ Pdef(\test, Pbind(\instrument, \clap, \midinote, Prand([1, 2, 5, 7, 9, 3], inf) // ---------------------------------------------------------------------------------- synthdesclib = SynthDescLib(project.asSymbol); - ("ixilang/"++project++"/synthdefs.scd").load; // instead of loadPath + (XiiLang.ixiDir +/+project++"/synthdefs.scd").load; // instead of loadPath - // thisProcess.interpreter.executeFile("ixilang/"++project++"/synthdefs.scd"); - // was - > ("ixilang/"++project++"/synthdefs.scd").loadPath; + // thisProcess.interpreter.executeFile(XiiLang.ixiDir +/+project++"/synthdefs.scd"); + // was - > (XiiLang.ixiDir +/+project++"/synthdefs.scd").loadPath; @@ -947,7 +936,7 @@ Pdef(\test, Pbind(\instrument, \clap, \midinote, Prand([1, 2, 5, 7, 9, 3], inf) // ---------------------- sample based instruments ----------------------------- if(loadsamples, { - samplePaths = ("ixilang/"++project++"/samples/*").pathMatch; + samplePaths = (XiiLang.ixiDir +/+project++"/samples/*").pathMatch; //samplePaths = samplePaths.reject({ |path| path.basename.splitext[1] == "scd" }); // not including the keymapping files //samplePaths = samplePaths.reject({ |path| path.basename.splitext[1] == "ixi" }); // not including the keymapping files sampleNames = samplePaths.collect({ |path| path.basename.splitext[0]}); @@ -1463,7 +1452,7 @@ Pdef(\test, Pbind(\instrument, \clap, \midinote, Prand([1, 2, 5, 7, 9, 3], inf) SynthDef(\deepdubsynth, {arg out=0, freq=220, amp=0.1, dur=1, gate=1, tmp=2, pan=0; var trig, note, son, sweep, bassenv, bd, sd, swr; var midinote, unienv; - ��� trig = Impulse.kr(tmp); + trig = Impulse.kr(tmp); midinote = freq.cpsmidi/2; @@ -1825,7 +1814,7 @@ Pdef(\test, Pbind(\instrument, \clap, \midinote, Prand([1, 2, 5, 7, 9, 3], inf) // else, the instrDict is created by mapping random sound files onto the letters var file; - if(Object.readArchive("ixilang/"++project++"/keyMapping.ixi").isNil, { + if(Object.readArchive(XiiLang.ixiDir +/+project++"/keyMapping.ixi").isNil, { instrDict = IdentityDictionary.new; [\A, \a, \B, \b, \C, \c, \D, \d, \E, \e, \F, \f, \G, \g, \H, \h, \I, \i, \J, \j, \K, \k, \L, \l, \M, \m, \N, \n, \O, \o, \P, \p, \Q, \q, \R, \r, \S, \s, \T, \t, @@ -1834,7 +1823,7 @@ Pdef(\test, Pbind(\instrument, \clap, \midinote, Prand([1, 2, 5, 7, 9, 3], inf) }); " ---> ixi lang : No key mappings were found, so samples will be randomly assigned to keys - see helpfile, or type 'new' and map the keys".postln; }, { - instrDict = Object.readArchive("ixilang/"++project++"/keyMapping.ixi"); + instrDict = Object.readArchive(XiiLang.ixiDir +/+project++"/keyMapping.ixi"); }); "The keys of your keyboard are mapped to the following samples :".postln; @@ -1848,8 +1837,8 @@ Pdef(\test, Pbind(\instrument, \clap, \midinote, Prand([1, 2, 5, 7, 9, 3], inf) createRecorderDoc {arg caller, numChan; // doccolor, oncolor, inbus=8; var doc, buffer, duration, recsynth, recording = false; - if(("ixilang/"++project++"/livesamples").pathMatch==[], { - ("mkdir -p" + ("ixilang/"++project++"/livesamples")).unixCmd; // create the samples folder + if((XiiLang.ixiDir +/+project++"/livesamples").pathMatch==[], { + ("mkdir -p" + (XiiLang.ixiDir +/+project++"/livesamples")).unixCmd; // create the samples folder "ixi-lang NOTE: a live samples folder was not found for saving scores - It was created".postln; }); "CREATING RECORDER".postln; @@ -1884,7 +1873,7 @@ Pdef(\test, Pbind(\instrument, \clap, \midinote, Prand([1, 2, 5, 7, 9, 3], inf) Server.default.sync(cond); buffer.copyData(tempbuf, 0, 0, duration * Server.default.sampleRate); Server.default.sync(cond); - tempbuf.write(("ixilang/"++project++"/livesamples/"++char++".aif"), "aiff", "int16"); + tempbuf.write((XiiLang.ixiDir +/+project++"/livesamples/"++char++".aif"), "aiff", "int16"); "WRITING BUFFER".postln; this.makeSynthDef(tempbuf, char, numChan); caller.updateInstrDict(char); diff --git a/XiiLangMatrix.sc b/XiiLangMatrix.sc index 07e1266..1cca477 100644 --- a/XiiLangMatrix.sc +++ b/XiiLangMatrix.sc @@ -57,6 +57,7 @@ XiiLangMatrix { // .promptToSave_(false) .keyDownAction_({arg doc, key, mod, unicode, keycode; var loc, loccol, locrow, selsize; + var returnVal = nil; [doc, key, mod, unicode, keycode].postln; loc = doc.selectionStart; @@ -67,18 +68,19 @@ XiiLangMatrix { if(loccol==size, {loccol = loccol-1}); {doc.parent.name_("matrix"+loccol.asString+locrow.asString)}.defer(0.1); -\deb0.postln; + \deb0.postln; + //matrix.postcs; + //instrDict.postcs; if(key.isNil.not, { if(key.isAlpha, { // all chars possible, no arrows and nums - if((doc.string[loc] == " "), { // no char into a space - \deb00.postln; - //doc.string_(" ", loc, 2); + if((doc.string[loc].asString == " "), { // no char into a space + doc.setString(" " ++ key.asSymbol, loc, 2); }, { - \deb01.postln; - //doc.string_("", loc, 1); + doc.setString("" ++ key.asSymbol, loc, 1); }); \deb1.postln; - if((mod == 2097152) || (mod == 131072) || (mod == 0) || (mod == 10486016), { // holding down fn (and optinally shift) opens a coding window + if((mod == 2097152) || (mod == 131072) || (mod == 10486016), + { // holding down fn (and optinally shift) opens a coding window \deb11.postln; if(matrix[locrow][loccol].instr == "none", { // just insert the synthdef from the instrDict @@ -89,7 +91,7 @@ XiiLangMatrix { }); \deb13.postln; - //codeDoc.value(loccol, locrow, key, true); // imposed key does not exist + codeDoc.value(loccol, locrow, key, true); // imposed key does not exist },{ // default is keys from instrDict (as mapped by instrDict) matrix[locrow][loccol].char = key; // parsing the code @@ -100,7 +102,7 @@ XiiLangMatrix { matrix[locrow][loccol].sccode = charDict[key.asSymbol].sccode; // [\code, matrix[locrow][loccol].sccode].postln; }); - matrixCopy = matrix.copy; + matrixCopy = matrix.copy.postln; // store the latest info in the charDict, so it will be set on next key charDict[key.asSymbol] = ().add(\instr -> matrix[locrow][loccol].instr) .add(\note -> matrix[locrow][loccol].note) @@ -108,6 +110,7 @@ XiiLangMatrix { .add(\wait -> matrix[locrow][loccol].wait) .add(\sccode -> matrix[locrow][loccol].sccode); }); + returnVal = true; }); \deb2.postln; if(key.isDecDigit, { // if number, then it sets the nextX or nextY (depending on direction) @@ -116,28 +119,33 @@ XiiLangMatrix { }, { matrix[locrow][loccol].nextY = key.asString.asInteger; }); + returnVal = true; }); if(key == $., { // full stop will remove instrument but keep timing and code - if((doc.string(loc) == " "), { // no char into a space - doc.string_(" ", loc, 2); + if((doc.string[loc].asString == " "), { // no char into a space + doc.setString(" " ++ key.asSymbol, loc, 2); }, { - doc.string_("", loc, 1); + doc.setString("" ++ key.asSymbol, loc, 1); }); matrix[locrow][loccol].instr = "none"; matrix[locrow][loccol].char = "."; + returnVal = true; }); if(selsize==1, { codeDoc.value(loccol, locrow, key, true); // force open the code window }); if(keycode == 48, { // use TAB to start a tempoclock start.value(loccol, locrow); + returnVal = true; }); if(keycode == 51, { // use DELETE to stop the last tempoclock clockArray.last.stop; - clockArray.removeAt(clockArray.size-1); + if(clockArray.size > 0, {clockArray.removeAt(clockArray.size-1);}); +returnVal = true; }); }); \deb3.postln; + returnVal; }) .onClose_({ clockArray.do({arg clock; clock.clear }); diff --git a/XiiLangRecord.sc b/XiiLangRecord.sc index e3e85ed..46bc2c9 100644 --- a/XiiLangRecord.sc +++ b/XiiLangRecord.sc @@ -3,24 +3,26 @@ XiiLangRecord { var