commit 748053b60f5aec7b95be318c8621b36b782a46fa
parent 3d15e1169f7cf10b8f881f15267d350def4d52b3
Author: fundamental <[email protected]>
Date: Sun, 3 Jan 2010 23:26:32 -0500
Nio: Separation of Midi and Audio
- Midi and Audio are now seperate in Jack, Alsa, and Oss
- Wav and Nul engines conform to the new api for the most part
- PortAudio driver is broken by this commit, must be fixed later
- UI now has access to seperately enable/disable midi and audio as well as the
engine as a whole
- There are possible race conditions in starting/stopping midi/audio
- Major refactoring in drivers done when conforming to new api
- HACK configuration is removed, as there is no more need for the workaround
- several bugs fixed (jack failures at Start() and other misc)
Diffstat:
20 files changed, 672 insertions(+), 554 deletions(-)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
@@ -32,16 +32,10 @@ SET (OssEnable ${ALSA_FOUND} CACHE BOOL #TODO perhaps check for /dev/dsp
"Enable support for Open Sound System")
SET (PaEnable ${PORTAUDIO_FOUND} CACHE BOOL
"Enable support for Port Audio System")
-SET (HACK OFF CACHE BOOL
- "If you do not know what this does do not touch it")
# Now, handle the incoming settings and set define flags/variables based
# on this
-if(HACK)
- add_definitions(-DHACK=1)
-endif(HACK)
-
if (GuiModule STREQUAL qt AND QT_FOUND)
set (QtGui TRUE)
elseif(GuiModule STREQUAL fltk AND FLTK_FOUND)
diff --git a/src/Nio/AlsaEngine.cpp b/src/Nio/AlsaEngine.cpp
@@ -33,12 +33,6 @@ AlsaEngine::AlsaEngine(OutMgr *out)
{
name = "ALSA";
audio.handle = NULL;
- audio.period_time = 0;
- audio.samplerate = 0;
- audio.buffer_size = SOUND_BUFFER_SIZE;//0;
- audio.period_size = 0;
- audio.alsaId = -1;
- audio.pThread = 0;
midi.handle = NULL;
midi.alsaId = -1;
@@ -51,194 +45,77 @@ AlsaEngine::~AlsaEngine()
Stop();
}
-
-bool AlsaEngine::openMidi()
-{
- int alsaport;
- midi.handle = NULL;
-
- if(snd_seq_open(&midi.handle, "default", SND_SEQ_OPEN_INPUT, 0) != 0)
- return false;
-
- snd_seq_set_client_name(midi.handle, "ZynAddSubFX");
-
- alsaport = snd_seq_create_simple_port(
- midi.handle,
- "ZynAddSubFX",
- SND_SEQ_PORT_CAP_WRITE
- | SND_SEQ_PORT_CAP_SUBS_WRITE,
- SND_SEQ_PORT_TYPE_SYNTH);
- if(alsaport < 0)
- return false;
- return true;
-}
-
-
-string AlsaEngine::audioClientName()
-{
- string name = "zynaddsubfx";
- if (!config.cfg.nameTag.empty())
- name += ("-" + config.cfg.nameTag);
- return name;
-}
-
-string AlsaEngine::midiClientName()
-{
- string name = "zynaddsubfx";
- if (!config.cfg.nameTag.empty())
- name += ("-" + config.cfg.nameTag);
- return name;
-}
-
void *AlsaEngine::_AudioThread(void *arg)
{
return (static_cast<AlsaEngine*>(arg))->AudioThread();
}
-
void *AlsaEngine::AudioThread()
{
set_realtime();
- RunStuff();
+ processAudio();
return NULL;
}
-
-void AlsaEngine::Write(const short *InterleavedSmps,int size)
-{
- snd_pcm_uframes_t towrite = size;//getBuffersize();
- snd_pcm_sframes_t wrote = 0;
- const short int *data = InterleavedSmps;
- while (towrite > 0)
- {
- wrote = pcmWrite(audio.handle, &data, towrite);
- if (wrote >= 0)
- {
- if ((snd_pcm_uframes_t)wrote < towrite || wrote == -EAGAIN)
- snd_pcm_wait(audio.handle, 707);
- if (wrote > 0)
- {
- towrite -= wrote;
- data += wrote * 2;
- }
- }
- else // (wrote < 0)
- {
- switch (wrote)
- {
- case -EBADFD:
- //alsaBad(-EBADFD, "alsa audio unfit for writing");
- break;
- case -EPIPE:
- xrunRecover();
- break;
- case -ESTRPIPE:
- Recover(wrote);
- break;
- default:
- //alsaBad(wrote, "alsa audio, snd_pcm_writei ==> weird state");
- break;
- }
- wrote = 0;
- }
- }
-}
-
-
-bool AlsaEngine::Recover(int err)
-{
- if (err > 0)
- err = -err;
- bool isgood = false;
- switch (err)
- {
- case -EINTR:
- isgood = true; // nuthin to see here
- break;
- case -ESTRPIPE:
- // if (!alsaBad(snd_pcm_prepare(audio.handle),
- // "Error, AlsaEngine failed to recover from suspend"))
- // isgood = true;
- break;
- case -EPIPE:
- // if (!alsaBad(snd_pcm_prepare(audio.handle),
- // "Error, AlsaEngine failed to recover from underrun"))
- // isgood = true;
- break;
- default:
- break;
- }
- return isgood;
-}
-
-
-bool AlsaEngine::xrunRecover()
-{
- bool isgood = false;
- if (audio.handle != NULL)
- {
- //if (!alsaBad(snd_pcm_drop(audio.handle), "pcm drop failed"))
- // if (!alsaBad(snd_pcm_prepare(audio.handle), "pcm prepare failed"))
- isgood = true;
- ;//config.cfg.verbose
- // && cout << "Info, xrun recovery " << ((isgood) ? "good" : "not good")
- // << endl;
- }
- return isgood;
-}
-
-
bool AlsaEngine::Start()
{
if(enabled())
return true;
-#if !HACK
- if(!OpenStuff())
- return false;
-#endif
- openMidi();
-
- pthread_attr_t attr;
enabled = true;
+ if(audio.en)
+ openAudio();
+ if(midi.en)
+ openMidi();
-#if !HACK
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
- pthread_create(&audio.pThread, &attr, _AudioThread, this);
-#endif
-
- if (NULL != midi.handle)
- {
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- pthread_create(&midi.pThread, &attr, _MidiThread, this);
- }
return true;
}
-
void AlsaEngine::Stop()
{
if(!enabled())
return;
enabled = false;
- pthread_join(audio.pThread, NULL);
- if (NULL != audio.handle && audio.pThread)
- if (pthread_cancel(audio.pThread))
- cerr << "Error, failed to cancel Alsa audio thread" << endl;
- snd_pcm_drain(handle);
- snd_pcm_close(handle);
- if (NULL != midi.handle && midi.pThread)
- if (pthread_cancel(midi.pThread))
- cerr << "Error, failed to cancel Alsa midi thread" << endl;
- //Stop midi
- if(midi.handle)
- snd_seq_close(midi.handle);
- cout << "foo" << endl;
}
+void AlsaEngine::setMidiEn(bool nval)
+{
+ midi.en = nval;
+ if(enabled()) {
+ if(nval)
+ openMidi();
+ else
+ stopMidi();
+ }
+}
+
+bool AlsaEngine::getMidiEn() const
+{
+ if(enabled())
+ return midi.handle;
+ else
+ return midi.en;
+}
+
+void AlsaEngine::setAudioEn(bool nval)
+{
+ audio.en = nval;
+ if(enabled()) {
+ if(nval)
+ openAudio();
+ else
+ stopAudio();
+ }
+}
+
+bool AlsaEngine::getAudioEn() const
+{
+ if(enabled())
+ return audio.handle;
+ else
+ return audio.en;
+}
void *AlsaEngine::_MidiThread(void *arg)
{
@@ -249,17 +126,11 @@ void *AlsaEngine::_MidiThread(void *arg)
void *AlsaEngine::MidiThread(void)
{
snd_seq_event_t *event;
- unsigned char channel;
- unsigned char note;
- unsigned char velocity;
- int ctrltype;
- int par;
- int chk;
MidiEvent ev;
set_realtime();
while (enabled())
{
- while ((chk = snd_seq_event_input(midi.handle, &event)) > 0)
+ while (snd_seq_event_input(midi.handle, &event) > 0)
{
//ensure ev is empty
ev.channel = 0;
@@ -269,7 +140,6 @@ void *AlsaEngine::MidiThread(void)
if (!event)
continue;
- par = event->data.control.param;
switch (event->type)
{
case SND_SEQ_EVENT_NOTEON:
@@ -337,20 +207,50 @@ void *AlsaEngine::MidiThread(void)
}
snd_seq_free_event(event);
}
- if (chk < 0)
- {
- if (true)
- cerr << "Error, ALSA midi input read failed: " << chk << endl;
- return NULL;
- }
}
return NULL;
}
+bool AlsaEngine::openMidi()
+{
+ int alsaport;
+ midi.handle = NULL;
+
+ if(snd_seq_open(&midi.handle, "default", SND_SEQ_OPEN_INPUT, 0) != 0)
+ return false;
+
+ snd_seq_set_client_name(midi.handle, "ZynAddSubFX");
+
+ alsaport = snd_seq_create_simple_port(
+ midi.handle,
+ "ZynAddSubFX",
+ SND_SEQ_PORT_CAP_WRITE
+ | SND_SEQ_PORT_CAP_SUBS_WRITE,
+ SND_SEQ_PORT_TYPE_SYNTH);
+ if(alsaport < 0)
+ return false;
+
+ pthread_attr_t attr;
+
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ pthread_create(&midi.pThread, &attr, _MidiThread, this);
+ return true;
+}
+
+void AlsaEngine::stopMidi()
+{
+ if (NULL != midi.handle && midi.pThread)
+ pthread_cancel(midi.pThread);
+ midi.handle = NULL;
+ if(midi.handle)
+ snd_seq_close(midi.handle);
+}
+
const short *AlsaEngine::interleave(const Stereo<Sample> smps)const
{
/**\todo TODO fix repeated allocation*/
- short *shortInterleaved = new short[smps.l().size()*2];//over allocation
+ short *shortInterleaved = new short[smps.l().size()*2];
memset(shortInterleaved,0,smps.l().size()*2*sizeof(short));
int idx = 0;//possible off by one error here
double scaled;
@@ -364,72 +264,89 @@ const short *AlsaEngine::interleave(const Stereo<Sample> smps)const
return shortInterleaved;
}
-bool AlsaEngine::OpenStuff()
+bool AlsaEngine::openAudio()
+{
+ int rc = 0;
+ /* Open PCM device for playback. */
+ audio.handle=NULL;
+ rc = snd_pcm_open(&audio.handle, "hw:0",
+ SND_PCM_STREAM_PLAYBACK, 0);
+ if (rc < 0) {
+ fprintf(stderr,
+ "unable to open pcm device: %s\n",
+ snd_strerror(rc));
+ return false;
+ }
+
+ /* Allocate a hardware parameters object. */
+ snd_pcm_hw_params_alloca(&audio.params);
+
+ /* Fill it in with default values. */
+ snd_pcm_hw_params_any(audio.handle, audio.params);
+
+ /* 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);
+
+ /* Signed 16-bit little-endian format */
+ snd_pcm_hw_params_set_format(audio.handle, audio.params,
+ SND_PCM_FORMAT_S16_LE);
+
+ /* Two channels (stereo) */
+ snd_pcm_hw_params_set_channels(audio.handle, audio.params, 2);
+
+ audio.sampleRate = SAMPLE_RATE;
+ snd_pcm_hw_params_set_rate_near(audio.handle, audio.params,
+ &audio.sampleRate, NULL);
+
+ audio.frames = 32;
+ snd_pcm_hw_params_set_period_size_near(audio.handle,
+ audio.params, &audio.frames, NULL);
+
+ /* Write the parameters to the driver */
+ rc = snd_pcm_hw_params(audio.handle, audio.params);
+ if (rc < 0) {
+ fprintf(stderr,
+ "unable to set hw parameters: %s\n",
+ snd_strerror(rc));
+ return false;
+ }
+
+ /* Set buffer size (in frames). The resulting latency is given by */
+ /* latency = periodsize * periods / (rate * bytes_per_frame) */
+ snd_pcm_hw_params_set_buffer_size(audio.handle, audio.params, SOUND_BUFFER_SIZE);
+
+ //snd_pcm_hw_params_get_period_size(audio.params, &audio.frames, NULL);
+ //snd_pcm_hw_params_get_period_time(audio.params, &val, NULL);
+
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+ pthread_create(&audio.pThread, &attr, _AudioThread, this);
+ return true;
+}
+
+void AlsaEngine::stopAudio()
{
- /* Open PCM device for playback. */
- handle=NULL;
- rc = snd_pcm_open(&handle, "hw:0",
- SND_PCM_STREAM_PLAYBACK, 0);
- if (rc < 0) {
- fprintf(stderr,
- "unable to open pcm device: %s\n",
- snd_strerror(rc));
- return false;
- }
-
- /* Allocate a hardware parameters object. */
- snd_pcm_hw_params_alloca(¶ms);
-
- /* Fill it in with default values. */
- snd_pcm_hw_params_any(handle, params);
-
- /* Set the desired hardware parameters. */
-
- /* Interleaved mode */
- snd_pcm_hw_params_set_access(handle, params,
- SND_PCM_ACCESS_RW_INTERLEAVED);
-
- /* Signed 16-bit little-endian format */
- snd_pcm_hw_params_set_format(handle, params,
- SND_PCM_FORMAT_S16_LE);
-
- /* Two channels (stereo) */
- snd_pcm_hw_params_set_channels(handle, params, 2);
-
- val = SAMPLE_RATE; //44100;
- snd_pcm_hw_params_set_rate_near(handle, params,
- &val, NULL);//&dir);
-
- frames = 32;
- snd_pcm_hw_params_set_period_size_near(handle,
- params, &frames, NULL);//&dir);
-
- /* Write the parameters to the driver */
- rc = snd_pcm_hw_params(handle, params);
- if (rc < 0) {
- fprintf(stderr,
- "unable to set hw parameters: %s\n",
- snd_strerror(rc));
- return false;
- }
-
- /* Set buffer size (in frames). The resulting latency is given by */
- /* latency = periodsize * periods / (rate * bytes_per_frame) */
- snd_pcm_hw_params_set_buffer_size(handle, params, SOUND_BUFFER_SIZE);
-
- /* Use a buffer large enough to hold one period */
- snd_pcm_hw_params_get_period_size(params, &frames, &dir);
-
- snd_pcm_hw_params_get_period_time(params, &val, &dir);
- return true;
+ snd_pcm_t *handle = audio.handle;
+ audio.handle = NULL;
+ pthread_join(audio.pThread, NULL);
+ snd_pcm_drain(handle);
+ snd_pcm_close(handle);
}
-void AlsaEngine::RunStuff()
+void AlsaEngine::processAudio()
{
- while (enabled()) {
- buffer = interleave(getNext());
- rc = snd_pcm_writei(handle, buffer, SOUND_BUFFER_SIZE);
- delete[] buffer;
+ int rc;
+ while (audio.handle) {
+ audio.buffer = interleave(getNext());
+ snd_pcm_t *handle = audio.handle;
+ if(handle)
+ rc = snd_pcm_writei(handle, audio.buffer, SOUND_BUFFER_SIZE);
+ delete[] audio.buffer;
if (rc == -EPIPE) {
/* EPIPE means underrun */
cerr << "underrun occurred" << endl;
@@ -437,8 +354,6 @@ void AlsaEngine::RunStuff()
}
else if (rc < 0)
cerr << "error from writei: " << snd_strerror(rc) << endl;
- //else if (rc != (int)frames)
- // cerr << "short write, write " << rc << "frames" << endl;
}
pthread_exit(NULL);
}
diff --git a/src/Nio/AlsaEngine.h b/src/Nio/AlsaEngine.h
@@ -37,18 +37,14 @@ class AlsaEngine : public AudioOut, MidiIn
AlsaEngine(OutMgr *out);
~AlsaEngine();
- bool openMidi();
bool Start();
void Stop();
- unsigned int getSamplerate() { return audio.samplerate; };
- unsigned int getBuffersize() { return audio.period_size; };
+ void setAudioEn(bool nval);
+ bool getAudioEn() const;
+ void setMidiEn(bool nval);
+ bool getMidiEn() const;
- std::string audioClientName();
- std::string midiClientName();
- int audioClientId() { return audio.alsaId; };
- int midiClientId() { return midi.alsaId; };
-
protected:
void *AudioThread();
static void *_AudioThread(void *arg);
@@ -56,54 +52,33 @@ class AlsaEngine : public AudioOut, MidiIn
static void *_MidiThread(void *arg);
private:
- bool prepHwparams();
- bool prepSwparams();
- void Write(const short *InterleavedSmps, int size);
- bool Recover(int err);
- bool xrunRecover();
- bool alsaBad(int op_result, std::string err_msg);
- void closeAudio();
- void closeMidi();
-
- snd_pcm_sframes_t (*pcmWrite)(snd_pcm_t *handle, const void *data,
- snd_pcm_uframes_t nframes);
+ bool openMidi();
+ void stopMidi();
+ bool openAudio();
+ void stopAudio();
- /**Interleave Samples. \todo move this to util*/
const short *interleave(const Stereo<Sample> smps) const;
struct {
- std::string device;
- snd_pcm_t *handle;
- unsigned int period_time;
- unsigned int samplerate;
- snd_pcm_uframes_t period_size;
- snd_pcm_uframes_t buffer_size;
- int alsaId;
- snd_pcm_state_t pcm_state;
- pthread_t pThread;
- } audio;
-
- struct {
std::string device;
snd_seq_t *handle;
int alsaId;
pthread_t pThread;
+ bool en;
} midi;
- //from alsa example
- long loops;
- int rc;
- int size;
- snd_pcm_t *handle;
- snd_pcm_hw_params_t *params;
- unsigned int val;
- int dir;
- snd_pcm_uframes_t frames;
- const short *buffer;
+ struct {
+ bool en;
+ bool run;
+ snd_pcm_t *handle;
+ snd_pcm_hw_params_t *params;
+ unsigned int sampleRate;
+ snd_pcm_uframes_t frames;
+ const short *buffer;
+ pthread_t pThread;
+ } audio;
- void RunStuff();
- bool OpenStuff();
- pthread_mutex_t close_m;
+ void processAudio();
};
#endif
diff --git a/src/Nio/AudioOut.cpp b/src/Nio/AudioOut.cpp
@@ -1,20 +1,23 @@
/*
- AudioOut.cpp
+ ZynAddSubFX - a software synthesizer
- Copyright 2009, Alan Calvert
+ AudioOut.h - Audio Output superclass
+ Copyright (C) 2009-2010 Mark McCurry
+ Author: Mark McCurry
- This file is part of yoshimi, which is free software: you can
- redistribute it and/or modify it under the terms of the GNU General
- Public License as published by the Free Software Foundation, either
- version 3 of the License, or (at your option) any later version.
+ 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.
- yoshimi is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
+ 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
- You should have received a copy of the GNU General Public License
- along with yoshimi. If not, see <http://www.gnu.org/licenses/>.
*/
#include <iostream>
@@ -28,7 +31,7 @@ using namespace std;
AudioOut::AudioOut(OutMgr *out)
:samplerate(SAMPLE_RATE),bufferSize(SOUND_BUFFER_SIZE),
usePartial(false),current(Sample(SOUND_BUFFER_SIZE,0.0)),
- buffering(6),manager(out),enabled(false)
+ buffering(6),manager(out)
{
pthread_mutex_init(&outBuf_mutex, NULL);
pthread_cond_init(&outBuf_cv, NULL);
@@ -118,6 +121,7 @@ int AudioOut::bufferingSize()
return buffering;
}
+
const Stereo<Sample> AudioOut::getNext()
{
const unsigned int BUFF_SIZE = buffering;
diff --git a/src/Nio/AudioOut.h b/src/Nio/AudioOut.h
@@ -1,21 +1,23 @@
/*
- MusicIO.h
+ ZynAddSubFX - a software synthesizer
- Copyright 2009, Alan Calvert
- Copyright 2009, James Morris
+ AudioOut.h - Audio Output superclass
+ Copyright (C) 2009-2010 Mark McCurry
+ Author: Mark McCurry
- This file is part of yoshimi, which is free software: you can
- redistribute it and/or modify it under the terms of the GNU General
- Public License as published by the Free Software Foundation, either
- version 3 of the License, or (at your option) any later version.
+ 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.
- yoshimi is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
+ 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
- You should have received a copy of the GNU General Public License
- along with yoshimi. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef AUDIO_OUT_H
@@ -35,31 +37,24 @@ class AudioOut : public virtual Engine
AudioOut(OutMgr *out);
virtual ~AudioOut();
- /**Start the Driver*/
- virtual bool Start()=0;
- /**Stop the Driver*/
- virtual void Stop()=0;
-
/**Give the Driver Samples to process*/
virtual void out(Stereo<Sample> smps);
- /**Determines if new operator should/can be used*/
- virtual bool isEnabled() const {return enabled();};
-
- /**Report the state of the engine
- * @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);
/**Sets the Samples required per Out of this driver
- * (used for getNext()).*/
+ * not a realtime opperation */
void setBufferSize(int _bufferSize);
+ /**Sets the Frame Size for output*/
void bufferingSize(int nBuffering);
int bufferingSize();
+ virtual void setAudioEn(bool nval)=0;
+ virtual bool getAudioEn() const=0;
+
protected:
void putBack(const Stereo<Sample> smp);
@@ -74,19 +69,20 @@ class AudioOut : public virtual Engine
pthread_mutex_t outBuf_mutex;
pthread_cond_t outBuf_cv;
- Stereo<Sample> partialIn;/**<used for taking in samples with a different samplerate/buffersize*/
+ /**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
+ //sampleRate!=SAMPLE_RATE || bufferSize!=SOUND_BUFFER_SIZE
unsigned int buffering;
OutMgr *manager;
//thread resources
pthread_t pThread;
- Atomic<bool> enabled;
};
#endif
diff --git a/src/Nio/Engine.cpp b/src/Nio/Engine.cpp
@@ -1,7 +1,34 @@
+/*
+ ZynAddSubFX - a software synthesizer
+
+ Engine.cpp - Audio Driver base class
+ Copyright (C) 2009-2010 Mark McCurry
+ Author: Mark McCurry
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of version 2 of the GNU General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License (version 2 or later) for more details.
+
+ You should have received a copy of the GNU General Public License (version 2)
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*/
#include "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
@@ -1,12 +1,47 @@
+/*
+ ZynAddSubFX - a software synthesizer
+
+ Engine.h - Audio Driver base class
+ Copyright (C) 2009-2010 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 ENGINE_H
#define ENGINE_H
#include <string>
+#include "../Misc/Atomic.h"
/**Marker for input/output driver*/
class Engine
{
public:
Engine();
virtual ~Engine();
+
+ /**Start the Driver
+ * @return true on success*/
+ virtual bool Start()=0;
+ /**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
@@ -41,6 +41,7 @@ EngineMgr::EngineMgr()
#if JACK
#if JACK_DEFAULT
engines.push_back(defaultEng = new JackEngine(sysOut));
+ cout << "jack go" << endl;
#else
engines.push_back(new JackEngine(sysOut));
#endif
diff --git a/src/Nio/JackEngine.cpp b/src/Nio/JackEngine.cpp
@@ -33,6 +33,8 @@ 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;
@@ -74,13 +76,17 @@ bool JackEngine::connectServer(string server)
bool JackEngine::Start()
{
+ cout << "Starting Jack" << endl;
if(enabled())
return true;
- cout << "Runn" << endl;
+
enabled = true;
if(!connectServer(""))
- return false;
- openAudio();
+ goto bail_out;
+ if(midi.en)
+ openMidi();
+ if(audio.en)
+ openAudio();
if (NULL != jackClient)
{
setBufferSize(jack_get_buffer_size(jackClient));
@@ -113,23 +119,57 @@ bail_out:
void JackEngine::Stop()
{
+ cout << "Stopping Jack" << endl;
if(!enabled())
return;
enabled = false;
if (jackClient)
{
- for (int i = 0; i < 2; ++i)
- {
- if (NULL != audio.ports[i])
- jack_port_unregister(jackClient, audio.ports[i]);
- audio.ports[i] = NULL;
- }
- jack_port_unregister(jackClient, midi.inport);
+ stopMidi();
+ stopAudio();
jack_client_close(jackClient);
jackClient = NULL;
}
}
+void JackEngine::setMidiEn(bool nval)
+{
+ midi.en = nval;
+ if(enabled()) { //lets rebind the ports
+ if(nval)
+ openMidi();
+ else
+ stopMidi();
+ }
+}
+
+bool JackEngine::getMidiEn() const
+{
+ if(enabled())
+ return midi.inport;
+ else
+ return midi.en;
+}
+
+void JackEngine::setAudioEn(bool nval)
+{
+ audio.en = nval;
+ if(enabled()) { //lets rebind the ports
+ if(nval)
+ openAudio();
+ else
+ stopAudio();
+ }
+}
+
+bool JackEngine::getAudioEn() const
+{
+ if(enabled())
+ return audio.ports[0];
+ else
+ return audio.en;
+}
+
bool JackEngine::openAudio()
{
const char *portnames[] = { "left", "right" };
@@ -143,17 +183,39 @@ bool JackEngine::openAudio()
{
audio.jackSamplerate = jack_get_sample_rate(jackClient);
audio.jackNframes = jack_get_buffer_size(jackClient);
- midi.inport = jack_port_register(jackClient, "midi_input",
- JACK_DEFAULT_MIDI_TYPE,
- JackPortIsInput | JackPortIsTerminal, 0);
return true;
}
else
cerr << "Error, failed to register jack audio ports" << endl;
- Stop();
return false;
}
+void JackEngine::stopAudio()
+{
+ for (int i = 0; i < 2; ++i)
+ {
+ jack_port_t *port = audio.ports[i];
+ audio.ports[i] = NULL;
+ if (NULL != port)
+ jack_port_unregister(jackClient, port);
+ }
+}
+
+bool JackEngine::openMidi()
+{
+ return midi.inport = jack_port_register(jackClient, "midi_input",
+ JACK_DEFAULT_MIDI_TYPE,
+ JackPortIsInput | JackPortIsTerminal, 0);
+}
+
+void JackEngine::stopMidi()
+{
+ jack_port_t *port = midi.inport;
+ midi.inport = NULL;
+ if(port)
+ jack_port_unregister(jackClient, port);
+}
+
int JackEngine::clientId()
{
if (NULL != jackClient)
@@ -187,7 +249,6 @@ int JackEngine::processCallback(jack_nframes_t nframes)
bool JackEngine::processAudio(jack_nframes_t nframes)
{
- //cout << "I got called with: " << nframes << endl;
for (int port = 0; port < 2; ++port)
{
audio.portBuffs[port] =
@@ -201,7 +262,6 @@ bool JackEngine::processAudio(jack_nframes_t nframes)
}
Stereo<Sample> smp = getNext();
- //cout << "smp size of: " << smp.l().size() << endl;
//Assumes smp.l().size() == nframes
memcpy(audio.portBuffs[0], smp.l().c_buf(), smp.l().size()*sizeof(REALTYPE));
@@ -241,6 +301,8 @@ int JackEngine::bufferSizeCallback(jack_nframes_t nframes)
void JackEngine::handleMidi(unsigned long frames)
{
+ if(!midi.inport)
+ return;
void *midi_buf = jack_port_get_buffer(midi.inport, frames);
jack_midi_event_t jack_midi_event;
jack_nframes_t event_index = 0;
diff --git a/src/Nio/JackEngine.h b/src/Nio/JackEngine.h
@@ -24,7 +24,6 @@
#include <pthread.h>
#include <semaphore.h>
#include <jack/jack.h>
-#include <jack/ringbuffer.h>
#include <pthread.h>
#include "MidiIn.h"
@@ -41,7 +40,13 @@ class JackEngine : public AudioOut, MidiIn
bool setServer(std::string server);
bool Start();
void Stop();
-
+
+ void setMidiEn(bool nval);
+ bool getMidiEn() const;
+
+ void setAudioEn(bool nval);
+ bool getAudioEn() const;
+
unsigned int getSamplerate() { return audio.jackSamplerate; };
unsigned int getBuffersize() { return audio.jackNframes; };
@@ -61,10 +66,14 @@ class JackEngine : public AudioOut, MidiIn
private:
bool connectServer(std::string server);
bool openAudio();
+ void stopAudio();
bool processAudio(jack_nframes_t nframes);
+ bool openMidi();
+ void stopMidi();
jack_client_t *jackClient;
struct {
+ bool en;
unsigned int jackSamplerate;
unsigned int jackNframes;
jack_port_t *ports[2];
@@ -72,6 +81,7 @@ class JackEngine : public AudioOut, MidiIn
} audio;
struct {
jack_port_t *inport;
+ bool en;
} midi;
void handleMidi(unsigned long frames);
diff --git a/src/Nio/MidiIn.h b/src/Nio/MidiIn.h
@@ -3,7 +3,9 @@
MidiIn.h - This class is inherited by all the Midi input classes
Copyright (C) 2002-2005 Nasca Octavian Paul
- Author: Nasca Octavian Paul
+ Copyright (C) 2009-2010 Mark McCurry
+ Author: Nasca Octavian Paula
+ 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
@@ -30,6 +32,9 @@ class MidiIn : public virtual Engine
{
public:
static int getcontroller(unsigned char b);
+
+ virtual void setMidiEn(bool nval)=0;
+ virtual bool getMidiEn() const=0;
};
#endif
diff --git a/src/Nio/NulEngine.cpp b/src/Nio/NulEngine.cpp
@@ -105,3 +105,11 @@ void NulEngine::Stop()
pthread_join(pThread, NULL);
}
+void NulEngine::setAudioEn(bool nval)
+{}
+
+bool NulEngine::getAudioEn() const
+{
+ return true;
+}
+
diff --git a/src/Nio/NulEngine.h b/src/Nio/NulEngine.h
@@ -32,16 +32,19 @@ class NulEngine: public AudioOut
public:
NulEngine(OutMgr *out);
~NulEngine();
-
+
bool Start();
void Stop();
+ void setAudioEn(bool nval);
+ bool getAudioEn() const;
+
protected:
void *AudioThread();
static void *_AudioThread(void *arg);
private:
-
+ bool en;
void dummyOut();
struct timeval playing_until;
};
diff --git a/src/Nio/OssEngine.cpp b/src/Nio/OssEngine.cpp
@@ -41,54 +41,82 @@ using namespace std;
OssEngine::OssEngine(OutMgr *out)
:AudioOut(out)
{
- name = "OSS";
- snd_fragment = 0x00080009; //fragment size (?)
- snd_stereo = 1; //stereo
- snd_format = AFMT_S16_LE;
- snd_samplerate = SAMPLE_RATE;
-
- smps = new short[SOUND_BUFFER_SIZE * 2];
- memset(smps, 0, sizeof(short) * SOUND_BUFFER_SIZE * 2);
+ name = "OSS";
+
+ midi.en = true;
+ audio.en = true;
+
+ audio.smps = new short[SOUND_BUFFER_SIZE * 2];
+ memset(audio.smps, 0, sizeof(short) * SOUND_BUFFER_SIZE * 2);
}
OssEngine::~OssEngine()
{
Stop();
- delete [] smps;
+ delete [] audio.smps;
}
bool OssEngine::openAudio()
{
- int snd_bitsize = 16;
- snd_handle = open(config.cfg.LinuxOSSWaveOutDev, O_WRONLY, 0);
- if(snd_handle == -1) {
+ 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) {
cerr << "ERROR - I can't open the "
<< config.cfg.LinuxOSSWaveOutDev << '.' << endl;
return false;
}
- ioctl(snd_handle, SNDCTL_DSP_RESET, NULL);
- ioctl(snd_handle, SNDCTL_DSP_SETFMT, &snd_format);
- ioctl(snd_handle, SNDCTL_DSP_STEREO, &snd_stereo);
- ioctl(snd_handle, SNDCTL_DSP_SPEED, &snd_samplerate);
- ioctl(snd_handle, SNDCTL_DSP_SAMPLESIZE, &snd_bitsize);
- ioctl(snd_handle, SNDCTL_DSP_SETFRAGMENT, &snd_fragment);
+ 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);
+
return true;
}
+void OssEngine::stopAudio()
+{
+ int handle = audio.snd_handle;
+ if(handle == -1) //already closed
+ return;
+ audio.snd_handle = -1;
+ close(handle);
+}
+
bool OssEngine::Start()
{
if(enabled())
return true;
- if(!openAudio())
- return false;
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) {
+ Stop();
+ return false;
+ }
+
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
- pthread_create(&pThread, &attr, _AudioThread, this);
-
-
- StartMidi();
+ pthread_create(&pThread, &attr, _thread, this);
return true;
}
@@ -98,169 +126,173 @@ void OssEngine::Stop()
if(!enabled())
return;
enabled = false;
+ stopAudio();
+ stopMidi();
pthread_join(pThread, NULL);
- close(snd_handle);
+}
+
+void OssEngine::setMidiEn(bool nval)
+{
+ midi.en = nval;
+ if(enabled()) {
+ if(nval)
+ openMidi();
+ else
+ stopMidi();
+ }
+}
- StopMidi();
+bool OssEngine::getMidiEn() const
+{
+ if(enabled())
+ return midi.handle != -1;
+ else
+ return midi.en;
}
-bool OssEngine::StartMidi()
+void OssEngine::setAudioEn(bool nval)
{
- openMidi();
- pthread_attr_t attr;
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- pthread_create(&pThreadMidi, &attr, _MidiThread, this);
+ audio.en = nval;
+ if(enabled()) { //lets rebind the ports
+ if(nval)
+ openAudio();
+ else
+ stopAudio();
+ }
+}
+bool OssEngine::getAudioEn() const
+{
+ if(enabled())
+ return audio.snd_handle != -1;
+ else
+ return audio.en;
+}
+
+bool OssEngine::openMidi()
+{
+ midi.handle = open(config.cfg.LinuxOSSSeqInDev, O_RDONLY, 0);
+
+ if(-1 == midi.handle)
+ return false;
+
+ midi.run = true;
return true;
}
-void OssEngine::StopMidi()
+void OssEngine::stopMidi()
{
- pthread_cancel(pThreadMidi);
- close(midiHandle);
+ int tmp = midi.handle;
+ if(tmp == -1) //already closed
+ return;
+
+ midi.run = false;
+ midi.handle = -1;
+ close(tmp);
}
-void *OssEngine::_AudioThread(void *arg)
+void *OssEngine::_thread(void *arg)
{
- return (static_cast<OssEngine*>(arg))->AudioThread();
+ return (static_cast<OssEngine*>(arg))->thread();
}
-void *OssEngine::AudioThread()
+void *OssEngine::thread()
{
- //get some initial samples
- manager->requestSamples();
- manager->requestSamples();
- manager->requestSamples();
+ MidiEvent ev;
+ unsigned char tmp[4] = {0, 0, 0, 0};
set_realtime();
- while (enabled())
+ while (midi.run || audio.snd_handle != -1)
{
- const Stereo<Sample> smps = getNext();
- smps.l().c_buf()[10];
- OSSout(smps.l().c_buf(),smps.r().c_buf());
+ if(audio.snd_handle != -1)
+ {
+ const Stereo<Sample> smps = getNext();
+
+ REALTYPE l, r;
+ for(int i = 0; i < SOUND_BUFFER_SIZE; i++) {
+ l = smps.l()[i];
+ r = smps.r()[i];
+
+ if(l < -1.0)
+ l = -1.0;
+ else
+ if(l > 1.0)
+ l = 1.0;
+ if(r < -1.0)
+ r = -1.0;
+ else
+ if(r > 1.0)
+ r = 1.0;
+
+ audio.smps[i * 2] = (short int) (l * 32767.0);
+ audio.smps[i * 2 + 1] = (short int) (r * 32767.0);
+ }
+ int handle = audio.snd_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) {
+ getMidi(tmp);
+ unsigned char type = tmp[0];
+ unsigned char header = tmp[1];
+ if(header!=0xfe&&type==SEQ_MIDIPUTC&&header>=0x80)
+ {
+ getMidi(tmp);
+ unsigned char num = tmp[1];
+ getMidi(tmp);
+ unsigned char value = tmp[1];
+
+ midiProcess(header, num, value);
+ }
+ }
}
pthread_exit(NULL);
+ return NULL;
}
-void *OssEngine::_MidiThread(void *arg)
+void OssEngine::getMidi(unsigned char *midiPtr)
{
- return (static_cast<OssEngine*>(arg))->MidiThread();
+ read(midi.handle, midiPtr, 4);
}
-void *OssEngine::MidiThread()
+void OssEngine::midiProcess(unsigned char head, unsigned char num, unsigned char value)
{
- set_realtime();
MidiEvent ev;
- while(1) {
- lastmidicmd = 0;
- unsigned char tmp, i;
- i = 0;
-
- if(lastmidicmd == 0) { //asteapta prima data pana cand vine prima comanda midi
- while(tmp < 0x80)
- tmp = getmidibyte();
- lastmidicmd = tmp;
- }
-
- tmp = getmidibyte();
-
- if(tmp >= 0x80) {
- lastmidicmd = tmp;
- tmp = getmidibyte();
- }
-
- if((lastmidicmd >= 0x80) && (lastmidicmd <= 0x8f)) { //Note OFF
+ unsigned char chan = head & 0x0f;
+ switch(head & 0xf0)
+ {
+ case 0x80: //Note Off
ev.type = M_NOTE;
- ev.channel = lastmidicmd%16;
- ev.num = tmp;
+ ev.channel = chan;
+ ev.num = num;
ev.value = 0;
sysIn->putEvent(ev);
- }
- else if((lastmidicmd >= 0x90) && (lastmidicmd <= 0x9f)) {//Note ON
+ break;
+ case 0x90: //Note On
ev.type = M_NOTE;
- ev.channel = lastmidicmd%16;
- ev.num = tmp;
- ev.value = getmidibyte();
+ ev.channel = chan;
+ ev.num = num;
+ ev.value = value;
sysIn->putEvent(ev);
- }
- else if((lastmidicmd >= 0xB0) && (lastmidicmd <= 0xBF)) {//Controllers
+ break;
+ case 0xb0: //Controller
ev.type = M_CONTROLLER;
- ev.channel = lastmidicmd%16;
- ev.num = tmp;
- ev.value = getmidibyte();
+ ev.channel = chan;
+ ev.num = num;
+ ev.value = value;
sysIn->putEvent(ev);
- }
- else if((lastmidicmd >= 0xE0) && (lastmidicmd <= 0xEF)) {//Pitch Wheel
+ break;
+ case 0xe0: //Pitch Wheel
ev.type = M_CONTROLLER;
- ev.channel = lastmidicmd%16;
+ ev.channel = chan;
ev.num = C_pitchwheel;
- ev.value = (tmp + getmidibyte() * (int) 128) - 8192;
+ ev.value = (num + value * (int) 128) - 8192;
sysIn->putEvent(ev);
- }
+ break;
}
}
-/*
- * Output the samples to the soundcard
- * The samples are bigger than -1.0 and smaller 1.0
- */
-void OssEngine::OSSout(const REALTYPE *smp_left, const REALTYPE *smp_right)
-{
- int i;
- REALTYPE l, r;
- for(i = 0; i < SOUND_BUFFER_SIZE; i++) {
- l = smp_left[i];
- r = smp_right[i];
-
- if(l < -1.0)
- l = -1.0;
- else
- if(l > 1.0)
- l = 1.0;
- if(r < -1.0)
- r = -1.0;
- else
- if(r > 1.0)
- r = 1.0;
-
- smps[i * 2] = (short int) (l * 32767.0);
- smps[i * 2 + 1] = (short int) (r * 32767.0);
- }
- write(snd_handle, smps, SOUND_BUFFER_SIZE * 4); // *2 because is 16 bit, again * 2 because is stereo
-}
-
-bool OssEngine::openMidi()
-{
- midiHandle = open(config.cfg.LinuxOSSSeqInDev, O_RDONLY, 0);
-
- lastmidicmd = 0;
- cmdtype = 0;
- cmdchan = 0;
-
- pthread_attr_t attr;
- pthread_attr_init(&attr);
-
-
- return midiHandle != -1;
-}
-
-unsigned char OssEngine::readbyte()
-{
- unsigned char tmp[4] = {0, 0, 0, 0};
- read(midiHandle, &tmp[0], 1);
- while(tmp[0] != SEQ_MIDIPUTC) {
- read(midiHandle, &tmp[0], 4);
- }
- return tmp[1];
-}
-
-unsigned char OssEngine::getmidibyte()
-{
- unsigned char b;
- do {
- b = readbyte();
- } while(b == 0xfe); //drops the Active Sense Messages
- return b;
-}
-
diff --git a/src/Nio/OssEngine.h b/src/Nio/OssEngine.h
@@ -37,43 +37,39 @@ class OssEngine: public AudioOut, MidiIn
bool Start();
void Stop();
- bool StartMidi();
- void StopMidi();
+ void setAudioEn(bool nval);
+ bool getAudioEn() const;
+
+ void setMidiEn(bool nval);
+ bool getMidiEn() const;
+
protected:
- void *AudioThread();
- static void *_AudioThread(void *arg);
- void *MidiThread();
- static void *_MidiThread(void *arg);
+ void *thread();
+ static void *_thread(void *arg);
private:
//Audio
- /**Open the audio device
- * @return true for success*/
bool openAudio();
-
- void OSSout(const REALTYPE *smp_left, const REALTYPE *smp_right);
- int snd_handle;
- int snd_fragment;
- int snd_stereo;
- int snd_format;
- int snd_samplerate;
-
- short int *smps; //Samples to be sent to soundcard
+ void stopAudio();
+ struct {
+ int snd_handle;
+ short int *smps; //Samples to be sent to soundcard
+ bool en;
+ } audio;
//Midi
- pthread_t pThreadMidi;
bool openMidi();
void stopMidi();
- unsigned char getmidibyte();
- unsigned char readbyte();
-
- unsigned char cmdtype; //the Message Type (noteon,noteof,sysex..)
- unsigned char cmdchan; //the channel number
+ void midiProcess(unsigned char head, unsigned char num, unsigned char value);
- int midiHandle;
- unsigned char lastmidicmd; //last byte (>=80) received from the Midi
+ void getMidi(unsigned char *midiPtr);
+ struct {
+ int handle;
+ bool en;
+ bool run;
+ } midi;
};
#endif
diff --git a/src/Nio/OutMgr.cpp b/src/Nio/OutMgr.cpp
@@ -91,7 +91,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->isEnabled())
+ if(out && out->isRunning() && out->getAudioEn())
out->out(smps);
}
diff --git a/src/Nio/WavEngine.h b/src/Nio/WavEngine.h
@@ -36,6 +36,9 @@ class WavEngine: public AudioOut
bool Start();
void Stop();
+ void setAudioEn(bool nval){};
+ bool getAudioEn() const{};
+
const Stereo<Sample> getNext();
protected:
diff --git a/src/UI/NioUI.cpp b/src/UI/NioUI.cpp
@@ -2,6 +2,7 @@
#include "../Nio/EngineMgr.h"
#include "../Nio/OutMgr.h"
#include "../Nio/AudioOut.h"
+#include "../Nio/MidiIn.h"
#include <cstdio>
#include <FL/Fl_Tabs.H>
#include <FL/Fl_Group.H>
@@ -33,8 +34,11 @@ NioUI::NioUI()
gen->end();
for(list<Engine *>::iterator itr = sysEngine->engines.begin();
- itr != sysEngine->engines.end(); ++itr)
- tabs.push_back(new NioTab((*itr)->name));
+ 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();
@@ -55,22 +59,46 @@ void NioUI::refresh()
(*itr)->refresh();
}
+//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)
{
Fl_Button *w = static_cast<Fl_Button *>(wid);
NioTab *p = static_cast<NioTab *>(arg);
bool val = w->value();
- AudioOut *out = sysOut->getOut(p->name);
- if(out) {
+ Engine *eng = sysEngine->getEng(p->name);
+ if(eng) {
if(val)
- out->Start();
+ eng->Start();
else
- out->Stop();
+ eng->Stop();
}
p->refresh();
}
+void NioTab::audioToggle(Fl_Widget *wid, void *arg)
+{
+ Fl_Button *w = static_cast<Fl_Button *>(wid);
+ NioTab *p = static_cast<NioTab *>(arg);
+ bool val = w->value();
+
+ AudioOut *out = sysOut->getOut(p->name);
+ out->setAudioEn(val);
+ p->refresh();
+}
+
+void NioTab::midiToggle(Fl_Widget *wid, void *arg)
+{
+ Fl_Button *w = static_cast<Fl_Button *>(wid);
+ NioTab *p = static_cast<NioTab *>(arg);
+ bool val = w->value();
+
+ MidiIn *in = dynamic_cast<MidiIn *>(sysEngine->getEng(p->name));
+ in->setMidiEn(val);
+ p->refresh();
+}
+
void NioTab::nioBuffer(Fl_Widget *wid, void *arg)
{
Fl_Spinner *w = static_cast<Fl_Spinner *>(wid);
@@ -85,27 +113,46 @@ void NioTab::nioBuffer(Fl_Widget *wid, void *arg)
}
}
-NioTab::NioTab(string name)
+NioTab::NioTab(string name, bool _midi, bool _audio)
:Fl_Group(10, 40, 400, 400-35, strdup(name.c_str())),
- outEnable(20, 30, 100, 25, "Enable"),
- buffer(70, 60, 50, 25, "Buffer:"),//in SOUND_BUFFER_SIZE units
+ enable(20, 30, 100, 25, "Enable"),
+ audio(NULL), midi(NULL), buffer(NULL),
name(name)
{
- outEnable.callback(nioToggle, (void *)this);
- buffer.callback(nioBuffer, (void *)name.c_str());
- //this is a COMPLETELY arbitrary max
- //I just assume that users do not want an overly long buffer
- buffer.range(1, 100);
- buffer.type(FL_INT_INPUT);
+ enable.callback(nioToggle, (void *)this);
+ if(_audio) {
+ buffer = new Fl_Spinner(70, 60, 50, 25, "Buffer:");//in SOUND_BUFFER_SIZE units
+ buffer->callback(nioBuffer, (void *)name.c_str());
+ //this is a COMPLETELY arbitrary max
+ //I just assume that users do not want an overly long buffer
+ buffer->range(1, 100);
+ buffer->type(FL_INT_INPUT);
+ audio = new Fl_Light_Button(20, 80, 100, 25, "Audio");
+ audio->callback(audioToggle, (void *)this);
+ }
+ if(_midi) {
+ midi = new Fl_Light_Button(20, 100, 100, 25, "Midi");
+ midi->callback(midiToggle, (void *)this);
+ }
+
end();
}
void NioTab::refresh()
{
- //getOut should only be called with present Engines
- bool state = sysOut->getOut(name)->isEnabled();
- outEnable.value(state);
- buffer.value(sysOut->getOut(name)->bufferingSize());
+ //get engine
+ Engine *eng = sysEngine->getEng(name);
+ MidiIn *midiIn = dynamic_cast<MidiIn *>(eng);
+ AudioOut *audioOut = dynamic_cast<AudioOut *>(eng);
+ if(midi)
+ midi->value(midiIn->getMidiEn());
+ if(audio)
+ audio->value(audioOut->getAudioEn());
+
+ bool state = eng->isRunning();
+ enable.value(state);
+ buffer->value(sysOut->getOut(name)->bufferingSize());
+
this->labelcolor(fl_rgb_color(0,255*state,0));
this->redraw();
diff --git a/src/UI/NioUI.h b/src/UI/NioUI.h
@@ -12,14 +12,18 @@
struct NioTab : public Fl_Group
{
- NioTab(std::string name);
+ NioTab(std::string name, bool _midi, bool _audio);
void refresh();
static void nioToggle(Fl_Widget *w, void *arg);
+ static void audioToggle(Fl_Widget *w, void *arg);
+ static void midiToggle(Fl_Widget *w, void *arg);
static void nioBuffer(Fl_Widget *w, void *arg);
- Fl_Light_Button outEnable;
- Fl_Spinner buffer;
+ Fl_Light_Button enable;
+ Fl_Light_Button *midi;
+ Fl_Light_Button *audio;
+ Fl_Spinner *buffer;
const std::string name;
};
diff --git a/src/main.cpp b/src/main.cpp
@@ -221,6 +221,7 @@ void initprogram()
void exitprogram()
{
pthread_mutex_lock(&master->mutex);
+ pthread_mutex_unlock(&master->mutex);
delete sysOut;
delete sysIn;
delete sysEngine;