/** * Copyright (c) 2021 Enzien Audio, Ltd. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions, and the following disclaimer. * * 2. Redistributions in binary form must reproduce the phrase "powered by heavy", * the heavy logo, and a hyperlink to https://enzienaudio.com, all in a visible * form. * * 2.1 If the Application is distributed in a store system (for example, * the Apple "App Store" or "Google Play"), the phrase "powered by heavy" * shall be included in the app description or the copyright text as well as * the in the app itself. The heavy logo will shall be visible in the app * itself as well. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include "HeavyDPF_dpf_example.hpp" #define HV_LV2_NUM_PARAMETERS 0 #define HV_HASH_NOTEIN 0x67E37ca3 #define HV_HASH_CTLIN 0x41be0f9c #define HV_HASH_BENDIN 0x3083f0f7 #define HV_HASH_TOUCHIN 0x553925bd #define HV_HASH_PGMIN 0x2e1ea03d #define HV_HASH_NOTEOUT 0xd1d4ac2 #define HV_HASH_CTLOUT 0xe5e2a040 #define HV_HASH_BENDOUT 0xe8458013 #define HV_HASH_TOUCHOUT 0x476d4387 #define HV_HASH_PGMOUT 0x8753e39e START_NAMESPACE_DISTRHO static void sendHookFunc(HeavyContextInterface *c, const char *sendName, uint32_t sendHash, const HvMessage *m) { printf("> midi output stuff! \n"); HeavyDPF_dpf_example* plugin = (HeavyDPF_dpf_example*)c->getUserData(); if (plugin != nullptr) { plugin->handleMidiSend(sendHash, m); } } HeavyDPF_dpf_example::HeavyDPF_dpf_example() : Plugin(HV_LV2_NUM_PARAMETERS, 0, 0) { _context = new Heavy_dpf_example(getSampleRate(), 10, 2, 5); _context->setUserData(this); _context->setSendHook(&sendHookFunc); } HeavyDPF_dpf_example::~HeavyDPF_dpf_example() { delete _context; } void HeavyDPF_dpf_example::initParameter(uint32_t index, Parameter& parameter) { } // ------------------------------------------------------------------- // Internal data float HeavyDPF_dpf_example::getParameterValue(uint32_t index) const { return 0.0f; } void HeavyDPF_dpf_example::setParameterValue(uint32_t index, float value) { // nothing to do } // ------------------------------------------------------------------- // Process // void HeavyDPF_dpf_example::activate() // { // } // void HeavyDPF_dpf_example::deactivate() // { // } void HeavyDPF_dpf_example::run(const float** inputs, float** outputs, uint32_t frames, const MidiEvent* midiEvents, uint32_t midiEventCount) { uint32_t framesDone = 0; uint32_t curEventIndex = 0; _context->process((float**)inputs, outputs, frames); while (framesDone < frames) { while (curEventIndex < midiEventCount && framesDone == midiEvents[curEventIndex].frame) { if (midiEvents[curEventIndex].size > MidiEvent::kDataSize) continue; handleMidiInput(frames, curEventIndex, midiEvents, midiEventCount); curEventIndex++; } framesDone++; } } // ------------------------------------------------------------------- // Callbacks void HeavyDPF_dpf_example::sampleRateChanged(double newSampleRate) { delete _context; _context = new Heavy_dpf_example(newSampleRate, 10, 2, 5); _context->setUserData(this); _context->setSendHook(&sendHookFunc); } void HeavyDPF_dpf_example::handleMidiInput(uint32_t frames, uint32_t curEventIndex, const MidiEvent* midiEvents, uint32_t midiEventCount) { int status = midiEvents[curEventIndex].data[0]; int command = status & 0xF0; int channel = status & 0x0F; int data1 = midiEvents[curEventIndex].data[1]; int data2 = midiEvents[curEventIndex].data[2]; switch (command) { case 0x80: // note off case 0x90: { // note on printf("> midi input stuff! pitch: %d - velocity: %d - channel: %d \n", data1, data2, channel); _context->sendMessageToReceiverV(HV_HASH_NOTEIN, 1000.0*frames/getSampleRate(), "fff", (float) data1, // pitch (float) data2, // velocity (float) channel); break; } case 0xB0: { // control change _context->sendMessageToReceiverV(HV_HASH_CTLIN, 0, "fff", (float) data2, // value (float) data1, // controller number (float) channel); break; } case 0xC0: { // program change _context->sendMessageToReceiverV(HV_HASH_PGMIN, 0, "ff", (float) data1, (float) channel); break; } case 0xD0: { // aftertouch _context->sendMessageToReceiverV(HV_HASH_TOUCHIN, 0, "ff", (float) data1, (float) channel); break; } case 0xE0: { // pitch bend hv_uint32_t value = (((hv_uint32_t) data2) << 7) | ((hv_uint32_t) data1); _context->sendMessageToReceiverV(HV_HASH_BENDIN, 0, "ff", (float) value, (float) channel); break; } default: break; } } void HeavyDPF_dpf_example::handleMidiSend(uint32_t sendHash, const HvMessage *m) { switch(sendHash){ case HV_HASH_NOTEOUT: // __hv_noteout { uint8_t note = hv_msg_getFloat(m, 0); uint8_t velocity = hv_msg_getFloat(m, 1); uint8_t ch = hv_msg_getFloat(m, 2); printf("> note: %d - velocity: %d - ch: %d \n", note, velocity, ch); MidiEvent midiSendEvent; midiSendEvent.frame = 0; midiSendEvent.size = m->numElements; midiSendEvent.dataExt = nullptr; if (velocity == 127){ midiSendEvent.data[0] = 0x80 | ch; // noteoff } else { midiSendEvent.data[0] = 0x90 | ch; // noteon } midiSendEvent.data[1] = note; midiSendEvent.data[2] = velocity; midiSendEvent.data[3] = 0; writeMidiEvent(midiSendEvent); break; } case HV_HASH_CTLOUT: { uint8_t value = hv_msg_getFloat(m, 0); uint8_t cc = hv_msg_getFloat(m, 1); uint8_t ch = hv_msg_getFloat(m, 2); printf("> value: %d - cc: %d - ch: %d \n", value, cc, ch); MidiEvent midiSendEvent; midiSendEvent.frame = 0; midiSendEvent.size = m->numElements; midiSendEvent.dataExt = nullptr; midiSendEvent.data[0] = 0xB0 | ch; // send CC midiSendEvent.data[1] = cc; midiSendEvent.data[2] = value; midiSendEvent.data[3] = 0; writeMidiEvent(midiSendEvent); break; } case HV_HASH_PGMOUT: { uint8_t cc_val = hv_msg_getFloat(m, 0); uint8_t cc_num = hv_msg_getFloat(m, 1); uint8_t ch = hv_msg_getFloat(m, 2); printf("> cc_val: %d - cc_num: %d - ch: %d \n", cc_val, cc_num, ch); MidiEvent midiSendEvent; midiSendEvent.frame = 0; midiSendEvent.size = m->numElements; midiSendEvent.dataExt = nullptr; midiSendEvent.data[0] = 0xC0 | ch; // send Program Change midiSendEvent.data[1] = cc_num; midiSendEvent.data[2] = cc_val; midiSendEvent.data[3] = 0; break; } case HV_HASH_TOUCHOUT: { uint8_t value = hv_msg_getFloat(m, 0); uint8_t ch = hv_msg_getFloat(m, 2); printf("> value: %d - ch: %d \n", value, ch); MidiEvent midiSendEvent; midiSendEvent.frame = 0; midiSendEvent.size = m->numElements; midiSendEvent.dataExt = nullptr; midiSendEvent.data[0] = 0xD0 | ch; // send Touch midiSendEvent.data[1] = value; midiSendEvent.data[2] = 0; midiSendEvent.data[3] = 0; break; } case HV_HASH_BENDOUT: { break; } default: break; } } // ----------------------------------------------------------------------- /* Plugin entry point, called by DPF to create a new plugin instance. */ Plugin* createPlugin() { return new HeavyDPF_dpf_example(); } // ----------------------------------------------------------------------- END_NAMESPACE_DISTRHO