Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Karan Goel
481-SoundBrain
Commits
640f55b4
Commit
640f55b4
authored
Feb 17, 2015
by
Max-Ferdinand Suffel
Browse files
enhance MIDI.js with a PCM callback
parent
066e8ed7
Changes
2
Hide whitespace changes
Inline
Side-by-side
webapp/demo-MultipleInstruments.html
View file @
640f55b4
...
...
@@ -15,30 +15,88 @@
<body>
<script
type=
"text/javascript"
>
// This iterates through all the notes in these two soundfonts.
// The synth_drum does not have as high or low of range of notes,
// so you wont hear it for a few seconds.
// For debug purpose only.
function
array2str
(
ua
)
{
var
h
=
''
;
for
(
var
i
=
0
;
i
<
ua
.
length
;
i
++
)
{
h
+=
"
\\
0x
"
+
ua
[
i
].
toString
(
16
);
}
return
h
;
}
// Utilities for sending light data over a web socket.
function
sendLightData
(
socket
,
color
,
brightness
)
{
if
(
brightness
<
0
||
brightness
>
255
)
{
throw
new
Error
(
'
Brightness must be between 0 and 255 (inclusive)
'
);
}
var
outputBuffer
;
if
(
color
==
"
red
"
)
{
outputBuffer
=
new
Uint8Array
([
0x01
,
brightness
]);
}
else
if
(
color
==
"
blue
"
)
{
outputBuffer
=
new
Uint8Array
([
0x02
,
brightness
]);
}
else
{
throw
new
Error
(
'
Color must be
\'
red
\'
or
\'
blue
\'
'
);
}
socket
.
send
(
outputBuffer
);
}
// Utilities for sending audio data over a web socket.
function
float32To16bitPCM
(
input
)
{
var
output
=
new
Int16Array
(
input
.
length
);
for
(
var
i
=
0
;
i
<
input
.
length
;
++
i
)
{
var
sample
=
input
[
i
];
//saturation: Math.max(-1, Math.min(1, buffer[l]));
output
[
i
]
=
(
sample
<
0
)
?
(
sample
*
0x8000
)
:
(
sample
*
0x7FFF
);
}
return
output
.
buffer
;
}
function
concatBuffers
(
buffer1
,
buffer2
)
{
var
tmp
=
new
Uint8Array
(
buffer1
.
byteLength
+
buffer2
.
byteLength
);
tmp
.
set
(
new
Uint8Array
(
buffer1
),
0
);
tmp
.
set
(
new
Uint8Array
(
buffer2
),
buffer1
.
byteLength
);
return
tmp
.
buffer
;
}
function
sendAudioData
(
socket
,
data
)
{
var
pcmBuffer
=
float32To16bitPCM
(
data
);
var
header
=
new
Uint8Array
([
0x00
]);
var
outputBuffer
=
concatBuffers
(
header
.
buffer
,
pcmBuffer
);
socket
.
send
(
outputBuffer
);
}
// On web page is loaded:
window
.
onload
=
function
()
{
MIDI
.
loadPlugin
({
soundfontUrl
:
"
./soundfont/
"
,
instruments
:
[
"
acoustic_grand_piano
"
,
"
synth_drum
"
],
callback
:
function
()
{
MIDI
.
programChange
(
0
,
0
);
MIDI
.
programChange
(
1
,
118
);
for
(
var
n
=
0
;
n
<
100
;
n
++
)
{
var
delay
=
n
/
4
;
// play one note every quarter second
var
note
=
MIDI
.
pianoKeyOffset
+
n
;
// the MIDI note
var
velocity
=
127
;
// how hard the note hits
// play the note
MIDI
.
noteOn
(
0
,
note
,
velocity
,
delay
);
// play the some note 3-steps up
MIDI
.
noteOn
(
1
,
note
+
3
,
velocity
,
delay
);
}
}
});
};
// Connect to relay server via web socket.
var
relaySocket
=
new
WebSocket
(
'
ws://localhost:9000
'
);
relaySocket
.
binaryType
=
"
arraybuffer
"
;
relaySocket
.
onopen
=
function
(
e
)
{
MIDI
.
loadPlugin
({
soundfontUrl
:
"
./soundfont/
"
,
instruments
:
[
"
acoustic_grand_piano
"
,
"
synth_drum
"
],
callback
:
function
()
{
MIDI
.
programChange
(
0
,
0
);
MIDI
.
programChange
(
1
,
118
);
for
(
var
n
=
0
;
n
<
100
;
n
++
)
{
var
delay
=
n
/
4
;
// play one note every quarter second
var
note
=
MIDI
.
pianoKeyOffset
+
n
;
// the MIDI note
var
velocity
=
127
;
// how hard the note hits
// play the note
MIDI
.
noteOn
(
0
,
note
,
velocity
,
delay
);
// play the some note 3-steps up
MIDI
.
noteOn
(
1
,
note
+
3
,
velocity
,
delay
);
}
},
callbackPCM
:
function
(
pcmBuffer
)
{
sendAudioData
(
relaySocket
,
pcmBuffer
);
},
silent
:
true
// Debug: remove to hear audio on system speaker
});
};
};
</script>
</body>
</html>
\ No newline at end of file
webapp/js/MIDI/Plugin.js
View file @
640f55b4
...
...
@@ -172,32 +172,59 @@ if (window.AudioContext || window.webkitAudioContext) (function () {
};
root
.
noteOn
=
function
(
channel
,
note
,
velocity
,
delay
)
{
/// check whether the note exists
if
(
!
MIDI
.
channels
[
channel
])
return
;
var
instrument
=
MIDI
.
channels
[
channel
].
instrument
;
if
(
!
audioBuffers
[
instrument
+
""
+
note
])
return
;
/// convert relative delay to absolute delay
if
(
delay
<
ctx
.
currentTime
)
delay
+=
ctx
.
currentTime
;
/// crate audio buffer
var
source
=
ctx
.
createBufferSource
();
sources
[
channel
+
""
+
note
]
=
source
;
source
.
buffer
=
audioBuffers
[
instrument
+
""
+
note
];
source
.
connect
(
ctx
.
destination
);
///
if
(
ctx
.
createGain
)
{
// firefox
source
.
gainNode
=
ctx
.
createGain
();
}
else
{
// chrome
source
.
gainNode
=
ctx
.
createGainNode
();
}
}
var
value
=
(
velocity
/
127
)
*
(
masterVolume
/
127
)
*
2
-
1
;
source
.
gainNode
.
connect
(
ctx
.
destination
);
source
.
gainNode
.
gain
.
value
=
Math
.
max
(
-
1
,
value
);
source
.
connect
(
source
.
gainNode
);
// SoundBrain: Inject an audio processor right before the speaker sink,
// to hijack the raw PCM 16-bit audio data.
if
(
root
.
callbackPCM
)
{
if
(
!
ctx
.
audioProcessor
)
{
ctx
.
audioProcessor
=
ctx
.
createScriptProcessor
(
0
,
1
,
1
);
ctx
.
audioProcessor
.
onaudioprocess
=
function
(
e
)
{
var
inputBuffer
=
e
.
inputBuffer
.
getChannelData
(
0
);
root
.
callbackPCM
(
inputBuffer
);
if
(
!
root
.
silent
)
{
var
outputBuffer
=
e
.
outputBuffer
.
getChannelData
(
0
);
for
(
var
sample
=
0
;
sample
<
inputBuffer
.
length
;
sample
++
)
{
outputBuffer
[
sample
]
=
inputBuffer
[
sample
];
}
}
};
ctx
.
audioProcessor
.
connect
(
ctx
.
destination
);
}
source
.
connect
(
ctx
.
audioProcessor
);
source
.
gainNode
.
connect
(
ctx
.
audioProcessor
);
}
else
{
source
.
connect
(
ctx
.
destination
);
source
.
gainNode
.
connect
(
ctx
.
destination
);
}
if
(
source
.
noteOn
)
{
// old api
source
.
noteOn
(
delay
||
0
);
}
else
{
// new api
source
.
start
(
delay
||
0
);
}
return
source
;
};
...
...
@@ -254,10 +281,13 @@ if (window.AudioContext || window.webkitAudioContext) (function () {
};
root
.
connect
=
function
(
conf
)
{
root
.
callbackPCM
=
conf
.
callbackPCM
;
root
.
silent
=
conf
.
silent
;
setPlugin
(
root
);
//
MIDI
.
Player
.
ctx
=
ctx
=
new
AudioContext
();
///
var
urlList
=
[];
var
keyToNote
=
MIDI
.
keyToNote
;
for
(
var
key
in
keyToNote
)
urlList
.
push
(
key
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment