static void port_event(alsa_seqmidi_t *self, snd_seq_event_t *ev) { const snd_seq_addr_t addr = ev->data.addr; if (addr.client == self->client_id) return; if (ev->type == SND_SEQ_EVENT_PORT_START || ev->type == SND_SEQ_EVENT_PORT_CHANGE) { assert (jack_ringbuffer_write_space(self->port_add) >= sizeof(addr)); debug_log("port_event: add/change %d:%d", addr.client, addr.port); jack_ringbuffer_write(self->port_add, (char*)&addr, sizeof(addr)); sem_post(&self->port_sem); } else if (ev->type == SND_SEQ_EVENT_PORT_EXIT) { debug_log("port_event: del %d:%d", addr.client, addr.port); port_setdead(self->stream[PORT_INPUT].ports, addr); port_setdead(self->stream[PORT_OUTPUT].ports, addr); } }
/* * ==================== Port add/del handling thread ============================== */ static void update_port_type(alsa_seqmidi_t *self, int type, snd_seq_addr_t addr, int caps, const snd_seq_port_info_t *info) { stream_t *str = &self->stream[type]; int alsa_mask = port_type[type].alsa_mask; port_t *port = port_get(str->ports, addr); debug_log("update_port_type(%d:%d)", addr.client, addr.port); if (port && (caps & alsa_mask)!=alsa_mask) { debug_log("setdead: %s", port->name); port->is_dead = 1; } if (!port && (caps & alsa_mask)==alsa_mask) { assert (jack_ringbuffer_write_space(str->new_ports) >= sizeof(port)); port = port_create(self, type, addr, info); if (port) jack_ringbuffer_write(str->new_ports, (char*)&port, sizeof(port)); } }
static void a2j_port_event (struct a2j * self, snd_seq_event_t * ev) { const snd_seq_addr_t addr = ev->data.addr; if (addr.client == self->client_id) return; if (ev->type == SND_SEQ_EVENT_PORT_START || ev->type == SND_SEQ_EVENT_PORT_CHANGE) { if (jack_ringbuffer_write_space(self->port_add) >= sizeof(addr)) { a2j_debug("port_event: add/change %d:%d", addr.client, addr.port); jack_ringbuffer_write(self->port_add, (char*)&addr, sizeof(addr)); } else { a2j_error("dropping port_event: add/change %d:%d", addr.client, addr.port); } } else if (ev->type == SND_SEQ_EVENT_PORT_EXIT) { a2j_debug("port_event: del %d:%d", addr.client, addr.port); a2j_port_setdead(self->stream.port_hash, addr); } }
static int process(jack_nframes_t nframes, void* arg) { int cnt; static int total; /* Do nothing until we're ready to begin. */ if (!unleash_jack) { printf ("nothing to do\n"); return 0; } for(int i = 0; i < CHANNELS; i++) { in[i] = jack_port_get_buffer(inputports[i], nframes); } for (size_t i = 0; i < nframes; i++) { for(int j = 0; j < CHANNELS; j++) { total++; if ((cnt = jack_ringbuffer_write_space(ringbuffer)) >= SAMPLE_SIZE) { jack_ringbuffer_write(ringbuffer, (void*) (in[j]+i), SAMPLE_SIZE); if (total % 5000 == 0) { printf ("Available writespace: %i\n", cnt); } } else { printf ("Only %i bytes available after %i samples\n", cnt, total); halt_tx = 1; } } } if (0 == pthread_mutex_trylock(&threadLock)) { pthread_cond_signal(&dataReady); pthread_mutex_unlock(&threadLock); } return 0; }
int audio_feed_process_audio(jack_nframes_t n_frames, void *arg) { struct audio_feed *self = audio_feed; struct threads_info *ti = self->threads_info; struct encoder *e; struct recorder *r; sample_t *input_port_buffer[2]; int i; input_port_buffer[0] = jack_port_get_buffer(g.port.output_in_l, n_frames); input_port_buffer[1] = jack_port_get_buffer(g.port.output_in_r, n_frames); /* feed pcm audio data to all encoders that request it */ for (i = 0; i < ti->n_encoders; i++) { e = ti->encoder[i]; switch (e->jack_dataflow_control) { case JD_OFF: break; case JD_ON: while (jack_ringbuffer_write_space(e->input_rb[1]) < n_frames * sizeof (sample_t)) nanosleep(&(struct timespec){0, 10000000}, NULL); jack_ringbuffer_write(e->input_rb[0], (char *)input_port_buffer[0], n_frames * sizeof (sample_t)); jack_ringbuffer_write(e->input_rb[1], (char *)input_port_buffer[1], n_frames * sizeof (sample_t)); break; case JD_FLUSH: jack_ringbuffer_reset(e->input_rb[0]); jack_ringbuffer_reset(e->input_rb[1]); e->jack_dataflow_control = JD_OFF; break; default: fprintf(stderr, "jack_process_callback: unhandled jack_dataflow_control parameter\n"); } }
int ringbuffer_cwrite(jack_ringbuffer_t *rbuf, uint32_t tag, const void *data, size_t len) /* C version: returns 1 on success and 0 on error */ { jack_ringbuffer_data_t vec[2]; hdr_t hdr; size_t space, cnt; hdr.tag = tag; hdr.len = data!=NULL ? len : 0; space = jack_ringbuffer_write_space(rbuf); if((sizeof(hdr) + hdr.len) > space) return 0; /* write header first (this automatically advances) */ cnt = jack_ringbuffer_write(rbuf, (const char *)&hdr, sizeof(hdr)); if(cnt != sizeof(hdr)) return luajack_error(UNEXPECTED_ERROR); if(hdr.len) { /* write data */ jack_ringbuffer_get_write_vector(rbuf, vec); if((vec[0].len+vec[1].len) < hdr.len) return luajack_error(UNEXPECTED_ERROR); if(vec[0].len >= hdr.len) memcpy(vec[0].buf, data, hdr.len); else { memcpy(vec[0].buf, data, vec[0].len); memcpy(vec[1].buf, (char*)data + vec[0].len, hdr.len - vec[0].len); } jack_ringbuffer_write_advance(rbuf, hdr.len); } return 1; }
size_t jack_ringbuffer_write (jack_ringbuffer_t * rb, const char *src, size_t cnt) { size_t free_cnt; size_t cnt2; size_t to_write; size_t n1, n2; if ((free_cnt = jack_ringbuffer_write_space (rb)) == 0) { return 0; } to_write = cnt > free_cnt ? free_cnt : cnt; cnt2 = rb->write_ptr + to_write; if (cnt2 > rb->size) { n1 = rb->size - rb->write_ptr; n2 = cnt2 & rb->size_mask; } else { n1 = to_write; n2 = 0; } memcpy (&(rb->buf[rb->write_ptr]), src, n1); rb->write_ptr += n1; rb->write_ptr &= rb->size_mask; if (n2) { memcpy (&(rb->buf[rb->write_ptr]), src + n1, n2); rb->write_ptr += n2; rb->write_ptr &= rb->size_mask; } return to_write; }
void gui_message(const char *msg) { if(jack_ringbuffer_write_space(gui_ring) >= 2048) jack_ringbuffer_write(gui_ring, msg, 2048); }
// TODO: nonblocking version int ezjack_write(ezjack_bundle_t *bun, void *buf, int len, ezjack_format_t fmt) { int i, j; int fmtsize = _helper_get_fmt_size(fmt); // FIXME: handle erroneous format int blockalign = bun->portstack.outcount * fmtsize; if(len % blockalign != 0) abort(); // FIXME: do this more gracefully int reqlen = len/blockalign; while(reqlen > 0) { int minspace = reqlen * sizeof(float); // Get smallest space count for(i = 0; i < bun->portstack.outcount; i++) { int cspace = (int)jack_ringbuffer_write_space(bun->portstack.outrb[i]); if(cspace < minspace) minspace = cspace; } minspace /= sizeof(float); // Write to ring buffers if(minspace > 0) { // Write to temporaries // FIXME: handle all formats #define HELPER_WRITE_FORMAT(inc, wrap) \ for(j = 0; j < minspace; j++) \ for(i = 0; i < bun->portstack.outcount; i++) \ { \ bun->portstack.outbuf[i][j] = wrap; \ buf += inc; \ } \ switch(fmt) { case EZJackFormatFloat32LE: case EZJackFormatFloat32Native: HELPER_WRITE_FORMAT(sizeof(float), *(float *)buf); break; case EZJackFormatU8: HELPER_WRITE_FORMAT(1, ((float)*(uint8_t *)buf)/128.0f-1.0f); break; case EZJackFormatS8: HELPER_WRITE_FORMAT(1, ((float)*(int8_t *)buf)/128.0f); break; case EZJackFormatS16Native: case EZJackFormatS16LE: HELPER_WRITE_FORMAT(2, ((float)*(int16_t *)buf)/32768.0f); break; case EZJackFormatU16Native: case EZJackFormatU16LE: HELPER_WRITE_FORMAT(2, ((float)*(uint16_t *)buf)/32768.0f-1.0f); break; } #undef HELPER_WRITE_FORMAT // Commit data for(i = 0; i < bun->portstack.outcount; i++) { // FIXME: handle the case where this returns something wrong jack_ringbuffer_write(bun->portstack.outrb[i], (char *)(bun->portstack.outbuf[i]), minspace*sizeof(float)); } reqlen -= minspace; } // Sleep a bit. // TODO: use a notify system usleep(1000); } return len; }
void collect_data(SynthEngine *synth, float value, unsigned char type, unsigned char control, unsigned char part, unsigned char kititem, unsigned char engine, unsigned char insert, unsigned char parameter, unsigned char par2) { if (part < NUM_MIDI_PARTS && engine == PART::engine::padSynth) { if (collect_readData(synth, 0, PART::control::partBusy, part, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED)) { fl_alert("Part %d is busy", int(part)); return; } } CommandBlock putData; size_t commandSize = sizeof(putData); putData.data.value = value; putData.data.control = control; putData.data.part = part; putData.data.kit = kititem; putData.data.engine = engine; putData.data.insert = insert; putData.data.parameter = parameter; putData.data.par2 = par2; unsigned char typetop = type & 0xd0; // pass through redraws *after* command unsigned char buttons = type & 7; if (part == TOPLEVEL::section::main && (control > 48 || control == 14)) type = 1; // TODO fix this properly! else if (part != TOPLEVEL::section::midiLearn) { if (buttons == 3 && Fl::event_is_click()) { float newValue; putData.data.type = 3 | TOPLEVEL::type::Limits; newValue = synth->interchange.readAllData(&putData); //cout << "Gui limits new value " << newValue << endl; if(Fl::event_state(FL_CTRL) != 0) { if (putData.data.type & TOPLEVEL::type::Learnable) type = 3; // previous type is now irrelevant // identifying this for button 3 as MIDI learn else { synth->getGuiMaster()->words->copy_label("Can't learn this control"); synth->getGuiMaster()->message->show(); synth->getGuiMaster()->message->position(Fl::event_x_root() + 16, Fl::event_y_root()); synth->getRuntime().Log("Can't MIDI-learn this control"); /* can't use fl_alert here. * For some reason it goes into a loop on spin boxes * and runs menus up to their max value. */ type = TOPLEVEL::type::Learnable; } } else { putData.data.value = newValue; type = TOPLEVEL::type::Write | TOPLEVEL::source::UpdateAfterSet; // has to be write as it's 'set default' } } else if(buttons > 2) type = 1; // change scroll wheel to button 1 } type |= typetop; putData.data.type = type | TOPLEVEL::source::GUI; //cout << "collect_data value " << value << " type " << int(type) << " control " << int(control) << " part " << int(part) << " kit " << int(kititem) << " engine " << int(engine) << " insert " << int(insert) << " par " << int(parameter) << " par2 " << int(par2) << endl; if (jack_ringbuffer_write_space(synth->interchange.fromGUI) >= commandSize) jack_ringbuffer_write(synth->interchange.fromGUI, (char*) putData.bytes, commandSize); else synth->getRuntime().Log("Unable to write to fromGUI buffer."); }
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; }
int main (int argc, char *argv[]) { const char *client_name; const char *server_name = NULL; jack_options_t options = JackNullOption; jack_status_t status; pcap_t* pcap; int offline=0; char* iface=NULL; char* fname=NULL; int slen=SNAPLEN; int rs=RINGSIZE; char errbuf[PCAP_ERRBUF_SIZE]; int promisc=PROMISC; double rate=1.0; client_name = strrchr(argv[0], '/'); if(!client_name) client_name=argv[0]; else client_name++; int opt; while ((opt = getopt(argc, argv, "c:n:s:pi:r:t:b:")) != -1) { switch (opt) { case 'c': client_name=optarg; break; case 'n': server_name=optarg; options |= JackServerName; break; case 's': slen=atoi(optarg); break; case 'p': promisc=0; break; case 'i': iface=optarg; break; case 'r': fname=optarg; break; case 't': rate=atof(optarg); break; case 'b': rs=atoi(optarg); break; case '?': usage(argv[0],0); break; default: /* '?' */ printf("Invalid option %c\n",opt); usage(argv[0],EXIT_FAILURE); } } /* open the pcap source */ if ((iface && fname) || (!iface && !fname)) { printf("Please specify either a interface or a dump file as packet source\n"); usage(argv[0],EXIT_FAILURE); } if (iface) { pcap = pcap_open_live(iface, slen, promisc, 0, errbuf); if (!pcap) { printf("Failed to open pcap source %s: %s\n", iface, errbuf); exit(EXIT_FAILURE); } } if (fname) { pcap = pcap_open_offline(fname, errbuf); if (!pcap) { printf("Failed to open dump file %s: %s\n", iface, errbuf); exit(EXIT_FAILURE); } offline=1; } /* set bpf filter */ if (optind < argc) { int i,s; char* bpf_str; struct bpf_program bpf_prog; for (s=0, i=optind; i<argc; i++) { s += strlen(argv[i]) + 1; } bpf_str = malloc(s); if (!bpf_str) { printf("Failed to malloc space for bpf filter\n"); exit(EXIT_FAILURE); } bpf_str[0]=0; for (i=optind; i<argc; i++) { strcat(bpf_str,argv[i]); strcat(bpf_str," "); } printf("Setting bpf filter to %s\n", bpf_str); if (0>pcap_compile(pcap, &bpf_prog, bpf_str, 1, 0)) { printf("Failed to compile bpf filter\n"); exit(EXIT_FAILURE); } if (0>pcap_setfilter(pcap, &bpf_prog)) { printf("Failed to set bpf filter\n"); exit(EXIT_FAILURE); } pcap_freecode(&bpf_prog); free(bpf_str); } /* allocate ringbuffer */ rb=jack_ringbuffer_create (rs*sizeof(jack_default_audio_sample_t)); if (!rb) { printf("Failed to allocate ringbuffer\n"); exit(EXIT_FAILURE); } /* open a client connection to the JACK server */ client = jack_client_open (client_name, options, &status, server_name); if (client == NULL) { fprintf (stderr, "jack_client_open() failed, " "status = 0x%2.0x\n", status); if (status & JackServerFailed) { fprintf (stderr, "Unable to connect to JACK server\n"); } exit (1); } if (status & JackServerStarted) { fprintf (stderr, "JACK server started\n"); } if (status & JackNameNotUnique) { client_name = jack_get_client_name(client); fprintf (stderr, "unique name `%s' assigned\n", client_name); } /* tell the JACK server to call `process()' whenever there is work to be done. */ jack_set_process_callback (client, process, 0); /* tell the JACK server to call `jack_shutdown()' if it ever shuts down, either entirely, or if it just decides to stop calling us. */ jack_on_shutdown (client, jack_shutdown, 0); /* display the current sample rate. */ printf ("engine sample rate: %" PRIu32 "\n", jack_get_sample_rate (client)); /* create two ports */ output_port = jack_port_register (client, "output", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); /* Tell the JACK server that we are ready to roll. Our * process() callback will start running now. */ if (jack_activate (client)) { fprintf (stderr, "cannot activate client"); exit (1); } /* read packets from pcap source and write it into the ringbuffer */ char *buf; struct pcap_pkthdr *h; u_int pcnt=0; struct timeval toff, tnow; /* mark offset for calculation on first packet */ toff.tv_sec = -1; /* main loop: get packets from pcap source */ while (0 <= pcap_next_ex(pcap, &h, (const u_char**) &buf)) { size_t s; if (!buf) break; pcnt++; /* * if we are reading from a file we sleep in the loop until the timestamp * of the packet is reached. */ if (offline) for(;;) { struct timeval dt; gettimeofday(&tnow, NULL); /* initialize toff on first packet */ if(toff.tv_sec == -1) { tvmov(toff,h->ts); tvsub(toff,tnow); tvnrm(toff); } tvmov(dt,h->ts); tvsub(dt,tnow); tvsub(dt,toff); tvnrm(dt); if (dt.tv_sec < 0 ) { break; } else if (dt.tv_sec > 0) { sleep(dt.tv_sec); } else { usleep(dt.tv_usec); } } /* check available buffer space */ s = jack_ringbuffer_write_space(rb); if (!s) continue; /* truncate packet if there is not enough space in the buffer */ if (s > h->caplen) s = h->caplen; /* write into the ringbuffer and get the next packet */ jack_ringbuffer_write(rb,buf,s); } jack_client_close (client); struct pcap_stat ps; if(!pcap_stats(pcap, &ps)) { printf( "%d packets captured\n" "%d received by filter\n" "%d packets dropped by kernel\n", ps.ps_recv, pcnt, ps.ps_drop ); } else { pcap_perror(pcap,"Failed to optain packet statistics"); } exit (0); }
size_t JackRingbuffer::writeSpace() { return jack_ringbuffer_write_space(ringbuffer_); }
/** read from the attached track's ports and stuff the ringbuffers */ nframes_t Record_DS::process ( nframes_t nframes ) { THREAD_ASSERT( RT ); if ( ! _recording ) return 0; if ( transport->frame < _frame ) return 0; /* DMESSAGE( "recording actually happening at %lu (start frame %lu)", (unsigned long)transport->frame, (unsigned long)_frame); */ nframes_t offset = 0; if ( _frame > transport->frame && _frame < transport->frame + nframes ) { /* The record start frame falls somewhere within the current buffer. We must discard the unneeded portion and only stuff the part requested into the ringbuffer. */ offset = _frame - transport->frame; /* DMESSAGE( "offset = %lu", (unsigned long)offset ); */ } const size_t offset_size = offset * sizeof( sample_t ); const size_t block_size = ( nframes * sizeof( sample_t ) ) - offset_size; for ( int i = channels(); i--; ) { /* read the entire input buffer */ void *buf = track()->input[ i ].buffer( nframes ); /* FIXME: this results in a ringbuffer size that is no longer necessarily a multiple of nframes... how will the other side handle that? */ if ( engine->freewheeling() ) { while ( jack_ringbuffer_write_space( _rb[i] ) < block_size ) usleep( 10 * 1000 ); jack_ringbuffer_write( _rb[ i ], ((char*)buf) + offset_size, block_size ); } else { if ( jack_ringbuffer_write_space( _rb[i] ) < block_size ) { memset( buf, 0, block_size ); /* FIXME: we need to resync somehow */ ++_xruns; } else { jack_ringbuffer_write( _rb[ i ], ((char*)buf) + offset_size, block_size ); } } } block_processed(); /* FIXME: bogus */ return nframes; }
size_t ringbuffer_write_space(jack_ringbuffer_t *rbuf) { return jack_ringbuffer_write_space(rbuf); }
void Playback_DS::disk_thread ( void ) { _thread.name( "Playback" ); DMESSAGE( "playback thread running" ); /* buffer to hold the interleaved data returned by the track reader */ sample_t *buf = buffer_alloc( _nframes * channels() * _disk_io_blocks ); sample_t *cbuf = buffer_alloc( _nframes ); const nframes_t nframes = _nframes; nframes_t blocks_written; while ( ! _terminate ) { seek: blocks_written = 0; read_block( buf, nframes * _disk_io_blocks ); while ( blocks_written < _disk_io_blocks && wait_for_block() ) { // lock(); // for seeking if ( _pending_seek ) { /* FIXME: non-RT-safe IO */ DMESSAGE( "performing seek to frame %lu", (unsigned long)_seek_frame ); _frame = _seek_frame; _pending_seek = false; flush(); goto seek; } /* might have received terminate signal while waiting for block */ if ( _terminate ) goto done; // unlock(); // for seeking /* deinterleave the buffer and stuff it into the per-channel ringbuffers */ const size_t block_size = nframes * sizeof( sample_t ); for ( int i = 0; i < channels(); i++ ) { buffer_deinterleave_one_channel( cbuf, buf + ( blocks_written * nframes * channels() ), i, channels(), nframes ); while ( jack_ringbuffer_write_space( _rb[ i ] ) < block_size ) usleep( 100 * 1000 ); jack_ringbuffer_write( _rb[ i ], ((char*)cbuf), block_size ); } blocks_written++; } } done: DMESSAGE( "playback thread terminating" ); free(buf); free(cbuf); // flush(); _terminate = false; _thread.exit(); }
static void a2j_input_event (struct a2j * self, snd_seq_event_t * alsa_event) { jack_midi_data_t data[MAX_EVENT_SIZE]; struct a2j_stream *str = &self->stream; long size; struct a2j_port *port; jack_nframes_t now; now = jack_frame_time (self->jack_client); if ((port = a2j_port_get(str->port_hash, alsa_event->source)) == NULL) { return; } /* * RPNs, NRPNs, Bank Change, etc. need special handling * but seems, ALSA does it for us already. */ snd_midi_event_reset_decode(str->codec); if ((size = snd_midi_event_decode(str->codec, data, sizeof(data), alsa_event))<0) { return; } // fixup NoteOn with vel 0 if ((data[0] & 0xF0) == 0x90 && data[2] == 0x00) { data[0] = 0x80 + (data[0] & 0x0F); data[2] = 0x40; } a2j_debug("input: %d bytes at event_frame=%u", (int)size, now); if (jack_ringbuffer_write_space(port->inbound_events) >= (sizeof(struct a2j_alsa_midi_event) + size)) { struct a2j_alsa_midi_event ev; char *ev_charp = (char*) &ev; size_t limit; size_t to_write = sizeof(ev); jack_ringbuffer_data_t vec[2]; jack_ringbuffer_get_write_vector( port->inbound_events, vec ); ev.time = now; ev.size = size; limit = (to_write > vec[0].len ? vec[0].len : to_write); if( limit ) { memcpy( vec[0].buf, ev_charp, limit ); to_write -= limit; ev_charp += limit; vec[0].buf += limit; vec[0].len -= limit; } if( to_write ) { memcpy( vec[1].buf, ev_charp, to_write ); vec[1].buf += to_write; vec[1].len -= to_write; } to_write = size; ev_charp = (char *)data; limit = (to_write > vec[0].len ? vec[0].len : to_write); if( limit ) memcpy( vec[0].buf, ev_charp, limit ); to_write -= limit; ev_charp += limit; if( to_write ) memcpy( vec[1].buf, ev_charp, to_write ); jack_ringbuffer_write_advance( port->inbound_events, sizeof(ev) + size ); } else { a2j_error ("MIDI data lost (incoming event buffer full): %ld bytes lost", size); } }
//================================================================ // /audio //handler for audio messages int osc_audio_handler(const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data) { if(shutdown_in_progress==1 || not_yet_ready==1) { return 0; } //init to 0, increment before use msg_received_counter++; gettimeofday(&tv, NULL); //first blob is at data_offset+1 (one-based) int data_offset=4; //ignore first n channels/blobs data_offset+=channel_offset; message_number_prev=message_number; //the messages are numbered sequentially. first msg is numberd 1 message_number=argv[0]->h; if(message_number_prev<message_number-1) { fprintf(stderr,"\ngap in message sequence! possibly lost %" PRId64" message(s) on the way.\n" ,message_number-message_number_prev-1); fflush(stderr); } //total args count minus metadata args count = number of blobs input_port_count=argc-data_offset; //only process useful number of channels port_count=fmin(input_port_count,output_port_count); if(port_count < 1) { fprintf(stderr,"channel offset %d >= available input channels %d! (nothing to receive). shutting down...\n" ,channel_offset ,channel_offset+input_port_count); fflush(stderr); shutdown_in_progress=1; return 0; } //check sample rate and period size if sender (re)started or values not yet initialized (=no /offer received) if(message_number_prev>message_number || message_number==1 || remote_sample_rate==0 || remote_period_size==0 ) { lo_address loa; if(use_tcp==1) { lo_address loa_=lo_message_get_source(data); loa=lo_address_new_with_proto(lo_proto,lo_address_get_hostname(loa_),remote_tcp_server_port); } else { loa=lo_message_get_source(data); } strcpy(sender_host,lo_address_get_hostname(loa)); strcpy(sender_port,lo_address_get_port(loa)); //option --rebuff if(rebuffer_on_restart==1) { uint64_t can_read_count=jack_ringbuffer_read_space(rb); pre_buffer_counter=fmax(0,(float)can_read_count/(float)bytes_per_sample/(float)period_size/(float)port_count); //start buffering process_enabled=0; } else { pre_buffer_counter=0; } remote_sample_rate=argv[3]->i; if(sample_rate!=remote_sample_rate) { if(close_on_incomp==0) { //sending deny will tell sender to stop/quit lo_message msg=lo_message_new(); lo_message_add_float(msg,format_version); lo_message_add_int32(msg,sample_rate); // /deny as reply to /audio should be the same as for /deny as reply to /offer //will need change of /audio (add format, bytes_per_sample) /////// lo_message_add_int32(msg,99); lo_send_message(loa, "/deny", msg); lo_message_free(msg); fprintf(stderr,"\ndenying transmission from %s:%s\n(incompatible JACK settings on sender: SR: %d). telling sender to stop.\n", lo_address_get_hostname(loa),lo_address_get_port(loa),remote_sample_rate ); fflush(stderr); message_number=0; message_number_prev=0; remote_sample_rate=0; remote_period_size=0; //pre_buffer_counter=0; } else { lo_address loa; if(use_tcp==1) { lo_address loa_=lo_message_get_source(data); loa=lo_address_new_with_proto(lo_proto,lo_address_get_hostname(loa_),remote_tcp_server_port); } else { loa=lo_message_get_source(data); } fprintf(stderr,"\ndenying transmission from %s:%s\nincompatible JACK settings on sender: SR: %d.\nshutting down (see option --close)...\n", lo_address_get_hostname(loa),lo_address_get_port(loa),remote_sample_rate ); fflush(stderr); shutdown_in_progress=1; return 0; } } remote_period_size=lo_blob_datasize((lo_blob)argv[0+data_offset])/bytes_per_sample; if(shutup==0 && quiet==0) { fprintf(stderr,"\nsender was (re)started. "); lo_address loa=lo_message_get_source(data); fprintf(stderr,"receiving from %s:%s\n",lo_address_get_hostname(loa),lo_address_get_port(loa)); } io_simple("/sender_restarted"); if(shutup==0 && quiet==0) { if(remote_period_size!=period_size) { fprintf(stderr,"sender period size: %d samples (%.3f x local)\n\n",remote_period_size,(float)remote_period_size/period_size); } else { fprintf(stderr,"equal sender and receiver period size\n\n"); } fflush(stderr); } }//end if "no-offer init" was needed remote_xrun_counter=argv[1]->h; lo_timetag tt=argv[2]->t; double msg_time=tt.sec+(double)tt.frac/1000000; double msg_time_prev=tt_prev.sec+(double)tt_prev.frac/1000000; //unused for now // double time_now=tv.tv_sec+(double)tv.tv_usec/1000000; time_interval=msg_time-msg_time_prev; time_interval_sum+=time_interval; time_interval_avg=(float)time_interval_sum/msg_received_counter; tt_prev=tt; //reset avg calc, check and reset after use if(msg_received_counter>=avg_calc_interval) { msg_received_counter=0; time_interval_sum=0; } if(pre_buffer_counter>=pre_buffer_size && process_enabled==0) { //if buffer filled, start to output audio in process() process_enabled=1; } int mc_period_bytes=period_size*bytes_per_sample*port_count; //check if a whole mc period can be written to the ringbuffer uint64_t can_write_count=jack_ringbuffer_write_space(rb); if(can_write_count < mc_period_bytes) { buffer_overflow_counter++; ///////////////// if(shutup==0 && quiet==0) { fprintf(stderr,"\rBUFFER OVERFLOW! this is bad -----%s","\033[0J"); } return 0; } //======================================== //new: support different period sizes on sender / receiver (still need same SR) //this needs more tests and optimization if(period_size==remote_period_size) { int i; //don't read more channels than we have outputs for(i=0;i < port_count;i++) { //get blob (=one period of one channel) unsigned char *data=lo_blob_dataptr((lo_blob)argv[i+data_offset]); //fprintf(stderr,"size %d\n",lo_blob_datasize((lo_blob)argv[i+data_offset])); //write to ringbuffer //========================================== //int cnt= jack_ringbuffer_write(rb, (void *) data, period_size*bytes_per_sample); } pre_buffer_counter++; } else if(period_size>remote_period_size) { int i; //don't read more channels than we have outputs for(i=0;i < port_count;i++) { //get blob (=one period of one channel) unsigned char *data=lo_blob_dataptr((lo_blob)argv[i+data_offset]); //fprintf(stderr,"size %d\n",lo_blob_datasize((lo_blob)argv[i+data_offset])); //write to temporary ringbuffer until there is enough data //========================================== //int cnt= jack_ringbuffer_write(rb_helper, (void *) data, remote_period_size*bytes_per_sample); } //if enough data collected for one larger multichannel period while(jack_ringbuffer_read_space(rb_helper) >=mc_period_bytes && jack_ringbuffer_write_space(rb) >=mc_period_bytes) { //transfer from helper to main ringbuffer unsigned char* data; data=malloc( mc_period_bytes); //store orig pointer unsigned char* orig_data=data; jack_ringbuffer_read(rb_helper,data, mc_period_bytes); for(i=0;i < port_count;i++) { int k; for(k=0;k<(period_size/remote_period_size);k++) { //reset pointer data=orig_data; //position in helper buffer for next sample for main buffer data+= k*remote_period_size*bytes_per_sample*port_count + i*remote_period_size*bytes_per_sample; //write one channel snipped (remote_period_size) to main buffer //int w= jack_ringbuffer_write(rb,(void *)data,remote_period_size*bytes_per_sample); } } data=orig_data; free(data); pre_buffer_counter++; } } else if(period_size<remote_period_size) { int k; for(k=0;k<(remote_period_size/period_size);k++) { int i; //don't read more channels than we have outputs for(i=0;i < port_count;i++) { //get blob (=one period of one channel) unsigned char *data=lo_blob_dataptr((lo_blob)argv[i+data_offset]); //fprintf(stderr,"size %d\n",lo_blob_datasize((lo_blob)argv[i+data_offset])); //write to ringbuffer //========================================== data+=k*period_size*bytes_per_sample; //int cnt= jack_ringbuffer_write(rb, (void *) data, period_size*bytes_per_sample); } pre_buffer_counter++; } } return 0; }//end osc_audio_handler
// JACK specifics. int qmidinetJackMidiDevice::process ( jack_nframes_t nframes ) { jack_nframes_t buffer_size = jack_get_buffer_size(m_pJackClient); m_last_frame_time = jack_last_frame_time(m_pJackClient); // Enqueue/dequeue events // to/from ring-buffers... for (int i = 0; i < m_nports; ++i) { if (m_ppJackPortIn && m_ppJackPortIn[i] && m_pJackBufferIn) { void *pvBufferIn = jack_port_get_buffer(m_ppJackPortIn[i], nframes); const int nevents = jack_midi_get_event_count(pvBufferIn); const unsigned int nlimit = jack_ringbuffer_write_space(m_pJackBufferIn); unsigned char achBuffer[nlimit]; unsigned char *pchBuffer = &achBuffer[0]; unsigned int nwrite = 0; for (int n = 0; n < nevents; ++n) { if (nwrite + sizeof(qmidinetJackMidiEvent) >= nlimit) break; qmidinetJackMidiEvent *pJackEventIn = (struct qmidinetJackMidiEvent *) pchBuffer; jack_midi_event_get(&pJackEventIn->event, pvBufferIn, n); if (nwrite + sizeof(qmidinetJackMidiEvent) + pJackEventIn->event.size >= nlimit) break; pJackEventIn->port = i; pchBuffer += sizeof(qmidinetJackMidiEvent); nwrite += sizeof(qmidinetJackMidiEvent); ::memcpy(pchBuffer, pJackEventIn->event.buffer, pJackEventIn->event.size); pchBuffer += pJackEventIn->event.size; nwrite += pJackEventIn->event.size; } if (nwrite > 0) { jack_ringbuffer_write(m_pJackBufferIn, (const char *) achBuffer, nwrite); } } if (m_ppJackPortOut && m_ppJackPortOut[i] && m_pJackBufferOut) { void *pvBufferOut = jack_port_get_buffer(m_ppJackPortOut[i], nframes); jack_midi_clear_buffer(pvBufferOut); const unsigned int nlimit = jack_midi_max_event_size(pvBufferOut); unsigned int nread = 0; qmidinetJackMidiEvent ev; while (jack_ringbuffer_peek(m_pJackBufferOut, (char *) &ev, sizeof(ev)) == sizeof(ev) && nread < nlimit) { if (ev.port != i) break; if (ev.event.time > m_last_frame_time) break; jack_nframes_t offset = m_last_frame_time - ev.event.time; if (offset > buffer_size) offset = 0; else offset = buffer_size - offset; jack_ringbuffer_read_advance(m_pJackBufferOut, sizeof(ev)); jack_midi_data_t *pMidiData = jack_midi_event_reserve(pvBufferOut, offset, ev.event.size); if (pMidiData) jack_ringbuffer_read(m_pJackBufferOut, (char *) pMidiData, ev.event.size); else jack_ringbuffer_read_advance(m_pJackBufferOut, ev.event.size); nread += ev.event.size; } } } if (m_pJackBufferIn && jack_ringbuffer_read_space(m_pJackBufferIn) > 0) m_pRecvThread->sync(); return 0; }
static int op_jack_write(const char *buffer, int count) { if (fail) { op_jack_exit(); return -OP_ERROR_INTERNAL; } if (!drop_done) { return 0; } int frame_size = sf_get_frame_size(sample_format); int channels = sf_get_channels(sample_format); size_t frames = count / frame_size; /* since this is the only place where the ringbuffers get * written, available space will only grow, therefore frames_min * is safe. */ size_t frames_min = SIZE_MAX; for (int c = 0; c < CHANNELS; c++) { size_t frames_available = jack_ringbuffer_write_space(ringbuffer[c]) / sizeof(jack_default_audio_sample_t); if (frames_available < frames_min) { frames_min = frames_available; } } if (frames > frames_min) { frames = frames_min; } jack_default_audio_sample_t buf[CHANNELS][buffer_size]; /* demux and convert to float */ for (int pos = 0; pos < count; ) { int frame = pos / frame_size; for (int c = 0; c < channels; c++) { int idx = pos + c * sample_bytes; /* for now, only 2 channels and mono are supported */ if (channel_map[c] == CHANNEL_POSITION_LEFT || channel_map[c] == CHANNEL_POSITION_MONO) { buf[0][frame] = read_sample(&buffer[idx]); } else if (channel_map[c] == CHANNEL_POSITION_RIGHT || channel_map[c] == CHANNEL_POSITION_MONO) { buf[1][frame] = read_sample(&buffer[idx]); } } pos += frame_size; } #ifdef HAVE_SAMPLERATE if (resample_ratio > 1.01f || resample_ratio < 0.99) { jack_default_audio_sample_t converted[buffer_size]; SRC_DATA src_data; for (int c = 0; c < CHANNELS; c++) { src_data.data_in = buf[c]; src_data.data_out = converted; src_data.input_frames = frames; src_data.output_frames = frames_min; src_data.src_ratio = resample_ratio; src_data.end_of_input = 0; int err = src_process(src_state[c], &src_data); if (err) { d_print("libsamplerate err %s\n", src_strerror(err)); } int byte_length = src_data.output_frames_gen * sizeof(jack_default_audio_sample_t); jack_ringbuffer_write(ringbuffer[c], (const char*) converted, byte_length); } return src_data.input_frames_used * frame_size; } else { #endif int byte_length = frames * sizeof(jack_default_audio_sample_t); for (int c = 0; c < CHANNELS; c++) { jack_ringbuffer_write(ringbuffer[c], (const char*) buf[c], byte_length); } return frames * frame_size; #ifdef HAVE_SAMPLERATE } #endif }
static size_t ja_write_avail(void *data) { jack_t *jd = (jack_t*)data; return jack_ringbuffer_write_space(jd->buffer[0]); }
/* * ----------------------------------------------------------------------------- */ static inline int can_pass(size_t sz, jack_ringbuffer_t *in, jack_ringbuffer_t *out) { return jack_ringbuffer_read_space(in) >= sz && jack_ringbuffer_write_space(out) >= sz; }
///Get the number of items that can be written at this time size_t getWriteSpace(){ return jack_ringbuffer_write_space(mRingBufferPtr) / sizeof(Type); }
void *jack_player_thread(void *unused){ WfAudioInfo* nfo = &myplayer->info; const int nframes = 1024; float *tmpbuf = (float*) calloc(nframes * nfo->channels, sizeof(float)); float *bufptr = tmpbuf; #ifdef ENABLE_RESAMPLING size_t maxbufsiz = nframes; int err = 0; SRC_STATE* src_state = src_new(SRC_QUALITY, nfo->channels, NULL); SRC_DATA src_data; int nframes_r = floorf((float) nframes*m_fResampleRatio); ///< # of frames after resampling #ifdef VARISPEED maxbufsiz = (2+nframes_r) * 2; #else maxbufsiz = (1+nframes_r); #endif float *smpbuf = (float*) calloc(maxbufsiz * nfo->channels, sizeof(float)); src_data.input_frames = nframes; src_data.output_frames = nframes_r; src_data.end_of_input = 0; src_data.src_ratio = m_fResampleRatio; src_data.input_frames_used = 0; src_data.output_frames_gen = 0; src_data.data_in = tmpbuf; src_data.data_out = smpbuf; #else int nframes_r = nframes; // no resampling #endif int ladspaerr = 0; #if (defined ENABLE_LADSPA) if (m_use_effect && play->enable_effect) { int i; for(i=0;i<nfo->channels;i++) { ladspaerr |= ladspah_init(myplugin[i], m_use_effect, m_effectno, jack_get_sample_rate(j_client) /* m_samplerate */, maxbufsiz); } if (ladspaerr) { dbg(0, "error setting up LADSPA plugin - effect disabled.\n"); } } else { ladspaerr = 1; } play->effect_enabled = ladspaerr ? false : true; // read-only for GUI #endif size_t rbchunk = nframes_r * nfo->channels * sizeof(float); play_position = 0; int64_t decoder_position = 0; pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); pthread_mutex_lock(&player_thread_lock); /** ALL SYSTEMS GO **/ player_active = 1; while(thread_run) { int rv = ad_read(myplayer, tmpbuf, nframes * nfo->channels); if (rv > 0) decoder_position += rv / nfo->channels; #ifdef JACK_MIDI const float pp[3] = {play->effect_param[0], play->effect_param[1] + midi_note, play->effect_param[2] + midi_octave}; #else const float pp[3] = {play->effect_param[0], play->effect_param[1], play->effect_param[2]}; #endif #if (defined ENABLE_RESAMPLING) && (defined VARISPEED) const float varispeed = play->playback_speed; #if 0 /* note: libsamplerate slowly approaches a new sample-rate slowly * src_set_ratio() allow for immediate updates at loss of quality */ static float oldspd = -1; if (oldspd != varispeed) { if ((err = src_set_ratio(src_state, m_fResampleRatio * varispeed))) dbg(0, "SRC ERROR: %s", src_strerror(err)); // instant change. oldspd = varispeed; } #endif nframes_r = floorf((float) nframes * m_fResampleRatio * varispeed); ///< # of frames after resampling src_data.input_frames = nframes; src_data.output_frames = nframes_r; src_data.src_ratio = m_fResampleRatio * varispeed; src_data.end_of_input = 0; #endif if (rv != nframes * nfo->channels) { dbg(1, "end of file."); if (rv > 0) { #ifdef ENABLE_RESAMPLING # ifdef VARISPEED if (1) # else if(m_fResampleRatio != 1.0) # endif { src_data.input_frames = rv / nfo->channels; #ifdef VARISPEED src_data.output_frames = floorf((float)(rv / nfo->channels) * m_fResampleRatio * varispeed); #else src_data.output_frames = floorf((float)(rv / nfo->channels) * m_fResampleRatio); #endif src_data.end_of_input = play->config.loop ? 0 : 1; src_process(src_state, &src_data); bufptr = smpbuf; rv = src_data.output_frames_gen * nfo->channels; } #endif if (!ladspaerr) { ladspah_set_param(myplugin, nfo->channels, 0 /*cents */, pp[0]); /* -100 .. 100 */ ladspah_set_param(myplugin, nfo->channels, 1 /*semitones */, pp[1]); /* -12 .. 12 */ ladspah_set_param(myplugin, nfo->channels, 2 /*octave */, pp[2]); /* -3 .. 3 */ ladspah_process_nch(myplugin, nfo->channels, bufptr, rv / nfo->channels); } jack_ringbuffer_write(rb, (char *) bufptr, rv * sizeof(float)); } if (play->config.loop) { ad_seek(myplayer, 0); decoder_position = 0; #ifdef ENABLE_RESAMPLING //src_reset (src_state); // XXX causes click # ifdef VARISPEED if (1) # else if(m_fResampleRatio != 1.0) # endif { src_data.end_of_input = 0; src_data.input_frames = nframes; src_data.output_frames = nframes_r; } #endif #if (defined ENABLE_RESAMPLING) && (defined VARISPEED) while(thread_run && jack_ringbuffer_write_space(rb) <= maxbufsiz*nfo->channels*sizeof(float)) #else while(thread_run && jack_ringbuffer_write_space(rb) <= rbchunk) #endif { pthread_cond_wait(&buffer_ready, &player_thread_lock); } continue; } else break; } /* end EOF handling */ #ifdef ENABLE_RESAMPLING #ifdef VARISPEED if(1) // m_fResampleRatio*varispeed != 1.0) #else if(m_fResampleRatio != 1.0) #endif { if ((err=src_process(src_state, &src_data))) { dbg(0, "SRC PROCESS ERROR: %s", src_strerror(err)); } bufptr = smpbuf; rbchunk = src_data.output_frames_gen * nfo->channels * sizeof(float); } #endif if (!ladspaerr) { ladspah_set_param(myplugin, nfo->channels, 0 /*cent */, pp[0]); /* -100 .. 100 */ ladspah_set_param(myplugin, nfo->channels, 1 /*semitones */, pp[1]); /* -12 .. 12 */ ladspah_set_param(myplugin, nfo->channels, 2 /*octave */, pp[2]); /* -3 .. 3 */ ladspah_process_nch(myplugin, nfo->channels, bufptr, rbchunk/ nfo->channels / sizeof(float)); } jack_ringbuffer_write(rb, (char *) bufptr, rbchunk); #if (defined ENABLE_RESAMPLING) && (defined VARISPEED) while(thread_run && jack_ringbuffer_write_space(rb) <= maxbufsiz*nfo->channels*sizeof(float)) #else while(thread_run && jack_ringbuffer_write_space(rb) <= rbchunk) #endif { #if 1 // flush_ringbuffer on seek if (playpause && seek_request != -1) break; #endif pthread_cond_wait(&buffer_ready, &player_thread_lock); } /* Handle SEEKs */ while (seek_request>=0 && seek_request<=1) { double csr = seek_request; decoder_position = floor(m_frames * seek_request); ad_seek(myplayer, decoder_position); if (csr == seek_request) { seek_request = -1; #if 1 // flush_ringbuffer ! size_t rs=jack_ringbuffer_read_space(rb); jack_ringbuffer_read_advance(rb,rs); #endif break; } } #if (defined ENABLE_RESAMPLING) && (defined VARISPEED) update_playposition (decoder_position, varispeed); #else update_playposition (decoder_position, 1.0); #endif } /** END OF PLAYBACK **/ #if (defined ENABLE_RESAMPLING) && (defined VARISPEED) const float varispeed = play->playback_speed; #else const float varispeed = 1.0; #endif pthread_mutex_unlock(&player_thread_lock); if (thread_run) { // wait for ringbuffer to empty. while (!silent && !playpause) { usleep(20); update_playposition (decoder_position, varispeed); } thread_run = 0; player_active = 0; play->effect_enabled = false; int i; for(i=0;i<nfo->channels;i++) { ladspah_deinit(myplugin[i]); } JACKclose(); } free(tmpbuf); #ifdef ENABLE_RESAMPLING src_delete(src_state); free(smpbuf); #endif player_active = 0; if(play->status != PLAY_PLAY_PENDING){ play->next(); } return NULL; }
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; }
unsigned int JackResampler::WriteSpace() { return (jack_ringbuffer_write_space(fRingBuffer) / sizeof(jack_default_audio_sample_t)); }
void* audio_thread(void* arg) { RECEIVER *rx=(RECEIVER*)arg; struct sockaddr_in audio; int audio_length=sizeof(audio); int old_state, old_type; int bytes_read; int on=1; #ifdef USE_PIPES int pipe_left = *softrock_get_jack_write_pipe_left(rx->client->receiver); int pipe_right = *softrock_get_jack_write_pipe_right(rx->client->receiver); #else // Use ringbuffers jack_ringbuffer_t *rb_left = softrock_get_jack_rb_left(rx->client->receiver); jack_ringbuffer_t *rb_right = softrock_get_jack_rb_right(rx->client->receiver); #endif int num_bytes = sizeof(float)*BUFFER_SIZE; static int second_time = 0; BUFFER buffer; unsigned long sequence=0L; unsigned short offset=0;; if (softrock_get_verbose()) fprintf(stderr,"audio_thread port=%d\n",audio_port+(rx->id*2)); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,&old_state); pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,&old_type); rx->audio_socket=socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP); if(rx->audio_socket<0) { perror("create socket failed for server audio socket"); exit(1); } setsockopt(rx->audio_socket, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); memset(&audio,0,audio_length); audio.sin_family=AF_INET; audio.sin_addr.s_addr=htonl(INADDR_ANY); audio.sin_port=htons(audio_port+(rx->id*2)); if(bind(rx->audio_socket,(struct sockaddr*)&audio,audio_length)<0) { perror("bind socket failed for server audio socket"); exit(1); } if (softrock_get_verbose()) fprintf(stderr,"listening for tx %d IQ audio on port %d\n",rx->id,audio_port+(rx->id*2)); while(1) { // get audio from a client #ifdef SMALL_PACKETS while(1) { bytes_read=recvfrom(rx->audio_socket,(char*)&buffer,sizeof(buffer),0,(struct sockaddr*)&audio,(socklen_t *)&audio_length); if(bytes_read<0) { perror("recvfrom socket failed for tx iq buffer"); exit(1); } //fprintf(stderr,"rcvd UDP packet: sequence=%lld offset=%d length=%d\n", buffer.sequence, buffer.offset, buffer.length); if(buffer.offset==0) { offset=0; sequence=buffer.sequence; // start of a frame memcpy((char *)&rx->output_buffer[buffer.offset/4],(char *)&buffer.data[0],buffer.length); offset+=buffer.length; } else { if((sequence==buffer.sequence) && (offset==buffer.offset)) { memcpy((char *)&rx->output_buffer[buffer.offset/4],(char *)&buffer.data[0],buffer.length); offset+=buffer.length; if(offset==sizeof(rx->output_buffer)) { offset=0; break; } } else { fprintf(stderr,"missing TX IQ frames expected %ld.%d got %ld.%d\n", (long)sequence,(int)offset,(long)buffer.sequence,(int)buffer.offset); } } } #else bytes_read=recvfrom(rx->audio_socket,rx->output_buffer,sizeof(rx->output_buffer),0,(struct sockaddr*)&audio,(socklen_t *)&audio_length); if(bytes_read<0) { perror("recvfrom socket failed for audio buffer"); exit(1); } #endif if (softrock_get_jack () == 1) { if (second_time == 32) {// This is for testing only. It will fail the second connection from QtRadio. softrock_set_client_active_rx(rx->client->receiver, ADD_RX); } second_time++; /*if ( second_time == 4000 ) { fprintf(stderr, "reached 4000.\n"); exit(0); }*/ #ifdef USE_PIPES //fprintf(stderr,"client.c pipe_left is: %d \n",pipe_left); //fprintf(stderr,"rx->client->receiver is: %d\n",rx->client->receiver); error_no = write(pipe_left, &rx->output_buffer[0], num_bytes); if (error_no == -1) { if ( softrock_get_verbose () == 1) perror("There were problems writing the left pipe for Jack in client.c"); //fprintf(stderr, "Note: resource temporarilly unavailable indicates write would have blocked. , blocked %d times\n",blocked_num); fprintf(stderr, "blocked %d times\nwritten %d times\n",blocked_num,second_time); blocked_num++; } //else fprintf(stderr,"Wrote %d bytes on left channel.\n",num_bytes); error_no = write(pipe_right, &rx->output_buffer[BUFFER_SIZE], num_bytes); if (error_no == -1) { if ( softrock_get_verbose () == 1) perror("There were problems writing the right pipe for Jack in client.c."); fprintf(stderr, "Note: resource temporarilly unavailable indicates write would have blocked.\n"); } #else // Use ringbuffers if (( jack_ringbuffer_write_space (rb_left) >= num_bytes ) && (jack_ringbuffer_write_space (rb_right) >= num_bytes )) { jack_ringbuffer_write (rb_left, (const char *) &rx->output_buffer[0], num_bytes); jack_ringbuffer_write (rb_right, (const char *) &rx->output_buffer[BUFFER_SIZE], num_bytes); } else { fprintf(stderr, "No space left to write in jack ringbuffers.\n"); } #endif } else { process_softrock_output_buffer(rx->output_buffer,&rx->output_buffer[BUFFER_SIZE]); } } softrock_set_client_active_rx (rx->client->receiver, DEC_RX); //How do we ever get here? }
int process(jack_nframes_t nframes, void *arg) { struct guitarseq *guitarseq = arg; if(!guitarseq) { fprintf(stderr, "No guitarseq instance!\n"); return 1; } void* port_buf; jack_nframes_t now = jack_frame_time (guitarseq->jack_client); //Output port_buf = jack_port_get_buffer(guitarseq->out_port, nframes); jack_midi_clear_buffer(port_buf); while (1) { jack_nframes_t time; //TODO: Do a safer read, in case only part of the message is here if (!jack_ringbuffer_read (guitarseq->out_buffer, (char *)&time, sizeof(time))) { break; } // from the future? if (time >= now) { break; } // time it right jack_nframes_t offset = time - now + nframes - 1; // get the size of the event size_t size; jack_ringbuffer_read(guitarseq->out_buffer, (char *)&size, sizeof(size)); INFO("out event at %u%+d size %zu\n", now, offset, size); if (offset > nframes) // from the past, somehow. cram it in at the front offset = 0; // proceed to giving it to jack jack_midi_data_t *buffer = jack_midi_event_reserve (port_buf, offset, size); if(buffer) { jack_ringbuffer_read(guitarseq->out_buffer, (char *)buffer, size); } else { // throw it away :( TODO: find more jack_ringbuffer_read_advance (guitarseq->out_buffer, size); ERROR("threw away MIDI event - no space reserved at time %u offset %d\n",time,offset); } } // Input port_buf = jack_port_get_buffer(guitarseq->in_port, nframes); jack_nframes_t event_count = jack_midi_get_event_count(port_buf); for(jack_nframes_t i=0; i<event_count; i++) { jack_midi_event_t in_event; jack_midi_event_get(&in_event, port_buf, i); //adds a note to the ringbuffer if (jack_ringbuffer_write_space(guitarseq->in_buffer) >= sizeof(in_event.time)+sizeof(in_event.size)+in_event.size) { jack_ringbuffer_write(guitarseq->in_buffer, (char *)&in_event.time, sizeof(in_event.time)); jack_ringbuffer_write(guitarseq->in_buffer, (char *)&in_event.size, sizeof(in_event.size)); jack_ringbuffer_write(guitarseq->in_buffer, (char *)in_event.buffer, in_event.size); } else { ERROR("Couldn't write to ringbuffer at %u, %zu midi data bytes lost\n", in_event.time, in_event.size); } } return 0; }