ZynAddSubFX: resynced with their Git repo

ZynAddSubFX has gained some new developer power so development has been
going on well for quite a while now in their Git repo. It's time for
the first big resync so future changes can be integrated easily.
This commit is contained in:
Tobias Doerffel
2009-09-17 23:21:26 +02:00
parent b73474ca73
commit 3c18e436cd
187 changed files with 19449 additions and 16454 deletions

View File

@@ -2,55 +2,6 @@ IF(LMMS_HAVE_FFTW3F)
INCLUDE(BuildPlugin)
SET(ZYN_SRC_CORE
${CMAKE_CURRENT_SOURCE_DIR}/src/DSP/AnalogFilter.C
${CMAKE_CURRENT_SOURCE_DIR}/src/DSP/Filter.C
${CMAKE_CURRENT_SOURCE_DIR}/src/DSP/SVFilter.C
${CMAKE_CURRENT_SOURCE_DIR}/src/DSP/FFTwrapper.C
${CMAKE_CURRENT_SOURCE_DIR}/src/DSP/FormantFilter.C
${CMAKE_CURRENT_SOURCE_DIR}/src/Input/NULLMidiIn.C
${CMAKE_CURRENT_SOURCE_DIR}/src/Input/MidiIn.C
${CMAKE_CURRENT_SOURCE_DIR}/src/Output/Recorder.C
${CMAKE_CURRENT_SOURCE_DIR}/src/Output/WAVaudiooutput.C
${CMAKE_CURRENT_SOURCE_DIR}/src/Effects/EffectMgr.C
${CMAKE_CURRENT_SOURCE_DIR}/src/Effects/Effect.C
${CMAKE_CURRENT_SOURCE_DIR}/src/Effects/Phaser.C
${CMAKE_CURRENT_SOURCE_DIR}/src/Effects/Echo.C
${CMAKE_CURRENT_SOURCE_DIR}/src/Effects/EffectLFO.C
${CMAKE_CURRENT_SOURCE_DIR}/src/Effects/Chorus.C
${CMAKE_CURRENT_SOURCE_DIR}/src/Effects/DynamicFilter.C
${CMAKE_CURRENT_SOURCE_DIR}/src/Effects/Reverb.C
${CMAKE_CURRENT_SOURCE_DIR}/src/Effects/EQ.C
${CMAKE_CURRENT_SOURCE_DIR}/src/Effects/Distorsion.C
${CMAKE_CURRENT_SOURCE_DIR}/src/Effects/Alienwah.C
${CMAKE_CURRENT_SOURCE_DIR}/src/Params/LFOParams.C
${CMAKE_CURRENT_SOURCE_DIR}/src/Params/EnvelopeParams.C
${CMAKE_CURRENT_SOURCE_DIR}/src/Params/SUBnoteParameters.C
${CMAKE_CURRENT_SOURCE_DIR}/src/Params/ADnoteParameters.C
${CMAKE_CURRENT_SOURCE_DIR}/src/Params/Presets.C
${CMAKE_CURRENT_SOURCE_DIR}/src/Params/FilterParams.C
${CMAKE_CURRENT_SOURCE_DIR}/src/Params/PADnoteParameters.C
${CMAKE_CURRENT_SOURCE_DIR}/src/Params/Controller.C
${CMAKE_CURRENT_SOURCE_DIR}/src/Params/PresetsStore.C
${CMAKE_CURRENT_SOURCE_DIR}/src/Seq/MIDIFile.C
${CMAKE_CURRENT_SOURCE_DIR}/src/Seq/MIDIEvents.C
${CMAKE_CURRENT_SOURCE_DIR}/src/Seq/Sequencer.C
${CMAKE_CURRENT_SOURCE_DIR}/src/Synth/PADnote.C
${CMAKE_CURRENT_SOURCE_DIR}/src/Synth/SUBnote.C
${CMAKE_CURRENT_SOURCE_DIR}/src/Synth/LFO.C
${CMAKE_CURRENT_SOURCE_DIR}/src/Synth/Resonance.C
${CMAKE_CURRENT_SOURCE_DIR}/src/Synth/ADnote.C
${CMAKE_CURRENT_SOURCE_DIR}/src/Synth/Envelope.C
${CMAKE_CURRENT_SOURCE_DIR}/src/Synth/OscilGen.C
${CMAKE_CURRENT_SOURCE_DIR}/src/Misc/Dump.C
${CMAKE_CURRENT_SOURCE_DIR}/src/Misc/Bank.C
${CMAKE_CURRENT_SOURCE_DIR}/src/Misc/Config.C
${CMAKE_CURRENT_SOURCE_DIR}/src/Misc/XMLwrapper.C
${CMAKE_CURRENT_SOURCE_DIR}/src/Misc/Util.C
${CMAKE_CURRENT_SOURCE_DIR}/src/Misc/Master.C
${CMAKE_CURRENT_SOURCE_DIR}/src/Misc/Microtonal.C
${CMAKE_CURRENT_SOURCE_DIR}/src/Misc/Part.C)
SET(ZYN_SRC_GUI
${CMAKE_CURRENT_SOURCE_DIR}/src/UI/MasterUI.cc
${CMAKE_CURRENT_SOURCE_DIR}/src/UI/VirKeyboard.cc
@@ -72,6 +23,7 @@ SET(ZYN_SRC_GUI
${CMAKE_CURRENT_SOURCE_DIR}/src/UI/BankUI.cc
)
SET(MXML_SRC
${CMAKE_CURRENT_SOURCE_DIR}/mxml/mxml-attr.c
${CMAKE_CURRENT_SOURCE_DIR}/mxml/mxml-entity.c
@@ -108,10 +60,37 @@ IF(LMMS_BUILD_WIN32)
ADD_DEFINITIONS(-DPTW32_STATIC_LIB)
ENDIF(LMMS_BUILD_WIN32)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/fltk/ ${CMAKE_CURRENT_SOURCE_DIR} ${FFTW3F_INCLUDE_DIRS})
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/fltk/ ${CMAKE_CURRENT_SOURCE_DIR}/mxml ${CMAKE_CURRENT_SOURCE_DIR} ${FFTW3F_INCLUDE_DIRS})
ADD_LIBRARY(ZynAddSubFxCore SHARED LocalZynAddSubFx.cpp ${ZYN_SRC_CORE} ${MXML_SRC})
TARGET_LINK_LIBRARIES(ZynAddSubFxCore ${FFTW3F_LIBRARIES} -lz -lpthread)
set(ZASF_CORE_LIBS
zynaddsubfx_input
zynaddsubfx_output
zynaddsubfx_misc
zynaddsubfx_synth
zynaddsubfx_seq
zynaddsubfx_effect
zynaddsubfx_params
zynaddsubfx_dsp
zynaddsubfx_samples
zynaddsubfx_controls
)
macro(unit_test NAME CXX_FILE FILES)
endmacro(unit_test)
add_subdirectory(src/Misc)
add_subdirectory(src/Input)
add_subdirectory(src/Controls)
add_subdirectory(src/Synth)
add_subdirectory(src/Output)
add_subdirectory(src/Seq)
add_subdirectory(src/Effects)
add_subdirectory(src/Params)
add_subdirectory(src/DSP)
add_subdirectory(src/Samples)
ADD_LIBRARY(ZynAddSubFxCore SHARED LocalZynAddSubFx.cpp ${MXML_SRC})
TARGET_LINK_LIBRARIES(ZynAddSubFxCore ${FFTW3F_LIBRARIES} ${ZASF_CORE_LIBS} -lz -lpthread)
IF(LMMS_BUILD_WIN32)
TARGET_LINK_LIBRARIES(ZynAddSubFxCore -lwsock32)
INSTALL(TARGETS ZynAddSubFxCore DESTINATION ${PLUGIN_DIR})

View File

@@ -26,7 +26,7 @@
#include "LocalZynAddSubFx.h"
#include "src/Input/MidiIn.h"
#include "src/Input/NULLMidiIn.h"
#include "src/Misc/Master.h"
#include "src/Misc/Dump.h"
@@ -169,7 +169,7 @@ void LocalZynAddSubFx::setPresetDir( const std::string & _dir )
void LocalZynAddSubFx::processMidiEvent( const midiEvent & _e )
{
// all functions are called while m_master->mutex is held
static MidiIn midiIn;
static NULLMidiIn midiIn;
switch( _e.m_type )
{

View File

@@ -191,8 +191,7 @@ void ZynAddSubFxInstrument::loadResource( const ResourceItem * _item )
{
m_remotePlugin->lock();
m_remotePlugin->sendMessage(
RemotePlugin::message( IdLoadPresetFromFile ).
addString( QSTR_TO_STDSTR( mapper.fileName() ) ) );
RemotePlugin::message( IdLoadPresetFromFile ).addString( fn ) );
m_remotePlugin->waitForMessage( IdLoadPresetFromFile );
m_remotePlugin->unlock();
}

View File

@@ -1,13 +1,16 @@
Main author:
Nasca Octavian Paul
Nasca Octavian Paul
Developers:
Mark McCurry
Mark McCurry
Harald Hvaal
Contributors:
Gerald Folcher (legato, mono notes memory)
Lars Luthman (zombie fix,jack midi, LASH support)
Daniel Clemente (with a workaround of X11 repeated key bug)
Gerald Folcher (legato, mono notes memory)
Lars Luthman (zombie fix,jack midi, LASH support)
Daniel Clemente (with a workaround of X11 repeated key bug)
Emmanuel Saracco (fix for JACK output)
Achim Settelmeier (QUERTZ keyboard layout for virtual keyboard)
J<>r<EFBFBD>mie Andr<64>i (AZERTY keyboard layout, Array index fix)
Alexis Ballier (const char* <-> string mismatch, NULLMidi prototype fix)

View File

@@ -840,7 +840,7 @@
hovers over them
- Created tooltips for the effects knobs
- Standardized the code, so it could compile with pedantic without
errors [it looks like some errors may have ben missed]
errors [it looks like some errors may have been missed]
22 Feb 2009 (Mark McCurry)
- Fix improper deallocation in PresetsStore
@@ -861,3 +861,34 @@
- Almost all changes contained in Effects until further
discussion on the style, so consistancy can be reached
28 May 2009 (Mark McCurry)
- Added some more Doxygen comments
- Added Audio Samples classes
- Added Stereo template
- Added Control class
- Added DelayCtl class
20 Iun 2009 (Paul Nasca)
- Bugfix: WAV export of PADsynth
10 Iul 2009 (Paul Nasca)
- Update copyright info
11 Jul 2009 (Mark McCurry)
- Added Proportinal Portamento
- Replaced Docbook with AsciiDoc
18 Jul 2009 (Mark McCurry)
- Enabled volume controller by default
20 Jul 2009 (Mark McCurry)
- Incorperated AZERTY layout by sourceforge user jimee
02 Sep 2009 (Mark McCurry)
- Incorperated const char* <-> string mismatch by Alexis Ballier
04 Sep 2009 (Mark McCurry)
- Incorperated NULLMidiIn function prototype fix by Alexis Ballier
07 Sep 2009 (Mark McCurry)
- Fixed glitch in XMLwrapper, which would prevent file loading

View File

@@ -0,0 +1,8 @@
set(zynaddsubfx_controls_SRCS
Control.cpp
DelayCtl.cpp
)
add_library(zynaddsubfx_controls STATIC
${zynaddsubfx_controls_SRCS}
)

View File

@@ -0,0 +1,40 @@
/*
ZynAddSubFX - a software synthesizer
Control.C - Control base class
Copyright (C) 2009-2009 Mark McCurry
Author: Mark McCurry
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "Control.h"
Control::Control(char ndefaultval)
:defaultval(ndefaultval),lockqueue(-1),locked(false)
{}
void Control::lock()
{
locked=true;
lockqueue=-1;
}
void Control::ulock()
{
if (locked&&lockqueue>=0)
setmVal(lockqueue);
locked=false;
}

View File

@@ -0,0 +1,58 @@
/*
ZynAddSubFX - a software synthesizer
Control.h - Control base class
Copyright (C) 2009-2009 Mark McCurry
Author: Mark McCurry
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef CONTROL_H
#define CONTROL_H
#include <string>
/**A control for a parameter within the program*/
class Control
{
public:
Control(char ndefaultval);/**\todo create proper initialization list*/
~Control() {};
/**Return the string, which represents the internal value
* @return a string representation of the current value*/
virtual std::string getString()const=0;
/**Set the Control to the given value
* @param nval A number 0-127*/
virtual void setmVal(char nval)=0;
/**Return the midi value (aka the char)
* @return the current value*/
virtual char getmVal()const=0;
/** Will lock the Control until it is ulocked
*
* Locking a Control will Stop it from having
* its internal data altered*/
void lock();
/** Will unlock the Control
*
* This will also update the Control
* if something attempted to update it while it was locked*/
void ulock();
private:
char defaultval;/**<Default value of the Control*/
char lockqueue; /**<The value is that is stored, while the Control is locked
* and something attempts to update it*/
bool locked;//upgrade this to a integer lock level if problems occur
};
#endif

View File

@@ -0,0 +1,50 @@
/*
ZynAddSubFX - a software synthesizer
DelayCtl.C - Control For Delays
Copyright (C) 2009-2009 Mark McCurry
Author: Mark McCurry
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "DelayCtl.h"
#include <sstream>
DelayCtl::DelayCtl()
:Control(64),value(64/127.0*1.5) {} /**\todo finishme*/
std::string DelayCtl::getString() const
{
std::ostringstream buf;
buf<<value;
return (buf.str() + " Seconds");
}
void DelayCtl::setmVal(char nval)
{
/**\todo add locking code*/
//value=1+(int)(nval/127.0*SAMPLE_RATE*1.5);//0 .. 1.5 sec
value=(nval/127.0*1.5);//0 .. 1.5 sec
}
char DelayCtl::getmVal() const
{
return((char)(value/1.5*127.0));
}
float DelayCtl::getiVal() const
{
return(value);
}

View File

@@ -0,0 +1,43 @@
/*
ZynAddSubFX - a software synthesizer
DelayCtl.h - Control For Delays
Copyright (C) 2009-2009 Mark McCurry
Author: Mark McCurry
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "Control.h"
#ifndef DELAYCTL_H
#define DELAYCTL_H
/**A Control for Delays
*
* Will vary from 0 seconds to 1.5 seconds*/
class DelayCtl:public Control
{
public:
DelayCtl();
~DelayCtl() {};
std::string getString() const;
void setmVal(char nval);
char getmVal() const;
float getiVal() const;
private:
float value;
};
#endif

View File

@@ -1,358 +0,0 @@
/*
ZynAddSubFX - a software synthesizer
AnalogFilter.C - Several analog filters (lowpass, highpass...)
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <math.h>
#include <stdio.h>
#include "AnalogFilter.h"
AnalogFilter::AnalogFilter(unsigned char Ftype,REALTYPE Ffreq, REALTYPE Fq,unsigned char Fstages){
stages=Fstages;
for (int i=0;i<3;i++){
oldc[i]=0.0;oldd[i]=0.0;
c[i]=0.0;d[i]=0.0;
};
type=Ftype;
freq=Ffreq;
q=Fq;
gain=1.0;
if (stages>=MAX_FILTER_STAGES) stages=MAX_FILTER_STAGES;
cleanup();
firsttime=0;
abovenq=0;oldabovenq=0;
setfreq_and_q(Ffreq,Fq);
firsttime=1;
d[0]=0;//this is not used
outgain=1.0;
};
AnalogFilter::~AnalogFilter(){
};
void AnalogFilter::cleanup(){
for (int i=0;i<MAX_FILTER_STAGES+1;i++){
x[i].c1=0.0;x[i].c2=0.0;
y[i].c1=0.0;y[i].c2=0.0;
oldx[i]=x[i];
oldy[i]=y[i];
};
needsinterpolation=0;
};
void AnalogFilter::computefiltercoefs(){
REALTYPE tmp;
REALTYPE omega,sn,cs,alpha,beta;
int zerocoefs=0;//this is used if the freq is too high
//do not allow frequencies bigger than samplerate/2
REALTYPE freq=this->freq;
if (freq>(SAMPLE_RATE/2-500.0)) {
freq=SAMPLE_RATE/2-500.0;
zerocoefs=1;
};
if (freq<0.1) freq=0.1;
//do not allow bogus Q
if (q<0.0) q=0.0;
REALTYPE tmpq,tmpgain;
if (stages==0) {
tmpq=q;
tmpgain=gain;
} else {
tmpq=(q>1.0 ? pow(q,1.0/(stages+1)) : q);
tmpgain=pow(gain,1.0/(stages+1));
};
//most of theese are implementations of
//the "Cookbook formulae for audio EQ" by Robert Bristow-Johnson
//The original location of the Cookbook is:
//http://www.harmony-central.com/Computer/Programming/Audio-EQ-Cookbook.txt
switch(type){
case 0://LPF 1 pole
if (zerocoefs==0) tmp=exp(-2.0*PI*freq/SAMPLE_RATE);
else tmp=0.0;
c[0]=1.0-tmp;c[1]=0.0;c[2]=0.0;
d[1]=tmp;d[2]=0.0;
order=1;
break;
case 1://HPF 1 pole
if (zerocoefs==0) tmp=exp(-2.0*PI*freq/SAMPLE_RATE);
else tmp=0.0;
c[0]=(1.0+tmp)/2.0;c[1]=-(1.0+tmp)/2.0;c[2]=0.0;
d[1]=tmp;d[2]=0.0;
order=1;
break;
case 2://LPF 2 poles
if (zerocoefs==0){
omega=2*PI*freq/SAMPLE_RATE;
sn=sin(omega);
cs=cos(omega);
alpha=sn/(2*tmpq);
tmp=1+alpha;
c[0]=(1.0-cs)/2.0/tmp;
c[1]=(1.0-cs)/tmp;
c[2]=(1.0-cs)/2.0/tmp;
d[1]=-2*cs/tmp*(-1);
d[2]=(1-alpha)/tmp*(-1);
} else {
c[0]=1.0;c[1]=0.0;c[2]=0.0;
d[1]=0.0;d[2]=0.0;
};
order=2;
break;
case 3://HPF 2 poles
if (zerocoefs==0){
omega=2*PI*freq/SAMPLE_RATE;
sn=sin(omega);
cs=cos(omega);
alpha=sn/(2*tmpq);
tmp=1+alpha;
c[0]=(1.0+cs)/2.0/tmp;
c[1]=-(1.0+cs)/tmp;
c[2]=(1.0+cs)/2.0/tmp;
d[1]=-2*cs/tmp*(-1);
d[2]=(1-alpha)/tmp*(-1);
} else {
c[0]=0.0;c[1]=0.0;c[2]=0.0;
d[1]=0.0;d[2]=0.0;
};
order=2;
break;
case 4://BPF 2 poles
if (zerocoefs==0){
omega=2*PI*freq/SAMPLE_RATE;
sn=sin(omega);
cs=cos(omega);
alpha=sn/(2*tmpq);
tmp=1+alpha;
c[0]=alpha/tmp*sqrt(tmpq+1);
c[1]=0;
c[2]=-alpha/tmp*sqrt(tmpq+1);
d[1]=-2*cs/tmp*(-1);
d[2]=(1-alpha)/tmp*(-1);
} else {
c[0]=0.0;c[1]=0.0;c[2]=0.0;
d[1]=0.0;d[2]=0.0;
};
order=2;
break;
case 5://NOTCH 2 poles
if (zerocoefs==0){
omega=2*PI*freq/SAMPLE_RATE;
sn=sin(omega);
cs=cos(omega);
alpha=sn/(2*sqrt(tmpq));
tmp=1+alpha;
c[0]=1/tmp;
c[1]=-2*cs/tmp;
c[2]=1/tmp;
d[1]=-2*cs/tmp*(-1);
d[2]=(1-alpha)/tmp*(-1);
} else {
c[0]=1.0;c[1]=0.0;c[2]=0.0;
d[1]=0.0;d[2]=0.0;
};
order=2;
break;
case 6://PEAK (2 poles)
if (zerocoefs==0){
omega=2*PI*freq/SAMPLE_RATE;
sn=sin(omega);
cs=cos(omega);
tmpq*=3.0;
alpha=sn/(2*tmpq);
tmp=1+alpha/tmpgain;
c[0]=(1.0+alpha*tmpgain)/tmp;
c[1]=(-2.0*cs)/tmp;
c[2]=(1.0-alpha*tmpgain)/tmp;
d[1]=-2*cs/tmp*(-1);
d[2]=(1-alpha/tmpgain)/tmp*(-1);
} else {
c[0]=1.0;c[1]=0.0;c[2]=0.0;
d[1]=0.0;d[2]=0.0;
};
order=2;
break;
case 7://Low Shelf - 2 poles
if (zerocoefs==0){
omega=2*PI*freq/SAMPLE_RATE;
sn=sin(omega);
cs=cos(omega);
tmpq=sqrt(tmpq);
alpha=sn/(2*tmpq);
beta=sqrt(tmpgain)/tmpq;
tmp=(tmpgain+1.0)+(tmpgain-1.0)*cs+beta*sn;
c[0]=tmpgain*((tmpgain+1.0)-(tmpgain-1.0)*cs+beta*sn)/tmp;
c[1]=2.0*tmpgain*((tmpgain-1.0)-(tmpgain+1.0)*cs)/tmp;
c[2]=tmpgain*((tmpgain+1.0)-(tmpgain-1.0)*cs-beta*sn)/tmp;
d[1]=-2.0*((tmpgain-1.0)+(tmpgain+1.0)*cs)/tmp*(-1);
d[2]=((tmpgain+1.0)+(tmpgain-1.0)*cs-beta*sn)/tmp*(-1);
} else {
c[0]=tmpgain;c[1]=0.0;c[2]=0.0;
d[1]=0.0;d[2]=0.0;
};
order=2;
break;
case 8://High Shelf - 2 poles
if (zerocoefs==0){
omega=2*PI*freq/SAMPLE_RATE;
sn=sin(omega);
cs=cos(omega);
tmpq=sqrt(tmpq);
alpha=sn/(2*tmpq);
beta=sqrt(tmpgain)/tmpq;
tmp=(tmpgain+1.0)-(tmpgain-1.0)*cs+beta*sn;
c[0]=tmpgain*((tmpgain+1.0)+(tmpgain-1.0)*cs+beta*sn)/tmp;
c[1]=-2.0*tmpgain*((tmpgain-1.0)+(tmpgain+1.0)*cs)/tmp;
c[2]=tmpgain*((tmpgain+1.0)+(tmpgain-1.0)*cs-beta*sn)/tmp;
d[1]=2.0*((tmpgain-1.0)-(tmpgain+1.0)*cs)/tmp*(-1);
d[2]=((tmpgain+1.0)-(tmpgain-1.0)*cs-beta*sn)/tmp*(-1);
} else {
c[0]=1.0;c[1]=0.0;c[2]=0.0;
d[1]=0.0;d[2]=0.0;
};
order=2;
break;
default://wrong type
type=0;
computefiltercoefs();
break;
};
};
void AnalogFilter::setfreq(REALTYPE frequency){
if (frequency<0.1) frequency=0.1;
REALTYPE rap=freq/frequency;if (rap<1.0) rap=1.0/rap;
oldabovenq=abovenq;abovenq=frequency>(SAMPLE_RATE/2-500.0);
int nyquistthresh=(abovenq^oldabovenq);
if ((rap>3.0)||(nyquistthresh!=0)){//if the frequency is changed fast, it needs interpolation (now, filter and coeficients backup)
for (int i=0;i<3;i++){
oldc[i]=c[i];oldd[i]=d[i];
};
for (int i=0;i<MAX_FILTER_STAGES+1;i++){
oldx[i]=x[i];
oldy[i]=y[i];
};
if (firsttime==0) needsinterpolation=1;
};
freq=frequency;
computefiltercoefs();
firsttime=0;
};
void AnalogFilter::setfreq_and_q(REALTYPE frequency,REALTYPE q_){
q=q_;
setfreq(frequency);
};
void AnalogFilter::setq(REALTYPE q_){
q=q_;
computefiltercoefs();
};
void AnalogFilter::settype(int type_){
type=type_;
computefiltercoefs();
};
void AnalogFilter::setgain(REALTYPE dBgain){
gain=dB2rap(dBgain);
computefiltercoefs();
};
void AnalogFilter::setstages(int stages_){
if (stages_>=MAX_FILTER_STAGES) stages_=MAX_FILTER_STAGES-1;
stages=stages_;
cleanup();
computefiltercoefs();
};
void AnalogFilter::singlefilterout(REALTYPE *smp,fstage &x,fstage &y,REALTYPE *c,REALTYPE *d){
int i;
REALTYPE y0;
if (order==1) {//First order filter
for (i=0;i<SOUND_BUFFER_SIZE;i++){
y0=smp[i]*c[0]+x.c1*c[1]+y.c1*d[1];
y.c1=y0;
x.c1=smp[i];
//output
smp[i]=y0;
};
};
if (order==2) {//Second order filter
for (i=0;i<SOUND_BUFFER_SIZE;i++){
y0=smp[i]*c[0]+x.c1*c[1]+x.c2*c[2]+y.c1*d[1]+y.c2*d[2];
y.c2=y.c1;
y.c1=y0;
x.c2=x.c1;
x.c1=smp[i];
//output
smp[i]=y0;
};
};
};
void AnalogFilter::filterout(REALTYPE *smp){
REALTYPE *ismp=NULL;//used if it needs interpolation
int i;
if (needsinterpolation!=0){
ismp=new REALTYPE[SOUND_BUFFER_SIZE];
for (i=0;i<SOUND_BUFFER_SIZE;i++) ismp[i]=smp[i];
for (i=0;i<stages+1;i++) singlefilterout(ismp,oldx[i],oldy[i],oldc,oldd);
};
for (i=0;i<stages+1;i++) singlefilterout(smp,x[i],y[i],c,d);
if (needsinterpolation!=0){
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
REALTYPE x=i/(REALTYPE) SOUND_BUFFER_SIZE;
smp[i]=ismp[i]*(1.0-x)+smp[i]*x;
};
delete [] ismp;
needsinterpolation=0;
};
for (i=0;i<SOUND_BUFFER_SIZE;i++) smp[i]*=outgain;
};
REALTYPE AnalogFilter::H(REALTYPE freq){
REALTYPE fr=freq/SAMPLE_RATE*PI*2.0;
REALTYPE x=c[0],y=0.0;
for (int n=1;n<3;n++){
x+=cos(n*fr)*c[n];
y-=sin(n*fr)*c[n];
};
REALTYPE h=x*x+y*y;
x=1.0;y=0.0;
for (int n=1;n<3;n++){
x-=cos(n*fr)*d[n];
y+=sin(n*fr)*d[n];
};
h=h/(x*x+y*y);
return(pow(h,(stages+1.0)/2.0));
};

View File

@@ -0,0 +1,407 @@
/*
ZynAddSubFX - a software synthesizer
AnalogFilter.C - Several analog filters (lowpass, highpass...)
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <math.h>
#include <stdio.h>
#include "AnalogFilter.h"
AnalogFilter::AnalogFilter(unsigned char Ftype,REALTYPE Ffreq, REALTYPE Fq,unsigned char Fstages)
{
stages=Fstages;
for (int i=0;i<3;i++) {
oldc[i]=0.0;
oldd[i]=0.0;
c[i]=0.0;
d[i]=0.0;
};
type=Ftype;
freq=Ffreq;
q=Fq;
gain=1.0;
if (stages>=MAX_FILTER_STAGES) stages=MAX_FILTER_STAGES;
cleanup();
firsttime=0;
abovenq=0;
oldabovenq=0;
setfreq_and_q(Ffreq,Fq);
firsttime=1;
d[0]=0;//this is not used
outgain=1.0;
};
AnalogFilter::~AnalogFilter()
{
};
void AnalogFilter::cleanup()
{
for (int i=0;i<MAX_FILTER_STAGES+1;i++) {
x[i].c1=0.0;
x[i].c2=0.0;
y[i].c1=0.0;
y[i].c2=0.0;
oldx[i]=x[i];
oldy[i]=y[i];
};
needsinterpolation=0;
};
void AnalogFilter::computefiltercoefs()
{
REALTYPE tmp;
REALTYPE omega,sn,cs,alpha,beta;
int zerocoefs=0;//this is used if the freq is too high
//do not allow frequencies bigger than samplerate/2
REALTYPE freq=this->freq;
if (freq>(SAMPLE_RATE/2-500.0)) {
freq=SAMPLE_RATE/2-500.0;
zerocoefs=1;
};
if (freq<0.1) freq=0.1;
//do not allow bogus Q
if (q<0.0) q=0.0;
REALTYPE tmpq,tmpgain;
if (stages==0) {
tmpq=q;
tmpgain=gain;
} else {
tmpq=(q>1.0 ? pow(q,1.0/(stages+1)) : q);
tmpgain=pow(gain,1.0/(stages+1));
};
//most of theese are implementations of
//the "Cookbook formulae for audio EQ" by Robert Bristow-Johnson
//The original location of the Cookbook is:
//http://www.harmony-central.com/Computer/Programming/Audio-EQ-Cookbook.txt
switch (type) {
case 0://LPF 1 pole
if (zerocoefs==0) tmp=exp(-2.0*PI*freq/SAMPLE_RATE);
else tmp=0.0;
c[0]=1.0-tmp;
c[1]=0.0;
c[2]=0.0;
d[1]=tmp;
d[2]=0.0;
order=1;
break;
case 1://HPF 1 pole
if (zerocoefs==0) tmp=exp(-2.0*PI*freq/SAMPLE_RATE);
else tmp=0.0;
c[0]=(1.0+tmp)/2.0;
c[1]=-(1.0+tmp)/2.0;
c[2]=0.0;
d[1]=tmp;
d[2]=0.0;
order=1;
break;
case 2://LPF 2 poles
if (zerocoefs==0) {
omega=2*PI*freq/SAMPLE_RATE;
sn=sin(omega);
cs=cos(omega);
alpha=sn/(2*tmpq);
tmp=1+alpha;
c[0]=(1.0-cs)/2.0/tmp;
c[1]=(1.0-cs)/tmp;
c[2]=(1.0-cs)/2.0/tmp;
d[1]=-2*cs/tmp*(-1);
d[2]=(1-alpha)/tmp*(-1);
} else {
c[0]=1.0;
c[1]=0.0;
c[2]=0.0;
d[1]=0.0;
d[2]=0.0;
};
order=2;
break;
case 3://HPF 2 poles
if (zerocoefs==0) {
omega=2*PI*freq/SAMPLE_RATE;
sn=sin(omega);
cs=cos(omega);
alpha=sn/(2*tmpq);
tmp=1+alpha;
c[0]=(1.0+cs)/2.0/tmp;
c[1]=-(1.0+cs)/tmp;
c[2]=(1.0+cs)/2.0/tmp;
d[1]=-2*cs/tmp*(-1);
d[2]=(1-alpha)/tmp*(-1);
} else {
c[0]=0.0;
c[1]=0.0;
c[2]=0.0;
d[1]=0.0;
d[2]=0.0;
};
order=2;
break;
case 4://BPF 2 poles
if (zerocoefs==0) {
omega=2*PI*freq/SAMPLE_RATE;
sn=sin(omega);
cs=cos(omega);
alpha=sn/(2*tmpq);
tmp=1+alpha;
c[0]=alpha/tmp*sqrt(tmpq+1);
c[1]=0;
c[2]=-alpha/tmp*sqrt(tmpq+1);
d[1]=-2*cs/tmp*(-1);
d[2]=(1-alpha)/tmp*(-1);
} else {
c[0]=0.0;
c[1]=0.0;
c[2]=0.0;
d[1]=0.0;
d[2]=0.0;
};
order=2;
break;
case 5://NOTCH 2 poles
if (zerocoefs==0) {
omega=2*PI*freq/SAMPLE_RATE;
sn=sin(omega);
cs=cos(omega);
alpha=sn/(2*sqrt(tmpq));
tmp=1+alpha;
c[0]=1/tmp;
c[1]=-2*cs/tmp;
c[2]=1/tmp;
d[1]=-2*cs/tmp*(-1);
d[2]=(1-alpha)/tmp*(-1);
} else {
c[0]=1.0;
c[1]=0.0;
c[2]=0.0;
d[1]=0.0;
d[2]=0.0;
};
order=2;
break;
case 6://PEAK (2 poles)
if (zerocoefs==0) {
omega=2*PI*freq/SAMPLE_RATE;
sn=sin(omega);
cs=cos(omega);
tmpq*=3.0;
alpha=sn/(2*tmpq);
tmp=1+alpha/tmpgain;
c[0]=(1.0+alpha*tmpgain)/tmp;
c[1]=(-2.0*cs)/tmp;
c[2]=(1.0-alpha*tmpgain)/tmp;
d[1]=-2*cs/tmp*(-1);
d[2]=(1-alpha/tmpgain)/tmp*(-1);
} else {
c[0]=1.0;
c[1]=0.0;
c[2]=0.0;
d[1]=0.0;
d[2]=0.0;
};
order=2;
break;
case 7://Low Shelf - 2 poles
if (zerocoefs==0) {
omega=2*PI*freq/SAMPLE_RATE;
sn=sin(omega);
cs=cos(omega);
tmpq=sqrt(tmpq);
alpha=sn/(2*tmpq);
beta=sqrt(tmpgain)/tmpq;
tmp=(tmpgain+1.0)+(tmpgain-1.0)*cs+beta*sn;
c[0]=tmpgain*((tmpgain+1.0)-(tmpgain-1.0)*cs+beta*sn)/tmp;
c[1]=2.0*tmpgain*((tmpgain-1.0)-(tmpgain+1.0)*cs)/tmp;
c[2]=tmpgain*((tmpgain+1.0)-(tmpgain-1.0)*cs-beta*sn)/tmp;
d[1]=-2.0*((tmpgain-1.0)+(tmpgain+1.0)*cs)/tmp*(-1);
d[2]=((tmpgain+1.0)+(tmpgain-1.0)*cs-beta*sn)/tmp*(-1);
} else {
c[0]=tmpgain;
c[1]=0.0;
c[2]=0.0;
d[1]=0.0;
d[2]=0.0;
};
order=2;
break;
case 8://High Shelf - 2 poles
if (zerocoefs==0) {
omega=2*PI*freq/SAMPLE_RATE;
sn=sin(omega);
cs=cos(omega);
tmpq=sqrt(tmpq);
alpha=sn/(2*tmpq);
beta=sqrt(tmpgain)/tmpq;
tmp=(tmpgain+1.0)-(tmpgain-1.0)*cs+beta*sn;
c[0]=tmpgain*((tmpgain+1.0)+(tmpgain-1.0)*cs+beta*sn)/tmp;
c[1]=-2.0*tmpgain*((tmpgain-1.0)+(tmpgain+1.0)*cs)/tmp;
c[2]=tmpgain*((tmpgain+1.0)+(tmpgain-1.0)*cs-beta*sn)/tmp;
d[1]=2.0*((tmpgain-1.0)-(tmpgain+1.0)*cs)/tmp*(-1);
d[2]=((tmpgain+1.0)-(tmpgain-1.0)*cs-beta*sn)/tmp*(-1);
} else {
c[0]=1.0;
c[1]=0.0;
c[2]=0.0;
d[1]=0.0;
d[2]=0.0;
};
order=2;
break;
default://wrong type
type=0;
computefiltercoefs();
break;
};
};
void AnalogFilter::setfreq(REALTYPE frequency)
{
if (frequency<0.1) frequency=0.1;
REALTYPE rap=freq/frequency;
if (rap<1.0) rap=1.0/rap;
oldabovenq=abovenq;
abovenq=frequency>(SAMPLE_RATE/2-500.0);
int nyquistthresh=(abovenq^oldabovenq);
if ((rap>3.0)||(nyquistthresh!=0)) {//if the frequency is changed fast, it needs interpolation (now, filter and coeficients backup)
for (int i=0;i<3;i++) {
oldc[i]=c[i];
oldd[i]=d[i];
};
for (int i=0;i<MAX_FILTER_STAGES+1;i++) {
oldx[i]=x[i];
oldy[i]=y[i];
};
if (firsttime==0) needsinterpolation=1;
};
freq=frequency;
computefiltercoefs();
firsttime=0;
};
void AnalogFilter::setfreq_and_q(REALTYPE frequency,REALTYPE q_)
{
q=q_;
setfreq(frequency);
};
void AnalogFilter::setq(REALTYPE q_)
{
q=q_;
computefiltercoefs();
};
void AnalogFilter::settype(int type_)
{
type=type_;
computefiltercoefs();
};
void AnalogFilter::setgain(REALTYPE dBgain)
{
gain=dB2rap(dBgain);
computefiltercoefs();
};
void AnalogFilter::setstages(int stages_)
{
if (stages_>=MAX_FILTER_STAGES) stages_=MAX_FILTER_STAGES-1;
stages=stages_;
cleanup();
computefiltercoefs();
};
void AnalogFilter::singlefilterout(REALTYPE *smp,fstage &x,fstage &y,REALTYPE *c,REALTYPE *d)
{
int i;
REALTYPE y0;
if (order==1) {//First order filter
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
y0=smp[i]*c[0]+x.c1*c[1]+y.c1*d[1];
y.c1=y0;
x.c1=smp[i];
//output
smp[i]=y0;
};
};
if (order==2) {//Second order filter
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
y0=smp[i]*c[0]+x.c1*c[1]+x.c2*c[2]+y.c1*d[1]+y.c2*d[2];
y.c2=y.c1;
y.c1=y0;
x.c2=x.c1;
x.c1=smp[i];
//output
smp[i]=y0;
};
};
};
void AnalogFilter::filterout(REALTYPE *smp)
{
REALTYPE *ismp=NULL;//used if it needs interpolation
int i;
if (needsinterpolation!=0) {
ismp=new REALTYPE[SOUND_BUFFER_SIZE];
for (i=0;i<SOUND_BUFFER_SIZE;i++) ismp[i]=smp[i];
for (i=0;i<stages+1;i++) singlefilterout(ismp,oldx[i],oldy[i],oldc,oldd);
};
for (i=0;i<stages+1;i++) singlefilterout(smp,x[i],y[i],c,d);
if (needsinterpolation!=0) {
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
REALTYPE x=i/(REALTYPE) SOUND_BUFFER_SIZE;
smp[i]=ismp[i]*(1.0-x)+smp[i]*x;
};
delete [] ismp;
needsinterpolation=0;
};
for (i=0;i<SOUND_BUFFER_SIZE;i++) smp[i]*=outgain;
};
REALTYPE AnalogFilter::H(REALTYPE freq)
{
REALTYPE fr=freq/SAMPLE_RATE*PI*2.0;
REALTYPE x=c[0],y=0.0;
for (int n=1;n<3;n++) {
x+=cos(n*fr)*c[n];
y-=sin(n*fr)*c[n];
};
REALTYPE h=x*x+y*y;
x=1.0;
y=0.0;
for (int n=1;n<3;n++) {
x-=cos(n*fr)*d[n];
y+=sin(n*fr)*d[n];
};
h=h/(x*x+y*y);
return(pow(h,(stages+1.0)/2.0));
};

View File

@@ -1,12 +1,12 @@
/*
ZynAddSubFX - a software synthesizer
Analog Filter.h - Several analog filters (lowpass, highpass...)
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
@@ -25,10 +25,13 @@
#include "../globals.h"
#include "Filter_.h"
class AnalogFilter:public Filter_{
public:
/**Implementation of Several analog filters (lowpass, highpass...)*/
class AnalogFilter:public Filter_
{
public:
AnalogFilter(unsigned char Ftype,REALTYPE Ffreq, REALTYPE Fq,unsigned char Fstages);
~AnalogFilter();
~AnalogFilter();
void filterout(REALTYPE *smp);
void setfreq(REALTYPE frequency);
void setfreq_and_q(REALTYPE frequency,REALTYPE q_);
@@ -38,14 +41,14 @@ class AnalogFilter:public Filter_{
void setgain(REALTYPE dBgain);
void setstages(int stages_);
void cleanup();
REALTYPE H(REALTYPE freq);//Obtains the response for a given frequency
private:
struct fstage{
REALTYPE c1,c2;
private:
struct fstage {
REALTYPE c1,c2;
} x[MAX_FILTER_STAGES+1],y[MAX_FILTER_STAGES+1],
oldx[MAX_FILTER_STAGES+1],oldy[MAX_FILTER_STAGES+1];
oldx[MAX_FILTER_STAGES+1],oldy[MAX_FILTER_STAGES+1];
void singlefilterout(REALTYPE *smp,fstage &x,fstage &y,REALTYPE *c,REALTYPE *d);
void computefiltercoefs();
@@ -54,7 +57,7 @@ class AnalogFilter:public Filter_{
REALTYPE freq;//Frequency given in Hz
REALTYPE q; //Q factor (resonance or Q factor)
REALTYPE gain;//the gain of the filter (if are shelf/peak) filters
int order;//the order of the filter (number of poles)
REALTYPE c[3],d[3];//coefficients
@@ -62,7 +65,7 @@ class AnalogFilter:public Filter_{
REALTYPE oldc[3],oldd[3];//old coefficients(used only if some filter paremeters changes very fast, and it needs interpolation)
REALTYPE xd[3],yd[3];//used if the filter is applied more times
int needsinterpolation,firsttime;
int needsinterpolation,firsttime;/**\todo see if bool works for these*/
int abovenq;//this is 1 if the frequency is above the nyquist
int oldabovenq;//if the last time was above nyquist (used to see if it needs interpolation)
};

View File

@@ -0,0 +1,13 @@
set(zynaddsubfx_dsp_SRCS
AnalogFilter.cpp
FFTwrapper.cpp
Filter.cpp
FormantFilter.cpp
SVFilter.cpp
)
add_library(zynaddsubfx_dsp STATIC
${zynaddsubfx_dsp_SRCS}
)
target_link_libraries(zynaddsubfx_dsp)

View File

@@ -1,12 +1,12 @@
/*
ZynAddSubFX - a software synthesizer
FFTwrapper.c - A wrapper for Fast Fourier Transforms
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
@@ -23,24 +23,26 @@
#include <math.h>
#include "FFTwrapper.h"
FFTwrapper::FFTwrapper(int fftsize_){
FFTwrapper::FFTwrapper(int fftsize_)
{
fftsize=fftsize_;
tmpfftdata1=new fftw_real[fftsize];
tmpfftdata2=new fftw_real[fftsize];
#ifdef FFTW_VERSION_2
planfftw=rfftwf_create_plan(fftsize,FFTW_REAL_TO_COMPLEX,FFTW_ESTIMATE|FFTW_IN_PLACE);
planfftwf_inv=rfftwf_create_plan(fftsize,FFTW_COMPLEX_TO_REAL,FFTW_ESTIMATE|FFTW_IN_PLACE);
planfftw=rfftw_create_plan(fftsize,FFTW_REAL_TO_COMPLEX,FFTW_ESTIMATE|FFTW_IN_PLACE);
planfftw_inv=rfftw_create_plan(fftsize,FFTW_COMPLEX_TO_REAL,FFTW_ESTIMATE|FFTW_IN_PLACE);
#else
planfftw=fftwf_plan_r2r_1d(fftsize,tmpfftdata1,tmpfftdata1,FFTW_R2HC,FFTW_ESTIMATE);
planfftw_inv=fftwf_plan_r2r_1d(fftsize,tmpfftdata2,tmpfftdata2,FFTW_HC2R,FFTW_ESTIMATE);
#endif
};
FFTwrapper::~FFTwrapper(){
FFTwrapper::~FFTwrapper()
{
#ifdef FFTW_VERSION_2
rfftwf_destroy_plan(planfftw);
rfftwf_destroy_plan(planfftwf_inv);
#else
rfftw_destroy_plan(planfftw);
rfftw_destroy_plan(planfftw_inv);
#else
fftwf_destroy_plan(planfftw);
fftwf_destroy_plan(planfftw_inv);
#endif
@@ -52,20 +54,21 @@ FFTwrapper::~FFTwrapper(){
/*
* do the Fast Fourier Transform
*/
void FFTwrapper::smps2freqs(REALTYPE *smps,FFTFREQS freqs){
void FFTwrapper::smps2freqs(REALTYPE *smps,FFTFREQS freqs)
{
#ifdef FFTW_VERSION_2
for (int i=0;i<fftsize;i++) tmpfftdata1[i]=smps[i];
rfftwf_one(planfftw,tmpfftdata1,tmpfftdata2);
rfftw_one(planfftw,tmpfftdata1,tmpfftdata2);
for (int i=0;i<fftsize/2;i++) {
freqs.c[i]=tmpfftdata2[i];
if (i!=0) freqs.s[i]=tmpfftdata2[fftsize-i];
freqs.c[i]=tmpfftdata2[i];
if (i!=0) freqs.s[i]=tmpfftdata2[fftsize-i];
};
#else
for (int i=0;i<fftsize;i++) tmpfftdata1[i]=smps[i];
fftwf_execute(planfftw);
for (int i=0;i<fftsize/2;i++) {
freqs.c[i]=tmpfftdata1[i];
if (i!=0) freqs.s[i]=tmpfftdata1[fftsize-i];
freqs.c[i]=tmpfftdata1[i];
if (i!=0) freqs.s[i]=tmpfftdata1[fftsize-i];
};
#endif
tmpfftdata2[fftsize/2]=0.0;
@@ -74,19 +77,20 @@ void FFTwrapper::smps2freqs(REALTYPE *smps,FFTFREQS freqs){
/*
* do the Inverse Fast Fourier Transform
*/
void FFTwrapper::freqs2smps(FFTFREQS freqs,REALTYPE *smps){
void FFTwrapper::freqs2smps(FFTFREQS freqs,REALTYPE *smps)
{
tmpfftdata2[fftsize/2]=0.0;
#ifdef FFTW_VERSION_2
for (int i=0;i<fftsize/2;i++) {
tmpfftdata1[i]=freqs.c[i];
if (i!=0) tmpfftdata1[fftsize-i]=freqs.s[i];
tmpfftdata1[i]=freqs.c[i];
if (i!=0) tmpfftdata1[fftsize-i]=freqs.s[i];
};
rfftwf_one(planfftwf_inv,tmpfftdata1,tmpfftdata2);
rfftw_one(planfftw_inv,tmpfftdata1,tmpfftdata2);
for (int i=0;i<fftsize;i++) smps[i]=tmpfftdata2[i];
#else
for (int i=0;i<fftsize/2;i++) {
tmpfftdata2[i]=freqs.c[i];
if (i!=0) tmpfftdata2[fftsize-i]=freqs.s[i];
tmpfftdata2[i]=freqs.c[i];
if (i!=0) tmpfftdata2[fftsize-i]=freqs.s[i];
};
fftwf_execute(planfftw_inv);
for (int i=0;i<fftsize;i++) smps[i]=tmpfftdata2[i];
@@ -94,6 +98,3 @@ void FFTwrapper::freqs2smps(FFTFREQS freqs,REALTYPE *smps){
};

View File

@@ -1,12 +1,12 @@
/*
ZynAddSubFX - a software synthesizer
FFTwrapper.h - A wrapper for Fast Fourier Transforms
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
@@ -25,20 +25,43 @@
#include "../globals.h"
#ifdef FFTW_VERSION_2
#include <fftw.h>
/* If you got error messages about rfftw.h, replace the next include line with "#include <srfftw.h>"
or with "#include <drfftw.h> (if one doesn't work try the other). It may be necessary to replace
the <fftw.h> with <dfftw.h> or <sfftw.h>. If the neither one doesn't work,
please install latest version of fftw(recomanded from the sources) from www.fftw.org.
If you'll install fftw3 you need to change the Makefile.inc
Hope all goes right." */
#include <rfftw.h>
#else
#include <fftw3.h>
#define fftw_real float
#define rfftw_plan fftwf_plan
#endif
class FFTwrapper{
public:
FFTwrapper(int fftsize_);
~FFTwrapper();
void smps2freqs(REALTYPE *smps,FFTFREQS freqs);
void freqs2smps(FFTFREQS freqs,REALTYPE *smps);
private:
int fftsize;
fftw_real *tmpfftdata1,*tmpfftdata2;
rfftw_plan planfftw,planfftw_inv;
/**A wrapper for the FFTW library (Fast Fourier Transforms)*/
class FFTwrapper
{
public:
/**Constructor
* @param fftsize The size of samples to be fed to fftw*/
FFTwrapper(int fftsize_);
/**Destructor*/
~FFTwrapper();
/**Convert Samples to Frequencies using Fourier Transform
* @param smps Pointer to Samples to be converted; has length fftsize_
* @param freqs Structure FFTFREQS which stores the frequencies*/
void smps2freqs(REALTYPE *smps,FFTFREQS freqs);
void freqs2smps(FFTFREQS freqs,REALTYPE *smps);
private:
int fftsize;
fftw_real *tmpfftdata1,*tmpfftdata2;
rfftw_plan planfftw,planfftw_inv;
};
#endif

View File

@@ -1,12 +1,12 @@
/*
ZynAddSubFX - a software synthesizer
Filter.C - Filters, uses analog,formant,etc. filters
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
@@ -25,48 +25,58 @@
#include "Filter.h"
Filter::Filter(FilterParams *pars){
Filter::Filter(FilterParams *pars)
{
unsigned char Ftype=pars->Ptype;
unsigned char Fstages=pars->Pstages;
category=pars->Pcategory;
switch (category) {
case 1:filter=new FormantFilter(pars);
break;
case 2:filter=new SVFilter(Ftype,1000.0,pars->getq(),Fstages);
filter->outgain=dB2rap(pars->getgain());
if (filter->outgain>1.0) filter->outgain=sqrt(filter->outgain);
break;
default:filter=new AnalogFilter(Ftype,1000.0,pars->getq(),Fstages);
if ((Ftype>=6)&&(Ftype<=8)) filter->setgain(pars->getgain());
else filter->outgain=dB2rap(pars->getgain());
break;
case 1:
filter=new FormantFilter(pars);
break;
case 2:
filter=new SVFilter(Ftype,1000.0,pars->getq(),Fstages);
filter->outgain=dB2rap(pars->getgain());
if (filter->outgain>1.0) filter->outgain=sqrt(filter->outgain);
break;
default:
filter=new AnalogFilter(Ftype,1000.0,pars->getq(),Fstages);
if ((Ftype>=6)&&(Ftype<=8)) filter->setgain(pars->getgain());
else filter->outgain=dB2rap(pars->getgain());
break;
};
};
Filter::~Filter(){
Filter::~Filter()
{
delete (filter);
};
void Filter::filterout(REALTYPE *smp){
void Filter::filterout(REALTYPE *smp)
{
filter->filterout(smp);
};
void Filter::setfreq(REALTYPE frequency){
void Filter::setfreq(REALTYPE frequency)
{
filter->setfreq(frequency);
};
void Filter::setfreq_and_q(REALTYPE frequency,REALTYPE q_){
void Filter::setfreq_and_q(REALTYPE frequency,REALTYPE q_)
{
filter->setfreq_and_q(frequency,q_);
};
void Filter::setq(REALTYPE q_){
void Filter::setq(REALTYPE q_)
{
filter->setq(q_);
};
REALTYPE Filter::getrealfreq(REALTYPE freqpitch){
REALTYPE Filter::getrealfreq(REALTYPE freqpitch)
{
if ((category==0)||(category==2)) return(pow(2.0,freqpitch+9.96578428));//log2(1000)=9.95748
else return(freqpitch);
else return(freqpitch);
};

View File

@@ -1,12 +1,12 @@
/*
ZynAddSubFX - a software synthesizer
Filter.h - Filters, uses analog,formant,etc. filters
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
@@ -31,17 +31,18 @@
#include "SVFilter.h"
#include "../Params/FilterParams.h"
class Filter{
public:
class Filter
{
public:
Filter(FilterParams *pars);
~Filter();
~Filter();
void filterout(REALTYPE *smp);
void setfreq(REALTYPE frequency);
void setfreq_and_q(REALTYPE frequency,REALTYPE q_);
void setq(REALTYPE q_);
REALTYPE getrealfreq(REALTYPE freqpitch);
private:
private:
Filter_ *filter;
unsigned char category;
};

View File

@@ -1,12 +1,12 @@
/*
ZynAddSubFX - a software synthesizer
Filter_.h - This class is inherited by filter classes
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
@@ -25,16 +25,17 @@
#include "../globals.h"
class Filter_{
public:
virtual ~Filter_(){};
virtual void filterout(REALTYPE *smp){};
virtual void setfreq(REALTYPE frequency){};
virtual void setfreq_and_q(REALTYPE frequency,REALTYPE q_){};
virtual void setq(REALTYPE q_){};
virtual void setgain(REALTYPE dBgain){};
class Filter_
{
public:
virtual ~Filter_() {};
virtual void filterout(REALTYPE *smp)=0;
virtual void setfreq(REALTYPE frequency)=0;
virtual void setfreq_and_q(REALTYPE frequency,REALTYPE q_)=0;
virtual void setq(REALTYPE q_)=0;
virtual void setgain(REALTYPE dBgain) {};
REALTYPE outgain;
private:
private:
};

View File

@@ -1,163 +0,0 @@
/*
ZynAddSubFX - a software synthesizer
FormantFilter.C - formant filters
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <math.h>
#include <stdio.h>
#include "FormantFilter.h"
FormantFilter::FormantFilter(FilterParams *pars){
numformants=pars->Pnumformants;
for (int i=0;i<numformants;i++) formant[i]=new AnalogFilter(4/*BPF*/,1000.0,10.0,pars->Pstages);
cleanup();
inbuffer=new REALTYPE [SOUND_BUFFER_SIZE];
tmpbuf=new REALTYPE [SOUND_BUFFER_SIZE];
for (int j=0;j<FF_MAX_VOWELS;j++)
for (int i=0;i<numformants;i++){
formantpar[j][i].freq=pars->getformantfreq(pars->Pvowels[j].formants[i].freq);
formantpar[j][i].amp=pars->getformantamp(pars->Pvowels[j].formants[i].amp);
formantpar[j][i].q=pars->getformantq(pars->Pvowels[j].formants[i].q);
};
for (int i=0;i<FF_MAX_FORMANTS;i++) oldformantamp[i]=1.0;
for (int i=0;i<numformants;i++){
currentformants[i].freq=1000.0;
currentformants[i].amp=1.0;
currentformants[i].q=2.0;
};
formantslowness=pow(1.0-(pars->Pformantslowness/128.0),3.0);
sequencesize=pars->Psequencesize;if (sequencesize==0) sequencesize=1;
for (int k=0;k<sequencesize;k++) sequence[k].nvowel=pars->Psequence[k].nvowel;
vowelclearness=pow(10.0,(pars->Pvowelclearness-32.0)/48.0);
sequencestretch=pow(0.1,(pars->Psequencestretch-32.0)/48.0);
if (pars->Psequencereversed) sequencestretch*= -1.0;
outgain=dB2rap(pars->getgain());
oldinput=-1.0;
Qfactor=1.0;oldQfactor=Qfactor;
firsttime=1;
};
FormantFilter::~FormantFilter(){
for (int i=0;i<numformants;i++) delete(formant[i]);
delete (inbuffer);
delete (tmpbuf);
};
void FormantFilter::cleanup(){
for (int i=0;i<numformants;i++) formant[i]->cleanup();
};
void FormantFilter::setpos(REALTYPE input){
int p1,p2;
if (firsttime!=0) slowinput=input;
else slowinput=slowinput*(1.0-formantslowness)+input*formantslowness;
if ((fabs(oldinput-input)<0.001)&&(fabs(slowinput-input)<0.001)&&
(fabs(Qfactor-oldQfactor)<0.001)) {
// oldinput=input; daca setez asta, o sa faca probleme la schimbari foarte lente
firsttime=0;
return;
} else oldinput=input;
REALTYPE pos=fmod(input*sequencestretch,1.0);if (pos<0.0) pos+=1.0;
F2I(pos*sequencesize,p2);
p1=p2-1;if (p1<0) p1+=sequencesize;
pos=fmod(pos*sequencesize,1.0);
if (pos<0.0) pos=0.0; else if (pos>1.0) pos=1.0;
pos=(atan((pos*2.0-1.0)*vowelclearness)/atan(vowelclearness)+1.0)*0.5;
p1=sequence[p1].nvowel;
p2=sequence[p2].nvowel;
if (firsttime!=0) {
for (int i=0;i<numformants;i++){
currentformants[i].freq=formantpar[p1][i].freq*(1.0-pos)+formantpar[p2][i].freq*pos;
currentformants[i].amp=formantpar[p1][i].amp*(1.0-pos)+formantpar[p2][i].amp*pos;
currentformants[i].q=formantpar[p1][i].q*(1.0-pos)+formantpar[p2][i].q*pos;
formant[i]->setfreq_and_q(currentformants[i].freq,currentformants[i].q*Qfactor);
oldformantamp[i]=currentformants[i].amp;
};
firsttime=0;
} else {
for (int i=0;i<numformants;i++){
currentformants[i].freq=currentformants[i].freq*(1.0-formantslowness)
+(formantpar[p1][i].freq*(1.0-pos)+formantpar[p2][i].freq*pos)*formantslowness;
currentformants[i].amp=currentformants[i].amp*(1.0-formantslowness)
+(formantpar[p1][i].amp*(1.0-pos)+formantpar[p2][i].amp*pos)*formantslowness;
currentformants[i].q=currentformants[i].q*(1.0-formantslowness)
+(formantpar[p1][i].q*(1.0-pos)+formantpar[p2][i].q*pos)*formantslowness;
formant[i]->setfreq_and_q(currentformants[i].freq,currentformants[i].q*Qfactor);
};
};
oldQfactor=Qfactor;
};
void FormantFilter::setfreq(REALTYPE frequency){
setpos(frequency);
};
void FormantFilter::setq(REALTYPE q_){
Qfactor=q_;
for (int i=0;i<numformants;i++) formant[i]->setq(Qfactor*currentformants[i].q);
};
void FormantFilter::setfreq_and_q(REALTYPE frequency,REALTYPE q_){
Qfactor=q_;
setpos(frequency);
};
void FormantFilter::filterout(REALTYPE *smp){
int i,j;
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
inbuffer[i]=smp[i];
smp[i]=0.0;
};
for (j=0;j<numformants;j++) {
for (i=0;i<SOUND_BUFFER_SIZE;i++) tmpbuf[i]=inbuffer[i]*outgain;
formant[j]->filterout(tmpbuf);
if (ABOVE_AMPLITUDE_THRESHOLD(oldformantamp[j],currentformants[j].amp))
for (i=0;i<SOUND_BUFFER_SIZE;i++) smp[i]+=tmpbuf[i]*
INTERPOLATE_AMPLITUDE(oldformantamp[j],currentformants[j].amp,i,SOUND_BUFFER_SIZE);
else for (i=0;i<SOUND_BUFFER_SIZE;i++) smp[i]+=tmpbuf[i]*currentformants[j].amp;
oldformantamp[j]=currentformants[j].amp;
};
};

View File

@@ -0,0 +1,176 @@
/*
ZynAddSubFX - a software synthesizer
FormantFilter.C - formant filters
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <math.h>
#include <stdio.h>
#include "FormantFilter.h"
FormantFilter::FormantFilter(FilterParams *pars)
{
numformants=pars->Pnumformants;
for (int i=0;i<numformants;i++) formant[i]=new AnalogFilter(4/*BPF*/,1000.0,10.0,pars->Pstages);
cleanup();
inbuffer=new REALTYPE [SOUND_BUFFER_SIZE];
tmpbuf=new REALTYPE [SOUND_BUFFER_SIZE];
for (int j=0;j<FF_MAX_VOWELS;j++)
for (int i=0;i<numformants;i++) {
formantpar[j][i].freq=pars->getformantfreq(pars->Pvowels[j].formants[i].freq);
formantpar[j][i].amp=pars->getformantamp(pars->Pvowels[j].formants[i].amp);
formantpar[j][i].q=pars->getformantq(pars->Pvowels[j].formants[i].q);
};
for (int i=0;i<FF_MAX_FORMANTS;i++) oldformantamp[i]=1.0;
for (int i=0;i<numformants;i++) {
currentformants[i].freq=1000.0;
currentformants[i].amp=1.0;
currentformants[i].q=2.0;
};
formantslowness=pow(1.0-(pars->Pformantslowness/128.0),3.0);
sequencesize=pars->Psequencesize;
if (sequencesize==0) sequencesize=1;
for (int k=0;k<sequencesize;k++) sequence[k].nvowel=pars->Psequence[k].nvowel;
vowelclearness=pow(10.0,(pars->Pvowelclearness-32.0)/48.0);
sequencestretch=pow(0.1,(pars->Psequencestretch-32.0)/48.0);
if (pars->Psequencereversed) sequencestretch*= -1.0;
outgain=dB2rap(pars->getgain());
oldinput=-1.0;
Qfactor=1.0;
oldQfactor=Qfactor;
firsttime=1;
};
FormantFilter::~FormantFilter()
{
for (int i=0;i<numformants;i++) delete(formant[i]);
delete[] inbuffer;
delete[] tmpbuf;
};
void FormantFilter::cleanup()
{
for (int i=0;i<numformants;i++) formant[i]->cleanup();
};
void FormantFilter::setpos(REALTYPE input)
{
int p1,p2;
if (firsttime!=0) slowinput=input;
else slowinput=slowinput*(1.0-formantslowness)+input*formantslowness;
if ((fabs(oldinput-input)<0.001)&&(fabs(slowinput-input)<0.001)&&
(fabs(Qfactor-oldQfactor)<0.001)) {
// oldinput=input; daca setez asta, o sa faca probleme la schimbari foarte lente
firsttime=0;
return;
} else oldinput=input;
REALTYPE pos=fmod(input*sequencestretch,1.0);
if (pos<0.0) pos+=1.0;
F2I(pos*sequencesize,p2);
p1=p2-1;
if (p1<0) p1+=sequencesize;
pos=fmod(pos*sequencesize,1.0);
if (pos<0.0) pos=0.0;
else if (pos>1.0) pos=1.0;
pos=(atan((pos*2.0-1.0)*vowelclearness)/atan(vowelclearness)+1.0)*0.5;
p1=sequence[p1].nvowel;
p2=sequence[p2].nvowel;
if (firsttime!=0) {
for (int i=0;i<numformants;i++) {
currentformants[i].freq=formantpar[p1][i].freq*(1.0-pos)+formantpar[p2][i].freq*pos;
currentformants[i].amp=formantpar[p1][i].amp*(1.0-pos)+formantpar[p2][i].amp*pos;
currentformants[i].q=formantpar[p1][i].q*(1.0-pos)+formantpar[p2][i].q*pos;
formant[i]->setfreq_and_q(currentformants[i].freq,currentformants[i].q*Qfactor);
oldformantamp[i]=currentformants[i].amp;
};
firsttime=0;
} else {
for (int i=0;i<numformants;i++) {
currentformants[i].freq=currentformants[i].freq*(1.0-formantslowness)
+(formantpar[p1][i].freq*(1.0-pos)+formantpar[p2][i].freq*pos)*formantslowness;
currentformants[i].amp=currentformants[i].amp*(1.0-formantslowness)
+(formantpar[p1][i].amp*(1.0-pos)+formantpar[p2][i].amp*pos)*formantslowness;
currentformants[i].q=currentformants[i].q*(1.0-formantslowness)
+(formantpar[p1][i].q*(1.0-pos)+formantpar[p2][i].q*pos)*formantslowness;
formant[i]->setfreq_and_q(currentformants[i].freq,currentformants[i].q*Qfactor);
};
};
oldQfactor=Qfactor;
};
void FormantFilter::setfreq(REALTYPE frequency)
{
setpos(frequency);
};
void FormantFilter::setq(REALTYPE q_)
{
Qfactor=q_;
for (int i=0;i<numformants;i++) formant[i]->setq(Qfactor*currentformants[i].q);
};
void FormantFilter::setfreq_and_q(REALTYPE frequency,REALTYPE q_)
{
Qfactor=q_;
setpos(frequency);
};
void FormantFilter::filterout(REALTYPE *smp)
{
int i,j;
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
inbuffer[i]=smp[i];
smp[i]=0.0;
};
for (j=0;j<numformants;j++) {
for (i=0;i<SOUND_BUFFER_SIZE;i++) tmpbuf[i]=inbuffer[i]*outgain;
formant[j]->filterout(tmpbuf);
if (ABOVE_AMPLITUDE_THRESHOLD(oldformantamp[j],currentformants[j].amp))
for (i=0;i<SOUND_BUFFER_SIZE;i++) smp[i]+=tmpbuf[i]*
INTERPOLATE_AMPLITUDE(oldformantamp[j],currentformants[j].amp,i,SOUND_BUFFER_SIZE);
else for (i=0;i<SOUND_BUFFER_SIZE;i++) smp[i]+=tmpbuf[i]*currentformants[j].amp;
oldformantamp[j]=currentformants[j].amp;
};
};

View File

@@ -1,12 +1,12 @@
/*
ZynAddSubFX - a software synthesizer
FormantFilter.h - formant filter
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
@@ -29,37 +29,38 @@
#include "../Params/FilterParams.h"
class FormantFilter:public Filter_{
public:
class FormantFilter:public Filter_
{
public:
FormantFilter(FilterParams *pars);
~FormantFilter();
~FormantFilter();
void filterout(REALTYPE *smp);
void setfreq(REALTYPE frequency);
void setfreq_and_q(REALTYPE frequency,REALTYPE q_);
void setq(REALTYPE q_);
void cleanup();
private:
private:
AnalogFilter *formant[FF_MAX_FORMANTS];
REALTYPE *inbuffer,*tmpbuf;
struct {
REALTYPE freq,amp,q;//frequency,amplitude,Q
REALTYPE freq,amp,q;//frequency,amplitude,Q
} formantpar[FF_MAX_VOWELS][FF_MAX_FORMANTS],currentformants[FF_MAX_FORMANTS];
struct {
unsigned char nvowel;
unsigned char nvowel;
} sequence [FF_MAX_SEQUENCE];
REALTYPE oldformantamp[FF_MAX_FORMANTS];
int sequencesize,numformants,firsttime;
REALTYPE oldinput,slowinput;
REALTYPE Qfactor,formantslowness,oldQfactor;
REALTYPE vowelclearness,sequencestretch;
void setpos(REALTYPE input);
};

View File

@@ -1,12 +1,12 @@
/*
ZynAddSubFX - a software synthesizer
SVFilter.C - Several state-variable filters
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
@@ -24,7 +24,8 @@
#include <stdio.h>
#include "SVFilter.h"
SVFilter::SVFilter(unsigned char Ftype,REALTYPE Ffreq, REALTYPE Fq,unsigned char Fstages){
SVFilter::SVFilter(unsigned char Ftype,REALTYPE Ffreq, REALTYPE Fq,unsigned char Fstages)
{
stages=Fstages;
type=Ftype;
freq=Ffreq;
@@ -38,19 +39,24 @@ SVFilter::SVFilter(unsigned char Ftype,REALTYPE Ffreq, REALTYPE Fq,unsigned char
setfreq_and_q(Ffreq,Fq);
};
SVFilter::~SVFilter(){
SVFilter::~SVFilter()
{
};
void SVFilter::cleanup(){
for (int i=0;i<MAX_FILTER_STAGES+1;i++){
st[i].low=0.0;st[i].high=0.0;
st[i].band=0.0;st[i].notch=0.0;
void SVFilter::cleanup()
{
for (int i=0;i<MAX_FILTER_STAGES+1;i++) {
st[i].low=0.0;
st[i].high=0.0;
st[i].band=0.0;
st[i].notch=0.0;
};
oldabovenq=0;
abovenq=0;
};
void SVFilter::computefiltercoefs(){
void SVFilter::computefiltercoefs()
{
par.f=freq / SAMPLE_RATE*4.0;
if (par.f>0.99999) par.f=0.99999;
par.q=1.0-atan(sqrt(q))*2.0/PI;
@@ -59,18 +65,21 @@ void SVFilter::computefiltercoefs(){
};
void SVFilter::setfreq(REALTYPE frequency){
void SVFilter::setfreq(REALTYPE frequency)
{
if (frequency<0.1) frequency=0.1;
REALTYPE rap=freq/frequency;if (rap<1.0) rap=1.0/rap;
oldabovenq=abovenq;abovenq=frequency>(SAMPLE_RATE/2-500.0);
REALTYPE rap=freq/frequency;
if (rap<1.0) rap=1.0/rap;
oldabovenq=abovenq;
abovenq=frequency>(SAMPLE_RATE/2-500.0);
int nyquistthresh=(abovenq^oldabovenq);
if ((rap>3.0)||(nyquistthresh!=0)){//if the frequency is changed fast, it needs interpolation (now, filter and coeficients backup)
if (firsttime==0) needsinterpolation=1;
ipar=par;
if ((rap>3.0)||(nyquistthresh!=0)) {//if the frequency is changed fast, it needs interpolation (now, filter and coeficients backup)
if (firsttime==0) needsinterpolation=1;
ipar=par;
};
freq=frequency;
computefiltercoefs();
@@ -78,72 +87,87 @@ void SVFilter::setfreq(REALTYPE frequency){
};
void SVFilter::setfreq_and_q(REALTYPE frequency,REALTYPE q_){
void SVFilter::setfreq_and_q(REALTYPE frequency,REALTYPE q_)
{
q=q_;
setfreq(frequency);
};
void SVFilter::setq(REALTYPE q_){
void SVFilter::setq(REALTYPE q_)
{
q=q_;
computefiltercoefs();
};
void SVFilter::settype(int type_){
void SVFilter::settype(int type_)
{
type=type_;
computefiltercoefs();
};
void SVFilter::setgain(REALTYPE dBgain){
void SVFilter::setgain(REALTYPE dBgain)
{
gain=dB2rap(dBgain);
computefiltercoefs();
};
void SVFilter::setstages(int stages_){
void SVFilter::setstages(int stages_)
{
if (stages_>=MAX_FILTER_STAGES) stages_=MAX_FILTER_STAGES-1;
stages=stages_;
cleanup();
computefiltercoefs();
};
void SVFilter::singlefilterout(REALTYPE *smp,fstage &x,parameters &par){
void SVFilter::singlefilterout(REALTYPE *smp,fstage &x,parameters &par)
{
int i;
REALTYPE *out=NULL;
switch(type){
case 0: out=&x.low;break;
case 1: out=&x.high;break;
case 2: out=&x.band;break;
case 3: out=&x.notch;break;
switch (type) {
case 0:
out=&x.low;
break;
case 1:
out=&x.high;
break;
case 2:
out=&x.band;
break;
case 3:
out=&x.notch;
break;
};
for (i=0;i<SOUND_BUFFER_SIZE;i++){
x.low = x.low + par.f * x.band;
x.high = par.q_sqrt * smp[i] - x.low - par.q*x.band;
x.band = par.f * x.high + x.band;
x.notch = x.high + x.low;
smp[i]= *out;
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
x.low = x.low + par.f * x.band;
x.high = par.q_sqrt * smp[i] - x.low - par.q*x.band;
x.band = par.f * x.high + x.band;
x.notch = x.high + x.low;
smp[i]= *out;
};
};
void SVFilter::filterout(REALTYPE *smp){
void SVFilter::filterout(REALTYPE *smp)
{
int i;
REALTYPE *ismp=NULL;
if (needsinterpolation!=0){
ismp=new REALTYPE[SOUND_BUFFER_SIZE];
for (i=0;i<SOUND_BUFFER_SIZE;i++) ismp[i]=smp[i];
for (i=0;i<stages+1;i++) singlefilterout(ismp,st[i],ipar);
if (needsinterpolation!=0) {
ismp=new REALTYPE[SOUND_BUFFER_SIZE];
for (i=0;i<SOUND_BUFFER_SIZE;i++) ismp[i]=smp[i];
for (i=0;i<stages+1;i++) singlefilterout(ismp,st[i],ipar);
};
for (i=0;i<stages+1;i++) singlefilterout(smp,st[i],par);
if (needsinterpolation!=0){
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
REALTYPE x=i/(REALTYPE) SOUND_BUFFER_SIZE;
smp[i]=ismp[i]*(1.0-x)+smp[i]*x;
};
delete [] ismp;
needsinterpolation=0;
if (needsinterpolation!=0) {
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
REALTYPE x=i/(REALTYPE) SOUND_BUFFER_SIZE;
smp[i]=ismp[i]*(1.0-x)+smp[i]*x;
};
delete [] ismp;
needsinterpolation=0;
};
for (i=0;i<SOUND_BUFFER_SIZE;i++) smp[i]*=outgain;

View File

@@ -1,12 +1,12 @@
/*
ZynAddSubFX - a software synthesizer
SV Filter.h - Several state-variable filters
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
@@ -25,10 +25,11 @@
#include "../globals.h"
#include "Filter_.h"
class SVFilter:public Filter_{
public:
class SVFilter:public Filter_
{
public:
SVFilter(unsigned char Ftype,REALTYPE Ffreq, REALTYPE Fq,unsigned char Fstages);
~SVFilter();
~SVFilter();
void filterout(REALTYPE *smp);
void setfreq(REALTYPE frequency);
void setfreq_and_q(REALTYPE frequency,REALTYPE q_);
@@ -39,13 +40,13 @@ class SVFilter:public Filter_{
void setstages(int stages_);
void cleanup();
private:
struct fstage{
REALTYPE low,high,band,notch;
private:
struct fstage {
REALTYPE low,high,band,notch;
} st[MAX_FILTER_STAGES+1];
struct parameters{
REALTYPE f,q,q_sqrt;
struct parameters {
REALTYPE f,q,q_sqrt;
}par,ipar;
@@ -56,7 +57,7 @@ class SVFilter:public Filter_{
REALTYPE freq;//Frequency given in Hz
REALTYPE q; //Q factor (resonance or Q factor)
REALTYPE gain;//the gain of the filter (if are shelf/peak) filters
int abovenq;//this is 1 if the frequency is above the nyquist
int oldabovenq;
int needsinterpolation,firsttime;

View File

@@ -1,12 +1,12 @@
/*
ZynAddSubFX - a software synthesizer
Alienwah.C - "AlienWah" effect
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
@@ -24,7 +24,7 @@
#include "Alienwah.h"
Alienwah::Alienwah(const int &insertion_,REALTYPE *const efxoutl_,REALTYPE *const efxoutr_)
:Effect(insertion_,efxoutl_,efxoutr_,NULL,0),oldl(NULL),oldr(NULL)
:Effect(insertion_,efxoutl_,efxoutr_,NULL,0),oldl(NULL),oldr(NULL)
{
setpreset(Ppreset);
cleanup();
@@ -32,7 +32,8 @@ Alienwah::Alienwah(const int &insertion_,REALTYPE *const efxoutl_,REALTYPE *cons
oldclfor=complex<REALTYPE>(fb,0.0);
};
Alienwah::~Alienwah(){
Alienwah::~Alienwah()
{
if (oldl!=NULL) delete [] oldl;
if (oldr!=NULL) delete [] oldr ;
};
@@ -41,7 +42,8 @@ Alienwah::~Alienwah(){
/*
* Apply the effect
*/
void Alienwah::out(REALTYPE *smpsl,REALTYPE *smpsr){
void Alienwah::out(REALTYPE *smpsl,REALTYPE *smpsr)
{
REALTYPE lfol,lfor; //Left/Right LFOs
complex<REALTYPE> clfol,clfor,out,tmp;
/**\todo Rework, as optimization can be used when the new complex type is
@@ -49,37 +51,37 @@ void Alienwah::out(REALTYPE *smpsl,REALTYPE *smpsr){
* Before all calculations needed to be done with individual REALTYPE,
* but now they can be done together*/
lfo.effectlfoout(&lfol,&lfor);
lfol*=depth*PI*2.0;lfor*=depth*PI*2.0;
lfol*=depth*PI*2.0;
lfor*=depth*PI*2.0;
clfol=complex<REALTYPE>(cos(lfol+phase)*fb,sin(lfol+phase)*fb); //rework
clfor=complex<REALTYPE>(cos(lfor+phase)*fb,sin(lfor+phase)*fb); //rework
for (int i=0;i<SOUND_BUFFER_SIZE;i++){/**\todo reduce significantly with
* valarray*/
REALTYPE x=((REALTYPE) i)/SOUND_BUFFER_SIZE;
REALTYPE x1=1.0-x;
//left
for (int i=0;i<SOUND_BUFFER_SIZE;i++) {
REALTYPE x=((REALTYPE) i)/SOUND_BUFFER_SIZE;
REALTYPE x1=1.0-x;
//left
tmp=clfol*x+oldclfol*x1;
out=tmp*oldl[oldk];
out.real()+=(1-fabs(fb))*smpsr[i]*(1.0-panning);
oldl[oldk]=out;
REALTYPE l=out.real()*10.0*(fb+0.1);
//right
REALTYPE l=out.real()*10.0*(fb+0.1);
//right
tmp=clfor*x+oldclfor*x1;
out=tmp*oldr[oldk];
out.real()+=(1-fabs(fb))*smpsr[i]*(1.0-panning);
oldr[oldk]=out;
REALTYPE r=out.real()*10.0*(fb+0.1);
REALTYPE r=out.real()*10.0*(fb+0.1);
if (++oldk>=Pdelay) oldk=0;
//LRcross
efxoutl[i]=l*(1.0-lrcross)+r*lrcross;
efxoutr[i]=r*(1.0-lrcross)+l*lrcross;
if (++oldk>=Pdelay) oldk=0;
//LRcross
efxoutl[i]=l*(1.0-lrcross)+r*lrcross;
efxoutr[i]=r*(1.0-lrcross)+l*lrcross;
};
oldclfol=clfol;
@@ -90,10 +92,11 @@ void Alienwah::out(REALTYPE *smpsl,REALTYPE *smpsr){
/*
* Cleanup the effect
*/
void Alienwah::cleanup(){
for (int i=0;i<Pdelay;i++) { /**\todo reduce with valarray*/
oldl[i]=complex<REALTYPE>(0.0,0.0);
oldr[i]=complex<REALTYPE>(0.0,0.0);
void Alienwah::cleanup()
{
for (int i=0;i<Pdelay;i++) {
oldl[i]=complex<REALTYPE>(0.0,0.0);
oldr[i]=complex<REALTYPE>(0.0,0.0);
};
oldk=0;
};
@@ -103,12 +106,14 @@ void Alienwah::cleanup(){
* Parameter control
*/
void Alienwah::setdepth(const unsigned char &Pdepth){
void Alienwah::setdepth(const unsigned char &Pdepth)
{
this->Pdepth=Pdepth;
depth=(Pdepth/127.0);
};
void Alienwah::setfb(const unsigned char &Pfb){
void Alienwah::setfb(const unsigned char &Pfb)
{
this->Pfb=Pfb;
fb=fabs((Pfb-64.0)/64.1);
fb=sqrt(fb);
@@ -116,29 +121,34 @@ void Alienwah::setfb(const unsigned char &Pfb){
if (Pfb<64) fb=-fb;
};
void Alienwah::setvolume(const unsigned char &Pvolume){
void Alienwah::setvolume(const unsigned char &Pvolume)
{
this->Pvolume=Pvolume;
outvolume=Pvolume/127.0;
if (insertion==0) volume=1.0;
else volume=outvolume;
else volume=outvolume;
};
void Alienwah::setpanning(const unsigned char &Ppanning){
void Alienwah::setpanning(const unsigned char &Ppanning)
{
this->Ppanning=Ppanning;
panning=Ppanning/127.0;
};
void Alienwah::setlrcross(const unsigned char &Plrcross){
void Alienwah::setlrcross(const unsigned char &Plrcross)
{
this->Plrcross=Plrcross;
lrcross=Plrcross/127.0;
};
void Alienwah::setphase(const unsigned char &Pphase){
void Alienwah::setphase(const unsigned char &Pphase)
{
this->Pphase=Pphase;
phase=(Pphase-64.0)/64.0*PI;
};
void Alienwah::setdelay(const unsigned char &Pdelay){
void Alienwah::setdelay(const unsigned char &Pdelay)
{
if (oldl!=NULL) delete [] oldl;
if (oldr!=NULL) delete [] oldr;
if (Pdelay>=MAX_ALIENWAH_DELAY) this->Pdelay=MAX_ALIENWAH_DELAY;
@@ -148,19 +158,21 @@ void Alienwah::setdelay(const unsigned char &Pdelay){
cleanup();
};
void Alienwah::setpreset(unsigned char npreset){
void Alienwah::setpreset(unsigned char npreset)
{
const int PRESET_SIZE=11;
const int NUM_PRESETS=4;
unsigned char presets[NUM_PRESETS][PRESET_SIZE]={
//AlienWah1
{127,64,70,0,0,62,60,105,25,0,64},
//AlienWah2
{127,64,73,106,0,101,60,105,17,0,64},
//AlienWah3
{127,64,63,0,1,100,112,105,31,0,42},
//AlienWah4
{93,64,25,0,1,66,101,11,47,0,86}};
//AlienWah1
{127,64,70,0,0,62,60,105,25,0,64},
//AlienWah2
{127,64,73,106,0,101,60,105,17,0,64},
//AlienWah3
{127,64,63,0,1,100,112,105,31,0,42},
//AlienWah4
{93,64,25,0,1,66,101,11,47,0,86}
};
if (npreset>=NUM_PRESETS) npreset=NUM_PRESETS-1;
for (int n=0;n<PRESET_SIZE;n++) changepar(n,presets[npreset][n]);
if (insertion==0) changepar(0,presets[npreset][0]/2);//lower the volume if this is system effect
@@ -168,63 +180,88 @@ void Alienwah::setpreset(unsigned char npreset){
};
void Alienwah::changepar(const int &npar,const unsigned char &value){
switch(npar){
case 0: setvolume(value);
break;
case 1: setpanning(value);
break;
case 2: lfo.Pfreq=value;
lfo.updateparams();
break;
case 3: lfo.Prandomness=value;
lfo.updateparams();
break;
case 4: lfo.PLFOtype=value;
lfo.updateparams();
break;
case 5: lfo.Pstereo=value;
lfo.updateparams();
break;
case 6: setdepth(value);
break;
case 7: setfb(value);
break;
case 8: setdelay(value);
break;
case 9: setlrcross(value);
break;
case 10:setphase(value);
break;
void Alienwah::changepar(const int &npar,const unsigned char &value)
{
switch (npar) {
case 0:
setvolume(value);
break;
case 1:
setpanning(value);
break;
case 2:
lfo.Pfreq=value;
lfo.updateparams();
break;
case 3:
lfo.Prandomness=value;
lfo.updateparams();
break;
case 4:
lfo.PLFOtype=value;
lfo.updateparams();
break;
case 5:
lfo.Pstereo=value;
lfo.updateparams();
break;
case 6:
setdepth(value);
break;
case 7:
setfb(value);
break;
case 8:
setdelay(value);
break;
case 9:
setlrcross(value);
break;
case 10:
setphase(value);
break;
};
};
unsigned char Alienwah::getpar(const int &npar)const{
switch (npar){
case 0: return(Pvolume);
break;
case 1: return(Ppanning);
break;
case 2: return(lfo.Pfreq);
break;
case 3: return(lfo.Prandomness);
break;
case 4: return(lfo.PLFOtype);
break;
case 5: return(lfo.Pstereo);
break;
case 6: return(Pdepth);
break;
case 7: return(Pfb);
break;
case 8: return(Pdelay);
break;
case 9: return(Plrcross);
break;
case 10:return(Pphase);
break;
default:return (0);
unsigned char Alienwah::getpar(const int &npar)const
{
switch (npar) {
case 0:
return(Pvolume);
break;
case 1:
return(Ppanning);
break;
case 2:
return(lfo.Pfreq);
break;
case 3:
return(lfo.Prandomness);
break;
case 4:
return(lfo.PLFOtype);
break;
case 5:
return(lfo.Pstereo);
break;
case 6:
return(Pdepth);
break;
case 7:
return(Pfb);
break;
case 8:
return(Pdelay);
break;
case 9:
return(Plrcross);
break;
case 10:
return(Pphase);
break;
default:
return (0);
};
};

View File

@@ -1,12 +1,12 @@
/*
ZynAddSubFX - a software synthesizer
Alienwah.h - "AlienWah" effect
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
@@ -32,50 +32,51 @@ using namespace std;
#define MAX_ALIENWAH_DELAY 100
/**"AlienWah" Effect*/
class Alienwah:public Effect {
public:
/**
* Constructor
* @param insetion_ 1 for insertion Effect, 0 for others
* @param efxoutl_ Pointer to Alienwah's left channel output buffer
* @param efxoutr_ Pointer to Alienwah's left channel output buffer
* @return Initialized Alienwah
*/
Alienwah(const int &insetion_,REALTYPE *const efxoutl_,REALTYPE *const efxoutr_);
~Alienwah();
void out(REALTYPE *const smpsl,REALTYPE *const smpsr);
class Alienwah:public Effect
{
public:
/**
* Constructor
* @param insetion_ 1 for insertion Effect, 0 for others
* @param efxoutl_ Pointer to Alienwah's left channel output buffer
* @param efxoutr_ Pointer to Alienwah's left channel output buffer
* @return Initialized Alienwah
*/
Alienwah(const int &insetion_,REALTYPE *const efxoutl_,REALTYPE *const efxoutr_);
~Alienwah();
void out(REALTYPE *const smpsl,REALTYPE *const smpsr);
void setpreset(unsigned char npreset);
void changepar(const int &npar,const unsigned char &value);
unsigned char getpar(const int &npar)const;
void cleanup();
private:
//Alienwah Parameters
EffectLFO lfo;//lfo-ul Alienwah
unsigned char Pvolume;
unsigned char Ppanning;
unsigned char Pdepth;//the depth of the Alienwah
unsigned char Pfb;//feedback
unsigned char Plrcross;//feedback
unsigned char Pdelay;
unsigned char Pphase;
void setpreset(unsigned char npreset);
void changepar(const int &npar,const unsigned char &value);
unsigned char getpar(const int &npar)const;
void cleanup();
//Control Parameters
void setvolume(const unsigned char &Pvolume);
void setpanning(const unsigned char &Ppanning);
void setdepth(const unsigned char &Pdepth);
void setfb(const unsigned char &Pfb);
void setlrcross(const unsigned char &Plrcross);
void setdelay(const unsigned char &Pdelay);
void setphase(const unsigned char &Pphase);
//Internal Values
REALTYPE panning,fb,depth,lrcross,phase;
complex<REALTYPE> *oldl,*oldr;
complex<REALTYPE> oldclfol,oldclfor;
int oldk;
private:
//Alienwah Parameters
EffectLFO lfo;//lfo-ul Alienwah
unsigned char Pvolume;
unsigned char Ppanning;
unsigned char Pdepth;//the depth of the Alienwah
unsigned char Pfb;//feedback
unsigned char Plrcross;//feedback
unsigned char Pdelay;
unsigned char Pphase;
//Control Parameters
void setvolume(const unsigned char &Pvolume);
void setpanning(const unsigned char &Ppanning);
void setdepth(const unsigned char &Pdepth);
void setfb(const unsigned char &Pfb);
void setlrcross(const unsigned char &Plrcross);
void setdelay(const unsigned char &Pdelay);
void setphase(const unsigned char &Pphase);
//Internal Values
REALTYPE panning,fb,depth,lrcross,phase;
complex<REALTYPE> *oldl,*oldr;
complex<REALTYPE> oldclfol,oldclfor;
int oldk;
};
#endif

View File

@@ -0,0 +1,19 @@
set(zynaddsubfx_effect_SRCS
Alienwah.cpp
Chorus.cpp
Distorsion.cpp
DynamicFilter.cpp
Echo.cpp
Effect.cpp
EffectLFO.cpp
EffectMgr.cpp
EQ.cpp
Phaser.cpp
Reverb.cpp
)
add_library(zynaddsubfx_effect STATIC
${zynaddsubfx_effect_SRCS}
)
target_link_libraries(zynaddsubfx_effect)

View File

@@ -1,275 +0,0 @@
/*
ZynAddSubFX - a software synthesizer
Chorus.C - Chorus and Flange effects
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <cmath>
#include "Chorus.h"
#include <iostream>
using namespace std;
Chorus::Chorus(const int &insertion_,REALTYPE *const efxoutl_,REALTYPE *const efxoutr_)
:Effect(insertion_,efxoutl_,efxoutr_,NULL,0)
{
dlk=0;drk=0;
maxdelay=(int)(MAX_CHORUS_DELAY/1000.0*SAMPLE_RATE);
delayl=new REALTYPE[maxdelay];
delayr=new REALTYPE[maxdelay];
setpreset(Ppreset);
lfo.effectlfoout(&lfol,&lfor);
dl2=getdelay(lfol);
dr2=getdelay(lfor);
cleanup();
};
Chorus::~Chorus(){
delete [] delayl;
delete [] delayr;
};
/*
* get the delay value in samples; xlfo is the current lfo value
*/
REALTYPE Chorus::getdelay(REALTYPE xlfo){
REALTYPE result;
if (Pflangemode==0){
result=(delay+xlfo*depth)*SAMPLE_RATE;
} else result=0;
//check if it is too big delay(caused bu errornous setdelay() and setdepth()
/**\todo fix setdelay() and setdepth(), so this error cannot occur*/
if ((result+0.5)>=maxdelay) {
cerr << "WARNING: Chorus.C::getdelay(..) too big delay (see setdelay and setdepth funcs.)\n";
result=maxdelay-1.0;
};
return(result);
};
/*
* Apply the effect
*/
void Chorus::out(REALTYPE *smpsl,REALTYPE *smpsr){
int i;
const REALTYPE one=1.0;
dl1=dl2;dr1=dr2;
lfo.effectlfoout(&lfol,&lfor);
dl2=getdelay(lfol);
dr2=getdelay(lfor);
for (i=0;i<SOUND_BUFFER_SIZE;i++){
REALTYPE inl=smpsl[i];
REALTYPE inr=smpsr[i];
//LRcross
REALTYPE l=inl;
REALTYPE r=inr;
inl=l*(1.0-lrcross)+r*lrcross;
inr=r*(1.0-lrcross)+l*lrcross;
//Left channel
//compute the delay in samples using linear interpolation between the lfo delays
mdel=(dl1*(SOUND_BUFFER_SIZE-i)+dl2*i)/SOUND_BUFFER_SIZE;
if (++dlk>=maxdelay) dlk=0;
REALTYPE tmp=dlk-mdel+maxdelay*2.0;//where should I get the sample from
F2I(tmp,dlhi);
dlhi%=maxdelay;
dlhi2=(dlhi-1+maxdelay)%maxdelay;
dllo=1.0-fmod(tmp,one);
efxoutl[i]=delayl[dlhi2]*dllo+delayl[dlhi]*(1.0-dllo);
delayl[dlk]=inl+efxoutl[i]*fb;
//Right channel
//compute the delay in samples using linear interpolation between the lfo delays
mdel=(dr1*(SOUND_BUFFER_SIZE-i)+dr2*i)/SOUND_BUFFER_SIZE;
if (++drk>=maxdelay) drk=0;
tmp=drk*1.0-mdel+maxdelay*2.0;//where should I get the sample from
F2I(tmp,dlhi);
dlhi%=maxdelay;
dlhi2=(dlhi-1+maxdelay)%maxdelay;
dllo=1.0-fmod(tmp,one);
efxoutr[i]=delayr[dlhi2]*dllo+delayr[dlhi]*(1.0-dllo);
delayr[dlk]=inr+efxoutr[i]*fb;
};
if (Poutsub!=0)
for (i=0;i<SOUND_BUFFER_SIZE;i++){
efxoutl[i] *= -1.0;
efxoutr[i] *= -1.0;
};
for (int i=0;i<SOUND_BUFFER_SIZE;i++){
efxoutl[i]*=panning;
efxoutr[i]*=(1.0-panning);
};
};
/*
* Cleanup the effect
*/
void Chorus::cleanup(){
for (int i=0;i<maxdelay;i++){
delayl[i]=0.0;
delayr[i]=0.0;
};
};
/*
* Parameter control
*/
void Chorus::setdepth(const unsigned char &Pdepth){
this->Pdepth=Pdepth;
depth=(pow(8.0,(Pdepth/127.0)*2.0)-1.0)/1000.0;//seconds
};
void Chorus::setdelay(const unsigned char &Pdelay){
this->Pdelay=Pdelay;
delay=(pow(10.0,(Pdelay/127.0)*2.0)-1.0)/1000.0;//seconds
};
void Chorus::setfb(const unsigned char &Pfb){
this->Pfb=Pfb;
fb=(Pfb-64.0)/64.1;
};
void Chorus::setvolume(const unsigned char &Pvolume){
this->Pvolume=Pvolume;
outvolume=Pvolume/127.0;
if (insertion==0) volume=1.0;
else volume=outvolume;
};
void Chorus::setpanning(const unsigned char &Ppanning){
this->Ppanning=Ppanning;
panning=Ppanning/127.0;
};
void Chorus::setlrcross(const unsigned char &Plrcross){
this->Plrcross=Plrcross;
lrcross=Plrcross/127.0;
};
void Chorus::setpreset(unsigned char npreset){
const int PRESET_SIZE=12;
const int NUM_PRESETS=10;
unsigned char presets[NUM_PRESETS][PRESET_SIZE]={
//Chorus1
{64,64,50,0,0,90,40,85,64,119,0,0},
//Chorus2
{64,64,45,0,0,98,56,90,64,19,0,0},
//Chorus3
{64,64,29,0,1,42,97,95,90,127,0,0},
//Celeste1
{64,64,26,0,0,42,115,18,90,127,0,0},
//Celeste2
{64,64,29,117,0,50,115,9,31,127,0,1},
//Flange1
{64,64,57,0,0,60,23,3,62,0,0,0},
//Flange2
{64,64,33,34,1,40,35,3,109,0,0,0},
//Flange3
{64,64,53,34,1,94,35,3,54,0,0,1},
//Flange4
{64,64,40,0,1,62,12,19,97,0,0,0},
//Flange5
{64,64,55,105,0,24,39,19,17,0,0,1}};
if (npreset>=NUM_PRESETS) npreset=NUM_PRESETS-1;
for (int n=0;n<PRESET_SIZE;n++) changepar(n,presets[npreset][n]);
Ppreset=npreset;
};
void Chorus::changepar(const int &npar,const unsigned char &value){
switch(npar){
case 0: setvolume(value);
break;
case 1: setpanning(value);
break;
case 2: lfo.Pfreq=value;
lfo.updateparams();
break;
case 3: lfo.Prandomness=value;
lfo.updateparams();
break;
case 4: lfo.PLFOtype=value;
lfo.updateparams();
break;
case 5: lfo.Pstereo=value;
lfo.updateparams();
break;
case 6: setdepth(value);
break;
case 7: setdelay(value);
break;
case 8: setfb(value);
break;
case 9: setlrcross(value);
break;
case 10:if (value>1) Pflangemode=1;
else Pflangemode=value;
break;
case 11:if (value>1) Poutsub=1;
else Poutsub=value;
break;
};
};
unsigned char Chorus::getpar(const int &npar)const{
switch (npar){
case 0: return(Pvolume);
break;
case 1: return(Ppanning);
break;
case 2: return(lfo.Pfreq);
break;
case 3: return(lfo.Prandomness);
break;
case 4: return(lfo.PLFOtype);
break;
case 5: return(lfo.Pstereo);
break;
case 6: return(Pdepth);
break;
case 7: return(Pdelay);
break;
case 8: return(Pfb);
break;
case 9: return(Plrcross);
break;
case 10:return(Pflangemode);
break;
case 11:return(Poutsub);
break;
default:return (0);
};
};

View File

@@ -0,0 +1,316 @@
/*
ZynAddSubFX - a software synthesizer
Chorus.C - Chorus and Flange effects
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <cmath>
#include "Chorus.h"
#include <iostream>
using namespace std;
Chorus::Chorus(const int &insertion_,REALTYPE *const efxoutl_,REALTYPE *const efxoutr_)
:Effect(insertion_,efxoutl_,efxoutr_,NULL,0),
maxdelay((int)(MAX_CHORUS_DELAY/1000.0*SAMPLE_RATE)),
delaySample(maxdelay)
{
dlk=0;
drk=0;
//maxdelay=(int)(MAX_CHORUS_DELAY/1000.0*SAMPLE_RATE);
//delayl=new REALTYPE[maxdelay];
//delayr=new REALTYPE[maxdelay];
setpreset(Ppreset);
lfo.effectlfoout(&lfol,&lfor);
dl2=getdelay(lfol);
dr2=getdelay(lfor);
cleanup();
};
Chorus::~Chorus() {};
/*
* get the delay value in samples; xlfo is the current lfo value
*/
REALTYPE Chorus::getdelay(REALTYPE xlfo)
{
REALTYPE result;
if (Pflangemode==0) {
result=(delay+xlfo*depth)*SAMPLE_RATE;
} else result=0;
//check if it is too big delay(caused bu errornous setdelay() and setdepth()
/**\todo fix setdelay() and setdepth(), so this error cannot occur*/
if ((result+0.5)>=maxdelay) {
cerr << "WARNING: Chorus.C::getdelay(..) too big delay (see setdelay and setdepth funcs.)\n";
result=maxdelay-1.0;
};
return(result);
};
/*
* Apply the effect
*/
void Chorus::out(REALTYPE *smpsl,REALTYPE *smpsr)
{
const Stereo<AuSample> input(AuSample(SOUND_BUFFER_SIZE,smpsl),AuSample(SOUND_BUFFER_SIZE,smpsr));
out(input);
}
void Chorus::out(const Stereo<AuSample> &input)
{
const REALTYPE one=1.0;
dl1=dl2;
dr1=dr2;
lfo.effectlfoout(&lfol,&lfor);
dl2=getdelay(lfol);
dr2=getdelay(lfor);
for (int i=0;i<input.l().size();i++) {
REALTYPE inl=input.l()[i];
REALTYPE inr=input.r()[i];
//LRcross
Stereo<REALTYPE> tmpc(inl,inr);
//REALTYPE r=inr;
inl=tmpc.l()*(1.0-lrcross)+tmpc.r()*lrcross;
inr=tmpc.r()*(1.0-lrcross)+tmpc.l()*lrcross;
//Left channel
//compute the delay in samples using linear interpolation between the lfo delays
mdel=(dl1*(SOUND_BUFFER_SIZE-i)+dl2*i)/SOUND_BUFFER_SIZE;
if (++dlk>=maxdelay) dlk=0;
REALTYPE tmp=dlk-mdel+maxdelay*2.0;//where should I get the sample from
F2I(tmp,dlhi);
dlhi%=maxdelay;
dlhi2=(dlhi-1+maxdelay)%maxdelay;
dllo=1.0-fmod(tmp,one);
efxoutl[i]=delaySample.l()[dlhi2]*dllo+delaySample.l()[dlhi]*(1.0-dllo);
delaySample.l()[dlk]=inl+efxoutl[i]*fb;
//Right channel
//compute the delay in samples using linear interpolation between the lfo delays
mdel=(dr1*(SOUND_BUFFER_SIZE-i)+dr2*i)/SOUND_BUFFER_SIZE;
if (++drk>=maxdelay) drk=0;
tmp=drk*1.0-mdel+maxdelay*2.0;//where should I get the sample from
F2I(tmp,dlhi);
dlhi%=maxdelay;
dlhi2=(dlhi-1+maxdelay)%maxdelay;
dllo=1.0-fmod(tmp,one);
efxoutr[i]=delaySample.r()[dlhi2]*dllo+delaySample.r()[dlhi]*(1.0-dllo);
delaySample.r()[dlk]=inr+efxoutr[i]*fb;
};
if (Poutsub!=0)
for (int i=0;i<input.l().size();i++) {
efxoutl[i] *= -1.0;
efxoutr[i] *= -1.0;
};
for (int i=0;i<input.l().size();i++) {
efxoutl[i]*=panning;
efxoutr[i]*=(1.0-panning);
};
};
/*
* Cleanup the effect
*/
void Chorus::cleanup()
{
delaySample.l().clear();
delaySample.r().clear();
};
/*
* Parameter control
*/
void Chorus::setdepth(const unsigned char &Pdepth)
{
this->Pdepth=Pdepth;
depth=(pow(8.0,(Pdepth/127.0)*2.0)-1.0)/1000.0;//seconds
};
void Chorus::setdelay(const unsigned char &Pdelay)
{
this->Pdelay=Pdelay;
delay=(pow(10.0,(Pdelay/127.0)*2.0)-1.0)/1000.0;//seconds
};
void Chorus::setfb(const unsigned char &Pfb)
{
this->Pfb=Pfb;
fb=(Pfb-64.0)/64.1;
};
void Chorus::setvolume(const unsigned char &Pvolume)
{
this->Pvolume=Pvolume;
outvolume=Pvolume/127.0;
if (insertion==0) volume=1.0;
else volume=outvolume;
};
void Chorus::setpanning(const unsigned char &Ppanning)
{
this->Ppanning=Ppanning;
panning=Ppanning/127.0;
};
void Chorus::setlrcross(const unsigned char &Plrcross)
{
this->Plrcross=Plrcross;
lrcross=Plrcross/127.0;
};
void Chorus::setpreset(unsigned char npreset)
{
const int PRESET_SIZE=12;
const int NUM_PRESETS=10;
unsigned char presets[NUM_PRESETS][PRESET_SIZE]={
//Chorus1
{64,64,50,0,0,90,40,85,64,119,0,0},
//Chorus2
{64,64,45,0,0,98,56,90,64,19,0,0},
//Chorus3
{64,64,29,0,1,42,97,95,90,127,0,0},
//Celeste1
{64,64,26,0,0,42,115,18,90,127,0,0},
//Celeste2
{64,64,29,117,0,50,115,9,31,127,0,1},
//Flange1
{64,64,57,0,0,60,23,3,62,0,0,0},
//Flange2
{64,64,33,34,1,40,35,3,109,0,0,0},
//Flange3
{64,64,53,34,1,94,35,3,54,0,0,1},
//Flange4
{64,64,40,0,1,62,12,19,97,0,0,0},
//Flange5
{64,64,55,105,0,24,39,19,17,0,0,1}
};
if (npreset>=NUM_PRESETS) npreset=NUM_PRESETS-1;
for (int n=0;n<PRESET_SIZE;n++) changepar(n,presets[npreset][n]);
Ppreset=npreset;
};
void Chorus::changepar(const int &npar,const unsigned char &value)
{
switch (npar) {
case 0:
setvolume(value);
break;
case 1:
setpanning(value);
break;
case 2:
lfo.Pfreq=value;
lfo.updateparams();
break;
case 3:
lfo.Prandomness=value;
lfo.updateparams();
break;
case 4:
lfo.PLFOtype=value;
lfo.updateparams();
break;
case 5:
lfo.Pstereo=value;
lfo.updateparams();
break;
case 6:
setdepth(value);
break;
case 7:
setdelay(value);
break;
case 8:
setfb(value);
break;
case 9:
setlrcross(value);
break;
case 10:
if (value>1) Pflangemode=1;
else Pflangemode=value;
break;
case 11:
if (value>1) Poutsub=1;
else Poutsub=value;
break;
};
};
unsigned char Chorus::getpar(const int &npar)const
{
switch (npar) {
case 0:
return(Pvolume);
break;
case 1:
return(Ppanning);
break;
case 2:
return(lfo.Pfreq);
break;
case 3:
return(lfo.Prandomness);
break;
case 4:
return(lfo.PLFOtype);
break;
case 5:
return(lfo.Pstereo);
break;
case 6:
return(Pdepth);
break;
case 7:
return(Pdelay);
break;
case 8:
return(Pfb);
break;
case 9:
return(Plrcross);
break;
case 10:
return(Pflangemode);
break;
case 11:
return(Poutsub);
break;
default:
return (0);
};
};

View File

@@ -1,12 +1,12 @@
/*
ZynAddSubFX - a software synthesizer
Chorus.h - Chorus and Flange effects
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
@@ -25,86 +25,91 @@
#include "../globals.h"
#include "Effect.h"
#include "EffectLFO.h"
#include "../Samples/AuSample.h"
#include "../Misc/Stereo.h"
#define MAX_CHORUS_DELAY 250.0 //ms
/**Chorus and Flange effects*/
class Chorus:public Effect {
public:
Chorus(const int &insetion_,REALTYPE *efxoutl_,REALTYPE *efxoutr_);
/**Destructor*/
~Chorus();
void out(REALTYPE *smpsl,REALTYPE *smpsr);
void setpreset(unsigned char npreset);
/**
* Sets the value of the chosen variable
*
* The possible parameters are:
* -# Volume
* -# Panning
* -# LFO Frequency
* -# LFO Randomness
* -# LFO Type
* -# LFO stereo
* -# Depth
* -# Delay
* -# Feedback
* -# Flange Mode
* -# Subtractive
* @param npar number of chosen parameter
* @param value the new value
*/
void changepar(const int &npar,const unsigned char &value);
/**
* Gets the value of the chosen variable
*
* The possible parameters are:
* -# Volume
* -# Panning
* -# LFO Frequency
* -# LFO Randomness
* -# LFO Type
* -# LFO stereo
* -# Depth
* -# Delay
* -# Feedback
* -# Flange Mode
* -# Subtractive
* @param npar number of chosen parameter
* @return the value of the parameter
*/
unsigned char getpar(const int &npar)const;
void cleanup();
private:
//Chorus Parameters
EffectLFO lfo;//lfo-ul chorus
unsigned char Pvolume;
unsigned char Ppanning;
unsigned char Pdepth;//the depth of the Chorus(ms)
unsigned char Pdelay;//the delay (ms)
unsigned char Pfb;//feedback
unsigned char Plrcross;//feedback
unsigned char Pflangemode;//how the LFO is scaled, to result chorus or flange
unsigned char Poutsub;//if I wish to substract the output instead of the adding it
class Chorus:public Effect
{
public:
Chorus(const int &insetion_,REALTYPE *efxoutl_,REALTYPE *efxoutr_);
/**Destructor*/
~Chorus();
void out(REALTYPE *smpsl,REALTYPE *smpsr);
void out(const Stereo<AuSample> &input);
void setpreset(unsigned char npreset);
/**
* Sets the value of the chosen variable
*
* The possible parameters are:
* -# Volume
* -# Panning
* -# LFO Frequency
* -# LFO Randomness
* -# LFO Type
* -# LFO stereo
* -# Depth
* -# Delay
* -# Feedback
* -# Flange Mode
* -# Subtractive
* @param npar number of chosen parameter
* @param value the new value
*/
void changepar(const int &npar,const unsigned char &value);
/**
* Gets the value of the chosen variable
*
* The possible parameters are:
* -# Volume
* -# Panning
* -# LFO Frequency
* -# LFO Randomness
* -# LFO Type
* -# LFO stereo
* -# Depth
* -# Delay
* -# Feedback
* -# Flange Mode
* -# Subtractive
* @param npar number of chosen parameter
* @return the value of the parameter
*/
unsigned char getpar(const int &npar)const;
void cleanup();
//Parameter Controls
void setvolume(const unsigned char &Pvolume);
void setpanning(const unsigned char &Ppanning);
void setdepth(const unsigned char &Pdepth);
void setdelay(const unsigned char &Pdelay);
void setfb(const unsigned char &Pfb);
void setlrcross(const unsigned char &Plrcross);
private:
//Chorus Parameters
EffectLFO lfo;//lfo-ul chorus
unsigned char Pvolume;
unsigned char Ppanning;
unsigned char Pdepth;//the depth of the Chorus(ms)
unsigned char Pdelay;//the delay (ms)
unsigned char Pfb;//feedback
unsigned char Plrcross;//feedback
unsigned char Pflangemode;//how the LFO is scaled, to result chorus or flange
unsigned char Poutsub;//if I wish to substract the output instead of the adding it
//Internal Values
REALTYPE depth,delay,fb,lrcross,panning;
REALTYPE dl1,dl2,dr1,dr2,lfol,lfor;
int maxdelay;
REALTYPE *delayl,*delayr;
int dlk,drk,dlhi,dlhi2;
REALTYPE getdelay(REALTYPE xlfo);
REALTYPE dllo,mdel;
//Parameter Controls
void setvolume(const unsigned char &Pvolume);
void setpanning(const unsigned char &Ppanning);
void setdepth(const unsigned char &Pdepth);
void setdelay(const unsigned char &Pdelay);
void setfb(const unsigned char &Pfb);
void setlrcross(const unsigned char &Plrcross);
//Internal Values
REALTYPE depth,delay,fb,lrcross,panning;
REALTYPE dl1,dl2,dr1,dr2,lfol,lfor;
int maxdelay;
Stereo<AuSample> delaySample;
//REALTYPE *delayl,*delayr;
int dlk,drk,dlhi,dlhi2;
REALTYPE getdelay(REALTYPE xlfo);
REALTYPE dllo,mdel;
};
#endif

View File

@@ -1,376 +0,0 @@
/*
ZynAddSubFX - a software synthesizer
Distorsion.C - Distorsion effect
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <cmath>
#include "Distorsion.h"
/*
* Waveshape (this is called by OscilGen::waveshape and Distorsion::process)
*/
void waveshapesmps(int n,REALTYPE *smps,unsigned char type,unsigned char drive){
int i;
REALTYPE ws=drive/127.0;
REALTYPE tmpv;
switch(type){
case 1: ws=pow(10,ws*ws*3.0)-1.0+0.001;//Arctangent
for (i=0;i<n;i++)
smps[i]=atan(smps[i]*ws)/atan(ws);
break;
case 2: ws=ws*ws*32.0+0.0001;//Asymmetric
if (ws<1.0) tmpv=sin(ws)+0.1;
else tmpv=1.1;
for (i=0;i<n;i++) {
smps[i]=sin(smps[i]*(0.1+ws-ws*smps[i]))/tmpv;
};
break;
case 3: ws=ws*ws*ws*20.0+0.0001;//Pow
for (i=0;i<n;i++) {
smps[i]*=ws;
if (fabs(smps[i])<1.0) {
smps[i]=(smps[i]-pow(smps[i],3.0))*3.0;
if (ws<1.0) smps[i]/=ws;
} else smps[i]=0.0;
};
break;
case 4: ws=ws*ws*ws*32.0+0.0001;//Sine
if (ws<1.57) tmpv=sin(ws);
else tmpv=1.0;
for (i=0;i<n;i++) smps[i]=sin(smps[i]*ws)/tmpv;
break;
case 5: ws=ws*ws+0.000001;//Quantisize
for (i=0;i<n;i++)
smps[i]=floor(smps[i]/ws+0.5)*ws;
break;
case 6: ws=ws*ws*ws*32+0.0001;//Zigzag
if (ws<1.0) tmpv=sin(ws);
else tmpv=1.0;
for (i=0;i<n;i++)
smps[i]=asin(sin(smps[i]*ws))/tmpv;
break;
case 7: ws=pow(2.0,-ws*ws*8.0); //Limiter
for (i=0;i<n;i++) {
REALTYPE tmp=smps[i];
if (fabs(tmp)>ws) {
if (tmp>=0.0) smps[i]=1.0;
else smps[i]=-1.0;
} else smps[i]/=ws;
};
break;
case 8: ws=pow(2.0,-ws*ws*8.0); //Upper Limiter
for (i=0;i<n;i++) {
REALTYPE tmp=smps[i];
if (tmp>ws) smps[i]=ws;
smps[i]*=2.0;
};
break;
case 9: ws=pow(2.0,-ws*ws*8.0); //Lower Limiter
for (i=0;i<n;i++) {
REALTYPE tmp=smps[i];
if (tmp<-ws) smps[i]=-ws;
smps[i]*=2.0;
};
break;
case 10:ws=(pow(2.0,ws*6.0)-1.0)/pow(2.0,6.0); //Inverse Limiter
for (i=0;i<n;i++) {
REALTYPE tmp=smps[i];
if (fabs(tmp)>ws) {
if (tmp>=0.0) smps[i]=tmp-ws;
else smps[i]=tmp+ws;
} else smps[i]=0;
};
break;
case 11:ws=pow(5,ws*ws*1.0)-1.0;//Clip
for (i=0;i<n;i++)
smps[i]=smps[i]*(ws+0.5)*0.9999-floor(0.5+smps[i]*(ws+0.5)*0.9999);
break;
case 12:ws=ws*ws*ws*30+0.001;//Asym2
if (ws<0.3) tmpv=ws;
else tmpv=1.0;
for (i=0;i<n;i++) {
REALTYPE tmp=smps[i]*ws;
if ((tmp>-2.0) && (tmp<1.0)) smps[i]=tmp*(1.0-tmp)*(tmp+2.0)/tmpv;
else smps[i]=0.0;
};
break;
case 13:ws=ws*ws*ws*32.0+0.0001;//Pow2
if (ws<1.0) tmpv=ws*(1+ws)/2.0;
else tmpv=1.0;
for (i=0;i<n;i++) {
REALTYPE tmp=smps[i]*ws;
if ((tmp>-1.0)&&(tmp<1.618034)) smps[i]=tmp*(1.0-tmp)/tmpv;
else if (tmp>0.0) smps[i]=-1.0;
else smps[i]=-2.0;
};
break;
case 14:ws=pow(ws,5.0)*80.0+0.0001;//sigmoid
if (ws>10.0) tmpv=0.5;
else tmpv=0.5-1.0/(exp(ws)+1.0);
for (i=0;i<n;i++) {
REALTYPE tmp=smps[i]*ws;
if (tmp<-10.0) tmp=-10.0;
else if (tmp>10.0) tmp=10.0;
tmp=0.5-1.0/(exp(tmp)+1.0);
smps[i]=tmp/tmpv;
};
break;
/**\todo update to Distorsion::changepar (Ptype max) if there is added more waveshapings functions*/
};
};
Distorsion::Distorsion(const int &insertion_,REALTYPE *efxoutl_,REALTYPE *efxoutr_)
:Effect(insertion_,efxoutl_,efxoutr_,NULL,0)
{
lpfl=new AnalogFilter(2,22000,1,0);
lpfr=new AnalogFilter(2,22000,1,0);
hpfl=new AnalogFilter(3,20,1,0);
hpfr=new AnalogFilter(3,20,1,0);
//default values
Pvolume=50;
Plrcross=40;
Pdrive=90;
Plevel=64;
Ptype=0;
Pnegate=0;
Plpf=127;
Phpf=0;
Pstereo=0;
Pprefiltering=0;
setpreset(Ppreset);
cleanup();
};
Distorsion::~Distorsion(){
delete lpfl;
delete lpfr;
delete hpfl;
delete hpfr;
};
/*
* Cleanup the effect
*/
void Distorsion::cleanup(){
lpfl->cleanup();
hpfl->cleanup();
lpfr->cleanup();
hpfr->cleanup();
};
/*
* Apply the filters
*/
void Distorsion::applyfilters(REALTYPE *efxoutl,REALTYPE *efxoutr){
lpfl->filterout(efxoutl);
hpfl->filterout(efxoutl);
if (Pstereo!=0){//stereo
lpfr->filterout(efxoutr);
hpfr->filterout(efxoutr);
};
};
/*
* Effect output
*/
void Distorsion::out(REALTYPE *smpsl,REALTYPE *smpsr){
int i;
REALTYPE l,r,lout,rout;
REALTYPE inputvol=pow(5.0,(Pdrive-32.0)/127.0);
if (Pnegate!=0) inputvol*=-1.0;
if (Pstereo!=0){//Stereo
for (i=0;i<SOUND_BUFFER_SIZE;i++){
efxoutl[i]=smpsl[i]*inputvol*panning;
efxoutr[i]=smpsr[i]*inputvol*(1.0-panning);
};
} else {
for (i=0;i<SOUND_BUFFER_SIZE;i++){
efxoutl[i]=( smpsl[i]*panning + smpsr[i]*(1.0-panning) ) * inputvol;
};
};
if (Pprefiltering!=0) applyfilters(efxoutl,efxoutr);
//no optimised, yet (no look table)
waveshapesmps(SOUND_BUFFER_SIZE,efxoutl,Ptype+1,Pdrive);
if (Pstereo!=0) waveshapesmps(SOUND_BUFFER_SIZE,efxoutr,Ptype+1,Pdrive);
if (Pprefiltering==0) applyfilters(efxoutl,efxoutr);
if (Pstereo==0) for (i=0;i<SOUND_BUFFER_SIZE;i++) efxoutr[i]=efxoutl[i];
REALTYPE level=dB2rap(60.0*Plevel/127.0-40.0);
for (i=0;i<SOUND_BUFFER_SIZE;i++){
lout=efxoutl[i];
rout=efxoutr[i];
l=lout*(1.0-lrcross)+rout*lrcross;
r=rout*(1.0-lrcross)+lout*lrcross;
lout=l;rout=r;
efxoutl[i]=lout*2.0*level;
efxoutr[i]=rout*2.0*level;
};
};
/*
* Parameter control
*/
void Distorsion::setvolume(const unsigned char &Pvolume){
this->Pvolume=Pvolume;
if (insertion==0) {
outvolume=pow(0.01,(1.0-Pvolume/127.0))*4.0;
volume=1.0;
} else {
volume=outvolume=Pvolume/127.0;
};
if (Pvolume==0) cleanup();
};
void Distorsion::setpanning(const unsigned char &Ppanning){
this->Ppanning=Ppanning;
panning=(Ppanning+0.5)/127.0;
};
void Distorsion::setlrcross(const unsigned char &Plrcross){
this->Plrcross=Plrcross;
lrcross=Plrcross/127.0*1.0;
};
void Distorsion::setlpf(const unsigned char &Plpf){
this->Plpf=Plpf;
REALTYPE fr=exp(pow(Plpf/127.0,0.5)*log(25000.0))+40;
lpfl->setfreq(fr);
lpfr->setfreq(fr);
};
void Distorsion::sethpf(const unsigned char &Phpf){
this->Phpf=Phpf;
REALTYPE fr=exp(pow(Phpf/127.0,0.5)*log(25000.0))+20.0;
hpfl->setfreq(fr);
hpfr->setfreq(fr);
};
void Distorsion::setpreset(unsigned char npreset){
const int PRESET_SIZE=11;
const int NUM_PRESETS=6;
unsigned char presets[NUM_PRESETS][PRESET_SIZE]={
//Overdrive 1
{127,64,35,56,70,0,0,96,0,0,0},
//Overdrive 2
{127,64,35,29,75,1,0,127,0,0,0},
//A. Exciter 1
{64,64,35,75,80,5,0,127,105,1,0},
//A. Exciter 2
{64,64,35,85,62,1,0,127,118,1,0},
//Guitar Amp
{127,64,35,63,75,2,0,55,0,0,0},
//Quantisize
{127,64,35,88,75,4,0,127,0,1,0}};
if (npreset>=NUM_PRESETS) npreset=NUM_PRESETS-1;
for (int n=0;n<PRESET_SIZE;n++) changepar(n,presets[npreset][n]);
if (insertion==0) changepar(0,(int) (presets[npreset][0]/1.5));//lower the volume if this is system effect
Ppreset=npreset;
cleanup();
};
void Distorsion::changepar(const int &npar,const unsigned char &value){
switch (npar){
case 0: setvolume(value);
break;
case 1: setpanning(value);
break;
case 2: setlrcross(value);
break;
case 3: Pdrive=value;
break;
case 4: Plevel=value;
break;
case 5: if (value>13) Ptype=13;//this must be increased if more distorsion types are added
else Ptype=value;
break;
case 6: if (value>1) Pnegate=1;
else Pnegate=value;
break;
case 7: setlpf(value);
break;
case 8: sethpf(value);
break;
case 9: if (value>1) Pstereo=1;
else Pstereo=value;
break;
case 10:Pprefiltering=value;
break;
};
};
unsigned char Distorsion::getpar(const int &npar)const{
switch (npar){
case 0: return(Pvolume);
break;
case 1: return(Ppanning);
break;
case 2: return(Plrcross);
break;
case 3: return(Pdrive);
break;
case 4: return(Plevel);
break;
case 5: return(Ptype);
break;
case 6: return(Pnegate);
break;
case 7: return(Plpf);
break;
case 8: return(Phpf);
break;
case 9: return(Pstereo);
break;
case 10:return(Pprefiltering);
break;
};
return(0);//in case of bogus parameter number
};

View File

@@ -0,0 +1,427 @@
/*
ZynAddSubFX - a software synthesizer
Distorsion.C - Distorsion effect
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <cmath>
#include "Distorsion.h"
/*
* Waveshape (this is called by OscilGen::waveshape and Distorsion::process)
*/
void waveshapesmps(int n,REALTYPE *smps,unsigned char type,unsigned char drive)
{
int i;
REALTYPE ws=drive/127.0;
REALTYPE tmpv;
switch (type) {
case 1:
ws=pow(10,ws*ws*3.0)-1.0+0.001;//Arctangent
for (i=0;i<n;i++)
smps[i]=atan(smps[i]*ws)/atan(ws);
break;
case 2:
ws=ws*ws*32.0+0.0001;//Asymmetric
if (ws<1.0) tmpv=sin(ws)+0.1;
else tmpv=1.1;
for (i=0;i<n;i++) {
smps[i]=sin(smps[i]*(0.1+ws-ws*smps[i]))/tmpv;
};
break;
case 3:
ws=ws*ws*ws*20.0+0.0001;//Pow
for (i=0;i<n;i++) {
smps[i]*=ws;
if (fabs(smps[i])<1.0) {
smps[i]=(smps[i]-pow(smps[i],3.0))*3.0;
if (ws<1.0) smps[i]/=ws;
} else smps[i]=0.0;
};
break;
case 4:
ws=ws*ws*ws*32.0+0.0001;//Sine
if (ws<1.57) tmpv=sin(ws);
else tmpv=1.0;
for (i=0;i<n;i++) smps[i]=sin(smps[i]*ws)/tmpv;
break;
case 5:
ws=ws*ws+0.000001;//Quantisize
for (i=0;i<n;i++)
smps[i]=floor(smps[i]/ws+0.5)*ws;
break;
case 6:
ws=ws*ws*ws*32+0.0001;//Zigzag
if (ws<1.0) tmpv=sin(ws);
else tmpv=1.0;
for (i=0;i<n;i++)
smps[i]=asin(sin(smps[i]*ws))/tmpv;
break;
case 7:
ws=pow(2.0,-ws*ws*8.0); //Limiter
for (i=0;i<n;i++) {
REALTYPE tmp=smps[i];
if (fabs(tmp)>ws) {
if (tmp>=0.0) smps[i]=1.0;
else smps[i]=-1.0;
} else smps[i]/=ws;
};
break;
case 8:
ws=pow(2.0,-ws*ws*8.0); //Upper Limiter
for (i=0;i<n;i++) {
REALTYPE tmp=smps[i];
if (tmp>ws) smps[i]=ws;
smps[i]*=2.0;
};
break;
case 9:
ws=pow(2.0,-ws*ws*8.0); //Lower Limiter
for (i=0;i<n;i++) {
REALTYPE tmp=smps[i];
if (tmp<-ws) smps[i]=-ws;
smps[i]*=2.0;
};
break;
case 10:
ws=(pow(2.0,ws*6.0)-1.0)/pow(2.0,6.0); //Inverse Limiter
for (i=0;i<n;i++) {
REALTYPE tmp=smps[i];
if (fabs(tmp)>ws) {
if (tmp>=0.0) smps[i]=tmp-ws;
else smps[i]=tmp+ws;
} else smps[i]=0;
};
break;
case 11:
ws=pow(5,ws*ws*1.0)-1.0;//Clip
for (i=0;i<n;i++)
smps[i]=smps[i]*(ws+0.5)*0.9999-floor(0.5+smps[i]*(ws+0.5)*0.9999);
break;
case 12:
ws=ws*ws*ws*30+0.001;//Asym2
if (ws<0.3) tmpv=ws;
else tmpv=1.0;
for (i=0;i<n;i++) {
REALTYPE tmp=smps[i]*ws;
if ((tmp>-2.0) && (tmp<1.0)) smps[i]=tmp*(1.0-tmp)*(tmp+2.0)/tmpv;
else smps[i]=0.0;
};
break;
case 13:
ws=ws*ws*ws*32.0+0.0001;//Pow2
if (ws<1.0) tmpv=ws*(1+ws)/2.0;
else tmpv=1.0;
for (i=0;i<n;i++) {
REALTYPE tmp=smps[i]*ws;
if ((tmp>-1.0)&&(tmp<1.618034)) smps[i]=tmp*(1.0-tmp)/tmpv;
else if (tmp>0.0) smps[i]=-1.0;
else smps[i]=-2.0;
};
break;
case 14:
ws=pow(ws,5.0)*80.0+0.0001;//sigmoid
if (ws>10.0) tmpv=0.5;
else tmpv=0.5-1.0/(exp(ws)+1.0);
for (i=0;i<n;i++) {
REALTYPE tmp=smps[i]*ws;
if (tmp<-10.0) tmp=-10.0;
else if (tmp>10.0) tmp=10.0;
tmp=0.5-1.0/(exp(tmp)+1.0);
smps[i]=tmp/tmpv;
};
break;
/**\todo update to Distorsion::changepar (Ptype max) if there is added more waveshapings functions*/
};
};
Distorsion::Distorsion(const int &insertion_,REALTYPE *efxoutl_,REALTYPE *efxoutr_)
:Effect(insertion_,efxoutl_,efxoutr_,NULL,0)
{
lpfl=new AnalogFilter(2,22000,1,0);
lpfr=new AnalogFilter(2,22000,1,0);
hpfl=new AnalogFilter(3,20,1,0);
hpfr=new AnalogFilter(3,20,1,0);
//default values
Pvolume=50;
Plrcross=40;
Pdrive=90;
Plevel=64;
Ptype=0;
Pnegate=0;
Plpf=127;
Phpf=0;
Pstereo=0;
Pprefiltering=0;
setpreset(Ppreset);
cleanup();
};
Distorsion::~Distorsion()
{
delete lpfl;
delete lpfr;
delete hpfl;
delete hpfr;
};
/*
* Cleanup the effect
*/
void Distorsion::cleanup()
{
lpfl->cleanup();
hpfl->cleanup();
lpfr->cleanup();
hpfr->cleanup();
};
/*
* Apply the filters
*/
void Distorsion::applyfilters(REALTYPE *efxoutl,REALTYPE *efxoutr)
{
lpfl->filterout(efxoutl);
hpfl->filterout(efxoutl);
if (Pstereo!=0) {//stereo
lpfr->filterout(efxoutr);
hpfr->filterout(efxoutr);
};
};
/*
* Effect output
*/
void Distorsion::out(REALTYPE *smpsl,REALTYPE *smpsr)
{
int i;
REALTYPE l,r,lout,rout;
REALTYPE inputvol=pow(5.0,(Pdrive-32.0)/127.0);
if (Pnegate!=0) inputvol*=-1.0;
if (Pstereo!=0) {//Stereo
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
efxoutl[i]=smpsl[i]*inputvol*panning;
efxoutr[i]=smpsr[i]*inputvol*(1.0-panning);
};
} else {
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
efxoutl[i]=( smpsl[i]*panning + smpsr[i]*(1.0-panning) ) * inputvol;
};
};
if (Pprefiltering!=0) applyfilters(efxoutl,efxoutr);
//no optimised, yet (no look table)
waveshapesmps(SOUND_BUFFER_SIZE,efxoutl,Ptype+1,Pdrive);
if (Pstereo!=0) waveshapesmps(SOUND_BUFFER_SIZE,efxoutr,Ptype+1,Pdrive);
if (Pprefiltering==0) applyfilters(efxoutl,efxoutr);
if (Pstereo==0) for (i=0;i<SOUND_BUFFER_SIZE;i++) efxoutr[i]=efxoutl[i];
REALTYPE level=dB2rap(60.0*Plevel/127.0-40.0);
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
lout=efxoutl[i];
rout=efxoutr[i];
l=lout*(1.0-lrcross)+rout*lrcross;
r=rout*(1.0-lrcross)+lout*lrcross;
lout=l;
rout=r;
efxoutl[i]=lout*2.0*level;
efxoutr[i]=rout*2.0*level;
};
};
/*
* Parameter control
*/
void Distorsion::setvolume(const unsigned char &Pvolume)
{
this->Pvolume=Pvolume;
if (insertion==0) {
outvolume=pow(0.01,(1.0-Pvolume/127.0))*4.0;
volume=1.0;
} else {
volume=outvolume=Pvolume/127.0;
};
if (Pvolume==0) cleanup();
};
void Distorsion::setpanning(const unsigned char &Ppanning)
{
this->Ppanning=Ppanning;
panning=(Ppanning+0.5)/127.0;
};
void Distorsion::setlrcross(const unsigned char &Plrcross)
{
this->Plrcross=Plrcross;
lrcross=Plrcross/127.0*1.0;
};
void Distorsion::setlpf(const unsigned char &Plpf)
{
this->Plpf=Plpf;
REALTYPE fr=exp(pow(Plpf/127.0,0.5)*log(25000.0))+40;
lpfl->setfreq(fr);
lpfr->setfreq(fr);
};
void Distorsion::sethpf(const unsigned char &Phpf)
{
this->Phpf=Phpf;
REALTYPE fr=exp(pow(Phpf/127.0,0.5)*log(25000.0))+20.0;
hpfl->setfreq(fr);
hpfr->setfreq(fr);
};
void Distorsion::setpreset(unsigned char npreset)
{
const int PRESET_SIZE=11;
const int NUM_PRESETS=6;
unsigned char presets[NUM_PRESETS][PRESET_SIZE]={
//Overdrive 1
{127,64,35,56,70,0,0,96,0,0,0},
//Overdrive 2
{127,64,35,29,75,1,0,127,0,0,0},
//A. Exciter 1
{64,64,35,75,80,5,0,127,105,1,0},
//A. Exciter 2
{64,64,35,85,62,1,0,127,118,1,0},
//Guitar Amp
{127,64,35,63,75,2,0,55,0,0,0},
//Quantisize
{127,64,35,88,75,4,0,127,0,1,0}
};
if (npreset>=NUM_PRESETS) npreset=NUM_PRESETS-1;
for (int n=0;n<PRESET_SIZE;n++) changepar(n,presets[npreset][n]);
if (insertion==0) changepar(0,(int) (presets[npreset][0]/1.5));//lower the volume if this is system effect
Ppreset=npreset;
cleanup();
};
void Distorsion::changepar(const int &npar,const unsigned char &value)
{
switch (npar) {
case 0:
setvolume(value);
break;
case 1:
setpanning(value);
break;
case 2:
setlrcross(value);
break;
case 3:
Pdrive=value;
break;
case 4:
Plevel=value;
break;
case 5:
if (value>13) Ptype=13;//this must be increased if more distorsion types are added
else Ptype=value;
break;
case 6:
if (value>1) Pnegate=1;
else Pnegate=value;
break;
case 7:
setlpf(value);
break;
case 8:
sethpf(value);
break;
case 9:
if (value>1) Pstereo=1;
else Pstereo=value;
break;
case 10:
Pprefiltering=value;
break;
};
};
unsigned char Distorsion::getpar(const int &npar)const
{
switch (npar) {
case 0:
return(Pvolume);
break;
case 1:
return(Ppanning);
break;
case 2:
return(Plrcross);
break;
case 3:
return(Pdrive);
break;
case 4:
return(Plevel);
break;
case 5:
return(Ptype);
break;
case 6:
return(Pnegate);
break;
case 7:
return(Plpf);
break;
case 8:
return(Phpf);
break;
case 9:
return(Pstereo);
break;
case 10:
return(Pprefiltering);
break;
};
return(0);//in case of bogus parameter number
};

View File

@@ -1,12 +1,12 @@
/*
ZynAddSubFX - a software synthesizer
Distorsion.h - Distorsion Effect
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
@@ -30,40 +30,41 @@
//Waveshaping(called by Distorsion effect and waveshape from OscilGen)
void waveshapesmps(int n,REALTYPE *smps,unsigned char type,unsigned char drive);
/**Distortion Effect*/
class Distorsion:public Effect{
public:
Distorsion(const int &insertion,REALTYPE *efxoutl_,REALTYPE *efxoutr_);
~Distorsion();
void out(REALTYPE *smpsl,REALTYPE *smpr);
void setpreset(unsigned char npreset);
void changepar(const int &npar,const unsigned char &value);
unsigned char getpar(const int &npar)const;
void cleanup();
void applyfilters(REALTYPE *efxoutl,REALTYPE *efxoutr);
class Distorsion:public Effect
{
public:
Distorsion(const int &insertion,REALTYPE *efxoutl_,REALTYPE *efxoutr_);
~Distorsion();
void out(REALTYPE *smpsl,REALTYPE *smpr);
void setpreset(unsigned char npreset);
void changepar(const int &npar,const unsigned char &value);
unsigned char getpar(const int &npar)const;
void cleanup();
void applyfilters(REALTYPE *efxoutl,REALTYPE *efxoutr);
private:
//Parametrii
unsigned char Pvolume; //Volumul or E/R
unsigned char Ppanning;//Panning
unsigned char Plrcross;// L/R Mixing
unsigned char Pdrive; //the input amplification
unsigned char Plevel; //the output amplification
unsigned char Ptype; //Distorsion type
unsigned char Pnegate; //if the input is negated
unsigned char Plpf; //lowpass filter
unsigned char Phpf; //highpass filter
unsigned char Pstereo; //0=mono,1=stereo
unsigned char Pprefiltering;//if you want to do the filtering before the distorsion
void setvolume(const unsigned char &Pvolume);
void setpanning(const unsigned char &Ppanning);
void setlrcross(const unsigned char &Plrcross);
void setlpf(const unsigned char &Plpf);
void sethpf(const unsigned char &Phpf);
//Real Parameters
REALTYPE panning,lrcross;
AnalogFilter *lpfl,*lpfr,*hpfl,*hpfr;
private:
//Parametrii
unsigned char Pvolume; //Volumul or E/R
unsigned char Ppanning;//Panning
unsigned char Plrcross;// L/R Mixing
unsigned char Pdrive; //the input amplification
unsigned char Plevel; //the output amplification
unsigned char Ptype; //Distorsion type
unsigned char Pnegate; //if the input is negated
unsigned char Plpf; //lowpass filter
unsigned char Phpf; //highpass filter
unsigned char Pstereo; //0=mono,1=stereo
unsigned char Pprefiltering;//if you want to do the filtering before the distorsion
void setvolume(const unsigned char &Pvolume);
void setpanning(const unsigned char &Ppanning);
void setlrcross(const unsigned char &Plrcross);
void setlpf(const unsigned char &Plpf);
void sethpf(const unsigned char &Phpf);
//Real Parameters
REALTYPE panning,lrcross;
AnalogFilter *lpfl,*lpfr,*hpfl,*hpfr;
};

View File

@@ -1,312 +0,0 @@
/*
ZynAddSubFX - a software synthesizer
DynamicFilter.C - "WahWah" effect and others
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <cmath>
#include "DynamicFilter.h"
DynamicFilter::DynamicFilter(int insertion_,REALTYPE *efxoutl_,REALTYPE *efxoutr_)
:Effect(insertion_,efxoutl_,efxoutr_,new FilterParams(0,64,64),0),
filterl(NULL),filterr(NULL)
{
setpreset(Ppreset);
cleanup();
/**\todo fix intialization issues here*/
};
DynamicFilter::~DynamicFilter(){
delete filterpars;
delete filterl;
delete filterr;
};
/*
* Apply the effect
*/
void DynamicFilter::out(REALTYPE *smpsl,REALTYPE *smpsr){
int i;
if (filterpars->changed){
filterpars->changed=false;
cleanup();
};
REALTYPE lfol,lfor;
lfo.effectlfoout(&lfol,&lfor);
lfol*=depth*5.0;lfor*=depth*5.0;
REALTYPE freq=filterpars->getfreq();
REALTYPE q=filterpars->getq();
for (i=0;i<SOUND_BUFFER_SIZE;i++){
efxoutl[i]=smpsl[i];
efxoutr[i]=smpsr[i];
REALTYPE x=(fabs(smpsl[i])+fabs(smpsr[i]))*0.5;
ms1=ms1*(1.0-ampsmooth)+x*ampsmooth+1e-10;
};
REALTYPE ampsmooth2=pow(ampsmooth,0.2)*0.3;
ms2=ms2*(1.0-ampsmooth2)+ms1*ampsmooth2;
ms3=ms3*(1.0-ampsmooth2)+ms2*ampsmooth2;
ms4=ms4*(1.0-ampsmooth2)+ms3*ampsmooth2;
REALTYPE rms=(sqrt(ms4))*ampsns;
REALTYPE frl=filterl->getrealfreq(freq+lfol+rms);
REALTYPE frr=filterr->getrealfreq(freq+lfor+rms);
filterl->setfreq_and_q(frl,q);
filterr->setfreq_and_q(frr,q);
filterl->filterout(efxoutl);
filterr->filterout(efxoutr);
//panning
for (i=0;i<SOUND_BUFFER_SIZE;i++){
efxoutl[i]*=panning;
efxoutr[i]*=(1.0-panning);
};
};
/*
* Cleanup the effect
*/
void DynamicFilter::cleanup(){
reinitfilter();
ms1=0.0;
ms2=0.0;
ms3=0.0;
ms4=0.0;
};
/*
* Parameter control
*/
void DynamicFilter::setdepth(const unsigned char &Pdepth){
this->Pdepth=Pdepth;
depth=pow((Pdepth/127.0),2.0);
};
void DynamicFilter::setvolume(const unsigned char &Pvolume){
this->Pvolume=Pvolume;
outvolume=Pvolume/127.0;
if (insertion==0) volume=1.0;
else volume=outvolume;
};
void DynamicFilter::setpanning(const unsigned char &Ppanning){
this->Ppanning=Ppanning;
panning=Ppanning/127.0;
};
void DynamicFilter::setampsns(const unsigned char &Pampsns){
ampsns=pow(Pampsns/127.0,2.5)*10.0;
if (Pampsnsinv!=0) ampsns=-ampsns;
ampsmooth=exp(-Pampsmooth/127.0*10.0)*0.99;/**\todo currently Pampsmooth is
* uninitialized when this is
* called. Please fix.
*/
this->Pampsns=Pampsns;
};
void DynamicFilter::reinitfilter(){
if (filterl!=NULL) delete(filterl);
if (filterr!=NULL) delete(filterr);
filterl=new Filter(filterpars);
filterr=new Filter(filterpars);
};
void DynamicFilter::setpreset(unsigned char npreset){
const int PRESET_SIZE=10;
const int NUM_PRESETS=5;
unsigned char presets[NUM_PRESETS][PRESET_SIZE]={
//WahWah
{110,64,80,0,0,64,0,90,0,60},
//AutoWah
{110,64,70,0,0,80,70,0,0,60},
//Sweep
{100,64,30,0,0,50,80,0,0,60},
//VocalMorph1
{110,64,80,0,0,64,0,64,0,60},
//VocalMorph1
{127,64,50,0,0,96,64,0,0,60}};
if (npreset>=NUM_PRESETS) npreset=NUM_PRESETS-1;
for (int n=0;n<PRESET_SIZE;n++) changepar(n,presets[npreset][n]);
filterpars->defaults();
switch(npreset){
case 0:
filterpars->Pcategory=0;
filterpars->Ptype=2;
filterpars->Pfreq=45;
filterpars->Pq=64;
filterpars->Pstages=1;
filterpars->Pgain=64;
break;
case 1:
filterpars->Pcategory=2;
filterpars->Ptype=0;
filterpars->Pfreq=72;
filterpars->Pq=64;
filterpars->Pstages=0;
filterpars->Pgain=64;
break;
case 2:
filterpars->Pcategory=0;
filterpars->Ptype=4;
filterpars->Pfreq=64;
filterpars->Pq=64;
filterpars->Pstages=2;
filterpars->Pgain=64;
break;
case 3:
filterpars->Pcategory=1;
filterpars->Ptype=0;
filterpars->Pfreq=50;
filterpars->Pq=70;
filterpars->Pstages=1;
filterpars->Pgain=64;
filterpars->Psequencesize=2;
// "I"
filterpars->Pvowels[0].formants[0].freq=34;
filterpars->Pvowels[0].formants[0].amp=127;
filterpars->Pvowels[0].formants[0].q=64;
filterpars->Pvowels[0].formants[1].freq=99;
filterpars->Pvowels[0].formants[1].amp=122;
filterpars->Pvowels[0].formants[1].q=64;
filterpars->Pvowels[0].formants[2].freq=108;
filterpars->Pvowels[0].formants[2].amp=112;
filterpars->Pvowels[0].formants[2].q=64;
// "A"
filterpars->Pvowels[1].formants[0].freq=61;
filterpars->Pvowels[1].formants[0].amp=127;
filterpars->Pvowels[1].formants[0].q=64;
filterpars->Pvowels[1].formants[1].freq=71;
filterpars->Pvowels[1].formants[1].amp=121;
filterpars->Pvowels[1].formants[1].q=64;
filterpars->Pvowels[1].formants[2].freq=99;
filterpars->Pvowels[1].formants[2].amp=117;
filterpars->Pvowels[1].formants[2].q=64;
break;
case 4:
filterpars->Pcategory=1;
filterpars->Ptype=0;
filterpars->Pfreq=64;
filterpars->Pq=70;
filterpars->Pstages=1;
filterpars->Pgain=64;
filterpars->Psequencesize=2;
filterpars->Pnumformants=2;
filterpars->Pvowelclearness=0;
filterpars->Pvowels[0].formants[0].freq=70;
filterpars->Pvowels[0].formants[0].amp=127;
filterpars->Pvowels[0].formants[0].q=64;
filterpars->Pvowels[0].formants[1].freq=80;
filterpars->Pvowels[0].formants[1].amp=122;
filterpars->Pvowels[0].formants[1].q=64;
filterpars->Pvowels[1].formants[0].freq=20;
filterpars->Pvowels[1].formants[0].amp=127;
filterpars->Pvowels[1].formants[0].q=64;
filterpars->Pvowels[1].formants[1].freq=100;
filterpars->Pvowels[1].formants[1].amp=121;
filterpars->Pvowels[1].formants[1].q=64;
break;
};
// for (int i=0;i<5;i++){
// printf("freq=%d amp=%d q=%d\n",filterpars->Pvowels[0].formants[i].freq,filterpars->Pvowels[0].formants[i].amp,filterpars->Pvowels[0].formants[i].q);
// };
if (insertion==0) changepar(0,presets[npreset][0]/2);//lower the volume if this is system effect
Ppreset=npreset;
reinitfilter();
};
void DynamicFilter::changepar(const int &npar,const unsigned char &value){
switch(npar){
case 0: setvolume(value);
break;
case 1: setpanning(value);
break;
case 2: lfo.Pfreq=value;
lfo.updateparams();
break;
case 3: lfo.Prandomness=value;
lfo.updateparams();
break;
case 4: lfo.PLFOtype=value;
lfo.updateparams();
break;
case 5: lfo.Pstereo=value;
lfo.updateparams();
break;
case 6: setdepth(value);
break;
case 7: setampsns(value);
break;
case 8: Pampsnsinv=value;
setampsns(Pampsns);
break;
case 9: Pampsmooth=value;
setampsns(Pampsns);
break;
};
};
unsigned char DynamicFilter::getpar(const int &npar)const{
switch (npar){
case 0: return(Pvolume);
break;
case 1: return(Ppanning);
break;
case 2: return(lfo.Pfreq);
break;
case 3: return(lfo.Prandomness);
break;
case 4: return(lfo.PLFOtype);
break;
case 5: return(lfo.Pstereo);
break;
case 6: return(Pdepth);
break;
case 7: return(Pampsns);
break;
case 8: return(Pampsnsinv);
break;
case 9: return(Pampsmooth);
break;
default:return (0);
};
};

View File

@@ -0,0 +1,344 @@
/*
ZynAddSubFX - a software synthesizer
DynamicFilter.C - "WahWah" effect and others
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <cmath>
#include "DynamicFilter.h"
DynamicFilter::DynamicFilter(int insertion_,REALTYPE *efxoutl_,REALTYPE *efxoutr_)
:Effect(insertion_,efxoutl_,efxoutr_,new FilterParams(0,64,64),0),
Pvolume(110),Ppanning(64),Pdepth(0),Pampsns(90),
Pampsnsinv(0),Pampsmooth(60),
filterl(NULL),filterr(NULL)
{
setpreset(Ppreset);
cleanup();
};
DynamicFilter::~DynamicFilter()
{
delete filterpars;
delete filterl;
delete filterr;
};
/*
* Apply the effect
*/
void DynamicFilter::out(REALTYPE *smpsl,REALTYPE *smpsr)
{
int i;
if (filterpars->changed) {
filterpars->changed=false;
cleanup();
};
REALTYPE lfol,lfor;
lfo.effectlfoout(&lfol,&lfor);
lfol*=depth*5.0;
lfor*=depth*5.0;
REALTYPE freq=filterpars->getfreq();
REALTYPE q=filterpars->getq();
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
efxoutl[i]=smpsl[i];
efxoutr[i]=smpsr[i];
REALTYPE x=(fabs(smpsl[i])+fabs(smpsr[i]))*0.5;
ms1=ms1*(1.0-ampsmooth)+x*ampsmooth+1e-10;
};
REALTYPE ampsmooth2=pow(ampsmooth,0.2)*0.3;
ms2=ms2*(1.0-ampsmooth2)+ms1*ampsmooth2;
ms3=ms3*(1.0-ampsmooth2)+ms2*ampsmooth2;
ms4=ms4*(1.0-ampsmooth2)+ms3*ampsmooth2;
REALTYPE rms=(sqrt(ms4))*ampsns;
REALTYPE frl=filterl->getrealfreq(freq+lfol+rms);
REALTYPE frr=filterr->getrealfreq(freq+lfor+rms);
filterl->setfreq_and_q(frl,q);
filterr->setfreq_and_q(frr,q);
filterl->filterout(efxoutl);
filterr->filterout(efxoutr);
//panning
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
efxoutl[i]*=panning;
efxoutr[i]*=(1.0-panning);
};
};
/*
* Cleanup the effect
*/
void DynamicFilter::cleanup()
{
reinitfilter();
ms1=0.0;
ms2=0.0;
ms3=0.0;
ms4=0.0;
};
/*
* Parameter control
*/
void DynamicFilter::setdepth(const unsigned char &Pdepth)
{
this->Pdepth=Pdepth;
depth=pow((Pdepth/127.0),2.0);
};
void DynamicFilter::setvolume(const unsigned char &Pvolume)
{
this->Pvolume=Pvolume;
outvolume=Pvolume/127.0;
if (insertion==0) volume=1.0;
else volume=outvolume;
};
void DynamicFilter::setpanning(const unsigned char &Ppanning)
{
this->Ppanning=Ppanning;
panning=Ppanning/127.0;
};
void DynamicFilter::setampsns(const unsigned char &Pampsns)
{
ampsns=pow(Pampsns/127.0,2.5)*10.0;
if (Pampsnsinv!=0) ampsns=-ampsns;
ampsmooth=exp(-Pampsmooth/127.0*10.0)*0.99;
this->Pampsns=Pampsns;
};
void DynamicFilter::reinitfilter()
{
if (filterl!=NULL) delete(filterl);
if (filterr!=NULL) delete(filterr);
filterl=new Filter(filterpars);
filterr=new Filter(filterpars);
};
void DynamicFilter::setpreset(unsigned char npreset)
{
const int PRESET_SIZE=10;
const int NUM_PRESETS=5;
unsigned char presets[NUM_PRESETS][PRESET_SIZE]={
//WahWah
{110,64,80,0,0,64,0,90,0,60},
//AutoWah
{110,64,70,0,0,80,70,0,0,60},
//Sweep
{100,64,30,0,0,50,80,0,0,60},
//VocalMorph1
{110,64,80,0,0,64,0,64,0,60},
//VocalMorph1
{127,64,50,0,0,96,64,0,0,60}
};
if (npreset>=NUM_PRESETS) npreset=NUM_PRESETS-1;
for (int n=0;n<PRESET_SIZE;n++) changepar(n,presets[npreset][n]);
filterpars->defaults();
switch (npreset) {
case 0:
filterpars->Pcategory=0;
filterpars->Ptype=2;
filterpars->Pfreq=45;
filterpars->Pq=64;
filterpars->Pstages=1;
filterpars->Pgain=64;
break;
case 1:
filterpars->Pcategory=2;
filterpars->Ptype=0;
filterpars->Pfreq=72;
filterpars->Pq=64;
filterpars->Pstages=0;
filterpars->Pgain=64;
break;
case 2:
filterpars->Pcategory=0;
filterpars->Ptype=4;
filterpars->Pfreq=64;
filterpars->Pq=64;
filterpars->Pstages=2;
filterpars->Pgain=64;
break;
case 3:
filterpars->Pcategory=1;
filterpars->Ptype=0;
filterpars->Pfreq=50;
filterpars->Pq=70;
filterpars->Pstages=1;
filterpars->Pgain=64;
filterpars->Psequencesize=2;
// "I"
filterpars->Pvowels[0].formants[0].freq=34;
filterpars->Pvowels[0].formants[0].amp=127;
filterpars->Pvowels[0].formants[0].q=64;
filterpars->Pvowels[0].formants[1].freq=99;
filterpars->Pvowels[0].formants[1].amp=122;
filterpars->Pvowels[0].formants[1].q=64;
filterpars->Pvowels[0].formants[2].freq=108;
filterpars->Pvowels[0].formants[2].amp=112;
filterpars->Pvowels[0].formants[2].q=64;
// "A"
filterpars->Pvowels[1].formants[0].freq=61;
filterpars->Pvowels[1].formants[0].amp=127;
filterpars->Pvowels[1].formants[0].q=64;
filterpars->Pvowels[1].formants[1].freq=71;
filterpars->Pvowels[1].formants[1].amp=121;
filterpars->Pvowels[1].formants[1].q=64;
filterpars->Pvowels[1].formants[2].freq=99;
filterpars->Pvowels[1].formants[2].amp=117;
filterpars->Pvowels[1].formants[2].q=64;
break;
case 4:
filterpars->Pcategory=1;
filterpars->Ptype=0;
filterpars->Pfreq=64;
filterpars->Pq=70;
filterpars->Pstages=1;
filterpars->Pgain=64;
filterpars->Psequencesize=2;
filterpars->Pnumformants=2;
filterpars->Pvowelclearness=0;
filterpars->Pvowels[0].formants[0].freq=70;
filterpars->Pvowels[0].formants[0].amp=127;
filterpars->Pvowels[0].formants[0].q=64;
filterpars->Pvowels[0].formants[1].freq=80;
filterpars->Pvowels[0].formants[1].amp=122;
filterpars->Pvowels[0].formants[1].q=64;
filterpars->Pvowels[1].formants[0].freq=20;
filterpars->Pvowels[1].formants[0].amp=127;
filterpars->Pvowels[1].formants[0].q=64;
filterpars->Pvowels[1].formants[1].freq=100;
filterpars->Pvowels[1].formants[1].amp=121;
filterpars->Pvowels[1].formants[1].q=64;
break;
};
// for (int i=0;i<5;i++){
// printf("freq=%d amp=%d q=%d\n",filterpars->Pvowels[0].formants[i].freq,filterpars->Pvowels[0].formants[i].amp,filterpars->Pvowels[0].formants[i].q);
// };
if (insertion==0) changepar(0,presets[npreset][0]/2);//lower the volume if this is system effect
Ppreset=npreset;
reinitfilter();
};
void DynamicFilter::changepar(const int &npar,const unsigned char &value)
{
switch (npar) {
case 0:
setvolume(value);
break;
case 1:
setpanning(value);
break;
case 2:
lfo.Pfreq=value;
lfo.updateparams();
break;
case 3:
lfo.Prandomness=value;
lfo.updateparams();
break;
case 4:
lfo.PLFOtype=value;
lfo.updateparams();
break;
case 5:
lfo.Pstereo=value;
lfo.updateparams();
break;
case 6:
setdepth(value);
break;
case 7:
setampsns(value);
break;
case 8:
Pampsnsinv=value;
setampsns(Pampsns);
break;
case 9:
Pampsmooth=value;
setampsns(Pampsns);
break;
};
};
unsigned char DynamicFilter::getpar(const int &npar)const
{
switch (npar) {
case 0:
return(Pvolume);
break;
case 1:
return(Ppanning);
break;
case 2:
return(lfo.Pfreq);
break;
case 3:
return(lfo.Prandomness);
break;
case 4:
return(lfo.PLFOtype);
break;
case 5:
return(lfo.Pstereo);
break;
case 6:
return(Pdepth);
break;
case 7:
return(Pampsns);
break;
case 8:
return(Pampsnsinv);
break;
case 9:
return(Pampsmooth);
break;
default:
return (0);
};
};

View File

@@ -1,12 +1,12 @@
/*
ZynAddSubFX - a software synthesizer
DynamicFilter.h - "WahWah" effect and others
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
@@ -28,43 +28,44 @@
#include "../DSP/Filter.h"
/**DynamicFilter Effect*/
class DynamicFilter:public Effect {
public:
DynamicFilter(int insetion_,REALTYPE *efxoutl_,REALTYPE *efxoutr_);
~DynamicFilter();
void out(REALTYPE *smpsl,REALTYPE *smpsr);
class DynamicFilter:public Effect
{
public:
DynamicFilter(int insetion_,REALTYPE *efxoutl_,REALTYPE *efxoutr_);
~DynamicFilter();
void out(REALTYPE *smpsl,REALTYPE *smpsr);
void setpreset(unsigned char npreset);
void changepar(const int &npar,const unsigned char &value);
unsigned char getpar(const int &npar)const;
void cleanup();
void setpreset(unsigned char npreset);
void changepar(const int &npar,const unsigned char &value);
unsigned char getpar(const int &npar)const;
void cleanup();
// void setdryonly();
private:
//Parametrii DynamicFilter
EffectLFO lfo;//lfo-ul DynamicFilter
unsigned char Pvolume;
unsigned char Ppanning;
unsigned char Pdepth;/**<the depth of the lfo of the DynamicFilter*/
unsigned char Pampsns;/**<how the filter varies according to the input amplitude*/
unsigned char Pampsnsinv;//if the filter freq is lowered if the input amplitude rises
unsigned char Pampsmooth;//how smooth the input amplitude changes the filter
//Parameter Control
void setvolume(const unsigned char &Pvolume);
void setpanning(const unsigned char &Ppanning);
void setdepth(const unsigned char &Pdepth);
void setampsns(const unsigned char &Pampsns);
void reinitfilter();
//Internal Values
REALTYPE panning,depth,ampsns,ampsmooth;
Filter *filterl,*filterr;
REALTYPE ms1,ms2,ms3,ms4;//mean squares
private:
//Parametrii DynamicFilter
EffectLFO lfo;//lfo-ul DynamicFilter
unsigned char Pvolume;
unsigned char Ppanning;
unsigned char Pdepth;/**<the depth of the lfo of the DynamicFilter*/
unsigned char Pampsns;/**<how the filter varies according to the input amplitude*/
unsigned char Pampsnsinv;//if the filter freq is lowered if the input amplitude rises
unsigned char Pampsmooth;//how smooth the input amplitude changes the filter
//Parameter Control
void setvolume(const unsigned char &Pvolume);
void setpanning(const unsigned char &Ppanning);
void setdepth(const unsigned char &Pdepth);
void setampsns(const unsigned char &Pampsns);
void reinitfilter();
//Internal Values
REALTYPE panning,depth,ampsns,ampsmooth;
Filter *filterl,*filterr;
REALTYPE ms1,ms2,ms3,ms4;//mean squares
};
#endif

View File

@@ -1,193 +0,0 @@
/*
ZynAddSubFX - a software synthesizer
EQ.C - EQ effect
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <cmath>
#include "EQ.h"
EQ::EQ(const int &insertion_,REALTYPE *efxoutl_,REALTYPE *efxoutr_)
:Effect(insertion_,efxoutl_,efxoutr_,NULL,0)
{
for (int i=0;i<MAX_EQ_BANDS;i++){
filter[i].Ptype=0;
filter[i].Pfreq=64;
filter[i].Pgain=64;
filter[i].Pq=64;
filter[i].Pstages=0;
filter[i].l=new AnalogFilter(6,1000.0,1.0,0);
filter[i].r=new AnalogFilter(6,1000.0,1.0,0);
};
//default values
Pvolume=50;
setpreset(Ppreset);
cleanup();
};
EQ::~EQ(){
};
/*
* Cleanup the effect
*/
void EQ::cleanup(){
for (int i=0;i<MAX_EQ_BANDS;i++){
filter[i].l->cleanup();
filter[i].r->cleanup();
};
};
/*
* Effect output
*/
void EQ::out(REALTYPE *smpsl,REALTYPE *smpsr){
int i;
for (i=0;i<SOUND_BUFFER_SIZE;i++){
efxoutl[i]=smpsl[i]*volume;
efxoutr[i]=smpsr[i]*volume;
};
for (i=0;i<MAX_EQ_BANDS;i++){
if (filter[i].Ptype==0) continue;
filter[i].l->filterout(efxoutl);
filter[i].r->filterout(efxoutr);
};
};
/*
* Parameter control
*/
void EQ::setvolume(const unsigned char &Pvolume){
this->Pvolume=Pvolume;
outvolume=pow(0.005,(1.0-Pvolume/127.0))*10.0;
if (insertion==0) {
volume=1.0;
} else {
volume=outvolume;
};
};
void EQ::setpreset(unsigned char npreset){
const int PRESET_SIZE=1;
const int NUM_PRESETS=2;
unsigned char presets[NUM_PRESETS][PRESET_SIZE]={
//EQ 1
{67},
//EQ 2
{67}};
if (npreset>=NUM_PRESETS) npreset=NUM_PRESETS-1;
for (int n=0;n<PRESET_SIZE;n++) changepar(n,presets[npreset][n]);
Ppreset=npreset;
};
void EQ::changepar(const int &npar,const unsigned char &value){
switch (npar){
case 0: setvolume(value);
break;
};
if (npar<10) return;
int nb=(npar-10)/5;//number of the band (filter)
if (nb>=MAX_EQ_BANDS) return;
int bp=npar%5;//band paramenter
REALTYPE tmp;
switch(bp){
case 0: filter[nb].Ptype=value;
if (value>9) filter[nb].Ptype=0;//has to be changed if more filters will be added
if (filter[nb].Ptype!=0){
filter[nb].l->settype(value-1);
filter[nb].r->settype(value-1);
};
break;
case 1: filter[nb].Pfreq=value;
tmp=600.0*pow(30.0,(value-64.0)/64.0);
filter[nb].l->setfreq(tmp);
filter[nb].r->setfreq(tmp);
break;
case 2: filter[nb].Pgain=value;
tmp=30.0*(value-64.0)/64.0;
filter[nb].l->setgain(tmp);
filter[nb].r->setgain(tmp);
break;
case 3: filter[nb].Pq=value;
tmp=pow(30.0,(value-64.0)/64.0);
filter[nb].l->setq(tmp);
filter[nb].r->setq(tmp);
break;
case 4: filter[nb].Pstages=value;
if (value>=MAX_FILTER_STAGES) filter[nb].Pstages=MAX_FILTER_STAGES-1;
filter[nb].l->setstages(value);
filter[nb].r->setstages(value);
break;
};
};
unsigned char EQ::getpar(const int &npar)const{
switch (npar){
case 0: return(Pvolume);
break;
};
if (npar<10) return(0);
int nb=(npar-10)/5;//number of the band (filter)
if (nb>=MAX_EQ_BANDS) return(0);
int bp=npar%5;//band paramenter
switch(bp){
case 0: return(filter[nb].Ptype);
break;
case 1: return(filter[nb].Pfreq);
break;
case 2: return(filter[nb].Pgain);
break;
case 3: return(filter[nb].Pq);
break;
case 4: return(filter[nb].Pstages);
break;
};
return(0);//in case of bogus parameter number
};
REALTYPE EQ::getfreqresponse(REALTYPE freq){
REALTYPE resp=1.0;
for (int i=0;i<MAX_EQ_BANDS;i++){
if (filter[i].Ptype==0) continue;
resp*=filter[i].l->H(freq);
};
return(rap2dB(resp*outvolume));
};

View File

@@ -0,0 +1,214 @@
/*
ZynAddSubFX - a software synthesizer
EQ.C - EQ effect
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <cmath>
#include "EQ.h"
EQ::EQ(const int &insertion_,REALTYPE *efxoutl_,REALTYPE *efxoutr_)
:Effect(insertion_,efxoutl_,efxoutr_,NULL,0)
{
for (int i=0;i<MAX_EQ_BANDS;i++) {
filter[i].Ptype=0;
filter[i].Pfreq=64;
filter[i].Pgain=64;
filter[i].Pq=64;
filter[i].Pstages=0;
filter[i].l=new AnalogFilter(6,1000.0,1.0,0);
filter[i].r=new AnalogFilter(6,1000.0,1.0,0);
};
//default values
Pvolume=50;
setpreset(Ppreset);
cleanup();
};
EQ::~EQ()
{
};
/*
* Cleanup the effect
*/
void EQ::cleanup()
{
for (int i=0;i<MAX_EQ_BANDS;i++) {
filter[i].l->cleanup();
filter[i].r->cleanup();
};
};
/*
* Effect output
*/
void EQ::out(REALTYPE *smpsl,REALTYPE *smpsr)
{
int i;
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
efxoutl[i]=smpsl[i]*volume;
efxoutr[i]=smpsr[i]*volume;
};
for (i=0;i<MAX_EQ_BANDS;i++) {
if (filter[i].Ptype==0) continue;
filter[i].l->filterout(efxoutl);
filter[i].r->filterout(efxoutr);
};
};
/*
* Parameter control
*/
void EQ::setvolume(const unsigned char &Pvolume)
{
this->Pvolume=Pvolume;
outvolume=pow(0.005,(1.0-Pvolume/127.0))*10.0;
if (insertion==0) {
volume=1.0;
} else {
volume=outvolume;
};
};
void EQ::setpreset(unsigned char npreset)
{
const int PRESET_SIZE=1;
const int NUM_PRESETS=2;
unsigned char presets[NUM_PRESETS][PRESET_SIZE]={
//EQ 1
{67},
//EQ 2
{67}
};
if (npreset>=NUM_PRESETS) npreset=NUM_PRESETS-1;
for (int n=0;n<PRESET_SIZE;n++) changepar(n,presets[npreset][n]);
Ppreset=npreset;
};
void EQ::changepar(const int &npar,const unsigned char &value)
{
switch (npar) {
case 0:
setvolume(value);
break;
};
if (npar<10) return;
int nb=(npar-10)/5;//number of the band (filter)
if (nb>=MAX_EQ_BANDS) return;
int bp=npar%5;//band paramenter
REALTYPE tmp;
switch (bp) {
case 0:
filter[nb].Ptype=value;
if (value>9) filter[nb].Ptype=0;//has to be changed if more filters will be added
if (filter[nb].Ptype!=0) {
filter[nb].l->settype(value-1);
filter[nb].r->settype(value-1);
};
break;
case 1:
filter[nb].Pfreq=value;
tmp=600.0*pow(30.0,(value-64.0)/64.0);
filter[nb].l->setfreq(tmp);
filter[nb].r->setfreq(tmp);
break;
case 2:
filter[nb].Pgain=value;
tmp=30.0*(value-64.0)/64.0;
filter[nb].l->setgain(tmp);
filter[nb].r->setgain(tmp);
break;
case 3:
filter[nb].Pq=value;
tmp=pow(30.0,(value-64.0)/64.0);
filter[nb].l->setq(tmp);
filter[nb].r->setq(tmp);
break;
case 4:
filter[nb].Pstages=value;
if (value>=MAX_FILTER_STAGES) filter[nb].Pstages=MAX_FILTER_STAGES-1;
filter[nb].l->setstages(value);
filter[nb].r->setstages(value);
break;
};
};
unsigned char EQ::getpar(const int &npar)const
{
switch (npar) {
case 0:
return(Pvolume);
break;
};
if (npar<10) return(0);
int nb=(npar-10)/5;//number of the band (filter)
if (nb>=MAX_EQ_BANDS) return(0);
int bp=npar%5;//band paramenter
switch (bp) {
case 0:
return(filter[nb].Ptype);
break;
case 1:
return(filter[nb].Pfreq);
break;
case 2:
return(filter[nb].Pgain);
break;
case 3:
return(filter[nb].Pq);
break;
case 4:
return(filter[nb].Pstages);
break;
};
return(0);//in case of bogus parameter number
};
REALTYPE EQ::getfreqresponse(REALTYPE freq)
{
REALTYPE resp=1.0;
for (int i=0;i<MAX_EQ_BANDS;i++) {
if (filter[i].Ptype==0) continue;
resp*=filter[i].l->H(freq);
};
return(rap2dB(resp*outvolume));
};

View File

@@ -1,12 +1,12 @@
/*
ZynAddSubFX - a software synthesizer
EQ.h - EQ Effect
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
@@ -28,29 +28,30 @@
#include "Effect.h"
/**EQ Effect*/
class EQ:public Effect{
public:
EQ(const int &insertion_,REALTYPE *efxoutl_,REALTYPE *efxoutr_);
~EQ();
void out(REALTYPE *smpsl,REALTYPE *smpr);
void setpreset(unsigned char npreset);
void changepar(const int &npar,const unsigned char &value);
unsigned char getpar(const int &npar)const;
void cleanup();
REALTYPE getfreqresponse(REALTYPE freq);
private:
//Parameters
unsigned char Pvolume;/**<Volume*/
void setvolume(const unsigned char &Pvolume);
struct {
//parameters
unsigned char Ptype,Pfreq,Pgain,Pq,Pstages;
//internal values
AnalogFilter *l,*r;
}filter[MAX_EQ_BANDS];
class EQ:public Effect
{
public:
EQ(const int &insertion_,REALTYPE *efxoutl_,REALTYPE *efxoutr_);
~EQ();
void out(REALTYPE *smpsl,REALTYPE *smpr);
void setpreset(unsigned char npreset);
void changepar(const int &npar,const unsigned char &value);
unsigned char getpar(const int &npar)const;
void cleanup();
REALTYPE getfreqresponse(REALTYPE freq);
private:
//Parameters
unsigned char Pvolume;/**<Volume*/
void setvolume(const unsigned char &Pvolume);
struct {
//parameters
unsigned char Ptype,Pfreq,Pgain,Pq,Pstages;
//internal values
AnalogFilter *l,*r;
}filter[MAX_EQ_BANDS];
};

View File

@@ -1,224 +0,0 @@
/*
ZynAddSubFX - a software synthesizer
Echo.C - Echo effect
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <cmath>
#include "Echo.h"
Echo::Echo(const int & insertion_,REALTYPE *const efxoutl_,REALTYPE *const efxoutr_)
: Effect(insertion_,efxoutl_,efxoutr_,NULL,0),
Pvolume(50),Ppanning(64),Pdelay(60),
Plrdelay(100),Plrcross(100),Pfb(40),Phidamp(60),
lrdelay(0),ldelay(NULL),rdelay(NULL)
{
setpreset(Ppreset);
cleanup();
}
Echo::~Echo(){
delete[] ldelay;
delete[] rdelay;
}
/*
* Cleanup the effect
*/
void Echo::cleanup(){
int i;
for (i=0;i<dl;i++) ldelay[i]=0.0;
for (i=0;i<dr;i++) rdelay[i]=0.0;
oldl=0.0;
oldr=0.0;
}
/*
* Initialize the delays
*/
void Echo::initdelays(){
kl=0;kr=0;
dl=delay-lrdelay;if (dl<1) dl=1;
dr=delay+lrdelay;if (dr<1) dr=1;
if (ldelay!=NULL) delete [] ldelay;
if (rdelay!=NULL) delete [] rdelay;
ldelay=new REALTYPE[dl];
rdelay=new REALTYPE[dr];
cleanup();
}
/*
* Effect output
*/
void Echo::out(REALTYPE *const smpsl,REALTYPE *const smpsr){
int i;
REALTYPE l,r,ldl,rdl;
for (i=0;i<SOUND_BUFFER_SIZE;i++){
ldl=ldelay[kl];
rdl=rdelay[kr];
l=ldl*(1.0-lrcross)+rdl*lrcross;
r=rdl*(1.0-lrcross)+ldl*lrcross;
ldl=l;rdl=r;
efxoutl[i]=ldl*2.0;
efxoutr[i]=rdl*2.0;
ldl=smpsl[i]*panning-ldl*fb;
rdl=smpsr[i]*(1.0-panning)-rdl*fb;
//LowPass Filter
ldelay[kl]=ldl=ldl*hidamp+oldl*(1.0-hidamp);
rdelay[kr]=rdl=rdl*hidamp+oldr*(1.0-hidamp);
oldl=ldl;
oldr=rdl;
if (++kl>=dl) kl=0;
if (++kr>=dr) kr=0;
};
}
/*
* Parameter control
*/
void Echo::setvolume(const unsigned char & Pvolume){
this->Pvolume=Pvolume;
if (insertion==0) {
outvolume=pow(0.01,(1.0-Pvolume/127.0))*4.0;
volume=1.0;
} else {
volume=outvolume=Pvolume/127.0;
};
if (Pvolume==0) cleanup();
}
void Echo::setpanning(const unsigned char & Ppanning){
this->Ppanning=Ppanning;
panning=(Ppanning+0.5)/127.0;
}
void Echo::setdelay(const unsigned char & Pdelay){
this->Pdelay=Pdelay;
delay=1+(int)(Pdelay/127.0*SAMPLE_RATE*1.5);//0 .. 1.5 sec
initdelays();
}
void Echo::setlrdelay(const unsigned char & Plrdelay){
REALTYPE tmp;
this->Plrdelay=Plrdelay;
tmp=(pow(2,fabs(Plrdelay-64.0)/64.0*9)-1.0)/1000.0*SAMPLE_RATE;
if (Plrdelay<64.0) tmp=-tmp;
lrdelay=(int) tmp;
initdelays();
}
void Echo::setlrcross(const unsigned char & Plrcross){
this->Plrcross=Plrcross;
lrcross=Plrcross/127.0*1.0;
}
void Echo::setfb(const unsigned char & Pfb){
this->Pfb=Pfb;
fb=Pfb/128.0;
}
void Echo::sethidamp(const unsigned char & Phidamp){
this->Phidamp=Phidamp;
hidamp=1.0-Phidamp/127.0;
}
void Echo::setpreset(unsigned char npreset){
/**\todo see if the preset array can be replaced with a struct or a class*/
const int PRESET_SIZE=7;
const int NUM_PRESETS=9;
unsigned char presets[NUM_PRESETS][PRESET_SIZE]={
//Echo 1
{67,64,35,64,30,59,0},
//Echo 2
{67,64,21,64,30,59,0},
//Echo 3
{67,75,60,64,30,59,10},
//Simple Echo
{67,60,44,64,30,0,0},
//Canyon
{67,60,102,50,30,82,48},
//Panning Echo 1
{67,64,44,17,0,82,24},
//Panning Echo 2
{81,60,46,118,100,68,18},
//Panning Echo 3
{81,60,26,100,127,67,36},
//Feedback Echo
{62,64,28,64,100,90,55}};
if (npreset>=NUM_PRESETS) npreset=NUM_PRESETS-1;
for (int n=0;n<PRESET_SIZE;n++) changepar(n,presets[npreset][n]);
if (insertion!=0) setvolume(presets[npreset][0]/2);//lower the volume if this is insertion effect
Ppreset=npreset;
}
void Echo::changepar(const int & npar,const unsigned char & value){
/**\todo get rid of this leaky abstraction*/
switch (npar){
case 0: setvolume(value);
break;
case 1: setpanning(value);
break;
case 2: setdelay(value);
break;
case 3: setlrdelay(value);
break;
case 4: setlrcross(value);
break;
case 5: setfb(value);
break;
case 6: sethidamp(value);
break;
};
}
unsigned char Echo::getpar(const int & npar)const{
/**\todo get rid of this leaky abstraction*/
switch (npar){
case 0: return(Pvolume);
break;
case 1: return(Ppanning);
break;
case 2: return(Pdelay);
break;
case 3: return(Plrdelay);
break;
case 4: return(Plrcross);
break;
case 5: return(Pfb);
break;
case 6: return(Phidamp);
break;
};
return(0);// in case of bogus parameter number
}

View File

@@ -0,0 +1,257 @@
/*
ZynAddSubFX - a software synthesizer
Echo.C - Echo effect
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <cmath>
#include <iostream>
#include "Echo.h"
Echo::Echo(const int & insertion_,REALTYPE *const efxoutl_,REALTYPE *const efxoutr_)
: Effect(insertion_,efxoutl_,efxoutr_,NULL,0),
Pvolume(50),Ppanning(64),//Pdelay(60),
Plrdelay(100),Plrcross(100),Pfb(40),Phidamp(60),
lrdelay(0),delaySample(1),old(0.0)
{
setpreset(Ppreset);
}
Echo::~Echo() {}
/*
* Cleanup the effect
*/
void Echo::cleanup()
{
delaySample.l().clear();
delaySample.r().clear();
old=Stereo<REALTYPE>(0.0);
}
/*
* Initialize the delays
*/
void Echo::initdelays()
{
/**\todo make this adjust insted of destroy old delays*/
kl=0;
kr=0;
dl=(int)(1+delay.getiVal()*SAMPLE_RATE-lrdelay);
if (dl<1) dl=1;
dr=(int)(1+delay.getiVal()*SAMPLE_RATE+lrdelay);
if (dr<1) dr=1;
delaySample.l()=AuSample(dl);
delaySample.r()=AuSample(dr);
old=Stereo<REALTYPE>(0.0);
}
/*
* Effect output
*/
void Echo::out(REALTYPE *const smpsl,REALTYPE *const smpsr)
{
Stereo<AuSample> input(AuSample(SOUND_BUFFER_SIZE,smpsl),AuSample(SOUND_BUFFER_SIZE,smpsr));
out(input);
}
void Echo::out(const Stereo<AuSample> &input)
{
//void Echo::out(const Stereo<AuSample> & input){ //ideal
REALTYPE l,r,ldl,rdl;/**\todo move l+r->? ldl+rdl->?*/
for (int i=0;i<input.l().size();i++) {
ldl=delaySample.l()[kl];
rdl=delaySample.r()[kr];
l=ldl*(1.0-lrcross)+rdl*lrcross;
r=rdl*(1.0-lrcross)+ldl*lrcross;
ldl=l;
rdl=r;
efxoutl[i]=ldl*2.0;
efxoutr[i]=rdl*2.0;
ldl=input.l()[i]*panning-ldl*fb;
rdl=input.r()[i]*(1.0-panning)-rdl*fb;
//LowPass Filter
delaySample.l()[kl]=ldl=ldl*hidamp+old.l()*(1.0-hidamp);
delaySample.r()[kr]=rdl=rdl*hidamp+old.r()*(1.0-hidamp);
old.l()=ldl;
old.r()=rdl;
if (++kl>=dl) kl=0;
if (++kr>=dr) kr=0;
};
}
/*
* Parameter control
*/
void Echo::setvolume(const unsigned char & Pvolume)
{
this->Pvolume=Pvolume;
if (insertion==0) {
outvolume=pow(0.01,(1.0-Pvolume/127.0))*4.0;
volume=1.0;
} else {
volume=outvolume=Pvolume/127.0;
};
if (Pvolume==0) cleanup();
}
void Echo::setpanning(const unsigned char & Ppanning)
{
this->Ppanning=Ppanning;
panning=(Ppanning+0.5)/127.0;
}
void Echo::setdelay(const unsigned char & Pdelay)
{
delay.setmVal(Pdelay);
//this->Pdelay=Pdelay;
//delay=1+(int)(Pdelay/127.0*SAMPLE_RATE*1.5);//0 .. 1.5 sec
initdelays();
}
void Echo::setlrdelay(const unsigned char & Plrdelay)
{
REALTYPE tmp;
this->Plrdelay=Plrdelay;
tmp=(pow(2,fabs(Plrdelay-64.0)/64.0*9)-1.0)/1000.0*SAMPLE_RATE;
if (Plrdelay<64.0) tmp=-tmp;
lrdelay=(int) tmp;
initdelays();
}
void Echo::setlrcross(const unsigned char & Plrcross)
{
this->Plrcross=Plrcross;
lrcross=Plrcross/127.0*1.0;
}
void Echo::setfb(const unsigned char & Pfb)
{
this->Pfb=Pfb;
fb=Pfb/128.0;
}
void Echo::sethidamp(const unsigned char & Phidamp)
{
this->Phidamp=Phidamp;
hidamp=1.0-Phidamp/127.0;
}
void Echo::setpreset(unsigned char npreset)
{
/**\todo see if the preset array can be replaced with a struct or a class*/
const int PRESET_SIZE=7;
const int NUM_PRESETS=9;
unsigned char presets[NUM_PRESETS][PRESET_SIZE]={
//Echo 1
{67,64,35,64,30,59,0},
//Echo 2
{67,64,21,64,30,59,0},
//Echo 3
{67,75,60,64,30,59,10},
//Simple Echo
{67,60,44,64,30,0,0},
//Canyon
{67,60,102,50,30,82,48},
//Panning Echo 1
{67,64,44,17,0,82,24},
//Panning Echo 2
{81,60,46,118,100,68,18},
//Panning Echo 3
{81,60,26,100,127,67,36},
//Feedback Echo
{62,64,28,64,100,90,55}
};
if (npreset>=NUM_PRESETS) npreset=NUM_PRESETS-1;
for (int n=0;n<PRESET_SIZE;n++) changepar(n,presets[npreset][n]);
if (insertion) setvolume(presets[npreset][0]/2);//lower the volume if this is insertion effect
Ppreset=npreset;
}
void Echo::changepar(const int & npar,const unsigned char & value)
{
switch (npar) {
case 0:
setvolume(value);
break;
case 1:
setpanning(value);
break;
case 2:
setdelay(value);
break;
case 3:
setlrdelay(value);
break;
case 4:
setlrcross(value);
break;
case 5:
setfb(value);
break;
case 6:
sethidamp(value);
break;
};
}
unsigned char Echo::getpar(const int & npar)const
{
switch (npar) {
case 0:
return(Pvolume);
break;
case 1:
return(Ppanning);
break;
case 2:
return(delay.getmVal());
break;
case 3:
return(Plrdelay);
break;
case 4:
return(Plrcross);
break;
case 5:
return(Pfb);
break;
case 6:
return(Phidamp);
break;
};
return(0);// in case of bogus parameter number
}

View File

@@ -1,12 +1,12 @@
/*
ZynAddSubFX - a software synthesizer
Echo.h - Echo Effect
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
@@ -25,108 +25,112 @@
#include "../globals.h"
#include "Effect.h"
#include "../Samples/AuSample.h"
#include "../Misc/Stereo.h"
#include "../Controls/DelayCtl.h"
/**Echo Effect*/
class Echo:public Effect{
public:
class Echo:public Effect
{
public:
/**
* The Constructor For Echo
* @param insertion_ integer to determine if Echo is an insertion effect
* or not
* @param efxoutl_ Effect out Left Channel
* @param efxoutr_ Effect out Right Channel
* @return An initialized Echo Object
*/
Echo(const int & insertion_,REALTYPE *const efxoutl_,REALTYPE *const efxoutr_);
/**
* The Constructor For Echo
* @param insertion_ integer to determine if Echo is an insertion effect
* or not
* @param efxoutl_ Effect out Left Channel
* @param efxoutr_ Effect out Right Channel
* @return An initialized Echo Object
*/
Echo(const int & insertion_,REALTYPE *const efxoutl_,REALTYPE *const efxoutr_);
/**
* The destructor
*/
~Echo();
/**
* The destructor
*/
~Echo();
/**
* Outputs the echo to efxoutl and efxoutr
* @param smpsl Sample from Left channel
* @param smpsr Sample from Right channel
* \todo try to figure out if smpsl should be const *const
* or not
*/
void out(REALTYPE *const smpsl,REALTYPE *const smpr);
/**
* Sets the state of Echo to the specified preset
* @param npreset number of chosen preset
*/
void setpreset(unsigned char npreset);
/**
* Outputs the echo to efxoutl and efxoutr
* @param smpsl Sample from Left channel
* @param smpsr Sample from Right channel
* \todo try to figure out if smpsl should be const *const
* or not (It should be)
*/
void out(REALTYPE *const smpsl,REALTYPE *const smpr);
void out(const Stereo<AuSample> &input);
/**
* Sets the value of the chosen variable
*
* The possible parameters are:
* -# Volume
* -# Panning
* -# Delay
* -# L/R Delay
* -# L/R Crossover
* -# Feedback
* -# Dampening
* @param npar number of chosen parameter
* @param value the new value
*/
void changepar(const int & npar,const unsigned char & value);
/**
* Sets the state of Echo to the specified preset
* @param npreset number of chosen preset
*/
void setpreset(unsigned char npreset);
/**
* Gets the specified parameter
*
* The possible parameters are
* -# Volume
* -# Panning
* -# Delay
* -# L/R Delay
* -# L/R Crossover
* -# Feedback
* -# Dampening
* @param npar number of chosen parameter
* @return value of parameter
*
* \todo make this method use constant variables by reference
*Currently doing so results in strange behavior
*/
unsigned char getpar(const int & npar)const;
/**
* Sets the value of the chosen variable
*
* The possible parameters are:
* -# Volume
* -# Panning
* -# Delay
* -# L/R Delay
* -# L/R Crossover
* -# Feedback
* -# Dampening
* @param npar number of chosen parameter
* @param value the new value
*/
void changepar(const int & npar,const unsigned char & value);
/**Zeros out the state of the Echo*/
void cleanup();
/**\todo This function needs to be implemented or the prototype should be removed*/
void setdryonly();
private:
/**\todo remove all of these once they have been depreciated*/
//Parameters
unsigned char Pvolume;/**<#1 Volume or Dry/Wetness*/
unsigned char Ppanning;/**<#2 Panning*/
unsigned char Pdelay;/**<#3 Delay of the Echo*/
unsigned char Plrdelay;/**<#4 L/R delay difference*/
unsigned char Plrcross;/**<#5 L/R Mixing*/
unsigned char Pfb;/**<#6Feedback*/
unsigned char Phidamp;/**<#7Dampening of the Echo*/
void setvolume(const unsigned char & Pvolume);
void setpanning(const unsigned char & Ppanning);
void setdelay(const unsigned char & Pdelay);
void setlrdelay(const unsigned char & Plrdelay);
void setlrcross(const unsigned char & Plrcross);
void setfb(const unsigned char & Pfb);
void sethidamp(const unsigned char & Phidamp);
/**
* Gets the specified parameter
*
* The possible parameters are
* -# Volume
* -# Panning
* -# Delay
* -# L/R Delay
* -# L/R Crossover
* -# Feedback
* -# Dampening
* @param npar number of chosen parameter
* @return value of parameter
*/
unsigned char getpar(const int & npar)const;
//Real Parameters
REALTYPE panning,lrcross,fb,hidamp;
int dl,dr,delay,lrdelay;
void initdelays();
REALTYPE *ldelay,*rdelay;
REALTYPE oldl,oldr;//pt. lpf
int kl,kr;
int getnumparams();
/**Zeros out the state of the Echo*/
void cleanup();
/**\todo This function needs to be implemented or the prototype should be removed*/
void setdryonly();
private:
//Parameters
char Pvolume;/**<#1 Volume or Dry/Wetness*/
char Ppanning;/**<#2 Panning*/
DelayCtl delay;/**<#3 Delay of the Echo*/
char Plrdelay;/**<#4 L/R delay difference*/
char Plrcross;/**<#5 L/R Mixing*/
char Pfb;/**<#6Feedback*/
char Phidamp;/**<#7Dampening of the Echo*/
void setvolume(const unsigned char & Pvolume);
void setpanning(const unsigned char & Ppanning);
void setdelay(const unsigned char & Pdelay);
void setlrdelay(const unsigned char & Plrdelay);
void setlrcross(const unsigned char & Plrcross);
void setfb(const unsigned char & Pfb);
void sethidamp(const unsigned char & Phidamp);
//Real Parameters
REALTYPE panning,lrcross,fb,hidamp; //needs better names
int dl,dr,lrdelay; //needs better names
void initdelays();
Stereo<AuSample> delaySample;
Stereo<REALTYPE> old;
int kl,kr;
};
#endif

View File

@@ -1,12 +1,12 @@
/*
ZynAddSubFX - a software synthesizer
Effect.C - this class is inherited by the all effects(Reverb, Echo, ..)
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
@@ -22,9 +22,9 @@
#include "Effect.h"
Effect::Effect(const int & insertion_,REALTYPE *const efxoutl_,
Effect::Effect(bool insertion_,REALTYPE *const efxoutl_,
REALTYPE *const efxoutr_,FilterParams *filterpars_,
const unsigned char & Ppreset_)
:Ppreset(Ppreset_),efxoutl(efxoutl_),efxoutr(efxoutr_),
filterpars(filterpars_),insertion(insertion_){}
:Ppreset(Ppreset_),efxoutl(efxoutl_),efxoutr(efxoutr_),
filterpars(filterpars_),insertion(insertion_) {}

View File

@@ -1,12 +1,12 @@
/*
ZynAddSubFX - a software synthesizer
Effect.h - this class is inherited by the all effects(Reverb, Echo, ..)
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
@@ -23,82 +23,81 @@
#ifndef EFFECT_H
#define EFFECT_H
#include <valarray>
#include "../Misc/Util.h"
#include "../globals.h"
#include "../Params/FilterParams.h"
/**this class is inherited by the all effects(Reverb, Echo, ..)*/
class Effect{
public:
/**
* Effect Constructor
* @param insertion_ 1 when it is an insertion Effect and 0 when it
* is not an insertion Effect
* @param efxoutl_ Effect output buffer Left channel
* @param efxoutr_ Effect output buffer Right channel
* @param filterpars_ pointer to FilterParams array
* @param Ppreset_ chosen preset
* @return Initialized Effect object*/
Effect(const int & insertion_,REALTYPE *const efxoutl_,
REALTYPE *const efxoutr_,FilterParams *filterpars_,
const unsigned char & Ppreset_);
/**Deconstructor
*
* Deconstructs the Effect and releases any resouces that it has
* allocated for itself*/
virtual ~Effect(){};
/**
* Choose a preset
* @param npreset number of chosen preset*/
virtual void setpreset(unsigned char npreset)=0;
/**Change parameter npar to value
* @param npar chosen parameter
* @param value chosen new value*/
virtual void changepar(const int &npar,const unsigned char &value)=0;
/**Get the value of parameter npar
* @param npar chosen parameter
* @return the value of the parameter in an unsigned char or 0 if it
* does not exist*/
virtual unsigned char getpar(const int &npar)const=0;
/**Output result of effect based on the given buffers
*
* This method should result in the effect generating its results
* and placing them into the efxoutl and efxoutr buffers.
* Every Effect should overide this method.
*
* @param smpsl Input buffer for the Left channel
* @param smpsr Input buffer for the Right channel
*/
virtual void out(REALTYPE *const smpsl,REALTYPE *const smpsr)=0;
/**Reset the state of the effect*/
virtual void cleanup(){};
/**This is only used for EQ (for user interface)*/
virtual REALTYPE getfreqresponse(REALTYPE freq){return (0);};
class Effect
{
public:
/**
* Effect Constructor
* @param insertion_ 1 when it is an insertion Effect and 0 when it
* is not an insertion Effect
* @param efxoutl_ Effect output buffer Left channel
* @param efxoutr_ Effect output buffer Right channel
* @param filterpars_ pointer to FilterParams array
* @param Ppreset_ chosen preset
* @return Initialized Effect object*/
Effect(bool insertion_,REALTYPE *const efxoutl_,
REALTYPE *const efxoutr_,FilterParams *filterpars_,
const unsigned char & Ppreset_);
/**Deconstructor
*
* Deconstructs the Effect and releases any resouces that it has
* allocated for itself*/
virtual ~Effect() {};
/**
* Choose a preset
* @param npreset number of chosen preset*/
virtual void setpreset(unsigned char npreset)=0;
/**Change parameter npar to value
* @param npar chosen parameter
* @param value chosen new value*/
virtual void changepar(const int &npar,const unsigned char &value)=0;
/**Get the value of parameter npar
* @param npar chosen parameter
* @return the value of the parameter in an unsigned char or 0 if it
* does not exist*/
virtual unsigned char getpar(const int &npar)const=0;
/**Output result of effect based on the given buffers
*
* This method should result in the effect generating its results
* and placing them into the efxoutl and efxoutr buffers.
* Every Effect should overide this method.
*
* @param smpsl Input buffer for the Left channel
* @param smpsr Input buffer for the Right channel
*/
virtual void out(REALTYPE *const smpsl,REALTYPE *const smpsr)=0;
/**Reset the state of the effect*/
virtual void cleanup() {};
/**This is only used for EQ (for user interface)*/
virtual REALTYPE getfreqresponse(REALTYPE freq) {
return (0);
};
unsigned char Ppreset;/**<Currently used preset*/
REALTYPE *const efxoutl;/**<Effect out Left Channel*/
REALTYPE *const efxoutr;/**<Effect out Right Channel*/
/**\todo make efxoutl and efxoutr private and replace them with a StereoSample*/
unsigned char Ppreset;/**<Currently used preset*/
REALTYPE *const efxoutl;/**<Effect out Left Channel*/
REALTYPE *const efxoutr;/**<Effect out Right Channel*/
/**\todo make efxoutl and efxoutr private and replace them with a StereoSample*/
REALTYPE outvolume;/**<This is the volume of effect and is public because
REALTYPE outvolume;/**<This is the volume of effect and is public because
* it is needed in system effects.
* The out volume of such effects are always 1.0, so
* this setting tells me how is the volume to the
* Master Output only.*/
REALTYPE volume;
REALTYPE volume;
FilterParams *filterpars;/**<Parameters for filters used by Effect*/
protected:
FilterParams *filterpars;/**<Parameters for filters used by Effect*/
protected:
const int insertion;/**<If Effect is an insertion effect, insertion=1
const bool insertion;/**<If Effect is an insertion effect, insertion=1
*otherwise, it should be insertion=0*/
};
#endif

View File

@@ -1,12 +1,12 @@
/*
ZynAddSubFX - a software synthesizer
EffectLFO.C - Stereo LFO used by some effects
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
@@ -26,13 +26,15 @@
#include "EffectLFO.h"
EffectLFO::EffectLFO(){
xl=0.0;xr=0.0;
EffectLFO::EffectLFO()
{
xl=0.0;
xr=0.0;
Pfreq=40;
Prandomness=0;
PLFOtype=0;
Pstereo=96;
updateparams();
ampl1=(1-lfornd)+lfornd*RND;
@@ -41,20 +43,23 @@ EffectLFO::EffectLFO(){
ampr2=(1-lfornd)+lfornd*RND;
};
EffectLFO::~EffectLFO(){
EffectLFO::~EffectLFO()
{
};
/*
* Update the changed parameters
*/
void EffectLFO::updateparams(){
void EffectLFO::updateparams()
{
REALTYPE lfofreq=(pow(2,Pfreq/127.0*10.0)-1.0)*0.03;
incx=fabs(lfofreq)*(REALTYPE)SOUND_BUFFER_SIZE/(REALTYPE)SAMPLE_RATE;
if (incx>0.49999999) incx=0.499999999; //Limit the Frequency
lfornd=Prandomness/127.0;
if (lfornd<0.0) lfornd=0.0; else if (lfornd>1.0) lfornd=1.0;
if (lfornd<0.0) lfornd=0.0;
else if (lfornd>1.0) lfornd=1.0;
if (PLFOtype>1) PLFOtype=1;//this has to be updated if more lfo's are added
lfotype=PLFOtype;
@@ -66,16 +71,18 @@ void EffectLFO::updateparams(){
/*
* Compute the shape of the LFO
*/
REALTYPE EffectLFO::getlfoshape(REALTYPE x){
REALTYPE EffectLFO::getlfoshape(REALTYPE x)
{
REALTYPE out;
switch (lfotype){
case 1: //EffectLFO_TRIANGLE
if ((x>0.0)&&(x<0.25)) out=4.0*x;
else if ((x>0.25)&&(x<0.75)) out=2-4*x;
else out=4.0*x-4.0;
break;
/**\todo more to be added here; also ::updateparams() need to be updated (to allow more lfotypes)*/
default:out=cos(x*2*PI);//EffectLFO_SINE
switch (lfotype) {
case 1: //EffectLFO_TRIANGLE
if ((x>0.0)&&(x<0.25)) out=4.0*x;
else if ((x>0.25)&&(x<0.75)) out=2-4*x;
else out=4.0*x-4.0;
break;
/**\todo more to be added here; also ::updateparams() need to be updated (to allow more lfotypes)*/
default:
out=cos(x*2*PI);//EffectLFO_SINE
};
return(out);
};
@@ -83,16 +90,17 @@ REALTYPE EffectLFO::getlfoshape(REALTYPE x){
/*
* LFO output
*/
void EffectLFO::effectlfoout(REALTYPE *outl,REALTYPE *outr){
REALTYPE out;
void EffectLFO::effectlfoout(REALTYPE *outl,REALTYPE *outr)
{
REALTYPE out;
out=getlfoshape(xl);
if ((lfotype==0)||(lfotype==1)) out*=(ampl1+xl*(ampl2-ampl1));
xl+=incx;
if (xl>1.0) {
xl-=1.0;
ampl1=ampl2;
ampl2=(1.0-lfornd)+lfornd*RND;
xl-=1.0;
ampl1=ampl2;
ampl2=(1.0-lfornd)+lfornd*RND;
};
*outl=(out+1.0)*0.5;
@@ -100,9 +108,9 @@ void EffectLFO::effectlfoout(REALTYPE *outl,REALTYPE *outr){
if ((lfotype==0)||(lfotype==1)) out*=(ampr1+xr*(ampr2-ampr1));
xr+=incx;
if (xr>1.0) {
xr-=1.0;
ampr1=ampr2;
ampr2=(1.0-lfornd)+lfornd*RND;
xr-=1.0;
ampr1=ampr2;
ampr2=(1.0-lfornd)+lfornd*RND;
};
*outr=(out+1.0)*0.5;
};

View File

@@ -1,12 +1,12 @@
/*
ZynAddSubFX - a software synthesizer
EffectLFO.h - Stereo LFO used by some effects
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
@@ -24,9 +24,11 @@
#define EFFECT_LFO_H
#include "../globals.h"
/**LFO for some of the Effect objects*/
class EffectLFO{
public:
/**LFO for some of the Effect objects
* \todo see if this should inherit LFO*/
class EffectLFO
{
public:
EffectLFO();
~EffectLFO();
void effectlfoout(REALTYPE *outl,REALTYPE *outr);
@@ -35,15 +37,15 @@ class EffectLFO{
unsigned char Prandomness;
unsigned char PLFOtype;
unsigned char Pstereo;//"64"=0
private:
private:
REALTYPE getlfoshape(REALTYPE x);
REALTYPE xl,xr;
REALTYPE incx;
REALTYPE ampl1,ampl2,ampr1,ampr2;//necessary for "randomness"
REALTYPE lfointensity;
REALTYPE lfornd;
char lfotype; /**\todo GET RID OF CHAR (use a subclass if types are needed)*/
char lfotype; /**\todo GET RID OF CHAR (replace with short or enum)*/
};

View File

@@ -1,295 +0,0 @@
/*
ZynAddSubFX - a software synthesizer
EffectMgr.C - Effect manager, an interface betwen the program and effects
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "EffectMgr.h"
EffectMgr::EffectMgr(int insertion_,pthread_mutex_t *mutex_)
:insertion(insertion_),
efxoutl(new REALTYPE[SOUND_BUFFER_SIZE]),
efxoutr(new REALTYPE[SOUND_BUFFER_SIZE]),
filterpars(NULL),nefx(0),efx(NULL),mutex(mutex_),dryonly(false)
{
setpresettype("Peffect"); /**\todo Figure out what this is doing
* , as it might be another leaky abstraction.*/
// efx=NULL;
// nefx=0;
// insertion=insertion_;
// mutex=mutex_;
// efxoutl=new REALTYPE[SOUND_BUFFER_SIZE];
// efxoutr=new REALTYPE[SOUND_BUFFER_SIZE];
for (int i=0;i<SOUND_BUFFER_SIZE;i++){
efxoutl[i]=0.0;
efxoutr[i]=0.0;
};
// filterpars=NULL;
// dryonly=false;
defaults();
}
EffectMgr::~EffectMgr(){
if (efx!=NULL) delete efx;
delete []efxoutl;
delete []efxoutr;
}
void EffectMgr::defaults(){
changeeffect(0);
setdryonly(false);
}
/*
* Change the effect
*/
void EffectMgr::changeeffect(int nefx_){
cleanup();
if (nefx==nefx_) return;
nefx=nefx_;
for (int i=0;i<SOUND_BUFFER_SIZE;i++){
efxoutl[i]=0.0;
efxoutr[i]=0.0;
};
if (efx!=NULL) delete efx;
switch (nefx){ /**\todo replace leaky abstraction*/
case 1:efx=new Reverb(insertion,efxoutl,efxoutr);break;
case 2:efx=new Echo(insertion,efxoutl,efxoutr);break;
case 3:efx=new Chorus(insertion,efxoutl,efxoutr);break;
case 4:efx=new Phaser(insertion,efxoutl,efxoutr);break;
case 5:efx=new Alienwah(insertion,efxoutl,efxoutr);break;
case 6:efx=new Distorsion(insertion,efxoutl,efxoutr);break;
case 7:efx=new EQ(insertion,efxoutl,efxoutr);break;
case 8:efx=new DynamicFilter(insertion,efxoutl,efxoutr);break;
//put more effect here
default:efx=NULL;break;//no effect (thru)
};
if (efx!=NULL) filterpars=efx->filterpars;
}
/*
* Obtain the effect number
*/
int EffectMgr::geteffect(){
return (nefx);
}
/*
* Cleanup the current effect
*/
void EffectMgr::cleanup(){
if (efx!=NULL) efx->cleanup();
}
/*
* Get the preset of the current effect
*/
unsigned char EffectMgr::getpreset(){
if (efx!=NULL) return(efx->Ppreset);
else return(0);
}
/*
* Change the preset of the current effect
*/
void EffectMgr::changepreset_nolock(unsigned char npreset){
if (efx!=NULL) efx->setpreset(npreset);
}
/*
* Change the preset of the current effect(with thread locking)
*/
void EffectMgr::changepreset(unsigned char npreset){
pthread_mutex_lock(mutex);
changepreset_nolock(npreset);
pthread_mutex_unlock(mutex);
}
/*
* Change a parameter of the current effect
*/
void EffectMgr::seteffectpar_nolock(int npar,unsigned char value){
if (efx==NULL) return;
efx->changepar(npar,value);
}
/*
* Change a parameter of the current effect (with thread locking)
*/
void EffectMgr::seteffectpar(int npar,unsigned char value){
pthread_mutex_lock(mutex);
seteffectpar_nolock(npar,value);
pthread_mutex_unlock(mutex);
}
/*
* Get a parameter of the current effect
*/
unsigned char EffectMgr::geteffectpar(int npar){
if (efx==NULL) return(0);
return(efx->getpar(npar));
}
/*
* Apply the effect
*/
void EffectMgr::out(REALTYPE *smpsl,REALTYPE *smpsr){
int i;
if (efx==NULL){
if (insertion==0)
for (i=0;i<SOUND_BUFFER_SIZE;i++){
smpsl[i]=0.0;smpsr[i]=0.0;
efxoutl[i]=0.0;efxoutr[i]=0.0;
};
return;
};
for (i=0;i<SOUND_BUFFER_SIZE;i++){
smpsl[i]+=denormalkillbuf[i];
smpsr[i]+=denormalkillbuf[i];
efxoutl[i]=0.0;
efxoutr[i]=0.0;
};
efx->out(smpsl,smpsr);
REALTYPE volume=efx->volume;
if (nefx==7){//this is need only for the EQ effect
/**\todo figure out why*/
for (i=0;i<SOUND_BUFFER_SIZE;i++){
smpsl[i]=efxoutl[i];
smpsr[i]=efxoutr[i];
};
return;
};
//Insertion effect
if (insertion!=0) {
REALTYPE v1,v2;
if (volume<0.5) {
v1=1.0;
v2=volume*2.0;
} else {
v1=(1.0-volume)*2.0;
v2=1.0;
};
if ((nefx==1)||(nefx==2)) v2*=v2;//for Reverb and Echo, the wet function is not liniar
if (dryonly){//this is used for instrument effect only
for (i=0;i<SOUND_BUFFER_SIZE;i++){
smpsl[i]*=v1;
smpsr[i]*=v1;
efxoutl[i]*=v2;
efxoutr[i]*=v2;
};
}else{//normal instrument/insertion effect
for (i=0;i<SOUND_BUFFER_SIZE;i++){
smpsl[i]=smpsl[i]*v1+efxoutl[i]*v2;
smpsr[i]=smpsr[i]*v1+efxoutr[i]*v2;
};
};
} else {//System effect
for (i=0;i<SOUND_BUFFER_SIZE;i++){
efxoutl[i]*=2.0*volume;
efxoutr[i]*=2.0*volume;
smpsl[i]=efxoutl[i];
smpsr[i]=efxoutr[i];
};
};
}
/*
* Get the effect volume for the system effect
*/
REALTYPE EffectMgr::sysefxgetvolume(){
if (efx==NULL) return (1.0);
else return(efx->outvolume);
}
/*
* Get the EQ response
*/
REALTYPE EffectMgr::getEQfreqresponse(REALTYPE freq){
if (nefx==7) return(efx->getfreqresponse(freq));
else return(0.0);
}
void EffectMgr::setdryonly(bool value){
dryonly=value;
}
void EffectMgr::add2XML(XMLwrapper *xml){
xml->addpar("type",geteffect());
if ((efx==NULL)||(geteffect()==0)) return;
xml->addpar("preset",efx->Ppreset);
xml->beginbranch("EFFECT_PARAMETERS");
for (int n=0;n<128;n++){ /**\todo evaluate who should oversee saving
* and loading of parameters*/
int par=geteffectpar(n);
if (par==0) continue;
xml->beginbranch("par_no",n);
xml->addpar("par",par);
xml->endbranch();
};
if (filterpars!=NULL){
xml->beginbranch("FILTER");
filterpars->add2XML(xml);
xml->endbranch();
};
xml->endbranch();
}
void EffectMgr::getfromXML(XMLwrapper *xml){
changeeffect(xml->getpar127("type",geteffect()));
if ((efx==NULL)||(geteffect()==0)) return;
efx->Ppreset=xml->getpar127("preset",efx->Ppreset);
if (xml->enterbranch("EFFECT_PARAMETERS")){
for (int n=0;n<128;n++){
seteffectpar_nolock(n,0);//erase effect parameter
if (xml->enterbranch("par_no",n)==0) continue;
int par=geteffectpar(n);
seteffectpar_nolock(n,xml->getpar127("par",par));
xml->exitbranch();
};
if (filterpars!=NULL){
if (xml->enterbranch("FILTER")){
filterpars->getfromXML(xml);
xml->exitbranch();
};
};
xml->exitbranch();
};
cleanup();
}

View File

@@ -0,0 +1,332 @@
/*
ZynAddSubFX - a software synthesizer
EffectMgr.C - Effect manager, an interface betwen the program and effects
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "EffectMgr.h"
EffectMgr::EffectMgr(int insertion_,pthread_mutex_t *mutex_)
:insertion(insertion_),
efxoutl(new REALTYPE[SOUND_BUFFER_SIZE]),
efxoutr(new REALTYPE[SOUND_BUFFER_SIZE]),
filterpars(NULL),nefx(0),efx(NULL),mutex(mutex_),dryonly(false)
{
setpresettype("Peffect"); /**\todo Figure out what this is doing
* , as it might be another leaky abstraction.*/
// efx=NULL;
// nefx=0;
// insertion=insertion_;
// mutex=mutex_;
// efxoutl=new REALTYPE[SOUND_BUFFER_SIZE];
// efxoutr=new REALTYPE[SOUND_BUFFER_SIZE];
for (int i=0;i<SOUND_BUFFER_SIZE;i++) {
efxoutl[i]=0.0;
efxoutr[i]=0.0;
};
// filterpars=NULL;
// dryonly=false;
defaults();
}
EffectMgr::~EffectMgr()
{
if (efx!=NULL) delete efx;
delete []efxoutl;
delete []efxoutr;
}
void EffectMgr::defaults()
{
changeeffect(0);
setdryonly(false);
}
/*
* Change the effect
*/
void EffectMgr::changeeffect(int nefx_)
{
cleanup();
if (nefx==nefx_) return;
nefx=nefx_;
for (int i=0;i<SOUND_BUFFER_SIZE;i++) {
efxoutl[i]=0.0;
efxoutr[i]=0.0;
};
if (efx!=NULL) delete efx;
switch (nefx) { /**\todo replace leaky abstraction*/
case 1:
efx=new Reverb(insertion,efxoutl,efxoutr);
break;
case 2:
efx=new Echo(insertion,efxoutl,efxoutr);
break;
case 3:
efx=new Chorus(insertion,efxoutl,efxoutr);
break;
case 4:
efx=new Phaser(insertion,efxoutl,efxoutr);
break;
case 5:
efx=new Alienwah(insertion,efxoutl,efxoutr);
break;
case 6:
efx=new Distorsion(insertion,efxoutl,efxoutr);
break;
case 7:
efx=new EQ(insertion,efxoutl,efxoutr);
break;
case 8:
efx=new DynamicFilter(insertion,efxoutl,efxoutr);
break;
//put more effect here
default:
efx=NULL;
break;//no effect (thru)
};
if (efx!=NULL) filterpars=efx->filterpars;
}
/*
* Obtain the effect number
*/
int EffectMgr::geteffect()
{
return (nefx);
}
/*
* Cleanup the current effect
*/
void EffectMgr::cleanup()
{
if (efx!=NULL) efx->cleanup();
}
/*
* Get the preset of the current effect
*/
unsigned char EffectMgr::getpreset()
{
if (efx!=NULL) return(efx->Ppreset);
else return(0);
}
/*
* Change the preset of the current effect
*/
void EffectMgr::changepreset_nolock(unsigned char npreset)
{
if (efx!=NULL) efx->setpreset(npreset);
}
/*
* Change the preset of the current effect(with thread locking)
*/
void EffectMgr::changepreset(unsigned char npreset)
{
pthread_mutex_lock(mutex);
changepreset_nolock(npreset);
pthread_mutex_unlock(mutex);
}
/*
* Change a parameter of the current effect
*/
void EffectMgr::seteffectpar_nolock(int npar,unsigned char value)
{
if (efx==NULL) return;
efx->changepar(npar,value);
}
/*
* Change a parameter of the current effect (with thread locking)
*/
void EffectMgr::seteffectpar(int npar,unsigned char value)
{
pthread_mutex_lock(mutex);
seteffectpar_nolock(npar,value);
pthread_mutex_unlock(mutex);
}
/*
* Get a parameter of the current effect
*/
unsigned char EffectMgr::geteffectpar(int npar)
{
if (efx==NULL) return(0);
return(efx->getpar(npar));
}
/*
* Apply the effect
*/
void EffectMgr::out(REALTYPE *smpsl,REALTYPE *smpsr)
{
int i;
if (efx==NULL) {
if (insertion==0)
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
smpsl[i]=0.0;
smpsr[i]=0.0;
efxoutl[i]=0.0;
efxoutr[i]=0.0;
};
return;
};
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
smpsl[i]+=denormalkillbuf[i];
smpsr[i]+=denormalkillbuf[i];
efxoutl[i]=0.0;
efxoutr[i]=0.0;
};
efx->out(smpsl,smpsr);
REALTYPE volume=efx->volume;
if (nefx==7) {//this is need only for the EQ effect
/**\todo figure out why*/
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
smpsl[i]=efxoutl[i];
smpsr[i]=efxoutr[i];
};
return;
};
//Insertion effect
if (insertion!=0) {
REALTYPE v1,v2;
if (volume<0.5) {
v1=1.0;
v2=volume*2.0;
} else {
v1=(1.0-volume)*2.0;
v2=1.0;
};
if ((nefx==1)||(nefx==2)) v2*=v2;//for Reverb and Echo, the wet function is not liniar
if (dryonly) {//this is used for instrument effect only
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
smpsl[i]*=v1;
smpsr[i]*=v1;
efxoutl[i]*=v2;
efxoutr[i]*=v2;
};
} else {//normal instrument/insertion effect
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
smpsl[i]=smpsl[i]*v1+efxoutl[i]*v2;
smpsr[i]=smpsr[i]*v1+efxoutr[i]*v2;
};
};
} else {//System effect
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
efxoutl[i]*=2.0*volume;
efxoutr[i]*=2.0*volume;
smpsl[i]=efxoutl[i];
smpsr[i]=efxoutr[i];
};
};
}
/*
* Get the effect volume for the system effect
*/
REALTYPE EffectMgr::sysefxgetvolume()
{
if (efx==NULL) return (1.0);
else return(efx->outvolume);
}
/*
* Get the EQ response
*/
REALTYPE EffectMgr::getEQfreqresponse(REALTYPE freq)
{
if (nefx==7) return(efx->getfreqresponse(freq));
else return(0.0);
}
void EffectMgr::setdryonly(bool value)
{
dryonly=value;
}
void EffectMgr::add2XML(XMLwrapper *xml)
{
xml->addpar("type",geteffect());
if ((efx==NULL)||(geteffect()==0)) return;
xml->addpar("preset",efx->Ppreset);
xml->beginbranch("EFFECT_PARAMETERS");
for (int n=0;n<128;n++) { /**\todo evaluate who should oversee saving
* and loading of parameters*/
int par=geteffectpar(n);
if (par==0) continue;
xml->beginbranch("par_no",n);
xml->addpar("par",par);
xml->endbranch();
};
if (filterpars!=NULL) {
xml->beginbranch("FILTER");
filterpars->add2XML(xml);
xml->endbranch();
};
xml->endbranch();
}
void EffectMgr::getfromXML(XMLwrapper *xml)
{
changeeffect(xml->getpar127("type",geteffect()));
if ((efx==NULL)||(geteffect()==0)) return;
efx->Ppreset=xml->getpar127("preset",efx->Ppreset);
if (xml->enterbranch("EFFECT_PARAMETERS")) {
for (int n=0;n<128;n++) {
seteffectpar_nolock(n,0);//erase effect parameter
if (xml->enterbranch("par_no",n)==0) continue;
int par=geteffectpar(n);
seteffectpar_nolock(n,xml->getpar127("par",par));
xml->exitbranch();
};
if (filterpars!=NULL) {
if (xml->enterbranch("FILTER")) {
filterpars->getfromXML(xml);
xml->exitbranch();
};
};
xml->exitbranch();
};
cleanup();
}

View File

@@ -1,12 +1,12 @@
/*
ZynAddSubFX - a software synthesizer
EffectMgr.h - Effect manager, an interface betwen the program and effects
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
@@ -39,67 +39,64 @@
/**Effect manager, an interface betwen the program and effects*/
class EffectMgr:public Presets{
public:
EffectMgr(int insertion_,pthread_mutex_t *mutex_);
~EffectMgr();
class EffectMgr:public Presets
{
public:
EffectMgr(int insertion_,pthread_mutex_t *mutex_);
~EffectMgr();
void add2XML(XMLwrapper *xml);
void defaults();
void getfromXML(XMLwrapper *xml);
void add2XML(XMLwrapper *xml);
void defaults();
void getfromXML(XMLwrapper *xml);
void out(REALTYPE *smpsl,REALTYPE *smpsr);
void out(REALTYPE *smpsl,REALTYPE *smpsr);
void setdryonly(bool value);
/**get the output(to speakers) volume of the systemeffect*/
REALTYPE sysefxgetvolume();
void setdryonly(bool value);
void cleanup();/**<cleanup the effect*/
/**get the output(to speakers) volume of the systemeffect*/
REALTYPE sysefxgetvolume();
/**change effect to the given int
void cleanup();/**<cleanup the effect*/
/**change effect to the given int
* @param nefx_ the number of the effect*/
void changeeffect(int nefx_);
/**Get the number of the effect
* @return the number
* \todo try to fix abstraction failure*/
int geteffect();
/**
* Change the preset to the given one
* @param npreset number of the chosen preset
* \todo figure out why this is binary
*/
void changepreset(unsigned char npreset);
/**
* Change the preset to the given one without locking the thread
* @param npreset number of the chosen preset
* \todo figure out why this is binary
*/
void changepreset_nolock(unsigned char npreset);
/**
* Get the current preset
* @return the current preset*/
unsigned char getpreset();
/**sets the effect par*/
void seteffectpar(int npar,unsigned char value);
/**<sets the effect par without thread lock*/
void seteffectpar_nolock(int npar,unsigned char value);
unsigned char geteffectpar(int npar);
int insertion;/**<1 if the effect is connected as insertion effect
* \todo figure out why this is not a bool*/
REALTYPE *efxoutl,*efxoutr;
void changeeffect(int nefx_);
/**Get the number of the effect
* @return the number*/
int geteffect();
/**
* Change the preset to the given one
* @param npreset number of the chosen preset
*/
void changepreset(unsigned char npreset);
/**
* Change the preset to the given one without locking the thread
* @param npreset number of the chosen preset
*/
void changepreset_nolock(unsigned char npreset);
/**
* Get the current preset
* @return the current preset*/
unsigned char getpreset();
/**sets the effect par*/
void seteffectpar(int npar,unsigned char value);
/**<sets the effect par without thread lock*/
void seteffectpar_nolock(int npar,unsigned char value);
unsigned char geteffectpar(int npar);
const bool insertion;/**<1 if the effect is connected as insertion effect*/
REALTYPE *efxoutl,*efxoutr;
/**used by UI
/**used by UI
* \todo needs to be decoupled*/
REALTYPE getEQfreqresponse(REALTYPE freq);
REALTYPE getEQfreqresponse(REALTYPE freq);
FilterParams *filterpars;
private:
int nefx;
Effect *efx;
pthread_mutex_t *mutex;
bool dryonly;
FilterParams *filterpars;
private:
int nefx;
Effect *efx;
pthread_mutex_t *mutex;
bool dryonly;
};
#endif

View File

@@ -1,250 +0,0 @@
/*
ZynAddSubFX - a software synthesizer
Phaser.C - Phaser effect
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <cmath>
#include "Phaser.h"
/**\todo figure out why this define was made*/
#define PHASER_LFO_SHAPE 2
Phaser::Phaser(const int &insertion_,REALTYPE *efxoutl_,REALTYPE *efxoutr_)
:Effect(insertion_,efxoutl_,efxoutr_,NULL,0),oldl(NULL),oldr(NULL)
{
setpreset(Ppreset);
cleanup();
};
Phaser::~Phaser(){
if (oldl!=NULL) delete [] oldl;
if (oldr!=NULL) delete [] oldr;
};
/*
* Effect output
*/
void Phaser::out(REALTYPE *smpsl,REALTYPE *smpsr){
int i,j;
REALTYPE lfol,lfor,lgain,rgain,tmp;
lfo.effectlfoout(&lfol,&lfor);
lgain=lfol;
rgain=lfor;
lgain=(exp(lgain*PHASER_LFO_SHAPE)-1)/(exp(PHASER_LFO_SHAPE)-1.0);
rgain=(exp(rgain*PHASER_LFO_SHAPE)-1)/(exp(PHASER_LFO_SHAPE)-1.0);
lgain=1.0-phase*(1.0-depth)-(1.0-phase)*lgain*depth;
rgain=1.0-phase*(1.0-depth)-(1.0-phase)*rgain*depth;
if (lgain>1.0) lgain=1.0;else if (lgain<0.0) lgain=0.0;
if (rgain>1.0) rgain=1.0;else if (rgain<0.0) rgain=0.0;
for (i=0;i<SOUND_BUFFER_SIZE;i++){
REALTYPE x=(REALTYPE) i /SOUND_BUFFER_SIZE;
REALTYPE x1=1.0-x;
REALTYPE gl=lgain*x+oldlgain*x1;
REALTYPE gr=rgain*x+oldrgain*x1;
REALTYPE inl=smpsl[i]*panning+fbl;
REALTYPE inr=smpsr[i]*(1.0-panning)+fbr;
//Left channel
for (j=0;j<Pstages*2;j++){//Phasing routine
tmp=oldl[j];
oldl[j]=gl*tmp+inl;
inl=tmp-gl*oldl[j];
};
//Right channel
for (j=0;j<Pstages*2;j++){//Phasing routine
tmp=oldr[j];
oldr[j]=gr*tmp+inr;
inr=tmp-gr*oldr[j];
};
//Left/Right crossing
REALTYPE l=inl;
REALTYPE r=inr;
inl=l*(1.0-lrcross)+r*lrcross;
inr=r*(1.0-lrcross)+l*lrcross;
fbl=inl*fb;
fbr=inr*fb;
efxoutl[i]=inl;
efxoutr[i]=inr;
};
oldlgain=lgain; oldrgain=rgain;
if (Poutsub!=0)
for (i=0;i<SOUND_BUFFER_SIZE;i++){
efxoutl[i]*= -1.0;
efxoutr[i]*= -1.0;
};
};
/*
* Cleanup the effect
*/
void Phaser::cleanup(){
fbl=0.0;fbr=0.0;
oldlgain=0.0;
oldrgain=0.0;
for (int i=0;i<Pstages*2;i++) {
oldl[i]=0.0;
oldr[i]=0.0;
};
};
/*
* Parameter control
*/
void Phaser::setdepth(const unsigned char &Pdepth){
this->Pdepth=Pdepth;
depth=(Pdepth/127.0);
};
void Phaser::setfb(const unsigned char &Pfb){
this->Pfb=Pfb;
fb=(Pfb-64.0)/64.1;
};
void Phaser::setvolume(const unsigned char &Pvolume){
this->Pvolume=Pvolume;
outvolume=Pvolume/127.0;
if (insertion==0) volume=1.0;
else volume=outvolume;
};
void Phaser::setpanning(const unsigned char &Ppanning){
this->Ppanning=Ppanning;
panning=Ppanning/127.0;
};
void Phaser::setlrcross(const unsigned char &Plrcross){
this->Plrcross=Plrcross;
lrcross=Plrcross/127.0;
};
void Phaser::setstages(const unsigned char &Pstages){
if (oldl!=NULL) delete [] oldl;
if (oldr!=NULL) delete [] oldr;
if (Pstages>=MAX_PHASER_STAGES) this->Pstages=MAX_PHASER_STAGES-1;
else this->Pstages=Pstages;
oldl=new REALTYPE[Pstages*2];
oldr=new REALTYPE[Pstages*2];
cleanup();
};
void Phaser::setphase(const unsigned char &Pphase){
this->Pphase=Pphase;
phase=(Pphase/127.0);
};
void Phaser::setpreset(unsigned char npreset){
const int PRESET_SIZE=12;
const int NUM_PRESETS=6;
unsigned char presets[NUM_PRESETS][PRESET_SIZE]={
//Phaser1
{64,64,36,0,0,64,110,64,1,0,0,20},
//Phaser2
{64,64,35,0,0,88,40,64,3,0,0,20},
//Phaser3
{64,64,31,0,0,66,68,107,2,0,0,20},
//Phaser4
{39,64,22,0,0,66,67,10,5,0,1,20},
//Phaser5
{64,64,20,0,1,110,67,78,10,0,0,20},
//Phaser6
{64,64,53,100,0,58,37,78,3,0,0,20}};
if (npreset>=NUM_PRESETS) npreset=NUM_PRESETS-1;
for (int n=0;n<PRESET_SIZE;n++) changepar(n,presets[npreset][n]);
Ppreset=npreset;
};
void Phaser::changepar(const int &npar,const unsigned char &value){
switch(npar){
case 0: setvolume(value);
break;
case 1: setpanning(value);
break;
case 2: lfo.Pfreq=value;
lfo.updateparams();
break;
case 3: lfo.Prandomness=value;
lfo.updateparams();
break;
case 4: lfo.PLFOtype=value;
lfo.updateparams();
break;
case 5: lfo.Pstereo=value;
lfo.updateparams();
break;
case 6: setdepth(value);
break;
case 7: setfb(value);
break;
case 8: setstages(value);
break;
case 9: setlrcross(value);
break;
case 10:if (value>1) Poutsub=1;
else Poutsub=value;
break;
case 11:setphase(value);
break;
};
};
unsigned char Phaser::getpar(const int &npar)const{
switch (npar){
case 0: return(Pvolume);
break;
case 1: return(Ppanning);
break;
case 2: return(lfo.Pfreq);
break;
case 3: return(lfo.Prandomness);
break;
case 4: return(lfo.PLFOtype);
break;
case 5: return(lfo.Pstereo);
break;
case 6: return(Pdepth);
break;
case 7: return(Pfb);
break;
case 8: return(Pstages);
break;
case 9: return(Plrcross);
break;
case 10:return(Poutsub);
break;
case 11:return(Pphase);
break;
default:return (0);
};
};

View File

@@ -0,0 +1,283 @@
/*
ZynAddSubFX - a software synthesizer
Phaser.C - Phaser effect
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <cmath>
#include "Phaser.h"
#define PHASER_LFO_SHAPE 2
Phaser::Phaser(const int &insertion_,REALTYPE *efxoutl_,REALTYPE *efxoutr_)
:Effect(insertion_,efxoutl_,efxoutr_,NULL,0),old(1),oldgain(0.0)
{
setpreset(Ppreset);
cleanup();
};
Phaser::~Phaser()
{
};
/*
* Effect output
*/
void Phaser::out(REALTYPE *smpsl,REALTYPE *smpsr)
{
int i,j;
REALTYPE lfol,lfor,lgain,rgain,tmp;
lfo.effectlfoout(&lfol,&lfor);
lgain=lfol;
rgain=lfor;
lgain=(exp(lgain*PHASER_LFO_SHAPE)-1)/(exp(PHASER_LFO_SHAPE)-1.0);
rgain=(exp(rgain*PHASER_LFO_SHAPE)-1)/(exp(PHASER_LFO_SHAPE)-1.0);
lgain=1.0-phase*(1.0-depth)-(1.0-phase)*lgain*depth;
rgain=1.0-phase*(1.0-depth)-(1.0-phase)*rgain*depth;
if (lgain>1.0) lgain=1.0;
else if (lgain<0.0) lgain=0.0;
if (rgain>1.0) rgain=1.0;
else if (rgain<0.0) rgain=0.0;
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
REALTYPE x=(REALTYPE) i /SOUND_BUFFER_SIZE;
REALTYPE x1=1.0-x;
REALTYPE gl=lgain*x+oldgain.left()*x1;
REALTYPE gr=rgain*x+oldgain.right()*x1;
REALTYPE inl=smpsl[i]*panning+fbl;
REALTYPE inr=smpsr[i]*(1.0-panning)+fbr;
//Left channel
for (j=0;j<Pstages*2;j++) {//Phasing routine
tmp=old.left()[j];
old.left()[j]=gl*tmp+inl;
inl=tmp-gl*old.left()[j];
};
//Right channel
for (j=0;j<Pstages*2;j++) {//Phasing routine
tmp=old.right()[j];
old.right()[j]=gr*tmp+inr;
inr=tmp-gr*old.right()[j];
};
//Left/Right crossing
REALTYPE l=inl;
REALTYPE r=inr;
inl=l*(1.0-lrcross)+r*lrcross;
inr=r*(1.0-lrcross)+l*lrcross;
fbl=inl*fb;
fbr=inr*fb;
efxoutl[i]=inl;
efxoutr[i]=inr;
};
oldgain=Stereo<REALTYPE>(lgain,rgain);
if (Poutsub!=0)
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
efxoutl[i]*= -1.0;
efxoutr[i]*= -1.0;
};
};
/*
* Cleanup the effect
*/
void Phaser::cleanup()
{
fbl=0.0;
fbr=0.0;
oldgain=Stereo<REALTYPE>(0.0);
old.l().clear();
old.r().clear();
};
/*
* Parameter control
*/
void Phaser::setdepth(const unsigned char &Pdepth)
{
this->Pdepth=Pdepth;
depth=(Pdepth/127.0);
};
void Phaser::setfb(const unsigned char &Pfb)
{
this->Pfb=Pfb;
fb=(Pfb-64.0)/64.1;
};
void Phaser::setvolume(const unsigned char &Pvolume)
{
this->Pvolume=Pvolume;
outvolume=Pvolume/127.0;
if (insertion==0) volume=1.0;
else volume=outvolume;
};
void Phaser::setpanning(const unsigned char &Ppanning)
{
this->Ppanning=Ppanning;
panning=Ppanning/127.0;
};
void Phaser::setlrcross(const unsigned char &Plrcross)
{
this->Plrcross=Plrcross;
lrcross=Plrcross/127.0;
};
void Phaser::setstages(const unsigned char &Pstages)
{
if (Pstages>=MAX_PHASER_STAGES) this->Pstages=MAX_PHASER_STAGES-1;
else this->Pstages=Pstages;
old=Stereo<AuSample>(Pstages*2);
cleanup();
};
void Phaser::setphase(const unsigned char &Pphase)
{
this->Pphase=Pphase;
phase=(Pphase/127.0);
};
void Phaser::setpreset(unsigned char npreset)
{
const int PRESET_SIZE=12;
const int NUM_PRESETS=6;
unsigned char presets[NUM_PRESETS][PRESET_SIZE]={
//Phaser1
{64,64,36,0,0,64,110,64,1,0,0,20},
//Phaser2
{64,64,35,0,0,88,40,64,3,0,0,20},
//Phaser3
{64,64,31,0,0,66,68,107,2,0,0,20},
//Phaser4
{39,64,22,0,0,66,67,10,5,0,1,20},
//Phaser5
{64,64,20,0,1,110,67,78,10,0,0,20},
//Phaser6
{64,64,53,100,0,58,37,78,3,0,0,20}
};
if (npreset>=NUM_PRESETS) npreset=NUM_PRESETS-1;
for (int n=0;n<PRESET_SIZE;n++) changepar(n,presets[npreset][n]);
Ppreset=npreset;
};
void Phaser::changepar(const int &npar,const unsigned char &value)
{
switch (npar) {
case 0:
setvolume(value);
break;
case 1:
setpanning(value);
break;
case 2:
lfo.Pfreq=value;
lfo.updateparams();
break;
case 3:
lfo.Prandomness=value;
lfo.updateparams();
break;
case 4:
lfo.PLFOtype=value;
lfo.updateparams();
break;
case 5:
lfo.Pstereo=value;
lfo.updateparams();
break;
case 6:
setdepth(value);
break;
case 7:
setfb(value);
break;
case 8:
setstages(value);
break;
case 9:
setlrcross(value);
break;
case 10:
if (value>1) Poutsub=1;
else Poutsub=value;
break;
case 11:
setphase(value);
break;
};
};
unsigned char Phaser::getpar(const int &npar)const
{
switch (npar) {
case 0:
return(Pvolume);
break;
case 1:
return(Ppanning);
break;
case 2:
return(lfo.Pfreq);
break;
case 3:
return(lfo.Prandomness);
break;
case 4:
return(lfo.PLFOtype);
break;
case 5:
return(lfo.Pstereo);
break;
case 6:
return(Pdepth);
break;
case 7:
return(Pfb);
break;
case 8:
return(Pstages);
break;
case 9:
return(Plrcross);
break;
case 10:
return(Poutsub);
break;
case 11:
return(Pphase);
break;
default:
return (0);
};
};

View File

@@ -1,71 +1,76 @@
/*
ZynAddSubFX - a software synthesizer
Phaser.h - Phaser effect
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef PHASER_H
#define PHASER_H
#include "../globals.h"
#include "Effect.h"
#include "EffectLFO.h"
#define MAX_PHASER_STAGES 12
/**Phaser Effect*/
class Phaser:public Effect {
public:
Phaser(const int &insetion_,REALTYPE *efxoutl_,REALTYPE *efxoutr_);
~Phaser();
void out(REALTYPE *smpsl,REALTYPE *smpsr);
void setpreset(unsigned char npreset);
void changepar(const int &npar,const unsigned char &value);
unsigned char getpar(const int &npar)const;
void cleanup();
void setdryonly();
private:
//Parametrii Phaser
EffectLFO lfo;/**<lfo-ul Phaser*/
unsigned char Pvolume;
unsigned char Ppanning;
unsigned char Pdepth;/**<the depth of the Phaser*/
unsigned char Pfb;/**<feedback*/
unsigned char Plrcross;/**<feedback*/
unsigned char Pstages;
unsigned char Poutsub;/**<if I wish to substract the output instead of the adding it*/
unsigned char Pphase;
//Control Parametrii
void setvolume(const unsigned char &Pvolume);
void setpanning(const unsigned char &Ppanning);
void setdepth(const unsigned char &Pdepth);
void setfb(const unsigned char &Pfb);
void setlrcross(const unsigned char &Plrcross);
void setstages(const unsigned char &Pstages);
void setphase(const unsigned char &Pphase);
//Internal Values
//int insertion; //inherited from Effect
REALTYPE panning,fb,depth,lrcross,fbl,fbr,phase;
REALTYPE *oldl,*oldr;
REALTYPE oldlgain,oldrgain;
};
#endif
/*
ZynAddSubFX - a software synthesizer
Phaser.h - Phaser effect
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef PHASER_H
#define PHASER_H
#include "../globals.h"
#include "../Misc/Stereo.h"
#include "../Samples/AuSample.h"
#include "Effect.h"
#include "EffectLFO.h"
#define MAX_PHASER_STAGES 12
/**Phaser Effect*/
class Phaser:public Effect
{
public:
Phaser(const int &insetion_,REALTYPE *efxoutl_,REALTYPE *efxoutr_);
~Phaser();
void out(REALTYPE *smpsl,REALTYPE *smpsr);
void setpreset(unsigned char npreset);
void changepar(const int &npar,const unsigned char &value);
unsigned char getpar(const int &npar)const;
void cleanup();
void setdryonly();
private:
//Parametrii Phaser
EffectLFO lfo;/**<lfo-ul Phaser*/
unsigned char Pvolume;
unsigned char Ppanning;
unsigned char Pdepth;/**<the depth of the Phaser*/
unsigned char Pfb;/**<feedback*/
unsigned char Plrcross;/**<feedback*/
unsigned char Pstages;
unsigned char Poutsub;/**<if I wish to substract the output instead of the adding it*/
unsigned char Pphase;
//Control Parametrii
void setvolume(const unsigned char &Pvolume);
void setpanning(const unsigned char &Ppanning);
void setdepth(const unsigned char &Pdepth);
void setfb(const unsigned char &Pfb);
void setlrcross(const unsigned char &Plrcross);
void setstages(const unsigned char &Pstages);
void setphase(const unsigned char &Pphase);
//Internal Values
//int insertion; //inherited from Effect
REALTYPE panning,fb,depth,lrcross,fbl,fbr,phase;
//REALTYPE *oldl,*oldr;
Stereo<AuSample> old;
//REALTYPE oldlgain,oldrgain;
Stereo<REALTYPE> oldgain;
};
#endif

View File

@@ -1,430 +0,0 @@
/*
ZynAddSubFX - a software synthesizer
Reverb.C - Reverberation effect
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <cmath>
#include "Reverb.h"
/**\todo: EarlyReflections,Prdelay,Perbalance */
Reverb::Reverb(const int &insertion_,REALTYPE *efxoutl_,REALTYPE *efxoutr_)
:Effect(insertion_,efxoutl_,efxoutr_,NULL,0)
{
inputbuf=new REALTYPE[SOUND_BUFFER_SIZE];
//defaults
Pvolume=48;
Ppan=64;
Ptime=64;
Pidelay=40;
Pidelayfb=0;
Prdelay=0;
Plpf=127;
Phpf=0;
Perbalance=64;
Plohidamp=80;
Ptype=1;
Proomsize=64;roomsize=1.0;rs=1.0;
for (int i=0;i<REV_COMBS*2;i++) {
comblen[i]=800+(int)(RND*1400);
combk[i]=0;
lpcomb[i]=0;
combfb[i]=-0.97;
comb[i]=NULL;
};
for (int i=0;i<REV_APS*2;i++) {
aplen[i]=500+(int)(RND*500);
apk[i]=0;
ap[i]=NULL;
};
lpf=NULL;hpf=NULL;//no filter
idelay=NULL;
setpreset(Ppreset);
cleanup();//do not call this before the comb initialisation
};
Reverb::~Reverb(){
int i;
if (idelay!=NULL) delete []idelay;
if (hpf!=NULL) delete hpf;
if (lpf!=NULL) delete lpf;
for (i=0;i<REV_APS*2;i++) delete [] ap[i];
for (i=0;i<REV_COMBS*2;i++) delete [] comb[i];
delete [] inputbuf;
};
/*
* Cleanup the effect
*/
void Reverb::cleanup(){
int i,j;
for (i=0;i<REV_COMBS*2;i++){
lpcomb[i]=0.0;
for (j=0;j<comblen[i];j++) comb[i][j]=0.0;
};
for (i=0;i<REV_APS*2;i++)
for (j=0;j<aplen[i];j++) ap[i][j]=0.0;
if (idelay!=NULL) for (i=0;i<idelaylen;i++) idelay[i]=0.0;
if (hpf!=NULL) hpf->cleanup();
if (lpf!=NULL) lpf->cleanup();
};
/*
* Process one channel; 0=left,1=right
*/
void Reverb::processmono(int ch,REALTYPE *output){
int i,j;
REALTYPE fbout,tmp;
/**\todo: implement the high part from lohidamp*/
for (j=REV_COMBS*ch;j<REV_COMBS*(ch+1);j++){
int ck=combk[j];
int comblength=comblen[j];
REALTYPE lpcombj=lpcomb[j];
for (i=0;i<SOUND_BUFFER_SIZE;i++){
fbout=comb[j][ck]*combfb[j];
fbout=fbout*(1.0-lohifb)+lpcombj*lohifb;
lpcombj=fbout;
comb[j][ck]=inputbuf[i]+fbout;
output[i]+=fbout;
if ((++ck)>=comblength) ck=0;
};
combk[j]=ck;
lpcomb[j]=lpcombj;
};
for (j=REV_APS*ch;j<REV_APS*(1+ch);j++){
int ak=apk[j];
int aplength=aplen[j];
for (i=0;i<SOUND_BUFFER_SIZE;i++){
tmp=ap[j][ak];
ap[j][ak]=0.7*tmp+output[i];
output[i]=tmp-0.7*ap[j][ak];
if ((++ak)>=aplength) ak=0;
};
apk[j]=ak;
};
};
/*
* Effect output
*/
void Reverb::out(REALTYPE *smps_l, REALTYPE *smps_r){
int i;
if ((Pvolume==0)&&(insertion!=0)) return;
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
inputbuf[i]=(smps_l[i]+smps_r[i])/2.0;
//Initial delay r
if (idelay!=NULL){
REALTYPE tmp=inputbuf[i]+idelay[idelayk]*idelayfb;
inputbuf[i]=idelay[idelayk];
idelay[idelayk]=tmp;
idelayk++;if (idelayk>=idelaylen) idelayk=0;
};
};
if (lpf!=NULL) lpf->filterout(inputbuf);
if (hpf!=NULL) hpf->filterout(inputbuf);
processmono(0,efxoutl);//left
processmono(1,efxoutr);//right
REALTYPE lvol=rs/REV_COMBS*pan;
REALTYPE rvol=rs/REV_COMBS*(1.0-pan);
if (insertion!=0){
lvol*=2;rvol*=2;
};
for (int i=0;i<SOUND_BUFFER_SIZE;i++){
efxoutl[i]*=lvol;
efxoutr[i]*=rvol;
};
};
/*
* Parameter control
*/
void Reverb::setvolume(const unsigned char &Pvolume){
this->Pvolume=Pvolume;
if (insertion==0) {
outvolume=pow(0.01,(1.0-Pvolume/127.0))*4.0;
volume=1.0;
} else {
volume=outvolume=Pvolume/127.0;
if (Pvolume==0) cleanup();
};
};
void Reverb::setpan(const unsigned char &Ppan){
this->Ppan=Ppan;
pan=(REALTYPE)Ppan/127.0;
};
void Reverb::settime(const unsigned char &Ptime){
int i;
REALTYPE t;
this->Ptime=Ptime;
t=pow(60.0,(REALTYPE)Ptime/127.0)-0.97;
for (i=0;i<REV_COMBS*2;i++){
combfb[i]=-exp((REALTYPE)comblen[i]/(REALTYPE)SAMPLE_RATE*log(0.001)/t);
//the feedback is negative because it removes the DC
};
};
void Reverb::setlohidamp(unsigned char Plohidamp){
REALTYPE x;
if (Plohidamp<64) Plohidamp=64;//remove this when the high part from lohidamp will be added
this->Plohidamp=Plohidamp;
if (Plohidamp==64) {
lohidamptype=0;
lohifb=0.0;
} else {
if (Plohidamp<64) lohidamptype=1;
if (Plohidamp>64) lohidamptype=2;
x=fabs((REALTYPE)(Plohidamp-64)/64.1);
lohifb=x*x;
};
};
void Reverb::setidelay(const unsigned char &Pidelay){
REALTYPE delay;
this->Pidelay=Pidelay;
delay=pow(50*Pidelay/127.0,2)-1.0;
if (idelay!=NULL) delete []idelay;
idelay=NULL;
idelaylen=(int) (SAMPLE_RATE*delay/1000);
if (idelaylen>1) {
idelayk=0;
idelay=new REALTYPE[idelaylen];
for (int i=0;i<idelaylen;i++) idelay[i]=0.0;
};
};
void Reverb::setidelayfb(const unsigned char &Pidelayfb){
this->Pidelayfb=Pidelayfb;
idelayfb=Pidelayfb/128.0;
};
void Reverb::sethpf(const unsigned char &Phpf){
this->Phpf=Phpf;
if (Phpf==0) {//No HighPass
if (hpf!=NULL) delete hpf;
hpf=NULL;
}
else{
REALTYPE fr=exp(pow(Phpf/127.0,0.5)*log(10000.0))+20.0;
if (hpf==NULL) hpf=new AnalogFilter(3,fr,1,0);
else hpf->setfreq(fr);
};
};
void Reverb::setlpf(const unsigned char &Plpf){
this->Plpf=Plpf;
if (Plpf==127) {//No LowPass
if (lpf!=NULL) delete lpf;
lpf=NULL;
}
else{
REALTYPE fr=exp(pow(Plpf/127.0,0.5)*log(25000.0))+40;
if (lpf==NULL) lpf=new AnalogFilter(2,fr,1,0);
else lpf->setfreq(fr);
};
};
void Reverb::settype(unsigned char Ptype){
const int NUM_TYPES=2;
int combtunings[NUM_TYPES][REV_COMBS]={
//this is unused (for random)
{0,0,0,0,0,0,0,0},
//Freeverb by Jezar at Dreampoint
{1116,1188,1277,1356,1422,1491,1557,1617}
};
int aptunings[NUM_TYPES][REV_APS]={
//this is unused (for random)
{0,0,0,0},
//Freeverb by Jezar at Dreampoint
{225,341,441,556}
};
if (Ptype>=NUM_TYPES) Ptype=NUM_TYPES-1;
this->Ptype=Ptype;
REALTYPE tmp;
for (int i=0;i<REV_COMBS*2;i++) {
if (Ptype==0) tmp=800.0+(int)(RND*1400.0);
else tmp=combtunings[Ptype][i%REV_COMBS];
tmp*=roomsize;
if (i>REV_COMBS) tmp+=23.0;
tmp*=SAMPLE_RATE/44100.0;//adjust the combs according to the samplerate
if (tmp<10) tmp=10;
comblen[i]=(int) tmp;
combk[i]=0;
lpcomb[i]=0;
if (comb[i]!=NULL) delete []comb[i];
comb[i]=new REALTYPE[comblen[i]];
};
for (int i=0;i<REV_APS*2;i++) {
if (Ptype==0) tmp=500+(int)(RND*500);
else tmp=aptunings[Ptype][i%REV_APS];
tmp*=roomsize;
if (i>REV_APS) tmp+=23.0;
tmp*=SAMPLE_RATE/44100.0;//adjust the combs according to the samplerate
if (tmp<10) tmp=10;
aplen[i]=(int) tmp;
apk[i]=0;
if (ap[i]!=NULL) delete []ap[i];
ap[i]=new REALTYPE[aplen[i]];
};
settime(Ptime);
cleanup();
};
void Reverb::setroomsize(const unsigned char &Proomsize){
this->Proomsize=Proomsize;
if (Proomsize==0) this->Proomsize=64;//this is because the older versions consider roomsize=0
roomsize=(this->Proomsize-64.0)/64.0;
if (roomsize>0.0) roomsize*=2.0;
roomsize=pow(10.0,roomsize);
rs=sqrt(roomsize);
settype(Ptype);
};
void Reverb::setpreset(unsigned char npreset){
const int PRESET_SIZE=12;
const int NUM_PRESETS=13;
unsigned char presets[NUM_PRESETS][PRESET_SIZE]={
//Cathedral1
{80,64,63,24,0,0,0,85,5,83,1,64},
//Cathedral2
{80,64,69,35,0,0,0,127,0,71,0,64},
//Cathedral3
{80,64,69,24,0,0,0,127,75,78,1,85},
//Hall1
{90,64,51,10,0,0,0,127,21,78,1,64},
//Hall2
{90,64,53,20,0,0,0,127,75,71,1,64},
//Room1
{100,64,33,0,0,0,0,127,0,106,0,30},
//Room2
{100,64,21,26,0,0,0,62,0,77,1,45},
//Basement
{110,64,14,0,0,0,0,127,5,71,0,25},
//Tunnel
{85,80,84,20,42,0,0,51,0,78,1,105},
//Echoed1
{95,64,26,60,71,0,0,114,0,64,1,64},
//Echoed2
{90,64,40,88,71,0,0,114,0,88,1,64},
//VeryLong1
{90,64,93,15,0,0,0,114,0,77,0,95},
//VeryLong2
{90,64,111,30,0,0,0,114,90,74,1,80}};
if (npreset>=NUM_PRESETS) npreset=NUM_PRESETS-1;
for (int n=0;n<PRESET_SIZE;n++) changepar(n,presets[npreset][n]);
if (insertion!=0) changepar(0,presets[npreset][0]/2);//lower the volume if reverb is insertion effect
Ppreset=npreset;
};
void Reverb::changepar(const int &npar,const unsigned char &value){
switch (npar){
case 0: setvolume(value);
break;
case 1: setpan(value);
break;
case 2: settime(value);
break;
case 3: setidelay(value);
break;
case 4: setidelayfb(value);
break;
// case 5: setrdelay(value);
// break;
// case 6: seterbalance(value);
// break;
case 7: setlpf(value);
break;
case 8: sethpf(value);
break;
case 9: setlohidamp(value);
break;
case 10:settype(value);
break;
case 11:setroomsize(value);
break;
};
};
unsigned char Reverb::getpar(const int &npar)const{
switch (npar){
case 0: return(Pvolume);
break;
case 1: return(Ppan);
break;
case 2: return(Ptime);
break;
case 3: return(Pidelay);
break;
case 4: return(Pidelayfb);
break;
// case 5: return(Prdelay);
// break;
// case 6: return(Perbalance);
// break;
case 7: return(Plpf);
break;
case 8: return(Phpf);
break;
case 9: return(Plohidamp);
break;
case 10:return(Ptype);
break;
case 11:return(Proomsize);
break;
};
return(0);//in case of bogus "parameter"
};

View File

@@ -0,0 +1,471 @@
/*
ZynAddSubFX - a software synthesizer
Reverb.C - Reverberation effect
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <cmath>
#include "Reverb.h"
/**\todo: EarlyReflections,Prdelay,Perbalance */
Reverb::Reverb(const int &insertion_,REALTYPE *efxoutl_,REALTYPE *efxoutr_)
:Effect(insertion_,efxoutl_,efxoutr_,NULL,0)
{
inputbuf=new REALTYPE[SOUND_BUFFER_SIZE];
//defaults
Pvolume=48;
Ppan=64;
Ptime=64;
Pidelay=40;
Pidelayfb=0;
Prdelay=0;
Plpf=127;
Phpf=0;
Perbalance=64;
Plohidamp=80;
Ptype=1;
Proomsize=64;
roomsize=1.0;
rs=1.0;
for (int i=0;i<REV_COMBS*2;i++) {
comblen[i]=800+(int)(RND*1400);
combk[i]=0;
lpcomb[i]=0;
combfb[i]=-0.97;
comb[i]=NULL;
};
for (int i=0;i<REV_APS*2;i++) {
aplen[i]=500+(int)(RND*500);
apk[i]=0;
ap[i]=NULL;
};
lpf=NULL;
hpf=NULL;//no filter
idelay=NULL;
setpreset(Ppreset);
cleanup();//do not call this before the comb initialisation
};
Reverb::~Reverb()
{
int i;
if (idelay!=NULL) delete []idelay;
if (hpf!=NULL) delete hpf;
if (lpf!=NULL) delete lpf;
for (i=0;i<REV_APS*2;i++) delete [] ap[i];
for (i=0;i<REV_COMBS*2;i++) delete [] comb[i];
delete [] inputbuf;
};
/*
* Cleanup the effect
*/
void Reverb::cleanup()
{
int i,j;
for (i=0;i<REV_COMBS*2;i++) {
lpcomb[i]=0.0;
for (j=0;j<comblen[i];j++) comb[i][j]=0.0;
};
for (i=0;i<REV_APS*2;i++)
for (j=0;j<aplen[i];j++) ap[i][j]=0.0;
if (idelay!=NULL) for (i=0;i<idelaylen;i++) idelay[i]=0.0;
if (hpf!=NULL) hpf->cleanup();
if (lpf!=NULL) lpf->cleanup();
};
/*
* Process one channel; 0=left,1=right
*/
void Reverb::processmono(int ch,REALTYPE *output)
{
int i,j;
REALTYPE fbout,tmp;
/**\todo: implement the high part from lohidamp*/
for (j=REV_COMBS*ch;j<REV_COMBS*(ch+1);j++) {
int ck=combk[j];
int comblength=comblen[j];
REALTYPE lpcombj=lpcomb[j];
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
fbout=comb[j][ck]*combfb[j];
fbout=fbout*(1.0-lohifb)+lpcombj*lohifb;
lpcombj=fbout;
comb[j][ck]=inputbuf[i]+fbout;
output[i]+=fbout;
if ((++ck)>=comblength) ck=0;
};
combk[j]=ck;
lpcomb[j]=lpcombj;
};
for (j=REV_APS*ch;j<REV_APS*(1+ch);j++) {
int ak=apk[j];
int aplength=aplen[j];
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
tmp=ap[j][ak];
ap[j][ak]=0.7*tmp+output[i];
output[i]=tmp-0.7*ap[j][ak];
if ((++ak)>=aplength) ak=0;
};
apk[j]=ak;
};
};
/*
* Effect output
*/
void Reverb::out(REALTYPE *smps_l, REALTYPE *smps_r)
{
int i;
if ((Pvolume==0)&&(insertion!=0)) return;
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
inputbuf[i]=(smps_l[i]+smps_r[i])/2.0;
//Initial delay r
if (idelay!=NULL) {
REALTYPE tmp=inputbuf[i]+idelay[idelayk]*idelayfb;
inputbuf[i]=idelay[idelayk];
idelay[idelayk]=tmp;
idelayk++;
if (idelayk>=idelaylen) idelayk=0;
};
};
if (lpf!=NULL) lpf->filterout(inputbuf);
if (hpf!=NULL) hpf->filterout(inputbuf);
processmono(0,efxoutl);//left
processmono(1,efxoutr);//right
REALTYPE lvol=rs/REV_COMBS*pan;
REALTYPE rvol=rs/REV_COMBS*(1.0-pan);
if (insertion!=0) {
lvol*=2;
rvol*=2;
};
for (int i=0;i<SOUND_BUFFER_SIZE;i++) {
efxoutl[i]*=lvol;
efxoutr[i]*=rvol;
};
};
/*
* Parameter control
*/
void Reverb::setvolume(const unsigned char &Pvolume)
{
this->Pvolume=Pvolume;
if (insertion==0) {
outvolume=pow(0.01,(1.0-Pvolume/127.0))*4.0;
volume=1.0;
} else {
volume=outvolume=Pvolume/127.0;
if (Pvolume==0) cleanup();
};
};
void Reverb::setpan(const unsigned char &Ppan)
{
this->Ppan=Ppan;
pan=(REALTYPE)Ppan/127.0;
};
void Reverb::settime(const unsigned char &Ptime)
{
int i;
REALTYPE t;
this->Ptime=Ptime;
t=pow(60.0,(REALTYPE)Ptime/127.0)-0.97;
for (i=0;i<REV_COMBS*2;i++) {
combfb[i]=-exp((REALTYPE)comblen[i]/(REALTYPE)SAMPLE_RATE*log(0.001)/t);
//the feedback is negative because it removes the DC
};
};
void Reverb::setlohidamp(unsigned char Plohidamp)
{
REALTYPE x;
if (Plohidamp<64) Plohidamp=64;//remove this when the high part from lohidamp will be added
this->Plohidamp=Plohidamp;
if (Plohidamp==64) {
lohidamptype=0;
lohifb=0.0;
} else {
if (Plohidamp<64) lohidamptype=1;
if (Plohidamp>64) lohidamptype=2;
x=fabs((REALTYPE)(Plohidamp-64)/64.1);
lohifb=x*x;
};
};
void Reverb::setidelay(const unsigned char &Pidelay)
{
REALTYPE delay;
this->Pidelay=Pidelay;
delay=pow(50*Pidelay/127.0,2)-1.0;
if (idelay!=NULL) delete []idelay;
idelay=NULL;
idelaylen=(int) (SAMPLE_RATE*delay/1000);
if (idelaylen>1) {
idelayk=0;
idelay=new REALTYPE[idelaylen];
for (int i=0;i<idelaylen;i++) idelay[i]=0.0;
};
};
void Reverb::setidelayfb(const unsigned char &Pidelayfb)
{
this->Pidelayfb=Pidelayfb;
idelayfb=Pidelayfb/128.0;
};
void Reverb::sethpf(const unsigned char &Phpf)
{
this->Phpf=Phpf;
if (Phpf==0) {//No HighPass
if (hpf!=NULL) delete hpf;
hpf=NULL;
} else {
REALTYPE fr=exp(pow(Phpf/127.0,0.5)*log(10000.0))+20.0;
if (hpf==NULL) hpf=new AnalogFilter(3,fr,1,0);
else hpf->setfreq(fr);
};
};
void Reverb::setlpf(const unsigned char &Plpf)
{
this->Plpf=Plpf;
if (Plpf==127) {//No LowPass
if (lpf!=NULL) delete lpf;
lpf=NULL;
} else {
REALTYPE fr=exp(pow(Plpf/127.0,0.5)*log(25000.0))+40;
if (lpf==NULL) lpf=new AnalogFilter(2,fr,1,0);
else lpf->setfreq(fr);
};
};
void Reverb::settype(unsigned char Ptype)
{
const int NUM_TYPES=2;
int combtunings[NUM_TYPES][REV_COMBS]={
//this is unused (for random)
{0,0,0,0,0,0,0,0},
//Freeverb by Jezar at Dreampoint
{1116,1188,1277,1356,1422,1491,1557,1617}
};
int aptunings[NUM_TYPES][REV_APS]={
//this is unused (for random)
{0,0,0,0},
//Freeverb by Jezar at Dreampoint
{225,341,441,556}
};
if (Ptype>=NUM_TYPES) Ptype=NUM_TYPES-1;
this->Ptype=Ptype;
REALTYPE tmp;
for (int i=0;i<REV_COMBS*2;i++) {
if (Ptype==0) tmp=800.0+(int)(RND*1400.0);
else tmp=combtunings[Ptype][i%REV_COMBS];
tmp*=roomsize;
if (i>REV_COMBS) tmp+=23.0;
tmp*=SAMPLE_RATE/44100.0;//adjust the combs according to the samplerate
if (tmp<10) tmp=10;
comblen[i]=(int) tmp;
combk[i]=0;
lpcomb[i]=0;
if (comb[i]!=NULL) delete []comb[i];
comb[i]=new REALTYPE[comblen[i]];
};
for (int i=0;i<REV_APS*2;i++) {
if (Ptype==0) tmp=500+(int)(RND*500);
else tmp=aptunings[Ptype][i%REV_APS];
tmp*=roomsize;
if (i>REV_APS) tmp+=23.0;
tmp*=SAMPLE_RATE/44100.0;//adjust the combs according to the samplerate
if (tmp<10) tmp=10;
aplen[i]=(int) tmp;
apk[i]=0;
if (ap[i]!=NULL) delete []ap[i];
ap[i]=new REALTYPE[aplen[i]];
};
settime(Ptime);
cleanup();
};
void Reverb::setroomsize(const unsigned char &Proomsize)
{
this->Proomsize=Proomsize;
if (Proomsize==0) this->Proomsize=64;//this is because the older versions consider roomsize=0
roomsize=(this->Proomsize-64.0)/64.0;
if (roomsize>0.0) roomsize*=2.0;
roomsize=pow(10.0,roomsize);
rs=sqrt(roomsize);
settype(Ptype);
};
void Reverb::setpreset(unsigned char npreset)
{
const int PRESET_SIZE=12;
const int NUM_PRESETS=13;
unsigned char presets[NUM_PRESETS][PRESET_SIZE]={
//Cathedral1
{80,64,63,24,0,0,0,85,5,83,1,64},
//Cathedral2
{80,64,69,35,0,0,0,127,0,71,0,64},
//Cathedral3
{80,64,69,24,0,0,0,127,75,78,1,85},
//Hall1
{90,64,51,10,0,0,0,127,21,78,1,64},
//Hall2
{90,64,53,20,0,0,0,127,75,71,1,64},
//Room1
{100,64,33,0,0,0,0,127,0,106,0,30},
//Room2
{100,64,21,26,0,0,0,62,0,77,1,45},
//Basement
{110,64,14,0,0,0,0,127,5,71,0,25},
//Tunnel
{85,80,84,20,42,0,0,51,0,78,1,105},
//Echoed1
{95,64,26,60,71,0,0,114,0,64,1,64},
//Echoed2
{90,64,40,88,71,0,0,114,0,88,1,64},
//VeryLong1
{90,64,93,15,0,0,0,114,0,77,0,95},
//VeryLong2
{90,64,111,30,0,0,0,114,90,74,1,80}
};
if (npreset>=NUM_PRESETS) npreset=NUM_PRESETS-1;
for (int n=0;n<PRESET_SIZE;n++) changepar(n,presets[npreset][n]);
if (insertion!=0) changepar(0,presets[npreset][0]/2);//lower the volume if reverb is insertion effect
Ppreset=npreset;
};
void Reverb::changepar(const int &npar,const unsigned char &value)
{
switch (npar) {
case 0:
setvolume(value);
break;
case 1:
setpan(value);
break;
case 2:
settime(value);
break;
case 3:
setidelay(value);
break;
case 4:
setidelayfb(value);
break;
// case 5: setrdelay(value);
// break;
// case 6: seterbalance(value);
// break;
case 7:
setlpf(value);
break;
case 8:
sethpf(value);
break;
case 9:
setlohidamp(value);
break;
case 10:
settype(value);
break;
case 11:
setroomsize(value);
break;
};
};
unsigned char Reverb::getpar(const int &npar)const
{
switch (npar) {
case 0:
return(Pvolume);
break;
case 1:
return(Ppan);
break;
case 2:
return(Ptime);
break;
case 3:
return(Pidelay);
break;
case 4:
return(Pidelayfb);
break;
// case 5: return(Prdelay);
// break;
// case 6: return(Perbalance);
// break;
case 7:
return(Plpf);
break;
case 8:
return(Phpf);
break;
case 9:
return(Plohidamp);
break;
case 10:
return(Ptype);
break;
case 11:
return(Proomsize);
break;
};
return(0);//in case of bogus "parameter"
};

View File

@@ -1,126 +1,127 @@
/*
ZynAddSubFX - a software synthesizer
Reverb.h - Reverberation effect
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef REVERB_H
#define REVERB_H
#include "../globals.h"
#include "../DSP/AnalogFilter.h"
#include "Effect.h"
#define REV_COMBS 8
#define REV_APS 4
/**Creates Reverberation Effects*/
class Reverb:public Effect {
public:
Reverb(const int &insertion_,REALTYPE *efxoutl_,REALTYPE *efxoutr_);
~Reverb();
void out(REALTYPE *smps_l,REALTYPE *smps_r);
void cleanup();
void setpreset(unsigned char npreset);
void changepar(const int &npar,const unsigned char &value);
unsigned char getpar(const int &npar)const;
private:
//Parametrii
/**Amount of the reverb*/
unsigned char Pvolume;
/**Left/Right Panning*/
unsigned char Ppan;
/**duration of reverb*/
unsigned char Ptime;
/**Initial delay*/
unsigned char Pidelay;
/**Initial delay feedback*/
unsigned char Pidelayfb;
/**delay between ER/Reverbs*/
unsigned char Prdelay;
/**EarlyReflections/Reverb Balance*/
unsigned char Perbalance;
/**HighPassFilter*/
unsigned char Plpf;
/**LowPassFilter*/
unsigned char Phpf;
/**Low/HighFrequency Damping
* \todo 0..63 lpf,64=off,65..127=hpf(TODO)*/
unsigned char Plohidamp;
/**Reverb type*/
unsigned char Ptype;
/**Room Size*/
unsigned char Proomsize;
//parameter control
void setvolume(const unsigned char &Pvolume);
void setpan(const unsigned char &Ppan);
void settime(const unsigned char &Ptime);
void setlohidamp(unsigned char Plohidamp);
void setidelay(const unsigned char &Pidelay);
void setidelayfb(const unsigned char &Pidelayfb);
void sethpf(const unsigned char &Phpf);
void setlpf(const unsigned char &Plpf);
void settype( unsigned char Ptype);
void setroomsize(const unsigned char &Proomsize);
REALTYPE pan,erbalance;
//Parametrii 2
int lohidamptype;/**<0=disable,1=highdamp(lowpass),2=lowdamp(highpass)*/
int idelaylen,rdelaylen;
int idelayk;
REALTYPE lohifb,idelayfb,roomsize,rs;//rs is used to "normalise" the volume according to the roomsize
int comblen[REV_COMBS*2];
int aplen[REV_APS*2];
//Internal Variables
REALTYPE *comb[REV_COMBS*2];
int combk[REV_COMBS*2];
REALTYPE combfb[REV_COMBS*2];/**<feedback-ul fiecarui filtru "comb"*/
REALTYPE lpcomb[REV_COMBS*2];/**<pentru Filtrul LowPass*/
REALTYPE *ap[REV_APS*2];
int apk[REV_APS*2];
REALTYPE *idelay;
AnalogFilter *lpf,*hpf;//filters
REALTYPE *inputbuf;
void processmono(int ch,REALTYPE *output);
};
#endif
/*
ZynAddSubFX - a software synthesizer
Reverb.h - Reverberation effect
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef REVERB_H
#define REVERB_H
#include "../globals.h"
#include "../DSP/AnalogFilter.h"
#include "Effect.h"
#define REV_COMBS 8
#define REV_APS 4
/**Creates Reverberation Effects*/
class Reverb:public Effect
{
public:
Reverb(const int &insertion_,REALTYPE *efxoutl_,REALTYPE *efxoutr_);
~Reverb();
void out(REALTYPE *smps_l,REALTYPE *smps_r);
void cleanup();
void setpreset(unsigned char npreset);
void changepar(const int &npar,const unsigned char &value);
unsigned char getpar(const int &npar)const;
private:
//Parametrii
/**Amount of the reverb*/
unsigned char Pvolume;
/**Left/Right Panning*/
unsigned char Ppan;
/**duration of reverb*/
unsigned char Ptime;
/**Initial delay*/
unsigned char Pidelay;
/**Initial delay feedback*/
unsigned char Pidelayfb;
/**delay between ER/Reverbs*/
unsigned char Prdelay;
/**EarlyReflections/Reverb Balance*/
unsigned char Perbalance;
/**HighPassFilter*/
unsigned char Plpf;
/**LowPassFilter*/
unsigned char Phpf;
/**Low/HighFrequency Damping
* \todo 0..63 lpf,64=off,65..127=hpf(TODO)*/
unsigned char Plohidamp;
/**Reverb type*/
unsigned char Ptype;
/**Room Size*/
unsigned char Proomsize;
//parameter control
void setvolume(const unsigned char &Pvolume);
void setpan(const unsigned char &Ppan);
void settime(const unsigned char &Ptime);
void setlohidamp(unsigned char Plohidamp);
void setidelay(const unsigned char &Pidelay);
void setidelayfb(const unsigned char &Pidelayfb);
void sethpf(const unsigned char &Phpf);
void setlpf(const unsigned char &Plpf);
void settype( unsigned char Ptype);
void setroomsize(const unsigned char &Proomsize);
REALTYPE pan,erbalance;
//Parametrii 2
int lohidamptype;/**<0=disable,1=highdamp(lowpass),2=lowdamp(highpass)*/
int idelaylen,rdelaylen;
int idelayk;
REALTYPE lohifb,idelayfb,roomsize,rs;//rs is used to "normalise" the volume according to the roomsize
int comblen[REV_COMBS*2];
int aplen[REV_APS*2];
//Internal Variables
REALTYPE *comb[REV_COMBS*2];
int combk[REV_COMBS*2];
REALTYPE combfb[REV_COMBS*2];/**<feedback-ul fiecarui filtru "comb"*/
REALTYPE lpcomb[REV_COMBS*2];/**<pentru Filtrul LowPass*/
REALTYPE *ap[REV_APS*2];
int apk[REV_APS*2];
REALTYPE *idelay;
AnalogFilter *lpf,*hpf;//filters
REALTYPE *inputbuf;
void processmono(int ch,REALTYPE *output);
};
#endif

View File

@@ -15,13 +15,13 @@ A1) The name of the program comes from 4 words:
Q2) How can I load files from older versions of ZynAddSubFX (like *.mas_zyn,etc)
A2) You need to convert them into new format. Please use 2.0.0pre1 or (recomanded) 2.0.0pre2 versions of ZynAddSubFX to load old file formants and save them in the new formats
A2) You need to convert them into new format. Please use 2.0.0pre1 or (recommended) 2.0.0pre2 versions of ZynAddSubFX to load old file formants and save them in the new formats
Q3) How can I change the number of parts, voices to ADSynth, effects, etc. ?
A3) Look in src/globals.h and change there theese values. You don't have to change anything else, just recompile all. But most settings must be below 128. As the rule of the thumb if a setting is 128 or below 128, please don't make it bigger than 128. Anyway, I don't belive that you'll need more than 128 for theese settings; for example you don't need 128(or more) effects same time? That's why I put the limit of 128 (using 7 bits of char).
A3) Look in src/globals.h and change there these values. You don't have to change anything else, just recompile all. But most settings must be below 128. As the rule of the thumb if a setting is 128 or below 128, please don't make it bigger than 128. Anyway, I don't believe that you'll need more than 128 for these settings; for example you don't need 128(or more) effects same time? That's why I put the limit of 128 (using 7 bits of char).
Q4) How do I enable Jack support on ZynAddSubFX ?
A4) Look in "Makefile.inc" from "src/" directory for more information. It is highly recomanded that the Jack samplerate to be equal to ZynAddSubFX samplerate (SAMPLE_RATE from globals.h), otherwise the resampling will be done and this will decrease the quality a bit.
A4) Look in "Makefile.inc" from "src/" directory for more information. It is highly recommended that the Jack samplerate to be equal to ZynAddSubFX samplerate (SAMPLE_RATE from globals.h), otherwise the resampling will be done and this will decrease the quality a bit.

View File

@@ -1,3 +1,16 @@
2.4.0 (21 Jun 2009)
- extended mono functionality
- legato mode
- export functionality on PADsynth
- inclusion of LASH client
- inclusion of DSSI audio output
- enabled tooltips for knobs (both description and value tooltips)
- added support for newer JACK api
- added quertz support for virtual keyboard
- started to encorperate cxxtest for unit testing
- many bugfixes
- code cleanup
2.2.1 (28 Apr 2005)
- made to work with mxml-2.2 (will NOT work on older versions)
- it is possible to remove completely the graphical user interface (e.g. it can run without X). For this you need to modify the DISABLE_GUI option from the Makefile.inc

View File

@@ -1,111 +0,0 @@
/*
ZynAddSubFX - a software synthesizer
ALSAMidiIn.C - Midi input for ALSA (this creates an ALSA virtual port)
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "ALSAMidiIn.h"
#include <stdlib.h>
#include <stdio.h>
ALSAMidiIn::ALSAMidiIn(){
int alsaport;
inputok=0;
char portname[50];
sprintf(portname,"ZynAddSubFX");
midi_handle=NULL;
if (snd_seq_open(&midi_handle,"default",SND_SEQ_OPEN_INPUT,0)!=0) return;
snd_seq_set_client_name(midi_handle,"ZynAddSubFX");//thanks to Frank Neumann
alsaport = snd_seq_create_simple_port(midi_handle,portname
,SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE
,SND_SEQ_PORT_TYPE_SYNTH);
if (alsaport<0) return;
inputok=1;
};
ALSAMidiIn::~ALSAMidiIn(){
if (midi_handle)
snd_seq_close(midi_handle);
};
/*
* Get the midi command,channel and parameters
*/
void ALSAMidiIn::getmidicmd(MidiCmdType &cmdtype,unsigned char &cmdchan,int *cmdparams){
snd_seq_event_t *midievent=NULL;
cmdtype=MidiNull;
if (inputok==0){
/* The input is broken. We need to block for a while anyway so other
non-RT threads get a chance to run. */
sleep(1);
return;
};
snd_seq_event_input(midi_handle,&midievent);
if (midievent==NULL) return;
switch (midievent->type){
case SND_SEQ_EVENT_NOTEON:
cmdtype=MidiNoteON;
cmdchan=midievent->data.note.channel;
cmdparams[0]=midievent->data.note.note;
cmdparams[1]=midievent->data.note.velocity;
break;
case SND_SEQ_EVENT_NOTEOFF:
cmdtype=MidiNoteOFF;
cmdchan=midievent->data.note.channel;
cmdparams[0]=midievent->data.note.note;
break;
case SND_SEQ_EVENT_PITCHBEND:
cmdtype=MidiController;
cmdchan=midievent->data.control.channel;
cmdparams[0]=C_pitchwheel;//Pitch Bend
cmdparams[1]=midievent->data.control.value;
break;
case SND_SEQ_EVENT_CONTROLLER:
cmdtype=MidiController;
cmdchan=midievent->data.control.channel;
cmdparams[0]=getcontroller(midievent->data.control.param);
cmdparams[1]=midievent->data.control.value;
//fprintf(stderr,"t=%d val=%d\n",midievent->data.control.param,midievent->data.control.value);
break;
};
};
int ALSAMidiIn::getalsaid() {
if (midi_handle) {
snd_seq_client_info_t* seq_info;
snd_seq_client_info_malloc(&seq_info);
snd_seq_get_client_info(midi_handle, seq_info);
int id = snd_seq_client_info_get_client(seq_info);
snd_seq_client_info_free(seq_info);
return id;
}
return -1;
}

View File

@@ -0,0 +1,110 @@
/*
ZynAddSubFX - a software synthesizer
ALSAMidiIn.C - Midi input for ALSA (this creates an ALSA virtual port)
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "ALSAMidiIn.h"
ALSAMidiIn::ALSAMidiIn()
{
int alsaport;
inputok=false;
midi_handle=NULL;
if (snd_seq_open(&midi_handle,"default",SND_SEQ_OPEN_INPUT,0)!=0) return;
snd_seq_set_client_name(midi_handle,"ZynAddSubFX");//thanks to Frank Neumann
alsaport = snd_seq_create_simple_port(midi_handle,"ZynAddSubFX"
,SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE
,SND_SEQ_PORT_TYPE_SYNTH);
if (alsaport<0) return;
inputok=true;
};
ALSAMidiIn::~ALSAMidiIn()
{
if (midi_handle) snd_seq_close(midi_handle);
};
/*
* Get the midi command,channel and parameters
*/
void ALSAMidiIn::getmidicmd(MidiCmdType &cmdtype,unsigned char &cmdchan,int *cmdparams)
{
snd_seq_event_t *midievent=NULL;
cmdtype=MidiNull;
if (inputok==false) {
/* The input is broken. We need to block for a while anyway so other
non-RT threads get a chance to run. */
sleep(1);
return;
};
snd_seq_event_input(midi_handle,&midievent);
if (midievent==NULL) return;
switch (midievent->type) {
case SND_SEQ_EVENT_NOTEON:
cmdtype=MidiNoteON;
cmdchan=midievent->data.note.channel;
cmdparams[0]=midievent->data.note.note;
cmdparams[1]=midievent->data.note.velocity;
break;
case SND_SEQ_EVENT_NOTEOFF:
cmdtype=MidiNoteOFF;
cmdchan=midievent->data.note.channel;
cmdparams[0]=midievent->data.note.note;
break;
case SND_SEQ_EVENT_PITCHBEND:
cmdtype=MidiController;
cmdchan=midievent->data.control.channel;
cmdparams[0]=C_pitchwheel;//Pitch Bend
cmdparams[1]=midievent->data.control.value;
break;
case SND_SEQ_EVENT_CONTROLLER:
cmdtype=MidiController;
cmdchan=midievent->data.control.channel;
cmdparams[0]=getcontroller(midievent->data.control.param);
cmdparams[1]=midievent->data.control.value;
//fprintf(stderr,"t=%d val=%d\n",midievent->data.control.param,midievent->data.control.value);
break;
};
};
int ALSAMidiIn::getalsaid()
{
if (midi_handle) {
snd_seq_client_info_t* seq_info;
snd_seq_client_info_malloc(&seq_info);
snd_seq_get_client_info(midi_handle, seq_info);
int id = snd_seq_client_info_get_client(seq_info);
snd_seq_client_info_free(seq_info);
return id;
}
return -1;
}

View File

@@ -1,12 +1,12 @@
/*
ZynAddSubFX - a software synthesizer
ALSAMidiIn.h - Midi input for ALSA (this creates an ALSA virtual port)
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
@@ -27,17 +27,23 @@
#include "MidiIn.h"
class ALSAMidiIn:public MidiIn{
public:
ALSAMidiIn();
~ALSAMidiIn();
void getmidicmd(MidiCmdType &cmdtype,unsigned char &cmdchan,int *cmdparams);
int getalsaid();
/**Midi input for ALSA (this creates an ALSA virtual port)*/
class ALSAMidiIn:public MidiIn
{
public:
/**Constructor*/
ALSAMidiIn();
/**Destructor*/
~ALSAMidiIn();
private:
snd_seq_t *midi_handle;
void getmidicmd(MidiCmdType &cmdtype,unsigned char &cmdchan,int *cmdparams);
/**Get the ALSA id
* @return ALSA id*/
int getalsaid();
private:
snd_seq_t *midi_handle;
};
#endif

View File

@@ -0,0 +1,19 @@
set(zynaddsubfx_input_SRCS
MidiIn.cpp
NULLMidiIn.cpp
#OSSMidiIn.cpp #[TODO] get OSS midi detection and
#WINMidiIn.cpp # Win midi detection working
)
if(AlsaMidiInput)
set(zynaddsubfx_input_SRCS
${zynaddsubfx_input_SRCS}
ALSAMidiIn.cpp
)
message(STATUS "Alsa midi input enabled")
set(MIDIINPUT_LIBRARIES ${ASOUND_LIBRARY} PARENT_SCOPE)
endif(AlsaMidiInput)
add_library(zynaddsubfx_input STATIC
${zynaddsubfx_input_SRCS}
)

View File

@@ -1,73 +0,0 @@
/*
ZynAddSubFX - a software synthesizer
MidiIn.C - This class is inherited by all the Midi input classes
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "../globals.h"
#include "MidiIn.h"
int MidiIn::getcontroller(unsigned char b){
int ctl=C_NULL;
switch (b){
case 1:ctl=C_modwheel;//Modulation Wheel
break;
case 7:ctl=C_volume;//Volume
break;
case 10:ctl=C_panning;//Panning
break;
case 11:ctl=C_expression;//Expression
break;
case 64:ctl=C_sustain;//Sustain pedal
break;
case 65:ctl=C_portamento;//Portamento
break;
case 71:ctl=C_filterq;//Filter Q (Sound Timbre)
break;
case 74:ctl=C_filtercutoff;//Filter Cutoff (Brightness)
break;
case 75:ctl=C_bandwidth;//BandWidth
break;
case 76:ctl=C_fmamp;//FM amplitude
break;
case 77:ctl=C_resonance_center;//Resonance Center Frequency
break;
case 78:ctl=C_resonance_bandwidth;//Resonance Bandwith
break;
case 120:ctl=C_allsoundsoff;//All Sounds OFF
break;
case 121:ctl=C_resetallcontrollers;//Reset All Controllers
break;
case 123:ctl=C_allnotesoff;//All Notes OFF
break;
//RPN and NRPN
case 0x06:ctl=C_dataentryhi;//Data Entry (Coarse)
break;
case 0x26:ctl=C_dataentrylo;//Data Entry (Fine)
break;
case 99:ctl=C_nrpnhi;//NRPN (Coarse)
break;
case 98:ctl=C_nrpnlo;//NRPN (Fine)
break;
default:ctl=C_NULL;//unknown controller
//fprintf(stderr,"Controller=%d , par=%d\n",midievent->data.control.param,cmdparams[1]);
break;
};
return(ctl);
};

View File

@@ -0,0 +1,95 @@
/*
ZynAddSubFX - a software synthesizer
MidiIn.C - This class is inherited by all the Midi input classes
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "../globals.h"
#include "MidiIn.h"
int MidiIn::getcontroller(unsigned char b)
{
/**\todo there might be a better way to do this*/
int ctl=C_NULL;
switch (b) {
case 1:
ctl=C_modwheel;//Modulation Wheel
break;
case 7:
ctl=C_volume;//Volume
break;
case 10:
ctl=C_panning;//Panning
break;
case 11:
ctl=C_expression;//Expression
break;
case 64:
ctl=C_sustain;//Sustain pedal
break;
case 65:
ctl=C_portamento;//Portamento
break;
case 71:
ctl=C_filterq;//Filter Q (Sound Timbre)
break;
case 74:
ctl=C_filtercutoff;//Filter Cutoff (Brightness)
break;
case 75:
ctl=C_bandwidth;//BandWidth
break;
case 76:
ctl=C_fmamp;//FM amplitude
break;
case 77:
ctl=C_resonance_center;//Resonance Center Frequency
break;
case 78:
ctl=C_resonance_bandwidth;//Resonance Bandwith
break;
case 120:
ctl=C_allsoundsoff;//All Sounds OFF
break;
case 121:
ctl=C_resetallcontrollers;//Reset All Controllers
break;
case 123:
ctl=C_allnotesoff;//All Notes OFF
break;
//RPN and NRPN
case 0x06:
ctl=C_dataentryhi;//Data Entry (Coarse)
break;
case 0x26:
ctl=C_dataentrylo;//Data Entry (Fine)
break;
case 99:
ctl=C_nrpnhi;//NRPN (Coarse)
break;
case 98:
ctl=C_nrpnlo;//NRPN (Fine)
break;
default:
ctl=C_NULL;//unknown controller
//fprintf(stderr,"Controller=%d , par=%d\n",midievent->data.control.param,cmdparams[1]);
break;
};
return(ctl);
};

View File

@@ -1,12 +1,12 @@
/*
ZynAddSubFX - a software synthesizer
MidiIn.h - This class is inherited by all the Midi input classes
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
@@ -25,18 +25,24 @@
#include "../globals.h"
enum MidiCmdType{MidiNull,MidiNoteOFF,MidiNoteON,MidiController};
enum MidiCmdType {MidiNull,MidiNoteOFF,MidiNoteON,MidiController};
#define MP_MAX_BYTES 4000 //in case of loooong SYS_EXes
class MidiIn{
public:
virtual void getmidicmd(MidiCmdType &cmdtype,unsigned char &cmdchan,int *cmdparams){};
virtual ~MidiIn(){};
int getcontroller(unsigned char b);
protected:
int inputok;//1 if I can read midi bytes from input ports
/**This class is inherited by all the Midi input classes*/
class MidiIn
{
public:
/**Get the command,channel and parameters of the MIDI
*
* \todo make pure virtual
* @param cmdtype the referece to the variable that will store the type
* @param cmdchan the channel for the event
* @param parameters for the event*/
virtual void getmidicmd(MidiCmdType &cmdtype,unsigned char &cmdchan,int *cmdparams)=0;
int getcontroller(unsigned char b);
protected:
bool inputok;/**<1 if I can read midi bytes from input ports*/
};
#endif

View File

@@ -1,12 +1,12 @@
/*
ZynAddSubFX - a software synthesizer
NULLMidiIn.C - a dummy Midi port
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
@@ -21,23 +21,21 @@
*/
#include "NULLMidiIn.h"
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
NULLMidiIn::NULLMidiIn(){
NULLMidiIn::NULLMidiIn()
{
};
NULLMidiIn::~NULLMidiIn(){
NULLMidiIn::~NULLMidiIn()
{
};
/*
* Get the midi command,channel and parameters
* It returns MidiNull because it is a dummy driver
*/
void NULLMidiIn::getmidicmd(MidiCmdType &cmdtype,unsigned char &cmdchan,unsigned char *cmdparams){
cmdtype=MidiNull;
void NULLMidiIn::getmidicmd(MidiCmdType &cmdtype,unsigned char &cmdchan,int *cmdparams)
{
cmdtype=MidiNull;
};

View File

@@ -1,12 +1,12 @@
/*
ZynAddSubFX - a software synthesizer
NULLMidiIn.h - a dummy Midi port
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
@@ -26,15 +26,23 @@
#include "MidiIn.h"
class NULLMidiIn:public MidiIn{
public:
NULLMidiIn();
~NULLMidiIn();
void getmidicmd(MidiCmdType &cmdtype,unsigned char &cmdchan,unsigned char *cmdparams);
/**a dummy Midi port*/
class NULLMidiIn:public MidiIn
{
public:
/**Dummy Constructor
* \todo see if the default constructor would work here*/
NULLMidiIn();
/**Dummy Destructor
* \todo see if the default destructor would work here*/
~NULLMidiIn();
/**Get the midi command,channel and parameters
* It returns MidiNull because it is a dummy driver
*/
void getmidicmd(MidiCmdType &cmdtype,unsigned char &cmdchan,int *cmdparams);
private:
private:
};
#endif

View File

@@ -1,12 +1,12 @@
/*
ZynAddSubFX - a software synthesizer
OSSMidiIn.C - Midi input for Open Sound System
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
@@ -31,34 +31,38 @@
#include "OSSMidiIn.h"
#include "../Misc/Util.h"
OSSMidiIn::OSSMidiIn(){
inputok=0;
OSSMidiIn::OSSMidiIn()
{
inputok=false;
midi_handle=open(config.cfg.LinuxOSSSeqInDev,O_RDONLY,0);
if (midi_handle!=-1) inputok=1;
if (midi_handle!=-1) inputok=true;
lastmidicmd=0;
cmdtype=0;
cmdchan=0;
};
OSSMidiIn::~OSSMidiIn(){
OSSMidiIn::~OSSMidiIn()
{
close(midi_handle);
};
unsigned char OSSMidiIn::readbyte(){
unsigned char OSSMidiIn::readbyte()
{
unsigned char tmp[4];
read(midi_handle,&tmp[0],1);
while (tmp[0]!=SEQ_MIDIPUTC){
read(midi_handle,&tmp[0],4);
};
while (tmp[0]!=SEQ_MIDIPUTC) {
read(midi_handle,&tmp[0],4);
}
return(tmp[1]);
};
unsigned char OSSMidiIn::getmidibyte(){
unsigned char OSSMidiIn::getmidibyte()
{
unsigned char b;
do {
b=readbyte();
b=readbyte();
} while (b==0xfe);//drops the Active Sense Messages
return(b);
};
@@ -66,50 +70,51 @@ unsigned char OSSMidiIn::getmidibyte(){
/*
* Get the midi command,channel and parameters
*/
void OSSMidiIn::getmidicmd(MidiCmdType &cmdtype,unsigned char &cmdchan,int *cmdparams){
void OSSMidiIn::getmidicmd(MidiCmdType &cmdtype,unsigned char &cmdchan,int *cmdparams)
{
unsigned char tmp,i;
if (inputok==0) {
cmdtype=MidiNull;
return;
};
if (inputok==false) {
cmdtype=MidiNull;
return;
}
i=0;
if (lastmidicmd==0){//asteapta prima data pana cand vine prima comanda midi
while (tmp<0x80) tmp=getmidibyte();
lastmidicmd=tmp;
};
if (lastmidicmd==0) {//asteapta prima data pana cand vine prima comanda midi
while (tmp<0x80) tmp=getmidibyte();
lastmidicmd=tmp;
}
tmp=getmidibyte();
if (tmp>=0x80) {
lastmidicmd=tmp;
tmp=getmidibyte();
};
lastmidicmd=tmp;
tmp=getmidibyte();
}
if ((lastmidicmd>=0x80)&&(lastmidicmd<=0x8f)){//Note OFF
cmdtype=MidiNoteOFF;
cmdchan=lastmidicmd%16;
cmdparams[0]=tmp;//note number
};
if ((lastmidicmd>=0x80)&&(lastmidicmd<=0x8f)) {//Note OFF
cmdtype=MidiNoteOFF;
cmdchan=lastmidicmd%16;
cmdparams[0]=tmp;//note number
}
if ((lastmidicmd>=0x90)&&(lastmidicmd<=0x9f)){//Note ON
cmdtype=MidiNoteON;
cmdchan=lastmidicmd%16;
cmdparams[0]=tmp;//note number
cmdparams[1]=getmidibyte();//velocity
if (cmdparams[1]==0) cmdtype=MidiNoteOFF;//if velocity==0 then is note off
};
if ((lastmidicmd>=0xB0)&&(lastmidicmd<=0xBF)){//Controllers
cmdtype=MidiController;
cmdchan=lastmidicmd%16;
cmdparams[0]=getcontroller(tmp);
cmdparams[1]=getmidibyte();
};
if ((lastmidicmd>=0xE0)&&(lastmidicmd<=0xEF)){//Pitch Wheel
cmdtype=MidiController;
cmdchan=lastmidicmd%16;
cmdparams[0]=C_pitchwheel;
cmdparams[1]=(tmp+getmidibyte()*(int) 128)-8192;//hope this is correct
};
if ((lastmidicmd>=0x90)&&(lastmidicmd<=0x9f)) {//Note ON
cmdtype=MidiNoteON;
cmdchan=lastmidicmd%16;
cmdparams[0]=tmp;//note number
cmdparams[1]=getmidibyte();//velocity
if (cmdparams[1]==0) cmdtype=MidiNoteOFF;//if velocity==0 then is note off
}
if ((lastmidicmd>=0xB0)&&(lastmidicmd<=0xBF)) {//Controllers
cmdtype=MidiController;
cmdchan=lastmidicmd%16;
cmdparams[0]=getcontroller(tmp);
cmdparams[1]=getmidibyte();
}
if ((lastmidicmd>=0xE0)&&(lastmidicmd<=0xEF)) {//Pitch Wheel
cmdtype=MidiController;
cmdchan=lastmidicmd%16;
cmdparams[0]=C_pitchwheel;
cmdparams[1]=(tmp+getmidibyte()*(int) 128)-8192;//hope this is correct
}
};

View File

@@ -1,12 +1,12 @@
/*
ZynAddSubFX - a software synthesizer
OSSMidiIn.h - Midi input for Open Sound System
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
@@ -25,21 +25,22 @@
#include "MidiIn.h"
class OSSMidiIn:public MidiIn{
public:
OSSMidiIn();
~OSSMidiIn();
unsigned char getmidibyte();
unsigned char readbyte();
class OSSMidiIn:public MidiIn
{
public:
OSSMidiIn();
~OSSMidiIn();
unsigned char getmidibyte();
unsigned char readbyte();
//Midi parser
void getmidicmd(MidiCmdType &cmdtype,unsigned char &cmdchan,int *cmdparams);
unsigned char cmdtype;//the Message Type (noteon,noteof,sysex..)
unsigned char cmdchan;//the channel number
//Midi parser
void getmidicmd(MidiCmdType &cmdtype,unsigned char &cmdchan,int *cmdparams);
unsigned char cmdtype;//the Message Type (noteon,noteof,sysex..)
unsigned char cmdchan;//the channel number
private:
int midi_handle;
unsigned char lastmidicmd;//last byte (>=80) received from the Midi
private:
int midi_handle;
unsigned char lastmidicmd;//last byte (>=80) received from the Midi
};

View File

@@ -1,83 +0,0 @@
/*
ZynAddSubFX - a software synthesizer
WINMidiIn.C - Midi input for Windows
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
#include <mmsystem.h>
#include <pthread.h>
#include "WINMidiIn.h"
#include "MidiIn.h"
#include "../Misc/Util.h"
Master *winmaster;
HMIDIIN winmidiinhandle;
MidiIn midictl;//used to convert the controllers to ZynAddSubFX controllers
void CALLBACK WinMidiInProc(HMIDIIN hMidiIn,UINT wMsg,DWORD dwInstance,
DWORD dwParam1,DWORD dwParam2){
int midicommand=MidiNull;
if (wMsg==MIM_DATA){
int cmd,par1,par2;
cmd=dwParam1&0xff;
if (cmd==0xfe) return;
par1=(dwParam1>>8)&0xff;
par2=dwParam1>>16;
//printf("%x %x %x\n",cmd,par1,par2);fflush(stdout);
int cmdchan=cmd&0x0f;
int cmdtype=(cmd>>4)&0x0f;
int tmp=0;
pthread_mutex_lock(&winmaster->mutex);
switch(cmdtype){
case(0x8)://noteon
winmaster->NoteOff(cmdchan,par1);
break;
case(0x9)://noteoff
winmaster->NoteOn(cmdchan,par1,par2&0xff);
break;
case(0xb)://controller
winmaster->SetController(cmdchan,midictl.getcontroller(par1),par2&0xff);
break;
case(0xe)://pitch wheel
tmp=(par1+par2*(long int) 128)-8192;
winmaster->SetController(cmdchan,C_pitchwheel,tmp);
break;
default:break;
};
pthread_mutex_unlock(&winmaster->mutex);
};
};
void InitWinMidi(Master *master_){
winmaster=master_;
long int result=midiInOpen(&winmidiinhandle,config.cfg.WindowsMidiInId,(DWORD)WinMidiInProc,0,CALLBACK_FUNCTION);
result=midiInStart(winmidiinhandle);
};
void StopWinMidi(){
midiInStop(winmidiinhandle);
midiInClose(winmidiinhandle);
};

View File

@@ -0,0 +1,87 @@
/*
ZynAddSubFX - a software synthesizer
WINMidiIn.C - Midi input for Windows
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
#include <mmsystem.h>
#include <pthread.h>
#include "WINMidiIn.h"
#include "MidiIn.h"
#include "../Misc/Util.h"
Master *winmaster;
HMIDIIN winmidiinhandle;
MidiIn midictl;//used to convert the controllers to ZynAddSubFX controllers
void CALLBACK WinMidiInProc(HMIDIIN hMidiIn,UINT wMsg,DWORD dwInstance,
DWORD dwParam1,DWORD dwParam2)
{
int midicommand=MidiNull;
if (wMsg==MIM_DATA) {
int cmd,par1,par2;
cmd=dwParam1&0xff;
if (cmd==0xfe) return;
par1=(dwParam1>>8)&0xff;
par2=dwParam1>>16;
//printf("%x %x %x\n",cmd,par1,par2);fflush(stdout);
int cmdchan=cmd&0x0f;
int cmdtype=(cmd>>4)&0x0f;
int tmp=0;
pthread_mutex_lock(&winmaster->mutex);
switch (cmdtype) {
case(0x8)://noteon
winmaster->NoteOff(cmdchan,par1);
break;
case(0x9)://noteoff
winmaster->NoteOn(cmdchan,par1,par2&0xff);
break;
case(0xb)://controller
winmaster->SetController(cmdchan,midictl.getcontroller(par1),par2&0xff);
break;
case(0xe)://pitch wheel
tmp=(par1+par2*(long int) 128)-8192;
winmaster->SetController(cmdchan,C_pitchwheel,tmp);
break;
default:
break;
};
pthread_mutex_unlock(&winmaster->mutex);
};
};
void InitWinMidi(Master *master_)
{
winmaster=master_;
long int result=midiInOpen(&winmidiinhandle,config.cfg.WindowsMidiInId,(DWORD)WinMidiInProc,0,CALLBACK_FUNCTION);
result=midiInStart(winmidiinhandle);
};
void StopWinMidi()
{
midiInStop(winmidiinhandle);
midiInClose(winmidiinhandle);
};

View File

@@ -1,12 +1,12 @@
/*
ZynAddSubFX - a software synthesizer
WINMidiIn.h - Midi input for Windows
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,

View File

@@ -1,12 +1,12 @@
/*
ZynAddSubFX - a software synthesizer
Bank.h - Instrument Bank
Bank.h - Instrument Bank
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
@@ -39,37 +39,39 @@
//if this file exists into a directory, this make the directory to be considered as a bank, even if it not contains a instrument file
#define FORCE_BANK_DIR_FILE ".bankdir"
Bank::Bank(){
Bank::Bank()
{
ZERO(defaultinsname,PART_MAX_NAME_LEN);
snprintf(defaultinsname,PART_MAX_NAME_LEN,"%s"," ");
for (int i=0;i<BANK_SIZE;i++){
ins[i].used=false;
ins[i].filename=NULL;
ins[i].info.PADsynth_used=false;
for (int i=0;i<BANK_SIZE;i++) {
ins[i].used=false;
ins[i].filename=NULL;
ins[i].info.PADsynth_used=false;
};
dirname=NULL;
clearbank();
for (int i=0;i<MAX_NUM_BANKS;i++){
banks[i].dir=NULL;
banks[i].name=NULL;
for (int i=0;i<MAX_NUM_BANKS;i++) {
banks[i].dir=NULL;
banks[i].name=NULL;
};
bankfiletitle=dirname;
loadbank(config.cfg.currentBankDir);
};
Bank::~Bank(){
for (int i=0;i<MAX_NUM_BANKS;i++){
if (banks[i].dir!=NULL) delete []banks[i].dir;
if (banks[i].name!=NULL) delete []banks[i].name;
Bank::~Bank()
{
for (int i=0;i<MAX_NUM_BANKS;i++) {
if (banks[i].dir!=NULL) delete []banks[i].dir;
if (banks[i].name!=NULL) delete []banks[i].name;
};
clearbank();
@@ -78,7 +80,8 @@ Bank::~Bank(){
/*
* Get the name of an instrument from the bank
*/
char *Bank::getname (unsigned int ninstrument){
char *Bank::getname (unsigned int ninstrument)
{
if (emptyslot(ninstrument)) return (defaultinsname);
return (ins[ninstrument].name);
};
@@ -86,7 +89,8 @@ char *Bank::getname (unsigned int ninstrument){
/*
* Get the numbered name of an instrument from the bank
*/
char *Bank::getnamenumbered (unsigned int ninstrument){
char *Bank::getnamenumbered (unsigned int ninstrument)
{
if (emptyslot(ninstrument)) return (defaultinsname);
snprintf(tmpinsname[ninstrument],PART_MAX_NAME_LEN+15,"%d. %s",ninstrument+1,getname(ninstrument));
return(tmpinsname[ninstrument]);
@@ -95,28 +99,29 @@ char *Bank::getnamenumbered (unsigned int ninstrument){
/*
* Changes the name of an instrument (and the filename)
*/
void Bank::setname(unsigned int ninstrument,const char *newname,int newslot){
void Bank::setname(unsigned int ninstrument,const char *newname,int newslot)
{
if (emptyslot(ninstrument)) return;
char newfilename[1000+1],tmpfilename[100+1];
ZERO(newfilename,1001);
ZERO(tmpfilename,101);
if (newslot>=0) snprintf(tmpfilename,100,"%4d-%s",newslot+1,newname);
else snprintf(tmpfilename,100,"%4d-%s",ninstrument+1,newname);
else snprintf(tmpfilename,100,"%4d-%s",ninstrument+1,newname);
//add the zeroes at the start of filename
for (int i=0;i<4;i++) if (tmpfilename[i]==' ') tmpfilename[i]='0';
//make the filenames legal
for (int i=0;i<(int) strlen(tmpfilename);i++) {
char c=tmpfilename[i];
if ((c>='0')&&(c<='9')) continue;
if ((c>='A')&&(c<='Z')) continue;
if ((c>='a')&&(c<='z')) continue;
if ((c=='-')||(c==' ')) continue;
tmpfilename[i]='_';
char c=tmpfilename[i];
if ((c>='0')&&(c<='9')) continue;
if ((c>='A')&&(c<='Z')) continue;
if ((c>='a')&&(c<='z')) continue;
if ((c=='-')||(c==' ')) continue;
tmpfilename[i]='_';
};
snprintf(newfilename,1000,"%s/%s.xiz",dirname,tmpfilename);
@@ -128,39 +133,42 @@ void Bank::setname(unsigned int ninstrument,const char *newname,int newslot){
ins[ninstrument].filename=new char[strlen(newfilename)+5];
snprintf(ins[ninstrument].filename,strlen(newfilename)+1,"%s",newfilename);
snprintf(ins[ninstrument].name,PART_MAX_NAME_LEN,"%s",&tmpfilename[5]);
};
/*
* Check if there is no instrument on a slot from the bank
*/
int Bank::emptyslot(unsigned int ninstrument){
int Bank::emptyslot(unsigned int ninstrument)
{
if (ninstrument>=BANK_SIZE) return (1);
if (ins[ninstrument].filename==NULL) return(1);
if (ins[ninstrument].used) return (0);
else return(1);
else return(1);
};
/*
* Removes the instrument from the bank
*/
void Bank::clearslot(unsigned int ninstrument){
void Bank::clearslot(unsigned int ninstrument)
{
if (emptyslot(ninstrument)) return;
// printf("remove %s \n",ins[ninstrument].filename);////////////////////////
remove(ins[ninstrument].filename);
deletefrombank(ninstrument);
};
/*
* Save the instrument to a slot
* Save the instrument to a slot
*/
void Bank::savetoslot(unsigned int ninstrument,Part *part){
void Bank::savetoslot(unsigned int ninstrument,Part *part)
{
clearslot(ninstrument);
const int maxfilename=200;
char tmpfilename[maxfilename+20];
ZERO(tmpfilename,maxfilename+20);
@@ -169,16 +177,16 @@ void Bank::savetoslot(unsigned int ninstrument,Part *part){
//add the zeroes at the start of filename
for (int i=0;i<4;i++) if (tmpfilename[i]==' ') tmpfilename[i]='0';
//make the filenames legal
for (int i=0;i<(int)strlen(tmpfilename);i++) {
char c=tmpfilename[i];
if ((c>='0')&&(c<='9')) continue;
if ((c>='A')&&(c<='Z')) continue;
if ((c>='a')&&(c<='z')) continue;
if ((c=='-')||(c==' ')) continue;
tmpfilename[i]='_';
char c=tmpfilename[i];
if ((c>='0')&&(c<='9')) continue;
if ((c>='A')&&(c<='Z')) continue;
if ((c>='a')&&(c<='z')) continue;
if ((c=='-')||(c==' ')) continue;
tmpfilename[i]='_';
};
strncat(tmpfilename,".xiz",maxfilename+10);
@@ -192,29 +200,31 @@ void Bank::savetoslot(unsigned int ninstrument,Part *part){
remove(filename);
part->saveXML(filename);
addtobank(ninstrument,tmpfilename,(char *) part->Pname);
delete[]filename;
};
/*
* Loads the instrument from the bank
*/
void Bank::loadfromslot(unsigned int ninstrument,Part *part){
void Bank::loadfromslot(unsigned int ninstrument,Part *part)
{
if (emptyslot(ninstrument)) return;
part->defaultsinstrument();
// printf("load: %s\n",ins[ninstrument].filename);
part->loadXMLinstrument(ins[ninstrument].filename);
};
/*
* Makes current a bank directory
*/
int Bank::loadbank(const char *bankdirname){
int Bank::loadbank(const char *bankdirname)
{
DIR *dir=opendir(bankdirname);
clearbank();
@@ -223,59 +233,59 @@ int Bank::loadbank(const char *bankdirname){
if (dirname!=NULL) delete[]dirname;
dirname=new char[strlen(bankdirname)+1];
snprintf(dirname,strlen(bankdirname)+1,"%s",bankdirname);
bankfiletitle=dirname;
// printf("loadbank %s/\n",bankdirname);
// printf("loadbank %s/\n",bankdirname);
struct dirent *fn;
while ((fn=readdir(dir))){
const char *filename= fn->d_name;
//sa verific daca e si extensia dorita
if (strstr(filename,INSTRUMENT_EXTENSION)==NULL) continue;
//verify if the name is like this NNNN-name (where N is a digit)
int no=0;
unsigned int startname=0;
for (unsigned int i=0;i<4;i++) {
if (strlen(filename)<=i) break;
if ((filename[i]>='0')&&(filename[i]<='9')) {
no=no*10+(filename[i]-'0');
startname++;
};
};
if ((startname+1)<strlen(filename)) startname++;//to take out the "-"
char name[PART_MAX_NAME_LEN+1];
ZERO(name,PART_MAX_NAME_LEN+1);
snprintf(name,PART_MAX_NAME_LEN,"%s",filename);
//remove the file extension
for (int i=strlen(name)-1;i>=2;i--){
if (name[i]=='.') {
name[i]='\0';
break;
};
};
if (no!=0){//the instrument position in the bank is found
addtobank(no-1,filename,&name[startname]);
} else {
addtobank(-1,filename,name);
};
while ((fn=readdir(dir))) {
const char *filename= fn->d_name;
//sa verific daca e si extensia dorita
if (strstr(filename,INSTRUMENT_EXTENSION)==NULL) continue;
//verify if the name is like this NNNN-name (where N is a digit)
int no=0;
unsigned int startname=0;
for (unsigned int i=0;i<4;i++) {
if (strlen(filename)<=i) break;
if ((filename[i]>='0')&&(filename[i]<='9')) {
no=no*10+(filename[i]-'0');
startname++;
};
};
if ((startname+1)<strlen(filename)) startname++;//to take out the "-"
char name[PART_MAX_NAME_LEN+1];
ZERO(name,PART_MAX_NAME_LEN+1);
snprintf(name,PART_MAX_NAME_LEN,"%s",filename);
//remove the file extension
for (int i=strlen(name)-1;i>=2;i--) {
if (name[i]=='.') {
name[i]='\0';
break;
};
};
if (no!=0) {//the instrument position in the bank is found
addtobank(no-1,filename,&name[startname]);
} else {
addtobank(-1,filename,name);
};
};
closedir(dir);
if (dirname!=NULL) {
sprintf(config.cfg.currentBankDir,"%s",dirname);
sprintf(config.cfg.currentBankDir,"%s",dirname);
};
return(0);
@@ -284,16 +294,17 @@ int Bank::loadbank(const char *bankdirname){
/*
* Makes a new bank, put it on a file and makes it current bank
*/
int Bank::newbank(const char *newbankdirname){
int Bank::newbank(const char *newbankdirname)
{
int result;
char tmpfilename[MAX_STRING_SIZE];
char bankdir[MAX_STRING_SIZE];
snprintf(bankdir,MAX_STRING_SIZE,"%s",config.cfg.bankRootDirList[0]);
if (((bankdir[strlen(bankdir)-1])!='/')&&((bankdir[strlen(bankdir)-1])!='\\')){
strncat(bankdir,"/",MAX_STRING_SIZE);
if (((bankdir[strlen(bankdir)-1])!='/')&&((bankdir[strlen(bankdir)-1])!='\\')) {
strncat(bankdir,"/",MAX_STRING_SIZE);
};
strncat(bankdir,newbankdirname,MAX_STRING_SIZE-1);
strncat(bankdir,newbankdirname,MAX_STRING_SIZE);
#ifdef OS_WINDOWS
result=mkdir(bankdir);
#else
@@ -305,57 +316,62 @@ int Bank::newbank(const char *newbankdirname){
// printf("%s\n",tmpfilename);
FILE *tmpfile=fopen(tmpfilename,"w+");
fclose(tmpfile);
return(loadbank(bankdir));
};
/*
* Check if the bank is locked (i.e. the file opened was readonly)
*/
int Bank::locked(){
int Bank::locked()
{
return(dirname==NULL);
};
/*
* Swaps a slot with another
*/
void Bank::swapslot(unsigned int n1, unsigned int n2){
void Bank::swapslot(unsigned int n1, unsigned int n2)
{
if ((n1==n2)||(locked())) return;
if (emptyslot(n1)&&(emptyslot(n2))) return;
if (emptyslot(n1)){//change n1 to n2 in order to make
int tmp=n2;n2=n1;n1=tmp;
if (emptyslot(n1)) {//change n1 to n2 in order to make
int tmp=n2;
n2=n1;
n1=tmp;
};
if (emptyslot(n2)){//this is just a movement from slot1 to slot2
setname(n1,getname(n1),n2);
ins[n2]=ins[n1];
ins[n1].used=false;
ins[n1].name[0]='\0';
ins[n1].filename=NULL;
ins[n1].info.PADsynth_used=0;
if (emptyslot(n2)) {//this is just a movement from slot1 to slot2
setname(n1,getname(n1),n2);
ins[n2]=ins[n1];
ins[n1].used=false;
ins[n1].name[0]='\0';
ins[n1].filename=NULL;
ins[n1].info.PADsynth_used=0;
} else {//if both slots are used
if (strcmp(ins[n1].name,ins[n2].name)==0){//change the name of the second instrument if the name are equal
strncat(ins[n2].name,"2",PART_MAX_NAME_LEN);
};
setname(n1,getname(n1),n2);
setname(n2,getname(n2),n1);
ins_t tmp;
tmp.used=true;
strcpy(tmp.name,ins[n2].name);
char *tmpfilename=ins[n2].filename;
bool padsynth_used=ins[n2].info.PADsynth_used;
ins[n2]=ins[n1];
strcpy(ins[n1].name,tmp.name);
ins[n1].filename=tmpfilename;
ins[n1].info.PADsynth_used=padsynth_used;
if (strcmp(ins[n1].name,ins[n2].name)==0) {//change the name of the second instrument if the name are equal
strncat(ins[n2].name,"2",PART_MAX_NAME_LEN);
};
setname(n1,getname(n1),n2);
setname(n2,getname(n2),n1);
ins_t tmp;
tmp.used=true;
strcpy(tmp.name,ins[n2].name);
char *tmpfilename=ins[n2].filename;
bool padsynth_used=ins[n2].info.PADsynth_used;
ins[n2]=ins[n1];
strcpy(ins[n1].name,tmp.name);
ins[n1].filename=tmpfilename;
ins[n1].info.PADsynth_used=padsynth_used;
};
};
//a helper function that compares 2 banks[] arrays
int Bank_compar(const void *a,const void *b){
int Bank_compar(const void *a,const void *b)
{
struct Bank::bankstruct *bank1= (Bank::bankstruct *)a;
struct Bank::bankstruct *bank2= (Bank::bankstruct *)b;
if (((bank1->name)==NULL)||((bank2->name)==NULL)) return(0);
@@ -369,156 +385,160 @@ int Bank_compar(const void *a,const void *b){
* Re-scan for directories containing instrument banks
*/
void Bank::rescanforbanks(){
for (int i=0;i<MAX_NUM_BANKS;i++){
if (banks[i].dir!=NULL) delete []banks[i].dir;
if (banks[i].name!=NULL) delete []banks[i].name;
banks[i].dir=NULL;
banks[i].name=NULL;
void Bank::rescanforbanks()
{
for (int i=0;i<MAX_NUM_BANKS;i++) {
if (banks[i].dir!=NULL) delete []banks[i].dir;
if (banks[i].name!=NULL) delete []banks[i].name;
banks[i].dir=NULL;
banks[i].name=NULL;
};
for (int i=0;i<MAX_BANK_ROOT_DIRS;i++) if (config.cfg.bankRootDirList[i]!=NULL) scanrootdir(config.cfg.bankRootDirList[i]);
//sort the banks
for (int j=0;j<MAX_NUM_BANKS-1;j++){
for (int i=j+1;i<MAX_NUM_BANKS;i++){
if (Bank_compar(&banks[i],&banks[j])) {
char *tmpname=banks[i].name;
char *tmpdir=banks[i].dir;
for (int j=0;j<MAX_NUM_BANKS-1;j++) {
for (int i=j+1;i<MAX_NUM_BANKS;i++) {
if (Bank_compar(&banks[i],&banks[j])) {
char *tmpname=banks[i].name;
char *tmpdir=banks[i].dir;
banks[i].name=banks[j].name;
banks[i].dir=banks[j].dir;
banks[i].name=banks[j].name;
banks[i].dir=banks[j].dir;
banks[j].name=tmpname;
banks[j].dir=tmpdir;
};
};
banks[j].name=tmpname;
banks[j].dir=tmpdir;
};
};
};
//remove duplicate bank names
int dupl=0;
for (int j=0;j<MAX_NUM_BANKS-1;j++){
for (int i=j+1;i<MAX_NUM_BANKS;i++){
if ((banks[i].name==NULL)||(banks[j].name==NULL)) continue;
if (strcmp(banks[i].name,banks[j].name)==0) {//add a [1] to the first bankname and [n] to others
char *tmpname=banks[i].name;
banks[i].name=new char[strlen(tmpname)+100];
sprintf(banks[i].name,"%s[%d]",tmpname,dupl+2);
delete[]tmpname;
if (dupl==0){
char *tmpname=banks[j].name;
banks[j].name=new char[strlen(tmpname)+100];
sprintf(banks[j].name,"%s[1]",tmpname);
delete[]tmpname;
};
dupl++;
} else dupl=0;
};
for (int j=0;j<MAX_NUM_BANKS-1;j++) {
for (int i=j+1;i<MAX_NUM_BANKS;i++) {
if ((banks[i].name==NULL)||(banks[j].name==NULL)) continue;
if (strcmp(banks[i].name,banks[j].name)==0) {//add a [1] to the first bankname and [n] to others
char *tmpname=banks[i].name;
banks[i].name=new char[strlen(tmpname)+100];
sprintf(banks[i].name,"%s[%d]",tmpname,dupl+2);
delete[]tmpname;
if (dupl==0) {
char *tmpname=banks[j].name;
banks[j].name=new char[strlen(tmpname)+100];
sprintf(banks[j].name,"%s[1]",tmpname);
delete[]tmpname;
};
dupl++;
} else dupl=0;
};
};
};
};
// private stuff
void Bank::scanrootdir(char *rootdir){
void Bank::scanrootdir(char *rootdir)
{
// printf("Scanning root dir:%s\n",rootdir);
DIR *dir=opendir(rootdir);
if (dir==NULL) return;
const int maxdirsize=1000;
struct {
char dir[maxdirsize];
char name[maxdirsize];
char dir[maxdirsize];
char name[maxdirsize];
}bank;
const char *separator="/";
if (strlen(rootdir)) {
char tmp=rootdir[strlen(rootdir)-1];
if ((tmp=='/') || (tmp=='\\')) separator="";
char tmp=rootdir[strlen(rootdir)-1];
if ((tmp=='/') || (tmp=='\\')) separator="";
};
struct dirent *fn;
while ((fn=readdir(dir))){
const char *dirname=fn->d_name;
if (dirname[0]=='.') continue;
snprintf(bank.dir,maxdirsize,"%s%s%s/",rootdir,separator,dirname);
snprintf(bank.name,maxdirsize,"%s",dirname);
//find out if the directory contains at least 1 instrument
bool isbank=false;
DIR *d=opendir(bank.dir);
if (d==NULL) continue;
struct dirent *fname;
while((fname=readdir(d))){
if ((strstr(fname->d_name,INSTRUMENT_EXTENSION)!=NULL)||
(strstr(fname->d_name,FORCE_BANK_DIR_FILE)!=NULL)){
isbank=true;
break;//aici as putea pune in loc de break un update la un counter care imi arata nr. de instrumente din bank
};
};
closedir(d);
if (isbank) {
int pos=-1;
for (int i=1;i<MAX_NUM_BANKS;i++){ //banks[0] e liber intotdeauna
if (banks[i].name==NULL) {
pos=i;
break;
};
};
if (pos>=0) {
banks[pos].name=new char[maxdirsize];
banks[pos].dir=new char[maxdirsize];
snprintf(banks[pos].name,maxdirsize,"%s",bank.name);
snprintf(banks[pos].dir,maxdirsize,"%s",bank.dir);
};
};
struct dirent *fn;
while ((fn=readdir(dir))) {
const char *dirname=fn->d_name;
if (dirname[0]=='.') continue;
snprintf(bank.dir,maxdirsize,"%s%s%s/",rootdir,separator,dirname);
snprintf(bank.name,maxdirsize,"%s",dirname);
//find out if the directory contains at least 1 instrument
bool isbank=false;
DIR *d=opendir(bank.dir);
if (d==NULL) continue;
struct dirent *fname;
while ((fname=readdir(d))) {
if ((strstr(fname->d_name,INSTRUMENT_EXTENSION)!=NULL)||
(strstr(fname->d_name,FORCE_BANK_DIR_FILE)!=NULL)) {
isbank=true;
break;//aici as putea pune in loc de break un update la un counter care imi arata nr. de instrumente din bank
};
};
closedir(d);
if (isbank) {
int pos=-1;
for (int i=1;i<MAX_NUM_BANKS;i++) { //banks[0] e liber intotdeauna
if (banks[i].name==NULL) {
pos=i;
break;
};
};
if (pos>=0) {
banks[pos].name=new char[maxdirsize];
banks[pos].dir=new char[maxdirsize];
snprintf(banks[pos].name,maxdirsize,"%s",bank.name);
snprintf(banks[pos].dir,maxdirsize,"%s",bank.dir);
};
};
};
closedir(dir);
};
void Bank::clearbank(){
void Bank::clearbank()
{
for (int i=0;i<BANK_SIZE;i++) deletefrombank(i);
if (dirname!=NULL) delete[]dirname;
bankfiletitle=NULL;
dirname=NULL;
};
int Bank::addtobank(int pos, const char *filename, const char* name){
if ((pos>=0)&&(pos<BANK_SIZE)){
if (ins[pos].used) pos=-1;//force it to find a new free position
int Bank::addtobank(int pos, const char *filename, const char* name)
{
if ((pos>=0)&&(pos<BANK_SIZE)) {
if (ins[pos].used) pos=-1;//force it to find a new free position
} else if (pos>=BANK_SIZE) pos=-1;
if (pos<0) {//find a free position
for (int i=BANK_SIZE-1;i>=0;i--)
if (!ins[i].used) {
pos=i;
break;
};
for (int i=BANK_SIZE-1;i>=0;i--)
if (!ins[i].used) {
pos=i;
break;
};
};
if (pos<0) return (-1);//the bank is full
// printf("%s %d\n",filename,pos);
// printf("%s %d\n",filename,pos);
deletefrombank(pos);
ins[pos].used=true;
snprintf(ins[pos].name,PART_MAX_NAME_LEN,"%s",name);
@@ -530,33 +550,35 @@ int Bank::addtobank(int pos, const char *filename, const char* name){
snprintf(ins[pos].filename,len+1,"%s/%s",dirname,filename);
//see if PADsynth is used
if (config.cfg.CheckPADsynth){
XMLwrapper *xml=new XMLwrapper();
xml->checkfileinformation(ins[pos].filename);
ins[pos].info.PADsynth_used=xml->information.PADsynth_used;
delete xml;
if (config.cfg.CheckPADsynth) {
XMLwrapper *xml=new XMLwrapper();
xml->checkfileinformation(ins[pos].filename);
ins[pos].info.PADsynth_used=xml->information.PADsynth_used;
delete xml;
} else ins[pos].info.PADsynth_used=false;
return(0);
};
bool Bank::isPADsynth_used(unsigned int ninstrument){
bool Bank::isPADsynth_used(unsigned int ninstrument)
{
if (config.cfg.CheckPADsynth==0) return(0);
else return(ins[ninstrument].info.PADsynth_used);
else return(ins[ninstrument].info.PADsynth_used);
};
void Bank::deletefrombank(int pos){
void Bank::deletefrombank(int pos)
{
if ((pos<0)||(pos>=BANK_SIZE)) return;
ins[pos].used=false;
ZERO(ins[pos].name,PART_MAX_NAME_LEN+1);
if (ins[pos].filename!=NULL) {
delete []ins[pos].filename;
ins[pos].filename=NULL;
delete []ins[pos].filename;
ins[pos].filename=NULL;
};
ZERO(tmpinsname[pos],PART_MAX_NAME_LEN+20);
};

View File

@@ -1,12 +1,12 @@
/*
ZynAddSubFX - a software synthesizer
Bank.C - Instrument Bank
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
@@ -29,71 +29,79 @@
#define BANK_SIZE 160
/*
/**
* The max. number of banks that are used
*/
#define MAX_NUM_BANKS 400
/**The instrument Bank
* \todo add in strings to replace char* */
class Bank
{
public:
/**Constructor*/
Bank();
~Bank();
char *getname(unsigned int ninstrument);
char *getnamenumbered(unsigned int ninstrument);
void setname(unsigned int ninstrument,const char *newname,int newslot);//if newslot==-1 then this is ignored, else it will be put on that slot
bool isPADsynth_used(unsigned int ninstrument);
class Bank{
public:
Bank();
~Bank();
char *getname(unsigned int ninstrument);
char *getnamenumbered(unsigned int ninstrument);
void setname(unsigned int ninstrument,const char *newname,int newslot);//if newslot==-1 then this is ignored, else it will be put on that slot
bool isPADsynth_used(unsigned int ninstrument);
//returns 0 if the slot is not empty or 1 if the slot is empty
int emptyslot(unsigned int ninstrument);
/**returns 0 if the slot is not empty or 1 if the slot is empty
* \todo start using bool before facepalm*/
int emptyslot(unsigned int ninstrument);
void clearslot(unsigned int ninstrument);
void savetoslot(unsigned int ninstrument,Part *part);
void loadfromslot(unsigned int ninstrument,Part *part);
/**Empties out the selected slot*/
void clearslot(unsigned int ninstrument);
/**Saves the given Part to slot*/
void savetoslot(unsigned int ninstrument,Part *part);
/**Loads the given slot into a Part*/
void loadfromslot(unsigned int ninstrument,Part *part);
void swapslot(unsigned int n1,unsigned int n2);
/**Swaps Slots*/
void swapslot(unsigned int n1,unsigned int n2);
int loadbank(const char *bankdirname);
int newbank(const char *newbankdirname);
char *bankfiletitle; //this is shown on the UI of the bank (the title of the window)
int locked();
void rescanforbanks();
struct bankstruct{
char *dir;
char *name;
};
bankstruct banks[MAX_NUM_BANKS];
private:
//it adds a filename to the bank
//if pos is -1 it try to find a position
//returns -1 if the bank is full, or 0 if the instrument was added
int addtobank(int pos,const char* filename,const char* name);
void deletefrombank(int pos);
void clearbank();
char defaultinsname[PART_MAX_NAME_LEN];
char tmpinsname[BANK_SIZE][PART_MAX_NAME_LEN+20];//this keeps the numbered names
struct ins_t{
bool used;
char name[PART_MAX_NAME_LEN+1];
char *filename;
struct{
bool PADsynth_used;
} info;
}ins[BANK_SIZE];
char *dirname;
int loadbank(const char *bankdirname);
int newbank(const char *newbankdirname);
void scanrootdir(char *rootdir);//scans a root dir for banks
char *bankfiletitle; //this is shown on the UI of the bank (the title of the window)
int locked();
void rescanforbanks();
struct bankstruct {
char *dir;
char *name;
};
bankstruct banks[MAX_NUM_BANKS];
private:
//it adds a filename to the bank
//if pos is -1 it try to find a position
//returns -1 if the bank is full, or 0 if the instrument was added
int addtobank(int pos,const char* filename,const char* name);
void deletefrombank(int pos);
void clearbank();
char defaultinsname[PART_MAX_NAME_LEN];
char tmpinsname[BANK_SIZE][PART_MAX_NAME_LEN+20];//this keeps the numbered names
struct ins_t {
bool used;
char name[PART_MAX_NAME_LEN+1];
char *filename;
struct {
bool PADsynth_used;
} info;
}ins[BANK_SIZE];
char *dirname;
void scanrootdir(char *rootdir);//scans a root dir for banks
};
#endif

View File

@@ -0,0 +1,18 @@
include_directories(${MXML_INCLUDE_DIR})
set(zynaddsubfx_misc_SRCS
Bank.cpp
Config.cpp
Dump.cpp
Master.cpp
Microtonal.cpp
Part.cpp
Util.cpp
XMLwrapper.cpp
)
add_library(zynaddsubfx_misc STATIC
${zynaddsubfx_misc_SRCS}
)
target_link_libraries(zynaddsubfx_misc zynaddsubfx_output)

View File

@@ -1,331 +0,0 @@
/*
ZynAddSubFX - a software synthesizer
Config.C - Configuration file functions
Copyright (C) 2003-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#ifdef OS_WINDOWS
#include <windows.h>
#include <mmsystem.h>
#endif
#include "Config.h"
#include "XMLwrapper.h"
Config::Config(){
};
void Config::init(){
maxstringsize=MAX_STRING_SIZE;//for ui
//defaults
cfg.SampleRate=44100;
cfg.SoundBufferSize=256;
cfg.OscilSize=1024;
cfg.SwapStereo=0;
cfg.LinuxOSSWaveOutDev=new char[MAX_STRING_SIZE];
snprintf(cfg.LinuxOSSWaveOutDev,MAX_STRING_SIZE,"/dev/dsp");
cfg.LinuxOSSSeqInDev=new char[MAX_STRING_SIZE];
snprintf(cfg.LinuxOSSSeqInDev,MAX_STRING_SIZE,"/dev/sequencer");
cfg.DumpFile=new char[MAX_STRING_SIZE];
snprintf(cfg.DumpFile,MAX_STRING_SIZE,"zynaddsubfx_dump.txt");
cfg.WindowsWaveOutId=0;
cfg.WindowsMidiInId=0;
cfg.BankUIAutoClose=0;
cfg.DumpNotesToFile=0;
cfg.DumpAppend=1;
cfg.GzipCompression=3;
cfg.Interpolation=0;
cfg.CheckPADsynth=1;
cfg.UserInterfaceMode=0;
cfg.VirKeybLayout=1;
winwavemax=1;winmidimax=1;
//try to find out how many input midi devices are there
#ifdef WINMIDIIN
winmidimax=midiInGetNumDevs();
if (winmidimax==0) winmidimax=1;
#endif
winmididevices=new winmidionedevice[winmidimax];
for (int i=0;i<winmidimax;i++) {
winmididevices[i].name=new char[MAX_STRING_SIZE];
for (int j=0;j<MAX_STRING_SIZE;j++) winmididevices[i].name[j]='\0';
};
//get the midi input devices name
#ifdef WINMIDIIN
MIDIINCAPS midiincaps;
for (int i=0;i<winmidimax;i++){
if (! midiInGetDevCaps(i,&midiincaps,sizeof(MIDIINCAPS)))
snprintf(winmididevices[i].name,MAX_STRING_SIZE,"%s",midiincaps.szPname);
};
#endif
for (int i=0;i<MAX_BANK_ROOT_DIRS;i++) cfg.bankRootDirList[i]=NULL;
cfg.currentBankDir=new char[MAX_STRING_SIZE];
sprintf(cfg.currentBankDir,"./testbnk");
for (int i=0;i<MAX_BANK_ROOT_DIRS;i++) cfg.presetsDirList[i]=NULL;
char filename[MAX_STRING_SIZE];
getConfigFileName(filename,MAX_STRING_SIZE);
readConfig(filename);
if (cfg.bankRootDirList[0]==NULL){
#if defined(OS_LINUX)
//banks
cfg.bankRootDirList[0]=new char[MAX_STRING_SIZE];
sprintf(cfg.bankRootDirList[0],"~/banks");
cfg.bankRootDirList[1]=new char[MAX_STRING_SIZE];
sprintf(cfg.bankRootDirList[1],"./");
cfg.bankRootDirList[2]=new char[MAX_STRING_SIZE];
sprintf(cfg.bankRootDirList[2],"/usr/share/zynaddsubfx/banks");
cfg.bankRootDirList[3]=new char[MAX_STRING_SIZE];
sprintf(cfg.bankRootDirList[3],"/usr/local/share/zynaddsubfx/banks");
cfg.bankRootDirList[4]=new char[MAX_STRING_SIZE];
sprintf(cfg.bankRootDirList[4],"../banks");
cfg.bankRootDirList[5]=new char[MAX_STRING_SIZE];
sprintf(cfg.bankRootDirList[5],"banks");
#else
//banks
cfg.bankRootDirList[0]=new char[MAX_STRING_SIZE];
sprintf(cfg.bankRootDirList[0],"./");
#ifdef VSTAUDIOOUT
cfg.bankRootDirList[1]=new char[MAX_STRING_SIZE];
sprintf(cfg.bankRootDirList[1],"c:/Program Files/ZynAddSubFX/banks");
#else
cfg.bankRootDirList[1]=new char[MAX_STRING_SIZE];
sprintf(cfg.bankRootDirList[1],"../banks");
#endif
cfg.bankRootDirList[2]=new char[MAX_STRING_SIZE];
sprintf(cfg.bankRootDirList[2],"banks");
#endif
};
if (cfg.presetsDirList[0]==NULL){
#if defined(OS_LINUX)
//presets
cfg.presetsDirList[0]=new char[MAX_STRING_SIZE];
sprintf(cfg.presetsDirList[0],"./");
cfg.presetsDirList[1]=new char[MAX_STRING_SIZE];
sprintf(cfg.presetsDirList[1],"../presets");
cfg.presetsDirList[2]=new char[MAX_STRING_SIZE];
sprintf(cfg.presetsDirList[2],"presets");
cfg.presetsDirList[3]=new char[MAX_STRING_SIZE];
sprintf(cfg.presetsDirList[3],"/usr/share/zynaddsubfx/presets");
cfg.presetsDirList[4]=new char[MAX_STRING_SIZE];
sprintf(cfg.presetsDirList[4],"/usr/local/share/zynaddsubfx/presets");
#else
//presets
cfg.presetsDirList[0]=new char[MAX_STRING_SIZE];
sprintf(cfg.presetsDirList[0],"./");
#ifdef VSTAUDIOOUT
cfg.presetsDirList[1]=new char[MAX_STRING_SIZE];
sprintf(cfg.presetsDirList[1],"c:/Program Files/ZynAddSubFX/presets");
#else
cfg.presetsDirList[1]=new char[MAX_STRING_SIZE];
sprintf(cfg.presetsDirList[1],"../presets");
#endif
cfg.presetsDirList[2]=new char[MAX_STRING_SIZE];
sprintf(cfg.presetsDirList[2],"presets");
#endif
};
};
Config::~Config(){
delete [] cfg.LinuxOSSWaveOutDev;
delete [] cfg.LinuxOSSSeqInDev;
delete [] cfg.DumpFile;
for (int i=0;i<winmidimax;i++) delete [] winmididevices[i].name;
delete [] winmididevices;
};
void Config::save(){
char filename[MAX_STRING_SIZE];
getConfigFileName(filename,MAX_STRING_SIZE);
saveConfig(filename);
};
void Config::clearbankrootdirlist(){
for (int i=0;i<MAX_BANK_ROOT_DIRS;i++) {
if (cfg.bankRootDirList[i]==NULL) delete(cfg.bankRootDirList[i]);
cfg.bankRootDirList[i]=NULL;
};
};
void Config::clearpresetsdirlist(){
for (int i=0;i<MAX_BANK_ROOT_DIRS;i++) {
if (cfg.presetsDirList[i]==NULL) delete(cfg.presetsDirList[i]);
cfg.presetsDirList[i]=NULL;
};
};
void Config::readConfig(const char *filename){
XMLwrapper *xmlcfg=new XMLwrapper();
if (xmlcfg->loadXMLfile(filename)<0) return;
if (xmlcfg->enterbranch("CONFIGURATION")){
cfg.SampleRate=xmlcfg->getpar("sample_rate",cfg.SampleRate,4000,1024000);
cfg.SoundBufferSize=xmlcfg->getpar("sound_buffer_size",cfg.SoundBufferSize,16,8192);
cfg.OscilSize=xmlcfg->getpar("oscil_size",cfg.OscilSize,MAX_AD_HARMONICS*2,131072);
cfg.SwapStereo=xmlcfg->getpar("swap_stereo",cfg.SwapStereo,0,1);
cfg.BankUIAutoClose=xmlcfg->getpar("bank_window_auto_close",cfg.BankUIAutoClose,0,1);
cfg.DumpNotesToFile=xmlcfg->getpar("dump_notes_to_file",cfg.DumpNotesToFile,0,1);
cfg.DumpAppend=xmlcfg->getpar("dump_append",cfg.DumpAppend,0,1);
xmlcfg->getparstr("dump_file",cfg.DumpFile,MAX_STRING_SIZE);
cfg.GzipCompression=xmlcfg->getpar("gzip_compression",cfg.GzipCompression,0,9);
xmlcfg->getparstr("bank_current",cfg.currentBankDir,MAX_STRING_SIZE);
cfg.Interpolation=xmlcfg->getpar("interpolation",cfg.Interpolation,0,1);
cfg.CheckPADsynth=xmlcfg->getpar("check_pad_synth",cfg.CheckPADsynth,0,1);
cfg.UserInterfaceMode=xmlcfg->getpar("user_interface_mode",cfg.UserInterfaceMode,0,2);
cfg.VirKeybLayout=xmlcfg->getpar("virtual_keyboard_layout",cfg.VirKeybLayout,0,10);
//get bankroot dirs
for (int i=0;i<MAX_BANK_ROOT_DIRS;i++){
if (xmlcfg->enterbranch("BANKROOT",i)){
cfg.bankRootDirList[i]=new char[MAX_STRING_SIZE];
xmlcfg->getparstr("bank_root",cfg.bankRootDirList[i],MAX_STRING_SIZE);
xmlcfg->exitbranch();
};
};
//get preset root dirs
for (int i=0;i<MAX_BANK_ROOT_DIRS;i++){
if (xmlcfg->enterbranch("PRESETSROOT",i)){
cfg.presetsDirList[i]=new char[MAX_STRING_SIZE];
xmlcfg->getparstr("presets_root",cfg.presetsDirList[i],MAX_STRING_SIZE);
xmlcfg->exitbranch();
};
};
//linux stuff
xmlcfg->getparstr("linux_oss_wave_out_dev",cfg.LinuxOSSWaveOutDev,MAX_STRING_SIZE);
xmlcfg->getparstr("linux_oss_seq_in_dev",cfg.LinuxOSSSeqInDev,MAX_STRING_SIZE);
//windows stuff
cfg.WindowsWaveOutId=xmlcfg->getpar("windows_wave_out_id",cfg.WindowsWaveOutId,0,winwavemax);
cfg.WindowsMidiInId=xmlcfg->getpar("windows_midi_in_id",cfg.WindowsMidiInId,0,winmidimax);
xmlcfg->exitbranch();
};
delete(xmlcfg);
cfg.OscilSize=(int) pow(2,ceil(log (cfg.OscilSize-1.0)/log(2.0)));
};
void Config::saveConfig(const char *filename){
XMLwrapper *xmlcfg=new XMLwrapper();
xmlcfg->beginbranch("CONFIGURATION");
xmlcfg->addpar("sample_rate",cfg.SampleRate);
xmlcfg->addpar("sound_buffer_size",cfg.SoundBufferSize);
xmlcfg->addpar("oscil_size",cfg.OscilSize);
xmlcfg->addpar("swap_stereo",cfg.SwapStereo);
xmlcfg->addpar("bank_window_auto_close",cfg.BankUIAutoClose);
xmlcfg->addpar("dump_notes_to_file",cfg.DumpNotesToFile);
xmlcfg->addpar("dump_append",cfg.DumpAppend);
xmlcfg->addparstr("dump_file",cfg.DumpFile);
xmlcfg->addpar("gzip_compression",cfg.GzipCompression);
xmlcfg->addpar("check_pad_synth",cfg.CheckPADsynth);
xmlcfg->addparstr("bank_current",cfg.currentBankDir);
xmlcfg->addpar("user_interface_mode",cfg.UserInterfaceMode);
xmlcfg->addpar("virtual_keyboard_layout",cfg.VirKeybLayout);
for (int i=0;i<MAX_BANK_ROOT_DIRS;i++) if (cfg.bankRootDirList[i]!=NULL) {
xmlcfg->beginbranch("BANKROOT",i);
xmlcfg->addparstr("bank_root",cfg.bankRootDirList[i]);
xmlcfg->endbranch();
};
for (int i=0;i<MAX_BANK_ROOT_DIRS;i++) if (cfg.presetsDirList[i]!=NULL) {
xmlcfg->beginbranch("PRESETSROOT",i);
xmlcfg->addparstr("presets_root",cfg.presetsDirList[i]);
xmlcfg->endbranch();
};
xmlcfg->addpar("interpolation",cfg.Interpolation);
//linux stuff
xmlcfg->addparstr("linux_oss_wave_out_dev",cfg.LinuxOSSWaveOutDev);
xmlcfg->addparstr("linux_oss_seq_in_dev",cfg.LinuxOSSSeqInDev);
//windows stuff
xmlcfg->addpar("windows_wave_out_id",cfg.WindowsWaveOutId);
xmlcfg->addpar("windows_midi_in_id",cfg.WindowsMidiInId);
xmlcfg->endbranch();
int tmp=cfg.GzipCompression;
cfg.GzipCompression=0;
xmlcfg->saveXMLfile(filename);
cfg.GzipCompression=tmp;
delete(xmlcfg);
};
void Config::getConfigFileName(char *name, int namesize){
name[0]=0;
#ifdef OS_LINUX
snprintf(name,namesize,"%s%s",getenv("HOME"),"/.zynaddsubfxXML.cfg");
#else
snprintf(name,namesize,"%s","zynaddsubfxXML.cfg");
#endif
};

View File

@@ -0,0 +1,341 @@
/*
ZynAddSubFX - a software synthesizer
Config.C - Configuration file functions
Copyright (C) 2003-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#ifdef OS_WINDOWS
#include <windows.h>
#include <mmsystem.h>
#endif
#include "Config.h"
#include "XMLwrapper.h"
Config::Config()
{
};
void Config::init()
{
maxstringsize=MAX_STRING_SIZE;//for ui
//defaults
cfg.SampleRate=44100;
cfg.SoundBufferSize=256;
cfg.OscilSize=1024;
cfg.SwapStereo=0;
cfg.LinuxOSSWaveOutDev=new char[MAX_STRING_SIZE];
snprintf(cfg.LinuxOSSWaveOutDev,MAX_STRING_SIZE,"/dev/dsp");
cfg.LinuxOSSSeqInDev=new char[MAX_STRING_SIZE];
snprintf(cfg.LinuxOSSSeqInDev,MAX_STRING_SIZE,"/dev/sequencer");
cfg.DumpFile=new char[MAX_STRING_SIZE];
snprintf(cfg.DumpFile,MAX_STRING_SIZE,"zynaddsubfx_dump.txt");
cfg.WindowsWaveOutId=0;
cfg.WindowsMidiInId=0;
cfg.BankUIAutoClose=0;
cfg.DumpNotesToFile=0;
cfg.DumpAppend=1;
cfg.GzipCompression=3;
cfg.Interpolation=0;
cfg.CheckPADsynth=1;
cfg.UserInterfaceMode=0;
cfg.VirKeybLayout=1;
winwavemax=1;
winmidimax=1;
//try to find out how many input midi devices are there
#ifdef WINMIDIIN
winmidimax=midiInGetNumDevs();
if (winmidimax==0) winmidimax=1;
#endif
winmididevices=new winmidionedevice[winmidimax];
for (int i=0;i<winmidimax;i++) {
winmididevices[i].name=new char[MAX_STRING_SIZE];
for (int j=0;j<MAX_STRING_SIZE;j++) winmididevices[i].name[j]='\0';
};
//get the midi input devices name
#ifdef WINMIDIIN
MIDIINCAPS midiincaps;
for (int i=0;i<winmidimax;i++) {
if (! midiInGetDevCaps(i,&midiincaps,sizeof(MIDIINCAPS)))
snprintf(winmididevices[i].name,MAX_STRING_SIZE,"%s",midiincaps.szPname);
};
#endif
for (int i=0;i<MAX_BANK_ROOT_DIRS;i++) cfg.bankRootDirList[i]=NULL;
cfg.currentBankDir=new char[MAX_STRING_SIZE];
sprintf(cfg.currentBankDir,"./testbnk");
for (int i=0;i<MAX_BANK_ROOT_DIRS;i++) cfg.presetsDirList[i]=NULL;
char filename[MAX_STRING_SIZE];
getConfigFileName(filename,MAX_STRING_SIZE);
readConfig(filename);
if (cfg.bankRootDirList[0]==NULL) {
#if defined(OS_LINUX)
//banks
cfg.bankRootDirList[0]=new char[MAX_STRING_SIZE];
sprintf(cfg.bankRootDirList[0],"~/banks");
cfg.bankRootDirList[1]=new char[MAX_STRING_SIZE];
sprintf(cfg.bankRootDirList[1],"./");
cfg.bankRootDirList[2]=new char[MAX_STRING_SIZE];
sprintf(cfg.bankRootDirList[2],"/usr/share/zynaddsubfx/banks");
cfg.bankRootDirList[3]=new char[MAX_STRING_SIZE];
sprintf(cfg.bankRootDirList[3],"/usr/local/share/zynaddsubfx/banks");
cfg.bankRootDirList[4]=new char[MAX_STRING_SIZE];
sprintf(cfg.bankRootDirList[4],"../banks");
cfg.bankRootDirList[5]=new char[MAX_STRING_SIZE];
sprintf(cfg.bankRootDirList[5],"banks");
#else
//banks
cfg.bankRootDirList[0]=new char[MAX_STRING_SIZE];
sprintf(cfg.bankRootDirList[0],"./");
#ifdef VSTAUDIOOUT
cfg.bankRootDirList[1]=new char[MAX_STRING_SIZE];
sprintf(cfg.bankRootDirList[1],"c:/Program Files/ZynAddSubFX/banks");
#else
cfg.bankRootDirList[1]=new char[MAX_STRING_SIZE];
sprintf(cfg.bankRootDirList[1],"../banks");
#endif
cfg.bankRootDirList[2]=new char[MAX_STRING_SIZE];
sprintf(cfg.bankRootDirList[2],"banks");
#endif
};
if (cfg.presetsDirList[0]==NULL) {
#if defined(OS_LINUX)
//presets
cfg.presetsDirList[0]=new char[MAX_STRING_SIZE];
sprintf(cfg.presetsDirList[0],"./");
cfg.presetsDirList[1]=new char[MAX_STRING_SIZE];
sprintf(cfg.presetsDirList[1],"../presets");
cfg.presetsDirList[2]=new char[MAX_STRING_SIZE];
sprintf(cfg.presetsDirList[2],"presets");
cfg.presetsDirList[3]=new char[MAX_STRING_SIZE];
sprintf(cfg.presetsDirList[3],"/usr/share/zynaddsubfx/presets");
cfg.presetsDirList[4]=new char[MAX_STRING_SIZE];
sprintf(cfg.presetsDirList[4],"/usr/local/share/zynaddsubfx/presets");
#else
//presets
cfg.presetsDirList[0]=new char[MAX_STRING_SIZE];
sprintf(cfg.presetsDirList[0],"./");
#ifdef VSTAUDIOOUT
cfg.presetsDirList[1]=new char[MAX_STRING_SIZE];
sprintf(cfg.presetsDirList[1],"c:/Program Files/ZynAddSubFX/presets");
#else
cfg.presetsDirList[1]=new char[MAX_STRING_SIZE];
sprintf(cfg.presetsDirList[1],"../presets");
#endif
cfg.presetsDirList[2]=new char[MAX_STRING_SIZE];
sprintf(cfg.presetsDirList[2],"presets");
#endif
};
};
Config::~Config()
{
delete [] cfg.LinuxOSSWaveOutDev;
delete [] cfg.LinuxOSSSeqInDev;
delete [] cfg.DumpFile;
for (int i=0;i<winmidimax;i++) delete [] winmididevices[i].name;
delete [] winmididevices;
};
void Config::save()
{
char filename[MAX_STRING_SIZE];
getConfigFileName(filename,MAX_STRING_SIZE);
saveConfig(filename);
};
void Config::clearbankrootdirlist()
{
for (int i=0;i<MAX_BANK_ROOT_DIRS;i++) {
if (cfg.bankRootDirList[i]==NULL) delete(cfg.bankRootDirList[i]);
cfg.bankRootDirList[i]=NULL;
};
};
void Config::clearpresetsdirlist()
{
for (int i=0;i<MAX_BANK_ROOT_DIRS;i++) {
if (cfg.presetsDirList[i]==NULL) delete(cfg.presetsDirList[i]);
cfg.presetsDirList[i]=NULL;
};
};
void Config::readConfig(const char *filename)
{
XMLwrapper *xmlcfg=new XMLwrapper();
if (xmlcfg->loadXMLfile(filename)<0) return;
if (xmlcfg->enterbranch("CONFIGURATION")) {
cfg.SampleRate=xmlcfg->getpar("sample_rate",cfg.SampleRate,4000,1024000);
cfg.SoundBufferSize=xmlcfg->getpar("sound_buffer_size",cfg.SoundBufferSize,16,8192);
cfg.OscilSize=xmlcfg->getpar("oscil_size",cfg.OscilSize,MAX_AD_HARMONICS*2,131072);
cfg.SwapStereo=xmlcfg->getpar("swap_stereo",cfg.SwapStereo,0,1);
cfg.BankUIAutoClose=xmlcfg->getpar("bank_window_auto_close",cfg.BankUIAutoClose,0,1);
cfg.DumpNotesToFile=xmlcfg->getpar("dump_notes_to_file",cfg.DumpNotesToFile,0,1);
cfg.DumpAppend=xmlcfg->getpar("dump_append",cfg.DumpAppend,0,1);
xmlcfg->getparstr("dump_file",cfg.DumpFile,MAX_STRING_SIZE);
cfg.GzipCompression=xmlcfg->getpar("gzip_compression",cfg.GzipCompression,0,9);
xmlcfg->getparstr("bank_current",cfg.currentBankDir,MAX_STRING_SIZE);
cfg.Interpolation=xmlcfg->getpar("interpolation",cfg.Interpolation,0,1);
cfg.CheckPADsynth=xmlcfg->getpar("check_pad_synth",cfg.CheckPADsynth,0,1);
cfg.UserInterfaceMode=xmlcfg->getpar("user_interface_mode",cfg.UserInterfaceMode,0,2);
cfg.VirKeybLayout=xmlcfg->getpar("virtual_keyboard_layout",cfg.VirKeybLayout,0,10);
//get bankroot dirs
for (int i=0;i<MAX_BANK_ROOT_DIRS;i++) {
if (xmlcfg->enterbranch("BANKROOT",i)) {
cfg.bankRootDirList[i]=new char[MAX_STRING_SIZE];
xmlcfg->getparstr("bank_root",cfg.bankRootDirList[i],MAX_STRING_SIZE);
xmlcfg->exitbranch();
};
};
//get preset root dirs
for (int i=0;i<MAX_BANK_ROOT_DIRS;i++) {
if (xmlcfg->enterbranch("PRESETSROOT",i)) {
cfg.presetsDirList[i]=new char[MAX_STRING_SIZE];
xmlcfg->getparstr("presets_root",cfg.presetsDirList[i],MAX_STRING_SIZE);
xmlcfg->exitbranch();
};
};
//linux stuff
xmlcfg->getparstr("linux_oss_wave_out_dev",cfg.LinuxOSSWaveOutDev,MAX_STRING_SIZE);
xmlcfg->getparstr("linux_oss_seq_in_dev",cfg.LinuxOSSSeqInDev,MAX_STRING_SIZE);
//windows stuff
cfg.WindowsWaveOutId=xmlcfg->getpar("windows_wave_out_id",cfg.WindowsWaveOutId,0,winwavemax);
cfg.WindowsMidiInId=xmlcfg->getpar("windows_midi_in_id",cfg.WindowsMidiInId,0,winmidimax);
xmlcfg->exitbranch();
};
delete(xmlcfg);
cfg.OscilSize=(int) pow(2,ceil(log (cfg.OscilSize-1.0)/log(2.0)));
};
void Config::saveConfig(const char *filename)
{
XMLwrapper *xmlcfg=new XMLwrapper();
xmlcfg->beginbranch("CONFIGURATION");
xmlcfg->addpar("sample_rate",cfg.SampleRate);
xmlcfg->addpar("sound_buffer_size",cfg.SoundBufferSize);
xmlcfg->addpar("oscil_size",cfg.OscilSize);
xmlcfg->addpar("swap_stereo",cfg.SwapStereo);
xmlcfg->addpar("bank_window_auto_close",cfg.BankUIAutoClose);
xmlcfg->addpar("dump_notes_to_file",cfg.DumpNotesToFile);
xmlcfg->addpar("dump_append",cfg.DumpAppend);
xmlcfg->addparstr("dump_file",cfg.DumpFile);
xmlcfg->addpar("gzip_compression",cfg.GzipCompression);
xmlcfg->addpar("check_pad_synth",cfg.CheckPADsynth);
xmlcfg->addparstr("bank_current",cfg.currentBankDir);
xmlcfg->addpar("user_interface_mode",cfg.UserInterfaceMode);
xmlcfg->addpar("virtual_keyboard_layout",cfg.VirKeybLayout);
for (int i=0;i<MAX_BANK_ROOT_DIRS;i++) if (cfg.bankRootDirList[i]!=NULL) {
xmlcfg->beginbranch("BANKROOT",i);
xmlcfg->addparstr("bank_root",cfg.bankRootDirList[i]);
xmlcfg->endbranch();
};
for (int i=0;i<MAX_BANK_ROOT_DIRS;i++) if (cfg.presetsDirList[i]!=NULL) {
xmlcfg->beginbranch("PRESETSROOT",i);
xmlcfg->addparstr("presets_root",cfg.presetsDirList[i]);
xmlcfg->endbranch();
};
xmlcfg->addpar("interpolation",cfg.Interpolation);
//linux stuff
xmlcfg->addparstr("linux_oss_wave_out_dev",cfg.LinuxOSSWaveOutDev);
xmlcfg->addparstr("linux_oss_seq_in_dev",cfg.LinuxOSSSeqInDev);
//windows stuff
xmlcfg->addpar("windows_wave_out_id",cfg.WindowsWaveOutId);
xmlcfg->addpar("windows_midi_in_id",cfg.WindowsMidiInId);
xmlcfg->endbranch();
int tmp=cfg.GzipCompression;
cfg.GzipCompression=0;
xmlcfg->saveXMLfile(filename);
cfg.GzipCompression=tmp;
delete(xmlcfg);
};
void Config::getConfigFileName(char *name, int namesize)
{
name[0]=0;
#ifdef OS_LINUX
snprintf(name,namesize,"%s%s",getenv("HOME"),"/.zynaddsubfxXML.cfg");
#else
snprintf(name,namesize,"%s","zynaddsubfxXML.cfg");
#endif
};

View File

@@ -1,12 +1,12 @@
/*
ZynAddSubFX - a software synthesizer
Config.h - Configuration file functions
Copyright (C) 2003-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
@@ -26,42 +26,46 @@
#define MAX_STRING_SIZE 4000
#define MAX_BANK_ROOT_DIRS 100
class Config{
public:
Config();
~Config();
struct {
char *LinuxOSSWaveOutDev,*LinuxOSSSeqInDev;
int SampleRate,SoundBufferSize,OscilSize,SwapStereo;
int WindowsWaveOutId,WindowsMidiInId;
int BankUIAutoClose;
int DumpNotesToFile,DumpAppend;
int GzipCompression;
int Interpolation;
char *DumpFile;
char *bankRootDirList[MAX_BANK_ROOT_DIRS],*currentBankDir;
char *presetsDirList[MAX_BANK_ROOT_DIRS];
int CheckPADsynth;
int UserInterfaceMode;
int VirKeybLayout;
} cfg;
int winwavemax,winmidimax;//number of wave/midi devices on Windows
int maxstringsize;
struct winmidionedevice{
char *name;
};
winmidionedevice *winmididevices;
/**Configuration file functions*/
class Config
{
public:
/** Constructor*/
Config();
/** Destructor*/
~Config();
struct {
char *LinuxOSSWaveOutDev,*LinuxOSSSeqInDev;
int SampleRate,SoundBufferSize,OscilSize,SwapStereo;
int WindowsWaveOutId,WindowsMidiInId;
int BankUIAutoClose;
int DumpNotesToFile,DumpAppend;
int GzipCompression;
int Interpolation;
char *DumpFile;
char *bankRootDirList[MAX_BANK_ROOT_DIRS],*currentBankDir;
char *presetsDirList[MAX_BANK_ROOT_DIRS];
int CheckPADsynth;
int UserInterfaceMode;
int VirKeybLayout;
} cfg;
int winwavemax,winmidimax;//number of wave/midi devices on Windows
int maxstringsize;
void clearbankrootdirlist();
void clearpresetsdirlist();
void init();
void save();
private:
void readConfig(const char *filename);
void saveConfig(const char *filename);
void getConfigFileName(char *name,int namesize);
struct winmidionedevice {
char *name;
};
winmidionedevice *winmididevices;
void clearbankrootdirlist();
void clearpresetsdirlist();
void init();
void save();
private:
void readConfig(const char *filename);
void saveConfig(const char *filename);
void getConfigFileName(char *name,int namesize);
};
#endif

View File

@@ -0,0 +1,100 @@
/*
ZynAddSubFX - a software synthesizer
Control.h - Defines a variable that can be controled from a frontend
Copyright (C) 2009 Harald Hvaal
Author: Harald Hvaal
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _CONTROL_H_
#define _CONTROL_H_
#include <string>
class Control
{
public:
/**
* The parent is the logical owner of this control. Parent should only
* be null for the root node.
* The id is a string uniquely identifying this control within the
* context of the parent control. No spaces or dots are allowed in this
* id.
* Children id's are denoted by <parent-id>.<children-id>, so that one
* can refer to any control in the hierarchy by separating them with
* dots. Example: Main.AddSynth.FrequencyLFO.Amplitude
*/
Control(Control *parent, string id);
/**
* Will recursively get the XML representation for all the subcontrols.
* Used for saving to file and copy-pasting settings
*/
string getXMLRepresentation();
/**
* Set the value of this (and possibly subcomponents as well) based on
* a xml description.
*/
void restoreFromXML(string xml);
/**
* Register a controluser. This will cause this user to be notified
* whenever the contents of the control changes.
*/
void registerControlUser(ControlUser *user);
/**
* This should return a string representation of the controls internal
* value
*/
virtual string getStringRepresentation() = 0;
};
class FloatControl : public Control
{
public:
/**
* Set the value of this control. If the ControlUser variable is set,
* then this user will not be updated with the new value. This is to
* avoid setting a value being set back to the source that set it
* (which would be redundant, or possibly causing infinite setValue
* loops).
* NOTE: this function is thread-safe (using a mutex internally)
*/
void setValue(float value, ControlUser *user = NULL);
/**
* Reimplemented from Control
*/
virtual string getStringRepresentation();
float value();
};
class ControlUser
{
public:
/**
* Pure virtual method, to notify the controluser that the value has
* been changed internally, and needs to be read again.
*/
virtual void controlUpdated(Control *control) = 0;
};
#endif /* _CONTROL_H_ */

View File

@@ -1,99 +0,0 @@
/*
ZynAddSubFX - a software synthesizer
Dump.C - It dumps the notes to a text file
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdlib.h>
#include <time.h>
#include "Util.h"
#include "Dump.h"
Dump dump;
Dump::Dump(){
file=NULL;
tick=0;
k=0;
keyspressed=0;
};
Dump::~Dump(){
if (file!=NULL) {
double duration=(double)tick*(double) SOUND_BUFFER_SIZE/(double) SAMPLE_RATE;
fprintf(file,"\n# statistics: duration = %d seconds; keyspressed = %d\n\n\n\n",(int) duration,keyspressed);
fclose(file);
};
};
void Dump::startnow(){
if (file!=NULL) return;//the file is already open
if (config.cfg.DumpNotesToFile!=0){
if (config.cfg.DumpAppend!=0) file=fopen(config.cfg.DumpFile,"a");
else file=fopen(config.cfg.DumpFile,"w");
if (file==NULL) return;
if (config.cfg.DumpAppend!=0) fprintf(file,"%s","#************************************\n");
time_t tm=time(NULL);
fprintf(file,"#date/time = %s\n",ctime(&tm));
fprintf(file,"#1 tick = %g milliseconds\n",SOUND_BUFFER_SIZE*1000.0/SAMPLE_RATE);
fprintf(file,"SAMPLERATE = %d\n",SAMPLE_RATE);
fprintf(file,"TICKSIZE = %d #samples\n",SOUND_BUFFER_SIZE);
fprintf(file,"\n\nSTART\n");
};
};
void Dump::inctick(){
tick++;
};
void Dump::dumpnote(char chan,char note, char vel){
if (file==NULL) return;
if (note==0) return;
if (vel==0) fprintf(file,"n %d -> %d %d \n",tick,chan,note);//note off
else fprintf(file,"N %d -> %d %d %d \n",tick,chan,note,vel);//note on
if (vel!=0) keyspressed++;
#ifndef JACKAUDIOOUT
if (k++>25) {
fflush(file);
k=0;
};
#endif
};
void Dump::dumpcontroller(char chan,unsigned int type,int par){
if (file==NULL) return;
switch(type){
case C_pitchwheel:fprintf(file,"P %d -> %d %d\n",tick,chan,par);
break;
default:fprintf(file,"C %d -> %d %d %d\n",tick,chan,type,par);
break;
};
#ifndef JACKAUDIOOUT
if (k++>25) {
fflush(file);
k=0;
};
#endif
};

View File

@@ -0,0 +1,107 @@
/*
ZynAddSubFX - a software synthesizer
Dump.C - It dumps the notes to a text file
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdlib.h>
#include <time.h>
#include "Util.h"
#include "Dump.h"
Dump dump;
Dump::Dump()
{
file=NULL;
tick=0;
k=0;
keyspressed=0;
};
Dump::~Dump()
{
if (file!=NULL) {
double duration=(double)tick*(double) SOUND_BUFFER_SIZE/(double) SAMPLE_RATE;
fprintf(file,"\n# statistics: duration = %d seconds; keyspressed = %d\n\n\n\n",(int) duration,keyspressed);
fclose(file);
};
};
void Dump::startnow()
{
if (file!=NULL) return;//the file is already open
if (config.cfg.DumpNotesToFile!=0) {
if (config.cfg.DumpAppend!=0) file=fopen(config.cfg.DumpFile,"a");
else file=fopen(config.cfg.DumpFile,"w");
if (file==NULL) return;
if (config.cfg.DumpAppend!=0) fprintf(file,"%s","#************************************\n");
time_t tm=time(NULL);
fprintf(file,"#date/time = %s\n",ctime(&tm));
fprintf(file,"#1 tick = %g milliseconds\n",SOUND_BUFFER_SIZE*1000.0/SAMPLE_RATE);
fprintf(file,"SAMPLERATE = %d\n",SAMPLE_RATE);
fprintf(file,"TICKSIZE = %d #samples\n",SOUND_BUFFER_SIZE);
fprintf(file,"\n\nSTART\n");
};
};
void Dump::inctick()
{
tick++;
};
void Dump::dumpnote(char chan,char note, char vel)
{
if (file==NULL) return;
if (note==0) return;
if (vel==0) fprintf(file,"n %d -> %d %d \n",tick,chan,note);//note off
else fprintf(file,"N %d -> %d %d %d \n",tick,chan,note,vel);//note on
if (vel!=0) keyspressed++;
#ifndef JACKAUDIOOUT
if (k++>25) {
fflush(file);
k=0;
};
#endif
};
void Dump::dumpcontroller(char chan,unsigned int type,int par)
{
if (file==NULL) return;
switch (type) {
case C_pitchwheel:
fprintf(file,"P %d -> %d %d\n",tick,chan,par);
break;
default:
fprintf(file,"C %d -> %d %d %d\n",tick,chan,type,par);
break;
};
#ifndef JACKAUDIOOUT
if (k++>25) {
fflush(file);
k=0;
};
#endif
};

View File

@@ -1,13 +1,13 @@
/*
ZynAddSubFX - a software synthesizer
Dump.h - It dumps the notes to a text file
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
@@ -24,20 +24,40 @@
#include <stdio.h>
class Dump{
public:
Dump();
~Dump();
void startnow();
void inctick();
void dumpnote(char chan,char note, char vel);
void dumpcontroller(char chan,unsigned int type,int par);
private:
FILE *file;
int tick;
int k;
int keyspressed;
/**Object used to dump the notes into a text file
* \todo see if this object should have knowledge about the file
* that it will write to
* \todo upgrade from stdio to iostream*/
class Dump
{
public:
/**Constructor*/
Dump();
/**Destructor
* Closes the dumpfile*/
~Dump();
/**Open dumpfile and prepare it for dumps
* \todo see if this fits better in the constructor*/
void startnow();
/**Tick the timestamp*/
void inctick();
/**Dump Note to dumpfile
* @param chan The channel of the note
* @param note The note
* @param vel The velocity of the note*/
void dumpnote(char chan,char note, char vel);
/** Dump the Controller
* @param chan The channel of the Controller
* @param type The type
* @param par The value of the controller
* \todo figure out what type is exactly meaning*/
void dumpcontroller(char chan,unsigned int type,int par);
private:
FILE *file;
int tick;
int k;//This appears to be a constant used to flush the file
//periodically when JACK is used
int keyspressed;
};
#endif

View File

@@ -0,0 +1,104 @@
/*
ZynAddSubFX - a software synthesizer
LASHClient.C - LASH support
Copyright (C) 2006-2009 Lars Luthman
Author: Lars Luthman
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <unistd.h>
#include <iostream>
#include <string>
#include "LASHClient.h"
LASHClient::LASHClient(int* argc, char*** argv)
{
client = lash_init(lash_extract_args(argc, argv), "ZynAddSubFX",
LASH_Config_File, LASH_PROTOCOL(2, 0));
}
void LASHClient::setalsaid(int id)
{
if (lash_enabled(client)) {
if (id != -1)
lash_alsa_client_id(client, id);
}
}
void LASHClient::setjackname(const char* name)
{
if (lash_enabled(client)) {
if (name != NULL) {
lash_jack_client_name(client, name);
lash_event_t *event = lash_event_new_with_type(LASH_Client_Name);
lash_event_set_string(event, name);
lash_send_event(client, event);
}
}
}
LASHClient::Event LASHClient::checkevents(std::string& filename)
{
if (!lash_enabled(client))
return NoEvent;
Event received = NoEvent;
lash_event_t* event;
while (event = lash_get_event(client)) {
// save
if (lash_event_get_type(event) == LASH_Save_File) {
std::cerr<<"LASH event: LASH_Save_File"<<std::endl;
filename = std::string(lash_event_get_string(event)) + "/master.xmz";
received = Save;
break;
}
// restore
else if (lash_event_get_type(event) == LASH_Restore_File) {
std::cerr<<"LASH event: LASH_Restore_File"<<std::endl;
filename = std::string(lash_event_get_string(event)) + "/master.xmz";
received = Restore;
break;
}
// quit
else if (lash_event_get_type(event) == LASH_Quit) {
std::cerr<<"LASH event: LASH_Quit"<<std::endl;
received = Quit;
break;
}
lash_event_destroy(event);
}
return received;
}
void LASHClient::confirmevent(Event event)
{
if (event == Save)
lash_send_event(client, lash_event_new_with_type(LASH_Save_File));
else if (event == Restore)
lash_send_event(client, lash_event_new_with_type(LASH_Restore_File));
}

View File

@@ -0,0 +1,66 @@
/*
ZynAddSubFX - a software synthesizer
LASHClient.h - LASH support
Copyright (C) 2006-2009 Lars Luthman
Author: Lars Luthman
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef LASHClient_h
#define LASHClient_h
#include <string>
#include <pthread.h>
#include <lash/lash.h>
/** This class wraps up some functions for initialising and polling
* the LASH daemon.
* \todo fix indentation nonconformism
* \todo see why there is no destructor*/
class LASHClient
{
public:
/**Enum to represent the LASH events that are currently handled*/
enum Event {
Save,
Restore,
Quit,
NoEvent
};
/** Constructor
* @param argc number of arguments
* @param argv the text arguments*/
LASHClient(int* argc, char*** argv);
/**set the ALSA id
* @param id new ALSA id*/
void setalsaid(int id);
/**Set the JACK name
* @param name the new name*/
void setjackname(const char* name);
Event checkevents(std::string& filename);
void confirmevent(Event event);
private:
lash_client_t* client;
};
#endif

View File

@@ -1,738 +0,0 @@
/*
ZynAddSubFX - a software synthesizer
Master.C - It sends Midi Messages to Parts, receives samples from parts,
process them with system/insertion effects and mix them
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "Master.h"
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
Master::Master(){
swaplr=0;
pthread_mutex_init(&mutex,NULL);
fft=new FFTwrapper(OSCIL_SIZE);
tmpmixl=new REALTYPE[SOUND_BUFFER_SIZE];
tmpmixr=new REALTYPE[SOUND_BUFFER_SIZE];
audiooutl=new REALTYPE[SOUND_BUFFER_SIZE];
audiooutr=new REALTYPE[SOUND_BUFFER_SIZE];
ksoundbuffersample=-1;//this is only time when this is -1; this means that the GetAudioOutSamples was never called
ksoundbuffersamplelow=0.0;
oldsamplel=0.0;oldsampler=0.0;
shutup=0;
for (int npart=0;npart<NUM_MIDI_PARTS;npart++) {
vuoutpeakpart[npart]=1e-9;
fakepeakpart[npart]=0;
};
for (int i=0;i<SOUND_BUFFER_SIZE;i++) {
audiooutl[i]=0.0;
audiooutr[i]=0.0;
};
for (int npart=0;npart<NUM_MIDI_PARTS;npart++)
part[npart]=new Part(&microtonal,fft,&mutex);
//Insertion Effects init
for (int nefx=0;nefx<NUM_INS_EFX;nefx++)
insefx[nefx]=new EffectMgr(1,&mutex);
//System Effects init
for (int nefx=0;nefx<NUM_SYS_EFX;nefx++) {
sysefx[nefx]=new EffectMgr(0,&mutex);
};
defaults();
};
void Master::defaults(){
volume=1.0;
setPvolume(80);
setPkeyshift(64);
for (int npart=0;npart<NUM_MIDI_PARTS;npart++){
part[npart]->defaults();
part[npart]->Prcvchn=npart%NUM_MIDI_CHANNELS;
};
partonoff(0,1);//enable the first part
for (int nefx=0;nefx<NUM_INS_EFX;nefx++) {
insefx[nefx]->defaults();
Pinsparts[nefx]=-1;
};
//System Effects init
for (int nefx=0;nefx<NUM_SYS_EFX;nefx++) {
sysefx[nefx]->defaults();
for (int npart=0;npart<NUM_MIDI_PARTS;npart++){
//if (nefx==0) setPsysefxvol(npart,nefx,64);
//else
setPsysefxvol(npart,nefx,0);
};
for (int nefxto=0;nefxto<NUM_SYS_EFX;nefxto++)
setPsysefxsend(nefx,nefxto,0);
};
// sysefx[0]->changeeffect(1);
microtonal.defaults();
ShutUp();
};
/*
* Note On Messages (velocity=0 for NoteOff)
*/
void Master::NoteOn(unsigned char chan,unsigned char note,unsigned char velocity){
dump.dumpnote(chan,note,velocity);
noteon(chan,note,velocity);
};
/*
* Internal Note On (velocity=0 for NoteOff)
*/
void Master::noteon(unsigned char chan,unsigned char note,unsigned char velocity){
int npart;
if (velocity!=0){
for (npart=0;npart<NUM_MIDI_PARTS;npart++){
if (chan==part[npart]->Prcvchn){
fakepeakpart[npart]=velocity*2;
if (part[npart]->Penabled!=0) part[npart]->NoteOn(note,velocity,keyshift);
};
};
}else{
this->NoteOff(chan,note);
};
HDDRecorder.triggernow();
};
/*
* Note Off Messages
*/
void Master::NoteOff(unsigned char chan,unsigned char note){
dump.dumpnote(chan,note,0);
noteoff(chan,note);
};
/*
* Internal Note Off
*/
void Master::noteoff(unsigned char chan,unsigned char note){
int npart;
for (npart=0;npart<NUM_MIDI_PARTS;npart++){
if ((chan==part[npart]->Prcvchn) && (part[npart]->Penabled!=0))
part[npart]->NoteOff(note);
};
};
/*
* Controllers
*/
void Master::SetController(unsigned char chan,unsigned int type,int par){
dump.dumpcontroller(chan,type,par);
setcontroller(chan,type,par);
};
/*
* Internal Controllers
*/
void Master::setcontroller(unsigned char chan,unsigned int type,int par){
if ((type==C_dataentryhi)||(type==C_dataentrylo)||
(type==C_nrpnhi)||(type==C_nrpnlo)){//Process RPN and NRPN by the Master (ignore the chan)
ctl.setparameternumber(type,par);
int parhi=-1,parlo=-1,valhi=-1,vallo=-1;
if (ctl.getnrpn(&parhi,&parlo,&valhi,&vallo)==0){//this is NRPN
//fprintf(stderr,"rcv. NRPN: %d %d %d %d\n",parhi,parlo,valhi,vallo);
switch (parhi){
case 0x04://System Effects
if (parlo<NUM_SYS_EFX) {
sysefx[parlo]->seteffectpar_nolock(valhi,vallo);
};
break;
case 0x08://Insertion Effects
if (parlo<NUM_INS_EFX) {
insefx[parlo]->seteffectpar_nolock(valhi,vallo);
};
break;
};
};
} else {//other controllers
for (int npart=0;npart<NUM_MIDI_PARTS;npart++){//Send the controller to all part assigned to the channel
if ((chan==part[npart]->Prcvchn) && (part[npart]->Penabled!=0))
part[npart]->SetController(type,par);
};
};
};
/*
* Enable/Disable a part
*/
void Master::partonoff(int npart,int what){
if (npart>=NUM_MIDI_PARTS) return;
if (what==0){//disable part
fakepeakpart[npart]=0;
part[npart]->Penabled=0;
part[npart]->cleanup();
for (int nefx=0;nefx<NUM_INS_EFX;nefx++){
if (Pinsparts[nefx]==npart) {
insefx[nefx]->cleanup();
};
};
} else {//enabled
part[npart]->Penabled=1;
fakepeakpart[npart]=0;
};
};
/*
* Master audio out (the final sound)
*/
void Master::AudioOut(REALTYPE *outl,REALTYPE *outr){
int i,npart,nefx;
/* //test!!!!!!!!!!!!! se poate bloca aici (mutex)
if (seq.play){
int type,par1,par2,again,midichan;
int ntrack=1;
// do{
again=seq.getevent(ntrack,&midichan,&type,&par1,&par2);
if (type>0) {
// printf("aaa\n");
if (type==1){//note_on or note_off
if (par2!=0) NoteOn(midichan,par1,par2);
else NoteOff(midichan,par1);
};
};
// } while (again);
};
*/
// printf("zzzz\n");
//Swaps the Left channel with Right Channel (if it is asked for)
if (swaplr!=0){
REALTYPE *tmp=outl;
outl=outr;
outr=tmp;
};
//clean up the output samples
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
outl[i]=0.0;
outr[i]=0.0;
};
//Compute part samples and store them part[npart]->partoutl,partoutr
for (npart=0;npart<NUM_MIDI_PARTS;npart++)
if (part[npart]->Penabled!=0) part[npart]->ComputePartSmps();
//Insertion effects
for (nefx=0;nefx<NUM_INS_EFX;nefx++){
if (Pinsparts[nefx]>=0) {
int efxpart=Pinsparts[nefx];
if (part[efxpart]->Penabled!=0)
insefx[nefx]->out(part[efxpart]->partoutl,part[efxpart]->partoutr);
};
};
//Apply the part volumes and pannings (after insertion effects)
for (npart=0;npart<NUM_MIDI_PARTS;npart++){
if (part[npart]->Penabled==0) continue;
REALTYPE newvol_l=part[npart]->volume;
REALTYPE newvol_r=part[npart]->volume;
REALTYPE oldvol_l=part[npart]->oldvolumel;
REALTYPE oldvol_r=part[npart]->oldvolumer;
REALTYPE pan=part[npart]->panning;
if (pan<0.5) newvol_l*=pan*2.0;
else newvol_r*=(1.0-pan)*2.0;
if (ABOVE_AMPLITUDE_THRESHOLD(oldvol_l,newvol_l)||
ABOVE_AMPLITUDE_THRESHOLD(oldvol_r,newvol_r)){//the volume or the panning has changed and needs interpolation
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
REALTYPE vol_l=INTERPOLATE_AMPLITUDE(oldvol_l,newvol_l,i,SOUND_BUFFER_SIZE);
REALTYPE vol_r=INTERPOLATE_AMPLITUDE(oldvol_r,newvol_r,i,SOUND_BUFFER_SIZE);
part[npart]->partoutl[i]*=vol_l;
part[npart]->partoutr[i]*=vol_r;
};
part[npart]->oldvolumel=newvol_l;
part[npart]->oldvolumer=newvol_r;
} else {
for (i=0;i<SOUND_BUFFER_SIZE;i++) {//the volume did not changed
part[npart]->partoutl[i]*=newvol_l;
part[npart]->partoutr[i]*=newvol_r;
};
};
};
//System effects
for (nefx=0;nefx<NUM_SYS_EFX;nefx++){
if (sysefx[nefx]->geteffect()==0) continue;//the effect is disabled
//Clean up the samples used by the system effects
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
tmpmixl[i]=0.0;
tmpmixr[i]=0.0;
};
//Mix the channels according to the part settings about System Effect
for (npart=0;npart<NUM_MIDI_PARTS;npart++){
//skip if the part has no output to effect
if (Psysefxvol[nefx][npart]==0) continue;
//skip if the part is disabled
if (part[npart]->Penabled==0) continue;
//the output volume of each part to system effect
REALTYPE vol=sysefxvol[nefx][npart];
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
tmpmixl[i]+=part[npart]->partoutl[i]*vol;
tmpmixr[i]+=part[npart]->partoutr[i]*vol;
};
};
// system effect send to next ones
for (int nefxfrom=0;nefxfrom<nefx;nefxfrom++){
if (Psysefxsend[nefxfrom][nefx]!=0){
REALTYPE v=sysefxsend[nefxfrom][nefx];
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
tmpmixl[i]+=sysefx[nefxfrom]->efxoutl[i]*v;
tmpmixr[i]+=sysefx[nefxfrom]->efxoutr[i]*v;
};
};
};
sysefx[nefx]->out(tmpmixl,tmpmixr);
//Add the System Effect to sound output
REALTYPE outvol=sysefx[nefx]->sysefxgetvolume();
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
outl[i]+=tmpmixl[i]*outvol;
outr[i]+=tmpmixr[i]*outvol;
};
};
//Mix all parts
for (npart=0;npart<NUM_MIDI_PARTS;npart++){
for (i=0;i<SOUND_BUFFER_SIZE;i++) {//the volume did not changed
outl[i]+=part[npart]->partoutl[i];
outr[i]+=part[npart]->partoutr[i];
};
};
//Insertion effects for Master Out
for (nefx=0;nefx<NUM_INS_EFX;nefx++){
if (Pinsparts[nefx] == -2)
insefx[nefx]->out(outl,outr);
};
//Master Volume
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
outl[i]*=volume;
outr[i]*=volume;
};
//Peak computation (for vumeters)
vuoutpeakl=1e-12;vuoutpeakr=1e-12;
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
if (fabs(outl[i])>vuoutpeakl) vuoutpeakl=fabs(outl[i]);
if (fabs(outr[i])>vuoutpeakr) vuoutpeakr=fabs(outr[i]);
};
if ((vuoutpeakl>1.0)||(vuoutpeakr>1.0)) vuclipped=1;
if (vumaxoutpeakl<vuoutpeakl) vumaxoutpeakl=vuoutpeakl;
if (vumaxoutpeakr<vuoutpeakr) vumaxoutpeakr=vuoutpeakr;
//RMS Peak computation (for vumeters)
vurmspeakl=1e-12;vurmspeakr=1e-12;
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
vurmspeakl+=outl[i]*outl[i];
vurmspeakr+=outr[i]*outr[i];
};
vurmspeakl=sqrt(vurmspeakl/SOUND_BUFFER_SIZE);
vurmspeakr=sqrt(vurmspeakr/SOUND_BUFFER_SIZE);
//Part Peak computation (for Part vumeters or fake part vumeters)
for (npart=0;npart<NUM_MIDI_PARTS;npart++){
vuoutpeakpart[npart]=1.0e-12;
if (part[npart]->Penabled!=0) {
REALTYPE *outl=part[npart]->partoutl,
*outr=part[npart]->partoutr;
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
REALTYPE tmp=fabs(outl[i]+outr[i]);
if (tmp>vuoutpeakpart[npart]) vuoutpeakpart[npart]=tmp;
};
vuoutpeakpart[npart]*=volume;
} else {
if (fakepeakpart[npart]>1) fakepeakpart[npart]--;
};
};
//Shutup if it is asked (with fade-out)
if (shutup!=0){
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
REALTYPE tmp=(SOUND_BUFFER_SIZE-i)/(REALTYPE) SOUND_BUFFER_SIZE;
outl[i]*=tmp;
outr[i]*=tmp;
};
ShutUp();
};
//update the LFO's time
LFOParams::time++;
if (HDDRecorder.recording()) HDDRecorder.recordbuffer(outl,outr);
dump.inctick();
};
void Master::GetAudioOutSamples(int nsamples,int samplerate,REALTYPE *outl,REALTYPE *outr){
if (ksoundbuffersample==-1){//first time
AudioOut(&audiooutl[0],&audiooutr[0]);
ksoundbuffersample=0;
};
if (samplerate==SAMPLE_RATE){//no resample
int ksample=0;
while (ksample<nsamples){
outl[ksample]=audiooutl[ksoundbuffersample];
outr[ksample]=audiooutr[ksoundbuffersample];
ksample++;
ksoundbuffersample++;
if (ksoundbuffersample>=SOUND_BUFFER_SIZE){
AudioOut(&audiooutl[0],&audiooutr[0]);
ksoundbuffersample=0;
};
};
} else {//Resample
int ksample=0;
REALTYPE srinc=SAMPLE_RATE/(REALTYPE)samplerate;
while (ksample<nsamples){
if (ksoundbuffersample!=0){
outl[ksample]=audiooutl[ksoundbuffersample]*ksoundbuffersamplelow
+audiooutl[ksoundbuffersample-1]*(1.0-ksoundbuffersamplelow);
outr[ksample]=audiooutr[ksoundbuffersample]*ksoundbuffersamplelow
+audiooutr[ksoundbuffersample-1]*(1.0-ksoundbuffersamplelow);
} else {
outl[ksample]=audiooutl[ksoundbuffersample]*ksoundbuffersamplelow
+oldsamplel*(1.0-ksoundbuffersamplelow);
outr[ksample]=audiooutr[ksoundbuffersample]*ksoundbuffersamplelow
+oldsampler*(1.0-ksoundbuffersamplelow);
};
ksample++;
ksoundbuffersamplelow+=srinc;
if (ksoundbuffersamplelow>=1.0){
ksoundbuffersample+=(int) floor(ksoundbuffersamplelow);
ksoundbuffersamplelow=ksoundbuffersamplelow-floor(ksoundbuffersamplelow);
};
if (ksoundbuffersample>=SOUND_BUFFER_SIZE){
oldsamplel=audiooutl[SOUND_BUFFER_SIZE-1];
oldsampler=audiooutr[SOUND_BUFFER_SIZE-1];
AudioOut(&audiooutl[0],&audiooutr[0]);
ksoundbuffersample=0;
};
};
};
};
Master::~Master(){
for (int npart=0;npart<NUM_MIDI_PARTS;npart++) delete part[npart];
for (int nefx=0;nefx<NUM_INS_EFX;nefx++) delete insefx[nefx];
for (int nefx=0;nefx<NUM_SYS_EFX;nefx++) delete sysefx[nefx];
delete [] audiooutl;
delete [] audiooutr;
delete [] tmpmixl;
delete [] tmpmixr;
delete (fft);
pthread_mutex_destroy(&mutex);
};
/*
* Parameter control
*/
void Master::setPvolume(char Pvolume_){
Pvolume=Pvolume_;
volume=dB2rap((Pvolume-96.0)/96.0*40.0);
};
void Master::setPkeyshift(char Pkeyshift_){
Pkeyshift=Pkeyshift_;
keyshift=(int)Pkeyshift-64;
};
void Master::setPsysefxvol(int Ppart,int Pefx,char Pvol){
Psysefxvol[Pefx][Ppart]=Pvol;
sysefxvol[Pefx][Ppart]=pow(0.1,(1.0-Pvol/96.0)*2.0);
};
void Master::setPsysefxsend(int Pefxfrom,int Pefxto,char Pvol){
Psysefxsend[Pefxfrom][Pefxto]=Pvol;
sysefxsend[Pefxfrom][Pefxto]=pow(0.1,(1.0-Pvol/96.0)*2.0);
};
/*
* Panic! (Clean up all parts and effects)
*/
void Master::ShutUp(){
for (int npart=0;npart<NUM_MIDI_PARTS;npart++) {
part[npart]->cleanup();
fakepeakpart[npart]=0;
};
for (int nefx=0;nefx<NUM_INS_EFX;nefx++) insefx[nefx]->cleanup();
for (int nefx=0;nefx<NUM_SYS_EFX;nefx++) sysefx[nefx]->cleanup();
vuresetpeaks();
shutup=0;
};
/*
* Reset peaks and clear the "cliped" flag (for VU-meter)
*/
void Master::vuresetpeaks(){
vuoutpeakl=1e-9;vuoutpeakr=1e-9;vumaxoutpeakl=1e-9;vumaxoutpeakr=1e-9;
vuclipped=0;
};
void Master::applyparameters(){
for (int npart=0;npart<NUM_MIDI_PARTS;npart++){
part[npart]->applyparameters();
};
};
void Master::add2XML(XMLwrapper *xml){
xml->addpar("volume",Pvolume);
xml->addpar("key_shift",Pkeyshift);
xml->addparbool("nrpn_receive",ctl.NRPN.receive);
xml->beginbranch("MICROTONAL");
microtonal.add2XML(xml);
xml->endbranch();
for (int npart=0;npart<NUM_MIDI_PARTS;npart++){
xml->beginbranch("PART",npart);
part[npart]->add2XML(xml);
xml->endbranch();
};
xml->beginbranch("SYSTEM_EFFECTS");
for (int nefx=0;nefx<NUM_SYS_EFX;nefx++){
xml->beginbranch("SYSTEM_EFFECT",nefx);
xml->beginbranch("EFFECT");
sysefx[nefx]->add2XML(xml);
xml->endbranch();
for (int pefx=0;pefx<NUM_MIDI_PARTS;pefx++){
xml->beginbranch("VOLUME",pefx);
xml->addpar("vol",Psysefxvol[nefx][pefx]);
xml->endbranch();
};
for (int tonefx=nefx+1;tonefx<NUM_SYS_EFX;tonefx++){
xml->beginbranch("SENDTO",tonefx);
xml->addpar("send_vol",Psysefxsend[nefx][tonefx]);
xml->endbranch();
};
xml->endbranch();
};
xml->endbranch();
xml->beginbranch("INSERTION_EFFECTS");
for (int nefx=0;nefx<NUM_INS_EFX;nefx++){
xml->beginbranch("INSERTION_EFFECT",nefx);
xml->addpar("part",Pinsparts[nefx]);
xml->beginbranch("EFFECT");
insefx[nefx]->add2XML(xml);
xml->endbranch();
xml->endbranch();
};
xml->endbranch();
};
int Master::getalldata(char **data){
XMLwrapper *xml=new XMLwrapper();
xml->beginbranch("MASTER");
pthread_mutex_lock(&mutex);
add2XML(xml);
pthread_mutex_unlock(&mutex);
xml->endbranch();
*data=xml->getXMLdata();
delete (xml);
return(strlen(*data)+1);
};
void Master::putalldata(char *data,int size){
XMLwrapper *xml=new XMLwrapper();
if (!xml->putXMLdata(data)) {
delete(xml);
return;
};
if (xml->enterbranch("MASTER")==0) return;
pthread_mutex_lock(&mutex);
getfromXML(xml);
pthread_mutex_unlock(&mutex);
xml->exitbranch();
delete(xml);
};
int Master::saveXML(char *filename){
XMLwrapper *xml=new XMLwrapper();
xml->beginbranch("MASTER");
add2XML(xml);
xml->endbranch();
int result=xml->saveXMLfile(filename);
delete (xml);
return(result);
};
int Master::loadXML(char *filename){
XMLwrapper *xml=new XMLwrapper();
if (xml->loadXMLfile(filename)<0) {
delete(xml);
return(-1);
};
if (xml->enterbranch("MASTER")==0) return(-10);
getfromXML(xml);
xml->exitbranch();
delete(xml);
return(0);
};
void Master::getfromXML(XMLwrapper *xml){
setPvolume(xml->getpar127("volume",Pvolume));
setPkeyshift(xml->getpar127("key_shift",Pkeyshift));
ctl.NRPN.receive=xml->getparbool("nrpn_receive",ctl.NRPN.receive);
part[0]->Penabled=0;
for (int npart=0;npart<NUM_MIDI_PARTS;npart++){
if (xml->enterbranch("PART",npart)==0) continue;
part[npart]->getfromXML(xml);
xml->exitbranch();
};
if (xml->enterbranch("MICROTONAL")){
microtonal.getfromXML(xml);
xml->exitbranch();
};
sysefx[0]->changeeffect(0);
if (xml->enterbranch("SYSTEM_EFFECTS")){
for (int nefx=0;nefx<NUM_SYS_EFX;nefx++){
if (xml->enterbranch("SYSTEM_EFFECT",nefx)==0) continue;
if (xml->enterbranch("EFFECT")){
sysefx[nefx]->getfromXML(xml);
xml->exitbranch();
};
for (int partefx=0;partefx<NUM_MIDI_PARTS;partefx++){
if (xml->enterbranch("VOLUME",partefx)==0) continue;
setPsysefxvol(partefx,nefx,xml->getpar127("vol",Psysefxvol[partefx][nefx]));
xml->exitbranch();
};
for (int tonefx=nefx+1;tonefx<NUM_SYS_EFX;tonefx++){
if (xml->enterbranch("SENDTO",tonefx)==0) continue;
setPsysefxsend(nefx,tonefx,xml->getpar127("send_vol",Psysefxsend[nefx][tonefx]));
xml->exitbranch();
};
xml->exitbranch();
};
xml->exitbranch();
};
if (xml->enterbranch("INSERTION_EFFECTS")){
for (int nefx=0;nefx<NUM_INS_EFX;nefx++){
if (xml->enterbranch("INSERTION_EFFECT",nefx)==0) continue;
Pinsparts[nefx]=xml->getpar("part",Pinsparts[nefx],-2,NUM_MIDI_PARTS);
if (xml->enterbranch("EFFECT")){
insefx[nefx]->getfromXML(xml);
xml->exitbranch();
};
xml->exitbranch();
};
xml->exitbranch();
};
};

View File

@@ -0,0 +1,778 @@
/*
ZynAddSubFX - a software synthesizer
Master.C - It sends Midi Messages to Parts, receives samples from parts,
process them with system/insertion effects and mix them
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "Master.h"
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
Master::Master()
{
swaplr=0;
pthread_mutex_init(&mutex,NULL);
fft=new FFTwrapper(OSCIL_SIZE);
tmpmixl=new REALTYPE[SOUND_BUFFER_SIZE];
tmpmixr=new REALTYPE[SOUND_BUFFER_SIZE];
audiooutl=new REALTYPE[SOUND_BUFFER_SIZE];
audiooutr=new REALTYPE[SOUND_BUFFER_SIZE];
ksoundbuffersample=-1;//this is only time when this is -1; this means that the GetAudioOutSamples was never called
ksoundbuffersamplelow=0.0;
oldsamplel=0.0;
oldsampler=0.0;
shutup=0;
for (int npart=0;npart<NUM_MIDI_PARTS;npart++) {
vuoutpeakpart[npart]=1e-9;
fakepeakpart[npart]=0;
};
for (int i=0;i<SOUND_BUFFER_SIZE;i++) {
audiooutl[i]=0.0;
audiooutr[i]=0.0;
};
for (int npart=0;npart<NUM_MIDI_PARTS;npart++)
part[npart]=new Part(&microtonal,fft,&mutex);
//Insertion Effects init
for (int nefx=0;nefx<NUM_INS_EFX;nefx++)
insefx[nefx]=new EffectMgr(1,&mutex);
//System Effects init
for (int nefx=0;nefx<NUM_SYS_EFX;nefx++) {
sysefx[nefx]=new EffectMgr(0,&mutex);
};
defaults();
};
void Master::defaults()
{
volume=1.0;
setPvolume(80);
setPkeyshift(64);
for (int npart=0;npart<NUM_MIDI_PARTS;npart++) {
part[npart]->defaults();
part[npart]->Prcvchn=npart%NUM_MIDI_CHANNELS;
};
partonoff(0,1);//enable the first part
for (int nefx=0;nefx<NUM_INS_EFX;nefx++) {
insefx[nefx]->defaults();
Pinsparts[nefx]=-1;
};
//System Effects init
for (int nefx=0;nefx<NUM_SYS_EFX;nefx++) {
sysefx[nefx]->defaults();
for (int npart=0;npart<NUM_MIDI_PARTS;npart++) {
//if (nefx==0) setPsysefxvol(npart,nefx,64);
//else
setPsysefxvol(npart,nefx,0);
};
for (int nefxto=0;nefxto<NUM_SYS_EFX;nefxto++)
setPsysefxsend(nefx,nefxto,0);
};
// sysefx[0]->changeeffect(1);
microtonal.defaults();
ShutUp();
};
/*
* Note On Messages (velocity=0 for NoteOff)
*/
void Master::NoteOn(unsigned char chan,unsigned char note,unsigned char velocity)
{
dump.dumpnote(chan,note,velocity);
noteon(chan,note,velocity);
};
/*
* Internal Note On (velocity=0 for NoteOff)
*/
void Master::noteon(unsigned char chan,unsigned char note,unsigned char velocity)
{
int npart;
if (velocity!=0) {
for (npart=0;npart<NUM_MIDI_PARTS;npart++) {
if (chan==part[npart]->Prcvchn) {
fakepeakpart[npart]=velocity*2;
if (part[npart]->Penabled!=0) part[npart]->NoteOn(note,velocity,keyshift);
};
};
} else {
this->NoteOff(chan,note);
};
HDDRecorder.triggernow();
};
/*
* Note Off Messages
*/
void Master::NoteOff(unsigned char chan,unsigned char note)
{
dump.dumpnote(chan,note,0);
noteoff(chan,note);
};
/*
* Internal Note Off
*/
void Master::noteoff(unsigned char chan,unsigned char note)
{
int npart;
for (npart=0;npart<NUM_MIDI_PARTS;npart++) {
if ((chan==part[npart]->Prcvchn) && (part[npart]->Penabled!=0))
part[npart]->NoteOff(note);
};
};
/*
* Controllers
*/
void Master::SetController(unsigned char chan,unsigned int type,int par)
{
dump.dumpcontroller(chan,type,par);
setcontroller(chan,type,par);
};
/*
* Internal Controllers
*/
void Master::setcontroller(unsigned char chan,unsigned int type,int par)
{
if ((type==C_dataentryhi)||(type==C_dataentrylo)||
(type==C_nrpnhi)||(type==C_nrpnlo)) {//Process RPN and NRPN by the Master (ignore the chan)
ctl.setparameternumber(type,par);
int parhi=-1,parlo=-1,valhi=-1,vallo=-1;
if (ctl.getnrpn(&parhi,&parlo,&valhi,&vallo)==0) {//this is NRPN
//fprintf(stderr,"rcv. NRPN: %d %d %d %d\n",parhi,parlo,valhi,vallo);
switch (parhi) {
case 0x04://System Effects
if (parlo<NUM_SYS_EFX) {
sysefx[parlo]->seteffectpar_nolock(valhi,vallo);
};
break;
case 0x08://Insertion Effects
if (parlo<NUM_INS_EFX) {
insefx[parlo]->seteffectpar_nolock(valhi,vallo);
};
break;
};
};
} else {//other controllers
for (int npart=0;npart<NUM_MIDI_PARTS;npart++) {//Send the controller to all part assigned to the channel
if ((chan==part[npart]->Prcvchn) && (part[npart]->Penabled!=0))
part[npart]->SetController(type,par);
};
if (type==C_allsoundsoff) { //cleanup insertion/system FX
for (int nefx=0;nefx<NUM_SYS_EFX;++nefx) {
sysefx[nefx]->cleanup();
}
for (int nefx=0;nefx<NUM_INS_EFX;++nefx) {
insefx[nefx]->cleanup();
}
}
};
};
/*
* Enable/Disable a part
*/
void Master::partonoff(int npart,int what)
{
if (npart>=NUM_MIDI_PARTS) return;
if (what==0) {//disable part
fakepeakpart[npart]=0;
part[npart]->Penabled=0;
part[npart]->cleanup();
for (int nefx=0;nefx<NUM_INS_EFX;nefx++) {
if (Pinsparts[nefx]==npart) {
insefx[nefx]->cleanup();
};
};
} else {//enabled
part[npart]->Penabled=1;
fakepeakpart[npart]=0;
};
};
/*
* Master audio out (the final sound)
*/
void Master::AudioOut(REALTYPE *outl,REALTYPE *outr)
{
int i,npart,nefx;
/* //test!!!!!!!!!!!!! se poate bloca aici (mutex)
if (seq.play){
int type,par1,par2,again,midichan;
int ntrack=1;
// do{
again=seq.getevent(ntrack,&midichan,&type,&par1,&par2);
if (type>0) {
// printf("aaa\n");
if (type==1){//note_on or note_off
if (par2!=0) NoteOn(midichan,par1,par2);
else NoteOff(midichan,par1);
};
};
// } while (again);
};
*/
// printf("zzzz\n");
//Swaps the Left channel with Right Channel (if it is asked for)
if (swaplr!=0) {
REALTYPE *tmp=outl;
outl=outr;
outr=tmp;
};
//clean up the output samples
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
outl[i]=0.0;
outr[i]=0.0;
};
//Compute part samples and store them part[npart]->partoutl,partoutr
for (npart=0;npart<NUM_MIDI_PARTS;npart++)
if (part[npart]->Penabled!=0) part[npart]->ComputePartSmps();
//Insertion effects
for (nefx=0;nefx<NUM_INS_EFX;nefx++) {
if (Pinsparts[nefx]>=0) {
int efxpart=Pinsparts[nefx];
if (part[efxpart]->Penabled!=0)
insefx[nefx]->out(part[efxpart]->partoutl,part[efxpart]->partoutr);
};
};
//Apply the part volumes and pannings (after insertion effects)
for (npart=0;npart<NUM_MIDI_PARTS;npart++) {
if (part[npart]->Penabled==0) continue;
REALTYPE newvol_l=part[npart]->volume;
REALTYPE newvol_r=part[npart]->volume;
REALTYPE oldvol_l=part[npart]->oldvolumel;
REALTYPE oldvol_r=part[npart]->oldvolumer;
REALTYPE pan=part[npart]->panning;
if (pan<0.5) newvol_l*=pan*2.0;
else newvol_r*=(1.0-pan)*2.0;
if (ABOVE_AMPLITUDE_THRESHOLD(oldvol_l,newvol_l)||
ABOVE_AMPLITUDE_THRESHOLD(oldvol_r,newvol_r)) {//the volume or the panning has changed and needs interpolation
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
REALTYPE vol_l=INTERPOLATE_AMPLITUDE(oldvol_l,newvol_l,i,SOUND_BUFFER_SIZE);
REALTYPE vol_r=INTERPOLATE_AMPLITUDE(oldvol_r,newvol_r,i,SOUND_BUFFER_SIZE);
part[npart]->partoutl[i]*=vol_l;
part[npart]->partoutr[i]*=vol_r;
};
part[npart]->oldvolumel=newvol_l;
part[npart]->oldvolumer=newvol_r;
} else {
for (i=0;i<SOUND_BUFFER_SIZE;i++) {//the volume did not changed
part[npart]->partoutl[i]*=newvol_l;
part[npart]->partoutr[i]*=newvol_r;
};
};
};
//System effects
for (nefx=0;nefx<NUM_SYS_EFX;nefx++) {
if (sysefx[nefx]->geteffect()==0) continue;//the effect is disabled
//Clean up the samples used by the system effects
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
tmpmixl[i]=0.0;
tmpmixr[i]=0.0;
};
//Mix the channels according to the part settings about System Effect
for (npart=0;npart<NUM_MIDI_PARTS;npart++) {
//skip if the part has no output to effect
if (Psysefxvol[nefx][npart]==0) continue;
//skip if the part is disabled
if (part[npart]->Penabled==0) continue;
//the output volume of each part to system effect
REALTYPE vol=sysefxvol[nefx][npart];
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
tmpmixl[i]+=part[npart]->partoutl[i]*vol;
tmpmixr[i]+=part[npart]->partoutr[i]*vol;
};
};
// system effect send to next ones
for (int nefxfrom=0;nefxfrom<nefx;nefxfrom++) {
if (Psysefxsend[nefxfrom][nefx]!=0) {
REALTYPE v=sysefxsend[nefxfrom][nefx];
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
tmpmixl[i]+=sysefx[nefxfrom]->efxoutl[i]*v;
tmpmixr[i]+=sysefx[nefxfrom]->efxoutr[i]*v;
};
};
};
sysefx[nefx]->out(tmpmixl,tmpmixr);
//Add the System Effect to sound output
REALTYPE outvol=sysefx[nefx]->sysefxgetvolume();
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
outl[i]+=tmpmixl[i]*outvol;
outr[i]+=tmpmixr[i]*outvol;
};
};
//Mix all parts
for (npart=0;npart<NUM_MIDI_PARTS;npart++) {
for (i=0;i<SOUND_BUFFER_SIZE;i++) {//the volume did not changed
outl[i]+=part[npart]->partoutl[i];
outr[i]+=part[npart]->partoutr[i];
};
};
//Insertion effects for Master Out
for (nefx=0;nefx<NUM_INS_EFX;nefx++) {
if (Pinsparts[nefx] == -2)
insefx[nefx]->out(outl,outr);
};
//Master Volume
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
outl[i]*=volume;
outr[i]*=volume;
};
//Peak computation (for vumeters)
vuoutpeakl=1e-12;
vuoutpeakr=1e-12;
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
if (fabs(outl[i])>vuoutpeakl) vuoutpeakl=fabs(outl[i]);
if (fabs(outr[i])>vuoutpeakr) vuoutpeakr=fabs(outr[i]);
};
if ((vuoutpeakl>1.0)||(vuoutpeakr>1.0)) vuclipped=1;
if (vumaxoutpeakl<vuoutpeakl) vumaxoutpeakl=vuoutpeakl;
if (vumaxoutpeakr<vuoutpeakr) vumaxoutpeakr=vuoutpeakr;
//RMS Peak computation (for vumeters)
vurmspeakl=1e-12;
vurmspeakr=1e-12;
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
vurmspeakl+=outl[i]*outl[i];
vurmspeakr+=outr[i]*outr[i];
};
vurmspeakl=sqrt(vurmspeakl/SOUND_BUFFER_SIZE);
vurmspeakr=sqrt(vurmspeakr/SOUND_BUFFER_SIZE);
//Part Peak computation (for Part vumeters or fake part vumeters)
for (npart=0;npart<NUM_MIDI_PARTS;npart++) {
vuoutpeakpart[npart]=1.0e-12;
if (part[npart]->Penabled!=0) {
REALTYPE *outl=part[npart]->partoutl,
*outr=part[npart]->partoutr;
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
REALTYPE tmp=fabs(outl[i]+outr[i]);
if (tmp>vuoutpeakpart[npart]) vuoutpeakpart[npart]=tmp;
};
vuoutpeakpart[npart]*=volume;
} else {
if (fakepeakpart[npart]>1) fakepeakpart[npart]--;
};
};
//Shutup if it is asked (with fade-out)
if (shutup!=0) {
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
REALTYPE tmp=(SOUND_BUFFER_SIZE-i)/(REALTYPE) SOUND_BUFFER_SIZE;
outl[i]*=tmp;
outr[i]*=tmp;
};
ShutUp();
};
//update the LFO's time
LFOParams::time++;
if (HDDRecorder.recording()) HDDRecorder.recordbuffer(outl,outr);
dump.inctick();
};
void Master::GetAudioOutSamples(int nsamples,int samplerate,REALTYPE *outl,REALTYPE *outr)
{
if (ksoundbuffersample==-1) {//first time
AudioOut(&audiooutl[0],&audiooutr[0]);
ksoundbuffersample=0;
};
if (samplerate==SAMPLE_RATE) {//no resample
int ksample=0;
while (ksample<nsamples) {
outl[ksample]=audiooutl[ksoundbuffersample];
outr[ksample]=audiooutr[ksoundbuffersample];
ksample++;
ksoundbuffersample++;
if (ksoundbuffersample>=SOUND_BUFFER_SIZE) {
AudioOut(&audiooutl[0],&audiooutr[0]);
ksoundbuffersample=0;
};
};
} else {//Resample
int ksample=0;
REALTYPE srinc=SAMPLE_RATE/(REALTYPE)samplerate;
while (ksample<nsamples) {
if (ksoundbuffersample!=0) {
outl[ksample]=audiooutl[ksoundbuffersample]*ksoundbuffersamplelow
+audiooutl[ksoundbuffersample-1]*(1.0-ksoundbuffersamplelow);
outr[ksample]=audiooutr[ksoundbuffersample]*ksoundbuffersamplelow
+audiooutr[ksoundbuffersample-1]*(1.0-ksoundbuffersamplelow);
} else {
outl[ksample]=audiooutl[ksoundbuffersample]*ksoundbuffersamplelow
+oldsamplel*(1.0-ksoundbuffersamplelow);
outr[ksample]=audiooutr[ksoundbuffersample]*ksoundbuffersamplelow
+oldsampler*(1.0-ksoundbuffersamplelow);
};
ksample++;
ksoundbuffersamplelow+=srinc;
if (ksoundbuffersamplelow>=1.0) {
ksoundbuffersample+=(int) floor(ksoundbuffersamplelow);
ksoundbuffersamplelow=ksoundbuffersamplelow-floor(ksoundbuffersamplelow);
};
if (ksoundbuffersample>=SOUND_BUFFER_SIZE) {
oldsamplel=audiooutl[SOUND_BUFFER_SIZE-1];
oldsampler=audiooutr[SOUND_BUFFER_SIZE-1];
AudioOut(&audiooutl[0],&audiooutr[0]);
ksoundbuffersample=0;
};
};
};
};
Master::~Master()
{
for (int npart=0;npart<NUM_MIDI_PARTS;npart++) delete part[npart];
for (int nefx=0;nefx<NUM_INS_EFX;nefx++) delete insefx[nefx];
for (int nefx=0;nefx<NUM_SYS_EFX;nefx++) delete sysefx[nefx];
delete [] audiooutl;
delete [] audiooutr;
delete [] tmpmixl;
delete [] tmpmixr;
delete (fft);
pthread_mutex_destroy(&mutex);
};
/*
* Parameter control
*/
void Master::setPvolume(char Pvolume_)
{
Pvolume=Pvolume_;
volume=dB2rap((Pvolume-96.0)/96.0*40.0);
};
void Master::setPkeyshift(char Pkeyshift_)
{
Pkeyshift=Pkeyshift_;
keyshift=(int)Pkeyshift-64;
};
void Master::setPsysefxvol(int Ppart,int Pefx,char Pvol)
{
Psysefxvol[Pefx][Ppart]=Pvol;
sysefxvol[Pefx][Ppart]=pow(0.1,(1.0-Pvol/96.0)*2.0);
};
void Master::setPsysefxsend(int Pefxfrom,int Pefxto,char Pvol)
{
Psysefxsend[Pefxfrom][Pefxto]=Pvol;
sysefxsend[Pefxfrom][Pefxto]=pow(0.1,(1.0-Pvol/96.0)*2.0);
};
/*
* Panic! (Clean up all parts and effects)
*/
void Master::ShutUp()
{
for (int npart=0;npart<NUM_MIDI_PARTS;npart++) {
part[npart]->cleanup();
fakepeakpart[npart]=0;
};
for (int nefx=0;nefx<NUM_INS_EFX;nefx++) insefx[nefx]->cleanup();
for (int nefx=0;nefx<NUM_SYS_EFX;nefx++) sysefx[nefx]->cleanup();
vuresetpeaks();
shutup=0;
};
/*
* Reset peaks and clear the "cliped" flag (for VU-meter)
*/
void Master::vuresetpeaks()
{
vuoutpeakl=1e-9;
vuoutpeakr=1e-9;
vumaxoutpeakl=1e-9;
vumaxoutpeakr=1e-9;
vuclipped=0;
};
void Master::applyparameters()
{
for (int npart=0;npart<NUM_MIDI_PARTS;npart++) {
part[npart]->applyparameters();
};
};
void Master::add2XML(XMLwrapper *xml)
{
xml->addpar("volume",Pvolume);
xml->addpar("key_shift",Pkeyshift);
xml->addparbool("nrpn_receive",ctl.NRPN.receive);
xml->beginbranch("MICROTONAL");
microtonal.add2XML(xml);
xml->endbranch();
for (int npart=0;npart<NUM_MIDI_PARTS;npart++) {
xml->beginbranch("PART",npart);
part[npart]->add2XML(xml);
xml->endbranch();
};
xml->beginbranch("SYSTEM_EFFECTS");
for (int nefx=0;nefx<NUM_SYS_EFX;nefx++) {
xml->beginbranch("SYSTEM_EFFECT",nefx);
xml->beginbranch("EFFECT");
sysefx[nefx]->add2XML(xml);
xml->endbranch();
for (int pefx=0;pefx<NUM_MIDI_PARTS;pefx++) {
xml->beginbranch("VOLUME",pefx);
xml->addpar("vol",Psysefxvol[nefx][pefx]);
xml->endbranch();
};
for (int tonefx=nefx+1;tonefx<NUM_SYS_EFX;tonefx++) {
xml->beginbranch("SENDTO",tonefx);
xml->addpar("send_vol",Psysefxsend[nefx][tonefx]);
xml->endbranch();
};
xml->endbranch();
};
xml->endbranch();
xml->beginbranch("INSERTION_EFFECTS");
for (int nefx=0;nefx<NUM_INS_EFX;nefx++) {
xml->beginbranch("INSERTION_EFFECT",nefx);
xml->addpar("part",Pinsparts[nefx]);
xml->beginbranch("EFFECT");
insefx[nefx]->add2XML(xml);
xml->endbranch();
xml->endbranch();
};
xml->endbranch();
};
int Master::getalldata(char **data)
{
XMLwrapper *xml=new XMLwrapper();
xml->beginbranch("MASTER");
pthread_mutex_lock(&mutex);
add2XML(xml);
pthread_mutex_unlock(&mutex);
xml->endbranch();
*data=xml->getXMLdata();
delete (xml);
return(strlen(*data)+1);
};
void Master::putalldata(char *data,int size)
{
XMLwrapper *xml=new XMLwrapper();
if (!xml->putXMLdata(data)) {
delete(xml);
return;
};
if (xml->enterbranch("MASTER")==0) return;
pthread_mutex_lock(&mutex);
getfromXML(xml);
pthread_mutex_unlock(&mutex);
xml->exitbranch();
delete(xml);
};
int Master::saveXML(const char *filename)
{
XMLwrapper *xml=new XMLwrapper();
xml->beginbranch("MASTER");
add2XML(xml);
xml->endbranch();
int result=xml->saveXMLfile(filename);
delete (xml);
return(result);
};
int Master::loadXML(const char *filename)
{
XMLwrapper *xml=new XMLwrapper();
if (xml->loadXMLfile(filename)<0) {
delete(xml);
return(-1);
};
if (xml->enterbranch("MASTER")==0) return(-10);
getfromXML(xml);
xml->exitbranch();
delete(xml);
return(0);
};
void Master::getfromXML(XMLwrapper *xml)
{
setPvolume(xml->getpar127("volume",Pvolume));
setPkeyshift(xml->getpar127("key_shift",Pkeyshift));
ctl.NRPN.receive=xml->getparbool("nrpn_receive",ctl.NRPN.receive);
part[0]->Penabled=0;
for (int npart=0;npart<NUM_MIDI_PARTS;npart++) {
if (xml->enterbranch("PART",npart)==0) continue;
part[npart]->getfromXML(xml);
xml->exitbranch();
};
if (xml->enterbranch("MICROTONAL")) {
microtonal.getfromXML(xml);
xml->exitbranch();
};
sysefx[0]->changeeffect(0);
if (xml->enterbranch("SYSTEM_EFFECTS")) {
for (int nefx=0;nefx<NUM_SYS_EFX;nefx++) {
if (xml->enterbranch("SYSTEM_EFFECT",nefx)==0) continue;
if (xml->enterbranch("EFFECT")) {
sysefx[nefx]->getfromXML(xml);
xml->exitbranch();
};
for (int partefx=0;partefx<NUM_MIDI_PARTS;partefx++) {
if (xml->enterbranch("VOLUME",partefx)==0) continue;
setPsysefxvol(partefx,nefx,xml->getpar127("vol",Psysefxvol[partefx][nefx]));
xml->exitbranch();
};
for (int tonefx=nefx+1;tonefx<NUM_SYS_EFX;tonefx++) {
if (xml->enterbranch("SENDTO",tonefx)==0) continue;
setPsysefxsend(nefx,tonefx,xml->getpar127("send_vol",Psysefxsend[nefx][tonefx]));
xml->exitbranch();
};
xml->exitbranch();
};
xml->exitbranch();
};
if (xml->enterbranch("INSERTION_EFFECTS")) {
for (int nefx=0;nefx<NUM_INS_EFX;nefx++) {
if (xml->enterbranch("INSERTION_EFFECT",nefx)==0) continue;
Pinsparts[nefx]=xml->getpar("part",Pinsparts[nefx],-2,NUM_MIDI_PARTS);
if (xml->enterbranch("EFFECT")) {
insefx[nefx]->getfromXML(xml);
xml->exitbranch();
};
xml->exitbranch();
};
xml->exitbranch();
};
};

View File

@@ -1,13 +1,13 @@
/*
ZynAddSubFX - a software synthesizer
Master.h - It sends Midi Messages to Parts, receives samples from parts,
process them with system/insertion effects and mix them
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
@@ -36,127 +36,132 @@
#include "XMLwrapper.h"
extern Dump dump;
class Master{
public:
Master();
~Master();
/** It sends Midi Messages to Parts, receives samples from parts,
* process them with system/insertion effects and mix them */
class Master
{
public:
/** Constructor*/
Master();
/** Destructor*/
~Master();
//saves all settings to a XML file
//returns 0 for ok or <0 if there is an error
int saveXML(char *filename);
/**Saves all settings to a XML file
* @return 0 for ok or <0 if there is an error*/
int saveXML(const char *filename);
//this adds the parameters to the XML data
void add2XML(XMLwrapper *xml);
/**This adds the parameters to the XML data*/
void add2XML(XMLwrapper *xml);
void defaults();
void defaults();
//loads all settings from a XML file
//returns 0 for ok or -1 if there is an error
int loadXML(char *filename);
void applyparameters();
/**loads all settings from a XML file
* @return 0 for ok or -1 if there is an error*/
int loadXML(const char *filename);
void applyparameters();
void getfromXML(XMLwrapper *xml);
//get all data to a newly allocated array (used for VST)
//returns the datasize
int getalldata(char **data);
//put all data from the *data array to zynaddsubfx parameters (used for VST)
void putalldata(char *data,int size);
void getfromXML(XMLwrapper *xml);
/**get all data to a newly allocated array (used for VST)
* @return the datasize*/
int getalldata(char **data);
/**put all data from the *data array to zynaddsubfx parameters (used for VST)*/
void putalldata(char *data,int size);
//Midi IN
void NoteOn(unsigned char chan,unsigned char note,unsigned char velocity);
void NoteOff(unsigned char chan,unsigned char note);
void SetController(unsigned char chan,unsigned int type,int par);
//void NRPN...
void ShutUp();
int shutup;
//Audio Output
void AudioOut(REALTYPE *outl,REALTYPE *outr);
//Audio Output (for callback mode). This allows the program to be controled by an external program
void GetAudioOutSamples(int nsamples,int samplerate,REALTYPE *outl,REALTYPE *outr);
//Midi IN
void NoteOn(unsigned char chan,unsigned char note,unsigned char velocity);
void NoteOff(unsigned char chan,unsigned char note);
void SetController(unsigned char chan,unsigned int type,int par);
//void NRPN...
void partonoff(int npart,int what);
//parts
Part *part[NUM_MIDI_PARTS];
//parameters
unsigned char Pvolume;
unsigned char Pkeyshift;
unsigned char Psysefxvol[NUM_SYS_EFX][NUM_MIDI_PARTS];
unsigned char Psysefxsend[NUM_SYS_EFX][NUM_SYS_EFX];
//parameters control
void setPvolume(char Pvolume_);
void setPkeyshift(char Pkeyshift_);
void setPsysefxvol(int Ppart,int Pefx,char Pvol);
void setPsysefxsend(int Pefxfrom,int Pefxto,char Pvol);
void ShutUp();
int shutup;
//effects
EffectMgr *sysefx[NUM_SYS_EFX];//system
EffectMgr *insefx[NUM_INS_EFX];//insertion
/**Audio Output*/
void AudioOut(REALTYPE *outl,REALTYPE *outr);
/**Audio Output (for callback mode). This allows the program to be controled by an external program*/
void GetAudioOutSamples(int nsamples,int samplerate,REALTYPE *outl,REALTYPE *outr);
void partonoff(int npart,int what);
/**parts \todo see if this can be made to be dynamic*/
Part *part[NUM_MIDI_PARTS];
//parameters
unsigned char Pvolume;
unsigned char Pkeyshift;
unsigned char Psysefxvol[NUM_SYS_EFX][NUM_MIDI_PARTS];
unsigned char Psysefxsend[NUM_SYS_EFX][NUM_SYS_EFX];
//parameters control
void setPvolume(char Pvolume_);
void setPkeyshift(char Pkeyshift_);
void setPsysefxvol(int Ppart,int Pefx,char Pvol);
void setPsysefxsend(int Pefxfrom,int Pefxto,char Pvol);
//effects
EffectMgr *sysefx[NUM_SYS_EFX];//system
EffectMgr *insefx[NUM_INS_EFX];//insertion
// void swapcopyeffects(int what,int type,int neff1,int neff2);
//HDD recorder
Recorder HDDRecorder;
//HDD recorder
Recorder HDDRecorder;
//part that's apply the insertion effect; -1 to disable
short int Pinsparts[NUM_INS_EFX];
//peaks for VU-meter
void vuresetpeaks();
REALTYPE vuoutpeakl,vuoutpeakr,vumaxoutpeakl,vumaxoutpeakr,vurmspeakl,vurmspeakr;
int vuclipped;
//peaks for part VU-meters
REALTYPE vuoutpeakpart[NUM_MIDI_PARTS];
unsigned char fakepeakpart[NUM_MIDI_PARTS];//this is used to compute the "peak" when the part is disabled
//part that's apply the insertion effect; -1 to disable
short int Pinsparts[NUM_INS_EFX];
Controller ctl;
int swaplr;//1 if L and R are swapped
//peaks for VU-meter
void vuresetpeaks();
REALTYPE vuoutpeakl,vuoutpeakr,vumaxoutpeakl,vumaxoutpeakr,vurmspeakl,vurmspeakr;
int vuclipped;
//Sequencer
Sequencer seq;
//other objects
Microtonal microtonal;
Bank bank;
FFTwrapper *fft;
pthread_mutex_t mutex;
//peaks for part VU-meters
REALTYPE vuoutpeakpart[NUM_MIDI_PARTS];
unsigned char fakepeakpart[NUM_MIDI_PARTS];//this is used to compute the "peak" when the part is disabled
private:
REALTYPE volume;
REALTYPE sysefxvol[NUM_SYS_EFX][NUM_MIDI_PARTS];
REALTYPE sysefxsend[NUM_SYS_EFX][NUM_SYS_EFX];
Controller ctl;
int swaplr;//1 if L and R are swapped
//Temporary mixing samples for part samples which is sent to system effect
REALTYPE *tmpmixl;
REALTYPE *tmpmixr;
//Sequencer
Sequencer seq;
//other objects
Microtonal microtonal;
Bank bank;
FFTwrapper *fft;
pthread_mutex_t mutex;
private:
REALTYPE volume;
REALTYPE sysefxvol[NUM_SYS_EFX][NUM_MIDI_PARTS];
REALTYPE sysefxsend[NUM_SYS_EFX][NUM_SYS_EFX];
//Temporary mixing samples for part samples which is sent to system effect
REALTYPE *tmpmixl;
REALTYPE *tmpmixr;
int keyshift;
int keyshift;
//Audio Output samples (if it used GetAudioOutSamples - eg. for Jack output; elsewhere is unused)
REALTYPE *audiooutl;
REALTYPE *audiooutr;
int ksoundbuffersample;//this is used to know if there is need to call AudioOut by GetAudioOutSamples method
REALTYPE ksoundbuffersamplelow;//this is used for resampling (eg. if Jack samplerate!= SAMPLE_RATE)
REALTYPE oldsamplel,oldsampler;//this is used for resampling
//Audio Output samples (if it used GetAudioOutSamples - eg. for Jack output; elsewhere is unused)
REALTYPE *audiooutl;
REALTYPE *audiooutr;
//Theese are called by the NoteOn, NoteOff,SetController (which are from external sources like MIDI, Virtual Keyboard)
//and are called by internal parts of the program (like sequencer)
void noteon(unsigned char chan,unsigned char note,unsigned char velocity);
void noteoff(unsigned char chan,unsigned char note);
void setcontroller(unsigned char chan,unsigned int type,int par);
int ksoundbuffersample;//this is used to know if there is need to call AudioOut by GetAudioOutSamples method
REALTYPE ksoundbuffersamplelow;//this is used for resampling (eg. if Jack samplerate!= SAMPLE_RATE)
REALTYPE oldsamplel,oldsampler;//this is used for resampling
//These are called by the NoteOn, NoteOff,SetController (which are from external sources like MIDI, Virtual Keyboard)
//and are called by internal parts of the program (like sequencer)
void noteon(unsigned char chan,unsigned char note,unsigned char velocity);
void noteoff(unsigned char chan,unsigned char note);
void setcontroller(unsigned char chan,unsigned int type,int par);
};

View File

@@ -1,514 +0,0 @@
/*
ZynAddSubFX - a software synthesizer
Microtonal.C - Tuning settings and microtonal capabilities
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <math.h>
#include <string.h>
#include "Microtonal.h"
#define MAX_LINE_SIZE 80
Microtonal::Microtonal(){
Pname=new unsigned char[MICROTONAL_MAX_NAME_LEN];
Pcomment=new unsigned char[MICROTONAL_MAX_NAME_LEN];
defaults();
};
void Microtonal::defaults(){
Pinvertupdown=0;
Pinvertupdowncenter=60;
octavesize=12;
Penabled=0;
PAnote=69;
PAfreq=440.0;
Pscaleshift=64;
Pfirstkey=0;Plastkey=127;
Pmiddlenote=60;Pmapsize=12;
Pmappingenabled=0;
for (int i=0;i<128;i++) Pmapping[i]=i;
for (int i=0;i<MAX_OCTAVE_SIZE;i++){
octave[i].tuning=tmpoctave[i].tuning=pow(2,(i%octavesize+1)/12.0);
octave[i].type=tmpoctave[i].type=1;
octave[i].x1=tmpoctave[i].x1=(i%octavesize+1)*100;
octave[i].x2=tmpoctave[i].x2=0;
};
octave[11].type=2;octave[11].x1=2;octave[11].x2=1;
for (int i=0;i<MICROTONAL_MAX_NAME_LEN;i++){
Pname[i]='\0';
Pcomment[i]='\0';
};
snprintf((char *) Pname,MICROTONAL_MAX_NAME_LEN,"12tET");
snprintf((char *) Pcomment,MICROTONAL_MAX_NAME_LEN,"Equal Temperament 12 notes per octave");
Pglobalfinedetune=64;
};
Microtonal::~Microtonal(){
delete [] Pname;
delete [] Pcomment;
};
/*
* Get the size of the octave
*/
unsigned char Microtonal::getoctavesize(){
if (Penabled!=0) return(octavesize);
else return(12);
};
/*
* Get the frequency according the note number
*/
REALTYPE Microtonal::getnotefreq(int note,int keyshift){
// in this function will appears many times things like this:
// var=(a+b*100)%b
// I had written this way because if I use var=a%b gives unwanted results when a<0
// This is the same with divisions.
if ((Pinvertupdown!=0)&&((Pmappingenabled==0)||(Penabled==0))) note=(int) Pinvertupdowncenter*2-note;
//compute global fine detune
REALTYPE globalfinedetunerap=pow(2.0,(Pglobalfinedetune-64.0)/1200.0);//-64.0 .. 63.0 cents
if (Penabled==0) return(pow(2.0,(note-PAnote+keyshift)/12.0)*PAfreq*globalfinedetunerap);//12tET
int scaleshift=((int)Pscaleshift-64+(int) octavesize*100)%octavesize;
//compute the keyshift
REALTYPE rap_keyshift=1.0;
if (keyshift!=0){
int kskey=(keyshift+(int)octavesize*100)%octavesize;
int ksoct=(keyshift+(int)octavesize*100)/octavesize-100;
rap_keyshift=(kskey==0) ? (1.0):(octave[kskey-1].tuning);
rap_keyshift*=pow(octave[octavesize-1].tuning,ksoct);
};
//if the mapping is enabled
if (Pmappingenabled!=0){
if ((note<Pfirstkey)||(note>Plastkey)) return (-1.0);
//Compute how many mapped keys are from middle note to reference note
//and find out the proportion between the freq. of middle note and "A" note
int tmp=PAnote-Pmiddlenote,minus=0;
if (tmp<0) { tmp=-tmp; minus=1; };
int deltanote=0;
for (int i=0;i<tmp;i++) if (Pmapping[i%Pmapsize]>=0) deltanote++;
REALTYPE rap_anote_middlenote=(deltanote==0) ? (1.0) : (octave[(deltanote-1)%octavesize].tuning);
if (deltanote!=0) rap_anote_middlenote*=pow(octave[octavesize-1].tuning,(deltanote-1)/octavesize);
if (minus!=0) rap_anote_middlenote=1.0/rap_anote_middlenote;
//Convert from note (midi) to degree (note from the tunning)
int degoct=(note-(int)Pmiddlenote+(int) Pmapsize*200)/(int)Pmapsize-200;
int degkey=(note-Pmiddlenote+(int)Pmapsize*100)%Pmapsize;
degkey=Pmapping[degkey];
if (degkey<0) return(-1.0);//this key is not mapped
//invert the keyboard upside-down if it is asked for
//TODO: do the right way by using Pinvertupdowncenter
if (Pinvertupdown!=0){
degkey=octavesize-degkey-1;
degoct=-degoct;
};
//compute the frequency of the note
degkey=degkey+scaleshift;
degoct+=degkey/octavesize;
degkey%=octavesize;
REALTYPE freq=(degkey==0) ? (1.0):octave[degkey-1].tuning;
freq*=pow(octave[octavesize-1].tuning,degoct);
freq*=PAfreq/rap_anote_middlenote;
freq*=globalfinedetunerap;
if (scaleshift!=0) freq/=octave[scaleshift-1].tuning;
return(freq*rap_keyshift);
} else {//if the mapping is disabled
int nt=note-PAnote+scaleshift;
int ntkey=(nt+(int)octavesize*100)%octavesize;
int ntoct=(nt-ntkey)/octavesize;
REALTYPE oct=octave[octavesize-1].tuning;
REALTYPE freq=octave[(ntkey+octavesize-1)%octavesize].tuning*pow(oct,ntoct)*PAfreq;
if (ntkey==0) freq/=oct;
if (scaleshift!=0) freq/=octave[scaleshift-1].tuning;
// fprintf(stderr,"note=%d freq=%.3f cents=%d\n",note,freq,(int)floor(log(freq/PAfreq)/log(2.0)*1200.0+0.5));
freq*=globalfinedetunerap;
return(freq*rap_keyshift);
};
};
/*
* Convert a line to tunings; returns -1 if it ok
*/
int Microtonal::linetotunings(unsigned int nline,const char *line){
int x1=-1,x2=-1,type=-1;
REALTYPE x=-1.0,tmp,tuning=1.0;
if (strstr(line,"/")==NULL){
if (strstr(line,".")==NULL){// M case (M=M/1)
sscanf(line,"%d",&x1);
x2=1;
type=2;//division
} else {// float number case
sscanf(line,"%f",&x);
if (x<0.000001) return(1);
type=1;//float type(cents)
};
} else {// M/N case
sscanf(line,"%d/%d",&x1,&x2);
if ((x1<0)||(x2<0)) return(1);
if (x2==0) x2=1;
type=2;//division
};
if (x1<=0) x1=1;//not allow zero frequency sounds (consider 0 as 1)
//convert to float if the number are too big
if ((type==2)&&((x1>(128*128*128-1))||(x2>(128*128*128-1)))){
type=1;
x=((REALTYPE) x1)/x2;
};
switch (type){
case 1: x1=(int) floor(x);
tmp=fmod(x,1.0);
x2=(int) (floor (tmp*1e6));
tuning=pow(2.0,x/1200.0);
break;
case 2: x=((REALTYPE)x1)/x2;
tuning=x;
break;
};
tmpoctave[nline].tuning=tuning;
tmpoctave[nline].type=type;
tmpoctave[nline].x1=x1;
tmpoctave[nline].x2=x2;
return(-1);//ok
};
/*
* Convert the text to tunnings
*/
int Microtonal::texttotunings(const char *text){
unsigned int i,k=0,nl=0;
char *lin;
lin=new char[MAX_LINE_SIZE+1];
while (k<strlen(text)){
for (i=0;i<MAX_LINE_SIZE;i++){
lin[i]=text[k++];
if (lin[i]<0x20) break;
};
lin[i]='\0';
if (strlen(lin)==0) continue;
int err=linetotunings(nl,lin);
if (err!=-1) {
delete [] lin;
return(nl);//Parse error
};
nl++;
};
delete [] lin;
if (nl>MAX_OCTAVE_SIZE) nl=MAX_OCTAVE_SIZE;
if (nl==0) return(-2);//the input is empty
octavesize=nl;
for (i=0;i<octavesize;i++){
octave[i].tuning=tmpoctave[i].tuning;
octave[i].type=tmpoctave[i].type;
octave[i].x1=tmpoctave[i].x1;
octave[i].x2=tmpoctave[i].x2;
};
return(-1);//ok
};
/*
* Convert the text to mapping
*/
void Microtonal::texttomapping(const char *text){
unsigned int i,k=0;
char *lin;
lin=new char[MAX_LINE_SIZE+1];
for (i=0;i<128;i++) Pmapping[i]=-1;
int tx=0;
while (k<strlen(text)){
for (i=0;i<MAX_LINE_SIZE;i++){
lin[i]=text[k++];
if (lin[i]<0x20) break;
};
lin[i]='\0';
if (strlen(lin)==0) continue;
int tmp=0;
if (sscanf(lin,"%d",&tmp)==0) tmp=-1;
if (tmp<-1) tmp=-1;
Pmapping[tx]=tmp;
if ((tx++)>127) break;
};
delete [] lin;
if (tx==0) tx=1;
Pmapsize=tx;
};
/*
* Convert tunning to text line
*/
void Microtonal::tuningtoline(int n,char *line,int maxn){
if ((n>octavesize) || (n>MAX_OCTAVE_SIZE)) {
line[0]='\0';
return;
};
if (octave[n].type==1) snprintf(line,maxn,"%d.%d",octave[n].x1,octave[n].x2);
if (octave[n].type==2) snprintf(line,maxn,"%d/%d",octave[n].x1,octave[n].x2);
};
int Microtonal::loadline(FILE *file,char *line){
do {
if (fgets(line,500,file)==0) return(1);
} while (line[0]=='!');
return(0);
};
/*
* Loads the tunnings from a scl file
*/
int Microtonal::loadscl(const char *filename){
FILE *file=fopen(filename, "r");
char tmp[500];
fseek(file,0,SEEK_SET);
//loads the short description
if (loadline(file,&tmp[0])!=0) return(2);
for (int i=0;i<500;i++) if (tmp[i]<32) tmp[i]=0;
snprintf((char *) Pname,MICROTONAL_MAX_NAME_LEN,"%s",tmp);
snprintf((char *) Pcomment,MICROTONAL_MAX_NAME_LEN,"%s",tmp);
//loads the number of the notes
if (loadline(file,&tmp[0])!=0) return(2);
int nnotes=MAX_OCTAVE_SIZE;
sscanf(&tmp[0],"%d",&nnotes);
if (nnotes>MAX_OCTAVE_SIZE) return (2);
//load the tunnings
for (int nline=0;nline<nnotes;nline++){
if (loadline(file,&tmp[0])!=0) return(2);
linetotunings(nline,&tmp[0]);
};
fclose(file);
octavesize=nnotes;
for (int i=0;i<octavesize;i++){
octave[i].tuning=tmpoctave[i].tuning;
octave[i].type=tmpoctave[i].type;
octave[i].x1=tmpoctave[i].x1;
octave[i].x2=tmpoctave[i].x2;
};
return(0);
};
/*
* Loads the mapping from a kbm file
*/
int Microtonal::loadkbm(const char *filename){
FILE *file=fopen(filename, "r");
int x;
char tmp[500];
fseek(file,0,SEEK_SET);
//loads the mapsize
if (loadline(file,&tmp[0])!=0) return(2);
if (sscanf(&tmp[0],"%d",&x)==0) return(2);
if (x<1) x=0;if (x>127) x=127;//just in case...
Pmapsize=x;
//loads first MIDI note to retune
if (loadline(file,&tmp[0])!=0) return(2);
if (sscanf(&tmp[0],"%d",&x)==0) return(2);
if (x<1) x=0;if (x>127) x=127;//just in case...
Pfirstkey=x;
//loads last MIDI note to retune
if (loadline(file,&tmp[0])!=0) return(2);
if (sscanf(&tmp[0],"%d",&x)==0) return(2);
if (x<1) x=0;if (x>127) x=127;//just in case...
Plastkey=x;
//loads last the middle note where scale fro scale degree=0
if (loadline(file,&tmp[0])!=0) return(2);
if (sscanf(&tmp[0],"%d",&x)==0) return(2);
if (x<1) x=0;if (x>127) x=127;//just in case...
Pmiddlenote=x;
//loads the reference note
if (loadline(file,&tmp[0])!=0) return(2);
if (sscanf(&tmp[0],"%d",&x)==0) return(2);
if (x<1) x=0;if (x>127) x=127;//just in case...
PAnote=x;
//loads the reference freq.
if (loadline(file,&tmp[0])!=0) return(2);
REALTYPE tmpPAfreq=440.0;
if (sscanf(&tmp[0],"%f",&tmpPAfreq)==0) return(2);
PAfreq=tmpPAfreq;
//the scale degree(which is the octave) is not loaded, it is obtained by the tunnings with getoctavesize() method
if (loadline(file,&tmp[0])!=0) return(2);
//load the mappings
if (Pmapsize!=0){
for (int nline=0;nline<Pmapsize;nline++){
if (loadline(file,&tmp[0])!=0) return(2);
if (sscanf(&tmp[0],"%d",&x)==0) x=-1;
Pmapping[nline]=x;
};
Pmappingenabled=1;
} else {
Pmappingenabled=0;
Pmapping[0]=0;
Pmapsize=1;
};
fclose(file);
return(0);
};
void Microtonal::add2XML(XMLwrapper *xml){
xml->addparstr("name",(char *) Pname);
xml->addparstr("comment",(char *) Pcomment);
xml->addparbool("invert_up_down",Pinvertupdown);
xml->addparbool("invert_up_down_center",Pinvertupdowncenter);
xml->addparbool("enabled",Penabled);
xml->addpar("global_fine_detune",Pglobalfinedetune);
xml->addpar("a_note",PAnote);
xml->addparreal("a_freq",PAfreq);
if ((Penabled==0)&&(xml->minimal)) return;
xml->beginbranch("SCALE");
xml->addpar("scale_shift",Pscaleshift);
xml->addpar("first_key",Pfirstkey);
xml->addpar("last_key",Plastkey);
xml->addpar("middle_note",Pmiddlenote);
xml->beginbranch("OCTAVE");
xml->addpar("octave_size",octavesize);
for (int i=0;i<octavesize;i++){
xml->beginbranch("DEGREE",i);
if (octave[i].type==1){
xml->addparreal("cents",octave[i].tuning);
};
if (octave[i].type==2){
xml->addpar("numerator",octave[i].x1);
xml->addpar("denominator",octave[i].x2);
};
xml->endbranch();
};
xml->endbranch();
xml->beginbranch("KEYBOARD_MAPPING");
xml->addpar("map_size",Pmapsize);
xml->addpar("mapping_enabled",Pmappingenabled);
for (int i=0;i<Pmapsize;i++){
xml->beginbranch("KEYMAP",i);
xml->addpar("degree",Pmapping[i]);
xml->endbranch();
};
xml->endbranch();
xml->endbranch();
};
void Microtonal::getfromXML(XMLwrapper *xml){
xml->getparstr("name",(char *) Pname,MICROTONAL_MAX_NAME_LEN);
xml->getparstr("comment",(char *) Pcomment,MICROTONAL_MAX_NAME_LEN);
Pinvertupdown=xml->getparbool("invert_up_down",Pinvertupdown);
Pinvertupdowncenter=xml->getparbool("invert_up_down_center",Pinvertupdowncenter);
Penabled=xml->getparbool("enabled",Penabled);
Pglobalfinedetune=xml->getpar127("global_fine_detune",Pglobalfinedetune);
PAnote=xml->getpar127("a_note",PAnote);
PAfreq=xml->getparreal("a_freq",PAfreq,1.0,10000.0);
if (xml->enterbranch("SCALE")){
Pscaleshift=xml->getpar127("scale_shift",Pscaleshift);
Pfirstkey=xml->getpar127("first_key",Pfirstkey);
Plastkey=xml->getpar127("last_key",Plastkey);
Pmiddlenote=xml->getpar127("middle_note",Pmiddlenote);
if (xml->enterbranch("OCTAVE")){
octavesize=xml->getpar127("octave_size",octavesize);
for (int i=0;i<octavesize;i++){
if (xml->enterbranch("DEGREE",i)==0) continue;
octave[i].x2=0;
octave[i].tuning=xml->getparreal("cents",octave[i].tuning);
octave[i].x1=xml->getpar127("numerator",octave[i].x1);
octave[i].x2=xml->getpar127("denominator",octave[i].x2);
if (octave[i].x2!=0) octave[i].type=2;
else octave[i].type=1;
xml->exitbranch();
};
xml->exitbranch();
};
if (xml->enterbranch("KEYBOARD_MAPPING")){
Pmapsize=xml->getpar127("map_size",Pmapsize);
Pmappingenabled=xml->getpar127("mapping_enabled",Pmappingenabled);
for (int i=0;i<Pmapsize;i++){
if (xml->enterbranch("KEYMAP",i)==0) continue;
Pmapping[i]=xml->getpar127("degree",Pmapping[i]);
xml->exitbranch();
};
xml->exitbranch();
};
xml->exitbranch();
};
};
int Microtonal::saveXML(char *filename){
XMLwrapper *xml=new XMLwrapper();
xml->beginbranch("MICROTONAL");
add2XML(xml);
xml->endbranch();
int result=xml->saveXMLfile(filename);
delete (xml);
return(result);
};
int Microtonal::loadXML(char *filename){
XMLwrapper *xml=new XMLwrapper();
if (xml->loadXMLfile(filename)<0) {
delete(xml);
return(-1);
};
if (xml->enterbranch("MICROTONAL")==0) return(-10);
getfromXML(xml);
xml->exitbranch();
delete(xml);
return(0);
};

View File

@@ -0,0 +1,597 @@
/*
ZynAddSubFX - a software synthesizer
Microtonal.C - Tuning settings and microtonal capabilities
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <math.h>
#include <string.h>
#include "Microtonal.h"
#define MAX_LINE_SIZE 80
Microtonal::Microtonal()
{
Pname=new unsigned char[MICROTONAL_MAX_NAME_LEN];
Pcomment=new unsigned char[MICROTONAL_MAX_NAME_LEN];
defaults();
};
void Microtonal::defaults()
{
Pinvertupdown=0;
Pinvertupdowncenter=60;
octavesize=12;
Penabled=0;
PAnote=69;
PAfreq=440.0;
Pscaleshift=64;
Pfirstkey=0;
Plastkey=127;
Pmiddlenote=60;
Pmapsize=12;
Pmappingenabled=0;
for (int i=0;i<128;i++) Pmapping[i]=i;
for (int i=0;i<MAX_OCTAVE_SIZE;i++) {
octave[i].tuning=tmpoctave[i].tuning=pow(2,(i%octavesize+1)/12.0);
octave[i].type=tmpoctave[i].type=1;
octave[i].x1=tmpoctave[i].x1=(i%octavesize+1)*100;
octave[i].x2=tmpoctave[i].x2=0;
};
octave[11].type=2;
octave[11].x1=2;
octave[11].x2=1;
for (int i=0;i<MICROTONAL_MAX_NAME_LEN;i++) {
Pname[i]='\0';
Pcomment[i]='\0';
};
snprintf((char *) Pname,MICROTONAL_MAX_NAME_LEN,"12tET");
snprintf((char *) Pcomment,MICROTONAL_MAX_NAME_LEN,"Equal Temperament 12 notes per octave");
Pglobalfinedetune=64;
};
Microtonal::~Microtonal()
{
delete [] Pname;
delete [] Pcomment;
};
/*
* Get the size of the octave
*/
unsigned char Microtonal::getoctavesize() const
{
if (Penabled!=0) return(octavesize);
else return(12);
};
/*
* Get the frequency according the note number
*/
REALTYPE Microtonal::getnotefreq(int note,int keyshift) const
{
// in this function will appears many times things like this:
// var=(a+b*100)%b
// I had written this way because if I use var=a%b gives unwanted results when a<0
// This is the same with divisions.
if ((Pinvertupdown!=0)&&((Pmappingenabled==0)||(Penabled==0))) note=(int) Pinvertupdowncenter*2-note;
//compute global fine detune
REALTYPE globalfinedetunerap=pow(2.0,(Pglobalfinedetune-64.0)/1200.0);//-64.0 .. 63.0 cents
if (Penabled==0) return(pow(2.0,(note-PAnote+keyshift)/12.0)*PAfreq*globalfinedetunerap);//12tET
int scaleshift=((int)Pscaleshift-64+(int) octavesize*100)%octavesize;
//compute the keyshift
REALTYPE rap_keyshift=1.0;
if (keyshift!=0) {
int kskey=(keyshift+(int)octavesize*100)%octavesize;
int ksoct=(keyshift+(int)octavesize*100)/octavesize-100;
rap_keyshift=(kskey==0) ? (1.0):(octave[kskey-1].tuning);
rap_keyshift*=pow(octave[octavesize-1].tuning,ksoct);
};
//if the mapping is enabled
if (Pmappingenabled!=0) {
if ((note<Pfirstkey)||(note>Plastkey)) return (-1.0);
//Compute how many mapped keys are from middle note to reference note
//and find out the proportion between the freq. of middle note and "A" note
int tmp=PAnote-Pmiddlenote,minus=0;
if (tmp<0) {
tmp=-tmp;
minus=1;
};
int deltanote=0;
for (int i=0;i<tmp;i++) if (Pmapping[i%Pmapsize]>=0) deltanote++;
REALTYPE rap_anote_middlenote=(deltanote==0) ? (1.0) : (octave[(deltanote-1)%octavesize].tuning);
if (deltanote!=0) rap_anote_middlenote*=pow(octave[octavesize-1].tuning,(deltanote-1)/octavesize);
if (minus!=0) rap_anote_middlenote=1.0/rap_anote_middlenote;
//Convert from note (midi) to degree (note from the tunning)
int degoct=(note-(int)Pmiddlenote+(int) Pmapsize*200)/(int)Pmapsize-200;
int degkey=(note-Pmiddlenote+(int)Pmapsize*100)%Pmapsize;
degkey=Pmapping[degkey];
if (degkey<0) return(-1.0);//this key is not mapped
//invert the keyboard upside-down if it is asked for
//TODO: do the right way by using Pinvertupdowncenter
if (Pinvertupdown!=0) {
degkey=octavesize-degkey-1;
degoct=-degoct;
};
//compute the frequency of the note
degkey=degkey+scaleshift;
degoct+=degkey/octavesize;
degkey%=octavesize;
REALTYPE freq=(degkey==0) ? (1.0):octave[degkey-1].tuning;
freq*=pow(octave[octavesize-1].tuning,degoct);
freq*=PAfreq/rap_anote_middlenote;
freq*=globalfinedetunerap;
if (scaleshift!=0) freq/=octave[scaleshift-1].tuning;
return(freq*rap_keyshift);
} else {//if the mapping is disabled
int nt=note-PAnote+scaleshift;
int ntkey=(nt+(int)octavesize*100)%octavesize;
int ntoct=(nt-ntkey)/octavesize;
REALTYPE oct=octave[octavesize-1].tuning;
REALTYPE freq=octave[(ntkey+octavesize-1)%octavesize].tuning*pow(oct,ntoct)*PAfreq;
if (ntkey==0) freq/=oct;
if (scaleshift!=0) freq/=octave[scaleshift-1].tuning;
// fprintf(stderr,"note=%d freq=%.3f cents=%d\n",note,freq,(int)floor(log(freq/PAfreq)/log(2.0)*1200.0+0.5));
freq*=globalfinedetunerap;
return(freq*rap_keyshift);
};
};
bool Microtonal::operator==(const Microtonal &micro) const
{
return(!(*this!=micro));
}
bool Microtonal::operator!=(const Microtonal &micro) const
{
//A simple macro to test equality MiCRotonal EQuals (not the perfect
//approach, but good enough)
#define MCREQ( x ) if(x!=micro.x)return true;
//for floats
#define FMCREQ( x ) if(!((x<micro.x+0.0001)&&(x>micro.x-0.0001)))return true;
MCREQ(Pinvertupdown);
MCREQ(Pinvertupdowncenter);
MCREQ(octavesize);
MCREQ(Penabled);
MCREQ(PAnote);
FMCREQ(PAfreq);
MCREQ(Pscaleshift);
MCREQ(Pfirstkey);
MCREQ(Plastkey);
MCREQ(Pmiddlenote);
MCREQ(Pmapsize);
MCREQ(Pmappingenabled);
for (int i=0;i<128;i++)
MCREQ(Pmapping[i]);
for (int i=0;i<octavesize;i++) {
FMCREQ(octave[i].tuning);
MCREQ(octave[i].type);
MCREQ(octave[i].x1);
MCREQ(octave[i].x2);
}
if(strcmp((const char *)this->Pname,(const char *)micro.Pname))
return true;
if(strcmp((const char *)this->Pcomment,(const char *)micro.Pcomment))
return true;
MCREQ(Pglobalfinedetune);
return false;
//undefine macros, as they are no longer needed
#undef MCREQ
#undef FMCREQ
}
/*
* Convert a line to tunings; returns -1 if it ok
*/
int Microtonal::linetotunings(unsigned int nline,const char *line)
{
int x1=-1,x2=-1,type=-1;
REALTYPE x=-1.0,tmp,tuning=1.0;
if (strstr(line,"/")==NULL) {
if (strstr(line,".")==NULL) {// M case (M=M/1)
sscanf(line,"%d",&x1);
x2=1;
type=2;//division
} else {// float number case
sscanf(line,"%f",&x);
if (x<0.000001) return(1);
type=1;//float type(cents)
};
} else {// M/N case
sscanf(line,"%d/%d",&x1,&x2);
if ((x1<0)||(x2<0)) return(1);
if (x2==0) x2=1;
type=2;//division
};
if (x1<=0) x1=1;//not allow zero frequency sounds (consider 0 as 1)
//convert to float if the number are too big
if ((type==2)&&((x1>(128*128*128-1))||(x2>(128*128*128-1)))) {
type=1;
x=((REALTYPE) x1)/x2;
};
switch (type) {
case 1:
x1=(int) floor(x);
tmp=fmod(x,1.0);
x2=(int) (floor (tmp*1e6));
tuning=pow(2.0,x/1200.0);
break;
case 2:
x=((REALTYPE)x1)/x2;
tuning=x;
break;
};
tmpoctave[nline].tuning=tuning;
tmpoctave[nline].type=type;
tmpoctave[nline].x1=x1;
tmpoctave[nline].x2=x2;
return(-1);//ok
};
/*
* Convert the text to tunnings
*/
int Microtonal::texttotunings(const char *text)
{
unsigned int i,k=0,nl=0;
char *lin;
lin=new char[MAX_LINE_SIZE+1];
while (k<strlen(text)) {
for (i=0;i<MAX_LINE_SIZE;i++) {
lin[i]=text[k++];
if (lin[i]<0x20) break;
};
lin[i]='\0';
if (strlen(lin)==0) continue;
int err=linetotunings(nl,lin);
if (err!=-1) {
delete [] lin;
return(nl);//Parse error
};
nl++;
};
delete [] lin;
if (nl>MAX_OCTAVE_SIZE) nl=MAX_OCTAVE_SIZE;
if (nl==0) return(-2);//the input is empty
octavesize=nl;
for (i=0;i<octavesize;i++) {
octave[i].tuning=tmpoctave[i].tuning;
octave[i].type=tmpoctave[i].type;
octave[i].x1=tmpoctave[i].x1;
octave[i].x2=tmpoctave[i].x2;
};
return(-1);//ok
};
/*
* Convert the text to mapping
*/
void Microtonal::texttomapping(const char *text)
{
unsigned int i,k=0;
char *lin;
lin=new char[MAX_LINE_SIZE+1];
for (i=0;i<128;i++) Pmapping[i]=-1;
int tx=0;
while (k<strlen(text)) {
for (i=0;i<MAX_LINE_SIZE;i++) {
lin[i]=text[k++];
if (lin[i]<0x20) break;
};
lin[i]='\0';
if (strlen(lin)==0) continue;
int tmp=0;
if (sscanf(lin,"%d",&tmp)==0) tmp=-1;
if (tmp<-1) tmp=-1;
Pmapping[tx]=tmp;
if ((tx++)>127) break;
};
delete [] lin;
if (tx==0) tx=1;
Pmapsize=tx;
};
/*
* Convert tunning to text line
*/
void Microtonal::tuningtoline(int n,char *line,int maxn)
{
if ((n>octavesize) || (n>MAX_OCTAVE_SIZE)) {
line[0]='\0';
return;
};
if (octave[n].type==1) snprintf(line,maxn,"%d.%d",octave[n].x1,octave[n].x2);
if (octave[n].type==2) snprintf(line,maxn,"%d/%d",octave[n].x1,octave[n].x2);
};
int Microtonal::loadline(FILE *file,char *line)
{
do {
if (fgets(line,500,file)==0) return(1);
} while (line[0]=='!');
return(0);
};
/*
* Loads the tunnings from a scl file
*/
int Microtonal::loadscl(const char *filename)
{
FILE *file=fopen(filename, "r");
char tmp[500];
fseek(file,0,SEEK_SET);
//loads the short description
if (loadline(file,&tmp[0])!=0) return(2);
for (int i=0;i<500;i++) if (tmp[i]<32) tmp[i]=0;
snprintf((char *) Pname,MICROTONAL_MAX_NAME_LEN,"%s",tmp);
snprintf((char *) Pcomment,MICROTONAL_MAX_NAME_LEN,"%s",tmp);
//loads the number of the notes
if (loadline(file,&tmp[0])!=0) return(2);
int nnotes=MAX_OCTAVE_SIZE;
sscanf(&tmp[0],"%d",&nnotes);
if (nnotes>MAX_OCTAVE_SIZE) return (2);
//load the tunnings
for (int nline=0;nline<nnotes;nline++) {
if (loadline(file,&tmp[0])!=0) return(2);
linetotunings(nline,&tmp[0]);
};
fclose(file);
octavesize=nnotes;
for (int i=0;i<octavesize;i++) {
octave[i].tuning=tmpoctave[i].tuning;
octave[i].type=tmpoctave[i].type;
octave[i].x1=tmpoctave[i].x1;
octave[i].x2=tmpoctave[i].x2;
};
return(0);
};
/*
* Loads the mapping from a kbm file
*/
int Microtonal::loadkbm(const char *filename)
{
FILE *file=fopen(filename, "r");
int x;
char tmp[500];
fseek(file,0,SEEK_SET);
//loads the mapsize
if (loadline(file,&tmp[0])!=0) return(2);
if (sscanf(&tmp[0],"%d",&x)==0) return(2);
if (x<1) x=0;
if (x>127) x=127;//just in case...
Pmapsize=x;
//loads first MIDI note to retune
if (loadline(file,&tmp[0])!=0) return(2);
if (sscanf(&tmp[0],"%d",&x)==0) return(2);
if (x<1) x=0;
if (x>127) x=127;//just in case...
Pfirstkey=x;
//loads last MIDI note to retune
if (loadline(file,&tmp[0])!=0) return(2);
if (sscanf(&tmp[0],"%d",&x)==0) return(2);
if (x<1) x=0;
if (x>127) x=127;//just in case...
Plastkey=x;
//loads last the middle note where scale fro scale degree=0
if (loadline(file,&tmp[0])!=0) return(2);
if (sscanf(&tmp[0],"%d",&x)==0) return(2);
if (x<1) x=0;
if (x>127) x=127;//just in case...
Pmiddlenote=x;
//loads the reference note
if (loadline(file,&tmp[0])!=0) return(2);
if (sscanf(&tmp[0],"%d",&x)==0) return(2);
if (x<1) x=0;
if (x>127) x=127;//just in case...
PAnote=x;
//loads the reference freq.
if (loadline(file,&tmp[0])!=0) return(2);
REALTYPE tmpPAfreq=440.0;
if (sscanf(&tmp[0],"%f",&tmpPAfreq)==0) return(2);
PAfreq=tmpPAfreq;
//the scale degree(which is the octave) is not loaded, it is obtained by the tunnings with getoctavesize() method
if (loadline(file,&tmp[0])!=0) return(2);
//load the mappings
if (Pmapsize!=0) {
for (int nline=0;nline<Pmapsize;nline++) {
if (loadline(file,&tmp[0])!=0) return(2);
if (sscanf(&tmp[0],"%d",&x)==0) x=-1;
Pmapping[nline]=x;
};
Pmappingenabled=1;
} else {
Pmappingenabled=0;
Pmapping[0]=0;
Pmapsize=1;
};
fclose(file);
return(0);
};
void Microtonal::add2XML(XMLwrapper *xml)const
{
xml->addparstr("name",(char *) Pname);
xml->addparstr("comment",(char *) Pcomment);
xml->addparbool("invert_up_down",Pinvertupdown);
xml->addpar("invert_up_down_center",Pinvertupdowncenter);
xml->addparbool("enabled",Penabled);
xml->addpar("global_fine_detune",Pglobalfinedetune);
xml->addpar("a_note",PAnote);
xml->addparreal("a_freq",PAfreq);
if ((Penabled==0)&&(xml->minimal)) return;
xml->beginbranch("SCALE");
xml->addpar("scale_shift",Pscaleshift);
xml->addpar("first_key",Pfirstkey);
xml->addpar("last_key",Plastkey);
xml->addpar("middle_note",Pmiddlenote);
xml->beginbranch("OCTAVE");
xml->addpar("octave_size",octavesize);
for (int i=0;i<octavesize;i++) {
xml->beginbranch("DEGREE",i);
if (octave[i].type==1) {
xml->addparreal("cents",octave[i].tuning);
};
if (octave[i].type==2) {
xml->addpar("numerator",octave[i].x1);
xml->addpar("denominator",octave[i].x2);
};
xml->endbranch();
};
xml->endbranch();
xml->beginbranch("KEYBOARD_MAPPING");
xml->addpar("map_size",Pmapsize);
xml->addpar("mapping_enabled",Pmappingenabled);
for (int i=0;i<Pmapsize;i++) {
xml->beginbranch("KEYMAP",i);
xml->addpar("degree",Pmapping[i]);
xml->endbranch();
};
xml->endbranch();
xml->endbranch();
};
void Microtonal::getfromXML(XMLwrapper *xml)
{
xml->getparstr("name",(char *) Pname,MICROTONAL_MAX_NAME_LEN);
xml->getparstr("comment",(char *) Pcomment,MICROTONAL_MAX_NAME_LEN);
Pinvertupdown=xml->getparbool("invert_up_down",Pinvertupdown);
Pinvertupdowncenter=xml->getpar127("invert_up_down_center",Pinvertupdowncenter);
Penabled=xml->getparbool("enabled",Penabled);
Pglobalfinedetune=xml->getpar127("global_fine_detune",Pglobalfinedetune);
PAnote=xml->getpar127("a_note",PAnote);
PAfreq=xml->getparreal("a_freq",PAfreq,1.0,10000.0);
if (xml->enterbranch("SCALE")) {
Pscaleshift=xml->getpar127("scale_shift",Pscaleshift);
Pfirstkey=xml->getpar127("first_key",Pfirstkey);
Plastkey=xml->getpar127("last_key",Plastkey);
Pmiddlenote=xml->getpar127("middle_note",Pmiddlenote);
if (xml->enterbranch("OCTAVE")) {
octavesize=xml->getpar127("octave_size",octavesize);
for (int i=0;i<octavesize;i++) {
if (xml->enterbranch("DEGREE",i)==0) continue;
octave[i].x2=0;
octave[i].tuning=xml->getparreal("cents",octave[i].tuning);
octave[i].x1=xml->getpar127("numerator",octave[i].x1);
octave[i].x2=xml->getpar127("denominator",octave[i].x2);
if (octave[i].x2!=0) octave[i].type=2;
else octave[i].type=1;
xml->exitbranch();
};
xml->exitbranch();
};
if (xml->enterbranch("KEYBOARD_MAPPING")) {
Pmapsize=xml->getpar127("map_size",Pmapsize);
Pmappingenabled=xml->getpar127("mapping_enabled",Pmappingenabled);
for (int i=0;i<Pmapsize;i++) {
if (xml->enterbranch("KEYMAP",i)==0) continue;
Pmapping[i]=xml->getpar127("degree",Pmapping[i]);
xml->exitbranch();
};
xml->exitbranch();
};
xml->exitbranch();
};
};
int Microtonal::saveXML(const char *filename)const
{
XMLwrapper *xml=new XMLwrapper();
xml->beginbranch("MICROTONAL");
add2XML(xml);
xml->endbranch();
int result=xml->saveXMLfile(filename);
delete (xml);
return(result);
};
int Microtonal::loadXML(const char *filename)
{
XMLwrapper *xml=new XMLwrapper();
if (xml->loadXMLfile(filename)<0) {
delete(xml);
return(-1);
};
if (xml->enterbranch("MICROTONAL")==0) return(-10);
getfromXML(xml);
xml->exitbranch();
delete(xml);
return(0);
};

View File

@@ -1,12 +1,12 @@
/*
ZynAddSubFX - a software synthesizer
Microtonal.h - Tuning settings and microtonal capabilities
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
@@ -31,81 +31,107 @@
#include <stdio.h>
class Microtonal{
public:
Microtonal();
~Microtonal();
void defaults();
REALTYPE getnotefreq(int note,int keyshift);
//Parameters
//if the keys are inversed (the pitch is lower to keys from the right direction)
unsigned char Pinvertupdown;
/**Tuning settings and microtonal capabilities*/
class Microtonal
{
public:
/**Constructor*/
Microtonal();
/**Destructor*/
~Microtonal();
void defaults();
/**Calculates the frequency for a given note
*/
REALTYPE getnotefreq(int note,int keyshift) const;
//the central key of the inversion
unsigned char Pinvertupdowncenter;
//0 for 12 key temperate scale, 1 for microtonal
unsigned char Penabled;
//Parameters
/**if the keys are inversed (the pitch is lower to keys from the right direction)*/
unsigned char Pinvertupdown;
//the note of "A" key
unsigned char PAnote;
/**the central key of the inversion*/
unsigned char Pinvertupdowncenter;
//the frequency of the "A" note
REALTYPE PAfreq;
//if the scale is "tuned" to a note, you can tune to other note
unsigned char Pscaleshift;
/**0 for 12 key temperate scale, 1 for microtonal*/
unsigned char Penabled;
//first and last key (to retune)
unsigned char Pfirstkey;
unsigned char Plastkey;
//The middle note where scale degree 0 is mapped to
unsigned char Pmiddlenote;
//Map size
unsigned char Pmapsize;
/**the note of "A" key*/
unsigned char PAnote;
//Mapping ON/OFF
unsigned char Pmappingenabled;
//Mapping (keys)
short int Pmapping[128];
unsigned char Pglobalfinedetune;
// Functions
unsigned char getoctavesize();
void tuningtoline(int n,char *line,int maxn);
int loadscl(const char *filename);//load the tunnings from a .scl file
int loadkbm(const char *filename);//load the mapping from .kbm file
int texttotunings(const char *text);
void texttomapping(const char *text);
unsigned char *Pname;
unsigned char *Pcomment;
/**the frequency of the "A" note*/
REALTYPE PAfreq;
void add2XML(XMLwrapper *xml);
void getfromXML(XMLwrapper *xml);
int saveXML(char *filename);
int loadXML(char *filename);
/**if the scale is "tuned" to a note, you can tune to other note*/
unsigned char Pscaleshift;
private:
int linetotunings(unsigned int nline,const char *line);
int loadline(FILE *file,char *line);//loads a line from the text file, while ignoring the lines beggining with "!"
unsigned char octavesize;
struct {
unsigned char type;//1 for cents or 2 for division
//first and last key (to retune)
unsigned char Pfirstkey;
unsigned char Plastkey;
/**The middle note where scale degree 0 is mapped to*/
unsigned char Pmiddlenote;
/**Map size*/
unsigned char Pmapsize;
/**Mapping ON/OFF*/
unsigned char Pmappingenabled;
/**Mapping (keys)*/
short int Pmapping[128];
/**Fine detune to be applied to all notes*/
unsigned char Pglobalfinedetune;
// Functions
/** Return the current octave size*/
unsigned char getoctavesize() const;
/**Convert tunning to string*/
void tuningtoline(int n,char *line,int maxn);
/**load the tunnings from a .scl file*/
int loadscl(const char *filename);
/**load the mapping from .kbm file*/
int loadkbm(const char *filename);
/**Load text into the internal tunings
*
*\todo better description*/
int texttotunings(const char *text);
/**Load text into the internal mappings
*
*\todo better description*/
void texttomapping(const char *text);
/**Name of Microtonal tuning*/
unsigned char *Pname;
/**Comment about the tuning*/
unsigned char *Pcomment;
void add2XML(XMLwrapper *xml)const;
void getfromXML(XMLwrapper *xml);
int saveXML(const char *filename)const;
int loadXML(const char *filename);
//simple operators primarily for debug
bool operator==(const Microtonal &micro) const;
bool operator!=(const Microtonal &micro) const;
private:
int linetotunings(unsigned int nline,const char *line);
int loadline(FILE *file,char *line);//loads a line from the text file, while ignoring the lines beggining with "!"
unsigned char octavesize;
struct {
unsigned char type;//1 for cents or 2 for division
// the real tuning (eg. +1.05946 for one halftone)
// or 2.0 for one octave
REALTYPE tuning;
//the real tunning is x1/x2
unsigned int x1,x2;
} octave[MAX_OCTAVE_SIZE],tmpoctave[MAX_OCTAVE_SIZE];
// the real tuning (eg. +1.05946 for one halftone)
// or 2.0 for one octave
REALTYPE tuning;
//the real tunning is x1/x2
unsigned int x1,x2;
} octave[MAX_OCTAVE_SIZE],tmpoctave[MAX_OCTAVE_SIZE];
};
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +1,12 @@
/*
ZynAddSubFX - a software synthesizer
Part.h - Part implementation
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
@@ -40,140 +40,147 @@
#include <list> // For the monomemnotes list.
class Part{
/** Part implementation*/
class Part
{
public:
Part(Microtonal *microtonal_,FFTwrapper *fft_,pthread_mutex_t *mutex_);
~Part();
public:
/**Constructor
* @param microtonal_ Pointer to the microtonal object
* @param fft_ Pointer to the FFTwrapper
* @param mutex_ Pointer to the master pthread_mutex_t*/
Part(Microtonal *microtonal_,FFTwrapper *fft_,pthread_mutex_t *mutex_);
/**Destructor*/
~Part();
/* Midi commands implemented */
void NoteOn(unsigned char note,unsigned char velocity,int masterkeyshift);
void NoteOff(unsigned char note);
void AllNotesOff();//panic
void SetController(unsigned int type,int par);
void RelaseSustainedKeys();//this is called when the sustain pedal is relased
void RelaseAllKeys();//this is called on AllNotesOff controller
// Midi commands implemented
void NoteOn(unsigned char note,unsigned char velocity,int masterkeyshift);
void NoteOff(unsigned char note);
void AllNotesOff();//panic
void SetController(unsigned int type,int par);
void RelaseSustainedKeys();//this is called when the sustain pedal is relased
void RelaseAllKeys();//this is called on AllNotesOff controller
/* The synthesizer part output */
void ComputePartSmps();//Part output
//instrumentonly: 0 - save all, 1 - save only instrumnet, 2 - save only instrument without the name(used in bank)
/* The synthesizer part output */
void ComputePartSmps();//Part output
//instrumentonly: 0 - save all, 1 - save only instrumnet, 2 - save only instrument without the name(used in bank)
//saves the instrument settings to a XML file
//returns 0 for ok or <0 if there is an error
int saveXML(char *filename);
int loadXMLinstrument(const char *filename);
//saves the instrument settings to a XML file
//returns 0 for ok or <0 if there is an error
int saveXML(char *filename);
int loadXMLinstrument(const char *filename);
void add2XML(XMLwrapper *xml);
void add2XMLinstrument(XMLwrapper *xml);
void defaults();
void defaultsinstrument();
void applyparameters();
void getfromXML(XMLwrapper *xml);
void getfromXMLinstrument(XMLwrapper *xml);
void add2XML(XMLwrapper *xml);
void add2XMLinstrument(XMLwrapper *xml);
void cleanup();
void defaults();
void defaultsinstrument();
void applyparameters();
void getfromXML(XMLwrapper *xml);
void getfromXMLinstrument(XMLwrapper *xml);
void cleanup();
// ADnoteParameters *ADPartParameters;
// SUBnoteParameters *SUBPartParameters;
//the part's kit
struct {
//the part's kit
struct {
unsigned char Penabled,Pmuted,Pminkey,Pmaxkey;
unsigned char *Pname;
unsigned char Padenabled,Psubenabled,Ppadenabled;
unsigned char Psendtoparteffect;
unsigned char *Pname;
unsigned char Padenabled,Psubenabled,Ppadenabled;
unsigned char Psendtoparteffect;
ADnoteParameters *adpars;
SUBnoteParameters *subpars;
PADnoteParameters *padpars;
} kit[NUM_KIT_ITEMS];
} kit[NUM_KIT_ITEMS];
//Part parameters
void setkeylimit(unsigned char Pkeylimit);
void setkititemstatus(int kititem,int Penabled_);
unsigned char Penabled;//if the part is enabled
unsigned char Pvolume;//part volume
unsigned char Pminkey;//the minimum key that the part receives noteon messages
unsigned char Pmaxkey;//the maximum key that the part receives noteon messages
void setPvolume(char Pvolume);
unsigned char Pkeyshift;//Part keyshift
unsigned char Prcvchn;//from what midi channel it receive commnads
unsigned char Ppanning;//part panning
void setPpanning(char Ppanning);
unsigned char Pvelsns;//velocity sensing (amplitude velocity scale)
unsigned char Pveloffs;//velocity offset
unsigned char Pnoteon;//if the part receives NoteOn messages
unsigned char Pkitmode;//if the kitmode is enabled
unsigned char Pdrummode;//if all keys are mapped and the system is 12tET (used for drums)
//Part parameters
void setkeylimit(unsigned char Pkeylimit);
void setkititemstatus(int kititem,int Penabled_);
unsigned char Ppolymode;//Part mode - 0=monophonic , 1=polyphonic
unsigned char Plegatomode;// 0=normal, 1=legato
unsigned char Pkeylimit;//how many keys are alowed to be played same time (0=off), the older will be relased
unsigned char *Pname; //name of the instrument
struct{//instrument additional information
unsigned char Ptype;
unsigned char Pauthor[MAX_INFO_TEXT_SIZE+1];
unsigned char Pcomments[MAX_INFO_TEXT_SIZE+1];
} info;
REALTYPE *partoutl;//Left channel output of the part
REALTYPE *partoutr;//Right channel output of the part
unsigned char Penabled;/**<if the part is enabled*/
unsigned char Pvolume;/**<part volume*/
unsigned char Pminkey;/**<the minimum key that the part receives noteon messages*/
unsigned char Pmaxkey;//the maximum key that the part receives noteon messages
void setPvolume(char Pvolume);
unsigned char Pkeyshift;//Part keyshift
unsigned char Prcvchn;//from what midi channel it receive commnads
unsigned char Ppanning;//part panning
void setPpanning(char Ppanning);
unsigned char Pvelsns;//velocity sensing (amplitude velocity scale)
unsigned char Pveloffs;//velocity offset
unsigned char Pnoteon;//if the part receives NoteOn messages
unsigned char Pkitmode;//if the kitmode is enabled
unsigned char Pdrummode;//if all keys are mapped and the system is 12tET (used for drums)
REALTYPE *partfxinputl[NUM_PART_EFX+1],*partfxinputr[NUM_PART_EFX+1];//Left and right signal that pass thru part effects; partfxinput l/r [NUM_PART_EFX] is for "no effect" buffer
unsigned char Ppolymode;//Part mode - 0=monophonic , 1=polyphonic
unsigned char Plegatomode;// 0=normal, 1=legato
unsigned char Pkeylimit;//how many keys are alowed to be played same time (0=off), the older will be relased
enum NoteStatus{KEY_OFF,KEY_PLAYING,KEY_RELASED_AND_SUSTAINED,KEY_RELASED};
unsigned char *Pname; //name of the instrument
struct {//instrument additional information
unsigned char Ptype;
unsigned char Pauthor[MAX_INFO_TEXT_SIZE+1];
unsigned char Pcomments[MAX_INFO_TEXT_SIZE+1];
} info;
REALTYPE volume,oldvolumel,oldvolumer;//this is applied by Master
REALTYPE panning;//this is applied by Master, too
Controller ctl;//Part controllers
EffectMgr *partefx[NUM_PART_EFX];//insertion part effects (they are part of the instrument)
unsigned char Pefxroute[NUM_PART_EFX];//how the effect's output is routed(to next effect/to out)
bool Pefxbypass[NUM_PART_EFX+1];//if the effects are bypassed
REALTYPE *partoutl;//Left channel output of the part
REALTYPE *partoutr;//Right channel output of the part
pthread_mutex_t *mutex;
int lastnote;
private:
void KillNotePos(int pos);
void RelaseNotePos(int pos);
void MonoMemRenote(); // MonoMem stuff.
REALTYPE *partfxinputl[NUM_PART_EFX+1],*partfxinputr[NUM_PART_EFX+1];//Left and right signal that pass thru part effects; partfxinput l/r [NUM_PART_EFX] is for "no effect" buffer
int killallnotes;//is set to 1 if I want to kill all notes
struct PartNotes{
enum NoteStatus {KEY_OFF,KEY_PLAYING,KEY_RELASED_AND_SUSTAINED,KEY_RELASED};
REALTYPE volume,oldvolumel,oldvolumer;//this is applied by Master
REALTYPE panning;//this is applied by Master, too
Controller ctl;//Part controllers
EffectMgr *partefx[NUM_PART_EFX];//insertion part effects (they are part of the instrument)
unsigned char Pefxroute[NUM_PART_EFX];//how the effect's output is routed(to next effect/to out)
bool Pefxbypass[NUM_PART_EFX];//if the effects are bypassed
pthread_mutex_t *mutex;
int lastnote;
private:
void KillNotePos(int pos);
void RelaseNotePos(int pos);
void MonoMemRenote(); // MonoMem stuff.
int killallnotes;//is set to 1 if I want to kill all notes
struct PartNotes {
NoteStatus status;
int note;//if there is no note playing, the "note"=-1
int itemsplaying;
struct {
ADnote *adnote;
SUBnote *subnote;
PADnote *padnote;
int sendtoparteffect;
} kititem[NUM_KIT_ITEMS];
int time;
};
int itemsplaying;
struct {
ADnote *adnote;
SUBnote *subnote;
PADnote *padnote;
int sendtoparteffect;
} kititem[NUM_KIT_ITEMS];
int time;
};
int lastpos, lastposb; // To keep track of previously used pos and posb.
bool lastlegatomodevalid; // To keep track of previous legatomodevalid.
int lastpos, lastposb; // To keep track of previously used pos and posb.
bool lastlegatomodevalid; // To keep track of previous legatomodevalid.
// MonoMem stuff
std::list<unsigned char> monomemnotes; // A list to remember held notes.
struct {
unsigned char velocity;
int mkeyshift;// I'm not sure masterkeyshift should be remembered.
} monomem[256]; /* 256 is to cover all possible note values.
// MonoMem stuff
std::list<unsigned char> monomemnotes; // A list to remember held notes.
struct {
unsigned char velocity;
int mkeyshift;// I'm not sure masterkeyshift should be remembered.
} monomem[256]; /* 256 is to cover all possible note values.
monomem[] is used in conjunction with the list to
store the velocity and masterkeyshift values of a
given note (the list only store note values).
@@ -181,14 +188,14 @@ class Part{
velocity value of the note 'note'.
*/
PartNotes partnote[POLIPHONY];
REALTYPE *tmpoutl;//used to get the note
REALTYPE *tmpoutr;
REALTYPE oldfreq;//this is used for portamento
Microtonal *microtonal;
FFTwrapper *fft;
PartNotes partnote[POLIPHONY];
REALTYPE *tmpoutl;//used to get the note
REALTYPE *tmpoutr;
REALTYPE oldfreq;//this is used for portamento
Microtonal *microtonal;
FFTwrapper *fft;
};
#endif

View File

@@ -0,0 +1,37 @@
/*
ZynAddSubFX - a software synthesizer
Stereo.C - Object for storing a pair of objects
Copyright (C) 2009-2009 Mark McCurry
Author: Mark McCurry
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
template <class T>
Stereo<T>::Stereo(const T &left, const T &right)
:leftChannel(left),rightChannel(right)
{}
template <class T>
Stereo<T>::Stereo(const T &val)
:leftChannel(val),rightChannel(val)
{}
template <class T>
void Stereo<T>::operator=(const Stereo<T> & nstr)
{
leftChannel=nstr.leftChannel;
rightChannel=nstr.rightChannel;
}

View File

@@ -0,0 +1,67 @@
/*
ZynAddSubFX - a software synthesizer
Stereo.h - Object for storing a pair of objects
Copyright (C) 2009-2009 Mark McCurry
Author: Mark McCurry
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef STEREO_H
#define STEREO_H
template <class T>
class Stereo
{
public:
Stereo(const T &left,const T &right);
/**Initializes Stereo with left and right set to val
* @param val the value for both channels*/
Stereo(const T &val);
~Stereo() {};
void operator=(const Stereo<T> &smp);
T &left() {
return leftChannel;
};
T &right() {
return rightChannel;
};
T &l() {
return leftChannel;
};
T &r() {
return rightChannel;
};
const T &left()const {
return leftChannel;
};
const T &right()const {
return rightChannel;
};
const T &l()const {
return leftChannel;
};
const T &r()const {
return rightChannel;
};
private:
T leftChannel;
T rightChannel;
};
#include "Stereo.cpp"
#endif

View File

@@ -1,12 +1,12 @@
/*
ZynAddSubFX - a software synthesizer
Util.C - Miscellaneous functions
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
@@ -42,17 +42,19 @@ REALTYPE *denormalkillbuf;
/*
* Transform the velocity according the scaling parameter (velocity sensing)
*/
REALTYPE VelF(REALTYPE velocity,unsigned char scaling){
REALTYPE VelF(REALTYPE velocity,unsigned char scaling)
{
REALTYPE x;
x=pow(VELOCITY_MAX_SCALE,(64.0-scaling)/64.0);
if ((scaling==127)||(velocity>0.99)) return(1.0);
else return(pow(velocity,x));
else return(pow(velocity,x));
};
/*
* Get the detune in cents
* Get the detune in cents
*/
REALTYPE getdetune(unsigned char type,unsigned short int coarsedetune,unsigned short int finedetune){
REALTYPE getdetune(unsigned char type,unsigned short int coarsedetune,unsigned short int finedetune)
{
REALTYPE det=0.0,octdet=0.0,cdet=0.0,findet=0.0;
//Get Octave
int octave=coarsedetune/1024;
@@ -62,49 +64,57 @@ REALTYPE getdetune(unsigned char type,unsigned short int coarsedetune,unsigned s
//Coarse and fine detune
int cdetune=coarsedetune%1024;
if (cdetune>512) cdetune-=1024;
int fdetune=finedetune-8192;
switch (type){
switch (type) {
// case 1: is used for the default (see below)
case 2: cdet=fabs(cdetune*10.0);
findet=fabs(fdetune/8192.0)*10.0;
break;
case 3: cdet=fabs(cdetune*100);
findet=pow(10,fabs(fdetune/8192.0)*3.0)/10.0-0.1;
break;
case 4: cdet=fabs(cdetune*701.95500087);//perfect fifth
findet=(pow(2,fabs(fdetune/8192.0)*12.0)-1.0)/4095*1200;
break;
//case ...: need to update N_DETUNE_TYPES, if you'll add more
default:cdet=fabs(cdetune*50.0);
findet=fabs(fdetune/8192.0)*35.0;//almost like "Paul's Sound Designer 2"
break;
case 2:
cdet=fabs(cdetune*10.0);
findet=fabs(fdetune/8192.0)*10.0;
break;
case 3:
cdet=fabs(cdetune*100);
findet=pow(10,fabs(fdetune/8192.0)*3.0)/10.0-0.1;
break;
case 4:
cdet=fabs(cdetune*701.95500087);//perfect fifth
findet=(pow(2,fabs(fdetune/8192.0)*12.0)-1.0)/4095*1200;
break;
//case ...: need to update N_DETUNE_TYPES, if you'll add more
default:
cdet=fabs(cdetune*50.0);
findet=fabs(fdetune/8192.0)*35.0;//almost like "Paul's Sound Designer 2"
break;
};
if (finedetune<8192) findet=-findet;
if (cdetune<0) cdet=-cdet;
det=octdet+cdet+findet;
return(det);
};
bool fileexists(char *filename){
bool fileexists(const char *filename)
{
struct stat tmp;
int result=stat(filename,&tmp);
if (result>=0) return(true);
return(false);
};
void newFFTFREQS(FFTFREQS *f,int size){
void newFFTFREQS(FFTFREQS *f,int size)
{
f->c=new REALTYPE[size];
f->s=new REALTYPE[size];
for (int i=0;i<size;i++){
f->c[i]=0.0;f->s[i]=0.0;
for (int i=0;i<size;i++) {
f->c[i]=0.0;
f->s[i]=0.0;
};
};
void deleteFFTFREQS(FFTFREQS *f){
void deleteFFTFREQS(FFTFREQS *f)
{
delete[] f->c;
delete[] f->s;
f->c=f->s=NULL;

View File

@@ -1,12 +1,12 @@
/*
ZynAddSubFX - a software synthesizer
Util.h - Miscellaneous functions
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
@@ -32,12 +32,12 @@
//Velocity Sensing function
extern REALTYPE VelF(REALTYPE velocity,unsigned char scaling);
bool fileexists(char *filename);
bool fileexists(const char *filename);
#define N_DETUNE_TYPES 4 //the number of detune types
extern REALTYPE getdetune(unsigned char type,unsigned short int coarsedetune,unsigned short int finedetune);
extern REALTYPE *denormalkillbuf;//the buffer to add noise in order to avoid denormalisation
extern REALTYPE *denormalkillbuf;/**<the buffer to add noise in order to avoid denormalisation*/
extern Config config;

View File

@@ -1,12 +1,12 @@
/*
ZynAddSubFX - a software synthesizer
XMLwrapper.C - XML wrapper
Copyright (C) 2003-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
@@ -21,50 +21,58 @@
*/
#include "XMLwrapper.h"
#include <cstring>
#include <stdio.h>
#include <stdlib.h>
#include <cstdarg>
#include <zlib.h>
#include <iostream>
#include <sstream>
#include "../globals.h"
#include "Util.h"
using namespace std;
int xml_k=0;
char tabs[STACKSIZE+2];
const char *XMLwrapper_whitespace_callback(mxml_node_t *node,int where){
const char *XMLwrapper_whitespace_callback(mxml_node_t *node,int where)
{
const char *name=node->value.element.name;
if ((where==MXML_WS_BEFORE_OPEN)&&(!strcmp(name,"?xml"))) return(NULL);
if ((where==MXML_WS_BEFORE_CLOSE)&&(!strcmp(name,"string"))) return(NULL);
if ((where==MXML_WS_BEFORE_OPEN)||(where==MXML_WS_BEFORE_CLOSE)) {
/* const char *tmp=node->value.element.name;
if (tmp!=NULL) {
if ((strstr(tmp,"par")!=tmp)&&(strstr(tmp,"string")!=tmp)) {
printf("%s ",tmp);
if (where==MXML_WS_BEFORE_OPEN) xml_k++;
if (where==MXML_WS_BEFORE_CLOSE) xml_k--;
if (xml_k>=STACKSIZE) xml_k=STACKSIZE-1;
if (xml_k<0) xml_k=0;
printf("%d\n",xml_k);
printf("\n");
};
};
int i=0;
for (i=1;i<xml_k;i++) tabs[i]='\t';
tabs[0]='\n';tabs[i+1]='\0';
if (where==MXML_WS_BEFORE_OPEN) return(tabs);
else return("\n");
*/
return("\n");
/* const char *tmp=node->value.element.name;
if (tmp!=NULL) {
if ((strstr(tmp,"par")!=tmp)&&(strstr(tmp,"string")!=tmp)) {
printf("%s ",tmp);
if (where==MXML_WS_BEFORE_OPEN) xml_k++;
if (where==MXML_WS_BEFORE_CLOSE) xml_k--;
if (xml_k>=STACKSIZE) xml_k=STACKSIZE-1;
if (xml_k<0) xml_k=0;
printf("%d\n",xml_k);
printf("\n");
};
};
int i=0;
for (i=1;i<xml_k;i++) tabs[i]='\t';
tabs[0]='\n';tabs[i+1]='\0';
if (where==MXML_WS_BEFORE_OPEN) return(tabs);
else return("\n");
*/
return("\n");
};
return(0);
};
XMLwrapper::XMLwrapper(){
XMLwrapper::XMLwrapper()
{
ZERO(&parentstack,(int)sizeof(parentstack));
ZERO(&values,(int)sizeof(values));
@@ -72,50 +80,53 @@ XMLwrapper::XMLwrapper(){
stackpos=0;
information.PADsynth_used=false;
tree=mxmlNewElement(MXML_NO_PARENT,"?xml version=\"1.0\" encoding=\"UTF-8\"?");
/* for mxml 2.1 (and older)
tree=mxmlNewElement(MXML_NO_PARENT,"?xml");
mxmlElementSetAttr(tree,"version","1.0");
mxmlElementSetAttr(tree,"encoding","UTF-8");
*/
/* for mxml 2.1 (and older)
tree=mxmlNewElement(MXML_NO_PARENT,"?xml");
mxmlElementSetAttr(tree,"version","1.0");
mxmlElementSetAttr(tree,"encoding","UTF-8");
*/
mxml_node_t *doctype=mxmlNewElement(tree,"!DOCTYPE");
mxmlElementSetAttr(doctype,"ZynAddSubFX-data",NULL);
node=root=mxmlNewElement(tree,"ZynAddSubFX-data");
mxmlElementSetAttr(root,"version-major","1");
mxmlElementSetAttr(root,"version-minor","1");
mxmlElementSetAttr(root,"ZynAddSubFX-author","Nasca Octavian Paul");
//make the empty branch that will contain the information parameters
info=addparams0("INFORMATION");
//save zynaddsubfx specifications
beginbranch("BASE_PARAMETERS");
addpar("max_midi_parts",NUM_MIDI_PARTS);
addpar("max_kit_items_per_instrument",NUM_KIT_ITEMS);
addpar("max_midi_parts",NUM_MIDI_PARTS);
addpar("max_kit_items_per_instrument",NUM_KIT_ITEMS);
addpar("max_system_effects",NUM_SYS_EFX);
addpar("max_insertion_effects",NUM_INS_EFX);
addpar("max_instrument_effects",NUM_PART_EFX);
addpar("max_system_effects",NUM_SYS_EFX);
addpar("max_insertion_effects",NUM_INS_EFX);
addpar("max_instrument_effects",NUM_PART_EFX);
addpar("max_addsynth_voices",NUM_VOICES);
addpar("max_addsynth_voices",NUM_VOICES);
endbranch();
};
XMLwrapper::~XMLwrapper(){
XMLwrapper::~XMLwrapper()
{
if (tree!=NULL) mxmlDelete(tree);
};
bool XMLwrapper::checkfileinformation(const char *filename){
bool XMLwrapper::checkfileinformation(const char *filename)
{
stackpos=0;
ZERO(&parentstack,(int)sizeof(parentstack));
information.PADsynth_used=false;
if (tree!=NULL) mxmlDelete(tree);tree=NULL;
if (tree!=NULL) mxmlDelete(tree);
tree=NULL;
char *xmldata=doloadfile(filename);
if (xmldata==NULL) return(-1);//the file could not be loaded or uncompressed
@@ -124,31 +135,31 @@ bool XMLwrapper::checkfileinformation(const char *filename){
char *end=strstr(xmldata,"</INFORMATION>");
if ((start==NULL)||(end==NULL)||(start>end)) {
delete []xmldata;
return(false);
delete []xmldata;
return(false);
};
end+=strlen("</INFORMATION>");
end[0]='\0';
end[0]='\0';
tree=mxmlNewElement(MXML_NO_PARENT,"?xml");
node=root=mxmlLoadString(tree,xmldata,MXML_OPAQUE_CALLBACK);
if (root==NULL) {
delete []xmldata;
mxmlDelete(tree);
node=root=tree=NULL;
return(false);
delete []xmldata;
mxmlDelete(tree);
node=root=tree=NULL;
return(false);
};
root=mxmlFindElement(tree,tree,"INFORMATION",NULL,NULL,MXML_DESCEND);
push(root);
if (root==NULL){
delete []xmldata;
mxmlDelete(tree);
node=root=tree=NULL;
return(false);
if (root==NULL) {
delete []xmldata;
mxmlDelete(tree);
node=root=tree=NULL;
return(false);
};
information.PADsynth_used=getparbool("PADsynth_used",false);
exitbranch();
@@ -162,33 +173,29 @@ bool XMLwrapper::checkfileinformation(const char *filename){
/* SAVE XML members */
int XMLwrapper::saveXMLfile(const char *filename){
int XMLwrapper::saveXMLfile(const string &filename)
{
char *xmldata=getXMLdata();
if (xmldata==NULL) return(-2);
int compression=config.cfg.GzipCompression;
int fnsize=strlen(filename)+100;
char *filenamenew=new char [fnsize];
snprintf(filenamenew,fnsize,"%s",filename);
int result=dosavefile(filenamenew,compression,xmldata);
delete []filenamenew;
free(xmldata);
int result=dosavefile(filename.c_str(),compression,xmldata);
free(xmldata);
return(result);
};
char *XMLwrapper::getXMLdata(){
char *XMLwrapper::getXMLdata()
{
xml_k=0;
ZERO(tabs,STACKSIZE+2);
mxml_node_t *oldnode=node;
node=info;
//Info storing
addparbool("PADsynth_used",information.PADsynth_used);
node=oldnode;
char *xmldata=mxmlSaveAllocString(tree,XMLwrapper_whitespace_callback);
@@ -196,62 +203,70 @@ char *XMLwrapper::getXMLdata(){
};
int XMLwrapper::dosavefile(const char *filename,int compression,const char *xmldata){
if (compression==0){
FILE *file;
file=fopen(filename,"w");
if (file==NULL) return(-1);
fputs(xmldata,file);
fclose(file);
int XMLwrapper::dosavefile(const char *filename,int compression,const char *xmldata)
{
if (compression==0) {
FILE *file;
file=fopen(filename,"w");
if (file==NULL) return(-1);
fputs(xmldata,file);
fclose(file);
} else {
if (compression>9) compression=9;
if (compression<1) compression=1;
char options[10];
snprintf(options,10,"wb%d",compression);
if (compression>9) compression=9;
if (compression<1) compression=1;
char options[10];
snprintf(options,10,"wb%d",compression);
gzFile gzfile;
gzfile=gzopen(filename,options);
if (gzfile==NULL) return(-1);
gzputs(gzfile,xmldata);
gzclose(gzfile);
gzFile gzfile;
gzfile=gzopen(filename,options);
if (gzfile==NULL) return(-1);
gzputs(gzfile,xmldata);
gzclose(gzfile);
};
return(0);
};
void XMLwrapper::addpar(const char *name,int val){
addparams2("par","name",name,"value",int2str(val));
void XMLwrapper::addpar(const string &name,int val)
{
addparams2("par","name",name.c_str(),"value",int2str(val));
};
void XMLwrapper::addparreal(const char *name,REALTYPE val){
addparams2("par_real","name",name,"value",real2str(val));
void XMLwrapper::addparreal(const string &name,REALTYPE val)
{
addparams2("par_real","name",name.c_str(),"value",real2str(val));
};
void XMLwrapper::addparbool(const char *name,int val){
if (val!=0) addparams2("par_bool","name",name,"value","yes");
else addparams2("par_bool","name",name,"value","no");
void XMLwrapper::addparbool(const string &name,int val)
{
if (val!=0) addparams2("par_bool","name",name.c_str(),"value","yes");
else addparams2("par_bool","name",name.c_str(),"value","no");
};
void XMLwrapper::addparstr(const char *name,const char *val){
void XMLwrapper::addparstr(const string &name,const string &val)
{
mxml_node_t *element=mxmlNewElement(node,"string");
mxmlElementSetAttr(element,"name",name);
mxmlNewText(element,0,val);
mxmlElementSetAttr(element,"name",name.c_str());
mxmlNewText(element,0,val.c_str());
};
void XMLwrapper::beginbranch(const char *name){
void XMLwrapper::beginbranch(const string &name)
{
push(node);
node=addparams0(name);
node=addparams0(name.c_str());
};
void XMLwrapper::beginbranch(const char *name,int id){
void XMLwrapper::beginbranch(const string &name,int id)
{
push(node);
node=addparams1(name,"id",int2str(id));
node=addparams1(name.c_str(),"id",int2str(id));
};
void XMLwrapper::endbranch(){
void XMLwrapper::endbranch()
{
node=pop();
};
@@ -259,7 +274,8 @@ void XMLwrapper::endbranch(){
/* LOAD XML members */
int XMLwrapper::loadXMLfile(const char *filename){
int XMLwrapper::loadXMLfile(const string &filename)
{
if (tree!=NULL) mxmlDelete(tree);
tree=NULL;
@@ -268,16 +284,16 @@ int XMLwrapper::loadXMLfile(const char *filename){
stackpos=0;
const char *xmldata=doloadfile(filename);
const char *xmldata=doloadfile(filename.c_str());
if (xmldata==NULL) return(-1);//the file could not be loaded or uncompressed
root=tree=mxmlLoadString(NULL,xmldata,MXML_OPAQUE_CALLBACK);
delete []xmldata;
if (tree==NULL) return(-2);//this is not XML
node=root=mxmlFindElement(tree,tree,"ZynAddSubFX-data",NULL,NULL,MXML_DESCEND);
if (root==NULL) return(-3);//the XML doesnt embbed zynaddsubfx data
push(root);
@@ -289,51 +305,39 @@ int XMLwrapper::loadXMLfile(const char *filename){
};
char *XMLwrapper::doloadfile(const char *filename){
char *xmldata=NULL;
int filesize=-1;
//try get filesize as gzip data (first)
gzFile gzfile=gzopen(filename,"rb");
if (gzfile!=NULL){//this is a gzip file
// first check it's size
while(!gzeof(gzfile)) {
gzseek (gzfile,1024*1024,SEEK_CUR);
if (gztell(gzfile)>10000000) {
gzclose(gzfile);
goto notgzip;//the file is too big
};
};
filesize=gztell(gzfile);
char *XMLwrapper::doloadfile(const string &filename)
{
char * xmldata = NULL;
gzFile gzfile = gzopen(filename.c_str(),"rb");
//rewind the file and load the data
xmldata=new char[filesize+1];
ZERO(xmldata,filesize+1);
if (gzfile != NULL) {//The possibly compressed file opened
gzrewind(gzfile);
gzread(gzfile,xmldata,filesize);
gzclose(gzfile);
return (xmldata);
} else {//this is not a gzip file
notgzip:
FILE *file=fopen(filename,"rb");
if (file==NULL) return(NULL);
fseek(file,0,SEEK_END);
filesize=ftell(file);
stringstream strBuf; //reading stream
const int bufSize = 500; //fetch size
char fetchBuf[bufSize+1];//fetch buffer
int read = 0; //chars read in last fetch
xmldata=new char [filesize+1];
ZERO(xmldata,filesize+1);
rewind(file);
fread(xmldata,filesize,1,file);
fclose(file);
return(xmldata);
};
};
fetchBuf[bufSize] = 0;//force null termination
bool XMLwrapper::putXMLdata(const char *xmldata){
while(bufSize == (read = gzread(gzfile, fetchBuf, bufSize)))
strBuf << fetchBuf;
fetchBuf[read] = 0;//Truncate last partial read
strBuf << fetchBuf;
gzclose(gzfile);
//Place data in output format
string tmp = strBuf.str();
xmldata = new char[tmp.size()+1];
strncpy(xmldata, tmp.c_str(), tmp.size()+1);
}
return xmldata;
}
bool XMLwrapper::putXMLdata(const char *xmldata)
{
if (tree!=NULL) mxmlDelete(tree);
tree=NULL;
@@ -343,11 +347,11 @@ bool XMLwrapper::putXMLdata(const char *xmldata){
stackpos=0;
if (xmldata==NULL) return (false);
root=tree=mxmlLoadString(NULL,xmldata,MXML_OPAQUE_CALLBACK);
if (tree==NULL) return(false);
node=root=mxmlFindElement(tree,tree,"ZynAddSubFX-data",NULL,NULL,MXML_DESCEND);
if (root==NULL) return (false);;
push(root);
@@ -357,17 +361,19 @@ bool XMLwrapper::putXMLdata(const char *xmldata){
int XMLwrapper::enterbranch(const char *name){
node=mxmlFindElement(peek(),peek(),name,NULL,NULL,MXML_DESCEND_FIRST);
int XMLwrapper::enterbranch(const string &name)
{
node=mxmlFindElement(peek(),peek(),name.c_str(),NULL,NULL,MXML_DESCEND_FIRST);
if (node==NULL) return(0);
push(node);
return(1);
};
int XMLwrapper::enterbranch(const char *name,int id){
int XMLwrapper::enterbranch(const string &name,int id)
{
snprintf(tmpstr,TMPSTR_SIZE,"%d",id);
node=mxmlFindElement(peek(),peek(),name,"id",tmpstr,MXML_DESCEND_FIRST);
node=mxmlFindElement(peek(),peek(),name.c_str(),"id",tmpstr,MXML_DESCEND_FIRST);
if (node==NULL) return(0);
push(node);
@@ -375,142 +381,157 @@ int XMLwrapper::enterbranch(const char *name,int id){
};
void XMLwrapper::exitbranch(){
void XMLwrapper::exitbranch()
{
/**@bug Does not set the current node correctly*/
pop();
};
int XMLwrapper::getbranchid(int min, int max){
int XMLwrapper::getbranchid(int min, int max)
{
int id=str2int(mxmlElementGetAttr(node,"id"));
if ((min==0)&&(max==0)) return(id);
if (id<min) id=min;
else if (id>max) id=max;
else if (id>max) id=max;
return(id);
};
int XMLwrapper::getpar(const char *name,int defaultpar,int min,int max){
node=mxmlFindElement(peek(),peek(),"par","name",name,MXML_DESCEND_FIRST);
int XMLwrapper::getpar(const string &name,int defaultpar,int min,int max)
{
node=mxmlFindElement(peek(),peek(),"par","name",name.c_str(),MXML_DESCEND_FIRST);
if (node==NULL) return(defaultpar);
const char *strval=mxmlElementGetAttr(node,"value");
if (strval==NULL) return(defaultpar);
int val=str2int(strval);
if (val<min) val=min;
else if (val>max) val=max;
else if (val>max) val=max;
return(val);
};
int XMLwrapper::getpar127(const char *name,int defaultpar){
int XMLwrapper::getpar127(const string &name,int defaultpar)
{
return(getpar(name,defaultpar,0,127));
};
int XMLwrapper::getparbool(const char *name,int defaultpar){
node=mxmlFindElement(peek(),peek(),"par_bool","name",name,MXML_DESCEND_FIRST);
int XMLwrapper::getparbool(const string &name,int defaultpar)
{
node=mxmlFindElement(peek(),peek(),"par_bool","name",name.c_str(),MXML_DESCEND_FIRST);
if (node==NULL) return(defaultpar);
const char *strval=mxmlElementGetAttr(node,"value");
if (strval==NULL) return(defaultpar);
if ((strval[0]=='Y')||(strval[0]=='y')) return(1);
else return(0);
else return(0);
};
void XMLwrapper::getparstr(const char *name,char *par,int maxstrlen){
void XMLwrapper::getparstr(const string &name,char *par,int maxstrlen)
{
ZERO(par,maxstrlen);
node=mxmlFindElement(peek(),peek(),"string","name",name,MXML_DESCEND_FIRST);
node=mxmlFindElement(peek(),peek(),"string","name",name.c_str(),MXML_DESCEND_FIRST);
if (node==NULL) return;
if (node->child==NULL) return;
if (node->child->type!=MXML_OPAQUE) return;
snprintf(par,maxstrlen,"%s",node->child->value.element.name);
};
REALTYPE XMLwrapper::getparreal(const char *name,REALTYPE defaultpar){
REALTYPE XMLwrapper::getparreal(const char *name,REALTYPE defaultpar)
{
node=mxmlFindElement(peek(),peek(),"par_real","name",name,MXML_DESCEND_FIRST);
if (node==NULL) return(defaultpar);
const char *strval=mxmlElementGetAttr(node,"value");
if (strval==NULL) return(defaultpar);
return(str2real(strval));
};
REALTYPE XMLwrapper::getparreal(const char *name,REALTYPE defaultpar,REALTYPE min,REALTYPE max){
REALTYPE XMLwrapper::getparreal(const char *name,REALTYPE defaultpar,REALTYPE min,REALTYPE max)
{
REALTYPE result=getparreal(name,defaultpar);
if (result<min) result=min;
else if (result>max) result=max;
else if (result>max) result=max;
return(result);
};
/** Private members **/
char *XMLwrapper::int2str(int x){
char *XMLwrapper::int2str(int x)
{
snprintf(tmpstr,TMPSTR_SIZE,"%d",x);
return(tmpstr);
};
char *XMLwrapper::real2str(REALTYPE x){
char *XMLwrapper::real2str(REALTYPE x)
{
snprintf(tmpstr,TMPSTR_SIZE,"%g",x);
return(tmpstr);
};
int XMLwrapper::str2int(const char *str){
int XMLwrapper::str2int(const char *str)
{
if (str==NULL) return(0);
int result=strtol(str,NULL,10);
return(result);
};
REALTYPE XMLwrapper::str2real(const char *str){
REALTYPE XMLwrapper::str2real(const char *str)
{
if (str==NULL) return(0.0);
REALTYPE result=strtod(str,NULL);
return(result);
};
mxml_node_t *XMLwrapper::addparams0(const char *name){
mxml_node_t *XMLwrapper::addparams0(const char *name)
{
mxml_node_t *element=mxmlNewElement(node,name);
return(element);
};
mxml_node_t *XMLwrapper::addparams1(const char *name,const char *par1,const char *val1){
mxml_node_t *XMLwrapper::addparams1(const char *name,const char *par1,const char *val1)
{
mxml_node_t *element=mxmlNewElement(node,name);
mxmlElementSetAttr(element,par1,val1);
return(element);
};
mxml_node_t *XMLwrapper::addparams2(const char *name,const char *par1,const char *val1,const char *par2, const char *val2){
mxml_node_t *XMLwrapper::addparams2(const char *name,const char *par1,const char *val1,const char *par2, const char *val2)
{
mxml_node_t *element=mxmlNewElement(node,name);
mxmlElementSetAttr(element,par1,val1);
mxmlElementSetAttr(element,par2,val2);
return(element);
};
void XMLwrapper::push(mxml_node_t *node){
void XMLwrapper::push(mxml_node_t *node)
{
if (stackpos>=STACKSIZE-1) {
printf("BUG!: XMLwrapper::push() - full parentstack\n");
return;
cerr << "BUG!: XMLwrapper::push() - full parentstack" << endl;
return;
};
stackpos++;
parentstack[stackpos]=node;
// printf("push %d - %s\n",stackpos,node->value.element.name);
};
mxml_node_t *XMLwrapper::pop(){
mxml_node_t *XMLwrapper::pop()
{
if (stackpos<=0) {
printf("BUG!: XMLwrapper::pop() - empty parentstack\n");
return (root);
cerr << "BUG!: XMLwrapper::pop() - empty parentstack" << endl;
return (root);
};
mxml_node_t *node=parentstack[stackpos];
parentstack[stackpos]=NULL;
@@ -521,10 +542,11 @@ mxml_node_t *XMLwrapper::pop(){
return(node);
};
mxml_node_t *XMLwrapper::peek(){
mxml_node_t *XMLwrapper::peek()
{
if (stackpos<=0) {
printf("BUG!: XMLwrapper::peek() - empty parentstack\n");
return (root);
cerr << "BUG!: XMLwrapper::peek() - empty parentstack" << endl;
return (root);
};
return(parentstack[stackpos]);
};

View File

@@ -1,12 +1,14 @@
/*
ZynAddSubFX - a software synthesizer
XML.h - XML wrapper
XMLwrapper.h - XML wrapper
Copyright (C) 2003-2005 Nasca Octavian Paul
Copyright (C) 2009-2009 Mark McCurry
Author: Nasca Octavian Paul
Mark McCurry
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
@@ -20,7 +22,8 @@
*/
#include <mxml/mxml.h>
#include <mxml.h>
#include <string>
#ifndef REALTYPE
#define REALTYPE float
#endif
@@ -33,143 +36,282 @@
//the maxim tree depth
#define STACKSIZE 100
class XMLwrapper{
public:
XMLwrapper();
~XMLwrapper();
/********************************/
/* SAVE to XML */
/********************************/
/**Mxml wrapper*/
class XMLwrapper
{
public:
/**
* Constructor.
* Will Construct the object and fill in top level branch
* */
XMLwrapper();
//returns 0 if ok or -1 if the file cannot be saved
int saveXMLfile(const char *filename);
/**Destructor*/
~XMLwrapper();
//returns the new allocated string that contains the XML data (used for clipboard)
//the string is NULL terminated
char *getXMLdata();
//add simple parameter (name and value)
void addpar(const char *name,int val);
void addparreal(const char *name,REALTYPE val);
//add boolean parameter (name and boolean value)
//if the value is 0 => "yes", else "no"
void addparbool(const char *name,int val);
/**
* Saves the XML to a file.
* @param filename the name of the destination file.
* @returns 0 if ok or -1 if the file cannot be saved.
*/
int saveXMLfile(const std::string &filename);
//add string parameter (name and string)
void addparstr(const char *name,const char *val);
/**
* Return XML tree as a string.
* Note: The string must be freed with free() to deallocate
* @returns a newly allocated NULL terminated string of the XML data.
*/
char *getXMLdata();
//add a branch
void beginbranch(const char *name);
void beginbranch(const char *name, int id);
/**
* Add simple parameter.
* @param name The name of the mXML node.
* @param val The string value of the mXml node
*/
void addpar(const std::string &name,int val);
//this must be called after each branch (nodes that contains child nodes)
void endbranch();
/**
* Adds a realtype parameter.
* @param name The name of the mXML node.
* @param val The REALTYPE value of the node.
*/
void addparreal(const std::string &name,REALTYPE val);
/********************************/
/* LOAD from XML */
/********************************/
//returns 0 if ok or -1 if the file cannot be loaded
int loadXMLfile(const char *filename);
/**
* Add boolean parameter.
* \todo Fix this reverse boolean logic.
* @param name The name of the mXML node.
* @param val The boolean value of the node (0->"yes";else->"no").
*/
void addparbool(const std::string &name,int val);
//used by the clipboard
bool putXMLdata(const char *xmldata);
//enter into the branch
//returns 1 if is ok, or 0 otherwise
int enterbranch(const char *name);
/**
* Add string parameter.
* @param name The name of the mXML node.
* @param val The string value of the node.
*/
void addparstr(const std::string &name,const std::string &val);
//enter into the branch with id
//returns 1 if is ok, or 0 otherwise
int enterbranch(const char *name, int id);
/**
* Create a new branch.
* @param name Name of new branch
* @see void endbranch()
*/
void beginbranch(const std::string &name);
/**
* Create a new branch.
* @param name Name of new branch
* @param id "id" value of branch
* @see void endbranch()
*/
void beginbranch(const std::string &name, int id);
//exits from a branch
void exitbranch();
//get the the branch_id and limits it between the min and max
//if min==max==0, it will not limit it
//if there isn't any id, will return min
//this must be called only imediately after enterbranch()
int getbranchid(int min, int max);
/**Closes new branches.
* This must be called to exit each branch created by beginbranch( ).
* @see void beginbranch(const std::string &name)
* @see void beginbranch(const std::string &name, int id)
*/
void endbranch();
//it returns the parameter and limits it between min and max
//if min==max==0, it will not limit it
//if no parameter will be here, the defaultpar will be returned
int getpar(const char *name,int defaultpar,int min,int max);
/**
* Loads file into XMLwrapper.
* @param filename file to be loaded
* @returns 0 if ok or -1 if the file cannot be loaded
*/
int loadXMLfile(const std::string &filename);
//the same as getpar, but the limits are 0 and 127
int getpar127(const char *name,int defaultpar);
int getparbool(const char *name,int defaultpar);
/**
* Loads string into XMLwrapper.
* @param xmldata NULL terminated string of XML data.
* @returns true if successful.
*/
bool putXMLdata(const char *xmldata);
void getparstr(const char *name,char *par,int maxstrlen);
REALTYPE getparreal(const char *name,REALTYPE defaultpar);
REALTYPE getparreal(const char *name,REALTYPE defaultpar,REALTYPE min,REALTYPE max);
/**
* Enters the branch.
* @param name Name of branch.
* @returns 1 if is ok, or 0 otherwise.
*/
int enterbranch(const std::string &name);
bool minimal;//false if all parameters will be stored (used only for clipboard)
struct {
bool PADsynth_used;
}information;
//opens a file and parse only the "information" data on it
//returns "true" if all went ok or "false" on errors
bool checkfileinformation(const char *filename);
private:
int dosavefile(const char *filename,int compression,const char *xmldata);
char *doloadfile(const char *filename);
/**
* Enter into the branch \c name with id \c id.
* @param name Name of branch.
* @param id Value of branch's "id".
* @returns 1 if is ok, or 0 otherwise.
*/
int enterbranch(const std::string &name, int id);
mxml_node_t *tree;//all xml data
mxml_node_t *root;//xml data used by zynaddsubfx
mxml_node_t *node;//current node
mxml_node_t *info;//this node is used to store the information about the data
//adds params like this:
// <name>
//returns the node
mxml_node_t *addparams0(const char *name);
/**Exits from a branch*/
void exitbranch();
//adds params like this:
// <name par1="val1">
//returns the node
mxml_node_t *addparams1(const char *name,const char *par1,const char *val1);
/**Get the the branch_id and limits it between the min and max.
* if min==max==0, it will not limit it
* if there isn't any id, will return min
* this must be called only imediately after enterbranch()
*/
int getbranchid(int min, int max);
//adds params like this:
// <name par1="val1" par2="val2">
//returns the node
mxml_node_t *addparams2(const char *name,const char *par1,const char *val1,const char *par2, const char *val2);
char *int2str(int x);
char *real2str(REALTYPE x);
int str2int(const char *str);
REALTYPE str2real(const char *str);
char tmpstr[TMPSTR_SIZE];
//this is used to store the parents
mxml_node_t *parentstack[STACKSIZE];
int stackpos;
/**
* Returns the integer value stored in node name.
* It returns the integer value between the limits min and max.
* If min==max==0, then the value will not be limited.
* If there is no location named name, then defaultpar will be returned.
* @param name The parameter name.
* @param defaultpar The default value if the real value is not found.
* @param min The minimum return value.
* @param max The maximum return value.
*/
int getpar(const std::string &name,int defaultpar,int min,int max);
void push(mxml_node_t *node);
mxml_node_t *pop();
mxml_node_t *peek();
/**
* Returns the integer value stored in the node with range [0,127].
* @param name The parameter name.
* @param defaultpar The default value if the real value is not found.
*/
int getpar127(const std::string &name,int defaultpar);
/**
* Returns the boolean value stored in the node.
* @param name The parameter name.
* @param defaultpar The default value if the real value is not found.
*/
int getparbool(const std::string &name,int defaultpar);
/**
* Get the string value stored in the node.
* @param name The parameter name.
* @param par Pointer to destination string
* @param maxstrlen Max string length for destination
*/
void getparstr(const std::string &name,char *par,int maxstrlen);
/**
* Returns the real value stored in the node.
* @param name The parameter name.
* @param defaultpar The default value if the real value is not found.
*/
REALTYPE getparreal(const char *name,REALTYPE defaultpar);
/**
* Returns the real value stored in the node.
* @param name The parameter name.
* @param defaultpar The default value if the real value is not found.
* @param min The minimum value
* @param max The maximum value
*/
REALTYPE getparreal(const char *name,REALTYPE defaultpar,REALTYPE min,REALTYPE max);
bool minimal;/**<false if all parameters will be stored (used only for clipboard)*/
struct {
bool PADsynth_used;/**<if PADsynth is used*/
}information;/**<Defines if PADsynth is used*/
/**
* Opens a file and parses the "information" section data on it.
* @returns "true" if all went ok or "false" on errors.
*/
bool checkfileinformation(const char *filename);
private:
/**
* Save the file.
* @param filename File to save to
* @param compression Level of gzip compression
* @param xmldata String to be saved
*/
int dosavefile(const char *filename,int compression,const char *xmldata);
/**
* Loads specified file and returns data.
*
* Will load a gziped file or an uncompressed file.
* @param filename the file
* @return The decompressed data
*/
char *doloadfile(const std::string &filename);
mxml_node_t *tree;/**<all xml data*/
mxml_node_t *root;/**<xml data used by zynaddsubfx*/
mxml_node_t *node;/**<current node*/
mxml_node_t *info;/**<Node used to store the information about the data*/
/**
* Adds params like this:
* <name>.
* @returns The node
*/
mxml_node_t *addparams0(const char *name);
/**
* Adds params like this:
* <name par1="val1">.
* @returns The node
*/
mxml_node_t *addparams1(const char *name,const char *par1,const char *val1);
/**
* Adds params like this:
* <name par1="val1" par2="val2">.
* @returns the node
*/
mxml_node_t *addparams2(const char *name,const char *par1,const char *val1,const char *par2, const char *val2);
/**
* Convert integer to string
* @param x integer input
* @returns string output
*/
char *int2str(int x);
/**
* Convert integer to string
* @param x integer input
* @returns string output
*/
char *real2str(REALTYPE x);
/**
* Convert string to int
* @param str string input
* @returns integer output
*/
int str2int(const char *str);
/**
* Convert string to realtype
* @param x integer input
* @returns string output
*/
REALTYPE str2real(const char *str);
/**Temporary string for various uses*/
char tmpstr[TMPSTR_SIZE];
/**this is used to store the parents.
* @todo Use the stack class provided by C++*/
mxml_node_t *parentstack[STACKSIZE];
int stackpos;/**<position in stack*/
void push(mxml_node_t *node);
/**Pops top node off of parent stack*/
mxml_node_t *pop();
/**Returns top node off of parent stack*/
mxml_node_t *peek();
struct {
struct {
int major;/**<major version number.*/
int minor;/**<minor version number.*/
}xml_version;/**<Stores ZynAddSubFX versioning information*/
}values;/**< Stores ZynAddSubFX versioning information*/
//theese are used to store the values
struct{
struct {
int major,minor;
}xml_version;
}values;
};
#endif

View File

@@ -0,0 +1,33 @@
set(zynaddsubfx_output_SRCS
Recorder.cpp
WAVaudiooutput.cpp
)
if(AlsaMidiOutput)
set(zynaddsubfx_output_SRCS
${zynaddsubfx_output_SRCS}
OSSaudiooutput.cpp)
set(zynaddsubfx_output_lib ${ASOUND_LIBRARY})
endif(AlsaMidiOutput)
if(JackOutput)
include_directories(${JACK_INCLUDE_DIR})
set(zynaddsubfx_output_SRCS
${zynaddsubfx_output_SRCS}
JACKaudiooutput.cpp)
set(zynaddsubfx_output_lib ${JACK_LIBRARIES})
endif(JackOutput)
if(PortAudioOutput)
include_directories(${PORTAUDIO_INCLUDE_DIR})
set(zynaddsubfx_output_SRCS
${zynaddsubfx_output_SRCS}
PAaudiooutput.cpp)
set(zynaddsubfx_output_lib ${PORTAUDIO_LIBRARIES})
endif(PortAudioOutput)
add_library(zynaddsubfx_output STATIC
${zynaddsubfx_output_SRCS}
)
target_link_libraries(zynaddsubfx_output ${zynaddsubfx_output_lib})

View File

@@ -1,279 +0,0 @@
/*
ZynAddSubFX - a software synthesizer
DSSIaudiooutput.C - Audio functions for DSSI
Copyright (C) 2002 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
//this file contains code used from trivial_synth.c from
//the DSSI (published by Steve Harris under public domain) as a template
//the code is incomplete
#include <string.h>
#include "DSSIaudiooutput.h"
static LADSPA_Descriptor *tsLDescriptor = NULL;
static DSSI_Descriptor *tsDDescriptor = NULL;
typedef struct {
LADSPA_Data *outl;
LADSPA_Data *outr;
// note_data data[MIDI_NOTES];
// float omega[MIDI_NOTES];
} TS;
static void cleanupTS(LADSPA_Handle instance){
free(instance);
}
static void connectPortTS(LADSPA_Handle instance, unsigned long port,
LADSPA_Data * data){
TS *plugin;
plugin = (TS *) instance;
switch (port) {
case 0:
plugin->outl = data;
break;
case 1:
plugin->outr = data;
break;
}
}
const LADSPA_Descriptor *ladspa_descriptor(unsigned long index){
switch (index) {
case 0:
return tsLDescriptor;
default:
return NULL;
}
}
const DSSI_Descriptor *dssi_descriptor(unsigned long index){
// FILE *a=fopen("/tmp/zzzzz11z","w");
// fprintf(a,"aaaaaaaaaaa TEST\n");
// fclose(a);
switch (index) {
case 0:
return tsDDescriptor;
default:
return NULL;
}
}
static LADSPA_Handle instantiateTS(const LADSPA_Descriptor * descriptor,
unsigned long s_rate)
{
TS *plugin_data = (TS *) malloc(sizeof(TS));
/* for (i=0; i<MIDI_NOTES; i++) {
plugin_data->omega[i] = M_PI * 2.0 / (double)s_rate *
pow(2.0, (i-69.0) / 12.0);
}
*/
return (LADSPA_Handle) plugin_data;
}
static void activateTS(LADSPA_Handle instance)
{
TS *plugin_data = (TS *) instance;
// for (i=0; i<MIDI_NOTES; i++) {
// plugin_data->data[i].active = 0;
// }
}
static void runTS(LADSPA_Handle instance, unsigned long sample_count,
snd_seq_event_t *events, unsigned long event_count){
TS *plugin_data = (TS *) instance;
// LADSPA_Data *const output = plugin_data->output;
// LADSPA_Data freq = *(plugin_data->freq);
// LADSPA_Data vol = *(plugin_data->vol);
// note_data *data = plugin_data->data;
unsigned long pos;
unsigned long event_pos;
unsigned long note;
/* if (freq < 1.0) {
freq = 440.0f;
}
if (vol < 0.000001) {
vol = 1.0f;
}
if (event_count > 0) {
printf("trivial_synth: have %ld events\n", event_count);
}
for (pos = 0, event_pos = 0; pos < sample_count; pos++) {
while (event_pos < event_count
&& pos == events[event_pos].time.tick) {
printf("trivial_synth: event type %d\n", events[event_pos].type);
if (events[event_pos].type == SND_SEQ_EVENT_NOTEON) {
data[events[event_pos].data.note.note].amp =
events[event_pos].data.note.velocity / 512.0f;
data[events[event_pos].data.note.note].
active = events[event_pos].data.note.velocity > 0;
data[events[event_pos].data.note.note].
phase = 0.0;
} else if (events[event_pos].type == SND_SEQ_EVENT_NOTEOFF) {
data[events[event_pos].data.note.note].
active = 0;
}
event_pos++;
}
output[pos] = 0.0f;
for (note = 0; note < MIDI_NOTES; note++) {
if (data[note].active) {
output[pos] += sin(data[note].phase) * data[note].amp * vol;
data[note].phase += plugin_data->omega[note] * freq;
if (data[note].phase > M_PI * 2.0) {
data[note].phase -= M_PI * 2.0;
}
}
}
}
*/
}
static void runTSWrapper(LADSPA_Handle instance,
unsigned long sample_count){
runTS(instance, sample_count, NULL, 0);
}
int getControllerTS(LADSPA_Handle instance, unsigned long port){
return -1;
}
void _init(){
char **port_names;
LADSPA_PortDescriptor *port_descriptors;
LADSPA_PortRangeHint *port_range_hints;
FILE *a=fopen("/tmp/zzzzzz","w");
fprintf(a,"aaaaaaaaaaa TEST\n");
fclose(a);
tsLDescriptor = (LADSPA_Descriptor *) malloc(sizeof(LADSPA_Descriptor));
if (tsLDescriptor) {
tsLDescriptor->UniqueID = 100;
tsLDescriptor->Label = "ZASF";
tsLDescriptor->Properties = 0;
tsLDescriptor->Name = "ZynAddSubFX";
tsLDescriptor->Maker = "Nasca Octavian Paul <zynaddsubfx@yahoo.com>";
tsLDescriptor->Copyright = "GNU General Public License v.2";
tsLDescriptor->PortCount = 2;
port_descriptors = (LADSPA_PortDescriptor *)
calloc(tsLDescriptor->PortCount, sizeof
(LADSPA_PortDescriptor));
tsLDescriptor->PortDescriptors =
(const LADSPA_PortDescriptor *) port_descriptors;
port_range_hints = (LADSPA_PortRangeHint *)
calloc(tsLDescriptor->PortCount, sizeof
(LADSPA_PortRangeHint));
tsLDescriptor->PortRangeHints =
(const LADSPA_PortRangeHint *) port_range_hints;
port_names = (char **) calloc(tsLDescriptor->PortCount, sizeof(char *));
tsLDescriptor->PortNames = (const char **) port_names;
port_descriptors[0] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;
port_names[0] = "Output L";
port_range_hints[0].HintDescriptor = 0;
port_descriptors[1] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;
port_names[1] = "Output R";
port_range_hints[1].HintDescriptor = 0;
tsLDescriptor->activate = activateTS;
tsLDescriptor->cleanup = cleanupTS;
tsLDescriptor->connect_port = connectPortTS;
tsLDescriptor->deactivate = NULL;
tsLDescriptor->instantiate = instantiateTS;
tsLDescriptor->run = runTSWrapper;
tsLDescriptor->run_adding = NULL;
tsLDescriptor->set_run_adding_gain = NULL;
}
tsDDescriptor = (DSSI_Descriptor *) malloc(sizeof(DSSI_Descriptor));
if (tsDDescriptor) {
tsDDescriptor->DSSI_API_Version = 1;
tsDDescriptor->LADSPA_Plugin = tsLDescriptor;
tsDDescriptor->configure = NULL;
tsDDescriptor->get_program = NULL;
tsDDescriptor->get_midi_controller_for_port = getControllerTS;
tsDDescriptor->select_program = NULL;
tsDDescriptor->run_synth = runTS;
tsDDescriptor->run_synth_adding = NULL;
tsDDescriptor->run_multiple_synths = NULL;
tsDDescriptor->run_multiple_synths_adding = NULL;
}
};
void _fini(){
};
//the constructor and the destructor are defined in main.C
/*
void VSTSynth::process (float **inputs, float **outputs, long sampleframes){
float *outl=outputs[0];
float *outr=outputs[1];
pthread_mutex_lock(&vmaster->mutex);
vmaster->GetAudioOutSamples(sampleframes,(int) getSampleRate(),outl,outr);
pthread_mutex_unlock(&vmaster->mutex);
};
void VSTSynth::processReplacing (float **inputs, float **outputs, long sampleframes){
process(inputs,outputs,sampleframes);
};
long int VSTSynth::canDo(char *txt){
if (strcmp(txt,"receiveVstEvents")==0) return (1);
if (strcmp(txt,"receiveVstMidiEvent")==0) return (1);
return(-1);
};
bool VSTSynth::getVendorString(char *txt){
strcpy(txt,"Nasca O. Paul");
return(true);
};
bool VSTSynth::getProductString(char *txt){
strcpy(txt,"ZynAddSubFX");
return(true);
};
void VSTSynth::resume(){
wantEvents();
};
*/

Some files were not shown because too many files have changed in this diff Show More