我一直在搞乱midi教程并触发样本。但是我无法弄清楚如何去除代码中样本的随机音高变化。知道如何消除音高变化吗?
链接到教程:http://www.keithmcmillen.com/blog/making-music-in-the-browser-web-midi-api/
<html>
<head>
<meta charset="UTF-8">
<title>Web MIDI API</title>
<style>
*:before, *:after {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
h4 {
margin: 0 0 5px 0;
}
p {
margin: 0 0 10px 0;
}
#content, #device_info {
max-width: 800px;
margin: 0 auto;
padding: 10px 0;
font-family: sans-serif;
font-size: 12px;
line-height: 12px;
letter-spacing: 1.5px;
}
#content, #key_data {
margin-top: 0px;
text-align: center;
}
#inputs, #outputs {
display: inline-block;
width: 49%;
margin-top: 10px;
vertical-align: top;
}
#outputs {
text-align: right;
}
.info {
padding: 20px;
border-radius: 3px;
box-shadow: inset 0 0 10px #ccc;
background-color: rgba(233,233,233,0.25);
}
.small {
border-bottom: 1px solid #ccc;
margin-left: 10px;
}
p:not(.small){
text-transform: uppercase;
font-weight: 800;
}
.button {
display: inline-block;
width: 100px;
height: 100px;
margin: 10px;
background-color: #00adef;
border-radius: 10px;
opacity: 1;
cursor: pointer;
border: 2px solid white;
transition: all 0.2s;
}
.button.active {
background-color: #9a6aad;
opacity: 0.25;
box-shadow: inset 0px 0px 30px orange;
border: 2px solid rgba(100,100,100,0.3);
animation: shake .2s ease-in-out;
}
@keyframes shake {
0% {
transform: translateX(0);
transform: translateY(0);
transform: scale(1,1);
}
20% {
transform: translateX(-10px);
transform: translateY(-100px);
transform: scale(0.5,0.75);
}
40% {
transform: translateX(10px);
transform: translateY(0px);
transform: scale(1.5,2);
}
60% {
transform: translateX(-10px);
transform: translateY(-50px);
transform: scale(0.5,0.75);
}
80% {
transform: translateX(10px);
transform: translateY(50px);
transform: scale(1.3,2);
}
100% {
transform: translateX(0);
transform: translateY(0);
}
}
</style>
</head>
<body>
<div id="content">
<div class="button" data-key="q" data-sound="audio/Slice1.mp3"></div>
<div class="button" data-key="w" data-sound="audio/dinky-snare.mp3"></div>
<div class="button" data-key="e" data-sound="audio/dinky-hat-2.mp3"></div>
<div class="button" data-key="r" data-sound="audio/dinky-cym.mp3"></div>
<div class="button" data-key="t" data-sound="audio/dinky-cym-noise.mp3"></div>
</div>
<div id="device_info">
<div id="key_data"></div>
<div id="inputs"></div>
<div id="outputs"></div>
</div>
<script>
//http://stackoverflow.com/questions/23687635/how-to-stop-audio-in-an-iframe-using-web-audio-api-after-hiding-its-container-di
(function(){
var log = console.log.bind(console), keyData = document.getElementById('key_data'),
deviceInfoInputs = document.getElementById('inputs'), deviceInfoOutputs = document.getElementById('outputs'), midi;
var AudioContext = AudioContext || webkitAudioContext; // for ios/safari
var context = new AudioContext();
var activeNotes = [];
var btnBox = document.getElementById('content'), btn = document.getElementsByClassName('button');
var data, cmd, channel, type, note, velocity;
// request MIDI access
if(navigator.requestMIDIAccess){
navigator.requestMIDIAccess({sysex: false}).then(onMIDISuccess, onMIDIFailure);
}
else {
alert("No MIDI support in your browser.");
}
// add event listeners
document.addEventListener('keydown', keyController);
document.addEventListener('keyup', keyController);
for(var i = 0; i < btn.length; i++){
btn[i].addEventListener('mousedown', clickPlayOn);
btn[i].addEventListener('mouseup', clickPlayOff);
}
// prepare audio files
for(var i = 0; i < btn.length; i++){
addAudioProperties(btn[i]);
}
var sampleMap = {
key60: 1,
key61: 2,
key62: 3,
key63: 4,
key64: 5
};
// user interaction
function clickPlayOn(e){
e.target.classList.add('active');
e.target.play();
}
function clickPlayOff(e){
e.target.classList.remove('active');
}
function keyController(e){
if(e.type == "keydown"){
switch(e.keyCode){
case 81:
btn[0].classList.add('active');
btn[0].play();
break;
case 87:
btn[1].classList.add('active');
btn[1].play();
break;
case 69:
btn[2].classList.add('active');
btn[2].play();
break;
case 82:
btn[3].classList.add('active');
btn[3].play();
break;
case 84:
btn[4].classList.add('active');
btn[4].play();
break;
default:
//console.log(e);
}
}
else if(e.type == "keyup"){
switch(e.keyCode){
case 81:
btn[0].classList.remove('active');
break;
case 87:
btn[1].classList.remove('active');
break;
case 69:
btn[2].classList.remove('active');
break;
case 82:
btn[3].classList.remove('active');
break;
case 84:
btn[4].classList.remove('active');
break;
default:
//console.log(e.keyCode);
}
}
}
// midi functions
function onMIDISuccess(midiAccess){
midi = midiAccess;
var inputs = midi.inputs.values();
// loop through all inputs
for(var input = inputs.next(); input && !input.done; input = inputs.next()){
// listen for midi messages
input.value.onmidimessage = onMIDIMessage;
listInputs(input);
}
// listen for connect/disconnect message
midi.onstatechange = onStateChange;
showMIDIPorts(midi);
}
function onMIDIMessage(event){
data = event.data,
cmd = data[0] >> 4,
channel = data[0] & 0xf,
type = data[0] & 0xf0, // channel agnostic message type. Thanks, Phil Burk.
note = data[1],
velocity = data[2];
// with pressure and tilt off
// note off: 128, cmd: 8
// note on: 144, cmd: 9
// pressure / tilt on
// pressure: 176, cmd 11:
// bend: 224, cmd: 14
log('MIDI data', data);
switch(type){
case 144: // noteOn message
noteOn(note, velocity);
break;
case 128: // noteOff message
noteOff(note, velocity);
break;
}
//log('data', data, 'cmd', cmd, 'channel', channel);
logger(keyData, 'key data', data);
}
function onStateChange(event){
showMIDIPorts(midi);
var port = event.port, state = port.state, name = port.name, type = port.type;
if(type == "input")
log("name", name, "port", port, "state", state);
}
function listInputs(inputs){
var input = inputs.value;
log("Input port : [ type:'" + input.type + "' id: '" + input.id +
"' manufacturer: '" + input.manufacturer + "' name: '" + input.name +
"' version: '" + input.version + "']");
}
function noteOn(midiNote, velocity){
player(midiNote, velocity);
}
function noteOff(midiNote, velocity){
player(midiNote, velocity);
}
function player(note, velocity){
var sample = sampleMap['key'+note];
if(sample){
if(type == (0x80 & 0xf0) || velocity == 0){ //needs to be fixed for QuNexus, which always returns 144
btn[sample - 1].classList.remove('active');
return;
}
btn[sample - 1].classList.add('active');
btn[sample - 1].play(velocity);
}
}
function onMIDIFailure(e){
log("No access to MIDI devices or your browser doesn't support WebMIDI API. Please use WebMIDIAPIShim " + e);
}
// MIDI utility functions
function showMIDIPorts(midiAccess){
var inputs = midiAccess.inputs,
outputs = midiAccess.outputs,
html;
html = '<h4>MIDI Inputs:</h4><div class="info">';
inputs.forEach(function(port){
html += '<p>' + port.name + '<p>';
html += '<p class="small">connection: ' + port.connection + '</p>';
html += '<p class="small">state: ' + port.state + '</p>';
html += '<p class="small">manufacturer: ' + port.manufacturer + '</p>';
if(port.version){
html += '<p class="small">version: ' + port.version + '</p>';
}
});
deviceInfoInputs.innerHTML = html + '</div>';
html = '<h4>MIDI Outputs:</h4><div class="info">';
outputs.forEach(function(port){
html += '<p>' + port.name + '<br>';
html += '<p class="small">manufacturer: ' + port.manufacturer + '</p>';
if(port.version){
html += '<p class="small">version: ' + port.version + '</p>';
}
});
deviceInfoOutputs.innerHTML = html + '</div>';
}
// audio functions
function loadAudio(object, url){
var request = new XMLHttpRequest();
request.open('GET', url, true);
request.responseType = 'arraybuffer';
request.onload = function(){
context.decodeAudioData(request.response, function(buffer){
object.buffer = buffer;
});
}
request.send();
}
function addAudioProperties(object){
object.name = object.id;
object.source = object.dataset.sound;
loadAudio(object, object.source);
object.play = function(volume){
var s = context.createBufferSource();
var g = context.createGain();
var v;
s.buffer = object.buffer;
s.playbackRate.value = randomRange(0.5, 2);
if(volume){
v = rangeMap(volume, 1, 127, 0.2, 2);
s.connect(g);
g.gain.value = v * v;
g.connect(context.destination);
}
else{
s.connect(context.destination);
}
s.start();
object.s = s;
}
}
// utility functions
function randomRange(min, max){
return Math.random() * (max + min) + min;
}
function rangeMap(x, a1, a2, b1, b2){
return ((x - a1)/(a2-a1)) * (b2 - b1) + b1;
}
//function frequencyFromNoteNumber( note ) {
// return 440 * Math.pow(2,(note-69)/12);
//}
function logger(container, label, data){
messages = label + " [channel: " + (data[0] & 0xf) + ", cmd: " + (data[0] >> 4) + ", type: " + (data[0] & 0xf0) + " , note: " + data[1] + " , velocity: " + data[2] + "]";
container.textContent = messages;
}
})();
</script>
</body>
</html>
答案 0 :(得分:0)
addAudioProperties()
功能中有一行,每次都将播放速率设置为随机。您可以通过将播放速率设置为1来删除它:
s.playbackRate.value = randomRange(0.5, 2);
变为
s.playbackRate.value = 1;