class PianoRecorder{constructor(){this.isRecording=!1;this.recordedNotes=[];this.recordingStartTime=null;this.exportTempo=160;this.timeScale=0.5}
setTempo(bpm){this.exportTempo=bpm}
startRecording(){this.isRecording=!0;this.recordedNotes=[];this.recordingStartTime=performance.now()}
stopRecording(){this.isRecording=!1}
recordNote(key,note){if(!this.isRecording)return;const currentTime=performance.now();this.recordedNotes.push({key,note,time:currentTime-this.recordingStartTime,})}
playRecording(playTuneFn,onComplete){if(!this.recordedNotes.length)return;const referenceTempo=160;const tempoScale=referenceTempo/this.exportTempo;console.log(this.exportTempo);let startTime=performance.now();this.playingNotes=[];this.recordedNotes.forEach(note=>{const delay=Math.max(note.time*tempoScale,20);const timer=setTimeout(()=>{playTuneFn(note.key)},delay);this.playingNotes.push(timer)});const lastNoteTime=this.recordedNotes[this.recordedNotes.length-1].time;const totalTime=lastNoteTime*tempoScale;this.playbackTimer=setTimeout(()=>{this.playingNotes=[];this.playbackTimer=null;if(onComplete&&typeof onComplete==="function"){onComplete()}},totalTime+200)}
stopPlayback(){if(this.playbackTimer){clearTimeout(this.playbackTimer);this.playbackTimer=null}
if(this.playingNotes&&this.playingNotes.length){this.playingNotes.forEach(timer=>clearTimeout(timer));this.playingNotes=[]}}
downloadMidi(){if(!this.recordedNotes||!this.recordedNotes.length){alert("No notes recorded yet!");return}
const track=new MidiWriter.Track();const ppq=128;track.setTempo(this.exportTempo);track.setTimeSignature(4,4);track.addTrackName("Virtual Piano Track");track.addInstrumentName("Acoustic Grand Piano");let lastTimestamp=0;this.recordedNotes.forEach(note=>{const midiNote=this.noteToMidiNumber(note.note);const timeDiffMs=note.time-lastTimestamp;lastTimestamp=note.time;const ticks=Math.round(((timeDiffMs*this.timeScale)/1000)*(ppq*this.exportTempo/60));const noteEvent=new MidiWriter.NoteEvent({pitch:[midiNote],duration:'T'+ticks,wait:'T'+ticks});track.addEvent(noteEvent)});const writer=new MidiWriter.Writer(track);const midiData=writer.buildFile();const blob=new Blob([midiData],{type:'audio/midi'});const url=URL.createObjectURL(blob);const a=document.createElement('a');a.href=url;a.download='piano-recording.mid';a.click();URL.revokeObjectURL(url)}
noteToMidiNumber(note){const noteMap={'C':0,'C#':1,'D':2,'D#':3,'E':4,'F':5,'F#':6,'G':7,'G#':8,'A':9,'A#':10,'B':11};const baseMidi=60;return this.midiNumberToPitch(baseMidi+(noteMap[note]??0))}
midiNumberToPitch(midiNumber){const noteNames=['C','C#','D','D#','E','F','F#','G','G#','A','A#','B'];const note=noteNames[midiNumber%12];const octave=Math.floor(midiNumber/12)-1;return note+octave}}
const pianoRecorder=new PianoRecorder();window.pianoRecorder=pianoRecorder