view Source/SoundField.cpp @ 9:53f99cbc5dbd

Heavily updated GUI. Added Heller et. al. decoding. Changed gain knobs.
author martinm_home <martin.morrell@eecs.qmul.ac.uk>
date Thu, 20 Sep 2012 16:41:01 +0100
parents d967dd1eafe8
children b5d48e9b9aea
line wrap: on
line source
//-------------------------------------------------------------------------------------------------------
// VST Plug-Ins SDK
// Version 2.4		$Date: 2006/11/13 09:08:27 $
//
// Category     : VST 2.x SDK Samples
// Filename     : adelay.cpp
// Created by   : Steinberg Media Technologies
// Description  : Simple Delay plugin (Mono->Stereo)
//
// © 2006, Steinberg Media Technologies, All Rights Reserved
//-------------------------------------------------------------------------------------------------------


#ifndef __SoundField__
#include "SoundField.h"
#include "Version.h"
#endif
//C++ Headers
#include <stdio.h>
#include <string.h>
#include <cmath>

//GUI Headers
#include "aeffguieditor.h"



//----------------------------------------------------------------------------- 
SoundFieldProgram::SoundFieldProgram ()
{
    //Define name if all programs are to be the same
    
}

//-----------------------------------------------------------------------------
SoundField::SoundField (audioMasterCallback audioMaster)
: AudioEffectX (audioMaster, 1, kNumParameters)
{	
	// init
	programs = new SoundFieldProgram[numPrograms];
    
    
    //	if (programs)
    //		setProgram (0);
	
    //Set the number of input and output channels
	setNumInputs (4);	// 4 Channel Classic B-Format Input
	setNumOutputs (6);	// MAX_CHANNELS 5.1 Outpu
	setUniqueID ('MMca');	// this should be unique, use the Steinberg web page for plugin Id registration
    canDoubleReplacing(); //Plugin can use process double replacing
    canProcessReplacing(); //Plugin can use process replacing
    noTail ();
    
    bool bit64 = setProcessPrecision(kVstProcessPrecision64);
    
    if (bit64==true) {
        bits=64;
    }
    else{
        bits=32;
    }
    
    
    
	//Load GUI
    extern AEffGUIEditor* createEditor (AudioEffectX*);
	setEditor (createEditor (this));
    
    
	resume ();		// flush buffer
    
	
    //Default Program Names
    vst_strncpy (programs[0].name, "Default",kVstMaxProgNameLen);
    
    vst_strncpy (programName, "Default", kVstMaxProgNameLen);	// default program name
    

    //  Declare any variables to their default values
    //  Default Program Values if NOT using a bank of programs
    fMode = 0.f;
    fWidth = 0.5f;
    fPattern = 0.5f;
    fRotate = 0.5f;
    fTilt = 0.5f;
	fTumble = 0.5f;
	fZoom = 0.5f;
	fZoomMethod = 0.f;
	fRearVerb = 0.f;
	fHiVerb = 0.f;
    fCentrePattern =0.5f;
    fCentreGain = 0.75f;
    fSubGain = 0.75f;
    fFc = 5.0f/11.0f;
    fSurroundMode = 0.f;
    fSurroundPattern = 0.5;
    fSurroundWidth = 2.f/3.f;
    fSurroundGain = 0.75f;
    fDecoderMode = 0.f;
    fChannelOrder = 0.f;
    
	
    //  myDecoder parameters
	myDecoder.Rotate=0.0;
	myDecoder.Tilt=0.0;
	myDecoder.Tumble=0.0;
	myDecoder.Zoom=0.0;
	myDecoder.ZoomMethod=0.0;
	myDecoder.Width=45.0;
	myDecoder.Pattern=0.5;
	myDecoder.Mode=0;
	myDecoder.RearVerb=-100;
	myDecoder.HiVerb=-100;
    myDecoder.surMode=0;
    myDecoder.surPattern=0.5;
    myDecoder.surWidth=60.0;
    myDecoder.surGain = 0.0;
    myDecoder.Fc = 120;
    myDecoder.centrePattern=0.5;
    myDecoder.centreGain=0.0;
    myDecoder.subGain=0.0;
    myDecoder.Fs = sampleRate;
    myDecoder.filterCoefs();
    myDecoder.decoderMode=2; //Default mode is Stereo
    myDecoder.channelOrder=0;
    myDecoder.mode5x=0;
    
    // Zero up decoder outputs as a safety
    myDecoder.outputL=0.0;
    myDecoder.outputR=0.0;
    myDecoder.outputC=0.0;
    myDecoder.outputS=0.0;
    myDecoder.outputSL=0.0;
    myDecoder.outputSR=0.0;
}


