-
Notifications
You must be signed in to change notification settings - Fork 2
/
generate-melody.js
101 lines (94 loc) · 3.71 KB
/
generate-melody.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
// --------------------------------------------------------------------------
// -- generate-melody.js
// -- initial author: Renick Bell ([email protected])
// -- initial creation date: Wed Jun 28 10:08:48 AM CST 2023
// -- contributors: Yiler Huang ([email protected]); Steve Wang ([email protected])
// -- license: GPL 3.0
// --------------------------------------------------------------------------
//Generated a random melody and outputs an array with objects that contains notes and octaves:
function generateRandomMelody (rootNote, mode, melodyLength, octaveMin = 1, octaveMax = 12, melodyMin = 1, melodyMax = 12, chords){
let modes = {
ionian: [0, 2, 4, 5, 7, 9, 11],
dorian: [0, 2, 3, 5, 7, 9, 10],
phrygian: [0, 1, 3, 5, 7, 8, 10],
lydian: [0, 2, 4, 6, 7, 9, 11],
mixolydian: [0, 2, 4, 5, 7, 9, 10],
aeolian: [0, 2, 3, 5, 7, 8, 10],
locrian: [0, 1, 3, 5, 6, 8, 10],
bluesScale: [0, 3, 5, 6, 7, 10],
bluesPentatonicScale: [0, 3, 5, 6, 7, 10],
minorBluesPentatonicScale: [0, 3, 5, 7, 10],
};
let modeMap = new QuantizedMap(12, modes[mode], modes[mode])
let randomMelody;
let randomOctaves;
randomMelody = A.buildArray (melodyLength, x => randomRangeInt (melodyMin, melodyMax))
randomOctaves = A.buildArray (melodyLength, x => randomRangeInt (octaveMin, octaveMax))
return randomMelody.map((x, i) => {
return {note: modeMap.nearestLookup(x % 12), octave: randomOctaves[i], rootNote: rootNote}
})
}
//Filters melody through a musical mode:
function quantizeMelody (melody, mode){
let quantizedMode = new QuantizedMap(mode[mode.length - 1], mode, mode)
console.log(quantizedMode)
return melody.map(x => {return quantizedMode.floorLookup(x)})
}
function changeNoteBy (originalNumber, changeBy, min, max){
let newNum = originalNumber
console.log('changeBy', changeBy)
if (changeBy === 'same'){
return originalNumber
}
else if (changeBy === 'increase'){
return randomRange(originalNumber, max)
}
else if (changeBy === 'decrease'){
return randomRange(min, originalNumber)
}
}
//lengthen Mode array to that it can filter MIDI values:
function createModeArray(mode) {
let modeArray = [];
// for (let i = 0; i < 128; i++) {
Array.from({length: 128}).forEach((x, i) =>{
let scaleDegree = i % 12;
if (mode.includes(scaleDegree)) {
modeArray.push(i);
}
})
return modeArray;
}
//generated by chatgpt
function generateChangeMethod (rules){
let randomNum = randomRange(0, 99)
let currentMin = 0
let changeBy;
Object.keys(rules).map(x => {
if (changeBy !== undefined){
return true
}
if (randomNum >= currentMin && randomNum < currentMin + rules[x]){
changeBy = x
}
else {
currentMin += rules[x]
}
})
return changeBy
}
function randomlyGeneratingMelodiesWithRules (mode, startValue, rules, min = 0, max = 127, melodyLength = 15){
let currentValue = startValue
let generatedMelody = []
// for (let i = 0; i < melodyLength; i++) {
Array.from({length: melodyLength}, () => {
let generatedChange = generateChangeMethod(rules)
currentValue = changeNoteBy(currentValue, generatedChange , min, max)
console.log('currentValue', currentValue)
generatedMelody.push(currentValue)
})
let modeArray = createModeArray(mode)
let quantizedModeArray = new QuantizedMap(modeArray[modeArray.length - 1], modeArray, modeArray)
return generatedMelody.map(x => {return quantizedModeArray.floorLookup(x)})
}
// randomlyGeneratingMelodiesWithRules([0,2,4,7,9,11], 80, {increase: 30, decrease: 30, same: 40},50, 120, 100)