mirror of
https://github.com/scratchfoundation/scratch-vm.git
synced 2024-12-24 06:52:40 -05:00
Add support for scratch 1.x MIDI drum blocks
This commit is contained in:
parent
e0550db404
commit
f617723348
1 changed files with 116 additions and 7 deletions
|
@ -611,6 +611,64 @@ class Scratch3MusicBlocks {
|
|||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* An array that is a mapping from MIDI drum numbers in range (35..81) to Scratch drum numbers.
|
||||
* It's in the format [drumNum, pitch, decay].
|
||||
* The pitch and decay properties are not currently being used.
|
||||
* @type {Array[]}
|
||||
*/
|
||||
get MIDI_DRUMS () {
|
||||
return [
|
||||
[1, -4], // "BassDrum" in 2.0, "Bass Drum" in 3.0 (which was "Tom" in 2.0)
|
||||
[1, 0], // Same as just above
|
||||
[2, 0],
|
||||
[0, 0],
|
||||
[7, 0],
|
||||
[0, 2],
|
||||
[1, -6, 4],
|
||||
[5, 0],
|
||||
[1, -3, 3.2],
|
||||
[5, 0], // "HiHatPedal" in 2.0, "Closed Hi-Hat" in 3.0
|
||||
[1, 0, 3],
|
||||
[4, -8],
|
||||
[1, 4, 3],
|
||||
[1, 7, 2.7],
|
||||
[3, -8],
|
||||
[1, 10, 2.7],
|
||||
[4, -2],
|
||||
[3, -11],
|
||||
[4, 2],
|
||||
[6, 0],
|
||||
[3, 0, 3.5],
|
||||
[10, 0],
|
||||
[3, -8, 3.5],
|
||||
[16, -6],
|
||||
[4, 2],
|
||||
[12, 2],
|
||||
[12, 0],
|
||||
[13, 0, 0.2],
|
||||
[13, 0, 2],
|
||||
[13, -5, 2],
|
||||
[12, 12],
|
||||
[12, 5],
|
||||
[10, 19],
|
||||
[10, 12],
|
||||
[14, 0],
|
||||
[14, 0], // "Maracas" in 2.0, "Cabasa" in 3.0 (TODO: pitch up?)
|
||||
[17, 12],
|
||||
[17, 5],
|
||||
[15, 0], // "GuiroShort" in 2.0, "Guiro" in 3.0 (which was "GuiroLong" in 2.0) (TODO: decay?)
|
||||
[15, 0],
|
||||
[8, 0],
|
||||
[9, 0],
|
||||
[9, -4],
|
||||
[17, -5],
|
||||
[17, 0],
|
||||
[11, -6, 1],
|
||||
[11, -6, 3]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* The key to load & store a target's music-related state.
|
||||
* @type {string}
|
||||
|
@ -725,6 +783,27 @@ class Scratch3MusicBlocks {
|
|||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
opcode: 'midiPlayDrumForBeats',
|
||||
blockType: BlockType.COMMAND,
|
||||
text: formatMessage({
|
||||
id: 'music.midiPlayDrumForBeats',
|
||||
default: 'play drum [DRUM] for [BEATS] beats',
|
||||
description: 'play drum sample for a number of beats according to a mapping of MIDI codes'
|
||||
}),
|
||||
arguments: {
|
||||
DRUM: {
|
||||
type: ArgumentType.NUMBER,
|
||||
menu: 'DRUM',
|
||||
defaultValue: 1
|
||||
},
|
||||
BEATS: {
|
||||
type: ArgumentType.NUMBER,
|
||||
defaultValue: 0.25
|
||||
}
|
||||
},
|
||||
hideFromPalette: true
|
||||
},
|
||||
{
|
||||
opcode: 'restForBeats',
|
||||
blockType: BlockType.COMMAND,
|
||||
|
@ -846,14 +925,44 @@ class Scratch3MusicBlocks {
|
|||
* @property {number} BEATS - the duration in beats of the drum sound.
|
||||
*/
|
||||
playDrumForBeats (args, util) {
|
||||
this._playDrumForBeats(args.DRUM, args.BEATS, util);
|
||||
}
|
||||
|
||||
/**
|
||||
* Play a drum sound for some number of beats according to the range of "MIDI" drum codes supported.
|
||||
* This block is implemented for compatibility with old Scratch projects that use the
|
||||
* 'drum:duration:elapsed:from:' block.
|
||||
* @param {object} args - the block arguments.
|
||||
* @param {object} util - utility object provided by the runtime.
|
||||
*/
|
||||
midiPlayDrumForBeats (args, util) {
|
||||
let drumNum = Cast.toNumber(args.DRUM);
|
||||
drumNum = Math.round(drumNum);
|
||||
const midiDescription = this.MIDI_DRUMS[drumNum - 35];
|
||||
if (midiDescription) {
|
||||
drumNum = midiDescription[0];
|
||||
} else {
|
||||
drumNum = 2; // Default instrument used in Scratch 2.0
|
||||
}
|
||||
drumNum += 1; // drumNum input to _playDrumForBeats is one-indexed
|
||||
this._playDrumForBeats(drumNum, args.BEATS, util);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal code to play a drum sound for some number of beats.
|
||||
* @param {number} drumNum - the drum number.
|
||||
* @param {beats} beats - the duration in beats to pause after playing the sound.
|
||||
* @param {object} util - utility object provided by the runtime.
|
||||
*/
|
||||
_playDrumForBeats (drumNum, beats, util) {
|
||||
if (this._stackTimerNeedsInit(util)) {
|
||||
let drum = Cast.toNumber(args.DRUM);
|
||||
drum = Math.round(drum);
|
||||
drum -= 1; // drums are one-indexed
|
||||
drum = MathUtil.wrapClamp(drum, 0, this.DRUM_INFO.length - 1);
|
||||
let beats = Cast.toNumber(args.BEATS);
|
||||
drumNum = Cast.toNumber(drumNum);
|
||||
drumNum = Math.round(drumNum);
|
||||
drumNum -= 1; // drums are one-indexed
|
||||
drumNum = MathUtil.wrapClamp(drumNum, 0, this.DRUM_INFO.length - 1);
|
||||
beats = Cast.toNumber(beats);
|
||||
beats = this._clampBeats(beats);
|
||||
this._playDrumNum(util, drum);
|
||||
this._playDrumNum(util, drumNum);
|
||||
this._startStackTimer(util, this._beatsToSec(beats));
|
||||
} else {
|
||||
this._checkStackTimer(util);
|
||||
|
|
Loading…
Reference in a new issue