new "play sound at sample rate" command primitive

pull/89/head
jmoenig 2019-04-08 15:13:55 +02:00
rodzic 6b874c18f3
commit 1c9532edc3
4 zmienionych plików z 88 dodań i 0 usunięć

Wyświetl plik

@ -17,6 +17,7 @@
* new sound + music "volume" feature + blocks
* new sound + music stereo "panning" feature + blocks
* new sound attribute getter reporter
* new "play sound at sample rate" command
* new "play frequency" commands in the Sounds category
* added "neg" selector to monadic function reporter in "Operators" category
* added "log2" selector to monadic function reporter in "Operators" category
@ -60,6 +61,7 @@
### 2019-04-08
* Blocks, Objects, Threads: new "getSoundAttribute" reporter primitive
* Blocks, Objects, Threads: new "play sound at sample rate" command primitive
### 2019-04-05
* Objects: eliminated "clicks" when playing music notes

Wyświetl plik

@ -1010,6 +1010,19 @@ SyntaxElementMorph.prototype.labelPart = function (spec) {
true // read-only
);
break;
case '%rate':
part = new InputSlotMorph(
null,
true,
{
'22.05 kHz' : 22050,
'44.1 kHz' : 44100,
'88.2 kHz' : 88200,
'96 kHz' : 96000
}
);
part.setContents(1);
break;
case '%month':
part = new InputSlotMorph(
null, // text

Wyświetl plik

@ -434,6 +434,12 @@ SpriteMorph.prototype.initBlocks = function () {
category: 'sound',
spec: 'play sound %snd until done'
},
doPlaySoundAtRate: {
type: 'command',
category: 'sound',
spec: 'play sound %snd at %rate hz',
defaults: ['', 44100]
},
doStopAllSounds: {
type: 'command',
category: 'sound',
@ -2035,6 +2041,7 @@ SpriteMorph.prototype.blockTemplates = function (category) {
blocks.push(block('doPlaySoundUntilDone'));
blocks.push(block('doStopAllSounds'));
blocks.push('-');
blocks.push(block('doPlaySoundAtRate'));
blocks.push(block('reportGetSoundAttribute'));
blocks.push('-');
blocks.push(block('doRest'));
@ -7517,6 +7524,7 @@ StageMorph.prototype.blockTemplates = function (category) {
blocks.push(block('doPlaySoundUntilDone'));
blocks.push(block('doStopAllSounds'));
blocks.push('-');
blocks.push(block('doPlaySoundAtRate'));
blocks.push(block('reportGetSoundAttribute'));
blocks.push('-');
blocks.push(block('doRest'));

Wyświetl plik

@ -2249,6 +2249,71 @@ Process.prototype.doStopAllSounds = function () {
}
};
Process.prototype.doPlaySoundAtRate = function (name, rate) {
var sound, samples, ctx, gain, pan, channels, frameCount, arrayBuffer,
i, source, rcvr;
if (!(name instanceof List)) {
sound = name instanceof Sound ? name : detect(
this.blockReceiver().sounds.asArray(),
function (s) {return s.name === name.toString(); }
);
if (!sound.audioBuffer) {
this.decodeSound(sound);
return;
}
samples = this.reportGetSoundAttribute('samples', sound);
} else {
samples = name;
}
rcvr = this.blockReceiver();
ctx = rcvr.audioContext();
gain = rcvr.getGainNode();
pan = rcvr.getPannerNode();
channels = (samples.at(1) instanceof List) ? samples.length() : 1;
frameCount = (channels === 1) ? samples.length() : samples.at(1).length();
arrayBuffer = ctx.createBuffer(channels, frameCount, +rate || 44100);
if (!arrayBuffer.copyToChannel) {
arrayBuffer.copyToChannel = function (src, channel) {
var buffer = this.getChannelData(channel);
for (i = 0; i < src.length; i += 1) {
buffer[i] = src[i];
}
};
}
if (channels === 1) {
arrayBuffer.copyToChannel(
Float32Array.from(samples.asArray()),
0,
0
);
} else {
for (i = 0; i < channels; i += 1) {
arrayBuffer.copyToChannel(
Float32Array.from(samples.at(i + 1).asArray()),
i,
0
);
}
}
source = ctx.createBufferSource();
source.buffer = arrayBuffer;
rcvr.setVolume(rcvr.volume);
source.connect(gain);
if (pan) {
gain.connect(pan);
pan.connect(ctx.destination);
rcvr.setPan(rcvr.pan);
} else {
gain.connect(ctx.destination);
}
source.start();
source.pause = source.stop;
rcvr.parentThatIsA(StageMorph).activeSounds.push(source);
};
Process.prototype.reportGetSoundAttribute = function (choice, soundName) {
var sound = soundName instanceof Sound ? soundName : detect(
this.blockReceiver().sounds.asArray(),