Files
SonicForgeStudio/md/37_FIXVST3_SUGGEST.md
T

86 lines
4.3 KiB
Markdown

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.