fix: sử dụng soundfont từ server
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
Nguyên nhân xuất hiện thông báo lỗi từ SpessaSynth Core:
|
||||
`basic_synthesizer_core.ts:169 No preset found for 0:0:0! Did you forget to add a sound bank?`
|
||||
|
||||
Thông số `0:0:0` trong thông báo đại diện cho `Bank MSB : Bank LSB : Program Number` (cấu hình mặc định ban đầu của kênh MIDI). Lỗi này xảy ra do **3 nguyên nhân chính** sau:
|
||||
|
||||
---
|
||||
|
||||
### 1. Phân tích nguyên nhân kỹ thuật
|
||||
|
||||
1. **Chưa gửi lệnh `programChange` & `controllerChange` sang SpessaSynth khi chọn "Pipa"**:
|
||||
* Khi chọn nhạc cụ "Pipa" trên UI, ứng dụng mới chỉ cập nhật giao diện mà **chưa kích hoạt lệnh đổi tiếng** (`synthInstance.programChange(channel, program)`) sang kênh MIDI tương ứng của SpessaSynth.
|
||||
* Khi gõ phím trên `SE49` (nhận dữ liệu Raw MIDI `[144, 65, 78]`), SpessaSynth vẫn truy xuất bộ tiếng ở vị trí mặc định là `Bank 0 : Program 0` (thường là Grand Piano theo chuẩn General MIDI).
|
||||
* Trong SoundFont `DSK_Asian_DreamZ`, vị trí `0:0:0` không tồn tại hoặc không chứa thông tin nốt, khiến SpessaSynth thông báo không tìm thấy preset.
|
||||
|
||||
|
||||
2. **Sai chỉ số Bank / Program của nhạc cụ "Pipa"**:
|
||||
* Tệp SoundFont `DSK_Asian_DreamZ` là bộ tiếng tùy chỉnh (Non-General MIDI). 8 nhạc cụ bên trong (*Pipa, Pipa Tremolo, Luan, Guzhen, Erhu, Koto, Ban Di, Percussion*) được đánh số `Program` riêng biệt.
|
||||
* Nếu UI gửi `program = 0` nhưng thực tế trong file SoundFont, tiếng Pipa nằm ở `program = 1` hoặc `bank = 1`, SpessaSynth sẽ không tìm thấy preset tương ứng.
|
||||
|
||||
|
||||
3. **Lỗi Header/Mapping khi convert từ `.sf2` sang `.sf3**`:
|
||||
* Một số công cụ nén (như `mscore` CLI) khi convert các SoundFont tùy chỉnh có cấu trúc phi chuẩn có thể làm mất hoặc biến đổi bảng thông tin Preset Header.
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
### 2. Các bước khắc phục
|
||||
|
||||
#### **Bước 1: Gọi `programChange` & `controllerChange` ngay khi chọn nhạc cụ trên UI**
|
||||
|
||||
Đảm bảo khi người dùng chọn nhạc cụ trên giao diện, hàm chọn Bank/Program được kích hoạt trên kênh MIDI phát tiếng:
|
||||
|
||||
```javascript
|
||||
// Khi người dùng chọn "Pipa" trên Dropdown Synth UI
|
||||
async function onSelectTrackInstrument(trackChannel, sfId, bank, program) {
|
||||
// 1. Nạp file .sf3 vào SpessaSynth (nếu chưa nạp)
|
||||
await soundFontPlayerInstance.loadSoundFont(sfId);
|
||||
|
||||
// 2. BẮT BUỘC: Gửi lệnh đổi Bank (CC 0) và Program Change sang SpessaSynth
|
||||
if (soundFontPlayerInstance.synthInstance) {
|
||||
soundFontPlayerInstance.synthInstance.controllerChange(trackChannel, 0, bank);
|
||||
soundFontPlayerInstance.synthInstance.programChange(trackChannel, program);
|
||||
console.log(`[SonicSF] Switched Channel ${trackChannel} -> Bank: ${bank}, Program: ${program}`);
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
#### **Bước 2: Kiểm tra chính xác chỉ số Bank & Program của Pipa từ Catalog API**
|
||||
|
||||
Sử dụng API `GET /api/v1/plugins/soundfonts/catalog` (từ mô-đun `SoundFontInspector` đã xây dựng) để tra cứu vị trí chính xác của "Pipa":
|
||||
|
||||
```json
|
||||
"dsk_asian_dreamz": {
|
||||
"soundfont_id": "dsk_asian_dreamz",
|
||||
"instruments": [
|
||||
{ "bank": 0, "program": 0, "name": "Pipa" },
|
||||
{ "bank": 0, "program": 1, "name": "Pipa Tremolo" },
|
||||
{ "bank": 0, "program": 6, "name": "Ban Di" }
|
||||
]
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
*Lưu ý:* Nếu kết quả trả về tiếng Pipa nằm ở `program: 1` hoặc `bank: 1`, hãy truyền đúng thông số này vào hàm `programChange`.
|
||||
|
||||
#### **Bước 3: Kiểm tra danh sách Presets mà SpessaSynth đọc được từ file `.sf3**`
|
||||
|
||||
Để đảm bảo quá trình convert `.sf3` không làm hỏng dữ liệu Preset Header, bạn hãy log danh sách preset sau khi nạp tệp:
|
||||
|
||||
```javascript
|
||||
// Thêm log kiểm tra sau khi addSoundFont vào SpessaSynth
|
||||
try {
|
||||
await this.synthInstance.soundFontManager.addSoundFont(buffer);
|
||||
|
||||
// In danh sách các preset đọc được ra console để kiểm tra
|
||||
const loadedSF = this.synthInstance.soundFontManager.soundFonts[0];
|
||||
console.log("[SonicSF] Loaded Presets in SF3:", loadedSF.presets);
|
||||
} catch (e) {
|
||||
console.error("[SonicSF] Error parsing SF3:", e);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
* Nếu `loadedSF.presets` rỗng (`[]`), file `.sf3` đã bị hỏng khi nén. Bạn hãy thử nạp lại file `.sf2` gốc chưa nén để đối chiếu.
|
||||
Reference in New Issue
Block a user