static void clone_cb_mcc(int fnid, const char *key, const char *kv, unsigned char val, void *arg) { if (fnid >= 0) { callMIDIControlFunction(((struct b_instance *) arg)->midicfg, key, val); } }
static void run(LV2_Handle instance, uint32_t n_samples) { B3S* b3s = (B3S*)instance; float* audio[2]; audio[0] = b3s->outL; audio[1] = b3s->outR; /* prepare outgoing MIDI */ const uint32_t capacity = b3s->midiout->atom.size; static bool warning_printed = false; if (!warning_printed && capacity < 4096) { warning_printed = true; fprintf(stderr, "B3LV2: LV message buffer is only %d bytes. Expect problems.\n", capacity); fprintf(stderr, "B3LV2: if your LV2 host allows one to configure a buffersize use at least 4kBytes.\n"); } lv2_atom_forge_set_buffer(&b3s->forge, (uint8_t*)b3s->midiout, capacity); lv2_atom_forge_sequence_head(&b3s->forge, &b3s->frame, 0); uint32_t written = 0; if (b3s->queue_panic) { b3s->queue_panic = 0; midi_panic(b3s->inst); } /* Process incoming events from GUI and handle MIDI events */ if (b3s->midiin) { LV2_Atom_Event* ev = lv2_atom_sequence_begin(&(b3s->midiin)->body); while(!lv2_atom_sequence_is_end(&(b3s->midiin)->body, (b3s->midiin)->atom.size, ev)) { if (ev->body.type == b3s->uris.midi_MidiEvent) { /* process midi messages from player */ if (written + BUFFER_SIZE_SAMPLES < ev->time.frames && ev->time.frames < n_samples) { /* first syntheize sound up until the message timestamp */ written = synthSound(b3s, written, ev->time.frames, audio); } /* send midi message to synth, CC's will trigger hook -> update GUI */ parse_raw_midi_data(b3s->inst, (uint8_t*)(ev+1), ev->body.size); } else if (ev->body.type == b3s->uris.atom_Blank || ev->body.type == b3s->uris.atom_Object) { /* process messages from GUI */ const LV2_Atom_Object* obj = (LV2_Atom_Object*)&ev->body; if (obj->body.otype == b3s->uris.sb3_uiinit) { b3s->update_gui_now = 1; } else if (obj->body.otype == b3s->uris.sb3_uimccquery) { midi_loopCCAssignment(b3s->inst->midicfg, 7, mcc_cb, b3s); } else if (obj->body.otype == b3s->uris.sb3_uimccset) { const LV2_Atom* cmd = NULL; const LV2_Atom* flags = NULL; lv2_atom_object_get(obj, b3s->uris.sb3_cckey, &flags, b3s->uris.sb3_ccval, &cmd, 0); if (cmd && flags) { midi_uiassign_cc(b3s->inst->midicfg, (const char*)LV2_ATOM_BODY(cmd), ((LV2_Atom_Int*)flags)->body); } } else if (obj->body.otype == b3s->uris.sb3_midipgm) { const LV2_Atom* key = NULL; lv2_atom_object_get(obj, b3s->uris.sb3_cckey, &key, 0); if (key) { installProgram(b3s->inst, ((LV2_Atom_Int*)key)->body); } } else if (obj->body.otype == b3s->uris.sb3_midisavepgm) { const LV2_Atom* pgm = NULL; const LV2_Atom* name = NULL; lv2_atom_object_get(obj, b3s->uris.sb3_cckey, &pgm, b3s->uris.sb3_ccval, &name, 0); if (pgm && name) { saveProgramm(b3s->inst, (int) ((LV2_Atom_Int*)pgm)->body, (char*) LV2_ATOM_BODY(name), 0); b3s->update_pgm_now = 1; } } else if (obj->body.otype == b3s->uris.sb3_loadpgm) { iowork(b3s, obj, CMD_LOADPGM); } else if (obj->body.otype == b3s->uris.sb3_loadcfg) { iowork(b3s, obj, CMD_LOADCFG); } else if (obj->body.otype == b3s->uris.sb3_savepgm) { iowork(b3s, obj, CMD_SAVEPGM); } else if (obj->body.otype == b3s->uris.sb3_savecfg) { iowork(b3s, obj, CMD_SAVECFG); } else if (obj->body.otype == b3s->uris.sb3_cfgstr) { if (!b3s->inst_offline) { advanced_config_set(b3s, obj); } } else if (obj->body.otype == b3s->uris.sb3_control) { b3s->suspend_ui_msg = 1; const LV2_Atom_Object* obj = (LV2_Atom_Object*)&ev->body; char *k; int v; if (!get_cc_key_value(&b3s->uris, obj, &k, &v)) { #ifdef DEBUGPRINT fprintf(stderr, "B3LV2: callMIDIControlFunction(..,\"%s\", %d);\n", k, v); #endif callMIDIControlFunction(b3s->inst->midicfg, k, v); } b3s->suspend_ui_msg = 0; } } ev = lv2_atom_sequence_next(ev); } } /* synthesize [remaining] sound */ synthSound(b3s, written, n_samples, audio); /* send active keys to GUI - IFF changed */ bool keychanged = false; for (int i = 0 ; i < MAX_KEYS/32; ++i) { if (b3s->active_keys[i] != b3s->inst->synth->_activeKeys[i]) { keychanged = true; } b3s->active_keys[i] = b3s->inst->synth->_activeKeys[i]; } if (keychanged) { LV2_Atom_Forge_Frame frame; lv2_atom_forge_frame_time(&b3s->forge, 0); x_forge_object(&b3s->forge, &frame, 1, b3s->uris.sb3_activekeys); lv2_atom_forge_property_head(&b3s->forge, b3s->uris.sb3_keyarrary, 0); lv2_atom_forge_vector(&b3s->forge, sizeof(unsigned int), b3s->uris.atom_Int, MAX_KEYS/32, b3s->active_keys); lv2_atom_forge_pop(&b3s->forge, &frame); } /* check for new instances */ postrun(b3s); if (b3s->update_gui_now) { b3s->update_gui_now = 0; b3s->update_pgm_now = 1; b3s->suspend_ui_msg = 1; rc_loop_state(b3s->inst->state, rc_cb, b3s); b3s->suspend_ui_msg = 0; forge_kvconfigmessage(&b3s->forge, &b3s->uris, b3s->uris.sb3_cfgkv, "lv2.info", b3s->lv2nfo); forge_kvcontrolmessage(&b3s->forge, &b3s->uris, "special.init", (int32_t) b3s->thirtysec); } else if (b3s->update_pgm_now) { b3s->update_pgm_now = 0; loopProgammes(b3s->inst->progs, 1, pgm_cb, b3s); } }
static LV2_State_Status restore(LV2_Handle instance, LV2_State_Retrieve_Function retrieve, LV2_State_Handle handle, uint32_t flags, const LV2_Feature* const* features) { B3S* b3s = (B3S*)instance; size_t size; uint32_t type; uint32_t valflags; const void* value = retrieve(handle, b3s->uris.sb3_state, &size, &type, &valflags); if (!value) { return LV2_STATE_ERR_UNKNOWN; } if (b3s->inst_offline) { fprintf(stderr, "B3LV2: restore ignored. re-init in progress\n"); return LV2_STATE_ERR_UNKNOWN; } b3s->inst_offline = (b_instance*) calloc(1, sizeof(struct b_instance)); allocSynth(b3s->inst_offline); const char* cfg = (const char*)value; const char *te, *ts = cfg; LOCALEGUARD_START; /* pass1 - evaulate CFG -- before initializing synth */ while (ts && *ts && (te=strchr(ts, '\n'))) { char *val; char kv[1024]; memcpy(kv, ts, te-ts); kv[te-ts]=0; #ifdef DEBUGPRINT fprintf(stderr, "B3LV2 CFG Pass1: %s\n", kv); #endif if(kv[0]=='C' && (val=strchr(kv,'='))) { *val=0; #ifdef DEBUGPRINT fprintf(stderr, "B3LV2: evaluateConfigKeyValue(..,\"%s\", \"%s\");\n", kv+2, val+1); #endif evaluateConfigKeyValue((void*)b3s->inst_offline, kv+2, val+1); } else if(kv[0]=='P') { #ifdef DEBUGPRINT printf("PGM '%s'\n", kv+2); #endif loadProgrammeString(b3s->inst_offline->progs, kv+2); } ts=te+1; } initSynth(b3s->inst_offline, SampleRateD); /* pass2 - replay CC's after initializing synth */ ts = cfg; while (ts && *ts && (te=strchr(ts, '\n'))) { char *val; char kv[1024]; memcpy(kv, ts, te-ts); kv[te-ts]=0; #ifdef DEBUGPRINT fprintf(stderr, "B3LV2 CFG Pass2: %s\n", kv); #endif if(kv[0]=='M' && (val=strchr(kv,'='))) { *val=0; #ifdef DEBUGPRINT fprintf(stderr, "B3LV2: callMIDIControlFunction(..,\"%s\", %d);\n", kv+2, atoi(val+1)); #endif callMIDIControlFunction(b3s->inst_offline->midicfg, kv+2, atoi(val+1)); } ts=te+1; } LOCALEGUARD_END; b3s->swap_instances = 1; return LV2_STATE_SUCCESS; }
/** * This is the routine called by the MIDI parser when it detects * a Program Change message. */ void installProgram (void *instance, unsigned char uc) { int p = (int) uc; b_instance * inst = (b_instance*) instance; p += inst->progs->MIDIControllerPgmOffset; if ((0 < p) && (p < MAXPROGS)) { Programme * PGM = &(inst->progs->programmes[p]); unsigned int flags0 = PGM->flags[0]; #ifdef DEBUG_MIDI_PROGRAM_CHANGES char display[128]; #endif if (flags0 & FL_INUSE) { #ifdef DEBUG_MIDI_PROGRAM_CHANGES strcpy (display, PGM->name); #endif if (flags0 & FL_DRWRND) { char buf [32]; if (flags0 & FL_DRAWBR) { randomizeDrawbars (PGM->drawbars, buf); #ifdef DEBUG_MIDI_PROGRAM_CHANGES strcat (display, "UPR:"); strcat (display, buf); #endif } if (flags0 & FL_LOWDRW) { randomizeDrawbars (PGM->lowerDrawbars, buf); #ifdef DEBUG_MIDI_PROGRAM_CHANGES strcat (display, "LOW:"); strcat (display, buf); #endif } if (flags0 & FL_PDLDRW) { randomizeDrawbars (PGM->pedalDrawbars, buf); #ifdef DEBUG_MIDI_PROGRAM_CHANGES strcat (display, "PDL:"); strcat (display, buf); #endif } } #ifdef DEBUG_MIDI_PROGRAM_CHANGES /* this is not RT safe */ //fprintf (stdout, "\rPGM: %s \r", display); fflush (stdout); fprintf (stdout, "PGM: %s\n", display); #endif if (flags0 & FL_DRAWBR) { setDrawBars (inst, 0, PGM->drawbars); } if (flags0 & FL_LOWDRW) { setDrawBars (inst, 1, PGM->lowerDrawbars); } if (flags0 & FL_PDLDRW) { setDrawBars (inst, 2, PGM->pedalDrawbars); } if (flags0 & FL_SCANNR) { //setVibrato (inst->synth, PGM->scanner & 0x00FF); assert((PGM->scanner & 0xff) > 0); int knob = ((PGM->scanner & 0xf) << 1) - ((PGM->scanner & CHO_) ? 1 : 2); callMIDIControlFunction(inst->midicfg, "vibrato.knob", knob * 23); } if (flags0 & FL_VCRUPR) { //setVibratoUpper (inst->synth, PGM->scanner & 0x200); int rt = getVibratoRouting(inst->synth) & ~0x2; rt |= (PGM->scanner & 0x200) ? 2 : 0; callMIDIControlFunction(inst->midicfg, "vibrato.routing", rt << 5); } if (flags0 & FL_VCRLWR) { //setVibratoLower (inst->synth, PGM->scanner & 0x100); int rt = getVibratoRouting(inst->synth) & ~0x1; rt |= (PGM->scanner & 0x100) ? 1 : 0; callMIDIControlFunction(inst->midicfg, "vibrato.routing", rt << 5); } if (flags0 & FL_PRCENA) { setPercussionEnabled (inst->synth, PGM->percussionEnabled); callMIDIControlFunction(inst->midicfg, "percussion.enable", PGM->percussionEnabled ? 127 : 0); } if (flags0 & FL_PRCVOL) { //setPercussionVolume (inst->synth, PGM->percussionVolume); callMIDIControlFunction(inst->midicfg, "percussion.volume", PGM->percussionVolume ? 127 : 0); } if (flags0 & FL_PRCSPD) { //setPercussionFast (inst->synth, PGM->percussionSpeed); callMIDIControlFunction(inst->midicfg, "percussion.decay", PGM->percussionSpeed ? 127 : 0); } if (flags0 & FL_PRCHRM) { //setPercussionFirst (inst->synth, PGM->percussionHarmonic); callMIDIControlFunction(inst->midicfg, "percussion.harmonic", PGM->percussionHarmonic ? 127 : 0); } if (flags0 & FL_OVRSEL) { //setClean (inst->preamp, PGM->overdriveSelect); callMIDIControlFunction(inst->midicfg, "overdrive.enable", PGM->overdriveSelect ? 0 : 127); } if (flags0 & FL_ROTENA) { /* Rotary enabled */ } if (flags0 & FL_ROTSPS) { // setRevSelect (inst->whirl, (int) (PGM->rotarySpeedSelect)); callMIDIControlFunction(inst->midicfg, "rotary.speed-preset", PGM->rotarySpeedSelect * 32); } if (flags0 & FL_RVBMIX) { //setReverbMix (inst->reverb, PGM->reverbMix); callMIDIControlFunction(inst->midicfg, "reverb.mix-preset", (PGM->reverbMix * 127.0)); } /* TODO -- keyboard split & transpose are not yet saved */ if (flags0 & (FL_KSPLTL|FL_KSPLTP|FL_TRA_PD|FL_TRA_LM|FL_TRA_UM)) { int b; b = (flags0 & FL_KSPLTP) ? 1 : 0; b |= (flags0 & FL_KSPLTL) ? 2 : 0; b |= (flags0 & FL_TRA_PD) ? 4 : 0; b |= (flags0 & FL_TRA_LM) ? 8 : 0; b |= (flags0 & FL_TRA_UM) ? 16 : 0; setKeyboardSplitMulti (inst->midicfg, b, PGM->keyboardSplitPedals, PGM->keyboardSplitLower, PGM->transpose[TR_CHA_PD], PGM->transpose[TR_CHA_LM], PGM->transpose[TR_CHA_UM]); } if (flags0 & FL_TRANSP) { setKeyboardTranspose (inst->midicfg, PGM->transpose[TR_TRANSP]); } if (flags0 & FL_TRCH_A) { setKeyboardTransposeA (inst->midicfg, PGM->transpose[TR_CHNL_A]); } if (flags0 & FL_TRCH_B) { setKeyboardTransposeB (inst->midicfg, PGM->transpose[TR_CHNL_B]); } if (flags0 & FL_TRCH_C) { setKeyboardTransposeC (inst->midicfg, PGM->transpose[TR_CHNL_C]); } } } }