diff --git a/src/carla-discovery/carla-discovery.cpp b/src/carla-discovery/carla-discovery.cpp index e96397c..4aa7f16 100644 --- a/src/carla-discovery/carla-discovery.cpp +++ b/src/carla-discovery/carla-discovery.cpp @@ -940,7 +940,7 @@ void do_vst_check(void* lib_handle) DISCOVERY_OUT("label", c_product); DISCOVERY_OUT("maker", c_vendor); DISCOVERY_OUT("copyright", c_vendor); - DISCOVERY_OUT("id", VstCurrentUniqueId); + DISCOVERY_OUT("unique_id", VstCurrentUniqueId); DISCOVERY_OUT("hints", hints); DISCOVERY_OUT("category", category); DISCOVERY_OUT("audio.ins", audio_ins); @@ -1012,7 +1012,7 @@ void do_sf2_check(const char* filename) DISCOVERY_OUT("label", ""); DISCOVERY_OUT("maker", ""); DISCOVERY_OUT("copyright", ""); - DISCOVERY_OUT("id", 0); + DISCOVERY_OUT("unique_id", 0); DISCOVERY_OUT("hints", 0); DISCOVERY_OUT("category", PLUGIN_CATEGORY_SYNTH); diff --git a/src/carla.py b/src/carla.py index f31e0ac..eaf8604 100755 --- a/src/carla.py +++ b/src/carla.py @@ -2353,13 +2353,18 @@ class PluginWidget(QFrame, ui_carla_plugin.Ui_PluginWidget): content += " \n" content += " %s\n" % (custom_data['type']) content += " %s\n" % (custom_data['key']) - content += " %s\n" % (custom_data['value']) + if (custom_data['type'] == CUSTOM_DATA_BINARY): + content += " \n" + content += "%s\n" % (custom_data['value']) + content += " \n" + else: + content += " %s\n" % (custom_data['value']) content += " \n" if (x_save_state_dict['Chunk']): content += "\n" content += " \n" - content += "%s" % (x_save_state_dict['Chunk']) + content += "%s\n" % (x_save_state_dict['Chunk']) content += " \n" content += " \n" diff --git a/src/carla/vst.cpp b/src/carla/vst.cpp index ed14ed5..f5d217b 100644 --- a/src/carla/vst.cpp +++ b/src/carla/vst.cpp @@ -1054,6 +1054,8 @@ public: static intptr_t VstHostCallback(AEffect* effect, int32_t opcode, int32_t index, intptr_t value, void* ptr, float opt) { + // TODO - completely verify all calls + qDebug("VstHostCallback() - code: %02i, index: %02i, value: " P_INTPTR ", opt: %03f", opcode, index, value, opt); VstPlugin* plugin = (effect && effect->user) ? (VstPlugin*)effect->user : nullptr; @@ -1073,12 +1075,168 @@ public: //case audioMasterCurrentId: // return VstCurrentUniqueId; + case audioMasterIdle: + if (effect) + effect->dispatcher(effect, effEditIdle, 0, 0, nullptr, 0.0f); + return 1; // FIXME? + + case audioMasterWantMidi: + // Deprecated in VST SDK 2.4 +#if 0 + if (plugin && plugin->jack_client && plugin->min.count == 0) + { + i = plugin->id; + bool unlock = carla_proc_trylock(); + plugin->id = -1; + if (unlock) carla_proc_unlock(); + + const int port_name_size = jack_port_name_size(); + char port_name[port_name_size]; + +#ifndef BRIDGE_WINVST + if (carla_options.global_jack_client) + { + strncpy(port_name, plugin->name, (port_name_size/2)-2); + strcat(port_name, ":midi-in"); + } + else +#endif + strcpy(port_name, "midi-in"); + + plugin->min.count = 1; + plugin->min.ports = new jack_port_t*[1]; + plugin->min.ports[0] = jack_port_register(plugin->jack_client, port_name, JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0); + + plugin->id = i; +#ifndef BRIDGE_WINVST + callback_action(CALLBACK_RELOAD_INFO, plugin->id, 0, 0, 0.0f); +#endif + } +#endif + return 1; + case audioMasterGetTime: static VstTimeInfo timeInfo; memset(&timeInfo, 0, sizeof(VstTimeInfo)); + timeInfo.sampleRate = get_sample_rate(); + timeInfo.tempo = 120.0; + + if (plugin && plugin->jack_client) + { + static jack_position_t jack_pos; + static jack_transport_state_t jack_state; + + jack_state = jack_transport_query(plugin->jack_client, &jack_pos); + + if (jack_state == JackTransportRolling) + timeInfo.flags |= kVstTransportChanged|kVstTransportPlaying; + else + timeInfo.flags |= kVstTransportChanged; + + if (jack_pos.unique_1 == jack_pos.unique_2) + { + timeInfo.samplePos = jack_pos.frame; + timeInfo.sampleRate = jack_pos.frame_rate; + + if (jack_pos.valid & JackPositionBBT) + { + // Tempo + timeInfo.tempo = jack_pos.beats_per_minute; + timeInfo.timeSigNumerator = jack_pos.beats_per_bar; + timeInfo.timeSigDenominator = jack_pos.beat_type; + timeInfo.flags |= kVstTempoValid|kVstTimeSigValid; + + // Position + double dPos = timeInfo.samplePos / timeInfo.sampleRate; + timeInfo.nanoSeconds = dPos * 1000.0; + timeInfo.flags |= kVstNanosValid; + + // Position + timeInfo.barStartPos = 0; + timeInfo.ppqPos = dPos * timeInfo.tempo / 60.0; + timeInfo.flags |= kVstBarsValid|kVstPpqPosValid; + } + } + } + return (intptr_t)&timeInfo; + case audioMasterProcessEvents: +#if 0 + if (plugin && plugin->mout.count > 0 && ptr) + { + VstEvents* events = (VstEvents*)ptr; + + jack_default_audio_sample_t* mout_buffer = (jack_default_audio_sample_t*)jack_port_get_buffer(plugin->mout.ports[0], get_buffer_size()); + jack_midi_clear_buffer(mout_buffer); + + for (int32_t i=0; i < events->numEvents; i++) + { + VstMidiEvent* midi_event = (VstMidiEvent*)events->events[i]; + + if (midi_event && midi_event->type == kVstMidiType) + { + // TODO - send event over jack rinbuffer + } + } + return 1; + } + else + qDebug("Some MIDI Out events were ignored"); +#endif + return 0; + + case audioMasterTempoAt: + // Deprecated in VST SDK 2.4 + if (plugin && plugin->jack_client) + { + static jack_position_t jack_pos; + jack_transport_query(plugin->jack_client, &jack_pos); + + if (jack_pos.valid & JackPositionBBT) + return jack_pos.beats_per_minute; + } + return 120.0; + + case audioMasterGetNumAutomatableParameters: + // Deprecated in VST SDK 2.4 + return MAX_PARAMETERS; // FIXME - what exacly is this for? + + case audioMasterIOChanged: +// if (plugin && plugin->jack_client) +// { +// i = plugin->id; +// bool unlock = carla_proc_trylock(); +// plugin->id = -1; +// if (unlock) carla_proc_unlock(); + +// if (plugin->active) +// { +// plugin->effect->dispatcher(plugin->effect, 72 /* effStopProcess */, 0, 0, nullptr, 0.0f); +// plugin->effect->dispatcher(plugin->effect, effMainsChanged, 0, 0, nullptr, 0.0f); +// } + +// plugin->reload(); + +// if (plugin->active) +// { +// plugin->effect->dispatcher(plugin->effect, effMainsChanged, 0, 1, nullptr, 0.0f); +// plugin->effect->dispatcher(plugin->effect, 71 /* effStartProcess */, 0, 0, nullptr, 0.0f); +// } + +// plugin->id = i; +//#ifndef BRIDGE_WINVST +// callback_action(CALLBACK_RELOAD_ALL, plugin->id, 0, 0, 0.0); +//#endif +// } + return 1; + + case audioMasterNeedIdle: + // Deprecated in VST SDK 2.4 + effect->dispatcher(effect, 53 /* effIdle */, 0, 0, nullptr, 0.0f); + return 1; + case audioMasterSizeWindow: if (plugin) { @@ -1141,7 +1299,7 @@ public: else if (strcmp((char*)ptr, "startStopProcess") == 0) return 1; else if (strcmp((char*)ptr, "shellCategory") == 0) - return 1; + return -1; else if (strcmp((char*)ptr, "sendVstMidiEventFlagIsRealtime") == 0) return -1; else @@ -1153,6 +1311,26 @@ public: case audioMasterGetLanguage: return kVstLangEnglish; + case audioMasterUpdateDisplay: + if (plugin) + { + // Update current program name + if (plugin->prog.current >= 0 && plugin->prog.count > 0) + { + char buf_str[STR_MAX] = { 0 }; + + if (plugin->effect->dispatcher(plugin->effect, effGetProgramNameIndexed, plugin->prog.current, 0, buf_str, 0.0f) != 1) + plugin->effect->dispatcher(plugin->effect, effGetProgramName, 0, 0, buf_str, 0.0f); + + if (plugin->prog.names[plugin->prog.current]) + free((void*)plugin->prog.names[plugin->prog.current]); + + plugin->prog.names[plugin->prog.current] = strdup(buf_str); + } + callback_action(CALLBACK_UPDATE, plugin->id(), 0, 0, 0.0); + } + return 1; + default: break; }