1 | /*
|
---|
2 | ----------------------------------------------------------------------
|
---|
3 | AudioTag <audio> - OGG or MPEG Soundbank
|
---|
4 | ----------------------------------------------------------------------
|
---|
5 | http://dev.w3.org/html5/spec/Overview.html#the-audio-element
|
---|
6 | ----------------------------------------------------------------------
|
---|
7 | */
|
---|
8 |
|
---|
9 | (function(root) { 'use strict';
|
---|
10 |
|
---|
11 | window.Audio && (function() {
|
---|
12 | var midi = root.AudioTag = { api: 'audiotag' };
|
---|
13 | var noteToKey = {};
|
---|
14 | var volume = 127; // floating point
|
---|
15 | var buffer_nid = -1; // current channel
|
---|
16 | var audioBuffers = []; // the audio channels
|
---|
17 | var notesOn = []; // instrumentId + noteId that is currently playing in each 'channel', for routing noteOff/chordOff calls
|
---|
18 | var notes = {}; // the piano keys
|
---|
19 | for (var nid = 0; nid < 12; nid ++) {
|
---|
20 | audioBuffers[nid] = new Audio();
|
---|
21 | }
|
---|
22 |
|
---|
23 | var playChannel = function(channel, note) {
|
---|
24 | if (!root.channels[channel]) return;
|
---|
25 | var instrument = root.channels[channel].instrument;
|
---|
26 | var instrumentId = root.GM.byId[instrument].id;
|
---|
27 | var note = notes[note];
|
---|
28 | if (note) {
|
---|
29 | var instrumentNoteId = instrumentId + '' + note.id;
|
---|
30 | var nid = (buffer_nid + 1) % audioBuffers.length;
|
---|
31 | var audio = audioBuffers[nid];
|
---|
32 | notesOn[ nid ] = instrumentNoteId;
|
---|
33 | if (!root.Soundfont[instrumentId]) {
|
---|
34 | if (root.DEBUG) {
|
---|
35 | console.log('404', instrumentId);
|
---|
36 | }
|
---|
37 | return;
|
---|
38 | }
|
---|
39 | audio.src = root.Soundfont[instrumentId][note.id];
|
---|
40 | audio.volume = volume / 127;
|
---|
41 | audio.play();
|
---|
42 | buffer_nid = nid;
|
---|
43 | }
|
---|
44 | };
|
---|
45 |
|
---|
46 | var stopChannel = function(channel, note) {
|
---|
47 | if (!root.channels[channel]) return;
|
---|
48 | var instrument = root.channels[channel].instrument;
|
---|
49 | var instrumentId = root.GM.byId[instrument].id;
|
---|
50 | var note = notes[note];
|
---|
51 | if (note) {
|
---|
52 | var instrumentNoteId = instrumentId + '' + note.id;
|
---|
53 | for (var i = 0, len = audioBuffers.length; i < len; i++) {
|
---|
54 | var nid = (i + buffer_nid + 1) % len;
|
---|
55 | var cId = notesOn[nid];
|
---|
56 | if (cId && cId == instrumentNoteId) {
|
---|
57 | audioBuffers[nid].pause();
|
---|
58 | notesOn[nid] = null;
|
---|
59 | return;
|
---|
60 | }
|
---|
61 | }
|
---|
62 | }
|
---|
63 | };
|
---|
64 |
|
---|
65 | midi.audioBuffers = audioBuffers;
|
---|
66 | midi.send = function(data, delay) { };
|
---|
67 | midi.setController = function(channel, type, value, delay) { };
|
---|
68 | midi.setVolume = function(channel, n) {
|
---|
69 | volume = n; //- should be channel specific volume
|
---|
70 | };
|
---|
71 |
|
---|
72 | midi.programChange = function(channel, program) {
|
---|
73 | root.channels[channel].instrument = program;
|
---|
74 | };
|
---|
75 |
|
---|
76 | midi.pitchBend = function(channel, program, delay) { };
|
---|
77 |
|
---|
78 | midi.noteOn = function(channel, note, velocity, delay) {
|
---|
79 | var id = noteToKey[note];
|
---|
80 | if (!notes[id]) return;
|
---|
81 | if (delay) {
|
---|
82 | return setTimeout(function() {
|
---|
83 | playChannel(channel, id);
|
---|
84 | }, delay * 1000);
|
---|
85 | } else {
|
---|
86 | playChannel(channel, id);
|
---|
87 | }
|
---|
88 | };
|
---|
89 |
|
---|
90 | midi.noteOff = function(channel, note, delay) {
|
---|
91 | // var id = noteToKey[note];
|
---|
92 | // if (!notes[id]) return;
|
---|
93 | // if (delay) {
|
---|
94 | // return setTimeout(function() {
|
---|
95 | // stopChannel(channel, id);
|
---|
96 | // }, delay * 1000)
|
---|
97 | // } else {
|
---|
98 | // stopChannel(channel, id);
|
---|
99 | // }
|
---|
100 | };
|
---|
101 |
|
---|
102 | midi.chordOn = function(channel, chord, velocity, delay) {
|
---|
103 | for (var idx = 0; idx < chord.length; idx ++) {
|
---|
104 | var n = chord[idx];
|
---|
105 | var id = noteToKey[n];
|
---|
106 | if (!notes[id]) continue;
|
---|
107 | if (delay) {
|
---|
108 | return setTimeout(function() {
|
---|
109 | playChannel(channel, id);
|
---|
110 | }, delay * 1000);
|
---|
111 | } else {
|
---|
112 | playChannel(channel, id);
|
---|
113 | }
|
---|
114 | }
|
---|
115 | };
|
---|
116 |
|
---|
117 | midi.chordOff = function(channel, chord, delay) {
|
---|
118 | for (var idx = 0; idx < chord.length; idx ++) {
|
---|
119 | var n = chord[idx];
|
---|
120 | var id = noteToKey[n];
|
---|
121 | if (!notes[id]) continue;
|
---|
122 | if (delay) {
|
---|
123 | return setTimeout(function() {
|
---|
124 | stopChannel(channel, id);
|
---|
125 | }, delay * 1000);
|
---|
126 | } else {
|
---|
127 | stopChannel(channel, id);
|
---|
128 | }
|
---|
129 | }
|
---|
130 | };
|
---|
131 |
|
---|
132 | midi.stopAllNotes = function() {
|
---|
133 | for (var nid = 0, length = audioBuffers.length; nid < length; nid++) {
|
---|
134 | audioBuffers[nid].pause();
|
---|
135 | }
|
---|
136 | };
|
---|
137 |
|
---|
138 | midi.connect = function(opts) {
|
---|
139 | root.setDefaultPlugin(midi);
|
---|
140 | ///
|
---|
141 | for (var key in root.keyToNote) {
|
---|
142 | noteToKey[root.keyToNote[key]] = key;
|
---|
143 | notes[key] = {id: key};
|
---|
144 | }
|
---|
145 | ///
|
---|
146 | opts.onsuccess && opts.onsuccess();
|
---|
147 | };
|
---|
148 | })();
|
---|
149 |
|
---|
150 | })(MIDI); |
---|