void SoundField::suspend()
{
    myDecoder.clearFilter();
    
    if (editor){
        ((AEffGUIEditor*)editor)->setParameter (100, 0);
    }
}

void SoundField::close()
{
}


void SoundField::open()
{
}



//------------------------------------------------------------------------
bool SoundField::setSpeakerArrangement (VstSpeakerArrangement* pluginInput,
                                        VstSpeakerArrangement* pluginOutput)
{
    numberInputs = pluginInput->numChannels;
    numberOutputs = pluginOutput->numChannels;

	return true;
}


//------------------------------------------------------------------------
void SoundField::setProgram (VstInt32 program) //Host to SET the Program
{
    curProgram = program; //Change the curProgram value
}


//------------------------------------------------------------------------
void	SoundField::setProgramName(char *name) //SET the Program name
{ 
	strcpy(programs[curProgram].name, name); //Host SETS the Program[].name
}


//------------------------------------------------------------------------
void	SoundField::getProgramName(char *name) //GET the Program name
{ 
	strcpy(name, programs[curProgram].name); //Host GETS the Program[].name
}


//------------------------------------------------------------------------
bool	SoundField::getProgramNameIndexed (VstInt32 category, VstInt32 which, char* name)
{
	if ((unsigned int)which < kNumPrograms) //Check the ProgramNameIndexed is within range
	{
	    strcpy(name, programs[which].name);	//Host GETS the programs[].name
	    return true; //TRUE- ProgramNameIndexed does exits
	}
	return false; //FALSE- ProgramNameIndexed does not exits
}


//------------------------------------------------------------------------
SoundField::~SoundField () //clears protected variables
{
	if (programs)
		delete[] programs; 
    
}


//------------------------------------------------------------------------
void SoundField::resume ()  //Do this on a resume from the host
{
	AudioEffectX::resume ();
    if (editor){
        ((AEffGUIEditor*)editor)->setParameter (101, 0);
    }
}


