kopia lustrzana https://github.com/backface/turtlestitch
new "getSoundAttribute" reporter primitive
rodzic
4e4d4cb5db
commit
6b874c18f3
|
@ -16,6 +16,7 @@
|
||||||
* selectors for changing and querying "draggable" and "rotation style" settings
|
* selectors for changing and querying "draggable" and "rotation style" settings
|
||||||
* new sound + music "volume" feature + blocks
|
* new sound + music "volume" feature + blocks
|
||||||
* new sound + music stereo "panning" feature + blocks
|
* new sound + music stereo "panning" feature + blocks
|
||||||
|
* new sound attribute getter reporter
|
||||||
* new "play frequency" commands in the Sounds category
|
* new "play frequency" commands in the Sounds category
|
||||||
* added "neg" selector to monadic function reporter in "Operators" category
|
* added "neg" selector to monadic function reporter in "Operators" category
|
||||||
* added "log2" selector to monadic function reporter in "Operators" category
|
* added "log2" selector to monadic function reporter in "Operators" category
|
||||||
|
@ -57,6 +58,9 @@
|
||||||
* German
|
* German
|
||||||
* French
|
* French
|
||||||
|
|
||||||
|
### 2019-04-08
|
||||||
|
* Blocks, Objects, Threads: new "getSoundAttribute" reporter primitive
|
||||||
|
|
||||||
### 2019-04-05
|
### 2019-04-05
|
||||||
* Objects: eliminated "clicks" when playing music notes
|
* Objects: eliminated "clicks" when playing music notes
|
||||||
* Objects: eliminated "clicks" when playing a frequency
|
* Objects: eliminated "clicks" when playing a frequency
|
||||||
|
|
|
@ -6,9 +6,9 @@
|
||||||
<link rel="shortcut icon" href="src/favicon.ico">
|
<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/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/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/blocks.js?version=2019-04-08"></script>
|
||||||
<script type="text/javascript" src="src/threads.js?version=2019-04-07"></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-05"></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/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/paint.js?version=2019-02-22"></script>
|
||||||
<script type="text/javascript" src="src/lists.js?version=2019-02-07"></script>
|
<script type="text/javascript" src="src/lists.js?version=2019-02-07"></script>
|
||||||
|
|
|
@ -148,7 +148,7 @@ CustomCommandBlockMorph, SymbolMorph, ToggleButtonMorph, DialMorph*/
|
||||||
|
|
||||||
// Global stuff ////////////////////////////////////////////////////////
|
// Global stuff ////////////////////////////////////////////////////////
|
||||||
|
|
||||||
modules.blocks = '2019-April-05';
|
modules.blocks = '2019-April-08';
|
||||||
|
|
||||||
var SyntaxElementMorph;
|
var SyntaxElementMorph;
|
||||||
var BlockMorph;
|
var BlockMorph;
|
||||||
|
@ -995,6 +995,21 @@ SyntaxElementMorph.prototype.labelPart = function (spec) {
|
||||||
true // read-only
|
true // read-only
|
||||||
);
|
);
|
||||||
break;
|
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':
|
case '%month':
|
||||||
part = new InputSlotMorph(
|
part = new InputSlotMorph(
|
||||||
null, // text
|
null, // text
|
||||||
|
|
|
@ -84,7 +84,7 @@ BlockEditorMorph, BlockDialogMorph, PrototypeHatBlockMorph, localize,
|
||||||
TableMorph, TableFrameMorph, normalizeCanvas, BooleanSlotMorph, HandleMorph,
|
TableMorph, TableFrameMorph, normalizeCanvas, BooleanSlotMorph, HandleMorph,
|
||||||
AlignmentMorph, Process, XML_Element, VectorPaintEditorMorph*/
|
AlignmentMorph, Process, XML_Element, VectorPaintEditorMorph*/
|
||||||
|
|
||||||
modules.objects = '2019-April-05';
|
modules.objects = '2019-April-08';
|
||||||
|
|
||||||
var SpriteMorph;
|
var SpriteMorph;
|
||||||
var StageMorph;
|
var StageMorph;
|
||||||
|
@ -439,6 +439,12 @@ SpriteMorph.prototype.initBlocks = function () {
|
||||||
category: 'sound',
|
category: 'sound',
|
||||||
spec: 'stop all sounds'
|
spec: 'stop all sounds'
|
||||||
},
|
},
|
||||||
|
reportGetSoundAttribute: {
|
||||||
|
type: 'reporter',
|
||||||
|
category: 'sound',
|
||||||
|
spec: '%aa of sound %snd',
|
||||||
|
defaults: [['duration']]
|
||||||
|
},
|
||||||
doRest: {
|
doRest: {
|
||||||
type: 'command',
|
type: 'command',
|
||||||
category: 'sound',
|
category: 'sound',
|
||||||
|
@ -2029,6 +2035,8 @@ SpriteMorph.prototype.blockTemplates = function (category) {
|
||||||
blocks.push(block('doPlaySoundUntilDone'));
|
blocks.push(block('doPlaySoundUntilDone'));
|
||||||
blocks.push(block('doStopAllSounds'));
|
blocks.push(block('doStopAllSounds'));
|
||||||
blocks.push('-');
|
blocks.push('-');
|
||||||
|
blocks.push(block('reportGetSoundAttribute'));
|
||||||
|
blocks.push('-');
|
||||||
blocks.push(block('doRest'));
|
blocks.push(block('doRest'));
|
||||||
blocks.push(block('doPlayNote'));
|
blocks.push(block('doPlayNote'));
|
||||||
blocks.push(block('doSetInstrument'));
|
blocks.push(block('doSetInstrument'));
|
||||||
|
@ -7509,6 +7517,8 @@ StageMorph.prototype.blockTemplates = function (category) {
|
||||||
blocks.push(block('doPlaySoundUntilDone'));
|
blocks.push(block('doPlaySoundUntilDone'));
|
||||||
blocks.push(block('doStopAllSounds'));
|
blocks.push(block('doStopAllSounds'));
|
||||||
blocks.push('-');
|
blocks.push('-');
|
||||||
|
blocks.push(block('reportGetSoundAttribute'));
|
||||||
|
blocks.push('-');
|
||||||
blocks.push(block('doRest'));
|
blocks.push(block('doRest'));
|
||||||
blocks.push(block('doPlayNote'));
|
blocks.push(block('doPlayNote'));
|
||||||
blocks.push(block('doSetInstrument'));
|
blocks.push(block('doSetInstrument'));
|
||||||
|
@ -9140,6 +9150,13 @@ CostumeEditorMorph.prototype.mouseMove
|
||||||
function Sound(audio, name) {
|
function Sound(audio, name) {
|
||||||
this.audio = audio; // mandatory
|
this.audio = audio; // mandatory
|
||||||
this.name = name || "Sound";
|
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 () {
|
Sound.prototype.play = function () {
|
||||||
|
|
|
@ -62,7 +62,7 @@ StageMorph, SpriteMorph, StagePrompterMorph, Note, modules, isString, copy,
|
||||||
isNil, WatcherMorph, List, ListWatcherMorph, alert, console, TableMorph, Color,
|
isNil, WatcherMorph, List, ListWatcherMorph, alert, console, TableMorph, Color,
|
||||||
TableFrameMorph, ColorSlotMorph, isSnapObject, Map*/
|
TableFrameMorph, ColorSlotMorph, isSnapObject, Map*/
|
||||||
|
|
||||||
modules.threads = '2019-April-07';
|
modules.threads = '2019-April-08';
|
||||||
|
|
||||||
var ThreadManager;
|
var ThreadManager;
|
||||||
var Process;
|
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 audio input (interpolated)
|
||||||
|
|
||||||
Process.prototype.reportAudio = function (choice) {
|
Process.prototype.reportAudio = function (choice) {
|
||||||
|
|
Ładowanie…
Reference in New Issue