xxxxxxxxxx
459
let isAudioRecording = false;
let soundRecorder, soundFile;
let isMarkovChainProcessed = false;
let recordButton;
let isRecording = false;
let startTime;
let recordedNotes = [];
let recordingStartTime;
let isPlayingBack = false;
let playbackStartTime;
let osc;
let keyStates = {};
let originalRecordedNotes = [];
let notes = {
A: 261.63, // C
W: 277.18, // C#
S: 293.66, // D
E: 311.13, // D#
D: 329.63, // E
F: 349.23, // F
T: 369.99, // F#
G: 392.0, // G
Y: 415.3, // G#
H: 440.0, // A
U: 466.16, // A#
J: 493.88, // B
K: 523.25, // C
};
function setup() {
createCanvas(400, 400);
osc = new p5.Oscillator();
osc.setType("sine");
osc.amp(0);
osc.start();
soundRecorder = new p5.SoundRecorder();
soundRecorder.setInput(osc);
soundFile = new p5.SoundFile();
for (let key in notes) {
keyStates[key] = false;
}
let recordButton = createButton("Record");
recordButton.mousePressed(startRecording);
let playButton = createButton("Play");
playButton.mousePressed(startPlayback);
let exportAudioButton = createButton('Export Audio');
exportAudioButton.mousePressed(exportAudio);
let markovButton = createButton("Markov Chain");
markovButton.mousePressed(applyMarkovChain);
let exportMarkovAudioButton = createButton('Export Markov Chain'); //NOT WORKING
exportMarkovAudioButton.mousePressed(exportMarkovChainAudio);
}
function draw() {
background(220);
drawPianoKeys();
if (isPlayingBack) {
playbackRecordedNotes();
}
//Markov Chain transitions
if (isMarkovChainProcessed) {
drawMarkovChainLines();
}
// markov done rect
if (isMarkovChainProcessed) {
fill(0, 0, 255); // Blue
rect(width - 50, height - 50, 40, 40); //blue rect
}
drawNoteTimeline();
}
function startRecordingAudio() {
soundRecorder.record(soundFile);
isAudioRecording = true;
startPlayback();
}
function stopRecordingAudio() {
soundRecorder.stop();
setTimeout(function() {
if (soundFile && soundFile.duration() > 0) {
soundFile.save('mySound', 'wav');
} else {
console.log('No audio was recorded.');
}
isAudioRecording = false;
}, 500); // Adjust this timeout as necessary
}
function exportAudio() {
if (!isAudioRecording) {
// Start recording
soundRecorder.record(soundFile);
isAudioRecording = true;
// Start playback
startPlayback();
} else {
// Stop recording
soundRecorder.stop();
soundFile.save('playback', 'wav');
isAudioRecording = false;
}
}
function exportMarkovChainAudio() {
if (!isAudioRecording) {
applyMarkovChain(); // Apply the Markov chain
startRecordingAudio(); // Then start recording
} else {
// If already recording, this will stop and save the recording
stopRecordingAudio();
}
}
function drawNoteTimeline() {
// existing code
for (let i = 0; i < recordedNotes.length; i++) {
let note = recordedNotes[i];
if (typeof note.duration === 'undefined') {
console.error("Missing duration for note", note);
note.duration = 500; // set a default duration if missing
}
// existing code to draw the timeline
}
}
// Function to draw lines representing Markov Chain transitions
function drawMarkovChainLines() {
/*
let markovModel = generateMarkovChain();
stroke(0, 102, 153); // Set the color for the lines
for (let note in markovModel) {
let startPos = getNotePosition(note); // Get the start position of the line
for (let nextNote in markovModel[note]) {
let endPos = getNotePosition(nextNote); // Get the end position of the line
let probability = markovModel[note][nextNote]; // Probability of transition
strokeWeight(probability * 5); // Line thickness based on probability
// Define control points for the Bezier curve
let controlPoint1 = createVector(startPos.x, startPos.y - 100);
let controlPoint2 = createVector(endPos.x, endPos.y - 100);
noFill();
bezier(startPos.x, startPos.y, controlPoint1.x, controlPoint1.y, controlPoint2.x, controlPoint2.y, endPos.x, endPos.y);
}
}
*/
}
function getNotePosition(note) {
let x, y;
let whiteKeyWidth = 40;
let blackKeyWidth = 20;
let blackKeyOffset = 30; // Offset for the black key from the start of the white key
let startY = 100; // Y position of keys (as per your drawPianoKeys function)
let keyHeight = 160; // Height of the keys
// Define the order of the keys on the piano
let whiteKeysOrder = ["A", "S", "D", "F", "G", "H", "J", "K"];
let blackKeysOrder = ["W", "E", "T", "Y", "U"];
let whiteKeyIndex = whiteKeysOrder.indexOf(note);
let blackKeyIndex = blackKeysOrder.indexOf(note);
if (whiteKeyIndex != -1) {
// It's a white key
x = 20 + whiteKeyWidth * whiteKeyIndex + whiteKeyWidth / 2; // Center of the white key
y = startY + keyHeight / 2; // Middle of the key height
} else if (blackKeyIndex != -1) {
// It's a black key
x = 20 + blackKeyOffset + whiteKeyWidth * blackKeyIndex + blackKeyWidth / 2; // Center of the black key
y = startY + keyHeight / 2; // Middle of the key height
} else {
// If the note is not found, return a default position
x = -1;
y = -1;
}
return createVector(x, y);
}
function drawPianoKeys() {
//white keys
let whiteKeys = ["A", "S", "D", "F", "G", "H", "J", "K"];
for (let i = 0; i < whiteKeys.length; i++) {
let key = whiteKeys[i];
fill(keyStates[key] ? "rgb(255,97,0)" : "white");
rect(20 + 40 * i, 100, 40, 160);
}
//black keys
let blackKeys = ["W", "E", "T", "Y", "U"];
let blackKeyOffsets = [30, 70, 150, 190, 230];
for (let i = 0; i < blackKeys.length; i++) {
let key = blackKeys[i];
fill(keyStates[key] ? "rgb(255,97,0)" : "black");
rect(blackKeyOffsets[i] + 20, 100, 20, 100);
}
}
/*function startRecording() {
if (!isRecording) {
recordedNotes = [];
isRecording = true;
recordingStartTime = millis();
setTimeout(() => {
isRecording = false;
stopRecordingAudio();
}, 20000);
startRecordingAudio();
}
}*/
function startRecording() {
if (!isRecording) {
recordedNotes = [];
isRecording = true;
recordingStartTime = millis();
soundRecorder.record(soundFile); // Start recording audio
// Set a timeout to stop recording after 10 seconds
setTimeout(function() {
if (isRecording) {
isRecording = false;
stopRecordingAudio(); // Call stopRecordingAudio to handle the end of recording
}
}, 10000); // 10 seconds in milliseconds
console.log("Recording Started");
}
}
function keyPressed() {
let freq = notes[key.toUpperCase()];
if (freq) {
keyStates[key.toUpperCase()] = true;
osc.freq(freq);
osc.amp(0.5, 0.1);
if (isRecording) {
recordedNotes.push({
note: key.toUpperCase(),
startTime: millis(),
freq: freq,
// Duration will be calculated on key release
});
}
}
}
function keyReleased() {
let freq = notes[key.toUpperCase()];
if (freq) {
keyStates[key.toUpperCase()] = false;
osc.amp(0, 0.1);
if (isRecording) {
let noteIndex = recordedNotes.findIndex(n => n.freq === freq && n.duration === undefined);
if (noteIndex !== -1) {
recordedNotes[noteIndex].duration = millis() - recordedNotes[noteIndex].startTime;
}
}
}
}
function startPlayback() {
if (!isPlayingBack && recordedNotes.length > 0) {
playbackStartTime = millis();
isPlayingBack = true;
// Reset 'isPlaying' state for each note
for (let note of recordedNotes) {
note.isPlaying = false;
}
}
}
function playbackRecordedNotes() {
let currentTime = millis() - playbackStartTime;
let currentNoteIndex = -1; // Declare currentNoteIndex at the beginning of the function
for (let i = 0; i < recordedNotes.length; i++) {
let note = recordedNotes[i];
let noteStart = note.startTime;
let noteEnd = noteStart + note.duration;
if (currentTime >= noteStart && currentTime <= noteEnd) {
if (!note.isPlaying) {
osc.freq(note.freq);
osc.amp(0.5, 0.1);
note.isPlaying = true;
}
currentNoteIndex = i; // Update currentNoteIndex for the currently playing note
} else if (note.isPlaying) {
osc.amp(0, 0.1);
note.isPlaying = false;
}
}
// Check if the playback of all notes is complete
if (currentNoteIndex == recordedNotes.length - 1 || currentNoteIndex == -1) {
isPlayingBack = false;
// Additional logic to handle the end of playback, if necessary
}
}
function drawBezierCurveForNotes(currentNoteName, nextNoteName) {
let startPos = getNotePosition(currentNoteName);
let endPos = getNotePosition(nextNoteName);
stroke(0, 102, 153);
strokeWeight(2);
let controlPointHeight = 150;
let controlPoint1 = createVector(
(startPos.x + endPos.x) / 2,
startPos.y - controlPointHeight
);
let controlPoint2 = createVector(
(startPos.x + endPos.x) / 2,
endPos.y - controlPointHeight
);
noFill();
bezier(
startPos.x,
startPos.y,
controlPoint1.x,
controlPoint1.y,
controlPoint2.x,
controlPoint2.y,
endPos.x,
endPos.y
);
}
//key from freq
function getKeyFromFrequency(freq) {
for (let key in notes) {
if (notes[key] === freq) {
return key;
}
}
return null;
}
function generateMarkovChain() {
let markovModel = {};
for (let i = 0; i < recordedNotes.length - 1; i++) {
let currentNote = recordedNotes[i].note;
let nextNote = recordedNotes[i + 1].note;
if (!markovModel[currentNote]) {
markovModel[currentNote] = {};
}
if (!markovModel[currentNote][nextNote]) {
markovModel[currentNote][nextNote] = 0;
}
markovModel[currentNote][nextNote] += 1;
}
//count to probabilities
for (let currentNote in markovModel) {
let total = 0;
for (let nextNote in markovModel[currentNote]) {
total += markovModel[currentNote][nextNote];
}
for (let nextNote in markovModel[currentNote]) {
markovModel[currentNote][nextNote] /= total;
}
}
return markovModel;
}
function applyMarkovChain() {
originalRecordedNotes = [recordedNotes];
let markovModel = generateMarkovChain();
let newSequence = [];
let currentNoteName = recordedNotes[0].note; //start from first note
let cumulativeTime = 0;
for (let i = 0; i < recordedNotes.length - 1; i++) {
//recorded note iterations
let currentNoteFreq = notes[currentNoteName]; //current note get freq
newSequence.push({
note: currentNoteName,
freq: currentNoteFreq, //store freq
startTime: cumulativeTime,
duration: recordedNotes[i].duration, // original seq duration
});
cumulativeTime += recordedNotes[i].duration;
//markov choose next note
if (markovModel[currentNoteName]) {
let nextNotes = markovModel[currentNoteName];
let totalProb = 0;
let rand = Math.random();
for (let nextNote in nextNotes) {
totalProb += nextNotes[nextNote];
if (rand <= totalProb) {
currentNoteName = nextNote;
break;
}
}
}
}
let lastNoteFreq = notes[currentNoteName];
newSequence.push({
note: currentNoteName,
freq: lastNoteFreq,
startTime: cumulativeTime,
duration: recordedNotes[recordedNotes.length - 1].duration,
});
recordedNotes = newSequence; // new seq to recordedNotes
isMarkovChainProcessed = true; //markov finished flag
startPlaybackAfterMarkov();
}
function startPlaybackAfterMarkov() {
playbackStartTime = millis();
isPlayingBack = true;
for (let key in keyStates) {
keyStates[key] = false;
}
for (let note of recordedNotes) {
note.isPlaying = false;
}
if (!isAudioRecording) {
startRecordingAudio();
}
}