1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ 2 3 /* 4 Rosegarden 5 A MIDI and audio sequencer and musical notation editor. 6 Copyright 2000-2009 the Rosegarden development team. 7 8 Other copyrights also apply to some parts of this work. Please 9 see the AUTHORS file and individual file headers for details. 10 11 This program is free software; you can redistribute it and/or 12 modify it under the terms of the GNU General Public License as 13 published by the Free Software Foundation; either version 2 of the 14 License, or (at your option) any later version. See the file 15 COPYING included with this distribution for more information. 16 */ 17 18 #define RG_MODULE_STRING "[JackCaptureClient]" 19 20 #include "JackCaptureClient.h" 21 #include "misc/Debug.h" 22 23 #define DEBUG_JACK_CAPTURE_CLIENT 0 24 25 namespace Rosegarden 26 { 27 28 29 /************************************* 30 CONSTRUCTOR, DESTRUCTOR, AND INIT 31 *************************************/ 32 JackCaptureClient::JackCaptureClient( const char *captureClientName, int fs ) : 33 m_isConnected(false), 34 m_processing(false), 35 m_jackRingBuffer(nullptr), 36 m_frameSize(fs) 37 { 38 // Try to connect to Jack server 39 //if ( (client = jack_client_new(captureClientName)) == 0 ) { 40 if ( (client = jack_client_open(captureClientName, JackNullOption, nullptr)) == nullptr ) { 41 return; 42 } 43 #if DEBUG_JACK_CAPTURE_CLIENT 44 RG_DEBUG << "Registered as Jack client"; 45 #endif 46 47 // get stream info 48 m_jackSampleRate = jack_get_sample_rate( client ); 49 m_jackBufferSize = jack_get_buffer_size( client ); 50 m_jackSampleSize = sizeof(jack_default_audio_sample_t); 51 #if DEBUG_JACK_CAPTURE_CLIENT 52 RG_DEBUG << "Sample Rate " << m_jackSampleRate; 53 RG_DEBUG << "Max buffer size " << m_jackBufferSize; 54 RG_DEBUG << "Sample size (bytes) " << m_jackSampleSize; 55 #endif 56 57 //setup ringbuffer 58 setFrameSize(m_frameSize); 59 60 //register process and shutdown calls 61 jack_set_process_callback(client, &process, (void*)this); 62 jack_on_shutdown(client, jackShutdown, (void*)this); 63 #if DEBUG_JACK_CAPTURE_CLIENT 64 RG_DEBUG << "Process and shutdown calls registered"; 65 #endif 66 67 // Activate 68 if ( jack_activate(client) ) { 69 RG_WARNING << "Can't activate client"; 70 throw("Cannot activate client"); 71 } 72 #if DEBUG_JACK_CAPTURE_CLIENT 73 RG_DEBUG << "Activated"; 74 #endif 75 76 //set default port to the first available port 77 const char **ports = getPorts(); 78 setupPorts(ports[0], captureClientName); 79 80 m_isConnected = true; 81 } 82 83 JackCaptureClient::~JackCaptureClient() 84 { 85 stopProcessing(); 86 jack_client_close(client); 87 if (m_jackRingBuffer) jack_ringbuffer_free(m_jackRingBuffer); 88 } 89 90 void 91 JackCaptureClient::setFrameSize(int nextFrameSize) 92 { 93 m_frameSize = nextFrameSize + 1; 94 95 #if DEBUG_JACK_CAPTURE_CLIENT 96 RG_DEBUG << "CaptureClient: setting framesize to at least" 97 << m_frameSize; 98 #endif 99 100 if (m_processing) { 101 RG_DEBUG << "CaptureClient: Procesing, can't change framesize"; 102 return; 103 } 104 105 if (m_jackRingBuffer) jack_ringbuffer_free(m_jackRingBuffer); 106 107 // framesize must be larger than size of max buffer size (m_jackBufferSize) 108 // else a complete jack frame can never be written to ringbuffer 109 if ( m_frameSize < m_jackBufferSize ) m_frameSize = m_jackBufferSize+1; 110 111 size_t m_jackRingBufferSize = m_jackSampleSize * m_frameSize; 112 m_jackRingBuffer = jack_ringbuffer_create( m_jackRingBufferSize ); 113 jack_ringbuffer_reset( m_jackRingBuffer ); 114 #if DEBUG_JACK_CAPTURE_CLIENT 115 RG_DEBUG << "Created ringbuffer, write space: " 116 << jack_ringbuffer_write_space(m_jackRingBuffer) 117 << "read space: " 118 << jack_ringbuffer_read_space(m_jackRingBuffer) 119 << " m_jackSampleSize " << m_jackSampleSize; 120 #endif 121 } 122 123 const char 124 **JackCaptureClient::getPorts() 125 { 126 return jack_get_ports( client, nullptr, nullptr, JackPortIsOutput ); 127 } 128 129 const char* 130 JackCaptureClient::getCapturePortName() 131 { 132 return jack_port_name( m_capturePort); 133 } 134 135 void 136 JackCaptureClient::setupPorts(const char *portName, 137 const char *captureClientName) 138 { 139 #if DEBUG_JACK_CAPTURE_CLIENT 140 RG_DEBUG << "Connecting ports..."; 141 #endif 142 143 // register port 144 std::string inPortName = captureClientName; 145 inPortName.append(" In"); 146 147 #if DEBUG_JACK_CAPTURE_CLIENT 148 RG_DEBUG << "Registering input port as:" << inPortName; 149 #endif 150 inPort = jack_port_register(client, inPortName.c_str(), 151 JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0 ); 152 if (inPort == nullptr) { 153 RG_DEBUG << "Cannot open Jack port"; 154 } 155 156 if ( jack_port_connected(inPort) ) { 157 #if DEBUG_JACK_CAPTURE_CLIENT 158 RG_DEBUG << "Disconnecting ports"; 159 #endif 160 161 const char **connectedPorts = jack_port_get_connections(inPort); 162 int i=0; 163 while (connectedPorts[i] != nullptr) 164 { 165 #if DEBUG_JACK_CAPTURE_CLIENT 166 RG_DEBUG << "disconnecting from " << connectedPorts[i]; 167 #endif 168 jack_port_disconnect(client, inPort); 169 i++; 170 } 171 } 172 173 m_capturePort = jack_port_by_name(client, portName); 174 175 #if DEBUG_JACK_CAPTURE_CLIENT 176 RG_DEBUG << "Recording from" << jack_port_name(m_capturePort); 177 #endif 178 179 // Connect ports 180 if (jack_connect( client, portName, jack_port_name(inPort) ) < 0 ) 181 { 182 RG_DEBUG << "------------------------------" 183 << "Jack Client: cant connect port" 184 << "------------------------------"; 185 } 186 187 #if DEBUG_JACK_CAPTURE_CLIENT 188 RG_DEBUG << "Port connected"; 189 #endif 190 } 191 192 193 /********************************* 194 REALTIME OPERATIONS 195 ********************************/ 196 int 197 JackCaptureClient::process(jack_nframes_t nframes, void *arg) 198 { 199 JackCaptureClient *jcc = (JackCaptureClient*)arg; 200 if ( !jcc->m_processing ) { 201 return 0; 202 } 203 204 jack_default_audio_sample_t *inSamp = (jack_default_audio_sample_t *) 205 jack_port_get_buffer( 206 jcc->m_capturePort, 207 nframes); 208 209 //check space to write 210 uint writeSpace = jack_ringbuffer_write_space( jcc->m_jackRingBuffer ); 211 int writeSamples = writeSpace / jcc->m_jackSampleSize; 212 213 #if DEBUG_JACK_CAPTURE_CLIENT 214 RG_DEBUG << "Want to write" << nframes << "frames\t" 215 << writeSamples << "available"; 216 #endif 217 218 219 if ( writeSpace < (jcc->m_jackSampleSize * nframes) ) { 220 unsigned int advance = nframes - writeSamples; 221 unsigned int advanceBytes = advance * jcc->m_jackSampleSize; 222 jack_ringbuffer_read_advance( jcc->m_jackRingBuffer, advanceBytes ); 223 #if DEBUG_JACK_CAPTURE_CLIENT 224 RG_DEBUG << "Advancing read pointer" << advance << "frames," 225 << advanceBytes << "bytes"; 226 writeSpace = jack_ringbuffer_write_space( jcc->m_jackRingBuffer ); 227 writeSamples = writeSpace / jcc->m_jackSampleSize; 228 RG_DEBUG << writeSamples << "frames now available"; 229 #endif 230 } 231 232 233 size_t written = jack_ringbuffer_write(jcc->m_jackRingBuffer, 234 (char*)(inSamp), 235 jcc->m_jackSampleSize * nframes); 236 #if DEBUG_JACK_CAPTURE_CLIENT 237 RG_DEBUG << "I've written" << written / jcc->m_jackSampleSize << "frames"; 238 #else 239 (void) written; // stops warning about unused variable 240 #endif 241 242 #if DEBUG_JACK_CAPTURE_CLIENT 243 uint readSpace = jack_ringbuffer_read_space( jcc->m_jackRingBuffer ); 244 uint readSamples = readSpace / jcc->m_jackSampleSize; 245 RG_DEBUG << "Now" << readSamples << "samples available to read"; 246 #endif 247 248 return 0; 249 } 250 251 252 /********************************* 253 CONTROL REALTIME OPERATIONS 254 ********************************/ 255 void 256 JackCaptureClient::startProcessing() 257 { 258 if (m_isConnected) { 259 m_processing = true; 260 } 261 } 262 263 void 264 JackCaptureClient::stopProcessing() 265 { 266 m_processing = false; 267 } 268 269 // Method will be called if Jack shuts process down 270 void 271 JackCaptureClient::jackShutdown(void *arg) 272 { 273 (void)arg; 274 #if DEBUG_JACK_CAPTURE_CLIENT 275 // JackCaptureClient *jcc = (JackCaptureClient*)arg; 276 RG_DEBUG << "Shutdown by Jack!!!!!!!!!"; 277 #endif 278 } 279 280 281 /********************************* 282 GET SAMPLE DATA 283 ********************************/ 284 bool 285 JackCaptureClient::getFrame(float *frame, size_t captureSize) 286 { 287 size_t availableSize = jack_ringbuffer_read_space(m_jackRingBuffer) 288 / m_jackSampleSize; 289 // ensure a full chunk is available & processing is allowed 290 if (captureSize <= availableSize) 291 { 292 size_t read = jack_ringbuffer_read(m_jackRingBuffer, 293 (char*)(frame), 294 (sizeof(float)*captureSize) ); 295 (void) read; // stops warning about unused variable 296 #if DEBUG_JACK_CAPTURE_CLIENT 297 RG_DEBUG << "JackCaptureClient::getFrame - Got frame!"; 298 #endif 299 return true; 300 } 301 else { 302 #if DEBUG_JACK_CAPTURE_CLIENT 303 RG_DEBUG << "JackCaptureClient::getFrame - " 304 << availableSize << " samples available. " 305 << captureSize << " samples wanted"; 306 #endif 307 return false; 308 } 309 } 310 311 312 } // end namespace 313 314