xxxxxxxxxx
175
// frequency detection based on Coding Challenge 151: Ukulele Tuner
// Daniel Shiffman
// https://thecodingtrain.com/CodingChallenges/151-ukulele-tuner.html
// https://youtu.be/F1OkDTUkKFo
// https://editor.p5js.org/codingtrain/sketches/8io2zvT03
const model_url = 'https://cdn.jsdelivr.net/gh/ml5js/ml5-data-and-models/models/pitch-detection/crepe/';
let pitch;
let mic;
let vol = 0;
let volThreshold = 0.01;
let freq = 0;
let threshold = 10;
let volThresholdSlider;
let currentFrequency = 0;
let synth;
let synthVol;
let previousNote = null
let previouslyPlayedNote = null
let majorKey = true;
let majorNoteModifiers = [-8, -5, -1, 4, 7, 11];
let minorNoteModifiers = [-9, -5, -1, 3, 7, 11];
function setup() {
createCanvas(400, 400);
setupTone();
volThresholdSlider = createSlider(0.0, 0.07, 0.01, 0.01);
audioContext = getAudioContext();
mic = new p5.AudioIn();
mic.start(listening);
}
function listening() {
console.log('listening');
pitch = ml5.pitchDetection(
model_url,
audioContext,
mic.stream,
modelLoaded
);
}
function draw() {
vol = mic.getLevel();
volThreshold = volThresholdSlider.value();
// console.log(vol);
background(0);
textAlign(CENTER, CENTER);
fill(255);
textSize(32);
text(freq.toFixed(2), width / 2, height - 150);
let closestNote = -1;
let recordDiff = Infinity;
let freqDiff = abs(currentFrequency - freq);
if (freqDiff > 10) {
currentFrequency = freq;
}
let noteIndex = -1;
//filter out background noise w/ volThreshold:
if (vol < volThreshold) {
freq = 0;
} else {
for (let i = 0; i < notes.length; i++) {
let diff = currentFrequency - notes[i].freq;
if (abs(diff) < abs(recordDiff)) {
closestNote = notes[i];
noteIndex = i;
recordDiff = diff;
}
}
let r = random(1);
let noteRandomizer = int(random((-7, 7)));
let noteToPlay;
if (r < 0.9) {
//set major or minor parameters with "majorKey" vs "minorKey"
if (majorKey) {
noteToPlay = notes[noteIndex + (random(majorNoteModifiers))];
} else if (majorKey == false) {
noteToPlay = notes[noteIndex + (random(minorNoteModifiers))];
}
// } else if (r < 0.9 && r >= 0.5) {
// noteToPlay = notes[noteIndex + 7];
} else {
noteToPlay = notes[noteIndex + noteRandomizer];
}
if (noteIndex !== -1) {
// on change
if (noteIndex !== previousNote && noteToPlay){
synth.triggerRelease(Tone.now())
synth.triggerAttack(noteToPlay.note, Tone.now() + 0.1)
}
// previouslyPlayedNote = noteToPlay
} else if (noteIndex === -1 && previousNote !== -1){
synth.triggerRelease(Tone.now() - 0.1)
}
previousNote = noteIndex;
}
textSize(64);
text(closestNote.note, width / 2, height - 50);
let diff = recordDiff;
let alpha = map(abs(diff), 0, 100, 255, 0);
rectMode(CENTER);
fill(255, alpha);
stroke(255);
strokeWeight(1);
if (abs(diff) < threshold) {
fill(0, 255, 0);
}
rect(200, 100, 200, 50);
stroke(255);
strokeWeight(4);
line(200, 0, 200, 200);
noStroke();
fill(255, 0, 0);
if (abs(diff) < threshold) {
fill(0, 255, 0);
}
rect(200 + diff / 2, 100, 10, 75);
}
function modelLoaded() {
console.log('model loaded');
pitch.getPitch(gotPitch);
}
function gotPitch(error, frequency) {
if (error) {
console.error(error);
} else {
//console.log(frequency);
if (frequency) {
freq = frequency;
}
pitch.getPitch(gotPitch);
}
}
function setupTone() {
synthVol = new Tone.Volume(0).toMaster();
synth = new Tone.Synth({
envelope: {
attack: 0.05,
decay: 0.1,
release: 0.1
},
oscillator : {
partials: [0.5, 0.1, 0.1, 0.1, 0.3, 0.3]
}
}).toMaster();
}