134 lines
5.1 KiB
C++
134 lines
5.1 KiB
C++
#include <VulcanoLE/Audio/JackClient.h>
|
|
#include <VUtils/Logging.h>
|
|
|
|
int JackClient::processSamples(jack_nframes_t frames, void *arg) {
|
|
JackClient &client = JackClient::get();
|
|
jack_default_audio_sample_t *inl;
|
|
jack_default_audio_sample_t *inr;
|
|
unsigned int i;
|
|
if (client.input_port_l == nullptr || client.input_port_r == nullptr) {
|
|
return 0;
|
|
}
|
|
inl = (jack_default_audio_sample_t *) jack_port_get_buffer(client.input_port_l, frames);
|
|
inr = (jack_default_audio_sample_t *) jack_port_get_buffer(client.input_port_r, frames);
|
|
client.addFrames(inl, inr, frames);
|
|
return 0;
|
|
}
|
|
void JackClient::onExit() {
|
|
DBG("SHUTDOWN JACK!")
|
|
JackClient &jackClient = JackClient::get();
|
|
const char **all_ports;
|
|
unsigned int i;
|
|
if (jackClient.input_port_l != nullptr) {
|
|
all_ports = jack_port_get_all_connections(jackClient.client, jackClient.input_port_l);
|
|
for (i = 0; all_ports && all_ports[i]; i++) {
|
|
jack_disconnect(jackClient.client, all_ports[i], jack_port_name(jackClient.input_port_l));
|
|
}
|
|
all_ports = jack_port_get_all_connections(jackClient.client, jackClient.input_port_r);
|
|
for (i = 0; all_ports && all_ports[i]; i++) {
|
|
jack_disconnect(jackClient.client, all_ports[i], jack_port_name(jackClient.input_port_r));
|
|
}
|
|
}
|
|
jack_client_close(jackClient.client);
|
|
}
|
|
|
|
void JackClient::connect(const char *port_name, jack_port_t *channel) {
|
|
jack_port_t *port;
|
|
port = jack_port_by_name(client, port_name);
|
|
if (port == nullptr) {
|
|
ERR("Cannot Find Port: %s", port_name)
|
|
exit(1);
|
|
}
|
|
LOG("Connecting %s to %s", jack_port_name(port), jack_port_name(channel))
|
|
if (jack_connect(client, jack_port_name(port), jack_port_name(channel))) {
|
|
ERR("Cannot connect port '%s' to '%s'", jack_port_name(port), jack_port_name(channel))
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
void JackClient::start() {
|
|
jack_status_t status;
|
|
client = jack_client_open("Keyboard Visual", options, &status);
|
|
if (client == nullptr) {
|
|
ERR("Failed to start JACK client: %d", status)
|
|
exit(1);
|
|
}
|
|
DBG("Register as %s", jack_get_client_name(client))
|
|
input_port_l = jack_port_register(client, "left", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, BUFFER_SIZE);
|
|
input_port_r = jack_port_register(client, "right", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, BUFFER_SIZE);
|
|
if (!input_port_l || !input_port_r) {
|
|
ERR("Cannot Register input port left")
|
|
exit(1);
|
|
}
|
|
|
|
atexit(JackClient::onExit);
|
|
jack_set_process_callback(client, JackClient::processSamples, nullptr);
|
|
if (jack_activate(client)) {
|
|
ERR("Cannot Activate Client")
|
|
exit(1);
|
|
}
|
|
auto inputL = env->getEnv("input_l", "");
|
|
auto inputR = env->getEnv("input_r", "");
|
|
DBG("Try Using InputL: %s", inputL.c_str())
|
|
DBG("Try Using InputR: %s", inputR.c_str())
|
|
if (inputL.empty() || inputR.empty() || !checkPort(inputL) || !checkPort(inputR)) {
|
|
inputL = getPort(true);
|
|
inputR = getPort(false);
|
|
DBG("Picking new InputL: %s", inputL.c_str())
|
|
DBG("Picking new InputR: %s", inputR.c_str())
|
|
env->set("input_l", inputL.c_str());
|
|
env->set("input_r", inputR.c_str());
|
|
}
|
|
if (inputL.empty() || inputR.empty()) return;
|
|
connect(inputL.c_str(), input_port_l);
|
|
connect(inputR.c_str(), input_port_r);
|
|
}
|
|
bool JackClient::isData() {
|
|
std::lock_guard<std::mutex> lockGuard(guard);
|
|
return m_newDataAvailable;
|
|
}
|
|
std::string JackClient::getPort(bool isLeft) {
|
|
std::string type = isLeft ? ":monitor_FL" : ":monitor_FR";
|
|
auto port = jack_get_ports(client, type.c_str(), nullptr,
|
|
JackPortIsOutput);
|
|
if (port == nullptr)
|
|
return "";
|
|
return std::string(port[0]);
|
|
}
|
|
bool JackClient::checkPort(const std::string &port) {
|
|
return jack_get_ports(client, port.c_str(), nullptr,
|
|
JackPortIsOutput) != nullptr;
|
|
}
|
|
void JackClient::addFrames(jack_default_audio_sample_t *l, jack_default_audio_sample_t *r, jack_nframes_t i) {
|
|
std::lock_guard<std::mutex> lockGuard(guard);
|
|
if (!grabber)
|
|
return;
|
|
if (grabber->requestMode == AudioGrabber::ReqMode::FFT || grabber->requestMode == AudioGrabber::ReqMode::ALL) {
|
|
for (int j = 0; j < i; ++j) {
|
|
if (samplesAdded >= BUFFER_SIZE) {
|
|
for (int k = 0; k < BUFFER_SIZE; ++k) {
|
|
samples[k].l = ringBuffer[k].l;
|
|
samples[k].r = ringBuffer[k].r;
|
|
}
|
|
m_newDataAvailable = true;
|
|
samplesAdded = 0;
|
|
}
|
|
ringBuffer[samplesAdded].l = l[j];
|
|
ringBuffer[samplesAdded].r = r[j];
|
|
samplesAdded++;
|
|
}
|
|
} else {
|
|
for (int k = 0; k < i; ++k) {
|
|
samples[k].l = l[k];
|
|
samples[k].r = r[k];
|
|
}
|
|
m_newDataAvailable = true;
|
|
samplesAdded = (int) i;
|
|
}
|
|
}
|
|
int JackClient::getFrames() {
|
|
std::lock_guard<std::mutex> lockGuard(guard);
|
|
return grabber->requestMode == AudioGrabber::ReqMode::FFT || grabber->requestMode == AudioGrabber::ReqMode::ALL
|
|
? BUFFER_SIZE : samplesAdded;
|
|
}
|