static int get_current_preset(struct SoundPlugin *plugin){ #if JUCE_LINUX const MessageManagerLock mmLock; #endif Data *data = (Data*)plugin->data; AudioPluginInstance *instance = data->audio_instance; return instance->getCurrentProgram(); }
virtual void menuItemSelected(int menuItemID, int) { if (menuItemID == 200) { WildcardFileFilter wildcardFilter("*.mid", String::empty, "Midi files"); FileBrowserComponent browser(FileBrowserComponent::canSelectFiles | FileBrowserComponent::openMode, lastOpenedFile.exists() ? lastOpenedFile : File(String("C:\\Users\\GeorgeKrueger\\Documents")), &wildcardFilter, nullptr); FileChooserDialogBox dialogBox("Open a midi file", "Please choose a midi file to open...", browser, false, Colours::lightgrey); if (dialogBox.show()) { File selectedFile = browser.getSelectedFile(0); lastOpenedFile = selectedFile; FileInputStream fileStream(selectedFile); juce::MidiFile midiFile; midiFile.readFrom(fileStream); int numTracks = midiFile.getNumTracks(); midiFile.convertTimestampTicksToSeconds(); String msg; msg << "Opened midi file: " << selectedFile.getFileName() << " Tracks: " << numTracks << "\n"; log(msg); for (int i = 0; i < numTracks; ++i) { const MidiMessageSequence* msgSeq = midiFile.getTrack(i); OwnedArray<PluginDescription> results; String plugFile = "C:\\VST\\FMMF.dll"; VSTPluginFormat vstFormat; vstFormat.findAllTypesForFile(results, plugFile); if (results.size() > 0) { msg.clear(); msg << "Found " << results.size() << " plugin(s) matching file " << plugFile << "\n"; log(msg); int secsToRender = 10; double sampleRate = 44100; int totalSizeInSamples = static_cast<int>(44100 * secsToRender); AudioPluginInstance* plugInst = vstFormat.createInstanceFromDescription(*results[0], sampleRate, totalSizeInSamples); if (!plugInst) { msg.clear(); msg << "Failed to load plugin " << plugFile << "\n"; log(msg); continue; } int numInputChannels = plugInst->getTotalNumInputChannels(); int numOutputChannels = plugInst->getTotalNumOutputChannels(); msg.clear(); msg << "Plugin input channels: " << numInputChannels << " output channels: " << numOutputChannels << " Current program: " << plugInst->getCurrentProgram() << "\n"; log(msg); int maxChannels = std::max(numInputChannels, numOutputChannels); AudioBuffer<float> buffer(maxChannels, totalSizeInSamples); MidiBuffer midiMessages; for (int j = 0; j < msgSeq->getNumEvents(); ++j) { MidiMessageSequence::MidiEventHolder* midiEventHolder = msgSeq->getEventPointer(j); MidiMessage midiMsg = midiEventHolder->message; int samplePos = static_cast<int>(midiMsg.getTimeStamp() * sampleRate); midiMessages.addEvent(midiMsg, samplePos); } plugInst->prepareToPlay(sampleRate, totalSizeInSamples); plugInst->processBlock(buffer, midiMessages); /*File txtOutFile("C:\\Users\\GeorgeKrueger\\Documents\\GitHub\\soundserver2\\out.txt"); FileOutputStream* txtOutStream = txtOutFile.createOutputStream(); for (int j = 0; j < 44100; ++j) { float sample = buffer.getSample(0, j); txtOutStream->writeFloat(sample); txtOutStream->writeText(" ", true, false); }*/ File outputFile("C:\\Users\\GeorgeKrueger\\Documents\\GitHub\\soundserver2\\out.wav"); if (outputFile.exists()) { outputFile.deleteFile(); } FileOutputStream* fileOutputStream = outputFile.createOutputStream(); WavAudioFormat wavFormat; StringPairArray metadataValues; juce::AudioFormatWriter* wavFormatWriter = wavFormat.createWriterFor( fileOutputStream, sampleRate, 2, 16, metadataValues, 0); bool writeAudioDataRet = wavFormatWriter->writeFromAudioSampleBuffer(buffer, 0, buffer.getNumSamples()); wavFormatWriter->flush(); msg.clear(); msg << "Done writing to output file " << outputFile.getFileName() << " . Write return value: " << (int)writeAudioDataRet << "\n"; log(msg); delete wavFormatWriter; delete plugInst; } else { msg.clear(); msg << "Could not find plugin from file " << plugFile << "\n"; log(msg); } } } } }
bool handlePluginRequest(const PluginRequestParameters ¶ms, OutputStream &ostream, ThreadSafePlugin *plugin = nullptr) { if (!plugin) { // It's very possible that all of this was a premature optimization. // For VSTs at least, code loading and caching is handled by ModuleHandle::findOrCreateModule, // and each instantiation only requires a couple of disc hits for working directory setting. // On the other hand, we want to make sure that each audio request has a "fresh" instance. // The easiest way to do this is by bypassing the instance pool and instantiating on demand. #if PLUGIN_POOL_SIZE // Recurse with a plugin from the pool, locking on it. // Keep trying with a delay until a timeout occurs. const int TIMEOUT = 5000, WAIT = 200; int64 startTime = Time::currentTimeMillis(); while (Time::currentTimeMillis() < startTime + TIMEOUT) { int i = 0; while ((plugin = pluginPool[i++])) { const ScopedTryLock pluginTryLock(plugin->crit); if (pluginTryLock.isLocked()) { DBG << "Handling with plugin " << i << endl; return handlePluginRequest(params, ostream, plugin); } } DBG << "Trying again in " << WAIT << endl; Thread::sleep(WAIT); } // If we were unable to obtain a lock, return failure. DBG << "Timeout" << endl; return false; #else ThreadSafePlugin temporaryPlugin(createSynthInstance()); return handlePluginRequest(params, ostream, &temporaryPlugin); #endif } else { // Re-acquire or acquire the lock. const ScopedLock pluginLock(plugin->crit); AudioPluginInstance *instance = plugin->instance; // unmanaged, for simplicity // Attempt to reset the plugin in all ways possible. instance->reset(); // Setting default parameters here causes miniTERA to become unresponsive to parameter settings. // It's possible that it's effectively pressing some interface buttons that change the editor mode entirely. // It's not necessary anyways if the plugin instance has been freshly created (see above). // pluginParametersOldNewFallback(instance, nullptr, &pluginDefaults); // note that the defaults may be empty instance->setCurrentProgram(0); // Load preset if specified, before listing or modifying parameters! if (params.presetNumber >= 0 && params.presetNumber < instance->getNumPrograms()) { DBG << "Setting program/preset: " << params.presetNumber << endl; instance->setCurrentProgram(params.presetNumber); } int currentProgram = instance->getCurrentProgram(); DBG << "Current program/preset: " << currentProgram << " - " << instance->getProgramName(currentProgram) << endl; // Set parameters, starting with named, then indexed pluginParametersSet(instance, params.parameters); pluginParametersSetIndexed(instance, params.indexedParameters); // If parameters requested, output them and return if (params.listParameters) { DBG << "Rendering parameter list: # parameters " << instance->getNumPrograms() << endl; // Output each parameter setting in two places: // an indexed array and a dictionary by name // All DynamicObjects created will be freed when their var's leave scope. DynamicObject *outer = new DynamicObject(); DynamicObject *innerParams = new DynamicObject(); var indexedParamVar; { for (int i = 0, n = instance->getNumParameters(); i < n; ++i) { String name = instance->getParameterName(i); float val = instance->getParameter(i); innerParams->setProperty(name, val); DynamicObject *indexedInnerObj = new DynamicObject(); indexedInnerObj->setProperty("index", i); indexedInnerObj->setProperty("name", name); indexedInnerObj->setProperty("value", val); indexedParamVar.append(var(indexedInnerObj)); // frees indexedInnerObj when this scope ends } } outer->setProperty(Identifier("parameters"), var(innerParams)); outer->setProperty(Identifier("indexedParameters"), indexedParamVar); // List presets/programs. var progVar; { for (int i = 0, n = instance->getNumPrograms(); i < n; ++i) { progVar.append(var(instance->getProgramName(i))); } } outer->setProperty(Identifier("presets"), progVar); var outerVar(outer); JSON::writeToStream(ostream, outerVar); // DBG << JSON::toString(outerVar, true /* allOnOneLine */) << endl; return true; } // Now attempt to render audio. AudioFormatManager formatManager; formatManager.registerBasicFormats(); OptionalScopedPointer<AudioFormat> outputFormat(formatManager.findFormatForFileExtension(params.getFormatName()), false); if (!outputFormat) return false; instance->setNonRealtime(true); instance->prepareToPlay(params.sampleRate, params.blockSize); instance->setNonRealtime(true); // The writer takes ownership of the output stream; the writer will delete it when the writer leaves scope. // Therefore, we pass a special pointer class that does not allow the writer to delete it. OutputStream *ostreamNonDeleting = new NonDeletingOutputStream(&ostream); ScopedPointer<AudioFormatWriter> writer(outputFormat->createWriterFor(ostreamNonDeleting, params.sampleRate, params.nChannels, params.bitDepth, StringPairArray(), 0)); // Create a MIDI buffer MidiBuffer midiBuffer; midiBuffer.addEvent(MidiMessage::noteOn(params.midiChannel, (uint8)params.midiPitch, (uint8)params.midiVelocity), 0 /* time */); midiBuffer.addEvent(MidiMessage::allNotesOff(params.midiChannel), params.noteSeconds * params.sampleRate); AudioSampleBuffer buffer(params.nChannels, params.blockSize); int numBuffers = (int)(params.renderSeconds * params.sampleRate / params.blockSize); for (int i = 0; i < numBuffers; ++i) { // DBG << "Processing block " << i << "..." << flush; instance->processBlock(buffer, midiBuffer); // DBG << " left RMS level " << buffer.getRMSLevel(0, 0, params.blockSize) << endl; writer->writeFromAudioSampleBuffer(buffer, 0 /* offset into buffer */, params.blockSize); } instance->reset(); return true; } }