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
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
| /*******************************************************************************************************************
/**
* @see: https://odino.org/emit-a-beeping-sound-with-javascript/
* @see: https://stackoverflow.com/questions/39200994/how-to-play-a-specific-frequency-with-javascript
* @see: https://pages.mtu.edu/~suits/notefreqs.html
*
* @see: https://www.javascripture.com/OscillatorNode
*
*/
//const audioContext=new AudioContext() ;// browsers limit the number of concurrent audio contexts, so you better re-use'em
//var audioContext = new (window.AudioContext || window.webkitAudioContext)();
// Tone JS Synthetizer
const synth = new Tone.Synth();
// synth.oscillator.type = "sine";
synth.toMaster();
const intervals = [
"Un-C-Do-q-z", //0
"2m-C#-Do#-2-s", //1
"2M-D-Re-w-x", //2
"3m-D#-Re#-3-d", //3
"3M-E-Mi-e-c", //4
"4J-F-Fa-r-v", //5
"4A-F#-Fa#-5-g", //6
"5J-G-Sol-t-b", //7
"6m-G#-Sol#-6-h", //8
"6M-A-La-y-n", //9
"7m-A#-La#-7-j", //10
"7M-B-Si-u-m", //11
"8J-C-Do" //12
];
const ascen=["Asc","Desc"]
const duration=["Redonda","Blanca","Negra","Corchea","Semicorchea"];
//const volume=[100, 70, 40, 10, 7, 4, 1, 0.7, 0.4, 0.1, 0.07, 0.04, 0.01, 0.007, 0.004, 0.001];
const volume=[20, 15, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2 ];
const fqLa4=440; // Frecuencia La4
const octaves = [0,1,2,3,4,5,6,7,8,9,10];
var octaveFrom =2;
var octaveTo =5;
// Variable that stores the last interval to play
var aa={};
/**
* Obtenemos la frecuencia de una nota en nomenclatura inglesa
* Web audio solo trabaja en frecuencia
* nota: "A3", "C4".....
*/
function getFrequency(note) {
var notes=getNthArrayElement(intervals,"-",1) ; //Get array of music notes
var notat=note.trim();
var octave=notat.substr(notat.length-1,1);
var nota1=notat.substring(0,notat.length-1);
var found=false;
var i=-1;
while (! found && i<12){
if (notes[++i].localeCompare(nota1)==0) found=true;
}
var freq=fqLa4*(2**((i-9)/12));
freq=freq*(2**(octave-4));
return freq;
}
//==========================TONEJS =================================
/**
* Plays a note in Tone.js
* note1: "A4", "B3", "C#3" ...
* note2: "A4", "B3", "C#3" ...
* duration (ms)
* noecho: stop playing, avoiding residual vibration
*/
function playInterval(note1, note2, myDuration, noecho) {
synth.triggerAttackRelease(note1, myDuration/1000);
window.setTimeout(playSecondTone, myDuration, note2, myDuration);
if (noecho)window.setTimeout(removeEcho, myDuration*2);
}
/**
Plays the second note of the Interval {
* note2 : note to play
* duration (ms)
*/
function playSecondTone(note, myDuration) {
synth.triggerAttackRelease(note, myDuration/1000);
}
/**
* Play a note of small duration without any volumen
* and removes remaining vibrations
*/
function removeEcho() {
synth.volume.value = "-Infinity";
changeVolume();
}
/**
* Convert volume in WebAudio to Tonejs
*
* WebAudio equals to Tone
* ======= ========
* 100 100
* 50 25
* 25 0
* 0 "-Infinite"
*/
function convertVolumeWAudiotoTone(volume) {
if (volume==0) return "-Infinity";
var a = 100*Math.log(volume/10)/Math.log(10);
//console.log ("convertVolumeWAudiotoTone.volumen.js="+a + " volumen="+ volume);
return a;
}
/**
* Get selected duration from form in miliseconds
*/
function getDurationms() {
var select=document.getElementById("selDuration");
//var opc = select.options[select.selectedIndex].value;
var opc = select.selectedIndex;
return 4/(2**opc)*1000 ;
}
/**
* Get selected volume in %
*/
function getVolume() {
var select=document.getElementById("selVolume");
return select.options[select.selectedIndex].value;
}
/**
* Get Octaves
*/
function getOctaves() {
var selectFrom=document.getElementById("seloctavefrom");
octaveFrom= selectFrom.options[selectFrom.selectedIndex].value;
var selectTo=document.getElementById("seloctaveto");
octaveTo= selectTo.options[selectTo.selectedIndex].value;
}
/**
* Change Volum =
*/
function changeVolume() {
synth.volume.value = convertVolumeWAudiotoTone(getVolume());
//console.log("changeVolume.vol="+getVolume());
}
/**
* Get the selected duration in nth of a whole note (redonda)
* 1n , 2n, 3n, 4n, 8n,
*/
function getDurationNth() {
var select=document.getElementById("selDuration");
//var opc = select.options[select.selectedIndex].value;
var opc = select.selectedIndex;
return ""+(2**opc)+"n" ;
}
/**
* Fill the variable "aa" with the info of the interval to play:
*
* note1
* note2
* asc: 0/1 for ascending/descending
*/
function getNotesInterval() {
var arrInts=[ ];
var arrAsc= [ ];
for (var i=0; i<13; i++) if (checkboxes[i].checked) arrInts.push(i);
for (var i=0; i<2; i++) if (checkboxesAsc[i].checked) arrAsc.push(i);
var interval=getRandomInt(0, arrInts.length-1); //Posion relativa
interval=arrInts[interval]; //Posicion absoluta
var asc=getRandomInt(0, arrAsc.length-1);
asc=arrAsc[asc];
var arrNot1=getRandomNote();
var arrNot2=getInterval2ndNote(arrNot1[0],arrNot1[1], interval);
aa=getNotesIntervalFromNotePos(arrNot1[0], arrNot1[1],arrNot2[0], arrNot2[1], interval, asc);
console.log("getNotesInterval.aa="+aa);
}
/**
* Grts tje second note of an interval
*
*/
function getInterval2ndNote(nota1, octave1, interval){
var a=[ ];
var octave2=octave1;
var nota2=+interval+nota1;
if (nota2>11) {
nota2=+nota2-12;
octave2=+octave1+1;
}
a.push(+nota2);
a.push(+octave2);
return a;
}
/**
* get notes in English notation like "A4", "B#3" ..
* params:
* nota1: int position of first note (0..11)
* octave1: int octave of first note (0..6)
* nota2: int position of second note (0..11)
* octave2: int octave of second note (0..6)
* interval: Not used but needed to fill aa structure
*/
function getNotesIntervalFromNotePos(nota1, octave1,nota2, octave2, interval, asc) {
var notes=getNthArrayElement(intervals,"-",1) ; //Get array of music notes
var bb={};
bb.nota1=notes[nota1]+octave1;
bb.nota2=notes[nota2]+octave2;
bb.interval=interval;
bb.asc=asc;
return bb;
}
/**
* Get a random note
* return an array of integer: first = note number, second=octave
*
*/
function getRandomNote() {
var a=[ ];
a.push(getRandomInt(0, 11)); //Nota);
a.push(getRandomInt(octaveFrom, octaveTo)); // octaves
return a;
}
/**
* Next play
*/
function nextPlay() {
//Enable/disable Buttons
disableComponent("btok" ,false);
disableComponent("btnext",true);
disableComponent("btrep" ,false);
getNotesInterval(); // get new interval to play into variable "aa"
repeatAudition(); // Play interval
incrementCounter("intentos"); //Increment attempts "intentos"
}
/**
* Play an interval
*
*/
function playIntervalByValue(bb){
if (bb.asc==0) playInterval(bb.nota1, bb.nota2, getDurationms(), true);
else playInterval(bb.nota2, bb.nota1, getDurationms(), true);
console.log("playIntervalByValue.nota1="+bb.nota1 + " nota2="+bb.nota2 + " interval="+bb.interval +" asc="+bb.asc);
}
/**
* Repeat audition
*/
function repeatAudition() {
playIntervalByValue(aa);
}
/**
* Check Answer
*/
function checkAnswer() {
//Enable/disable Buttons
disableComponent("btok" ,true);
disableComponent("btnext",false);
disableComponent("btrep" ,false);
var aText=getNthArrayElement(intervals,"-",0);
var selAns=document.getElementById("selInt");
var intUsr=selAns.selectedIndex;
var selAnsAsc=document.getElementById("selAsc");
var ascUsr=selAnsAsc.selectedIndex;
//Acertamos
console.log("checkAnswer.aa.interval="+aa.interval + " intUsr=" + intUsr);
if (intUsr==aa.interval && (ascUsr==aa.asc || intUsr == 0) ) {
incrementCounter("aciertos");
fillTextBox("message", "¡Correcto! ", "blue");
//Fallamos
} else {
incrementCounter("fallos");
fillTextBox("message", "¡Noo! La respuesta correcta es: "+ aText[aa.interval] + "-"+ ascen[aa.asc], "red");
}
}
/**
* Function that plays an interval whose first note is C4
* It is triggered by buttons
*/
function playDemoInterval(interval, asc) {
nota1=0; //C4
octave1=4;
var arrNot2=getInterval2ndNote(nota1, octave1, interval);
var nota2=arrNot2[0]; //Position nota
var octave2=arrNot2[1]; //octave
console.log("playDemoInterval.1.nota1:" + nota1 + " nota2=" + nota2);
var bb=getNotesIntervalFromNotePos(nota1, octave1,nota2, octave2, interval, asc);
console.log("playDemoInterval.2.bb="+ bb);
var myMessage= (asc==0) ? ascIntervalMusics[interval] : desIntervalMusics[interval];
console.log("playDemoInterval.3.interval:" + interval + " asc="+ asc +" mensaje="+ myMessage + " ascInterv:" + ascIntervalMusics[interval]);
fillTextBox("message", myMessage, "deepskyblue");
playIntervalByValue(bb);
}
|