Mercurial > hg > yjdafx13bpr
changeset 0:2cd427e000b0
initial commit
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/AddressPlugin/PluginEditor.cpp Tue Sep 03 12:53:16 2013 +0100 @@ -0,0 +1,178 @@ +/* + ============================================================================== + + This file was auto-generated by the Introjucer! + + It contains the basic startup code for a Juce application. + + ============================================================================== +*/ + +#include "PluginProcessor.h" +#include "PluginEditor.h" + + +//============================================================================== +ADRessAudioProcessorEditor::ADRessAudioProcessorEditor (ADRessAudioProcessor* ownerFilter) + : AudioProcessorEditor (ownerFilter), + fftSizeLabel_("", "FFT Size:"), + hopSizeLabel_("", "Hop Size:"), + windowTypeLabel_("", "Window Type:"), + widthLabel_("", "Width:"), + widthSlider_("width"), + azimuthLabel_("", "Azimuth:"), + azimuthSlider_("azimuth") +{ + // This is where our plugin's editor size is set. + // setSize(170, 80); + + betaE_ = 5; + // Set up the selection boxes + + addAndMakeVisible(&fftSizeComboBox_); + fftSizeComboBox_.setEditableText(false); + fftSizeComboBox_.setJustificationType(Justification::left); + fftSizeComboBox_.addItem("1024", 1024); + fftSizeComboBox_.addItem("2048", 2048); + fftSizeComboBox_.addItem("4096", 4096); + fftSizeComboBox_.addListener(this); + + addAndMakeVisible(&hopSizeComboBox_); + hopSizeComboBox_.setEditableText(false); + hopSizeComboBox_.setJustificationType(Justification::left); + hopSizeComboBox_.addItem("1/4 Window", ADRessAudioProcessor::kHopSize1_4Window); + hopSizeComboBox_.addItem("1/8 Window", ADRessAudioProcessor::kHopSize1_8Window); + hopSizeComboBox_.addListener(this); + + addAndMakeVisible(&windowTypeComboBox_); + windowTypeComboBox_.setEditableText(false); + windowTypeComboBox_.setJustificationType(Justification::left); + windowTypeComboBox_.addItem("Rectangular", ADRessAudioProcessor::kWindowRectangular); + windowTypeComboBox_.addItem("Bartlett", ADRessAudioProcessor::kWindowBartlett); + windowTypeComboBox_.addItem("Hann", ADRessAudioProcessor::kWindowHann); + windowTypeComboBox_.addItem("Hamming", ADRessAudioProcessor::kWindowHamming); + windowTypeComboBox_.addListener(this); + + + // Set up the sliders + addAndMakeVisible(&widthSlider_); + widthSlider_.setSliderStyle(Slider::Rotary); + widthSlider_.addListener(this); + widthSlider_.setRange(0, betaE_, 1); + + widthLabel_.attachToComponent(&widthSlider_, false); + widthLabel_.setFont(Font (11.0f)); + + + // Set up the sliders + addAndMakeVisible(&azimuthSlider_); + azimuthSlider_.setSliderStyle(Slider::Rotary); + azimuthSlider_.addListener(this); + azimuthSlider_.setRange(0, 2*betaE_, 1); + + + + azimuthLabel_.attachToComponent(&azimuthSlider_, false); + azimuthLabel_.setFont(Font (11.0f)); + + fftSizeLabel_.attachToComponent(&fftSizeComboBox_, false); + fftSizeLabel_.setFont(Font (11.0f)); + + hopSizeLabel_.attachToComponent(&hopSizeComboBox_, false); + hopSizeLabel_.setFont(Font (11.0f)); + + windowTypeLabel_.attachToComponent(&windowTypeComboBox_, false); + windowTypeLabel_.setFont(Font (11.0f)); + + // add the triangular resizer component for the bottom-right of the UI + addAndMakeVisible(resizer_ = new ResizableCornerComponent (this, &resizeLimits_)); + resizeLimits_.setSizeLimits(360, 400, 360, 400); + + // set our component's initial size to be the last one that was stored in the filter's settings + setSize(ownerFilter->lastUIWidth_, + ownerFilter->lastUIHeight_); + + startTimer(50); +} + +ADRessAudioProcessorEditor::~ADRessAudioProcessorEditor() +{ +} + +//============================================================================== +void ADRessAudioProcessorEditor::paint (Graphics& g) +{ + g.fillAll (Colours::grey); +} + +void ADRessAudioProcessorEditor::resized() +{ + fftSizeComboBox_.setBounds(20, 20, 150, 30); + hopSizeComboBox_.setBounds(200, 20, 150, 30); + windowTypeComboBox_.setBounds(20, 75, 150, 30); + widthSlider_.setBounds(200, 70, 150, 40); + + azimuthSlider_.setBounds(20, 150, 150, 40); + resizer_->setBounds(getWidth() - 16, getHeight() - 16, 16, 16); + + getProcessor()->lastUIWidth_ = getWidth(); + getProcessor()->lastUIHeight_ = getHeight(); +} + +//============================================================================== +// This timer periodically checks whether any of the filter's parameters have changed... +void ADRessAudioProcessorEditor::timerCallback() +{ + ADRessAudioProcessor* ourProcessor = getProcessor(); + + fftSizeComboBox_.setSelectedId(ourProcessor->fftSelectedSize_, false); + hopSizeComboBox_.setSelectedId(ourProcessor->hopSelectedSize_, false); + windowTypeComboBox_.setSelectedId(ourProcessor->windowType_, false); + + widthSlider_.setValue(ourProcessor->width_, dontSendNotification); + azimuthSlider_.setValue(ourProcessor->azimuth_, dontSendNotification); +} + +// This is our Slider::Listener callback, when the user drags a slider. +void ADRessAudioProcessorEditor::sliderValueChanged (Slider* slider) +{ + if (slider == &widthSlider_) + { + // It's vital to use setParameterNotifyingHost to change any parameters that are automatable + // by the host, rather than just modifying them directly, otherwise the host won't know + // that they've changed. + getProcessor()->setParameterNotifyingHost (ADRessAudioProcessor::kWidthParam, + (float)widthSlider_.getValue()); + } + + if (slider == &azimuthSlider_) + { + getProcessor()->setParameterNotifyingHost (ADRessAudioProcessor::kAzimuthParam, + (float)azimuthSlider_.getValue()); + } +} + +// Similar callback to sliderValueChanged for ComboBox updates +void ADRessAudioProcessorEditor::comboBoxChanged (ComboBox *comboBox) +{ + if(comboBox == &fftSizeComboBox_) + { + getProcessor()->setParameterNotifyingHost (ADRessAudioProcessor::kFFTSizeParam, + (float)fftSizeComboBox_.getSelectedId()); + } + else if(comboBox == &hopSizeComboBox_) + { + getProcessor()->setParameterNotifyingHost (ADRessAudioProcessor::kHopSizeParam, + (float)hopSizeComboBox_.getSelectedId()); + } + else if(comboBox == &windowTypeComboBox_) + { + getProcessor()->setParameterNotifyingHost (ADRessAudioProcessor::kWindowTypeParam, + (float)windowTypeComboBox_.getSelectedId()); + } +} + +int ADRessAudioProcessorEditor::getBeta() +{ + return betaE_; +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/AddressPlugin/PluginEditor.h Tue Sep 03 12:53:16 2013 +0100 @@ -0,0 +1,61 @@ +/* + ============================================================================== + + This file was auto-generated by the Introjucer! + + It contains the basic startup code for a Juce application. + + ============================================================================== +*/ + +#ifndef __PLUGINEDITOR_H_6E48F605__ +#define __PLUGINEDITOR_H_6E48F605__ + +#include "../JuceLibraryCode/JuceHeader.h" +#include "PluginProcessor.h" + + +//============================================================================== + +class ADRessAudioProcessorEditor : public AudioProcessorEditor, + public SliderListener, + public ComboBox::Listener, + public Timer +{ +public: + ADRessAudioProcessorEditor (ADRessAudioProcessor* ownerFilter); + ~ADRessAudioProcessorEditor(); + + //============================================================================== + // This is just a standard Juce paint method... + void timerCallback(); + void paint (Graphics& g); + void resized(); + void sliderValueChanged (Slider*); + void comboBoxChanged (ComboBox *); + + int getBeta(); + +private: + Label fftSizeLabel_, hopSizeLabel_, windowTypeLabel_; + ComboBox fftSizeComboBox_, hopSizeComboBox_, windowTypeComboBox_; + + Label widthLabel_; + Slider widthSlider_; + + Label azimuthLabel_; + Slider azimuthSlider_; + + + ScopedPointer<ResizableCornerComponent> resizer_; + ComponentBoundsConstrainer resizeLimits_; + int betaE_; + + ADRessAudioProcessor* getProcessor() const + { + return static_cast <ADRessAudioProcessor*> (getAudioProcessor()); + } +}; + + +#endif // __PLUGINEDITOR_H_6E48F605__
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/AddressPlugin/PluginProcessor.cpp Tue Sep 03 12:53:16 2013 +0100 @@ -0,0 +1,834 @@ +/* + ============================================================================== + + This file was auto-generated! + + It contains the basic startup code for a Juce application. + + ============================================================================== +*/ + +#include "PluginProcessor.h" +#include "PluginEditor.h" + + +//============================================================================== + +#define M_PI 3.14159265358979323846 /* pi */ + +ADRessAudioProcessor::ADRessAudioProcessor() : inputBuffer_(2, 1), outputBuffer_(2, 1) +{ + // Set default values: + fftSelectedSize_ = 2048; + hopSelectedSize_ = kHopSize1_8Window; + windowType_ = kWindowHann; + + fftInitialised_ = false; + fftActualTransformSize_ = 0; + inputBufferLength_ = 1; + outputBufferLength_ = 1; + inputBufferWritePosition_ = outputBufferWritePosition_ = outputBufferReadPosition_ = 0; + samplesSinceLastFFT_ = 0; + windowBuffer_ = 0; + windowBufferLength_ = 0; + preparedToPlay_ = false; + fftScaleFactor_ = 0.0; + beta_ = 5; + width_ = 0; + azimuth_ = beta_; + + + indMinL_ = beta_; + indMaxL_ = beta_; + indMinR_ = beta_; + indMaxR_ = beta_; + computeR_ = true; + computeL_ = true; + invGain_ = 2; + invBeta_ = 1/(float)beta_; + i1 = std::complex<double>(0,1); + + + lastUIWidth_ = 360; + lastUIHeight_ = 400; +} + +ADRessAudioProcessor::~ADRessAudioProcessor() +{ + // Release FFT resources if allocated. This should be handled by + // releaseResources() but in the event it doesn't happen, this avoids + // a leak. Harmless to call it twice. + deinitFFT(); + deinitWindow(); +} + +//============================================================================== +const String ADRessAudioProcessor::getName() const +{ + return JucePlugin_Name; +} + +int ADRessAudioProcessor::getNumParameters() +{ + return kNumParameters; +} + +float ADRessAudioProcessor::getParameter (int index) +{ + // This method will be called by the host, probably on the audio thread, so + // it's absolutely time-critical. Don't use critical sections or anything + // UI-related, or anything at all that may block in any way! + switch (index) + { + case kFFTSizeParam: return (float)fftSelectedSize_; + case kHopSizeParam: return (float)hopSelectedSize_; + case kWindowTypeParam: return (float)windowType_; + case kWidthParam: return (float)width_; + case kAzimuthParam: return (float)azimuth_; + + default: return 0.0f; + } +} + +void ADRessAudioProcessor::setParameter (int index, float newValue) +{ + // This method will be called by the host, probably on the audio thread, so + // it's absolutely time-critical. Don't use critical sections or anything + // UI-related, or anything at all that may block in any way! + switch (index) + { + case kFFTSizeParam: + if((int)newValue != fftSelectedSize_) + { + fftSelectedSize_ = (int)newValue; + if(preparedToPlay_) + { + // Update settings if currently playing, else wait until prepareToPlay() called + initFFT(fftSelectedSize_); + initWindow(fftSelectedSize_, windowType_); + } + } + break; + case kHopSizeParam: + hopSelectedSize_ = (int)newValue; + if(preparedToPlay_) + updateHopSize(); + break; + case kWindowTypeParam: + // Recalculate window if needed + if((int)newValue != windowType_) + { + windowType_ = (int)newValue; + if(preparedToPlay_) + initWindow(fftActualTransformSize_, (int)newValue); + } + break; + + case kWidthParam: + width_ = (int)newValue; + changeParams(); + break; + + case kAzimuthParam: + azimuth_ = (int)newValue; + changeParams(); + break; + + default: + break; + } +} + +void ADRessAudioProcessor::changeParams() +{ + int maxA = std::min(azimuth_ + width_,2*beta_); + int minA = std::max(azimuth_ - width_,0); + if (maxA >= beta_) + { + computeR_ = true; + indMinR_ = 2*beta_ - maxA; + if (minA >= beta_) + { + indMaxR_ = 2*beta_ - minA; + } else { + indMaxR_ = beta_; + } + } else { + computeR_ = false; + } + + if (minA <= beta_) + { + computeL_ = true; + indMinL_ = minA; + if (maxA <= beta_) + { + indMaxL_ = maxA; + } else { + indMaxL_ = beta_; + } + } else { + computeL_ = false; + } + + invGain_ = (indMaxR_ - indMinR_ + indMaxL_ - indMinL_); + if (computeR_) + invGain_++; + if (computeL_) + invGain_++; + invGain_ = 1;//invGain_; + +} + + +const String ADRessAudioProcessor::getParameterName (int index) +{ + switch (index) + { + case kFFTSizeParam: return "FFT size"; + case kHopSizeParam: return "hop size"; + case kWindowTypeParam: return "window type"; + case kWidthParam: return "volume"; + case kAzimuthParam: return "azimuth"; + + default: break; + } + + return String::empty; +} + +const String ADRessAudioProcessor::getParameterText (int index) +{ + return String (getParameter (index), 2); +} + +const String ADRessAudioProcessor::getInputChannelName (int channelIndex) const +{ + return String (channelIndex + 1); +} + +const String ADRessAudioProcessor::getOutputChannelName (int channelIndex) const +{ + return String (channelIndex + 1); +} + +bool ADRessAudioProcessor::isInputChannelStereoPair (int index) const +{ + return true; +} + +bool ADRessAudioProcessor::isOutputChannelStereoPair (int index) const +{ + return true; +} + +bool ADRessAudioProcessor::silenceInProducesSilenceOut() const +{ +#if JucePlugin_SilenceInProducesSilenceOut + return true; +#else + return false; +#endif +} + +bool ADRessAudioProcessor::acceptsMidi() const +{ +#if JucePlugin_WantsMidiInput + return true; +#else + return false; +#endif +} + +bool ADRessAudioProcessor::producesMidi() const +{ +#if JucePlugin_ProducesMidiOutput + return true; +#else + return false; +#endif +} + +double ADRessAudioProcessor::getTailLengthSeconds() const +{ + return 0; +} + +int ADRessAudioProcessor::getNumPrograms() +{ + return 0; +} + +int ADRessAudioProcessor::getCurrentProgram() +{ + return 0; +} + +void ADRessAudioProcessor::setCurrentProgram (int index) +{ +} + +const String ADRessAudioProcessor::getProgramName (int index) +{ + return String::empty; +} + +void ADRessAudioProcessor::changeProgramName (int index, const String& newName) +{ +} + +//============================================================================== +void ADRessAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock) +{ + // Use this method as the place to do any pre-playback + // initialisation that you need.. + + initFFT(fftSelectedSize_); + initWindow(fftSelectedSize_, windowType_); + preparedToPlay_ = true; +} + +void ADRessAudioProcessor::releaseResources() +{ + // When playback stops, you can use this as an opportunity to free up any + // spare memory, etc. + + deinitFFT(); + deinitWindow(); + preparedToPlay_ = false; +} + + + + + +void ADRessAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages) +{ + // Helpful information about this block of samples: + const int numInputChannels = getNumInputChannels(); // How many input channels for our effect? + const int numOutputChannels = getNumOutputChannels(); // How many output channels for our effect? + const int numSamples = buffer.getNumSamples(); // How many samples in the buffer for this block? + + int channel, inwritepos, sampsincefft; + int outreadpos, outwritepos; + + // Grab the lock that prevents the FFT settings from changing + fftSpinLock_.enter(); + + // Check that we're initialised and ready to go. If not, set output to 0 + if(!fftInitialised_) + { + for (channel = 0; channel < numOutputChannels; ++channel) + { + buffer.clear (channel, 0, buffer.getNumSamples()); + } + + fftSpinLock_.exit(); + return; + } + + + + // Go through each channel of audio that's passed in. Collect the samples in the input + // buffer. When we've reached the next hop interval, calculate the FFT. + + // channelDataL is an array of length numSamples which contains the audio for one channel + float* channelDataL = buffer.getSampleData(0); + float* channelDataR = buffer.getSampleData(1); + + // inputBufferDataL is the circular buffer for collecting input samples for the FFT + float* inputBufferDataL = inputBuffer_.getSampleData(0); + float* inputBufferDataR = inputBuffer_.getSampleData(1); + + float* outputBufferDataL = outputBuffer_.getSampleData(0); + float* outputBufferDataR = outputBuffer_.getSampleData(1); + + + // State variables need to be temporarily cached for each channel. We don't want the + // operations on one channel to affect the identical behaviour of the next channel + inwritepos = inputBufferWritePosition_; + outwritepos = outputBufferWritePosition_; + outreadpos = outputBufferReadPosition_; + sampsincefft = samplesSinceLastFFT_; + + for (int i = 0; i < numSamples; ++i) + { + const float inL = channelDataL[i]; + const float inR = channelDataR[i]; + + // Store the next buffered sample in the output. Do this first before anything + // changes the output buffer-- we will have at least one FFT size worth of data + // stored and ready to go. Set the result to 0 when finished in preparation for the + // next overlap/add procedure. + + channelDataL[i] = outputBufferDataL[outreadpos]; + channelDataR[i] = outputBufferDataR[outreadpos]; + outputBufferDataL[outreadpos] = 0.0; + outputBufferDataR[outreadpos] = 0.0; + + if(++outreadpos >= outputBufferLength_) + outreadpos = 0; + + // Store the current sample in the input buffer, incrementing the write pointer. Also + // increment how many samples we've stored since the last transform. If it reaches the + // hop size, perform an FFT and any frequency-domain processing. + inputBufferDataL[inwritepos] = inL; + inputBufferDataR[inwritepos] = inR; + if (++inwritepos >= inputBufferLength_) + inwritepos = 0; + if (++sampsincefft >= hopActualSize_) + { + sampsincefft = 0; + + // Find the index of the starting sample in the buffer. When the buffer length + // is equal to the transform size, this will be the current write position but + // this code is more general for larger buffers. + int inputBufferStartPosition = (inwritepos + inputBufferLength_ + - fftActualTransformSize_) % inputBufferLength_; + + // Window the buffer and copy it into the FFT input + int inputBufferIndex = inputBufferStartPosition; + for(int fftBufferIndex = 0; fftBufferIndex < fftActualTransformSize_; fftBufferIndex++) + { + // Set real part to windowed signal; imaginary part to 0. + fftTimeDomain_[fftBufferIndex][1] = 0.0; + if(fftBufferIndex >= windowBufferLength_) // Safety check, in case window isn't ready + fftTimeDomain_[fftBufferIndex][0] = 0.0; + else + fftTimeDomain_[fftBufferIndex][0] = windowBuffer_[fftBufferIndex] + * inputBufferDataL[inputBufferIndex]; + inputBufferIndex++; + if(inputBufferIndex >= inputBufferLength_) + inputBufferIndex = 0; + } + + // Perform the FFT on the windowed data, going into the frequency domain.Result will be in fftFrequencyDomain_ + fftw_execute(fftForwardPlan_); + + // ********** PHASE VOCODER PROCESSING GOES HERE ************** + // This is the place where frequency-domain calculations are made on the transformed signal. + //Put the result back into fftFrequencyDomain_ before transforming back. + + for (int ii = 0; ii < fftActualTransformSize_/2+1; ii++) + { + realL_[ii] = fftFrequencyDomain_[ii][0]; + imagL_[ii] = fftFrequencyDomain_[ii][1]; + } + + inputBufferIndex = inputBufferStartPosition; + for(int fftBufferIndex = 0; fftBufferIndex < fftActualTransformSize_; fftBufferIndex++) + { + if(fftBufferIndex >= windowBufferLength_) // Safety check, in case window isn't ready + fftTimeDomain_[fftBufferIndex][0] = 0.0; + else + fftTimeDomain_[fftBufferIndex][0] = windowBuffer_[fftBufferIndex] + * inputBufferDataR[inputBufferIndex]; + inputBufferIndex++; + if(inputBufferIndex >= inputBufferLength_) + inputBufferIndex = 0; + } + fftw_execute(fftForwardPlan_); + + + for (int ii = 0; ii < fftActualTransformSize_/2+1; ii++) + { + realR_[ii] = fftFrequencyDomain_[ii][0]; + imagR_[ii] = fftFrequencyDomain_[ii][1]; + } + + + + double minV, maxV,newVal; + std::complex<double> fftTemp; + int indMin; + for (int ii = 0; ii <fftActualTransformSize_/2+1; ii++) + { + if (computeR_) + { + //Right plane + minV = realL_[ii]*realL_[ii] + imagL_[ii]*imagL_[ii]; + maxV = minV; + azr_[ii][0] = 0; + indMin = 0; + for (int j = 1; j <= beta_; j++) + { + newVal = (realL_[ii] - j*invBeta_*realR_[ii])*(realL_[ii] - j*invBeta_*realR_[ii]) + (imagL_[ii] - j*invBeta_*imagR_[ii])*(imagL_[ii] - j*invBeta_*imagR_[ii]); + azr_[ii][j] = 0; + + if (newVal>maxV) + { + maxV = newVal; + } + else if (newVal<minV) + { + minV = newVal; + indMin = j; + } + } + azr_[ii][indMin] = sqrt(maxV) - sqrt(minV); + } + + if(computeL_) + { + ////Left plane + minV = realR_[ii]*realR_[ii] + imagR_[ii]*imagR_[ii]; + maxV = minV; + indMin = 0; + azl_[ii][0] = 0; + for (int j = 1; j <= beta_; j++) + { + newVal = (realR_[ii] - j*invBeta_*realL_[ii])*(realR_[ii] - j*invBeta_*realL_[ii]) + (imagR_[ii] - j*invBeta_*imagL_[ii])*(imagR_[ii] - j*invBeta_*imagL_[ii]); + azr_[ii][j] = 0; + if (newVal>maxV) + { + maxV = newVal; + } + else if (newVal<minV) + { + minV = newVal; + indMin = j; + } + } + azl_[ii][indMin] = sqrt(maxV) - sqrt(minV); + } + } + + + for (int ii = 0; ii < fftActualTransformSize_/2+1; ii++) + { + fftTemp = 0; + for ( int j = indMinR_; j <= indMaxR_; j++) + { + fftTemp += azr_[ii][j]*exp(i1*imagR_[ii]); + } + for ( int j = indMinL_; j <= indMaxL_; j++) + { + fftTemp += azl_[ii][j]*exp(i1*imagL_[ii]); + } +// fftTemp *= invGain_; + + fftFrequencyDomain_[ii][0] = real(fftTemp); + fftFrequencyDomain_[ii][1] = imag(fftTemp); + } + + for (int ii = 1; ii < fftActualTransformSize_/2; ii++) + { + fftFrequencyDomain_[fftActualTransformSize_-ii][0] = fftFrequencyDomain_[ii][0]; + fftFrequencyDomain_[fftActualTransformSize_-ii][1] = -fftFrequencyDomain_[ii][1]; + } + fftw_execute(fftBackwardPlan_); + + float audioTemp; + int outputBufferIndex = outwritepos; + for(int fftBufferIndex = 0; fftBufferIndex < fftActualTransformSize_; fftBufferIndex++) + { + audioTemp = (float)fftTimeDomain_[fftBufferIndex][0] * fftScaleFactor_; + outputBufferDataR[outputBufferIndex] += audioTemp; + outputBufferDataL[outputBufferIndex] += audioTemp; + if(++outputBufferIndex >= outputBufferLength_) + outputBufferIndex = 0; + } + + + + // Add the result to the output buffer, starting at the current write position + // (Output buffer will have been zeroed after reading the last time around) + // Output needs to be scaled by the transform size to get back to original amplitude: + // this is a property of how fftw is implemented. Scaling will also need to be adjusted + // based on hop size to get the same output level (smaller hop size produces more overlap + // and hence higher signal level) + + + + + // Advance the write position within the buffer by the hop size + outwritepos = (outwritepos + hopActualSize_) % outputBufferLength_; + } + } + + + // Having made a local copy of the state variables for each channel, now transfer the result + // back to the main state variable so they will be preserved for the next call of processBlock() + inputBufferWritePosition_ = inwritepos; + outputBufferWritePosition_ = outwritepos; + outputBufferReadPosition_ = outreadpos; + samplesSinceLastFFT_ = sampsincefft; + + // In case we have more outputs than inputs, we'll clear any output + // channels that didn't contain input data, (because these aren't + // guaranteed to be empty - they may contain garbage). + for (int i = numInputChannels; i < numOutputChannels; ++i) + { + buffer.clear (i, 0, buffer.getNumSamples()); + } + + fftSpinLock_.exit(); +} + +//============================================================================== +bool ADRessAudioProcessor::hasEditor() const +{ + return true; // (change this to false if you choose to not supply an editor) +} + +AudioProcessorEditor* ADRessAudioProcessor::createEditor() +{ + return new ADRessAudioProcessorEditor (this); +} + +//============================================================================== +void ADRessAudioProcessor::getStateInformation (MemoryBlock& destData) +{ + // You should use this method to store your parameters in the memory block. + // You could do that either as raw data, or use the XML or ValueTree classes + // as intermediaries to make it easy to save and load complex data. + + // Create an outer XML element.. + XmlElement xml("C4DMPLUGINSETTINGS"); + + // add some attributes to it.. + xml.setAttribute("uiWidth", lastUIWidth_); + xml.setAttribute("uiHeight", lastUIHeight_); + xml.setAttribute("fftSize", fftSelectedSize_); + xml.setAttribute("hopSize", hopSelectedSize_); + xml.setAttribute("windowType", windowType_); + xml.setAttribute("volume", width_); + xml.setAttribute("azimuth", azimuth_); + + // then use this helper function to stuff it into the binary blob and return it.. + copyXmlToBinary(xml, destData); +} + +void ADRessAudioProcessor::setStateInformation (const void* data, int sizeInBytes) +{ + // You should use this method to restore your parameters from this memory block, + // whose contents will have been created by the getStateInformation() call. + + // This getXmlFromBinary() helper function retrieves our XML from the binary blob.. + ScopedPointer<XmlElement> xmlState (getXmlFromBinary (data, sizeInBytes)); + + if(xmlState != 0) + { + // make sure that it's actually our type of XML object.. + if(xmlState->hasTagName("C4DMPLUGINSETTINGS")) + { + // ok, now pull out our parameters.. + lastUIWidth_ = xmlState->getIntAttribute("uiWidth", lastUIWidth_); + lastUIHeight_ = xmlState->getIntAttribute("uiHeight", lastUIHeight_); + + fftSelectedSize_ = (int)xmlState->getDoubleAttribute("fftSize", fftSelectedSize_); + hopSelectedSize_ = (int)xmlState->getDoubleAttribute("hopSize", hopSelectedSize_); + windowType_ = (int)xmlState->getDoubleAttribute("windowType", windowType_); + width_ = (int)xmlState->getDoubleAttribute("volume", width_); + azimuth_ = (int)xmlState->getDoubleAttribute("azimuth", azimuth_); + + + if(preparedToPlay_) + { + // Update settings if currently playing, else wait until prepareToPlay() called + initFFT(fftSelectedSize_); + initWindow(fftSelectedSize_, windowType_); + } + } + } +} + +//============================================================================== +// Initialise the FFT data structures for a given length transform +void ADRessAudioProcessor::initFFT(int length) +{ + if(fftInitialised_) + deinitFFT(); + + // Save the current length so we know how big our results are later + fftActualTransformSize_ = length; + + // Here we allocate the complex-number buffers for the FFT. This uses + // a convenient wrapper on the more general fftw_malloc() + fftTimeDomain_ = fftw_alloc_complex(length); + fftFrequencyDomain_ = fftw_alloc_complex(length); + + // FFTW_ESTIMATE doesn't necessarily produce the fastest executing code (FFTW_MEASURE + // will get closer) but it carries a minimum startup cost. FFTW_MEASURE might stall for + // several seconds which would be annoying in an audio plug-in context. + fftForwardPlan_ = fftw_plan_dft_1d(fftActualTransformSize_, fftTimeDomain_, + fftFrequencyDomain_, FFTW_FORWARD, FFTW_ESTIMATE); + fftBackwardPlan_ = fftw_plan_dft_1d(fftActualTransformSize_, fftFrequencyDomain_, + fftTimeDomain_, FFTW_BACKWARD, FFTW_ESTIMATE); + + // Allocate the buffer that the samples will be collected in + inputBufferLength_ = fftActualTransformSize_; + inputBuffer_.setSize(2, inputBufferLength_); + inputBuffer_.clear(); + inputBufferWritePosition_ = 0; + samplesSinceLastFFT_ = 0; + + // Allocate the output buffer to be twice the size of the FFT + // This will be enough for all hop size cases + outputBufferLength_ = 2*fftActualTransformSize_; + outputBuffer_.setSize(2, outputBufferLength_); + outputBuffer_.clear(); + outputBufferReadPosition_ = 0; + + updateHopSize(); + + fftInitialised_ = true; +} + +// Free the FFT data structures +void ADRessAudioProcessor::deinitFFT() +{ + if(!fftInitialised_) + return; + + // Prevent this variable from changing while an audio callback is running. + // Once it has changed, the next audio callback will find that it's not + // initialised and will return silence instead of attempting to work with the + // (invalid) FFT structures. This produces an audible glitch but no crash, + // and is the simplest way to handle parameter changes in this example code. + fftSpinLock_.enter(); + fftInitialised_ = false; + fftSpinLock_.exit(); + + fftw_destroy_plan(fftForwardPlan_); + fftw_destroy_plan(fftBackwardPlan_); + fftw_free(fftTimeDomain_); + fftw_free(fftFrequencyDomain_); + + // Leave the input buffer in memory until the plugin is released +} + +//============================================================================== +// Create a new window of a given length and type +void ADRessAudioProcessor::initWindow(int length, int windowType) +{ + if(windowBuffer_ != 0) + deinitWindow(); + if(length == 0) // Sanity check + return; + + // Allocate memory for the window + windowBuffer_ = (double *)malloc(length * sizeof(double)); + + // Write the length as a double here to simplify the code below (otherwise + // typecasts would be wise) + double windowLength = length; + + // Set values for the window, depending on its type + for(int i = 0; i < length; i++) + { + // Window functions are typically defined to be symmetrical. This will cause a + // problem in the overlap-add process: the windows instead need to be periodic + // when arranged end-to-end. As a result we calculate the window of one sample + // larger than usual, and drop the last sample. (This works as long as N is even.) + // See Julius Smith, "Spectral Audio Signal Processing" for details. + switch(windowType) + { + case kWindowBartlett: + windowBuffer_[i] = (2.0/(windowLength + 2.0))* + (0.5*(windowLength + 2.0) - abs((double)i - 0.5*windowLength)); + break; + case kWindowHann: + windowBuffer_[i] = 0.5*(1.0 - cos(2.0*M_PI*(double)i/windowLength)); + break; + case kWindowHamming: + windowBuffer_[i] = 0.54 - 0.46*cos(2.0*M_PI*(double)i/windowLength); + break; + case kWindowRectangular: + default: + windowBuffer_[i] = 1.0; + break; + } + } + + windowBufferLength_ = length; + updateScaleFactor(); +} + +// Free the window buffer +void ADRessAudioProcessor::deinitWindow() +{ + if(windowBuffer_ == 0) + return; + + // Delay clearing the window until the audio thread is not running + // to avoid a crash if the code tries to access an invalid window + fftSpinLock_.enter(); + windowBufferLength_ = 0; + fftSpinLock_.exit(); + + free(windowBuffer_); + windowBuffer_ = 0; +} + +// Update the actual hop size depending on the window size and hop size settings +// Hop size is expressed as a fraction of a window in the parameters. +void ADRessAudioProcessor::updateHopSize() +{ + switch(hopSelectedSize_) + { + case kHopSize1Window: + hopActualSize_ = fftActualTransformSize_; + break; + case kHopSize1_2Window: + hopActualSize_ = fftActualTransformSize_ / 2; + break; + case kHopSize1_4Window: + hopActualSize_ = fftActualTransformSize_ / 4; + break; + case kHopSize1_8Window: + hopActualSize_ = fftActualTransformSize_ / 8; + break; + } + + // Update the factor by which samples are scaled to preserve unity gain + updateScaleFactor(); + + // Read pointer lags the write pointer to allow for FFT buffers to accumulate and + // be processed. Total latency is sum of the FFT size and the hop size. + outputBufferWritePosition_ = hopActualSize_ + fftActualTransformSize_; +} + +// Update the factor by which each output sample is scaled. This needs to update +// every time FFT size, hop size, and window type are changed. +void ADRessAudioProcessor::updateScaleFactor() +{ + // The gain needs to be normalised by the sum of the window, which implicitly + // accounts for the length of the transform and the window type. From there + // we also update based on hop size: smaller hop means more overlap means the + // overall gain should be reduced. + double windowSum = 0.0; + + for(int i = 0; i < windowBufferLength_; i++) + { + windowSum += windowBuffer_[i]; + } + + if(windowSum == 0.0) + fftScaleFactor_ = 0.0; // Catch invalid cases and mute output + else + { + switch(hopSelectedSize_) + { + case kHopSize1Window: // 0dB + fftScaleFactor_ = 1.0/(double)windowSum; + break; + case kHopSize1_2Window: // -6dB + fftScaleFactor_ = 0.5/(double)windowSum; + break; + case kHopSize1_4Window: // -12dB + fftScaleFactor_ = 0.25/(double)windowSum; + break; + case kHopSize1_8Window: // -18dB + fftScaleFactor_ = 0.125/(double)windowSum; + break; + } + } +} + +//============================================================================== +// This creates new instances of the plugin.. +AudioProcessor* JUCE_CALLTYPE createPluginFilter() +{ + return new ADRessAudioProcessor(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/AddressPlugin/PluginProcessor.h Tue Sep 03 12:53:16 2013 +0100 @@ -0,0 +1,187 @@ +/* + ============================================================================== + + This file was auto-generated! + + It contains the basic startup code for a Juce application. + + ============================================================================== +*/ + +#ifndef __PLUGINPROCESSOR_H_4693CB6E__ +#define __PLUGINPROCESSOR_H_4693CB6E__ + +#include "../JuceLibraryCode/JuceHeader.h" +#include <fftw3.h> +#include <complex> +//============================================================================== +/** +*/ +class ADRessAudioProcessor : public AudioProcessor +{ +public: + //============================================================================== + ADRessAudioProcessor(); + ~ADRessAudioProcessor(); + + //============================================================================== + void prepareToPlay (double sampleRate, int samplesPerBlock); + void releaseResources(); + + + void processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages); + + //============================================================================== + AudioProcessorEditor* createEditor(); + bool hasEditor() const; + + //============================================================================== + const String getName() const; + + int getNumParameters(); + + float getParameter (int index); + void setParameter (int index, float newValue); + + const String getParameterName (int index); + const String getParameterText (int index); + + const String getInputChannelName (int channelIndex) const; + const String getOutputChannelName (int channelIndex) const; + bool isInputChannelStereoPair (int index) const; + bool isOutputChannelStereoPair (int index) const; + + bool silenceInProducesSilenceOut() const; + bool acceptsMidi() const; + bool producesMidi() const; + + double getTailLengthSeconds() const; + + //============================================================================== + int getNumPrograms(); + int getCurrentProgram(); + void setCurrentProgram (int index); + const String getProgramName (int index); + void changeProgramName (int index, const String& newName); + + //============================================================================== + void getStateInformation (MemoryBlock& destData); + void setStateInformation (const void* data, int sizeInBytes); + + //============================================================================== + + // these are used to persist the UI's size - the values are stored along with the + // filter's other parameters, and the UI component will update them when it gets + // resized. + int lastUIWidth_, lastUIHeight_; + + enum Parameters + { + kFFTSizeParam = 0, + kHopSizeParam, + kWindowTypeParam, + kWidthParam, + kAzimuthParam, + kNumParameters + }; + + enum Window + { + kWindowRectangular = 1, + kWindowBartlett, + kWindowHann, + kWindowHamming + }; + + enum HopSize + { + kHopSize1Window = 1, + kHopSize1_2Window, + kHopSize1_4Window, + kHopSize1_8Window + }; + + // This parameter indicates the FFT size for phase vocoder computation. It is selected + // by the GUI and may temporarily differ from the actual size used in calculations. + int fftSelectedSize_; + int hopSelectedSize_; // Hop size, chosen from one of the options above + int windowType_; // Type of window used + + int /*indL_, indR_,*/ width_, azimuth_, beta_; + int indMinL_,indMinR_,indMaxL_,indMaxR_; + float invGain_; + + bool computeR_, computeL_; + float invBeta_; + std::complex<double> i1; + +private: + + double azr_[2049][11]; + double azl_[2049][11]; + double realR_[2049]; + double imagR_[2049]; + double realL_[2049]; + double imagL_[2049]; + + // Methods to initialise and de-initialise the FFT machinery + void initFFT(int length); + void deinitFFT(); + + // Methods to initialise and de-initialise the window + void initWindow(int length, int windowType); + void deinitWindow(); + + // Methods to update the buffering for the given hop size and the output scaling + void updateHopSize(); + void updateScaleFactor(); + + // Whether the FFT has been initialised and is therefore ready to go + bool fftInitialised_; + + // Variables for calculating the FFT and IFFT: complex data structures and the + // "plan" used by the fftw library to calculate the transforms. + fftw_complex *fftTimeDomain_, *fftFrequencyDomain_; + fftw_plan fftForwardPlan_, fftBackwardPlan_; + + // Size of the FFT (generally a power of two) and the hop size (in samples, generally a fraction of FFT size) + int fftActualTransformSize_; + int hopActualSize_; + + // Amount by which to scale_ the inverse FFT to return to original amplitude: depends on the + // transform size (because of fftw implementation) and the hop size (because of inherent overlap) + double fftScaleFactor_; + + // Circular buffer gathers audio samples from the input until enough are available + // for the FFT calculation + AudioSampleBuffer inputBuffer_; + int inputBufferLength_; + int inputBufferWritePosition_; + + // Circular buffer that collects output samples from the FFT overlap-add process + // before they are ready to be sent to the output stream + AudioSampleBuffer outputBuffer_; + int outputBufferLength_; + int outputBufferReadPosition_, outputBufferWritePosition_; + + // How many samples since the last FFT? + int samplesSinceLastFFT_; + + // Stored window function for pre-processing input frames + double *windowBuffer_; + int windowBufferLength_; + + // Whether or not prepareToPlay() has been called, i.e. that resources are in use + bool preparedToPlay_; + + // Spin lock that prevents the FFT settings from changing in the middle of the audio + // thread. + SpinLock fftSpinLock_; + + void changeParams(); + + //============================================================================== + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ADRessAudioProcessor); +}; + +#endif // __PLUGINPROCESSOR_H_4693CB6E__
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/BassPedalRackPlugin/BassPedalRack.jucer Tue Sep 03 12:53:16 2013 +0100 @@ -0,0 +1,49 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<JUCERPROJECT id="AC7ScK" name="BassPedalRack" projectType="audioplug" version="2.0.0" + bundleIdentifier="BPREffect" buildVST="1" buildRTAS="0" buildAU="0" + pluginName="BPR" pluginDesc="Selective Chebychev Distortion and Tone Control" + pluginManufacturer="JYs&M" pluginManufacturerCode="JYsM" + pluginCode="bpr" pluginChannelConfigs="{1, 1}, {2, 2}" pluginIsSynth="0" + pluginWantsMidiIn="0" pluginProducesMidiOut="0" pluginSilenceInIsSilenceOut="1" + pluginTailLength="0" pluginEditorRequiresKeys="0" pluginAUExportPrefix="bprAU" + pluginAUViewClass="emptyAU_V1" pluginRTASCategory="" jucerVersion="3.0.0" + companyName="JYs&M" aaxIdentifier="com.yourcompany.empty" + pluginAAXCategory="AAX_ePlugInCategory_Dynamics"> + <EXPORTFORMATS> + <VS2010 targetFolder="Builds/VisualStudio2010" libraryType="1" juceFolder="C:\Users\Spook's\Desktop\QMUL\DAFX\Assignments\AS3\juce-latest\juce\modules" + vstFolder="C:\Users\Spook's\Desktop\QMUL\DAFX\Assignments\AS3\vstsdk2.4"> + <CONFIGURATIONS> + <CONFIGURATION name="Debug" winWarningLevel="4" generateManifest="1" winArchitecture="32-bit" + isDebug="1" optimisation="1" targetName="bpr"/> + <CONFIGURATION name="Release" winWarningLevel="4" generateManifest="1" winArchitecture="32-bit" + isDebug="0" optimisation="2" targetName="bpr"/> + </CONFIGURATIONS> + </VS2010> + </EXPORTFORMATS> + <MAINGROUP id="oVUVUz" name="BassPedalRack"> + <GROUP id="{F4483B04-0E7A-D77C-795E-A491F61E239B}" name="Source"> + <FILE id="d7EIMU" name="PluginProcessor.cpp" compile="1" resource="0" + file="Source/PluginProcessor.cpp"/> + <FILE id="YDAD0P" name="PluginProcessor.h" compile="0" resource="0" + file="Source/PluginProcessor.h"/> + <FILE id="VTO1E6" name="PluginEditor.cpp" compile="1" resource="0" + file="Source/PluginEditor.cpp"/> + <FILE id="mhOgcd" name="PluginEditor.h" compile="0" resource="0" file="Source/PluginEditor.h"/> + </GROUP> + </MAINGROUP> + <MODULES> + <MODULE id="juce_core" showAllCode="1" useLocalCopy="0"/> + <MODULE id="juce_events" showAllCode="1" useLocalCopy="0"/> + <MODULE id="juce_graphics" showAllCode="1" useLocalCopy="0"/> + <MODULE id="juce_gui_basics" showAllCode="1" useLocalCopy="0"/> + <MODULE id="juce_gui_extra" showAllCode="1" useLocalCopy="0"/> + <MODULE id="juce_gui_audio" showAllCode="1" useLocalCopy="1"/> + <MODULE id="juce_audio_basics" showAllCode="1" useLocalCopy="0"/> + <MODULE id="juce_audio_formats" showAllCode="1" useLocalCopy="0"/> + <MODULE id="juce_audio_processors" showAllCode="1" useLocalCopy="0"/> + <MODULE id="juce_audio_plugin_client" showAllCode="1" useLocalCopy="0"/> + <MODULE id="juce_data_structures" showAllCode="1" useLocalCopy="0"/> + </MODULES> + <JUCEOPTIONS JUCE_QUICKTIME="disabled"/> +</JUCERPROJECT>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/BassPedalRackPlugin/ParametersRecap.txt Tue Sep 03 12:53:16 2013 +0100 @@ -0,0 +1,37 @@ +Parameters recap: + +-lowCut: cutoff frequency of the low pass filter. + 0 to 10. + 0 is no filter. + 10 is no output. + 1 to 9 increases the cutoff frequency. + +-highCut: cutoff frequency of the high pass filter. + 0 to 10. + 0 is no filter. + 10 is no output. + 1 to 9 increases the cutoff frequency. + +-index: distortion index + 0 to 5. + 0 no signal + 1 basic distortion + preprocess x =x*index before distortion + +-gain1-9: gain of the Nth Chebychev polynomial + 0 to 5 + 0 no gain at the polynomial + correspond to the gain of the Nth harmonic + +-mix: mixing value between filtered low frequencies and distorted filterd high frequencies + 0 to 1 + 0 is only output from low pass filter + 0.5 is balance between both + 1 is only output from distorted high pass filter + +-treble, gain of the three tone control knobs + mid, 0 to 1 + low 0 is minimum + 0.5 is neutral (although still does not have a falt frequency response) + 1 is maximum +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/BassPedalRackPlugin/PluginEditor.cpp Tue Sep 03 12:53:16 2013 +0100 @@ -0,0 +1,224 @@ +/* + ============================================================================== + + This file was auto-generated by the Introjucer! + + It contains the basic startup code for a Juce application. + + ============================================================================== +*/ + +#include "PluginProcessor.h" +#include "PluginEditor.h" + + +//============================================================================== +BassPedalRackProcessorEditor::BassPedalRackProcessorEditor (BassPedalRackProcessor* ownerFilter) + : AudioProcessorEditor (ownerFilter), + + + lowCutLabel_("","LowCut:"), + lowCutSlider_("lowcut"), + highCutLabel_("","HighCut:"), + highCutSlider_("highcut"), + + indexLabel_("", "Index:"), + indexSlider_("index"), + gain1Label_("", "Gain1:"), + gain1Slider_("gain1"), + gain2Label_("", "Gain2:"), + gain2Slider_("gain2"), + gain3Label_("", "Gain3:"), + gain3Slider_("gain3"), + gain4Label_("", "Gain4:"), + gain4Slider_("gain4"), + gain5Label_("", "Gain5:"), + gain5Slider_("gain5"), + gain6Label_("", "Gain6:"), + gain6Slider_("gain6"), + gain7Label_("", "Gain7:"), + gain7Slider_("gain7"), + gain8Label_("", "Gain8:"), + gain8Slider_("gain8"), + gain9Label_("", "Gain9:"), + gain9Slider_("gain9"), + + mixLabel_("", "Mix:"), + mixSlider_("mix"), + + gainTreLabel_("", "Treble:"), + gainTreSlider_("treble"), + gainLowLabel_("", "Low:"), + gainLowSlider_("low"), + gainMidLabel_("", "Mid:"), + gainMidSlider_("mid"), + + gainLabel_("", "Gain:"), + gainSlider_("gain") +{ + // This is where our plugin's editor size is set. + // setSize(170, 80); + + // Set up the sliders + addAndMakeVisible(&lowCutSlider_); lowCutSlider_.setSliderStyle(Slider::Rotary); lowCutSlider_.addListener(this); + lowCutSlider_.setRange(0, 10, 1); lowCutLabel_.attachToComponent(&lowCutSlider_, false); lowCutLabel_.setFont(Font (11.0f)); + + addAndMakeVisible(&highCutSlider_); highCutSlider_.setSliderStyle(Slider::Rotary); highCutSlider_.addListener(this); + highCutSlider_.setRange(0, 10, 1); highCutLabel_.attachToComponent(&highCutSlider_, false); highCutLabel_.setFont(Font (11.0f)); + + addAndMakeVisible(&indexSlider_); indexSlider_.setSliderStyle(Slider::Rotary); indexSlider_.addListener(this); + indexSlider_.setRange(0.0, 5.0, 0.01); indexLabel_.attachToComponent(&indexSlider_, false); indexLabel_.setFont(Font (11.0f)); + + addAndMakeVisible(&gain1Slider_); gain1Slider_.setSliderStyle(Slider::Rotary); gain1Slider_.addListener(this); + gain1Slider_.setRange(0.0, 5.0, 0.01); gain1Label_.attachToComponent(&gain1Slider_, false); gain1Label_.setFont(Font (11.0f)); + addAndMakeVisible(&gain2Slider_); gain2Slider_.setSliderStyle(Slider::Rotary); gain2Slider_.addListener(this); + gain2Slider_.setRange(0.0, 5.0, 0.01); gain2Label_.attachToComponent(&gain2Slider_, false); gain2Label_.setFont(Font (11.0f)); + addAndMakeVisible(&gain3Slider_); gain3Slider_.setSliderStyle(Slider::Rotary); gain3Slider_.addListener(this); + gain3Slider_.setRange(0.0, 5.0, 0.01); gain3Label_.attachToComponent(&gain3Slider_, false); gain3Label_.setFont(Font (11.0f)); + addAndMakeVisible(&gain4Slider_); gain4Slider_.setSliderStyle(Slider::Rotary); gain4Slider_.addListener(this); + gain4Slider_.setRange(0.0, 5.0, 0.01); gain4Label_.attachToComponent(&gain4Slider_, false); gain4Label_.setFont(Font (11.0f)); + addAndMakeVisible(&gain5Slider_); gain5Slider_.setSliderStyle(Slider::Rotary); gain5Slider_.addListener(this); + gain5Slider_.setRange(0.0, 5.0, 0.01); gain5Label_.attachToComponent(&gain5Slider_, false); gain5Label_.setFont(Font (11.0f)); + addAndMakeVisible(&gain6Slider_); gain6Slider_.setSliderStyle(Slider::Rotary); gain6Slider_.addListener(this); + gain6Slider_.setRange(0.0, 5.0, 0.01); gain6Label_.attachToComponent(&gain6Slider_, false); gain6Label_.setFont(Font (11.0f)); + addAndMakeVisible(&gain7Slider_); gain7Slider_.setSliderStyle(Slider::Rotary); gain7Slider_.addListener(this); + gain7Slider_.setRange(0.0, 5.0, 0.01); gain7Label_.attachToComponent(&gain7Slider_, false); gain7Label_.setFont(Font (11.0f)); + addAndMakeVisible(&gain8Slider_); gain8Slider_.setSliderStyle(Slider::Rotary); gain8Slider_.addListener(this); + gain8Slider_.setRange(0.0, 5.0, 0.01); gain8Label_.attachToComponent(&gain8Slider_, false); gain8Label_.setFont(Font (11.0f)); + addAndMakeVisible(&gain9Slider_); gain9Slider_.setSliderStyle(Slider::Rotary); gain9Slider_.addListener(this); + gain9Slider_.setRange(0.0, 5.0, 0.01); gain9Label_.attachToComponent(&gain9Slider_, false); gain9Label_.setFont(Font (11.0f)); + + + addAndMakeVisible(&mixSlider_); mixSlider_.setSliderStyle(Slider::Rotary); mixSlider_.addListener(this); + mixSlider_.setRange(0.0, 1.0, 0.001); mixLabel_.attachToComponent(&mixSlider_, false); mixLabel_.setFont(Font (11.0f)); + + addAndMakeVisible(&gainTreSlider_); gainTreSlider_.setSliderStyle(Slider::Rotary); gainTreSlider_.addListener(this); + gainTreSlider_.setRange(0.0, 1.0, 0.001); gainTreLabel_.attachToComponent(&gainTreSlider_, false); gainTreLabel_.setFont(Font (11.0f)); + addAndMakeVisible(&gainMidSlider_); gainMidSlider_.setSliderStyle(Slider::Rotary); gainMidSlider_.addListener(this); + gainMidSlider_.setRange(0.0, 1.0, 0.001); gainMidLabel_.attachToComponent(&gainMidSlider_, false); gainMidLabel_.setFont(Font (11.0f)); + addAndMakeVisible(&gainLowSlider_); gainLowSlider_.setSliderStyle(Slider::Rotary); gainLowSlider_.addListener(this); + gainLowSlider_.setRange(0.0, 1.0, 0.001); gainLowLabel_.attachToComponent(&gainLowSlider_, false); gainLowLabel_.setFont(Font (11.0f)); + + addAndMakeVisible(&gainSlider_); gainSlider_.setSliderStyle(Slider::Rotary); gainSlider_.addListener(this); + gainSlider_.setRange(0.0, 10.0, 0.001); gainLabel_.attachToComponent(&gainSlider_, false); gainLabel_.setFont(Font (11.0f)); + + // add the triangular resizer component for the bottom-right of the UI + addAndMakeVisible(resizer_ = new ResizableCornerComponent (this, &resizeLimits_)); + resizeLimits_.setSizeLimits(300, 200, 800, 600); + + // set our component's initial size to be the last one that was stored in the filter's settings + setSize(ownerFilter->lastUIWidth_, + ownerFilter->lastUIHeight_); + + startTimer(50); +} + +BassPedalRackProcessorEditor::~BassPedalRackProcessorEditor() +{ +} + +//============================================================================== +void BassPedalRackProcessorEditor::paint (Graphics& g) +{ + g.fillAll (Colours::grey); +} + +void BassPedalRackProcessorEditor::resized() +{ + + lowCutSlider_.setBounds(20, 20, 150, 40); + highCutSlider_.setBounds(200, 20, 150, 40); + mixSlider_.setBounds(380, 20, 150, 40); + + indexSlider_.setBounds(200, 75, 150, 40); + gain1Slider_.setBounds(380, 75, 150, 40); + gain2Slider_.setBounds(200, 130, 150, 40); + gain3Slider_.setBounds(380, 130, 150, 40); + gain4Slider_.setBounds(200, 185, 150, 40); + gain5Slider_.setBounds(380, 185, 150, 40); + gain6Slider_.setBounds(200, 240, 150, 40); + gain7Slider_.setBounds(380, 240, 150, 40); + gain8Slider_.setBounds(200, 295, 150, 40); + gain9Slider_.setBounds(380, 295, 150, 40); + + + + + gainTreSlider_.setBounds(20,185,150, 40); + gainMidSlider_.setBounds(20,240,150, 40); + gainLowSlider_.setBounds(20,295,150, 40); + + gainSlider_.setBounds(20, 75, 150, 40); + + resizer_->setBounds(getWidth() - 16, getHeight() - 16, 16, 16); + + getProcessor()->lastUIWidth_ = getWidth(); + getProcessor()->lastUIHeight_ = getHeight(); +} + +//============================================================================== +// This timer periodically checks whether any of the filter's parameters have changed... +void BassPedalRackProcessorEditor::timerCallback() +{ + BassPedalRackProcessor* ourProcessor = getProcessor(); + + mixSlider_.setValue(ourProcessor->mix_, dontSendNotification); + indexSlider_.setValue(ourProcessor->index_, dontSendNotification); + gainSlider_.setValue(ourProcessor->gain_, dontSendNotification); + lowCutSlider_.setValue(ourProcessor->lowCut_, dontSendNotification); + highCutSlider_.setValue(ourProcessor->highCut_, dontSendNotification); + gainLowSlider_.setValue(ourProcessor->bassGain_, dontSendNotification); + gainMidSlider_.setValue(ourProcessor->midGain_, dontSendNotification); + gainTreSlider_.setValue(ourProcessor->trebleGain_, dontSendNotification); + gain1Slider_.setValue(ourProcessor->gain1_, dontSendNotification); + gain2Slider_.setValue(ourProcessor->gain2_, dontSendNotification); + gain3Slider_.setValue(ourProcessor->gain3_, dontSendNotification); + gain4Slider_.setValue(ourProcessor->gain4_, dontSendNotification); + gain5Slider_.setValue(ourProcessor->gain5_, dontSendNotification); + gain6Slider_.setValue(ourProcessor->gain6_, dontSendNotification); + gain7Slider_.setValue(ourProcessor->gain7_, dontSendNotification); + gain8Slider_.setValue(ourProcessor->gain8_, dontSendNotification); + gain9Slider_.setValue(ourProcessor->gain9_, dontSendNotification); +} + +// This is our Slider::Listener callback, when the user drags a slider. +void BassPedalRackProcessorEditor::sliderValueChanged (Slider* slider) +{ + if (slider == &mixSlider_){ + // It's vital to use setParameterNotifyingHost to change any parameters that are automatable + // by the host, rather than just modifying them directly, otherwise the host won't know + // that they've changed. + getProcessor()->setParameterNotifyingHost (BassPedalRackProcessor::kMixParam,(float)mixSlider_.getValue());} + if (slider == &lowCutSlider_){ + getProcessor()->setParameterNotifyingHost (BassPedalRackProcessor::kLowCutParam,(float)lowCutSlider_.getValue());} + if (slider == &highCutSlider_){ + getProcessor()->setParameterNotifyingHost (BassPedalRackProcessor::kHighCutParam,(float)highCutSlider_.getValue());} + if (slider == &indexSlider_){ + getProcessor()->setParameterNotifyingHost (BassPedalRackProcessor::kIndexParam,(float)indexSlider_.getValue());} + if (slider == &gainSlider_){ + getProcessor()->setParameterNotifyingHost (BassPedalRackProcessor::kGainParam,(float)gainSlider_.getValue());} + if (slider == &gainMidSlider_){ + getProcessor()->setParameterNotifyingHost (BassPedalRackProcessor::kGainMidParam,(float)gainMidSlider_.getValue());} + if (slider == &gainLowSlider_){ + getProcessor()->setParameterNotifyingHost (BassPedalRackProcessor::kGainLowParam,(float)gainLowSlider_.getValue());} + if (slider == &gainTreSlider_){ + getProcessor()->setParameterNotifyingHost (BassPedalRackProcessor::kGainTreParam,(float)gainTreSlider_.getValue());} + if (slider == &gain1Slider_){ + getProcessor()->setParameterNotifyingHost (BassPedalRackProcessor::kGain1Param,(float)gain1Slider_.getValue());} + if (slider == &gain2Slider_){ + getProcessor()->setParameterNotifyingHost (BassPedalRackProcessor::kGain2Param,(float)gain2Slider_.getValue());} + if (slider == &gain3Slider_){ + getProcessor()->setParameterNotifyingHost (BassPedalRackProcessor::kGain3Param,(float)gain3Slider_.getValue());} + if (slider == &gain4Slider_){ + getProcessor()->setParameterNotifyingHost (BassPedalRackProcessor::kGain4Param,(float)gain4Slider_.getValue());} + if (slider == &gain5Slider_){ + getProcessor()->setParameterNotifyingHost (BassPedalRackProcessor::kGain5Param,(float)gain5Slider_.getValue());} + if (slider == &gain6Slider_){ + getProcessor()->setParameterNotifyingHost (BassPedalRackProcessor::kGain6Param,(float)gain6Slider_.getValue());} + if (slider == &gain7Slider_){ + getProcessor()->setParameterNotifyingHost (BassPedalRackProcessor::kGain7Param,(float)gain7Slider_.getValue());} + if (slider == &gain8Slider_){ + getProcessor()->setParameterNotifyingHost (BassPedalRackProcessor::kGain8Param,(float)gain8Slider_.getValue());} + if (slider == &gain9Slider_){ + getProcessor()->setParameterNotifyingHost (BassPedalRackProcessor::kGain9Param,(float)gain9Slider_.getValue());} +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/BassPedalRackPlugin/PluginEditor.h Tue Sep 03 12:53:16 2013 +0100 @@ -0,0 +1,85 @@ +/* + ============================================================================== + + This file was auto-generated by the Introjucer! + + It contains the basic startup code for a Juce application. + + ============================================================================== +*/ + +#ifndef __PLUGINEDITOR_H_6E48F605__ +#define __PLUGINEDITOR_H_6E48F605__ + +#include "../JuceLibraryCode/JuceHeader.h" +#include "PluginProcessor.h" + + +//============================================================================== + +class BassPedalRackProcessorEditor : public AudioProcessorEditor, + public SliderListener, + public Timer +{ +public: + BassPedalRackProcessorEditor (BassPedalRackProcessor* ownerFilter); + ~BassPedalRackProcessorEditor(); + + //============================================================================== + // This is just a standard Juce paint method... + void timerCallback(); + void paint (Graphics& g); + void resized(); + void sliderValueChanged (Slider*); + +private: + Label mixLabel_; + Slider mixSlider_; + + Label lowCutLabel_; + Slider lowCutSlider_; + + Label gainTreLabel_; + Slider gainTreSlider_; + Label gainLowLabel_; + Slider gainLowSlider_; + Label gainMidLabel_; + Slider gainMidSlider_; + + Label highCutLabel_; + Slider highCutSlider_; + + Label gainLabel_; + Slider gainSlider_; + + Label indexLabel_; + Slider indexSlider_; + Label gain1Label_; + Slider gain1Slider_; + Label gain2Label_; + Slider gain2Slider_; + Label gain3Label_; + Slider gain3Slider_; + Label gain4Label_; + Slider gain4Slider_; + Label gain5Label_; + Slider gain5Slider_; + Label gain6Label_; + Slider gain6Slider_; + Label gain7Label_; + Slider gain7Slider_; + Label gain8Label_; + Slider gain8Slider_; + Label gain9Label_; + Slider gain9Slider_; + + ScopedPointer<ResizableCornerComponent> resizer_; + ComponentBoundsConstrainer resizeLimits_; + BassPedalRackProcessor* getProcessor() const + { + return static_cast <BassPedalRackProcessor*> (getAudioProcessor()); + } +}; + + +#endif // __PLUGINEDITOR_H_6E48F605__
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/BassPedalRackPlugin/PluginProcessor.cpp Tue Sep 03 12:53:16 2013 +0100 @@ -0,0 +1,841 @@ +/* + ============================================================================== + + This file was auto-generated! + + It contains the basic startup code for a Juce application. + + ============================================================================== +*/ + +#include "PluginProcessor.h" +#include "PluginEditor.h" +#include "filter.h" + + +//============================================================================== +BassPedalRackProcessor::BassPedalRackProcessor() +{ + // Set default values: + + gain_ = 1.0; //Orignal volume set to one + index_ = 1.0; //Index is one by default + mix_ = 0.5; //as much low than high + gain1_ = 1.0; //fundamental =1 + gain2_ = 0.0; //no other distortion + gain3_ = 0.0; + gain4_ = 0.0; + gain5_ = 0.0; + gain6_ = 0.0; + gain7_ = 0.0; + gain8_ = 0.0; + gain9_ = 0.0; + + //neutral tone stack (even is it is not strictly an allpass filter) + trebleGain_ = 0.5; + bassGain_ = 0.5; + midGain_ = 0.5; + //filterLength + filterLength_ = 151; + + toneStack_ = true; + shaper_ = false; + + //circular buffers initialisation + currInd_ =0; + for (int i = 0; i < 3; i++) + { + memIn_[i] = 0; + memOut_[i] = 0; + } + + for (int i = 0; i < 6; i++) + { + tonStackIn_[i] = 0; + tonStackIn_[i] = 0; + } + + + for (int i = 0; i < 2*filterLength_; i++) + inputMem_[i] = 0; + + + //Distortion coefficients initialisation + RC_ = 6.25*pow((double)10,-6); + RC2_ = RC_*RC_; + RC3_ = RC2_*RC_; + + //allpass filter + highCut_ = 0; + lowCut_ = 0; + + lastUIWidth_ = 550; + lastUIHeight_ = 350; + + //initialise distortion + coeffs_[9] = 256*gain9_; + coeffs_[8] = 128*gain8_; + coeffs_[7] = -576*gain9_ + 64*gain7_; + coeffs_[6] = -256*gain8_ + 32*gain6_; + coeffs_[5] = 432*gain9_ -112*gain7_ + 16*gain5_; + coeffs_[4] = 160*gain8_ -48*gain6_ + 8*gain4_; + coeffs_[3] = -120*gain9_ + 56*gain7_ -20*gain5_ + 4*gain3_; + coeffs_[2] = -32*gain8_ + 18*gain6_ -8*gain4_ + 2*gain2_; + coeffs_[1] = 9*gain9_ -7*gain7_ + 5*gain5_ -3*gain3_ + gain1_; + coeffs_[0] = gain8_ - gain6_ + gain4_ - gain2_; +} + +BassPedalRackProcessor::~BassPedalRackProcessor() +{ +} + +//============================================================================== +const String BassPedalRackProcessor::getName() const +{ + return JucePlugin_Name; +} + +int BassPedalRackProcessor::getNumParameters() +{ + return kNumParameters; +} + +float BassPedalRackProcessor::getParameter (int index) +{ + // This method will be called by the host, probably on the audio thread, so + // it's absolutely time-critical. Don't use critical sections or anything + // UI-related, or anything at all that may block in any way! + switch (index) + { + case kMixParam: return mix_; + case kHighCutParam: return (float)highCut_; + case kIndexParam: return index_; + case kGainParam: return gain_; + case kLowCutParam: return (float)lowCut_; + case kGainLowParam: return bassGain_; + case kGainMidParam: return midGain_; + case kGainTreParam: return trebleGain_; + case kGain1Param: return gain1_; + case kGain2Param: return gain2_; + case kGain3Param: return gain3_; + case kGain4Param: return gain4_; + case kGain5Param: return gain5_; + case kGain6Param: return gain6_; + case kGain7Param: return gain7_; + case kGain8Param: return gain8_; + case kGain9Param: return gain9_; + default: return 0.0f; + } +} + +void BassPedalRackProcessor::setParameter (int index, float newValue) +{ + // This method will be called by the host, probably on the audio thread, so + // it's absolutely time-critical. Don't use critical sections or anything + // UI-related, or anything at all that may block in any way! + switch (index) + { + case kMixParam: + mix_ = newValue; + break; + case kHighCutParam: + highCut_ = (int)newValue; + break; + case kIndexParam: + index_ = newValue; + break; + case kGainParam: + gain_ = newValue; + break; + case kLowCutParam: + lowCut_ = (int)newValue; + break; + case kGainTreParam: + trebleGain_ = newValue; + changeToneStack(); + break; + case kGainLowParam: + bassGain_ = newValue; + changeToneStack(); + break; + case kGainMidParam: + midGain_ = newValue; + changeToneStack(); + break; + case kGain1Param: + gain1_ = newValue; + changeCoefficients(kGain1Param); + break; + case kGain2Param: + gain2_ = newValue; + changeCoefficients(kGain2Param); + break; + case kGain3Param: + gain3_ = newValue; + changeCoefficients(kGain3Param); + break; + case kGain4Param: + gain4_ = newValue; + changeCoefficients(kGain4Param); + break; + case kGain5Param: + gain5_ = newValue; + changeCoefficients(kGain5Param); + break; + case kGain6Param: + gain6_ = newValue; + changeCoefficients(kGain6Param); + break; + case kGain7Param: + gain7_ = newValue; + changeCoefficients(kGain7Param); + break; + case kGain8Param: + gain8_ = newValue; + changeCoefficients(kGain8Param); + break; + case kGain9Param: + gain9_ = newValue; + changeCoefficients(kGain9Param); + break; + default: + break; + } +} + +const String BassPedalRackProcessor::getParameterName (int index) +{ + switch (index) + { + case kMixParam: return "mix"; + case kLowCutParam: return "lowcut"; + case kIndexParam: return "index"; + case kGainParam: return "gain"; + case kHighCutParam: return "highcut"; + case kGainLowParam: return "low"; + case kGainMidParam: return "mid"; + case kGainTreParam: return "treble"; + case kGain1Param: return "gain1"; + case kGain2Param: return "gain2"; + case kGain3Param: return "gain3"; + case kGain4Param: return "gain4"; + case kGain5Param: return "gain5"; + case kGain6Param: return "gain6"; + case kGain7Param: return "gain7"; + case kGain8Param: return "gain8"; + case kGain9Param: return "gain9"; + default: break; + } + + return String::empty; +} + +const String BassPedalRackProcessor::getParameterText (int index) +{ + return String (getParameter (index), 2); +} + +const String BassPedalRackProcessor::getInputChannelName (int channelIndex) const +{ + return String (channelIndex + 1); +} + +const String BassPedalRackProcessor::getOutputChannelName (int channelIndex) const +{ + return String (channelIndex + 1); +} + +bool BassPedalRackProcessor::isInputChannelStereoPair (int index) const +{ + return true; +} + +bool BassPedalRackProcessor::isOutputChannelStereoPair (int index) const +{ + return true; +} + +bool BassPedalRackProcessor::silenceInProducesSilenceOut() const +{ +#if JucePlugin_SilenceInProducesSilenceOut + return true; +#else + return false; +#endif +} + +bool BassPedalRackProcessor::acceptsMidi() const +{ +#if JucePlugin_WantsMidiInput + return true; +#else + return false; +#endif +} + +bool BassPedalRackProcessor::producesMidi() const +{ +#if JucePlugin_ProducesMidiOutput + return true; +#else + return false; +#endif +} + +double BassPedalRackProcessor::getTailLengthSeconds() const +{ + return 0; +} + +int BassPedalRackProcessor::getNumPrograms() +{ + return 0; +} + +int BassPedalRackProcessor::getCurrentProgram() +{ + return 0; +} + +void BassPedalRackProcessor::setCurrentProgram (int index) +{ +} + +const String BassPedalRackProcessor::getProgramName (int index) +{ + return String::empty; +} + +void BassPedalRackProcessor::changeProgramName (int index, const String& newName) +{ +} + +//============================================================================== +void BassPedalRackProcessor::prepareToPlay (double sampleRate, int samplesPerBlock) +{ + //initialise sampling frequency + fsd_ = 2*sampleRate; + fsd2_ = fsd_*fsd_; + fsd3_ = fsd2_*fsd_; + + //initilise tone control + a0_ = 1; + changeToneStack(); +} + +void BassPedalRackProcessor::releaseResources() +{ + +} + +void BassPedalRackProcessor::changeToneStack() +{ + if (trebleGain_ + midGain_ + bassGain_ < 0.01 ) + toneStack_ = false; + else + { + toneStack_ = true; + //Transfer function update + b1_ = (10*trebleGain_+80*midGain_+3240*bassGain_+81)*RC_; + b2_ = 16*(1120*trebleGain_-2025*midGain_*midGain_+81000*bassGain_*midGain_+2275*midGain_+14480*bassGain_+362)*RC2_*0.2; + b3_ = -512*(midGain_-40*bassGain_-1)*(280*trebleGain_+153*midGain_)*RC3_; + a1_ = (400*midGain_+16200*bassGain_+2247)*RC_*0.2; + a2_ = -16*(2025*midGain_*midGain_-81000*bassGain_*midGain_+2205*midGain_-193680*bassGain_-5962)*RC2_*0.2; + a3_ = -512*(midGain_-40*bassGain_-1)*(153*midGain_+280)*RC3_; + + //Filter coefficient update + B0 = -b1_*fsd_ - b2_*fsd2_ - b3_*fsd3_; + B1 = -b1_*fsd_ + b2_*fsd2_ + 3*b3_*fsd3_; + B2 = b1_*fsd_ + b2_*fsd2_ - 3*b3_*fsd3_; + B3 = b1_*fsd_ - b2_*fsd2_ + b3_*fsd3_; + A0 = 1/( -a0_ - a1_*fsd_ - a2_*fsd2_ - a3_*fsd3_); + A1 = -3*a0_ - a1_*fsd_ + a2_*fsd2_ + 3*a3_*fsd3_; + A2 = -3*a0_ + a1_*fsd_ + a2_*fsd2_ - 3*a3_*fsd3_; + A3 = -a0_ + a1_*fsd_ - a2_*fsd2_ + a3_*fsd3_; + } + +} + +void BassPedalRackProcessor::changeCoefficients(int kcase) +{ + if (abs(gain1_-1)<0.01 && (gain2_ + gain3_ + gain4_ + gain5_ + gain6_ + gain7_ + gain8_ + gain9_)<0.01) + { + shaper_ = false; + scale_ = 1; + } + else + { + shaper_ = true; + //scale by the sum of the gains time the distortion index + scale_ = (gain1_ + gain2_ + gain3_ + gain4_ + gain5_ + gain6_ + gain7_ + gain8_ + gain9_)*index_; + if (scale_>1) + scale_ = 1/scale_; + else + scale_ = 1; + //switch to avoid unecessary editing (even/odd and bigger indices that degree) + switch(kcase) + { + case 0: //Update all (initialisation) + coeffs_[9] = 256*gain9_; + coeffs_[8] = 128*gain8_; + coeffs_[7] = -576*gain9_ + 64*gain7_; + coeffs_[6] = -256*gain8_ + 32*gain6_; + coeffs_[5] = 432*gain9_ -112*gain7_ + 16*gain5_; + coeffs_[4] = 160*gain8_ -48*gain6_ + 8*gain4_; + coeffs_[3] = -120*gain9_ + 56*gain7_ -20*gain5_ + 4*gain3_; + coeffs_[2] = -32*gain8_ + 18*gain6_ -8*gain4_ + 2*gain2_; + coeffs_[1] = 9*gain9_ -7*gain7_ + 5*gain5_ -3*gain3_ + gain1_; + coeffs_[0] = gain8_ - gain6_ + gain4_ - gain2_; + break; + case kGain1Param: + coeffs_[1] = 9*gain9_ -7*gain7_ + 5*gain5_ -3*gain3_ + gain1_; + break; + case kGain2Param: + coeffs_[2] = -32*gain8_ + 18*gain6_ -8*gain4_ + 2*gain2_; + coeffs_[0] = gain8_ - gain6_ + gain4_ - gain2_; + break; + case kGain3Param: + coeffs_[3] = -120*gain9_ + 56*gain7_ -20*gain5_ + 4*gain3_; + coeffs_[1] = 9*gain9_ -7*gain7_ + 5*gain5_ -3*gain3_ + gain1_; + break; + case kGain4Param: + coeffs_[4] = 160*gain8_ -48*gain6_ + 8*gain4_; + coeffs_[2] = -32*gain8_ + 18*gain6_ -8*gain4_ + 2*gain2_; + coeffs_[0] = gain8_ - gain6_ + gain4_ - gain2_; + break; + case kGain5Param: + coeffs_[5] = 432*gain9_ -112*gain7_ + 16*gain5_; + coeffs_[3] = -120*gain9_ + 56*gain7_ -20*gain5_ + 4*gain3_; + coeffs_[1] = 9*gain9_ -7*gain7_ + 5*gain5_ -3*gain3_ + gain1_; + break; + case kGain6Param: + coeffs_[6] = -256*gain8_ + 32*gain6_; + coeffs_[4] = 160*gain8_ -48*gain6_ + 8*gain4_; + coeffs_[2] = -32*gain8_ + 18*gain6_ -8*gain4_ + 2*gain2_; + coeffs_[0] = gain8_ - gain6_ + gain4_ - gain2_; + break; + case kGain7Param: + coeffs_[7] = -576*gain9_ + 64*gain7_; + coeffs_[5] = 432*gain9_ -112*gain7_ + 16*gain5_; + coeffs_[3] = -120*gain9_ + 56*gain7_ -20*gain5_ + 4*gain3_; + coeffs_[1] = 9*gain9_ -7*gain7_ + 5*gain5_ -3*gain3_ + gain1_; + break; + case kGain8Param: + coeffs_[8] = 128*gain8_; + coeffs_[6] = -256*gain8_ + 32*gain6_; + coeffs_[4] = 160*gain8_ -48*gain6_ + 8*gain4_; + coeffs_[2] = -32*gain8_ + 18*gain6_ -8*gain4_ + 2*gain2_; + coeffs_[0] = gain8_ - gain6_ + gain4_ - gain2_; + break; + case kGain9Param: + coeffs_[9] = 256*gain9_; + coeffs_[7] = -576*gain9_ + 64*gain7_; + coeffs_[5] = 432*gain9_ -112*gain7_ + 16*gain5_; + coeffs_[3] = -120*gain9_ + 56*gain7_ -20*gain5_ + 4*gain3_; + coeffs_[1] = 9*gain9_ -7*gain7_ + 5*gain5_ -3*gain3_ + gain1_; + break; + } + } +} + +double* BassPedalRackProcessor::applyFilter(float input) +{ + double final[2]; //output + final[0] = 0; + final[1] = 0; + double output = 0; // temp output + lastIn_[filterInd_] = (double)input; //update the circular buffer with the new index + int firstMax = filterLength_ - filterInd_; //when indice reaches the end of the circular buffer + switch(highCut_) + { //switch for the index of the HIgh Pass filter + case 0: + output = input; //allpass + break; + case 1: + for (int i = 0; i< firstMax; i++) //until the end of the circular buffer + output += lastIn_[i+filterInd_]*filter_high_1[i]; + for (int i = firstMax; i< filterLength_; i++) //from the beginning of the circular buffer + output += lastIn_[i+filterInd_-filterLength_]*filter_high_1[i]; + break; + case 2: + for (int i = 0; i< firstMax; i++) + output += lastIn_[i+filterInd_]*filter_high_2[i]; + for (int i = firstMax; i< filterLength_; i++) + output += lastIn_[i+filterInd_-filterLength_]*filter_high_2[i]; + break; + case 3: + for (int i = 0; i< firstMax; i++) + output += lastIn_[i+filterInd_]*filter_high_3[i]; + for (int i = firstMax; i< filterLength_; i++) + output += lastIn_[i+filterInd_-filterLength_]*filter_high_3[i]; + break; + case 4: + for (int i = 0; i< firstMax; i++) + output += lastIn_[i+filterInd_]*filter_high_4[i]; + for (int i = firstMax; i< filterLength_; i++) + output += lastIn_[i+filterInd_-filterLength_]*filter_high_4[i]; + break; + case 5: + for (int i = 0; i< firstMax; i++) + output += lastIn_[i+filterInd_]*filter_high_5[i]; + for (int i = firstMax; i< filterLength_; i++) + output += lastIn_[i+filterInd_-filterLength_]*filter_high_5[i]; + break; + case 6: + for (int i = 0; i< firstMax; i++) + output += lastIn_[i+filterInd_]*filter_high_6[i]; + for (int i = firstMax; i< filterLength_; i++) + output += lastIn_[i+filterInd_-filterLength_]*filter_high_6[i]; + break; + case 7: + for (int i = 0; i< firstMax; i++) + output += lastIn_[i+filterInd_]*filter_high_7[i]; + for (int i = firstMax; i< filterLength_; i++) + output += lastIn_[i+filterInd_-filterLength_]*filter_high_7[i]; + break; + case 8: + for (int i = 0; i< firstMax; i++) + output += lastIn_[i+filterInd_]*filter_high_8[i]; + for (int i = firstMax; i< filterLength_; i++) + output += lastIn_[i+filterInd_-filterLength_]*filter_high_8[i]; + break; + + case 9: + for (int i = 0; i< firstMax; i++) + output += lastIn_[i+filterInd_]*filter_high_9[i]; + for (int i = firstMax; i< filterLength_; i++) + output += lastIn_[i+filterInd_-filterLength_]*filter_high_9[i]; + break; + default: + break; + } + final[0] = output; //store the output + output = 0; //new output + switch(lowCut_) + { //switch over the Low pass Filter + case 0: + output = input; + break; + case 1: + for (int i = 0; i< firstMax; i++) + output += lastIn_[i+filterInd_]*filter_low_1[i]; + for (int i = firstMax; i< filterLength_; i++) + output += lastIn_[i+filterInd_-filterLength_]*filter_low_1[i]; + break; + case 2: + for (int i = 0; i< firstMax; i++) + output += lastIn_[i+filterInd_]*filter_low_2[i]; + for (int i = firstMax; i< filterLength_; i++) + output += lastIn_[i+filterInd_-filterLength_]*filter_low_2[i]; + break; + case 3: + for (int i = 0; i< firstMax; i++) + output += lastIn_[i+filterInd_]*filter_low_3[i]; + for (int i = firstMax; i< filterLength_; i++) + output += lastIn_[i+filterInd_-filterLength_]*filter_low_3[i]; + break; + case 4: + for (int i = 0; i< firstMax; i++) + output += lastIn_[i+filterInd_]*filter_low_4[i]; + for (int i = firstMax; i< filterLength_; i++) + output += lastIn_[i+filterInd_-filterLength_]*filter_low_4[i]; + break; + case 5: + for (int i = 0; i< firstMax; i++) + output += lastIn_[i+filterInd_]*filter_low_5[i]; + for (int i = firstMax; i< filterLength_; i++) + output += lastIn_[i+filterInd_-filterLength_]*filter_low_5[i]; + break; + case 6: + for (int i = 0; i< firstMax; i++) + output += lastIn_[i+filterInd_]*filter_low_6[i]; + for (int i = firstMax; i< filterLength_; i++) + output += lastIn_[i+filterInd_-filterLength_]*filter_low_6[i]; + break; + case 7: + for (int i = 0; i< firstMax; i++) + output += lastIn_[i+filterInd_]*filter_low_7[i]; + for (int i = firstMax; i< filterLength_; i++) + output += lastIn_[i+filterInd_-filterLength_]*filter_low_7[i]; + break; + case 8: + for (int i = 0; i< firstMax; i++) + output += lastIn_[i+filterInd_]*filter_low_8[i]; + for (int i = firstMax; i< filterLength_; i++) + output += lastIn_[i+filterInd_-filterLength_]*filter_low_8[i]; + break; + case 9: + for (int i = 0; i< firstMax; i++) + output += lastIn_[i+filterInd_]*filter_low_9[i]; + for (int i = firstMax; i< filterLength_; i++) + output += lastIn_[i+filterInd_-filterLength_]*filter_low_9[i]; + break; + default: + break; + } + final[1] = output; //update output + if (filterInd_==0) //update circular buffer indice (with modulo) + filterInd_=filterLength_-1; + else + filterInd_--; + return final; +} + +float BassPedalRackProcessor::shaper(float x) +{ + double output; + if(shaper_) + { + double dx = (double)x * index_; //distorted input + //efficient polynomial computation + output = coeffs_[9]; + for (int ind = 8; ind > -1; ind--) + { + output = output*dx + coeffs_[ind]; + } + output *=scale_; + } + else + output = (double)x; + + return (float)output; +} + +void BassPedalRackProcessor::saveMem(int channel) +{ + //Store the information of this channel + + //divided for the cirular buffer in config indice = 0; + int firstMax = filterLength_ - filterInd_; + for (int i=0; i < firstMax; i++) + { + //offset of the size of the buffer to have both buffer stored in inputMem; + inputMem_[channel*filterLength_ + i] = lastIn_[filterInd_ +i]; + } + for (int i=firstMax; i < filterLength_; i++) + { + inputMem_[channel*filterLength_ + i] = lastIn_[filterInd_ + i - filterLength_]; + } + + //Switch for the little (3) circular buffers in configuration index = 2 + switch(currInd_) + { + case 0: + tonStackIn_[channel*3] = memIn_[1]; + tonStackIn_[channel*3+1] = memIn_[2]; + tonStackIn_[channel*3+2] = memIn_[0]; + tonStackOut_[channel*3] = memOut_[1]; + tonStackOut_[channel*3+1] = memOut_[2]; + tonStackOut_[channel*3+2] = memOut_[0]; + break; + case 1: + tonStackOut_[channel*3] = memOut_[2]; + tonStackOut_[channel*3+1] = memOut_[0]; + tonStackOut_[channel*3+2] = memOut_[1]; + + tonStackIn_[channel*3] = memIn_[2]; + tonStackIn_[channel*3+1] = memIn_[0]; + tonStackIn_[channel*3+2] = memIn_[1]; + break; + case 2: + tonStackOut_[channel*3] = memOut_[0]; + tonStackOut_[channel*3+1] = memOut_[1]; + tonStackOut_[channel*3+2] = memOut_[2]; + + tonStackIn_[channel*3] = memIn_[0]; + tonStackIn_[channel*3+1] = memIn_[1]; + tonStackIn_[channel*3+2] = memIn_[2]; + break; + default: + break; + } +} + +void BassPedalRackProcessor::loadMem(int channel) +{ + //Relaod the information af the new channel + //Circular buffer for high and low pass filter + for (int i=0; i < filterLength_; i++) + { + lastIn_[i] = inputMem_[channel*filterLength_+i]; + } + filterInd_ = 0; + + //Circular buffers for Tone control + memIn_[0] = tonStackIn_[channel*3]; + memIn_[1] = tonStackIn_[channel*3+1]; + memIn_[2] = tonStackIn_[channel*3+2]; + memOut_[0] = tonStackOut_[channel*3]; + memOut_[1] = tonStackOut_[channel*3+1]; + memOut_[2] = tonStackOut_[channel*3+2]; + currInd_ = 2; +} + +float BassPedalRackProcessor::applyToneStack(float input) +{ + double di = (double)input; + double output = di; + switch(currInd_) + { + + case 0: + if (toneStack_) + output = A0*(di*B0 + memIn_[1]*B1 + memIn_[2]*B2 + memIn_[0]*B3 -( memOut_[1]*A1 + memOut_[2]*A2 + memOut_[0]*A3)); + memOut_[currInd_] = output; + memIn_[currInd_] = di; + currInd_ = 2; + break; + case 1: + if (toneStack_) + output = A0*(di*B0 + memIn_[2]*B1 + memIn_[0]*B2 + memIn_[1]*B3 -( memOut_[2]*A1 + memOut_[0]*A2 + memOut_[1]*A3)); + memOut_[currInd_] = output; + memIn_[currInd_] = di; + currInd_ = 0; + break; + case 2: + if (toneStack_) + output = A0*(di*B0 + memIn_[0]*B1 + memIn_[1]*B2 + memIn_[2]*B3 -( memOut_[0]*A1 + memOut_[1]*A2 + memOut_[2]*A3)); + memOut_[currInd_] = output; + memIn_[currInd_] = di; + currInd_ = 1; + break; + default: + break; + } + + return (float)output; +} + + +void BassPedalRackProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages) +{ + // Helpful information about this block of samples: + const int numInputChannels = getNumInputChannels(); // How many input channels for our effect? + const int numOutputChannels = getNumOutputChannels(); // How many output channels for our effect? + const int numSamples = buffer.getNumSamples(); // How many samples in the buffer for this block? + // Go through each channel of audio that's passed in + double* filtered; //output of the high/low pass filter + float mixed; //mix of both + for (int channel = 0; channel < numInputChannels; ++channel) + { + // channelData is an array of length numSamples which contains the audio for one channel + float* channelData = buffer.getSampleData(channel); + loadMem(channel); //load the buffers for this channel + for (int i = 0; i < numSamples; ++i) + { + const float in = channelData[i]; + + filtered = applyFilter(in); //Apply Low and High Pass Filter + + //mix the signal while adding distortion the scaled high frequencies + mixed = (1-mix_)*filtered[1] + mix_*shaper(filtered[0]); + + //Apply the tone control and the final gain + channelData[i] = applyToneStack(mixed)*gain_; + + + } + saveMem(channel); + + } + + // In case we have more outputs than inputs, we'll clear any output + // channels that didn't contain input data, (because these aren't + // guaranteed to be empty - they may contain garbage). + for (int i = numInputChannels; i < numOutputChannels; ++i) + { + buffer.clear (i, 0, buffer.getNumSamples()); + } +} + +//============================================================================== +bool BassPedalRackProcessor::hasEditor() const +{ + return true; // (change this to false if you choose to not supply an editor) +} + +AudioProcessorEditor* BassPedalRackProcessor::createEditor() +{ + return new BassPedalRackProcessorEditor (this); +} + +//============================================================================== +void BassPedalRackProcessor::getStateInformation (MemoryBlock& destData) +{ + // You should use this method to store your parameters in the memory block. + // You could do that either as raw data, or use the XML or ValueTree classes + // as intermediaries to make it easy to save and load complex data. + + // Create an outer XML element.. + XmlElement xml("C4DMPLUGINSETTINGS"); + + // add some attributes to it.. + xml.setAttribute("uiWidth", lastUIWidth_); + xml.setAttribute("uiHeight", lastUIHeight_); + xml.setAttribute("mix", mix_); + xml.setAttribute("index", index_); + xml.setAttribute("gain", gain_); + xml.setAttribute("highcut", highCut_); + xml.setAttribute("treble", trebleGain_); + xml.setAttribute("lowcut", lowCut_); + xml.setAttribute("mid", midGain_); + xml.setAttribute("bass", bassGain_); + xml.setAttribute("gain1", gain1_); + xml.setAttribute("gain2", gain2_); + xml.setAttribute("gain3", gain3_); + xml.setAttribute("gain4", gain4_); + xml.setAttribute("gain5", gain5_); + xml.setAttribute("gain6", gain6_); + xml.setAttribute("gain7", gain7_); + xml.setAttribute("gain8", gain8_); + xml.setAttribute("gain9", gain9_); + + + // then use this helper function to stuff it into the binary blob and return it.. + copyXmlToBinary(xml, destData); +} + +void BassPedalRackProcessor::setStateInformation (const void* data, int sizeInBytes) +{ + // You should use this method to restore your parameters from this memory block, + // whose contents will have been created by the getStateInformation() call. + + // This getXmlFromBinary() helper function retrieves our XML from the binary blob.. + ScopedPointer<XmlElement> xmlState (getXmlFromBinary (data, sizeInBytes)); + + if(xmlState != 0) + { + // make sure that it's actually our type of XML object.. + if(xmlState->hasTagName("C4DMPLUGINSETTINGS")) + { + // ok, now pull out our parameters.. + lastUIWidth_ = xmlState->getIntAttribute("uiWidth", lastUIWidth_); + lastUIHeight_ = xmlState->getIntAttribute("uiHeight", lastUIHeight_); + + mix_ = (float)xmlState->getDoubleAttribute("mix", mix_); + index_ = (float)xmlState->getDoubleAttribute("index", index_); + gain_ = (float)xmlState->getDoubleAttribute("gain", gain_); + bassGain_ = (float)xmlState->getDoubleAttribute("bass", bassGain_); + midGain_ = (float)xmlState->getDoubleAttribute("mid", midGain_); + trebleGain_ = (float)xmlState->getDoubleAttribute("tre", trebleGain_); + highCut_ = (int)xmlState->getDoubleAttribute("highcut", highCut_); + lowCut_ = (int)xmlState->getDoubleAttribute("lowcut", lowCut_); + gain1_ = (float)xmlState->getDoubleAttribute("gain1", gain1_); + gain2_ = (float)xmlState->getDoubleAttribute("gain2", gain2_); + gain3_ = (float)xmlState->getDoubleAttribute("gain3", gain3_); + gain4_ = (float)xmlState->getDoubleAttribute("gain4", gain4_); + gain5_ = (float)xmlState->getDoubleAttribute("gain5", gain5_); + gain6_ = (float)xmlState->getDoubleAttribute("gain6", gain6_); + gain7_ = (float)xmlState->getDoubleAttribute("gain7", gain7_); + gain8_ = (float)xmlState->getDoubleAttribute("gain8", gain8_); + gain9_ = (float)xmlState->getDoubleAttribute("gain9", gain9_); + } + } +} + +//============================================================================== +// This creates new instances of the plugin.. +AudioProcessor* JUCE_CALLTYPE createPluginFilter() +{ + return new BassPedalRackProcessor(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/BassPedalRackPlugin/PluginProcessor.h Tue Sep 03 12:53:16 2013 +0100 @@ -0,0 +1,162 @@ +/* + ============================================================================== + + This file was auto-generated! + + It contains the basic startup code for a Juce application. + + ============================================================================== +*/ + +#ifndef __PLUGINPROCESSOR_H_4693CB6E__ +#define __PLUGINPROCESSOR_H_4693CB6E__ + +#include "../JuceLibraryCode/JuceHeader.h" + + +//============================================================================== +/** +*/ +class BassPedalRackProcessor : public AudioProcessor +{ +public: + //============================================================================== + BassPedalRackProcessor(); + ~BassPedalRackProcessor(); + + //============================================================================== + void prepareToPlay (double sampleRate, int samplesPerBlock); + void releaseResources(); + + void processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages); + + //============================================================================== + AudioProcessorEditor* createEditor(); + bool hasEditor() const; + + //============================================================================== + const String getName() const; + + int getNumParameters(); + + float getParameter (int index); + void setParameter (int index, float newValue); + + const String getParameterName (int index); + const String getParameterText (int index); + + const String getInputChannelName (int channelIndex) const; + const String getOutputChannelName (int channelIndex) const; + bool isInputChannelStereoPair (int index) const; + bool isOutputChannelStereoPair (int index) const; + + bool silenceInProducesSilenceOut() const; + bool acceptsMidi() const; + bool producesMidi() const; + + double getTailLengthSeconds() const; + + //============================================================================== + int getNumPrograms(); + int getCurrentProgram(); + void setCurrentProgram (int index); + const String getProgramName (int index); + void changeProgramName (int index, const String& newName); + + //============================================================================== + void getStateInformation (MemoryBlock& destData); + void setStateInformation (const void* data, int sizeInBytes); + + //============================================================================== + + // these are used to persist the UI's size - the values are stored along with the + // filter's other parameters, and the UI component will update them when it gets + // resized. + int lastUIWidth_, lastUIHeight_; + + + + enum Parameters + { + kMixParam = 0, + kLowCutParam, + kIndexParam, + kGainParam, + kHighCutParam, + kGainTreParam, + kGainMidParam, + kGainLowParam, + kGain1Param, + kGain2Param, + kGain3Param, + kGain4Param, + kGain5Param, + kGain6Param, + kGain7Param, + kGain8Param, + kGain9Param, + kNumParameters + }; + //Distortion related parameters + float index_; //Distortion index (x = x*index_) + //gainN is the gain of the Nth Chebychev polynomial => gain of the Nth harmonic for a sinusoid + float gain1_, gain2_, gain3_, gain4_, gain5_, gain6_, gain7_, gain8_, gain9_; + + float gain_; //Overall gain of the amp => volume + + int lowCut_, highCut_; //indices of the low pass filter (0 is allpass, max is nopass) + float mix_; //Mix between the low and high (0 is only low, 1 is only high) + + float bassGain_, midGain_, trebleGain_; //gains for Low, Mid and Treble + +private: + +//Variables for tones + //temp variable for polynomial of tone control + //lower case for transfer function, capital for filter coefficent + //RC is the system's characterstic time (2 and 3 are respectivly square and cube of that) + double a1_, a2_, a3_, b1_, b2_, b3_, RC_, RC2_, RC3_, A0,A1,A2,A3,B0,B1,B2,B3; + double fsd_, fsd2_, fsd3_;//sampling frequency, then squared and cubed + int a0_; + //Circular Buffers + double memIn_[3]; //input + double memOut_[3]; //output + int currInd_; //indice in the circular buffers + //Memory for stereo + double tonStackIn_[6]; //input + double tonStackOut_[6]; //output + + bool toneStack_, shaper_; //if tone Stack(or shaper) is applied + +//Variables for Chebychev distortion + double coeffs_[10]; //Coefficient fo the polynomial + float scale_; //scale to attenuate the gain of the distortion + +//Variables for high and low pass filters + double lastIn_[151]; //input circular buffer + double inputMem_[302]; //Memory for stereo + int filterLength_; //length of the filters + int filterInd_; //indice for the circular buffer + + + //Update distortion coefficients + void changeCoefficients(int kcase); //kcase enable to only update relevant coefficients + //Update the tone coefficients + void changeToneStack(); + //Save and load previous buffer for stereo handling + void saveMem(int channel); + void loadMem(int channel); + + //Apply low and high pass filter + double* applyFilter(float input); + //Apply Chebychev Distotion + float shaper(float x); + //Apply Tone control + float applyToneStack(float); + + //============================================================================== + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BassPedalRackProcessor); + +}; + +#endif // __PLUGINPROCESSOR_H_4693CB6E__
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/BassPedalRackPlugin/filter.h Tue Sep 03 12:53:16 2013 +0100 @@ -0,0 +1,2825 @@ +/******************************************************************************* +* FILENAME +* highpass_table.h +* +* DESCRIPTION +* Header File for table of FIR filters +* +*******************************************************************************/ + +#ifndef HIGHPASS_TABLE_H +#define HIGHPASS_TABLE_H + + +/*-----------------------------------------------------------------------*/ +/* highpass 1 FIR filter */ +/*-----------------------------------------------------------------------*/ +const double filter_high_1[] = { + -0.00017322, + -0.00017432, + -0.00017717, + -0.00018177, + -0.00018812, + -0.00019621, + -0.00020605, + -0.00021761, + -0.00023088, + -0.00024585, + -0.00026249, + -0.00028078, + -0.00030070, + -0.00032220, + -0.00034527, + -0.00036986, + -0.00039593, + -0.00042344, + -0.00045236, + -0.00048262, + -0.00051418, + -0.00054699, + -0.00058099, + -0.00061612, + -0.00065233, + -0.00068956, + -0.00072773, + -0.00076679, + -0.00080666, + -0.00084728, + -0.00088858, + -0.00093048, + -0.00097292, + -0.00101581, + -0.00105908, + -0.00110267, + -0.00114648, + -0.00119044, + -0.00123447, + -0.00127851, + -0.00132246, + -0.00136624, + -0.00140980, + -0.00145303, + -0.00149587, + -0.00153824, + -0.00158007, + -0.00162127, + -0.00166178, + -0.00170152, + -0.00174042, + -0.00177841, + -0.00181543, + -0.00185140, + -0.00188626, + -0.00191994, + -0.00195240, + -0.00198356, + -0.00201337, + -0.00204179, + -0.00206874, + -0.00209420, + -0.00211811, + -0.00214042, + -0.00216110, + -0.00218011, + -0.00219742, + -0.00221299, + -0.00222679, + -0.00223881, + -0.00224901, + -0.00225739, + -0.00226392, + -0.00226859, + -0.00227140, + 0.99755456, + -0.00227140, + -0.00226859, + -0.00226392, + -0.00225739, + -0.00224901, + -0.00223881, + -0.00222679, + -0.00221299, + -0.00219742, + -0.00218011, + -0.00216110, + -0.00214042, + -0.00211811, + -0.00209420, + -0.00206874, + -0.00204179, + -0.00201337, + -0.00198356, + -0.00195240, + -0.00191994, + -0.00188626, + -0.00185140, + -0.00181543, + -0.00177841, + -0.00174042, + -0.00170152, + -0.00166178, + -0.00162127, + -0.00158007, + -0.00153824, + -0.00149587, + -0.00145303, + -0.00140980, + -0.00136624, + -0.00132246, + -0.00127851, + -0.00123447, + -0.00119044, + -0.00114648, + -0.00110267, + -0.00105908, + -0.00101581, + -0.00097292, + -0.00093048, + -0.00088858, + -0.00084728, + -0.00080666, + -0.00076679, + -0.00072773, + -0.00068956, + -0.00065233, + -0.00061612, + -0.00058099, + -0.00054699, + -0.00051418, + -0.00048262, + -0.00045236, + -0.00042344, + -0.00039593, + -0.00036986, + -0.00034527, + -0.00032220, + -0.00030070, + -0.00028078, + -0.00026249, + -0.00024585, + -0.00023088, + -0.00021761, + -0.00020605, + -0.00019621, + -0.00018812, + -0.00018177, + -0.00017717, + -0.00017432, + -0.00017432}; + +/*-----------------------------------------------------------------------*/ +/* highpass 2 FIR filter */ +/*-----------------------------------------------------------------------*/ +const double filter_high_2[] = { + -0.00029791, + -0.00030106, + -0.00030725, + -0.00031651, + -0.00032888, + -0.00034438, + -0.00036304, + -0.00038487, + -0.00040988, + -0.00043805, + -0.00046939, + -0.00050388, + -0.00054150, + -0.00058222, + -0.00062599, + -0.00067278, + -0.00072254, + -0.00077520, + -0.00083071, + -0.00088899, + -0.00094996, + -0.00101354, + -0.00107963, + -0.00114814, + -0.00121897, + -0.00129200, + -0.00136712, + -0.00144421, + -0.00152314, + -0.00160378, + -0.00168600, + -0.00176966, + -0.00185461, + -0.00194071, + -0.00202780, + -0.00211574, + -0.00220435, + -0.00229349, + -0.00238300, + -0.00247270, + -0.00256244, + -0.00265204, + -0.00274135, + -0.00283019, + -0.00291839, + -0.00300580, + -0.00309225, + -0.00317756, + -0.00326158, + -0.00334415, + -0.00342511, + -0.00350430, + -0.00358156, + -0.00365675, + -0.00372972, + -0.00380033, + -0.00386844, + -0.00393392, + -0.00399663, + -0.00405645, + -0.00411327, + -0.00416697, + -0.00421745, + -0.00426461, + -0.00430834, + -0.00434857, + -0.00438522, + -0.00441821, + -0.00444747, + -0.00447296, + -0.00449461, + -0.00451238, + -0.00452624, + -0.00453616, + -0.00454212, + 0.99515881, + -0.00454212, + -0.00453616, + -0.00452624, + -0.00451238, + -0.00449461, + -0.00447296, + -0.00444747, + -0.00441821, + -0.00438522, + -0.00434857, + -0.00430834, + -0.00426461, + -0.00421745, + -0.00416697, + -0.00411327, + -0.00405645, + -0.00399663, + -0.00393392, + -0.00386844, + -0.00380033, + -0.00372972, + -0.00365675, + -0.00358156, + -0.00350430, + -0.00342511, + -0.00334415, + -0.00326158, + -0.00317756, + -0.00309225, + -0.00300580, + -0.00291839, + -0.00283019, + -0.00274135, + -0.00265204, + -0.00256244, + -0.00247270, + -0.00238300, + -0.00229349, + -0.00220435, + -0.00211574, + -0.00202780, + -0.00194071, + -0.00185461, + -0.00176966, + -0.00168600, + -0.00160378, + -0.00152314, + -0.00144421, + -0.00136712, + -0.00129200, + -0.00121897, + -0.00114814, + -0.00107963, + -0.00101354, + -0.00094996, + -0.00088899, + -0.00083071, + -0.00077520, + -0.00072254, + -0.00067278, + -0.00062599, + -0.00058222, + -0.00054150, + -0.00050388, + -0.00046939, + -0.00043805, + -0.00040988, + -0.00038487, + -0.00036304, + -0.00034438, + -0.00032888, + -0.00031651, + -0.00030725, + -0.00030106, + -0.00030106}; + +/*-----------------------------------------------------------------------*/ +/* highpass 3 FIR filter */ +/*-----------------------------------------------------------------------*/ +const double filter_high_3[] = { + -0.00028555, + -0.00029609, + -0.00030978, + -0.00032689, + -0.00034768, + -0.00037238, + -0.00040124, + -0.00043449, + -0.00047233, + -0.00051497, + -0.00056260, + -0.00061540, + -0.00067352, + -0.00073711, + -0.00080629, + -0.00088117, + -0.00096184, + -0.00104836, + -0.00114080, + -0.00123916, + -0.00134347, + -0.00145370, + -0.00156983, + -0.00169179, + -0.00181951, + -0.00195288, + -0.00209179, + -0.00223608, + -0.00238558, + -0.00254012, + -0.00269947, + -0.00286342, + -0.00303170, + -0.00320406, + -0.00338019, + -0.00355980, + -0.00374256, + -0.00392813, + -0.00411615, + -0.00430626, + -0.00449806, + -0.00469118, + -0.00488519, + -0.00507969, + -0.00527425, + -0.00546844, + -0.00566182, + -0.00585395, + -0.00604439, + -0.00623269, + -0.00641841, + -0.00660111, + -0.00678034, + -0.00695567, + -0.00712666, + -0.00729290, + -0.00745397, + -0.00760947, + -0.00775900, + -0.00790219, + -0.00803867, + -0.00816809, + -0.00829011, + -0.00840443, + -0.00851074, + -0.00860876, + -0.00869825, + -0.00877896, + -0.00885069, + -0.00891324, + -0.00896645, + -0.00901018, + -0.00904431, + -0.00906876, + -0.00908345, + 0.99063061, + -0.00908345, + -0.00906876, + -0.00904431, + -0.00901018, + -0.00896645, + -0.00891324, + -0.00885069, + -0.00877896, + -0.00869825, + -0.00860876, + -0.00851074, + -0.00840443, + -0.00829011, + -0.00816809, + -0.00803867, + -0.00790219, + -0.00775900, + -0.00760947, + -0.00745397, + -0.00729290, + -0.00712666, + -0.00695567, + -0.00678034, + -0.00660111, + -0.00641841, + -0.00623269, + -0.00604439, + -0.00585395, + -0.00566182, + -0.00546844, + -0.00527425, + -0.00507969, + -0.00488519, + -0.00469118, + -0.00449806, + -0.00430626, + -0.00411615, + -0.00392813, + -0.00374256, + -0.00355980, + -0.00338019, + -0.00320406, + -0.00303170, + -0.00286342, + -0.00269947, + -0.00254012, + -0.00238558, + -0.00223608, + -0.00209179, + -0.00195288, + -0.00181951, + -0.00169179, + -0.00156983, + -0.00145370, + -0.00134347, + -0.00123916, + -0.00114080, + -0.00104836, + -0.00096184, + -0.00088117, + -0.00080629, + -0.00073711, + -0.00067352, + -0.00061540, + -0.00056260, + -0.00051497, + -0.00047233, + -0.00043449, + -0.00040124, + -0.00037238, + -0.00034768, + -0.00032689, + -0.00030978, + -0.00029609, + -0.00029609}; + +/*-----------------------------------------------------------------------*/ +/* highpass 4 FIR filter */ +/*-----------------------------------------------------------------------*/ +const double filter_high_4[] = { + 0.00002422, + 0.00000988, + -0.00000508, + -0.00002111, + -0.00003868, + -0.00005828, + -0.00008043, + -0.00010564, + -0.00013444, + -0.00016738, + -0.00020497, + -0.00024777, + -0.00029630, + -0.00035109, + -0.00041264, + -0.00048145, + -0.00055800, + -0.00064274, + -0.00073611, + -0.00083849, + -0.00095027, + -0.00107177, + -0.00120330, + -0.00134509, + -0.00149736, + -0.00166028, + -0.00183397, + -0.00201848, + -0.00221384, + -0.00242000, + -0.00263687, + -0.00286431, + -0.00310212, + -0.00335002, + -0.00360772, + -0.00387483, + -0.00415093, + -0.00443555, + -0.00472815, + -0.00502814, + -0.00533490, + -0.00564775, + -0.00596595, + -0.00628875, + -0.00661533, + -0.00694485, + -0.00727644, + -0.00760919, + -0.00794217, + -0.00827442, + -0.00860499, + -0.00893287, + -0.00925709, + -0.00957664, + -0.00989053, + -0.01019777, + -0.01049736, + -0.01078834, + -0.01106976, + -0.01134068, + -0.01160021, + -0.01184746, + -0.01208160, + -0.01230184, + -0.01250741, + -0.01269760, + -0.01287175, + -0.01302927, + -0.01316958, + -0.01329221, + -0.01339672, + -0.01348273, + -0.01354995, + -0.01359814, + -0.01362712, + 0.98639451, + -0.01362712, + -0.01359814, + -0.01354995, + -0.01348273, + -0.01339672, + -0.01329221, + -0.01316958, + -0.01302927, + -0.01287175, + -0.01269760, + -0.01250741, + -0.01230184, + -0.01208160, + -0.01184746, + -0.01160021, + -0.01134068, + -0.01106976, + -0.01078834, + -0.01049736, + -0.01019777, + -0.00989053, + -0.00957664, + -0.00925709, + -0.00893287, + -0.00860499, + -0.00827442, + -0.00794217, + -0.00760919, + -0.00727644, + -0.00694485, + -0.00661533, + -0.00628875, + -0.00596595, + -0.00564775, + -0.00533490, + -0.00502814, + -0.00472815, + -0.00443555, + -0.00415093, + -0.00387483, + -0.00360772, + -0.00335002, + -0.00310212, + -0.00286431, + -0.00263687, + -0.00242000, + -0.00221384, + -0.00201848, + -0.00183397, + -0.00166028, + -0.00149736, + -0.00134509, + -0.00120330, + -0.00107177, + -0.00095027, + -0.00083849, + -0.00073611, + -0.00064274, + -0.00055800, + -0.00048145, + -0.00041264, + -0.00035109, + -0.00029630, + -0.00024777, + -0.00020497, + -0.00016738, + -0.00013444, + -0.00010564, + -0.00008043, + -0.00005828, + -0.00003868, + -0.00002111, + -0.00000508, + 0.00000988, + 0.00000988}; + +/*-----------------------------------------------------------------------*/ +/* highpass 5 FIR filter */ +/*-----------------------------------------------------------------------*/ +const double filter_high_5[] = { + 0.00030894, + 0.00030598, + 0.00030484, + 0.00030528, + 0.00030699, + 0.00030957, + 0.00031257, + 0.00031546, + 0.00031764, + 0.00031846, + 0.00031719, + 0.00031308, + 0.00030528, + 0.00029294, + 0.00027514, + 0.00025096, + 0.00021941, + 0.00017953, + 0.00013033, + 0.00007081, + -0.00000000, + -0.00008307, + -0.00017935, + -0.00028972, + -0.00041506, + -0.00055618, + -0.00071381, + -0.00088865, + -0.00108129, + -0.00129225, + -0.00152196, + -0.00177074, + -0.00203881, + -0.00232629, + -0.00263317, + -0.00295934, + -0.00330455, + -0.00366843, + -0.00405049, + -0.00445011, + -0.00486655, + -0.00529894, + -0.00574629, + -0.00620748, + -0.00668128, + -0.00716637, + -0.00766129, + -0.00816451, + -0.00867438, + -0.00918920, + -0.00970717, + -0.01022644, + -0.01074509, + -0.01126117, + -0.01177268, + -0.01227762, + -0.01277396, + -0.01325968, + -0.01373276, + -0.01419123, + -0.01463312, + -0.01505655, + -0.01545966, + -0.01584070, + -0.01619797, + -0.01652988, + -0.01683493, + -0.01711175, + -0.01735908, + -0.01757579, + -0.01776088, + -0.01791350, + -0.01803294, + -0.01811866, + -0.01817025, + 0.98212344, + -0.01817025, + -0.01811866, + -0.01803294, + -0.01791350, + -0.01776088, + -0.01757579, + -0.01735908, + -0.01711175, + -0.01683493, + -0.01652988, + -0.01619797, + -0.01584070, + -0.01545966, + -0.01505655, + -0.01463312, + -0.01419123, + -0.01373276, + -0.01325968, + -0.01277396, + -0.01227762, + -0.01177268, + -0.01126117, + -0.01074509, + -0.01022644, + -0.00970717, + -0.00918920, + -0.00867438, + -0.00816451, + -0.00766129, + -0.00716637, + -0.00668128, + -0.00620748, + -0.00574629, + -0.00529894, + -0.00486655, + -0.00445011, + -0.00405049, + -0.00366843, + -0.00330455, + -0.00295934, + -0.00263317, + -0.00232629, + -0.00203881, + -0.00177074, + -0.00152196, + -0.00129225, + -0.00108129, + -0.00088865, + -0.00071381, + -0.00055618, + -0.00041506, + -0.00028972, + -0.00017935, + -0.00008307, + -0.00000000, + 0.00007081, + 0.00013033, + 0.00017953, + 0.00021941, + 0.00025096, + 0.00027514, + 0.00029294, + 0.00030528, + 0.00031308, + 0.00031719, + 0.00031846, + 0.00031764, + 0.00031546, + 0.00031257, + 0.00030957, + 0.00030699, + 0.00030528, + 0.00030484, + 0.00030598, + 0.00030598}; + +/*-----------------------------------------------------------------------*/ +/* highpass 6 FIR filter */ +/*-----------------------------------------------------------------------*/ +const double filter_high_6[] = { + -0.00004832, + -0.00001974, + 0.00001016, + 0.00004214, + 0.00007696, + 0.00011536, + 0.00015807, + 0.00020577, + 0.00025903, + 0.00031834, + 0.00038406, + 0.00045641, + 0.00053543, + 0.00062097, + 0.00071267, + 0.00080996, + 0.00091205, + 0.00101788, + 0.00112617, + 0.00123539, + 0.00134376, + 0.00144928, + 0.00154970, + 0.00164260, + 0.00172532, + 0.00179507, + 0.00184889, + 0.00188374, + 0.00189647, + 0.00188389, + 0.00184281, + 0.00177008, + 0.00166260, + 0.00151740, + 0.00133166, + 0.00110279, + 0.00082839, + 0.00050639, + 0.00013502, + -0.00028714, + -0.00076110, + -0.00128747, + -0.00186639, + -0.00249754, + -0.00318011, + -0.00391281, + -0.00469382, + -0.00552083, + -0.00639100, + -0.00730102, + -0.00824709, + -0.00922496, + -0.01022995, + -0.01125697, + -0.01230057, + -0.01335498, + -0.01441418, + -0.01547188, + -0.01652165, + -0.01755695, + -0.01857115, + -0.01955766, + -0.02050993, + -0.02142155, + -0.02228627, + -0.02309812, + -0.02385140, + -0.02454078, + -0.02516135, + -0.02570863, + -0.02617867, + -0.02656804, + -0.02687389, + -0.02709398, + -0.02722668, + 0.97266661, + -0.02722668, + -0.02709398, + -0.02687389, + -0.02656804, + -0.02617867, + -0.02570863, + -0.02516135, + -0.02454078, + -0.02385140, + -0.02309812, + -0.02228627, + -0.02142155, + -0.02050993, + -0.01955766, + -0.01857115, + -0.01755695, + -0.01652165, + -0.01547188, + -0.01441418, + -0.01335498, + -0.01230057, + -0.01125697, + -0.01022995, + -0.00922496, + -0.00824709, + -0.00730102, + -0.00639100, + -0.00552083, + -0.00469382, + -0.00391281, + -0.00318011, + -0.00249754, + -0.00186639, + -0.00128747, + -0.00076110, + -0.00028714, + 0.00013502, + 0.00050639, + 0.00082839, + 0.00110279, + 0.00133166, + 0.00151740, + 0.00166260, + 0.00177008, + 0.00184281, + 0.00188389, + 0.00189647, + 0.00188374, + 0.00184889, + 0.00179507, + 0.00172532, + 0.00164260, + 0.00154970, + 0.00144928, + 0.00134376, + 0.00123539, + 0.00112617, + 0.00101788, + 0.00091205, + 0.00080996, + 0.00071267, + 0.00062097, + 0.00053543, + 0.00045641, + 0.00038406, + 0.00031834, + 0.00025903, + 0.00020577, + 0.00015807, + 0.00011536, + 0.00007696, + 0.00004214, + 0.00001016, + -0.00001974, + -0.00001974}; + +/*-----------------------------------------------------------------------*/ +/* highpass 7 FIR filter */ +/*-----------------------------------------------------------------------*/ +const double filter_high_7[] = { + -0.00025654, + -0.00028542, + -0.00031466, + -0.00034444, + -0.00037472, + -0.00040523, + -0.00043544, + -0.00046456, + -0.00049152, + -0.00051499, + -0.00053339, + -0.00054492, + -0.00054762, + -0.00053937, + -0.00051800, + -0.00048132, + -0.00042719, + -0.00035361, + -0.00025882, + -0.00014132, + -0.00000000, + 0.00016578, + 0.00035616, + 0.00057064, + 0.00080811, + 0.00106671, + 0.00134386, + 0.00163621, + 0.00193963, + 0.00224921, + 0.00255929, + 0.00286353, + 0.00315491, + 0.00342585, + 0.00366829, + 0.00387377, + 0.00403360, + 0.00413895, + 0.00418101, + 0.00415115, + 0.00404104, + 0.00384287, + 0.00354944, + 0.00315436, + 0.00265221, + 0.00203863, + 0.00131051, + 0.00046603, + -0.00049514, + -0.00157186, + -0.00276142, + -0.00405950, + -0.00546018, + -0.00695594, + -0.00853772, + -0.01019498, + -0.01191579, + -0.01368696, + -0.01549416, + -0.01732210, + -0.01915472, + -0.02097535, + -0.02276695, + -0.02451233, + -0.02619438, + -0.02779626, + -0.02930169, + -0.03069514, + -0.03196205, + -0.03308902, + -0.03406404, + -0.03487663, + -0.03551801, + -0.03598121, + -0.03626117, + 0.96340302, + -0.03626117, + -0.03598121, + -0.03551801, + -0.03487663, + -0.03406404, + -0.03308902, + -0.03196205, + -0.03069514, + -0.02930169, + -0.02779626, + -0.02619438, + -0.02451233, + -0.02276695, + -0.02097535, + -0.01915472, + -0.01732210, + -0.01549416, + -0.01368696, + -0.01191579, + -0.01019498, + -0.00853772, + -0.00695594, + -0.00546018, + -0.00405950, + -0.00276142, + -0.00157186, + -0.00049514, + 0.00046603, + 0.00131051, + 0.00203863, + 0.00265221, + 0.00315436, + 0.00354944, + 0.00384287, + 0.00404104, + 0.00415115, + 0.00418101, + 0.00413895, + 0.00403360, + 0.00387377, + 0.00366829, + 0.00342585, + 0.00315491, + 0.00286353, + 0.00255929, + 0.00224921, + 0.00193963, + 0.00163621, + 0.00134386, + 0.00106671, + 0.00080811, + 0.00057064, + 0.00035616, + 0.00016578, + -0.00000000, + -0.00014132, + -0.00025882, + -0.00035361, + -0.00042719, + -0.00048132, + -0.00051800, + -0.00053937, + -0.00054762, + -0.00054492, + -0.00053339, + -0.00051499, + -0.00049152, + -0.00046456, + -0.00043544, + -0.00040523, + -0.00037472, + -0.00034444, + -0.00031466, + -0.00028542, + -0.00028542}; + +/*-----------------------------------------------------------------------*/ +/* highpass 8 FIR filter */ +/*-----------------------------------------------------------------------*/ +const double filter_high_8[] = { + -0.00009565, + -0.00003942, + 0.00002031, + 0.00008373, + 0.00015084, + 0.00022136, + 0.00029459, + 0.00036929, + 0.00044361, + 0.00051505, + 0.00058048, + 0.00063615, + 0.00067783, + 0.00070096, + 0.00070084, + 0.00067290, + 0.00061295, + 0.00051750, + 0.00038405, + 0.00021142, + -0.00000000, + -0.00024803, + -0.00052849, + -0.00083511, + -0.00115951, + -0.00149130, + -0.00181821, + -0.00212640, + -0.00240083, + -0.00262575, + -0.00278524, + -0.00286387, + -0.00284735, + -0.00272325, + -0.00248171, + -0.00211611, + -0.00162369, + -0.00100612, + -0.00026991, + 0.00057331, + 0.00150662, + 0.00250787, + 0.00354986, + 0.00460080, + 0.00562485, + 0.00658294, + 0.00743365, + 0.00813435, + 0.00864234, + 0.00891616, + 0.00891689, + 0.00860945, + 0.00796394, + 0.00695677, + 0.00557174, + 0.00380099, + 0.00164568, + -0.00088358, + -0.00376642, + -0.00697286, + -0.01046356, + -0.01419048, + -0.01809773, + -0.02212273, + -0.02619750, + -0.03025027, + -0.03420712, + -0.03799378, + -0.04153746, + -0.04476867, + -0.04762303, + -0.05004288, + -0.05197885, + -0.05339107, + -0.05425033, + 0.94533834, + -0.05425033, + -0.05339107, + -0.05197885, + -0.05004288, + -0.04762303, + -0.04476867, + -0.04153746, + -0.03799378, + -0.03420712, + -0.03025027, + -0.02619750, + -0.02212273, + -0.01809773, + -0.01419048, + -0.01046356, + -0.00697286, + -0.00376642, + -0.00088358, + 0.00164568, + 0.00380099, + 0.00557174, + 0.00695677, + 0.00796394, + 0.00860945, + 0.00891689, + 0.00891616, + 0.00864234, + 0.00813435, + 0.00743365, + 0.00658294, + 0.00562485, + 0.00460080, + 0.00354986, + 0.00250787, + 0.00150662, + 0.00057331, + -0.00026991, + -0.00100612, + -0.00162369, + -0.00211611, + -0.00248171, + -0.00272325, + -0.00284735, + -0.00286387, + -0.00278524, + -0.00262575, + -0.00240083, + -0.00212640, + -0.00181821, + -0.00149130, + -0.00115951, + -0.00083511, + -0.00052849, + -0.00024803, + -0.00000000, + 0.00021142, + 0.00038405, + 0.00051750, + 0.00061295, + 0.00067290, + 0.00070084, + 0.00070096, + 0.00067783, + 0.00063615, + 0.00058048, + 0.00051505, + 0.00044361, + 0.00036929, + 0.00029459, + 0.00022136, + 0.00015084, + 0.00008373, + 0.00002031, + -0.00003942, + -0.00003942}; + +/*-----------------------------------------------------------------------*/ +/* highpass 9 FIR filter */ +/*-----------------------------------------------------------------------*/ +const double filter_high_9[] = { + 0.00033619, + 0.00032240, + 0.00029386, + 0.00025008, + 0.00019063, + 0.00011541, + 0.00002488, + -0.00007956, + -0.00019534, + -0.00031847, + -0.00044341, + -0.00056312, + -0.00066919, + -0.00075225, + -0.00080248, + -0.00081029, + -0.00076716, + -0.00066648, + -0.00050448, + -0.00028095, + -0.00000000, + 0.00032960, + 0.00069420, + 0.00107554, + 0.00145123, + 0.00179579, + 0.00208189, + 0.00228200, + 0.00237024, + 0.00232432, + 0.00212757, + 0.00177079, + 0.00125380, + 0.00058668, + -0.00020963, + -0.00110323, + -0.00205202, + -0.00300503, + -0.00390455, + -0.00468890, + -0.00529572, + -0.00566569, + -0.00574645, + -0.00549650, + -0.00488887, + -0.00391439, + -0.00258413, + -0.00093109, + 0.00098924, + 0.00309948, + 0.00530221, + 0.00748295, + 0.00951439, + 0.01126149, + 0.01258749, + 0.01336035, + 0.01345940, + 0.01278194, + 0.01124934, + 0.00881232, + 0.00545517, + 0.00119864, + -0.00389883, + -0.00974149, + -0.01619843, + -0.02310740, + -0.03028025, + -0.03750966, + -0.04457702, + -0.05126097, + -0.05734632, + -0.06263288, + -0.06694380, + -0.07013303, + -0.07209153, + 0.92758750, + -0.07209153, + -0.07013303, + -0.06694380, + -0.06263288, + -0.05734632, + -0.05126097, + -0.04457702, + -0.03750966, + -0.03028025, + -0.02310740, + -0.01619843, + -0.00974149, + -0.00389883, + 0.00119864, + 0.00545517, + 0.00881232, + 0.01124934, + 0.01278194, + 0.01345940, + 0.01336035, + 0.01258749, + 0.01126149, + 0.00951439, + 0.00748295, + 0.00530221, + 0.00309948, + 0.00098924, + -0.00093109, + -0.00258413, + -0.00391439, + -0.00488887, + -0.00549650, + -0.00574645, + -0.00566569, + -0.00529572, + -0.00468890, + -0.00390455, + -0.00300503, + -0.00205202, + -0.00110323, + -0.00020963, + 0.00058668, + 0.00125380, + 0.00177079, + 0.00212757, + 0.00232432, + 0.00237024, + 0.00228200, + 0.00208189, + 0.00179579, + 0.00145123, + 0.00107554, + 0.00069420, + 0.00032960, + -0.00000000, + -0.00028095, + -0.00050448, + -0.00066648, + -0.00076716, + -0.00081029, + -0.00080248, + -0.00075225, + -0.00066919, + -0.00056312, + -0.00044341, + -0.00031847, + -0.00019534, + -0.00007956, + 0.00002488, + 0.00011541, + 0.00019063, + 0.00025008, + 0.00029386, + 0.00032240, + 0.00032240}; + +/*-----------------------------------------------------------------------*/ +/* lowpass 1 FIR filter */ +/*-----------------------------------------------------------------------*/ +const double filter_low_1[] = { + 0.00094747, + 0.00095348, + 0.00096905, + 0.00099421, + 0.00102895, + 0.00107323, + 0.00112702, + 0.00119025, + 0.00126284, + 0.00134471, + 0.00143573, + 0.00153578, + 0.00164470, + 0.00176233, + 0.00188850, + 0.00202299, + 0.00216560, + 0.00231609, + 0.00247423, + 0.00263975, + 0.00281238, + 0.00299183, + 0.00317780, + 0.00336998, + 0.00356804, + 0.00377164, + 0.00398043, + 0.00419406, + 0.00441215, + 0.00463434, + 0.00486022, + 0.00508942, + 0.00532153, + 0.00555614, + 0.00579283, + 0.00603121, + 0.00627084, + 0.00651129, + 0.00675216, + 0.00699300, + 0.00723339, + 0.00747290, + 0.00771111, + 0.00794758, + 0.00818191, + 0.00841366, + 0.00864243, + 0.00886780, + 0.00908937, + 0.00930674, + 0.00951951, + 0.00972732, + 0.00992977, + 0.01012651, + 0.01031719, + 0.01050145, + 0.01067896, + 0.01084941, + 0.01101248, + 0.01116788, + 0.01131533, + 0.01145457, + 0.01158532, + 0.01170737, + 0.01182049, + 0.01192448, + 0.01201914, + 0.01210430, + 0.01217981, + 0.01224554, + 0.01230135, + 0.01234716, + 0.01238287, + 0.01240843, + 0.01242378, + 0.01242890, + 0.01242378, + 0.01240843, + 0.01238287, + 0.01234716, + 0.01230135, + 0.01224554, + 0.01217981, + 0.01210430, + 0.01201914, + 0.01192448, + 0.01182049, + 0.01170737, + 0.01158532, + 0.01145457, + 0.01131533, + 0.01116788, + 0.01101248, + 0.01084941, + 0.01067896, + 0.01050145, + 0.01031719, + 0.01012651, + 0.00992977, + 0.00972732, + 0.00951951, + 0.00930674, + 0.00908937, + 0.00886780, + 0.00864243, + 0.00841366, + 0.00818191, + 0.00794758, + 0.00771111, + 0.00747290, + 0.00723339, + 0.00699300, + 0.00675216, + 0.00651129, + 0.00627084, + 0.00603121, + 0.00579283, + 0.00555614, + 0.00532153, + 0.00508942, + 0.00486022, + 0.00463434, + 0.00441215, + 0.00419406, + 0.00398043, + 0.00377164, + 0.00356804, + 0.00336998, + 0.00317780, + 0.00299183, + 0.00281238, + 0.00263975, + 0.00247423, + 0.00231609, + 0.00216560, + 0.00202299, + 0.00188850, + 0.00176233, + 0.00164470, + 0.00153578, + 0.00143573, + 0.00134471, + 0.00126284, + 0.00119025, + 0.00112702, + 0.00107323, + 0.00102895, + 0.00099421, + 0.00096905, + 0.00095348, + 0.00095348}; + +/*-----------------------------------------------------------------------*/ +/* lowpass 2 FIR filter */ +/*-----------------------------------------------------------------------*/ +const double filter_low_2[] = { + 0.00083374, + 0.00084256, + 0.00085987, + 0.00088579, + 0.00092041, + 0.00096380, + 0.00101603, + 0.00107712, + 0.00114709, + 0.00122594, + 0.00131365, + 0.00141018, + 0.00151546, + 0.00162940, + 0.00175191, + 0.00188287, + 0.00202212, + 0.00216951, + 0.00232485, + 0.00248795, + 0.00265858, + 0.00283651, + 0.00302148, + 0.00321322, + 0.00341143, + 0.00361582, + 0.00382605, + 0.00404179, + 0.00426269, + 0.00448838, + 0.00471849, + 0.00495262, + 0.00519037, + 0.00543132, + 0.00567506, + 0.00592115, + 0.00616916, + 0.00641863, + 0.00666911, + 0.00692016, + 0.00717129, + 0.00742206, + 0.00767200, + 0.00792063, + 0.00816749, + 0.00841211, + 0.00865404, + 0.00889280, + 0.00912795, + 0.00935903, + 0.00958560, + 0.00980721, + 0.01002344, + 0.01023387, + 0.01043809, + 0.01063570, + 0.01082631, + 0.01100955, + 0.01118506, + 0.01135249, + 0.01151150, + 0.01166180, + 0.01180307, + 0.01193503, + 0.01205743, + 0.01217003, + 0.01227259, + 0.01236491, + 0.01244681, + 0.01251813, + 0.01257871, + 0.01262845, + 0.01266724, + 0.01269500, + 0.01271168, + 0.01271724, + 0.01271168, + 0.01269500, + 0.01266724, + 0.01262845, + 0.01257871, + 0.01251813, + 0.01244681, + 0.01236491, + 0.01227259, + 0.01217003, + 0.01205743, + 0.01193503, + 0.01180307, + 0.01166180, + 0.01151150, + 0.01135249, + 0.01118506, + 0.01100955, + 0.01082631, + 0.01063570, + 0.01043809, + 0.01023387, + 0.01002344, + 0.00980721, + 0.00958560, + 0.00935903, + 0.00912795, + 0.00889280, + 0.00865404, + 0.00841211, + 0.00816749, + 0.00792063, + 0.00767200, + 0.00742206, + 0.00717129, + 0.00692016, + 0.00666911, + 0.00641863, + 0.00616916, + 0.00592115, + 0.00567506, + 0.00543132, + 0.00519037, + 0.00495262, + 0.00471849, + 0.00448838, + 0.00426269, + 0.00404179, + 0.00382605, + 0.00361582, + 0.00341143, + 0.00321322, + 0.00302148, + 0.00283651, + 0.00265858, + 0.00248795, + 0.00232485, + 0.00216951, + 0.00202212, + 0.00188287, + 0.00175191, + 0.00162940, + 0.00151546, + 0.00141018, + 0.00131365, + 0.00122594, + 0.00114709, + 0.00107712, + 0.00101603, + 0.00096380, + 0.00092041, + 0.00088579, + 0.00085987, + 0.00084256, + 0.00084256}; + +/*-----------------------------------------------------------------------*/ +/* lowpass 3 FIR filter */ +/*-----------------------------------------------------------------------*/ +const double filter_low_3[] = { + 0.00043674, + 0.00045286, + 0.00047380, + 0.00049997, + 0.00053176, + 0.00056954, + 0.00061368, + 0.00066453, + 0.00072240, + 0.00078762, + 0.00086048, + 0.00094123, + 0.00103012, + 0.00112738, + 0.00123319, + 0.00134772, + 0.00147110, + 0.00160343, + 0.00174480, + 0.00189525, + 0.00205478, + 0.00222338, + 0.00240099, + 0.00258753, + 0.00278287, + 0.00298686, + 0.00319931, + 0.00341999, + 0.00364865, + 0.00388501, + 0.00412874, + 0.00437948, + 0.00463687, + 0.00490048, + 0.00516987, + 0.00544457, + 0.00572409, + 0.00600791, + 0.00629548, + 0.00658624, + 0.00687961, + 0.00717497, + 0.00747170, + 0.00776918, + 0.00806675, + 0.00836375, + 0.00865952, + 0.00895338, + 0.00924465, + 0.00953265, + 0.00981671, + 0.01009613, + 0.01037026, + 0.01063841, + 0.01089994, + 0.01115420, + 0.01140055, + 0.01163838, + 0.01186708, + 0.01208608, + 0.01229482, + 0.01249276, + 0.01267939, + 0.01285423, + 0.01301683, + 0.01316676, + 0.01330362, + 0.01342707, + 0.01353677, + 0.01363244, + 0.01371383, + 0.01378071, + 0.01383291, + 0.01387030, + 0.01389277, + 0.01390027, + 0.01389277, + 0.01387030, + 0.01383291, + 0.01378071, + 0.01371383, + 0.01363244, + 0.01353677, + 0.01342707, + 0.01330362, + 0.01316676, + 0.01301683, + 0.01285423, + 0.01267939, + 0.01249276, + 0.01229482, + 0.01208608, + 0.01186708, + 0.01163838, + 0.01140055, + 0.01115420, + 0.01089994, + 0.01063841, + 0.01037026, + 0.01009613, + 0.00981671, + 0.00953265, + 0.00924465, + 0.00895338, + 0.00865952, + 0.00836375, + 0.00806675, + 0.00776918, + 0.00747170, + 0.00717497, + 0.00687961, + 0.00658624, + 0.00629548, + 0.00600791, + 0.00572409, + 0.00544457, + 0.00516987, + 0.00490048, + 0.00463687, + 0.00437948, + 0.00412874, + 0.00388501, + 0.00364865, + 0.00341999, + 0.00319931, + 0.00298686, + 0.00278287, + 0.00258753, + 0.00240099, + 0.00222338, + 0.00205478, + 0.00189525, + 0.00174480, + 0.00160343, + 0.00147110, + 0.00134772, + 0.00123319, + 0.00112738, + 0.00103012, + 0.00094123, + 0.00086048, + 0.00078762, + 0.00072240, + 0.00066453, + 0.00061368, + 0.00056954, + 0.00053176, + 0.00049997, + 0.00047380, + 0.00045286, + 0.00045286}; + +/*-----------------------------------------------------------------------*/ +/* lowpass 4 FIR filter */ +/*-----------------------------------------------------------------------*/ +const double filter_low_4[] = { + -0.00002835, + -0.00001156, + 0.00000595, + 0.00002470, + 0.00004526, + 0.00006820, + 0.00009412, + 0.00012362, + 0.00015733, + 0.00019587, + 0.00023987, + 0.00028995, + 0.00034674, + 0.00041085, + 0.00048288, + 0.00056340, + 0.00065298, + 0.00075215, + 0.00086141, + 0.00098123, + 0.00111204, + 0.00125422, + 0.00140813, + 0.00157406, + 0.00175226, + 0.00194291, + 0.00214616, + 0.00236208, + 0.00259069, + 0.00283195, + 0.00308574, + 0.00335190, + 0.00363018, + 0.00392029, + 0.00422185, + 0.00453443, + 0.00485754, + 0.00519060, + 0.00553301, + 0.00588407, + 0.00624305, + 0.00660915, + 0.00698152, + 0.00735926, + 0.00774144, + 0.00812705, + 0.00851509, + 0.00890448, + 0.00929414, + 0.00968296, + 0.01006979, + 0.01045350, + 0.01083291, + 0.01120686, + 0.01157418, + 0.01193371, + 0.01228430, + 0.01262482, + 0.01295414, + 0.01327118, + 0.01357489, + 0.01386423, + 0.01413823, + 0.01439595, + 0.01463651, + 0.01485908, + 0.01506289, + 0.01524721, + 0.01541141, + 0.01555492, + 0.01567721, + 0.01577787, + 0.01585653, + 0.01591292, + 0.01594683, + 0.01595815, + 0.01594683, + 0.01591292, + 0.01585653, + 0.01577787, + 0.01567721, + 0.01555492, + 0.01541141, + 0.01524721, + 0.01506289, + 0.01485908, + 0.01463651, + 0.01439595, + 0.01413823, + 0.01386423, + 0.01357489, + 0.01327118, + 0.01295414, + 0.01262482, + 0.01228430, + 0.01193371, + 0.01157418, + 0.01120686, + 0.01083291, + 0.01045350, + 0.01006979, + 0.00968296, + 0.00929414, + 0.00890448, + 0.00851509, + 0.00812705, + 0.00774144, + 0.00735926, + 0.00698152, + 0.00660915, + 0.00624305, + 0.00588407, + 0.00553301, + 0.00519060, + 0.00485754, + 0.00453443, + 0.00422185, + 0.00392029, + 0.00363018, + 0.00335190, + 0.00308574, + 0.00283195, + 0.00259069, + 0.00236208, + 0.00214616, + 0.00194291, + 0.00175226, + 0.00157406, + 0.00140813, + 0.00125422, + 0.00111204, + 0.00098123, + 0.00086141, + 0.00075215, + 0.00065298, + 0.00056340, + 0.00048288, + 0.00041085, + 0.00034674, + 0.00028995, + 0.00023987, + 0.00019587, + 0.00015733, + 0.00012362, + 0.00009412, + 0.00006820, + 0.00004526, + 0.00002470, + 0.00000595, + -0.00001156, + -0.00001156}; + +/*-----------------------------------------------------------------------*/ +/* lowpass 5 FIR filter */ +/*-----------------------------------------------------------------------*/ +const double filter_low_5[] = { + -0.00032178, + -0.00031869, + -0.00031751, + -0.00031797, + -0.00031974, + -0.00032243, + -0.00032555, + -0.00032856, + -0.00033083, + -0.00033169, + -0.00033037, + -0.00032608, + -0.00031796, + -0.00030511, + -0.00028657, + -0.00026138, + -0.00022853, + -0.00018699, + -0.00013574, + -0.00007375, + 0.00000000, + 0.00008652, + 0.00018680, + 0.00030176, + 0.00043231, + 0.00057928, + 0.00074347, + 0.00092557, + 0.00112621, + 0.00134594, + 0.00158519, + 0.00184430, + 0.00212351, + 0.00242293, + 0.00274257, + 0.00308228, + 0.00344183, + 0.00382083, + 0.00421876, + 0.00463499, + 0.00506873, + 0.00551908, + 0.00598501, + 0.00646536, + 0.00695885, + 0.00746409, + 0.00797957, + 0.00850369, + 0.00903475, + 0.00957096, + 0.01011045, + 0.01065129, + 0.01119149, + 0.01172901, + 0.01226177, + 0.01278769, + 0.01330465, + 0.01381054, + 0.01430328, + 0.01478079, + 0.01524105, + 0.01568206, + 0.01610193, + 0.01649879, + 0.01687090, + 0.01721660, + 0.01753433, + 0.01782265, + 0.01808026, + 0.01830597, + 0.01849874, + 0.01865770, + 0.01878211, + 0.01887139, + 0.01892512, + 0.01894306, + 0.01892512, + 0.01887139, + 0.01878211, + 0.01865770, + 0.01849874, + 0.01830597, + 0.01808026, + 0.01782265, + 0.01753433, + 0.01721660, + 0.01687090, + 0.01649879, + 0.01610193, + 0.01568206, + 0.01524105, + 0.01478079, + 0.01430328, + 0.01381054, + 0.01330465, + 0.01278769, + 0.01226177, + 0.01172901, + 0.01119149, + 0.01065129, + 0.01011045, + 0.00957096, + 0.00903475, + 0.00850369, + 0.00797957, + 0.00746409, + 0.00695885, + 0.00646536, + 0.00598501, + 0.00551908, + 0.00506873, + 0.00463499, + 0.00421876, + 0.00382083, + 0.00344183, + 0.00308228, + 0.00274257, + 0.00242293, + 0.00212351, + 0.00184430, + 0.00158519, + 0.00134594, + 0.00112621, + 0.00092557, + 0.00074347, + 0.00057928, + 0.00043231, + 0.00030176, + 0.00018680, + 0.00008652, + 0.00000000, + -0.00007375, + -0.00013574, + -0.00018699, + -0.00022853, + -0.00026138, + -0.00028657, + -0.00030511, + -0.00031796, + -0.00032608, + -0.00033037, + -0.00033169, + -0.00033083, + -0.00032856, + -0.00032555, + -0.00032243, + -0.00031974, + -0.00031797, + -0.00031751, + -0.00031869, + -0.00031869}; + +/*-----------------------------------------------------------------------*/ +/* lowpass 6 FIR filter */ +/*-----------------------------------------------------------------------*/ +const double filter_low_6[] = { + 0.00004813, + 0.00001967, + -0.00001012, + -0.00004198, + -0.00007666, + -0.00011492, + -0.00015747, + -0.00020498, + -0.00025804, + -0.00031712, + -0.00038260, + -0.00045467, + -0.00053338, + -0.00061859, + -0.00070994, + -0.00080687, + -0.00090856, + -0.00101399, + -0.00112187, + -0.00123067, + -0.00133863, + -0.00144374, + -0.00154378, + -0.00163632, + -0.00171873, + -0.00178821, + -0.00184183, + -0.00187654, + -0.00188922, + -0.00187669, + -0.00183577, + -0.00176332, + -0.00165624, + -0.00151160, + -0.00132658, + -0.00109857, + -0.00082523, + -0.00050446, + -0.00013450, + 0.00028604, + 0.00075820, + 0.00128255, + 0.00185926, + 0.00248799, + 0.00316796, + 0.00389787, + 0.00467589, + 0.00549974, + 0.00636658, + 0.00727312, + 0.00821558, + 0.00918972, + 0.01019087, + 0.01121396, + 0.01225358, + 0.01330397, + 0.01435911, + 0.01541277, + 0.01645854, + 0.01748988, + 0.01850021, + 0.01948295, + 0.02043158, + 0.02133971, + 0.02220114, + 0.02300988, + 0.02376028, + 0.02444704, + 0.02506523, + 0.02561042, + 0.02607866, + 0.02646654, + 0.02677123, + 0.02699047, + 0.02712267, + 0.02716685, + 0.02712267, + 0.02699047, + 0.02677123, + 0.02646654, + 0.02607866, + 0.02561042, + 0.02506523, + 0.02444704, + 0.02376028, + 0.02300988, + 0.02220114, + 0.02133971, + 0.02043158, + 0.01948295, + 0.01850021, + 0.01748988, + 0.01645854, + 0.01541277, + 0.01435911, + 0.01330397, + 0.01225358, + 0.01121396, + 0.01019087, + 0.00918972, + 0.00821558, + 0.00727312, + 0.00636658, + 0.00549974, + 0.00467589, + 0.00389787, + 0.00316796, + 0.00248799, + 0.00185926, + 0.00128255, + 0.00075820, + 0.00028604, + -0.00013450, + -0.00050446, + -0.00082523, + -0.00109857, + -0.00132658, + -0.00151160, + -0.00165624, + -0.00176332, + -0.00183577, + -0.00187669, + -0.00188922, + -0.00187654, + -0.00184183, + -0.00178821, + -0.00171873, + -0.00163632, + -0.00154378, + -0.00144374, + -0.00133863, + -0.00123067, + -0.00112187, + -0.00101399, + -0.00090856, + -0.00080687, + -0.00070994, + -0.00061859, + -0.00053338, + -0.00045467, + -0.00038260, + -0.00031712, + -0.00025804, + -0.00020498, + -0.00015747, + -0.00011492, + -0.00007666, + -0.00004198, + -0.00001012, + 0.00001967, + 0.00001967}; + +/*-----------------------------------------------------------------------*/ +/* lowpass 7 FIR filter */ +/*-----------------------------------------------------------------------*/ +const double filter_low_7[] = { + 0.00025614, + 0.00028498, + 0.00031418, + 0.00034391, + 0.00037414, + 0.00040460, + 0.00043477, + 0.00046384, + 0.00049076, + 0.00051419, + 0.00053256, + 0.00054408, + 0.00054677, + 0.00053854, + 0.00051720, + 0.00048057, + 0.00042653, + 0.00035307, + 0.00025842, + 0.00014110, + -0.00000000, + -0.00016553, + -0.00035561, + -0.00056976, + -0.00080686, + -0.00106506, + -0.00134179, + -0.00163369, + -0.00193663, + -0.00224573, + -0.00255534, + -0.00285911, + -0.00315004, + -0.00342056, + -0.00366262, + -0.00386778, + -0.00402737, + -0.00413256, + -0.00417455, + -0.00414474, + -0.00403480, + -0.00383693, + -0.00354396, + -0.00314949, + -0.00264812, + -0.00203549, + -0.00130848, + -0.00046531, + 0.00049437, + 0.00156943, + 0.00275716, + 0.00405323, + 0.00545174, + 0.00694519, + 0.00852453, + 0.01017923, + 0.01189739, + 0.01366582, + 0.01547023, + 0.01729535, + 0.01912514, + 0.02094295, + 0.02273178, + 0.02447447, + 0.02615392, + 0.02775333, + 0.02925644, + 0.03064774, + 0.03191268, + 0.03303791, + 0.03401143, + 0.03482277, + 0.03546316, + 0.03592564, + 0.03620517, + 0.03629868, + 0.03620517, + 0.03592564, + 0.03546316, + 0.03482277, + 0.03401143, + 0.03303791, + 0.03191268, + 0.03064774, + 0.02925644, + 0.02775333, + 0.02615392, + 0.02447447, + 0.02273178, + 0.02094295, + 0.01912514, + 0.01729535, + 0.01547023, + 0.01366582, + 0.01189739, + 0.01017923, + 0.00852453, + 0.00694519, + 0.00545174, + 0.00405323, + 0.00275716, + 0.00156943, + 0.00049437, + -0.00046531, + -0.00130848, + -0.00203549, + -0.00264812, + -0.00314949, + -0.00354396, + -0.00383693, + -0.00403480, + -0.00414474, + -0.00417455, + -0.00413256, + -0.00402737, + -0.00386778, + -0.00366262, + -0.00342056, + -0.00315004, + -0.00285911, + -0.00255534, + -0.00224573, + -0.00193663, + -0.00163369, + -0.00134179, + -0.00106506, + -0.00080686, + -0.00056976, + -0.00035561, + -0.00016553, + -0.00000000, + 0.00014110, + 0.00025842, + 0.00035307, + 0.00042653, + 0.00048057, + 0.00051720, + 0.00053854, + 0.00054677, + 0.00054408, + 0.00053256, + 0.00051419, + 0.00049076, + 0.00046384, + 0.00043477, + 0.00040460, + 0.00037414, + 0.00034391, + 0.00031418, + 0.00028498, + 0.00028498}; + +/*-----------------------------------------------------------------------*/ +/* lowpass 8 FIR filter */ +/*-----------------------------------------------------------------------*/ +const double filter_low_8[] = { + 0.00009588, + 0.00003952, + -0.00002036, + -0.00008394, + -0.00015121, + -0.00022191, + -0.00029532, + -0.00037020, + -0.00044471, + -0.00051633, + -0.00058192, + -0.00063773, + -0.00067951, + -0.00070270, + -0.00070258, + -0.00067457, + -0.00061447, + -0.00051878, + -0.00038500, + -0.00021195, + 0.00000000, + 0.00024864, + 0.00052980, + 0.00083718, + 0.00116239, + 0.00149501, + 0.00182273, + 0.00213168, + 0.00240679, + 0.00263227, + 0.00279216, + 0.00287098, + 0.00285442, + 0.00273001, + 0.00248787, + 0.00212136, + 0.00162772, + 0.00100862, + 0.00027058, + -0.00057473, + -0.00151036, + -0.00251409, + -0.00355868, + -0.00461222, + -0.00563882, + -0.00659928, + -0.00745211, + -0.00815454, + -0.00866380, + -0.00893830, + -0.00893903, + -0.00863083, + -0.00798372, + -0.00697404, + -0.00558557, + -0.00381043, + -0.00164976, + 0.00088577, + 0.00377578, + 0.00699017, + 0.01048954, + 0.01422571, + 0.01814267, + 0.02217766, + 0.02626255, + 0.03032538, + 0.03429206, + 0.03808812, + 0.04164059, + 0.04487983, + 0.04774127, + 0.05016713, + 0.05210790, + 0.05352364, + 0.05438503, + 0.05467417, + 0.05438503, + 0.05352364, + 0.05210790, + 0.05016713, + 0.04774127, + 0.04487983, + 0.04164059, + 0.03808812, + 0.03429206, + 0.03032538, + 0.02626255, + 0.02217766, + 0.01814267, + 0.01422571, + 0.01048954, + 0.00699017, + 0.00377578, + 0.00088577, + -0.00164976, + -0.00381043, + -0.00558557, + -0.00697404, + -0.00798372, + -0.00863083, + -0.00893903, + -0.00893830, + -0.00866380, + -0.00815454, + -0.00745211, + -0.00659928, + -0.00563882, + -0.00461222, + -0.00355868, + -0.00251409, + -0.00151036, + -0.00057473, + 0.00027058, + 0.00100862, + 0.00162772, + 0.00212136, + 0.00248787, + 0.00273001, + 0.00285442, + 0.00287098, + 0.00279216, + 0.00263227, + 0.00240679, + 0.00213168, + 0.00182273, + 0.00149501, + 0.00116239, + 0.00083718, + 0.00052980, + 0.00024864, + 0.00000000, + -0.00021195, + -0.00038500, + -0.00051878, + -0.00061447, + -0.00067457, + -0.00070258, + -0.00070270, + -0.00067951, + -0.00063773, + -0.00058192, + -0.00051633, + -0.00044471, + -0.00037020, + -0.00029532, + -0.00022191, + -0.00015121, + -0.00008394, + -0.00002036, + 0.00003952, + 0.00003952}; + +/*-----------------------------------------------------------------------*/ +/* lowpass 9 FIR filter */ +/*-----------------------------------------------------------------------*/ +const double filter_low_9[] = { + -0.00033605, + -0.00032227, + -0.00029374, + -0.00024997, + -0.00019055, + -0.00011536, + -0.00002487, + 0.00007952, + 0.00019526, + 0.00031834, + 0.00044323, + 0.00056289, + 0.00066892, + 0.00075194, + 0.00080215, + 0.00080995, + 0.00076684, + 0.00066621, + 0.00050427, + 0.00028084, + -0.00000000, + -0.00032946, + -0.00069392, + -0.00107509, + -0.00145063, + -0.00179505, + -0.00208103, + -0.00228107, + -0.00236926, + -0.00232336, + -0.00212670, + -0.00177006, + -0.00125328, + -0.00058643, + 0.00020954, + 0.00110278, + 0.00205118, + 0.00300380, + 0.00390295, + 0.00468697, + 0.00529355, + 0.00566337, + 0.00574409, + 0.00549424, + 0.00488686, + 0.00391278, + 0.00258306, + 0.00093071, + -0.00098883, + -0.00309821, + -0.00530003, + -0.00747988, + -0.00951048, + -0.01125686, + -0.01258232, + -0.01335486, + -0.01345387, + -0.01277669, + -0.01124472, + -0.00880870, + -0.00545293, + -0.00119815, + 0.00389723, + 0.00973749, + 0.01619178, + 0.02309791, + 0.03026781, + 0.03749425, + 0.04455871, + 0.05123992, + 0.05732277, + 0.06260716, + 0.06691631, + 0.07010422, + 0.07206192, + 0.07272208, + 0.07206192, + 0.07010422, + 0.06691631, + 0.06260716, + 0.05732277, + 0.05123992, + 0.04455871, + 0.03749425, + 0.03026781, + 0.02309791, + 0.01619178, + 0.00973749, + 0.00389723, + -0.00119815, + -0.00545293, + -0.00880870, + -0.01124472, + -0.01277669, + -0.01345387, + -0.01335486, + -0.01258232, + -0.01125686, + -0.00951048, + -0.00747988, + -0.00530003, + -0.00309821, + -0.00098883, + 0.00093071, + 0.00258306, + 0.00391278, + 0.00488686, + 0.00549424, + 0.00574409, + 0.00566337, + 0.00529355, + 0.00468697, + 0.00390295, + 0.00300380, + 0.00205118, + 0.00110278, + 0.00020954, + -0.00058643, + -0.00125328, + -0.00177006, + -0.00212670, + -0.00232336, + -0.00236926, + -0.00228107, + -0.00208103, + -0.00179505, + -0.00145063, + -0.00107509, + -0.00069392, + -0.00032946, + -0.00000000, + 0.00028084, + 0.00050427, + 0.00066621, + 0.00076684, + 0.00080995, + 0.00080215, + 0.00075194, + 0.00066892, + 0.00056289, + 0.00044323, + 0.00031834, + 0.00019526, + 0.00007952, + -0.00002487, + -0.00011536, + -0.00019055, + -0.00024997, + -0.00029374, + -0.00032227, + -0.00032227}; + +#endif +/*-----------------------------------------------------------------------*/ +/* End of highpass_table.h */ +/*-----------------------------------------------------------------------*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Sirtassa/Sirtassa.m Tue Sep 03 12:53:16 2013 +0100 @@ -0,0 +1,257 @@ +%% Default Values +%Audio and score information +if(~exist('midiCell','var')) + midiCell = cell(2,1); + midiCell{1} = 'Lussier_bassoon.mid'; + midiCell{2} = 'Lussier_trumpet.mid'; + mixName = 'Lussier_mix.wav'; + %mixName = '311CLNOF.WAV'; + %midiCell{1} = '311CLNOF.mid'; +end +if(~exist('blockSize','var')) blockSize = 2048; end +if(~exist('overlap','var')) overlap = 2; end +%Maximum frequency of the filter +if(~exist('bandPassFilterMaxFreq','var')) bandPassFilterMaxFreq = 10000; end +%Number of band pass filters in the filter +if(~exist('nbBandPassFilters','var')) nbBandPassFilters = 20;end +%Maximum updates per frame +if(~exist('maxUpdates','var')) maxUpdates = 2;end +%Number of partials in the model +if(~exist('nbPartials','var')) nbPartials = 8;end +if(~exist('plotRefinedScore','var')) plotRefinedScore = 0;end +if(~exist('plotPartial','var')) plotPartial = 0;end +if(~exist('plotFilter','var')) plotFilter = 0;end +%Nummber of instrument in the mix. +nbInstrument = length(midiCell); +fftSize = blockSize; + +%Weights of the harmonic series +partialsWeights = ones(nbPartials,nbInstrument); + +colors = 'rwm'; +%% Initialisation +hopSize =blockSize/overlap; %Hopsize +HFFTS = fftSize/2+1; %Size of the usefull part of the fft (half+1) +[audio, fs] = wavread(mixName); + +% zeropadding the audio length +audio(end:end+hopSize-mod(length(audio),hopSize)) = 0; +audioLength = length(audio); + +scoreLength = audioLength/hopSize - overlap+1; %Number of frames +wdw = hamming(blockSize); + +tic +%% Create filters +filterBasis = createBPFilters(bandPassFilterMaxFreq,nbBandPassFilters,fftSize,fftSize/fs); +filterCoefficients = ones(nbBandPassFilters,nbInstrument); +%% Creating the score +originalScore = createScore(scoreLength,midiCell,fs/hopSize,fftSize/fs); +originalScore(scoreLength+1:end,:) = []; +gains = double(originalScore'>0); +%% Creating spectrogram +magnitude = zeros(fftSize, scoreLength); +phase = zeros(fftSize, scoreLength); +audioVector = zeros(fftSize,1); +for curFrame = 1:scoreLength + audioVector(1:blockSize) = audio(hopSize*(curFrame-1)+1:hopSize*(curFrame-1)+blockSize,1).*wdw; + spectrogramVector = fft(audioVector); + magnitude(:,curFrame) = abs(spectrogramVector); + phase(:,curFrame) = angle(spectrogramVector); +end +magnitude(HFFTS+1:end,:) = []; +phase(HFFTS+1:end,:) = []; +maxSizeWindows = 400; +hammingWindows = cell(1,maxSizeWindows); +for len = 1:maxSizeWindows + hammingWindows{len} = hamming(len); +end + +%% Refine Score and create Excitation Spectrum +refinedScore = originalScore; %score to be refiened +basicSpec = zeros(HFFTS, scoreLength); %Basic theoretical spectrogram +excitationSpectrums = cell(nbInstrument,scoreLength); %cell for each frame +largerES = cell(nbInstrument,scoreLength); %cell for each frame + +for ins = 1:nbInstrument %for each isntrument + for curFrame = 1: scoreLength %for each frame + excitationSpectrums{ins,curFrame} = sparse(zeros(HFFTS,nbPartials)); + largerES{ins,curFrame} = sparse(zeros(HFFTS,nbPartials)); + if(originalScore(curFrame,ins)) %if there is a note + %Refine score and creates Excitation Spectrum + [refinedScore(curFrame,ins), width] = refineScore(magnitude(:,curFrame),originalScore(curFrame,ins)); + excitationSpectrums{ins,curFrame} = sparse(createExcitationSpectrums(refinedScore(curFrame,ins),HFFTS,nbPartials,partialsWeights(:,ins),width,hammingWindows)); + largerES{ins,curFrame} = sparse(createExcitationSpectrums(refinedScore(curFrame,ins),HFFTS,nbPartials,partialsWeights(:,ins),2*width,hammingWindows)); + end + basicSpec(:,curFrame) = basicSpec(:,curFrame) + (excitationSpectrums{ins,curFrame}*partialsWeights(:,ins))*gains(ins,curFrame); %Spectrogram without update + end +end +%% Plot spectrogram and add original and refined score +if (plotRefinedScore) + figure(1),imagesc(log(10*magnitude(1:fftSize/16,:)+1)), axis xy + plotableScore = originalScore+1; + plotableScore(plotableScore==1) = 0; + hold on ,plot(plotableScore,'.k'), + + for harm = 1 : nbPartials + for ins = nbInstrument:-1:1 + plot(refinedScore(:,ins)*harm+1,['.' colors(ins)]), colorbar + end + end +end +%% Online Processing +%Values that can be changed by the model. +maskForChangeableValues = basicSpec > 10^-4; +maskedSpectrogram = magnitude.*maskForChangeableValues; +bufferSize = 100; +nextProcess = 1; +for curFrame = 1:scoreLength + if sum(refinedScore(curFrame,:),2) + UpdateGainCoefficientsOL2 + if (curFrame==nextProcess) + first = max(curFrame-bufferSize+1,1); + currentMag = magnitude(:,first:curFrame); + tmpMaskForChangeableValues = basicSpec(:,first:curFrame) > 10^-4; + tmpMaskedSpectrogram = currentMag.*tmpMaskForChangeableValues; + len = curFrame-first+1; + for nbUpdates = 1:maxUpdates %update loop + UpdatePartialCoefficientsOL + UpdateFilterCoefficientsOL + if (plotFilter) + %%%Filter + figure(4),plot(outlook(1:blockSize/8,:)), title('Filter') + end + if (plotPartial) + %%%Decay + figure(5),stem(partialsWeights), title('Partial Weights') + end + end + nextProcess = min(ceil(curFrame*1.2),scoreLength) + %bufferSize = round(max(bufferSize,curFrame*0.5)); + if (plotFilter) + %%%Filter + figure(4),plot(outlook(1:blockSize/8,:)), title('Filter') + end + if (plotPartial) + %%%Decay + figure(5),stem(partialsWeights), title('Partial Weights') + + end + end + end +end +timeV = toc; +fprintf('Time: %6.3g s, %6.2g times real time \t \n ', timeV, timeV*fs/audioLength); + + +% Remodel Spectrogram +ECA = cell(nbInstrument,1); +xHat = zeros(HFFTS,scoreLength); +for ins = 1:nbInstrument + ECA{ins} = sparse(zeros(HFFTS,scoreLength)); + for frame = 1:scoreLength + ECA{ins}(:,frame) = filterBasis * filterCoefficients(:,ins).*(largerES{ins,frame}*partialsWeights(:,ins)); + end + xHat = xHat + ECA{ins}.*repmat(gains(ins,:),HFFTS,1); +end +%% Final plot +%%%Spectrogram (comparison with basic and final) +% % bMax = max(max(log(10*basicSpec+1))); +% % xMax = max(max(log(10*xHat+1))); +% % mMax = max(max(log(10*magnitude+1))); +% % tMax = max([bMax mMax xMax]); +% % figure(3), subplot(3,1,1), imagesc(log(10*basicSpec(1:hopSize/2,:)+1)), axis xy, linkaxes, caxis([0 tMax]), colorbar, title('Basic Model') +% % subplot(3,1,2), imagesc(log(10*xHat(1:hopSize/2,:)+1)), axis xy, linkaxes, caxis([0 tMax]), colorbar, title('Optimised Spectrogram') +% % subplot(3,1,3), imagesc(log(10*magnitude(1:hopSize/2,:)+1)), axis xy, linkaxes, caxis([0 tMax]), colorbar, title('Actual Spectrogram') +% % +% % +% % %%%Filter +% % figure(4),plot(outlook(1:blockSize/8,:)), title('Filter') +% % +% % %%%Decay +% % figure(5),stem(partialsWeights), title('Partial Weights') + +%% Writing +%extraInfo = [sprintf('_%d_%d_%d_%d_%d_%d',blockSize,overlap,maxUpdates,nbPartials,nbBandPassFilters,bandPassFilterMaxFreq) specExp]; +finalScale = zeros(audioLength,1); +freq = zeros(fftSize,1); +finalAudio = cell(nbInstrument+1,1); +finalAudioMasked = cell(nbInstrument,1); + +wdw2 = hamming(fftSize); +nbMaskingTechniques = 4; +maskingCell = cell(1,nbMaskingTechniques); +maskingCell{1} = 'raw'; +maskingCell{2} = 'per'; +maskingCell{3} = 'sha'; +maskingCell{4} = '10p'; +finalMask = cell(nbInstrument,nbMaskingTechniques); %4 is the number of different masking techniques +for ins = 1:nbInstrument + finalMask{ins,1} = sparse(zeros(HFFTS,scoreLength)); + finalMask{ins,4} = sparse(zeros(HFFTS,scoreLength)); + for curFrame = 1:scoreLength + finalMask{ins,1}(:,curFrame) = filterBasis * filterCoefficients(:,ins).*(excitationSpectrums{ins,curFrame}*partialsWeights(:,ins)); + finalMask{ins,4}(:,curFrame) = filterBasis * filterCoefficients(:,ins).*(largerES{ins,curFrame}*partialsWeights(:,ins)); + end + + finalMask{ins,1} = finalMask{ins,1}.*repmat(gains(ins,:),HFFTS,1); + finalMask{ins,4} = finalMask{ins,4}.*repmat(gains(ins,:),HFFTS,1); + + % masking strategy 1 + finalMask{ins,2} = magnitude .* (finalMask{ins,4} ./ (xHat+eps)); + + % masking strategy 2 + finalMask{ins,3} = magnitude .* ( (finalMask{ins,4}+eps) ./ (xHat+eps)); + + % masking strategy 3 + finalMask{ins,4} = magnitude .* ( (finalMask{ins,4}+0.1 * eps) ./ (xHat+eps)); + + finalAudio{ins} = zeros(audioLength,1); + finalAudioMasked{ins} = zeros(audioLength,1); +end + +% sonifying the model +finalAudio{nbInstrument+1} = zeros(audioLength,1); +%Overlap and add +for curFrame = 1:scoreLength + freq(1:HFFTS) = xHat(:,curFrame).*exp(1i*phase(:,curFrame)); + freq(HFFTS+1:fftSize) = freq(HFFTS-1:-1:2); + faudio = real(ifft(freq)).*wdw2; + finalAudio{nbInstrument+1}((curFrame-1)*hopSize+1:(curFrame-1)*hopSize+fftSize,1) = finalAudio{nbInstrument+1}((curFrame-1)*hopSize+1:(curFrame-1)*hopSize+fftSize,1) + faudio; + for ins = 1:nbInstrument + freq(1:HFFTS) = finalMask{ins,1}(:,curFrame).*exp(1i*phase(:,curFrame)); + freq(HFFTS+1:fftSize) = freq(HFFTS-1:-1:2); + faudio = real(ifft(freq)).*wdw2; + finalAudio{ins}((curFrame-1)*hopSize+1:(curFrame-1)*hopSize+fftSize,1) = finalAudio{ins}((curFrame-1)*hopSize+1:(curFrame-1)*hopSize+fftSize,1) + faudio; + end + finalScale((curFrame-1)*hopSize+1:(curFrame-1)*hopSize+fftSize,1) = finalScale((curFrame-1)*hopSize+1:(curFrame-1)*hopSize+fftSize,1) + wdw2; +end + +for ins = 1:nbInstrument + finalAudio{ins} = finalAudio{ins}./finalScale; + % wavwrite(finalAudio{ins},fs,16,[midiCell{ins}(1:4) '_' num2str(ins) '_' maskingCell{1} extraInfo '.wav']); +end +finalAudio{nbInstrument+1} = finalAudio{nbInstrument+1}./finalScale; +%wavwrite(finalAudio{nbInstrument+1},fs,16,[mixName(1:4) '_0_' maskingCell{1} extraInfo '.wav']); + +% sonifying the masked version +%Overlap and add +for tech = 2:nbMaskingTechniques + finalScale = zeros(audioLength,1); + for curFrame = 1:scoreLength + for ins = 1:nbInstrument + freq(1:HFFTS) = finalMask{ins,tech}(:,curFrame).*exp(i*phase(:,curFrame)); + freq(HFFTS+1:fftSize) = freq(HFFTS-1:-1:2); + faudio = real(ifft(freq)).*wdw2; + finalAudioMasked{ins}((curFrame-1)*hopSize+1:(curFrame-1)*hopSize+fftSize,1) = finalAudioMasked{ins}((curFrame-1)*hopSize+1:(curFrame-1)*hopSize+fftSize,1) + faudio; + end + finalScale((curFrame-1)*hopSize+1:(curFrame-1)*hopSize+fftSize,1) = finalScale((curFrame-1)*hopSize+1:(curFrame-1)*hopSize+fftSize,1) + wdw2; + end + for ins = 1:nbInstrument + finalAudioMasked{ins} = finalAudioMasked{ins}./finalScale; + % wavwrite(finalAudioMasked{ins},fs,16,[midiCell{ins}(1:4) '_' num2str(ins) '_' maskingCell{tech} extraInfo '.wav']); + end +end + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Sirtassa/UpdateFilterCoefficientsOL.m Tue Sep 03 12:53:16 2013 +0100 @@ -0,0 +1,36 @@ +GEA = cell(nbInstrument,nbBandPassFilters); + + +xHat = sparse(zeros(HFFTS,len)); + +% Model Spectrogram +for ins = 1:nbInstrument + for filterInd = 1:nbBandPassFilters + GEA{ins,filterInd} = sparse(zeros(HFFTS, len)); + for frame = first:curFrame + GEA{ins,filterInd}(:,frame-first+1) = (filterBasis(:,filterInd)*gains(ins,frame)).*(excitationSpectrums{ins,frame}*partialsWeights(:,ins)); + end + xHat = xHat + GEA{ins,filterInd}*filterCoefficients(filterInd,ins); + end +end + +%Compute distance and r +distFilter(nbUpdates) = sum(sum( tmpMaskedSpectrogram .* log((tmpMaskedSpectrogram+eps) ./ (xHat+eps)) - tmpMaskedSpectrogram + xHat)); +r = (currentMag+eps)./(xHat+eps); +updateFilterCoeff = ones(nbBandPassFilters,nbInstrument); + +%Update Filter Coefficients +for ins = 1:nbInstrument + for filterInd = 1:nbBandPassFilters + updateFilterCoeff(filterInd,ins) = (sum(sum(GEA{ins,filterInd}.*r))+eps)/(sum(sum(GEA{ins,filterInd}))+eps); + end +end +clear GEA; +filterCoefficients = filterCoefficients.*updateFilterCoeff; +for ins=1:nbInstrument + maxValue = max(filterCoefficients(:,ins)); + filterCoefficients(:,ins) = filterCoefficients(:,ins) / maxValue; + gains(ins,:) = gains(ins,:) * maxValue; +end +outlook = filterBasis * filterCoefficients; +% figure, plot(outlook(1:blockSize/8,:)); \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Sirtassa/UpdateGainCoefficientsOL2.m Tue Sep 03 12:53:16 2013 +0100 @@ -0,0 +1,22 @@ +ECA = zeros(HFFTS,nbInstrument); + +for ins = 1:nbInstrument + ECA(:,ins) = filterBasis * filterCoefficients(:,ins).*(excitationSpectrums{ins,curFrame}*partialsWeights(:,ins)); +end + +xHat = sum(ECA.*repmat(gains(:,curFrame)',HFFTS,1),2); + +maskedSpectrogram = magnitude(:,curFrame).* basicSpec(:,curFrame) > 10^-4; + + +%Compute distance and r +distGain = sum(sum( maskedSpectrogram .* log((maskedSpectrogram+eps) ./ (xHat+eps)) - maskedSpectrogram + xHat)); +r = (magnitude(:,curFrame)+eps)./(xHat+eps); + +%Update Gain Coefficients +updateGainsCoeff = sum(ECA.*repmat(r,1,nbInstrument) +eps,1)./sum(ECA +eps,1); + +clear ECA; +gains(:,curFrame) = gains(:,curFrame).*updateGainsCoeff'; + +% figure;plot(gains'); \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Sirtassa/UpdatePartialCoefficientsOL.m Tue Sep 03 12:53:16 2013 +0100 @@ -0,0 +1,33 @@ +GEH = cell(nbInstrument,nbPartials); + +% Remodel Spectrogram +xHat = zeros(HFFTS,len); +for ins = 1:nbInstrument + for harm = 1:nbPartials + GEH{ins,harm} = sparse(zeros(HFFTS, len)); + for frame = first:curFrame + GEH{ins,harm}(:,frame-first+1) = (filterBasis * filterCoefficients(:,ins)*gains(ins,frame)).*excitationSpectrums{ins,frame}(:,harm); + end + xHat = xHat + GEH{ins,harm}*partialsWeights(harm,ins); + end +end + +%Compute distance and r +distPartial(nbUpdates) = sum(sum( tmpMaskedSpectrogram .* log((tmpMaskedSpectrogram+eps) ./ (xHat+eps)) - tmpMaskedSpectrogram + xHat)); +r = (currentMag+eps)./(xHat+eps); + +%Update partialsWeights +updateGammaCoeff = ones(nbPartials,nbInstrument); +for ins=1:nbInstrument + for harm = 1:nbPartials + updateGammaCoeff(harm,ins) = sum(sum(GEH{ins,harm}.*r +eps,1))./sum(sum(GEH{ins,harm} +eps,1)); + end +end +clear GEH +partialsWeights = partialsWeights.*updateGammaCoeff; +for ins=1:nbInstrument + maxValue = max(partialsWeights(:,ins)); + partialsWeights(:,ins) = partialsWeights(:,ins) / maxValue; + gains(ins,:) = gains(ins,:) * maxValue; +end +% figure;stem(partialsWeights), title(sprintf('Partial Weights (iter%d)',nbUpdates));
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Sirtassa/createBPFilters.m Tue Sep 03 12:53:16 2013 +0100 @@ -0,0 +1,23 @@ +function filterBasis = createBPFilters(maxFreq,nbBandPassFilters,fftSize,factor) +melfreq = linspace(0,2595*log10(1 + maxFreq/700),nbBandPassFilters); +hertzfreq = 700*(10.^(melfreq/2595)-1); + +filterBasis = zeros(fftSize/2+1,nbBandPassFilters); +mid = floor(hertzfreq(1)*factor+1); +last = floor(hertzfreq(2)*factor+1); +if (mid~=last) + + filterBasis(mid:last,1) = 1:-1/(last-mid):0; + for ind = 1:length(hertzfreq) -2 + first = floor(hertzfreq(ind)*factor+1); + mid = floor(hertzfreq(ind+1)*factor+1); + last = floor(hertzfreq(ind +2)*factor+1); + filterBasis(first:mid,ind+1) = 0:1/(mid-first):1; + filterBasis(mid:last,ind+1) = 1:-1/(last-mid):0; + end + first = floor(hertzfreq(end-1)*factor+1); + mid = floor(hertzfreq(end)*factor+1); + filterBasis(first:mid,end) = 0:1/(mid-first):1; +% else +% error('myApp:filterSize', 'Too many filters for parameters') +end \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Sirtassa/createExcitationSpectrums.m Tue Sep 03 12:53:16 2013 +0100 @@ -0,0 +1,16 @@ +function spec = createExcitationSpectrums(pitch,size,nbPartials,partialsWeights,dif,hammingWindows) +spec = zeros(size,nbPartials); +if (pitch) + for harm = 1:nbPartials + freq =pitch*harm+1; + low = floor(freq-dif/2); + low = max(low,1); + high = ceil(freq+dif/2); + len = high-low+1; + + spec(low:high,harm) = hammingWindows{len}*partialsWeights(harm); + spec(low:high,harm) = spec(low:high,harm)/max(spec(low:high,harm)); + end +end +spec(size+1:end,:)=[]; +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Sirtassa/createScore.m Tue Sep 03 12:53:16 2013 +0100 @@ -0,0 +1,21 @@ +function score = createScore(scoreLength,MIDI,timeFactor,freqFactor) + +nbInstrument = length(MIDI); +instruments = cell(nbInstrument,1); +for ins = 1:nbInstrument + instruments{ins} = midi2nmat( MIDI{ins}); +end +%Score frame by frame +score = zeros(scoreLength,nbInstrument); + +% instrument : onset, offset, frequency +for ins = 1:nbInstrument + + instruments{ins}(:,1) = max(1,round(instruments{ins}(:,6)*timeFactor)-1); + instruments{ins}(:,2) = round((instruments{ins}(:,6) + instruments{ins}(:,7))*timeFactor); + instruments{ins}(:,3) = 440/32*2.^((instruments{ins}(:,4)-9)/12); + instruments{ins}(:,4:end) = []; + for j = 1: size(instruments{ins},1) + score(instruments{ins}(j,1):instruments{ins}(j,2),ins) = instruments{ins}(j,3)*freqFactor; + end +end \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Sirtassa/midi2nmat.m Tue Sep 03 12:53:16 2013 +0100 @@ -0,0 +1,999 @@ +function [nmat,n] = midi2nmat(filename) +% nmat = midi2nmat(filename) +% Read midi file FILENAME into Matlab variable NMAT (Beta) +% Based on Ken Schutte's m-files (readmidi, midiInfo, getTempoChanges) +% This beta might replace the mex-files used in the previous version of the toolbox as +% newer versions of Matlab (7.4+) and various OS's need new compilations +% of the mex files. Using the C sources and the compiled mex files provides +% faster reading of midi files but because the compatibility is limited, this +% simple workaround is offered. This beta version is very primitive, +% though. - Tuomas Eerola +% +% KNOWN PROBLEMS: - Tempo changes are handled in a simple way +% - Extra messages are not retained +% - Channels may not be handled correctly +% +% For more information on Ken Schutte's functions, see +% http://www.kenschutte.com/software +% +% CREATED ON 31.12.2007 BY TE (MATLAB 7.4 MacOSX 10.4) +% + +%% USE KEN SCHUTTE'S FUNCTIONS +m = readmidi(filename); +n = midiInfo(m,0); +[tempos, tempos_time] = getTempoChanges(m); + +%% CONVERT OUTPUT INTO MIDI TOOLBOX NMAT FORMAT +nmat(:,6) = n(:,5); +nmat(:,7) = n(:,6)-n(:,5); % duration +nmat(:,3) = n(:,2); +nmat(:,4) = n(:,3); +nmat(:,5) = n(:,4); + +%% CHECK IF MULTIPLE TEMPI +if isempty(tempos), tempos=500000;end % some files may not contain the tempo, use default in that case +if length(tempos)>1 + % here for diff tempi.... + + disp('WARNING: Multiple tempi detected, simple recoding of timing (seconds, not beats!)'); + disp(num2str(60./(tempos./1000000))) + + + tc_ind=0; + starttime=0; + for i=1:length(tempos_time)-1 + tempo_begin = (tempos_time(i+1)-tempos_time(i))/m.ticks_per_quarter_note*tempos(i)/1000000; + tempo_begin = tempo_begin+starttime; + starttime = tempo_begin; + tc_ind=[tc_ind tempo_begin]; + end + nmat2=nmat; + for i=1:length(tc_ind) + if i==length(tc_ind) + time_index = nmat(:,6)>=tc_ind(i); + else + time_index = nmat(:,6)>=tc_ind(i); %& nmat(:,6)<=tc_ind(i+1); + end + + timeratio = tempos(i)/tempos(1); + +% realign timing after tempo changes + tmp1 = nmat2(time_index,:); + tmp2 = n(time_index,5).*timeratio; tmp2=tmp2(1); + realign = tmp1(1,6)-tmp2; % previous onset time + nmat2(time_index,6) = (n(time_index,5).*timeratio)+realign; + nmat2(time_index,7) = nmat2(time_index,7).*timeratio; + end + nmat(:,1) = n(:,5)/(tempos(1)/1000000); % beats are not modified according to tempi + nmat(:,2) = (n(:,6)-n(:,5))/(tempos(1)/1000000); + +else + nmat(:,1) = n(:,5)/(tempos(1)/1000000); + nmat(:,2) = (n(:,6)-n(:,5))/(tempos(1)/1000000); +end + +% postprocessing... + +% IF CHANNEL IS EMPTY + +if nmat(:,3)==0 + nmat(:,3)=1; +end + +%% FUNCTIONS + + +function [Notes,endtime] = midiInfo(midi,outputFormat,tracklist) +% [Notes,endtime] = midiInfo(midi,outputFormat,tracklist) +% +% Takes a midi structre and generates info on notes and messages +% Can return a matrix of note parameters and/or output/display +% formatted table of messages +% +% Inputs: +% midi - Matlab structure (created by readmidi.m) +% tracklist - which tracks to show ([] for all) +% outputFormat +% - if it's a string write the formated output to the file +% - if 0, don't display or write formatted output +% - if 1, just display (default) +% +% outputs: +% Notes - a matrix containing a list of notes, ordered by start time +% column values are: +% 1 2 3 4 5 6 7 8 +% [track chan nn vel t1 t2 msgNum1 msgNum2] +% endtime - time of end of track message +% +%--------------------------------------------------------------- +% Subversion Revision: 14 (2006-11-28) +% minor alterations by TE 2.1.2008 +% This software can be used freely for non-commerical use. +% Visit http://www.kenschutte.com/software for more +% documentation, copyright info, and updates. +%--------------------------------------------------------------- + + +if nargin<3 + tracklist=[]; + if nargin<2 + outputFormat=1; + end +end +if (isempty(tracklist)) + tracklist = 1:length(midi.track); +end + +[tempos, tempos_time] = getTempoChanges(midi); + +current_tempo = 500000; % default tempo + +fid = -1; +if (ischar(outputFormat)) + fid = fopen(outputFormat,'w'); +end + +endtime = -1; + +% each row: +% 1 2 3 4 5 6 7 8 +% [track chan nn vel t1 t2 msgNum1 msgNum2] +Notes = zeros(0,8); + +for i=1:length(tracklist) + tracknum = tracklist(i); + cumtime=0; + seconds=0; + + Msg = cell(0); + Msg{1,1} = 'chan'; + Msg{1,2} = 'deltatime'; + Msg{1,3} = 'time'; + Msg{1,4} = 'name'; + Msg{1,5} = 'data'; + + runnro=1; + + for msgNum=1:length(midi.track(tracknum).messages) + + currMsg = midi.track(tracknum).messages(msgNum); + + midimeta = currMsg.midimeta; + deltatime = currMsg.deltatime; + data = currMsg.data; + type = currMsg.type; + chan = currMsg.chan; + + cumtime = cumtime + deltatime; + %current_tempo/midi.ticks_per_quarter_note; + %debug = deltatime*1e-6*current_tempo/midi.ticks_per_quarter_note; + + seconds = seconds + deltatime*1e-6*current_tempo/midi.ticks_per_quarter_note; + [mx ind] = max(find(cumtime >= tempos_time)); + + %% % ADDED BY TE 1.1.2008 + if isempty(ind) + % do nothing + else + current_tempo = tempos(ind); + end + %% end + + % find start/stop of notes: + % if (strcmp(name,'Note on') && (data(2)>0)) + % note on with vel>0: + if (midimeta==1 && type==144 && data(2)>0) + % note on: + + if isempty(Notes) + Notes(1,:) = [tracknum chan data(1) data(2) seconds 0 runnro -1]; + runnro=runnro+1; + else +% Notes(end+1,:) = [tracknum chan data(1) data(2) seconds 0 msgNum -1] + Notes(end+1,:) = [tracknum chan data(1) data(2) seconds 0 runnro -1]; + runnro=runnro+1; + end + % elseif ((strcmp(name,'Note on') && (data(2)==0)) || strcmp(name,'Note off')) + % note on with vel==0 or note off: + + elseif (midimeta==1 && ( (type==144 && data(2)==0) || type==128 )) + + % note off: + % % find index, wther tr,chan,and nn match, and not complete + + ind = find((... + (Notes(:,1)==tracknum) + ... + (Notes(:,2)==chan) + ... + (Notes(:,3)==data(1)) + ... + (Notes(:,8)==-1)... + )==4); + + if (length(ind)==0) + error('ending non-open note?'); + elseif (length(ind)>1) + disp('warning: found multiple matches in endNote, taking first...'); + ind = ind(1); + end + + % set info on ending: + Notes(ind,6) = seconds; + Notes(ind,8) = msgNum; + + % end of track: + elseif (midimeta==0 && type==47) + if (endtime == -1) + endtime = seconds; + else + disp('two "end of track" messages?'); + endtime(end+1) = seconds; + end + + + end + + % we could check to make sure it ends with + % 'end of track' + + + if (outputFormat ~= 0) + % get some specific descriptions: + name = num2str(type); + dataStr = num2str(data); + + if (isempty(chan)) + Msg{msgNum,1} = '-'; + else + Msg{msgNum,1} = num2str(chan); + end + + Msg{msgNum,2} = num2str(deltatime); + Msg{msgNum,3} = formatTime(seconds); + + if (midimeta==0) + Msg{msgNum,4} = 'meta'; + else + Msg{msgNum,4} = ''; + end + + [name,dataStr] = getMsgInfo(midimeta, type, data); + Msg{msgNum,5} = name; + Msg{msgNum,6} = dataStr; + end + + + end + + if (outputFormat ~= 0) + printTrackInfo(Msg,tracknum,fid); + end + +end + +% make this an option!!! +% - I'm not sure why it's needed... +% remove start silence: + +%_ removed by TE +%_first_t = min(Notes(:,5)); +%_Notes(:,5) = Notes(:,5) - first_t; +%_Notes(:,6) = Notes(:,6) - first_t; + +% sort Notes by start time: +[junk,ord] = sort(Notes(:,5)); +Notes = Notes(ord,:); + + +if (fid ~= -1) + fclose(fid); +end + + + + + + + + + + + +function printTrackInfo(Msg,tracknum,fid) + + +% make cols same length instead of just using \t +for i=1:size(Msg,2) + maxLen(i)=0; + for j=1:size(Msg,1) + if (length(Msg{j,i})>maxLen(i)) + maxLen(i) = length(Msg{j,i}); + end + end +end + + +s=''; +s=[s sprintf('--------------------------------------------------\n')]; +s=[s sprintf('Track %d\n',tracknum)]; +s=[s sprintf('--------------------------------------------------\n')]; + +if (fid == -1) + disp(s) +else + fprintf(fid,'%s',s); +end + + +for i=1:size(Msg,1) + line=''; + for j=1:size(Msg,2) + sp = repmat(' ',1,5+maxLen(j)-length(Msg{i,j})); + m = Msg{i,j}; + m = m(:)'; % ensure column vector +% line = [line Msg{i,j} sp]; + line = [line m sp]; + end + + if (fid == -1) + disp(line) + else + fprintf(fid,'%s\n',line); + end + +end + + + +function s=formatTime(seconds) + +minutes = floor(seconds/60); +secs = seconds - 60*minutes; + +s = sprintf('%d:%2.3f',minutes,secs); + + + +function [name,dataStr]=getMsgInfo(midimeta, type, data) + +% meta events: +if (midimeta==0) + if (type==0); name = 'Sequence Number'; len=2; dataStr = num2str(data); + elseif (type==1); name = 'Text Events'; len=-1; dataStr = char(data); + elseif (type==2); name = 'Copyright Notice'; len=-1; dataStr = char(data); + elseif (type==3); name = 'Sequence/Track Name'; len=-1; dataStr = char(data); + elseif (type==4); name = 'Instrument Name'; len=-1; dataStr = char(data); + elseif (type==5); name = 'Lyric'; len=-1; dataStr = char(data); + elseif (type==6); name = 'Marker'; len=-1; dataStr = char(data); + elseif (type==7); name = 'Cue Point'; len=-1; dataStr = char(data); + elseif (type==32); name = 'MIDI Channel Prefix'; len=1; dataStr = num2str(data); + elseif (type==47); name = 'End of Track'; len=0; dataStr = ''; + elseif (type==81); name = 'Set Tempo'; len=3; + val = data(1)*16^4+data(2)*16^2+data(3); dataStr = ['microsec per quarter note: ' num2str(val)]; + elseif (type==84); name = 'SMPTE Offset'; len=5; + if size(data)==5 + dataStr = ['[hh mm ss fr ff]=' num2str(data)]; + else + dataStr = ['[hh mm ss fr ff]=' num2str(data')]; + end + elseif (type==88); name = 'Time Signature'; len=4; + dataStr = [num2str(data(1)) '/' num2str(data(2)) ', clock ticks and notated 32nd notes=' num2str(data(3)) '/' num2str(data(4))]; + elseif (type==89); name = 'Key Signature'; len=2; + % num sharps/flats (flats negative) + if (data(1)>=0) + % 1 2 3 4 5 6 7 + ss={'C','G','D', 'A', 'E','B', 'F#', 'C#'}; + if data(1)>7 + dataStr='C'; % ADDED BY TE 1.1.2008 + else + dataStr = ss{data(1)+1}; + end + + else + % 1 2 3 4 5 6 7 + ss={'F','Bb','Eb','Ab','Db','Gb','Cb'}; + dataStr = ss{abs(data(1))}; + end + if (data(2)==0) + dataStr = [dataStr ' Major']; + else + dataStr = [dataStr ' Minor']; + end + + elseif (type==89); name = 'Sequencer-Specific Meta-event'; len=-1; + dataStr = char(data); + % !! last two conflict... + + else + name = ['UNKNOWN META EVENT: ' num2str(type)]; dataStr = num2str(data); + end + +% meta 0x21 = MIDI port number, length 1 (? perhaps) +else + + % channel voice messages: + % (from event byte with chan removed, eg 0x8n -> 0x80 = 128 for + % note off) + if (type==128); name = 'Note off'; len=2; dataStr = ['nn=' num2str(data(1)) ' vel=' num2str(data(2))]; + elseif (type==144); name = 'Note on'; len=2; dataStr = ['nn=' num2str(data(1)) ' vel=' num2str(data(2))]; + elseif (type==160); name = 'Polyphonic Key Pressure'; len=2; dataStr = ['nn=' num2str(data(1)) ' vel=' num2str(data(2))]; + elseif (type==176); name = 'Controller Change'; len=2; dataStr = ['ctrl=' controllers(data(1)) ' value=' num2str(data(2))]; + elseif (type==192); name = 'Program Change'; len=1; dataStr = ['instr=' num2str(data)]; + elseif (type==208); name = 'Channel Key Pressure'; len=1; dataStr = ['vel=' num2str(data)]; + elseif (type==224); name = 'Pitch Bend'; len=2; + val = data(1)+data(2)*256; + val = base2dec('2000',16) - val; + dataStr = ['change=' num2str(val) '?']; + + % channel mode messages: + % ... unsure about data for these... (do some have a data byte and + % others not?) + % + % 0xC1 .. 0xC8 + elseif (type==193); name = 'All Sounds Off'; dataStr = num2str(data); + elseif (type==194); name = 'Reset All Controllers'; dataStr = num2str(data); + elseif (type==195); name = 'Local Control'; dataStr = num2str(data); + elseif (type==196); name = 'All Notes Off'; dataStr = num2str(data); + elseif (type==197); name = 'Omni Mode Off'; dataStr = num2str(data); + elseif (type==198); name = 'Omni Mode On'; dataStr = num2str(data); + elseif (type==199); name = 'Mono Mode On'; dataStr = num2str(data); + elseif (type==200); name = 'Poly Mode On'; dataStr = num2str(data); + + % sysex, F0->F7 + elseif (type==240); name = 'Sysex 0xF0'; dataStr = num2str(data); + elseif (type==241); name = 'Sysex 0xF1'; dataStr = num2str(data); + elseif (type==242); name = 'Sysex 0xF2'; dataStr = num2str(data); + elseif (type==243); name = 'Sysex 0xF3'; dataStr = num2str(data); + elseif (type==244); name = 'Sysex 0xF4'; dataStr = num2str(data); + elseif (type==245); name = 'Sysex 0xF5'; dataStr = num2str(data); + elseif (type==246); name = 'Sysex 0xF6'; dataStr = num2str(data); + elseif (type==247); name = 'Sysex 0xF7'; dataStr = num2str(data); + + % realtime + % (i think have no data..?) + elseif (type==248); name = 'Real-time 0xF8 - Timing clock'; dataStr = num2str(data); + elseif (type==249); name = 'Real-time 0xF9'; dataStr = num2str(data); + elseif (type==250); name = 'Real-time 0xFA - Start a sequence'; dataStr = num2str(data); + elseif (type==251); name = 'Real-time 0xFB - Continue a sequence'; dataStr = num2str(data); + elseif (type==252); name = 'Real-time 0xFC - Stop a sequence'; dataStr = num2str(data); + elseif (type==253); name = 'Real-time 0xFD'; dataStr = num2str(data); + elseif (type==254); name = 'Real-time 0xFE'; dataStr = num2str(data); + elseif (type==255); name = 'Real-time 0xFF'; dataStr = num2str(data); + + + else + name = ['UNKNOWN MIDI EVENT: ' num2str(type)]; dataStr = num2str(data); + end + + +end + +function s=controllers(n) +if (n==1); s='Mod Wheel'; +elseif (n==2); s='Breath Controllery'; +elseif (n==4); s='Foot Controller'; +elseif (n==5); s='Portamento Time'; +elseif (n==6); s='Data Entry MSB'; +elseif (n==7); s='Volume'; +elseif (n==8); s='Balance'; +elseif (n==10); s='Pan'; +elseif (n==11); s='Expression Controller'; +elseif (n==16); s='General Purpose 1'; +elseif (n==17); s='General Purpose 2'; +elseif (n==18); s='General Purpose 3'; +elseif (n==19); s='General Purpose 4'; +elseif (n==64); s='Sustain'; +elseif (n==65); s='Portamento'; +elseif (n==66); s='Sustenuto'; +elseif (n==67); s='Soft Pedal'; +elseif (n==69); s='Hold 2'; +elseif (n==80); s='General Purpose 5'; +elseif (n==81); s='Temp Change (General Purpose 6)'; +elseif (n==82); s='General Purpose 7'; +elseif (n==83); s='General Purpose 8'; +elseif (n==91); s='Ext Effects Depth'; +elseif (n==92); s='Tremelo Depthy'; +elseif (n==93); s='Chorus Depth'; +elseif (n==94); s='Detune Depth (Celeste Depth)'; +elseif (n==95); s='Phaser Depth'; +elseif (n==96); s='Data Increment (Data Entry +1)'; +elseif (n==97); s='Data Decrement (Data Entry -1)'; +elseif (n==98); s='Non-Registered Param LSB'; +elseif (n==99); s='Non-Registered Param MSB'; +elseif (n==100); s='Registered Param LSB'; +elseif (n==101); s='Registered Param MSB'; +else + s='UNKNOWN CONTROLLER'; +end + +%Channel mode message values +%Reset All Controllers 79 121 Val ?? +%Local Control 7A 122 Val 0 = off, 7F (127) = on +%All Notes Off 7B 123 Val must be 0 +%Omni Mode Off 7C 124 Val must be 0 +%Omni Mode On 7D 125 Val must be 0 +%Mono Mode On 7E 126 Val = # of channels, or 0 if # channels equals # voices in receiver +%Poly Mode On 7F 127 Val must be 0 + + +function [tempos,tempos_time]=getTempoChanges(midi) +% [tempos,tempos_time]=getTempoChanges(midi) +% +% input: a midi struct from readmidi.m +% output: +% tempos = tempo values indexed by tempos_time +% tempos_time is in units of ticks +% +% should tempo changes effect across tracks? across channels? +% +%--------------------------------------------------------------- +% Subversion Revision: 14 (2006-01-24) +% +% This software can be used freely for non-commerical use. +% Visit http://www.kenschutte.com/software for more +% documentation, copyright info, and updates. +%--------------------------------------------------------------- + + +tempos = []; +tempos_time = []; +%tempos_index = []; +for i=1:length(midi.track) + cumtime=0; + for j=1:length(midi.track(i).messages) + cumtime = cumtime+midi.track(i).messages(j).deltatime; +% if (strcmp(midi.track(i).messages(j).name,'Set Tempo')) + if (midi.track(i).messages(j).midimeta==0 && midi.track(i).messages(j).type==81) + + tempos_time(end+1) = cumtime; + d = midi.track(i).messages(j).data; + tempos(end+1) = d(1)*16^4 + d(2)*16^2 + d(3); + end + end +end + + +function midi = readmidi(filename, rawbytes) +% midi = readmidi(filename, rawbytes) +% midi = readmidi(filename) +% +% Read MIDI file and store in a Matlab structure +% (use midiInfo.m to see structure detail) +% +% Inputs: +% filename - input MIDI file +% rawbytes - 0 or 1: Include raw bytes in structure +% This info is redundant, but can be +% useful for debugging. default=0 +% +%--------------------------------------------------------------- +% Subversion Revision: 14 (2006-12-03) +% +% This software can be used freely for non-commerical use. +% Visit http://www.kenschutte.com/software for more +% documentation, copyright info, and updates. +%--------------------------------------------------------------- + + + +if (nargin<2) + rawbytes=0; +end + +fid = fopen(filename); +%[A count] = fread(fid,'char'); +[A count] = fread(fid,'uint8'); +fclose(fid); + +midi.filename = filename; +if (rawbytes) midi.rawbytes_all = A; end + + +% realtime events: status: [F8, FF]. no data bytes +%clock, undefined, start, continue, stop, undefined, active +%sensing, systerm reset + +% file consists of "header chunk" and "track chunks" +% 4B 'MThd' (header) or 'MTrk' (track) +% 4B 32-bit unsigned int = number of bytes in chunk, not +% counting these first 8 + + +% HEADER CHUNK -------------------------------------------------------- +% 4B 'Mthd' +% 4B length +% 2B file format +% 0=single track, 1=multitrack synchronous, 2=multitrack asynchronous +% Synchronous formats start all tracks at the same time, while asynchronous formats can start and end any track at any time during the score. +% 2B track cout (must be 1 for format 0) +% 2B num delta-time ticks per quarter note +% + +if ~isequal(A(1:4)',[77 84 104 100]) % double('MThd') + error('File does not begin with header ID (MThd)'); +end + +header_len = decode_int(A(5:8)); +if (header_len == 6) +else + error('Header length != 6 bytes.'); +end + +format = decode_int(A(9:10)); +if (format==0 || format==1 || format==2) + midi.format = format; +else + error('Format does not equal 0,1,or 2'); +end + +num_tracks = decode_int(A(11:12)); +if (format==0 && num_tracks~=1) + error('File is format 0, but num_tracks != 1'); +end + +time_unit = decode_int(A(13:14)); +if (bitand(time_unit,2^15)==0) + midi.ticks_per_quarter_note = time_unit; +else + error('Header: SMPTE time format found - not currently supported'); +end + +if (rawbytes), midi.rawbytes_header = A(1:14); end + +% end header parse ---------------------------------------------------- + + + + + + +% BREAK INTO SEPARATE TRACKS ------------------------------------------ +% midi.track(1).data = [byte byte byte ...]; +% midi.track(2).date = ... +% ... +% +% Track Chunks--------- +% 4B 'MTrk' +% 4B length (after first 8B) +% +ctr = 15; +for i=1:num_tracks + + if ~isequal(A(ctr:ctr+3)',[77 84 114 107]) % double('MTrk') + error(['Track ' num2str(i) ' does not begin with track ID=MTrk']); + end + ctr = ctr+4; + + track_len = decode_int(A(ctr:ctr+3)); + ctr = ctr+4; + + % have track.rawbytes hold initial 8B also... + track_rawbytes{i} = A((ctr-8):(ctr+track_len-1)); + + if (rawbytes) + midi.track(i).rawbytes_header = A(ctr-8:ctr-1); + end + + ctr = ctr+track_len; +end +% ---------------------------------------------------------------------- + + + + + + +% Events: +% - meta events: start with 'FF' +% - MIDI events: all others + +% MIDI events: +% optional command byte + 0,1,or 2 bytes of parameters +% "running mode": command byte omitted. +% +% all midi command bytes have MSB=1 +% all data for inside midi command have value <= 127 (ie MSB=0) +% -> so can determine running mode +% +% meta events' data may have any values (meta events have to set +% len) +% + + + +% 'Fn' MIDI commands: +% no chan. control the entire system +%F8 Timing Clock +%FA start a sequence +%FB continue a sequence +%FC stop a sequence + +% Meta events: +% 1B 0xFF +% 1B event type +% 1B length of additional data +% ?? additional data +% + + +% "channel mode messages" +% have same code as "control change": 0xBn +% but uses reserved controller numbers 120-127 +% + + +%Midi events consist of an optional command byte +% followed by zero, one or two bytes of parameters. +% In running mode, the command can be omitted, in +% which case the last MIDI command specified is +% assumed. The first bit of a command byte is 1, +% while the first bit of a parameter is always 0. +% In addition, the last 4 bits of a command +% indicate the channel to which the event should +% be sent; therefore, there are 6 possible +% commands (really 7, but we will discuss the x'Fn' +% commands later) that can be specified. They are: + + +% parse tracks ----------------------------------------- +for i=1:num_tracks + + track = track_rawbytes{i}; + + if (rawbytes); midi.track(i).rawbytes = track; end + + msgCtr = 1; + ctr=9; % first 8B were MTrk and length + while (ctr < length(track_rawbytes{i})) + + clear currMsg; + currMsg.used_running_mode = 0; + % note: + % .used_running_mode is necessary only to + % be able to reconstruct a file _exactly_ from + % the 'midi' structure. this is helpful for + % debugging since write(read(filename)) can be + % tested for exact replication... + % + + ctr_start_msg = ctr; + + [deltatime,ctr] = decode_var_length(track, ctr); + + % ? + %if (rawbytes) + % currMsg.rawbytes_deltatime = track(ctr_start_msg:ctr-1); + %end + + % deltaime must be 1-4 bytes long. + % could check here... + + + % CHECK FOR META EVENTS ------------------------ + % 'FF' + if track(ctr)==255 + + type = track(ctr+1); + + ctr = ctr+2; + + % get variable length 'length' field + [len,ctr] = decode_var_length(track, ctr); + + % note: some meta events have pre-determined lengths... + % we could try verifiying they are correct here. + + thedata = track(ctr:ctr+len-1); + chan = []; + + ctr = ctr + len; + + midimeta = 0; + + else + midimeta = 1; + % MIDI EVENT --------------------------- + + + + + % check for running mode: + if (track(ctr)<128) + + % make it re-do last command: + %ctr = ctr - 1; + %track(ctr) = last_byte; + currMsg.used_running_mode = 1; + + B = last_byte; + nB = track(ctr); % ? + + else + + B = track(ctr); + nB = track(ctr+1); + + ctr = ctr + 1; + + end + + % nibbles: + %B = track(ctr); + %nB = track(ctr+1); + + + Hn = bitshift(B,-4); + Ln = bitand(B,15); + + chan = []; + + msg_type = midi_msg_type(B,nB); + + % DEBUG: + if (i==2) + if (msgCtr==1) + disp(msg_type); + end + end + + + switch msg_type + + case 'channel_mode' + + % UNSURE: if all channel mode messages have 2 data byes (?) + type = bitshift(Hn,4) + (nB-120+1); + thedata = track(ctr:ctr+1); + chan = Ln; + + ctr = ctr + 2; + + % ---- channel voice messages: + case 'channel_voice' + + type = bitshift(Hn,4); + len = channel_voice_msg_len(type); % var length data: + thedata = track(ctr:ctr+len-1); + chan = Ln; + + % DEBUG: + if (i==2) + if (msgCtr==1) + disp([999 Hn type]) + end + end + + ctr = ctr + len; + + case 'sysex' + + % UNSURE: do sysex events (F0-F7) have + % variable length 'length' field? + + [len,ctr] = decode_var_length(track, ctr); + + type = B; + thedata = track(ctr:ctr+len-1); + chan = []; + + ctr = ctr + len; + + case 'sys_realtime' + + % UNSURE: I think these are all just one byte + type = B; + thedata = []; + chan = []; + + end + + last_byte = Ln + bitshift(Hn,4); + + end % end midi event 'if' + + + currMsg.deltatime = deltatime; + currMsg.midimeta = midimeta; + currMsg.type = type; + currMsg.data = thedata; + currMsg.chan = chan; + + if (rawbytes) + currMsg.rawbytes = track(ctr_start_msg:ctr-1); + end + + midi.track(i).messages(msgCtr) = currMsg; + msgCtr = msgCtr + 1; + + + end % end loop over rawbytes +end % end loop over tracks + + +function val=decode_int(A) + +val = 0; +for i=1:length(A) + val = val + bitshift(A(length(A)-i+1), 8*(i-1)); +end + + +function len=channel_voice_msg_len(type) + +if (type==128); len=2; +elseif (type==144); len=2; +elseif (type==160); len=2; +elseif (type==176); len=2; +elseif (type==192); len=1; +elseif (type==208); len=1; +elseif (type==224); len=2; +else + disp(type); error('bad channel voice message type'); +end + + +% +% decode variable length field (often deltatime) +% +% return value and new position of pointer into 'bytes' +% +function [val,ptr] = decode_var_length(bytes, ptr) + +keepgoing=1; +binarystring = ''; +while (keepgoing) + % check MSB: + % if MSB=1, then delta-time continues into next byte... + if(~bitand(bytes(ptr),128)) + keepgoing=0; + end + % keep appending last 7 bits from each byte in the deltatime: + binbyte = ['00000000' dec2base(bytes(ptr),2)]; + binarystring = [binarystring binbyte(end-6:end)]; + ptr=ptr+1; +end +val = base2dec(binarystring,2); + + + + +% +% Read first 2 bytes of msg and +% determine the type +% (most require only 1st byte) +% +% str is one of: +% 'channel_mode' +% 'channel_voice' +% 'sysex' +% 'sys_realtime' +% +function str=midi_msg_type(B,nB) + +Hn = bitshift(B,-4); +Ln = bitand(B,7); + +% ---- channel mode messages: +%if (Hn==11 && nB>=120 && nB<=127) +if (Hn==11 && nB>=122 && nB<=127) + str = 'channel_mode'; + + % ---- channel voice messages: +elseif (Hn>=8 && Hn<=14) + str = 'channel_voice'; + + % ---- sysex events: +elseif (Hn==15 && Ln>=0 && Ln<=7) + str = 'sysex'; + + % system real-time messages +elseif (Hn==15 && Ln>=8 && Ln<=15) + % UNSURE: how can you tell between 0xFF system real-time + % message and 0xFF meta event? + % (now, it will always be processed by meta) + str = 'sys_realtime'; + +else + % don't think it can get here... + error('bad midi message'); +end +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Sirtassa/refineScore.m Tue Sep 03 12:53:16 2013 +0100 @@ -0,0 +1,35 @@ +function [binNb, width] = refineScore(mag,binNb) + +toneFactor = 2^(1/12); + +firstBin = floor((binNb+1)/toneFactor)-2; +lastBin = ceil((binNb+1)*toneFactor)+2; +firstBin = max(firstBin,1); +width =0; +if (firstBin<lastBin-1) + %pitch refinment + [maxB,indMax ]= max(mag(firstBin:lastBin)); + maxIdx = firstBin+indMax-1; + if (maxB <0.9) + binNb =0; + elseif (maxIdx ~= lastBin && maxIdx ~= firstBin) + a = log(mag(maxIdx-1)); + b = log(mag(maxIdx)); + c = log(mag(maxIdx+1)); + binNb = (maxIdx + (a - c)/(2*(a-2*b+c)))-1; + minIdx = floor(binNb); + maxIdx = ceil(binNb); + while(minIdx>0&&mag(minIdx)>0.1*maxB) + minIdx = minIdx-1; + end + while(mag(maxIdx)>0.1*maxB) + maxIdx = maxIdx+1; + end + width = 2*min( maxIdx -binNb+1,binNb- minIdx+1); + width = max(width,3); + else +% plot(mag(1:maxIdx+10)) +% close all; + end +end +