//------------------------------------------------------------------------
void SoundField::setParameter (VstInt32 index, float value) // SET Parameter value from host
{
	switch (index)
	{
        case kMode :
			fMode = value;
			if (value<=0.5f) {
				myDecoder.Mode = 0;
			}
			else {
				myDecoder.Mode = 1;
			}
            break;
		case kWidth:
			fWidth = value;
			myDecoder.Width = (double)value*90;
			break;
		case kPattern:
			fPattern = value;
			myDecoder.Pattern = (double)value;
			break;
		case kRotate :
			fRotate = value;
			if (value==0.5f) {
				myDecoder.Rotate=0.0;
			}
			else {
				myDecoder.Rotate = (double)value*-360+180;
			}
			break;
		case kTilt:
			fTilt = value;
			if (value==0.5f) {
				myDecoder.Tilt=0.0;
			}
			else {
				myDecoder.Tilt = (double)value*-360+180;
			}
			break;
		case kTumble:
			fTumble = value;
			if (value==0.5f) {
				myDecoder.Tumble=0.00;
			}
			else {
				myDecoder.Tumble = (double)value*-360+180;
			}
			break;
		case kZoom:
			fZoom = value;
			myDecoder.Zoom = (double)value*200-100;
			break;
		case kZoomMethod:
			fZoomMethod = value;
			if (value<=0.2f) {
				myDecoder.ZoomMethod = 0;
			}
			else if (value>0.2f && value<=0.5f) {
				myDecoder.ZoomMethod = 1;
			}
			else if (value>0.5f && value<=0.8f) {
				myDecoder.ZoomMethod = 2;
			}
			else if (value>0.8f && value<=1.f) {
				myDecoder.ZoomMethod = 3;
			}
			
			break;
		case kRearVerb :
			fRearVerb = value;
            if (value==0.0f) {
                myDecoder.RearVerb=-100;
            }
            else {
                myDecoder.RearVerb = -36+(double)value*36;
            }
			break;
		case kHiVerb :
			fHiVerb = value;
            if (value==0.0f) {
                myDecoder.HiVerb=-100;
            }
            else {
                myDecoder.HiVerb= -36+(double)value*36;
            }
			break;
        case kCentrePattern:
            fCentrePattern = value;
			myDecoder.centrePattern = (double)value;
            break;
        case kCentreGain:
            fCentreGain = value;
			myDecoder.centreGain = ((double)value*24-18);
            break;
        case kSubGain:
            fSubGain = value;
			myDecoder.subGain = ((double)value*24-18);
            break;
        case kFc:
            fFc = value;
			myDecoder.Fc = (int)((value*220)+20);
            myDecoder.filterCoefs();
            break;
        case kSurroundMode:
            fSurroundMode = value;
            if (value<=0.5f) {
				myDecoder.surMode = 0;
			}
			else {
				myDecoder.surMode = 1;
			}
            break;
        case kSurroundPattern:
            fSurroundPattern = value;
			myDecoder.surPattern = (double)value;
            break;
        case kSurroundWidth:
            fSurroundWidth = value;
			myDecoder.surWidth = (double)value*90;
            break;
        case kSurroundGain:
            fSurroundGain = value;
			myDecoder.surGain = ((double)value*24-18);
            break;
        case kDecoderMode:
            fDecoderMode = value;
            if (value<=0.2f) {
				myDecoder.decoderMode = 2; //Stereo
			}
			else if (value>0.2f && value<=0.4f) {
				myDecoder.decoderMode = 3; //2.1
			}
			else if (value>0.4f && value<=0.6f) {
				myDecoder.decoderMode = 4; //Quad
			}
			else if (value>0.6f && value<=0.8f) {
				myDecoder.decoderMode = 5; //5.0
			}
            else if (value>0.8f && value<=1.0f) {
				myDecoder.decoderMode = 6; //5.1
			}
            break;
            
        case kChannelOrder:
            fChannelOrder = value;
			if (value<=0.5f) {
				myDecoder.channelOrder = 0; //Natural Outputs
			}
			else {
				myDecoder.channelOrder = 1; //5.1 Outputs
			}
            break;
            
            
        default:
            break;
	}
    if (editor){
        ((AEffGUIEditor*)editor)->setParameter (index, value);
    }
}


//------------------------------------------------------------------------
float SoundField::getParameter (VstInt32 index) // GET the value of the parameter
{
	float returnFloat;    //Define a float to output
    
    // Use a switch when more than 1 parameter
	switch (index)
	{
        case kMode :
			returnFloat = fMode;
            break;
		case kWidth:
			returnFloat = fWidth;
			break;
		case kPattern:
			returnFloat = fPattern;
			break;
		case kRotate :
			returnFloat = fRotate;
			break;
		case kTilt:
			returnFloat = fTilt;
			break;
		case kTumble:
			returnFloat = fTumble;
			break;
		case kZoom:
			returnFloat = fZoom;
			break;
		case kZoomMethod:
			returnFloat = fZoomMethod;
			break;
		case kRearVerb :
			returnFloat = fRearVerb;
			break;
		case kHiVerb :
			returnFloat = fHiVerb;
			break;
        case kCentrePattern:
            returnFloat = fCentrePattern;
            break;
        case kCentreGain:
            returnFloat = fCentreGain;
            break;
        case kSubGain:
            returnFloat = fSubGain;
            break;
        case kFc:
            returnFloat = fFc;
            break;
        case kSurroundMode:
            returnFloat = fSurroundMode;
            break;
        case kSurroundPattern:
            returnFloat = fSurroundPattern;
            break;
        case kSurroundWidth:
            returnFloat = fSurroundWidth;
            break;
        case kSurroundGain:
            returnFloat = fSurroundGain;
            break;
        case kDecoderMode:
            returnFloat = fDecoderMode;
            break;
        case kChannelOrder:
            returnFloat = fChannelOrder;
            break;
            
            
        //HIDDEN PArameters for GUI Control
        case 102: //Bit Mode for GUI display
            returnFloat = bits;
            break;
        case 103:
            returnFloat = myDecoder.mode5x;
            break;
            
        default:
            break;
	}
	return returnFloat; //Returns the chosen Parameters value
}


