// make a ConsoleInput ConsoleInput in; // tokenizer StringTokenizer tok; // line string line[0]; // pitches [ 0, 0, 0, 0 ] @=> int pitches[]; // seed word "nothing" => string seedWord; // program close Event endEvent; 0 => int endSignal; // TODO: read from the pitches array every T seconds // play corresponding chord // generate poem based on chord "quality" // write instructions // write reflection // sound 250::ms => dur BEAT_MS; 1000::ms => dur MEASURE_MS; 10 => int K; ModalBar crystal => Gain left => dac.left; crystal => Gain right => dac.right; 1 => crystal.preset; // feedback delay for echos left => DelayL DL => left; .5 => DL.gain; BEAT_MS*1.5 => DL.max => DL.delay; right => DelayL DR => right; .3 => DR.gain; BEAT_MS*2 => DR.max => DR.delay; // our default model Word2Vec model; // loading any default here "glove-50.txt" => string filepath; model.load( filepath ); spork ~ printWords(); spork ~ playChord(); info(); // loop while( true ) { // prompt in.prompt() => now; // read while( in.more() ) { // get it tok.set( in.getLine() ); // print tokens while( tok.more() ) { tok.next() => string curr; if (curr.lower() == "q") { 1 => endSignal; endEvent => now; me.exit(); } // print it handleChord(curr); } } } fun void handleChord(string chord) { trim(chord) => chord; if (!chord.length() || chord.length() > 3) return; chord.substring(0, 1) => string root; "n" => string accidental; "" => string seventh; if (chord.length() == 2) { chord.substring(1).lower() => string tmp; if (tmp == "f" || tmp == "s" || tmp == "b" || tmp == "#") { tmp => accidental; } else { tmp => seventh; } } else if (chord.length() == 3) { chord.substring(1, 1).lower() => accidental; chord.substring(2).lower() => seventh; } chord2pitches( pitches, root, accidental, seventh ); } fun string trim(string chord) { return chord.rtrim().ltrim(); } fun void chord2pitches( int result[], string pitch, string accidental, string seventh ) { pitch.lower().charAt(0) - 51 => int root; if (accidental == "f" || accidental == "b") { 1 -=> root; } else if (accidental == "s" || accidental == "#") { 1 +=> root; } pitch.lower() == pitch || seventh == "-" || seventh == "h" || seventh == "d" => int minor; minor && seventh != "+" => minor; seventh == "+" => int augmented; seventh == "h" || seventh == "d" || seventh == "-" => int diminished; seventh == "d" => int diminishedSeventh; seventh == "m" => int majorSeventh; seventh == "7" || seventh == "h" => int minorSeventh; root => result[0]; root + 4 - minor => result[1]; root + 7 + augmented - diminished => result[2]; root + 12 - majorSeventh - (2 * minorSeventh) - (3 * diminishedSeventh) => result[3]; setSeedWord( pitch.lower(), minor, diminished, augmented, minorSeventh, majorSeventh, diminishedSeventh ); } fun void printWords() { while ( true ) { // <<< "this is a test" >>>; 3::second => now; } } fun void setSeedWord( string pitch, int minor, int diminished, int augmented, int minorSeventh, int majorSeventh, int diminishedSeventh ) { if (pitch == "a") { if (minor) { "authentic" => seedWord; if (diminished) { "anxious" => seedWord; } if (diminishedSeventh) { "acrimonious" => seedWord; } if (majorSeventh) { "alert" => seedWord; } if (minorSeventh) { "artistic" => seedWord; } } else { "attentive" => seedWord; if (augmented) { "aimless" => seedWord; } if (majorSeventh) { "animated" => seedWord; } if (minorSeventh) { "active" => seedWord; } } } if (pitch == "b") { if (minor) { "boring" => seedWord; if (diminished) { "belittling" => seedWord; } if (diminishedSeventh) { "beautiful" => seedWord; } if (majorSeventh) { "batty" => seedWord; } if (minorSeventh) { "basic" => seedWord; } } else { "benign" => seedWord; if (augmented) { "busy" => seedWord; } if (majorSeventh) { "bashful" => seedWord; } if (minorSeventh) { "bold" => seedWord; } } } if (pitch == "c") { if (minor) { "cool" => seedWord; if (diminished) { "calculating" => seedWord; } if (diminishedSeventh) { "creepy" => seedWord; } if (majorSeventh) { "crazy" => seedWord; } if (minorSeventh) { "colorful" => seedWord; } } else { "calming" => seedWord; if (augmented) { "cute" => seedWord; } if (majorSeventh) { "charming" => seedWord; } if (minorSeventh) { "cresting" => seedWord; } } } if (pitch == "d") { if (minor) { "dreary" => seedWord; if (diminished) { "dreadful" => seedWord; } if (diminishedSeventh) { "diminished" => seedWord; } if (majorSeventh) { "dashing" => seedWord; } if (minorSeventh) { "dense" => seedWord; } } else { "dapper" => seedWord; if (augmented) { "dangerous" => seedWord; } if (majorSeventh) { "dauntless" => seedWord; } if (minorSeventh) { "dramatic" => seedWord; } } } if (pitch == "e") { if (minor) { "even" => seedWord; if (diminished) { "evil" => seedWord; } if (diminishedSeventh) { "extra" => seedWord; } if (majorSeventh) { "effervescent" => seedWord; } if (minorSeventh) { "exemplary" => seedWord; } } else { "endearing" => seedWord; if (augmented) { "efficacious" => seedWord; } if (majorSeventh) { "equable" => seedWord; } if (minorSeventh) { "emotive" => seedWord; } } } if (pitch == "f") { if (minor) { "fickle" => seedWord; if (diminished) { "frugal" => seedWord; } if (diminishedSeventh) { "frustrating" => seedWord; } if (majorSeventh) { "flippant" => seedWord; } if (minorSeventh) { "fabulous" => seedWord; } } else { "fun" => seedWord; if (augmented) { "frisky" => seedWord; } if (majorSeventh) { "friendly" => seedWord; } if (minorSeventh) { "fulfilling" => seedWord; } } } if (pitch == "g") { if (minor) { "gentle" => seedWord; if (diminished) { "ghostly" => seedWord; } if (diminishedSeventh) { "gabby" => seedWord; } if (majorSeventh) { "goofy" => seedWord; } if (minorSeventh) { "gleaming" => seedWord; } } else { "great" => seedWord; if (augmented) { "gabby" => seedWord; } if (majorSeventh) { "golden" => seedWord; } if (minorSeventh) { "glorified" => seedWord; } } } } fun void playChord() { until ( endSignal ) { if (!pitches[0]) { MEASURE_MS => now; if (endSignal) { endEvent.signal(); } continue; } int tmp[4]; seedWord => string printout; for (0 => int i; i < pitches.size(); i++) { pitches[i] => tmp[i]; } <<< "this chord is", "" >>>; for (0 => int j; j < 4; j++) { <<< printout, "" >>>; Math.random2(1, K - 1) => int selection; W2V.eval(model, printout, K)[selection] => printout; for (0 => int i; i < tmp.size(); i++) { tmp[i] => Std.mtof => crystal.freq; .7 - .15 * i => crystal.noteOn; BEAT_MS => now; } } if (endSignal) { tmp[0] => Std.mtof => crystal.freq; .7 => crystal.noteOn; MEASURE_MS => now; <<< "And now silence", "" >>>; MEASURE_MS => now; endEvent.signal(); } } } fun void info() { <<< "", "" >>>; <<< "Do you want to ascribe an arbitrary word to a chord", "" >>>; <<< "based on its base pitch and quality? Now, you can do", "" >>>; <<< "with the help of AI!", "" >>>; <<< "", "" >>>; <<< "To get started, type any chord you'd like. Here's a guide:", "" >>>; <<< " Pitch character:", "" >>>; <<< " Chord root: a-g (lowercase is minor, uppercase is major)", "" >>>; <<< " Accidental character:", "" >>>; <<< " Flat modifier: b or f", "" >>>; <<< " Sharp modifier: # or s", "" >>>; <<< " (Omit this for natural/no modifier)", "" >>>; <<< " Quality character:", "" >>>; <<< " Augmented: + Diminished: -", "" >>>; <<< " HalfDim: h FullDim: d", "" >>>; <<< " Major 7th: m Minor 7th: 7", "" >>>; <<< "For example, C# fully diminished would be typed as \"csd\"", "" >>>; <<< "", "" >>>; <<< "Keep on typing new chords, the poem will respond at the next phrase.", "" >>>; <<< "To quit, enter q at any time. The poem will end gracefully.", "" >>>; } // word2vec helper class W2V { fun static void copy( float to[], float from[] ) { to.size(from.size()); // add into element for( int i; i < to.size(); i++ ) from[i] => to[i]; } fun static float[] dup( float from[] ) { float to[from.size()]; // add into element for( int i; i < to.size(); i++ ) from[i] => to[i]; // return return to; } // result stored in x fun static void add( float x[], float y[] ) { // smaller of the two x.size() < y.size() ? x.size() : y.size() => int size; // add into element for( int i; i < size; i++ ) y[i] +=> x[i]; } // result stored in x fun static void minus( float x[], float y[] ) { // smaller of the two x.size() < y.size() ? x.size() : y.size() => int size; // add into element for( int i; i < size; i++ ) y[i] -=> x[i]; } fun static void scale( float x[], float scalar ) { // scale for( int i; i < x.size(); i++ ) scalar *=> x[i]; } fun static void scale( float result[], float x[], float scalar ) { // scale for( int i; i < x.size(); i++ ) scalar * x[i] => result[i]; } fun static string[] eval( Word2Vec @ w, string expr, int k ) { // init int pos; 1.0 => float multiplier; string word; float wordVector[w.dim()]; float exprVector[w.dim()]; // compute while( true ) { expr.find(" ") => pos; if( pos == -1 ) { w.getVector(expr, wordVector); for( 0 => int i; i < w.dim(); i++ ) { wordVector[i] * multiplier +=> exprVector[i]; } break; } else { expr.substring(0, pos) => word; w.getVector(word, wordVector); for( 0 => int i; i < w.dim(); i++ ) { wordVector[i] * multiplier +=> exprVector[i]; } expr.substring(pos + 1) => expr; if( expr.charAt(0) == '+' ) { 1.0 => multiplier; expr.substring(2) => expr; } else { -1.0 => multiplier; expr.substring(2) => expr; } } } // return string results[k]; w.getSimilar( exprVector, k, results ); return results; } // logical analogy: A to B is as C is to [what this function returns] fun static string[] analogy( Word2Vec @ w, string A, string B, string C, int k ) { // the vector sum B + " - " + A + " + " + C => string v; return eval( w, v, k ); } fun static string[] antonym( Word2Vec @ w, string A, int k ) { float wordVector[w.dim()]; float newVector[w.dim()]; w.getVector(A, wordVector); 0 => float running_total; // wordVector[1] => newVector[0]; // -1 * wordVector[0] => newVector[1]; for( 0 => int i; i < w.dim() - 1; i++ ) { wordVector[i] * wordVector[i] +=> running_total; wordVector[i] => newVector[i]; } running_total * -1.0 / wordVector[w.dim() - 1] => newVector[w.dim() - 1]; // return string results[k]; w.getSimilar( newVector, k, results ); <<< wordVector[0], wordVector[1], "", newVector[0], newVector[1] >>>; return results; } }