Fix a-fluidsynth bank/program restore (during session load)
authorRobin Gareus <robin@gareus.org>
Mon, 11 Sep 2017 14:45:17 +0000 (16:45 +0200)
committerRobin Gareus <robin@gareus.org>
Mon, 11 Sep 2017 14:48:54 +0000 (16:48 +0200)
* set program in work-response, synchronous to run()
* properly store bank per channel (for replay)

libs/plugins/a-fluidsynth.lv2/a-fluidsynth.cc

index 14e1ae4610e964b3948f3a5b2d6fdc82d175bc22..0c3e20a888154baa65aa4bad099dd967149fee46 100644 (file)
@@ -153,8 +153,6 @@ typedef struct {
        bool reinit_in_progress; // set in run, cleared in work_response
        bool queue_reinit; // set in restore, cleared in work_response
 
-       uint8_t last_bank_lsb;
-       uint8_t last_bank_msb;
        BankProgram program_state[16];
 
        fluid_midi_event_t* fmidi_event;
@@ -210,24 +208,6 @@ load_sf2 (AFluidSynth* self, const char* fn)
                return false;
        }
 
-       for (chn = 0; chn < 16; ++chn) {
-               if (self->program_state[chn].program < 0) {
-                       continue;
-               }
-               fluid_synth_program_select (self->synth, chn, synth_id,
-                               self->program_state[chn].bank, self->program_state[chn].program);
-       }
-
-       for (chn = 0; chn < 16; ++chn) {
-               unsigned int sfid = 0;
-               unsigned int bank = 0;
-               unsigned int program = -1;
-               if (FLUID_OK == fluid_synth_get_program (self->synth, chn, &sfid, &bank, &program)) {
-                       self->program_state[chn].bank = bank;
-                       self->program_state[chn].program = program;
-               }
-       }
-
        return true;
 }
 
@@ -550,14 +530,21 @@ run (LV2_Handle instance, uint32_t n_samples)
                                        fluid_midi_event_set_value (self->fmidi_event, data[2]);
                                }
                                if (0xb0 /* CC */ == fluid_midi_event_get_type (self->fmidi_event)) {
-                                       if (data[1] == 0x00) { self->last_bank_msb = data[2]; }
-                                       if (data[1] == 0x20) { self->last_bank_lsb = data[2]; }
+                                       int chn = fluid_midi_event_get_channel (self->fmidi_event);
+                                       assert (chn >= 0 && chn < 16);
+                                       if (data[1] == 0x00) {
+                                               self->program_state[chn].bank &= 0x7f;
+                                               self->program_state[chn].bank |= (data[2] &0x7f) << 7;
+                                       }
+                                       if (data[1] == 0x20) {
+                                               self->program_state[chn].bank &= 0x3F80;
+                                               self->program_state[chn].bank |= data[2] & 0x7f;
+                                       }
                                }
                        }
                        if (ev->body.size == 2 && 0xc0 /* Pgm */ == fluid_midi_event_get_type (self->fmidi_event)) {
                                int chn = fluid_midi_event_get_channel (self->fmidi_event);
                                assert (chn >= 0 && chn < 16);
-                               self->program_state[chn].bank = (self->last_bank_msb << 7) | self->last_bank_lsb;
                                self->program_state[chn].program = data[1];
 #ifdef LV2_EXTENDED
                                if (self->bankpatch) {
@@ -567,6 +554,7 @@ run (LV2_Handle instance, uint32_t n_samples)
                                }
 #endif
                        }
+
                        fluid_synth_handle_midi_event (self->synth, self->fmidi_event);
                }
        }
@@ -672,6 +660,36 @@ work_response (LV2_Handle  instance,
 
        if (self->initialized) {
                strcpy (self->current_sf2_file_path, self->queue_sf2_file_path);
+
+               for (int chn = 0; chn < 16; ++chn) {
+                       if (self->program_state[chn].program < 0) {
+                               continue;
+                       }
+                       /* cannot direcly call fluid_channel_set_bank_msb/fluid_channel_set_bank_lsb, use CCs */
+                       fluid_midi_event_set_type (self->fmidi_event, 0xb0 /* CC */);
+                       fluid_midi_event_set_channel (self->fmidi_event, chn);
+
+                       fluid_midi_event_set_control (self->fmidi_event, 0x00); // BANK_SELECT_MSB
+                       fluid_midi_event_set_value (self->fmidi_event, (self->program_state[chn].bank >> 7) & 0x7f);
+                       fluid_synth_handle_midi_event (self->synth, self->fmidi_event);
+
+                       fluid_midi_event_set_control (self->fmidi_event, 0x20); // BANK_SELECT_LSB
+                       fluid_midi_event_set_value (self->fmidi_event, self->program_state[chn].bank & 0x7f);
+                       fluid_synth_handle_midi_event (self->synth, self->fmidi_event);
+
+                       fluid_synth_program_change (self->synth, chn, self->program_state[chn].program);
+               }
+
+               for (int chn = 0; chn < 16; ++chn) {
+                       unsigned int sfid = 0;
+                       unsigned int bank = 0;
+                       unsigned int program = -1;
+                       if (FLUID_OK == fluid_synth_get_program (self->synth, chn, &sfid, &bank, &program)) {
+                               self->program_state[chn].bank = bank;
+                               self->program_state[chn].program = program;
+                       }
+               }
+
        } else {
                self->current_sf2_file_path[0] = 0;
        }