Initial integration of updated ZynAddSubFX
This commit is contained in:
@@ -128,7 +128,7 @@ const int MidiControllerCount = 128;
|
||||
const int MidiProgramCount = 128;
|
||||
const int MidiMaxVelocity = 127;
|
||||
const int MidiMaxControllerValue = 127;
|
||||
const int MidiMaxNote = 127;
|
||||
const int MidiMaxKey = 127;
|
||||
|
||||
const int MidiMaxPanning = 127;
|
||||
const int MidiMinPanning = -128;
|
||||
|
||||
@@ -1,26 +1,5 @@
|
||||
INCLUDE(BuildPlugin)
|
||||
|
||||
SET(ZYN_SRC_GUI
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/UI/MasterUI.cc"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/UI/VirKeyboard.cc"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/UI/ConfigUI.cc"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/UI/OscilGenUI.cc"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/UI/WidgetPDial.cc"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/UI/ResonanceUI.cc"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/UI/MicrotonalUI.cc"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/UI/ADnoteUI.cc"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/UI/PresetsUI.cc"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/UI/EffUI.cc"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/UI/FilterUI.cc"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/UI/PartUI.cc"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/UI/EnvelopeUI.cc"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/UI/LFOUI.cc"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/UI/SeqUI.cc"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/UI/PADnoteUI.cc"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/UI/SUBnoteUI.cc"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/UI/BankUI.cc"
|
||||
)
|
||||
|
||||
|
||||
# definitions for ZynAddSubFX
|
||||
IF(LMMS_BUILD_LINUX OR LMMS_BUILD_APPLE)
|
||||
@@ -48,42 +27,80 @@ ENDIF(LMMS_BUILD_WIN32)
|
||||
SET(FLTK_SKIP_OPENGL TRUE)
|
||||
SET(FLTK_SKIP_FORMS TRUE)
|
||||
SET(FLTK_SKIP_IMAGES TRUE)
|
||||
SET(FLTK_SKIP_FLUID TRUE)
|
||||
SET(FLTK_SKIP_MATH TRUE)
|
||||
IF(MINGW_PREFIX)
|
||||
SET(FLTK_SKIP_FLUID TRUE)
|
||||
ENDIF()
|
||||
|
||||
FIND_PACKAGE(FLTK REQUIRED)
|
||||
|
||||
IF(MINGW_PREFIX)
|
||||
SET(FLTK_FLUID_EXECUTABLE "${MINGW_PREFIX}/bin/fluid")
|
||||
ENDIF()
|
||||
|
||||
INCLUDE_DIRECTORIES("${FLTK_INCLUDE_DIR}"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
${FFTW3F_INCLUDE_DIRS}
|
||||
"${CMAKE_CURRENT_BINARY_DIR}"
|
||||
"${CMAKE_BINARY_DIR}")
|
||||
set(ZASF_CORE_LIBS
|
||||
zynaddsubfx_input
|
||||
zynaddsubfx_output
|
||||
zynaddsubfx_misc
|
||||
zynaddsubfx_synth
|
||||
zynaddsubfx_seq
|
||||
zynaddsubfx_effect
|
||||
zynaddsubfx_params
|
||||
zynaddsubfx_dsp
|
||||
zynaddsubfx_samples
|
||||
|
||||
include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/zynaddsubfx/src/UI)
|
||||
|
||||
add_subdirectory(zynaddsubfx/src/Nio)
|
||||
add_subdirectory(zynaddsubfx/src/UI)
|
||||
|
||||
SET(zynaddsubfx_core_SRCS
|
||||
zynaddsubfx/src/DSP/AnalogFilter.cpp
|
||||
zynaddsubfx/src/DSP/FFTwrapper.cpp
|
||||
zynaddsubfx/src/DSP/Filter.cpp
|
||||
zynaddsubfx/src/DSP/FormantFilter.cpp
|
||||
zynaddsubfx/src/DSP/SVFilter.cpp
|
||||
zynaddsubfx/src/DSP/Unison.cpp
|
||||
zynaddsubfx/src/Effects/Alienwah.cpp
|
||||
zynaddsubfx/src/Effects/Chorus.cpp
|
||||
zynaddsubfx/src/Effects/Distorsion.cpp
|
||||
zynaddsubfx/src/Effects/DynamicFilter.cpp
|
||||
zynaddsubfx/src/Effects/Echo.cpp
|
||||
zynaddsubfx/src/Effects/Effect.cpp
|
||||
zynaddsubfx/src/Effects/EffectLFO.cpp
|
||||
zynaddsubfx/src/Effects/EffectMgr.cpp
|
||||
zynaddsubfx/src/Effects/EQ.cpp
|
||||
zynaddsubfx/src/Effects/Phaser.cpp
|
||||
zynaddsubfx/src/Effects/Reverb.cpp
|
||||
zynaddsubfx/src/Misc/Bank.cpp
|
||||
zynaddsubfx/src/Misc/Config.cpp
|
||||
zynaddsubfx/src/Misc/Dump.cpp
|
||||
zynaddsubfx/src/Misc/Master.cpp
|
||||
zynaddsubfx/src/Misc/Microtonal.cpp
|
||||
zynaddsubfx/src/Misc/Part.cpp
|
||||
zynaddsubfx/src/Misc/Util.cpp
|
||||
zynaddsubfx/src/Misc/QtXmlWrapper.cpp
|
||||
zynaddsubfx/src/Misc/Recorder.cpp
|
||||
zynaddsubfx/src/Misc/WavFile.cpp
|
||||
zynaddsubfx/src/Misc/WaveShapeSmps.cpp
|
||||
zynaddsubfx/src/Params/ADnoteParameters.cpp
|
||||
zynaddsubfx/src/Params/Controller.cpp
|
||||
zynaddsubfx/src/Params/EnvelopeParams.cpp
|
||||
zynaddsubfx/src/Params/FilterParams.cpp
|
||||
zynaddsubfx/src/Params/LFOParams.cpp
|
||||
zynaddsubfx/src/Params/PADnoteParameters.cpp
|
||||
zynaddsubfx/src/Params/Presets.cpp
|
||||
zynaddsubfx/src/Params/PresetsArray.cpp
|
||||
zynaddsubfx/src/Params/PresetsStore.cpp
|
||||
zynaddsubfx/src/Params/SUBnoteParameters.cpp
|
||||
zynaddsubfx/src/Synth/SynthNote.cpp
|
||||
zynaddsubfx/src/Synth/ADnote.cpp
|
||||
zynaddsubfx/src/Synth/Envelope.cpp
|
||||
zynaddsubfx/src/Synth/LFO.cpp
|
||||
zynaddsubfx/src/Synth/OscilGen.cpp
|
||||
zynaddsubfx/src/Synth/PADnote.cpp
|
||||
zynaddsubfx/src/Synth/Resonance.cpp
|
||||
zynaddsubfx/src/Synth/SUBnote.cpp
|
||||
)
|
||||
|
||||
macro(unit_test NAME CXX_FILE FILES)
|
||||
endmacro(unit_test)
|
||||
|
||||
add_subdirectory(src/Misc)
|
||||
add_subdirectory(src/Input)
|
||||
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)
|
||||
TARGET_LINK_LIBRARIES(ZynAddSubFxCore ${ZASF_CORE_LIBS} ${FFTW3F_LIBRARIES} ${QT_LIBRARIES} -lz -lpthread)
|
||||
ADD_LIBRARY(ZynAddSubFxCore SHARED LocalZynAddSubFx.cpp ${zynaddsubfx_core_SRCS})
|
||||
TARGET_LINK_LIBRARIES(ZynAddSubFxCore zynaddsubfx_nio ${FFTW3F_LIBRARIES} ${QT_LIBRARIES} -lz -lpthread)
|
||||
IF(LMMS_BUILD_WIN32)
|
||||
TARGET_LINK_LIBRARIES(ZynAddSubFxCore -lws2_32)
|
||||
INSTALL(TARGETS ZynAddSubFxCore RUNTIME DESTINATION "${PLUGIN_DIR}")
|
||||
@@ -106,12 +123,11 @@ ENDIF(WIN32)
|
||||
|
||||
SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${PLUGIN_DIR}")
|
||||
SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
|
||||
ADD_EXECUTABLE(RemoteZynAddSubFx RemoteZynAddSubFx.cpp ${ZYN_SRC_GUI} "${WINRC}")
|
||||
ADD_EXECUTABLE(RemoteZynAddSubFx RemoteZynAddSubFx.cpp "${WINRC}")
|
||||
INSTALL(TARGETS RemoteZynAddSubFx RUNTIME DESTINATION "${PLUGIN_DIR}")
|
||||
TARGET_LINK_LIBRARIES(RemoteZynAddSubFx ${FLTK_LIBRARIES} -lpthread "-L\"${CMAKE_CURRENT_BINARY_DIR}\"" -lZynAddSubFxCore )
|
||||
ADD_DEPENDENCIES(RemoteZynAddSubFx ZynAddSubFxCore)
|
||||
TARGET_LINK_LIBRARIES(RemoteZynAddSubFx zynaddsubfx_gui ZynAddSubFxCore ${FLTK_LIBRARIES} -lpthread )
|
||||
|
||||
# link system libraries when on win32
|
||||
# link Qt libraries when on win32
|
||||
IF(LMMS_BUILD_WIN32)
|
||||
TARGET_LINK_LIBRARIES(RemoteZynAddSubFx ${QT_LIBRARIES})
|
||||
ENDIF(LMMS_BUILD_WIN32)
|
||||
|
||||
@@ -24,19 +24,25 @@
|
||||
|
||||
#include <lmmsconfig.h>
|
||||
|
||||
#include "zynaddsubfx/src/Misc/Util.h"
|
||||
#include <unistd.h>
|
||||
|
||||
#include "LocalZynAddSubFx.h"
|
||||
|
||||
#include "src/Input/NULLMidiIn.h"
|
||||
#include "src/Misc/Master.h"
|
||||
#include "src/Misc/Dump.h"
|
||||
#include "zynaddsubfx/src/Nio/NulEngine.h"
|
||||
#include "zynaddsubfx/src/Misc/Master.h"
|
||||
#include "zynaddsubfx/src/Misc/Part.h"
|
||||
#include "zynaddsubfx/src/Misc/Dump.h"
|
||||
|
||||
|
||||
SYNTH_T* synth = NULL;
|
||||
|
||||
int LocalZynAddSubFx::s_instanceCount = 0;
|
||||
|
||||
|
||||
LocalZynAddSubFx::LocalZynAddSubFx()
|
||||
LocalZynAddSubFx::LocalZynAddSubFx() :
|
||||
m_master( NULL ),
|
||||
m_ioEngine( new NulEngine )
|
||||
{
|
||||
for( int i = 0; i < NumKeys; ++i )
|
||||
{
|
||||
@@ -53,15 +59,19 @@ LocalZynAddSubFx::LocalZynAddSubFx()
|
||||
|
||||
initConfig();
|
||||
|
||||
OSCIL_SIZE = config.cfg.OscilSize;
|
||||
synth = new SYNTH_T;
|
||||
synth->oscilsize = config.cfg.OscilSize;
|
||||
synth->alias();
|
||||
|
||||
srand( time( NULL ) );
|
||||
denormalkillbuf = new REALTYPE[SOUND_BUFFER_SIZE];
|
||||
for( int i = 0; i < SOUND_BUFFER_SIZE; ++i )
|
||||
|
||||
denormalkillbuf = new float[synth->buffersize];
|
||||
for( int i = 0; i < synth->buffersize; ++i )
|
||||
{
|
||||
denormalkillbuf[i] = (RND-0.5)*1e-16;
|
||||
}
|
||||
}
|
||||
|
||||
++s_instanceCount;
|
||||
|
||||
m_master = new Master();
|
||||
@@ -94,17 +104,19 @@ void LocalZynAddSubFx::initConfig()
|
||||
|
||||
|
||||
|
||||
void LocalZynAddSubFx::setSampleRate( int _sampleRate )
|
||||
void LocalZynAddSubFx::setSampleRate( int sampleRate )
|
||||
{
|
||||
SAMPLE_RATE = _sampleRate;
|
||||
synth->samplerate = sampleRate;
|
||||
synth->alias();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void LocalZynAddSubFx::setBufferSize( int _bufferSize )
|
||||
void LocalZynAddSubFx::setBufferSize( int bufferSize )
|
||||
{
|
||||
SOUND_BUFFER_SIZE = _bufferSize;
|
||||
synth->buffersize = bufferSize;
|
||||
synth->alias();
|
||||
}
|
||||
|
||||
|
||||
@@ -160,14 +172,12 @@ void LocalZynAddSubFx::setPresetDir( const std::string & _dir )
|
||||
m_presetsDir = _dir;
|
||||
for( int i = 0; i < MAX_BANK_ROOT_DIRS; ++i )
|
||||
{
|
||||
if( config.cfg.bankRootDirList[i] == NULL )
|
||||
if( config.cfg.bankRootDirList[i].empty() )
|
||||
{
|
||||
config.cfg.bankRootDirList[i] = new char[MAX_STRING_SIZE];
|
||||
strcpy( config.cfg.bankRootDirList[i], m_presetsDir.c_str() );
|
||||
config.cfg.bankRootDirList[i] = m_presetsDir;
|
||||
break;
|
||||
}
|
||||
else if( strcmp( config.cfg.bankRootDirList[i],
|
||||
m_presetsDir.c_str() ) == 0 )
|
||||
else if( config.cfg.bankRootDirList[i] == m_presetsDir )
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -192,41 +202,38 @@ void LocalZynAddSubFx::setLmmsWorkingDir( const std::string & _dir )
|
||||
|
||||
void LocalZynAddSubFx::processMidiEvent( const MidiEvent& event )
|
||||
{
|
||||
// all functions are called while m_master->mutex is held
|
||||
static NULLMidiIn midiIn;
|
||||
|
||||
switch( event.type() )
|
||||
{
|
||||
case MidiNoteOn:
|
||||
if( event.velocity() > 0 )
|
||||
{
|
||||
if( event.key() <= 0 || event.key() >= 128 )
|
||||
if( event.key() < 0 || event.key() > MidiMaxKey )
|
||||
{
|
||||
break;
|
||||
}
|
||||
if( m_runningNotes[event.key()] > 0 )
|
||||
{
|
||||
m_master->NoteOff( event.channel(), event.key() );
|
||||
m_master->noteOff( event.channel(), event.key() );
|
||||
}
|
||||
++m_runningNotes[event.key()];
|
||||
m_master->NoteOn( event.channel(), event.key(), event.velocity() );
|
||||
m_master->noteOn( event.channel(), event.key(), event.velocity() );
|
||||
break;
|
||||
}
|
||||
case MidiNoteOff:
|
||||
if( event.key() <= 0 || event.key() >= 128 )
|
||||
if( event.key() < 0 || event.key() > MidiMaxKey )
|
||||
{
|
||||
break;
|
||||
}
|
||||
if( --m_runningNotes[event.key()] <= 0 )
|
||||
{
|
||||
m_master->NoteOff( event.channel(), event.key() );
|
||||
m_master->noteOff( event.channel(), event.key() );
|
||||
}
|
||||
break;
|
||||
case MidiPitchBend:
|
||||
m_master->SetController( event.channel(), C_pitchwheel, event.pitchBend()-8192 );
|
||||
m_master->setController( event.channel(), C_pitchwheel, event.pitchBend()-8192 );
|
||||
break;
|
||||
case MidiControlChange:
|
||||
m_master->SetController( event.channel(), midiIn.getcontroller( event.controllerNumber() ), event.controllerValue() );
|
||||
m_master->setController( event.channel(), event.controllerNumber(), event.controllerValue() );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -238,12 +245,13 @@ void LocalZynAddSubFx::processMidiEvent( const MidiEvent& event )
|
||||
|
||||
void LocalZynAddSubFx::processAudio( sampleFrame * _out )
|
||||
{
|
||||
REALTYPE outputl[SOUND_BUFFER_SIZE];
|
||||
REALTYPE outputr[SOUND_BUFFER_SIZE];
|
||||
float outputl[synth->buffersize];
|
||||
float outputr[synth->buffersize];
|
||||
|
||||
m_master->AudioOut( outputl, outputr );
|
||||
|
||||
for( int f = 0; f < SOUND_BUFFER_SIZE; ++f )
|
||||
// TODO: move to MixHelpers
|
||||
for( int f = 0; f < synth->buffersize; ++f )
|
||||
{
|
||||
_out[f][0] = outputl[f];
|
||||
_out[f][1] = outputr[f];
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "note.h"
|
||||
|
||||
class Master;
|
||||
class NulEngine;
|
||||
|
||||
class LocalZynAddSubFx
|
||||
{
|
||||
@@ -66,6 +67,7 @@ protected:
|
||||
|
||||
int m_runningNotes[NumKeys];
|
||||
Master * m_master;
|
||||
NulEngine* m_ioEngine;
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
#include "RemoteZynAddSubFx.h"
|
||||
#include "LocalZynAddSubFx.h"
|
||||
|
||||
#include "src/UI/MasterUI.h"
|
||||
#include "zynaddsubfx/src/UI/MasterUI.h"
|
||||
|
||||
#include <FL/x.H>
|
||||
|
||||
@@ -282,3 +282,22 @@ int main( int _argc, char * * _argv )
|
||||
}
|
||||
|
||||
|
||||
#ifdef NTK_GUI
|
||||
static Fl_Tiled_Image *module_backdrop;
|
||||
#endif
|
||||
|
||||
void set_module_parameters ( Fl_Widget *o )
|
||||
{
|
||||
#ifdef NTK_GUI
|
||||
o->box( FL_DOWN_FRAME );
|
||||
o->align( o->align() | FL_ALIGN_IMAGE_BACKDROP );
|
||||
o->color( FL_BLACK );
|
||||
o->image( module_backdrop );
|
||||
o->labeltype( FL_SHADOW_LABEL );
|
||||
#else
|
||||
o->box( FL_PLASTIC_UP_BOX );
|
||||
o->color( FL_CYAN );
|
||||
o->labeltype( FL_EMBOSSED_LABEL );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#include "Instrument.h"
|
||||
#include "InstrumentView.h"
|
||||
#include "RemotePlugin.h"
|
||||
#include "src/globals.h"
|
||||
#include "zynaddsubfx/src/globals.h"
|
||||
|
||||
|
||||
class QPushButton;
|
||||
|
||||
@@ -1,450 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
AnalogFilter.cpp - 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);
|
||||
}
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
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
|
||||
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 ANALOG_FILTER_H
|
||||
#define ANALOG_FILTER_H
|
||||
|
||||
#include "../globals.h"
|
||||
#include "Filter_.h"
|
||||
|
||||
/**Implementation of Several analog filters (lowpass, highpass...)*/
|
||||
class AnalogFilter:public Filter_
|
||||
{
|
||||
public:
|
||||
AnalogFilter(unsigned char Ftype,
|
||||
REALTYPE Ffreq,
|
||||
REALTYPE Fq,
|
||||
unsigned char Fstages);
|
||||
~AnalogFilter();
|
||||
void filterout(REALTYPE *smp);
|
||||
void setfreq(REALTYPE frequency);
|
||||
void setfreq_and_q(REALTYPE frequency, REALTYPE q_);
|
||||
void setq(REALTYPE q_);
|
||||
|
||||
void settype(int type_);
|
||||
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;
|
||||
} x[MAX_FILTER_STAGES + 1], y[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();
|
||||
int type; //The type of the filter (LPF1,HPF1,LPF2,HPF2...)
|
||||
int stages; //how many times the filter is applied (0->1,1->2,etc.)
|
||||
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
|
||||
|
||||
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; /**\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)
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
set(zynaddsubfx_dsp_SRCS
|
||||
AnalogFilter.cpp
|
||||
FFTwrapper.cpp
|
||||
Filter.cpp
|
||||
FormantFilter.cpp
|
||||
SVFilter.cpp
|
||||
Unison.cpp
|
||||
)
|
||||
|
||||
add_library(zynaddsubfx_dsp STATIC
|
||||
${zynaddsubfx_dsp_SRCS}
|
||||
)
|
||||
|
||||
target_link_libraries(zynaddsubfx_dsp)
|
||||
@@ -1,136 +0,0 @@
|
||||
/*
|
||||
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
|
||||
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 "FFTwrapper.h"
|
||||
|
||||
FFTwrapper::FFTwrapper(int fftsize_)
|
||||
{
|
||||
fftsize = fftsize_;
|
||||
tmpfftdata1 = new fftw_real[fftsize];
|
||||
tmpfftdata2 = new fftw_real[fftsize];
|
||||
#ifdef FFTW_VERSION_2
|
||||
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()
|
||||
{
|
||||
#ifdef FFTW_VERSION_2
|
||||
rfftw_destroy_plan(planfftw);
|
||||
rfftw_destroy_plan(planfftw_inv);
|
||||
#else
|
||||
fftwf_destroy_plan(planfftw);
|
||||
fftwf_destroy_plan(planfftw_inv);
|
||||
#endif
|
||||
|
||||
delete [] tmpfftdata1;
|
||||
delete [] tmpfftdata2;
|
||||
}
|
||||
|
||||
/*
|
||||
* do the Fast Fourier Transform
|
||||
*/
|
||||
void FFTwrapper::smps2freqs(REALTYPE *smps, FFTFREQS freqs)
|
||||
{
|
||||
#ifdef FFTW_VERSION_2
|
||||
for(int i = 0; i < fftsize; i++)
|
||||
tmpfftdata1[i] = smps[i];
|
||||
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];
|
||||
}
|
||||
#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];
|
||||
}
|
||||
#endif
|
||||
tmpfftdata2[fftsize / 2] = 0.0;
|
||||
}
|
||||
|
||||
/*
|
||||
* do the Inverse Fast Fourier Transform
|
||||
*/
|
||||
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];
|
||||
}
|
||||
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];
|
||||
}
|
||||
fftwf_execute(planfftw_inv);
|
||||
for(int i = 0; i < fftsize; i++)
|
||||
smps[i] = tmpfftdata2[i];
|
||||
#endif
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
void deleteFFTFREQS(FFTFREQS *f)
|
||||
{
|
||||
delete[] f->c;
|
||||
delete[] f->s;
|
||||
f->c = f->s = NULL;
|
||||
}
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
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
|
||||
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 FFT_WRAPPER_H
|
||||
#define FFT_WRAPPER_H
|
||||
|
||||
#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
|
||||
|
||||
/**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;
|
||||
};
|
||||
|
||||
void newFFTFREQS(FFTFREQS *f, int size);
|
||||
void deleteFFTFREQS(FFTFREQS *f);
|
||||
#endif
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
Filter.cpp - 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
|
||||
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 "Filter.h"
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
Filter::~Filter()
|
||||
{
|
||||
delete (filter);
|
||||
}
|
||||
|
||||
void Filter::filterout(REALTYPE *smp)
|
||||
{
|
||||
filter->filterout(smp);
|
||||
}
|
||||
|
||||
void Filter::setfreq(REALTYPE frequency)
|
||||
{
|
||||
filter->setfreq(frequency);
|
||||
}
|
||||
|
||||
void Filter::setfreq_and_q(REALTYPE frequency, REALTYPE q_)
|
||||
{
|
||||
filter->setfreq_and_q(frequency, q_);
|
||||
}
|
||||
|
||||
void Filter::setq(REALTYPE q_)
|
||||
{
|
||||
filter->setq(q_);
|
||||
}
|
||||
|
||||
REALTYPE Filter::getrealfreq(REALTYPE freqpitch)
|
||||
{
|
||||
if((category == 0) || (category == 2))
|
||||
return pow(2.0, freqpitch + 9.96578428); //log2(1000)=9.95748
|
||||
else
|
||||
return freqpitch;
|
||||
}
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
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
|
||||
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 FILTER_H
|
||||
#define FILTER_H
|
||||
|
||||
#include "../globals.h"
|
||||
|
||||
#include "Filter_.h"
|
||||
#include "AnalogFilter.h"
|
||||
#include "FormantFilter.h"
|
||||
#include "SVFilter.h"
|
||||
#include "../Params/FilterParams.h"
|
||||
|
||||
class Filter
|
||||
{
|
||||
public:
|
||||
Filter(FilterParams *pars);
|
||||
~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:
|
||||
Filter_ *filter;
|
||||
unsigned char category;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
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
|
||||
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 FILTER__H
|
||||
#define FILTER__H
|
||||
|
||||
#include "../globals.h"
|
||||
|
||||
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) = 0;
|
||||
REALTYPE outgain;
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,231 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
FormantFilter.cpp - 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::setgain(REALTYPE dBgain)
|
||||
{}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
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
|
||||
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 FORMANT_FILTER_H
|
||||
#define FORMANT_FILTER_H
|
||||
|
||||
#include "../globals.h"
|
||||
#include "Filter_.h"
|
||||
#include "AnalogFilter.h"
|
||||
#include "../Params/FilterParams.h"
|
||||
|
||||
|
||||
class FormantFilter:public Filter_
|
||||
{
|
||||
public:
|
||||
FormantFilter(FilterParams *pars);
|
||||
~FormantFilter();
|
||||
void filterout(REALTYPE *smp);
|
||||
void setfreq(REALTYPE frequency);
|
||||
void setfreq_and_q(REALTYPE frequency, REALTYPE q_);
|
||||
void setq(REALTYPE q_);
|
||||
void setgain(REALTYPE dBgain);
|
||||
|
||||
void cleanup();
|
||||
private:
|
||||
AnalogFilter *formant[FF_MAX_FORMANTS];
|
||||
REALTYPE *inbuffer, *tmpbuf;
|
||||
|
||||
struct {
|
||||
REALTYPE freq, amp, q; //frequency,amplitude,Q
|
||||
} formantpar[FF_MAX_VOWELS][FF_MAX_FORMANTS],
|
||||
currentformants[FF_MAX_FORMANTS];
|
||||
|
||||
struct {
|
||||
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);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,186 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
SVFilter.cpp - 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
|
||||
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 "SVFilter.h"
|
||||
|
||||
SVFilter::SVFilter(unsigned char Ftype,
|
||||
REALTYPE Ffreq,
|
||||
REALTYPE Fq,
|
||||
unsigned char Fstages)
|
||||
{
|
||||
stages = Fstages;
|
||||
type = Ftype;
|
||||
freq = Ffreq;
|
||||
q = Fq;
|
||||
gain = 1.0;
|
||||
outgain = 1.0;
|
||||
needsinterpolation = 0;
|
||||
firsttime = 1;
|
||||
if(stages >= MAX_FILTER_STAGES)
|
||||
stages = MAX_FILTER_STAGES;
|
||||
cleanup();
|
||||
setfreq_and_q(Ffreq, Fq);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
oldabovenq = 0;
|
||||
abovenq = 0;
|
||||
}
|
||||
|
||||
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;
|
||||
par.q = pow(par.q, 1.0 / (stages + 1));
|
||||
par.q_sqrt = sqrt(par.q);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
freq = frequency;
|
||||
computefiltercoefs();
|
||||
firsttime = 0;
|
||||
}
|
||||
|
||||
void SVFilter::setfreq_and_q(REALTYPE frequency, REALTYPE q_)
|
||||
{
|
||||
q = q_;
|
||||
setfreq(frequency);
|
||||
}
|
||||
|
||||
void SVFilter::setq(REALTYPE q_)
|
||||
{
|
||||
q = q_;
|
||||
computefiltercoefs();
|
||||
}
|
||||
|
||||
void SVFilter::settype(int type_)
|
||||
{
|
||||
type = type_;
|
||||
computefiltercoefs();
|
||||
}
|
||||
|
||||
void SVFilter::setgain(REALTYPE dBgain)
|
||||
{
|
||||
gain = dB2rap(dBgain);
|
||||
computefiltercoefs();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
for(i = 0; i < SOUND_BUFFER_SIZE; i++)
|
||||
smp[i] *= outgain;
|
||||
}
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
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
|
||||
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 SV_FILTER_H
|
||||
#define SV_FILTER_H
|
||||
|
||||
#include "../globals.h"
|
||||
#include "Filter_.h"
|
||||
class SVFilter:public Filter_
|
||||
{
|
||||
public:
|
||||
SVFilter(unsigned char Ftype,
|
||||
REALTYPE Ffreq,
|
||||
REALTYPE Fq,
|
||||
unsigned char Fstages);
|
||||
~SVFilter();
|
||||
void filterout(REALTYPE *smp);
|
||||
void setfreq(REALTYPE frequency);
|
||||
void setfreq_and_q(REALTYPE frequency, REALTYPE q_);
|
||||
void setq(REALTYPE q_);
|
||||
|
||||
void settype(int type_);
|
||||
void setgain(REALTYPE dBgain);
|
||||
void setstages(int stages_);
|
||||
void cleanup();
|
||||
|
||||
private:
|
||||
struct fstage {
|
||||
REALTYPE low, high, band, notch;
|
||||
} st[MAX_FILTER_STAGES + 1];
|
||||
|
||||
struct parameters {
|
||||
REALTYPE f, q, q_sqrt;
|
||||
} par, ipar;
|
||||
|
||||
|
||||
void singlefilterout(REALTYPE *smp, fstage &x, parameters &par);
|
||||
void computefiltercoefs();
|
||||
int type; //The type of the filter (LPF1,HPF1,LPF2,HPF2...)
|
||||
int stages; //how many times the filter is applied (0->1,1->2,etc.)
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,184 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
Unison.cpp - Unison effect (multivoice chorus)
|
||||
Copyright (C) 2002-2009 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 "Unison.h"
|
||||
|
||||
Unison::Unison(int update_period_samples_, REALTYPE max_delay_sec_) {
|
||||
update_period_samples = update_period_samples_;
|
||||
max_delay = (int)(max_delay_sec_ * (REALTYPE)SAMPLE_RATE + 1);
|
||||
if(max_delay < 10)
|
||||
max_delay = 10;
|
||||
delay_buffer = new REALTYPE[max_delay];
|
||||
delay_k = 0;
|
||||
base_freq = 1.0;
|
||||
unison_bandwidth_cents = 10.0;
|
||||
|
||||
ZERO_REALTYPE(delay_buffer, max_delay);
|
||||
|
||||
uv = NULL;
|
||||
update_period_sample_k = 0;
|
||||
first_time = 0;
|
||||
|
||||
set_size(1);
|
||||
}
|
||||
|
||||
Unison::~Unison() {
|
||||
delete [] delay_buffer;
|
||||
if(uv)
|
||||
delete [] uv;
|
||||
}
|
||||
|
||||
void Unison::set_size(int new_size) {
|
||||
if(new_size < 1)
|
||||
new_size = 1;
|
||||
unison_size = new_size;
|
||||
if(uv)
|
||||
delete [] uv;
|
||||
uv = new UnisonVoice[unison_size];
|
||||
first_time = true;
|
||||
update_parameters();
|
||||
}
|
||||
|
||||
void Unison::set_base_frequency(REALTYPE freq) {
|
||||
base_freq = freq;
|
||||
update_parameters();
|
||||
}
|
||||
|
||||
void Unison::set_bandwidth(REALTYPE bandwidth) {
|
||||
if(bandwidth < 0)
|
||||
bandwidth = 0.0;
|
||||
if(bandwidth > 1200.0)
|
||||
bandwidth = 1200.0;
|
||||
|
||||
//printf("bandwidth %g\n", bandwidth);
|
||||
unison_bandwidth_cents = bandwidth;
|
||||
update_parameters();
|
||||
}
|
||||
|
||||
void Unison::update_parameters() {
|
||||
if(!uv)
|
||||
return;
|
||||
REALTYPE increments_per_second = SAMPLE_RATE
|
||||
/ (REALTYPE) update_period_samples;
|
||||
// printf("#%g, %g\n",increments_per_second,base_freq);
|
||||
for(int i = 0; i < unison_size; i++) {
|
||||
REALTYPE base = pow(UNISON_FREQ_SPAN, RND * 2.0 - 1.0);
|
||||
uv[i].relative_amplitude = base;
|
||||
REALTYPE period = base / base_freq;
|
||||
REALTYPE m = 4.0 / (period * increments_per_second);
|
||||
if(RND < 0.5)
|
||||
m = -m;
|
||||
uv[i].step = m;
|
||||
// printf("%g %g\n",uv[i].relative_amplitude,period);
|
||||
}
|
||||
|
||||
REALTYPE max_speed = pow(2.0, unison_bandwidth_cents / 1200.0);
|
||||
unison_amplitude_samples = 0.125
|
||||
* (max_speed - 1.0) * SAMPLE_RATE / base_freq;
|
||||
//printf("unison_amplitude_samples %g\n", unison_amplitude_samples);
|
||||
|
||||
if(unison_amplitude_samples >= max_delay - 1)
|
||||
unison_amplitude_samples = max_delay - 2;
|
||||
|
||||
update_unison_data();
|
||||
}
|
||||
|
||||
void Unison::process(int bufsize, REALTYPE *inbuf, REALTYPE *outbuf) {
|
||||
if(!uv)
|
||||
return;
|
||||
if(!outbuf)
|
||||
outbuf = inbuf;
|
||||
|
||||
REALTYPE volume = 1.0 / sqrt(unison_size);
|
||||
REALTYPE xpos_step = 1.0 / (REALTYPE) update_period_samples;
|
||||
REALTYPE xpos = (REALTYPE) update_period_sample_k * xpos_step;
|
||||
for(int i = 0; i < bufsize; i++) {
|
||||
if((update_period_sample_k++) >= update_period_samples) {
|
||||
update_unison_data();
|
||||
update_period_sample_k = 0;
|
||||
xpos = 0.0;
|
||||
}
|
||||
xpos += xpos_step;
|
||||
REALTYPE in = inbuf[i], out = 0.0;
|
||||
|
||||
REALTYPE sign = 1.0;
|
||||
for(int k = 0; k < unison_size; k++) {
|
||||
REALTYPE vpos = uv[k].realpos1
|
||||
* (1.0 - xpos) + uv[k].realpos2 * xpos; //optimize
|
||||
REALTYPE pos = delay_k + max_delay - vpos - 1.0; //optimize
|
||||
int posi;
|
||||
REALTYPE posf;
|
||||
F2I(pos, posi); //optimize!
|
||||
if(posi >= max_delay)
|
||||
posi -= max_delay;
|
||||
posf = pos - floor(pos);
|
||||
out +=
|
||||
((1.0
|
||||
- posf) * delay_buffer[posi] + posf
|
||||
* delay_buffer[posi + 1]) * sign;
|
||||
sign = -sign;
|
||||
}
|
||||
outbuf[i] = out * volume;
|
||||
// printf("%d %g\n",i,outbuf[i]);
|
||||
delay_buffer[delay_k] = in;
|
||||
if((++delay_k) >= max_delay)
|
||||
delay_k = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Unison::update_unison_data() {
|
||||
if(!uv)
|
||||
return;
|
||||
|
||||
for(int k = 0; k < unison_size; k++) {
|
||||
REALTYPE pos = uv[k].position;
|
||||
REALTYPE step = uv[k].step;
|
||||
pos += step;
|
||||
if(pos <= -1.0) {
|
||||
pos = -1.0;
|
||||
step = -step;
|
||||
}
|
||||
if(pos >= 1.0) {
|
||||
pos = 1.0;
|
||||
step = -step;
|
||||
}
|
||||
REALTYPE vibratto_val = (pos - 0.333333333 * pos * pos * pos) * 1.5; //make the vibratto lfo smoother
|
||||
REALTYPE newval = 1.0 + 0.5
|
||||
* (vibratto_val
|
||||
+ 1.0) * unison_amplitude_samples
|
||||
* uv[k].relative_amplitude;
|
||||
|
||||
if(first_time)
|
||||
uv[k].realpos1 = uv[k].realpos2 = newval;
|
||||
else{
|
||||
uv[k].realpos1 = uv[k].realpos2;
|
||||
uv[k].realpos2 = newval;
|
||||
}
|
||||
|
||||
uv[k].position = pos;
|
||||
uv[k].step = step;
|
||||
}
|
||||
if(first_time)
|
||||
first_time = false;
|
||||
}
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
Unison.h - Unison effect (multivoice chorus)
|
||||
Copyright (C) 2002-2009 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 UNISON_H
|
||||
#define UNISON_H
|
||||
#include <stdlib.h>
|
||||
#include "../globals.h"
|
||||
|
||||
#define UNISON_FREQ_SPAN 2.0
|
||||
//how much the unison frequencies varies (always >= 1.0)
|
||||
|
||||
class Unison
|
||||
{
|
||||
public:
|
||||
Unison(int update_period_samples_, REALTYPE max_delay_sec_);
|
||||
~Unison();
|
||||
|
||||
void set_size(int new_size);
|
||||
void set_base_frequency(REALTYPE freq);
|
||||
void set_bandwidth(REALTYPE bandwidth_cents);
|
||||
|
||||
void process(int bufsize, REALTYPE *inbuf, REALTYPE *outbuf = NULL);
|
||||
|
||||
private:
|
||||
void update_parameters();
|
||||
void update_unison_data();
|
||||
|
||||
int unison_size;
|
||||
REALTYPE base_freq;
|
||||
struct UnisonVoice {
|
||||
REALTYPE step, position; //base LFO
|
||||
REALTYPE realpos1, realpos2; //the position regarding samples
|
||||
REALTYPE relative_amplitude;
|
||||
REALTYPE lin_fpos, lin_ffreq;
|
||||
UnisonVoice() {
|
||||
position = RND * 1.8 - 0.9;
|
||||
realpos1 = 0.0;
|
||||
realpos2 = 0.0;
|
||||
step = 0.0;
|
||||
relative_amplitude = 1.0;
|
||||
}
|
||||
} *uv;
|
||||
int update_period_samples, update_period_sample_k;
|
||||
int max_delay, delay_k;
|
||||
bool first_time;
|
||||
REALTYPE *delay_buffer;
|
||||
REALTYPE unison_amplitude_samples;
|
||||
REALTYPE unison_bandwidth_cents;
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -1,281 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
Alienwah.cpp - "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
|
||||
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 "Alienwah.h"
|
||||
|
||||
Alienwah::Alienwah(const int &insertion_,
|
||||
REALTYPE *const efxoutl_,
|
||||
REALTYPE *const efxoutr_)
|
||||
:Effect(insertion_, efxoutl_, efxoutr_, NULL, 0), oldl(NULL), oldr(NULL)
|
||||
{
|
||||
setpreset(Ppreset);
|
||||
cleanup();
|
||||
oldclfol = complex<REALTYPE>(fb, 0.0);
|
||||
oldclfor = complex<REALTYPE>(fb, 0.0);
|
||||
}
|
||||
|
||||
Alienwah::~Alienwah()
|
||||
{
|
||||
if(oldl != NULL)
|
||||
delete [] oldl;
|
||||
if(oldr != NULL)
|
||||
delete [] oldr;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Apply the effect
|
||||
*/
|
||||
void Alienwah::out(const Stereo<float *> &smp)
|
||||
{
|
||||
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
|
||||
* utilized.
|
||||
* 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;
|
||||
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++) {
|
||||
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)) * smp.l[i] * (1.0 - panning);
|
||||
|
||||
oldl[oldk] = out;
|
||||
REALTYPE l = out.real() * 10.0 * (fb + 0.1);
|
||||
|
||||
//right
|
||||
tmp = clfor * x + oldclfor * x1;
|
||||
|
||||
out = tmp * oldr[oldk];
|
||||
out.real() += (1 - fabs(fb)) * smp.r[i] * (1.0 - panning);
|
||||
|
||||
oldr[oldk] = out;
|
||||
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;
|
||||
}
|
||||
|
||||
oldclfol = clfol;
|
||||
oldclfor = clfor;
|
||||
}
|
||||
|
||||
/*
|
||||
* Cleanup the effect
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Parameter control
|
||||
*/
|
||||
|
||||
void Alienwah::setdepth(unsigned char Pdepth)
|
||||
{
|
||||
this->Pdepth = Pdepth;
|
||||
depth = (Pdepth / 127.0);
|
||||
}
|
||||
|
||||
void Alienwah::setfb(unsigned char Pfb)
|
||||
{
|
||||
this->Pfb = Pfb;
|
||||
fb = fabs((Pfb - 64.0) / 64.1);
|
||||
fb = sqrt(fb);
|
||||
if(fb < 0.4)
|
||||
fb = 0.4;
|
||||
if(Pfb < 64)
|
||||
fb = -fb;
|
||||
}
|
||||
|
||||
void Alienwah::setvolume(unsigned char Pvolume)
|
||||
{
|
||||
this->Pvolume = Pvolume;
|
||||
outvolume = Pvolume / 127.0;
|
||||
if(insertion == 0)
|
||||
volume = 1.0;
|
||||
else
|
||||
volume = outvolume;
|
||||
}
|
||||
|
||||
void Alienwah::setpanning(unsigned char Ppanning)
|
||||
{
|
||||
this->Ppanning = Ppanning;
|
||||
panning = Ppanning / 127.0;
|
||||
}
|
||||
|
||||
void Alienwah::setlrcross(unsigned char Plrcross)
|
||||
{
|
||||
this->Plrcross = Plrcross;
|
||||
lrcross = Plrcross / 127.0;
|
||||
}
|
||||
|
||||
void Alienwah::setphase(unsigned char Pphase)
|
||||
{
|
||||
this->Pphase = Pphase;
|
||||
phase = (Pphase - 64.0) / 64.0 * PI;
|
||||
}
|
||||
|
||||
void Alienwah::setdelay(unsigned char Pdelay)
|
||||
{
|
||||
if(oldl != NULL)
|
||||
delete [] oldl;
|
||||
if(oldr != NULL)
|
||||
delete [] oldr;
|
||||
if(Pdelay >= MAX_ALIENWAH_DELAY)
|
||||
this->Pdelay = MAX_ALIENWAH_DELAY;
|
||||
else
|
||||
this->Pdelay = Pdelay;
|
||||
oldl = new complex<REALTYPE>[Pdelay];
|
||||
oldr = new complex<REALTYPE>[Pdelay];
|
||||
cleanup();
|
||||
}
|
||||
|
||||
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}
|
||||
};
|
||||
|
||||
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
|
||||
Ppreset = npreset;
|
||||
}
|
||||
|
||||
|
||||
void Alienwah::changepar(int npar, 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(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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
/*
|
||||
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
|
||||
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 ALIENWAH_H
|
||||
#define ALIENWAH_H
|
||||
#include <complex>
|
||||
#include "../globals.h"
|
||||
#include "Effect.h"
|
||||
#include "EffectLFO.h"
|
||||
|
||||
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(const Stereo<float *> &smp);
|
||||
|
||||
void setpreset(unsigned char npreset);
|
||||
void changepar(int npar, unsigned char value);
|
||||
unsigned char getpar(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;
|
||||
|
||||
|
||||
//Control Parameters
|
||||
void setvolume(unsigned char Pvolume);
|
||||
void setpanning(unsigned char Ppanning);
|
||||
void setdepth(unsigned char Pdepth);
|
||||
void setfb(unsigned char Pfb);
|
||||
void setlrcross(unsigned char Plrcross);
|
||||
void setdelay(unsigned char Pdelay);
|
||||
void setphase(unsigned char Pphase);
|
||||
|
||||
//Internal Values
|
||||
REALTYPE panning, fb, depth, lrcross, phase;
|
||||
complex<REALTYPE> *oldl, *oldr;
|
||||
complex<REALTYPE> oldclfol, oldclfor;
|
||||
int oldk;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
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)
|
||||
@@ -1,320 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
Chorus.cpp - 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;
|
||||
|
||||
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.cpp::getdelay(..) too big delay (see setdelay and setdepth funcs.)\n";
|
||||
result = maxdelay - 1.0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void Chorus::out(const Stereo<float *> &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 < SOUND_BUFFER_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 < 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()
|
||||
{
|
||||
delaySample.l.clear();
|
||||
delaySample.r.clear();
|
||||
}
|
||||
|
||||
/*
|
||||
* Parameter control
|
||||
*/
|
||||
void Chorus::setdepth(unsigned char Pdepth)
|
||||
{
|
||||
this->Pdepth = Pdepth;
|
||||
depth = (pow(8.0, (Pdepth / 127.0) * 2.0) - 1.0) / 1000.0; //seconds
|
||||
}
|
||||
|
||||
void Chorus::setdelay(unsigned char Pdelay)
|
||||
{
|
||||
this->Pdelay = Pdelay;
|
||||
delay = (pow(10.0, (Pdelay / 127.0) * 2.0) - 1.0) / 1000.0; //seconds
|
||||
}
|
||||
|
||||
void Chorus::setfb(unsigned char Pfb)
|
||||
{
|
||||
this->Pfb = Pfb;
|
||||
fb = (Pfb - 64.0) / 64.1;
|
||||
}
|
||||
void Chorus::setvolume(unsigned char Pvolume)
|
||||
{
|
||||
this->Pvolume = Pvolume;
|
||||
outvolume = Pvolume / 127.0;
|
||||
if(insertion == 0)
|
||||
volume = 1.0;
|
||||
else
|
||||
volume = outvolume;
|
||||
}
|
||||
|
||||
void Chorus::setpanning(unsigned char Ppanning)
|
||||
{
|
||||
this->Ppanning = Ppanning;
|
||||
panning = Ppanning / 127.0;
|
||||
}
|
||||
|
||||
void Chorus::setlrcross(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(int npar, 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(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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,114 +0,0 @@
|
||||
/*
|
||||
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
|
||||
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 CHORUS_H
|
||||
#define CHORUS_H
|
||||
#include "../globals.h"
|
||||
#include "Effect.h"
|
||||
#include "EffectLFO.h"
|
||||
#include "../Samples/Sample.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(const Stereo<float *> &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(int npar, 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(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
|
||||
|
||||
|
||||
//Parameter Controls
|
||||
void setvolume(unsigned char Pvolume);
|
||||
void setpanning(unsigned char Ppanning);
|
||||
void setdepth(unsigned char Pdepth);
|
||||
void setdelay(unsigned char Pdelay);
|
||||
void setfb(unsigned char Pfb);
|
||||
void setlrcross(unsigned char Plrcross);
|
||||
|
||||
//Internal Values
|
||||
REALTYPE depth, delay, fb, lrcross, panning;
|
||||
REALTYPE dl1, dl2, dr1, dr2, lfol, lfor;
|
||||
int maxdelay;
|
||||
Stereo<Sample> delaySample;
|
||||
int dlk, drk, dlhi, dlhi2;
|
||||
REALTYPE getdelay(REALTYPE xlfo);
|
||||
REALTYPE dllo, mdel;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,481 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
Distorsion.cpp - 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(const Stereo<float *> &smp)
|
||||
{
|
||||
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] = smp.l[i] * inputvol * panning;
|
||||
efxoutr[i] = smp.r[i] * inputvol * (1.0 - panning);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for(i = 0; i < SOUND_BUFFER_SIZE; i++)
|
||||
efxoutl[i] =
|
||||
(smp.l[i] * panning + smp.r[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(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(unsigned char Ppanning)
|
||||
{
|
||||
this->Ppanning = Ppanning;
|
||||
panning = (Ppanning + 0.5) / 127.0;
|
||||
}
|
||||
|
||||
|
||||
void Distorsion::setlrcross(unsigned char Plrcross)
|
||||
{
|
||||
this->Plrcross = Plrcross;
|
||||
lrcross = Plrcross / 127.0 * 1.0;
|
||||
}
|
||||
|
||||
void Distorsion::setlpf(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(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(int npar, 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(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
|
||||
}
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
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
|
||||
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 DISTORSION_H
|
||||
#define DISTORSION_H
|
||||
|
||||
#include "../globals.h"
|
||||
#include "../DSP/AnalogFilter.h"
|
||||
#include "Effect.h"
|
||||
|
||||
//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(const Stereo<float *> &smp);
|
||||
void setpreset(unsigned char npreset);
|
||||
void changepar(int npar, unsigned char value);
|
||||
unsigned char getpar(int npar) const;
|
||||
void cleanup();
|
||||
void applyfilters(REALTYPE *efxoutl, REALTYPE *efxoutr);
|
||||
|
||||
private:
|
||||
//Parametrii
|
||||
unsigned char Pvolume; //Volume 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(unsigned char Pvolume);
|
||||
void setpanning(unsigned char Ppanning);
|
||||
void setlrcross(unsigned char Plrcross);
|
||||
void setlpf(unsigned char Plpf);
|
||||
void sethpf(unsigned char Phpf);
|
||||
|
||||
//Real Parameters
|
||||
REALTYPE panning, lrcross;
|
||||
AnalogFilter *lpfl, *lpfr, *hpfl, *hpfr;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,352 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
DynamicFilter.cpp - "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(const Stereo<float *> &smp)
|
||||
{
|
||||
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] = smp.l[i];
|
||||
efxoutr[i] = smp.r[i];
|
||||
|
||||
REALTYPE x = (fabs(smp.l[i]) + fabs(smp.l[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(unsigned char Pdepth)
|
||||
{
|
||||
this->Pdepth = Pdepth;
|
||||
depth = pow((Pdepth / 127.0), 2.0);
|
||||
}
|
||||
|
||||
|
||||
void DynamicFilter::setvolume(unsigned char Pvolume)
|
||||
{
|
||||
this->Pvolume = Pvolume;
|
||||
outvolume = Pvolume / 127.0;
|
||||
if(insertion == 0)
|
||||
volume = 1.0;
|
||||
else
|
||||
volume = outvolume;
|
||||
}
|
||||
|
||||
void DynamicFilter::setpanning(unsigned char Ppanning)
|
||||
{
|
||||
this->Ppanning = Ppanning;
|
||||
panning = Ppanning / 127.0;
|
||||
}
|
||||
|
||||
|
||||
void DynamicFilter::setampsns(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(int npar, 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(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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
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
|
||||
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 DYNAMICFILTER_H
|
||||
#define DYNAMICFILTER_H
|
||||
#include "../globals.h"
|
||||
#include "Effect.h"
|
||||
#include "EffectLFO.h"
|
||||
|
||||
#include "../DSP/Filter.h"
|
||||
/**DynamicFilter Effect*/
|
||||
class DynamicFilter:public Effect
|
||||
{
|
||||
public:
|
||||
DynamicFilter(int insetion_, REALTYPE *efxoutl_, REALTYPE *efxoutr_);
|
||||
~DynamicFilter();
|
||||
void out(const Stereo<float *> &smp);
|
||||
|
||||
void setpreset(unsigned char npreset);
|
||||
void changepar(int npar, unsigned char value);
|
||||
unsigned char getpar(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(unsigned char Pvolume);
|
||||
void setpanning(unsigned char Ppanning);
|
||||
void setdepth(unsigned char Pdepth);
|
||||
void setampsns(unsigned char Pampsns);
|
||||
|
||||
void reinitfilter();
|
||||
|
||||
//Internal Values
|
||||
REALTYPE panning, depth, ampsns, ampsmooth;
|
||||
|
||||
Filter *filterl, *filterr;
|
||||
|
||||
REALTYPE ms1, ms2, ms3, ms4; //mean squares
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,212 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
EQ.cpp - 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()
|
||||
{}
|
||||
|
||||
void EQ::cleanup()
|
||||
{
|
||||
for(int i = 0; i < MAX_EQ_BANDS; i++) {
|
||||
filter[i].l->cleanup();
|
||||
filter[i].r->cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
void EQ::out(const Stereo<float *> &smp)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < SOUND_BUFFER_SIZE; i++) {
|
||||
efxoutl[i] = smp.l[i] * volume;
|
||||
efxoutr[i] = smp.r[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(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(int npar, 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(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);
|
||||
}
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
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
|
||||
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 EQ_H
|
||||
#define EQ_H
|
||||
|
||||
#include "../globals.h"
|
||||
#include "../DSP/AnalogFilter.h"
|
||||
#include "Effect.h"
|
||||
|
||||
/**EQ Effect*/
|
||||
class EQ:public Effect
|
||||
{
|
||||
public:
|
||||
EQ(const int &insertion_, REALTYPE *efxoutl_, REALTYPE *efxoutr_);
|
||||
~EQ();
|
||||
void out(const Stereo<float *> &smp);
|
||||
void setpreset(unsigned char npreset);
|
||||
void changepar(int npar, unsigned char value);
|
||||
unsigned char getpar(int npar) const;
|
||||
void cleanup();
|
||||
REALTYPE getfreqresponse(REALTYPE freq);
|
||||
private:
|
||||
//Parameters
|
||||
unsigned char Pvolume; /**<Volume*/
|
||||
|
||||
void setvolume(unsigned char Pvolume);
|
||||
|
||||
struct {
|
||||
//parameters
|
||||
unsigned char Ptype, Pfreq, Pgain, Pq, Pstages;
|
||||
//internal values
|
||||
AnalogFilter *l, *r;
|
||||
} filter[MAX_EQ_BANDS];
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,270 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
Echo.cpp - Echo effect
|
||||
Copyright (C) 2002-2005 Nasca Octavian Paul
|
||||
Copyright (C) 2009-2010 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
|
||||
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"
|
||||
|
||||
#define MAX_DELAY 2
|
||||
|
||||
Echo::Echo(const int &insertion_,
|
||||
REALTYPE *const efxoutl_,
|
||||
REALTYPE *const efxoutr_)
|
||||
:Effect(insertion_, efxoutl_, efxoutr_, NULL, 0),
|
||||
samplerate(SAMPLE_RATE),
|
||||
Pvolume(50), Ppanning(64), Pdelay(60),
|
||||
Plrdelay(100), Plrcross(100), Pfb(40), Phidamp(60),
|
||||
delayTime(1), lrdelay(0), avgDelay(0),
|
||||
delay(new REALTYPE[(int)(MAX_DELAY * samplerate)],
|
||||
new REALTYPE[(int)(MAX_DELAY * samplerate)]),
|
||||
old(0.0), pos(0), delta(1), ndelta(1)
|
||||
{
|
||||
initdelays();
|
||||
setpreset(Ppreset);
|
||||
}
|
||||
|
||||
Echo::~Echo()
|
||||
{
|
||||
delete[] delay.l;
|
||||
delete[] delay.r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Cleanup the effect
|
||||
*/
|
||||
void Echo::cleanup()
|
||||
{
|
||||
memset(delay.l,0,MAX_DELAY*samplerate*sizeof(REALTYPE));
|
||||
memset(delay.r,0,MAX_DELAY*samplerate*sizeof(REALTYPE));
|
||||
old = Stereo<REALTYPE>(0.0);
|
||||
}
|
||||
|
||||
inline int max(int a, int b)
|
||||
{
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the delays
|
||||
*/
|
||||
void Echo::initdelays()
|
||||
{
|
||||
cleanup();
|
||||
//number of seconds to delay left chan
|
||||
float dl = avgDelay - lrdelay;
|
||||
|
||||
//number of seconds to delay right chan
|
||||
float dr = avgDelay + lrdelay;
|
||||
|
||||
ndelta.l = max(1,(int) (dl * samplerate));
|
||||
ndelta.r = max(1,(int) (dr * samplerate));
|
||||
}
|
||||
|
||||
void Echo::out(const Stereo<float *> &input)
|
||||
{
|
||||
REALTYPE ldl, rdl;
|
||||
|
||||
for(int i = 0; i < SOUND_BUFFER_SIZE; ++i) {
|
||||
ldl = delay.l[pos.l];
|
||||
rdl = delay.r[pos.r];
|
||||
ldl = ldl * (1.0 - lrcross) + rdl * lrcross;
|
||||
rdl = rdl * (1.0 - lrcross) + ldl * lrcross;
|
||||
|
||||
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
|
||||
old.l = delay.l[(pos.l+delta.l)%(MAX_DELAY * samplerate)] = ldl * hidamp + old.l * (1.0 - hidamp);
|
||||
old.r = delay.r[(pos.r+delta.r)%(MAX_DELAY * samplerate)] = rdl * hidamp + old.r * (1.0 - hidamp);
|
||||
|
||||
//increment
|
||||
++pos.l;// += delta.l;
|
||||
++pos.r;// += delta.r;
|
||||
|
||||
//ensure that pos is still in bounds
|
||||
pos.l %= MAX_DELAY * samplerate;
|
||||
pos.r %= MAX_DELAY * samplerate;
|
||||
|
||||
//adjust delay if needed
|
||||
delta.l = (15*delta.l + ndelta.l)/16;
|
||||
delta.r = (15*delta.r + ndelta.r)/16;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Parameter control
|
||||
*/
|
||||
void Echo::setvolume(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(unsigned char Ppanning)
|
||||
{
|
||||
this->Ppanning = Ppanning;
|
||||
panning = (Ppanning + 0.5) / 127.0;
|
||||
}
|
||||
|
||||
void Echo::setdelay(unsigned char Pdelay)
|
||||
{
|
||||
this->Pdelay=Pdelay;
|
||||
avgDelay=(Pdelay/127.0*1.5);//0 .. 1.5 sec
|
||||
initdelays();
|
||||
}
|
||||
|
||||
void Echo::setlrdelay(unsigned char Plrdelay)
|
||||
{
|
||||
REALTYPE tmp;
|
||||
this->Plrdelay = Plrdelay;
|
||||
tmp =
|
||||
(pow(2, fabs(Plrdelay - 64.0) / 64.0 * 9) - 1.0) / 1000.0;
|
||||
if(Plrdelay < 64.0)
|
||||
tmp = -tmp;
|
||||
lrdelay = tmp;
|
||||
initdelays();
|
||||
}
|
||||
|
||||
void Echo::setlrcross(unsigned char Plrcross)
|
||||
{
|
||||
this->Plrcross = Plrcross;
|
||||
lrcross = Plrcross / 127.0 * 1.0;
|
||||
}
|
||||
|
||||
void Echo::setfb(unsigned char Pfb)
|
||||
{
|
||||
this->Pfb = Pfb;
|
||||
fb = Pfb / 128.0;
|
||||
}
|
||||
|
||||
void Echo::sethidamp(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(int npar, 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(int npar) const
|
||||
{
|
||||
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
|
||||
}
|
||||
|
||||
@@ -1,140 +0,0 @@
|
||||
/*
|
||||
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
|
||||
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 ECHO_H
|
||||
#define ECHO_H
|
||||
|
||||
#include "../globals.h"
|
||||
#include "Effect.h"
|
||||
#include "../Misc/Stereo.h"
|
||||
#include "../Samples/Sample.h"
|
||||
|
||||
/**Echo Effect*/
|
||||
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 destructor
|
||||
*/
|
||||
~Echo();
|
||||
|
||||
void out(const Stereo<float *> &input);
|
||||
|
||||
/**
|
||||
* Sets the state of Echo to the specified preset
|
||||
* @param npreset number of chosen preset
|
||||
*/
|
||||
void setpreset(unsigned char npreset);
|
||||
|
||||
/**
|
||||
* 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(int npar, unsigned char value);
|
||||
|
||||
/**
|
||||
* 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(int npar) const;
|
||||
|
||||
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:
|
||||
int samplerate;
|
||||
|
||||
//Parameters
|
||||
char Pvolume; /**<#1 Volume or Dry/Wetness*/
|
||||
char Ppanning; /**<#2 Panning*/
|
||||
char Pdelay; /**<#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(unsigned char Pvolume);
|
||||
void setpanning(unsigned char Ppanning);
|
||||
void setdelay(unsigned char Pdelay);
|
||||
void setlrdelay(unsigned char Plrdelay);
|
||||
void setlrcross(unsigned char Plrcross);
|
||||
void setfb(unsigned char Pfb);
|
||||
void sethidamp(unsigned char Phidamp);
|
||||
|
||||
//Real Parameters
|
||||
REALTYPE panning, lrcross, fb, hidamp;
|
||||
//Left/Right delay lengths
|
||||
Stereo<int> delayTime;
|
||||
REALTYPE lrdelay;
|
||||
REALTYPE avgDelay;
|
||||
|
||||
void initdelays();
|
||||
//2 channel ring buffer
|
||||
Stereo<REALTYPE *> delay;
|
||||
Stereo<REALTYPE> old;
|
||||
|
||||
//position of reading/writing from delaysample
|
||||
Stereo<int> pos;
|
||||
//step size for delay buffer
|
||||
Stereo<int> delta;
|
||||
Stereo<int> ndelta;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
Effect.cpp - 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
|
||||
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 "Effect.h"
|
||||
|
||||
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_)
|
||||
{}
|
||||
|
||||
void Effect::out(REALTYPE *const smpsl, REALTYPE *const smpsr)
|
||||
{
|
||||
out(Stereo<float *>(smpsl,smpsr));
|
||||
};
|
||||
|
||||
@@ -1,105 +0,0 @@
|
||||
/*
|
||||
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
|
||||
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 EFFECT_H
|
||||
#define EFFECT_H
|
||||
|
||||
#include "../Misc/Util.h"
|
||||
#include "../globals.h"
|
||||
#include "../Params/FilterParams.h"
|
||||
#include "../Misc/Stereo.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(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(int npar, 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(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
|
||||
*/
|
||||
void out(REALTYPE *const smpsl, REALTYPE *const smpsr);
|
||||
virtual void out(const Stereo<float *> &smp) = 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 freq;
|
||||
}
|
||||
|
||||
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 Stereo<float*>*/
|
||||
|
||||
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;
|
||||
|
||||
FilterParams *filterpars; /**<Parameters for filters used by Effect*/
|
||||
protected:
|
||||
|
||||
const bool insertion;/**<If Effect is an insertion effect, insertion=1
|
||||
*otherwise, it should be insertion=0*/
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,127 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
EffectLFO.cpp - 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
|
||||
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 <cstdlib>
|
||||
#include <cmath>
|
||||
|
||||
#include "EffectLFO.h"
|
||||
|
||||
|
||||
EffectLFO::EffectLFO()
|
||||
{
|
||||
xl = 0.0;
|
||||
xr = 0.0;
|
||||
Pfreq = 40;
|
||||
Prandomness = 0;
|
||||
PLFOtype = 0;
|
||||
Pstereo = 96;
|
||||
|
||||
updateparams();
|
||||
|
||||
ampl1 = (1 - lfornd) + lfornd * RND;
|
||||
ampl2 = (1 - lfornd) + lfornd * RND;
|
||||
ampr1 = (1 - lfornd) + lfornd * RND;
|
||||
ampr2 = (1 - lfornd) + lfornd * RND;
|
||||
}
|
||||
|
||||
EffectLFO::~EffectLFO()
|
||||
{}
|
||||
|
||||
|
||||
/*
|
||||
* Update the changed parameters
|
||||
*/
|
||||
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(PLFOtype > 1)
|
||||
PLFOtype = 1; //this has to be updated if more lfo's are added
|
||||
lfotype = PLFOtype;
|
||||
|
||||
xr = fmod(xl + (Pstereo - 64.0) / 127.0 + 1.0, 1.0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Compute the shape of the LFO
|
||||
*/
|
||||
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
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/*
|
||||
* LFO output
|
||||
*/
|
||||
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;
|
||||
}
|
||||
*outl = (out + 1.0) * 0.5;
|
||||
|
||||
out = getlfoshape(xr);
|
||||
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;
|
||||
}
|
||||
*outr = (out + 1.0) * 0.5;
|
||||
}
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
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
|
||||
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 EFFECT_LFO_H
|
||||
#define EFFECT_LFO_H
|
||||
|
||||
#include "../globals.h"
|
||||
/**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);
|
||||
void updateparams();
|
||||
unsigned char Pfreq;
|
||||
unsigned char Prandomness;
|
||||
unsigned char PLFOtype;
|
||||
unsigned char Pstereo; //"64"=0
|
||||
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 (replace with short or enum)*/
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,357 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
EffectMgr.cpp - 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"
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
/*
|
||||
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
|
||||
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 EFFECTMGR_H
|
||||
#define EFFECTMGR_H
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "Effect.h"
|
||||
#include "Reverb.h"
|
||||
#include "Echo.h"
|
||||
#include "Chorus.h"
|
||||
#include "Phaser.h"
|
||||
#include "Alienwah.h"
|
||||
#include "Distorsion.h"
|
||||
#include "EQ.h"
|
||||
#include "DynamicFilter.h"
|
||||
#include "../Misc/XMLwrapper.h"
|
||||
#include "../Params/FilterParams.h"
|
||||
#include "../Params/Presets.h"
|
||||
|
||||
/**Effect manager, an interface betwen the program and effects*/
|
||||
class EffectMgr:public Presets
|
||||
{
|
||||
public:
|
||||
EffectMgr(int insertion_, pthread_mutex_t *mutex_);
|
||||
~EffectMgr();
|
||||
|
||||
void add2XML(XMLwrapper *xml);
|
||||
void defaults();
|
||||
void getfromXML(XMLwrapper *xml);
|
||||
|
||||
void out(REALTYPE *smpsl, REALTYPE *smpsr);
|
||||
|
||||
void setdryonly(bool value);
|
||||
|
||||
/**get the output(to speakers) volume of the systemeffect*/
|
||||
REALTYPE sysefxgetvolume();
|
||||
|
||||
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*/
|
||||
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
|
||||
* \todo needs to be decoupled*/
|
||||
REALTYPE getEQfreqresponse(REALTYPE freq);
|
||||
|
||||
FilterParams *filterpars;
|
||||
|
||||
private:
|
||||
int nefx;
|
||||
Effect *efx;
|
||||
pthread_mutex_t *mutex;
|
||||
bool dryonly;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,473 +0,0 @@
|
||||
/*
|
||||
|
||||
Phaser.cpp - Phasing and Approximate digital model of an analog JFET phaser.
|
||||
Analog modeling implemented by Ryan Billing aka Transmogrifox.
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
Phaser.cpp - Phaser effect
|
||||
Copyright (C) 2002-2005 Nasca Octavian Paul
|
||||
Copyright (C) 2009-2010 Ryan Billing
|
||||
Copyright (C) 2010-2010 Mark McCurry
|
||||
Author: Nasca Octavian Paul
|
||||
Ryan Billing
|
||||
Mark McCurry
|
||||
|
||||
DSP analog modeling theory & practice largely influenced by various CCRMA publications, particularly works by Julius O. Smith.
|
||||
|
||||
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 <algorithm>
|
||||
#include "Phaser.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
#define PHASER_LFO_SHAPE 2
|
||||
#define ONE_ 0.99999f // To prevent LFO ever reaching 1.0 for filter stability purposes
|
||||
#define ZERO_ 0.00001f // Same idea as above.
|
||||
|
||||
Phaser::Phaser(const int &insertion_, REALTYPE *efxoutl_, REALTYPE *efxoutr_)
|
||||
:Effect(insertion_, efxoutl_, efxoutr_, NULL, 0), old(NULL), xn1(NULL), yn1(NULL), diff(0.0), oldgain(0.0),
|
||||
fb(0.0)
|
||||
{
|
||||
analog_setup();
|
||||
setpreset(Ppreset);
|
||||
cleanup();
|
||||
}
|
||||
|
||||
void Phaser::analog_setup()
|
||||
{
|
||||
//model mismatch between JFET devices
|
||||
offset[0] = -0.2509303f;
|
||||
offset[1] = 0.9408924f;
|
||||
offset[2] = 0.998f;
|
||||
offset[3] = -0.3486182f;
|
||||
offset[4] = -0.2762545f;
|
||||
offset[5] = -0.5215785f;
|
||||
offset[6] = 0.2509303f;
|
||||
offset[7] = -0.9408924f;
|
||||
offset[8] = -0.998f;
|
||||
offset[9] = 0.3486182f;
|
||||
offset[10] = 0.2762545f;
|
||||
offset[11] = 0.5215785f;
|
||||
|
||||
barber = 0; //Deactivate barber pole phasing by default
|
||||
|
||||
mis = 1.0f;
|
||||
Rmin = 625.0f;// 2N5457 typical on resistance at Vgs = 0
|
||||
Rmax = 22000.0f;// Resistor parallel to FET
|
||||
Rmx = Rmin/Rmax;
|
||||
Rconst = 1.0f + Rmx; // Handle parallel resistor relationship
|
||||
C = 0.00000005f; // 50 nF
|
||||
CFs = (float) 2.0f*(float)SAMPLE_RATE*C;
|
||||
invperiod = 1.0f / ((float) SOUND_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
Phaser::~Phaser()
|
||||
{
|
||||
if(xn1.l)
|
||||
delete[] xn1.l;
|
||||
if(yn1.l)
|
||||
delete[] yn1.l;
|
||||
if(xn1.r)
|
||||
delete[] xn1.r;
|
||||
if(yn1.r)
|
||||
delete[] yn1.r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Effect output
|
||||
*/
|
||||
void Phaser::out(const Stereo<REALTYPE *> &input)
|
||||
{
|
||||
if(Panalog)
|
||||
AnalogPhase(input);
|
||||
else
|
||||
normalPhase(input);
|
||||
}
|
||||
|
||||
void Phaser::AnalogPhase(const Stereo<REALTYPE *> &input)
|
||||
{
|
||||
Stereo<REALTYPE> gain(0.0), lfoVal(0.0), mod(0.0), g(0.0), b(0.0), hpf(0.0);
|
||||
|
||||
lfo.effectlfoout(&lfoVal.l, &lfoVal.r);
|
||||
mod.l = lfoVal.l*width + (depth - 0.5f);
|
||||
mod.r = lfoVal.r*width + (depth - 0.5f);
|
||||
|
||||
mod.l = limit(mod.l, ZERO_, ONE_);
|
||||
mod.r = limit(mod.r, ZERO_, ONE_);
|
||||
|
||||
if(Phyper) {
|
||||
//Triangle wave squared is approximately sin on bottom, tri on top
|
||||
//Result is exponential sweep more akin to filter in synth with
|
||||
//exponential generator circuitry.
|
||||
mod.l *= mod.l;
|
||||
mod.r *= mod.r;
|
||||
}
|
||||
|
||||
//g.l,g.r is Vp - Vgs. Typical FET drain-source resistance follows constant/[1-sqrt(Vp - Vgs)]
|
||||
mod.l = sqrtf(1.0f - mod.l);
|
||||
mod.r = sqrtf(1.0f - mod.r);
|
||||
|
||||
diff.r = (mod.r - oldgain.r) * invperiod;
|
||||
diff.l = (mod.l - oldgain.l) * invperiod;
|
||||
|
||||
g = oldgain;
|
||||
oldgain = mod;
|
||||
|
||||
for (int i = 0; i < SOUND_BUFFER_SIZE; i++) {
|
||||
g.l += diff.l;// Linear interpolation between LFO samples
|
||||
g.r += diff.r;
|
||||
|
||||
Stereo<REALTYPE> xn(input.l[i] * panning,
|
||||
input.r[i] * (1.0f - panning));
|
||||
|
||||
if (barber) {
|
||||
g.l = fmodf((g.l + 0.25f), ONE_);
|
||||
g.r = fmodf((g.r + 0.25f), ONE_);
|
||||
}
|
||||
|
||||
xn.l = applyPhase(xn.l, g.l, fb.l, hpf.l, yn1.l, xn1.l);
|
||||
xn.r = applyPhase(xn.r, g.r, fb.r, hpf.r, yn1.r, xn1.r);
|
||||
|
||||
|
||||
fb.l = xn.l * feedback;
|
||||
fb.r = xn.r * feedback;
|
||||
efxoutl[i] = xn.l;
|
||||
efxoutr[i] = xn.r;
|
||||
}
|
||||
|
||||
if(Poutsub) {
|
||||
invSignal(efxoutl, SOUND_BUFFER_SIZE);
|
||||
invSignal(efxoutr, SOUND_BUFFER_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
REALTYPE Phaser::applyPhase(REALTYPE x, REALTYPE g, REALTYPE fb,
|
||||
REALTYPE &hpf, REALTYPE *yn1, REALTYPE *xn1)
|
||||
{
|
||||
for(int j = 0; j < Pstages; j++) { //Phasing routine
|
||||
mis = 1.0f + offsetpct*offset[j];
|
||||
|
||||
//This is symmetrical.
|
||||
//FET is not, so this deviates slightly, however sym dist. is
|
||||
//better sounding than a real FET.
|
||||
float d = (1.0f + 2.0f*(0.25f + g)*hpf*hpf*distortion) * mis;
|
||||
Rconst = 1.0f + mis*Rmx;
|
||||
|
||||
// This is 1/R. R is being modulated to control filter fc.
|
||||
float b = (Rconst - g)/ (d*Rmin);
|
||||
float gain = (CFs - b)/(CFs + b);
|
||||
yn1[j] = gain * (x + yn1[j]) - xn1[j];
|
||||
|
||||
//high pass filter:
|
||||
//Distortion depends on the high-pass part of the AP stage.
|
||||
hpf = yn1[j] + (1.0f-gain)*xn1[j];
|
||||
|
||||
xn1[j] = x;
|
||||
x = yn1[j];
|
||||
if (j==1)
|
||||
x += fb; //Insert feedback after first phase stage
|
||||
}
|
||||
return x;
|
||||
}
|
||||
void Phaser::normalPhase(const Stereo<REALTYPE *> &input)
|
||||
{
|
||||
Stereo<REALTYPE> gain(0.0), lfoVal(0.0);
|
||||
|
||||
lfo.effectlfoout(&lfoVal.l, &lfoVal.r);
|
||||
gain.l = (exp(lfoVal.l * PHASER_LFO_SHAPE) - 1) / (exp(PHASER_LFO_SHAPE) - 1.0);
|
||||
gain.r = (exp(lfoVal.r * PHASER_LFO_SHAPE) - 1) / (exp(PHASER_LFO_SHAPE) - 1.0);
|
||||
|
||||
gain.l = 1.0 - phase * (1.0 - depth) - (1.0 - phase) * gain.l * depth;
|
||||
gain.r = 1.0 - phase * (1.0 - depth) - (1.0 - phase) * gain.r * depth;
|
||||
|
||||
gain.l = limit(gain.l, ZERO_, ONE_);
|
||||
gain.r = limit(gain.r, ZERO_, ONE_);
|
||||
|
||||
for(int i = 0; i < SOUND_BUFFER_SIZE; i++) {
|
||||
REALTYPE x = (REALTYPE) i / SOUND_BUFFER_SIZE;
|
||||
REALTYPE x1 = 1.0 - x;
|
||||
//TODO think about making panning an external feature
|
||||
Stereo<REALTYPE> xn(input.l[i] * panning + fb.l,
|
||||
input.r[i] * (1.0 - panning) + fb.r);
|
||||
|
||||
Stereo<REALTYPE> g(gain.l * x + oldgain.l * x1,
|
||||
gain.r * x + oldgain.r * x1);
|
||||
|
||||
xn.l = applyPhase(xn.l, g.l, old.l);
|
||||
xn.r = applyPhase(xn.r, g.r, old.r);
|
||||
|
||||
//Left/Right crossing
|
||||
crossover(xn.l, xn.r, lrcross);
|
||||
|
||||
fb.l = xn.l * feedback;
|
||||
fb.r = xn.r * feedback;
|
||||
efxoutl[i] = xn.l;
|
||||
efxoutr[i] = xn.r;
|
||||
}
|
||||
|
||||
oldgain = gain;
|
||||
|
||||
if(Poutsub) {
|
||||
invSignal(efxoutl, SOUND_BUFFER_SIZE);
|
||||
invSignal(efxoutr, SOUND_BUFFER_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
REALTYPE Phaser::applyPhase(REALTYPE x, REALTYPE g, REALTYPE *old)
|
||||
{
|
||||
for(int j = 0; j < Pstages * 2; j++) { //Phasing routine
|
||||
REALTYPE tmp = old[j];
|
||||
old[j] = g * tmp + x;
|
||||
x = tmp - g *old[j];
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
/*
|
||||
* Cleanup the effect
|
||||
*/
|
||||
void Phaser::cleanup()
|
||||
{
|
||||
fb = oldgain = Stereo<REALTYPE>(0.0);
|
||||
for(int i = 0; i < Pstages * 2; i++) {
|
||||
old.l[i] = 0.0;
|
||||
old.r[i] = 0.0;
|
||||
}
|
||||
for(int i = 0; i < Pstages; i++) {
|
||||
xn1.l[i] = 0.0;
|
||||
yn1.l[i] = 0.0;
|
||||
xn1.r[i] = 0.0;
|
||||
yn1.r[i] = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Parameter control
|
||||
*/
|
||||
void Phaser::setwidth(unsigned char Pwidth)
|
||||
{
|
||||
this->Pwidth = Pwidth;
|
||||
width = ((float)Pwidth / 127.0f);
|
||||
}
|
||||
|
||||
void Phaser::setfb(unsigned char Pfb)
|
||||
{
|
||||
this->Pfb = Pfb;
|
||||
feedback = (float) (Pfb - 64) / 64.2f;
|
||||
}
|
||||
|
||||
void Phaser::setvolume(unsigned char Pvolume)
|
||||
{
|
||||
this->Pvolume = Pvolume;
|
||||
outvolume = Pvolume / 127.0;
|
||||
if(insertion == 0)
|
||||
volume = 1.0;
|
||||
else
|
||||
volume = outvolume;
|
||||
}
|
||||
|
||||
void Phaser::setpanning(unsigned char Ppanning)
|
||||
{
|
||||
this->Ppanning = Ppanning;
|
||||
panning = (float)Ppanning / 127.0;
|
||||
}
|
||||
|
||||
void Phaser::setlrcross(unsigned char Plrcross)
|
||||
{
|
||||
this->Plrcross = Plrcross;
|
||||
lrcross = Plrcross / 127.0;
|
||||
}
|
||||
|
||||
void Phaser::setdistortion(unsigned char Pdistortion)
|
||||
{
|
||||
this->Pdistortion = Pdistortion;
|
||||
distortion = (float)Pdistortion / 127.0f;
|
||||
}
|
||||
|
||||
void Phaser::setoffset(unsigned char Poffset)
|
||||
{
|
||||
this->Poffset = Poffset;
|
||||
offsetpct = (float)Poffset / 127.0f;
|
||||
}
|
||||
|
||||
void Phaser::setstages(unsigned char Pstages)
|
||||
{
|
||||
if(xn1.l)
|
||||
delete[] xn1.l;
|
||||
if(yn1.l)
|
||||
delete[] yn1.l;
|
||||
if(xn1.r)
|
||||
delete[] xn1.r;
|
||||
if(yn1.r)
|
||||
delete[] yn1.r;
|
||||
|
||||
|
||||
this->Pstages = min(MAX_PHASER_STAGES, (int)Pstages);
|
||||
|
||||
old = Stereo<REALTYPE *>(new REALTYPE[Pstages * 2],
|
||||
new REALTYPE[Pstages * 2]);
|
||||
|
||||
xn1 = Stereo<REALTYPE *>(new REALTYPE[Pstages],
|
||||
new REALTYPE[Pstages]);
|
||||
|
||||
yn1 = Stereo<REALTYPE *>(new REALTYPE[Pstages],
|
||||
new REALTYPE[Pstages]);
|
||||
|
||||
cleanup();
|
||||
}
|
||||
|
||||
void Phaser::setphase(unsigned char Pphase)
|
||||
{
|
||||
this->Pphase = Pphase;
|
||||
phase = (Pphase / 127.0);
|
||||
}
|
||||
|
||||
void Phaser::setdepth(unsigned char Pdepth)
|
||||
{
|
||||
this->Pdepth = Pdepth;
|
||||
depth = (float)(Pdepth) / 127.0f;
|
||||
}
|
||||
|
||||
|
||||
void Phaser::setpreset(unsigned char npreset)
|
||||
{
|
||||
const int PRESET_SIZE = 15;
|
||||
const int NUM_PRESETS = 12;
|
||||
unsigned char presets[NUM_PRESETS][PRESET_SIZE] = {
|
||||
//Phaser
|
||||
//0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
||||
{64, 64, 36, 0, 0, 64, 110, 64, 1, 0, 0, 20, 0, 0, 0},
|
||||
{64, 64, 35, 0, 0, 88, 40, 64, 3, 0, 0, 20, 0, 0, 0},
|
||||
{64, 64, 31, 0, 0, 66, 68, 107, 2, 0, 0, 20, 0, 0, 0},
|
||||
{39, 64, 22, 0, 0, 66, 67, 10, 5, 0, 1, 20, 0, 0, 0},
|
||||
{64, 64, 20, 0, 1, 110, 67, 78, 10, 0, 0, 20, 0, 0, 0},
|
||||
{64, 64, 53, 100, 0, 58, 37, 78, 3, 0, 0, 20, 0, 0, 0},
|
||||
//APhaser
|
||||
//0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
||||
{64, 64, 14, 0, 1, 64, 64, 40, 4, 10, 0, 110, 1, 20, 1},
|
||||
{64, 64, 14, 5, 1, 64, 70, 40, 6, 10, 0, 110, 1, 20, 1},
|
||||
{64, 64, 9, 0, 0, 64, 60, 40, 8, 10, 0, 40, 0, 20, 1},
|
||||
{64, 64, 14, 10, 0, 64, 45, 80, 7, 10, 1, 110, 1, 20, 1},
|
||||
{25, 64, 127, 10, 0, 64, 25, 16, 8, 100, 0, 25, 0, 20, 1},
|
||||
{64, 64, 1, 10, 1, 64, 70, 40, 12, 10, 0, 110, 1, 20, 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 Phaser::changepar(int npar, 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();
|
||||
barber = (2 == value);
|
||||
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);
|
||||
setoffset(value);
|
||||
break;
|
||||
case 10:
|
||||
Poutsub = min((int)value,1);
|
||||
break;
|
||||
case 11:
|
||||
setphase(value);
|
||||
setwidth(value);
|
||||
break;
|
||||
case 12:
|
||||
Phyper = min((int)value, 1);
|
||||
break;
|
||||
case 13:
|
||||
setdistortion(value);
|
||||
break;
|
||||
case 14:
|
||||
Panalog = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char Phaser::getpar(int npar) const
|
||||
{
|
||||
switch(npar) {
|
||||
case 0:
|
||||
return Pvolume;
|
||||
case 1:
|
||||
return Ppanning;
|
||||
case 2:
|
||||
return lfo.Pfreq;
|
||||
case 3:
|
||||
return lfo.Prandomness;
|
||||
case 4:
|
||||
return lfo.PLFOtype;
|
||||
case 5:
|
||||
return lfo.Pstereo;
|
||||
case 6:
|
||||
return Pdepth;
|
||||
case 7:
|
||||
return Pfb;
|
||||
case 8:
|
||||
return Pstages;
|
||||
case 9:
|
||||
return Plrcross;
|
||||
return Poffset;
|
||||
case 10:
|
||||
return Poutsub;
|
||||
case 11:
|
||||
return Pphase;
|
||||
return Pwidth;
|
||||
case 12:
|
||||
return Phyper;
|
||||
case 13:
|
||||
return Pdistortion;
|
||||
case 14:
|
||||
return Panalog;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
Phaser.h - Phaser effect
|
||||
Copyright (C) 2002-2005 Nasca Octavian Paul
|
||||
Copyright (C) 2009-2010 Ryan Billing
|
||||
Copyright (C) 2010-2010 Mark McCurry
|
||||
Author: Nasca Octavian Paul
|
||||
Ryan Billing
|
||||
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 PHASER_H
|
||||
#define PHASER_H
|
||||
#include "../globals.h"
|
||||
#include "Effect.h"
|
||||
#include "EffectLFO.h"
|
||||
|
||||
#define MAX_PHASER_STAGES 12
|
||||
|
||||
class Phaser:public Effect
|
||||
{
|
||||
public:
|
||||
Phaser(const int &insertion_, REALTYPE *efxoutl_, REALTYPE *efxoutr_);
|
||||
~Phaser();
|
||||
void out(const Stereo<REALTYPE *> &input);
|
||||
void setpreset(unsigned char npreset);
|
||||
void changepar(int npar, unsigned char value);
|
||||
unsigned char getpar(int npar) const;
|
||||
void cleanup();
|
||||
|
||||
private:
|
||||
//Phaser parameters
|
||||
EffectLFO lfo; //Phaser modulator
|
||||
unsigned char Pvolume; //Used to set wet/dry mix
|
||||
unsigned char Ppanning;
|
||||
unsigned char Pdistortion; //Model distortion added by FET element
|
||||
unsigned char Pdepth; //Depth of phaser sweep
|
||||
unsigned char Pwidth; //Phaser width (LFO amplitude)
|
||||
unsigned char Pfb; //feedback
|
||||
unsigned char Poffset; //Model mismatch between variable resistors
|
||||
unsigned char Plrcross; //crossover
|
||||
unsigned char Pstages; //Number of first-order All-Pass stages
|
||||
unsigned char Poutsub; //if I wish to subtract the output instead of adding
|
||||
unsigned char Pphase;
|
||||
unsigned char Phyper; //lfo^2 -- converts tri into hyper-sine
|
||||
unsigned char Panalog;
|
||||
|
||||
//Control parameters
|
||||
void setvolume(unsigned char Pvolume);
|
||||
void setpanning(unsigned char Ppanning);
|
||||
void setdepth(unsigned char Pdepth);
|
||||
void setfb(unsigned char Pfb);
|
||||
void setdistortion(unsigned char Pdistortion);
|
||||
void setwidth(unsigned char Pwidth);
|
||||
void setoffset(unsigned char Poffset);
|
||||
void setlrcross(unsigned char Plrcross);
|
||||
void setstages(unsigned char Pstages);
|
||||
void setphase(unsigned char Pphase);
|
||||
|
||||
//Internal Variables
|
||||
bool barber; //Barber pole phasing flag
|
||||
REALTYPE distortion, width, offsetpct;
|
||||
REALTYPE panning, feedback, depth, lrcross, phase;
|
||||
Stereo<REALTYPE *> old, xn1, yn1;
|
||||
Stereo<REALTYPE> diff, oldgain, fb;
|
||||
REALTYPE invperiod;
|
||||
REALTYPE offset[12];
|
||||
|
||||
float mis;
|
||||
float Rmin; // 3N5457 typical on resistance at Vgs = 0
|
||||
float Rmax; // Resistor parallel to FET
|
||||
float Rmx; // Rmin/Rmax to avoid division in loop
|
||||
float Rconst; // Handle parallel resistor relationship
|
||||
float C; // Capacitor
|
||||
float CFs; // A constant derived from capacitor and resistor relationships
|
||||
|
||||
void analog_setup();
|
||||
void AnalogPhase(const Stereo<REALTYPE *> &input);
|
||||
//analog case
|
||||
REALTYPE applyPhase(REALTYPE x, REALTYPE g, REALTYPE fb,
|
||||
REALTYPE &hpf, REALTYPE *yn1, REALTYPE *xn1);
|
||||
|
||||
void normalPhase(const Stereo<REALTYPE *> &input);
|
||||
REALTYPE applyPhase(REALTYPE x, REALTYPE g, REALTYPE *old);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,551 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
Reverb.cpp - 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];
|
||||
|
||||
bandwidth = NULL;
|
||||
|
||||
//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;
|
||||
Pbandwidth = 30;
|
||||
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;
|
||||
if(bandwidth)
|
||||
delete bandwidth;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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(const Stereo<float *> &smp)
|
||||
{
|
||||
int i;
|
||||
if((Pvolume == 0) && (insertion != 0))
|
||||
return;
|
||||
|
||||
for(i = 0; i < SOUND_BUFFER_SIZE; i++)
|
||||
inputbuf[i] = (smp.l[i] + smp.r[i]) / 2.0;
|
||||
|
||||
if(idelay != NULL) {
|
||||
for(i = 0; i < SOUND_BUFFER_SIZE; i++) {
|
||||
//Initial delay r
|
||||
REALTYPE tmp = inputbuf[i] + idelay[idelayk] * idelayfb;
|
||||
inputbuf[i] = idelay[idelayk];
|
||||
idelay[idelayk] = tmp;
|
||||
idelayk++;
|
||||
if(idelayk >= idelaylen)
|
||||
idelayk = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(bandwidth)
|
||||
bandwidth->process(SOUND_BUFFER_SIZE, inputbuf);
|
||||
|
||||
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(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(unsigned char Ppan)
|
||||
{
|
||||
this->Ppan = Ppan;
|
||||
pan = (REALTYPE)Ppan / 127.0;
|
||||
}
|
||||
|
||||
void Reverb::settime(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)
|
||||
{
|
||||
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;
|
||||
REALTYPE x = fabs((REALTYPE)(Plohidamp - 64) / 64.1);
|
||||
lohifb = x * x;
|
||||
}
|
||||
}
|
||||
|
||||
void Reverb::setidelay(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(unsigned char Pidelayfb)
|
||||
{
|
||||
this->Pidelayfb = Pidelayfb;
|
||||
idelayfb = Pidelayfb / 128.0;
|
||||
}
|
||||
|
||||
void Reverb::sethpf(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(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 = 3;
|
||||
const 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 },
|
||||
//Freeverb by Jezar at Dreampoint //duplicate
|
||||
{1116, 1188, 1277, 1356, 1422, 1491, 1557, 1617 }
|
||||
};
|
||||
const int aptunings[NUM_TYPES][REV_APS] = {
|
||||
//this is unused (for random)
|
||||
{0, 0, 0, 0 },
|
||||
//Freeverb by Jezar at Dreampoint
|
||||
{225, 341, 441, 556 },
|
||||
//Freeverb by Jezar at Dreampoint (duplicate)
|
||||
{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();
|
||||
if(bandwidth)
|
||||
delete bandwidth;
|
||||
bandwidth = NULL;
|
||||
if(Ptype == 2) { //bandwidth
|
||||
bandwidth = new Unison(SOUND_BUFFER_SIZE / 4 + 1, 2.0);
|
||||
bandwidth->set_size(50);
|
||||
bandwidth->set_base_frequency(1.0);
|
||||
}
|
||||
}
|
||||
|
||||
void Reverb::setroomsize(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::setbandwidth(unsigned char Pbandwidth) {
|
||||
this->Pbandwidth = Pbandwidth;
|
||||
REALTYPE v = Pbandwidth / 127.0;
|
||||
if(bandwidth)
|
||||
bandwidth->set_bandwidth(pow(v, 2.0) * 200.0);
|
||||
}
|
||||
|
||||
void Reverb::setpreset(unsigned char npreset)
|
||||
{
|
||||
const int PRESET_SIZE = 13;
|
||||
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, 20 },
|
||||
//Cathedral2
|
||||
{80, 64, 69, 35, 0, 0, 0, 127, 0, 71, 0, 64, 20 },
|
||||
//Cathedral3
|
||||
{80, 64, 69, 24, 0, 0, 0, 127, 75, 78, 1, 85, 20 },
|
||||
//Hall1
|
||||
{90, 64, 51, 10, 0, 0, 0, 127, 21, 78, 1, 64, 20 },
|
||||
//Hall2
|
||||
{90, 64, 53, 20, 0, 0, 0, 127, 75, 71, 1, 64, 20 },
|
||||
//Room1
|
||||
{100, 64, 33, 0, 0, 0, 0, 127, 0, 106, 0, 30, 20 },
|
||||
//Room2
|
||||
{100, 64, 21, 26, 0, 0, 0, 62, 0, 77, 1, 45, 20 },
|
||||
//Basement
|
||||
{110, 64, 14, 0, 0, 0, 0, 127, 5, 71, 0, 25, 20 },
|
||||
//Tunnel
|
||||
{85, 80, 84, 20, 42, 0, 0, 51, 0, 78, 1, 105, 20 },
|
||||
//Echoed1
|
||||
{95, 64, 26, 60, 71, 0, 0, 114, 0, 64, 1, 64, 20 },
|
||||
//Echoed2
|
||||
{90, 64, 40, 88, 71, 0, 0, 114, 0, 88, 1, 64, 20 },
|
||||
//VeryLong1
|
||||
{90, 64, 93, 15, 0, 0, 0, 114, 0, 77, 0, 95, 20 },
|
||||
//VeryLong2
|
||||
{90, 64, 111, 30, 0, 0, 0, 114, 90, 74, 1, 80, 20 }
|
||||
};
|
||||
|
||||
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(int npar, 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;
|
||||
case 12:
|
||||
setbandwidth(value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char Reverb::getpar(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;
|
||||
case 12:
|
||||
return Pbandwidth;
|
||||
break;
|
||||
}
|
||||
return 0; //in case of bogus "parameter"
|
||||
}
|
||||
|
||||
@@ -1,135 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
Reverb.h - Reverberation effect
|
||||
Copyright (C) 2002-2009 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 <math.h>
|
||||
#include "../globals.h"
|
||||
#include "../DSP/AnalogFilter.h"
|
||||
#include "../DSP/FFTwrapper.h"
|
||||
#include "../DSP/Unison.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(const Stereo<float *> &smp);
|
||||
void cleanup();
|
||||
|
||||
void setpreset(unsigned char npreset);
|
||||
void changepar(int npar, unsigned char value);
|
||||
unsigned char getpar(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;
|
||||
|
||||
/**Bandwidth */
|
||||
unsigned char Pbandwidth;
|
||||
|
||||
//parameter control
|
||||
void setvolume(unsigned char Pvolume);
|
||||
void setpan(unsigned char Ppan);
|
||||
void settime(unsigned char Ptime);
|
||||
void setlohidamp(unsigned char Plohidamp);
|
||||
void setidelay(unsigned char Pidelay);
|
||||
void setidelayfb(unsigned char Pidelayfb);
|
||||
void sethpf(unsigned char Phpf);
|
||||
void setlpf(unsigned char Plpf);
|
||||
void settype(unsigned char Ptype);
|
||||
void setroomsize(unsigned char Proomsize);
|
||||
void setbandwidth(unsigned char Pbandwidth);
|
||||
|
||||
REALTYPE pan, erbalance;
|
||||
//Parameters
|
||||
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];
|
||||
Unison *bandwidth;
|
||||
|
||||
//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
|
||||
|
||||
@@ -1,118 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
ALSAMidiIn.cpp - 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;
|
||||
}
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
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
|
||||
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 ALSA_MIDI_IN_H
|
||||
#define ALSA_MIDI_IN_H
|
||||
|
||||
#include <alsa/asoundlib.h>
|
||||
#include "MidiIn.h"
|
||||
|
||||
|
||||
/**Midi input for ALSA (this creates an ALSA virtual port)*/
|
||||
class ALSAMidiIn:public MidiIn
|
||||
{
|
||||
public:
|
||||
/**Constructor*/
|
||||
ALSAMidiIn();
|
||||
/**Destructor*/
|
||||
~ALSAMidiIn();
|
||||
|
||||
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
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
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}
|
||||
)
|
||||
@@ -1,96 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
MidiIn.cpp - 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;
|
||||
}
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
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
|
||||
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 MIDI_IN_H
|
||||
#define MIDI_IN_H
|
||||
|
||||
#include "../globals.h"
|
||||
|
||||
enum MidiCmdType {
|
||||
MidiNull, MidiNoteOFF, MidiNoteON, MidiController
|
||||
};
|
||||
#define MP_MAX_BYTES 4000 //in case of loooong SYS_EXes
|
||||
|
||||
/**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
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
NULLMidiIn.cpp - 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
|
||||
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 "NULLMidiIn.h"
|
||||
|
||||
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,
|
||||
int *cmdparams)
|
||||
{
|
||||
cmdtype = MidiNull;
|
||||
}
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
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
|
||||
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 NULL_MIDI_IN_H
|
||||
#define NULL_MIDI_IN_H
|
||||
|
||||
#include "MidiIn.h"
|
||||
|
||||
|
||||
/**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:
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,123 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
OSSMidiIn.cpp - 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
|
||||
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 <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/soundcard.h>
|
||||
|
||||
#include "OSSMidiIn.h"
|
||||
#include "../Misc/Util.h"
|
||||
|
||||
OSSMidiIn::OSSMidiIn()
|
||||
{
|
||||
inputok = false;
|
||||
midi_handle = open(config.cfg.LinuxOSSSeqInDev, O_RDONLY, 0);
|
||||
if(midi_handle != -1)
|
||||
inputok = true;
|
||||
|
||||
lastmidicmd = 0;
|
||||
cmdtype = 0;
|
||||
cmdchan = 0;
|
||||
}
|
||||
|
||||
OSSMidiIn::~OSSMidiIn()
|
||||
{
|
||||
close(midi_handle);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
return tmp[1];
|
||||
}
|
||||
|
||||
unsigned char OSSMidiIn::getmidibyte()
|
||||
{
|
||||
unsigned char b;
|
||||
do {
|
||||
b = readbyte();
|
||||
} while(b == 0xfe); //drops the Active Sense Messages
|
||||
return b;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the midi command,channel and parameters
|
||||
*/
|
||||
void OSSMidiIn::getmidicmd(MidiCmdType &cmdtype,
|
||||
unsigned char &cmdchan,
|
||||
int *cmdparams)
|
||||
{
|
||||
unsigned char tmp, i;
|
||||
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;
|
||||
}
|
||||
|
||||
tmp = getmidibyte();
|
||||
|
||||
if(tmp >= 0x80) {
|
||||
lastmidicmd = tmp;
|
||||
tmp = getmidibyte();
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
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
|
||||
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 OSS_MIDI_IN_H
|
||||
#define OSS_MIDI_IN_H
|
||||
|
||||
#include "MidiIn.h"
|
||||
|
||||
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
|
||||
|
||||
private:
|
||||
int midi_handle;
|
||||
unsigned char lastmidicmd; //last byte (>=80) received from the Midi
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
WINMidiIn.cpp - 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);
|
||||
}
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
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
|
||||
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 WIN_MIDI_IN_H
|
||||
#define WIN_MIDI_IN_H
|
||||
|
||||
|
||||
#include "../Misc/Master.h"
|
||||
|
||||
void InitWinMidi(Master *master_);
|
||||
void StopWinMidi();
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,644 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
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
|
||||
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 "Bank.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "Config.h"
|
||||
|
||||
#define INSTRUMENT_EXTENSION ".xiz"
|
||||
|
||||
//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()
|
||||
{
|
||||
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;
|
||||
}
|
||||
dirname = NULL;
|
||||
clearbank();
|
||||
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
clearbank();
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the name of an instrument from the bank
|
||||
*/
|
||||
char *Bank::getname(unsigned int ninstrument)
|
||||
{
|
||||
if(emptyslot(ninstrument))
|
||||
return defaultinsname;
|
||||
return ins[ninstrument].name;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the numbered name of an instrument from the bank
|
||||
*/
|
||||
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];
|
||||
}
|
||||
|
||||
/*
|
||||
* Changes the name of an instrument (and the filename)
|
||||
*/
|
||||
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);
|
||||
|
||||
//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] = '_';
|
||||
}
|
||||
|
||||
snprintf(newfilename, 1000, "%s/%s.xiz", dirname, tmpfilename);
|
||||
|
||||
// printf("rename %s -> %s\n",ins[ninstrument].filename,newfilename);//////////////
|
||||
|
||||
rename(ins[ninstrument].filename, newfilename);
|
||||
if(ins[ninstrument].filename)
|
||||
delete [] ins[ninstrument].filename;
|
||||
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)
|
||||
{
|
||||
if(ninstrument >= BANK_SIZE)
|
||||
return 1;
|
||||
if(ins[ninstrument].filename == NULL)
|
||||
return 1;
|
||||
|
||||
if(ins[ninstrument].used)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Removes the instrument from the bank
|
||||
*/
|
||||
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
|
||||
*/
|
||||
void Bank::savetoslot(unsigned int ninstrument, Part *part)
|
||||
{
|
||||
clearslot(ninstrument);
|
||||
|
||||
const int maxfilename = 200;
|
||||
char tmpfilename[maxfilename + 20];
|
||||
ZERO(tmpfilename, maxfilename + 20);
|
||||
|
||||
snprintf(tmpfilename,
|
||||
maxfilename,
|
||||
"%4d-%s",
|
||||
ninstrument + 1,
|
||||
(char *)part->Pname);
|
||||
|
||||
//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] = '_';
|
||||
}
|
||||
|
||||
strncat(tmpfilename, ".xiz", maxfilename + 10);
|
||||
|
||||
int fnsize = strlen(dirname) + strlen(tmpfilename) + 10;
|
||||
char *filename = new char[fnsize + 4];
|
||||
ZERO(filename, fnsize + 2);
|
||||
|
||||
snprintf(filename, fnsize, "%s/%s", dirname, tmpfilename);
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
DIR *dir = opendir(bankdirname);
|
||||
clearbank();
|
||||
|
||||
if(dir == NULL)
|
||||
return -1;
|
||||
|
||||
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);
|
||||
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);
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
closedir(dir);
|
||||
|
||||
if(dirname != NULL)
|
||||
sprintf(config.cfg.currentBankDir, "%s", dirname);
|
||||
;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Makes a new bank, put it on a file and makes it current bank
|
||||
*/
|
||||
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 - strlen(bankdir) - 1 );
|
||||
;
|
||||
strncat(bankdir, newbankdirname, MAX_STRING_SIZE - strlen(bankdir) - 1);
|
||||
#ifdef OS_WINDOWS
|
||||
result = mkdir(bankdir);
|
||||
#else
|
||||
result = mkdir(bankdir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
|
||||
#endif
|
||||
if(result < 0)
|
||||
return -1;
|
||||
|
||||
snprintf(tmpfilename,
|
||||
MAX_STRING_SIZE,
|
||||
"%s/%s",
|
||||
bankdir,
|
||||
FORCE_BANK_DIR_FILE);
|
||||
// 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()
|
||||
{
|
||||
return dirname == NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Swaps a slot with another
|
||||
*/
|
||||
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(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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//a helper function that compares 2 banks[] arrays
|
||||
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;
|
||||
|
||||
int result = strcasecmp(bank1->name, bank2->name);
|
||||
return result < 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
banks[i].name = banks[j].name;
|
||||
banks[i].dir = banks[j].dir;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// private stuff
|
||||
|
||||
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];
|
||||
} bank;
|
||||
|
||||
const char *separator = "/";
|
||||
if(strlen(rootdir)) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
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;
|
||||
}
|
||||
;
|
||||
}
|
||||
|
||||
if(pos < 0)
|
||||
return -1; //the bank is full
|
||||
|
||||
// printf("%s %d\n",filename,pos);
|
||||
|
||||
deletefrombank(pos);
|
||||
|
||||
ins[pos].used = true;
|
||||
snprintf(ins[pos].name, PART_MAX_NAME_LEN, "%s", name);
|
||||
|
||||
snprintf(tmpinsname[pos], PART_MAX_NAME_LEN + 10, " ");
|
||||
|
||||
int len = strlen(filename) + 1 + strlen(dirname);
|
||||
ins[pos].filename = new char[len + 2];
|
||||
ins[pos].filename[len + 1] = 0;
|
||||
snprintf(ins[pos].filename, len + 1, "%s/%s", dirname, filename);
|
||||
|
||||
//see if PADsynth is used
|
||||
if(config.cfg.CheckPADsynth) {
|
||||
XMLwrapper *xml = new XMLwrapper();
|
||||
xml->loadXMLfile(ins[pos].filename);
|
||||
|
||||
ins[pos].info.PADsynth_used = xml->hasPadSynth();
|
||||
delete xml;
|
||||
}
|
||||
else
|
||||
ins[pos].info.PADsynth_used = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool Bank::isPADsynth_used(unsigned int ninstrument)
|
||||
{
|
||||
if(config.cfg.CheckPADsynth == 0)
|
||||
return 0;
|
||||
else
|
||||
return ins[ninstrument].info.PADsynth_used;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
ZERO(tmpinsname[pos], PART_MAX_NAME_LEN + 20);
|
||||
}
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
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
|
||||
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 BANK_H
|
||||
#define BANK_H
|
||||
|
||||
#include "../globals.h"
|
||||
#include "XMLwrapper.h"
|
||||
#include "Part.h"
|
||||
|
||||
#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);
|
||||
|
||||
/**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);
|
||||
|
||||
/**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);
|
||||
|
||||
/**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;
|
||||
|
||||
void scanrootdir(char *rootdir); //scans a root dir for banks
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
if(NOT ("${MXML_INCLUDE_DIR}" STREQUAL ""))
|
||||
include_directories("${MXML_INCLUDE_DIR}")
|
||||
endif()
|
||||
|
||||
set(zynaddsubfx_misc_SRCS
|
||||
Bank.cpp
|
||||
Config.cpp
|
||||
Dump.cpp
|
||||
Master.cpp
|
||||
Microtonal.cpp
|
||||
Part.cpp
|
||||
Util.cpp
|
||||
QtXmlWrapper.cpp
|
||||
)
|
||||
|
||||
if (LASH_FOUND)
|
||||
set(zynaddsubfx_misc_SRCS ${zynaddsubfx_misc_SRCS} LASHClient.cpp)
|
||||
endif()
|
||||
|
||||
add_library(zynaddsubfx_misc STATIC
|
||||
${zynaddsubfx_misc_SRCS}
|
||||
)
|
||||
|
||||
target_link_libraries(zynaddsubfx_misc zynaddsubfx_output)
|
||||
@@ -1,409 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
Config.cpp - 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() :
|
||||
workingDir( NULL )
|
||||
{}
|
||||
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;
|
||||
if( workingDir != NULL )
|
||||
{
|
||||
snprintf(name, namesize, "%s%s", workingDir, ".zynaddsubfxXML.cfg");
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef OS_LINUX
|
||||
snprintf(name, namesize, "%s%s", getenv("HOME"), "/.zynaddsubfxXML.cfg");
|
||||
#else
|
||||
snprintf(name, namesize, "%s", "zynaddsubfxXML.cfg");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
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
|
||||
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 CONFIG_H
|
||||
#define CONFIG_H
|
||||
#include "../globals.h"
|
||||
#define MAX_STRING_SIZE 4000
|
||||
#define MAX_BANK_ROOT_DIRS 100
|
||||
|
||||
/**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;
|
||||
|
||||
char * workingDir;
|
||||
|
||||
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
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
/*
|
||||
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_ */
|
||||
|
||||
@@ -1,124 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
Dump.cpp - 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
|
||||
}
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
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
|
||||
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 DUMP_H
|
||||
#define DUMP_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/**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
|
||||
|
||||
@@ -1,104 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
LASHClient.cpp - 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));
|
||||
}
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
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
|
||||
|
||||
@@ -1,828 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
Master.cpp - 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(µtonal, 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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,177 +0,0 @@
|
||||
/*
|
||||
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
|
||||
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 MASTER_H
|
||||
#define MASTER_H
|
||||
|
||||
#include "../globals.h"
|
||||
#include "../Effects/EffectMgr.h"
|
||||
#include "Part.h"
|
||||
#include "../Output/Recorder.h"
|
||||
#include "Microtonal.h"
|
||||
|
||||
#include "Bank.h"
|
||||
#include "Dump.h"
|
||||
#include "../Seq/Sequencer.h"
|
||||
#include "XMLwrapper.h"
|
||||
|
||||
extern Dump dump;
|
||||
/** 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
|
||||
* @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);
|
||||
|
||||
void defaults();
|
||||
|
||||
|
||||
/**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)
|
||||
* @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);
|
||||
|
||||
|
||||
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;
|
||||
|
||||
//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
|
||||
|
||||
Controller ctl;
|
||||
int swaplr; //1 if L and R are swapped
|
||||
|
||||
//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;
|
||||
|
||||
//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
|
||||
|
||||
//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);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,687 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
Microtonal.cpp - 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 µ) const
|
||||
{
|
||||
return !(*this != micro);
|
||||
}
|
||||
|
||||
bool Microtonal::operator!=(const Microtonal µ) 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.%06d", 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;
|
||||
}
|
||||
|
||||
@@ -1,135 +0,0 @@
|
||||
/*
|
||||
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
|
||||
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 MICROTONAL_H
|
||||
#define MICROTONAL_H
|
||||
|
||||
#include "../globals.h"
|
||||
#include "XMLwrapper.h"
|
||||
|
||||
#define MAX_OCTAVE_SIZE 128
|
||||
#define MICROTONAL_MAX_NAME_LEN 120
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
/**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;
|
||||
|
||||
|
||||
//Parameters
|
||||
/**if the keys are inversed (the pitch is lower to keys from the right direction)*/
|
||||
unsigned char Pinvertupdown;
|
||||
|
||||
/**the central key of the inversion*/
|
||||
unsigned char Pinvertupdowncenter;
|
||||
|
||||
/**0 for 12 key temperate scale, 1 for microtonal*/
|
||||
unsigned char Penabled;
|
||||
|
||||
/**the note of "A" key*/
|
||||
unsigned char PAnote;
|
||||
|
||||
/**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;
|
||||
|
||||
//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 µ) const;
|
||||
bool operator!=(const Microtonal µ) 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];
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,206 +0,0 @@
|
||||
/*
|
||||
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
|
||||
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 PART_H
|
||||
#define PART_H
|
||||
|
||||
#define MAX_INFO_TEXT_SIZE 1000
|
||||
|
||||
#include "../globals.h"
|
||||
#include "../Params/ADnoteParameters.h"
|
||||
#include "../Params/SUBnoteParameters.h"
|
||||
#include "../Params/PADnoteParameters.h"
|
||||
#include "../Synth/ADnote.h"
|
||||
#include "../Synth/SUBnote.h"
|
||||
#include "../Synth/PADnote.h"
|
||||
#include "../Params/Controller.h"
|
||||
#include "../Misc/Microtonal.h"
|
||||
#include "../DSP/FFTwrapper.h"
|
||||
#include "../Effects/EffectMgr.h"
|
||||
#include "XMLwrapper.h"
|
||||
|
||||
#include <list> // For the monomemnotes list.
|
||||
|
||||
/** Part implementation*/
|
||||
class 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
|
||||
|
||||
/* 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);
|
||||
|
||||
void add2XML(XMLwrapper *xml);
|
||||
void add2XMLinstrument(XMLwrapper *xml);
|
||||
|
||||
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 {
|
||||
unsigned char Penabled, Pmuted, Pminkey, Pmaxkey;
|
||||
unsigned char *Pname;
|
||||
unsigned char Padenabled, Psubenabled, Ppadenabled;
|
||||
unsigned char Psendtoparteffect;
|
||||
ADnoteParameters *adpars;
|
||||
SUBnoteParameters *subpars;
|
||||
PADnoteParameters *padpars;
|
||||
} 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)
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
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 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[] is used in conjunction with the list to
|
||||
store the velocity and masterkeyshift values of a
|
||||
given note (the list only store note values).
|
||||
For example 'monomem[note].velocity' would be the
|
||||
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;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,550 +0,0 @@
|
||||
/*
|
||||
* QtXmlWrapper.cpp - a QtXml based XML backend for ZynAddSubxFX
|
||||
*
|
||||
* Copyright (c) 2009 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
*
|
||||
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program (see COPYING); if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/* File derived from QtXmlWrapper.C: */
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
QtXmlWrapper.C - 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
|
||||
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 <QtXml/QDomDocument>
|
||||
#include <QtCore/QDebug>
|
||||
#include "QtXmlWrapper.h"
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <cstdarg>
|
||||
#include <zlib.h>
|
||||
#include "lmmsconfig.h"
|
||||
#include "../globals.h"
|
||||
#include "Util.h"
|
||||
|
||||
|
||||
struct XmlData
|
||||
{
|
||||
XmlData() :
|
||||
m_doc( "ZynAddSubFX-data" )
|
||||
{
|
||||
}
|
||||
QDomDocument m_doc;
|
||||
QDomElement m_node;
|
||||
QDomElement m_info;
|
||||
|
||||
QDomElement addparams( const char *name, unsigned int params, ... );
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
QtXmlWrapper::QtXmlWrapper() :
|
||||
d( new XmlData )
|
||||
{
|
||||
version.Major = 2;
|
||||
version.Minor = 4;
|
||||
version.Revision = 1;
|
||||
|
||||
minimal = true;
|
||||
|
||||
d->m_node = d->m_doc.createElement( "ZynAddSubFX-data" );
|
||||
d->m_node.setAttribute( "version-major", QString::number( version.Major ) );
|
||||
d->m_node.setAttribute( "version-minor", QString::number( version.Minor ) );
|
||||
d->m_node.setAttribute( "version-revision", QString::number( version.Revision ) );
|
||||
d->m_node.setAttribute( "ZynAddSubFX-author", "Nasca Octavian Paul" );
|
||||
d->m_doc.appendChild( d->m_node );
|
||||
|
||||
//make the empty branch that will contain the information parameters
|
||||
d->m_info = d->addparams("INFORMATION", 0);
|
||||
|
||||
//save zynaddsubfx specifications
|
||||
beginbranch("BASE_PARAMETERS");
|
||||
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_addsynth_voices", NUM_VOICES);
|
||||
endbranch();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
QtXmlWrapper::~QtXmlWrapper()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void QtXmlWrapper::setPadSynth(bool enabled)
|
||||
{
|
||||
/**@bug this might create multiple nodes when only one is needed*/
|
||||
QDomElement oldNode = d->m_node;
|
||||
d->m_node = d->m_info;
|
||||
//Info storing
|
||||
addparbool("PADsynth_used", enabled);
|
||||
d->m_node = oldNode;
|
||||
}
|
||||
|
||||
QDomElement findElement( QDomElement root, const QString & tagname, const QString & attrname,
|
||||
const QString & attrval )
|
||||
{
|
||||
QDomNodeList list = root.elementsByTagName( tagname );
|
||||
for( int i = 0; i < list.size(); ++i )
|
||||
{
|
||||
QDomNode n = list.at( i );
|
||||
if( n.isElement() )
|
||||
{
|
||||
QDomElement e = n.toElement();
|
||||
if( e.hasAttribute( attrname ) && e.attribute( attrname ) == attrval )
|
||||
{
|
||||
return e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return QDomElement();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bool QtXmlWrapper::hasPadSynth() const
|
||||
{
|
||||
/**Right now this has a copied implementation of setparbool, so this should
|
||||
* be reworked as XMLwrapper evolves*/
|
||||
QDomElement tmp = d->m_doc.elementsByTagName( "INFORMATION" ).at( 0 ).toElement();
|
||||
QDomElement parameter = findElement( tmp, "par_bool", "name", "PADsynth_used" );
|
||||
if( !parameter.isNull() )
|
||||
{
|
||||
const QString val = parameter.attribute( "value" ).toLower();
|
||||
return val[0] == 'y';
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* SAVE XML members */
|
||||
|
||||
int QtXmlWrapper::saveXMLfile(const std::string &filename) const
|
||||
{
|
||||
char *xmldata = getXMLdata();
|
||||
if(xmldata == NULL)
|
||||
return -2;
|
||||
|
||||
int compression = config.cfg.GzipCompression;
|
||||
int result = dosavefile(filename.c_str(), compression, xmldata);
|
||||
|
||||
delete[] xmldata;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
char *QtXmlWrapper::getXMLdata() const
|
||||
{
|
||||
QString xml = d->m_doc.toString( 1 );
|
||||
return qstrdup( xml.toUtf8().constData() );
|
||||
}
|
||||
|
||||
|
||||
int QtXmlWrapper::dosavefile(const char *filename,
|
||||
int compression,
|
||||
const char *xmldata) const
|
||||
{
|
||||
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);
|
||||
|
||||
gzFile gzfile;
|
||||
gzfile = gzopen(filename, options);
|
||||
if(gzfile == NULL)
|
||||
return -1;
|
||||
gzputs(gzfile, xmldata);
|
||||
gzclose(gzfile);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void QtXmlWrapper::addpar(const std::string &name, int val)
|
||||
{
|
||||
d->addparams("par", 2, "name", name.c_str(), "value", stringFrom<int>(
|
||||
val).c_str());
|
||||
}
|
||||
|
||||
void QtXmlWrapper::addparreal(const std::string &name, REALTYPE val)
|
||||
{
|
||||
d->addparams("par_real", 2, "name", name.c_str(), "value",
|
||||
stringFrom<REALTYPE>(val).c_str());
|
||||
}
|
||||
|
||||
void QtXmlWrapper::addparbool(const std::string &name, int val)
|
||||
{
|
||||
if(val != 0)
|
||||
d->addparams("par_bool", 2, "name", name.c_str(), "value", "yes");
|
||||
else
|
||||
d->addparams("par_bool", 2, "name", name.c_str(), "value", "no");
|
||||
}
|
||||
|
||||
void QtXmlWrapper::addparstr(const std::string &name, const std::string &val)
|
||||
{
|
||||
QDomElement e = d->m_doc.createElement( "string" );
|
||||
e.setAttribute( "name", name.c_str() );
|
||||
e.appendChild( d->m_doc.createTextNode( val.c_str() ) );
|
||||
d->m_node.appendChild( e );
|
||||
}
|
||||
|
||||
|
||||
void QtXmlWrapper::beginbranch(const std::string &name)
|
||||
{
|
||||
d->m_node = d->addparams(name.c_str(), 0);
|
||||
}
|
||||
|
||||
void QtXmlWrapper::beginbranch(const std::string &name, int id)
|
||||
{
|
||||
d->m_node = d->addparams(name.c_str(), 1, "id", stringFrom<int>(id).c_str());
|
||||
}
|
||||
|
||||
void QtXmlWrapper::endbranch()
|
||||
{
|
||||
d->m_node = d->m_node.parentNode().toElement();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* LOAD XML members */
|
||||
|
||||
int QtXmlWrapper::loadXMLfile(const std::string &filename)
|
||||
{
|
||||
const char *xmldata = doloadfile(filename.c_str());
|
||||
if(xmldata == NULL)
|
||||
{
|
||||
qDebug() << "QtXmlWrapper::loadXMLfile(): empty data";
|
||||
return -1; //the file could not be loaded or uncompressed
|
||||
}
|
||||
|
||||
QByteArray b( xmldata );
|
||||
while( !b.isEmpty() && b[0] != '<' )
|
||||
{
|
||||
// remove first blank line
|
||||
b.remove( 0, 1 );
|
||||
}
|
||||
|
||||
if( !d->m_doc.setContent( b ) )
|
||||
{
|
||||
qDebug() << "QtXmlWrapper::loadXMLfile(): could not set document content";
|
||||
delete[] xmldata;
|
||||
return -2;
|
||||
}
|
||||
delete[] xmldata;
|
||||
|
||||
d->m_node = d->m_doc.elementsByTagName( "ZynAddSubFX-data" ).at( 0 ).toElement();
|
||||
if( d->m_node.isNull() || !d->m_node.isElement() )
|
||||
{
|
||||
qDebug() << "QtXmlWrapper::loadXMLfile(): missing root node";
|
||||
return -3; //the XML doesnt embbed zynaddsubfx data
|
||||
}
|
||||
QDomElement root = d->m_node.toElement();
|
||||
//fetch version information
|
||||
version.Major = root.attribute( "version-major").toInt();
|
||||
version.Minor = root.attribute( "version-minor").toInt();
|
||||
version.Revision = root.attribute( "version-revision").toInt();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
char *QtXmlWrapper::doloadfile(const std::string &filename) const
|
||||
{
|
||||
char *xmldata = NULL;
|
||||
gzFile gzfile = gzopen(filename.c_str(), "rb");
|
||||
|
||||
if(gzfile != NULL) { //The possibly compressed file opened
|
||||
std::stringstream strBuf; //reading stream
|
||||
const int bufSize = 500; //fetch size
|
||||
char fetchBuf[bufSize + 1]; //fetch buffer
|
||||
int read = 0; //chars read in last fetch
|
||||
|
||||
fetchBuf[bufSize] = 0; //force null termination
|
||||
|
||||
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
|
||||
std::string tmp = strBuf.str();
|
||||
xmldata = new char[tmp.size() + 1];
|
||||
strncpy(xmldata, tmp.c_str(), tmp.size() + 1);
|
||||
}
|
||||
|
||||
return xmldata;
|
||||
}
|
||||
|
||||
bool QtXmlWrapper::putXMLdata(const char *xmldata)
|
||||
{
|
||||
d->m_doc.setContent( QString::fromUtf8( xmldata ) );
|
||||
|
||||
d->m_node = d->m_doc.elementsByTagName( "ZynAddSubFX-data" ).at( 0 ).toElement();
|
||||
if( d->m_node.isNull() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int QtXmlWrapper::enterbranch(const std::string &name)
|
||||
{
|
||||
QDomElement tmp = d->m_node.firstChildElement( name.c_str() );
|
||||
if( tmp.isNull() )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
d->m_node = tmp;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int QtXmlWrapper::enterbranch(const std::string &name, int id)
|
||||
{
|
||||
QDomElement tmp = findElement( d->m_node, name.c_str(),
|
||||
"id", QString::number( id ) );
|
||||
if( tmp.isNull() )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
d->m_node = tmp;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void QtXmlWrapper::exitbranch()
|
||||
{
|
||||
d->m_node = d->m_node.parentNode().toElement();
|
||||
}
|
||||
|
||||
|
||||
int QtXmlWrapper::getbranchid(int min, int max) const
|
||||
{
|
||||
if( !d->m_node.isElement() )
|
||||
{
|
||||
return min;
|
||||
}
|
||||
QDomElement tmp = d->m_node.toElement();
|
||||
if( !tmp.hasAttribute( "id" ) )
|
||||
{
|
||||
return min;
|
||||
}
|
||||
int id = tmp.attribute( "id" ).toInt();
|
||||
if((min == 0) && (max == 0))
|
||||
return id;
|
||||
|
||||
if(id < min)
|
||||
id = min;
|
||||
else
|
||||
if(id > max)
|
||||
id = max;
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
int QtXmlWrapper::getpar(const std::string &name, int defaultpar, int min,
|
||||
int max) const
|
||||
{
|
||||
QDomElement tmp = findElement( d->m_node, "par", "name", name.c_str() );
|
||||
if( tmp.isNull() || !tmp.hasAttribute( "value" ) )
|
||||
{
|
||||
return defaultpar;
|
||||
}
|
||||
|
||||
int val = tmp.attribute( "value" ).toInt();
|
||||
if(val < min)
|
||||
val = min;
|
||||
else
|
||||
if(val > max)
|
||||
val = max;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
int QtXmlWrapper::getpar127(const std::string &name, int defaultpar) const
|
||||
{
|
||||
return getpar(name, defaultpar, 0, 127);
|
||||
}
|
||||
|
||||
int QtXmlWrapper::getparbool(const std::string &name, int defaultpar) const
|
||||
{
|
||||
QDomElement tmp = findElement( d->m_node, "par_bool", "name", name.c_str() );
|
||||
if( tmp.isNull() || !tmp.hasAttribute( "value" ) )
|
||||
{
|
||||
return defaultpar;
|
||||
}
|
||||
|
||||
const QString val = tmp.attribute( "value" ).toLower();
|
||||
if( val[0] == 'y' )
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void QtXmlWrapper::getparstr(const std::string &name, char *par, int maxstrlen) const
|
||||
{
|
||||
ZERO(par, maxstrlen);
|
||||
QDomNode tmp = findElement( d->m_node, "string", "name", name.c_str() );
|
||||
if( tmp.isNull() || !tmp.hasChildNodes() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
tmp = tmp.firstChild();
|
||||
if( tmp.nodeType() == QDomNode::ElementNode )
|
||||
{
|
||||
snprintf(par, maxstrlen, "%s", tmp.toElement().tagName().toUtf8().constData() );
|
||||
return;
|
||||
}
|
||||
if( tmp.nodeType() == QDomNode::TextNode )
|
||||
{
|
||||
snprintf(par, maxstrlen, "%s", tmp.toText().data().toUtf8().constData() );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
std::string QtXmlWrapper::getparstr(const std::string &name,
|
||||
const std::string &defaultpar) const
|
||||
{
|
||||
QDomNode tmp = findElement( d->m_node, "string", "name", name.c_str() );
|
||||
if( tmp.isNull() || !tmp.hasChildNodes() )
|
||||
{
|
||||
return defaultpar;
|
||||
}
|
||||
|
||||
tmp = tmp.firstChild();
|
||||
if( tmp.nodeType() == QDomNode::ElementNode && !tmp.toElement().tagName().isEmpty() )
|
||||
{
|
||||
return tmp.toElement().tagName().toUtf8().constData();
|
||||
}
|
||||
if( tmp.nodeType() == QDomNode::TextNode && !tmp.toText().data().isEmpty() )
|
||||
{
|
||||
return tmp.toText().data().toUtf8().constData();
|
||||
}
|
||||
|
||||
return defaultpar;
|
||||
}
|
||||
|
||||
REALTYPE QtXmlWrapper::getparreal(const char *name, REALTYPE defaultpar) const
|
||||
{
|
||||
QDomElement tmp = findElement( d->m_node, "par_real", "name", name );
|
||||
if( tmp.isNull() || !tmp.hasAttribute( "value" ) )
|
||||
{
|
||||
return defaultpar;
|
||||
}
|
||||
|
||||
return tmp.attribute( "value" ).toFloat();
|
||||
}
|
||||
|
||||
REALTYPE QtXmlWrapper::getparreal(const char *name,
|
||||
REALTYPE defaultpar,
|
||||
REALTYPE min,
|
||||
REALTYPE max) const
|
||||
{
|
||||
REALTYPE result = getparreal(name, defaultpar);
|
||||
|
||||
if(result < min)
|
||||
result = min;
|
||||
else
|
||||
if(result > max)
|
||||
result = max;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/** Private members **/
|
||||
|
||||
QDomElement XmlData::addparams(const char *name, unsigned int params,
|
||||
...)
|
||||
{
|
||||
/**@todo make this function send out a good error message if something goes
|
||||
* wrong**/
|
||||
QDomElement element = m_doc.createElement( name );
|
||||
m_node.appendChild( element );
|
||||
|
||||
if(params) {
|
||||
va_list variableList;
|
||||
va_start(variableList, params);
|
||||
|
||||
const char *ParamName;
|
||||
const char *ParamValue;
|
||||
while(params--) {
|
||||
ParamName = va_arg(variableList, const char *);
|
||||
ParamValue = va_arg(variableList, const char *);
|
||||
element.setAttribute( ParamName, ParamValue);
|
||||
}
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
@@ -1,125 +0,0 @@
|
||||
/*
|
||||
* QtXmlWrapper.h - a QtXml based XML backend for ZynAddSubxFX
|
||||
*
|
||||
* Copyright (c) 2009 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
*
|
||||
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program (see COPYING); if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/* File derived from XMLwrapper.h: */
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
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
|
||||
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 QT_XML_WRAPPER_H
|
||||
#define QT_XML_WRAPPER_H
|
||||
|
||||
#include "../globals.h"
|
||||
|
||||
#include <string>
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#define QtXmlWrapper XMLwrapper
|
||||
|
||||
struct XmlData;
|
||||
|
||||
class QtXmlWrapper
|
||||
{
|
||||
public:
|
||||
QtXmlWrapper();
|
||||
~QtXmlWrapper();
|
||||
|
||||
int saveXMLfile( const std::string & filename ) const;
|
||||
int loadXMLfile( const std::string & filename );
|
||||
|
||||
char *getXMLdata() const;
|
||||
bool putXMLdata( const char *xmldata );
|
||||
|
||||
void addpar( const std::string & name, int val );
|
||||
void addparreal( const std::string & name, REALTYPE val);
|
||||
void addparbool( const std::string & name, int val );
|
||||
void addparstr( const std::string & name, const std::string & val );
|
||||
|
||||
void beginbranch( const std::string & name );
|
||||
void beginbranch( const std::string & name, int id );
|
||||
void endbranch();
|
||||
|
||||
|
||||
int enterbranch( const std::string & name );
|
||||
int enterbranch( const std::string & name, int id );
|
||||
void exitbranch();
|
||||
int getbranchid( int min, int max ) const;
|
||||
|
||||
int getpar( const std::string & name, int defaultpar, int min, int max ) const;
|
||||
int getpar127( const std::string & name, int defaultpar ) const;
|
||||
int getparbool( const std::string & name, int defaultpar ) const;
|
||||
|
||||
void getparstr( const std::string & name, char * par, int maxstrlen ) const;
|
||||
std::string getparstr( const std::string & name, const std::string & defaultpar ) const;
|
||||
REALTYPE getparreal( const char * name, REALTYPE defaultpar ) const;
|
||||
|
||||
REALTYPE getparreal(const char *name, REALTYPE defaultpar, REALTYPE min, REALTYPE max) const;
|
||||
|
||||
bool minimal; /**<false if all parameters will be stored (used only for clipboard)*/
|
||||
|
||||
void setPadSynth( bool enabled );
|
||||
bool hasPadSynth() const;
|
||||
|
||||
|
||||
private:
|
||||
int dosavefile(const char *filename, int compression, const char *xmldata) const;
|
||||
|
||||
char *doloadfile(const std::string &filename) const;
|
||||
|
||||
struct
|
||||
{
|
||||
int Major;
|
||||
int Minor;
|
||||
int Revision;
|
||||
} version;
|
||||
|
||||
XmlData * d;
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
Stereo.cpp - 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)
|
||||
:l(left), r(right)
|
||||
{}
|
||||
|
||||
template<class T>
|
||||
Stereo<T>::Stereo(const T &val)
|
||||
:l(val), r(val)
|
||||
{}
|
||||
|
||||
template<class T>
|
||||
Stereo<T> &Stereo<T>::operator=(const Stereo<T> &nstr)
|
||||
{
|
||||
l = nstr.l;
|
||||
r = nstr.r;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
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>
|
||||
struct 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() {}
|
||||
|
||||
Stereo<T> &operator=(const Stereo<T> &smp);
|
||||
|
||||
//data
|
||||
T l, r;
|
||||
};
|
||||
#include "Stereo.cpp"
|
||||
#endif
|
||||
|
||||
@@ -1,130 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
Util.cpp - 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
|
||||
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 "Util.h"
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
int SAMPLE_RATE = 44100;
|
||||
int SOUND_BUFFER_SIZE = 256;
|
||||
int OSCIL_SIZE = 1024;
|
||||
|
||||
Config config;
|
||||
REALTYPE *denormalkillbuf;
|
||||
|
||||
|
||||
/*
|
||||
* Transform the velocity according the scaling parameter (velocity sensing)
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the detune in cents
|
||||
*/
|
||||
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;
|
||||
if(octave >= 8)
|
||||
octave -= 16;
|
||||
octdet = octave * 1200.0;
|
||||
|
||||
//Coarse and fine detune
|
||||
int cdetune = coarsedetune % 1024;
|
||||
if(cdetune > 512)
|
||||
cdetune -= 1024;
|
||||
|
||||
int fdetune = finedetune - 8192;
|
||||
|
||||
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;
|
||||
}
|
||||
if(finedetune < 8192)
|
||||
findet = -findet;
|
||||
if(cdetune < 0)
|
||||
cdet = -cdet;
|
||||
|
||||
det = octdet + cdet + findet;
|
||||
return det;
|
||||
}
|
||||
|
||||
|
||||
bool fileexists(const char *filename)
|
||||
{
|
||||
struct stat tmp;
|
||||
int result = stat(filename, &tmp);
|
||||
if(result >= 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void invSignal(REALTYPE *sig, size_t len)
|
||||
{
|
||||
for(unsigned int i = 0; i < len; i++)
|
||||
sig[i] *= -1.0f;
|
||||
}
|
||||
|
||||
void crossover(REALTYPE &a, REALTYPE &b, REALTYPE crossover)
|
||||
{
|
||||
REALTYPE tmpa = a;
|
||||
REALTYPE tmpb = b;
|
||||
a = tmpa * (1.0 - crossover) + tmpb * crossover;
|
||||
b = tmpb * (1.0 - crossover) + tmpa * crossover;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
/*
|
||||
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
|
||||
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 UTIL_H
|
||||
#define UTIL_H
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include "../globals.h"
|
||||
#include "Config.h"
|
||||
|
||||
//Velocity Sensing function
|
||||
extern REALTYPE VelF(REALTYPE velocity, unsigned char scaling);
|
||||
|
||||
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 Config config;
|
||||
|
||||
void invSignal(REALTYPE *sig, size_t len);
|
||||
|
||||
void crossover(REALTYPE &a, REALTYPE &b, REALTYPE crossover);
|
||||
|
||||
template<class T>
|
||||
std::string stringFrom(T x)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << x;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
std::string stringFrom(REALTYPE x)
|
||||
{
|
||||
char buf[64];
|
||||
sprintf( buf, "%f", x );
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
T stringTo(const char *x)
|
||||
{
|
||||
std::string str = x != NULL ? x : "0"; //should work for the basic float/int
|
||||
std::stringstream ss(str);
|
||||
T ans;
|
||||
ss >> ans;
|
||||
return ans;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T limit(T val, T min, T max)
|
||||
{
|
||||
return (val < min ? min : (val > max ? max : val));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,617 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
XMLwrapper.cpp - 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
|
||||
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 "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;
|
||||
bool verbose = false;
|
||||
|
||||
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";
|
||||
;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//temporary const overload of mxmlFindElement
|
||||
const mxml_node_t *mxmlFindElement(const mxml_node_t *node,
|
||||
const mxml_node_t *top,
|
||||
const char *name,
|
||||
const char *attr,
|
||||
const char *value,
|
||||
int descend)
|
||||
{
|
||||
return const_cast<const mxml_node_t *>(mxmlFindElement(
|
||||
const_cast<mxml_node_t *>(node),
|
||||
const_cast<mxml_node_t *>(top),
|
||||
name, attr, value, descend));
|
||||
}
|
||||
|
||||
//temporary const overload of mxmlElementGetAttr
|
||||
const char *mxmlElementGetAttr(const mxml_node_t *node, const char *name)
|
||||
{
|
||||
return mxmlElementGetAttr(const_cast<mxml_node_t *>(node), name);
|
||||
}
|
||||
|
||||
XMLwrapper::XMLwrapper()
|
||||
{
|
||||
version.Major = 2;
|
||||
version.Minor = 4;
|
||||
version.Revision = 1;
|
||||
|
||||
minimal = true;
|
||||
|
||||
node = 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");
|
||||
*/
|
||||
|
||||
mxml_node_t *doctype = mxmlNewElement(tree, "!DOCTYPE");
|
||||
mxmlElementSetAttr(doctype, "ZynAddSubFX-data", NULL);
|
||||
|
||||
node = root = addparams("ZynAddSubFX-data", 4,
|
||||
"version-major", stringFrom<int>(
|
||||
version.Major).c_str(),
|
||||
"version-minor", stringFrom<int>(
|
||||
version.Minor).c_str(),
|
||||
"version-revision",
|
||||
stringFrom<int>(version.Revision).c_str(),
|
||||
"ZynAddSubFX-author", "Nasca Octavian Paul");
|
||||
|
||||
//make the empty branch that will contain the information parameters
|
||||
info = addparams("INFORMATION", 0);
|
||||
|
||||
//save zynaddsubfx specifications
|
||||
beginbranch("BASE_PARAMETERS");
|
||||
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_addsynth_voices", NUM_VOICES);
|
||||
endbranch();
|
||||
}
|
||||
|
||||
XMLwrapper::~XMLwrapper()
|
||||
{
|
||||
if(tree != NULL)
|
||||
mxmlDelete(tree);
|
||||
}
|
||||
|
||||
void XMLwrapper::setPadSynth(bool enabled)
|
||||
{
|
||||
/**@bug this might create multiple nodes when only one is needed*/
|
||||
mxml_node_t *oldnode = node;
|
||||
node = info;
|
||||
//Info storing
|
||||
addparbool("PADsynth_used", enabled);
|
||||
node = oldnode;
|
||||
}
|
||||
|
||||
bool XMLwrapper::hasPadSynth() const
|
||||
{
|
||||
/**Right now this has a copied implementation of setparbool, so this should
|
||||
* be reworked as XMLwrapper evolves*/
|
||||
mxml_node_t *tmp = mxmlFindElement(tree,
|
||||
tree,
|
||||
"INFORMATION",
|
||||
NULL,
|
||||
NULL,
|
||||
MXML_DESCEND);
|
||||
|
||||
mxml_node_t *parameter = mxmlFindElement(tmp,
|
||||
tmp,
|
||||
"par_bool",
|
||||
"name",
|
||||
"PADsynth_used",
|
||||
MXML_DESCEND_FIRST);
|
||||
if(parameter == NULL) //no information availiable
|
||||
return false;
|
||||
|
||||
const char *strval = mxmlElementGetAttr(parameter, "value");
|
||||
if(strval == NULL) //no information available
|
||||
return false;
|
||||
|
||||
if((strval[0] == 'Y') || (strval[0] == 'y'))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* SAVE XML members */
|
||||
|
||||
int XMLwrapper::saveXMLfile(const string &filename) const
|
||||
{
|
||||
char *xmldata = getXMLdata();
|
||||
if(xmldata == NULL)
|
||||
return -2;
|
||||
|
||||
int compression = config.cfg.GzipCompression;
|
||||
int result = dosavefile(filename.c_str(), compression, xmldata);
|
||||
|
||||
free(xmldata);
|
||||
return result;
|
||||
}
|
||||
|
||||
char *XMLwrapper::getXMLdata() const
|
||||
{
|
||||
xml_k = 0;
|
||||
|
||||
char *xmldata = mxmlSaveAllocString(tree, XMLwrapper_whitespace_callback);
|
||||
|
||||
return xmldata;
|
||||
}
|
||||
|
||||
|
||||
int XMLwrapper::dosavefile(const char *filename,
|
||||
int compression,
|
||||
const char *xmldata) const
|
||||
{
|
||||
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);
|
||||
|
||||
gzFile gzfile;
|
||||
gzfile = gzopen(filename, options);
|
||||
if(gzfile == NULL)
|
||||
return -1;
|
||||
gzputs(gzfile, xmldata);
|
||||
gzclose(gzfile);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void XMLwrapper::addpar(const string &name, int val)
|
||||
{
|
||||
addparams("par", 2, "name", name.c_str(), "value", stringFrom<int>(
|
||||
val).c_str());
|
||||
}
|
||||
|
||||
void XMLwrapper::addparreal(const string &name, REALTYPE val)
|
||||
{
|
||||
addparams("par_real", 2, "name", name.c_str(), "value",
|
||||
stringFrom<REALTYPE>(val).c_str());
|
||||
}
|
||||
|
||||
void XMLwrapper::addparbool(const string &name, int val)
|
||||
{
|
||||
if(val != 0)
|
||||
addparams("par_bool", 2, "name", name.c_str(), "value", "yes");
|
||||
else
|
||||
addparams("par_bool", 2, "name", name.c_str(), "value", "no");
|
||||
}
|
||||
|
||||
void XMLwrapper::addparstr(const string &name, const string &val)
|
||||
{
|
||||
mxml_node_t *element = mxmlNewElement(node, "string");
|
||||
mxmlElementSetAttr(element, "name", name.c_str());
|
||||
mxmlNewText(element, 0, val.c_str());
|
||||
}
|
||||
|
||||
|
||||
void XMLwrapper::beginbranch(const string &name)
|
||||
{
|
||||
if(verbose)
|
||||
cout << "beginbranch()" << name << endl;
|
||||
node = addparams(name.c_str(), 0);
|
||||
}
|
||||
|
||||
void XMLwrapper::beginbranch(const string &name, int id)
|
||||
{
|
||||
if(verbose)
|
||||
cout << "beginbranch(" << id << ")" << name << endl;
|
||||
node = addparams(name.c_str(), 1, "id", stringFrom<int>(id).c_str());
|
||||
}
|
||||
|
||||
void XMLwrapper::endbranch()
|
||||
{
|
||||
if(verbose)
|
||||
cout << "endbranch()" << node << "-" << node->value.element.name
|
||||
<< " To "
|
||||
<< node->parent << "-" << node->parent->value.element.name << endl;
|
||||
node = node->parent;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* LOAD XML members */
|
||||
|
||||
int XMLwrapper::loadXMLfile(const string &filename)
|
||||
{
|
||||
if(tree != NULL)
|
||||
mxmlDelete(tree);
|
||||
tree = NULL;
|
||||
|
||||
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
|
||||
|
||||
//fetch version information
|
||||
version.Major = stringTo<int>(mxmlElementGetAttr(root, "version-major"));
|
||||
version.Minor = stringTo<int>(mxmlElementGetAttr(root, "version-minor"));
|
||||
version.Revision =
|
||||
stringTo<int>(mxmlElementGetAttr(root, "version-revision"));
|
||||
|
||||
if(verbose)
|
||||
cout << "loadXMLfile() version: " << version.Major << '.'
|
||||
<< version.Minor << '.' << version.Revision << endl;
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
char *XMLwrapper::doloadfile(const string &filename) const
|
||||
{
|
||||
char *xmldata = NULL;
|
||||
gzFile gzfile = gzopen(filename.c_str(), "rb");
|
||||
|
||||
if(gzfile != NULL) { //The possibly compressed file opened
|
||||
stringstream strBuf; //reading stream
|
||||
const int bufSize = 500; //fetch size
|
||||
char fetchBuf[bufSize + 1]; //fetch buffer
|
||||
int read = 0; //chars read in last fetch
|
||||
|
||||
fetchBuf[bufSize] = 0; //force null termination
|
||||
|
||||
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;
|
||||
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;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int XMLwrapper::enterbranch(const string &name)
|
||||
{
|
||||
if(verbose)
|
||||
cout << "enterbranch() " << name << endl;
|
||||
mxml_node_t *tmp = mxmlFindElement(node, node,
|
||||
name.c_str(), NULL, NULL,
|
||||
MXML_DESCEND_FIRST);
|
||||
if(tmp == NULL)
|
||||
return 0;
|
||||
|
||||
node = tmp;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int XMLwrapper::enterbranch(const string &name, int id)
|
||||
{
|
||||
if(verbose)
|
||||
cout << "enterbranch(" << id << ") " << name << endl;
|
||||
mxml_node_t *tmp = mxmlFindElement(node, node,
|
||||
name.c_str(), "id", stringFrom<int>(
|
||||
id).c_str(), MXML_DESCEND_FIRST);
|
||||
if(tmp == NULL)
|
||||
return 0;
|
||||
|
||||
node = tmp;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void XMLwrapper::exitbranch()
|
||||
{
|
||||
if(verbose)
|
||||
cout << "exitbranch()" << node << "-" << node->value.element.name
|
||||
<< " To "
|
||||
<< node->parent << "-" << node->parent->value.element.name << endl;
|
||||
node = node->parent;
|
||||
}
|
||||
|
||||
|
||||
int XMLwrapper::getbranchid(int min, int max) const
|
||||
{
|
||||
int id = stringTo<int>(mxmlElementGetAttr(node, "id"));
|
||||
if((min == 0) && (max == 0))
|
||||
return id;
|
||||
|
||||
if(id < min)
|
||||
id = min;
|
||||
else
|
||||
if(id > max)
|
||||
id = max;
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
int XMLwrapper::getpar(const string &name, int defaultpar, int min,
|
||||
int max) const
|
||||
{
|
||||
const mxml_node_t *tmp = mxmlFindElement(node,
|
||||
node,
|
||||
"par",
|
||||
"name",
|
||||
name.c_str(),
|
||||
MXML_DESCEND_FIRST);
|
||||
|
||||
if(tmp == NULL)
|
||||
return defaultpar;
|
||||
|
||||
const char *strval = mxmlElementGetAttr(tmp, "value");
|
||||
if(strval == NULL)
|
||||
return defaultpar;
|
||||
|
||||
int val = stringTo<int>(strval);
|
||||
if(val < min)
|
||||
val = min;
|
||||
else
|
||||
if(val > max)
|
||||
val = max;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
int XMLwrapper::getpar127(const string &name, int defaultpar) const
|
||||
{
|
||||
return getpar(name, defaultpar, 0, 127);
|
||||
}
|
||||
|
||||
int XMLwrapper::getparbool(const string &name, int defaultpar) const
|
||||
{
|
||||
const mxml_node_t *tmp = mxmlFindElement(node,
|
||||
node,
|
||||
"par_bool",
|
||||
"name",
|
||||
name.c_str(),
|
||||
MXML_DESCEND_FIRST);
|
||||
|
||||
if(tmp == NULL)
|
||||
return defaultpar;
|
||||
|
||||
const char *strval = mxmlElementGetAttr(tmp, "value");
|
||||
if(strval == NULL)
|
||||
return defaultpar;
|
||||
|
||||
if((strval[0] == 'Y') || (strval[0] == 'y'))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void XMLwrapper::getparstr(const string &name, char *par, int maxstrlen) const
|
||||
{
|
||||
ZERO(par, maxstrlen);
|
||||
const mxml_node_t *tmp = mxmlFindElement(node,
|
||||
node,
|
||||
"string",
|
||||
"name",
|
||||
name.c_str(),
|
||||
MXML_DESCEND_FIRST);
|
||||
|
||||
if(tmp == NULL)
|
||||
return;
|
||||
if(tmp->child == NULL)
|
||||
return;
|
||||
if(tmp->child->type == MXML_OPAQUE) {
|
||||
snprintf(par, maxstrlen, "%s", tmp->child->value.element.name);
|
||||
return;
|
||||
}
|
||||
if((tmp->child->type == MXML_TEXT)
|
||||
&& (tmp->child->value.text.string != NULL)) {
|
||||
snprintf(par, maxstrlen, "%s", tmp->child->value.text.string);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
string XMLwrapper::getparstr(const string &name,
|
||||
const std::string &defaultpar) const
|
||||
{
|
||||
const mxml_node_t *tmp = mxmlFindElement(node,
|
||||
node,
|
||||
"string",
|
||||
"name",
|
||||
name.c_str(),
|
||||
MXML_DESCEND_FIRST);
|
||||
|
||||
if((tmp == NULL) || (tmp->child == NULL))
|
||||
return defaultpar;
|
||||
|
||||
if((tmp->child->type == MXML_OPAQUE)
|
||||
&& (tmp->child->value.element.name != NULL))
|
||||
return tmp->child->value.element.name;
|
||||
|
||||
if((tmp->child->type == MXML_TEXT)
|
||||
&& (tmp->child->value.text.string != NULL))
|
||||
return tmp->child->value.text.string;
|
||||
|
||||
return defaultpar;
|
||||
}
|
||||
|
||||
REALTYPE XMLwrapper::getparreal(const char *name, REALTYPE defaultpar) const
|
||||
{
|
||||
const mxml_node_t *tmp = mxmlFindElement(node,
|
||||
node,
|
||||
"par_real",
|
||||
"name",
|
||||
name,
|
||||
MXML_DESCEND_FIRST);
|
||||
if(tmp == NULL)
|
||||
return defaultpar;
|
||||
|
||||
const char *strval = mxmlElementGetAttr(tmp, "value");
|
||||
if(strval == NULL)
|
||||
return defaultpar;
|
||||
|
||||
return stringTo<REALTYPE>(strval);
|
||||
}
|
||||
|
||||
REALTYPE XMLwrapper::getparreal(const char *name,
|
||||
REALTYPE defaultpar,
|
||||
REALTYPE min,
|
||||
REALTYPE max) const
|
||||
{
|
||||
REALTYPE result = getparreal(name, defaultpar);
|
||||
|
||||
if(result < min)
|
||||
result = min;
|
||||
else
|
||||
if(result > max)
|
||||
result = max;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/** Private members **/
|
||||
|
||||
mxml_node_t *XMLwrapper::addparams(const char *name, unsigned int params,
|
||||
...) const
|
||||
{
|
||||
/**@todo make this function send out a good error message if something goes
|
||||
* wrong**/
|
||||
mxml_node_t *element = mxmlNewElement(node, name);
|
||||
|
||||
if(params) {
|
||||
va_list variableList;
|
||||
va_start(variableList, params);
|
||||
|
||||
const char *ParamName;
|
||||
const char *ParamValue;
|
||||
while(params--) {
|
||||
ParamName = va_arg(variableList, const char *);
|
||||
ParamValue = va_arg(variableList, const char *);
|
||||
if(verbose)
|
||||
cout << "addparams()[" << params << "]=" << name << " "
|
||||
<< ParamName << "=\"" << ParamValue << "\"" << endl;
|
||||
mxmlElementSetAttr(element, ParamName, ParamValue);
|
||||
}
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
@@ -1,275 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
*/
|
||||
|
||||
#if 1
|
||||
#include "QtXmlWrapper.h"
|
||||
#else
|
||||
#include <mxml.h>
|
||||
#include <string>
|
||||
#ifndef REALTYPE
|
||||
#define REALTYPE float
|
||||
#endif
|
||||
|
||||
#ifndef XML_WRAPPER_H
|
||||
#define XML_WRAPPER_H
|
||||
|
||||
/**Mxml wrapper*/
|
||||
class XMLwrapper
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
* Will Construct the object and fill in top level branch
|
||||
* */
|
||||
XMLwrapper();
|
||||
|
||||
/**Destructor*/
|
||||
~XMLwrapper();
|
||||
|
||||
/**
|
||||
* 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) const;
|
||||
|
||||
/**
|
||||
* 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() const;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**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();
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* Loads string into XMLwrapper.
|
||||
* @param xmldata NULL terminated string of XML data.
|
||||
* @returns true if successful.
|
||||
*/
|
||||
bool putXMLdata(const char *xmldata);
|
||||
|
||||
/**
|
||||
* Enters the branch.
|
||||
* @param name Name of branch.
|
||||
* @returns 1 if is ok, or 0 otherwise.
|
||||
*/
|
||||
int enterbranch(const std::string &name);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**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) const;
|
||||
|
||||
/**
|
||||
* 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) const;
|
||||
|
||||
/**
|
||||
* 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) const;
|
||||
|
||||
/**
|
||||
* 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) const;
|
||||
|
||||
/**
|
||||
* 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) const;
|
||||
|
||||
/**
|
||||
* Get the string value stored in the node.
|
||||
* @param name The parameter name.
|
||||
* @param defaultpar The default value if the real value is not found.
|
||||
*/
|
||||
std::string getparstr(const std::string &name,
|
||||
const std::string &defaultpar) const;
|
||||
|
||||
/**
|
||||
* 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) const;
|
||||
|
||||
/**
|
||||
* 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) const;
|
||||
|
||||
bool minimal; /**<false if all parameters will be stored (used only for clipboard)*/
|
||||
|
||||
/**
|
||||
* Sets the current tree's PAD Synth usage
|
||||
*/
|
||||
void setPadSynth(bool enabled);
|
||||
/**
|
||||
* Checks the current tree for PADsynth usage
|
||||
*/
|
||||
bool hasPadSynth() const;
|
||||
|
||||
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) const;
|
||||
|
||||
/**
|
||||
* 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) const;
|
||||
|
||||
mxml_node_t *tree; /**<all xml data*/
|
||||
mxml_node_t *root; /**<xml data used by zynaddsubfx*/
|
||||
mxml_node_t *node; /**<current subtree in parsing or writing */
|
||||
mxml_node_t *info; /**<Node used to store the information about the data*/
|
||||
|
||||
/**
|
||||
* Create mxml_node_t with specified name and parameters
|
||||
*
|
||||
* Results should look like:
|
||||
* <name optionalParam1="value1" optionalParam2="value2" ...>
|
||||
*
|
||||
* @param name The name of the xml node
|
||||
* @param params The number of the attributes
|
||||
* @param ... const char * pairs that are in the format attribute_name,
|
||||
* attribute_value
|
||||
*/
|
||||
mxml_node_t *addparams(const char *name, unsigned int params,
|
||||
...) const;
|
||||
|
||||
/**@todo keep these numbers up to date*/
|
||||
struct {
|
||||
int Major; /**<major version number.*/
|
||||
int Minor; /**<minor version number.*/
|
||||
int Revision; /**<version revision number.*/
|
||||
} version;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,33 +0,0 @@
|
||||
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})
|
||||
@@ -1,685 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
DSSIaudiooutput.cpp - 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
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* Inital working DSSI output code contributed by Stephen G. Parry
|
||||
*/
|
||||
|
||||
//this file contains code used from trivial_synth.c from
|
||||
//the DSSI (published by Steve Harris under public domain) as a template.
|
||||
|
||||
#include <string.h>
|
||||
#include "DSSIaudiooutput.h"
|
||||
#include "../Misc/Config.h"
|
||||
#include "../Misc/Bank.h"
|
||||
#include <limits.h>
|
||||
|
||||
//
|
||||
// Static stubs for LADSPA member functions
|
||||
//
|
||||
// LADSPA is essentially a C handle based API; This plug-in implementation is
|
||||
// a C++ OO one so we need stub functions to map from C API calls to C++ object
|
||||
// method calls.
|
||||
void DSSIaudiooutput::stub_connectPort(LADSPA_Handle instance, unsigned long port, LADSPA_Data * data)
|
||||
{
|
||||
getInstance(instance)->connectPort(port, data);
|
||||
}
|
||||
|
||||
void DSSIaudiooutput::stub_activate(LADSPA_Handle instance)
|
||||
{
|
||||
getInstance(instance)->activate();
|
||||
}
|
||||
|
||||
void DSSIaudiooutput::stub_run(LADSPA_Handle instance, unsigned long sample_count)
|
||||
{
|
||||
getInstance(instance)->run(sample_count);
|
||||
}
|
||||
|
||||
void DSSIaudiooutput::stub_deactivate(LADSPA_Handle instance)
|
||||
{
|
||||
getInstance(instance)->deactivate();
|
||||
}
|
||||
|
||||
|
||||
void DSSIaudiooutput::stub_cleanup(LADSPA_Handle instance)
|
||||
{
|
||||
DSSIaudiooutput* plugin_instance = getInstance(instance);
|
||||
plugin_instance->cleanup();
|
||||
delete plugin_instance;
|
||||
}
|
||||
|
||||
|
||||
const LADSPA_Descriptor *ladspa_descriptor(unsigned long index)
|
||||
{
|
||||
return DSSIaudiooutput::getLadspaDescriptor(index);
|
||||
}
|
||||
|
||||
//
|
||||
// Static stubs for DSSI member functions
|
||||
//
|
||||
// DSSI is essentially a C handle based API; This plug-in implementation is
|
||||
// a C++ OO one so we need stub functions to map from C API calls to C++ object
|
||||
// method calls.
|
||||
const DSSI_Program_Descriptor* DSSIaudiooutput::stub_getProgram (LADSPA_Handle instance, unsigned long index)
|
||||
{
|
||||
return getInstance(instance)->getProgram(index);
|
||||
}
|
||||
|
||||
void DSSIaudiooutput::stub_selectProgram(LADSPA_Handle instance, unsigned long bank, unsigned long program)
|
||||
{
|
||||
getInstance(instance)->selectProgram(bank, program);
|
||||
}
|
||||
|
||||
int DSSIaudiooutput::stub_getMidiControllerForPort(LADSPA_Handle instance, unsigned long port)
|
||||
{
|
||||
return getInstance(instance)->getMidiControllerForPort(port);
|
||||
}
|
||||
|
||||
void DSSIaudiooutput::stub_runSynth(LADSPA_Handle instance, unsigned long sample_count,
|
||||
snd_seq_event_t *events, unsigned long event_count)
|
||||
{
|
||||
getInstance(instance)->runSynth(sample_count, events, event_count);
|
||||
}
|
||||
|
||||
const DSSI_Descriptor *dssi_descriptor(unsigned long index)
|
||||
{
|
||||
return DSSIaudiooutput::getDssiDescriptor(index);
|
||||
}
|
||||
|
||||
//
|
||||
// LADSPA member functions
|
||||
//
|
||||
|
||||
/**
|
||||
* Instantiates a plug-in.
|
||||
*
|
||||
* This LADSPA member function instantiates a plug-in.
|
||||
* Note that instance initialisation should generally occur in
|
||||
* activate() rather than here.
|
||||
*
|
||||
* Zyn Implementation
|
||||
* ------------------
|
||||
* This implementation creates a C++ class object and hides its pointer
|
||||
* in the handle by type casting.
|
||||
*
|
||||
* @param descriptor [in] the descriptor for this plug-in
|
||||
* @param s_rate [in] the sample rate
|
||||
* @return the plug-in instance handle if successful else NULL
|
||||
*/
|
||||
LADSPA_Handle DSSIaudiooutput::instantiate(const LADSPA_Descriptor * descriptor, unsigned long s_rate)
|
||||
{
|
||||
if(descriptor->UniqueID == dssiDescriptor->LADSPA_Plugin->UniqueID)
|
||||
{
|
||||
return (LADSPA_Handle)(new DSSIaudiooutput(s_rate));
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Connects a port on an instantiated plug-in.
|
||||
*
|
||||
* This LADSPA member function connects a port on an instantiated plug-in to a
|
||||
* memory location at which a block of data for the port will be read/written.
|
||||
* The data location is expected to be an array of LADSPA_Data for audio ports
|
||||
* or a single LADSPA_Data value for control ports. Memory issues will be
|
||||
* managed by the host. The plug-in must read/write the data at these locations
|
||||
* every time run() or run_adding() is called and the data present at the time
|
||||
* of this connection call should not be considered meaningful.
|
||||
*
|
||||
* Zyn Implementation
|
||||
* ------------------
|
||||
* The buffer pointers are stored as member variables
|
||||
*
|
||||
* @param port [in] the port to be connected
|
||||
* @param data [in] the data buffer to write to / read from
|
||||
*/
|
||||
void DSSIaudiooutput::connectPort(unsigned long port, LADSPA_Data * data)
|
||||
{
|
||||
switch (port) {
|
||||
case 0:
|
||||
outl = data;
|
||||
break;
|
||||
case 1:
|
||||
outr = data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialises a plug-in instance and activates it for use.
|
||||
*
|
||||
* This LADSPA member function initialises a plug-in instance and activates it
|
||||
* for use. This is separated from instantiate() to aid real-time support and
|
||||
* so that hosts can reinitialise a plug-in instance by calling deactivate() and
|
||||
* then activate(). In this case the plug-in instance must reset all state
|
||||
* information dependent on the history of the plug-in instance except for any
|
||||
* data locations provided by connect_port() and any gain set by
|
||||
* set_run_adding_gain().
|
||||
*
|
||||
* Zyn Implementation
|
||||
* ------------------
|
||||
* Currently this does nothing; Care must be taken as to code placed here as
|
||||
* too much code here seems to cause time-out problems in jack-dssi-host.
|
||||
*/
|
||||
void DSSIaudiooutput::activate()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs an instance of a plug-in for a block.
|
||||
*
|
||||
* This LADSPA member function runs an instance of a plug-in for a block.
|
||||
* Note that if an activate() function exists then it must be called before
|
||||
* run() or run_adding(). If deactivate() is called for a plug-in instance then
|
||||
* the plug-in instance may not be reused until activate() has been called again.
|
||||
*
|
||||
* Zyn Implementation
|
||||
* ------------------
|
||||
* This is a LADSPA function that does not process any MIDI events; it is hence
|
||||
* implemented by simply calling runSynth() with an empty event list.
|
||||
*
|
||||
* @param sample_count [in] the block size (in samples) for which the plug-in instance may run
|
||||
*/
|
||||
void DSSIaudiooutput::run(unsigned long sample_count)
|
||||
{
|
||||
runSynth(sample_count,NULL,(unsigned long)0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Counterpart to activate().
|
||||
*
|
||||
* This LADSPA member function is the counterpart to activate() (see above).
|
||||
* Deactivation is not similar to pausing as the plug-in instance will be
|
||||
* reinitialised when activate() is called to reuse it.
|
||||
*
|
||||
* Zyn Implementation
|
||||
* ------------------
|
||||
* Currently this function does nothing.
|
||||
*/
|
||||
void DSSIaudiooutput::deactivate()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a plug-in instance that is no longer required.
|
||||
*
|
||||
* LADSPA member function; once an instance of a plug-in has been finished with
|
||||
* it can be deleted using this function. The instance handle ceases to be
|
||||
* valid after this call.
|
||||
*
|
||||
* If activate() was called for a plug-in instance then a corresponding call to
|
||||
* deactivate() must be made before cleanup() is called.
|
||||
*
|
||||
* Zyn Implementation
|
||||
* ------------------
|
||||
* Currently cleanup is deferred to the destructor that is invoked after cleanup()
|
||||
*/
|
||||
void DSSIaudiooutput::cleanup()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Initial entry point for the LADSPA plug-in library.
|
||||
*
|
||||
* This LADSPA function is the initial entry point for the plug-in library.
|
||||
* The LADSPA host looks for this entry point in each shared library object it
|
||||
* finds and then calls the function to enumerate the plug-ins within the
|
||||
* library.
|
||||
*
|
||||
* Zyn Implementation
|
||||
* ------------------
|
||||
* As the Zyn plug-in is a DSSI plug-in, the LADSPA descriptor is embedded inside
|
||||
* the DSSI descriptor, which is created by DSSIaudiooutput::initDssiDescriptor()
|
||||
* statically when the library is loaded. This function then merely returns a pointer
|
||||
* to that embedded descriptor.
|
||||
*
|
||||
* @param index [in] the index number of the plug-in within the library.
|
||||
* @return if index is in range, a pointer to the plug-in descriptor is returned, else NULL
|
||||
*/
|
||||
const LADSPA_Descriptor* DSSIaudiooutput::getLadspaDescriptor(unsigned long index)
|
||||
{
|
||||
if(index > 0 || dssiDescriptor == NULL)
|
||||
return NULL;
|
||||
else
|
||||
return dssiDescriptor->LADSPA_Plugin;
|
||||
}
|
||||
|
||||
//
|
||||
// DSSI member functions
|
||||
//
|
||||
|
||||
/**
|
||||
* Provides a description of a program available on this synth.
|
||||
*
|
||||
* This DSSI member function pointer provides a description of a program (named
|
||||
* preset sound) available on this synth.
|
||||
*
|
||||
* Zyn Implementation
|
||||
* ------------------
|
||||
* The instruments in all Zyn's bank directories, as shown by the `instrument
|
||||
* -> show instrument bank` command, are enumerated to the host by this
|
||||
* function, allowing access to all those instruments.
|
||||
* The first time an instrument is requested, the bank it is in and any
|
||||
* unmapped ones preceding that are mapped; all the instruments names and
|
||||
* filenames from those banks are stored in the programMap member variable for
|
||||
* later use. This is done on demand in this way, rather than up front in one
|
||||
* go because loading all the instrument names in one go can lead to timeouts
|
||||
* and zombies.
|
||||
*
|
||||
* @param index [in] index into the plug-in's list of
|
||||
* programs, not a program number as represented by the Program
|
||||
* field of the DSSI_Program_Descriptor. (This distinction is
|
||||
* needed to support synths that use non-contiguous program or
|
||||
* bank numbers.)
|
||||
* @return a DSSI_Program_Descriptor pointer that is
|
||||
* guaranteed to be valid only until the next call to get_program,
|
||||
* deactivate, or configure, on the same plug-in instance, or NULL if index is out of range.
|
||||
*/
|
||||
const DSSI_Program_Descriptor* DSSIaudiooutput::getProgram (unsigned long index)
|
||||
{
|
||||
static DSSI_Program_Descriptor retVal;
|
||||
|
||||
/* Make sure we have the list of banks loaded */
|
||||
initBanks();
|
||||
|
||||
/* Make sure that the bank containing the instrument has been mapped */
|
||||
while (index >= programMap.size() && mapNextBank())
|
||||
/* DO NOTHING MORE */;
|
||||
|
||||
if(index >= programMap.size())
|
||||
{
|
||||
/* No more instruments */
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* OK, return the instrument */
|
||||
retVal.Name = programMap[index].name.c_str();
|
||||
retVal.Program = programMap[index].program;
|
||||
retVal.Bank = programMap[index].bank;
|
||||
return &retVal;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects a new program for this synth.
|
||||
*
|
||||
* This DSSI member function selects a new program for this synth. The program
|
||||
* change will take effect immediately at the start of the next run_synth()
|
||||
* call. An invalid bank / instrument combination is ignored.
|
||||
*
|
||||
* Zyn Implementation
|
||||
* ------------------
|
||||
* the banks and instruments are as shown in the `instrument -> show instrument
|
||||
* bank` command in Zyn. The bank no is a 1-based index into the list of banks
|
||||
* Zyn loads and shows in the drop down and the program number is the
|
||||
* instrument within that bank.
|
||||
*
|
||||
* @param bank [in] the bank number to select
|
||||
* @param program [in] the program number within the bank to select
|
||||
*/
|
||||
void DSSIaudiooutput::selectProgram(unsigned long bank, unsigned long program)
|
||||
{
|
||||
initBanks();
|
||||
// cerr << "selectProgram(" << (bank & 0x7F) << ':' << ((bank >> 7) & 0x7F) << "," << program << ")" << '\n';
|
||||
if(bank < MAX_NUM_BANKS && program < BANK_SIZE)
|
||||
{
|
||||
char* bankdir = master->bank.banks[ bank ].dir;
|
||||
if(bankdir != NULL)
|
||||
{
|
||||
pthread_mutex_lock(&master->mutex);
|
||||
|
||||
/* We have to turn off the CheckPADsynth functionality, else
|
||||
* the program change takes way too long and we get timeouts
|
||||
* and hence zombies (!) */
|
||||
int save = config.cfg.CheckPADsynth;
|
||||
config.cfg.CheckPADsynth = 0;
|
||||
|
||||
/* Load the bank... */
|
||||
master->bank.loadbank(bankdir);
|
||||
|
||||
/* restore the CheckPADsynth flag */
|
||||
config.cfg.CheckPADsynth = save;
|
||||
|
||||
/* Now load the instrument... */
|
||||
master->bank.loadfromslot((unsigned int)program, master->part[0]);
|
||||
|
||||
pthread_mutex_unlock(&master->mutex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the MIDI controller number or NRPN for a input control port
|
||||
*
|
||||
* This DSSI member function returns the MIDI controller number or NRPN that
|
||||
* should be mapped to the given input control port. If the given port should
|
||||
* not have any MIDI controller mapped to it, the function will return DSSI_NONE.
|
||||
* The behaviour of this function is undefined if the given port
|
||||
* number does not correspond to an input control port.
|
||||
*
|
||||
* Zyn Implementation
|
||||
* ------------------
|
||||
* Currently Zyn does not define any controller ports, but may do in the future.
|
||||
*
|
||||
* @param port [in] the input controller port
|
||||
* @return the CC and NRPN values shifted and ORed together.
|
||||
*/
|
||||
int DSSIaudiooutput::getMidiControllerForPort(unsigned long port)
|
||||
{
|
||||
return DSSI_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the synth for a block.
|
||||
*
|
||||
* This DSSI member function runs the synth for a block. This is identical in
|
||||
* function to the LADSPA run() function, except that it also supplies events
|
||||
* to the synth.
|
||||
*
|
||||
* Zyn Implementation
|
||||
* ------------------
|
||||
* Zyn implements synthesis in Master::GetAudioOutSamples; runSynth calls this
|
||||
* function in chunks delimited by the sample_count and the frame indexes in
|
||||
* the events block, calling the appropriate NoteOn, NoteOff and SetController
|
||||
* members of Master to process the events supplied between each chunk.
|
||||
*
|
||||
* @param sample_count [in] the block size (in samples) for which the synth
|
||||
* instance may run.
|
||||
* @param events [in] The Events pointer points to a block of ALSA
|
||||
* sequencer events, used to communicate MIDI and related events to the synth.
|
||||
* Each event must be timestamped relative to the start of the block,
|
||||
* (mis)using the ALSA "tick time" field as a frame count. The host is
|
||||
* responsible for ensuring that events with differing timestamps are already
|
||||
* ordered by time. Must not include NOTE (only NOTE_ON / NOTE_OFF), LSB or MSB
|
||||
* events.
|
||||
* @param event_count [in] the number of entries in the `events` block
|
||||
*/
|
||||
void DSSIaudiooutput::runSynth(unsigned long sample_count, snd_seq_event_t *events, unsigned long event_count)
|
||||
{
|
||||
unsigned long from_frame = 0;
|
||||
unsigned long event_index = 0;
|
||||
unsigned long next_event_frame = 0;
|
||||
unsigned long to_frame = 0;
|
||||
pthread_mutex_lock(&master->mutex);
|
||||
|
||||
do {
|
||||
/* Find the time of the next event, if any */
|
||||
if(events == NULL || event_index >= event_count)
|
||||
next_event_frame = ULONG_MAX;
|
||||
else
|
||||
next_event_frame = events[event_index].time.tick;
|
||||
|
||||
/* find the end of the sub-sample to be processed this time round... */
|
||||
/* if the next event falls within the desired sample interval... */
|
||||
if(next_event_frame < sample_count && next_event_frame >= to_frame)
|
||||
/* set the end to be at that event */
|
||||
to_frame = next_event_frame;
|
||||
else
|
||||
/* ...else go for the whole remaining sample */
|
||||
to_frame = sample_count;
|
||||
if(from_frame<to_frame)
|
||||
{
|
||||
// call master to fill from `from_frame` to `to_frame`:
|
||||
master->GetAudioOutSamples(to_frame - from_frame, (int)sampleRate, &(outl[from_frame]), &(outr[from_frame]));
|
||||
// next sub-sample please...
|
||||
from_frame = to_frame;
|
||||
}
|
||||
|
||||
// Now process any event(s) at the current timing point
|
||||
while(events != NULL && event_index < event_count && events[event_index].time.tick == to_frame)
|
||||
{
|
||||
if(events[event_index].type == SND_SEQ_EVENT_NOTEON)
|
||||
{
|
||||
master->NoteOn(events[event_index].data.note.channel, events[event_index].data.note.note, events[event_index].data.note.velocity);
|
||||
}
|
||||
else if(events[event_index].type == SND_SEQ_EVENT_NOTEOFF)
|
||||
{
|
||||
master->NoteOff(events[event_index].data.note.channel, events[event_index].data.note.note);
|
||||
}
|
||||
else if(events[event_index].type == SND_SEQ_EVENT_CONTROLLER)
|
||||
{
|
||||
master->SetController(events[event_index].data.control.channel, events[event_index].data.control.param, events[event_index].data.control.value);
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
event_index++;
|
||||
}
|
||||
|
||||
// Keep going until we have the desired total length of sample...
|
||||
} while(to_frame < sample_count);
|
||||
|
||||
pthread_mutex_unlock(&master->mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initial entry point for the DSSI plug-in library.
|
||||
*
|
||||
* This DSSI function is the initial entry point for the plug-in library.
|
||||
* The DSSI host looks for this entry point in each shared library object it
|
||||
* finds and then calls the function to enumerate the plug-ins within the
|
||||
* library.
|
||||
*
|
||||
* Zyn Implementation
|
||||
* ------------------
|
||||
* The descriptor is created statically by DSSIaudiooutput::initDssiDescriptor()
|
||||
* when the plug-in library is loaded. This function merely returns a pointer to
|
||||
* that descriptor.
|
||||
*
|
||||
* @param index [in] the index number of the plug-in within the library.
|
||||
* @return if index is in range, a pointer to the plug-in descriptor is returned, else NULL
|
||||
*/
|
||||
const DSSI_Descriptor* DSSIaudiooutput::getDssiDescriptor(unsigned long index)
|
||||
{
|
||||
if(index > 0 || dssiDescriptor == NULL)
|
||||
return NULL;
|
||||
else
|
||||
return dssiDescriptor;
|
||||
}
|
||||
|
||||
//
|
||||
// Internal member functions
|
||||
//
|
||||
|
||||
// Initialise the DSSI descriptor, statically:
|
||||
DSSI_Descriptor* DSSIaudiooutput::dssiDescriptor = DSSIaudiooutput::initDssiDescriptor();
|
||||
|
||||
/**
|
||||
* Initializes the DSSI (and LADSPA) descriptor, returning it is an object.
|
||||
*/
|
||||
DSSI_Descriptor* DSSIaudiooutput::initDssiDescriptor()
|
||||
{
|
||||
DSSI_Descriptor* newDssiDescriptor = new DSSI_Descriptor;
|
||||
|
||||
LADSPA_PortDescriptor* newPortDescriptors;
|
||||
char** newPortNames;
|
||||
LADSPA_PortRangeHint* newPortRangeHints;
|
||||
|
||||
if (newDssiDescriptor)
|
||||
{
|
||||
LADSPA_Descriptor* newLadspaDescriptor = new LADSPA_Descriptor;
|
||||
if (newLadspaDescriptor)
|
||||
{
|
||||
newLadspaDescriptor->UniqueID = 100;
|
||||
newLadspaDescriptor->Label = "ZASF";
|
||||
newLadspaDescriptor->Properties = 0;
|
||||
newLadspaDescriptor->Name = "ZynAddSubFX";
|
||||
newLadspaDescriptor->Maker = "Nasca Octavian Paul <zynaddsubfx@yahoo.com>";
|
||||
newLadspaDescriptor->Copyright = "GNU General Public License v.2";
|
||||
newLadspaDescriptor->PortCount = 2;
|
||||
|
||||
newPortNames = new char *[newLadspaDescriptor->PortCount];
|
||||
newPortNames[0] = "Output L";
|
||||
newPortNames[1] = "Output R";
|
||||
newLadspaDescriptor->PortNames = newPortNames;
|
||||
|
||||
newPortDescriptors = new LADSPA_PortDescriptor[newLadspaDescriptor->PortCount];
|
||||
newPortDescriptors[0] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;
|
||||
newPortDescriptors[1] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;
|
||||
newLadspaDescriptor->PortDescriptors = newPortDescriptors;
|
||||
|
||||
newPortRangeHints = new LADSPA_PortRangeHint[newLadspaDescriptor->PortCount];
|
||||
newPortRangeHints[0].HintDescriptor = 0;
|
||||
newPortRangeHints[1].HintDescriptor = 0;
|
||||
newLadspaDescriptor->PortRangeHints = newPortRangeHints;
|
||||
|
||||
newLadspaDescriptor->activate = stub_activate;
|
||||
newLadspaDescriptor->cleanup = stub_cleanup;
|
||||
newLadspaDescriptor->connect_port = stub_connectPort;
|
||||
newLadspaDescriptor->deactivate = stub_deactivate;
|
||||
newLadspaDescriptor->instantiate = instantiate;
|
||||
newLadspaDescriptor->run = stub_run;
|
||||
newLadspaDescriptor->run_adding = NULL;
|
||||
newLadspaDescriptor->set_run_adding_gain = NULL;
|
||||
}
|
||||
newDssiDescriptor->LADSPA_Plugin = newLadspaDescriptor;
|
||||
newDssiDescriptor->DSSI_API_Version = 1;
|
||||
newDssiDescriptor->configure = NULL;
|
||||
newDssiDescriptor->get_program = stub_getProgram;
|
||||
newDssiDescriptor->get_midi_controller_for_port = stub_getMidiControllerForPort;
|
||||
newDssiDescriptor->select_program = stub_selectProgram;
|
||||
newDssiDescriptor->run_synth = stub_runSynth;
|
||||
newDssiDescriptor->run_synth_adding = NULL;
|
||||
newDssiDescriptor->run_multiple_synths = NULL;
|
||||
newDssiDescriptor->run_multiple_synths_adding = NULL;
|
||||
}
|
||||
|
||||
dssiDescriptor = newDssiDescriptor;
|
||||
|
||||
return dssiDescriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a LADSPA / DSSI handle into a DSSIaudiooutput instance.
|
||||
*
|
||||
* @param instance [in]
|
||||
* @return the instance
|
||||
*/
|
||||
DSSIaudiooutput* DSSIaudiooutput::getInstance(LADSPA_Handle instance)
|
||||
{
|
||||
return (DSSIaudiooutput*)(instance);
|
||||
}
|
||||
|
||||
/**
|
||||
* The private sole constructor for the DSSIaudiooutput class.
|
||||
*
|
||||
* Only ever called via instantiate().
|
||||
* @param sampleRate [in] the sample rate to be used by the synth.
|
||||
* @return
|
||||
*/
|
||||
DSSIaudiooutput::DSSIaudiooutput(unsigned long sampleRate)
|
||||
{
|
||||
this->sampleRate = sampleRate;
|
||||
this->banksInited = false;
|
||||
|
||||
config.init();
|
||||
|
||||
srand(time(NULL));
|
||||
denormalkillbuf=new REALTYPE [SOUND_BUFFER_SIZE];
|
||||
for (int i=0;i<SOUND_BUFFER_SIZE;i++) denormalkillbuf[i]=(RND-0.5)*1e-16;
|
||||
|
||||
this->master = new Master();
|
||||
}
|
||||
|
||||
/**
|
||||
* The destructor for the DSSIaudiooutput class
|
||||
* @return
|
||||
*/
|
||||
DSSIaudiooutput::~DSSIaudiooutput()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures the list of bank (directories) has been initialised.
|
||||
*/
|
||||
void DSSIaudiooutput::initBanks(void)
|
||||
{
|
||||
if(!banksInited)
|
||||
{
|
||||
pthread_mutex_lock(&master->mutex);
|
||||
master->bank.rescanforbanks();
|
||||
banksInited = true;
|
||||
pthread_mutex_unlock(&master->mutex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* constructor for the internally used ProgramDescriptor class
|
||||
*
|
||||
* @param _bank [in] bank number
|
||||
* @param _program [in] program number
|
||||
* @param _name [in] instrument / sample name
|
||||
* @return
|
||||
*/
|
||||
DSSIaudiooutput::ProgramDescriptor::ProgramDescriptor(unsigned long _bank, unsigned long _program, char* _name) :
|
||||
bank(_bank), program(_program), name(_name)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* The map of programs available; held as a single shared statically allocated object.
|
||||
*/
|
||||
vector <DSSIaudiooutput::ProgramDescriptor> DSSIaudiooutput::programMap = vector<DSSIaudiooutput::ProgramDescriptor>();
|
||||
|
||||
/**
|
||||
* Index controlling the map of banks
|
||||
*/
|
||||
long DSSIaudiooutput::bankNoToMap = 1;
|
||||
|
||||
/**
|
||||
* Queries and maps the next available bank of instruments.
|
||||
*
|
||||
* If the program index requested to getProgram() lies beyond the banks mapped to date,
|
||||
* this member function is called to map the next one.
|
||||
* @return true if a new bank has been found and mapped, else false.
|
||||
*/
|
||||
bool DSSIaudiooutput::mapNextBank()
|
||||
{
|
||||
pthread_mutex_lock(&master->mutex);
|
||||
Bank& bank = master->bank;
|
||||
bool retval;
|
||||
if(bankNoToMap >= MAX_NUM_BANKS || bank.banks[bankNoToMap].dir == NULL)
|
||||
{
|
||||
retval = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
bank.loadbank(bank.banks[bankNoToMap].dir);
|
||||
for(unsigned long instrument = 0; instrument < BANK_SIZE; instrument++)
|
||||
{
|
||||
char* insName = bank.getname(instrument);
|
||||
if(insName != NULL && insName[0] != '\0' && insName[0] != ' ')
|
||||
{
|
||||
programMap.push_back(ProgramDescriptor(bankNoToMap,instrument,insName));
|
||||
}
|
||||
}
|
||||
bankNoToMap ++;
|
||||
retval = true;
|
||||
}
|
||||
pthread_mutex_unlock(&master->mutex);
|
||||
return retval;
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
VSTaudiooutput.h - Audio output for VST
|
||||
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
|
||||
|
||||
*/
|
||||
#ifndef VST_AUDIO_OUTPUT_H
|
||||
#define VST_AUDIO_OUTPUT_H
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "../globals.h"
|
||||
#include "../Misc/Master.h"
|
||||
|
||||
#include <dssi.h>
|
||||
#include <ladspa.h>
|
||||
#include <vector>
|
||||
|
||||
class DSSIaudiooutput
|
||||
{
|
||||
public:
|
||||
//
|
||||
// Static stubs for LADSPA member functions
|
||||
//
|
||||
static void stub_connectPort(LADSPA_Handle instance, unsigned long port, LADSPA_Data * data);
|
||||
static void stub_activate(LADSPA_Handle instance);
|
||||
static void stub_run(LADSPA_Handle instance, unsigned long sample_count);
|
||||
static void stub_deactivate(LADSPA_Handle Instance);
|
||||
static void stub_cleanup(LADSPA_Handle instance);
|
||||
|
||||
//
|
||||
// Static stubs for DSSI member functions
|
||||
//
|
||||
static const DSSI_Program_Descriptor* stub_getProgram (LADSPA_Handle instance, unsigned long Index);
|
||||
static void stub_selectProgram(LADSPA_Handle instance, unsigned long bank, unsigned long program);
|
||||
static int stub_getMidiControllerForPort(LADSPA_Handle instance, unsigned long port);
|
||||
static void stub_runSynth(LADSPA_Handle instance, unsigned long sample_count,
|
||||
snd_seq_event_t *events, unsigned long event_count);
|
||||
|
||||
/*
|
||||
* LADSPA member functions
|
||||
*/
|
||||
static LADSPA_Handle instantiate(const LADSPA_Descriptor * descriptor, unsigned long s_rate);
|
||||
void connectPort(unsigned long port, LADSPA_Data * data);
|
||||
void activate();
|
||||
void run(unsigned long sample_count);
|
||||
void deactivate();
|
||||
void cleanup();
|
||||
static const LADSPA_Descriptor* getLadspaDescriptor(unsigned long index);
|
||||
|
||||
/*
|
||||
* DSSI member functions
|
||||
*/
|
||||
const DSSI_Program_Descriptor* getProgram (unsigned long Index);
|
||||
void selectProgram(unsigned long bank, unsigned long program);
|
||||
int getMidiControllerForPort(unsigned long port);
|
||||
void runSynth(unsigned long sample_count, snd_seq_event_t *events, unsigned long event_count);
|
||||
static const DSSI_Descriptor* getDssiDescriptor(unsigned long index);
|
||||
|
||||
struct ProgramDescriptor
|
||||
{
|
||||
unsigned long bank;
|
||||
unsigned long program;
|
||||
string name;
|
||||
ProgramDescriptor(unsigned long _bank, unsigned long _program, char* _name);
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
DSSIaudiooutput(unsigned long sampleRate);
|
||||
~DSSIaudiooutput();
|
||||
static DSSI_Descriptor* initDssiDescriptor();
|
||||
static DSSIaudiooutput* getInstance(LADSPA_Handle instance);
|
||||
void initBanks();
|
||||
bool mapNextBank();
|
||||
|
||||
LADSPA_Data *outl;
|
||||
LADSPA_Data *outr;
|
||||
long sampleRate;
|
||||
Master* master;
|
||||
static DSSI_Descriptor* dssiDescriptor;
|
||||
static string bankDirNames[];
|
||||
static
|
||||
vector <ProgramDescriptor> programMap;
|
||||
|
||||
/**
|
||||
* Flag controlling the list of bank directories
|
||||
*/
|
||||
bool banksInited;
|
||||
|
||||
static
|
||||
long bankNoToMap;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,229 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
JACKaudiooutput.cpp - Audio output for JACK
|
||||
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
|
||||
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include <jack/ringbuffer.h>
|
||||
};
|
||||
#include "JACKaudiooutput.h"
|
||||
|
||||
Master *jackmaster;
|
||||
jack_client_t *jackclient;
|
||||
jack_port_t *outport_left, *outport_right;
|
||||
jack_ringbuffer_t *rb = NULL;
|
||||
|
||||
REALTYPE *jackoutl, *jackoutr;
|
||||
int jackfinish = 0;
|
||||
|
||||
void *thread_blocked(void *arg);
|
||||
int jackprocess(jack_nframes_t nframes, void *arg);
|
||||
int jacksrate(jack_nframes_t nframes, void *arg);
|
||||
void jackshutdown(void *arg);
|
||||
|
||||
pthread_cond_t more_data = PTHREAD_COND_INITIALIZER;
|
||||
pthread_mutex_t zyn_thread_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
pthread_t bthr;
|
||||
|
||||
|
||||
bool JACKaudiooutputinit(Master *master_)
|
||||
{
|
||||
jackmaster = master_;
|
||||
jackclient = 0;
|
||||
char tmpstr[100];
|
||||
|
||||
jackoutl = new REALTYPE [SOUND_BUFFER_SIZE];
|
||||
jackoutr = new REALTYPE [SOUND_BUFFER_SIZE];
|
||||
|
||||
int rbbufsize = SOUND_BUFFER_SIZE * sizeof(REALTYPE) * 2 * 2;
|
||||
printf("%d\n", rbbufsize);
|
||||
rb = jack_ringbuffer_create(rbbufsize);
|
||||
for(int i = 0; i < rbbufsize; i++)
|
||||
rb->buf[i] = 0.0;
|
||||
|
||||
|
||||
for(int i = 0; i < 15; i++) {
|
||||
if(i != 0)
|
||||
snprintf(tmpstr, 100, "ZynAddSubFX_%d", i);
|
||||
else
|
||||
snprintf(tmpstr, 100, "ZynAddSubFX");
|
||||
jackclient = jack_client_new(tmpstr);
|
||||
if(jackclient != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if(jackclient == 0) {
|
||||
fprintf(
|
||||
stderr,
|
||||
"\nERROR: Cannot make a jack client (possible reasons: JACK server is not running or jackd is launched by root and zynaddsubfx by another user.).\n\n\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
fprintf(stderr,
|
||||
"Internal SampleRate = %d\nJack Output SampleRate= %d\n",
|
||||
SAMPLE_RATE,
|
||||
jack_get_sample_rate(jackclient));
|
||||
if((unsigned int)jack_get_sample_rate(jackclient) !=
|
||||
(unsigned int) SAMPLE_RATE)
|
||||
fprintf(stderr,
|
||||
"It is recomanded that the both samplerates to be equal.\n");
|
||||
|
||||
jack_set_process_callback(jackclient, jackprocess, 0);
|
||||
jack_set_sample_rate_callback(jackclient, jacksrate, 0);
|
||||
jack_on_shutdown(jackclient, jackshutdown, 0);
|
||||
|
||||
outport_left = jack_port_register(jackclient,
|
||||
"out_1",
|
||||
JACK_DEFAULT_AUDIO_TYPE,
|
||||
JackPortIsOutput | JackPortIsTerminal,
|
||||
0);
|
||||
outport_right = jack_port_register(jackclient,
|
||||
"out_2",
|
||||
JACK_DEFAULT_AUDIO_TYPE,
|
||||
JackPortIsOutput | JackPortIsTerminal,
|
||||
0);
|
||||
|
||||
if(jack_activate(jackclient)) {
|
||||
fprintf(stderr, "Cannot activate jack client\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
pthread_create(&bthr, NULL, thread_blocked, NULL);
|
||||
|
||||
/*
|
||||
jack_connect(jackclient,jack_port_name(outport_left),"alsa_pcm:out_1");
|
||||
jack_connect(jackclient,jack_port_name(outport_right),"alsa_pcm:out_2");
|
||||
*/
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void *thread_blocked(void *arg)
|
||||
{
|
||||
int datasize = SOUND_BUFFER_SIZE * sizeof(REALTYPE);
|
||||
|
||||
//try to get realtime
|
||||
sched_param sc;
|
||||
sc.sched_priority = 50;
|
||||
int err = sched_setscheduler(0, SCHED_FIFO, &sc);
|
||||
|
||||
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
|
||||
pthread_mutex_lock(&zyn_thread_lock);
|
||||
|
||||
while(jackfinish == 0) {
|
||||
while(jack_ringbuffer_write_space(rb) >= datasize) {
|
||||
pthread_mutex_lock(&jackmaster->mutex);
|
||||
jackmaster->GetAudioOutSamples(SOUND_BUFFER_SIZE,
|
||||
jack_get_sample_rate(jackclient),
|
||||
jackoutl,
|
||||
jackoutr);
|
||||
pthread_mutex_unlock(&jackmaster->mutex);
|
||||
|
||||
jack_ringbuffer_write(rb, (char *) jackoutl, datasize);
|
||||
jack_ringbuffer_write(rb, (char *) jackoutr, datasize);
|
||||
}
|
||||
pthread_cond_wait(&more_data, &zyn_thread_lock);
|
||||
}
|
||||
pthread_mutex_unlock(&zyn_thread_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int jackprocess(jack_nframes_t nframes, void *arg)
|
||||
{
|
||||
jack_default_audio_sample_t *outl =
|
||||
(jack_default_audio_sample_t *) jack_port_get_buffer(outport_left,
|
||||
nframes);
|
||||
jack_default_audio_sample_t *outr =
|
||||
(jack_default_audio_sample_t *) jack_port_get_buffer(outport_right,
|
||||
nframes);
|
||||
|
||||
int datasize = nframes * sizeof(REALTYPE);
|
||||
int incoming_datasize = SOUND_BUFFER_SIZE * sizeof(REALTYPE);
|
||||
int data_read = 0;
|
||||
|
||||
|
||||
if(jack_ringbuffer_read_space(rb) >= (2 * incoming_datasize)) {
|
||||
if(datasize > incoming_datasize) {
|
||||
data_read = 0;
|
||||
while(data_read < datasize) {
|
||||
jack_ringbuffer_read(rb, (char *) outl + data_read, datasize);
|
||||
jack_ringbuffer_read(rb, (char *) outr + data_read, datasize);
|
||||
data_read += incoming_datasize;
|
||||
}
|
||||
}
|
||||
else
|
||||
if(datasize == incoming_datasize) {
|
||||
jack_ringbuffer_read(rb, (char *) outl, datasize);
|
||||
jack_ringbuffer_read(rb, (char *) outr, datasize);
|
||||
}
|
||||
else {}
|
||||
}
|
||||
else { //the ringbuffer is empty or there are too small amount of samples in it
|
||||
for(int i = 0; i < nframes; i++) {
|
||||
outl[i] = 0.0;
|
||||
outr[i] = 0.0;
|
||||
}
|
||||
}
|
||||
/* if (jack_ringbuffer_read_space(rb)>=datasize){
|
||||
jack_ringbuffer_read(rb, (char *) outl,datasize);
|
||||
jack_ringbuffer_read(rb, (char *) outr,datasize);
|
||||
} else {//the ringbuffer is empty or there are too small amount of samples in it
|
||||
for (int i=0;i<nframes;i++){
|
||||
outl[i]=0.0;outr[i]=0.0;
|
||||
};
|
||||
};
|
||||
*/
|
||||
if(pthread_mutex_trylock(&zyn_thread_lock) == 0) {
|
||||
pthread_cond_signal(&more_data);
|
||||
pthread_mutex_unlock(&zyn_thread_lock);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void JACKfinish()
|
||||
{
|
||||
jackfinish = 1;
|
||||
jack_ringbuffer_free(rb);
|
||||
jack_client_close(jackclient);
|
||||
|
||||
usleep(100000);
|
||||
delete (jackoutl);
|
||||
delete (jackoutr);
|
||||
}
|
||||
|
||||
int jacksrate(jack_nframes_t nframes, void *arg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void jackshutdown(void *arg)
|
||||
{}
|
||||
|
||||
@@ -1,185 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
JACKaudiooutput.cpp - Audio output for JACK
|
||||
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
|
||||
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <jack/midiport.h>
|
||||
#include "JACKaudiooutput.h"
|
||||
|
||||
Master *jackmaster;
|
||||
jack_client_t *jackclient;
|
||||
char jackname[100];
|
||||
jack_port_t *outport_left, *outport_right, *midi_inport;
|
||||
|
||||
int jackprocess(jack_nframes_t nframes, void *arg);
|
||||
int jacksrate(jack_nframes_t nframes, void *arg);
|
||||
void jackshutdown(void *arg);
|
||||
|
||||
bool JACKaudiooutputinit(Master *master_)
|
||||
{
|
||||
jackmaster = master_;
|
||||
jackclient = 0;
|
||||
|
||||
for(int i = 0; i < 15; i++) {
|
||||
if(i != 0)
|
||||
snprintf(jackname, 100, "ZynAddSubFX_%d", i);
|
||||
else
|
||||
snprintf(jackname, 100, "ZynAddSubFX");
|
||||
jackclient = jack_client_new(jackname);
|
||||
if(jackclient != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if(jackclient == 0) {
|
||||
fprintf(
|
||||
stderr,
|
||||
"\nERROR: Cannot make a jack client (possible reasons: JACK server is not running or jackd is launched by root and zynaddsubfx by another user.).\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
fprintf(stderr,
|
||||
"Internal SampleRate = %d\nJack Output SampleRate= %d\n",
|
||||
SAMPLE_RATE,
|
||||
jack_get_sample_rate(jackclient));
|
||||
if((unsigned int)jack_get_sample_rate(jackclient) !=
|
||||
(unsigned int) SAMPLE_RATE)
|
||||
fprintf(stderr,
|
||||
"It is recomanded that the both samplerates to be equal.\n");
|
||||
|
||||
jack_set_process_callback(jackclient, jackprocess, 0);
|
||||
jack_set_sample_rate_callback(jackclient, jacksrate, 0);
|
||||
jack_on_shutdown(jackclient, jackshutdown, 0);
|
||||
|
||||
outport_left = jack_port_register(jackclient,
|
||||
"out_1",
|
||||
JACK_DEFAULT_AUDIO_TYPE,
|
||||
JackPortIsOutput | JackPortIsTerminal,
|
||||
0);
|
||||
outport_right = jack_port_register(jackclient,
|
||||
"out_2",
|
||||
JACK_DEFAULT_AUDIO_TYPE,
|
||||
JackPortIsOutput | JackPortIsTerminal,
|
||||
0);
|
||||
midi_inport = jack_port_register(jackclient,
|
||||
"midi_input",
|
||||
JACK_DEFAULT_MIDI_TYPE,
|
||||
JackPortIsInput | JackPortIsTerminal,
|
||||
0);
|
||||
|
||||
if(jack_activate(jackclient)) {
|
||||
fprintf(stderr, "Cannot activate jack client\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
jack_connect(jackclient,jack_port_name(outport_left),"alsa_pcm:out_1");
|
||||
jack_connect(jackclient,jack_port_name(outport_right),"alsa_pcm:out_2");
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
int jackprocess(jack_nframes_t nframes, void *arg)
|
||||
{
|
||||
jack_default_audio_sample_t *outl =
|
||||
(jack_default_audio_sample_t *) jack_port_get_buffer(outport_left,
|
||||
nframes);
|
||||
jack_default_audio_sample_t *outr =
|
||||
(jack_default_audio_sample_t *) jack_port_get_buffer(outport_right,
|
||||
nframes);
|
||||
|
||||
if(!pthread_mutex_trylock(&jackmaster->mutex)) {
|
||||
JACKhandlemidi(nframes);
|
||||
jackmaster->GetAudioOutSamples(nframes, jack_get_sample_rate(
|
||||
jackclient), outl, outr);
|
||||
pthread_mutex_unlock(&jackmaster->mutex);
|
||||
}
|
||||
else {
|
||||
memset(outl, 0, sizeof(jack_default_audio_sample_t) * nframes);
|
||||
memset(outr, 0, sizeof(jack_default_audio_sample_t) * nframes);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void JACKfinish()
|
||||
{
|
||||
jack_client_close(jackclient);
|
||||
}
|
||||
|
||||
int jacksrate(jack_nframes_t nframes, void *arg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void jackshutdown(void *arg)
|
||||
{}
|
||||
|
||||
|
||||
void JACKhandlemidi(unsigned long frames)
|
||||
{
|
||||
// We must have the master mutex before we run this function
|
||||
|
||||
// XXX This is really nasty, not only do we lose the sample accuracy of
|
||||
// JACK MIDI, but any accuracy at all below the buffer size
|
||||
|
||||
void *midi_buf = jack_port_get_buffer(midi_inport, frames);
|
||||
jack_midi_event_t jack_midi_event;
|
||||
jack_nframes_t event_index = 0;
|
||||
unsigned char *midi_data;
|
||||
unsigned char type, chan;
|
||||
|
||||
while(jack_midi_event_get(&jack_midi_event, midi_buf,
|
||||
event_index++) == 0) {
|
||||
midi_data = jack_midi_event.buffer;
|
||||
type = midi_data[0] & 0xF0;
|
||||
chan = midi_data[0] & 0x0F;
|
||||
|
||||
switch(type) {
|
||||
case 0x80: /* note-off */
|
||||
jackmaster->NoteOff(chan, midi_data[1]);
|
||||
break;
|
||||
|
||||
case 0x90: /* note-on */
|
||||
jackmaster->NoteOn(chan, midi_data[1], midi_data[2]);
|
||||
break;
|
||||
|
||||
case 0xB0: /* controller */
|
||||
jackmaster->SetController(chan, midi_data[1], midi_data[2]);
|
||||
break;
|
||||
|
||||
case 0xE0: /* pitch bend */
|
||||
jackmaster->SetController(chan, C_pitchwheel,
|
||||
((midi_data[2] << 7) | midi_data[1]));
|
||||
break;
|
||||
|
||||
/* XXX TODO: handle MSB/LSB controllers and RPNs and NRPNs */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const char *JACKgetname()
|
||||
{
|
||||
if(jackclient != NULL)
|
||||
return jackname;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
JACKaudiooutput.h - Audio output for JACK
|
||||
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
|
||||
|
||||
*/
|
||||
#ifndef JACK_AUDIO_OUTPUT_H
|
||||
#define JACK_AUDIO_OUTPUT_H
|
||||
|
||||
#include <jack/jack.h>
|
||||
|
||||
#include "../globals.h"
|
||||
#include "../Misc/Master.h"
|
||||
|
||||
|
||||
#if (REALTYPE != jack_default_audio_sample_t)
|
||||
#error \
|
||||
"The internal sample datatype of ZynAddSubFX and the datatype of jack differs. \
|
||||
In order to compile ZynAddSubFX the 'REALTYPE' and 'jack_default_audio_sample_t' must be equal. \
|
||||
Set the 'REALTYPE' data type (which is defined in 'globals.h') to what is defined \
|
||||
in the file types.h from jack include directory as 'jack_default_audio_sample_t' (as float or double)."
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
bool JACKaudiooutputinit(Master *master_);
|
||||
void JACKfinish();
|
||||
void JACKhandlemidi(unsigned long frames);
|
||||
const char *JACKgetname();
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,128 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
OSSaudiooutput.cpp - Audio output 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
|
||||
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 <fcntl.h>
|
||||
#include <sys/soundcard.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#include <iostream>
|
||||
|
||||
#include "OSSaudiooutput.h"
|
||||
#include "../Misc/Util.h"
|
||||
#include "../globals.h"
|
||||
using namespace std;
|
||||
|
||||
OSSaudiooutput::OSSaudiooutput()
|
||||
{
|
||||
int i;
|
||||
int snd_bitsize = 16;
|
||||
snd_fragment = 0x00080009; //fragment size (?)
|
||||
snd_stereo = 1; //stereo
|
||||
snd_format = AFMT_S16_LE;
|
||||
snd_samplerate = SAMPLE_RATE;
|
||||
playing_until.tv_sec = 0;
|
||||
playing_until.tv_usec = 0;
|
||||
|
||||
smps = new short int[SOUND_BUFFER_SIZE * 2];
|
||||
for(i = 0; i < SOUND_BUFFER_SIZE * 2; i++)
|
||||
smps[i] = 0;
|
||||
|
||||
snd_handle = open(config.cfg.LinuxOSSWaveOutDev, O_WRONLY, 0);
|
||||
if(snd_handle == -1) {
|
||||
cerr << "ERROR - I can't open the ";
|
||||
cerr << config.cfg.LinuxOSSWaveOutDev << '.' << endl;
|
||||
return;
|
||||
}
|
||||
ioctl(snd_handle, SNDCTL_DSP_RESET, NULL);
|
||||
|
||||
ioctl(snd_handle, SNDCTL_DSP_SETFMT, &snd_format);
|
||||
ioctl(snd_handle, SNDCTL_DSP_STEREO, &snd_stereo);
|
||||
ioctl(snd_handle, SNDCTL_DSP_SPEED, &snd_samplerate);
|
||||
ioctl(snd_handle, SNDCTL_DSP_SAMPLESIZE, &snd_bitsize);
|
||||
ioctl(snd_handle, SNDCTL_DSP_SETFRAGMENT, &snd_fragment);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Output the samples to the soundcard
|
||||
* The samples are bigger than -1.0 and smaller 1.0
|
||||
*/
|
||||
void OSSaudiooutput::OSSout(REALTYPE *smp_left, REALTYPE *smp_right)
|
||||
{
|
||||
int i;
|
||||
REALTYPE l, r;
|
||||
if(snd_handle < 0) { //output could not be opened
|
||||
struct timeval now;
|
||||
int remaining;
|
||||
gettimeofday(&now, NULL);
|
||||
if((playing_until.tv_usec == 0) && (playing_until.tv_sec == 0)) {
|
||||
playing_until.tv_usec = now.tv_usec;
|
||||
playing_until.tv_sec = now.tv_sec;
|
||||
}
|
||||
else {
|
||||
remaining = (playing_until.tv_usec - now.tv_usec)
|
||||
+ (playing_until.tv_sec - now.tv_sec) * 1000000;
|
||||
if(remaining > 10000) //Don't sleep() less than 10ms.
|
||||
//This will add latency...
|
||||
usleep(remaining - 10000);
|
||||
if(remaining < 0)
|
||||
cerr << "WARNING - too late" << endl;
|
||||
}
|
||||
playing_until.tv_usec += SOUND_BUFFER_SIZE * 1000000 / SAMPLE_RATE;
|
||||
if(remaining < 0)
|
||||
playing_until.tv_usec -= remaining;
|
||||
playing_until.tv_sec += playing_until.tv_usec / 1000000;
|
||||
playing_until.tv_usec %= 1000000;
|
||||
return;
|
||||
}
|
||||
|
||||
for(i = 0; i < SOUND_BUFFER_SIZE; i++) {
|
||||
l = smp_left[i];
|
||||
r = smp_right[i];
|
||||
|
||||
if(l < -1.0)
|
||||
l = -1.0;
|
||||
else
|
||||
if(l > 1.0)
|
||||
l = 1.0;
|
||||
if(r < -1.0)
|
||||
r = -1.0;
|
||||
else
|
||||
if(r > 1.0)
|
||||
r = 1.0;
|
||||
|
||||
smps[i * 2] = (short int) (l * 32767.0);
|
||||
smps[i * 2 + 1] = (short int) (r * 32767.0);
|
||||
}
|
||||
write(snd_handle, smps, SOUND_BUFFER_SIZE * 4); // *2 because is 16 bit, again * 2 because is stereo
|
||||
}
|
||||
|
||||
|
||||
OSSaudiooutput::~OSSaudiooutput()
|
||||
{
|
||||
close(snd_handle);
|
||||
delete [] smps;
|
||||
}
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
OSSaudiooutput.h - Audio output 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
|
||||
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 OSS_AUDIO_OUTPUT_H
|
||||
#define OSS_AUDIO_OUTPUT_H
|
||||
|
||||
#include <sys/time.h>
|
||||
#include "../globals.h"
|
||||
|
||||
class OSSaudiooutput
|
||||
{
|
||||
public:
|
||||
OSSaudiooutput();
|
||||
~OSSaudiooutput();
|
||||
|
||||
//the out is [-1.0 .. 1.0]
|
||||
/* smp_left[] and smp_right[] has the size of SOUND_BUFFER_SIZE */
|
||||
void OSSout(REALTYPE *smp_left, REALTYPE *smp_right);
|
||||
private:
|
||||
int snd_handle;
|
||||
int snd_fragment;
|
||||
int snd_stereo;
|
||||
int snd_format;
|
||||
int snd_samplerate;
|
||||
struct timeval playing_until;
|
||||
|
||||
short int *smps; //Samples to be sent to soundcard
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
PAaudiooutput.cpp - Audio output for PortAudio
|
||||
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
|
||||
|
||||
*/
|
||||
|
||||
#include "PAaudiooutput.h"
|
||||
|
||||
Master *PAmaster;
|
||||
PaStream *stream;
|
||||
REALTYPE *outl, *outr;
|
||||
|
||||
int PAprocess(void *inputBuffer, void *outputBuffer,
|
||||
unsigned long framesPerBuffer,
|
||||
PaTimestamp outTime, void *userData)
|
||||
{
|
||||
if(framesPerBuffer != SOUND_BUFFER_SIZE) {
|
||||
fprintf(
|
||||
stderr,
|
||||
"Bug: PAudioOutput::PAprocess SOUND_BUFFER_SIZE!=framesPerBuffer");
|
||||
fprintf(stderr, "%d %d\n", framesPerBuffer, SOUND_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&PAmaster->mutex);
|
||||
PAmaster->GetAudioOutSamples(SOUND_BUFFER_SIZE, SAMPLE_RATE, outl, outr);
|
||||
pthread_mutex_unlock(&PAmaster->mutex);
|
||||
|
||||
float *out = (float *)outputBuffer;
|
||||
|
||||
for(int i = 0; i < framesPerBuffer; i++) {
|
||||
if(i >= SOUND_BUFFER_SIZE)
|
||||
break; //this should never happens, except only when framesPerBuffer!>SOUND_BUFFER_SIZE
|
||||
out[i * 2] = outl[i];
|
||||
out[i * 2 + 1] = outr[i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PAaudiooutputinit(Master *master_)
|
||||
{
|
||||
PAmaster = master_;
|
||||
outl = new REALTYPE [SOUND_BUFFER_SIZE];
|
||||
outr = new REALTYPE [SOUND_BUFFER_SIZE];
|
||||
Pa_Initialize();
|
||||
Pa_OpenDefaultStream(&stream,
|
||||
0,
|
||||
2,
|
||||
paFloat32,
|
||||
SAMPLE_RATE,
|
||||
SOUND_BUFFER_SIZE,
|
||||
0,
|
||||
PAprocess,
|
||||
NULL);
|
||||
Pa_StartStream(stream);
|
||||
}
|
||||
|
||||
void PAfinish()
|
||||
{
|
||||
Pa_StopStream(stream);
|
||||
delete (outl);
|
||||
delete (outr);
|
||||
}
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
PAaudiooutput.h - Audio output for PortAudio
|
||||
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
|
||||
|
||||
*/
|
||||
#ifndef PA_AUDIO_OUTPUT_H
|
||||
#define PA_AUDIO_OUTPUT_H
|
||||
|
||||
#include <portaudio.h>
|
||||
|
||||
#include "../globals.h"
|
||||
#include "../Misc/Master.h"
|
||||
|
||||
void PAaudiooutputinit(Master *master_);
|
||||
void PAfinish();
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,113 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
Recorder.cpp - Records sound to a 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 <sys/stat.h>
|
||||
#include "Recorder.h"
|
||||
|
||||
Recorder::Recorder()
|
||||
{
|
||||
recordbuf_16bit = new short int [SOUND_BUFFER_SIZE * 2];
|
||||
status = 0;
|
||||
notetrigger = 0;
|
||||
for(int i = 0; i < SOUND_BUFFER_SIZE * 2; i++)
|
||||
recordbuf_16bit[i] = 0;
|
||||
}
|
||||
|
||||
Recorder::~Recorder()
|
||||
{
|
||||
if(recording() == 1)
|
||||
stop();
|
||||
delete [] recordbuf_16bit;
|
||||
}
|
||||
|
||||
int Recorder::preparefile(std::string filename_, int overwrite)
|
||||
{
|
||||
if(!overwrite) {
|
||||
struct stat fileinfo;
|
||||
int statr;
|
||||
statr = stat(filename_.c_str(), &fileinfo);
|
||||
if(statr == 0) //file exists
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(!wav.newfile(filename_, SAMPLE_RATE, 2))
|
||||
return 2;
|
||||
|
||||
status = 1; //ready
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Recorder::start()
|
||||
{
|
||||
notetrigger = 0;
|
||||
status = 2; //recording
|
||||
}
|
||||
|
||||
void Recorder::stop()
|
||||
{
|
||||
wav.close();
|
||||
status = 0;
|
||||
}
|
||||
|
||||
void Recorder::pause()
|
||||
{
|
||||
status = 0;
|
||||
}
|
||||
|
||||
int Recorder::recording()
|
||||
{
|
||||
if((status == 2) && (notetrigger != 0))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Recorder::recordbuffer(REALTYPE *outl, REALTYPE *outr)
|
||||
{
|
||||
int tmp;
|
||||
if(status != 2)
|
||||
return;
|
||||
for(int i = 0; i < SOUND_BUFFER_SIZE; i++) {
|
||||
tmp = (int)(outl[i] * 32767.0);
|
||||
if(tmp < -32768)
|
||||
tmp = -32768;
|
||||
if(tmp > 32767)
|
||||
tmp = 32767;
|
||||
recordbuf_16bit[i * 2] = tmp;
|
||||
|
||||
tmp = (int)(outr[i] * 32767.0);
|
||||
if(tmp < -32768)
|
||||
tmp = -32768;
|
||||
if(tmp > 32767)
|
||||
tmp = 32767;
|
||||
recordbuf_16bit[i * 2 + 1] = tmp;
|
||||
}
|
||||
wav.write_stereo_samples(SOUND_BUFFER_SIZE, recordbuf_16bit);
|
||||
}
|
||||
|
||||
void Recorder::triggernow()
|
||||
{
|
||||
if(status == 2)
|
||||
notetrigger = 1;
|
||||
}
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
Recorder.h - Records sound to a 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
|
||||
|
||||
*/
|
||||
|
||||
#ifndef RECORDER_H
|
||||
#define RECORDER_H
|
||||
#include <string>
|
||||
#include "../globals.h"
|
||||
#include "WAVaudiooutput.h"
|
||||
|
||||
/**Records sound to a file*/
|
||||
class Recorder
|
||||
{
|
||||
public:
|
||||
|
||||
Recorder();
|
||||
~Recorder();
|
||||
int preparefile(std::string filename_, int overwrite); //returns 1 if the file exists
|
||||
void start();
|
||||
void stop();
|
||||
void pause();
|
||||
int recording();
|
||||
void triggernow();
|
||||
void recordbuffer(REALTYPE *outl, REALTYPE *outr);
|
||||
|
||||
/** Status:
|
||||
* 0 - not ready(no file selected),
|
||||
* 1 - ready
|
||||
* 2 - recording */
|
||||
int status;
|
||||
|
||||
private:
|
||||
WAVaudiooutput wav;
|
||||
short int *recordbuf_16bit;
|
||||
int notetrigger;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
VSTaudiooutput.cpp - Audio output for VST
|
||||
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
|
||||
|
||||
*/
|
||||
#include <string.h>
|
||||
#include "VSTaudiooutput.h"
|
||||
|
||||
//the constructor and the destructor are defined in main.cpp
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
VSTaudiooutput.h - Audio output for VST
|
||||
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
|
||||
|
||||
*/
|
||||
#ifndef VST_AUDIO_OUTPUT_H
|
||||
#define VST_AUDIO_OUTPUT_H
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "../globals.h"
|
||||
#include "../Misc/Master.h"
|
||||
#include "../UI/MasterUI.h"
|
||||
|
||||
#include "../../../vstsdk2/source/common/audioeffectx.h"
|
||||
|
||||
class VSTSynth:public AudioEffectX
|
||||
{
|
||||
public:
|
||||
VSTSynth(audioMasterCallback audioMaster);
|
||||
~VSTSynth();
|
||||
|
||||
virtual void process(float **inputs, float **outputs, long sampleframes);
|
||||
virtual void processReplacing(float **inputs,
|
||||
float **outputs,
|
||||
long sampleframes);
|
||||
virtual long processEvents(VstEvents *events); //this is used for Midi input
|
||||
virtual long int canDo(char *txt);
|
||||
virtual bool getVendorString(char *txt);
|
||||
virtual bool getProductString(char *txt);
|
||||
virtual void resume();
|
||||
|
||||
virtual long getChunk(void **data, bool isPreset = false);
|
||||
virtual long setChunk(void *data, long size, bool isPreset = false);
|
||||
|
||||
MasterUI *ui;
|
||||
int Pexitprogram;
|
||||
|
||||
Master *vmaster;
|
||||
pthread_t thr;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2006 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) 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 <stdlib.h>
|
||||
#include "WAVaudiooutput.h"
|
||||
using namespace std;
|
||||
|
||||
WAVaudiooutput::WAVaudiooutput()
|
||||
{
|
||||
file = NULL;
|
||||
sampleswritten = 0;
|
||||
samplerate = 44100;
|
||||
}
|
||||
|
||||
WAVaudiooutput::~WAVaudiooutput()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
bool WAVaudiooutput::newfile(string filename, int samplerate, int channels)
|
||||
{
|
||||
/**\todo Move this into the Constructor*/
|
||||
close(); //inchide un posibil fisier existent
|
||||
file = fopen(filename.c_str(), "w");
|
||||
if(!file)
|
||||
return false;
|
||||
this->samplerate = samplerate;
|
||||
this->channels = channels;
|
||||
sampleswritten = 0;
|
||||
char tmp[44];
|
||||
fwrite(tmp, 1, 44, file);
|
||||
return true;
|
||||
}
|
||||
|
||||
void WAVaudiooutput::close()
|
||||
{
|
||||
if(file) {
|
||||
unsigned int chunksize;
|
||||
rewind(file);
|
||||
|
||||
fwrite("RIFF", 4, 1, file);
|
||||
chunksize = sampleswritten * 4 + 36;
|
||||
fwrite(&chunksize, 4, 1, file);
|
||||
|
||||
fwrite("WAVEfmt ", 8, 1, file);
|
||||
chunksize = 16;
|
||||
fwrite(&chunksize, 4, 1, file);
|
||||
unsigned short int formattag = 1; //uncompresed wave
|
||||
fwrite(&formattag, 2, 1, file);
|
||||
unsigned short int nchannels = channels; //stereo
|
||||
fwrite(&nchannels, 2, 1, file);
|
||||
unsigned int samplerate_ = samplerate; //samplerate
|
||||
fwrite(&samplerate_, 4, 1, file);
|
||||
unsigned int bytespersec = samplerate * 2 * channels; //bytes/sec
|
||||
fwrite(&bytespersec, 4, 1, file);
|
||||
unsigned short int blockalign = 2 * channels; //2 channels * 16 bits/8
|
||||
fwrite(&blockalign, 2, 1, file);
|
||||
unsigned short int bitspersample = 16;
|
||||
fwrite(&bitspersample, 2, 1, file);
|
||||
|
||||
fwrite("data", 4, 1, file);
|
||||
chunksize = sampleswritten * blockalign;
|
||||
fwrite(&chunksize, 4, 1, file);
|
||||
|
||||
fclose(file);
|
||||
file = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void WAVaudiooutput::write_stereo_samples(int nsmps, short int *smps)
|
||||
{
|
||||
if(!file)
|
||||
return;
|
||||
fwrite(smps, nsmps, 4, file);
|
||||
sampleswritten += nsmps;
|
||||
}
|
||||
|
||||
void WAVaudiooutput::write_mono_samples(int nsmps, short int *smps)
|
||||
{
|
||||
if(!file)
|
||||
return;
|
||||
fwrite(smps, nsmps, 2, file);
|
||||
sampleswritten += nsmps;
|
||||
}
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (C) 2008 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) 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 WAVOUTPUT_H
|
||||
#define WAVOUTPUT_H
|
||||
#include <string>
|
||||
|
||||
class WAVaudiooutput
|
||||
{
|
||||
public:
|
||||
WAVaudiooutput();
|
||||
~WAVaudiooutput();
|
||||
|
||||
bool newfile(std::string filename, int samplerate, int channels);
|
||||
void close();
|
||||
|
||||
void write_mono_samples(int nsmps, short int *smps);
|
||||
void write_stereo_samples(int nsmps, short int *smps);
|
||||
|
||||
private:
|
||||
int sampleswritten;
|
||||
int samplerate;
|
||||
int channels;
|
||||
FILE *file;
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -1,840 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
ADnoteParameters.cpp - Parameters for ADnote (ADsynth)
|
||||
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 <math.h>
|
||||
|
||||
#include "ADnoteParameters.h"
|
||||
int ADnote_unison_sizes[] =
|
||||
{1, 2, 3, 4, 5, 6, 8, 10, 12, 15, 20, 25, 30, 40, 50, 0};
|
||||
|
||||
ADnoteParameters::ADnoteParameters(FFTwrapper *fft_)
|
||||
:PresetsArray()
|
||||
{
|
||||
setpresettype("Padsyth");
|
||||
fft = fft_;
|
||||
|
||||
GlobalPar.FreqEnvelope = new EnvelopeParams(0, 0);
|
||||
GlobalPar.FreqEnvelope->ASRinit(64, 50, 64, 60);
|
||||
GlobalPar.FreqLfo = new LFOParams(70, 0, 64, 0, 0, 0, 0, 0);
|
||||
|
||||
GlobalPar.AmpEnvelope = new EnvelopeParams(64, 1);
|
||||
GlobalPar.AmpEnvelope->ADSRinit_dB(0, 40, 127, 25);
|
||||
GlobalPar.AmpLfo = new LFOParams(80, 0, 64, 0, 0, 0, 0, 1);
|
||||
|
||||
GlobalPar.GlobalFilter = new FilterParams(2, 94, 40);
|
||||
GlobalPar.FilterEnvelope = new EnvelopeParams(0, 1);
|
||||
GlobalPar.FilterEnvelope->ADSRinit_filter(64, 40, 64, 70, 60, 64);
|
||||
GlobalPar.FilterLfo = new LFOParams(80, 0, 64, 0, 0, 0, 0, 2);
|
||||
GlobalPar.Reson = new Resonance();
|
||||
|
||||
for(int nvoice = 0; nvoice < NUM_VOICES; nvoice++)
|
||||
EnableVoice(nvoice);
|
||||
|
||||
defaults();
|
||||
}
|
||||
|
||||
void ADnoteParameters::defaults()
|
||||
{
|
||||
//Default Parameters
|
||||
/* Frequency Global Parameters */
|
||||
GlobalPar.PStereo = 1; //stereo
|
||||
GlobalPar.PDetune = 8192; //zero
|
||||
GlobalPar.PCoarseDetune = 0;
|
||||
GlobalPar.PDetuneType = 1;
|
||||
GlobalPar.FreqEnvelope->defaults();
|
||||
GlobalPar.FreqLfo->defaults();
|
||||
GlobalPar.PBandwidth = 64;
|
||||
|
||||
/* Amplitude Global Parameters */
|
||||
GlobalPar.PVolume = 90;
|
||||
GlobalPar.PPanning = 64; //center
|
||||
GlobalPar.PAmpVelocityScaleFunction = 64;
|
||||
GlobalPar.AmpEnvelope->defaults();
|
||||
GlobalPar.AmpLfo->defaults();
|
||||
GlobalPar.PPunchStrength = 0;
|
||||
GlobalPar.PPunchTime = 60;
|
||||
GlobalPar.PPunchStretch = 64;
|
||||
GlobalPar.PPunchVelocitySensing = 72;
|
||||
GlobalPar.Hrandgrouping = 0;
|
||||
|
||||
/* Filter Global Parameters*/
|
||||
GlobalPar.PFilterVelocityScale = 64;
|
||||
GlobalPar.PFilterVelocityScaleFunction = 64;
|
||||
GlobalPar.GlobalFilter->defaults();
|
||||
GlobalPar.FilterEnvelope->defaults();
|
||||
GlobalPar.FilterLfo->defaults();
|
||||
GlobalPar.Reson->defaults();
|
||||
|
||||
|
||||
for(int nvoice = 0; nvoice < NUM_VOICES; nvoice++)
|
||||
defaults(nvoice);
|
||||
;
|
||||
VoicePar[0].Enabled = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Defaults a voice
|
||||
*/
|
||||
void ADnoteParameters::defaults(int n)
|
||||
{
|
||||
int nvoice = n;
|
||||
VoicePar[nvoice].Enabled = 0;
|
||||
|
||||
VoicePar[nvoice].Unison_size = 1;
|
||||
VoicePar[nvoice].Unison_frequency_spread = 60;
|
||||
VoicePar[nvoice].Unison_stereo_spread = 64;
|
||||
VoicePar[nvoice].Unison_vibratto = 64;
|
||||
VoicePar[nvoice].Unison_vibratto_speed = 64;
|
||||
VoicePar[nvoice].Unison_invert_phase = 0;
|
||||
|
||||
VoicePar[nvoice].Type = 0;
|
||||
VoicePar[nvoice].Pfixedfreq = 0;
|
||||
VoicePar[nvoice].PfixedfreqET = 0;
|
||||
VoicePar[nvoice].Presonance = 1;
|
||||
VoicePar[nvoice].Pfilterbypass = 0;
|
||||
VoicePar[nvoice].Pextoscil = -1;
|
||||
VoicePar[nvoice].PextFMoscil = -1;
|
||||
VoicePar[nvoice].Poscilphase = 64;
|
||||
VoicePar[nvoice].PFMoscilphase = 64;
|
||||
VoicePar[nvoice].PDelay = 0;
|
||||
VoicePar[nvoice].PVolume = 100;
|
||||
VoicePar[nvoice].PVolumeminus = 0;
|
||||
VoicePar[nvoice].PPanning = 64; //center
|
||||
VoicePar[nvoice].PDetune = 8192; //8192=0
|
||||
VoicePar[nvoice].PCoarseDetune = 0;
|
||||
VoicePar[nvoice].PDetuneType = 0;
|
||||
VoicePar[nvoice].PFreqLfoEnabled = 0;
|
||||
VoicePar[nvoice].PFreqEnvelopeEnabled = 0;
|
||||
VoicePar[nvoice].PAmpEnvelopeEnabled = 0;
|
||||
VoicePar[nvoice].PAmpLfoEnabled = 0;
|
||||
VoicePar[nvoice].PAmpVelocityScaleFunction = 127;
|
||||
VoicePar[nvoice].PFilterEnabled = 0;
|
||||
VoicePar[nvoice].PFilterEnvelopeEnabled = 0;
|
||||
VoicePar[nvoice].PFilterLfoEnabled = 0;
|
||||
VoicePar[nvoice].PFMEnabled = 0;
|
||||
|
||||
//I use the internal oscillator (-1)
|
||||
VoicePar[nvoice].PFMVoice = -1;
|
||||
|
||||
VoicePar[nvoice].PFMVolume = 90;
|
||||
VoicePar[nvoice].PFMVolumeDamp = 64;
|
||||
VoicePar[nvoice].PFMDetune = 8192;
|
||||
VoicePar[nvoice].PFMCoarseDetune = 0;
|
||||
VoicePar[nvoice].PFMDetuneType = 0;
|
||||
VoicePar[nvoice].PFMFreqEnvelopeEnabled = 0;
|
||||
VoicePar[nvoice].PFMAmpEnvelopeEnabled = 0;
|
||||
VoicePar[nvoice].PFMVelocityScaleFunction = 64;
|
||||
|
||||
VoicePar[nvoice].OscilSmp->defaults();
|
||||
VoicePar[nvoice].FMSmp->defaults();
|
||||
|
||||
VoicePar[nvoice].AmpEnvelope->defaults();
|
||||
VoicePar[nvoice].AmpLfo->defaults();
|
||||
|
||||
VoicePar[nvoice].FreqEnvelope->defaults();
|
||||
VoicePar[nvoice].FreqLfo->defaults();
|
||||
|
||||
VoicePar[nvoice].VoiceFilter->defaults();
|
||||
VoicePar[nvoice].FilterEnvelope->defaults();
|
||||
VoicePar[nvoice].FilterLfo->defaults();
|
||||
|
||||
VoicePar[nvoice].FMFreqEnvelope->defaults();
|
||||
VoicePar[nvoice].FMAmpEnvelope->defaults();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Init the voice parameters
|
||||
*/
|
||||
void ADnoteParameters::EnableVoice(int nvoice)
|
||||
{
|
||||
VoicePar[nvoice].OscilSmp = new OscilGen(fft, GlobalPar.Reson);
|
||||
VoicePar[nvoice].FMSmp = new OscilGen(fft, NULL);
|
||||
|
||||
VoicePar[nvoice].AmpEnvelope = new EnvelopeParams(64, 1);
|
||||
VoicePar[nvoice].AmpEnvelope->ADSRinit_dB(0, 100, 127, 100);
|
||||
VoicePar[nvoice].AmpLfo = new LFOParams(90, 32, 64, 0, 0, 30, 0, 1);
|
||||
|
||||
VoicePar[nvoice].FreqEnvelope = new EnvelopeParams(0, 0);
|
||||
VoicePar[nvoice].FreqEnvelope->ASRinit(30, 40, 64, 60);
|
||||
VoicePar[nvoice].FreqLfo = new LFOParams(50, 40, 0, 0, 0, 0, 0, 0);
|
||||
|
||||
VoicePar[nvoice].VoiceFilter = new FilterParams(2, 50, 60);
|
||||
VoicePar[nvoice].FilterEnvelope = new EnvelopeParams(0, 0);
|
||||
VoicePar[nvoice].FilterEnvelope->ADSRinit_filter(90, 70, 40, 70, 10, 40);
|
||||
VoicePar[nvoice].FilterLfo = new LFOParams(50, 20, 64, 0, 0, 0, 0, 2);
|
||||
|
||||
VoicePar[nvoice].FMFreqEnvelope = new EnvelopeParams(0, 0);
|
||||
VoicePar[nvoice].FMFreqEnvelope->ASRinit(20, 90, 40, 80);
|
||||
VoicePar[nvoice].FMAmpEnvelope = new EnvelopeParams(64, 1);
|
||||
VoicePar[nvoice].FMAmpEnvelope->ADSRinit(80, 90, 127, 100);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the Multiplier of the fine detunes of the voices
|
||||
*/
|
||||
REALTYPE ADnoteParameters::getBandwidthDetuneMultiplier()
|
||||
{
|
||||
REALTYPE bw = (GlobalPar.PBandwidth - 64.0) / 64.0;
|
||||
bw = pow(2.0, bw * pow(fabs(bw), 0.2) * 5.0);
|
||||
|
||||
return bw;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the unison spread in cents for a voice
|
||||
*/
|
||||
|
||||
REALTYPE ADnoteParameters::getUnisonFrequencySpreadCents(int nvoice) {
|
||||
REALTYPE unison_spread = VoicePar[nvoice].Unison_frequency_spread / 127.0;
|
||||
unison_spread = pow(unison_spread * 2.0, 2.0) * 50.0; //cents
|
||||
return unison_spread;
|
||||
}
|
||||
|
||||
/*
|
||||
* Kill the voice
|
||||
*/
|
||||
void ADnoteParameters::KillVoice(int nvoice)
|
||||
{
|
||||
delete (VoicePar[nvoice].OscilSmp);
|
||||
delete (VoicePar[nvoice].FMSmp);
|
||||
|
||||
delete (VoicePar[nvoice].AmpEnvelope);
|
||||
delete (VoicePar[nvoice].AmpLfo);
|
||||
|
||||
delete (VoicePar[nvoice].FreqEnvelope);
|
||||
delete (VoicePar[nvoice].FreqLfo);
|
||||
|
||||
delete (VoicePar[nvoice].VoiceFilter);
|
||||
delete (VoicePar[nvoice].FilterEnvelope);
|
||||
delete (VoicePar[nvoice].FilterLfo);
|
||||
|
||||
delete (VoicePar[nvoice].FMFreqEnvelope);
|
||||
delete (VoicePar[nvoice].FMAmpEnvelope);
|
||||
}
|
||||
|
||||
ADnoteParameters::~ADnoteParameters()
|
||||
{
|
||||
delete (GlobalPar.FreqEnvelope);
|
||||
delete (GlobalPar.FreqLfo);
|
||||
delete (GlobalPar.AmpEnvelope);
|
||||
delete (GlobalPar.AmpLfo);
|
||||
delete (GlobalPar.GlobalFilter);
|
||||
delete (GlobalPar.FilterEnvelope);
|
||||
delete (GlobalPar.FilterLfo);
|
||||
delete (GlobalPar.Reson);
|
||||
|
||||
for(int nvoice = 0; nvoice < NUM_VOICES; nvoice++)
|
||||
KillVoice(nvoice);
|
||||
;
|
||||
}
|
||||
|
||||
int ADnoteParameters::get_unison_size_index(int nvoice) {
|
||||
int index = 0;
|
||||
if(nvoice >= NUM_VOICES)
|
||||
return 0;
|
||||
int unison = VoicePar[nvoice].Unison_size;
|
||||
|
||||
while(1) {
|
||||
if(ADnote_unison_sizes[index] >= unison)
|
||||
return index;
|
||||
;
|
||||
if(ADnote_unison_sizes[index] == 0)
|
||||
return index - 1;
|
||||
;
|
||||
index++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ADnoteParameters::set_unison_size_index(int nvoice, int index) {
|
||||
int unison = 1;
|
||||
for(int i = 0; i <= index; i++) {
|
||||
unison = ADnote_unison_sizes[i];
|
||||
if(unison == 0) {
|
||||
unison = ADnote_unison_sizes[i - 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
VoicePar[nvoice].Unison_size = unison;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ADnoteParameters::add2XMLsection(XMLwrapper *xml, int n)
|
||||
{
|
||||
int nvoice = n;
|
||||
if(nvoice >= NUM_VOICES)
|
||||
return;
|
||||
|
||||
int oscilused = 0, fmoscilused = 0; //if the oscil or fmoscil are used by another voice
|
||||
|
||||
for(int i = 0; i < NUM_VOICES; i++) {
|
||||
if(VoicePar[i].Pextoscil == nvoice)
|
||||
oscilused = 1;
|
||||
if(VoicePar[i].PextFMoscil == nvoice)
|
||||
fmoscilused = 1;
|
||||
}
|
||||
|
||||
xml->addparbool("enabled", VoicePar[nvoice].Enabled);
|
||||
if(((VoicePar[nvoice].Enabled == 0) && (oscilused == 0)
|
||||
&& (fmoscilused == 0)) && (xml->minimal))
|
||||
return;
|
||||
|
||||
|
||||
xml->addpar("type", VoicePar[nvoice].Type);
|
||||
|
||||
xml->addpar("unison_size", VoicePar[nvoice].Unison_size);
|
||||
xml->addpar("unison_frequency_spread",
|
||||
VoicePar[nvoice].Unison_frequency_spread);
|
||||
xml->addpar("unison_stereo_spread", VoicePar[nvoice].Unison_stereo_spread);
|
||||
xml->addpar("unison_vibratto", VoicePar[nvoice].Unison_vibratto);
|
||||
xml->addpar("unison_vibratto_speed", VoicePar[nvoice].Unison_vibratto_speed);
|
||||
xml->addpar("unison_invert_phase", VoicePar[nvoice].Unison_invert_phase);
|
||||
|
||||
xml->addpar("delay", VoicePar[nvoice].PDelay);
|
||||
xml->addparbool("resonance", VoicePar[nvoice].Presonance);
|
||||
|
||||
xml->addpar("ext_oscil", VoicePar[nvoice].Pextoscil);
|
||||
xml->addpar("ext_fm_oscil", VoicePar[nvoice].PextFMoscil);
|
||||
|
||||
xml->addpar("oscil_phase", VoicePar[nvoice].Poscilphase);
|
||||
xml->addpar("oscil_fm_phase", VoicePar[nvoice].PFMoscilphase);
|
||||
|
||||
xml->addparbool("filter_enabled", VoicePar[nvoice].PFilterEnabled);
|
||||
xml->addparbool("filter_bypass", VoicePar[nvoice].Pfilterbypass);
|
||||
|
||||
xml->addpar("fm_enabled", VoicePar[nvoice].PFMEnabled);
|
||||
|
||||
xml->beginbranch("OSCIL");
|
||||
VoicePar[nvoice].OscilSmp->add2XML(xml);
|
||||
xml->endbranch();
|
||||
|
||||
|
||||
xml->beginbranch("AMPLITUDE_PARAMETERS");
|
||||
xml->addpar("panning", VoicePar[nvoice].PPanning);
|
||||
xml->addpar("volume", VoicePar[nvoice].PVolume);
|
||||
xml->addparbool("volume_minus", VoicePar[nvoice].PVolumeminus);
|
||||
xml->addpar("velocity_sensing", VoicePar[nvoice].PAmpVelocityScaleFunction);
|
||||
|
||||
xml->addparbool("amp_envelope_enabled",
|
||||
VoicePar[nvoice].PAmpEnvelopeEnabled);
|
||||
if((VoicePar[nvoice].PAmpEnvelopeEnabled != 0) || (!xml->minimal)) {
|
||||
xml->beginbranch("AMPLITUDE_ENVELOPE");
|
||||
VoicePar[nvoice].AmpEnvelope->add2XML(xml);
|
||||
xml->endbranch();
|
||||
}
|
||||
xml->addparbool("amp_lfo_enabled", VoicePar[nvoice].PAmpLfoEnabled);
|
||||
if((VoicePar[nvoice].PAmpLfoEnabled != 0) || (!xml->minimal)) {
|
||||
xml->beginbranch("AMPLITUDE_LFO");
|
||||
VoicePar[nvoice].AmpLfo->add2XML(xml);
|
||||
xml->endbranch();
|
||||
}
|
||||
xml->endbranch();
|
||||
|
||||
xml->beginbranch("FREQUENCY_PARAMETERS");
|
||||
xml->addparbool("fixed_freq", VoicePar[nvoice].Pfixedfreq);
|
||||
xml->addpar("fixed_freq_et", VoicePar[nvoice].PfixedfreqET);
|
||||
xml->addpar("detune", VoicePar[nvoice].PDetune);
|
||||
xml->addpar("coarse_detune", VoicePar[nvoice].PCoarseDetune);
|
||||
xml->addpar("detune_type", VoicePar[nvoice].PDetuneType);
|
||||
|
||||
xml->addparbool("freq_envelope_enabled",
|
||||
VoicePar[nvoice].PFreqEnvelopeEnabled);
|
||||
if((VoicePar[nvoice].PFreqEnvelopeEnabled != 0) || (!xml->minimal)) {
|
||||
xml->beginbranch("FREQUENCY_ENVELOPE");
|
||||
VoicePar[nvoice].FreqEnvelope->add2XML(xml);
|
||||
xml->endbranch();
|
||||
}
|
||||
xml->addparbool("freq_lfo_enabled", VoicePar[nvoice].PFreqLfoEnabled);
|
||||
if((VoicePar[nvoice].PFreqLfoEnabled != 0) || (!xml->minimal)) {
|
||||
xml->beginbranch("FREQUENCY_LFO");
|
||||
VoicePar[nvoice].FreqLfo->add2XML(xml);
|
||||
xml->endbranch();
|
||||
}
|
||||
xml->endbranch();
|
||||
|
||||
|
||||
if((VoicePar[nvoice].PFilterEnabled != 0) || (!xml->minimal)) {
|
||||
xml->beginbranch("FILTER_PARAMETERS");
|
||||
xml->beginbranch("FILTER");
|
||||
VoicePar[nvoice].VoiceFilter->add2XML(xml);
|
||||
xml->endbranch();
|
||||
|
||||
xml->addparbool("filter_envelope_enabled",
|
||||
VoicePar[nvoice].PFilterEnvelopeEnabled);
|
||||
if((VoicePar[nvoice].PFilterEnvelopeEnabled != 0) || (!xml->minimal)) {
|
||||
xml->beginbranch("FILTER_ENVELOPE");
|
||||
VoicePar[nvoice].FilterEnvelope->add2XML(xml);
|
||||
xml->endbranch();
|
||||
}
|
||||
|
||||
xml->addparbool("filter_lfo_enabled",
|
||||
VoicePar[nvoice].PFilterLfoEnabled);
|
||||
if((VoicePar[nvoice].PFilterLfoEnabled != 0) || (!xml->minimal)) {
|
||||
xml->beginbranch("FILTER_LFO");
|
||||
VoicePar[nvoice].FilterLfo->add2XML(xml);
|
||||
xml->endbranch();
|
||||
}
|
||||
xml->endbranch();
|
||||
}
|
||||
|
||||
if((VoicePar[nvoice].PFMEnabled != 0) || (fmoscilused != 0)
|
||||
|| (!xml->minimal)) {
|
||||
xml->beginbranch("FM_PARAMETERS");
|
||||
xml->addpar("input_voice", VoicePar[nvoice].PFMVoice);
|
||||
|
||||
xml->addpar("volume", VoicePar[nvoice].PFMVolume);
|
||||
xml->addpar("volume_damp", VoicePar[nvoice].PFMVolumeDamp);
|
||||
xml->addpar("velocity_sensing",
|
||||
VoicePar[nvoice].PFMVelocityScaleFunction);
|
||||
|
||||
xml->addparbool("amp_envelope_enabled",
|
||||
VoicePar[nvoice].PFMAmpEnvelopeEnabled);
|
||||
if((VoicePar[nvoice].PFMAmpEnvelopeEnabled != 0) || (!xml->minimal)) {
|
||||
xml->beginbranch("AMPLITUDE_ENVELOPE");
|
||||
VoicePar[nvoice].FMAmpEnvelope->add2XML(xml);
|
||||
xml->endbranch();
|
||||
}
|
||||
xml->beginbranch("MODULATOR");
|
||||
xml->addpar("detune", VoicePar[nvoice].PFMDetune);
|
||||
xml->addpar("coarse_detune", VoicePar[nvoice].PFMCoarseDetune);
|
||||
xml->addpar("detune_type", VoicePar[nvoice].PFMDetuneType);
|
||||
|
||||
xml->addparbool("freq_envelope_enabled",
|
||||
VoicePar[nvoice].PFMFreqEnvelopeEnabled);
|
||||
if((VoicePar[nvoice].PFMFreqEnvelopeEnabled != 0) || (!xml->minimal)) {
|
||||
xml->beginbranch("FREQUENCY_ENVELOPE");
|
||||
VoicePar[nvoice].FMFreqEnvelope->add2XML(xml);
|
||||
xml->endbranch();
|
||||
}
|
||||
|
||||
xml->beginbranch("OSCIL");
|
||||
VoicePar[nvoice].FMSmp->add2XML(xml);
|
||||
xml->endbranch();
|
||||
|
||||
xml->endbranch();
|
||||
xml->endbranch();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ADnoteParameters::add2XML(XMLwrapper *xml)
|
||||
{
|
||||
xml->addparbool("stereo", GlobalPar.PStereo);
|
||||
|
||||
xml->beginbranch("AMPLITUDE_PARAMETERS");
|
||||
xml->addpar("volume", GlobalPar.PVolume);
|
||||
xml->addpar("panning", GlobalPar.PPanning);
|
||||
xml->addpar("velocity_sensing", GlobalPar.PAmpVelocityScaleFunction);
|
||||
xml->addpar("punch_strength", GlobalPar.PPunchStrength);
|
||||
xml->addpar("punch_time", GlobalPar.PPunchTime);
|
||||
xml->addpar("punch_stretch", GlobalPar.PPunchStretch);
|
||||
xml->addpar("punch_velocity_sensing", GlobalPar.PPunchVelocitySensing);
|
||||
xml->addpar("harmonic_randomness_grouping", GlobalPar.Hrandgrouping);
|
||||
|
||||
xml->beginbranch("AMPLITUDE_ENVELOPE");
|
||||
GlobalPar.AmpEnvelope->add2XML(xml);
|
||||
xml->endbranch();
|
||||
|
||||
xml->beginbranch("AMPLITUDE_LFO");
|
||||
GlobalPar.AmpLfo->add2XML(xml);
|
||||
xml->endbranch();
|
||||
xml->endbranch();
|
||||
|
||||
xml->beginbranch("FREQUENCY_PARAMETERS");
|
||||
xml->addpar("detune", GlobalPar.PDetune);
|
||||
|
||||
xml->addpar("coarse_detune", GlobalPar.PCoarseDetune);
|
||||
xml->addpar("detune_type", GlobalPar.PDetuneType);
|
||||
|
||||
xml->addpar("bandwidth", GlobalPar.PBandwidth);
|
||||
|
||||
xml->beginbranch("FREQUENCY_ENVELOPE");
|
||||
GlobalPar.FreqEnvelope->add2XML(xml);
|
||||
xml->endbranch();
|
||||
|
||||
xml->beginbranch("FREQUENCY_LFO");
|
||||
GlobalPar.FreqLfo->add2XML(xml);
|
||||
xml->endbranch();
|
||||
xml->endbranch();
|
||||
|
||||
|
||||
xml->beginbranch("FILTER_PARAMETERS");
|
||||
xml->addpar("velocity_sensing_amplitude", GlobalPar.PFilterVelocityScale);
|
||||
xml->addpar("velocity_sensing", GlobalPar.PFilterVelocityScaleFunction);
|
||||
|
||||
xml->beginbranch("FILTER");
|
||||
GlobalPar.GlobalFilter->add2XML(xml);
|
||||
xml->endbranch();
|
||||
|
||||
xml->beginbranch("FILTER_ENVELOPE");
|
||||
GlobalPar.FilterEnvelope->add2XML(xml);
|
||||
xml->endbranch();
|
||||
|
||||
xml->beginbranch("FILTER_LFO");
|
||||
GlobalPar.FilterLfo->add2XML(xml);
|
||||
xml->endbranch();
|
||||
xml->endbranch();
|
||||
|
||||
xml->beginbranch("RESONANCE");
|
||||
GlobalPar.Reson->add2XML(xml);
|
||||
xml->endbranch();
|
||||
|
||||
for(int nvoice = 0; nvoice < NUM_VOICES; nvoice++) {
|
||||
xml->beginbranch("VOICE", nvoice);
|
||||
add2XMLsection(xml, nvoice);
|
||||
xml->endbranch();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ADnoteParameters::getfromXML(XMLwrapper *xml)
|
||||
{
|
||||
GlobalPar.PStereo = xml->getparbool("stereo", GlobalPar.PStereo);
|
||||
|
||||
if(xml->enterbranch("AMPLITUDE_PARAMETERS")) {
|
||||
GlobalPar.PVolume = xml->getpar127("volume", GlobalPar.PVolume);
|
||||
GlobalPar.PPanning = xml->getpar127("panning", GlobalPar.PPanning);
|
||||
GlobalPar.PAmpVelocityScaleFunction = xml->getpar127(
|
||||
"velocity_sensing",
|
||||
GlobalPar.
|
||||
PAmpVelocityScaleFunction);
|
||||
|
||||
GlobalPar.PPunchStrength = xml->getpar127("punch_strength",
|
||||
GlobalPar.PPunchStrength);
|
||||
GlobalPar.PPunchTime = xml->getpar127("punch_time",
|
||||
GlobalPar.PPunchTime);
|
||||
GlobalPar.PPunchStretch = xml->getpar127("punch_stretch",
|
||||
GlobalPar.PPunchStretch);
|
||||
GlobalPar.PPunchVelocitySensing = xml->getpar127(
|
||||
"punch_velocity_sensing",
|
||||
GlobalPar.PPunchVelocitySensing);
|
||||
GlobalPar.Hrandgrouping = xml->getpar127(
|
||||
"harmonic_randomness_grouping",
|
||||
GlobalPar.Hrandgrouping);
|
||||
|
||||
if(xml->enterbranch("AMPLITUDE_ENVELOPE")) {
|
||||
GlobalPar.AmpEnvelope->getfromXML(xml);
|
||||
xml->exitbranch();
|
||||
}
|
||||
|
||||
if(xml->enterbranch("AMPLITUDE_LFO")) {
|
||||
GlobalPar.AmpLfo->getfromXML(xml);
|
||||
xml->exitbranch();
|
||||
}
|
||||
|
||||
xml->exitbranch();
|
||||
}
|
||||
|
||||
if(xml->enterbranch("FREQUENCY_PARAMETERS")) {
|
||||
GlobalPar.PDetune = xml->getpar("detune",
|
||||
GlobalPar.PDetune,
|
||||
0,
|
||||
16383);
|
||||
GlobalPar.PCoarseDetune = xml->getpar("coarse_detune",
|
||||
GlobalPar.PCoarseDetune,
|
||||
0,
|
||||
16383);
|
||||
GlobalPar.PDetuneType = xml->getpar127("detune_type",
|
||||
GlobalPar.PDetuneType);
|
||||
|
||||
GlobalPar.PBandwidth = xml->getpar127("bandwidth",
|
||||
GlobalPar.PBandwidth);
|
||||
|
||||
xml->enterbranch("FREQUENCY_ENVELOPE");
|
||||
GlobalPar.FreqEnvelope->getfromXML(xml);
|
||||
xml->exitbranch();
|
||||
|
||||
xml->enterbranch("FREQUENCY_LFO");
|
||||
GlobalPar.FreqLfo->getfromXML(xml);
|
||||
xml->exitbranch();
|
||||
|
||||
xml->exitbranch();
|
||||
}
|
||||
|
||||
|
||||
if(xml->enterbranch("FILTER_PARAMETERS")) {
|
||||
GlobalPar.PFilterVelocityScale = xml->getpar127(
|
||||
"velocity_sensing_amplitude",
|
||||
GlobalPar.PFilterVelocityScale);
|
||||
GlobalPar.PFilterVelocityScaleFunction = xml->getpar127(
|
||||
"velocity_sensing",
|
||||
GlobalPar.PFilterVelocityScaleFunction);
|
||||
|
||||
xml->enterbranch("FILTER");
|
||||
GlobalPar.GlobalFilter->getfromXML(xml);
|
||||
xml->exitbranch();
|
||||
|
||||
xml->enterbranch("FILTER_ENVELOPE");
|
||||
GlobalPar.FilterEnvelope->getfromXML(xml);
|
||||
xml->exitbranch();
|
||||
|
||||
xml->enterbranch("FILTER_LFO");
|
||||
GlobalPar.FilterLfo->getfromXML(xml);
|
||||
xml->exitbranch();
|
||||
xml->exitbranch();
|
||||
}
|
||||
|
||||
if(xml->enterbranch("RESONANCE")) {
|
||||
GlobalPar.Reson->getfromXML(xml);
|
||||
xml->exitbranch();
|
||||
}
|
||||
|
||||
for(int nvoice = 0; nvoice < NUM_VOICES; nvoice++) {
|
||||
VoicePar[nvoice].Enabled = 0;
|
||||
if(xml->enterbranch("VOICE", nvoice) == 0)
|
||||
continue;
|
||||
getfromXMLsection(xml, nvoice);
|
||||
xml->exitbranch();
|
||||
}
|
||||
}
|
||||
|
||||
void ADnoteParameters::getfromXMLsection(XMLwrapper *xml, int n)
|
||||
{
|
||||
int nvoice = n;
|
||||
if(nvoice >= NUM_VOICES)
|
||||
return;
|
||||
|
||||
VoicePar[nvoice].Enabled = xml->getparbool("enabled", 0);
|
||||
|
||||
VoicePar[nvoice].Unison_size =
|
||||
xml->getpar127("unison_size", VoicePar[nvoice].Unison_size);
|
||||
VoicePar[nvoice].Unison_frequency_spread = xml->getpar127(
|
||||
"unison_frequency_spread",
|
||||
VoicePar[nvoice].Unison_frequency_spread);
|
||||
VoicePar[nvoice].Unison_stereo_spread = xml->getpar127(
|
||||
"unison_stereo_spread",
|
||||
VoicePar[nvoice].Unison_stereo_spread);
|
||||
VoicePar[nvoice].Unison_vibratto = xml->getpar127(
|
||||
"unison_vibratto",
|
||||
VoicePar[nvoice].
|
||||
Unison_vibratto);
|
||||
VoicePar[nvoice].Unison_vibratto_speed = xml->getpar127(
|
||||
"unison_vibratto_speed",
|
||||
VoicePar[nvoice].Unison_vibratto_speed);
|
||||
VoicePar[nvoice].Unison_invert_phase = xml->getpar127(
|
||||
"unison_invert_phase",
|
||||
VoicePar[nvoice].Unison_invert_phase);
|
||||
|
||||
VoicePar[nvoice].Type = xml->getpar127("type",
|
||||
VoicePar[nvoice].Type);
|
||||
VoicePar[nvoice].PDelay = xml->getpar127("delay",
|
||||
VoicePar[nvoice].PDelay);
|
||||
VoicePar[nvoice].Presonance =
|
||||
xml->getparbool("resonance", VoicePar[nvoice].Presonance);
|
||||
|
||||
VoicePar[nvoice].Pextoscil = xml->getpar("ext_oscil",
|
||||
-1,
|
||||
-1,
|
||||
nvoice - 1);
|
||||
VoicePar[nvoice].PextFMoscil = xml->getpar("ext_fm_oscil",
|
||||
-1,
|
||||
-1,
|
||||
nvoice - 1);
|
||||
|
||||
VoicePar[nvoice].Poscilphase =
|
||||
xml->getpar127("oscil_phase", VoicePar[nvoice].Poscilphase);
|
||||
VoicePar[nvoice].PFMoscilphase = xml->getpar127(
|
||||
"oscil_fm_phase",
|
||||
VoicePar[nvoice].
|
||||
PFMoscilphase);
|
||||
|
||||
VoicePar[nvoice].PFilterEnabled = xml->getparbool(
|
||||
"filter_enabled",
|
||||
VoicePar[nvoice].
|
||||
PFilterEnabled);
|
||||
VoicePar[nvoice].Pfilterbypass = xml->getparbool(
|
||||
"filter_bypass",
|
||||
VoicePar[nvoice].
|
||||
Pfilterbypass);
|
||||
|
||||
VoicePar[nvoice].PFMEnabled =
|
||||
xml->getpar127("fm_enabled", VoicePar[nvoice].PFMEnabled);
|
||||
|
||||
if(xml->enterbranch("OSCIL")) {
|
||||
VoicePar[nvoice].OscilSmp->getfromXML(xml);
|
||||
xml->exitbranch();
|
||||
}
|
||||
|
||||
|
||||
if(xml->enterbranch("AMPLITUDE_PARAMETERS")) {
|
||||
VoicePar[nvoice].PPanning =
|
||||
xml->getpar127("panning", VoicePar[nvoice].PPanning);
|
||||
VoicePar[nvoice].PVolume =
|
||||
xml->getpar127("volume", VoicePar[nvoice].PVolume);
|
||||
VoicePar[nvoice].PVolumeminus = xml->getparbool(
|
||||
"volume_minus",
|
||||
VoicePar[nvoice].
|
||||
PVolumeminus);
|
||||
VoicePar[nvoice].PAmpVelocityScaleFunction = xml->getpar127(
|
||||
"velocity_sensing",
|
||||
VoicePar[nvoice].PAmpVelocityScaleFunction);
|
||||
|
||||
VoicePar[nvoice].PAmpEnvelopeEnabled = xml->getparbool(
|
||||
"amp_envelope_enabled",
|
||||
VoicePar[nvoice].PAmpEnvelopeEnabled);
|
||||
if(xml->enterbranch("AMPLITUDE_ENVELOPE")) {
|
||||
VoicePar[nvoice].AmpEnvelope->getfromXML(xml);
|
||||
xml->exitbranch();
|
||||
}
|
||||
|
||||
VoicePar[nvoice].PAmpLfoEnabled = xml->getparbool(
|
||||
"amp_lfo_enabled",
|
||||
VoicePar[nvoice].
|
||||
PAmpLfoEnabled);
|
||||
if(xml->enterbranch("AMPLITUDE_LFO")) {
|
||||
VoicePar[nvoice].AmpLfo->getfromXML(xml);
|
||||
xml->exitbranch();
|
||||
}
|
||||
xml->exitbranch();
|
||||
}
|
||||
|
||||
if(xml->enterbranch("FREQUENCY_PARAMETERS")) {
|
||||
VoicePar[nvoice].Pfixedfreq =
|
||||
xml->getparbool("fixed_freq", VoicePar[nvoice].Pfixedfreq);
|
||||
VoicePar[nvoice].PfixedfreqET = xml->getpar127(
|
||||
"fixed_freq_et",
|
||||
VoicePar[nvoice].
|
||||
PfixedfreqET);
|
||||
|
||||
|
||||
VoicePar[nvoice].PDetune = xml->getpar("detune",
|
||||
VoicePar[nvoice].PDetune,
|
||||
0,
|
||||
16383);
|
||||
|
||||
VoicePar[nvoice].PCoarseDetune =
|
||||
xml->getpar("coarse_detune",
|
||||
VoicePar[nvoice].PCoarseDetune,
|
||||
0,
|
||||
16383);
|
||||
VoicePar[nvoice].PDetuneType = xml->getpar127(
|
||||
"detune_type",
|
||||
VoicePar[nvoice].
|
||||
PDetuneType);
|
||||
|
||||
VoicePar[nvoice].PFreqEnvelopeEnabled = xml->getparbool(
|
||||
"freq_envelope_enabled",
|
||||
VoicePar[nvoice].PFreqEnvelopeEnabled);
|
||||
if(xml->enterbranch("FREQUENCY_ENVELOPE")) {
|
||||
VoicePar[nvoice].FreqEnvelope->getfromXML(xml);
|
||||
xml->exitbranch();
|
||||
}
|
||||
|
||||
VoicePar[nvoice].PFreqLfoEnabled = xml->getparbool(
|
||||
"freq_lfo_enabled",
|
||||
VoicePar[nvoice].
|
||||
PFreqLfoEnabled);
|
||||
if(xml->enterbranch("FREQUENCY_LFO")) {
|
||||
VoicePar[nvoice].FreqLfo->getfromXML(xml);
|
||||
xml->exitbranch();
|
||||
}
|
||||
xml->exitbranch();
|
||||
}
|
||||
|
||||
if(xml->enterbranch("FILTER_PARAMETERS")) {
|
||||
if(xml->enterbranch("FILTER")) {
|
||||
VoicePar[nvoice].VoiceFilter->getfromXML(xml);
|
||||
xml->exitbranch();
|
||||
}
|
||||
|
||||
VoicePar[nvoice].PFilterEnvelopeEnabled = xml->getparbool(
|
||||
"filter_envelope_enabled",
|
||||
VoicePar[nvoice].PFilterEnvelopeEnabled);
|
||||
if(xml->enterbranch("FILTER_ENVELOPE")) {
|
||||
VoicePar[nvoice].FilterEnvelope->getfromXML(xml);
|
||||
xml->exitbranch();
|
||||
}
|
||||
|
||||
VoicePar[nvoice].PFilterLfoEnabled = xml->getparbool(
|
||||
"filter_lfo_enabled",
|
||||
VoicePar[nvoice].PFilterLfoEnabled);
|
||||
if(xml->enterbranch("FILTER_LFO")) {
|
||||
VoicePar[nvoice].FilterLfo->getfromXML(xml);
|
||||
xml->exitbranch();
|
||||
}
|
||||
xml->exitbranch();
|
||||
}
|
||||
|
||||
if(xml->enterbranch("FM_PARAMETERS")) {
|
||||
VoicePar[nvoice].PFMVoice =
|
||||
xml->getpar("input_voice",
|
||||
VoicePar[nvoice].PFMVoice,
|
||||
-1,
|
||||
nvoice - 1);
|
||||
|
||||
VoicePar[nvoice].PFMVolume =
|
||||
xml->getpar127("volume", VoicePar[nvoice].PFMVolume);
|
||||
VoicePar[nvoice].PFMVolumeDamp = xml->getpar127(
|
||||
"volume_damp",
|
||||
VoicePar[nvoice].
|
||||
PFMVolumeDamp);
|
||||
VoicePar[nvoice].PFMVelocityScaleFunction = xml->getpar127(
|
||||
"velocity_sensing",
|
||||
VoicePar[nvoice].PFMVelocityScaleFunction);
|
||||
|
||||
VoicePar[nvoice].PFMAmpEnvelopeEnabled = xml->getparbool(
|
||||
"amp_envelope_enabled",
|
||||
VoicePar[nvoice].PFMAmpEnvelopeEnabled);
|
||||
if(xml->enterbranch("AMPLITUDE_ENVELOPE")) {
|
||||
VoicePar[nvoice].FMAmpEnvelope->getfromXML(xml);
|
||||
xml->exitbranch();
|
||||
}
|
||||
|
||||
if(xml->enterbranch("MODULATOR")) {
|
||||
VoicePar[nvoice].PFMDetune =
|
||||
xml->getpar("detune", VoicePar[nvoice].PFMDetune, 0, 16383);
|
||||
VoicePar[nvoice].PFMCoarseDetune = xml->getpar(
|
||||
"coarse_detune",
|
||||
VoicePar[nvoice].
|
||||
PFMCoarseDetune,
|
||||
0,
|
||||
16383);
|
||||
VoicePar[nvoice].PFMDetuneType = xml->getpar127(
|
||||
"detune_type",
|
||||
VoicePar[nvoice].
|
||||
PFMDetuneType);
|
||||
|
||||
VoicePar[nvoice].PFMFreqEnvelopeEnabled = xml->getparbool(
|
||||
"freq_envelope_enabled",
|
||||
VoicePar[nvoice].PFMFreqEnvelopeEnabled);
|
||||
if(xml->enterbranch("FREQUENCY_ENVELOPE")) {
|
||||
VoicePar[nvoice].FMFreqEnvelope->getfromXML(xml);
|
||||
xml->exitbranch();
|
||||
}
|
||||
|
||||
if(xml->enterbranch("OSCIL")) {
|
||||
VoicePar[nvoice].FMSmp->getfromXML(xml);
|
||||
xml->exitbranch();
|
||||
}
|
||||
|
||||
xml->exitbranch();
|
||||
}
|
||||
xml->exitbranch();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,307 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
ADnoteParameters.h - Parameters for ADnote (ADsynth)
|
||||
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 AD_NOTE_PARAMETERS_H
|
||||
#define AD_NOTE_PARAMETERS_H
|
||||
|
||||
|
||||
#include "../globals.h"
|
||||
#include "EnvelopeParams.h"
|
||||
#include "LFOParams.h"
|
||||
#include "FilterParams.h"
|
||||
#include "../Synth/OscilGen.h"
|
||||
#include "../Synth/Resonance.h"
|
||||
#include "../Misc/Util.h"
|
||||
#include "../Misc/XMLwrapper.h"
|
||||
#include "../DSP/FFTwrapper.h"
|
||||
#include "PresetsArray.h"
|
||||
|
||||
enum FMTYPE {
|
||||
NONE, MORPH, RING_MOD, PHASE_MOD, FREQ_MOD, PITCH_MOD
|
||||
};
|
||||
extern int ADnote_unison_sizes[];
|
||||
|
||||
/*****************************************************************/
|
||||
/* GLOBAL PARAMETERS */
|
||||
/*****************************************************************/
|
||||
|
||||
struct ADnoteGlobalParam {
|
||||
/* The instrument type - MONO/STEREO
|
||||
If the mode is MONO, the panning of voices are not used
|
||||
Stereo=1, Mono=0. */
|
||||
|
||||
unsigned char PStereo;
|
||||
|
||||
|
||||
/******************************************
|
||||
* FREQUENCY GLOBAL PARAMETERS *
|
||||
******************************************/
|
||||
unsigned short int PDetune; //fine detune
|
||||
unsigned short int PCoarseDetune; //coarse detune+octave
|
||||
unsigned char PDetuneType; //detune type
|
||||
|
||||
unsigned char PBandwidth; //how much the relative fine detunes of the voices are changed
|
||||
|
||||
EnvelopeParams *FreqEnvelope; //Frequency Envelope
|
||||
|
||||
LFOParams *FreqLfo; //Frequency LFO
|
||||
|
||||
/********************************************
|
||||
* AMPLITUDE GLOBAL PARAMETERS *
|
||||
********************************************/
|
||||
|
||||
/* Panning - 0 - random
|
||||
1 - left
|
||||
64 - center
|
||||
127 - right */
|
||||
unsigned char PPanning;
|
||||
|
||||
unsigned char PVolume;
|
||||
|
||||
unsigned char PAmpVelocityScaleFunction;
|
||||
|
||||
EnvelopeParams *AmpEnvelope;
|
||||
|
||||
LFOParams *AmpLfo;
|
||||
|
||||
unsigned char PPunchStrength, PPunchTime, PPunchStretch,
|
||||
PPunchVelocitySensing;
|
||||
|
||||
/******************************************
|
||||
* FILTER GLOBAL PARAMETERS *
|
||||
******************************************/
|
||||
FilterParams *GlobalFilter;
|
||||
|
||||
// filter velocity sensing
|
||||
unsigned char PFilterVelocityScale;
|
||||
|
||||
// filter velocity sensing
|
||||
unsigned char PFilterVelocityScaleFunction;
|
||||
|
||||
EnvelopeParams *FilterEnvelope;
|
||||
|
||||
LFOParams *FilterLfo;
|
||||
|
||||
// RESONANCE
|
||||
Resonance *Reson;
|
||||
|
||||
//how the randomness is applied to the harmonics on more voices using the same oscillator
|
||||
unsigned char Hrandgrouping;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/***********************************************************/
|
||||
/* VOICE PARAMETERS */
|
||||
/***********************************************************/
|
||||
struct ADnoteVoiceParam {
|
||||
/** If the voice is enabled */
|
||||
unsigned char Enabled;
|
||||
|
||||
/** How many subvoices are used in this voice */
|
||||
unsigned char Unison_size;
|
||||
|
||||
/** How subvoices are spread */
|
||||
unsigned char Unison_frequency_spread;
|
||||
|
||||
/** Stereo spread of the subvoices*/
|
||||
unsigned char Unison_stereo_spread;
|
||||
|
||||
/** Vibratto of the subvoices (which makes the unison more "natural")*/
|
||||
unsigned char Unison_vibratto;
|
||||
|
||||
/** Medium speed of the vibratto of the subvoices*/
|
||||
unsigned char Unison_vibratto_speed;
|
||||
|
||||
/** Unison invert phase */
|
||||
unsigned char Unison_invert_phase; //0=none,1=random,2=50%,3=33%,4=25%
|
||||
|
||||
/** Type of the voice (0=Sound,1=Noise)*/
|
||||
unsigned char Type;
|
||||
|
||||
/** Voice Delay */
|
||||
unsigned char PDelay;
|
||||
|
||||
/** If the resonance is enabled for this voice */
|
||||
unsigned char Presonance;
|
||||
|
||||
// What external oscil should I use, -1 for internal OscilSmp&FMSmp
|
||||
short int Pextoscil, PextFMoscil;
|
||||
// it is not allowed that the externoscil,externFMoscil => current voice
|
||||
|
||||
// oscillator phases
|
||||
unsigned char Poscilphase, PFMoscilphase;
|
||||
|
||||
// filter bypass
|
||||
unsigned char Pfilterbypass;
|
||||
|
||||
/** Voice oscillator */
|
||||
OscilGen *OscilSmp;
|
||||
|
||||
/**********************************
|
||||
* FREQUENCY PARAMETERS *
|
||||
**********************************/
|
||||
|
||||
/** If the base frequency is fixed to 440 Hz*/
|
||||
unsigned char Pfixedfreq;
|
||||
|
||||
/* Equal temperate (this is used only if the Pfixedfreq is enabled)
|
||||
If this parameter is 0, the frequency is fixed (to 440 Hz);
|
||||
if this parameter is 64, 1 MIDI halftone -> 1 frequency halftone */
|
||||
unsigned char PfixedfreqET;
|
||||
|
||||
/** Fine detune */
|
||||
unsigned short int PDetune;
|
||||
|
||||
/** Coarse detune + octave */
|
||||
unsigned short int PCoarseDetune;
|
||||
|
||||
/** Detune type */
|
||||
unsigned char PDetuneType;
|
||||
|
||||
/* Frequency Envelope */
|
||||
unsigned char PFreqEnvelopeEnabled;
|
||||
EnvelopeParams *FreqEnvelope;
|
||||
|
||||
/* Frequency LFO */
|
||||
unsigned char PFreqLfoEnabled;
|
||||
LFOParams *FreqLfo;
|
||||
|
||||
|
||||
/***************************
|
||||
* AMPLITUDE PARAMETERS *
|
||||
***************************/
|
||||
|
||||
/* Panning 0 - random
|
||||
1 - left
|
||||
64 - center
|
||||
127 - right
|
||||
The Panning is ignored if the instrument is mono */
|
||||
unsigned char PPanning;
|
||||
|
||||
/* Voice Volume */
|
||||
unsigned char PVolume;
|
||||
|
||||
/* If the Volume negative */
|
||||
unsigned char PVolumeminus;
|
||||
|
||||
/* Velocity sensing */
|
||||
unsigned char PAmpVelocityScaleFunction;
|
||||
|
||||
/* Amplitude Envelope */
|
||||
unsigned char PAmpEnvelopeEnabled;
|
||||
EnvelopeParams *AmpEnvelope;
|
||||
|
||||
/* Amplitude LFO */
|
||||
unsigned char PAmpLfoEnabled;
|
||||
LFOParams *AmpLfo;
|
||||
|
||||
|
||||
|
||||
/*************************
|
||||
* FILTER PARAMETERS *
|
||||
*************************/
|
||||
|
||||
/* Voice Filter */
|
||||
unsigned char PFilterEnabled;
|
||||
FilterParams *VoiceFilter;
|
||||
|
||||
/* Filter Envelope */
|
||||
unsigned char PFilterEnvelopeEnabled;
|
||||
EnvelopeParams *FilterEnvelope;
|
||||
|
||||
/* LFO Envelope */
|
||||
unsigned char PFilterLfoEnabled;
|
||||
LFOParams *FilterLfo;
|
||||
|
||||
/****************************
|
||||
* MODULLATOR PARAMETERS *
|
||||
****************************/
|
||||
|
||||
/* Modullator Parameters (0=off,1=Morph,2=RM,3=PM,4=FM.. */
|
||||
unsigned char PFMEnabled;
|
||||
|
||||
/* Voice that I use as modullator instead of FMSmp.
|
||||
It is -1 if I use FMSmp(default).
|
||||
It maynot be equal or bigger than current voice */
|
||||
short int PFMVoice;
|
||||
|
||||
/* Modullator oscillator */
|
||||
OscilGen *FMSmp;
|
||||
|
||||
/* Modullator Volume */
|
||||
unsigned char PFMVolume;
|
||||
|
||||
/* Modullator damping at higher frequencies */
|
||||
unsigned char PFMVolumeDamp;
|
||||
|
||||
/* Modullator Velocity Sensing */
|
||||
unsigned char PFMVelocityScaleFunction;
|
||||
|
||||
/* Fine Detune of the Modullator*/
|
||||
unsigned short int PFMDetune;
|
||||
|
||||
/* Coarse Detune of the Modullator */
|
||||
unsigned short int PFMCoarseDetune;
|
||||
|
||||
/* The detune type */
|
||||
unsigned char PFMDetuneType;
|
||||
|
||||
/* Frequency Envelope of the Modullator */
|
||||
unsigned char PFMFreqEnvelopeEnabled;
|
||||
EnvelopeParams *FMFreqEnvelope;
|
||||
|
||||
/* Frequency Envelope of the Modullator */
|
||||
unsigned char PFMAmpEnvelopeEnabled;
|
||||
EnvelopeParams *FMAmpEnvelope;
|
||||
};
|
||||
|
||||
class ADnoteParameters : public PresetsArray
|
||||
{
|
||||
public:
|
||||
ADnoteParameters(FFTwrapper *fft_);
|
||||
~ADnoteParameters();
|
||||
|
||||
ADnoteGlobalParam GlobalPar;
|
||||
ADnoteVoiceParam VoicePar[NUM_VOICES];
|
||||
|
||||
void defaults();
|
||||
void add2XML(XMLwrapper *xml);
|
||||
void getfromXML(XMLwrapper *xml);
|
||||
|
||||
REALTYPE getBandwidthDetuneMultiplier();
|
||||
REALTYPE getUnisonFrequencySpreadCents(int nvoice);
|
||||
int get_unison_size_index(int nvoice);
|
||||
void set_unison_size_index(int nvoice, int index);
|
||||
private:
|
||||
void defaults(int n); //n is the nvoice
|
||||
|
||||
void EnableVoice(int nvoice);
|
||||
void KillVoice(int nvoice);
|
||||
FFTwrapper *fft;
|
||||
|
||||
void add2XMLsection(XMLwrapper *xml, int n);
|
||||
void getfromXMLsection(XMLwrapper *xml, int n);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
set(zynaddsubfx_params_SRCS
|
||||
ADnoteParameters.cpp
|
||||
Controller.cpp
|
||||
EnvelopeParams.cpp
|
||||
FilterParams.cpp
|
||||
LFOParams.cpp
|
||||
PADnoteParameters.cpp
|
||||
Presets.cpp
|
||||
PresetsArray.cpp
|
||||
PresetsStore.cpp
|
||||
SUBnoteParameters.cpp
|
||||
|
||||
)
|
||||
|
||||
add_library(zynaddsubfx_params STATIC
|
||||
${zynaddsubfx_params_SRCS}
|
||||
)
|
||||
|
||||
target_link_libraries(zynaddsubfx_params)# ${ASOUND_LIBRARY})
|
||||
@@ -1,415 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
Controller.cpp - (Midi) Controllers 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
|
||||
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 "Controller.h"
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
Controller::Controller()
|
||||
{
|
||||
defaults();
|
||||
resetall();
|
||||
}
|
||||
|
||||
Controller::~Controller()
|
||||
{}
|
||||
|
||||
void Controller::defaults()
|
||||
{
|
||||
setpitchwheelbendrange(100); //2 halftones
|
||||
expression.receive = 1;
|
||||
panning.depth = 64;
|
||||
filtercutoff.depth = 64;
|
||||
filterq.depth = 64;
|
||||
bandwidth.depth = 64;
|
||||
bandwidth.exponential = 0;
|
||||
modwheel.depth = 80;
|
||||
modwheel.exponential = 0;
|
||||
fmamp.receive = 1;
|
||||
volume.receive = 1;
|
||||
sustain.receive = 1;
|
||||
NRPN.receive = 1;
|
||||
|
||||
portamento.portamento = 0;
|
||||
portamento.used = 0;
|
||||
portamento.proportional = 0;
|
||||
portamento.propRate = 80;
|
||||
portamento.propDepth = 90;
|
||||
portamento.receive = 1;
|
||||
portamento.time = 64;
|
||||
portamento.updowntimestretch = 64;
|
||||
portamento.pitchthresh = 3;
|
||||
portamento.pitchthreshtype = 1;
|
||||
portamento.noteusing = -1;
|
||||
resonancecenter.depth = 64;
|
||||
resonancebandwidth.depth = 64;
|
||||
|
||||
initportamento(440.0, 440.0, false); // Now has a third argument
|
||||
setportamento(0);
|
||||
}
|
||||
|
||||
void Controller::resetall()
|
||||
{
|
||||
setpitchwheel(0); //center
|
||||
setexpression(127);
|
||||
setpanning(64);
|
||||
setfiltercutoff(64);
|
||||
setfilterq(64);
|
||||
setbandwidth(64);
|
||||
setmodwheel(64);
|
||||
setfmamp(127);
|
||||
setvolume(127);
|
||||
setsustain(0);
|
||||
setresonancecenter(64);
|
||||
setresonancebw(64);
|
||||
|
||||
//reset the NRPN
|
||||
NRPN.parhi = -1;
|
||||
NRPN.parlo = -1;
|
||||
NRPN.valhi = -1;
|
||||
NRPN.vallo = -1;
|
||||
}
|
||||
|
||||
void Controller::setpitchwheel(int value)
|
||||
{
|
||||
pitchwheel.data = value;
|
||||
REALTYPE cents = value / 8192.0;
|
||||
cents *= pitchwheel.bendrange;
|
||||
pitchwheel.relfreq = pow(2, cents / 1200.0);
|
||||
//fprintf(stderr,"%ld %ld -> %.3f\n",pitchwheel.bendrange,pitchwheel.data,pitchwheel.relfreq);fflush(stderr);
|
||||
}
|
||||
|
||||
void Controller::setpitchwheelbendrange(unsigned short int value)
|
||||
{
|
||||
pitchwheel.bendrange = value;
|
||||
}
|
||||
|
||||
void Controller::setexpression(int value)
|
||||
{
|
||||
expression.data = value;
|
||||
if(expression.receive != 0)
|
||||
expression.relvolume = value / 127.0;
|
||||
else
|
||||
expression.relvolume = 1.0;
|
||||
}
|
||||
|
||||
void Controller::setpanning(int value)
|
||||
{
|
||||
panning.data = value;
|
||||
panning.pan = (value / 128.0 - 0.5) * (panning.depth / 64.0);
|
||||
}
|
||||
|
||||
void Controller::setfiltercutoff(int value)
|
||||
{
|
||||
filtercutoff.data = value;
|
||||
filtercutoff.relfreq =
|
||||
(value - 64.0) * filtercutoff.depth / 4096.0 * 3.321928; //3.3219..=ln2(10)
|
||||
}
|
||||
|
||||
void Controller::setfilterq(int value)
|
||||
{
|
||||
filterq.data = value;
|
||||
filterq.relq = pow(30.0, (value - 64.0) / 64.0 * (filterq.depth / 64.0));
|
||||
}
|
||||
|
||||
void Controller::setbandwidth(int value)
|
||||
{
|
||||
bandwidth.data = value;
|
||||
if(bandwidth.exponential == 0) {
|
||||
REALTYPE tmp = pow(25.0, pow(bandwidth.depth / 127.0, 1.5)) - 1.0;
|
||||
if((value < 64) && (bandwidth.depth >= 64))
|
||||
tmp = 1.0;
|
||||
bandwidth.relbw = (value / 64.0 - 1.0) * tmp + 1.0;
|
||||
if(bandwidth.relbw < 0.01)
|
||||
bandwidth.relbw = 0.01;
|
||||
}
|
||||
else
|
||||
bandwidth.relbw =
|
||||
pow(25.0, (value - 64.0) / 64.0 * (bandwidth.depth / 64.0));
|
||||
;
|
||||
}
|
||||
|
||||
void Controller::setmodwheel(int value)
|
||||
{
|
||||
modwheel.data = value;
|
||||
if(modwheel.exponential == 0) {
|
||||
REALTYPE tmp = pow(25.0, pow(modwheel.depth / 127.0, 1.5) * 2.0) / 25.0;
|
||||
if((value < 64) && (modwheel.depth >= 64))
|
||||
tmp = 1.0;
|
||||
modwheel.relmod = (value / 64.0 - 1.0) * tmp + 1.0;
|
||||
if(modwheel.relmod < 0.0)
|
||||
modwheel.relmod = 0.0;
|
||||
}
|
||||
else
|
||||
modwheel.relmod =
|
||||
pow(25.0, (value - 64.0) / 64.0 * (modwheel.depth / 80.0));
|
||||
}
|
||||
|
||||
void Controller::setfmamp(int value)
|
||||
{
|
||||
fmamp.data = value;
|
||||
fmamp.relamp = value / 127.0;
|
||||
if(fmamp.receive != 0)
|
||||
fmamp.relamp = value / 127.0;
|
||||
else
|
||||
fmamp.relamp = 1.0;
|
||||
}
|
||||
|
||||
void Controller::setvolume(int value)
|
||||
{
|
||||
volume.data = value;
|
||||
if(volume.receive != 0)
|
||||
volume.volume = pow(0.1, (127 - value) / 127.0 * 2.0);
|
||||
else
|
||||
volume.volume = 1.0;
|
||||
}
|
||||
|
||||
void Controller::setsustain(int value)
|
||||
{
|
||||
sustain.data = value;
|
||||
if(sustain.receive != 0)
|
||||
sustain.sustain = ((value < 64) ? 0 : 1);
|
||||
else
|
||||
sustain.sustain = 0;
|
||||
}
|
||||
|
||||
void Controller::setportamento(int value)
|
||||
{
|
||||
portamento.data = value;
|
||||
if(portamento.receive != 0)
|
||||
portamento.portamento = ((value < 64) ? 0 : 1);
|
||||
}
|
||||
|
||||
int Controller::initportamento(REALTYPE oldfreq,
|
||||
REALTYPE newfreq,
|
||||
bool legatoflag)
|
||||
{
|
||||
portamento.x = 0.0;
|
||||
|
||||
if(legatoflag) { // Legato in progress
|
||||
if(portamento.portamento == 0)
|
||||
return 0;
|
||||
}
|
||||
else // No legato, do the original if...return
|
||||
if((portamento.used != 0) || (portamento.portamento == 0))
|
||||
return 0;
|
||||
;
|
||||
|
||||
REALTYPE portamentotime = pow(100.0, portamento.time / 127.0) / 50.0; //portamento time in seconds
|
||||
|
||||
if(portamento.proportional) {
|
||||
//If there is a min(float,float) and a max(float,float) then they
|
||||
//could be used here
|
||||
//Linear functors could also make this nicer
|
||||
if(oldfreq > newfreq) //2 is the center of propRate
|
||||
portamentotime *=
|
||||
pow(oldfreq / newfreq / (portamento.propRate / 127.0 * 3 + .05),
|
||||
(portamento.propDepth / 127.0 * 1.6 + .2));
|
||||
else //1 is the center of propDepth
|
||||
portamentotime *=
|
||||
pow(newfreq / oldfreq / (portamento.propRate / 127.0 * 3 + .05),
|
||||
(portamento.propDepth / 127.0 * 1.6 + .2));
|
||||
}
|
||||
|
||||
if((portamento.updowntimestretch >= 64) && (newfreq < oldfreq)) {
|
||||
if(portamento.updowntimestretch == 127)
|
||||
return 0;
|
||||
portamentotime *= pow(0.1, (portamento.updowntimestretch - 64) / 63.0);
|
||||
}
|
||||
if((portamento.updowntimestretch < 64) && (newfreq > oldfreq)) {
|
||||
if(portamento.updowntimestretch == 0)
|
||||
return 0;
|
||||
portamentotime *= pow(0.1, (64.0 - portamento.updowntimestretch) / 64.0);
|
||||
}
|
||||
|
||||
//printf("%f->%f : Time %f\n",oldfreq,newfreq,portamentotime);
|
||||
|
||||
portamento.dx = SOUND_BUFFER_SIZE / (portamentotime * SAMPLE_RATE);
|
||||
portamento.origfreqrap = oldfreq / newfreq;
|
||||
|
||||
REALTYPE tmprap = ((portamento.origfreqrap > 1.0) ?
|
||||
(portamento.origfreqrap) :
|
||||
(1.0 / portamento.origfreqrap));
|
||||
|
||||
REALTYPE thresholdrap = pow(2.0, portamento.pitchthresh / 12.0);
|
||||
if((portamento.pitchthreshtype == 0) && (tmprap - 0.00001 > thresholdrap))
|
||||
return 0;
|
||||
if((portamento.pitchthreshtype == 1) && (tmprap + 0.00001 < thresholdrap))
|
||||
return 0;
|
||||
|
||||
portamento.used = 1;
|
||||
portamento.freqrap = portamento.origfreqrap;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Controller::updateportamento()
|
||||
{
|
||||
if(portamento.used == 0)
|
||||
return;
|
||||
|
||||
portamento.x += portamento.dx;
|
||||
if(portamento.x > 1.0) {
|
||||
portamento.x = 1.0;
|
||||
portamento.used = 0;
|
||||
}
|
||||
portamento.freqrap =
|
||||
(1.0 - portamento.x) * portamento.origfreqrap + portamento.x;
|
||||
}
|
||||
|
||||
|
||||
void Controller::setresonancecenter(int value)
|
||||
{
|
||||
resonancecenter.data = value;
|
||||
resonancecenter.relcenter =
|
||||
pow(3.0, (value - 64.0) / 64.0 * (resonancecenter.depth / 64.0));
|
||||
}
|
||||
void Controller::setresonancebw(int value)
|
||||
{
|
||||
resonancebandwidth.data = value;
|
||||
resonancebandwidth.relbw =
|
||||
pow(1.5, (value - 64.0) / 64.0 * (resonancebandwidth.depth / 127.0));
|
||||
}
|
||||
|
||||
|
||||
//Returns 0 if there is NRPN or 1 if there is not
|
||||
int Controller::getnrpn(int *parhi, int *parlo, int *valhi, int *vallo)
|
||||
{
|
||||
if(NRPN.receive == 0)
|
||||
return 1;
|
||||
if((NRPN.parhi < 0) || (NRPN.parlo < 0) || (NRPN.valhi < 0)
|
||||
|| (NRPN.vallo < 0))
|
||||
return 1;
|
||||
|
||||
*parhi = NRPN.parhi;
|
||||
*parlo = NRPN.parlo;
|
||||
*valhi = NRPN.valhi;
|
||||
*vallo = NRPN.vallo;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void Controller::setparameternumber(unsigned int type, int value)
|
||||
{
|
||||
switch(type) {
|
||||
case C_nrpnhi:
|
||||
NRPN.parhi = value;
|
||||
NRPN.valhi = -1;
|
||||
NRPN.vallo = -1; //clear the values
|
||||
break;
|
||||
case C_nrpnlo:
|
||||
NRPN.parlo = value;
|
||||
NRPN.valhi = -1;
|
||||
NRPN.vallo = -1; //clear the values
|
||||
break;
|
||||
case C_dataentryhi:
|
||||
if((NRPN.parhi >= 0) && (NRPN.parlo >= 0))
|
||||
NRPN.valhi = value;
|
||||
break;
|
||||
case C_dataentrylo:
|
||||
if((NRPN.parhi >= 0) && (NRPN.parlo >= 0))
|
||||
NRPN.vallo = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Controller::add2XML(XMLwrapper *xml)
|
||||
{
|
||||
xml->addpar("pitchwheel_bendrange", pitchwheel.bendrange);
|
||||
|
||||
xml->addparbool("expression_receive", expression.receive);
|
||||
xml->addpar("panning_depth", panning.depth);
|
||||
xml->addpar("filter_cutoff_depth", filtercutoff.depth);
|
||||
xml->addpar("filter_q_depth", filterq.depth);
|
||||
xml->addpar("bandwidth_depth", bandwidth.depth);
|
||||
xml->addpar("mod_wheel_depth", modwheel.depth);
|
||||
xml->addparbool("mod_wheel_exponential", modwheel.exponential);
|
||||
xml->addparbool("fm_amp_receive", fmamp.receive);
|
||||
xml->addparbool("volume_receive", volume.receive);
|
||||
xml->addparbool("sustain_receive", sustain.receive);
|
||||
|
||||
xml->addparbool("portamento_receive", portamento.receive);
|
||||
xml->addpar("portamento_time", portamento.time);
|
||||
xml->addpar("portamento_pitchthresh", portamento.pitchthresh);
|
||||
xml->addpar("portamento_pitchthreshtype", portamento.pitchthreshtype);
|
||||
xml->addpar("portamento_portamento", portamento.portamento);
|
||||
xml->addpar("portamento_updowntimestretch", portamento.updowntimestretch);
|
||||
xml->addpar("portamento_proportional", portamento.proportional);
|
||||
xml->addpar("portamento_proprate", portamento.propRate);
|
||||
xml->addpar("portamento_propdepth", portamento.propDepth);
|
||||
|
||||
xml->addpar("resonance_center_depth", resonancecenter.depth);
|
||||
xml->addpar("resonance_bandwidth_depth", resonancebandwidth.depth);
|
||||
}
|
||||
|
||||
void Controller::getfromXML(XMLwrapper *xml)
|
||||
{
|
||||
pitchwheel.bendrange = xml->getpar("pitchwheel_bendrange",
|
||||
pitchwheel.bendrange,
|
||||
-6400,
|
||||
6400);
|
||||
|
||||
expression.receive = xml->getparbool("expression_receive",
|
||||
expression.receive);
|
||||
panning.depth = xml->getpar127("panning_depth", panning.depth);
|
||||
filtercutoff.depth = xml->getpar127("filter_cutoff_depth",
|
||||
filtercutoff.depth);
|
||||
filterq.depth = xml->getpar127("filter_q_depth", filterq.depth);
|
||||
bandwidth.depth = xml->getpar127("bandwidth_depth", bandwidth.depth);
|
||||
modwheel.depth = xml->getpar127("mod_wheel_depth", modwheel.depth);
|
||||
modwheel.exponential = xml->getparbool("mod_wheel_exponential",
|
||||
modwheel.exponential);
|
||||
fmamp.receive = xml->getparbool("fm_amp_receive",
|
||||
fmamp.receive);
|
||||
volume.receive = xml->getparbool("volume_receive",
|
||||
volume.receive);
|
||||
sustain.receive = xml->getparbool("sustain_receive",
|
||||
sustain.receive);
|
||||
|
||||
portamento.receive = xml->getparbool("portamento_receive",
|
||||
portamento.receive);
|
||||
portamento.time = xml->getpar127("portamento_time",
|
||||
portamento.time);
|
||||
portamento.pitchthresh = xml->getpar127("portamento_pitchthresh",
|
||||
portamento.pitchthresh);
|
||||
portamento.pitchthreshtype = xml->getpar127("portamento_pitchthreshtype",
|
||||
portamento.pitchthreshtype);
|
||||
portamento.portamento = xml->getpar127("portamento_portamento",
|
||||
portamento.portamento);
|
||||
portamento.updowntimestretch = xml->getpar127(
|
||||
"portamento_updowntimestretch",
|
||||
portamento.updowntimestretch);
|
||||
portamento.proportional = xml->getpar127("portamento_proportional",
|
||||
portamento.proportional);
|
||||
portamento.propRate = xml->getpar127("portamento_proprate",
|
||||
portamento.propRate);
|
||||
portamento.propDepth = xml->getpar127("portamento_propdepth",
|
||||
portamento.propDepth);
|
||||
|
||||
|
||||
resonancecenter.depth = xml->getpar127("resonance_center_depth",
|
||||
resonancecenter.depth);
|
||||
resonancebandwidth.depth = xml->getpar127("resonance_bandwidth_depth",
|
||||
resonancebandwidth.depth);
|
||||
}
|
||||
|
||||
@@ -1,221 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
Controller.h - (Midi) Controllers 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
|
||||
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 CONTROLLER_H
|
||||
#define CONTROLLER_H
|
||||
|
||||
#include "../globals.h"
|
||||
#include "../Misc/XMLwrapper.h"
|
||||
|
||||
/**(Midi) Controllers implementation*/
|
||||
class Controller
|
||||
{
|
||||
public:
|
||||
Controller();
|
||||
~Controller();
|
||||
void resetall();
|
||||
|
||||
void add2XML(XMLwrapper *xml);
|
||||
void defaults();
|
||||
void getfromXML(XMLwrapper *xml);
|
||||
|
||||
//Controllers functions
|
||||
void setpitchwheel(int value);
|
||||
void setpitchwheelbendrange(unsigned short int value);
|
||||
void setexpression(int value);
|
||||
void setpanning(int value);
|
||||
void setfiltercutoff(int value);
|
||||
void setfilterq(int value);
|
||||
void setbandwidth(int value);
|
||||
void setmodwheel(int value);
|
||||
void setfmamp(int value);
|
||||
void setvolume(int value);
|
||||
void setsustain(int value);
|
||||
/**Enable or disable portamento
|
||||
* @param value 0-127 MIDI value (greater than 64 enables)*/
|
||||
void setportamento(int value);
|
||||
void setresonancecenter(int value);
|
||||
void setresonancebw(int value);
|
||||
|
||||
|
||||
void setparameternumber(unsigned int type, int value); //used for RPN and NRPN's
|
||||
int getnrpn(int *parhi, int *parlo, int *valhi, int *vallo);
|
||||
|
||||
/**
|
||||
* Initialize a portamento
|
||||
*
|
||||
* @param oldfreq Starting frequency of the portamento (Hz)
|
||||
* @param newfreq Ending frequency of the portamento (Hz)
|
||||
* @param legatoflag true when legato is in progress, false otherwise
|
||||
* @returns 1 if properly initialized, 0 otherwise*/
|
||||
int initportamento(REALTYPE oldfreq, REALTYPE newfreq, bool legatoflag);
|
||||
/**Update portamento's freqrap to next value based upon dx*/
|
||||
void updateportamento();
|
||||
|
||||
// Controllers values
|
||||
struct { //Pitch Wheel
|
||||
int data;
|
||||
short int bendrange; //bendrange is in cents
|
||||
REALTYPE relfreq; //the relative frequency (default is 1.0)
|
||||
} pitchwheel;
|
||||
|
||||
struct { //Expression
|
||||
int data;
|
||||
REALTYPE relvolume;
|
||||
unsigned char receive;
|
||||
} expression;
|
||||
|
||||
struct { //Panning
|
||||
int data;
|
||||
REALTYPE pan;
|
||||
unsigned char depth;
|
||||
} panning;
|
||||
|
||||
|
||||
struct { //Filter cutoff
|
||||
int data;
|
||||
REALTYPE relfreq;
|
||||
unsigned char depth;
|
||||
} filtercutoff;
|
||||
|
||||
struct { //Filter Q
|
||||
int data;
|
||||
REALTYPE relq;
|
||||
unsigned char depth;
|
||||
} filterq;
|
||||
|
||||
struct { //Bandwidth
|
||||
int data;
|
||||
REALTYPE relbw;
|
||||
unsigned char depth;
|
||||
unsigned char exponential;
|
||||
} bandwidth;
|
||||
|
||||
struct { //Modulation Wheel
|
||||
int data;
|
||||
REALTYPE relmod;
|
||||
unsigned char depth;
|
||||
unsigned char exponential;
|
||||
} modwheel;
|
||||
|
||||
struct { //FM amplitude
|
||||
int data;
|
||||
REALTYPE relamp;
|
||||
unsigned char receive;
|
||||
} fmamp;
|
||||
|
||||
struct { //Volume
|
||||
int data;
|
||||
REALTYPE volume;
|
||||
unsigned char receive;
|
||||
} volume;
|
||||
|
||||
struct { //Sustain
|
||||
int data, sustain;
|
||||
unsigned char receive;
|
||||
} sustain;
|
||||
|
||||
struct { /**<Portamento*/
|
||||
//parameters
|
||||
int data;
|
||||
unsigned char portamento;
|
||||
/**Whether the portamento midi events are received or not*/
|
||||
unsigned char receive;
|
||||
/** The time that it takes for the portamento to complete
|
||||
*
|
||||
* Translates in an expontal fashion to 0 Seconds to 1.93 Seconds
|
||||
* of completion time*/
|
||||
unsigned char time;
|
||||
/**If the portamento is proportinal to the distance spanned
|
||||
*
|
||||
* 0 - constant time(default)
|
||||
* 1 - proportional*/
|
||||
unsigned char proportional;
|
||||
/**Rate of proportinal portamento*/
|
||||
unsigned char propRate;
|
||||
/**Depth of proportinal portamento*/
|
||||
unsigned char propDepth;
|
||||
/**pitchthresh is the threshold of enabling protamento*/
|
||||
unsigned char pitchthresh;
|
||||
/**enable the portamento only below(0)/above(1) the threshold*/
|
||||
unsigned char pitchthreshtype;
|
||||
|
||||
/**this value represent how the portamento time is reduced
|
||||
* 0 - for down portamento
|
||||
* 1-63 - the up portamento's time is smaller than the down portamento
|
||||
* 64 - the portamento time is always the same
|
||||
* 64-126 - the down portamento's time is smaller than the up portamento
|
||||
* 127 - for upper portamento
|
||||
* 'up portamento' means when the frequency is rising
|
||||
* (eg: the portamento is from 200Hz to 300 Hz)
|
||||
* 'down portamento' means when the frequency is lowering
|
||||
* (eg: the portamento is from 300Hz to 200 Hz)
|
||||
*/
|
||||
unsigned char updowntimestretch;
|
||||
/**this value is used to compute the actual portamento
|
||||
*
|
||||
* This is a multiplyer to change the frequency of the newer
|
||||
* frequency to fit the profile of the portamento.
|
||||
* This will be linear with respect to x.*/
|
||||
REALTYPE freqrap;
|
||||
/**this is used by the Part for knowing which note uses the portamento*/
|
||||
int noteusing;
|
||||
/**if a the portamento is used by a note
|
||||
* \todo see if this can be a bool*/
|
||||
int used;
|
||||
|
||||
//Internal data
|
||||
|
||||
/**x is from 0.0 (start portamento) to 1.0 (finished portamento)*/
|
||||
REALTYPE x;
|
||||
/**dx is the increment to x when updateportamento is called*/
|
||||
REALTYPE dx;
|
||||
/** this is used for computing oldfreq value from x*/
|
||||
REALTYPE origfreqrap;
|
||||
} portamento;
|
||||
|
||||
struct { //Resonance Center Frequency
|
||||
int data;
|
||||
REALTYPE relcenter;
|
||||
unsigned char depth;
|
||||
} resonancecenter;
|
||||
|
||||
struct { //Resonance Bandwidth
|
||||
int data;
|
||||
REALTYPE relbw;
|
||||
unsigned char depth;
|
||||
} resonancebandwidth;
|
||||
|
||||
|
||||
/** RPN and NPRPN */
|
||||
struct { //nrpn
|
||||
int parhi, parlo;
|
||||
int valhi, vallo;
|
||||
unsigned char receive; //this is saved to disk by Master
|
||||
} NRPN;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,298 +0,0 @@
|
||||
/*
|
||||
ZynAddSubFX - a software synthesizer
|
||||
|
||||
EnvelopeParams.cpp - Parameters for Envelope
|
||||
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 <stdio.h>
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include "EnvelopeParams.h"
|
||||
|
||||
EnvelopeParams::EnvelopeParams(unsigned char Penvstretch_,
|
||||
unsigned char Pforcedrelease_):Presets()
|
||||
{
|
||||
int i;
|
||||
|
||||
PA_dt = 10;
|
||||
PD_dt = 10;
|
||||
PR_dt = 10;
|
||||
PA_val = 64;
|
||||
PD_val = 64;
|
||||
PS_val = 64;
|
||||
PR_val = 64;
|
||||
|
||||
for(i = 0; i < MAX_ENVELOPE_POINTS; i++) {
|
||||
Penvdt[i] = 32;
|
||||
Penvval[i] = 64;
|
||||
}
|
||||
Penvdt[0] = 0; //no used
|
||||
Penvsustain = 1;
|
||||
Penvpoints = 1;
|
||||
Envmode = 1;
|
||||
Penvstretch = Penvstretch_;
|
||||
Pforcedrelease = Pforcedrelease_;
|
||||
Pfreemode = 1;
|
||||
Plinearenvelope = 0;
|
||||
|
||||
store2defaults();
|
||||
}
|
||||
|
||||
EnvelopeParams::~EnvelopeParams()
|
||||
{}
|
||||
|
||||
REALTYPE EnvelopeParams::getdt(char i)
|
||||
{
|
||||
REALTYPE result = (pow(2.0, Penvdt[(int)i] / 127.0 * 12.0) - 1.0) * 10.0; //miliseconds
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ADSR/ASR... initialisations
|
||||
*/
|
||||
void EnvelopeParams::ADSRinit(char A_dt, char D_dt, char S_val, char R_dt)
|
||||
{
|
||||
setpresettype("Penvamplitude");
|
||||
Envmode = 1;
|
||||
PA_dt = A_dt;
|
||||
PD_dt = D_dt;
|
||||
PS_val = S_val;
|
||||
PR_dt = R_dt;
|
||||
Pfreemode = 0;
|
||||
converttofree();
|
||||
|
||||
store2defaults();
|
||||
}
|
||||
|
||||
void EnvelopeParams::ADSRinit_dB(char A_dt, char D_dt, char S_val, char R_dt)
|
||||
{
|
||||
setpresettype("Penvamplitude");
|
||||
Envmode = 2;
|
||||
PA_dt = A_dt;
|
||||
PD_dt = D_dt;
|
||||
PS_val = S_val;
|
||||
PR_dt = R_dt;
|
||||
Pfreemode = 0;
|
||||
converttofree();
|
||||
|
||||
store2defaults();
|
||||
}
|
||||
|
||||
void EnvelopeParams::ASRinit(char A_val, char A_dt, char R_val, char R_dt)
|
||||
{
|
||||
setpresettype("Penvfrequency");
|
||||
Envmode = 3;
|
||||
PA_val = A_val;
|
||||
PA_dt = A_dt;
|
||||
PR_val = R_val;
|
||||
PR_dt = R_dt;
|
||||
Pfreemode = 0;
|
||||
converttofree();
|
||||
|
||||
store2defaults();
|
||||
}
|
||||
|
||||
void EnvelopeParams::ADSRinit_filter(char A_val,
|
||||
char A_dt,
|
||||
char D_val,
|
||||
char D_dt,
|
||||
char R_dt,
|
||||
char R_val)
|
||||
{
|
||||
setpresettype("Penvfilter");
|
||||
Envmode = 4;
|
||||
PA_val = A_val;
|
||||
PA_dt = A_dt;
|
||||
PD_val = D_val;
|
||||
PD_dt = D_dt;
|
||||
PR_dt = R_dt;
|
||||
PR_val = R_val;
|
||||
Pfreemode = 0;
|
||||
converttofree();
|
||||
store2defaults();
|
||||
}
|
||||
|
||||
void EnvelopeParams::ASRinit_bw(char A_val, char A_dt, char R_val, char R_dt)
|
||||
{
|
||||
setpresettype("Penvbandwidth");
|
||||
Envmode = 5;
|
||||
PA_val = A_val;
|
||||
PA_dt = A_dt;
|
||||
PR_val = R_val;
|
||||
PR_dt = R_dt;
|
||||
Pfreemode = 0;
|
||||
converttofree();
|
||||
store2defaults();
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert the Envelope to freemode
|
||||
*/
|
||||
void EnvelopeParams::converttofree()
|
||||
{
|
||||
switch(Envmode) {
|
||||
case 1:
|
||||
Penvpoints = 4;
|
||||
Penvsustain = 2;
|
||||
Penvval[0] = 0;
|
||||
Penvdt[1] = PA_dt;
|
||||
Penvval[1] = 127;
|
||||
Penvdt[2] = PD_dt;
|
||||
Penvval[2] = PS_val;
|
||||
Penvdt[3] = PR_dt;
|
||||
Penvval[3] = 0;
|
||||
break;
|
||||
case 2:
|
||||
Penvpoints = 4;
|
||||
Penvsustain = 2;
|
||||
Penvval[0] = 0;
|
||||
Penvdt[1] = PA_dt;
|
||||
Penvval[1] = 127;
|
||||
Penvdt[2] = PD_dt;
|
||||
Penvval[2] = PS_val;
|
||||
Penvdt[3] = PR_dt;
|
||||
Penvval[3] = 0;
|
||||
break;
|
||||
case 3:
|
||||
Penvpoints = 3;
|
||||
Penvsustain = 1;
|
||||
Penvval[0] = PA_val;
|
||||
Penvdt[1] = PA_dt;
|
||||
Penvval[1] = 64;
|
||||
Penvdt[2] = PR_dt;
|
||||
Penvval[2] = PR_val;
|
||||
break;
|
||||
case 4:
|
||||
Penvpoints = 4;
|
||||
Penvsustain = 2;
|
||||
Penvval[0] = PA_val;
|
||||
Penvdt[1] = PA_dt;
|
||||
Penvval[1] = PD_val;
|
||||
Penvdt[2] = PD_dt;
|
||||
Penvval[2] = 64;
|
||||
Penvdt[3] = PR_dt;
|
||||
Penvval[3] = PR_val;
|
||||
break;
|
||||
case 5:
|
||||
Penvpoints = 3;
|
||||
Penvsustain = 1;
|
||||
Penvval[0] = PA_val;
|
||||
Penvdt[1] = PA_dt;
|
||||
Penvval[1] = 64;
|
||||
Penvdt[2] = PR_dt;
|
||||
Penvval[2] = PR_val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void EnvelopeParams::add2XML(XMLwrapper *xml)
|
||||
{
|
||||
xml->addparbool("free_mode", Pfreemode);
|
||||
xml->addpar("env_points", Penvpoints);
|
||||
xml->addpar("env_sustain", Penvsustain);
|
||||
xml->addpar("env_stretch", Penvstretch);
|
||||
xml->addparbool("forced_release", Pforcedrelease);
|
||||
xml->addparbool("linear_envelope", Plinearenvelope);
|
||||
xml->addpar("A_dt", PA_dt);
|
||||
xml->addpar("D_dt", PD_dt);
|
||||
xml->addpar("R_dt", PR_dt);
|
||||
xml->addpar("A_val", PA_val);
|
||||
xml->addpar("D_val", PD_val);
|
||||
xml->addpar("S_val", PS_val);
|
||||
xml->addpar("R_val", PR_val);
|
||||
|
||||
if((Pfreemode != 0) || (!xml->minimal)) {
|
||||
for(int i = 0; i < Penvpoints; i++) {
|
||||
xml->beginbranch("POINT", i);
|
||||
if(i != 0)
|
||||
xml->addpar("dt", Penvdt[i]);
|
||||
xml->addpar("val", Penvval[i]);
|
||||
xml->endbranch();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void EnvelopeParams::getfromXML(XMLwrapper *xml)
|
||||
{
|
||||
Pfreemode = xml->getparbool("free_mode", Pfreemode);
|
||||
Penvpoints = xml->getpar127("env_points", Penvpoints);
|
||||
Penvsustain = xml->getpar127("env_sustain", Penvsustain);
|
||||
Penvstretch = xml->getpar127("env_stretch", Penvstretch);
|
||||
Pforcedrelease = xml->getparbool("forced_release", Pforcedrelease);
|
||||
Plinearenvelope = xml->getparbool("linear_envelope", Plinearenvelope);
|
||||
|
||||
PA_dt = xml->getpar127("A_dt", PA_dt);
|
||||
PD_dt = xml->getpar127("D_dt", PD_dt);
|
||||
PR_dt = xml->getpar127("R_dt", PR_dt);
|
||||
PA_val = xml->getpar127("A_val", PA_val);
|
||||
PD_val = xml->getpar127("D_val", PD_val);
|
||||
PS_val = xml->getpar127("S_val", PS_val);
|
||||
PR_val = xml->getpar127("R_val", PR_val);
|
||||
|
||||
for(int i = 0; i < Penvpoints; i++) {
|
||||
if(xml->enterbranch("POINT", i) == 0)
|
||||
continue;
|
||||
if(i != 0)
|
||||
Penvdt[i] = xml->getpar127("dt", Penvdt[i]);
|
||||
Penvval[i] = xml->getpar127("val", Penvval[i]);
|
||||
xml->exitbranch();
|
||||
}
|
||||
|
||||
if(!Pfreemode)
|
||||
converttofree();
|
||||
}
|
||||
|
||||
|
||||
void EnvelopeParams::defaults()
|
||||
{
|
||||
Penvstretch = Denvstretch;
|
||||
Pforcedrelease = Dforcedrelease;
|
||||
Plinearenvelope = Dlinearenvelope;
|
||||
PA_dt = DA_dt;
|
||||
PD_dt = DD_dt;
|
||||
PR_dt = DR_dt;
|
||||
PA_val = DA_val;
|
||||
PD_val = DD_val;
|
||||
PS_val = DS_val;
|
||||
PR_val = DR_val;
|
||||
Pfreemode = 0;
|
||||
converttofree();
|
||||
}
|
||||
|
||||
void EnvelopeParams::store2defaults()
|
||||
{
|
||||
Denvstretch = Penvstretch;
|
||||
Dforcedrelease = Pforcedrelease;
|
||||
Dlinearenvelope = Plinearenvelope;
|
||||
DA_dt = PA_dt;
|
||||
DD_dt = PD_dt;
|
||||
DR_dt = PR_dt;
|
||||
DA_val = PA_val;
|
||||
DD_val = PD_val;
|
||||
DS_val = PS_val;
|
||||
DR_val = PR_val;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user