Skip to content

Instantly share code, notes, and snippets.

@nickbailey
Last active June 13, 2019 09:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nickbailey/aea9032cfdce75706bd80720372061aa to your computer and use it in GitHub Desktop.
Save nickbailey/aea9032cfdce75706bd80720372061aa to your computer and use it in GitHub Desktop.
An adapter to allow old-school data-push audio apps to work as JACK clients
// A little bit of research to find out how to regress jack to ALSA :)
// compile with g++ push_to_jack.cpp -ljack
#include <jack/jack.h>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <iostream>
class JackBlockingOutputAdaptor {
size_t bufsize;
jack_client_t* client;
jack_port_t* port;
jack_default_audio_sample_t* buffer;
jack_nframes_t sr;
std::mutex mtx;
std::condition_variable cv;
bool dav {false};
JackThreadCallback process_dispatch;
public:
jack_default_audio_sample_t * const data(void) const { return buffer; }
const size_t size(void) const { return bufsize; };
const jack_nframes_t rate(void) const { return sr; };
JackBlockingOutputAdaptor(const char* client_name,
const char* server_name = nullptr) {
// Communicate with jack
jack_status_t status;
jack_options_t options = JackNullOption;
client = jack_client_open (client_name, options, &status, server_name);
if (client == nullptr) {
std::cerr << "jack_client_open() failed, "
"status = " << status << std::endl;
if (status & JackServerFailed) {
std::cerr << "Unable to connect to JACK server\n";
}
exit (1);
}
// Initialise working parameters
bufsize = jack_get_buffer_size(client);
buffer = new jack_default_audio_sample_t[bufsize];
std::fill(buffer, buffer + bufsize, 0);
sr = jack_get_sample_rate(client);
port = jack_port_register(client, "output",
JACK_DEFAULT_AUDIO_TYPE,
JackPortIsOutput, 0);
if (port == nullptr) {
std::cerr << "No more JACK ports available\n";
exit (1);
}
jack_set_process_thread(client,
JackBlockingOutputAdaptor::process, this);
}
~JackBlockingOutputAdaptor() {
jack_deactivate(client);
jack_client_close(client);
delete[] buffer;
}
void commence() {
if (jack_activate(client)) {
std::cerr << "Cannot activate client\n";
exit (1);
}
}
void dispatch(void) {
{
std::unique_lock<std::mutex> lck(mtx);
dav = true;
cv.notify_one();
}
while(dav) std::this_thread::yield();
}
private:
static void* process(void* o) {
return static_cast<JackBlockingOutputAdaptor*>(o)->process_delegate(nullptr);
}
void* process_delegate(void* args) {
while(true) {
jack_default_audio_sample_t* in(
static_cast<jack_default_audio_sample_t*>(
jack_port_get_buffer(port, bufsize)
));
std::unique_lock<std::mutex> lck(mtx);
cv.wait(lck, [this](){return dav;});
std::copy(buffer, buffer + bufsize, in);
jack_cycle_signal(client, 0);
dav = false;
jack_cycle_wait(client);
}
jack_cycle_signal(client, -1);
return nullptr;
}
};
#include <cmath>
int main()
{
JackBlockingOutputAdaptor a("BEEEEP!");
int writes(10*a.rate()/a.size());
jack_default_audio_sample_t * const target{a.data()};
a.commence();
long s{0};
while (writes--) {
for(int i = 0; i < a.size(); i++) {
s++;
target[i] = sin(s*2.0*M_PI*442.0/a.rate());
}
a.dispatch();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment