new "getSoundAttribute" reporter primitive

pull/89/head
jmoenig 2019-04-08 14:21:02 +02:00
rodzic 4e4d4cb5db
commit 6b874c18f3
5 zmienionych plików z 122 dodań i 6 usunięć

Wyświetl plik

@ -16,6 +16,7 @@
* selectors for changing and querying "draggable" and "rotation style" settings
* new sound + music "volume" feature + blocks
* new sound + music stereo "panning" feature + blocks
* new sound attribute getter reporter
* 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
@ -57,6 +58,9 @@
* German
* French
### 2019-04-08
* Blocks, Objects, Threads: new "getSoundAttribute" reporter primitive
### 2019-04-05
* Objects: eliminated "clicks" when playing music notes
* Objects: eliminated "clicks" when playing a frequency

Wyświetl plik

@ -6,9 +6,9 @@
<link rel="shortcut icon" href="src/favicon.ico">
<script type="text/javascript" src="src/morphic.js?version=2019-02-07"></script>
<script type="text/javascript" src="src/widgets.js?version=2019-04-05"></script>
<script type="text/javascript" src="src/blocks.js?version=2019-04-04"></script>
<script type="text/javascript" src="src/threads.js?version=2019-04-07"></script>
<script type="text/javascript" src="src/objects.js?version=2019-04-05"></script>
<script type="text/javascript" src="src/blocks.js?version=2019-04-08"></script>
<script type="text/javascript" src="src/threads.js?version=2019-04-08"></script>
<script type="text/javascript" src="src/objects.js?version=2019-04-08"></script>
<script type="text/javascript" src="src/gui.js?version=2019-03-25"></script>
<script type="text/javascript" src="src/paint.js?version=2019-02-22"></script>
<script type="text/javascript" src="src/lists.js?version=2019-02-07"></script>

Wyświetl plik

@ -148,7 +148,7 @@ CustomCommandBlockMorph, SymbolMorph, ToggleButtonMorph, DialMorph*/
// Global stuff ////////////////////////////////////////////////////////
modules.blocks = '2019-April-05';
modules.blocks = '2019-April-08';
var SyntaxElementMorph;
var BlockMorph;
@ -995,6 +995,21 @@ SyntaxElementMorph.prototype.labelPart = function (spec) {
true // read-only
);
break;
case '%aa': // audio attributes
part = new InputSlotMorph(
null, // text
false, // numeric?
{
'name' : ['name'],
'duration' : ['duration'],
'length' : ['length'],
'number of channels' : ['number of channels'],
'sample rate' : ['sample rate'],
'samples' : ['samples']
},
true // read-only
);
break;
case '%month':
part = new InputSlotMorph(
null, // text

Wyświetl plik

@ -84,7 +84,7 @@ BlockEditorMorph, BlockDialogMorph, PrototypeHatBlockMorph, localize,
TableMorph, TableFrameMorph, normalizeCanvas, BooleanSlotMorph, HandleMorph,
AlignmentMorph, Process, XML_Element, VectorPaintEditorMorph*/
modules.objects = '2019-April-05';
modules.objects = '2019-April-08';
var SpriteMorph;
var StageMorph;
@ -439,6 +439,12 @@ SpriteMorph.prototype.initBlocks = function () {
category: 'sound',
spec: 'stop all sounds'
},
reportGetSoundAttribute: {
type: 'reporter',
category: 'sound',
spec: '%aa of sound %snd',
defaults: [['duration']]
},
doRest: {
type: 'command',
category: 'sound',
@ -2029,6 +2035,8 @@ SpriteMorph.prototype.blockTemplates = function (category) {
blocks.push(block('doPlaySoundUntilDone'));
blocks.push(block('doStopAllSounds'));
blocks.push('-');
blocks.push(block('reportGetSoundAttribute'));
blocks.push('-');
blocks.push(block('doRest'));
blocks.push(block('doPlayNote'));
blocks.push(block('doSetInstrument'));
@ -7509,6 +7517,8 @@ StageMorph.prototype.blockTemplates = function (category) {
blocks.push(block('doPlaySoundUntilDone'));
blocks.push(block('doStopAllSounds'));
blocks.push('-');
blocks.push(block('reportGetSoundAttribute'));
blocks.push('-');
blocks.push(block('doRest'));
blocks.push(block('doPlayNote'));
blocks.push(block('doSetInstrument'));
@ -9140,6 +9150,13 @@ CostumeEditorMorph.prototype.mouseMove
function Sound(audio, name) {
this.audio = audio; // mandatory
this.name = name || "Sound";
// cached samples, don't persist
this.cachedSamples = null;
// internal for decoding, don't persist
this.audioBuffer = null; // for decoding ops
this.isDecoding = false;
}
Sound.prototype.play = function () {

Wyświetl plik

@ -62,7 +62,7 @@ StageMorph, SpriteMorph, StagePrompterMorph, Note, modules, isString, copy,
isNil, WatcherMorph, List, ListWatcherMorph, alert, console, TableMorph, Color,
TableFrameMorph, ColorSlotMorph, isSnapObject, Map*/
modules.threads = '2019-April-07';
modules.threads = '2019-April-08';
var ThreadManager;
var Process;
@ -2249,6 +2249,86 @@ Process.prototype.doStopAllSounds = function () {
}
};
Process.prototype.reportGetSoundAttribute = function (choice, soundName) {
var sound = soundName instanceof Sound ? soundName : detect(
this.blockReceiver().sounds.asArray(),
function (s) {return s.name === soundName.toString(); }
),
option = this.inputOption(choice);
if (option === 'name') {
return sound.name;
}
if (!sound.audioBuffer) {
this.decodeSound(sound);
return;
}
switch (option) {
case 'samples':
if (!sound.cachedSamples) {
sound.cachedSamples = function (sound) {
var buf = sound.audioBuffer,
result, i;
if (buf.numberOfChannels > 1) {
result = new List();
for (i = 0; i < buf.numberOfChannels; i += 1) {
result.add(new List(buf.getChannelData(i)));
}
return result;
}
return new List(buf.getChannelData(0));
} (sound);
}
return sound.cachedSamples;
case 'sample rate':
return sound.audioBuffer.sampleRate;
case 'duration':
return sound.audioBuffer.duration;
case 'length':
return sound.audioBuffer.length;
case 'number of channels':
return sound.audioBuffer.numberOfChannels;
default:
return 0;
}
};
Process.prototype.decodeSound = function (sound, callback) {
// private - callback is optional and invoked with sound as argument
var base64, binaryString, len, bytes, i, arrayBuffer, audioCtx,
myself = this;
if (sound.audioBuffer) {
return (callback || nop)(sound);
}
if (!sound.isDecoding) {
base64 = sound.audio.src.split(',')[1];
binaryString = window.atob(base64);
len = binaryString.length;
bytes = new Uint8Array(len);
for (i = 0; i < len; i += 1) {
bytes[i] = binaryString.charCodeAt(i);
}
arrayBuffer = bytes.buffer;
audioCtx = Note.prototype.getAudioContext();
sound.isDecoding = true;
audioCtx.decodeAudioData(
arrayBuffer,
function(buffer) {
sound.audioBuffer = buffer;
sound.isDecoding = false;
},
function (err) {
sound.isDecoding = false;
myself.handleError(err);
}
);
}
this.pushContext('doYield');
this.pushContext();
};
// Process audio input (interpolated)
Process.prototype.reportAudio = function (choice) {