Chord thing, sorry for using an AI again for this as there could be some shoddy mistakes (still using my phone, gotta shower and eat food), I also like reading code from others that isn't mine but AIs don't easily impress me that much (too verbose, too simple, or doesn't think outside the box, can't correct certain mistakes that require visualization/hearing/runtime)… [code=javascript] //(16 Nov 2024 10:00) I asked o1 to write a chord progression interpreter. //I don't like using redundant spaces between tokens (but newlines and tab indentations are OK), it's better to be more concise and use ES6 tricks whenever possible. //(11:40) There were some issues with minor chords. Now it's “error: Cannot read properties of undefined (reading 'match')”… var PI=Math.PI,TAU=PI*2, noteNumbers={ "C":0, "C#":1,"Db":1, "D":2, "D#":3,"Eb":3, "E":4, "F":5, "F#":6,"Gb":6, "G":7, "G#":8,"Ab":8, "A":9, "A#":10,"Bb":10, "B":11 }; //parse a chord string into root note, modifiers, and bass note function parseChordString(chordStr){ /* //split the chord by slash to separate chord and bass note var parts=chordStr.split('/'), chordPart=parts[0], bassNote=parts[1]||null; */ //check if the chord contains a bass note var bassNoteMatch=chordStr.match(/\/([A-G][#b]?)$/), bassNote=null; if(bassNoteMatch){ bassNote=bassNoteMatch[1]; chordStr=chordStr.slice(0,chordStr.length-bassNoteMatch[0].length); //remove bass note part from chordStr } //extract the root note and modifiers from the chordStr var match=chordStr.match(/^([A-G][#b]?)(.*)$/); if(!match)throw new Error("Invalid chord: "+chordStr); var rootNote=match[1], modifiers=match[2]; return{ rootNote:rootNote, modifiers:modifiers, bassNote:bassNote }; } //function to parse chord modifiers into tokens function parseModifiers(modifiers){ let tokens=[], str=modifiers; while(str.length>0){ let matched=false, res; //match 'maj' with optional extension if(res=str.match(/^maj(7|9|11|13)?/)){ tokens.push('maj'); if(res[1])tokens.push(res[1]); str=str.substr(res[0].length); matched=true; } //match 'm' or 'min' with optional extension else if(res=str.match(/^m(in)?(7|9|11|13)?/)){ tokens.push('min'); if(res[2])tokens.push(res[2]); str=str.substr(res[0].length); matched=true; } //match 'dim' with optional '7' else if(res=str.match(/^dim(7)?/)){ tokens.push('dim'); if(res[1])tokens.push(res[1]); str=str.substr(res[0].length); matched=true; } //match 'aug' else if(res=str.match(/^aug/)){ tokens.push('aug'); str=str.substr(res[0].length); matched=true; } //match 'sus', 'sus2', 'sus4' else if(res=str.match(/^sus(2|4)?/)){ tokens.push('sus'+(res[1]||'')); str=str.substr(res[0].length); matched=true; } //match 'add' with optional alteration else if(res=str.match(/^add(#|b)?(\d+)/)){ tokens.push('add'); tokens.push((res[1]||'')+res[2]); str=str.substr(res[0].length); matched=true; } //match extensions like '13', '11', '9' else if(res=str.match(/^(13|11|9)/)){ tokens.push(res[1]); str=str.substr(res[1].length); matched=true; } //match alterations like '#5', 'b9' else if(res=str.match(/^([#b])(\d+)/)){ tokens.push(res[1]+res[2]); str=str.substr(res[0].length); matched=true; } //match '6/9' else if(res=str.match(/^6\/9/)){ tokens.push('6/9'); str=str.substr(4); matched=true; } //match '6', '7', '5' else if(res=str.match(/^(6|7|5)/)){ tokens.push(res[1]); str=str.substr(1); matched=true; } //skip unrecognized characters else{ str=str.substr(1); } } return tokens; } //helper function to get interval from scale degree var intervalsMap={1:0,2:2,3:4,4:5,5:7,6:9,7:11,9:14,11:17,13:21}; function getIntervalFromDegree(degree){return intervalsMap[degree]||0;} //function to get chord intervals based on modifiers function getChordIntervals(modifiers){ var tokens=parseModifiers(modifiers), intervals=[]; //start with basic triad var chordQuality='major'; //default if(tokens.includes('maj')){ chordQuality='major'; }else if(tokens.includes('min')){ chordQuality='minor'; }else if(tokens.includes('dim')){ chordQuality='diminished'; }else if(tokens.includes('aug')){ chordQuality='augmented'; } //build the basic triad intervals if(chordQuality=='major'){ intervals.push(0,4,7); }else if(chordQuality=='minor'){ intervals.push(0,3,7); }else if(chordQuality=='diminished'){ intervals.push(0,3,6); }else if(chordQuality=='augmented'){ intervals.push(0,4,8); } //handle sevenths if(tokens.includes('maj') && tokens.includes('7')){ intervals.push(11); }else if(tokens.includes('7')){ intervals.push(10); } //handle extensions if(tokens.includes('9')){ intervals.push(14); } if(tokens.includes('11')){ intervals.push(17); } if(tokens.includes('13')){ intervals.push(21); } //handle '6' and '6/9' if(tokens.includes('6/9')){ intervals.push(9,14); }else if(tokens.includes('6')){ intervals.push(9); } //handle added tones if(tokens.includes('add')){ tokens.filter(t=>t.startsWith('#')||t.startsWith('b')||/^\d+$/.test(t)).forEach(t=>{ var number=parseInt(t.replace('#','').replace('b','')), interval = getIntervalFromDegree(number); if(t.startsWith('#'))interval++; if(t.startsWith('b'))interval--; intervals.push(interval); }); } //handle suspensions if(tokens.includes('sus2')){ //replace the third with major 2nd var index=intervals.indexOf(chordQuality=='major'?4:3); if(index>=0)intervals[index]=2; }else if(tokens.includes('sus4')){ //replace the third with perfect 4th var index=intervals.indexOf(chordQuality=='major'?4:3); if(index>=0)intervals[index]=5; }else if(tokens.includes('sus')){ //replace the third with perfect 4th var index=intervals.indexOf(chordQuality=='major'?4:3); if(index>=0)intervals[index]=5; } //handle alterations tokens.forEach(t=>{ if(t=='#5'){ //replace the fifth with augmented fifth var index=intervals.indexOf(7); if(index>=0)intervals[index]=8; }else if(t=='b5'){ //replace the fifth with diminished fifth var index=intervals.indexOf(7); if(index>=0)intervals[index]=6; }else if(t=='#9'){ intervals.push(15); //sharp ninth }else if(t=='b9'){ intervals.push(13); //flat ninth }else if(t=='#11'){ intervals.push(18); //sharp eleventh }else if(t=='b13'){ intervals.push(20); //flat thirteenth } }); //remove duplicates and sort intervals intervals=intervals.filter((v,i,a)=>a.indexOf(v)===i); intervals.sort((a,b)=>a-b); return intervals; } function note(n,base=440,keys=12){return base*Math.pow(2,n/keys);} function sine(x){return Math.sin(TAU*x);} function pulse(x){return x%1<.5?-1:1;} //limit frequency within a given range function limitFrequency(freq,minFreq,maxFreq){ while(freqmaxFreq)freq/=2; return freq; } var chordDuration=2, //seconds per chord //chords="Amaj7sus2/Ab Gmaj7sus2 C69#11 Bm11 Ab7#5b9 Dbm11 Cmaj7b5/6 Abm11 F#m11".split(" "), chords="Gb7 Gmmaj7 Emmaj9 Ab9addb13/C Gbaug Bmaj9 Abm11 Dbm11 Gb7/#11 Dbmaj9sus2 Eb13sus4 Dbm9".split(" "), //chords="Am7 Dm9 Em11 Fmaj7 G7 Cmaj9".split(" "), totalChords = chords.length; return function dsp(t){ var out=0, chordIndex=Math.floor(t/chordDuration)%totalChords, chordTime=t%chordDuration, chordStr=chords[chordIndex], chord=parseChordString(chordStr), rootNote=chord.rootNote, modifiers=chord.modifiers, bassNote=chord.bassNote||chord.rootNote, intervals=getChordIntervals(modifiers), rootNoteNumber=noteNumbers[rootNote], //get the semitone offset from A4 (note number 9) semitoneOffset=rootNoteNumber-9, //calculate frequencies and sum the sine waves numNotes=intervals.length+1; //number of notes in the chord including bass for(var i=0;i[b]Error[/b] >Your post has too many lines. Fuck off.