//------------------------------------------------------------------------
void SoundField::getParameterName (VstInt32 index, char *label) //SET display value shown for Parameters
{
	switch (index)
	{
        case kMode :
			switch (myDecoder.Mode) {
				case 0 :
					strcpy(label, "XY");
					break;
				case 1 :
					strcpy(label, "MS");
					break;
			}
            break;
		case kWidth:
			strcpy(label, "Width");
			break;
		case kPattern:
			strcpy(label, "Pattern");
			break;
		case kRotate :
			strcpy(label, "Rotate");
			break;
		case kTilt:
			strcpy(label, "Tilt");
			break;
		case kTumble:
			strcpy(label, "Tumble");
			break;
		case kZoom:
			strcpy(label, "Zoom");
			break;
		case kZoomMethod:
			strcpy(label, "Zoom Method");
			break;
		case kRearVerb :
			strcpy(label, "RearVerb");
			break;
		case kHiVerb :
			strcpy(label, "HiVerb");
			break;
        case kCentrePattern:
            strcpy(label, "Ctr. Pattern");
            break;
        case kCentreGain:
            strcpy(label, "Ctr. Gain");
            break;
        case kSubGain:
            strcpy(label, "Sub. Gain");
            break;
        case kFc:
            strcpy(label, "Sub. Xover");
            break;
        case kSurroundMode:
            strcpy(label, "Sur. Mode");
            break;
        case kSurroundPattern:
            strcpy(label, "Sur. Pattern");
            break;
        case kSurroundWidth:
            strcpy(label, "Sur. Width");
            break;
        case kSurroundGain:
            strcpy(label, "Sur. Gain");
            break;
        case kDecoderMode:
            strcpy(label, "Dec. Mode");
            break;
        case kChannelOrder:
            strcpy(label, "Ch. Order");
            break;
            
        default:
            break;
	}
}


