commit 6685c8cfe0df5e2daf6d893abc8357e1389131ba
parent 6063bcaa3de6faa77d4eee5d0853693d145bb62f
Author: fundamental <[email protected]>
Date: Fri, 12 Feb 2010 16:24:04 -0500
Nio: Restructuring
Warning this is a messy commit because the local copy was not updating the
remote often enough
Diffstat:
29 files changed, 693 insertions(+), 662 deletions(-)
diff --git a/src/Misc/Util.h b/src/Misc/Util.h
@@ -69,5 +69,11 @@ T stringTo(const char *x)
return ans;
}
+template <class T>
+T limit(T val, T min, T max)
+{
+ return (val < min ? min : (val > max ? max : val));
+}
+
#endif
diff --git a/src/Nio/AlsaEngine.cpp b/src/Nio/AlsaEngine.cpp
@@ -33,9 +33,7 @@ AlsaEngine::AlsaEngine(OutMgr *out)
{
name = "ALSA";
audio.handle = NULL;
- audio.en = true;
- midi.en = true;
midi.handle = NULL;
midi.alsaId = -1;
midi.pThread = 0;
@@ -61,62 +59,41 @@ void *AlsaEngine::AudioThread()
bool AlsaEngine::Start()
{
- if(enabled())
- return true;
- enabled = true;
- if(audio.en)
- openAudio();
- if(midi.en)
- openMidi();
-
- return true;
+ return openAudio() && openMidi();
}
void AlsaEngine::Stop()
{
- if(!enabled())
- return;
- enabled = false;
-
-
+ if(getMidiEn())
+ setMidiEn(false);
+ if(getAudioEn())
+ setAudioEn(false);
}
void AlsaEngine::setMidiEn(bool nval)
{
- midi.en = nval;
- if(enabled()) {
- if(nval)
- openMidi();
- else
- stopMidi();
- }
+ if(nval)
+ openMidi();
+ else
+ stopMidi();
}
bool AlsaEngine::getMidiEn() const
{
- if(enabled())
- return midi.handle;
- else
- return midi.en;
+ return midi.handle;
}
void AlsaEngine::setAudioEn(bool nval)
{
- audio.en = nval;
- if(enabled()) {
- if(nval)
- openAudio();
- else
- stopAudio();
- }
+ if(nval)
+ openAudio();
+ else
+ stopAudio();
}
bool AlsaEngine::getAudioEn() const
{
- if(enabled())
- return audio.handle;
- else
- return audio.en;
+ return audio.handle;
}
void *AlsaEngine::_MidiThread(void *arg)
@@ -130,91 +107,91 @@ void *AlsaEngine::MidiThread(void)
snd_seq_event_t *event;
MidiEvent ev;
set_realtime();
- while (enabled())
+ while (snd_seq_event_input(midi.handle, &event) > 0)
{
- while (snd_seq_event_input(midi.handle, &event) > 0)
+ //ensure ev is empty
+ ev.channel = 0;
+ ev.num = 0;
+ ev.value = 0;
+ ev.type = 0;
+
+ if (!event)
+ continue;
+ switch (event->type)
{
- //ensure ev is empty
- ev.channel = 0;
- ev.num = 0;
- ev.value = 0;
- ev.type = 0;
-
- if (!event)
- continue;
- switch (event->type)
- {
- case SND_SEQ_EVENT_NOTEON:
- if (event->data.note.note)
- {
- ev.type = M_NOTE;
- ev.channel = event->data.note.channel;
- ev.num = event->data.note.note;
- ev.value = event->data.note.velocity;
- sysIn->putEvent(ev);
- }
- break;
-
- case SND_SEQ_EVENT_NOTEOFF:
+ case SND_SEQ_EVENT_NOTEON:
+ if (event->data.note.note)
+ {
ev.type = M_NOTE;
ev.channel = event->data.note.channel;
ev.num = event->data.note.note;
- ev.value = 0;
- sysIn->putEvent(ev);
- break;
-
- case SND_SEQ_EVENT_PITCHBEND:
- ev.type = M_CONTROLLER;
- ev.channel = event->data.control.channel;
- ev.num = C_pitchwheel;
- ev.value = event->data.control.value;
- sysIn->putEvent(ev);
- break;
-
- case SND_SEQ_EVENT_CONTROLLER:
- ev.type = M_CONTROLLER;
- ev.channel = event->data.control.channel;
- ev.num = event->data.control.param;
- ev.value = event->data.control.value;
- sysIn->putEvent(ev);
- break;
-
- case SND_SEQ_EVENT_RESET: // reset to power-on state
- ev.type = M_CONTROLLER;
- ev.channel = event->data.control.channel;
- ev.num = C_resetallcontrollers;
- ev.value = 0;
+ ev.value = event->data.note.velocity;
sysIn->putEvent(ev);
- break;
-
- case SND_SEQ_EVENT_PORT_SUBSCRIBED: // ports connected
- if (true)
- cout << "Info, alsa midi port connected" << endl;
- break;
-
- case SND_SEQ_EVENT_PORT_UNSUBSCRIBED: // ports disconnected
- if (true)
- cout << "Info, alsa midi port disconnected" << endl;
- break;
-
- case SND_SEQ_EVENT_SYSEX: // system exclusive
- case SND_SEQ_EVENT_SENSING: // midi device still there
- break;
-
- default:
- if (true)
- cout << "Info, other non-handled midi event, type: "
- << (int)event->type << endl;
- break;
- }
- snd_seq_free_event(event);
+ }
+ break;
+
+ case SND_SEQ_EVENT_NOTEOFF:
+ ev.type = M_NOTE;
+ ev.channel = event->data.note.channel;
+ ev.num = event->data.note.note;
+ ev.value = 0;
+ sysIn->putEvent(ev);
+ break;
+
+ case SND_SEQ_EVENT_PITCHBEND:
+ ev.type = M_CONTROLLER;
+ ev.channel = event->data.control.channel;
+ ev.num = C_pitchwheel;
+ ev.value = event->data.control.value;
+ sysIn->putEvent(ev);
+ break;
+
+ case SND_SEQ_EVENT_CONTROLLER:
+ ev.type = M_CONTROLLER;
+ ev.channel = event->data.control.channel;
+ ev.num = event->data.control.param;
+ ev.value = event->data.control.value;
+ sysIn->putEvent(ev);
+ break;
+
+ case SND_SEQ_EVENT_RESET: // reset to power-on state
+ ev.type = M_CONTROLLER;
+ ev.channel = event->data.control.channel;
+ ev.num = C_resetallcontrollers;
+ ev.value = 0;
+ sysIn->putEvent(ev);
+ break;
+
+ case SND_SEQ_EVENT_PORT_SUBSCRIBED: // ports connected
+ if (true)
+ cout << "Info, alsa midi port connected" << endl;
+ break;
+
+ case SND_SEQ_EVENT_PORT_UNSUBSCRIBED: // ports disconnected
+ if (true)
+ cout << "Info, alsa midi port disconnected" << endl;
+ break;
+
+ case SND_SEQ_EVENT_SYSEX: // system exclusive
+ case SND_SEQ_EVENT_SENSING: // midi device still there
+ break;
+
+ default:
+ if (true)
+ cout << "Info, other non-handled midi event, type: "
+ << (int)event->type << endl;
+ break;
}
+ snd_seq_free_event(event);
}
return NULL;
}
bool AlsaEngine::openMidi()
{
+ if(getMidiEn())
+ return true;
+
int alsaport;
midi.handle = NULL;
@@ -242,11 +219,15 @@ bool AlsaEngine::openMidi()
void AlsaEngine::stopMidi()
{
+ if(!getMidiEn())
+ return;
+
+ snd_seq_t *handle = midi.handle;
if (NULL != midi.handle && midi.pThread)
pthread_cancel(midi.pThread);
midi.handle = NULL;
- if(midi.handle)
- snd_seq_close(midi.handle);
+ if(handle)
+ snd_seq_close(handle);
}
const short *AlsaEngine::interleave(const Stereo<Sample> smps)const
@@ -268,6 +249,9 @@ const short *AlsaEngine::interleave(const Stereo<Sample> smps)const
bool AlsaEngine::openAudio()
{
+ if(getAudioEn())
+ return true;
+
int rc = 0;
/* Open PCM device for playback. */
audio.handle=NULL;
@@ -288,10 +272,9 @@ bool AlsaEngine::openAudio()
/* Set the desired hardware parameters. */
-#warning TODO Make Access noninterleaved
/* Interleaved mode */
snd_pcm_hw_params_set_access(audio.handle, audio.params,
- SND_PCM_ACCESS_RW_INTERLEAVED);
+ SND_PCM_ACCESS_RW_NONINTERLEAVED);
/* Signed 16-bit little-endian format */
snd_pcm_hw_params_set_format(audio.handle, audio.params,
@@ -333,6 +316,9 @@ bool AlsaEngine::openAudio()
void AlsaEngine::stopAudio()
{
+ if(!getAudioEn())
+ return;
+
snd_pcm_t *handle = audio.handle;
audio.handle = NULL;
pthread_join(audio.pThread, NULL);
diff --git a/src/Nio/AlsaEngine.h b/src/Nio/AlsaEngine.h
@@ -64,12 +64,9 @@ class AlsaEngine : public AudioOut, MidiIn
snd_seq_t *handle;
int alsaId;
pthread_t pThread;
- bool en;
} midi;
struct {
- bool en;
- bool run;
snd_pcm_t *handle;
snd_pcm_hw_params_t *params;
unsigned int sampleRate;
diff --git a/src/Nio/AudioOut.cpp b/src/Nio/AudioOut.cpp
@@ -22,134 +22,168 @@
#include <iostream>
#include <cstring>
+#include "SafeQueue.h"
using namespace std;
+#include "OutMgr.h"
#include "../Misc/Master.h"
#include "AudioOut.h"
-AudioOut::AudioOut(OutMgr *out)
+struct AudioOut::Data
+{
+ Data(OutMgr *out);
+
+ int samplerate;
+ int bufferSize;
+
+ SafeQueue<Stereo<Sample> > outBuf;
+ pthread_mutex_t outBuf_mutex;
+ pthread_cond_t outBuf_cv;
+
+ /**used for taking in samples with a different
+ * samplerate/buffersize*/
+ Stereo<Sample> partialIn;
+ bool usePartial;
+ Stereo<Sample> current;/**<used for xrun defence*/
+
+ //The number of Samples that are used to buffer
+ //Note: there is some undetermined behavior when:
+ //sampleRate!=SAMPLE_RATE || bufferSize!=SOUND_BUFFER_SIZE
+ unsigned int buffering;
+
+ OutMgr *manager;
+};
+
+AudioOut::Data::Data(OutMgr *out)
:samplerate(SAMPLE_RATE),bufferSize(SOUND_BUFFER_SIZE),
- usePartial(false),current(Sample(SOUND_BUFFER_SIZE,0.0)),
- buffering(6),manager(out)
+ outBuf(100),usePartial(false),
+ current(Sample(SOUND_BUFFER_SIZE,0.0)),buffering(6),
+ manager(out)
+{}
+
+AudioOut::AudioOut(OutMgr *out)
+ :dat(new Data(out))
{
- pthread_mutex_init(&outBuf_mutex, NULL);
- pthread_cond_init(&outBuf_cv, NULL);
+ pthread_mutex_init(&dat->outBuf_mutex, NULL);
+ pthread_cond_init(&dat->outBuf_cv, NULL);
}
AudioOut::~AudioOut()
{
- pthread_mutex_destroy(&outBuf_mutex);
- pthread_cond_destroy(&outBuf_cv);
+ pthread_mutex_destroy(&dat->outBuf_mutex);
+ pthread_cond_destroy(&dat->outBuf_cv);
+ delete dat;
}
void AudioOut::out(Stereo<Sample> smps)
{
- pthread_mutex_lock(&outBuf_mutex);
- if(samplerate != SAMPLE_RATE) { //we need to resample
- smps.l().resample(SAMPLE_RATE,samplerate);
- smps.r().resample(SAMPLE_RATE,samplerate);
+ pthread_mutex_lock(&dat->outBuf_mutex);
+ if(dat->samplerate != SAMPLE_RATE) { //we need to resample
+ smps.l().resample(SAMPLE_RATE,dat->samplerate);
+ smps.r().resample(SAMPLE_RATE,dat->samplerate);
}
- if(usePartial) { //we have a partial to use
- smps.l() = partialIn.l().append(smps.l());
- smps.r() = partialIn.r().append(smps.r());
+ if(dat->usePartial) { //we have a partial to use
+ smps.l() = dat->partialIn.l().append(smps.l());
+ smps.r() = dat->partialIn.r().append(smps.r());
}
- if(smps.l().size() == bufferSize) { //sized just right
- outBuf.push(smps);
- usePartial = false;
- pthread_cond_signal(&outBuf_cv);
+ if(smps.l().size() == dat->bufferSize) { //sized just right
+ dat->outBuf.push(smps);
+ dat->usePartial = false;
+ pthread_cond_signal(&dat->outBuf_cv);
}
- else if(smps.l().size() > bufferSize) { //store overflow
+ else if(smps.l().size() > dat->bufferSize) { //store overflow
- while(smps.l().size() > bufferSize) {
- outBuf.push(Stereo<Sample>(smps.l().subSample(0,bufferSize),
- smps.r().subSample(0,bufferSize)));
- smps = Stereo<Sample>(smps.l().subSample(bufferSize,smps.l().size()),
- smps.r().subSample(bufferSize,smps.r().size()));
+ while(smps.l().size() > dat->bufferSize) {
+ dat->outBuf.push(Stereo<Sample>(smps.l().subSample(0,dat->bufferSize),
+ smps.r().subSample(0,dat->bufferSize)));
+ smps = Stereo<Sample>(smps.l().subSample(dat->bufferSize,smps.l().size()),
+ smps.r().subSample(dat->bufferSize,smps.r().size()));
}
- if(smps.l().size() == bufferSize) { //no partial
- outBuf.push(smps);
- usePartial = false;
+ if(smps.l().size() == dat->bufferSize) { //no partial
+ dat->outBuf.push(smps);
+ dat->usePartial = false;
}
else { //partial
- partialIn = smps;
- usePartial = true;
+ dat->partialIn = smps;
+ dat->usePartial = true;
}
- pthread_cond_signal(&outBuf_cv);
+ pthread_cond_signal(&dat->outBuf_cv);
}
else { //underflow
- partialIn = smps;
- usePartial = true;
+ dat->partialIn = smps;
+ dat->usePartial = true;
}
- pthread_mutex_unlock(&outBuf_mutex);
+ pthread_mutex_unlock(&dat->outBuf_mutex);
}
void AudioOut::setSamplerate(int _samplerate)
{
- pthread_mutex_lock(&outBuf_mutex);
- usePartial = false;
- samplerate = _samplerate;
- //hm, the queue does not have a clear
- while(!outBuf.empty())
- outBuf.pop();
- pthread_mutex_unlock(&outBuf_mutex);
+ pthread_mutex_lock(&dat->outBuf_mutex);
+ dat->usePartial = false;
+ dat->samplerate = _samplerate;
+ dat->outBuf.clear();
+ pthread_mutex_unlock(&dat->outBuf_mutex);
}
void AudioOut::setBufferSize(int _bufferSize)
{
- pthread_mutex_lock(&outBuf_mutex);
- usePartial = false;
- bufferSize = _bufferSize;
- //hm, the queue does not have a clear
- while(!outBuf.empty())
- outBuf.pop();
- pthread_mutex_unlock(&outBuf_mutex);
-};
+ pthread_mutex_lock(&dat->outBuf_mutex);
+ dat->usePartial = false;
+ dat->bufferSize = _bufferSize;
+ dat->outBuf.clear();
+ pthread_mutex_unlock(&dat->outBuf_mutex);
+}
void AudioOut::bufferingSize(int nBuffering)
{
- buffering = nBuffering;
+ dat->buffering = nBuffering;
}
int AudioOut::bufferingSize()
{
- return buffering;
+ return dat->buffering;
}
-
-const Stereo<Sample> AudioOut::getNext()
+const Stereo<Sample> AudioOut::getNext(bool wait)
{
- const unsigned int BUFF_SIZE = buffering;
+ const unsigned int BUFF_SIZE = dat->buffering;
Stereo<Sample> ans;
- pthread_mutex_lock(&outBuf_mutex);
- bool isEmpty = outBuf.empty();
- pthread_mutex_unlock(&outBuf_mutex);
+ pthread_mutex_lock(&dat->outBuf_mutex);
+ bool isEmpty = !dat->outBuf.size();
+ pthread_mutex_unlock(&dat->outBuf_mutex);
if(isEmpty)//fetch samples if possible
{
- if((unsigned int)manager->getRunning() < BUFF_SIZE)
- manager->requestSamples(BUFF_SIZE-manager->getRunning());
+ if((unsigned int)dat->manager->getRunning() < BUFF_SIZE)
+ dat->manager->requestSamples(BUFF_SIZE-dat->manager->getRunning());
if(true)
cout << "-----------------Starvation------------------"<< endl;
- return current;
- }
- else
- {
- pthread_mutex_lock(&outBuf_mutex);
- ans = outBuf.front();
- outBuf.pop();
- if(outBuf.size()+manager->getRunning()<BUFF_SIZE)
- manager->requestSamples(BUFF_SIZE - (outBuf.size()
- + manager->getRunning()));
- if(false)
- cout << "AudioOut "<< outBuf.size()<< '+' << manager->getRunning() << endl;
- pthread_mutex_unlock(&outBuf_mutex);
+ if(wait)
+ {
+ pthread_mutex_lock(&dat->outBuf_mutex);
+ pthread_cond_wait(&dat->outBuf_cv,&dat->outBuf_mutex);
+ pthread_mutex_unlock(&dat->outBuf_mutex);
+ //now the code has a sample to fetch
+ }
+ else
+ return dat->current;
}
- current=ans;
+
+ pthread_mutex_lock(&dat->outBuf_mutex);
+ dat->outBuf.pop(ans);
+ if(dat->outBuf.size()+dat->manager->getRunning()<BUFF_SIZE)
+ dat->manager->requestSamples(BUFF_SIZE - (dat->outBuf.size()
+ + dat->manager->getRunning()));
+ if(false)
+ cout << "AudioOut "<< dat->outBuf.size()<< '+' << dat->manager->getRunning() << endl;
+ pthread_mutex_unlock(&dat->outBuf_mutex);
+
+ dat->current = ans;
return ans;
}
diff --git a/src/Nio/AudioOut.h b/src/Nio/AudioOut.h
@@ -25,16 +25,12 @@
#include "../Misc/Stereo.h"
#include "../Samples/Sample.h"
-#include <queue>
-#include <pthread.h>
-#include "OutMgr.h"
-#include "../Misc/Atomic.h"
#include "Engine.h"
class AudioOut : public virtual Engine
{
public:
- AudioOut(OutMgr *out);
+ AudioOut(class OutMgr *out);
virtual ~AudioOut();
/**Give the Driver Samples to process*/
@@ -60,29 +56,11 @@ class AudioOut : public virtual Engine
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();
+ const Stereo<Sample> getNext(bool wait = false);
- int samplerate;
- int bufferSize;
-
- std::queue<Stereo<Sample> > outBuf;
- pthread_mutex_t outBuf_mutex;
- pthread_cond_t outBuf_cv;
-
- /**used for taking in samples with a different
- * samplerate/buffersize*/
- Stereo<Sample> partialIn;
- bool usePartial;
- Stereo<Sample> current;/**<used for xrun defence*/
-
- //The number of Samples that are used to buffer
- //Note: there is some undetermined behavior when:
- //sampleRate!=SAMPLE_RATE || bufferSize!=SOUND_BUFFER_SIZE
- unsigned int buffering;
-
- OutMgr *manager;
- //thread resources
- pthread_t pThread;
+ //using opaque pointer to reduce compile times
+ struct Data;
+ Data *dat;
};
#endif
diff --git a/src/Nio/CMakeLists.txt b/src/Nio/CMakeLists.txt
@@ -7,6 +7,7 @@ set(zynaddsubfx_nio_SRCS
WavEngine.cpp
NulEngine.cpp
AudioOut.cpp
+ MidiIn.cpp
OutMgr.cpp
InMgr.cpp
Engine.cpp
diff --git a/src/Nio/Engine.cpp b/src/Nio/Engine.cpp
@@ -22,13 +22,8 @@
#include "Engine.h"
Engine::Engine()
- :enabled(false)
{};
Engine::~Engine()
{};
-bool Engine::isRunning() const
-{
- return enabled();
-}
diff --git a/src/Nio/Engine.h b/src/Nio/Engine.h
@@ -23,7 +23,6 @@
#ifndef ENGINE_H
#define ENGINE_H
#include <string>
-#include "../Misc/Atomic.h"
/**Marker for input/output driver*/
class Engine
{
@@ -31,17 +30,12 @@ class Engine
Engine();
virtual ~Engine();
- /**Start the Driver
+ /**Start the Driver with all capabilities
* @return true on success*/
virtual bool Start()=0;
- /**Stop the Driver*/
+ /**Completely stop the Driver*/
virtual void Stop()=0;
- /**Retruns if engine is on*/
- bool isRunning() const;
-
std::string name;
- protected:
- Atomic<bool> enabled;
};
#endif
diff --git a/src/Nio/EngineMgr.cpp b/src/Nio/EngineMgr.cpp
@@ -1,6 +1,7 @@
#include "EngineMgr.h"
#include <algorithm>
#include <iostream>
+#include "OutMgr.h"
#include "AudioOut.h"
#include "NulEngine.h"
#if OSS
@@ -76,3 +77,10 @@ Engine *EngineMgr::getEng(string name)
return NULL;
}
+void EngineMgr::stop()
+{
+ for(list<Engine*>::iterator itr = engines.begin();
+ itr != engines.end(); ++itr)
+ (*itr)->Stop();
+}
+
diff --git a/src/Nio/EngineMgr.h b/src/Nio/EngineMgr.h
@@ -10,9 +10,8 @@ class MidiIn;
class AudioOut;
class OutMgr;
/**Container/Owner of the long lived Engines*/
-class EngineMgr
+struct EngineMgr
{
- public:
EngineMgr();
~EngineMgr();
@@ -22,15 +21,12 @@ class EngineMgr
*/
Engine *getEng(std::string name);
- private:
+ /**Stop all engines*/
+ void stop();
+
std::list<Engine *> engines;
Engine *defaultEng;/**<The default output*/
-
- //Engine Manager user
- //[if there is another 'user, just make this class a struct]
- friend class OutMgr;
- friend class NioUI;
};
extern EngineMgr *sysEngine;
diff --git a/src/Nio/InMgr.cpp b/src/Nio/InMgr.cpp
@@ -1,4 +1,7 @@
#include "InMgr.h"
+#include "MidiIn.h"
+#include "EngineMgr.h"
+#include "../Misc/Master.h"
#include <iostream>
using namespace std;
@@ -86,3 +89,35 @@ void *InMgr::inputThread()
return NULL;
}
+bool InMgr::setSource(string name)
+{
+ MidiIn *src = NULL;
+ for(list<Engine*>::iterator itr = sysEngine->engines.begin();
+ itr != sysEngine->engines.end(); ++itr) {
+ MidiIn *in = dynamic_cast<MidiIn *>(*itr);
+ if(in) {
+ if(in->name == name)
+ src = in;
+ else
+ in->setMidiEn(false);
+ }
+ }
+
+ if(!src)
+ return false;
+
+ src->setMidiEn(true);
+
+ return src->getMidiEn();
+}
+
+string InMgr::getSource() const
+{
+ for(list<Engine*>::iterator itr = sysEngine->engines.begin();
+ itr != sysEngine->engines.end(); ++itr) {
+ MidiIn *in = dynamic_cast<MidiIn *>(*itr);
+ if(in && in->getMidiEn())
+ return in->name;
+ }
+}
+
diff --git a/src/Nio/InMgr.h b/src/Nio/InMgr.h
@@ -4,7 +4,6 @@
#include <string>
#include <pthread.h>
#include <semaphore.h>
-#include "../Misc/Master.h"
#include "../Misc/Atomic.h"
#include "SafeQueue.h"
@@ -37,6 +36,10 @@ class InMgr
void *inputThread();
+ bool setSource(std::string name);
+
+ std::string getSource() const;
+
private:
SafeQueue<MidiEvent> queue;
sem_t work;
diff --git a/src/Nio/JackEngine.cpp b/src/Nio/JackEngine.cpp
@@ -33,8 +33,6 @@ using namespace std;
JackEngine::JackEngine(OutMgr *out)
:AudioOut(out), jackClient(NULL)
{
- midi.en = true;
- audio.en = true;
name = "JACK";
audio.jackSamplerate = 0;
audio.jackNframes = 0;
@@ -47,46 +45,35 @@ JackEngine::JackEngine(OutMgr *out)
bool JackEngine::connectServer(string server)
{
- //temporary (move to a higher level configuation)
bool autostart_jack = true;
+ if(jackClient)
+ return true;
- if (NULL == jackClient) // ie, not already connected
- {
- string clientname = "zynaddsubfx";
- jack_status_t jackstatus;
- bool use_server_name = server.size() && server.compare("default") != 0;
- jack_options_t jopts = (jack_options_t)
- (((use_server_name) ? JackServerName : JackNullOption)
- | ((autostart_jack) ? JackNullOption : JackNoStartServer));
- if (use_server_name)
- jackClient = jack_client_open(clientname.c_str(), jopts, &jackstatus,
- server.c_str());
- else
- jackClient = jack_client_open(clientname.c_str(), jopts, &jackstatus);
- if (NULL != jackClient)
- return true;
- else
- cerr << "Error, failed to open jack client on server: " << server
- << " status " << jackstatus << endl;
- return false;
- }
+ string clientname = "zynaddsubfx";
+ jack_status_t jackstatus;
+ bool use_server_name = server.size() && server.compare("default") != 0;
+ jack_options_t jopts = (jack_options_t)
+ (((use_server_name) ? JackServerName : JackNullOption)
+ | ((autostart_jack) ? JackNullOption : JackNoStartServer));
+ if (use_server_name)
+ jackClient = jack_client_open(clientname.c_str(), jopts, &jackstatus,
+ server.c_str());
+ else
+ jackClient = jack_client_open(clientname.c_str(), jopts, &jackstatus);
+ if (NULL != jackClient)
+ return true;
+ else
+ cerr << "Error, failed to open jack client on server: " << server
+ << " status " << jackstatus << endl;
+ return false;
+
return true;
}
-bool JackEngine::Start()
+bool JackEngine::connectJack()
{
- cout << "Starting Jack" << endl;
- if(enabled())
- return true;
-
- enabled = true;
- if(!connectServer(""))
- goto bail_out;
- if(midi.en)
- openMidi();
- if(audio.en)
- openAudio();
+ connectServer("");
if (NULL != jackClient)
{
setBufferSize(jack_get_buffer_size(jackClient));
@@ -100,78 +87,76 @@ bool JackEngine::Start()
if (jack_set_process_callback(jackClient, _processCallback, this))
{
cerr << "Error, JackEngine failed to set process callback" << endl;
- goto bail_out;
+ return false;
}
if (jack_activate(jackClient))
{
cerr << "Error, failed to activate jack client" << endl;;
- goto bail_out;
+ return false;
}
return true;
}
else
cerr << "Error, NULL jackClient through Start()" << endl;
-bail_out:
- Stop();
return false;
}
-void JackEngine::Stop()
+void JackEngine::disconnectJack()
{
- cout << "Stopping Jack" << endl;
- if(!enabled())
- return;
- enabled = false;
- if (jackClient)
- {
- stopMidi();
- stopAudio();
+ if(jackClient) {
jack_client_close(jackClient);
jackClient = NULL;
}
}
+bool JackEngine::Start()
+{
+ return openMidi() && openAudio();
+}
+
+void JackEngine::Stop()
+{
+ stopMidi();
+ stopAudio();
+}
+
void JackEngine::setMidiEn(bool nval)
{
- midi.en = nval;
- if(enabled()) { //lets rebind the ports
- if(nval)
- openMidi();
- else
- stopMidi();
- }
+ if(nval)
+ openMidi();
+ else
+ stopMidi();
}
bool JackEngine::getMidiEn() const
{
- if(enabled())
- return midi.inport;
- else
- return midi.en;
+ return midi.inport;
}
void JackEngine::setAudioEn(bool nval)
{
- audio.en = nval;
- if(enabled()) { //lets rebind the ports
- if(nval)
- openAudio();
- else
- stopAudio();
- }
+ if(nval)
+ openAudio();
+ else
+ stopAudio();
}
bool JackEngine::getAudioEn() const
{
- if(enabled())
- return audio.ports[0];
- else
- return audio.en;
+ return audio.ports[0];
}
bool JackEngine::openAudio()
{
+ if(getAudioEn())
+ return true;
+
+ if(!getMidiEn())
+ if(!connectJack())
+ return false;
+
+
const char *portnames[] = { "left", "right" };
for (int port = 0; port < 2; ++port)
{
@@ -199,13 +184,22 @@ void JackEngine::stopAudio()
if (NULL != port)
jack_port_unregister(jackClient, port);
}
+ if(!getMidiEn())
+ disconnectJack();
}
bool JackEngine::openMidi()
{
- return midi.inport = jack_port_register(jackClient, "midi_input",
- JACK_DEFAULT_MIDI_TYPE,
- JackPortIsInput | JackPortIsTerminal, 0);
+ if(getMidiEn())
+ return true;
+ if(!getAudioEn())
+ if(!connectJack())
+ return false;
+
+ midi.inport = jack_port_register(jackClient, "midi_input",
+ JACK_DEFAULT_MIDI_TYPE,
+ JackPortIsInput | JackPortIsTerminal, 0);
+ return midi.inport;
}
void JackEngine::stopMidi()
@@ -214,6 +208,9 @@ void JackEngine::stopMidi()
midi.inport = NULL;
if(port)
jack_port_unregister(jackClient, port);
+
+ if(!getAudioEn())
+ disconnectJack();
}
int JackEngine::clientId()
diff --git a/src/Nio/JackEngine.h b/src/Nio/JackEngine.h
@@ -37,7 +37,6 @@ class JackEngine : public AudioOut, MidiIn
JackEngine(OutMgr *out);
~JackEngine() { };
- bool setServer(std::string server);
bool Start();
void Stop();
@@ -65,6 +64,8 @@ class JackEngine : public AudioOut, MidiIn
private:
bool connectServer(std::string server);
+ bool connectJack();
+ void disconnectJack();
bool openAudio();
void stopAudio();
bool processAudio(jack_nframes_t nframes);
@@ -72,16 +73,14 @@ class JackEngine : public AudioOut, MidiIn
void stopMidi();
jack_client_t *jackClient;
- struct {
- bool en;
+ struct audio{
unsigned int jackSamplerate;
unsigned int jackNframes;
jack_port_t *ports[2];
jsample_t *portBuffs[2];
} audio;
- struct {
+ struct midi{
jack_port_t *inport;
- bool en;
} midi;
void handleMidi(unsigned long frames);
diff --git a/src/Nio/MidiIn.cpp b/src/Nio/MidiIn.cpp
@@ -21,75 +21,42 @@
*/
#include "MidiIn.h"
+#include "../globals.h"
+#include "InMgr.h"
-int MidiIn::getcontroller(unsigned char b)
+void MidiIn::midiProcess(unsigned char head, unsigned char num, unsigned char value)
{
- /**\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;
+ MidiEvent ev;
+ unsigned char chan = head & 0x0f;
+ switch(head & 0xf0)
+ {
+ case 0x80: //Note Off
+ ev.type = M_NOTE;
+ ev.channel = chan;
+ ev.num = num;
+ ev.value = 0;
+ sysIn->putEvent(ev);
+ break;
+ case 0x90: //Note On
+ ev.type = M_NOTE;
+ ev.channel = chan;
+ ev.num = num;
+ ev.value = value;
+ sysIn->putEvent(ev);
+ break;
+ case 0xb0: //Controller
+ ev.type = M_CONTROLLER;
+ ev.channel = chan;
+ ev.num = num;
+ ev.value = value;
+ sysIn->putEvent(ev);
+ break;
+ case 0xe0: //Pitch Wheel
+ ev.type = M_CONTROLLER;
+ ev.channel = chan;
+ ev.num = C_pitchwheel;
+ ev.value = (num + value * (int) 128) - 8192;
+ sysIn->putEvent(ev);
+ break;
}
- return ctl;
}
-
diff --git a/src/Nio/MidiIn.h b/src/Nio/MidiIn.h
@@ -28,13 +28,13 @@
#include "Engine.h"
/**This class is inherited by all the Midi input classes*/
-class MidiIn : public virtual Engine
+struct MidiIn : public virtual Engine
{
- public:
- static int getcontroller(unsigned char b);
-
- virtual void setMidiEn(bool nval)=0;
- virtual bool getMidiEn() const=0;
+ /**Enables or disables driver based upon value*/
+ virtual void setMidiEn(bool nval)=0;
+ /**Returns if driver is initialized*/
+ virtual bool getMidiEn() const=0;
+ static void midiProcess(unsigned char head, unsigned char num, unsigned char value);
};
#endif
diff --git a/src/Nio/NulEngine.cpp b/src/Nio/NulEngine.cpp
@@ -28,88 +28,88 @@
using namespace std;
NulEngine::NulEngine(OutMgr *out)
- :AudioOut(out)
+ :AudioOut(out), pThread(NULL)
{
name = "NULL";
playing_until.tv_sec = 0;
playing_until.tv_usec = 0;
}
-
-
void *NulEngine::_AudioThread(void *arg)
{
return (static_cast<NulEngine*>(arg))->AudioThread();
}
-
void *NulEngine::AudioThread()
{
- while (enabled())
+ while(pThread)
{
const Stereo<Sample> smps = getNext();
- dummyOut();
- }
- pthread_exit(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);
+ 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)
- cerr << "WARNING - too late" << endl;
+ playing_until.tv_usec -= remaining;
+ playing_until.tv_sec += playing_until.tv_usec / 1000000;
+ playing_until.tv_usec %= 1000000;
}
- 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;
+ pthread_exit(NULL);
}
-
NulEngine::~NulEngine()
{
}
-
bool NulEngine::Start()
{
- if(enabled())
- return true;
- pthread_attr_t attr;
- enabled = true;
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
- pthread_create(&pThread, &attr, _AudioThread, this);
-
- return true;
+ setAudioEn(true);
+ return getAudioEn();
}
void NulEngine::Stop()
{
- if(!enabled())
- return;
- enabled = false;
- pthread_join(pThread, NULL);
+ setAudioEn(false);
}
void NulEngine::setAudioEn(bool nval)
-{}
+{
+ if(nval) {
+ if(!getAudioEn()) {
+ pthread_t *thread = new pthread_t;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+ pThread = thread;
+ pthread_create(pThread, &attr, _AudioThread, this);
+ }
+ }
+ else {
+ if(getAudioEn()) {
+ pthread_t *thread = pThread;
+ pThread = NULL;
+ pthread_join(*thread, NULL);
+ delete thread;
+ }
+ }
+}
bool NulEngine::getAudioEn() const
{
- return true;
+ return pThread;
}
diff --git a/src/Nio/NulEngine.h b/src/Nio/NulEngine.h
@@ -24,6 +24,7 @@
#define NUL_ENGINE_H
#include <sys/time.h>
+#include <pthread.h>
#include "../globals.h"
#include "AudioOut.h"
@@ -44,9 +45,8 @@ class NulEngine: public AudioOut
static void *_AudioThread(void *arg);
private:
- bool en;
- void dummyOut();
struct timeval playing_until;
+ pthread_t *pThread;
};
#endif
diff --git a/src/Nio/OssEngine.cpp b/src/Nio/OssEngine.cpp
@@ -43,8 +43,8 @@ OssEngine::OssEngine(OutMgr *out)
{
name = "OSS";
- midi.en = true;
- audio.en = true;
+ midi.handle = -1;
+ audio.handle = -1;
audio.smps = new short[SOUND_BUFFER_SIZE * 2];
memset(audio.smps, 0, sizeof(short) * SOUND_BUFFER_SIZE * 2);
@@ -58,144 +58,142 @@ OssEngine::~OssEngine()
bool OssEngine::openAudio()
{
+ if(audio.handle != -1)
+ return true; //already open
+
int snd_bitsize = 16;
int snd_fragment = 0x00080009; //fragment size (?);
int snd_stereo = 1; //stereo;
int snd_format = AFMT_S16_LE;
int snd_samplerate = SAMPLE_RATE;;
- audio.snd_handle = open(config.cfg.LinuxOSSWaveOutDev, O_WRONLY, 0);
- if(audio.snd_handle == -1) {
+ audio.handle = open(config.cfg.LinuxOSSWaveOutDev, O_WRONLY, 0);
+ if(audio.handle == -1) {
cerr << "ERROR - I can't open the "
<< config.cfg.LinuxOSSWaveOutDev << '.' << endl;
- stopAudio();
return false;
}
- ioctl(audio.snd_handle, SNDCTL_DSP_RESET, NULL);
- ioctl(audio.snd_handle, SNDCTL_DSP_SETFMT, &snd_format);
- ioctl(audio.snd_handle, SNDCTL_DSP_STEREO, &snd_stereo);
- ioctl(audio.snd_handle, SNDCTL_DSP_SPEED, &snd_samplerate);
- ioctl(audio.snd_handle, SNDCTL_DSP_SAMPLESIZE, &snd_bitsize);
- ioctl(audio.snd_handle, SNDCTL_DSP_SETFRAGMENT, &snd_fragment);
+ ioctl(audio.handle, SNDCTL_DSP_RESET, NULL);
+ ioctl(audio.handle, SNDCTL_DSP_SETFMT, &snd_format);
+ ioctl(audio.handle, SNDCTL_DSP_STEREO, &snd_stereo);
+ ioctl(audio.handle, SNDCTL_DSP_SPEED, &snd_samplerate);
+ ioctl(audio.handle, SNDCTL_DSP_SAMPLESIZE, &snd_bitsize);
+ ioctl(audio.handle, SNDCTL_DSP_SETFRAGMENT, &snd_fragment);
+
+ if(!getMidiEn()) {
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+ engThread = new pthread_t;
+ pthread_create(engThread, &attr, _thread, this);
+ }
return true;
}
void OssEngine::stopAudio()
{
- int handle = audio.snd_handle;
+ int handle = audio.handle;
if(handle == -1) //already closed
return;
- audio.snd_handle = -1;
+ audio.handle = -1;
+
+ if(!getMidiEn())
+ pthread_join(*engThread, NULL);
+ delete engThread;
+ engThread = NULL;
+
close(handle);
}
bool OssEngine::Start()
{
- if(enabled())
- return true;
- enabled = true;
-
bool good = true;
- if(audio.en)
- if(!openAudio()) {
- cerr << "Failed to open OSS audio" << endl;
- good = false;
- }
-
- if(midi.en)
- if(!openMidi()) {
- cerr << "Failed to open OSS midi" << endl;
- good = false;
- }
- if(!good) {
- return false;
+ if(!openAudio()) {
+ cerr << "Failed to open OSS audio" << endl;
+ good = false;
}
- pthread_attr_t attr;
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
- engThread = new pthread_t;
- pthread_create(engThread, &attr, _thread, this);
+ if(!openMidi()) {
+ cerr << "Failed to open OSS midi" << endl;
+ good = false;
+ }
- return true;
+ return good;
}
void OssEngine::Stop()
{
- if(!enabled())
- return;
- enabled = false;
stopAudio();
stopMidi();
- if(engThread)
- pthread_join(*engThread, NULL);
- delete engThread;
- engThread = NULL;
}
void OssEngine::setMidiEn(bool nval)
{
- midi.en = nval;
- if(enabled()) {
- if(nval)
- openMidi();
- else
- stopMidi();
- }
+ if(nval)
+ openMidi();
+ else
+ stopMidi();
}
bool OssEngine::getMidiEn() const
{
- if(enabled())
- return midi.handle != -1;
- else
- return midi.en;
+ return midi.handle != -1;
}
void OssEngine::setAudioEn(bool nval)
{
- audio.en = nval;
- if(enabled()) { //lets rebind the ports
- if(nval)
- openAudio();
- else
- stopAudio();
- }
+ if(nval)
+ openAudio();
+ else
+ stopAudio();
}
bool OssEngine::getAudioEn() const
{
- if(enabled())
- return audio.snd_handle != -1;
- else
- return audio.en;
+ return audio.handle != -1;
}
bool OssEngine::openMidi()
{
- midi.handle = open(config.cfg.LinuxOSSSeqInDev, O_RDONLY, 0);
+ int handle = midi.handle;
+ if(handle != -1)
+ return true;//already open
- if(-1 == midi.handle) {
- stopMidi();
- midi.run = false;
+ handle = open(config.cfg.LinuxOSSSeqInDev, O_RDONLY, 0);
+
+ if(-1 == handle) {
return false;
}
+ midi.handle = handle;
+
+ if(!getAudioEn()) {
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+ engThread = new pthread_t;
+ pthread_create(engThread, &attr, _thread, this);
+ }
- midi.run = true;
return true;
}
void OssEngine::stopMidi()
{
- int tmp = midi.handle;
- if(tmp == -1) //already closed
+ int handle = midi.handle;
+ if(handle == -1) //already closed
return;
- midi.run = false;
midi.handle = -1;
- close(tmp);
+
+ if(!getAudioEn()) {
+ pthread_join(*engThread, NULL);
+ delete engThread;
+ engThread = NULL;
+ }
+
+ close(handle);
}
void *OssEngine::_thread(void *arg)
@@ -203,15 +201,13 @@ void *OssEngine::_thread(void *arg)
return (static_cast<OssEngine*>(arg))->thread();
}
-
void *OssEngine::thread()
{
- MidiEvent ev;
unsigned char tmp[4] = {0, 0, 0, 0};
set_realtime();
- while (midi.run || audio.snd_handle != -1)
+ while (getAudioEn() || getMidiEn())
{
- if(audio.snd_handle != -1)
+ if(getAudioEn())
{
const Stereo<Sample> smps = getNext();
@@ -234,15 +230,15 @@ void *OssEngine::thread()
audio.smps[i * 2] = (short int) (l * 32767.0);
audio.smps[i * 2 + 1] = (short int) (r * 32767.0);
}
- int handle = audio.snd_handle;
+ int handle = audio.handle;
if(handle != -1)
write(handle, audio.smps, SOUND_BUFFER_SIZE * 4); // *2 because is 16 bit, again * 2 because is stereo
else
break;
}
- //Collect up to 10 midi events
- for (int k = 0; k < 10 && midi.run; ++k) {
+ //Collect up to 30 midi events
+ for (int k = 0; k < 30 && getMidiEn(); ++k) {
getMidi(tmp);
unsigned char type = tmp[0];
unsigned char header = tmp[1];
@@ -266,40 +262,3 @@ void OssEngine::getMidi(unsigned char *midiPtr)
read(midi.handle, midiPtr, 4);
}
-void OssEngine::midiProcess(unsigned char head, unsigned char num, unsigned char value)
-{
- MidiEvent ev;
- unsigned char chan = head & 0x0f;
- switch(head & 0xf0)
- {
- case 0x80: //Note Off
- ev.type = M_NOTE;
- ev.channel = chan;
- ev.num = num;
- ev.value = 0;
- sysIn->putEvent(ev);
- break;
- case 0x90: //Note On
- ev.type = M_NOTE;
- ev.channel = chan;
- ev.num = num;
- ev.value = value;
- sysIn->putEvent(ev);
- break;
- case 0xb0: //Controller
- ev.type = M_CONTROLLER;
- ev.channel = chan;
- ev.num = num;
- ev.value = value;
- sysIn->putEvent(ev);
- break;
- case 0xe0: //Pitch Wheel
- ev.type = M_CONTROLLER;
- ev.channel = chan;
- ev.num = C_pitchwheel;
- ev.value = (num + value * (int) 128) - 8192;
- sysIn->putEvent(ev);
- break;
- }
-}
-
diff --git a/src/Nio/OssEngine.h b/src/Nio/OssEngine.h
@@ -49,11 +49,14 @@ class OssEngine: public AudioOut, MidiIn
static void *_thread(void *arg);
private:
+ pthread_t *engThread;
+
//Audio
bool openAudio();
void stopAudio();
- struct {
- int snd_handle;
+
+ struct audio{
+ int handle;
short int *smps; //Samples to be sent to soundcard
bool en;
} audio;
@@ -61,13 +64,9 @@ class OssEngine: public AudioOut, MidiIn
//Midi
bool openMidi();
void stopMidi();
- void midiProcess(unsigned char head, unsigned char num, unsigned char value);
-
void getMidi(unsigned char *midiPtr);
- pthread_t *engThread;
-
- struct {
+ struct midi{
int handle;
bool en;
bool run;
diff --git a/src/Nio/OutMgr.cpp b/src/Nio/OutMgr.cpp
@@ -27,10 +27,6 @@ OutMgr::OutMgr(Master *nmaster)
OutMgr::~OutMgr()
{
- for(map<string,AudioOut*>::iterator itr = managedOuts.begin();
- itr != managedOuts.end(); ++itr) {
- itr->second->Stop();
- }
running = false;
sem_post(&requested);
@@ -40,11 +36,75 @@ OutMgr::~OutMgr()
sem_destroy(&requested);
}
+void OutMgr::add(AudioOut *driver)
+{
+ pthread_mutex_lock(&mutex);
+ unmanagedOuts.push_back(driver);
+ if(running())//hotplug
+ driver->Start();
+ pthread_mutex_unlock(&mutex);
+}
+
+void OutMgr::remove(AudioOut *out)
+{
+ pthread_mutex_lock(&mutex);
+ unmanagedOuts.remove(out);
+ out->Stop();//tells engine to stop
+
+ //gives a dummy sample to make sure it is not stuck
+ out->out(Stereo<Sample>(Sample(SOUND_BUFFER_SIZE, 0.0),
+ Sample(SOUND_BUFFER_SIZE, 0.0)));
+ pthread_mutex_unlock(&mutex);
+}
+
+void OutMgr::requestSamples(unsigned int n)
+{
+ for(unsigned int i = 0; i < n; ++i)
+ sem_post(&requested);
+}
+
+int OutMgr::getRunning()
+{
+ int tmp;
+ sem_getvalue(&requested, &tmp);
+ if(tmp < 0)
+ tmp = 0;
+ return tmp;
+}
+
void *_outputThread(void *arg)
{
return (static_cast<OutMgr*>(arg))->outputThread();
}
+void OutMgr::run()
+{
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+ pthread_create(&outThread, &attr, _outputThread, this);
+}
+
+AudioOut *OutMgr::getOut(string name)
+{
+ return dynamic_cast<AudioOut *>(sysEngine->getEng(name));
+}
+
+string OutMgr::getDriver() const
+{
+ for(list<Engine*>::iterator itr = sysEngine->engines.begin();
+ itr != sysEngine->engines.end(); ++itr) {
+ AudioOut *out = dynamic_cast<AudioOut *>(*itr);
+ if(out && out->getAudioEn())
+ return out->name;
+ }
+}
+
+bool OutMgr::setDriver(string name)
+{
+ return false;
+}
+
void *OutMgr::outputThread()
{
defaultOut = dynamic_cast<AudioOut *>(sysEngine->defaultEng);
@@ -69,7 +129,6 @@ void *OutMgr::outputThread()
if(false) {
cout << "Status: ";
pthread_mutex_lock(&mutex);
- cout << managedOuts.size() << "-";
cout << unmanagedOuts.size();
pthread_mutex_unlock(&mutex);
cout << " outs, ";
@@ -91,7 +150,7 @@ void *OutMgr::outputThread()
for(list<Engine*>::iterator itr = sysEngine->engines.begin();
itr != sysEngine->engines.end(); ++itr) {
AudioOut *out = dynamic_cast<AudioOut *>(*itr);
- if(out && out->isRunning() && out->getAudioEn())
+ if(out && out->getAudioEn())
out->out(smps);
}
@@ -109,52 +168,35 @@ void *OutMgr::outputThread()
return NULL;
}
-void OutMgr::run()
+bool OutMgr::setSink(string name)
{
- pthread_attr_t attr;
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
- pthread_create(&outThread, &attr, _outputThread, this);
-}
-
-AudioOut *OutMgr::getOut(string name)
-{
- return dynamic_cast<AudioOut *>(sysEngine->getEng(name));
-}
-
-void OutMgr::add(AudioOut *driver)
-{
- pthread_mutex_lock(&mutex);
- unmanagedOuts.push_back(driver);
- if(running())//hotplug
- driver->Start();
- pthread_mutex_unlock(&mutex);
-}
+ AudioOut *sink = NULL;
+ for(list<Engine*>::iterator itr = sysEngine->engines.begin();
+ itr != sysEngine->engines.end(); ++itr) {
+ AudioOut *out = dynamic_cast<AudioOut *>(*itr);
+ if(out) {
+ if(out->name == name)
+ sink = out;
+ else
+ out->setAudioEn(false);
+ }
+ }
-void OutMgr::remove(AudioOut *out)
-{
- pthread_mutex_lock(&mutex);
- unmanagedOuts.remove(out);
- out->Stop();//tells engine to stop
+ if(!sink)
+ return false;
- //gives a dummy sample to make sure it is not stuck
- out->out(Stereo<Sample>(Sample(SOUND_BUFFER_SIZE, 0.0),
- Sample(SOUND_BUFFER_SIZE, 0.0)));
- pthread_mutex_unlock(&mutex);
-}
+ sink->setAudioEn(true);
-int OutMgr::getRunning()
-{
- int tmp;
- sem_getvalue(&requested, &tmp);
- if(tmp < 0)
- tmp = 0;
- return tmp;
+ return sink->getAudioEn();
}
-void OutMgr::requestSamples(unsigned int n)
+string OutMgr::getSink() const
{
- for(unsigned int i = 0; i < n; ++i)
- sem_post(&requested);
+ for(list<Engine*>::iterator itr = sysEngine->engines.begin();
+ itr != sysEngine->engines.end(); ++itr) {
+ AudioOut *out = dynamic_cast<AudioOut *>(*itr);
+ if(out && out->getAudioEn())
+ return out->name;
+ }
}
diff --git a/src/Nio/OutMgr.h b/src/Nio/OutMgr.h
@@ -43,13 +43,25 @@ class OutMgr
*/
AudioOut *getOut(std::string name);
+ /**Sets the running driver by name
+ * @return true for successful insertion*/
+ bool setDriver(std::string name);
+
+ /**Gets the name of the first running driver
+ * @return if no running output, "" is returned
+ */
+ std::string getDriver() const;
+
void *outputThread();
+
+ bool setSink(std::string name);
+
+ std::string getSink() const;
private:
Atomic<bool> running;
bool init;
//should hold outputs here that exist for the life of the OutMgr
- std::map<std::string,AudioOut *> managedOuts;
AudioOut *defaultOut;/**<The default output*/
//should hold short lived, externally controlled Outputs (eg WavEngine)
diff --git a/src/Nio/SafeQueue.cpp b/src/Nio/SafeQueue.cpp
@@ -9,7 +9,7 @@ SafeQueue<T>::SafeQueue(size_t maxlen)
template<class T>
SafeQueue<T>::~SafeQueue()
{
- delete buffer;
+ delete[] buffer;
}
template<class T>
@@ -76,3 +76,8 @@ int SafeQueue<T>::pop(T &out)
return 0;
}
+template<class T>
+void SafeQueue<T>::clear()
+{
+ readPtr = writePtr;
+}
diff --git a/src/Nio/SafeQueue.h b/src/Nio/SafeQueue.h
@@ -1,7 +1,7 @@
#ifndef SAFEQUEUE_H
#define SAFEQUEUE_H
-
+#include <cstdlib>
/**
* C++ thread safe lockless queue
@@ -21,6 +21,9 @@ class SafeQueue
int push(const T &in);
int pop(T &out);
+ //clears reading space
+ void clear();
+
private:
unsigned int wSpace() const;
unsigned int rSpace() const;
diff --git a/src/Nio/WavEngine.cpp b/src/Nio/WavEngine.cpp
@@ -20,11 +20,14 @@
#include <cstdio>
#include <iostream>
#include <cstdlib>
+#include "SafeQueue.h"
+#include "../Misc/Util.h"
using namespace std;
WavEngine::WavEngine(OutMgr *out, string filename, int samplerate, int channels)
- :AudioOut(out), file(filename, samplerate, channels)
+ :AudioOut(out), file(filename, samplerate, channels),
+ enabled(false)
{
}
@@ -57,48 +60,14 @@ void WavEngine::Stop()
return;
enabled = false;
- //put something in the queue
- pthread_mutex_lock(&outBuf_mutex);
- outBuf.push(Stereo<Sample>(Sample(1,0.0),Sample(1,0.0)));
- pthread_mutex_unlock(&outBuf_mutex);
-
- //make sure it moves
- pthread_cond_signal(&outBuf_cv);
- pthread_mutex_unlock(&outBuf_mutex);
pthread_join(pThread, NULL);
}
-//lazy getter
-const Stereo<Sample> WavEngine::getNext()
-{
- 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();
- 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];
@@ -107,7 +76,7 @@ void *WavEngine::AudioThread()
while (enabled())
{
- const Stereo<Sample> smps = getNext();
+ const Stereo<Sample> smps = getNext(true);
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);
diff --git a/src/Nio/WavEngine.h b/src/Nio/WavEngine.h
@@ -24,7 +24,9 @@
#define WAVENGINE_H
#include "AudioOut.h"
#include "../Misc/WavFile.h"
+#include "../Misc/Atomic.h"
#include <string>
+#include <pthread.h>
class WavEngine: public AudioOut
{
@@ -39,14 +41,14 @@ class WavEngine: public AudioOut
void setAudioEn(bool nval){};
bool getAudioEn() const{};
- const Stereo<Sample> getNext();
-
protected:
void *AudioThread();
static void *_AudioThread(void *arg);
private:
WavFile file;
+ Atomic<bool> enabled;
+ pthread_t pThread;
};
#endif
diff --git a/src/UI/NioUI.cpp b/src/UI/NioUI.cpp
@@ -1,6 +1,7 @@
#include "NioUI.h"
#include "../Nio/EngineMgr.h"
#include "../Nio/OutMgr.h"
+#include "../Nio/InMgr.h"
#include "../Nio/AudioOut.h"
#include "../Nio/MidiIn.h"
#include <cstdio>
@@ -33,32 +34,63 @@ NioUI::NioUI()
}
gen->end();
+ Fl_Group *settings = new Fl_Group(0,20,400,400-35,"Settings");
+ {
+ audio = new Fl_Choice(60, 80, 100, 25, "Audio");
+ audio->callback(audioCallback);
+ midi = new Fl_Choice(60, 100, 100, 25, "Midi");
+ midi->callback(midiCallback);
+ }
+ settings->end();
+
for(list<Engine *>::iterator itr = sysEngine->engines.begin();
itr != sysEngine->engines.end(); ++itr) {
- bool midi = dynamic_cast<MidiIn *>(*itr);
- bool audio = dynamic_cast<AudioOut *>(*itr);
- tabs.push_back(new NioTab((*itr)->name, midi, audio));
+ Engine *eng = *itr;
+ if(dynamic_cast<MidiIn *>(eng))
+ midi->add(eng->name.c_str());
+ if(dynamic_cast<AudioOut *>(eng))
+ audio->add(eng->name.c_str());
}
+
+ //for(list<Engine *>::iterator itr = sysEngine->engines.begin();
+ // itr != sysEngine->engines.end(); ++itr) {
+ // bool midi = dynamic_cast<MidiIn *>(*itr);
+ // bool audio = dynamic_cast<AudioOut *>(*itr);
+ // tabs.push_back(new NioTab((*itr)->name, midi, audio));
+ //}
+
//add tabs
- for(list<NioTab *>::iterator itr = tabs.begin();
- itr != tabs.end(); ++itr)
- wintabs->add(*itr);
+ //for(list<NioTab *>::iterator itr = tabs.begin();
+ // itr != tabs.end(); ++itr)
+ // wintabs->add(*itr);
}
wintabs->end();
- Fl::scheme("plastic");
resizable(this);
size_range(400,300);
}
void NioUI::refresh()
{
- for(list<NioTab *>::iterator itr = tabs.begin();
- itr != tabs.end(); ++itr)
- (*itr)->refresh();
+ //for(list<NioTab *>::iterator itr = tabs.begin();
+ // itr != tabs.end(); ++itr)
+ // (*itr)->refresh();
+
}
+void NioUI::midiCallback(Fl_Widget *c)
+{
+ bool good = sysIn->setSource(static_cast<Fl_Choice *>(c)->text());
+ static_cast<Fl_Choice *>(c)->textcolor(fl_rgb_color(255*!good,0,0));
+}
+
+void NioUI::audioCallback(Fl_Widget *c)
+{
+ bool good = sysOut->setSink(static_cast<Fl_Choice *>(c)->text());
+ static_cast<Fl_Choice *>(c)->textcolor(fl_rgb_color(255*!good,0,0));
+}
+#if 0
//this is a repetitve block of code
//perhaps something on the Engine's side should be refactored
void NioTab::nioToggle(Fl_Widget *wid, void *arg)
@@ -157,4 +189,5 @@ void NioTab::refresh()
this->labelcolor(fl_rgb_color(0,255*state,0));
this->redraw();
}
+#endif
diff --git a/src/UI/NioUI.h b/src/UI/NioUI.h
@@ -7,9 +7,12 @@
#include <FL/Fl_Pack.H>
#include <FL/Fl_Spinner.H>
#include <FL/Enumerations.H>
+#include <FL/Fl_Choice.H>
#include <list>
#include <string>
+//removed from code for now
+#if 0
struct NioTab : public Fl_Group
{
NioTab(std::string name, bool _midi, bool _audio);
@@ -26,6 +29,8 @@ struct NioTab : public Fl_Group
Fl_Spinner *buffer;
const std::string name;
};
+#endif
+
class NioUI : public Fl_Window
{
@@ -33,7 +38,12 @@ class NioUI : public Fl_Window
NioUI();
void refresh();
private:
- std::list<NioTab *> tabs;
+ //std::list<NioTab *> tabs;
+
+ Fl_Choice *midi;
+ Fl_Choice *audio;
+ static void midiCallback(Fl_Widget *c);
+ static void audioCallback(Fl_Widget *c);
};
#endif
diff --git a/src/main.cpp b/src/main.cpp
@@ -222,6 +222,7 @@ void exitprogram()
{
pthread_mutex_lock(&master->mutex);
pthread_mutex_unlock(&master->mutex);
+ sysEngine->stop();
delete sysOut;
delete sysIn;
delete sysEngine;