I have a problem in how to play waveform data from a high-latency device (think disk file, network socket). I cannot call any blocking function from the realtime thread, so I cannot fetch data directly. I guess some kind of FIFO should work. The writing to the FIFO must block when the FIFO is full, but must not when testing for emptyness. The JACK ringbuffer does not block at all, so the file I/O thread will then need to busywait. What is the canonical solution to this problem.
Recording works easier, because I can let the realtime thread signal the I/O thread when a new data block is ready. Reversing that mechanism would not work, because
1) this requires blocking the realtime thread
2) the I/O thread is to fast, so it needs to be paused anyways.
Pump audio data from file into JACK
Moderators: MattKingUSA, khz
- raboof
- Established Member
- Posts: 1855
- Joined: Tue Apr 08, 2008 11:58 am
- Location: Deventer, NL
- Has thanked: 50 times
- Been thanked: 74 times
- Contact:
Re: Pump audio data from file into JACK
Good question, looking forward to the answers.f00bar wrote:I have a problem in how to play waveform data from a high-latency device (think disk file, network socket). I cannot call any blocking function from the realtime thread, so I cannot fetch data directly. I guess some kind of FIFO should work. The writing to the FIFO must block when the FIFO is full, but must not when testing for emptyness. The JACK ringbuffer does not block at all, so the file I/O thread will then need to busywait. What is the canonical solution to this problem.
Not really answering your question, but of course you could simply read the whole waveform into memory before starting playback.
That's certainly easy, but of course might not work in your situation - it might introduce unacceptable latency while loading the waveform, or use an unacceptable amount of memory.
Re: Pump audio data from file into JACK
Dump it into memory first works for small amounts of data. That is what Hydrogen does, and I used that approach in Anja. But now I want to play longer files and then I need a streaming solution.raboof wrote:Good question, looking forward to the answers.f00bar wrote:I have a problem in how to play waveform data from a high-latency device (think disk file, network socket). I cannot call any blocking function from the realtime thread, so I cannot fetch data directly. I guess some kind of FIFO should work. The writing to the FIFO must block when the FIFO is full, but must not when testing for emptyness. The JACK ringbuffer does not block at all, so the file I/O thread will then need to busywait. What is the canonical solution to this problem.
Not really answering your question, but of course you could simply read the whole waveform into memory before starting playback.
That's certainly easy, but of course might not work in your situation - it might introduce unacceptable latency while loading the waveform, or use an unacceptable amount of memory.
-
- Established Member
- Posts: 2347
- Joined: Mon Jul 01, 2013 8:13 am
- Has thanked: 9 times
- Been thanked: 466 times
Re: Pump audio data from file into JACK
Using 2 fixed size buffers, big enough, and switch them between disk and realtime thread.
To say, read data in the first buffer, hand it over to the rt-thread. As soon the rt-thread starts to read the buffer, signal the disk thread to fill the other buffer. Switch them, when the rt-thread have reach the end of the first buffer, . . .
Here is how I use it for record, but the same approve, just in turn, could work for play.
https://github.com/brummer10/screcord.l ... record1.cc
To say, read data in the first buffer, hand it over to the rt-thread. As soon the rt-thread starts to read the buffer, signal the disk thread to fill the other buffer. Switch them, when the rt-thread have reach the end of the first buffer, . . .
Here is how I use it for record, but the same approve, just in turn, could work for play.
https://github.com/brummer10/screcord.l ... record1.cc
On the road again.
Re: Pump audio data from file into JACK
The problem is how to determine the current buffer. I havetramp wrote:Using 2 fixed size buffers, big enough, and switch them between disk and realtime thread.
To say, read data in the first buffer, hand it over to the rt-thread. As soon the rt-thread starts to read the buffer, signal the disk thread to fill the other buffer. Switch them, when the rt-thread have reach the end of the first buffer, . . .
Here is how I use it for record, but the same approve, just in turn, could work for play.
https://github.com/brummer10/screcord.l ... record1.cc
Code: Select all
void Jasmine::Impl::writeByChannel(const float* data,unsigned int n_frames
,unsigned int n_channels_in,unsigned int channel_out_first)
{
auto buffer=m_buffers_in[0].get();
buffer->readyWait();
printf("Writing to %p\n",buffer);
buffer->writeByChannel(data,n_frames,n_channels_in,channel_out_first);
}
inline int Jasmine::Impl::dataProcess(jack_nframes_t N) noexcept
{
// Write data to output port
{
auto buffer_in_front=m_buffers_in[1].get();
auto ports_out_begin=m_ports_out.data();
auto ports_out_end=ports_out_begin + m_ports_out.size();
auto ch=0;
while( ports_out_begin!=ports_out_end )
{
float* buffer_out=static_cast<float*>
(jack_port_get_buffer(*ports_out_begin,N));
buffer_in_front->read(buffer_out,N,ch);
++ch;
++ports_out_begin;
}
buffer_in_front->frameOffsetAdvance(N);
if(buffer_in_front->done())
{
std::swap(m_buffers_in[0],m_buffers_in[1]);
m_buffers_in[1].get()->readySet();
}
}
return 0;
}
Code: Select all
Writing to 0x21eaef0
Writing to 0x21eaef0
Writing to 0x21eae60
Writing to 0x21eae60
Writing to 0x21eaef0
Writing to 0x21eae60
Code: Select all
Writing to 0x21eaef0
Writing to 0x21eae60
Writing to 0x21eaef0
Writing to 0x21eae60
Writing to 0x21eaef0
Writing to 0x21eae60
-
- Established Member
- Posts: 2347
- Joined: Mon Jul 01, 2013 8:13 am
- Has thanked: 9 times
- Been thanked: 466 times
Re: Pump audio data from file into JACK
What I mean is, switch the buffer and signal the disc thread to fill the second buffer, when the rt-thread start to read the first buffer, not when it's finished. Choose the buffer size big enough to have a couple of jack-frame sizes in it, to give the disc thread more time to fill the buffer.
When you switch the buffer in the rt-thread, you could assume, that it is ready, as the disc thread fill a big chunk of data faster (at once) then the jack thread needs to play them.
This introduced a latency (playback wont start immediately when you press start), but, for playback files, that shouldn't matter.
When you switch the buffer in the rt-thread, you could assume, that it is ready, as the disc thread fill a big chunk of data faster (at once) then the jack thread needs to play them.
This introduced a latency (playback wont start immediately when you press start), but, for playback files, that shouldn't matter.
On the road again.
Re: Pump audio data from file into JACK
Swapping and signaling before data outut seems to worktramp wrote:What I mean is, switch the buffer and signal the disc thread to fill the second buffer, when the rt-thread start to read the first buffer, not when it's finished. Choose the buffer size big enough to have a couple of jack-frame sizes in it, to give the disc thread more time to fill the buffer.
When you switch the buffer in the rt-thread, you could assume, that it is ready, as the disc thread fill a big chunk of data faster (at once) then the jack thread needs to play them.
This introduced a latency (playback wont start immediately when you press start), but, for playback files, that shouldn't matter.