zynaddsubfx

ZynAddSubFX open source synthesizer
Log | Files | Refs | Submodules | LICENSE

commit e75a6c086287c4deb14fac74078b5c9431807c7f
parent 1846501ba96d1ed09d29500de114396cee53c948
Author: fundamental <mark.d.mccurry@gmail.com>
Date:   Wed, 18 Nov 2009 10:02:27 -0500

Nio: Wav output addition and other modifications

Added NulEngine
Added WavEngine
Added Atom (for simple atomic variables)
Moved several incluldes from .h to .cpp (for debug and compile speed)
OutMgr updated internal representation
Enhanced AudioOut class
General Nio cleanup

Diffstat:
Msrc/CMakeLists.txt | 8+++++---
Msrc/Effects/Effect.cpp | 1+
Msrc/Effects/Effect.h | 4++--
Msrc/Effects/EffectMgr.cpp | 10++++++++++
Msrc/Effects/EffectMgr.h | 14++++----------
Asrc/Misc/Atom.cpp | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Misc/Atom.h | 46++++++++++++++++++++++++++++++++++++++++++++++
Msrc/Misc/Bank.h | 1+
Msrc/Misc/Master.cpp | 30+++++++++++++++++++++++++++++-
Msrc/Misc/Master.h | 12+++++++++---
Msrc/Misc/Part.cpp | 7+++++++
Msrc/Misc/Part.h | 15++++++++-------
Msrc/Nio/AlsaEngine.cpp | 8++++++--
Msrc/Nio/AlsaEngine.h | 2+-
Msrc/Nio/AudioOut.cpp | 45++++++++++++++++++++++++++++++++++++++++++++-
Msrc/Nio/AudioOut.h | 24+++++++++++++++++-------
Msrc/Nio/CMakeLists.txt | 2++
Asrc/Nio/NulEngine.cpp | 112+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Nio/NulEngine.h | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/Nio/OssEngine.cpp | 109++++++++++++++++++++++++++-----------------------------------------------------
Msrc/Nio/OssEngine.h | 16+---------------
Msrc/Nio/OutMgr.cpp | 93+++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
Msrc/Nio/OutMgr.h | 18++++++++----------
Asrc/Nio/WavEngine.cpp | 197+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Nio/WavEngine.h | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/Output/Recorder.cpp | 44+++++++++++++++++++++++++++++++++++++++++---
Msrc/Output/Recorder.h | 12+++++++++++-
Msrc/Params/ADnoteParameters.cpp | 3+++
Msrc/Params/ADnoteParameters.h | 5+++--
Msrc/Synth/ADnote.cpp | 2+-
Msrc/Tests/EchoTest.h | 1+
Msrc/UI/MasterUI.fl | 32+++++++++++++++++++++++---------
Msrc/main.cpp | 6+++++-
33 files changed, 873 insertions(+), 184 deletions(-)

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt @@ -79,6 +79,8 @@ add_definitions(-DFFTW_VERSION_${FFTW_VERSION} -DALSAMIDIIN -DASM_F2I_YES -g #TODO #todo put in a better location + -Wall + -Wextra ) @@ -158,15 +160,15 @@ endmacro(unit_test) set(NONGUI_LIBRARIES zynaddsubfx_input zynaddsubfx_misc - zynaddsubfx_nio zynaddsubfx_synth zynaddsubfx_seq zynaddsubfx_effect zynaddsubfx_params + zynaddsubfx_output zynaddsubfx_dsp zynaddsubfx_samples zynaddsubfx_controls - zynaddsubfx_output + zynaddsubfx_nio ) set(CXXTEST_LINK_LIBS ${NONGUI_LIBRARIES}) @@ -199,8 +201,8 @@ target_link_libraries(zynaddsubfx ${zlib_LIBRARIES} ${fftw_LIBRARIES} ${MXML_LIBRARIES} + ${NIO_LIBRARIES} ${AUDIO_LIBRARIES} ${MIDIINPUT_LIBRARIES} - ${NIO_LIBRARIES} ) diff --git a/src/Effects/Effect.cpp b/src/Effects/Effect.cpp @@ -21,6 +21,7 @@ */ #include "Effect.h" +#include "../Params/FilterParams.h" Effect::Effect(bool insertion_, REALTYPE *const efxoutl_, diff --git a/src/Effects/Effect.h b/src/Effects/Effect.h @@ -25,8 +25,8 @@ #include "../Misc/Util.h" #include "../globals.h" -#include "../Params/FilterParams.h" +class FilterParams; /**this class is inherited by the all effects(Reverb, Echo, ..)*/ class Effect @@ -76,7 +76,7 @@ class Effect virtual void cleanup() {} /**This is only used for EQ (for user interface)*/ virtual REALTYPE getfreqresponse(REALTYPE freq) { - return 0; + return freq; } unsigned char Ppreset; /**<Currently used preset*/ diff --git a/src/Effects/EffectMgr.cpp b/src/Effects/EffectMgr.cpp @@ -21,6 +21,16 @@ */ #include "EffectMgr.h" +#include "Effect.h" +#include "Reverb.h" +#include "Echo.h" +#include "Chorus.h" +#include "Distorsion.h" +#include "EQ.h" +#include "DynamicFilter.h" +#include "../Misc/XMLwrapper.h" +#include "../Params/FilterParams.h" + EffectMgr::EffectMgr(int insertion_, pthread_mutex_t *mutex_) :insertion(insertion_), diff --git a/src/Effects/EffectMgr.h b/src/Effects/EffectMgr.h @@ -24,19 +24,13 @@ #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 "Phaser.h" #include "../Params/Presets.h" +class Effect; +class FilterParams; +class XMLwrapper; /**Effect manager, an interface betwen the program and effects*/ class EffectMgr:public Presets diff --git a/src/Misc/Atom.cpp b/src/Misc/Atom.cpp @@ -0,0 +1,69 @@ +/* + ZynAddSubFX - a software synthesizer + + Atom.cpp - Simple Atomic operation wrapper + 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> +Atom<T>::Atom(const T &val) + :value(val) +{ + pthread_mutex_init(&mutex, NULL); +} + +template<class T> +Atom<T>::~Atom() +{ + pthread_mutex_destroy(&mutex); +} + +template<class T> +void Atom<T>::operator=(const T &nval) +{ + pthread_mutex_lock(&mutex); + value = nval; + pthread_mutex_unlock(&mutex); +} + +template<class T> +T Atom<T>::operator()() const +{ + T tmp; + pthread_mutex_lock(&mutex); + tmp = value; + pthread_mutex_unlock(&mutex); + return tmp; +} + +template<class T> +T Atom<T>::operator++(){ + T tmp; + pthread_mutex_lock(&mutex); + tmp = ++value; + pthread_mutex_unlock(&mutex); + return tmp; +} + +template<class T> +T Atom<T>::operator--(){ + T tmp; + pthread_mutex_lock(&mutex); + tmp = --value; + pthread_mutex_unlock(&mutex); + return tmp; +} diff --git a/src/Misc/Atom.h b/src/Misc/Atom.h @@ -0,0 +1,46 @@ +/* + ZynAddSubFX - a software synthesizer + + Atom.h - Simple Atomic operation wrapper + 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 ATOM_H +#define ATOM_H + +#include <pthread.h> + +/**Very simple threaded value container*/ +template<class T> +class Atom +{ + public: + /**Initializes Atom + * @param val the value of the atom*/ + Atom(const T &val); + ~Atom(); + + void operator=(const T &val); + T operator()() const; + T operator++(); + T operator--(); + private: + mutable pthread_mutex_t mutex; + T value; +}; +#include "Atom.cpp" +#endif + diff --git a/src/Misc/Bank.h b/src/Misc/Bank.h @@ -24,6 +24,7 @@ #define BANK_H #include "../globals.h" +#include "Util.h" #include "XMLwrapper.h" #include "Part.h" diff --git a/src/Misc/Master.cpp b/src/Misc/Master.cpp @@ -23,14 +23,22 @@ #include "Master.h" +#include "../Params/LFOParams.h" +#include "../Effects/EffectMgr.h" +#include "../Nio/NulEngine.h" + #include <stdio.h> #include <sys/stat.h> #include <sys/types.h> +#include <iostream> #include <unistd.h> +using namespace std; + Master::Master() { + myNull=NULL; swaplr = 0; pthread_mutex_init(&mutex, NULL); @@ -158,7 +166,6 @@ void Master::noteon(unsigned char chan, } else this->NoteOff(chan, note); - ; HDDRecorder.triggernow(); } @@ -492,8 +499,10 @@ void Master::AudioOut(REALTYPE *outl, REALTYPE *outr) //update the LFO's time LFOParams::time++; +#ifndef NEW_IO if(HDDRecorder.recording()) HDDRecorder.recordbuffer(outl, outr); +#endif dump.inctick(); } @@ -662,6 +671,25 @@ vuData Master::getVuData() return tmp; } +void Master::toggleNull() +{ + if(myNull==NULL) + { + myNull=new NulEngine(sysOut); + nullRun=false; + } + if(nullRun) + { + sysOut->add(myNull); + cout << "Inserting A Null Output-----------------" << endl; + } + else + { + sysOut->remove(myNull); + cout << "Uninserting A Null Output-----------------" << endl; + } + nullRun=!nullRun; +} void Master::applyparameters() { diff --git a/src/Misc/Master.h b/src/Misc/Master.h @@ -25,12 +25,11 @@ #define MASTER_H #include "../globals.h" -#include "../Effects/EffectMgr.h" -#include "Part.h" -#include "../Output/Recorder.h" #include "Microtonal.h" #include "Bank.h" +#include "../Output/Recorder.h" +#include "Part.h" #include "Dump.h" #include "../Seq/Sequencer.h" #include "XMLwrapper.h" @@ -39,12 +38,15 @@ typedef enum { MUTEX_TRYLOCK, MUTEX_LOCK, MUTEX_UNLOCK } lockset; extern Dump dump; +class NulEngine; + typedef struct vuData_t { REALTYPE outpeakl, outpeakr, maxoutpeakl, maxoutpeakr, rmspeakl, rmspeakr; int clipped; } vuData; + /** It sends Midi Messages to Parts, receives samples from parts, * process them with system/insertion effects and mix them */ class Master @@ -157,8 +159,12 @@ class Master FFTwrapper *fft; pthread_mutex_t mutex; pthread_mutex_t vumutex; + + void toggleNull();//temporary debug function private: + NulEngine *myNull; + bool nullRun; vuData vu; REALTYPE volume; REALTYPE sysefxvol[NUM_SYS_EFX][NUM_MIDI_PARTS]; diff --git a/src/Misc/Part.cpp b/src/Misc/Part.cpp @@ -22,6 +22,13 @@ #include "Part.h" #include "Microtonal.h" +#include "../Effects/EffectMgr.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 <stdlib.h> #include <stdio.h> #include <string.h> diff --git a/src/Misc/Part.h b/src/Misc/Part.h @@ -26,20 +26,21 @@ #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. +class EffectMgr; +class ADnoteParameters; +class SUBnoteParameters; +class PADnoteParameters; +class ADnote; +class SUBnote; +class PADnote; + /** Part implementation*/ class Part { diff --git a/src/Nio/AlsaEngine.cpp b/src/Nio/AlsaEngine.cpp @@ -18,6 +18,7 @@ */ #include <iostream> +#include <cmath> using namespace std; @@ -26,7 +27,8 @@ using namespace std; #include "../Misc/Master.h" #include "AlsaEngine.h" -AlsaEngine::AlsaEngine() +AlsaEngine::AlsaEngine(OutMgr *out) + :AudioOut(out) { audio.handle = NULL; audio.period_time = 0; @@ -314,9 +316,11 @@ void *AlsaEngine::AudioThread() delete [] tmp; } else - ;//config.cfg.verbose + { + //config.cfg.verbose // && cerr << "Error, audio pcm still not RUNNING" << endl; cerr << "Error, audio pcm still not running"; + } } return NULL; } diff --git a/src/Nio/AlsaEngine.h b/src/Nio/AlsaEngine.h @@ -34,7 +34,7 @@ class AlsaEngine : public AudioOut//, MidiIn { public: - AlsaEngine(); + AlsaEngine(OutMgr *out); ~AlsaEngine() { }; bool openAudio(); diff --git a/src/Nio/AudioOut.cpp b/src/Nio/AudioOut.cpp @@ -25,7 +25,13 @@ using namespace std; #include "../Misc/Master.h" #include "AudioOut.h" -AudioOut::AudioOut(){} +AudioOut::AudioOut(OutMgr *out) + :manager(out),threadStop(false) +{ + cout << out; + pthread_mutex_init(&outBuf_mutex, NULL); + pthread_cond_init (&outBuf_cv, NULL); +} //bool AudioOut::prepAudiobuffers(unsigned int nframes, bool with_interleaved) //{ @@ -112,3 +118,40 @@ AudioOut::AudioOut(){} // } //} +void AudioOut::out(const Stereo<Sample> smps) +{ + pthread_mutex_lock(&outBuf_mutex); + outBuf.push(smps); + pthread_cond_signal(&outBuf_cv); + pthread_mutex_unlock(&outBuf_mutex); +} + +const Stereo<Sample> AudioOut::getNext() +{ + Stereo<Sample> ans; + pthread_mutex_lock(&outBuf_mutex); + bool isEmpty = outBuf.empty(); + pthread_mutex_unlock(&outBuf_mutex); + if(isEmpty)//fetch samples if possible + { + //cerr << manager << endl; + if(manager->getRunning()<4) + manager->requestSamples(); + if(true) + cout << "-----------------Starvation------------------"<< endl; + return current; + } + else + { + pthread_mutex_lock(&outBuf_mutex); + ans = outBuf.front(); + outBuf.pop(); + if(outBuf.size()+manager->getRunning()<4) + manager->requestSamples(); + if(true) + cout << "AudioOut "<< outBuf.size()<< '+' << manager->getRunning() << endl; + pthread_mutex_unlock(&outBuf_mutex); + } + current=ans; + return ans; +} diff --git a/src/Nio/AudioOut.h b/src/Nio/AudioOut.h @@ -26,19 +26,20 @@ #include <queue> #include <pthread.h> #include "OutMgr.h" +#include "../Misc/Atom.h" -class AudioOut; +//class AudioOut; class AudioOut { public: - AudioOut(); + AudioOut(OutMgr *out); virtual ~AudioOut() {}; virtual bool openAudio()=0; virtual bool Start()=0; virtual void Stop()=0; virtual void Close()=0; - virtual void out(const Stereo<Sample> smps)=0; + virtual void out(const Stereo<Sample> smps); //bool prepAudiobuffers(unsigned int buffersize, bool with_interleaved); //void silenceBuffers(); //void dimBuffers(); @@ -46,10 +47,19 @@ class AudioOut //virtual bool isSingleton() const {return true;}; protected: - //float *outl; - //float *outr; - //short int *shortInterleaved; - //int buffersize; + /**Get the next sample for output.*/ + virtual const Stereo<Sample> getNext(); + + std::queue<Stereo<Sample> > outBuf; + const Sample * curSmp; + Stereo<Sample> current; + pthread_mutex_t outBuf_mutex; + pthread_cond_t outBuf_cv; + + OutMgr *manager; + //thread resources + Atom<bool> threadStop; + pthread_t pThread; }; #endif diff --git a/src/Nio/CMakeLists.txt b/src/Nio/CMakeLists.txt @@ -1,5 +1,7 @@ set(zynaddsubfx_nio_SRCS OssEngine.cpp + NulEngine.cpp + WavEngine.cpp AlsaEngine.cpp AudioOut.cpp OutMgr.cpp diff --git a/src/Nio/NulEngine.cpp b/src/Nio/NulEngine.cpp @@ -0,0 +1,112 @@ +/* + ZynAddSubFX - a software synthesizer + + OSSaudiooutput.C - 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 "NulEngine.h" +#include "../globals.h" + +#include <iostream> + +using namespace std; + +NulEngine::NulEngine(OutMgr *out) + :AudioOut(out) +{ + playing_until.tv_sec = 0; + playing_until.tv_usec = 0; +} + + + +void *NulEngine::_AudioThread(void *arg) +{ + return (static_cast<NulEngine*>(arg))->AudioThread(); +} + + +void *NulEngine::AudioThread() +{ + //set_realtime(); + while (!threadStop()) + { + const Stereo<Sample> smps = getNext(); + dummyOut(); + } + return NULL; +} + +void NulEngine::dummyOut() +{ + struct timeval now; + int remaining = 0; + 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; +} + + +NulEngine::~NulEngine() +{ +} + + +bool NulEngine::Start() +{ + pthread_attr_t attr; + threadStop = false; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + pthread_create(&pThread, &attr, _AudioThread, this); + + return true; +} + +void NulEngine::Stop() +{ + threadStop = true; +} + +void NulEngine::Close() +{ + Stop(); +} + +bool NulEngine::openAudio() +{ + return true; +} diff --git a/src/Nio/NulEngine.h b/src/Nio/NulEngine.h @@ -0,0 +1,52 @@ +/* + ZynAddSubFX - a software synthesizer + + NulEngine.h - Dummy In/Out driver + 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 NUL_ENGINE_H +#define NUL_ENGINE_H + +#include <sys/time.h> +#include "../globals.h" +#include "AudioOut.h" + +class NulEngine: public AudioOut +{ + public: + NulEngine(OutMgr *out); + ~NulEngine(); + + bool openAudio(); + bool Start(); + void Stop(); + void Close(); + + protected: + void *AudioThread(); + static void *_AudioThread(void *arg); + + private: + + void dummyOut(); + struct timeval playing_until; +}; + +#endif + diff --git a/src/Nio/OssEngine.cpp b/src/Nio/OssEngine.cpp @@ -20,6 +20,10 @@ */ +#include "OssEngine.h" +#include "../Misc/Util.h" +#include "../globals.h" + #include <stdlib.h> #include <stdio.h> #include <fcntl.h> @@ -29,12 +33,10 @@ #include <unistd.h> #include <iostream> -#include "OssEngine.h" -#include "../Misc/Util.h" -#include "../globals.h" using namespace std; -OssEngine::OssEngine() +OssEngine::OssEngine(OutMgr *out) + :AudioOut(out) { current = Stereo<Sample>(Sample(SOUND_BUFFER_SIZE), Sample(SOUND_BUFFER_SIZE)); @@ -65,21 +67,39 @@ OssEngine::OssEngine() ioctl(snd_handle, SNDCTL_DSP_SPEED, &snd_samplerate); ioctl(snd_handle, SNDCTL_DSP_SAMPLESIZE, &snd_bitsize); ioctl(snd_handle, SNDCTL_DSP_SETFRAGMENT, &snd_fragment); +} + +OssEngine::~OssEngine() +{ + close(snd_handle); + delete [] smps; +} + +bool OssEngine::openAudio() +{ + return true; +} + +bool OssEngine::Start() +{ + int chk; + pthread_attr_t attr; + threadStop = false; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + pthread_create(&pThread, &attr, _AudioThread, this); - pthread_mutex_init(&outBuf_mutex, NULL); - pthread_cond_init (&outBuf_cv, NULL); - manager = sysOut; + return true; } +void OssEngine::Stop() +{ + threadStop = true; +} -void OssEngine::out(const Stereo<Sample> smps) +void OssEngine::Close() { - pthread_mutex_lock(&outBuf_mutex); - outBuf.push(smps); - //if(outBuf.size()<) - // manager->requestSamples(); - pthread_cond_signal(&outBuf_cv); - pthread_mutex_unlock(&outBuf_mutex); + Stop(); } void *OssEngine::_AudioThread(void *arg) @@ -95,7 +115,7 @@ void *OssEngine::AudioThread() manager->requestSamples(); manager->requestSamples(); set_realtime(); - while (!threadStop) + while (!threadStop()) { //cout << "OssEngine THREAD" << endl; const Stereo<Sample> smps = getNext(); @@ -165,62 +185,3 @@ void OssEngine::outOut(const REALTYPE *smp_left, const REALTYPE *smp_right) write(snd_handle, smps, SOUND_BUFFER_SIZE * 4); // *2 because is 16 bit, again * 2 because is stereo } -OssEngine::~OssEngine() -{ - close(snd_handle); - delete [] smps; -} - -const Stereo<Sample> OssEngine::getNext() -{ - Stereo<Sample> ans; - pthread_mutex_lock(&outBuf_mutex); - bool isEmpty =outBuf.empty(); - pthread_mutex_unlock(&outBuf_mutex); - if(isEmpty)//fetch samples if possible - { - if(manager->getRunning()<1) - manager->requestSamples(); - cout << "Starvation"<< endl; - return current; - } - else - { - pthread_mutex_lock(&outBuf_mutex); - ans = outBuf.front(); - outBuf.pop(); - if(outBuf.size()+manager->getRunning()==0) - manager->requestSamples(); - cout << outBuf.size()+manager->getRunning() << endl; - pthread_mutex_unlock(&outBuf_mutex); - } - current=ans; - return ans; -} - -bool OssEngine::Start() -{ - int chk; - pthread_attr_t attr; - threadStop = false; - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - pthread_create(&pThread, &attr, _AudioThread, this); - - return true; -} - -void OssEngine::Stop(void) -{ - threadStop = true; -} - -void OssEngine::Close() -{ - Stop(); -} - -bool OssEngine::openAudio() -{ - return true; -} diff --git a/src/Nio/OssEngine.h b/src/Nio/OssEngine.h @@ -30,7 +30,7 @@ class OssEngine: public AudioOut { public: - OssEngine(); + OssEngine(OutMgr *out); ~OssEngine(); //the out is [-1.0 .. 1.0] @@ -41,16 +41,12 @@ class OssEngine: public AudioOut void Stop(); void Close(); - void out(const Stereo<Sample> smps); - protected: void *AudioThread(); static void *_AudioThread(void *arg); private: - /**Get the next sample for output.*/ - const Stereo<Sample> getNext(); void OSSout(const REALTYPE *smp_left, const REALTYPE *smp_right); void outOut(const REALTYPE *smp_left, const REALTYPE *smp_right); int snd_handle; @@ -61,18 +57,8 @@ class OssEngine: public AudioOut struct timeval playing_until; short int *smps; //Samples to be sent to soundcard - bool threadStop; - //outside audio interface - std::queue<Stereo<Sample> > outBuf; - const Sample * curSmp; - Stereo<Sample> current; - pthread_mutex_t outBuf_mutex; - pthread_cond_t outBuf_cv; - pthread_t pThread; - - OutMgr *manager; }; #endif diff --git a/src/Nio/OutMgr.cpp b/src/Nio/OutMgr.cpp @@ -1,6 +1,8 @@ #include "OutMgr.h" #include <algorithm> #include <iostream> +#include "AudioOut.h" +#include "../Misc/Master.h" using namespace std; OutMgr *sysOut; @@ -14,11 +16,14 @@ OutMgr *sysOut; //} outputDriver; OutMgr::OutMgr(Master *nmaster) + :numRequests(0) { + running = false; master = nmaster; //initialize mutex pthread_mutex_init(&mutex, NULL); pthread_mutex_init(&processing, NULL); + //pthread_mutex_init(&request_m, NULL); pthread_cond_init(&needsProcess, NULL); //init samples outr = new REALTYPE[SOUND_BUFFER_SIZE]; @@ -41,38 +46,62 @@ void *_outputThread(void *arg) void *OutMgr::outputThread() { pthread_mutex_lock(&mutex); - //cout << "run start" << endl; - for(int i = 0; i < outs.size(); ++i) - outs[i]->Start(); - //cout << "running" << endl; + for(list<AudioOut*>::iterator itr = outs.begin(); itr != outs.end(); ++itr) + (*itr)->Start(); pthread_mutex_unlock(&mutex); + running=true; init=true; - bool doWait; + bool doWait=false; + int lRequests; while(running){ - //cout << "OutMgr THREAD" << endl; - pthread_mutex_lock(&request_m); - doWait = numRequests--<1; - //cout << numRequests << endl; - pthread_mutex_unlock(&request_m); + //pthread_mutex_lock(&request_m); + //lRequests=numRequests--; + //pthread_mutex_unlock(&request_m); + + --numRequests; + + pthread_mutex_lock(&mutex); + if(true) + { + cout << "Status: "; + cout << outs.size(); + cout << " outs, "; + cout << doWait; + cout << " waits, "; + cout << numRequests(); + cout << " requests" << endl; + } + pthread_mutex_unlock(&mutex); + + doWait = (numRequests()<1); + pthread_mutex_lock(&processing); if(doWait) { - //cout << "OutMgr wait" << endl; pthread_cond_wait(&needsProcess, &processing); } - //make master use samples - //cout << "have some food" << endl; + else + if(true) + cout << "Run Forest Run!" << endl; + pthread_mutex_lock(&(master->mutex)); master->AudioOut(outl,outr); pthread_mutex_unlock(&(master->mutex)); - smps = Stereo<Sample>(Sample(SOUND_BUFFER_SIZE, outl), + + smps = Stereo<Sample>(Sample(SOUND_BUFFER_SIZE, outl), Sample(SOUND_BUFFER_SIZE, outr)); - //cout << "Samp: " << outl[2] << outr[2] << endl; pthread_mutex_unlock(&processing); pthread_mutex_lock(&mutex); - for(int i = 0; i < outs.size(); ++i) - outs[i]->out(smps); + if(false) + cout << "output to "; + for(list<AudioOut*>::iterator itr = outs.begin(); itr != outs.end(); ++itr) { + (*itr)->out(smps); + if(false) + cout << *itr << " "; + } + if(false) + cout << endl; pthread_mutex_unlock(&mutex); } @@ -84,7 +113,6 @@ void *OutMgr::outputThread() void OutMgr::run() { - int chk; pthread_attr_t attr; //threadStop = false; pthread_attr_init(&attr); @@ -93,39 +121,42 @@ void OutMgr::run() } -int OutMgr::add(AudioOut *driver) +void OutMgr::add(AudioOut *driver) { pthread_mutex_lock(&mutex); outs.push_back(driver); + if(running)//hotplug + driver->Start(); pthread_mutex_unlock(&mutex); } -int OutMgr::remove(AudioOut *out) +void OutMgr::remove(AudioOut *out) { pthread_mutex_lock(&mutex); - //vector<AudioOut>::iterator it; - //outs.remove(out); + outs.remove(out); + out->Stop();//tells engine to stop + out->out(Stereo<Sample>(Sample(SOUND_BUFFER_SIZE), + Sample(SOUND_BUFFER_SIZE)));//gives a dummy sample to make sure it is not stuck pthread_mutex_unlock(&mutex); } int OutMgr::getRunning() { - int tmp; - pthread_mutex_lock(&request_m); - tmp=numRequests; - pthread_mutex_unlock(&request_m); - return tmp; + //int tmp; + //pthread_mutex_lock(&request_m); + //tmp=eumRequests; + //pthread_mutex_unlock(&request_m); + return numRequests();//tmp; } int OutMgr::requestSamples() { - //cout << "me hungry" << endl; - pthread_mutex_lock(&request_m); + //pthread_mutex_lock(&request_m); ++numRequests; - pthread_mutex_unlock(&request_m); + //pthread_mutex_unlock(&request_m); + pthread_mutex_lock(&processing); pthread_cond_signal(&needsProcess); - //cout << "me start fire" << endl; pthread_mutex_unlock(&processing); return 0; } diff --git a/src/Nio/OutMgr.h b/src/Nio/OutMgr.h @@ -3,10 +3,10 @@ #include "../globals.h" #include "../Misc/Stereo.h" +#include "../Misc/Atom.h" #include "../Samples/Sample.h" -#include "../Misc/Master.h" -#include "AudioOut.h" -#include <vector> +//#include "../Misc/Master.h" +#include <list> #include <pthread.h> //typedef enum @@ -19,7 +19,7 @@ //} outputDriver; class AudioOut; - +class Master; class OutMgr { public: @@ -27,10 +27,10 @@ class OutMgr ~OutMgr(); /**Adds audio output out. * @return -1 for error 0 otherwise*/ - int add(AudioOut *out); + void add(AudioOut *out); /**Removes given audio output engine * @return -1 for error 0 otherwise*/ - int remove(AudioOut *out); + void remove(AudioOut *out); /**Request a new set of samples * @return -1 for locking issues 0 for valid request*/ int requestSamples(); @@ -47,16 +47,14 @@ class OutMgr bool running; bool init; - std::vector<AudioOut *> outs; + std::list<AudioOut *> outs; mutable pthread_mutex_t mutex; pthread_mutex_t processing; pthread_t outThread; pthread_cond_t needsProcess; - /**for num requests*/ - pthread_mutex_t request_m; - int numRequests; + Atom<int> numRequests; /**for closing*/ pthread_mutex_t close_m; pthread_cond_t close_cond; diff --git a/src/Nio/WavEngine.cpp b/src/Nio/WavEngine.cpp @@ -0,0 +1,197 @@ +/* + 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 "WavEngine.h" +#include <cstdio> +#include <iostream> +#include <cstdlib> + +using namespace std; + +WavEngine::WavEngine(OutMgr *out, string _filename, int _samplerate, int _channels) + :AudioOut(out),filename(_filename),sampleswritten(0), + samplerate(_samplerate),channels(_channels),file(NULL) +{ + //pthread_mutex_init(&stop_mutex, NULL); + pthread_mutex_init(&write_mutex, NULL); + pthread_cond_init(&stop_cond, NULL); +} + + +WavEngine::~WavEngine() +{ + //TODO cleanup mutex + Close(); +} + +bool WavEngine::openAudio() +{ + //cerr << "stuff should open" << endl; + //Close(); //to ensure that file is closed/NULL + 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; +} + +bool WavEngine::Start() +{ + pthread_attr_t attr; + threadStop = false; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + pthread_create(&pThread, &attr, _AudioThread, this); + + return true; +} + +void WavEngine::Stop() +{ + //pthread_mutex_lock(&stop_mutex); + //if(!threadStop()) + //{ + threadStop = true; + //cout << "WavEngine Stopping" << endl; + //} + //pthread_mutex_unlock(&stop_mutex); + //cout << "WavEngine Stopped" << endl; +} + +void WavEngine::Close() +{ + //Stop(); + + pthread_mutex_lock(&write_mutex); + 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; + } + pthread_mutex_unlock(&write_mutex); + +} + +//lazy getter +const Stereo<Sample> WavEngine::getNext() +{ + //TODO make this write remaining sample to output when stopped. + Stereo<Sample> ans; + pthread_mutex_lock(&outBuf_mutex); + bool isEmpty = outBuf.empty(); + pthread_mutex_unlock(&outBuf_mutex); + if(isEmpty)//wait for samples + { + pthread_mutex_lock(&outBuf_mutex); + pthread_cond_wait(&outBuf_cv, &outBuf_mutex); + pthread_mutex_unlock(&outBuf_mutex); + } + pthread_mutex_lock(&outBuf_mutex); + ans = outBuf.front(); + outBuf.pop(); + //cout << "Wav Out: " << outBuf.size()<<'+'<<manager->getRunning() << endl; + pthread_mutex_unlock(&outBuf_mutex); + return ans; +} + +void *WavEngine::_AudioThread(void *arg) +{ + return (static_cast<WavEngine*>(arg))->AudioThread(); +} + +template <class T> +T limit(T val, T min, T max) +{ + return (val < min ? min : (val > max ? max : val)); +} + +void *WavEngine::AudioThread() +{ + short int *recordbuf_16bit = new short int [SOUND_BUFFER_SIZE*2]; + int size = SOUND_BUFFER_SIZE; + + //pthread_mutex_lock(&run_mutex); + //bool doRun = !threadStop(); + //pthread_mutex_unlock(&run_mutex); + + while (!threadStop()) + { + const Stereo<Sample> smps = getNext(); + for(int i = 0; i < size; i++) { + recordbuf_16bit[i*2] = limit((int)(smps.l()[i] * 32767.0), -32768, 32767); + recordbuf_16bit[i*2+1] = limit((int)(smps.r()[i] * 32767.0), -32768, 32767); + } + write_stereo_samples(size, recordbuf_16bit); + //cout << "foo" << threadStop() << endl; + //pthread_mutex_lock(&run_mutex); + //doRun = ; + //pthread_mutex_unlock(&run_mutex); + } + //cout << "WavEngine Stopped" << endl; + //cout << "WavEngine Stopped" << endl; + return NULL; +} + +void WavEngine::write_stereo_samples(int nsmps, short int *smps) +{ + pthread_mutex_lock(&write_mutex); + if(!file) + return; + fwrite(smps, nsmps, 4, file); + pthread_mutex_unlock(&write_mutex); + sampleswritten += nsmps; +} + +void WavEngine::write_mono_samples(int nsmps, short int *smps) +{ + if(!file) + return; + fwrite(smps, nsmps, 2, file); + sampleswritten += nsmps; +} + diff --git a/src/Nio/WavEngine.h b/src/Nio/WavEngine.h @@ -0,0 +1,57 @@ +/* + + Copyright (C) 2008 Nasca Octavian Paul + 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) 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 WAVENGINE_H +#define WAVENGINE_H +#include "AudioOut.h" +#include <string> + +class WavEngine: public AudioOut +{ + public: + WavEngine(OutMgr *out, std::string _filename, int _samplerate, int _channels); + ~WavEngine(); + + bool openAudio(); + bool Start(); + void Stop(); + void Close(); + + const Stereo<Sample> getNext(); + + protected: + void *AudioThread(); + static void *_AudioThread(void *arg); + + private: + void write_stereo_samples(int nsmps, short int *smps); + void write_mono_samples(int nsmps, short int *smps); + std::string filename; + int sampleswritten; + int samplerate; + int channels; + FILE *file; + //pthread_mutex_t run_mutex; + pthread_mutex_t write_mutex; + pthread_mutex_t stop_mutex; + pthread_cond_t stop_cond; +}; +#endif + diff --git a/src/Output/Recorder.cpp b/src/Output/Recorder.cpp @@ -22,21 +22,30 @@ #include <sys/stat.h> #include "Recorder.h" +#ifdef NEW_IO +#include "../Nio/OutMgr.h" +#include "../Nio/WavEngine.h" +#endif Recorder::Recorder() + :status(0), notetrigger(0) { +#ifndef NEW_IO 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; +#else + wave=NULL; +#endif } Recorder::~Recorder() { if(recording() == 1) stop(); +#ifndef NEW_IO delete [] recordbuf_16bit; +#endif } int Recorder::preparefile(std::string filename_, int overwrite) @@ -49,8 +58,13 @@ int Recorder::preparefile(std::string filename_, int overwrite) return 1; } +#ifndef NEW_IO if(!wav.newfile(filename_, SAMPLE_RATE, 2)) return 2; +#else + if(!(wave=new WavEngine(sysOut, filename_, SAMPLE_RATE, 2))) + return 2; +#endif status = 1; //ready @@ -65,13 +79,27 @@ void Recorder::start() void Recorder::stop() { +#ifndef NEW_IO wav.close(); +#else + if(wave) + { + sysOut->remove(wave); + wave->Close(); + delete wave; + wave = NULL; //is this even needed? + } +#endif status = 0; } void Recorder::pause() { status = 0; +#ifdef NEW_IO +// wave->Stop(); + sysOut->remove(wave); +#endif } int Recorder::recording() @@ -82,6 +110,7 @@ int Recorder::recording() return 0; } +#ifndef NEW_IO void Recorder::recordbuffer(REALTYPE *outl, REALTYPE *outr) { int tmp; @@ -104,10 +133,19 @@ void Recorder::recordbuffer(REALTYPE *outl, REALTYPE *outr) } wav.write_stereo_samples(SOUND_BUFFER_SIZE, recordbuf_16bit); } +#endif void Recorder::triggernow() { - if(status == 2) + if(status == 2) { +#ifdef NEW_IO + if(notetrigger!=1) { + wave->openAudio(); + //wave->Start(); + sysOut->add(wave); + } +#endif notetrigger = 1; + } } diff --git a/src/Output/Recorder.h b/src/Output/Recorder.h @@ -25,7 +25,9 @@ #include <string> #include "../globals.h" #include "WAVaudiooutput.h" +#include "../Nio/WavEngine.h" +//class WavEngine; /**Records sound to a file*/ class Recorder { @@ -33,13 +35,17 @@ class Recorder Recorder(); ~Recorder(); - int preparefile(std::string filename_, int overwrite); //returns 1 if the file exists + /**Prepare the given file. + * @returns 1 if the file exists */ + int preparefile(std::string filename_, int overwrite); void start(); void stop(); void pause(); int recording(); void triggernow(); +#ifndef NEW_IO void recordbuffer(REALTYPE *outl, REALTYPE *outr); +#endif /** Status: * 0 - not ready(no file selected), @@ -48,8 +54,12 @@ class Recorder int status; private: +#ifndef NEW_IO WAVaudiooutput wav; short int *recordbuf_16bit; +#else + WavEngine *wave; +#endif int notetrigger; }; diff --git a/src/Params/ADnoteParameters.cpp b/src/Params/ADnoteParameters.cpp @@ -25,6 +25,9 @@ #include <math.h> #include "ADnoteParameters.h" +#include "EnvelopeParams.h" +#include "LFOParams.h" + int ADnote_unison_sizes[] = {1, 2, 3, 4, 5, 6, 8, 10, 12, 15, 20, 25, 30, 40, 50, 0}; diff --git a/src/Params/ADnoteParameters.h b/src/Params/ADnoteParameters.h @@ -25,8 +25,6 @@ #include "../globals.h" -#include "EnvelopeParams.h" -#include "LFOParams.h" #include "FilterParams.h" #include "../Synth/OscilGen.h" #include "../Synth/Resonance.h" @@ -35,6 +33,9 @@ #include "../DSP/FFTwrapper.h" #include "Presets.h" +class EnvelopeParams; +class LFOParams; + enum FMTYPE { NONE, MORPH, RING_MOD, PHASE_MOD, FREQ_MOD, PITCH_MOD }; diff --git a/src/Synth/ADnote.cpp b/src/Synth/ADnote.cpp @@ -1876,7 +1876,7 @@ int ADnote::noteout(REALTYPE *outl, REALTYPE *outr) if(Legato.silent) // Silencer if(Legato.msg != LM_FadeIn) { memset(outl, 0, SOUND_BUFFER_SIZE * sizeof(REALTYPE)); - memset(outl, 0, SOUND_BUFFER_SIZE * sizeof(REALTYPE)); + memset(outr, 0, SOUND_BUFFER_SIZE * sizeof(REALTYPE)); } switch(Legato.msg) { case LM_CatchUp: // Continue the catch-up... diff --git a/src/Tests/EchoTest.h b/src/Tests/EchoTest.h @@ -21,6 +21,7 @@ */ #include <cxxtest/TestSuite.h> #include <cmath> +#include <cstdlib> #include "../Effects/Echo.h" #include "../globals.h" //int SOUND_BUFFER_SIZE=256; diff --git a/src/UI/MasterUI.fl b/src/UI/MasterUI.fl @@ -300,7 +300,7 @@ class Panellistitem {: {public Fl_Group} Function {make_window()} {private } { Fl_Window panellistitem { - private xywh {315 213 70 260} type Double hide + private xywh {315 213 70 260} type Double labeltype NORMAL_LABEL align 80 hide class Fl_Group } { Fl_Group panellistitemgroup { @@ -427,7 +427,7 @@ if (fl_choice("Exit and leave the unsaved data?","No","Yes",NULL)) { *exitprogram=1; }; \#endif} - xywh {31 206 390 465} type Double hide xclass zynaddsubfx + xywh {450 306 390 465} type Double labeltype NORMAL_LABEL align 80 hide xclass zynaddsubfx } { Fl_Menu_Bar mastermenu { xywh {-5 0 690 25} @@ -993,10 +993,15 @@ globalfinedetuneslider->do_callback();} panelwindow->show();} tooltip {Panel Window} xywh {293 62 92 16} box PLASTIC_UP_BOX color 183 labelfont 1 labelsize 10 } + Fl_Button {} { + label N + callback {newiowindow->show();} selected + xywh {270 75 20 25} + } } Fl_Window aboutwindow { label {Copyright...} - xywh {411 344 365 280} type Double hide + xywh {411 344 365 280} type Double labeltype NORMAL_LABEL align 80 hide } { Fl_Box {} { label {Copyright (c) 2002-2009 Nasca O. PAUL and others. Please read AUTHORS.txt} @@ -1023,7 +1028,7 @@ GNU General Public License for details.} } Fl_Window syseffsendwindow { label {System Effects Send} - xywh {171 234 120 250} type Double hide resizable + xywh {171 234 120 250} type Double labeltype NORMAL_LABEL align 80 hide resizable } { Fl_Scroll {} {open xywh {0 45 120 170} box FLAT_BOX resizable @@ -1042,7 +1047,7 @@ GNU General Public License for details.} } Fl_Window panelwindow { label {ZynAddSubFX Panel} - xywh {89 59 630 635} type Double hide + xywh {89 59 630 635} type Double labeltype NORMAL_LABEL align 80 hide } { Fl_Scroll {} { xywh {0 5 570 310} type HORIZONTAL box THIN_UP_BOX @@ -1082,7 +1087,7 @@ if (fl_choice("Exit and leave the unsaved data?","No","Yes",NULL)) { *exitprogram=1; }; \#endif} - xywh {400 405 600 335} type Double hide + xywh {400 405 600 335} type Double labeltype NORMAL_LABEL align 80 hide } { Fl_Menu_Bar {} { xywh {0 0 690 25} @@ -1564,7 +1569,7 @@ virkeys->take_focus();} Fl_Window selectuiwindow { label {User Interface mode} callback {*exitprogram=1;} - xywh {342 246 430 250} type Double hide non_modal + xywh {342 246 430 250} type Double labeltype NORMAL_LABEL align 80 hide non_modal } { Fl_Box {} { label {Welcome to ZynAddSubFX} @@ -1601,6 +1606,16 @@ config.cfg.UserInterfaceMode=2;} xywh {30 215 360 25} box BORDER_BOX color 51 labelfont 1 labelsize 11 align 144 } } + Fl_Window newiowindow { + label {New IO} + xywh {467 490 120 55} type Double labeltype NORMAL_LABEL align 80 hide + } { + Fl_Light_Button nullToggle { + label {Null Output} + callback {master->toggleNull();} + xywh {10 15 100 20} labelfont 13 + } + } } Function {updatesendwindow()} {} { code {for (int neff1=0;neff1<NUM_SYS_EFX;neff1++) @@ -1735,8 +1750,7 @@ if (result>=0) setfilelabel(filename); if (result==-10) fl_alert("Error: Could not load the file\\nbecause it is not a zynaddsubfx parameters file."); - else if (result<0) fl_alert("Error: Could not load the file.");} {selected - } + else if (result<0) fl_alert("Error: Could not load the file.");} {} } Function {do_save_master(const char* file = NULL)} {} { code {const char *filename; diff --git a/src/main.cpp b/src/main.cpp @@ -444,6 +444,7 @@ int main(int argc, char *argv[]) OSCIL_SIZE = config.cfg.OscilSize; swaplr = config.cfg.SwapStereo; + /* Parse command-line options */ #ifdef OS_LINUX struct option opts[] = { @@ -683,9 +684,12 @@ int main(int argc, char *argv[]) #endif #ifdef NEW_IO + sysOut=NULL; sysOut = new OutMgr(master); + if(sysOut); //AlsaEngine *tmp = new AlsaEngine(); - AudioOut *tmp = new OssEngine(); + AudioOut *tmp = new OssEngine(sysOut); + if(tmp); //tmp->openAudio(); sysOut->add(tmp); sysOut->run();