zynaddsubfx

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

commit 465f08fa3d58453e32404c5ddcbc7f45a82abfa2
parent a59b60e36cf0f4a465e268e33db5ca13f870b633
Author: fundamental <[email protected]>
Date:   Fri, 18 Dec 2009 16:42:43 -0500

Nio: Adding support for sampling rates/numbers

- Adding basic support for drivers with a different sampling rate
  from SAMPLE_RATE
- Adding basic support for drivers with a different buffer size than
  BUFFER_SIZE

Diffstat:
Msrc/Misc/Recorder.cpp | 2+-
Msrc/Nio/AlsaEngine.cpp | 29+++++++++++++----------------
Msrc/Nio/AlsaEngine.h | 2+-
Msrc/Nio/AudioOut.cpp | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
Msrc/Nio/AudioOut.h | 26++++++++++++++++++++------
Msrc/Nio/JackEngine.cpp | 15+++------------
Msrc/Nio/WavEngine.cpp | 24++----------------------
Msrc/Samples/Sample.cpp | 9+++++++--
Msrc/Samples/Sample.h | 3+++
9 files changed, 110 insertions(+), 68 deletions(-)

diff --git a/src/Misc/Recorder.cpp b/src/Misc/Recorder.cpp @@ -26,7 +26,7 @@ #include "../Nio/WavEngine.h" Recorder::Recorder() - :status(0), notetrigger(0), wave(NULL) + :status(0), wave(NULL), notetrigger(0) {} Recorder::~Recorder() diff --git a/src/Nio/AlsaEngine.cpp b/src/Nio/AlsaEngine.cpp @@ -204,17 +204,16 @@ bool AlsaEngine::Start() { if(enabled()) return true; - OpenStuff(); - int chk; + if(!OpenStuff()) + return false; + pthread_attr_t attr; threadStop = false; enabled = true; - //if (NULL != audio.handle) - //{ - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - pthread_create(&audio.pThread, &attr, _AudioThread, this); - //} + + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + pthread_create(&audio.pThread, &attr, _AudioThread, this); // if (NULL != midi.handle) // { @@ -360,8 +359,7 @@ const short *AlsaEngine::interleave(const Stereo<Sample> smps)const return shortInterleaved; } - -void AlsaEngine::OpenStuff() +bool AlsaEngine::OpenStuff() { /* Open PCM device for playback. */ handle=NULL; @@ -371,7 +369,7 @@ void AlsaEngine::OpenStuff() fprintf(stderr, "unable to open pcm device: %s\n", snd_strerror(rc)); - exit(1); + return false; } /* Allocate a hardware parameters object. */ @@ -393,9 +391,7 @@ void AlsaEngine::OpenStuff() /* Two channels (stereo) */ snd_pcm_hw_params_set_channels(handle, params, 2); - /* 44100 bits/second sampling rate (CD quality) - * \TODO make this dynamic*/ - val = 44100; + val = SAMPLE_RATE; //44100; snd_pcm_hw_params_set_rate_near(handle, params, &val, NULL);//&dir); @@ -409,7 +405,7 @@ void AlsaEngine::OpenStuff() fprintf(stderr, "unable to set hw parameters: %s\n", snd_strerror(rc)); - exit(1); + return false; } /* Set buffer size (in frames). The resulting latency is given by */ @@ -420,6 +416,7 @@ void AlsaEngine::OpenStuff() snd_pcm_hw_params_get_period_size(params, &frames, &dir); snd_pcm_hw_params_get_period_time(params, &val, &dir); + return true; } void AlsaEngine::RunStuff() @@ -428,7 +425,7 @@ void AlsaEngine::RunStuff() while (!threadStop()) { buffer = interleave(getNext()); rc = snd_pcm_writei(handle, buffer, SOUND_BUFFER_SIZE); - delete buffer; + delete[] buffer; if (rc == -EPIPE) { /* EPIPE means underrun */ cerr << "underrun occurred" << endl; diff --git a/src/Nio/AlsaEngine.h b/src/Nio/AlsaEngine.h @@ -102,7 +102,7 @@ class AlsaEngine : public AudioOut//, MidiIn const short *buffer; void RunStuff(); - void OpenStuff(); + bool OpenStuff(); pthread_mutex_t close_m; }; diff --git a/src/Nio/AudioOut.cpp b/src/Nio/AudioOut.cpp @@ -16,6 +16,7 @@ You should have received a copy of the GNU General Public License along with yoshimi. If not, see <http://www.gnu.org/licenses/>. */ +#warning TODO remove threadStop in favor of enabled #include <iostream> #include <cstring> @@ -26,9 +27,9 @@ using namespace std; #include "AudioOut.h" AudioOut::AudioOut(OutMgr *out) - :manager(out),threadStop(false),enabled(false) + :samplerate(SAMPLE_RATE),nsamples(SOUND_BUFFER_SIZE), + manager(out),threadStop(false),enabled(false) { - cout << out; pthread_mutex_init(&outBuf_mutex, NULL); pthread_cond_init (&outBuf_cv, NULL); } @@ -38,17 +39,24 @@ AudioOut::~AudioOut() #warning TODO destroy other mutex } -void AudioOut::out(const Stereo<Sample> smps) +void AudioOut::out(Stereo<Sample> smps) { + if(samplerate != SAMPLE_RATE) { + smps.l().resample(SAMPLE_RATE,samplerate);//we need to resample + smps.r().resample(SAMPLE_RATE,samplerate);//we need to resample + cout << "bad system" << endl; + } + pthread_mutex_lock(&outBuf_mutex); - outBuf.push(smps); + outBuf.push_back(smps); pthread_cond_signal(&outBuf_cv); pthread_mutex_unlock(&outBuf_mutex); } -const Stereo<Sample> AudioOut::getNext() +const Stereo<Sample> AudioOut::popOne() { - const int BUFF_SIZE = 4; + cout << "popOne" << endl; + const int BUFF_SIZE = 6; Stereo<Sample> ans; pthread_mutex_lock(&outBuf_mutex); bool isEmpty = outBuf.empty(); @@ -66,8 +74,8 @@ const Stereo<Sample> AudioOut::getNext() { pthread_mutex_lock(&outBuf_mutex); ans = outBuf.front(); - outBuf.pop(); - if(outBuf.size()+manager->getRunning()<4) + outBuf.pop_front(); + if(outBuf.size()+manager->getRunning()<BUFF_SIZE) manager->requestSamples(BUFF_SIZE - (outBuf.size() + manager->getRunning())); if(false) @@ -77,3 +85,47 @@ const Stereo<Sample> AudioOut::getNext() current=ans; return ans; } + +//hopefully this does not need to be called +//(it can cause a horrible mess with the current starvation behavior) +void AudioOut::putBack(const Stereo<Sample> smp) +{ + cout << "putBack"<< endl; + pthread_mutex_lock(&outBuf_mutex); + outBuf.push_front(smp); + pthread_mutex_unlock(&outBuf_mutex); +} + +const Stereo<Sample> AudioOut::getNext(int smps) +{ + cout << "getNext" << endl; + + if(smps<1) + smps = nsamples; + + Stereo<Sample> ans = popOne(); + + cout << "ans.l().size()" << ans.l().size() << endl; + + //if everything is perfectly configured, this should not need to loop + while(ans.l().size()!=smps) { + cout << "hi" << endl; + if(ans.l().size() > smps) { + //subsample/putback excess +#warning TODO check for off by one errors + putBack(Stereo<Sample>(ans.l().subSample(smps,ans.l().size()), + ans.l().subSample(smps,ans.l().size()))); + ans = Stereo<Sample>(ans.l().subSample(0,smps), + ans.l().subSample(0,smps)); + cout << "ans.l().size()" << ans.l().size() << endl; + } + else { + Stereo<Sample> next = popOne(); + ans.l().append(next.l()); + ans.r().append(next.r()); + cout << "ans.l().size()" << ans.l().size() << endl; + } + } + + return ans; +} diff --git a/src/Nio/AudioOut.h b/src/Nio/AudioOut.h @@ -23,7 +23,7 @@ #include "../Misc/Stereo.h" #include "../Samples/Sample.h" -#include <queue> +#include <deque> #include <pthread.h> #include "OutMgr.h" #include "../Misc/Atomic.h" @@ -40,7 +40,7 @@ class AudioOut virtual void Stop()=0; /**Give the Driver Samples to process*/ - virtual void out(const Stereo<Sample> smps); + virtual void out(Stereo<Sample> smps); /**Determines if new operator should/can be used*/ virtual bool isEnabled() const {return enabled();}; @@ -48,18 +48,32 @@ class AudioOut * @return 0 for stoped, 1 for running*/ virtual int state() const {return enabled();}; + /**Sets the Sample Rate of this Output + * (used for getNext()).*/ + void setSamplerate(int _samplerate) {samplerate=_samplerate;}; + + /**Sets the Samples required per Out of this driver + * (used for getNext()).*/ + void setNsamples(int _nsamples) {nsamples=_nsamples;}; + protected: - /**Get the next sample for output.*/ - virtual const Stereo<Sample> getNext(); - std::queue<Stereo<Sample> > outBuf; + const Stereo<Sample> popOne(); + void putBack(const Stereo<Sample> smp); + /**Get the next sample for output. + * (has nsamples sampled at a rate of samplerate)*/ + virtual const Stereo<Sample> getNext(int smps = -1); + + int samplerate; + int nsamples; + + std::deque<Stereo<Sample> > outBuf; const Sample * curSmp; Stereo<Sample> current; pthread_mutex_t outBuf_mutex; pthread_cond_t outBuf_cv; OutMgr *manager; -#warning TODO remove threadStop in favor of enabled //thread resources Atomic<bool> threadStop; pthread_t pThread; diff --git a/src/Nio/JackEngine.cpp b/src/Nio/JackEngine.cpp @@ -81,6 +81,8 @@ bool JackEngine::connectServer(string server) bool JackEngine::Start() { + if(enabled()) + return true; enabled = true; connectServer(""); openAudio(); @@ -194,21 +196,10 @@ bool JackEngine::processAudio(jack_nframes_t nframes) } } - Stereo<Sample> smp = getNext(); + Stereo<Sample> smp = getNext(nframes); //cout << "smp size of: " << smp.l().size() << endl; memcpy(audio.portBuffs[0], smp.l().c_buf(), smp.l().size()*sizeof(REALTYPE)); memcpy(audio.portBuffs[1], smp.r().c_buf(), smp.r().size()*sizeof(REALTYPE)); - //todo figure out how to do this right! - smp = getNext(); - memcpy(audio.portBuffs[0]+smp.l().size(), smp.l().c_buf(), smp.l().size()*sizeof(REALTYPE)); - memcpy(audio.portBuffs[1]+smp.r().size(), smp.r().c_buf(), smp.r().size()*sizeof(REALTYPE)); - smp = getNext(); - memcpy(audio.portBuffs[0]+2*smp.l().size(), smp.l().c_buf(), smp.l().size()*sizeof(REALTYPE)); - memcpy(audio.portBuffs[1]+2*smp.r().size(), smp.r().c_buf(), smp.r().size()*sizeof(REALTYPE)); - smp = getNext(); - memcpy(audio.portBuffs[0]+3*smp.l().size(), smp.l().c_buf(), smp.l().size()*sizeof(REALTYPE)); - memcpy(audio.portBuffs[1]+3*smp.r().size(), smp.r().c_buf(), smp.r().size()*sizeof(REALTYPE)); - return true; } diff --git a/src/Nio/WavEngine.cpp b/src/Nio/WavEngine.cpp @@ -27,7 +27,6 @@ WavEngine::WavEngine(OutMgr *out, string _filename, int _samplerate, int _channe :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); } @@ -35,14 +34,12 @@ WavEngine::WavEngine(OutMgr *out, string _filename, int _samplerate, int _channe WavEngine::~WavEngine() { - //TODO cleanup mutex +#warning 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; @@ -67,14 +64,7 @@ bool WavEngine::Start() 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() @@ -133,8 +123,7 @@ const Stereo<Sample> WavEngine::getNext() } pthread_mutex_lock(&outBuf_mutex); ans = outBuf.front(); - outBuf.pop(); - //cout << "Wav Out: " << outBuf.size()<<'+'<<manager->getRunning() << endl; + outBuf.pop_front(); pthread_mutex_unlock(&outBuf_mutex); return ans; } @@ -155,9 +144,6 @@ 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()) { @@ -167,13 +153,7 @@ void *WavEngine::AudioThread() 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; } diff --git a/src/Samples/Sample.cpp b/src/Samples/Sample.cpp @@ -149,7 +149,7 @@ void Sample::resample(const unsigned int rate, const unsigned int nrate) ceil((i+1)/ratio)); //put the new data in - delete buffer; + delete[] buffer; buffer = nBuffer; bufferSize = nBufferSize; } @@ -162,12 +162,17 @@ void Sample::append(const Sample &smp) memcpy(nbuffer, buffer, bufferSize * sizeof(float)); memcpy(nbuffer + bufferSize, smp.buffer, smp.bufferSize * sizeof(float)); - delete buffer; + delete[] buffer; buffer = nbuffer; bufferSize = nbufferSize; } +Sample Sample::subSample(int a, int b) const +{ + return Sample(b-a, buffer+a); +} + REALTYPE Sample::max() const { REALTYPE max = -1500; //a good low considering that samples should store values -1.0 to 1.0 diff --git a/src/Samples/Sample.h b/src/Samples/Sample.h @@ -64,6 +64,9 @@ class Sample /**Appends another Sample to this Sample*/ void append(const Sample &smp); + /**Gets a subsample from a to b*/ + Sample subSample(int a, int b) const; + REALTYPE max() const; REALTYPE min() const; REALTYPE absMax() const;