/* Start recording to a specified file */ void Audio::AudioRecorder::startRecording (const File& file) { // make sure recorder is stopped first stop(); if (sampleRate > 0) { // delete file contents first file.deleteFile(); // create file stream for file ScopedPointer<FileOutputStream> fileStream (file.createOutputStream()); if (fileStream != nullptr) { // create a wav format writer WavAudioFormat wavFormat; AudioFormatWriter* writer = wavFormat.createWriterFor (fileStream, sampleRate, 1, 16, StringPairArray(), 0); if (writer != nullptr) { fileStream.release(); // create a thread for the writer. threadedWriter = new AudioFormatWriter::ThreadedWriter (writer, backgroundThread, 32768); // set the next sample number to start nextSampleNum = 0; // scoped lock for writer const ScopedLock sl (writerLock); activeWriter = threadedWriter; } } } }
//============================================================================== void startRecording (const File& file) { stop(); if (sampleRate > 0) { // Create an OutputStream to write to our destination file... file.deleteFile(); ScopedPointer<FileOutputStream> fileStream (file.createOutputStream()); if (fileStream != 0) { // Now create a WAV writer object that writes to our output stream... WavAudioFormat wavFormat; AudioFormatWriter* writer = wavFormat.createWriterFor (fileStream, sampleRate, 1, 16, StringPairArray(), 0); if (writer != 0) { fileStream.release(); // (passes responsibility for deleting the stream to the writer object that is now using it) // Now we'll create one of these helper objects which will act as a FIFO buffer, and will // write the data to disk on our background thread. threadedWriter = new AudioFormatWriter::ThreadedWriter (writer, backgroundThread, 32768); // And now, swap over our active writer pointer so that the audio callback will start using it.. const ScopedLock sl (writerLock); activeWriter = threadedWriter; } } } }
BEGIN_UGEN_NAMESPACE #include "ugen_DiskOut.h" #include "../ugen_JuceUtility.h" DiskOutUGenInternal::DiskOutUGenInternal(File const& file, UGen const& input, bool overwriteExisitingFile, int bitDepth) throw() : ProxyOwnerUGenInternal(NumInputs, input.getNumChannels()-1), audioFormatWriter(0), bufferData(0), numInputChannels(input.getNumChannels()) { ugen_assert(bitDepth >= 16); inputs[Input] = input; bufferData = new float*[numInputChannels]; memset(bufferData, 0, numInputChannels * sizeof(float*)); File outputFile(file); if(outputFile.getFileExtension().isEmpty()) outputFile = outputFile.withFileExtension("wav"); if(overwriteExisitingFile == true && outputFile.exists()) outputFile.deleteFile(); else if(outputFile.exists()) { ugen_assertfalse; return; } if(outputFile.hasFileExtension(".wav")) { WavAudioFormat wavAudioFormat; FileOutputStream* fileOutputStream = outputFile.createOutputStream(); if(fileOutputStream) audioFormatWriter = wavAudioFormat.createWriterFor(fileOutputStream, UGen::getSampleRate(), numInputChannels, bitDepth, 0, 0); } else if(outputFile.hasFileExtension(".aif") || outputFile.hasFileExtension(".aiff")) { AiffAudioFormat aiffAudioFormat; FileOutputStream* fileOutputStream = outputFile.createOutputStream(); if(fileOutputStream) audioFormatWriter = aiffAudioFormat.createWriterFor(fileOutputStream, UGen::getSampleRate(), numInputChannels, bitDepth, 0, 0); } }
Writer (OutputStream* destStream, const String& formatName, const File& lameApp, int vbr, int cbr, double sampleRate, unsigned int numberOfChannels, unsigned int bitsPerSample, const StringPairArray& metadata) : AudioFormatWriter (destStream, formatName, sampleRate, numberOfChannels, bitsPerSample), vbrLevel (vbr), cbrBitrate (cbr), tempWav (".wav") { WavAudioFormat wavFormat; if (FileOutputStream* out = tempWav.getFile().createOutputStream()) { writer = wavFormat.createWriterFor (out, sampleRate, numChannels, bitsPerSample, metadata, 0); args.add (lameApp.getFullPathName()); args.add ("--quiet"); if (cbrBitrate == 0) { args.add ("--vbr-new"); args.add ("-V"); args.add (String (vbrLevel)); } else { args.add ("--cbr"); args.add ("-b"); args.add (String (cbrBitrate)); } addMetadataArg (metadata, "id3title", "--tt"); addMetadataArg (metadata, "id3artist", "--ta"); addMetadataArg (metadata, "id3album", "--tl"); addMetadataArg (metadata, "id3comment", "--tc"); addMetadataArg (metadata, "id3date", "--ty"); addMetadataArg (metadata, "id3genre", "--tg"); addMetadataArg (metadata, "id3trackNumber", "--tn"); } }
void AudioRecorder::startRecording(const File& file){ stop(); if (sampleRate > 0) { file.deleteFile(); ScopedPointer<FileOutputStream> fileStream(file.createOutputStream()); if (fileStream != nullptr) { WavAudioFormat wavFormat; AudioFormatWriter* writer = wavFormat.createWriterFor(fileStream, sampleRate, 1, 16, StringPairArray(), 0); if (writer != nullptr) { fileStream.release(); threadedWriter = new AudioFormatWriter::ThreadedWriter(writer, backgroundThread, 32768); // thumbnail.reset(writer->getNumChannels(), writer->getSampleRate()); nextSampleNum = 0; const ScopedLock sl(writerLock); activeWriter = threadedWriter; } } } }
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); } } } } }
void MedianSeparator::writeFiles() { ScopedPointer<ISTFT> istft = new ISTFT(); istft->initWindow(1); // Matrices to hold real number data after conversion Eigen::MatrixXf harmonicSpectrogramReal_Left; Eigen::MatrixXf harmonicSpectrogramReal_Right; Eigen::MatrixXf percussiveSpectrogramReal_Left; Eigen::MatrixXf percussiveSpectrogramReal_Right; // initialise with zeros harmonicSpectrogramReal_Left = MatrixXf::Zero(WINDOW_SIZE, numCols); harmonicSpectrogramReal_Right = MatrixXf::Zero(WINDOW_SIZE, numCols); percussiveSpectrogramReal_Left = MatrixXf::Zero(WINDOW_SIZE, numCols); percussiveSpectrogramReal_Right = MatrixXf::Zero(WINDOW_SIZE, numCols); // convert complex spectrogram data to real spectrogram data harmonicSpectrogramReal_Left = istft->complexToReal(resynthSpectrogram_H[0]); harmonicSpectrogramReal_Right = istft->complexToReal(resynthSpectrogram_H[1]); percussiveSpectrogramReal_Left = istft->complexToReal(resynthSpectrogram_P[0]); percussiveSpectrogramReal_Right = istft->complexToReal(resynthSpectrogram_P[1]); // arrays to hold output signals for harmonic and percussive files Array<float> outputSignal_P[2]; Array<float> outputSignal_H[2]; // fill with zeros (faster than looping through) outputSignal_P[0].insertMultiple(0, 0.0f, numSamples); outputSignal_P[1].insertMultiple(0, 0.0f, numSamples); outputSignal_H[0].insertMultiple(0, 0.0f, numSamples); outputSignal_H[1].insertMultiple(0, 0.0f, numSamples); // add-overlap ==================== int offset = 0; float temp_L[WINDOW_SIZE] = {}; float temp_R[WINDOW_SIZE] = {}; float ifftResults_Left[WINDOW_SIZE] = {}; float ifftResults_Right[WINDOW_SIZE] = {}; // loop through each column in spectrograms for (int col = 0; col < numCols; col++) { // insert 4096 samples into temp arrays from harmonic spectrogram for (int row = 0; row < WINDOW_SIZE; row++) { temp_L[row] = harmonicSpectrogramReal_Left(row, col); temp_R[row] = harmonicSpectrogramReal_Right(row, col); } // inverse short time fourier transform on temp_L and temp_R istft->performInverseTransform(temp_L, ifftResults_Left); istft->rescale(ifftResults_Left); istft->performInverseTransform(temp_R, ifftResults_Right); istft->rescale(ifftResults_Right); // set values in output signal arrays for Harmonic output signal for (int i = 0; i < WINDOW_SIZE; i++) { outputSignal_H[0].set(offset + i, (outputSignal_H[0][offset + i] + (ifftResults_Left[i] * istft->window[i]))); outputSignal_H[1].set(offset + i, (outputSignal_H[1][offset + i] + (ifftResults_Right[i] * istft->window[i]))); } // insert 4096 samples into temp arrays from percussive spectrogram for (int row = 0; row < WINDOW_SIZE; row++) { temp_L[row] = percussiveSpectrogramReal_Left(row, col); temp_R[row] = percussiveSpectrogramReal_Right(row, col); } // inverse short time fourier transform on temp arrays istft->performInverseTransform(temp_L, ifftResults_Left); istft->rescale(ifftResults_Left); istft->performInverseTransform(temp_R, ifftResults_Right); istft->rescale(ifftResults_Right); // set values in output arrays for Percussive output signal for (int i = 0; i < WINDOW_SIZE; i++) { outputSignal_P[0].set(offset + i, (outputSignal_P[0][offset + i] + (ifftResults_Left[i] * istft->window[i]))); outputSignal_P[1].set(offset + i, (outputSignal_P[1][offset + i] + (ifftResults_Right[i] * istft->window[i]))); } offset += HOP_SIZE; // increment offset by HOP_SIZE (1024) } //===================================================== WRITE FILES == float gain = 0.5f; // 1.0f divided by num of output files (2) AudioSampleBuffer outSamples_H(2, numSamples); AudioSampleBuffer outSamples_P(2, numSamples); outSamples_H.clear(); outSamples_P.clear(); const float* leftData_H = outputSignal_H[0].getRawDataPointer(); const float* rightData_H = outputSignal_H[1].getRawDataPointer(); const float* leftData_P = outputSignal_P[0].getRawDataPointer(); const float* rightData_P = outputSignal_P[1].getRawDataPointer(); outSamples_H.addFrom(0, 0, leftData_H, numSamples, gain); outSamples_H.addFrom(1, 0, rightData_H, numSamples, gain); outSamples_P.addFrom(0, 0, leftData_P, numSamples, gain); outSamples_P.addFrom(1, 0, rightData_P, numSamples, gain); File* outputFile_H = new File(File::getCurrentWorkingDirectory().getChildFile(fileNameNoExt + "_harmonic.wav")); File* outputFile_P = new File(File::getCurrentWorkingDirectory().getChildFile(fileNameNoExt + "_percussive.wav")); if (outputFile_H->exists()) { outputFile_H->deleteFile(); } if (outputFile_P->exists()) { outputFile_P->deleteFile(); } FileOutputStream* output_H; FileOutputStream* output_P; output_H = outputFile_H->createOutputStream(); output_P = outputFile_P->createOutputStream(); // write from sample buffer WavAudioFormat* wavFormat = new WavAudioFormat(); AudioFormatWriter* writer = wavFormat->createWriterFor(output_H, 44100.0, numChannels, 16, NULL, 0); writer->flush(); writer->writeFromAudioSampleBuffer(outSamples_H, 0, numSamples); delete writer; writer = wavFormat->createWriterFor(output_P, 44100.0, numChannels, 16, NULL, 0); writer->flush(); writer->writeFromAudioSampleBuffer(outSamples_P, 0, numSamples); // cleanup delete writer; delete wavFormat; wavFormat = nullptr; writer = nullptr; outSamples_H.clear(); outSamples_P.clear(); outputSignal_H[0].clear(); outputSignal_H[1].clear(); outputSignal_P[0].clear(); outputSignal_P[1].clear(); }
void MainContentComponent::buttonClicked (Button* buttonThatWasClicked) { //[UserbuttonClicked_Pre] //[/UserbuttonClicked_Pre] if (buttonThatWasClicked == convButton) { //[UserButtonCode_convButton] -- add your button handler code here.. const ScopedLock fl(soundListLock); setPlayheadUiEnabled(false); bool convValid = true; float q; float s; double nfft; { const ScopedLock pl(paramLock); q = qParam; s = sParam; nfft = static_cast<double>(nfftParam); } int fftInputLen = static_cast<int>(std::pow(2.0, nfft)); int fftOutputLen = fftInputLen / 2 + 1; int numChannels = 1; unordered_set<int> includedSounds; int maxChannels = 0; float pSum = 0.0f; float rSum = 0.0f; for (const auto& iter : idToSound) { int id = iter.first; Sound* sound = iter.second.get(); int numChannels = sound->getBufferNumChannels(); if (sound->isIncluded() && numChannels > 0) { maxChannels = numChannels > maxChannels ? numChannels : maxChannels; includedSounds.emplace(id); pSum += static_cast<float>(sound->getPValue()); rSum += static_cast<float>(sound->getRValue()); } } float n = static_cast<float>(includedSounds.size()); float pScale = n * q / pSum; float rScale = n * s / rSum; if (maxChannels == 0) { return; } kiss_fftr_state* fftInverseState = kiss_fftr_alloc(fftInputLen, 1, nullptr, nullptr); kiss_fft_cpx* CONV = static_cast<kiss_fft_cpx*>(calloc(fftOutputLen * maxChannels, sizeof(kiss_fft_cpx))); conv.setSize(maxChannels, fftInputLen); float max = -1.0f; // convolve for (int convChannel = 0; convChannel < maxChannels; ++convChannel) { kiss_fft_cpx* CONVCHANNEL = CONV + (convChannel * fftOutputLen); bool isFirstSound = true; for (const auto& id : includedSounds) { Sound* sound = idToSound[id].get(); jassert(sound != nullptr); float p = pScale * static_cast<float>(sound->getPValue()); float r = rScale * static_cast<float>(sound->getRValue()); int soundNumChannels = sound->getBufferNumChannels(); int soundNumSamples = sound->getBufferNumSamples(); int soundChannel = convChannel >= soundNumChannels ? soundNumChannels - 1 : convChannel; const kiss_fft_cpx* SOUNDCHANNEL = sound->getSpectra(fftInputLen, soundChannel); for (int i = 0; i < fftOutputLen; ++i) { float xr = SOUNDCHANNEL[i].r; float xi = SOUNDCHANNEL[i].i; float xMag = sqrtf((xr * xr) + (xi * xi)); float xPhs = atan2f(xi, xr); float convMag = powf(xMag, p); float convPhs = r * xPhs; float convr = convMag * cosf(convPhs); float convi = convMag * sinf(convPhs); if (std::isnan(convr) || std::isnan(convi)) { convValid = false; } if (isFirstSound) { CONVCHANNEL[i].r = convr; CONVCHANNEL[i].i = convi; } else { float a = CONVCHANNEL[i].r; float b = CONVCHANNEL[i].i; float c = convr; float d = convi; CONVCHANNEL[i].r = a * c - b * d; CONVCHANNEL[i].i = a * d + b * c; } } isFirstSound = false; } // ifft kiss_fftri(fftInverseState, CONVCHANNEL, conv.getWritePointer(convChannel)); // check max float channelMax = conv.findMinMax(convChannel, 0, fftInputLen).getEnd(); max = channelMax > max ? channelMax : max; } delete fftInverseState; delete CONV; // normalize conv.applyGain(1.0f / max); if (!convValid) { AlertWindow::showMessageBoxAsync(AlertWindow::WarningIcon, "Error", "Parameters produced NaN value."); return; } setPlayheadAudio(&conv); //[/UserButtonCode_convButton] } else if (buttonThatWasClicked == settingsButton) { //[UserButtonCode_settingsButton] -- add your button handler code here.. AudioDeviceSelectorComponent audioSettingsComp(deviceManager, 0, 256, 0, 256, true, true, true, false); audioSettingsComp.setSize(500, 450); DialogWindow::LaunchOptions o; o.content.setNonOwned(&audioSettingsComp); o.dialogTitle = "Audio Settings"; o.componentToCentreAround = this; o.dialogBackgroundColour = Colours::azure; o.escapeKeyTriggersCloseButton = true; o.useNativeTitleBar = false; o.resizable = false; o.runModal(); ScopedPointer<XmlElement> audioState(deviceManager.createStateXml()); getAppProperties().getUserSettings()->setValue("audioDeviceState", audioState); getAppProperties().getUserSettings()->saveIfNeeded(); //[/UserButtonCode_settingsButton] } else if (buttonThatWasClicked == playButton) { //[UserButtonCode_playButton] -- add your button handler code here.. const ScopedLock pal(playheadAudioLock); playheadState = PlayheadState::playing; playheadAudioSamplesCompleted = 0; //[/UserButtonCode_playButton] } else if (buttonThatWasClicked == loopButton) { //[UserButtonCode_loopButton] -- add your button handler code here.. const ScopedLock pal(playheadAudioLock); playheadState = PlayheadState::looping; //[/UserButtonCode_loopButton] } else if (buttonThatWasClicked == stopButton) { //[UserButtonCode_stopButton] -- add your button handler code here.. const ScopedLock pal(playheadAudioLock); playheadState = PlayheadState::stopped; playheadAudioSamplesCompleted = 0; //[/UserButtonCode_stopButton] } else if (buttonThatWasClicked == qDefaultButton) { //[UserButtonCode_qDefaultButton] -- add your button handler code here.. qSlider->setValue(1.0); //[/UserButtonCode_qDefaultButton] } else if (buttonThatWasClicked == sDefaultButton) { //[UserButtonCode_sDefaultButton] -- add your button handler code here.. sSlider->setValue(1.0); //[/UserButtonCode_sDefaultButton] } else if (buttonThatWasClicked == saveButton) { //[UserButtonCode_saveButton] -- add your button handler code here.. const ScopedLock pal(playheadAudioLock); if (playheadAudio.getNumChannels() > 0 && playheadAudio.getNumSamples() > 0) { FileChooser fileChooser("Save as...", File::nonexistent, "*.wav", true); if (fileChooser.browseForFileToSave(true)) { File outputFile = fileChooser.getResult(); outputFile.deleteFile(); WavAudioFormat wavFormat; ScopedPointer<FileOutputStream> outputFileStream = outputFile.createOutputStream(); ScopedPointer<AudioFormatWriter> writer = wavFormat.createWriterFor(outputFileStream, 44100.0, playheadAudio.getNumChannels(), 16, StringPairArray(), 0); writer->writeFromAudioSampleBuffer(playheadAudio, 0, playheadAudio.getNumSamples()); outputFileStream.release(); } } //[/UserButtonCode_saveButton] } else if (buttonThatWasClicked == inputRemoveButton) { //[UserButtonCode_inputRemoveButton] -- add your button handler code here.. const ScopedLock fl(soundListLock); SparseSet<int> selectedRows = inputFileListComponent->getSelectedRows(); for (int i = 0; i < selectedRows.size(); ++i) { int row = selectedRows[i]; int id = inputFileListComponent->getIdForRow(row); const auto& iter = idToSound.find(id); jassert(iter != idToSound.end()); idToSound.erase(iter); } if (selectedRows.size() > 0) { inputFilesChanged(dontSendNotification); } //[/UserButtonCode_inputRemoveButton] } else if (buttonThatWasClicked == inputAddButton) { //[UserButtonCode_inputAddButton] -- add your button handler code here.. const ScopedLock fl(soundListLock); FileChooser fileChooser("Add sound...", File::nonexistent, "*.wav;*.aif;*.aiff;*.ogg", true); if (fileChooser.browseForMultipleFilesToOpen()) { Array<File> files = fileChooser.getResults(); StringArray filePaths; for (int i = 0; i < files.size(); ++i) { filePaths.add(files[i].getFullPathName()); } filesDropped(filePaths, -1, -1); } //[/UserButtonCode_inputAddButton] } //[UserbuttonClicked_Post] //[/UserbuttonClicked_Post] }
//============================================================================== int main (int argc, char* argv[]) { if (argc != 3) { cout << "Usage: <prog> <midi input file> <wav output file>" << endl; return 0; } File inMidiFile = File(argv[1]); File outWavFile = File(argv[2]); //File inMidiFile = File("C:\\Users\\GeorgeKrueger\\Documents\\GitHub\\pymusic\\out.mid"); //File outWavFile = File("C:\\Users\\GeorgeKrueger\\Documents\\GitHub\\pymusic\\out.wav"); FileInputStream fileStream(inMidiFile); juce::MidiFile midiFile; midiFile.readFrom(fileStream); int numTracks = midiFile.getNumTracks(); midiFile.convertTimestampTicksToSeconds(); std::cout << "Opened midi file: " << inMidiFile.getFileName() << " Tracks: " << numTracks << std::endl;; playHead.posInfo.bpm = 120; playHead.posInfo.isPlaying = true; playHead.posInfo.timeInSamples = 0; playHead.posInfo.timeInSeconds = 0; playHead.posInfo.timeSigNumerator = 4; playHead.posInfo.timeSigDenominator = 4; for (int i = 0; i < numTracks; ++i) { const juce::MidiMessageSequence* msgSeq = midiFile.getTrack(i); double trackLengthSeconds = 0; String plugFile = ""; int program = 0; for (int j = 0; j < msgSeq->getNumEvents(); ++j) { juce::MidiMessageSequence::MidiEventHolder* midiEventHolder = msgSeq->getEventPointer(j); juce::MidiMessage midiMsg = midiEventHolder->message; if (midiMsg.isMetaEvent() && midiMsg.getMetaEventType() == 0x04) { // Instrument meta event int instrLength = midiMsg.getMetaEventLength(); const juce::uint8* instrChars = midiMsg.getMetaEventData(); String instrName((char*)instrChars, instrLength); plugFile = instrName; } if (midiMsg.isMetaEvent() && midiMsg.isEndOfTrackMetaEvent()) { //int oetDataLength = midiMsg.getMetaEventLength(); //const uint8* oetData = midiMsg.getMetaEventData(); //std::cout << "Found end of track event data size: " << oetDataLength << " data: " << oetData << std::endl; trackLengthSeconds = midiMsg.getTimeStamp(); std::cout << "Track length in seconds: " << trackLengthSeconds << std::endl; } } if (trackLengthSeconds == 0) { std::cerr << "Skipping track " << i << " since it has zero length" << std::endl; continue; } if (plugFile.isEmpty()) { plugFile = "C:\\VST\\helm.dll"; std::cout << "No plug found for track. Defaulting to: " << plugFile << std::endl; //std::cerr << "Skipping track " << i << ". No instrument found." << std::endl; //continue; } else { std::cout << "Found plugin file '" << plugFile << "' from track " << i << std::endl; } OwnedArray<PluginDescription> results; VSTPluginFormat vstFormat; vstFormat.findAllTypesForFile(results, plugFile); if (results.size() > 0) { std::cout << "Found " << results.size() << " plugin(s) in file '" << plugFile << "'" << std::endl; int blockSize = 1024; double sampleRate = 44100; int totalSizeInSamples = ((static_cast<int>(44100 * trackLengthSeconds) / 1024) + 1) * 1024; cout << "Total samples to render " << totalSizeInSamples << endl; juce::AudioPluginInstance* plugInst = vstFormat.createInstanceFromDescription(*results[0], sampleRate, blockSize); if (!plugInst) { cout << "Failed to load plugin " << plugFile << endl; continue; } AudioProcessorGraph* graph = new AudioProcessorGraph(); graph->setPlayConfigDetails(0, 2, sampleRate, blockSize); graph->setPlayHead(&playHead); graph->addNode(plugInst, 1000); int AUDIO_IN_ID = 101; int AUDIO_OUT_ID = 102; int MIDI_IN_ID = 103; juce::AudioPluginInstance* audioInNode = new AudioGraphIOProcessor(AudioGraphIOProcessor::audioInputNode); juce::AudioPluginInstance* audioOutNode = new AudioGraphIOProcessor(AudioGraphIOProcessor::audioOutputNode); juce::AudioPluginInstance* midiInNode = new AudioGraphIOProcessor(AudioGraphIOProcessor::midiInputNode); graph->addNode(audioInNode, AUDIO_IN_ID); graph->addNode(audioOutNode, AUDIO_OUT_ID); graph->addNode(midiInNode, MIDI_IN_ID); graph->addConnection(AUDIO_IN_ID, 0, 1000, 0); graph->addConnection(AUDIO_IN_ID, 1, 1000, 1); graph->addConnection(MIDI_IN_ID, AudioProcessorGraph::midiChannelIndex, 1000, AudioProcessorGraph::midiChannelIndex); graph->addConnection(1000, 0, AUDIO_OUT_ID, 0); graph->addConnection(1000, 1, AUDIO_OUT_ID, 1); plugInst->setCurrentProgram(program); int numInputChannels = plugInst->getTotalNumInputChannels(); int numOutputChannels = plugInst->getTotalNumOutputChannels(); cout << "----- Plugin Information -----" << endl; cout << "Input channels : " << numInputChannels << endl; cout << "Output channels : " << numOutputChannels << endl; cout << "Num Programs: " << plugInst->getNumPrograms() << endl; cout << "Current program: " << plugInst->getCurrentProgram() << endl; int numParams = plugInst->getNumParameters(); cout << "Num Parameters: " << numParams << endl; for (int p = 0; p < numParams; ++p) { std::cout << "Param " << p << ": " << plugInst->getParameterName(p); if (!plugInst->getParameterLabel(p).isEmpty()) { cout << "(" << plugInst->getParameterLabel(p) << ")"; } cout << " = " << plugInst->getParameter(p) << endl; } cout << "-----------------------------" << endl; int maxChannels = std::max(numInputChannels, numOutputChannels); AudioBuffer<float> entireAudioBuffer(maxChannels, totalSizeInSamples); entireAudioBuffer.clear(); unsigned int midiSeqPos = 0; graph->releaseResources(); graph->prepareToPlay(sampleRate, blockSize); cout << "Num midi events: " << msgSeq->getNumEvents() << endl; // Render the audio in blocks for (int t = 0; t < totalSizeInSamples; t += blockSize) { //cout << "processing block " << t << " to " << t + blockSize << endl; MidiBuffer midiBuffer; for (int j = midiSeqPos; j < msgSeq->getNumEvents(); ++j) { MidiMessageSequence::MidiEventHolder* midiEventHolder = msgSeq->getEventPointer(j); MidiMessage midiMsg = midiEventHolder->message; int samplePos = static_cast<int>(midiMsg.getTimeStamp() * sampleRate); if (samplePos >= t && samplePos < t + blockSize) { if (midiMsg.isNoteOnOrOff()) { if (midiMsg.isNoteOn()) { cout << "note on event (" << midiMsg.getNoteNumber() << ") at " << samplePos << "(" << midiMsg.getTimeStamp() << "s) bufferpos=" << (samplePos - t) << endl; } else if (midiMsg.isNoteOff()) { cout << "note off event (" << midiMsg.getNoteNumber() << ") at " << samplePos << "(" << midiMsg.getTimeStamp() << "s) bufferpos=" << (samplePos - t) << endl; } midiBuffer.addEvent(midiMsg, samplePos - t); } else if (midiMsg.isProgramChange()) { program = midiMsg.getProgramChangeNumber(); plugInst->setCurrentProgram(program); } midiSeqPos++; } else { break; } } playHead.posInfo.timeInSamples = t; playHead.posInfo.timeInSeconds = t / sampleRate; AudioBuffer<float> blockAudioBuffer(entireAudioBuffer.getNumChannels(), blockSize); blockAudioBuffer.clear(); graph->processBlock(blockAudioBuffer, midiBuffer); for (int ch = 0; ch < entireAudioBuffer.getNumChannels(); ++ch) { entireAudioBuffer.addFrom(ch, t, blockAudioBuffer, ch, 0, blockSize); } } if (outWavFile.exists()) { outWavFile.deleteFile(); } FileOutputStream* fileOutputStream = outWavFile.createOutputStream(); WavAudioFormat wavFormat; StringPairArray metadataValues; juce::AudioFormatWriter* wavFormatWriter = wavFormat.createWriterFor( fileOutputStream, sampleRate, 2, 16, metadataValues, 0); bool writeAudioDataRet = wavFormatWriter->writeFromAudioSampleBuffer(entireAudioBuffer, 0, entireAudioBuffer.getNumSamples()); wavFormatWriter->flush(); cout << "Done writing to output file " << outWavFile.getFileName() << " . Write return value: " << (int)writeAudioDataRet << endl; delete wavFormatWriter; } else { cerr << "Could not find plugin from file " << plugFile << endl; } } return 0; }