-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathFractalGenerator.qml
198 lines (167 loc) · 7.4 KB
/
FractalGenerator.qml
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
import QtQuick 2.2
import MuseScore 3.0
MuseScore {
version: "3.0.2"
description: "Create L-System score."
menuPath: "Plugins.random"
// Interpret an L-system
function lindenmayer(s, therules) {
var outputstring = ''; // start a blank output string
// iterate through 'therules' looking for symbol matches:
for (var i = 0; i < s.length; i++) {
var ismatch = 0; // by default, no match
for (var j = 0; j < therules.length; j++) {
if (s[i] == therules[j][0]) {
outputstring += therules[j][1]; // write substitution
ismatch = 1; // we have a match, so don't copy over symbol
break; // get out if the for() loop
}
}
// if nothing matches, just copy the symbol over.
if (ismatch == 0) outputstring+= s[i];
}
return outputstring; // send out the modified string
}
function setCurrentPitch(currentPitch) {
var newPitch = currentPitch;
getCurrentPitch(newPitch);
}
function getCurrentPitch(currentPitch) {
if (currentPitch == null){ // add note
currentPitch = 72;
return currentPitch;
} else {
return currentPitch;
}
}
//note to pitch
function n2p(note, octave){
var notenames=['C','C#','D','D#','E','F','F#','G','G#','A','A#','B'];
var pitch=notenames.indexOf(note);
if(pitch==-1) return -1;
pitch+=12*(octave+1);
//console.log('pitch: '+pitch);
return pitch;
}
//adds chord at current position. chord_notes is an array with pitch of notes.
function addChord(cursor, chord_notes, duration){
if(chord_notes.length==0) return -1;
var cur_time=cursor.tick;
cursor.setDuration(1, duration); //numerator, denominator (if denominator==0, sets duration to a quarter)
cursor.addNote(chord_notes[0]); //add 1st note
var next_time=cursor.tick;
setCursorToTime(cursor, cur_time); //rewind to this note
var chord = cursor.element; //get the chord created when 1st note was inserted
for(var i=1; i<chord_notes.length; i++){
chord.add(createNote(chord_notes[i])); //add notes to the chord
}
setCursorToTime(cursor, next_time);
return 0;
}
function setCursorToTime(cursor, time){
cursor.rewind(0);
while (cursor.segment) {
var current_time = cursor.tick;
if(current_time>=time){
return true;
}
cursor.next();
}
cursor.rewind(0);
return false;
}
// create and return a new Note element with given (midi) pitch, tpc1, tpc2 and headtype
function createNote(pitch, tpc1, tpc2, head){
var note = newElement(Element.NOTE);
note.pitch = pitch;
var pitch_mod12 = pitch%12;
var pitch2tpc=[14,21,16,23,18,13,20,15,22,17,24,19]; //get tpc from pitch... yes there is a logic behind these numbers :-p
if (tpc1){
note.tpc1 = tpc1;
note.tpc2 = tpc2;
}else{
note.tpc1 = pitch2tpc[pitch_mod12];
note.tpc2 = pitch2tpc[pitch_mod12];
}
// if (head) note.headType = head;
// else note.headType = NoteHead.HEAD_AUTO;
if (head) note.headType = head;
else note.headType = NoteHeadType.HEAD_AUTO;
// console.log(" created note with tpc: ",note.tpc1," ",note.tpc2," pitch: ",note.pitch);
return note;
}
onRun: {
var measures = 38;
var numerator = 3;
var denominator = 4;
var notes = [24,26,28,31,33,36,38,40,43,45,48,50,52,55,57,60,62,64,67,69,72,74,76,79,81,84,86,88,91,93,96,98,100,103,105,108]//pentatonic C scale
var currentPitch = 20;//setting where to start in note array
// Initializing a L-System that produces the Koch-curve
var thestring = 'F'; // "axiom" or start of the string
var numloops = 4; // how many iterations to pre-compute
var therules = []; // array for rules
therules[0] = ['F', 'F+F-F-F+F']; // first rule, based on Koch Curve
var whereinstring = 0; // where in the L-system are we?
//Score Setup
var score = newScore("Fractal.mscz", "piano", measures);
score.addText("title", "Fractal Melodies");
score.addText("subtitle", "Using L-Systems");
var cursor = score.newCursor();
cursor.track = 0;
cursor.rewind(0);
var ts = newElement(Element.TIMESIG);
// v1 settings
//ts.setSig(numerator, denominator);
//v3 update
ts.timesig = fraction(numerator, denominator)
cursor.add(ts);
cursor.rewind(0);
cursor.setDuration(1, denominator);
// Compute L-System
for (var i = 0; i < numloops; i++) {
thestring = lindenmayer(thestring, therules);
console.log(thestring); //debug F output
}
// Write out the generated melody
for(var n=0; n < 302; n++) {
var k = thestring[whereinstring];
cursor.setDuration(1, 4); //make all quarter notes
if (k=='F') { // add note
cursor.addNote(notes[currentPitch]);
console.log("F: " + currentPitch);
} else if (k == '+') {
currentPitch++; // up a note
console.log("F+1: " + currentPitch);
} else if (k == '-') {
currentPitch--; // down a note
console.log("F-1: " + currentPitch);
}
//cursor.next(); // goes to next measure
setCurrentPitch(currentPitch);
// increment the point for where we're reading the string.
// wrap around at the end.
whereinstring++;
if (whereinstring > thestring.length-1){
whereinstring = 0;
}
}
// Generate notes for other staff
var staff = 1
cursor.track = staff *4;
cursor.setDuration(1, 2);
var nMeasures= (score.nmeasures)/2;
cursor.rewind(0); //go to the start of the score
//first chord for 1 full measure
addChord(cursor, [n2p('C',3), n2p('G',3)], 2);
cursor.next();
//rest of the chords, back and forth
for(var n=0; n < nMeasures-1; n++) {
addChord(cursor, [n2p('A',2), n2p('E',3)],1);
addChord(cursor, [n2p('A',2), n2p('E',3)],2);
addChord(cursor, [n2p('C',3), n2p('G',3)], 1);
addChord(cursor, [n2p('C',3), n2p('G',3)], 2);
}
addChord(cursor, [n2p('A',2), n2p('E',3)],2);
Qt.quit();
}
}