kopia lustrzana https://github.com/backface/turtlestitch
added "new sound" from list of samples primitive reporter to "sound" category
rodzic
2b18ece5fe
commit
6306bcc279
|
@ -3,6 +3,7 @@
|
||||||
## in development:
|
## in development:
|
||||||
* **New Features:**
|
* **New Features:**
|
||||||
* new primitive in "looks": NEW COSTUME from a list of pixels and dimensions, allowing CURRENT
|
* new primitive in "looks": NEW COSTUME from a list of pixels and dimensions, allowing CURRENT
|
||||||
|
* new primitige in "sound": NEW SOUND from a list of samples
|
||||||
* added selectors for sprites' and the stage's bounding box (LEFT, RIGHT, TOP, BOTTOM) to MY dropdown
|
* added selectors for sprites' and the stage's bounding box (LEFT, RIGHT, TOP, BOTTOM) to MY dropdown
|
||||||
* **Notable Changes:**
|
* **Notable Changes:**
|
||||||
* running STOP ALL now also toggles (pauses and resumes) all generic WHEN hat blocks (just like pressing the stop button)
|
* running STOP ALL now also toggles (pauses and resumes) all generic WHEN hat blocks (just like pressing the stop button)
|
||||||
|
@ -12,6 +13,9 @@
|
||||||
* **Translation Updates:**
|
* **Translation Updates:**
|
||||||
* German
|
* German
|
||||||
|
|
||||||
|
### 2019-10-20
|
||||||
|
* objects, threads: added "new sound" from list of samples primitive reporter to "sound" category
|
||||||
|
|
||||||
### 2019-10-18
|
### 2019-10-18
|
||||||
* objects, blocks, threads: added dimension getters for the stage
|
* objects, blocks, threads: added dimension getters for the stage
|
||||||
* German translation update (left, right, top, bottom selectors in MY)
|
* German translation update (left, right, top, bottom selectors in MY)
|
||||||
|
|
|
@ -7,8 +7,8 @@
|
||||||
<script type="text/javascript" src="src/morphic.js?version=2019-10-16"></script>
|
<script type="text/javascript" src="src/morphic.js?version=2019-10-16"></script>
|
||||||
<script type="text/javascript" src="src/widgets.js?version=2019-10-16"></script>
|
<script type="text/javascript" src="src/widgets.js?version=2019-10-16"></script>
|
||||||
<script type="text/javascript" src="src/blocks.js?version=2019-10-18"></script>
|
<script type="text/javascript" src="src/blocks.js?version=2019-10-18"></script>
|
||||||
<script type="text/javascript" src="src/threads.js?version=2019-10-18"></script>
|
<script type="text/javascript" src="src/threads.js?version=2019-10-20"></script>
|
||||||
<script type="text/javascript" src="src/objects.js?version=2019-10-18"></script>
|
<script type="text/javascript" src="src/objects.js?version=2019-10-20"></script>
|
||||||
<script type="text/javascript" src="src/gui.js?version=2019-10-19"></script>
|
<script type="text/javascript" src="src/gui.js?version=2019-10-19"></script>
|
||||||
<script type="text/javascript" src="src/paint.js?version=2019-06-27"></script>
|
<script type="text/javascript" src="src/paint.js?version=2019-06-27"></script>
|
||||||
<script type="text/javascript" src="src/lists.js?version=2019-07-01"></script>
|
<script type="text/javascript" src="src/lists.js?version=2019-07-01"></script>
|
||||||
|
|
|
@ -84,7 +84,7 @@ BlockEditorMorph, BlockDialogMorph, PrototypeHatBlockMorph, BooleanSlotMorph,
|
||||||
localize, TableMorph, TableFrameMorph, normalizeCanvas, VectorPaintEditorMorph,
|
localize, TableMorph, TableFrameMorph, normalizeCanvas, VectorPaintEditorMorph,
|
||||||
HandleMorph, AlignmentMorph, Process, XML_Element, WorldMap*/
|
HandleMorph, AlignmentMorph, Process, XML_Element, WorldMap*/
|
||||||
|
|
||||||
modules.objects = '2019-October-18';
|
modules.objects = '2019-October-20';
|
||||||
|
|
||||||
var SpriteMorph;
|
var SpriteMorph;
|
||||||
var StageMorph;
|
var StageMorph;
|
||||||
|
@ -478,6 +478,11 @@ SpriteMorph.prototype.initBlocks = function () {
|
||||||
spec: '%aa of sound %snd',
|
spec: '%aa of sound %snd',
|
||||||
defaults: [['duration']]
|
defaults: [['duration']]
|
||||||
},
|
},
|
||||||
|
reportNewSoundFromSamples: {
|
||||||
|
type: 'reporter',
|
||||||
|
category: 'sound',
|
||||||
|
spec: 'new sound %l'
|
||||||
|
},
|
||||||
doRest: {
|
doRest: {
|
||||||
type: 'command',
|
type: 'command',
|
||||||
category: 'sound',
|
category: 'sound',
|
||||||
|
@ -2266,6 +2271,7 @@ SpriteMorph.prototype.blockTemplates = function (category) {
|
||||||
blocks.push('-');
|
blocks.push('-');
|
||||||
blocks.push(block('doPlaySoundAtRate'));
|
blocks.push(block('doPlaySoundAtRate'));
|
||||||
blocks.push(block('reportGetSoundAttribute'));
|
blocks.push(block('reportGetSoundAttribute'));
|
||||||
|
blocks.push(block('reportNewSoundFromSamples'));
|
||||||
blocks.push('-');
|
blocks.push('-');
|
||||||
blocks.push(block('doRest'));
|
blocks.push(block('doRest'));
|
||||||
blocks.push(block('doPlayNote'));
|
blocks.push(block('doPlayNote'));
|
||||||
|
@ -7227,6 +7233,25 @@ SpriteMorph.prototype.doScreenshot = function (imgSource, data) {
|
||||||
this.addCostume(costume);
|
this.addCostume(costume);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// SpriteMorph adding sounds
|
||||||
|
|
||||||
|
SpriteMorph.prototype.newSoundName = function (name, ignoredSound) {
|
||||||
|
var ix = name.indexOf('('),
|
||||||
|
stem = (ix < 0) ? name : name.substring(0, ix),
|
||||||
|
count = 1,
|
||||||
|
newName = stem,
|
||||||
|
all = this.sounds.asArray().filter(
|
||||||
|
function (each) {return each !== ignoredSound; }
|
||||||
|
).map(
|
||||||
|
function (each) {return each.name; }
|
||||||
|
);
|
||||||
|
while (contains(all, newName)) {
|
||||||
|
count += 1;
|
||||||
|
newName = stem + '(' + count + ')';
|
||||||
|
}
|
||||||
|
return newName;
|
||||||
|
};
|
||||||
|
|
||||||
// SpriteHighlightMorph /////////////////////////////////////////////////
|
// SpriteHighlightMorph /////////////////////////////////////////////////
|
||||||
|
|
||||||
// SpriteHighlightMorph inherits from Morph:
|
// SpriteHighlightMorph inherits from Morph:
|
||||||
|
@ -8317,6 +8342,7 @@ StageMorph.prototype.blockTemplates = function (category) {
|
||||||
blocks.push('-');
|
blocks.push('-');
|
||||||
blocks.push(block('doPlaySoundAtRate'));
|
blocks.push(block('doPlaySoundAtRate'));
|
||||||
blocks.push(block('reportGetSoundAttribute'));
|
blocks.push(block('reportGetSoundAttribute'));
|
||||||
|
blocks.push(block('reportNewSoundFromSamples'));
|
||||||
blocks.push('-');
|
blocks.push('-');
|
||||||
blocks.push(block('doRest'));
|
blocks.push(block('doRest'));
|
||||||
blocks.push(block('doPlayNote'));
|
blocks.push(block('doPlayNote'));
|
||||||
|
|
|
@ -61,7 +61,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, newCanvas, Symbol*/
|
TableFrameMorph, ColorSlotMorph, isSnapObject, Map, newCanvas, Symbol*/
|
||||||
|
|
||||||
modules.threads = '2019-October-18';
|
modules.threads = '2019-October-20';
|
||||||
|
|
||||||
var ThreadManager;
|
var ThreadManager;
|
||||||
var Process;
|
var Process;
|
||||||
|
@ -2816,6 +2816,99 @@ Process.prototype.encodeSound = function (samples, rate) {
|
||||||
return source;
|
return source;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Process first-class sound creation from samples, interpolated
|
||||||
|
|
||||||
|
Process.prototype.reportNewSoundFromSamples = function (samples) {
|
||||||
|
// interpolated
|
||||||
|
var audio, blob, reader,
|
||||||
|
myself = this;
|
||||||
|
|
||||||
|
if (isNil(this.context.accumulator)) {
|
||||||
|
this.context.accumulator = {
|
||||||
|
audio: null
|
||||||
|
};
|
||||||
|
audio = new Audio();
|
||||||
|
blob = this.audioBufferToWaveBlob(
|
||||||
|
this.encodeSound(samples, 44100).audioBuffer,
|
||||||
|
samples.length()
|
||||||
|
);
|
||||||
|
reader = new FileReader();
|
||||||
|
reader.onload = function () {
|
||||||
|
audio.src = reader.result;
|
||||||
|
myself.context.accumulator.audio = audio;
|
||||||
|
};
|
||||||
|
reader.readAsDataURL(blob);
|
||||||
|
}
|
||||||
|
if (this.context.accumulator.audio) {
|
||||||
|
return new Sound(
|
||||||
|
this.context.accumulator.audio,
|
||||||
|
this.blockReceiver().newSoundName(localize('sound'))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
this.pushContext('doYield');
|
||||||
|
this.pushContext();
|
||||||
|
};
|
||||||
|
|
||||||
|
Process.prototype.audioBufferToWaveBlob = function (aBuffer, len) {
|
||||||
|
// Convert AudioBuffer to a Blob using WAVE representation
|
||||||
|
// taken from:
|
||||||
|
// https://www.russellgood.com/how-to-convert-audiobuffer-to-audio-file/
|
||||||
|
|
||||||
|
var numOfChan = aBuffer.numberOfChannels,
|
||||||
|
length = len * numOfChan * 2 + 44,
|
||||||
|
buffer = new ArrayBuffer(length),
|
||||||
|
view = new DataView(buffer),
|
||||||
|
channels = [], i, sample,
|
||||||
|
offset = 0,
|
||||||
|
pos = 0;
|
||||||
|
|
||||||
|
function setUint16(data) {
|
||||||
|
view.setUint16(pos, data, true);
|
||||||
|
pos += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setUint32(data) {
|
||||||
|
view.setUint32(pos, data, true);
|
||||||
|
pos += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// write WAVE header
|
||||||
|
setUint32(0x46464952); // "RIFF"
|
||||||
|
setUint32(length - 8); // file length - 8
|
||||||
|
setUint32(0x45564157); // "WAVE"
|
||||||
|
|
||||||
|
setUint32(0x20746d66); // "fmt " chunk
|
||||||
|
setUint32(16); // length = 16
|
||||||
|
setUint16(1); // PCM (uncompressed)
|
||||||
|
setUint16(numOfChan);
|
||||||
|
setUint32(aBuffer.sampleRate);
|
||||||
|
setUint32(aBuffer.sampleRate * 2 * numOfChan); // avg. bytes/sec
|
||||||
|
setUint16(numOfChan * 2); // block-align
|
||||||
|
setUint16(16); // 16-bit (hardcoded in this demo)
|
||||||
|
|
||||||
|
setUint32(0x61746164); // "data" - chunk
|
||||||
|
setUint32(length - pos - 4); // chunk length
|
||||||
|
|
||||||
|
// write interleaved data
|
||||||
|
for (i = 0; i < aBuffer.numberOfChannels; i += 1) {
|
||||||
|
channels.push(aBuffer.getChannelData(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
while (pos < length) {
|
||||||
|
for (i = 0; i < numOfChan; i += 1) { // interleave channels
|
||||||
|
sample = Math.max(-1, Math.min(1, channels[i][offset])); // clamp
|
||||||
|
// scale to 16-bit signed int:
|
||||||
|
sample = (0.5 + sample < 0 ? sample * 32768 : sample * 32767) | 0;
|
||||||
|
view.setInt16(pos, sample, true); // write 16-bit sample
|
||||||
|
pos += 2;
|
||||||
|
}
|
||||||
|
offset += 1; // next source sample
|
||||||
|
}
|
||||||
|
|
||||||
|
// create Blob
|
||||||
|
return new Blob([buffer], {type: "audio/wav"});
|
||||||
|
};
|
||||||
|
|
||||||
// Process audio input (interpolated)
|
// Process audio input (interpolated)
|
||||||
|
|
||||||
Process.prototype.reportAudio = function (choice) {
|
Process.prototype.reportAudio = function (choice) {
|
||||||
|
|
Ładowanie…
Reference in New Issue