40 => int NUM_ATTEMPTS; 13 => int K; 333::ms => dur BEAT_MS; 1000::ms => dur PAUSE_MS; // tokenizer StringTokenizer tok; // line string line[0]; // sound 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; Word2Vec syllables; // loading any default here "glove-50.txt" => string filepath; <<< "loading glove50 model:", filepath, "..." >>>; model.load( filepath ); <<< "loading syllables model:", "syllables.txt", "..." >>>; syllables.load( "syllables.txt" ); // default file me.sourceDir() + "sonnet106.txt" => string filename; // look at command line if( me.args() > 0 ) me.arg(0) => filename; // instantiate FileIO fio; // open a file fio.open( filename, FileIO.READ ); // ensure it's ok if( !fio.good() ) { cherr <= "can't open file: " <= filename <= " for reading..." <= IO.newline(); me.exit(); } // loop until end while( fio.more() ) { // get it tok.set( fio.readLine() ); // print tokens 0 => int syl; while( tok.more() ) { // print it processToken(tok.next().lower(), syl) => syl; } endOfLine(); } // take in token and current syllable fun int processToken(string token, int syl) { W2V.eval( model, token, K) @=> string words[]; [10.0] @=> float sylToken[]; syllables.getVector(token, sylToken); [10.0] @=> float sylTest[]; 0 => int wordFound; for (0 => int i; i < NUM_ATTEMPTS; i++) { Math.random2(0, K - 1) => int i; // trivially reject self in output if( words[i] == token || words[i].find(".") >=0 || words[i].find(",") >= 0 || words[i].find("'") == 0 || words[i].find("?") >= 0 || words[i].find("!") >= 0 ) continue; syllables.getVector(words[i], sylTest); if ( sylTest[0] != sylToken[0] ) { continue; } 1 => wordFound; chout <= words[i]; break; } if ( !wordFound ) { chout <= token; } chout <= " "; chout.flush(); playWord(syl, sylToken[0] $ int); return syl + sylToken[0] $ int; } fun void playWord(int start, int num_syls) { // Assumes iambic pentameter for ( 0 => int i; i < num_syls; i++ ) { ((start + i) % 2) => int bigBeat; 55 + 5 * bigBeat => int pitch; pitch => Std.mtof => crystal.freq; .5 + .3 * bigBeat => crystal.noteOn; BEAT_MS * (1 + bigBeat) => now; } } fun void endOfLine() { PAUSE_MS => now; chout <= IO.newline(); } // 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; } }