| // struct definition, shared with UI
|
| struct rb_compute_buffers {
|
| uint8_t channels;
|
| uint16_t nframes;
|
| float buffers[16][2048]; // very generous worst case of 2048 buffer size and 16 channels to display on the scope
|
| };
|
|
|
| // dsp init
|
| #define DEFAULT_RB_SIZE 1048608 // also very generous, >1MB allocated to make sure there's always room for the dsp thread to write to the ring buffer
|
| ringbuffer_t *rb;
|
| // ...
|
| rb = ringbuffer_create(DEFAULT_RB_SIZE);
|
|
|
| // dsp thread
|
| virtual void processAudio(jack_nframes_t nframes)
|
| {
|
| // Audio
|
| AVOIDDENORMALS;
|
|
|
| // Retrieve JACK inputs/output audio buffers
|
| float** fInChannel = (float**)alloca(fInputPorts.size() * sizeof(float*));
|
| for (size_t i = 0; i < fInputPorts.size(); i++) {
|
| fInChannel[i] = (float*)jack_port_get_buffer(fInputPorts[i], nframes);
|
| }
|
|
|
| float** fOutChannel = (float**)alloca(fOutputPorts.size() * sizeof(float*));
|
| for (size_t i = 0; i < fOutputPorts.size(); i++) {
|
| fOutChannel[i] = (float*)jack_port_get_buffer(fOutputPorts[i], nframes);
|
| }
|
|
|
| // By convention timestamp of -1 means 'no timestamp conversion', events already have a timestamp expressed in frames
|
| fDSP->compute(-1, nframes, reinterpret_cast<FAUSTFLOAT**>(fInChannel), reinterpret_cast<FAUSTFLOAT**>(fOutChannel));
|
|
|
| rb_compute_buffers rb_buffer;
|
| rb_buffer.nframes = nframes;
|
| rb_buffer.channels = fOutputPorts.size();
|
| for (size_t i = 0; i < fOutputPorts.size(); i++) {
|
| memcpy(rb_buffer.buffers[i], fOutChannel[i], nframes * sizeof(float));
|
| }
|
| if (ringbuffer_write_space(rb) >= sizeof(rb_buffer))
|
| {
|
| size_t written = ringbuffer_write(rb, (void*)&rb_buffer, sizeof(rb_buffer));
|
| }
|
| }
|
|
|
| // UI thread
|
| // ...
|
| static constexpr size_t scope_buffer_length = 48000; // One second by default
|
| float scope_buffer[16][scope_buffer_length]; // <- this is the buffer the UI can use
|
| size_t scope_buffer_sizeof = scope_buffer_length * sizeof(float);
|
| // ...
|
| while (size_t available = ringbuffer_read_space(rb))
|
| {
|
| if (available >= sizeof(rb_compute_buffers))
|
| {
|
| rb_compute_buffers recv;
|
| size_t read = ringbuffer_read(rb, (void*)&recv, sizeof(rb_compute_buffers));
|
| size_t nframes_sizeof = recv.nframes * sizeof(float);
|
| for (size_t i = 0; i < recv.channels; i++) {
|
| memmove(scope_buffer[i], &scope_buffer[i][recv.nframes], scope_buffer_sizeof - nframes_sizeof);
|
| memcpy(&scope_buffer[i][scope_buffer_length - recv.nframes], recv.buffers[i], nframes_sizeof);
|
| }
|
| }
|
| }
|
| // ...
|