改声音目录
This commit is contained in:
@@ -7,12 +7,12 @@ export const sound_play_frequency = {
|
|||||||
.appendField(Blockly.Msg.MIXLY_SOUND_PLAY)
|
.appendField(Blockly.Msg.MIXLY_SOUND_PLAY)
|
||||||
.appendField(Blockly.Msg.MIXLY_SOUND_FREQUENCY);
|
.appendField(Blockly.Msg.MIXLY_SOUND_FREQUENCY);
|
||||||
this.appendValueInput("FREQUENCY")
|
this.appendValueInput("FREQUENCY")
|
||||||
.setCheck(null)
|
.setCheck(Number)
|
||||||
.setAlign(Blockly.ALIGN_RIGHT);
|
.setAlign(Blockly.ALIGN_RIGHT);
|
||||||
this.appendDummyInput()
|
this.appendDummyInput()
|
||||||
.appendField(Blockly.Msg.MIXLY_SOUND_DURATION);
|
.appendField(Blockly.Msg.MIXLY_SOUND_DURATION);
|
||||||
this.appendValueInput("DURATION")
|
this.appendValueInput("DURATION")
|
||||||
.setCheck(null)
|
.setCheck(Number)
|
||||||
.setAlign(Blockly.ALIGN_RIGHT);
|
.setAlign(Blockly.ALIGN_RIGHT);
|
||||||
this.setPreviousStatement(true);
|
this.setPreviousStatement(true);
|
||||||
this.setNextStatement(true);
|
this.setNextStatement(true);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ export const sound_play_frequency_no_duration = {
|
|||||||
init: function() {
|
init: function() {
|
||||||
this.setColour('#acc159');
|
this.setColour('#acc159');
|
||||||
this.appendValueInput("FREQUENCY")
|
this.appendValueInput("FREQUENCY")
|
||||||
.setCheck(null)
|
.setCheck(Number)
|
||||||
.appendField(Blockly.Msg.MIXLY_SOUND_PLAY_FREQUENCY_NO_DURATION);
|
.appendField(Blockly.Msg.MIXLY_SOUND_PLAY_FREQUENCY_NO_DURATION);
|
||||||
this.setPreviousStatement(true);
|
this.setPreviousStatement(true);
|
||||||
this.setNextStatement(true);
|
this.setNextStatement(true);
|
||||||
|
|||||||
@@ -4,8 +4,7 @@ export const sound_play_note_list = {
|
|||||||
init: function() {
|
init: function() {
|
||||||
this.setColour('#acc159');
|
this.setColour('#acc159');
|
||||||
this.appendDummyInput()
|
this.appendDummyInput()
|
||||||
.appendField(Blockly.Msg.MIXLY_SOUND_PLAY_NOTE_LIST);
|
.appendField(Blockly.Msg.MIXLY_SOUND_PLAY_NOTE_LIST)
|
||||||
this.appendDummyInput()
|
|
||||||
.appendField(new Blockly.FieldDropdown([
|
.appendField(new Blockly.FieldDropdown([
|
||||||
["DADADADUM", "DADADADUM"],
|
["DADADADUM", "DADADADUM"],
|
||||||
["BIRTHDAY", "BIRTHDAY"],
|
["BIRTHDAY", "BIRTHDAY"],
|
||||||
|
|||||||
@@ -1,23 +1,24 @@
|
|||||||
import * as Blockly from 'blockly/core';
|
import * as Blockly from 'blockly/core';
|
||||||
|
|
||||||
export const sound_note = {
|
export const sound_note = {
|
||||||
init: function() {
|
init: function () {
|
||||||
this.setColour('#acc159');
|
this.setColour('#acc159');
|
||||||
this.appendDummyInput()
|
this.appendDummyInput()
|
||||||
.appendField(new Blockly.FieldDropdown([
|
.appendField(new Blockly.FieldDropdown([
|
||||||
["NOTE_B3", "NOTE_B3"],
|
["NOTE_A4", "440"],
|
||||||
["NOTE_C4", "NOTE_C4"],
|
["NOTE_B3", "247"],
|
||||||
["NOTE_D4", "NOTE_D4"],
|
["NOTE_C4", "262"],
|
||||||
["NOTE_E4", "NOTE_E4"],
|
["NOTE_D4", "294"],
|
||||||
["NOTE_F4", "NOTE_F4"],
|
["NOTE_E4", "330"],
|
||||||
["NOTE_G4", "NOTE_G4"],
|
["NOTE_F4", "349"],
|
||||||
["NOTE_A4", "NOTE_A4"],
|
["NOTE_G4", "392"],
|
||||||
["NOTE_B4", "NOTE_B4"],
|
["NOTE_A4", "440"],
|
||||||
["NOTE_C5", "NOTE_C5"],
|
["NOTE_B4", "494"],
|
||||||
["NOTE_D5", "NOTE_D5"],
|
["NOTE_C5", "523"],
|
||||||
["NOTE_E5", "NOTE_E5"],
|
["NOTE_D5", "587"],
|
||||||
["NOTE_F5", "NOTE_F5"],
|
["NOTE_E5", "659"],
|
||||||
["NOTE_G5", "NOTE_G5"]
|
["NOTE_F5", "698"],
|
||||||
|
["NOTE_G5", "784"]
|
||||||
]), "NOTE");
|
]), "NOTE");
|
||||||
this.setOutput(true, null);
|
this.setOutput(true, null);
|
||||||
this.setOutputShape(Blockly.OUTPUT_SHAPE_ROUND);
|
this.setOutputShape(Blockly.OUTPUT_SHAPE_ROUND);
|
||||||
|
|||||||
@@ -1,75 +1,10 @@
|
|||||||
function hasPlayWaitBefore(block) {
|
export const sound_play_frequency = function (_block, generator) {
|
||||||
let currentBlock = block.getPreviousBlock();
|
|
||||||
while (currentBlock) {
|
|
||||||
if (currentBlock.type === 'sound_play_wait') {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
currentBlock = currentBlock.getPreviousBlock();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const sound_play_frequency = function(_block, generator) {
|
|
||||||
if (!generator.definitions_['import_sound']) {
|
if (!generator.definitions_['import_sound']) {
|
||||||
generator.definitions_['import_sound'] = 'import sound';
|
generator.definitions_['import_sound'] = 'import sound';
|
||||||
}
|
}
|
||||||
|
|
||||||
const frequencyInput = _block.getInputTargetBlock("FREQUENCY");
|
const frequencyInput = generator.valueToCode(this, "FREQUENCY", generator.ORDER_ATOMIC);
|
||||||
const durationInput = _block.getInputTargetBlock("DURATION");
|
const durationInput = generator.valueToCode(this, "DURATION", generator.ORDER_ATOMIC);
|
||||||
let frequencyCode, durationCode;
|
|
||||||
|
|
||||||
if (frequencyInput) {
|
return `sound.play_frequency(${frequencyInput}, ${durationInput})\n`;
|
||||||
try {
|
|
||||||
if (frequencyInput.type === "sound_note") {
|
|
||||||
const note = frequencyInput.getFieldValue("NOTE") || "NOTE_A4";
|
|
||||||
const noteFrequencies = {
|
|
||||||
"NOTE_B3": 247,
|
|
||||||
"NOTE_C4": 262,
|
|
||||||
"NOTE_D4": 294,
|
|
||||||
"NOTE_E4": 330,
|
|
||||||
"NOTE_F4": 349,
|
|
||||||
"NOTE_G4": 392,
|
|
||||||
"NOTE_A4": 440,
|
|
||||||
"NOTE_B4": 494,
|
|
||||||
"NOTE_C5": 523,
|
|
||||||
"NOTE_D5": 587,
|
|
||||||
"NOTE_E5": 659,
|
|
||||||
"NOTE_F5": 698,
|
|
||||||
"NOTE_G5": 784
|
|
||||||
};
|
|
||||||
frequencyCode = noteFrequencies[note] || 440;
|
|
||||||
} else if (frequencyInput.type === "math_number") {
|
|
||||||
const numValue = frequencyInput.getFieldValue("NUM");
|
|
||||||
frequencyCode = numValue || "440";
|
|
||||||
} else {
|
|
||||||
frequencyCode = generator.valueToCode(frequencyInput, "FREQUENCY", generator.ORDER_ATOMIC);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.warn("生成频率代码时出错:", error);
|
|
||||||
frequencyCode = "440";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
frequencyCode = "440";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (durationInput) {
|
|
||||||
try {
|
|
||||||
if (durationInput.type === "math_number") {
|
|
||||||
const numValue = durationInput.getFieldValue("NUM");
|
|
||||||
durationCode = numValue || "1000";
|
|
||||||
} else {
|
|
||||||
durationCode = generator.valueToCode(durationInput, "DURATION", generator.ORDER_ATOMIC);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.warn("生成持续时间代码时出错:", error);
|
|
||||||
durationCode = "1000";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
durationCode = "1000";
|
|
||||||
}
|
|
||||||
|
|
||||||
const useBlocking = hasPlayWaitBefore(_block);
|
|
||||||
const methodName = useBlocking ? 'play_frequency_blocking' : 'play_frequency';
|
|
||||||
|
|
||||||
return `sound.${methodName}(${frequencyCode}, ${durationCode})\n`;
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,58 +1,9 @@
|
|||||||
function hasPlayWaitBefore(block) {
|
export const sound_play_frequency_no_duration = function (_block, generator) {
|
||||||
let currentBlock = block.getPreviousBlock();
|
|
||||||
while (currentBlock) {
|
|
||||||
if (currentBlock.type === 'sound_play_wait') {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
currentBlock = currentBlock.getPreviousBlock();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const sound_play_frequency_no_duration = function(_block, generator) {
|
|
||||||
if (!generator.definitions_['import_sound']) {
|
if (!generator.definitions_['import_sound']) {
|
||||||
generator.definitions_['import_sound'] = 'import sound';
|
generator.definitions_['import_sound'] = 'import sound';
|
||||||
}
|
}
|
||||||
|
|
||||||
const frequencyInput = _block.getInputTargetBlock("FREQUENCY");
|
const frequencyInput = generator.valueToCode(this, "FREQUENCY", generator.ORDER_ATOMIC);
|
||||||
let frequencyCode;
|
|
||||||
|
|
||||||
if (frequencyInput) {
|
return `sound.play_frequency_no_duration(${frequencyInput})\n`;
|
||||||
try {
|
|
||||||
if (frequencyInput.type === "sound_note") {
|
|
||||||
const note = frequencyInput.getFieldValue("NOTE") || "NOTE_A4";
|
|
||||||
const noteFrequencies = {
|
|
||||||
"NOTE_B3": 247,
|
|
||||||
"NOTE_C4": 262,
|
|
||||||
"NOTE_D4": 294,
|
|
||||||
"NOTE_E4": 330,
|
|
||||||
"NOTE_F4": 349,
|
|
||||||
"NOTE_G4": 392,
|
|
||||||
"NOTE_A4": 440,
|
|
||||||
"NOTE_B4": 494,
|
|
||||||
"NOTE_C5": 523,
|
|
||||||
"NOTE_D5": 587,
|
|
||||||
"NOTE_E5": 659,
|
|
||||||
"NOTE_F5": 698,
|
|
||||||
"NOTE_G5": 784
|
|
||||||
};
|
|
||||||
frequencyCode = noteFrequencies[note] || 440;
|
|
||||||
} else if (frequencyInput.type === "math_number") {
|
|
||||||
const numValue = frequencyInput.getFieldValue("NUM");
|
|
||||||
frequencyCode = numValue || "440";
|
|
||||||
} else {
|
|
||||||
frequencyCode = generator.valueToCode(frequencyInput, "FREQUENCY", generator.ORDER_ATOMIC);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.warn("生成频率代码时出错:", error);
|
|
||||||
frequencyCode = "440";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
frequencyCode = "440";
|
|
||||||
}
|
|
||||||
|
|
||||||
const useBlocking = hasPlayWaitBefore(_block);
|
|
||||||
const methodName = useBlocking ? 'play_frequency_blocking' : 'play_frequency';
|
|
||||||
|
|
||||||
return `sound.${methodName}(${frequencyCode}, 0)\n`;
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,23 +1,9 @@
|
|||||||
function hasPlayWaitBefore(block) {
|
|
||||||
let currentBlock = block.getPreviousBlock();
|
|
||||||
while (currentBlock) {
|
|
||||||
if (currentBlock.type === 'sound_play_wait') {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
currentBlock = currentBlock.getPreviousBlock();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const sound_play_note_list = function(_block, _generator) {
|
export const sound_play_note_list = function(_block, _generator) {
|
||||||
if (!_generator.definitions_['import_sound']) {
|
if (!_generator.definitions_['import_sound']) {
|
||||||
_generator.definitions_['import_sound'] = 'import sound';
|
_generator.definitions_['import_sound'] = 'import sound';
|
||||||
}
|
}
|
||||||
|
|
||||||
const noteList = _block.getFieldValue("NOTE_LIST") || "DADADADUM";
|
const noteList = this.getFieldValue("NOTE_LIST");
|
||||||
|
|
||||||
const useBlocking = hasPlayWaitBefore(_block);
|
return `sound.play_note_list("${noteList}")\n`;
|
||||||
const methodName = useBlocking ? 'play_note_list_blocking' : 'play_note_list';
|
|
||||||
|
|
||||||
return `sound.${methodName}("${noteList}")\n`;
|
|
||||||
};
|
};
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
export const sound_note = function(_block, generator) {
|
export const sound_note = function (_block, generator) {
|
||||||
const note = _block.getFieldValue("NOTE") || "NOTE_A4";
|
// 获取频率值(字符串格式)
|
||||||
return [`"${note}"`, generator.ORDER_ATOMIC];
|
const frequency = this.getFieldValue("NOTE");
|
||||||
|
return [frequency, generator.ORDER_ATOMIC];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -156,79 +156,58 @@ Object.assign(
|
|||||||
import { sound_play } from './blocks/sound/play/play.js';
|
import { sound_play } from './blocks/sound/play/play.js';
|
||||||
import { sound_play_wait } from './blocks/sound/play/play_wait.js';
|
import { sound_play_wait } from './blocks/sound/play/play_wait.js';
|
||||||
import { sound_stop_all } from './blocks/sound/play/sound_stop_all.js';
|
import { sound_stop_all } from './blocks/sound/play/sound_stop_all.js';
|
||||||
|
|
||||||
import { sound_effect_add } from './blocks/sound/effect/add.js';
|
import { sound_effect_add } from './blocks/sound/effect/add.js';
|
||||||
import { sound_effect_set } from './blocks/sound/effect/sound_effect_set.js';
|
import { sound_effect_set } from './blocks/sound/effect/sound_effect_set.js';
|
||||||
import { sound_effect_clear } from './blocks/sound/effect/sound_effect_clear.js';
|
import { sound_effect_clear } from './blocks/sound/effect/sound_effect_clear.js';
|
||||||
|
|
||||||
import { sound_volume_add } from './blocks/sound/volume/add.js';
|
import { sound_volume_add } from './blocks/sound/volume/add.js';
|
||||||
import { sound_volume_set } from './blocks/sound/volume/set.js';
|
import { sound_volume_set } from './blocks/sound/volume/set.js';
|
||||||
import { sound_volume_get } from './blocks/sound/volume/get.js';
|
import { sound_volume_get } from './blocks/sound/volume/get.js';
|
||||||
|
|
||||||
import { sound_record } from './blocks/sound/play/record.js';
|
import { sound_record } from './blocks/sound/play/record.js';
|
||||||
|
|
||||||
import { sound_play_frequency } from './blocks/sound/play/play_frequency.js';
|
import { sound_play_frequency } from './blocks/sound/play/play_frequency.js';
|
||||||
import { sound_play_frequency_no_duration } from './blocks/sound/play/play_frequency_no_duration.js';
|
import { sound_play_frequency_no_duration } from './blocks/sound/play/play_frequency_no_duration.js';
|
||||||
import { sound_play_note_list } from './blocks/sound/play/play_note_list.js';
|
import { sound_play_note_list } from './blocks/sound/play/play_note_list.js';
|
||||||
import { sound_note } from './blocks/sound/play/sound_note.js';
|
import { sound_note } from './blocks/sound/play/sound_note.js';
|
||||||
|
|
||||||
import { sound_play as sound_play_gen } from './generators/sound/play/play.js';
|
import { sound_play as sound_play_gen } from './generators/sound/play/play.js';
|
||||||
import { sound_play_wait as sound_play_wait_gen } from './generators/sound/play/play_wait.js';
|
import { sound_play_wait as sound_play_wait_gen } from './generators/sound/play/play_wait.js';
|
||||||
import { sound_stop_all as sound_stop_all_gen } from './generators/sound/play/sound_stop_all.js';
|
import { sound_stop_all as sound_stop_all_gen } from './generators/sound/play/sound_stop_all.js';
|
||||||
|
|
||||||
import { sound_effect_add as sound_effect_add_gen } from './generators/sound/effect/add.js';
|
import { sound_effect_add as sound_effect_add_gen } from './generators/sound/effect/add.js';
|
||||||
import { sound_effect_set as sound_effect_set_gen } from './generators/sound/effect/sound_effect_set.js';
|
import { sound_effect_set as sound_effect_set_gen } from './generators/sound/effect/sound_effect_set.js';
|
||||||
import { sound_effect_clear as sound_effect_clear_gen } from './generators/sound/effect/sound_effect_clear.js';
|
import { sound_effect_clear as sound_effect_clear_gen } from './generators/sound/effect/sound_effect_clear.js';
|
||||||
|
|
||||||
import { sound_volume_add as sound_volume_add_gen } from './generators/sound/volume/add.js';
|
import { sound_volume_add as sound_volume_add_gen } from './generators/sound/volume/add.js';
|
||||||
import { sound_volume_set as sound_volume_set_gen } from './generators/sound/volume/set.js';
|
import { sound_volume_set as sound_volume_set_gen } from './generators/sound/volume/set.js';
|
||||||
import { sound_volume_get as sound_volume_get_gen } from './generators/sound/volume/get.js';
|
import { sound_volume_get as sound_volume_get_gen } from './generators/sound/volume/get.js';
|
||||||
|
|
||||||
import { sound_record as sound_record_gen } from './generators/sound/play/record.js';
|
import { sound_record as sound_record_gen } from './generators/sound/play/record.js';
|
||||||
|
|
||||||
import { sound_play_frequency as sound_play_frequency_gen } from './generators/sound/play/play_frequency.js';
|
import { sound_play_frequency as sound_play_frequency_gen } from './generators/sound/play/play_frequency.js';
|
||||||
import { sound_play_frequency_no_duration as sound_play_frequency_no_duration_gen } from './generators/sound/play/play_frequency_no_duration.js';
|
import { sound_play_frequency_no_duration as sound_play_frequency_no_duration_gen } from './generators/sound/play/play_frequency_no_duration.js';
|
||||||
import { sound_play_note_list as sound_play_note_list_gen } from './generators/sound/play/play_note_list.js';
|
import { sound_play_note_list as sound_play_note_list_gen } from './generators/sound/play/play_note_list.js';
|
||||||
import { sound_note as sound_note_gen } from './generators/sound/play/sound_note.js';
|
import { sound_note as sound_note_gen } from './generators/sound/play/sound_note.js';
|
||||||
|
const soundBlocks = {
|
||||||
Object.assign(Blockly.Blocks, {
|
sound_play, sound_play_wait, sound_stop_all,
|
||||||
sound_play,
|
sound_effect_add, sound_effect_set, sound_effect_clear,
|
||||||
sound_play_wait,
|
sound_volume_add, sound_volume_set, sound_volume_get,
|
||||||
sound_stop_all,
|
|
||||||
sound_effect_add,
|
|
||||||
sound_effect_set,
|
|
||||||
sound_effect_clear,
|
|
||||||
sound_volume_add,
|
|
||||||
sound_volume_set,
|
|
||||||
sound_volume_get,
|
|
||||||
sound_record,
|
sound_record,
|
||||||
|
sound_play_frequency, sound_play_frequency_no_duration,
|
||||||
|
sound_play_note_list, sound_note
|
||||||
|
};
|
||||||
|
|
||||||
sound_play_frequency,
|
const soundGenerators = {
|
||||||
sound_play_frequency_no_duration,
|
|
||||||
sound_play_note_list,
|
|
||||||
sound_note,
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
Object.assign(Blockly.Python.forBlock, {
|
|
||||||
sound_play: sound_play_gen,
|
sound_play: sound_play_gen,
|
||||||
sound_play_wait: sound_play_wait_gen,
|
sound_play_wait: sound_play_wait_gen,
|
||||||
sound_stop_all: sound_stop_all_gen,
|
sound_stop_all: sound_stop_all_gen,
|
||||||
|
|
||||||
sound_effect_add: sound_effect_add_gen,
|
sound_effect_add: sound_effect_add_gen,
|
||||||
sound_effect_set: sound_effect_set_gen,
|
sound_effect_set: sound_effect_set_gen,
|
||||||
sound_effect_clear: sound_effect_clear_gen,
|
sound_effect_clear: sound_effect_clear_gen,
|
||||||
|
|
||||||
sound_volume_add: sound_volume_add_gen,
|
sound_volume_add: sound_volume_add_gen,
|
||||||
sound_volume_set: sound_volume_set_gen,
|
sound_volume_set: sound_volume_set_gen,
|
||||||
sound_volume_get: sound_volume_get_gen,
|
sound_volume_get: sound_volume_get_gen,
|
||||||
|
|
||||||
sound_record: sound_record_gen,
|
sound_record: sound_record_gen,
|
||||||
|
|
||||||
sound_play_frequency: sound_play_frequency_gen,
|
sound_play_frequency: sound_play_frequency_gen,
|
||||||
sound_play_frequency_no_duration: sound_play_frequency_no_duration_gen,
|
sound_play_frequency_no_duration: sound_play_frequency_no_duration_gen,
|
||||||
sound_play_note_list: sound_play_note_list_gen,
|
sound_play_note_list: sound_play_note_list_gen,
|
||||||
sound_note: sound_note_gen,
|
sound_note: sound_note_gen
|
||||||
});
|
};
|
||||||
|
|
||||||
|
Object.assign(Blockly.Blocks, soundBlocks);
|
||||||
|
Object.assign(Blockly.Python.forBlock, soundGenerators);
|
||||||
|
|
||||||
window.sound = sound;
|
window.sound = sound;
|
||||||
@@ -632,6 +632,7 @@ const sound = {
|
|||||||
"NOTE_G5": 784
|
"NOTE_G5": 784
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// 播放指定频率的声音(带持续时间)
|
||||||
play_frequency: (frequency, duration = 1000) => {
|
play_frequency: (frequency, duration = 1000) => {
|
||||||
try {
|
try {
|
||||||
sound.initAudioContext();
|
sound.initAudioContext();
|
||||||
@@ -657,31 +658,84 @@ const sound = {
|
|||||||
gainNode.connect(sound.audioContext.destination);
|
gainNode.connect(sound.audioContext.destination);
|
||||||
|
|
||||||
oscillator.start();
|
oscillator.start();
|
||||||
|
oscillator.stop(sound.audioContext.currentTime + duration / 1000);
|
||||||
if (duration > 0) {
|
console.log(`播放频率: ${frequency}Hz, 持续时间: ${duration}ms, 音量: ${sound.volume}%`);
|
||||||
oscillator.stop(sound.audioContext.currentTime + duration / 1000);
|
|
||||||
} else {
|
|
||||||
oscillator.stop(sound.audioContext.currentTime + 2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("播放频率声音失败:", error);
|
console.error("播放频率声音失败:", error);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
play_frequency_blocking: (frequency, duration = 1000) => {
|
// 播放指定频率的声音(持续播放,无持续时间限制)
|
||||||
return new Promise((resolve, reject) => {
|
play_frequency_continuous: (frequency) => {
|
||||||
const actualDuration = duration > 0 ? duration : 2000;
|
try {
|
||||||
|
sound.initAudioContext();
|
||||||
|
|
||||||
|
if (sound.audioContext) {
|
||||||
|
const oscillator = sound.audioContext.createOscillator();
|
||||||
|
const gainNode = sound.audioContext.createGain();
|
||||||
|
|
||||||
|
oscillator.frequency.setValueAtTime(frequency, sound.audioContext.currentTime);
|
||||||
|
oscillator.type = 'sine';
|
||||||
|
|
||||||
|
const currentPitch = sound.effects.pitch;
|
||||||
|
if (currentPitch !== 0) {
|
||||||
|
oscillator.frequency.setValueAtTime(
|
||||||
|
frequency * Math.pow(2, currentPitch / 12),
|
||||||
|
sound.audioContext.currentTime
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
gainNode.gain.setValueAtTime(sound.volume / 100, sound.audioContext.currentTime);
|
||||||
|
|
||||||
|
oscillator.connect(gainNode);
|
||||||
|
gainNode.connect(sound.audioContext.destination);
|
||||||
|
|
||||||
|
oscillator.start();
|
||||||
|
oscillator.stop(sound.audioContext.currentTime + 2); // 默认播放2秒
|
||||||
|
console.log(`播放频率(持续): ${frequency}Hz, 无持续时间限制, 音量: ${sound.volume}%`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("播放频率声音失败:", error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 播放指定频率的声音(阻塞版本,使用队列,带持续时间)
|
||||||
|
play_frequency_blocking: (frequency, duration = 1000) => {
|
||||||
|
console.log(`=== 🔒 阻塞播放频率(加入队列): ${frequency}Hz, ${duration}ms ===`);
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
const queueItem = {
|
const queueItem = {
|
||||||
type: 'frequency',
|
type: 'frequency',
|
||||||
frequency,
|
frequency,
|
||||||
duration: actualDuration,
|
duration: duration,
|
||||||
resolve,
|
resolve,
|
||||||
reject
|
reject
|
||||||
};
|
};
|
||||||
|
|
||||||
sound.soundQueue.push(queueItem);
|
sound.soundQueue.push(queueItem);
|
||||||
|
console.log(`✅ 频率已加入声音队列,当前队列长度: ${sound.soundQueue.length}`);
|
||||||
|
sound.processQueue();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// 播放指定频率的声音(阻塞版本,使用队列,持续播放)
|
||||||
|
play_frequency_continuous_blocking: (frequency) => {
|
||||||
|
console.log(`=== 🔒 阻塞播放频率(持续,加入队列): ${frequency}Hz ===`);
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const duration = 2000; // 持续播放默认2秒
|
||||||
|
|
||||||
|
const queueItem = {
|
||||||
|
type: 'frequency',
|
||||||
|
frequency,
|
||||||
|
duration: duration,
|
||||||
|
resolve,
|
||||||
|
reject
|
||||||
|
};
|
||||||
|
|
||||||
|
sound.soundQueue.push(queueItem);
|
||||||
|
console.log(`✅ 频率(持续)已加入声音队列,当前队列长度: ${sound.soundQueue.length}`);
|
||||||
sound.processQueue();
|
sound.processQueue();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -1386,11 +1440,33 @@ function injectSoundToPython() {
|
|||||||
return sound.clear_effects();
|
return sound.clear_effects();
|
||||||
},
|
},
|
||||||
play_frequency: (frequency, duration) => {
|
play_frequency: (frequency, duration) => {
|
||||||
|
console.log(`Python调用: sound.play_frequency(${frequency}, ${duration})`);
|
||||||
|
// 自动判断是否需要阻塞
|
||||||
|
if (sound.soundQueue.length > 0 || sound.isProcessingQueue) {
|
||||||
|
return sound.play_frequency_blocking(frequency, duration);
|
||||||
|
}
|
||||||
return sound.play_frequency(frequency, duration);
|
return sound.play_frequency(frequency, duration);
|
||||||
},
|
},
|
||||||
|
play_frequency_no_duration: (frequency) => {
|
||||||
|
console.log(`Python调用: sound.play_frequency_no_duration(${frequency})`);
|
||||||
|
// 自动判断是否需要阻塞
|
||||||
|
if (sound.soundQueue.length > 0 || sound.isProcessingQueue) {
|
||||||
|
return sound.play_frequency_continuous_blocking(frequency);
|
||||||
|
}
|
||||||
|
return sound.play_frequency_continuous(frequency);
|
||||||
|
},
|
||||||
play_frequency_blocking: (frequency, duration) => {
|
play_frequency_blocking: (frequency, duration) => {
|
||||||
|
console.log(`Python调用: sound.play_frequency_blocking(${frequency}, ${duration})`);
|
||||||
return sound.play_frequency_blocking(frequency, duration);
|
return sound.play_frequency_blocking(frequency, duration);
|
||||||
},
|
},
|
||||||
|
play_frequency_continuous: (frequency) => {
|
||||||
|
console.log(`Python调用: sound.play_frequency_continuous(${frequency})`);
|
||||||
|
return sound.play_frequency_continuous(frequency);
|
||||||
|
},
|
||||||
|
play_frequency_continuous_blocking: (frequency) => {
|
||||||
|
console.log(`Python调用: sound.play_frequency_continuous_blocking(${frequency})`);
|
||||||
|
return sound.play_frequency_continuous_blocking(frequency);
|
||||||
|
},
|
||||||
play_note_list: (noteList) => {
|
play_note_list: (noteList) => {
|
||||||
return sound.play_note_list(noteList);
|
return sound.play_note_list(noteList);
|
||||||
},
|
},
|
||||||
@@ -1463,6 +1539,100 @@ def _sync_play_blocking(name):
|
|||||||
# 替换sound.play_blocking为同步版本
|
# 替换sound.play_blocking为同步版本
|
||||||
sound.play_blocking = _sync_play_blocking
|
sound.play_blocking = _sync_play_blocking
|
||||||
|
|
||||||
|
# 创建同步版本的play_frequency包装函数
|
||||||
|
_original_play_frequency = sound.play_frequency
|
||||||
|
|
||||||
|
def _sync_play_frequency(frequency, duration):
|
||||||
|
"""同步版本的play_frequency,会自动判断是否需要阻塞"""
|
||||||
|
promise = _original_play_frequency(frequency, duration)
|
||||||
|
# 使用Pyodide的Promise支持
|
||||||
|
import pyodide
|
||||||
|
if hasattr(pyodide, 'ffi') and hasattr(pyodide.ffi, 'run_sync'):
|
||||||
|
try:
|
||||||
|
return pyodide.ffi.run_sync(promise)
|
||||||
|
except Exception:
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
import asyncio
|
||||||
|
try:
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
|
except RuntimeError:
|
||||||
|
loop = asyncio.new_event_loop()
|
||||||
|
asyncio.set_event_loop(loop)
|
||||||
|
|
||||||
|
async def wait_promise():
|
||||||
|
try:
|
||||||
|
return await promise
|
||||||
|
except Exception:
|
||||||
|
return None
|
||||||
|
|
||||||
|
try:
|
||||||
|
return loop.run_until_complete(wait_promise())
|
||||||
|
except Exception:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# 创建同步版本的play_frequency_no_duration包装函数
|
||||||
|
_original_play_frequency_no_duration = sound.play_frequency_no_duration
|
||||||
|
|
||||||
|
def _sync_play_frequency_no_duration(frequency):
|
||||||
|
"""同步版本的play_frequency_no_duration,会自动判断是否需要阻塞"""
|
||||||
|
promise = _original_play_frequency_no_duration(frequency)
|
||||||
|
# 使用Pyodide的Promise支持
|
||||||
|
import pyodide
|
||||||
|
if hasattr(pyodide, 'ffi') and hasattr(pyodide.ffi, 'run_sync'):
|
||||||
|
try:
|
||||||
|
return pyodide.ffi.run_sync(promise)
|
||||||
|
except Exception:
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
import asyncio
|
||||||
|
try:
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
|
except RuntimeError:
|
||||||
|
loop = asyncio.new_event_loop()
|
||||||
|
asyncio.set_event_loop(loop)
|
||||||
|
|
||||||
|
async def wait_promise():
|
||||||
|
try:
|
||||||
|
return await promise
|
||||||
|
except Exception:
|
||||||
|
return None
|
||||||
|
|
||||||
|
try:
|
||||||
|
return loop.run_until_complete(wait_promise())
|
||||||
|
except Exception:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# 替换为同步版本
|
||||||
|
sound.play_frequency = _sync_play_frequency
|
||||||
|
sound.play_frequency_no_duration = _sync_play_frequency_no_duration
|
||||||
|
|
||||||
|
# 创建同步版本的play_frequency_continuous_blocking包装函数
|
||||||
|
_original_play_frequency_continuous_blocking = sound.play_frequency_continuous_blocking
|
||||||
|
|
||||||
|
def _sync_play_frequency_continuous_blocking(frequency):
|
||||||
|
"""同步版本的play_frequency_continuous_blocking,会等待频率播放完成"""
|
||||||
|
promise = _original_play_frequency_continuous_blocking(frequency)
|
||||||
|
# 使用Pyodide的Promise支持
|
||||||
|
import pyodide
|
||||||
|
if hasattr(pyodide, 'ffi') and hasattr(pyodide.ffi, 'run_sync'):
|
||||||
|
return pyodide.ffi.run_sync(promise)
|
||||||
|
else:
|
||||||
|
import asyncio
|
||||||
|
try:
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
|
except RuntimeError:
|
||||||
|
loop = asyncio.new_event_loop()
|
||||||
|
asyncio.set_event_loop(loop)
|
||||||
|
|
||||||
|
async def wait_promise():
|
||||||
|
return await promise
|
||||||
|
|
||||||
|
return loop.run_until_complete(wait_promise())
|
||||||
|
|
||||||
|
# 替换为同步版本
|
||||||
|
sound.play_frequency_continuous_blocking = _sync_play_frequency_continuous_blocking
|
||||||
|
|
||||||
# 创建同步版本的play_frequency_blocking包装函数
|
# 创建同步版本的play_frequency_blocking包装函数
|
||||||
_original_play_frequency_blocking = sound.play_frequency_blocking
|
_original_play_frequency_blocking = sound.play_frequency_blocking
|
||||||
|
|
||||||
|
|||||||
@@ -3846,20 +3846,7 @@
|
|||||||
</value>
|
</value>
|
||||||
</block>
|
</block>
|
||||||
</category>
|
</category>
|
||||||
<category id="catFactory" name="Factory" colour="#777777">
|
<category id="catSound" colour="#acc159">
|
||||||
<block type="factory_import"></block>
|
|
||||||
<block type="factory_from_import"></block>
|
|
||||||
<block type="factory_function_noreturn"></block>
|
|
||||||
<block type="factory_function_return"></block>
|
|
||||||
<block type="factory_declare"></block>
|
|
||||||
<block type="factory_callMethod_noreturn"></block>
|
|
||||||
<block type="factory_callMethod_return"></block>
|
|
||||||
<block type="factory_block"></block>
|
|
||||||
<block type="factory_block_return"></block>
|
|
||||||
<block type="factory_block_with_textarea"></block>
|
|
||||||
<block type="factory_block_return_with_textarea"></block>
|
|
||||||
</category>
|
|
||||||
<category id="catSound" colour="#acc159">
|
|
||||||
<block type="sound_play"></block>
|
<block type="sound_play"></block>
|
||||||
<block type="sound_play_wait"></block>
|
<block type="sound_play_wait"></block>
|
||||||
<block type="sound_stop_all"></block>
|
<block type="sound_stop_all"></block>
|
||||||
@@ -3916,6 +3903,20 @@
|
|||||||
<block type="sound_note">
|
<block type="sound_note">
|
||||||
<field name="NOTE">NOTE_A4</field>
|
<field name="NOTE">NOTE_A4</field>
|
||||||
</block>
|
</block>
|
||||||
|
</category>
|
||||||
|
<category id="catFactory" name="Factory" colour="#777777">
|
||||||
|
<block type="factory_import"></block>
|
||||||
|
<block type="factory_from_import"></block>
|
||||||
|
<block type="factory_function_noreturn"></block>
|
||||||
|
<block type="factory_function_return"></block>
|
||||||
|
<block type="factory_declare"></block>
|
||||||
|
<block type="factory_callMethod_noreturn"></block>
|
||||||
|
<block type="factory_callMethod_return"></block>
|
||||||
|
<block type="factory_block"></block>
|
||||||
|
<block type="factory_block_return"></block>
|
||||||
|
<block type="factory_block_with_textarea"></block>
|
||||||
|
<block type="factory_block_return_with_textarea"></block>
|
||||||
|
</category>
|
||||||
|
|
||||||
|
|
||||||
</xml>
|
</xml>
|
||||||
Reference in New Issue
Block a user