JAaudiooutput.cpp (6915B)
1 /* 2 JAaudiooutput.C - Audio output for JACK 3 Copyright (C) 2002-2009 Nasca Octavian Paul 4 Author: Robin Gareus <robin@gareus.org> 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of version 2 of the GNU General Public License 8 as published by the Free Software Foundation. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License (version 2) for more details. 14 15 You should have received a copy of the GNU General Public License (version 2) 16 along with this program; if not, write to the Free Software Foundation, 17 Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 19 */ 20 21 #ifdef HAVE_JACK 22 23 #ifndef DEFAULT_RB_SIZE 24 #define DEFAULT_RB_SIZE 16384 25 #endif 26 27 #include <stdlib.h> 28 #include <string.h> 29 #include <pthread.h> 30 #include <jack/jack.h> 31 #include <jack/ringbuffer.h> 32 #include "JAaudiooutput.h" 33 34 Player *myplayer=NULL; 35 jack_client_t *j_client = NULL; 36 jack_port_t **j_output_port = NULL; 37 jack_default_audio_sample_t **j_out = NULL; 38 jack_ringbuffer_t *rb = NULL; 39 40 int m_channels = 2; 41 int thread_run = 0; 42 43 pthread_t player_thread_id; 44 pthread_mutex_t player_thread_lock = PTHREAD_MUTEX_INITIALIZER; 45 pthread_cond_t buffer_ready = PTHREAD_COND_INITIALIZER; 46 47 #ifdef ENABLE_RESAMPLING 48 #include <samplerate.h> 49 float m_fResampleRatio = 1.0; 50 51 #ifndef SRC_QUALITY // alternatives: SRC_SINC_MEDIUM_QUALITY, SRC_SINC_BEST_QUALITY, (SRC_ZERO_ORDER_HOLD, SRC_LINEAR) 52 #define SRC_QUALITY SRC_SINC_FASTEST 53 #endif 54 55 #endif 56 57 void jack_shutdown_callback(void *arg){ 58 fprintf(stderr, "jack server [unexpectedly] shut down.\n"); 59 j_client=NULL; 60 JACKclose(); 61 } 62 63 int jack_audio_callback(jack_nframes_t nframes, void *arg){ 64 int c,s; 65 66 for(c=0; c< m_channels; c++) { 67 j_out[c] = (jack_default_audio_sample_t*) jack_port_get_buffer(j_output_port[c], nframes); 68 } 69 70 if(jack_ringbuffer_read_space(rb) < m_channels * nframes * sizeof(jack_default_audio_sample_t)) { 71 for(c=0; c< m_channels; c++) { 72 memset(j_out[c], 0, nframes * sizeof(jack_default_audio_sample_t)); 73 } 74 } else { 75 /* de-interleave */ 76 for(s=0; s<nframes; s++) { 77 for(c=0; c< m_channels; c++) { 78 jack_ringbuffer_read(rb, (char*) &j_out[c][s], sizeof(jack_default_audio_sample_t)); 79 } 80 } 81 } 82 83 /* Tell the player thread there is work to do. */ 84 if(pthread_mutex_trylock(&player_thread_lock) == 0) { 85 pthread_cond_signal(&buffer_ready); 86 pthread_mutex_unlock(&player_thread_lock); 87 } 88 89 return(0); 90 }; 91 92 void *jack_player_thread(void *){ 93 const int nframes = 4096; 94 float *tmpbuf = (float*) calloc(nframes * m_channels, sizeof(float)); 95 float *bufptr = tmpbuf; 96 #ifdef ENABLE_RESAMPLING 97 SRC_STATE* src_state = src_new(SRC_QUALITY, 2, NULL); 98 SRC_DATA src_data; 99 int nframes_r = floorf((float) nframes*m_fResampleRatio); ///< # of frames after resampling 100 float *smpbuf = (float*) calloc((1+nframes_r) * m_channels, sizeof(float)); 101 102 src_data.input_frames = nframes; 103 src_data.output_frames = nframes_r; 104 src_data.end_of_input = 0; 105 src_data.src_ratio = m_fResampleRatio; 106 src_data.input_frames_used = 0; 107 src_data.output_frames_gen = 0; 108 src_data.data_in = tmpbuf; 109 src_data.data_out = smpbuf; 110 #else 111 int nframes_r = nframes; 112 #endif 113 114 size_t rbsize = nframes_r * m_channels * sizeof(float); 115 116 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); 117 pthread_mutex_lock(&player_thread_lock); 118 119 while(thread_run) { 120 myplayer->getaudiobuffer(nframes, tmpbuf); 121 122 #ifdef ENABLE_RESAMPLING 123 if(m_fResampleRatio != 1.0) { 124 src_process(src_state, &src_data); 125 bufptr = smpbuf; 126 rbsize = src_data.output_frames_gen * m_channels * sizeof(float); 127 } 128 #endif 129 jack_ringbuffer_write(rb, (char *) bufptr, rbsize); 130 131 while(thread_run && jack_ringbuffer_write_space(rb) <= rbsize) { 132 pthread_cond_wait(&buffer_ready, &player_thread_lock); 133 } 134 } 135 136 pthread_mutex_unlock(&player_thread_lock); 137 free(tmpbuf); 138 #ifdef ENABLE_RESAMPLING 139 src_delete(src_state); 140 free(smpbuf); 141 #endif 142 } 143 144 void JACKaudiooutputinit(Player *player_, int samplerate){ 145 int i; 146 myplayer=player_; 147 148 if(j_client || thread_run || rb) { 149 fprintf(stderr, "already connected to jack.\n"); 150 return; 151 } 152 153 j_client = jack_client_open("paulstretch", (jack_options_t) 0, NULL); 154 155 if(!j_client) { 156 fprintf(stderr, "could not connect to jack.\n"); 157 return; 158 } 159 160 jack_on_shutdown(j_client, jack_shutdown_callback, NULL); 161 jack_set_process_callback(j_client, jack_audio_callback, NULL); 162 163 j_output_port=(jack_port_t**) calloc(m_channels, sizeof(jack_port_t*)); 164 165 for(i=0;i<m_channels;i++) { 166 char channelid[16]; 167 snprintf(channelid, 16, "output_%i", i); 168 j_output_port[i] = jack_port_register(j_client, channelid, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); 169 if(!j_output_port[i]) { 170 fprintf(stderr, "no more jack ports availabe.\n"); 171 JACKclose(); 172 return; 173 } 174 } 175 176 j_out = (jack_default_audio_sample_t**) calloc(m_channels, sizeof(jack_default_audio_sample_t*)); 177 const size_t rbsize = DEFAULT_RB_SIZE * m_channels * sizeof(jack_default_audio_sample_t); 178 rb = jack_ringbuffer_create(rbsize); 179 memset(rb->buf, 0, rbsize); 180 181 jack_nframes_t jsr = jack_get_sample_rate(j_client); 182 if(jsr != samplerate) { 183 #ifdef ENABLE_RESAMPLING 184 m_fResampleRatio = (float) jsr / (float) samplerate; 185 #else 186 fprintf(stderr, "Note: paulstretch audio samplerate does not match JACK's samplerate.\n"); 187 #endif 188 } 189 190 thread_run = 1; 191 pthread_create(&player_thread_id, NULL, jack_player_thread, NULL); 192 pthread_yield(); 193 194 jack_activate(j_client); 195 196 char *jack_autoconnect = getenv("JACK_AUTOCONNECT"); 197 if(!jack_autoconnect) { 198 jack_autoconnect = (char*) "system:playback_"; 199 } else if(!strncmp(jack_autoconnect,"DISABLE", 7)) { 200 jack_autoconnect = NULL; 201 } 202 if(jack_autoconnect) { 203 int myc=0; 204 const char **found_ports = jack_get_ports(j_client, jack_autoconnect, NULL, JackPortIsInput); 205 for(i = 0; found_ports && found_ports[i]; i++) { 206 if(jack_connect(j_client, jack_port_name(j_output_port[myc]), found_ports[i])) { 207 fprintf(stderr, "can not connect to jack output\n"); 208 } 209 if(myc >= m_channels) break; 210 } 211 } 212 } 213 214 void JACKclose(){ 215 if(thread_run) { 216 thread_run = 0; 217 if(pthread_mutex_trylock(&player_thread_lock) == 0) { 218 pthread_cond_signal(&buffer_ready); 219 pthread_mutex_unlock(&player_thread_lock); 220 } 221 pthread_join(player_thread_id, NULL); 222 } 223 if(j_client){ 224 jack_client_close(j_client); 225 } 226 if(j_output_port) { 227 free(j_output_port); 228 j_output_port=NULL; 229 } 230 if(j_out) { 231 free(j_out); 232 j_out = NULL; 233 } 234 if(rb) { 235 jack_ringbuffer_free(rb); 236 rb=NULL; 237 } 238 j_client=NULL; 239 }; 240 241 #endif /* HAVE_JACK */ 242 243 /* vim: set ts=8 sw=4: */