-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
58301fa
commit 36ca031
Showing
4 changed files
with
337 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
import { renderNotation } from './../shared/common.js'; | ||
import constants from "../shared/constants.js"; | ||
import { snare } from '../shared/audio.js'; | ||
import { state } from '../shared/common.js'; | ||
|
||
const rollDice = (dice) => { | ||
const roll = Math.floor(Math.random() * dice.length); | ||
return dice[roll]; | ||
} | ||
|
||
const pushBeats = (groove, dice) => { | ||
for(let i = 0; i < dice.length; i++) { | ||
groove.push(dice[i]); | ||
} | ||
} | ||
|
||
export const cube_driver = () => { | ||
|
||
snare(); | ||
console.log("Creating new groove..."); | ||
|
||
let groove = { | ||
kickSnare: [], | ||
hiHat: [], | ||
fill: [] | ||
}; | ||
|
||
let kickSnare = rollDice(constants.KICK_SNARE_PATTERNS); | ||
|
||
for(let i = 0; i < 2; i++) { | ||
pushBeats(groove.kickSnare, kickSnare.pattern); | ||
} | ||
|
||
for (let i = 0; i < groove.kickSnare.length; i += 2) { | ||
groove.kickSnare.splice(i + 1, 0, 0); | ||
} | ||
|
||
let hiHat = rollDice(constants.HIHAT_PATTERNS_SIMPLE); | ||
|
||
for(let i = 0; i < 4; i++) { | ||
pushBeats(groove.hiHat, hiHat.pattern); | ||
} | ||
|
||
let fill1 = rollDice(constants.FILL_PATTERNS); | ||
pushBeats(groove.fill, fill1.pattern); | ||
|
||
let fill2 = rollDice(constants.FILL_PATTERNS); | ||
pushBeats(groove.fill, fill2.pattern); | ||
|
||
let fill3 = rollDice(constants.FILL_PATTERNS); | ||
pushBeats(groove.fill, fill3.pattern); | ||
|
||
let fill4 = rollDice(constants.FILL_PATTERNS); | ||
pushBeats(groove.fill, fill4.pattern); | ||
|
||
console.log(groove); | ||
|
||
renderNotation(groove, 'grooveResults'); | ||
} | ||
|
||
export const cube_player = () => { | ||
|
||
let groove = [ | ||
...state.getState().cubeGroove[0].tickables, | ||
...state.getState().cubeFill[0].tickables | ||
]; | ||
|
||
|
||
play(groove); | ||
} | ||
|
||
const play = (groove) => { | ||
|
||
let audioCtx = state.getState().audioContext; | ||
|
||
const bpm = 90; | ||
const secondsPerBeat = 60 / bpm; | ||
const ticksPerQuarterNote = Vex.Flow.RESOLUTION / 4; // Default is 4096 ticks per quarter note | ||
console.log(Vex.Flow.RESOLUTION); | ||
const secondsPerTick = secondsPerBeat / ticksPerQuarterNote; | ||
|
||
function playBufferAtTime(buffer, time) { | ||
const source = audioCtx.createBufferSource(); | ||
source.buffer = buffer; | ||
source.connect(audioCtx.destination); | ||
source.start(time); | ||
} | ||
function getBufferForNoteName(noteName) { | ||
// Add your logic to return the correct buffer based on the note name | ||
// For example: | ||
switch (noteName) { | ||
case constants.KICK: | ||
return state.getState().kickBuffer; | ||
case constants.SNARE: | ||
return state.getState().snareBuffer; | ||
case constants.HIHAT: | ||
return state.getState().hiHatBuffer; | ||
case constants.RACK: | ||
return state.getState().midTomBuffer; | ||
default: | ||
return null; // Return null or undefined if there's no buffer for the note | ||
} | ||
} | ||
|
||
let currentTime = audioCtx.currentTime; | ||
console.log(currentTime); | ||
|
||
|
||
groove.forEach((note) => { | ||
// Determine the note's duration in seconds | ||
const noteDurationSeconds = note.ticks.value() * secondsPerTick; | ||
|
||
// If it's a chord, note.keys will have multiple notes | ||
note.keys.forEach((key) => { | ||
// Retrieve the buffer for this particular note | ||
const bufferToPlay = getBufferForNoteName(key); | ||
|
||
// If we have a buffer to play, schedule it | ||
if (bufferToPlay) { | ||
playBufferAtTime(bufferToPlay, currentTime); | ||
} | ||
}); | ||
|
||
// Increment the current time by the note's duration | ||
currentTime += noteDurationSeconds; | ||
}); | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,177 @@ | ||
import constants from "../shared/constants.js"; | ||
import { state, drawCircle, drawVerticalLines } from '../shared/common.js'; | ||
import { kick, snare, ghost } from '../shared/audio.js'; | ||
|
||
let kickCircles; | ||
let snareCircles; | ||
let ghostCircles; | ||
|
||
let groove; | ||
|
||
export const letter_driver = () => { | ||
let groove = generate_combo(); | ||
state.updateState({groove: groove}); | ||
visualize_groove(groove); | ||
} | ||
|
||
export const groove_driver = () => { | ||
|
||
const beats_element = document.getElementById('bpm'); | ||
const canvas = document.getElementById("alphabetCanvas"); | ||
const ctx = canvas.getContext("2d"); | ||
|
||
|
||
const bpm = beats_element && beats_element.value; | ||
const beatDuration = 60000 / bpm; | ||
const quarterBeatDuration = beatDuration / 4; | ||
|
||
const delay = 500; | ||
|
||
setTimeout(() => { | ||
|
||
state.getState().groove.forEach((value, index) => { | ||
setTimeout(() => { | ||
|
||
const { ghostCircles, kickCircles, snareCircles } = state.getState(); | ||
// Play the bass drum on every 4th beat | ||
if (index % 4 === 0) { | ||
kickCircles[index / 4].setColor("red"); | ||
kickCircles[index / 4].draw(ctx); | ||
kick(); | ||
} | ||
|
||
if (value === 1) { | ||
snare(); | ||
snareCircles[index].setColor("red"); | ||
snareCircles[index].draw(ctx); | ||
} else if (value === 0) { | ||
ghostCircles[index].setColor("red"); | ||
ghostCircles[index].draw(ctx); | ||
ghost(); | ||
} | ||
}, index * quarterBeatDuration); | ||
}); | ||
}, delay); | ||
} | ||
|
||
const visualize_groove = (groove) => { | ||
|
||
snareCircles = []; | ||
ghostCircles = []; | ||
kickCircles = []; | ||
|
||
const canvas = document.getElementById("alphabetCanvas"); | ||
const ctx = canvas.getContext("2d"); | ||
ctx.clearRect(0, 0, canvas.width, canvas.height); // Clear previous drawings | ||
|
||
const circleRadius = 15; // Adjust as needed | ||
const spacing = canvas.width / (groove.length + 1); | ||
const rowHeight = canvas.height / 4; // Divided by 4 to center 3 rows within the canvas height | ||
|
||
groove.forEach((value, index) => { | ||
let yPos; | ||
|
||
// Top row for groove = 1 | ||
if (value === 1) { | ||
yPos = rowHeight; | ||
let circle = drawCircle(ctx, index * spacing + spacing, yPos, circleRadius); | ||
snareCircles.push(circle); | ||
} | ||
else { | ||
snareCircles.push(null); | ||
} | ||
|
||
// Middle row for groove = 0 | ||
if (value === 0) { | ||
yPos = 2 * rowHeight; | ||
let circle = drawCircle(ctx, index * spacing + spacing, yPos, circleRadius); | ||
ghostCircles.push(circle); | ||
} | ||
else { | ||
ghostCircles.push(null); | ||
} | ||
|
||
if(index % 4 === 0) { | ||
yPos = 3 * rowHeight; | ||
let circle = drawCircle(ctx, index * spacing + spacing, yPos, circleRadius); | ||
kickCircles.push(circle); | ||
} | ||
}); | ||
|
||
drawVerticalLines(ctx, canvas); | ||
|
||
state.updateState({ | ||
ghostCircles: ghostCircles, | ||
kickCircles: kickCircles, | ||
snareCircles: snareCircles | ||
}); | ||
} | ||
|
||
const generate_combo = () => { | ||
|
||
let flag = true; | ||
let results; | ||
let combo; | ||
|
||
while(flag) { | ||
flag = false; | ||
|
||
results = ""; | ||
combo = new Array(); | ||
groove = new Array(); | ||
|
||
for(let i = 0; i < 4; i++) { | ||
combo.push(constants.LETTERS[Math.floor(Math.random() * constants.LETTERS.length)]); | ||
results += combo[i].letter; | ||
} | ||
|
||
for(let index of combo) { | ||
console.log(index); | ||
|
||
for(let num of index.beats) { | ||
groove.push(num); | ||
} | ||
} | ||
|
||
if(groove[0] == 1) { | ||
console.log(groove); | ||
} | ||
else { | ||
flag = true; | ||
} | ||
|
||
let streak = 0; | ||
let longest = 0; | ||
|
||
for(let i = 0; i < groove.length; i++) { | ||
if(groove[i] === 1) streak++; | ||
else streak = 0; | ||
|
||
if(streak > longest) longest = streak; | ||
} | ||
|
||
const combo_element = document.getElementById('maxCombo'); | ||
const maximumCombo = combo_element && !combo_element.disabled && combo_element.value; | ||
|
||
|
||
if(maximumCombo && longest > maximumCombo) { | ||
flag = true; | ||
} | ||
|
||
const hit_element = document.getElementById('minHits'); | ||
const minimumHits = hit_element && !hit_element.disabled && hit_element.value; | ||
|
||
const actualHits = groove.reduce((accumulator, currentValue) => accumulator + currentValue, 0); | ||
|
||
if(minimumHits && actualHits < minimumHits) { | ||
flag = true; | ||
} | ||
|
||
|
||
} | ||
|
||
console.log("FINAL GROOVE"); | ||
console.log(groove); | ||
|
||
return groove; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.