Skip to content

Commit

Permalink
updates
Browse files Browse the repository at this point in the history
  • Loading branch information
mayarajan3 committed Jul 22, 2024
1 parent 9fbf0d6 commit b5351dd
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 138 deletions.
181 changes: 45 additions & 136 deletions extensions/src/music_generation/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,51 +72,16 @@ export default class ExtensionNameGoesHere extends extension(details, "ui") {

userEnteredNotes;
userChordProgression: string[];
lastTime: number;
generatedNotes;
originalMelody;
currentBeat;
rnn;
musicInstance;
generated;


// setNotes(notes) {
// this.generatedNotes = notes;
// console.log(this.generatedNotes);
// }

// setSequence(notes) {
// this.originalMelody = notes;
// }

// quantizeNotes(notes, stepsPerQuarter, tempo = getTransport().bpm.value) {
// // Calculate the step duration based on steps per quarter and tempo
// const quartersPerMinute = tempo;
// const quartersPerSecond = quartersPerMinute / 60;
// const stepDuration = 1 / (stepsPerQuarter * quartersPerSecond); // Duration of each step in seconds

// // Function to quantize a single note
// function quantizeNote(note) {
// const quantizedStartStep = Math.round(note.startTime / stepDuration);
// const quantizedEndStep = Math.round(note.endTime / stepDuration);
// return {
// pitch: note.pitch,
// quantizedStartStep,
// quantizedEndStep
// };
// }

// // Quantize each note in the list
// const quantizedNotes = notes.map(quantizeNote);

// return quantizedNotes;
// }

modelLoaded;

async loadModel() {
this.rnn = new mm.MusicRNN('https://storage.googleapis.com/magentadata/js/checkpoints/music_rnn/chord_pitches_improv');
await this.rnn.initialize();
this.modelLoaded = true;
return this.rnn;
}

Expand All @@ -126,8 +91,6 @@ export default class ExtensionNameGoesHere extends extension(details, "ui") {


async generateMusic() {
console.log("user entered notes");
console.log(this.userEnteredNotes);
const unquantizedSequence: mm.INoteSequence = {
notes: this.userEnteredNotes,
totalTime: this.userEnteredNotes[this.userEnteredNotes.length - 1].endTime,
Expand All @@ -147,113 +110,37 @@ export default class ExtensionNameGoesHere extends extension(details, "ui") {
//return [];

const continuedSequence = await this.rnn.continueSequence(quantizedSequence, 40, 1.0, ['C', 'G', 'Am', 'F']);
console.log(continuedSequence.notes);
this.generated = continuedSequence.notes;
return continuedSequence.notes;
}



init(env: Environment) {
this.generated = [];
this.musicInstance = new Music();
this.musicInstance.init(this.runtime);
this.currentBeat = 0;
this.userEnteredNotes = [];
this.lastTime = 0;
this.generatedNotes = [];
this.userChordProgression = [];
this.originalMelody = [];
console.log(this.runtime);
this.modelLoaded = false;
this.loadModel();

}


// @(scratch.command`Add note at pitch ${"number"} with start time ${"number"} and end time ${"number"}`)
// addNote(pitch: number, startTime: number, endTime: number) {
// this.userEnteredNotes.push({ pitch: pitch, startTime: startTime, endTime: endTime });
// if (endTime > this.lastTime) {
// this.lastTime = endTime;
// }
// }

// @(scratch.command`Add chord ${"string"} to progression`)
// addChord(chord: string) {
// this.userChordProgression.push(chord);
// }

@(scratch.command`Generate song from played notes`)
async generateSong(util: BlockUtilityWithID) {
//this.openUI("UI")
console.log(util);
console.log(this.userEnteredNotes);
await this.generateMusic();
}

// midiToFrequency(midiNote: number): number {
// return 440 * Math.pow(2, (midiNote - 69) / 12);
// }

playbackCompleted = true;
startTime = 0;
// playUserEnteredNotes(notes): number {
// console.log(notes);
// if (getTransport().now() > this.startTime) {
// this.startTime = getTransport().now();
// }
// let lastSeconds = 0;
// this.playbackCompleted = false;
// const synth = new Synth({
// oscillator: {
// type: "amtriangle",
// harmonicity: 0.5,
// modulationType: "sine",
// },
// envelope: {
// attackCurve: "exponential",
// attack: 0.05,
// decay: 0.2,
// sustain: 0.2,
// release: 1.5,
// },
// portamento: 0.05,
// }).toDestination();

// notes.forEach(note => {
// getTransport().schedule((time) => {
// synth.triggerAttackRelease(this.midiToFrequency(note.pitch), `${(note.quantizedEndStep - note.quantizedStartStep) / 8}n`, time);
// }, this.startTime + note.quantizedStartStep / 8);
// if ((this.startTime + note.quantizedStartStep / 8 + (note.quantizedEndStep - note.quantizedStartStep) / 8 + 1) > lastSeconds) {
// lastSeconds = this.startTime + note.quantizedStartStep / 8 + (note.quantizedEndStep - note.quantizedStartStep) / 8 + 1;
// }
// });
// return lastSeconds;

// }


// @(scratch.command`Play generated song`)
// playNotes() {
// let lastSeconds = this.playUserEnteredNotes(this.generatedNotes);
// this.startTime = lastSeconds;
// }

// @(scratch.command`Play original song`)
// playOriginalSong() {
// let lastSeconds = this.playUserEnteredNotes(this.originalMelody);
// this.startTime = lastSeconds;
// }

@(scratch.command`Play note at pitch ${"number"} for ${"number"}`)
playNoteBlock(pitch: number, beats: number, util: BlockUtilityWithID) {
console.log("util");
console.log(util);
if (this.musicInstance._stackTimerNeedsInit(util)) {
let note = pitch;
note = Math.min(Math.max(note, 0), 130);
beats = Math.min(Math.max(beats, 0), 100);
// If the duration is 0, do not play the note. In Scratch 2.0, "play drum for 0 beats" plays the drum,
// but "play note for 0 beats" is silent.
if (beats === 0) return;
const durationSec = this.musicInstance._beatsToSec(beats);
Expand All @@ -262,13 +149,10 @@ export default class ExtensionNameGoesHere extends extension(details, "ui") {
this.musicInstance._startStackTimer(util, durationSec);
let oneNote = { pitch: pitch, startTime: this.currentBeat, endTime: this.currentBeat + beats };
this.currentBeat += beats;
this.userEnteredNotes.push(oneNote);
this.startTime = this.currentBeat;
} else {
Expand All @@ -288,11 +172,11 @@ export default class ExtensionNameGoesHere extends extension(details, "ui") {
console.log(sequenceNotes);
for (let i = 0; i < sequenceNotes.length; i++) {
let note = sequenceNotes[i];
let beats = note.endBeat - note.startBeat;
// Play the note
let beats = Math.min(Math.max(note.beats, 0), 100);
note = Math.min(Math.max(note.pitch, 0), 130);
beats = Math.min(Math.max(beats, 0), 100);
// If the duration is 0, do not play the note. In Scratch 2.0, "play drum for 0 beats" plays the drum,
// but "play note for 0 beats" is silent.
if (beats === 0) return;
Expand All @@ -307,9 +191,47 @@ export default class ExtensionNameGoesHere extends extension(details, "ui") {
}
}
@(scratch.reporter`Show generated notes`)
returnGeneratedPitches() {
return this.musicInstance.convertToBeats(this.generated).map((note: any) => note.pitch);
}
@(scratch.command`Play note ${"number"} of generated notes`)
async playGeneratedNote(index: number, util: BlockUtilityWithID) {
console.log("here");
util.stackFrame.timer = null;
let sequenceNotes = this.musicInstance.convertToBeats(this.generated);
console.log(sequenceNotes);
let note = sequenceNotes[index];
console.log(note);
// Play the note
let beats = Math.min(Math.max(note.beats, 0), 100);
note = Math.min(Math.max(note.pitch, 0), 130);
// If the duration is 0, do not play the note. In Scratch 2.0, "play drum for 0 beats" plays the drum,
// but "play note for 0 beats" is silent.
if (beats === 0) return;
const durationSec = this.musicInstance._beatsToSec(beats);
this.musicInstance._playNote(util, note, durationSec);
console.log(durationSec);
// Wait for the note duration before playing the next one
await this.delay(durationSec);
}
@(scratch.reporter`Beats ${"number"} to seconds`)
beatsToSeconds(beats: number) {
return this.musicInstance._beatsToSec(beats);
}
@(scratch.command`Start model`)
async startModel() {
await this.loadModel();
if (!this.modelLoaded) {
await this.loadModel();
}
this.userEnteredNotes = [];
this.currentBeat = 0;
}
Expand All @@ -330,17 +252,4 @@ export default class ExtensionNameGoesHere extends extension(details, "ui") {
console.log(volume);
this.musicInstance.setInstrument(volume);
}
// @(scratch.command`Play note at pitch ${"number"} from ${"number"} to ${"number"}`)
// playNote(pitch: number, startTime: number, endTime: number) {
// let oneNote = [
// { pitch: pitch, startTime: startTime, endTime: endTime }
// ]
// console.log(this.quantizeNotes(oneNote, 4));
// let lastSeconds = this.playUserEnteredNotes(this.quantizeNotes(oneNote, 4));
// this.startTime = lastSeconds;
// }



}
3 changes: 1 addition & 2 deletions extensions/src/music_generation/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,7 @@ export class Music {
convertToBeats(sequence, stepsPerBeat = 4) {
return sequence.map(note => ({
pitch: note.pitch,
startBeat: note.quantizedStartStep / stepsPerBeat,
endBeat: note.quantizedEndStep / stepsPerBeat
beats: (note.quantizedEndStep - note.quantizedStartStep) / stepsPerBeat
}));
}

Expand Down

0 comments on commit b5351dd

Please sign in to comment.