改声音目录

This commit is contained in:
whm1216
2025-12-02 19:11:04 +08:00
parent 3ecb7d8cfb
commit 69484c9c6b
11 changed files with 241 additions and 218 deletions

View File

@@ -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);

View File

@@ -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);

View File

@@ -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"],

View File

@@ -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);

View File

@@ -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`;
}; };

View File

@@ -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`;
}; };

View File

@@ -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`;
}; };

View File

@@ -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];
}; };

View File

@@ -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;

View File

@@ -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

View File

@@ -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>