static int process (jack_nframes_t nframes, void * arg) { thread_info_t *info = (thread_info_t *) arg ; jack_default_audio_sample_t buf [info->channels] ; unsigned i, n ; if (! info->can_process) return 0 ; for (n = 0 ; n < info->channels ; n++) outs [n] = jack_port_get_buffer (output_port [n], nframes) ; for (i = 0 ; i < nframes ; i++) { size_t read_cnt ; /* Read one frame of audio. */ read_cnt = jack_ringbuffer_read (ringbuf, (void*) buf, sample_size*info->channels) ; if (read_cnt == 0 && info->read_done) { /* File is done, so stop the main loop. */ info->play_done = 1 ; return 0 ; } ; /* Update play-position counter. */ info->pos += read_cnt / (sample_size*info->channels) ; /* Output each channel of the frame. */ for (n = 0 ; n < info->channels ; n++) outs [n][i] = buf [n] ; } ; /* Wake up the disk thread to read more data. */ if (pthread_mutex_trylock (&disk_thread_lock) == 0) { pthread_cond_signal (&data_ready) ; pthread_mutex_unlock (&disk_thread_lock) ; } ; return 0 ; } /* process */
// This is called by the JACK server in a // special realtime thread once for each audio cycle. int jackProcess(jack_nframes_t nframes, void *arg) { int portNum; jack_nframes_t frameNum; // Only proceed if all ports have been connected if (allConnected == 0) return 0; // Get pointers to the capture port buffers for (portNum=0 ; portNum<NUM_INPUT_PORTS ; portNum++) { inputBufferArray[portNum] = jack_port_get_buffer(inputPortArray[portNum], nframes); } // Iterate through input buffers, adding samples to the ring buffer for (frameNum=0; frameNum<nframes; frameNum++) { for (portNum=0; portNum<NUM_INPUT_PORTS; portNum++) { size_t written = jack_ringbuffer_write(ringBuffer, (void *) &inputBufferArray[portNum][frameNum], sizeof(jack_default_audio_sample_t)); if (written != sizeof(jack_default_audio_sample_t)) { printf("Ringbuffer overrun\n"); } } } // Attempt to lock the threadLock mutex, returns zero if lock acquired if (pthread_mutex_trylock(&threadLock) == 0) { // Wake up thread which is waiting for condition (should only be called after lock acquired) pthread_cond_signal(&dataReady); // Unlock mutex pthread_mutex_unlock(&threadLock); } return 0; }
static int coreaudio_driver_read (coreaudio_driver_t *driver, jack_nframes_t nframes) { jack_default_audio_sample_t *buf; channel_t chn; jack_port_t *port; JSList *node; for (chn = 0, node = driver->capture_ports; node; node = jack_slist_next (node), chn++) { port = (jack_port_t *)node->data; if (jack_port_connected (port) && (driver->incoreaudio[chn] != NULL)) { float *in = driver->incoreaudio[chn]; buf = jack_port_get_buffer (port, nframes); memcpy(buf,in,sizeof(float)*nframes); } } driver->engine->transport_cycle_start (driver->engine,jack_get_microseconds ()); return 0; }
static int jack_callaudio_process (jack_nframes_t nframes, void *arg) { jack_thread_info_t *info = (jack_thread_info_t *) arg; if (!info->ready || !info->running) { return 0; } if( input->getDeviceState() == DspOut::DeviceClosed ) { return 0; } out = (jack_default_audio_sample_t *) jack_port_get_buffer( portout, nframes ); int numBytes = input->readableBytes(); if (numBytes > 0) { unsigned int samplesleft = input->getBuffer().getSize() / sizeof( short ); short *inbuf = (short *)input->getBuffer().getData(); input->readBuffer(); memcpy( out, inbuf, samplesleft ); } return 1; }
void* luajack_get_buffer(luajack_t *port) /* Wrapper of jack_port_get_buffer() */ { #define cud ((pud)->cud) pud_t *pud; if(!(pud = get_pud(port))) return NULL; if(!IsProcessCallback(cud)) { luajack_error("function available only in process callback"); return NULL; } if(pud->buf) { luajack_error("buffer already retrieved"); return NULL; } pud->nframes = cud->nframes; pud->buf = jack_port_get_buffer(pud->port, pud->nframes); if(!pud->buf) { luajack_error("cannot get port buffer"); return NULL; } pud->bufp = 0; if(PortIsMidi(pud)) { if(PortIsOutput(pud)) jack_midi_clear_buffer(pud->buf); } return pud->buf; #undef cud }
/** * \brief JACK Callback function * \param nframes number of frames to fill into buffers * \param arg unused * \return currently always 0 * * Write silence into buffers if paused or an underrun occured */ static int outputaudio(jack_nframes_t nframes, void *arg) { struct ao *ao = arg; struct priv *p = ao->priv; float *bufs[MAX_CHANS]; int i; for (i = 0; i < p->num_ports; i++) bufs[i] = jack_port_get_buffer(p->ports[i], nframes); if (p->paused || p->underrun || !p->ring) silence(bufs, nframes, p->num_ports); else if (read_buffer(p->ring, bufs, nframes, p->num_ports) < nframes) p->underrun = 1; if (p->estimate) { float now = mp_time_us() / 1000000.0; float diff = p->callback_time + p->callback_interval - now; if ((diff > -0.002) && (diff < 0.002)) p->callback_time += p->callback_interval; else p->callback_time = now; p->callback_interval = (float)nframes / (float)ao->samplerate; } return 0; }
static int copy_midi_data_to_buffer(jack_port_t *port, int buffer_size, struct cbox_midi_buffer *destination) { void *midi = jack_port_get_buffer(port, buffer_size); if (!midi) return 0; uint32_t event_count = jack_midi_get_event_count(midi); cbox_midi_buffer_clear(destination); for (uint32_t i = 0; i < event_count; i++) { jack_midi_event_t event; if (!jack_midi_event_get(&event, midi, i)) { if (!cbox_midi_buffer_write_event(destination, event.time, event.buffer, event.size)) return -i; } else return -i; } return event_count; }
int process (jack_nframes_t nframes, void *arg) { //jack_default_audio_sample_t *out = (jack_default_audio_sample_t *) jack_port_get_buffer (output_port, nframes); jack_default_audio_sample_t *in = (jack_default_audio_sample_t *) jack_port_get_buffer (input_port, nframes); int start = (WINDOW_SIZE-1+current_window)*FRAME_SIZE; int start2 = (current_window-1)*FRAME_SIZE; for ( int i = 0 ; i < nframes ; i++ ) { //data_array[i] = (float)out[(pos+i)%DATA_SIZE]; fftw_in[start+i][0] = (double)in[i]; if ( current_window > 0 ) { fftw_in[start2+i][0] = (double)in[i]; } } //pos = (pos + nframes)%DATA_SIZE; //printf("Number of frames: %d.\n", (int)nframes); //memcpy (out, in, sizeof (jack_default_audio_sample_t) * nframes); current_window = (current_window + 1)%WINDOW_SIZE; return 0; }
/* Callback called by JACK when audio is available. Stores value of peak sample */ static int process_peak(jack_nframes_t nframes, void *arg) { jack_default_audio_sample_t *in; unsigned int i; /* just incase the port isn't registered yet */ if (input_port == NULL) { return 0; } /* get the audio samples, and find the peak sample */ in = (jack_default_audio_sample_t *) jack_port_get_buffer(input_port, nframes); for (i = 0; i < nframes; i++) { const float s = fabs(in[i]); if (s > peak) { peak = s; } } return 0; }
void MidiJackDevice::collectMidiEvents()/*{{{*/ { if (!_readEnable) return; if (!_in_client_jackport) // p3.3.55 return; void* port_buf = jack_port_get_buffer(_in_client_jackport, segmentSize); // p3.3.55 jack_midi_event_t event; jack_nframes_t eventCount = jack_midi_get_event_count(port_buf); for (jack_nframes_t i = 0; i < eventCount; ++i) { jack_midi_event_get(&event, port_buf, i); #ifdef JACK_MIDI_DEBUG printf("MidiJackDevice::collectMidiEvents number:%d time:%d\n", i, event.time); #endif eventReceived(&event); } }/*}}}*/
static int _process(jack_nframes_t nframes, void *arg) { _t *data = (_t *)arg; float *in0 = jack_port_get_buffer(framework_input(data,0), nframes); float *in1 = jack_port_get_buffer(framework_input(data,1), nframes); float *in2 = jack_port_get_buffer(framework_input(data,2), nframes); float *in3 = jack_port_get_buffer(framework_input(data,3), nframes); float *out0 = jack_port_get_buffer(framework_output(data,0), nframes); float *out1 = jack_port_get_buffer(framework_output(data,1), nframes); AVOID_DENORMALS; for (int i = nframes; --i >= 0; ) { const _Complex float a = *in0++ + *in1++ * I; const _Complex float b = *in2++ + *in3++ * I; const _Complex float c = a * b; *out0++ = crealf(c); *out1++ = cimagf(c); } return 0; }
static int process (jack_nframes_t nframes, void *arg) { int chn; size_t i; jack_thread_info_t *info = (jack_thread_info_t *) arg; /* Do nothing until we're ready to begin. */ if ((!info->can_process) || (!info->can_capture)) return 0; for (chn = 0; chn < nports; chn++) in[chn] = jack_port_get_buffer (ports[chn], nframes); /* Sndfile requires interleaved data. It is simpler here to * just queue interleaved samples to a single ringbuffer. */ for (i = 0; i < nframes; i++) { for (chn = 0; chn < nports; chn++) { if (jack_ringbuffer_write (rb, (void *) (in[chn]+i), sample_size) < sample_size) overruns++; } } /* Tell the disk thread there is work to do. If it is already * running, the lock will not be available. We can't wait * here in the process() thread, but we don't need to signal * in that case, because the disk thread will read all the * data queued before waiting again. */ if (pthread_mutex_trylock (&disk_thread_lock) == 0) { pthread_cond_signal (&data_ready); pthread_mutex_unlock (&disk_thread_lock); } return 0; }
void midiSendLong(unsigned char *buf, unsigned long len) { /*int err = snd_rawmidi_write(handle_out, buf, len); if (err != len) { fprintf(stderr, "could not write %ld byte to output, return: %d\n", len, err); exit(1); }*/ if (jack_midi_output_port == NULL) { fprintf(stderr, "midiSendLong failed: output port closed\n"); exit(1); } void* output_buf = jack_port_get_buffer (jack_midi_output_port, 1); jack_midi_clear_buffer(output_buf); printhex("send:", buf, len); int err = jack_midi_event_write(output_buf, 0, buf, len); if (err != 0) { if (err == ENOBUFS) { // if there's not enough space in buffer for event } fprintf(stderr, "could not write %ld byte to output, return: %d\n", len, err); exit(1); } }
static int iio_driver_read(iio_driver_t *driver, jack_nframes_t nframes) { JSList *node; channel_t chn; jack_nframes_t i; //Debugger<<"iio_driver_read\n"; if (nframes > 0) { ////Debugger<<"iio_driver_read nframes = "<<nframes<<"\n"; // for (jack_nframes_t i=0; i<nframes; i++){ // cout<<(float)(*data)(i,0)<<endl; // cout<<endl; // write to the connected capture ports ... node = (JSList *)driver->capture_ports; for (chn = 0; node; node = (JSList *)jack_slist_next(node), chn++) { //jack_port_t *port = static_cast<jack_port_t *>(node->data); jack_port_t *port = (jack_port_t*)(node->data); if (!jack_port_connected (port)) /* no-copy optimization */ continue; //jack_default_audio_sample_t *buf = static_cast<jack_default_audio_sample_t *>(jack_port_get_buffer (port, nframes)); jack_default_audio_sample_t *buf = (jack_default_audio_sample_t *)(jack_port_get_buffer (port, nframes)); for (i=0; i<nframes; i++) { //cout<<"row = "<<i*devChCnt+rowOffset<<" col = "<<col<<endl; //buf[i]=(*data)(i*devChCnt+rowOffset, col)*100.; buf[i]=(float)i/(float)nframes; //cout<<(*data)(i*devChCnt+rowOffset, col)<<'\t'<<buf[i]<<'\n'; } } //Debugger<<" spent "<< (driver->engine->get_microseconds()-driver->debug_last_time)<<" us waiting for lock and copying data over\n"; } return 0; }
// we read data from jack void MidiJack::JackMidiRead(jack_nframes_t nframes) { unsigned int i,b; void* port_buf = jack_port_get_buffer(m_input_port, nframes); jack_midi_event_t in_event; jack_nframes_t event_index = 0; jack_nframes_t event_count = jack_midi_get_event_count(port_buf); jack_midi_event_get(&in_event, port_buf, 0); for(i=0; i<nframes; i++) { if((in_event.time == i) && (event_index < event_count)) { // lmms is setup to parse bytes coming from a device // parse it byte by byte as it expects for(b=0;b<in_event.size;b++) parseData( *(in_event.buffer + b) ); event_index++; if(event_index < event_count) jack_midi_event_get(&in_event, port_buf, event_index); } } }
int jack_process(jack_nframes_t nframes, void *arg) { int chn; size_t i; jack_thread_info_t *info = (jack_thread_info_t *) arg; /* Do nothing until we're ready to begin. */ if ((!info->can_process) || (!info->can_capture)) return 0; for (chn = 0; chn < nports; chn++) in[chn] = (jack_default_audio_sample_t*) jack_port_get_buffer(ports[chn], nframes); //interleave data for (i = 0; i < nframes; i++) { for (chn = 0; chn < nports; chn++) { if (jack_ringbuffer_write(rb, (char *)(in[chn]+i), sample_size) < sample_size) { overruns++; if (overruns % 10000 == 0) { fprintf(stderr, "overruns [%u]\n", overruns); } } } } //notify detect_note that data is ready for reading if (pthread_mutex_trylock(&detect_lock) == 0) { pthread_cond_signal(&data_ready); pthread_mutex_unlock(&detect_lock); } return 0; }
/* this is the callback of jack. This should RT-safe. */ static int jack_process_cb (jack_nframes_t nframes, void *arg) { GstJackAudioSink *sink; GstRingBuffer *buf; gint readseg, len; guint8 *readptr; gint i, j, flen, channels; sample_t *data; buf = GST_RING_BUFFER_CAST (arg); sink = GST_JACK_AUDIO_SINK (GST_OBJECT_PARENT (buf)); channels = buf->spec.channels; /* get target buffers */ for (i = 0; i < channels; i++) { sink->buffers[i] = (sample_t *) jack_port_get_buffer (sink->ports[i], nframes); } if (gst_ring_buffer_prepare_read (buf, &readseg, &readptr, &len)) { flen = len / channels; /* the number of samples must be exactly the segment size */ if (nframes * sizeof (sample_t) != flen) goto wrong_size; GST_DEBUG_OBJECT (sink, "copy %d frames: %p, %d bytes, %d channels", nframes, readptr, flen, channels); data = (sample_t *) readptr; /* the samples in the ringbuffer have the channels interleaved, we need to * deinterleave into the jack target buffers */ for (i = 0; i < nframes; i++) { for (j = 0; j < channels; j++) { sink->buffers[j][i] = *data++; } } /* clear written samples in the ringbuffer */ gst_ring_buffer_clear (buf, readseg); /* we wrote one segment */ gst_ring_buffer_advance (buf, 1); } else { GST_DEBUG_OBJECT (sink, "write %d frames silence", nframes); /* We are not allowed to read from the ringbuffer, write silence to all * jack output buffers */ for (i = 0; i < channels; i++) { memset (sink->buffers[i], 0, nframes * sizeof (sample_t)); } } return 0; /* ERRORS */ wrong_size: { GST_ERROR_OBJECT (sink, "nbytes (%d) != flen (%d)", (gint) (nframes * sizeof (sample_t)), flen); return 1; } }
static int a2j_process (jack_nframes_t nframes, void * arg) { struct a2j* self = (struct a2j *) arg; struct a2j_stream * stream_ptr; int i; struct a2j_port ** port_ptr; struct a2j_port * port; if (g_freewheeling) { return 0; } self->cycle_start = jack_last_frame_time (self->jack_client); stream_ptr = &self->stream; a2j_add_ports (stream_ptr); // process ports for (i = 0 ; i < PORT_HASH_SIZE ; i++) { port_ptr = &stream_ptr->port_hash[i]; while (*port_ptr != NULL) { struct a2j_alsa_midi_event ev; jack_nframes_t now; jack_nframes_t one_period; char *ev_buf; port = *port_ptr; if (port->is_dead) { if (jack_ringbuffer_write_space (self->port_del) >= sizeof(port_ptr)) { a2j_debug("jack: removed port %s", port->name); *port_ptr = port->next; jack_ringbuffer_write (self->port_del, (char*)&port, sizeof(port)); } else { a2j_error ("port deletion lost - no space in event buffer!"); } port_ptr = &port->next; continue; } port->jack_buf = jack_port_get_buffer(port->jack_port, nframes); /* grab data queued by the ALSA input thread and write it into the JACK port buffer. it will delivered during the JACK period that this function is called from. */ /* first clear the JACK port buffer in preparation for new data */ // a2j_debug ("PORT: %s process input", jack_port_name (port->jack_port)); jack_midi_clear_buffer (port->jack_buf); now = jack_frame_time (self->jack_client); one_period = jack_get_buffer_size (self->jack_client); while (jack_ringbuffer_peek (port->inbound_events, (char*)&ev, sizeof(ev) ) == sizeof(ev) ) { jack_midi_data_t* buf; jack_nframes_t offset; if (ev.time >= self->cycle_start) { break; } //jack_ringbuffer_read_advance (port->inbound_events, sizeof (ev)); ev_buf = (char *) alloca( sizeof(ev) + ev.size ); if (jack_ringbuffer_peek (port->inbound_events, ev_buf, sizeof(ev) + ev.size ) != sizeof(ev) + ev.size) break; offset = self->cycle_start - ev.time; if (offset > one_period) { /* from a previous cycle, somehow. cram it in at the front */ offset = 0; } else { /* offset from start of the current cycle */ offset = one_period - offset; } a2j_debug ("event at %d offset %d", ev.time, offset); /* make sure there is space for it */ buf = jack_midi_event_reserve (port->jack_buf, offset, ev.size); if (buf) { /* grab the event */ memcpy( buf, ev_buf + sizeof(ev), ev.size ); } else { /* throw it away (no space) */ a2j_error ("threw away MIDI event - not reserved at time %d", ev.time); } jack_ringbuffer_read_advance (port->inbound_events, sizeof(ev) + ev.size); a2j_debug("input on %s: sucked %d bytes from inbound at %d", jack_port_name (port->jack_port), ev.size, ev.time); } port_ptr = &port->next; } } return 0; }
static int process_cb(jack_nframes_t nframes, void *arg) { struct cbox_jack_io_impl *jii = arg; struct cbox_io *io = jii->ioi.pio; struct cbox_io_callbacks *cb = io->cb; io->io_env.buffer_size = nframes; for (int i = 0; i < io->io_env.input_count; i++) io->input_buffers[i] = jack_port_get_buffer(jii->inputs[i], nframes); for (int i = 0; i < io->io_env.output_count; i++) { io->output_buffers[i] = jack_port_get_buffer(jii->outputs[i], nframes); if (!io->output_buffers[i]) continue; for (int j = 0; j < nframes; j ++) io->output_buffers[i][j] = 0.f; } for (GSList *p = io->midi_inputs; p; p = p->next) { struct cbox_jack_midi_input *input = p->data; if (input->hdr.output_set || input->hdr.enable_appsink) { copy_midi_data_to_buffer(input->port, io->io_env.buffer_size, &input->hdr.buffer); if (input->hdr.enable_appsink) cbox_midi_appsink_supply(&input->hdr.appsink, &input->hdr.buffer); } else cbox_midi_buffer_clear(&input->hdr.buffer); } if (cb->on_transport_sync) { jack_transport_state_t state = jack_transport_query(jii->client, NULL); if (state != jii->last_transport_state) { jack_position_t pos; jack_transport_query(jii->client, &pos); if (jii->debug_transport) g_message("JACK transport: incoming state change, state = %s, last state = %s, pos = %d\n", transport_state_names[state], transport_state_names[(int)jii->last_transport_state], (int)pos.frame); if (state == JackTransportStopped) { if (cb->on_transport_sync(cb->user_data, ts_stopping, pos.frame)) jii->last_transport_state = state; } else if (state == JackTransportRolling && jii->last_transport_state == JackTransportStarting) { if (cb->on_transport_sync(cb->user_data, ts_rolling, pos.frame)) jii->last_transport_state = state; } else jii->last_transport_state = state; } } cb->process(cb->user_data, io, nframes); for (int i = 0; i < io->io_env.input_count; i++) io->input_buffers[i] = NULL; for (int i = 0; i < io->io_env.output_count; i++) io->output_buffers[i] = NULL; for (GSList *p = io->midi_outputs; p; p = g_slist_next(p)) { struct cbox_jack_midi_output *midiout = p->data; void *pbuf = jack_port_get_buffer(midiout->port, nframes); jack_midi_clear_buffer(pbuf); cbox_midi_merger_render(&midiout->hdr.merger); if (midiout->hdr.buffer.count) { uint8_t tmp_data[4]; for (int i = 0; i < midiout->hdr.buffer.count; i++) { const struct cbox_midi_event *event = cbox_midi_buffer_get_event(&midiout->hdr.buffer, i); const uint8_t *pdata = cbox_midi_event_get_data(event); if ((pdata[0] & 0xF0) == 0x90 && !pdata[2] && event->size == 3) { tmp_data[0] = pdata[0] & ~0x10; tmp_data[1] = pdata[1]; tmp_data[2] = pdata[2]; pdata = tmp_data; } if (jack_midi_event_write(pbuf, event->time, pdata, event->size)) { g_warning("MIDI buffer overflow on JACK output port '%s'", midiout->hdr.name); break; } } } } return 0; }
static int process (jack_nframes_t nframes, void *arg) { int j; jack_default_audio_sample_t *out, *in; if (nframes > JACK_OUT_MAX) jack_out_max = nframes; else jack_out_max = JACK_OUT_MAX; if (jack_filled >= nframes) { if (jack_filled != nframes) fprintf(stderr,"Partial read"); /* hmm, how to find out whether 't_sample' and 'jack_default_audio_sample_t' are actually the same type? */ if(sizeof(t_sample)==sizeof(jack_default_audio_sample_t)) { for (j = 0; j < sys_outchannels; j++) { out = jack_port_get_buffer (output_port[j], nframes); memcpy(out, jack_outbuf + (j * BUF_JACK), sizeof(jack_default_audio_sample_t) * nframes); } for (j = 0; j < sys_inchannels; j++) { in = jack_port_get_buffer( input_port[j], nframes); memcpy(jack_inbuf + (j * BUF_JACK), in, sizeof(jack_default_audio_sample_t) * nframes); } } else { unsigned int frame=0; t_sample*data; for (j = 0; j < sys_outchannels; j++) { out = jack_port_get_buffer (output_port[j], nframes); data=jack_outbuf + (j * BUF_JACK); for(frame=0; frame<nframes; frame++) { *out++=*data++; } } for (j = 0; j < sys_inchannels; j++) { in = jack_port_get_buffer( input_port[j], nframes); data=jack_inbuf+(j*BUF_JACK); for(frame=0; frame<nframes; frame++) { *data++=*in++; } } } jack_filled -= nframes; } else { /* PD could not keep up ! */ if (jack_started) jack_dio_error = 1; for (j = 0; j < outport_count; j++) { out = jack_port_get_buffer (output_port[j], nframes); memset(out, 0, sizeof (float) * nframes); } memset(jack_outbuf,0,sizeof(jack_outbuf)); jack_filled = 0; } pthread_cond_broadcast(&jack_sem); return 0; }
/** * The process callback for this JACK application. * It is called by JACK at the appropriate times. */ int process (jack_nframes_t nframes, void *arg) { int rlen; int err; snd_pcm_sframes_t delay = target_delay; int i; delay = (num_periods*period_size)-snd_pcm_avail( alsa_handle ) ; delay -= jack_frames_since_cycle_start( client ); // Do it the hard way. // this is for compensating xruns etc... if( delay > (target_delay+max_diff) ) { snd_pcm_rewind( alsa_handle, delay - target_delay ); output_new_delay = (int) delay; delay = target_delay; // Set the resample_rate... we need to adjust the offset integral, to do this. // first look at the PI controller, this code is just a special case, which should never execute once // everything is swung in. offset_integral = - (resample_mean - static_resample_factor) * catch_factor * catch_factor2; // Also clear the array. we are beginning a new control cycle. for( i=0; i<smooth_size; i++ ) offset_array[i] = 0.0; } if( delay < (target_delay-max_diff) ) { output_new_delay = (int) delay; while ((target_delay-delay) > 0) { snd_pcm_uframes_t to_write = ((target_delay-delay) > 512) ? 512 : (target_delay-delay); snd_pcm_writei( alsa_handle, tmpbuf, to_write ); delay += to_write; } delay = target_delay; // Set the resample_rate... we need to adjust the offset integral, to do this. offset_integral = - (resample_mean - static_resample_factor) * catch_factor * catch_factor2; // Also clear the array. we are beginning a new control cycle. for( i=0; i<smooth_size; i++ ) offset_array[i] = 0.0; } /* ok... now we should have target_delay +- max_diff on the alsa side. * * calculate the number of frames, we want to get. */ double offset = delay - target_delay; // Save offset. offset_array[(offset_differential_index++)% smooth_size ] = offset; // Build the mean of the windowed offset array // basically fir lowpassing. double smooth_offset = 0.0; for( i=0; i<smooth_size; i++ ) smooth_offset += offset_array[ (i + offset_differential_index-1) % smooth_size] * window_array[i]; smooth_offset /= (double) smooth_size; // this is the integral of the smoothed_offset offset_integral += smooth_offset; // Clamp offset. // the smooth offset still contains unwanted noise // which would go straigth onto the resample coeff. // it only used in the P component and the I component is used for the fine tuning anyways. if( fabs( smooth_offset ) < pclamp ) smooth_offset = 0.0; // ok. now this is the PI controller. // u(t) = K * ( e(t) + 1/T \int e(t') dt' ) // K = 1/catch_factor and T = catch_factor2 double current_resample_factor = static_resample_factor - smooth_offset / (double) catch_factor - offset_integral / (double) catch_factor / (double)catch_factor2; // now quantize this value around resample_mean, so that the noise which is in the integral component doesnt hurt. current_resample_factor = floor( (current_resample_factor - resample_mean) * controlquant + 0.5 ) / controlquant + resample_mean; // Output "instrumentatio" gonna change that to real instrumentation in a few. output_resampling_factor = (float) current_resample_factor; output_diff = (float) smooth_offset; output_integral = (float) offset_integral; output_offset = (float) offset; // Clamp a bit. if( current_resample_factor < resample_lower_limit ) current_resample_factor = resample_lower_limit; if( current_resample_factor > resample_upper_limit ) current_resample_factor = resample_upper_limit; // Now Calculate how many samples we need. rlen = ceil( ((double)nframes) * current_resample_factor )+2; assert( rlen > 2 ); // Calculate resample_mean so we can init ourselves to saner values. resample_mean = 0.9999 * resample_mean + 0.0001 * current_resample_factor; /* * now this should do it... */ outbuf = alloca( rlen * formats[format].sample_size * num_channels ); resampbuf = alloca( rlen * sizeof( float ) ); /* * render jack ports to the outbuf... */ int chn = 0; JSList *node = playback_ports; JSList *src_node = playback_srcs; SRC_DATA src; while ( node != NULL) { jack_port_t *port = (jack_port_t *) node->data; float *buf = jack_port_get_buffer (port, nframes); SRC_STATE *src_state = src_node->data; src.data_in = buf; src.input_frames = nframes; src.data_out = resampbuf; src.output_frames = rlen; src.end_of_input = 0; src.src_ratio = current_resample_factor; src_process( src_state, &src ); formats[format].jack_to_soundcard( outbuf + format[formats].sample_size * chn, resampbuf, src.output_frames_gen, num_channels*format[formats].sample_size, NULL); src_node = jack_slist_next (src_node); node = jack_slist_next (node); chn++; } // now write the output... again: err = snd_pcm_writei(alsa_handle, outbuf, src.output_frames_gen); //err = snd_pcm_writei(alsa_handle, outbuf, src.output_frames_gen); if( err < 0 ) { printf( "err = %d\n", err ); if (xrun_recovery(alsa_handle, err) < 0) { printf("Write error: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } goto again; } return 0; }
float* AudioOutputDeviceJack::AudioChannelJack::CreateJackPort(uint ChannelNr, AudioOutputDeviceJack* pDevice) throw (AudioOutputException) { String port_id = ToString(ChannelNr); hJackPort = jack_port_register(pDevice->hJackClient, port_id.c_str(), JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); if (!hJackPort) throw AudioOutputException("Jack: Cannot register Jack output port."); return (float*) jack_port_get_buffer(hJackPort, pDevice->uiMaxSamplesPerCycle); }
float* JackOutput::getOut_R() { jack_default_audio_sample_t *out = ( jack_default_audio_sample_t * ) jack_port_get_buffer ( output_port_2, jack_server_bufferSize ); return out; }
TSampleBuffer TJackAudioPort::GetBuffer(jack_nframes_t nframes) { return TSampleBuffer( static_cast<jack_default_audio_sample_t*>(jack_port_get_buffer(Port, nframes)), nframes); }
static int process(jack_nframes_t nframes, void *arg) { static int quantize_frames = 0; #define on_quantize_boundary() (!quantize_frames) jack_default_audio_sample_t *out_l; jack_default_audio_sample_t *out_r; jack_default_audio_sample_t *in_l; jack_default_audio_sample_t *in_r; jack_nframes_t until_quantize, rate, nframes_left, nframes_offset, i; int j, group_count, next_bit; uint16_t qfield; jack_default_audio_sample_t *buffers[2]; rove_group_t *g; rove_file_t *f; group_count = state.group_count; rate = jack_get_sample_rate(state.client); /* initialize each group's output buffers and zero them */ for( i = 0; i < group_count; i++ ) { g = &state.groups[i]; g->output_buffer_l = out_l = jack_port_get_buffer(g->outport_l, nframes); g->output_buffer_r = out_r = jack_port_get_buffer(g->outport_r, nframes); for( j = 0; j < nframes; j++ ) out_l[j] = out_r[j] = 0; } for( nframes_offset = 0; nframes > 0; nframes -= nframes_left ) { if( on_quantize_boundary() ) { for( j = 0; j < group_count; j++ ) { g = &state.groups[j]; f = g->active_loop; process_file(f); } qfield = state.monome->quantize_field >> 1; for( j = 0; qfield; qfield >>= next_bit ) { next_bit = ffs(qfield); j += next_bit; f = (rove_file_t *) state.monome->callbacks[j].data; process_file(f); } } until_quantize = (state.snap_delay - quantize_frames); nframes_left = MIN(until_quantize, nframes); quantize_frames += nframes_left; if( quantize_frames >= state.snap_delay - 1 ) quantize_frames = 0; for( j = 0; j < group_count; j++ ) { g = &state.groups[j]; if( !(f = g->active_loop) ) continue; if( !rove_file_is_active(f) ) continue; /* will eventually become an array of arbitrary size for better multichannel support */ buffers[0] = g->output_buffer_l + nframes_offset; buffers[1] = g->output_buffer_r + nframes_offset; if( f->process_cb ) f->process_cb(f, buffers, 2, nframes_left, rate); } nframes_offset += nframes_left; } out_l = jack_port_get_buffer(outport_l, nframes_offset); out_r = jack_port_get_buffer(outport_r, nframes_offset); in_l = jack_port_get_buffer(group_mix_inport_l, nframes_offset); in_r = jack_port_get_buffer(group_mix_inport_r, nframes_offset); memcpy(out_l, in_l, sizeof(jack_default_audio_sample_t) * nframes_offset); memcpy(out_r, in_r, sizeof(jack_default_audio_sample_t) * nframes_offset); return 0; }
// rt static int _process(jack_nframes_t nsamples, void *data) { prog_t *handle = data; bin_t *bin = &handle->bin; sp_app_t *app = bin->app; #if defined(JACK_HAS_CYCLE_TIMES) clock_gettime(CLOCK_REALTIME, &handle->ntp); handle->ntp.tv_sec += JAN_1970; // convert NTP to OSC time jack_nframes_t offset = jack_frames_since_cycle_start(handle->client); float T; jack_get_cycle_times(handle->client, &handle->cycle.cur_frames, &handle->cycle.cur_usecs, &handle->cycle.nxt_usecs, &T); (void)T; handle->cycle.ref_frames = handle->cycle.cur_frames + offset; // calculate apparent period double diff = 1e-6 * (handle->cycle.nxt_usecs - handle->cycle.cur_usecs); // calculate apparent samples per period handle->cycle.dT = nsamples / diff; handle->cycle.dTm1 = 1.0 / handle->cycle.dT; #endif // get transport position jack_position_t pos; jack_transport_state_t rolling = jack_transport_query(handle->client, &pos) == JackTransportRolling; int trans_changed = (rolling != handle->trans.rolling) || (pos.frame != handle->trans.frame) || (pos.beats_per_bar != handle->trans.beats_per_bar) || (pos.beat_type != handle->trans.beat_type) || (pos.ticks_per_beat != handle->trans.ticks_per_beat) || (pos.beats_per_minute != handle->trans.beats_per_minute); const size_t sample_buf_size = sizeof(float) * nsamples; const sp_app_system_source_t *sources = sp_app_get_system_sources(app); const sp_app_system_sink_t *sinks = sp_app_get_system_sinks(app); if(sp_app_bypassed(app)) // aka loading state { //fprintf(stderr, "app is bypassed\n"); // clear output buffers for(const sp_app_system_sink_t *sink=sinks; sink->type != SYSTEM_PORT_NONE; sink++) { switch(sink->type) { case SYSTEM_PORT_NONE: case SYSTEM_PORT_CONTROL: case SYSTEM_PORT_COM: break; case SYSTEM_PORT_AUDIO: case SYSTEM_PORT_CV: { void *out_buf = jack_port_get_buffer(sink->sys_port, nsamples); memset(out_buf, 0x0, sample_buf_size); break; } case SYSTEM_PORT_MIDI: case SYSTEM_PORT_OSC: { void *out_buf = jack_port_get_buffer(sink->sys_port, nsamples); jack_midi_clear_buffer(out_buf); break; } } } bin_process_pre(bin, nsamples, true); bin_process_post(bin); return 0; } //TODO use __builtin_assume_aligned // fill input buffers for(const sp_app_system_source_t *source=sources; source->type != SYSTEM_PORT_NONE; source++) { switch(source->type) { case SYSTEM_PORT_NONE: case SYSTEM_PORT_CONTROL: break; case SYSTEM_PORT_AUDIO: case SYSTEM_PORT_CV: { const void *in_buf = jack_port_get_buffer(source->sys_port, nsamples); memcpy(source->buf, in_buf, sample_buf_size); break; } case SYSTEM_PORT_MIDI: { void *in_buf = jack_port_get_buffer(source->sys_port, nsamples); void *seq_in = source->buf; LV2_Atom_Forge *forge = &handle->forge; LV2_Atom_Forge_Frame frame; lv2_atom_forge_set_buffer(forge, seq_in, SEQ_SIZE); LV2_Atom_Forge_Ref ref = lv2_atom_forge_sequence_head(forge, &frame, 0); if(ref && trans_changed) ref = _trans_event(handle, forge, rolling, &pos); int n = jack_midi_get_event_count(in_buf); for(int i=0; i<n; i++) { jack_midi_event_t mev; jack_midi_event_get(&mev, in_buf, i); //add jack midi event to in_buf if(ref) ref = lv2_atom_forge_frame_time(forge, mev.time); if(ref) ref = lv2_atom_forge_atom(forge, mev.size, handle->midi_MidiEvent); if(ref) ref = lv2_atom_forge_raw(forge, mev.buffer, mev.size); if(ref) lv2_atom_forge_pad(forge, mev.size); } if(ref) lv2_atom_forge_pop(forge, &frame); else lv2_atom_sequence_clear(seq_in); break; } case SYSTEM_PORT_OSC: { void *in_buf = jack_port_get_buffer(source->sys_port, nsamples); void *seq_in = source->buf; LV2_Atom_Forge *forge = &handle->forge; LV2_Atom_Forge_Frame frame; lv2_atom_forge_set_buffer(forge, seq_in, SEQ_SIZE); LV2_Atom_Forge_Ref ref = lv2_atom_forge_sequence_head(forge, &frame, 0); if(ref && trans_changed) ref = _trans_event(handle, forge, rolling, &pos); int n = jack_midi_get_event_count(in_buf); for(int i=0; i<n; i++) { jack_midi_event_t mev; jack_midi_event_get(&mev, (void *)in_buf, i); //add jack osc event to in_buf if(osc_check_packet(mev.buffer, mev.size)) { if(ref) ref = lv2_atom_forge_frame_time(forge, mev.time); handle->ref = ref; osc_dispatch_method(mev.buffer, mev.size, methods, _bundle_in, _bundle_out, handle); ref = handle->ref; } } if(ref) lv2_atom_forge_pop(forge, &frame); else lv2_atom_sequence_clear(seq_in); break; } case SYSTEM_PORT_COM: { void *seq_in = source->buf; LV2_Atom_Forge *forge = &handle->forge; LV2_Atom_Forge_Frame frame; lv2_atom_forge_set_buffer(forge, seq_in, SEQ_SIZE); LV2_Atom_Forge_Ref ref = lv2_atom_forge_sequence_head(forge, &frame, 0); const LV2_Atom_Object *obj; size_t size; while((obj = varchunk_read_request(bin->app_from_com, &size))) { if(ref) ref = lv2_atom_forge_frame_time(forge, 0); if(ref) ref = lv2_atom_forge_raw(forge, obj, size); if(ref) lv2_atom_forge_pad(forge, size); varchunk_read_advance(bin->app_from_com); } if(ref) lv2_atom_forge_pop(forge, &frame); else lv2_atom_sequence_clear(seq_in); break; } } } // update transport state handle->trans.rolling = rolling; handle->trans.frame = rolling ? handle->trans.frame + nsamples : pos.frame; handle->trans.beats_per_bar = pos.beats_per_bar; handle->trans.beat_type = pos.beat_type; handle->trans.ticks_per_beat = pos.ticks_per_beat; handle->trans.beats_per_minute = pos.beats_per_minute; bin_process_pre(bin, nsamples, false); // fill output buffers for(const sp_app_system_sink_t *sink=sinks; sink->type != SYSTEM_PORT_NONE; sink++) { switch(sink->type) { case SYSTEM_PORT_NONE: case SYSTEM_PORT_CONTROL: break; case SYSTEM_PORT_AUDIO: case SYSTEM_PORT_CV: { void *out_buf = jack_port_get_buffer(sink->sys_port, nsamples); memcpy(out_buf, sink->buf, sample_buf_size); break; } case SYSTEM_PORT_MIDI: { void *out_buf = jack_port_get_buffer(sink->sys_port, nsamples); const LV2_Atom_Sequence *seq_out = sink->buf; // fill midi output buffer jack_midi_clear_buffer(out_buf); if(seq_out) { LV2_ATOM_SEQUENCE_FOREACH(seq_out, ev) { const LV2_Atom *atom = &ev->body; if(atom->type != handle->midi_MidiEvent) continue; // ignore non-MIDI events jack_midi_event_write(out_buf, ev->time.frames, LV2_ATOM_BODY_CONST(atom), atom->size); } } break; } case SYSTEM_PORT_OSC: { void *out_buf = jack_port_get_buffer(sink->sys_port, nsamples); const LV2_Atom_Sequence *seq_out = sink->buf; // fill midi output buffer jack_midi_clear_buffer(out_buf); if(seq_out) { LV2_ATOM_SEQUENCE_FOREACH(seq_out, ev) { const LV2_Atom_Object *obj = (const LV2_Atom_Object *)&ev->body; handle->osc_ptr = handle->osc_buf; handle->osc_end = handle->osc_buf + OSC_SIZE; osc_atom_event_unroll(&handle->oforge, obj, _bundle_push_cb, _bundle_pop_cb, _message_cb, handle); size_t size = handle->osc_ptr ? handle->osc_ptr - handle->osc_buf : 0; if(size) { jack_midi_event_write(out_buf, ev->time.frames, handle->osc_buf, size); } } } break; } case SYSTEM_PORT_COM: { const LV2_Atom_Sequence *seq_out = sink->buf; LV2_ATOM_SEQUENCE_FOREACH(seq_out, ev) { const LV2_Atom *atom = (const LV2_Atom *)&ev->body; // try do process events directly bin->advance_ui = sp_app_from_ui(bin->app, atom); if(!bin->advance_ui) // queue event in ringbuffer instead { //fprintf(stderr, "plugin ui direct is blocked\n"); void *ptr; size_t size = lv2_atom_total_size(atom); if((ptr = varchunk_write_request(bin->app_from_app, size))) { memcpy(ptr, atom, size); varchunk_write_advance(bin->app_from_app, size); } else { //fprintf(stderr, "app_from_ui ringbuffer full\n"); //FIXME } } } break; } } } bin_process_post(bin); return 0; }
bool MidiJackDevice::queueEvent(const MidiPlayEvent& e) { if (!_out_client_jackport) // p3.3.55 return false; void* pb = jack_port_get_buffer(_out_client_jackport, segmentSize); // p3.3.55 int frameOffset = audio->getFrameOffset(); unsigned pos = audio->pos().frame(); int ft = e.time() - frameOffset - pos; if (ft < 0) ft = 0; if (ft >= (int) segmentSize) { if(debugMsg) printf("MidiJackDevice::queueEvent: Event time:%d out of range. offset:%d ft:%d (seg=%d)\n", e.time(), frameOffset, ft, segmentSize); if (ft > (int) segmentSize) ft = segmentSize - 1; } #ifdef JACK_MIDI_DEBUG printf("MidiJackDevice::queueEvent time:%d type:%d ch:%d A:%d B:%d\n", e.time(), e.type(), e.channel(), e.dataA(), e.dataB()); #endif switch (e.type()) { case ME_NOTEON: case ME_NOTEOFF: case ME_POLYAFTER: case ME_CONTROLLER: case ME_PITCHBEND: { #ifdef JACK_MIDI_DEBUG printf("MidiJackDevice::queueEvent note on/off polyafter controller or pitch\n"); #endif unsigned char* p = jack_midi_event_reserve(pb, ft, 3); if (p == 0) { #ifdef JACK_MIDI_DEBUG fprintf(stderr, "MidiJackDevice::queueEvent NOTE CONTROL PAT or PB: buffer overflow, stopping until next cycle\n"); #endif return false; } p[0] = e.type() | e.channel(); p[1] = e.dataA(); p[2] = e.dataB(); } break; case ME_PROGRAM: case ME_AFTERTOUCH: { #ifdef JACK_MIDI_DEBUG printf("MidiJackDevice::queueEvent program or aftertouch\n"); #endif unsigned char* p = jack_midi_event_reserve(pb, ft, 2); if (p == 0) { #ifdef JACK_MIDI_DEBUG fprintf(stderr, "MidiJackDevice::queueEvent PROG or AT: buffer overflow, stopping until next cycle\n"); #endif return false; } p[0] = e.type() | e.channel(); p[1] = e.dataA(); } break; case ME_SYSEX: { #ifdef JACK_MIDI_DEBUG printf("MidiJackDevice::queueEvent sysex\n"); #endif const unsigned char* data = e.data(); int len = e.len(); unsigned char* p = jack_midi_event_reserve(pb, ft, len + 2); if (p == 0) { fprintf(stderr, "MidiJackDevice::queueEvent ME_SYSEX: buffer overflow, sysex too big, event lost\n"); return true; } p[0] = 0xf0; p[len + 1] = 0xf7; memcpy(p + 1, data, len); } break; case ME_SONGPOS: case ME_CLOCK: case ME_START: case ME_CONTINUE: case ME_STOP: if(debugMsg) printf("MidiJackDevice::queueEvent: event type %x not supported\n", e.type()); return true; break; } return true; }
static int jack_process (jack_nframes_t frames, void * data) { mlt_filter filter = (mlt_filter) data; mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); int channels = mlt_properties_get_int( properties, "channels" ); int frame_size = mlt_properties_get_int( properties, "_samples" ) * sizeof(float); int sync = mlt_properties_get_int( properties, "_sync" ); int err = 0; int i; static int total_size = 0; jack_ringbuffer_t **output_buffers = mlt_properties_get_data( properties, "output_buffers", NULL ); if ( output_buffers == NULL ) return 0; jack_ringbuffer_t **input_buffers = mlt_properties_get_data( properties, "input_buffers", NULL ); jack_port_t **jack_output_ports = mlt_properties_get_data( properties, "jack_output_ports", NULL ); jack_port_t **jack_input_ports = mlt_properties_get_data( properties, "jack_input_ports", NULL ); float **jack_output_buffers = mlt_properties_get_data( properties, "jack_output_buffers", NULL ); float **jack_input_buffers = mlt_properties_get_data( properties, "jack_input_buffers", NULL ); pthread_mutex_t *output_lock = mlt_properties_get_data( properties, "output_lock", NULL ); pthread_cond_t *output_ready = mlt_properties_get_data( properties, "output_ready", NULL ); for ( i = 0; i < channels; i++ ) { size_t jack_size = ( frames * sizeof(float) ); size_t ring_size; // Send audio through out port jack_output_buffers[i] = jack_port_get_buffer( jack_output_ports[i], frames ); if ( ! jack_output_buffers[i] ) { mlt_log_error( MLT_FILTER_SERVICE(filter), "no buffer for output port %d\n", i ); err = 1; break; } ring_size = jack_ringbuffer_read_space( output_buffers[i] ); jack_ringbuffer_read( output_buffers[i], ( char * )jack_output_buffers[i], ring_size < jack_size ? ring_size : jack_size ); if ( ring_size < jack_size ) memset( &jack_output_buffers[i][ring_size], 0, jack_size - ring_size ); // Return audio through in port jack_input_buffers[i] = jack_port_get_buffer( jack_input_ports[i], frames ); if ( ! jack_input_buffers[i] ) { mlt_log_error( MLT_FILTER_SERVICE(filter), "no buffer for input port %d\n", i ); err = 1; break; } // Do not start returning audio until we have sent first mlt frame if ( sync && i == 0 && frame_size > 0 ) total_size += ring_size; mlt_log_debug( MLT_FILTER_SERVICE(filter), "sync %d frame_size %d ring_size %zu jack_size %zu\n", sync, frame_size, ring_size, jack_size ); if ( ! sync || ( frame_size > 0 && total_size >= frame_size ) ) { ring_size = jack_ringbuffer_write_space( input_buffers[i] ); jack_ringbuffer_write( input_buffers[i], ( char * )jack_input_buffers[i], ring_size < jack_size ? ring_size : jack_size ); if ( sync ) { // Tell mlt that audio is available pthread_mutex_lock( output_lock); pthread_cond_signal( output_ready ); pthread_mutex_unlock( output_lock); // Clear sync phase mlt_properties_set_int( properties, "_sync", 0 ); } } } // Often jackd does not send the stopped event through the JackSyncCallback jack_client_t *jack_client = mlt_properties_get_data( properties, "jack_client", NULL ); jack_position_t jack_pos; jack_transport_state_t state = jack_transport_query( jack_client, &jack_pos ); int transport_state = mlt_properties_get_int( properties, "_transport_state" ); if ( state != transport_state ) { mlt_properties_set_int( properties, "_transport_state", state ); if ( state == JackTransportStopped ) jack_sync( state, &jack_pos, filter ); } return err; }
/** * The process callback for this JACK application. * It is called by JACK at the appropriate times. */ int process (jack_nframes_t nframes, void *arg) { jack_nframes_t net_period; int rx_bufsize, tx_bufsize; jack_default_audio_sample_t *buf; jack_port_t *port; JSList *node; int chn; int size, i; const char *porttype; int input_fd; jack_position_t local_trans_pos; uint32_t *packet_buf_tx, *packet_bufX; uint32_t *rx_packet_ptr; jack_time_t packet_recv_timestamp; if( bitdepth == 1000 || bitdepth == 999) net_period = (factor * jack_get_buffer_size(client) * 1024 / jack_get_sample_rate(client) / 8) & (~1) ; else net_period = (float) nframes / (float) factor; rx_bufsize = get_sample_size (bitdepth) * capture_channels * net_period + sizeof (jacknet_packet_header); tx_bufsize = get_sample_size (bitdepth) * playback_channels * net_period + sizeof (jacknet_packet_header); /* Allocate a buffer where both In and Out Buffer will fit */ packet_buf_tx = alloca (tx_bufsize); jacknet_packet_header *pkthdr_tx = (jacknet_packet_header *) packet_buf_tx; /* * for latency==0 we need to send out the packet before we wait on the reply. * but this introduces a cycle of latency, when netsource is connected to itself. * so we send out before read only in zero latency mode. * */ if( latency == 0 ) { /* reset packet_bufX... */ packet_bufX = packet_buf_tx + sizeof (jacknet_packet_header) / sizeof (jack_default_audio_sample_t); /* ---------- Send ---------- */ render_jack_ports_to_payload (bitdepth, playback_ports, playback_srcs, nframes, packet_bufX, net_period, dont_htonl_floats); /* fill in packet hdr */ pkthdr_tx->transport_state = jack_transport_query (client, &local_trans_pos); pkthdr_tx->transport_frame = local_trans_pos.frame; pkthdr_tx->framecnt = framecnt; pkthdr_tx->latency = latency; pkthdr_tx->reply_port = reply_port; pkthdr_tx->sample_rate = jack_get_sample_rate (client); pkthdr_tx->period_size = nframes; /* playback for us is capture on the other side */ pkthdr_tx->capture_channels_audio = playback_channels_audio; pkthdr_tx->playback_channels_audio = capture_channels_audio; pkthdr_tx->capture_channels_midi = playback_channels_midi; pkthdr_tx->playback_channels_midi = capture_channels_midi; pkthdr_tx->mtu = mtu; if( freewheeling != 0 ) pkthdr_tx->sync_state = (jack_nframes_t)MASTER_FREEWHEELS; else pkthdr_tx->sync_state = (jack_nframes_t)deadline_goodness; //printf("goodness=%d\n", deadline_goodness ); packet_header_hton (pkthdr_tx); if (cont_miss < 3 * latency + 5) { int r; for( r = 0; r < redundancy; r++ ) netjack_sendto (outsockfd, (char *) packet_buf_tx, tx_bufsize, 0, &destaddr, sizeof (destaddr), mtu); } else if (cont_miss > 50 + 5 * latency) { state_connected = 0; packet_cache_reset_master_address( packcache ); //printf ("Frame %d \tRealy too many packets missed (%d). Let's reset the counter\n", framecnt, cont_miss); cont_miss = 0; } } /* * ok... now the RECEIVE code. * */ if( reply_port ) input_fd = insockfd; else input_fd = outsockfd; // for latency == 0 we can poll. if( (latency == 0) || (freewheeling != 0) ) { jack_time_t deadline = jack_get_time() + 1000000 * jack_get_buffer_size(client) / jack_get_sample_rate(client); // Now loop until we get the right packet. while(1) { jack_nframes_t got_frame; if ( ! netjack_poll_deadline( input_fd, deadline ) ) break; packet_cache_drain_socket(packcache, input_fd); if (packet_cache_get_next_available_framecnt( packcache, framecnt - latency, &got_frame )) if( got_frame == (framecnt - latency) ) break; } } else { // normally: // only drain socket. packet_cache_drain_socket(packcache, input_fd); } size = packet_cache_retreive_packet_pointer( packcache, framecnt - latency, (char**)&rx_packet_ptr, rx_bufsize, &packet_recv_timestamp ); /* First alternative : we received what we expected. Render the data * to the JACK ports so it can be played. */ if (size == rx_bufsize) { uint32_t *packet_buf_rx = rx_packet_ptr; jacknet_packet_header *pkthdr_rx = (jacknet_packet_header *) packet_buf_rx; packet_bufX = packet_buf_rx + sizeof (jacknet_packet_header) / sizeof (jack_default_audio_sample_t); // calculate how much time there would have been, if this packet was sent at the deadline. int recv_time_offset = (int) (jack_get_time() - packet_recv_timestamp); packet_header_ntoh (pkthdr_rx); deadline_goodness = recv_time_offset - (int)pkthdr_rx->latency; //printf( "deadline goodness = %d ---> off: %d\n", deadline_goodness, recv_time_offset ); if (cont_miss) { //printf("Frame %d \tRecovered from dropouts\n", framecnt); cont_miss = 0; } render_payload_to_jack_ports (bitdepth, packet_bufX, net_period, capture_ports, capture_srcs, nframes, dont_htonl_floats); state_currentframe = framecnt; state_recv_packet_queue_time = recv_time_offset; state_connected = 1; sync_state = pkthdr_rx->sync_state; packet_cache_release_packet( packcache, framecnt - latency ); } /* Second alternative : we've received something that's not * as big as expected or we missed a packet. We render silence * to the ouput ports */ else { jack_nframes_t latency_estimate; if( packet_cache_find_latency( packcache, framecnt, &latency_estimate ) ) //if( (state_latency == 0) || (latency_estimate < state_latency) ) state_latency = latency_estimate; // Set the counters up. state_currentframe = framecnt; //state_latency = framecnt - pkthdr->framecnt; state_netxruns += 1; //printf ("Frame %d \tPacket missed or incomplete (expected: %d bytes, got: %d bytes)\n", framecnt, rx_bufsize, size); //printf ("Frame %d \tPacket missed or incomplete\n", framecnt); cont_miss += 1; chn = 0; node = capture_ports; while (node != NULL) { port = (jack_port_t *) node->data; buf = jack_port_get_buffer (port, nframes); porttype = jack_port_type (port); if (strncmp (porttype, JACK_DEFAULT_AUDIO_TYPE, jack_port_type_size ()) == 0) for (i = 0; i < nframes; i++) buf[i] = 0.0; else if (strncmp (porttype, JACK_DEFAULT_MIDI_TYPE, jack_port_type_size ()) == 0) jack_midi_clear_buffer (buf); node = jack_slist_next (node); chn++; } } if (latency != 0) { /* reset packet_bufX... */ packet_bufX = packet_buf_tx + sizeof (jacknet_packet_header) / sizeof (jack_default_audio_sample_t); /* ---------- Send ---------- */ render_jack_ports_to_payload (bitdepth, playback_ports, playback_srcs, nframes, packet_bufX, net_period, dont_htonl_floats); /* fill in packet hdr */ pkthdr_tx->transport_state = jack_transport_query (client, &local_trans_pos); pkthdr_tx->transport_frame = local_trans_pos.frame; pkthdr_tx->framecnt = framecnt; pkthdr_tx->latency = latency; pkthdr_tx->reply_port = reply_port; pkthdr_tx->sample_rate = jack_get_sample_rate (client); pkthdr_tx->period_size = nframes; /* playback for us is capture on the other side */ pkthdr_tx->capture_channels_audio = playback_channels_audio; pkthdr_tx->playback_channels_audio = capture_channels_audio; pkthdr_tx->capture_channels_midi = playback_channels_midi; pkthdr_tx->playback_channels_midi = capture_channels_midi; pkthdr_tx->mtu = mtu; if( freewheeling != 0 ) pkthdr_tx->sync_state = (jack_nframes_t)MASTER_FREEWHEELS; else pkthdr_tx->sync_state = (jack_nframes_t)deadline_goodness; //printf("goodness=%d\n", deadline_goodness ); packet_header_hton (pkthdr_tx); if (cont_miss < 3 * latency + 5) { int r; for( r = 0; r < redundancy; r++ ) netjack_sendto (outsockfd, (char *) packet_buf_tx, tx_bufsize, 0, &destaddr, sizeof (destaddr), mtu); } else if (cont_miss > 50 + 5 * latency) { state_connected = 0; packet_cache_reset_master_address( packcache ); //printf ("Frame %d \tRealy too many packets missed (%d). Let's reset the counter\n", framecnt, cont_miss); cont_miss = 0; } } framecnt++; return 0; }
int AudioJACKTarget::process(jack_nframes_t nframes) { if (m_done) return 0; if (!m_mutex.tryLock()) { return 0; } if (m_outputs.empty()) { m_mutex.unlock(); return 0; } #ifdef DEBUG_AUDIO_JACK_TARGET std::cout << "AudioJACKTarget::process(" << nframes << "): have a source" << std::endl; #endif #ifdef DEBUG_AUDIO_JACK_TARGET if (m_bufferSize != nframes) { std::cerr << "WARNING: m_bufferSize != nframes (" << m_bufferSize << " != " << nframes << ")" << std::endl; } #endif float **buffers = (float **)alloca(m_outputs.size() * sizeof(float *)); for (size_t ch = 0; ch < m_outputs.size(); ++ch) { buffers[ch] = (float *)jack_port_get_buffer(m_outputs[ch], nframes); } size_t received = 0; if (m_source) { received = m_source->getSourceSamples(nframes, buffers); } for (size_t ch = 0; ch < m_outputs.size(); ++ch) { for (size_t i = received; i < nframes; ++i) { buffers[ch][i] = 0.0; } } float peakLeft = 0.0, peakRight = 0.0; for (size_t ch = 0; ch < m_outputs.size(); ++ch) { float peak = 0.0; for (size_t i = 0; i < nframes; ++i) { buffers[ch][i] *= m_outputGain; float sample = fabsf(buffers[ch][i]); if (sample > peak) peak = sample; } if (ch == 0) peakLeft = peak; if (ch > 0 || m_outputs.size() == 1) peakRight = peak; } if (m_source) { m_source->setOutputLevels(peakLeft, peakRight); } m_mutex.unlock(); return 0; }