//------------------------------------------------------------------------
void SoundField::getParameterDisplay (VstInt32 index, char *text)   //GET display value shown for Parameters
{
	switch (index)
	{
        case kMode :
			switch (myDecoder.Mode) {
				case 0 :
					strcpy(text, "XY");
					break;
				case 1 :
					strcpy(text, "MS");
					break;
			}
            break;
		case kWidth:
			sprintf (text, "%.1f\u00B0", myDecoder.Width);
			break;
		case kPattern:
			//sprintf (text, "%.1f", myDecoder.Pattern);
			if (myDecoder.Pattern<=0.125) {
				strcpy(text, "Fig-of-8");
			}
			else if (myDecoder.Pattern>0.125 && myDecoder.Pattern<=0.375) {
				strcpy(text, "Hyper-Card.");
			}
			else if (myDecoder.Pattern>0.375 && myDecoder.Pattern<=0.625) {
				strcpy(text, "Cardioid");
			}
			else if (myDecoder.Pattern>0.625 && myDecoder.Pattern<=0.875) {
				strcpy(text, "Sub-Card.");
			}
			else {
				strcpy(text, "Omni.");
			}
			break;
		case kRotate :
			sprintf (text, "%.1f\u00B0", myDecoder.Rotate);
			break;
		case kTilt:
			sprintf (text, "%.1f\u00B0", myDecoder.Tilt);
			break;
		case kTumble:
			sprintf (text, "%.1f\u00B0", myDecoder.Tumble);
			break;
		case kZoom:
			sprintf (text, "%.1f%%", myDecoder.Zoom);
			break;
		case kZoomMethod:
			switch (myDecoder.ZoomMethod) {
				case 0:
					strcpy(text, "Dominance");
					break;
				case 1:
					strcpy(text, "Press");
					break;
				case 2:
					strcpy(text, "Push");
					break;
				case 3:
					strcpy(text, "Focus");
					break;
				default:
					break;
			}
			break;
		case kRearVerb :
            if (myDecoder.RearVerb>-40) {
                sprintf (text, "%.2fdB", myDecoder.RearVerb);
            }
			else {
                strcpy(text, "Off");
            }
			break;
		case kHiVerb :
            if (myDecoder.HiVerb>-40) {
                sprintf (text, "%.2fdB", myDecoder.HiVerb);
            }
            else {
                strcpy(text, "Off");
            }
			break;
        case kCentrePattern:
            if (myDecoder.centrePattern<=0.125) {
				strcpy(text, "Fig-of-8");
			}
			else if (myDecoder.centrePattern>0.125 && myDecoder.centrePattern<=0.375) {
				strcpy(text, "Hyper-Card.");
			}
			else if (myDecoder.centrePattern>0.375 && myDecoder.centrePattern<=0.625) {
				strcpy(text, "Cardioid");
			}
			else if (myDecoder.centrePattern>0.625 && myDecoder.centrePattern<=0.875) {
				strcpy(text, "Sub-Card.");
			}
			else {
				strcpy(text, "Omni.");
			}
            break;
        case kCentreGain:
            sprintf (text, "%.2fdB", myDecoder.centreGain);
            break;
        case kSubGain:
            sprintf (text, "%.2fdB", myDecoder.subGain);
            break;
        case kFc:
            sprintf (text, "%dHz", myDecoder.Fc);
            break;
        case kSurroundMode:
            switch (myDecoder.surMode) {
				case 0 :
					strcpy(text, "XY");
					break;
				case 1 :
					strcpy(text, "MS");
					break;
			}
            break;
        case kSurroundPattern:
            if (myDecoder.surPattern<=0.125) {
				strcpy(text, "Fig-of-8");
			}
			else if (myDecoder.surPattern>0.125 && myDecoder.surPattern<=0.375) {
				strcpy(text, "Hyper-Card.");
			}
			else if (myDecoder.surPattern>0.375 && myDecoder.surPattern<=0.625) {
				strcpy(text, "Cardioid");
			}
			else if (myDecoder.surPattern>0.625 && myDecoder.surPattern<=0.875) {
				strcpy(text, "Sub-Card.");
			}
			else {
				strcpy(text, "Omni.");
			}
            break;
        case kSurroundWidth:
            sprintf (text, "%.1f\u00B0", myDecoder.surWidth);
            break;
        case kSurroundGain:
            sprintf (text, "%.2fdB", myDecoder.surGain);
            break;
        case kDecoderMode:
            switch (myDecoder.decoderMode) {
				case 2 :
					strcpy(text, "Stereo");
					break;
				case 3 :
					strcpy(text, "2.1");
					break;
                case 4 :
					strcpy(text, "Quad");
					break;
                case 5 :
					strcpy(text, "5.0");
					break;
                case 6 :
					strcpy(text, "5.1");
					break;
			}
            break;
        case kChannelOrder:
            switch (myDecoder.channelOrder) {
				case 0 :
					strcpy(text, "Natural");
					break;
				case 1 :
					strcpy(text, "5.1");
					break;
			}
            break;
            
        default:
            break;
	}
	//kVstMaxParamStrLen
}


//------------------------------------------------------------------------
void SoundField::getParameterLabel (VstInt32 index, char *label)    // Labels shown for Parameters
{
	switch (index)
	{
        case kMode :
			strcpy(label, "Microphones");
			break;
		case kWidth:
			strcpy(label, "Degrees");
			break;
		case kPattern:
			strcpy(label, "Omni");
			break;
		case kRotate :
			strcpy(label, "Degrees");
			break;
		case kTilt:
			strcpy(label, "Degrees");
			break;
		case kTumble:
			strcpy(label, "Degrees");
			break;
		case kZoom:
			strcpy(label, "Percentage");
			break;
		case kZoomMethod:
			strcpy(label, "Selection");
			break;
		case kRearVerb :
			strcpy(label, "dB");
			break;
		case kHiVerb :
			strcpy(label, "dB");
			break;
        case kCentrePattern:
            strcpy(label, "Omni");
            break;
        case kCentreGain:
            strcpy(label, "dB");
            break;
        case kSubGain:
            strcpy(label, "dB");
            break;
        case kFc:
            strcpy(label, "Hz");
            break;
        case kSurroundMode:
            strcpy(label, "Microphones");
            break;
        case kSurroundPattern:
            strcpy(label, "Omni");
            break;
        case kSurroundWidth:
            strcpy(label, "Degrees");
            break;
        case kSurroundGain:
            strcpy(label, "dB");
            break;
        case kDecoderMode:
            strcpy(label, "Speakers");
            break;
        case kChannelOrder:
            strcpy(label, "Output");
            break;
	}
}


