Beispiel #1
0
    def open_stream(self, device):
        self.log_supported_input_formats(device)

        self.logger.info("Opening the stream for device '%s'", device['name'])

        # by default we open the device stream with all the channels
        # (interleaved in the data buffer)
        stream = rtmixer.Recorder(
            device=device['index'],
            channels=device['max_input_channels'],
            blocksize=FRAMES_PER_BUFFER,
            # latency=latency,
            samplerate=SAMPLING_RATE)

        sampleSize = 4  # the sample size in bytes (float32)
        nchannels_max = device['max_input_channels']  # the number of channels that we record
        elementSize = nchannels_max * sampleSize

        # arbitrary size to avoid overflows without using too much memory
        ringbufferSeconds = 3.

        # The number of elements in the buffer (must be a power of 2)
        ringbufferSize = 2**int(math.log2(ringbufferSeconds * SAMPLING_RATE))

        ringBuffer = rtmixer.RingBuffer(elementSize, ringbufferSize)

        # action can be used to read the count of input overflows
        action = stream.record_ringbuffer(ringBuffer)

        lat_ms = 1000 * stream.latency
        self.logger.info("Device claims %d ms latency", lat_ms)

        return (stream, ringBuffer, action, nchannels_max)
stream = rtmixer.MixerAndRecorder(device=device,
                                  channels=channels,
                                  blocksize=0,
                                  latency=latency,
                                  samplerate=samplerate)

print('  input latency:', stream.latency[0])
print(' output latency:', stream.latency[1])
print('            sum:', sum(stream.latency))
print('       DSP size:', dsp_size)

samplesize = 4
assert stream.dtype == ('float32', 'float32')
assert stream.samplesize == (samplesize, samplesize)

q_in = rtmixer.RingBuffer(samplesize * channels, buffersize_in)
q_out = rtmixer.RingBuffer(samplesize * channels, buffersize_out)

# Pre-fill output queue:
q_out.write(np.zeros((pre_filling, channels), dtype='float32'))

try:
    with stream:
        assert dsp_buffer.dtype == 'float32'
        assert dsp_buffer.flags.c_contiguous
        record_action = stream.record_ringbuffer(q_in)
        play_action = stream.play_ringbuffer(q_out)
        print('=== Start Processing')
        while True:
            while (q_in.read_available < dsp_size
                   and record_action in stream.actions):
Beispiel #3
0
 def __init__(self, elementsize, size):
     # Python 2.x doesn't have math.log2(), and it needs int():
     size = 2**int(math.ceil(math.log(size, 2)))
     self.ringbuffer = rtmixer.RingBuffer(elementsize, size)
     self.buffer = bytearray()
     self.action = None
Beispiel #4
0
fig, ax = plt.subplots()
lines = ax.plot(plotdata)
if channels > 1:
    ax.legend(['channel {}'.format(c + 1) for c in range(channels)],
              loc='lower left',
              ncol=channels)
ax.axis((0, len(plotdata), -1, 1))
ax.set_yticks([0])
ax.yaxis.grid(True)
ax.tick_params(bottom='off',
               top='off',
               labelbottom='off',
               right='off',
               left='off',
               labelleft='off')
fig.tight_layout(pad=0)

stream = rtmixer.Recorder(device=device,
                          channels=channels,
                          blocksize=blocksize,
                          latency=latency,
                          samplerate=samplerate)
ani = FuncAnimation(fig, update_plot, interval=interval, blit=True)
with stream:
    elementsize = channels * stream.samplesize
    q = rtmixer.RingBuffer(elementsize, stepsize * qsize)
    action = stream.record_ringbuffer(q)
    plt.show()
# TODO: check for ringbuffer errors?
print('Input overflows:', action.stats.input_overflows)
Beispiel #5
0
samplerate = 48000
safety = 0.001  # Increase if Python interpreter is slow

rb_size = 2**math.ceil(math.log2(delay * samplerate))

stream = rtmixer.MixerAndRecorder(
    channels=channels, blocksize=blocksize, samplerate=samplerate,
    latency=latency)
with stream:
    samplesize = 4
    assert {samplesize} == set(stream.samplesize)
    print('  input latency:', stream.latency[0])
    print(' output latency:', stream.latency[1])
    print('            sum:', sum(stream.latency))
    print('requested delay:', delay)
    rb = rtmixer.RingBuffer(samplesize * channels, rb_size)
    start = stream.time + safety
    record_action = stream.record_ringbuffer(rb, start=start,
                                             allow_belated=False)
    play_action = stream.play_ringbuffer(rb, start=start + delay,
                                         allow_belated=False)
    # Dummy recording to wait until "start" has passed:
    stream.wait(stream.record_buffer(b'', channels=1, start=start))
    if record_action not in stream.actions:
        if record_action.actual_time == 0:
            raise RuntimeError('Increase "safety"')
        else:
            # TODO: could there be another error?
            raise RuntimeError('Ring buffer overflow (increase "delay"?)')
    # Dummy playback to wait until "start + delay" has passed:
    stream.wait(stream.play_buffer(b'', channels=1, start=start + delay))
Beispiel #6
0
def print_action(action):
    print('            type:', next(
        k for k, v in vars(rtmixer).items() if v == action.type))
    print('  requested time:', action.requested_time)
    print('     actual time:', action.actual_time)
    print('    total frames:', action.total_frames)
    print('     done frames:', action.done_frames)


stream = rtmixer.Recorder(
    device=device, channels=channels, blocksize=blocksize,
    latency=latency, samplerate=samplerate)

buffer = bytearray(10 * int(stream.samplerate) * stream.samplesize)
ringbuffer = rtmixer.RingBuffer(stream.samplesize * channels, 128)

print('checking stats before opening stream:')
print_stats(stream)
assert stream.stats.blocks == 0
assert stream.stats.input_overflows == 0

with stream:
    print('waiting a few seconds ...')
    sd.sleep(3 * 1000)
    print('checking stats:')
    action = stream.fetch_and_reset_stats()
    stream.wait(action)
    print_stats(action)
    print('starting recording to buffer ...')
    action = stream.record_buffer(buffer, channels=channels)
Beispiel #7
0
import sounddevice as sd
import soundfile as sf

filename = sys.argv[1]
playback_blocksize = None
latency = None
reading_blocksize = 1024  # (reading_blocksize * rb_size) has to be power of 2
rb_size = 16  # Number of blocks

with sf.SoundFile(filename) as f:
    with rtmixer.Mixer(channels=f.channels,
                       blocksize=playback_blocksize,
                       samplerate=f.samplerate,
                       latency=latency) as m:
        elementsize = f.channels * m.samplesize
        rb = rtmixer.RingBuffer(elementsize, reading_blocksize * rb_size)
        # Pre-fill ringbuffer:
        _, buf, _ = rb.get_write_buffers(reading_blocksize * rb_size)
        written = f.buffer_read_into(buf, dtype='float32')
        rb.advance_write_index(written)
        action = m.play_ringbuffer(rb)
        while True:
            while rb.write_available < reading_blocksize:
                if action not in m.actions:
                    break
                sd.sleep(int(1000 * reading_blocksize / f.samplerate))
            if action not in m.actions:
                break
            size, buf1, buf2 = rb.get_write_buffers(reading_blocksize)
            assert not buf2
            written = f.buffer_read_into(buf1, dtype='float32')