commit 70e0346ea40f655a48a277a3cdc234c718e3082b
parent 37d769d22e471952b2132eca5da7b58d4587d44c
Author: fundamental <mark.d.mccurry@gmail.com>
Date: Fri, 18 Dec 2009 10:47:20 -0500
Nio: Added primitive JACK support in Nio
Diffstat:
7 files changed, 329 insertions(+), 9 deletions(-)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
@@ -47,7 +47,7 @@ if (DefaultOutput STREQUAL alsa)
elseif(DefaultOutput STREQUAL oss)
add_definitions(-DOSS_DEFAULT=1)
elseif(DefaultOutput STREQUAL jack)
- add_definitions(-DOSS_DEFAULT=1)
+ add_definitions(-DJACK_DEFAULT=1)
endif()
@@ -60,6 +60,7 @@ if(AlsaEnable)
add_definitions(-DALSA=1)
endif(AlsaEnable)
if(JackEnable)
+ list(APPEND AUDIO_LIBRARIES ${JACK_LIBRARIES})
add_definitions(-DJACK=1)
endif(JackEnable)
if(OssEnable)
diff --git a/src/Nio/CMakeLists.txt b/src/Nio/CMakeLists.txt
@@ -12,12 +12,11 @@ set(zynaddsubfx_nio_SRCS
set(zynaddsubfx_nio_lib )
-#Uncomment when Jack is integrated
-#if(JackEnable)
-# include_directories(${JACK_INCLUDE_DIR})
-# list(APPEND zynaddsubfx_nio_SRCS JackEngine.cpp)
-# set(zynaddsubfx_nio_lib ${JACK_LIBRARIES})
-#endif(JackEnable)
+if(JackEnable)
+ include_directories(${JACK_INCLUDE_DIR})
+ list(APPEND zynaddsubfx_nio_SRCS JackEngine.cpp)
+ list(APPEND zynaddsubfx_nio_lib ${JACK_LIBRARIES})
+endif(JackEnable)
#Uncomment when Port Audio is integrated
#if(PortAudioOutput)
diff --git a/src/Nio/JackEngine.cpp b/src/Nio/JackEngine.cpp
@@ -0,0 +1,230 @@
+/*
+ JackEngine.cpp
+
+ Copyright 2009, Alan Calvert
+
+ 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.
+
+ 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.
+
+ 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>
+
+//#include <jack/midiport.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+
+//#include "../Misc/Config.h"
+#include "../Misc/Master.h"
+#include "JackEngine.h"
+
+using namespace std;
+
+JackEngine::JackEngine(OutMgr *out)
+ :AudioOut(out), jackClient(NULL)
+{
+ audio.jackSamplerate = 0;
+ audio.jackNframes = 0;
+ for (int i = 0; i < 2; ++i)
+ {
+ audio.ports[i] = NULL;
+ audio.portBuffs[i] = NULL;
+ }
+}
+
+bool JackEngine::connectServer(string server)
+{
+ cout << "Bla" << endl;
+ //temporary (move to a higher level configuation)
+ bool autostart_jack = 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));
+ for (int tries = 0; tries < 3 && NULL == jackClient; ++tries)
+ {
+ 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)
+ break;
+ else
+ usleep(3333);
+ }
+ 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()
+{
+ enabled = true;
+ connectServer("");
+ openAudio();
+ if (NULL != jackClient)
+ {
+ int chk;
+ jack_set_error_function(_errorCallback);
+ jack_set_info_function(_infoCallback);
+ if ((chk = jack_set_xrun_callback(jackClient, _xrunCallback, this)))
+ cerr << "Error setting jack xrun callback" << endl;
+ if (jack_set_process_callback(jackClient, _processCallback, this))
+ {
+ cerr << "Error, JackEngine failed to set process callback" << endl;
+ goto bail_out;
+ }
+ if (jack_activate(jackClient))
+ {
+ cerr << "Error, failed to activate jack client" << endl;;
+ goto bail_out;
+ }
+
+ return true;
+ }
+ else
+ cerr << "Error, NULL jackClient through Start()" << endl;
+bail_out:
+ Stop();
+ return false;
+}
+
+void JackEngine::Stop()
+{
+ 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;
+ }
+ int chk = jack_client_close(jackClient);
+ jackClient = NULL;
+ }
+ enabled = false;
+}
+
+bool JackEngine::openAudio()
+{
+ const char *portnames[] = { "left", "right" };
+ for (int port = 0; port < 2; ++port)
+ {
+ audio.ports[port] = jack_port_register(jackClient, portnames[port],
+ JACK_DEFAULT_AUDIO_TYPE,
+ JackPortIsOutput, 0);
+ }
+ if (NULL != audio.ports[0] && NULL != audio.ports[1])
+ {
+ audio.jackSamplerate = jack_get_sample_rate(jackClient);
+ audio.jackNframes = jack_get_buffer_size(jackClient);
+ return true;
+ }
+ else
+ cerr << "Error, failed to register jack audio ports" << endl;
+ Stop();
+ return false;
+}
+
+int JackEngine::clientId()
+{
+ if (NULL != jackClient)
+ return jack_client_thread_id(jackClient);
+ else
+ return -1;
+}
+
+string JackEngine::clientName()
+{
+ if (NULL != jackClient)
+ return string(jack_get_client_name(jackClient));
+ else
+ cerr << "Error, clientName() with null jackClient" << endl;
+ return string("Oh, yoshimi :-(");
+}
+
+int JackEngine::_processCallback(jack_nframes_t nframes, void *arg)
+{
+ return static_cast<JackEngine*>(arg)->processCallback(nframes);
+}
+
+int JackEngine::processCallback(jack_nframes_t nframes)
+{
+ bool okaudio = true;
+
+ if (NULL != audio.ports[0] && NULL != audio.ports[1])
+ okaudio = processAudio(nframes);
+ return okaudio ? 0 : -1;
+}
+
+bool JackEngine::processAudio(jack_nframes_t nframes)
+{
+ //cout << "I got called with: " << nframes << endl;
+ for (int port = 0; port < 2; ++port)
+ {
+ audio.portBuffs[port] =
+ (jsample_t*)jack_port_get_buffer(audio.ports[port], nframes);
+ if (NULL == audio.portBuffs[port])
+ {
+ cerr << "Error, failed to get jack audio port buffer: "
+ << port << endl;
+ return false;
+ }
+ }
+
+ Stereo<Sample> smp = getNext();
+ //cout << "smp size of: " << smp.l().size() << endl;
+ memcpy(audio.portBuffs[0], smp.l().c_buf(), smp.l().size()*sizeof(REALTYPE));
+ memcpy(audio.portBuffs[1], smp.r().c_buf(), smp.r().size()*sizeof(REALTYPE));
+ //todo figure out how to do this right!
+ smp = getNext();
+ memcpy(audio.portBuffs[0]+smp.l().size(), smp.l().c_buf(), smp.l().size()*sizeof(REALTYPE));
+ memcpy(audio.portBuffs[1]+smp.r().size(), smp.r().c_buf(), smp.r().size()*sizeof(REALTYPE));
+ smp = getNext();
+ memcpy(audio.portBuffs[0]+2*smp.l().size(), smp.l().c_buf(), smp.l().size()*sizeof(REALTYPE));
+ memcpy(audio.portBuffs[1]+2*smp.r().size(), smp.r().c_buf(), smp.r().size()*sizeof(REALTYPE));
+ smp = getNext();
+ memcpy(audio.portBuffs[0]+3*smp.l().size(), smp.l().c_buf(), smp.l().size()*sizeof(REALTYPE));
+ memcpy(audio.portBuffs[1]+3*smp.r().size(), smp.r().c_buf(), smp.r().size()*sizeof(REALTYPE));
+
+ return true;
+
+}
+
+int JackEngine::_xrunCallback(void *arg)
+{
+ cerr << "Jack reports xrun" << endl;
+ return 0;
+}
+
+void JackEngine::_errorCallback(const char *msg)
+{
+ cerr << "Jack reports error: " << msg << endl;
+}
+
+void JackEngine::_infoCallback(const char *msg)
+{
+ cerr << "Jack info message: " << msg << endl;
+}
diff --git a/src/Nio/JackEngine.h b/src/Nio/JackEngine.h
@@ -0,0 +1,71 @@
+/*
+ JackEngine.h
+
+ Copyright 2009, Alan Calvert
+
+ 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.
+
+ 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.
+
+ You should have received a copy of the GNU General Public License
+ along with yoshimi. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef JACK_ENGINE_H
+#define JACK_ENGINE_H
+
+#include <string>
+#include <pthread.h>
+#include <semaphore.h>
+#include <jack/jack.h>
+#include <jack/ringbuffer.h>
+
+#include "AudioOut.h"
+
+typedef jack_default_audio_sample_t jsample_t;
+
+class JackEngine : public AudioOut
+{
+ public:
+ JackEngine(OutMgr *out);
+ ~JackEngine() { };
+
+ bool setServer(std::string server);
+ bool Start();
+ void Stop();
+
+ unsigned int getSamplerate() { return audio.jackSamplerate; };
+ unsigned int getBuffersize() { return audio.jackNframes; };
+
+ std::string clientName();
+ int clientId();
+
+ protected:
+
+ int processCallback(jack_nframes_t nframes);
+ static int _processCallback(jack_nframes_t nframes, void *arg);
+ static void _errorCallback(const char *msg);
+ static void _infoCallback(const char *msg);
+ static int _xrunCallback(void *arg);
+
+ private:
+ bool connectServer(std::string server);
+ bool openAudio();
+ bool processAudio(jack_nframes_t nframes);
+
+ jack_client_t *jackClient;
+ struct {
+ unsigned int jackSamplerate;
+ unsigned int jackNframes;
+ jack_port_t *ports[2];
+ jsample_t *portBuffs[2];
+ } audio;
+};
+
+#endif
diff --git a/src/Nio/OutMgr.cpp b/src/Nio/OutMgr.cpp
@@ -10,6 +10,9 @@
#if ALSA
#include "AlsaEngine.h"
#endif
+#if JACK
+#include "JackEngine.h"
+#endif
using namespace std;
@@ -46,6 +49,13 @@ OutMgr::OutMgr(Master *nmaster)
managedOuts["ALSA"] = new AlsaEngine(this);
#endif
#endif
+#if JACK
+#if JACK_DEFAULT
+ managedOuts["JACK"] = defaultOut = new JackEngine(this);
+#else
+ managedOuts["JACK"] = new JackEngine(this);
+#endif
+#endif
};
diff --git a/src/UI/NioUI.cpp b/src/UI/NioUI.cpp
@@ -7,14 +7,23 @@ Pack::Pack(int x, int y, int w, int h)
:Fl_Pack(x,y,w,h),
b1(0,0,100,25,"Null I/O"),
b2(0,0,100,25,"ALSA I/O"),
- b3(0,0,100,25,"OSS I/O")
+ b3(0,0,100,25,"OSS I/O"),
+ b4(0,0,100,25,"JACK I/O")
{
b1.selection_color(fl_rgb_color(0,255,0));
b2.selection_color(fl_rgb_color(0,255,0));
b3.selection_color(fl_rgb_color(0,255,0));
+ b4.selection_color(fl_rgb_color(0,255,0));
b1.callback(nioToggle, (void *)"NULL");
b2.callback(nioToggle, (void *)"ALSA");
b3.callback(nioToggle, (void *)"OSS");
+ b4.callback(nioToggle, (void *)"JACK");
+ //b1.value((NULL==sysOut->getOut("NULL")?false:
+ // sysOut->getOut("NULL")->isEnabled()));
+ //b2.value((NULL==sysOut->getOut("ALSA")?false:
+ // sysOut->getOut("ALSA")->isEnabled()));
+ //b3.value((NULL==sysOut->getOut("OSS")?false:
+ // sysOut->getOut("OSS")->isEnabled()));
}
void Pack::nioToggle(Fl_Widget *w, void *name)
diff --git a/src/UI/NioUI.h b/src/UI/NioUI.h
@@ -12,7 +12,7 @@ class Pack : public Fl_Pack
public:
Pack(int x, int y, int w, int h);
private:
- Fl_Light_Button b1,b2,b3;
+ Fl_Light_Button b1, b2, b3, b4;
static void nioToggle(Fl_Widget *w, void *name);
};