//------------------------------------------------------------------------
bool SoundField::getEffectName (char* name) // Tha NAME of the effect
{
	strcpy (name, "Classic Ambisonics Decoder");
	return true;
}


//------------------------------------------------------------------------
bool SoundField::getProductString (char* text)  // The PRODUCT name
{
	strcpy (text, "Classic Ambisonics Decoder");
	return true;
}


//------------------------------------------------------------------------
bool SoundField::getVendorString (char* text)   // Vendor (Creator/Publisher)
{
	strcpy (text, "Martin J. Morrell");
	return true;
}


//------------------------------------------------------------------------
VstInt32 SoundField::getVendorVersion () 
{
    return VERSION;
}



//------------------------------------------------------------------------
void SoundField::setSampleRate(float sampleRate)
{
    myDecoder.Fs = sampleRate;
    myDecoder.filterCoefs();
}



//---------------------------------------------------------------------------
void SoundField::processReplacing (float** inputs, float** outputs, VstInt32 sampleFrames) //The part that does some actual DSP. This section takes the input audio and gives the output audio back.
{
	while (--sampleFrames >= 0) //Do this process if the audio is running
	{
		//Set the internal B-Format values as doubles.
        double w, x, y, z;
        switch (numberInputs) {
            case 3:
                w = (double) *inputs[0]++;
                x = (double) *inputs[1]++;
                y = (double) *inputs[2]++;
                z = 0;
                break;
                
            case 4:
                w = (double) *inputs[0]++;
                x = (double) *inputs[1]++;
                y = (double) *inputs[2]++;
                z = (double) *inputs[3]++;
                break;
                
            default:
                w = 0;
                x = 0;
                y = 0;
                z = 0;
                break;
        }
		
		
        int numOut;
        numOut = myDecoder.processDecoder(w, x, y, z); //Process B-Format
        
        if (numOut<=numberOutputs) {
            for (int i=0; i<numOut; i++)
                *outputs[i]++ = float(myDecoder.output[i]);                
        }
        else{
            for (int i=0; i<numberOutputs; i++)
                *outputs[i]++ = float(myDecoder.output[i]);
        }
	}
}


//---------------------------------------------------------------------------
void SoundField::processDoubleReplacing(double **inputs, double **outputs, VstInt32 sampleFrames) //The part that does some actual DSP. This section takes the input audio and gives the output audio back.
{
	while (--sampleFrames >= 0) //Do this process if the audio is running
	{
		//Set the internal B-Format values as doubles.
        double w, x, y, z;
        switch (numberInputs) {
            case 3:
                w = (double) *inputs[0]++;
                x = (double) *inputs[1]++;
                y = (double) *inputs[2]++;
                z = 0;
                break;
                
            case 4:
                w = (double) *inputs[0]++;
                x = (double) *inputs[1]++;
                y = (double) *inputs[2]++;
                z = (double) *inputs[3]++;
                break;
                
            default:
                w = 0;
                x = 0;
                y = 0;
                z = 0;
                break;
        }
		
		
        int numOut;
        numOut = myDecoder.processDecoder(w, x, y, z); //Process B-Format
        
        if (numOut<=numberOutputs) {
            for (int i=0; i<numOut; i++)
                *outputs[i]++ = float(myDecoder.output[i]);
        }
        else{
            for (int i=0; i<numberOutputs; i++)
                *outputs[i]++ = float(myDecoder.output[i]);
        }
	}
}