123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222 |
- /*
- This file is part of QTau
- Copyright (C) 2013-2018 Tobias "Tomoko" Platen <tplaten@posteo.de>
- Copyright (C) 2013 digited <https://github.com/digited>
- Copyright (C) 2010-2013 HAL@ShurabaP <https://github.com/haruneko>
- QTau 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 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 this program. If not, see <http://www.gnu.org/licenses/>.
- SPDX-License-Identifier: GPL-3.0+
- */
- #define __devloglevel__ 4
- #include "jackaudio.h"
- #include <assert.h>
- #include <stdio.h>
- #include <QDebug>
- #include <QMessageBox>
- #include <QIcon>
- #include <sys/eventfd.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <stdint.h>
- #include <jack/midiport.h>
- #include <iostream>
- int JackAudio::createEFD()
- {
- _eventfd = eventfd(0, 0);
- return _eventfd;
- }
- int JackAudio::readMidiData(char *buffer, int maxlength)
- {
- int count = jack_ringbuffer_read_space(this->_midi_rb);
- if(count>0)
- {
- if(count>maxlength) count=maxlength;
- jack_ringbuffer_read(this->_midi_rb,buffer,count);
- }
- return count;
- }
- int JackAudio::process(jack_nframes_t nframes, void *arg)
- {
- JackAudio* conn = (JackAudio*) arg;
- // midi input handing
- void* port_buf = jack_port_get_buffer( conn->_midi_port, nframes);
- jack_nframes_t event_count = jack_midi_get_event_count(port_buf);
- if(event_count > 0)
- {
- for(jack_nframes_t i=0; i<event_count; i++)
- {
- jack_midi_event_t in_event;
- //jack_position_t position;
- jack_midi_event_get(&in_event, port_buf, i);
- //FIXME: sysex support
- jack_ringbuffer_write(conn->_midi_rb,(char*)in_event.buffer,in_event.size);
- }
- }
- // audio output
- sample_t* write_samp = (sample_t*)jack_port_get_buffer(conn->_write_port,nframes);
- if(jack_ringbuffer_read_space(conn->_write_rb)>=sizeof(sample_t)*nframes)
- {
- jack_ringbuffer_read(conn->_write_rb,(char*)write_samp,sizeof(sample_t)*nframes);
- }
- else
- {
- for(unsigned int i=0;i<nframes;i++) write_samp[i]=0.0;//buffer underrun
- DEVLOG_DEBUG("xrun in JackAudio::process");
- }
- // transport control
- if (conn->_use_transport) {
- conn->_transport_state = jack_transport_query(conn->_client, NULL);
- if (conn->_transport_state == JackTransportStopped && conn->_previous_transport_state == JackTransportRolling) {
- conn->_state_changed = true;
- }
- if (conn->_transport_state == JackTransportStarting && conn->_previous_transport_state != JackTransportStarting) {
- conn->_state_changed = true;
- }
- if (conn->_transport_state == JackTransportRolling && conn->_previous_transport_state != JackTransportRolling) {
- conn->_state_changed = true;
- }
- conn->_previous_transport_state = conn->_transport_state;
- }
- if(conn->_transport_command==TRANSPORT_START) jack_transport_start(conn->_client);
- if(conn->_transport_command==TRANSPORT_STOP) jack_transport_stop(conn->_client);
- if(conn->_transport_command==TRANSPORT_ZERO) {
- jack_position_t pos;
- pos.valid=(jack_position_bits_t)0;
- pos.frame=0;
- jack_transport_stop(conn->_client);
- jack_transport_reposition(conn->_client,&pos);
- }
- if(conn->_transport_command==TRANSPORT_STARTPOS)
- {
- jack_position_t pos;
- pos.valid=(jack_position_bits_t)0;
- pos.frame=conn->_startpos*conn->sampleRate();
- jack_transport_stop(conn->_client);
- jack_transport_reposition(conn->_client,&pos);
- jack_transport_start(conn->_client);
- }
- conn->_transport_command = 0;
- //notify
- uint64_t u = 1;
- if(write(conn->_eventfd, &u, sizeof(uint64_t))!=8) return 1;
- // no error
- return 0;
- }
- int JackAudio::sync(jack_transport_state_t state, jack_position_t *pos, void *arg)
- {
- (void) state;
- //start tranport
- JackAudio* conn = (JackAudio*) arg;
- if(conn->_use_transport)
- {
- conn->_position = pos->frame;
- return 1;
- }
- else return 1;
- }
- JackAudio::JackAudio(bool autoconnect)
- {
- _client = jack_client_open("QTau",JackNoStartServer,NULL);
-
- if(_client==NULL) {
- QMessageBox msgbox;
- msgbox.setText("jack is not running");
- msgbox.exec();
- exit(1);
- }
- _buffer_size = jack_get_buffer_size(_client);
- //TODO configurable port names ???
- _write_port = jack_port_register(_client,"out",JACK_DEFAULT_AUDIO_TYPE,JackPortIsOutput,_buffer_size);
- _write_rb = jack_ringbuffer_create (sizeof(sample_t) * 4096);
- _midi_rb = jack_ringbuffer_create(4096);
- _midi_port = jack_port_register(_client,"midi_in",JACK_DEFAULT_MIDI_TYPE,JackPortIsInput,0);
- jack_set_process_callback(_client,process,this);
- jack_set_sync_callback(_client,sync,this);
- jack_activate(_client);
- if(autoconnect)
- {
- jack_connect(_client,"QTau:out","system:playback_2");//FOR testing
- jack_connect(_client,"QTau:out","system:playback_1");//FOR testing
- }
- _transport_command = TRANSPORT_ZERO;
- _use_transport = true;
- _playback = false;
- }
- int JackAudio::sampleRate()
- {
- return jack_get_sample_rate(_client);
- }
- int JackAudio::writeData(void *framebuf, int bytes_per_frame)
- {
- if(jack_ringbuffer_write_space(_write_rb)>=(unsigned int)bytes_per_frame)
- {
- return jack_ringbuffer_write(_write_rb,(char*)framebuf,bytes_per_frame);
- }
- DEVLOG_DEBUG("xrun in JackAudio::writeData");//FIXME do not log while program startup
- return 0;//not data was written
- }
- float *JackAudio::allocateBuffer()
- {
- if(_buffer_size==0) return NULL;
- return new float[_buffer_size];
- }
- void JackAudio::shutdown()
- {
- jack_deactivate(_client);
- jack_client_close(_client);
- }
|