Skip to content

Commit 766a570

Browse files
committed
Simplify play_file.py by using a single queue
This is simpler, but but it uses about 10% to 40% more CPU
1 parent dcc8e65 commit 766a570

File tree

1 file changed

+21
-44
lines changed

1 file changed

+21
-44
lines changed

examples/play_file.py

Lines changed: 21 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
parser = argparse.ArgumentParser(description=__doc__)
2424
parser.add_argument('filename', help='audio file to be played back')
2525
parser.add_argument(
26-
'-b', '--buffersize', type=int, default=10,
26+
'-b', '--buffersize', type=int, default=20,
2727
help='number of blocks used for buffering (default: %(default)s)')
2828
parser.add_argument('-c', '--clientname', default='file player',
2929
help='JACK client name')
@@ -33,8 +33,7 @@
3333
if args.buffersize < 1:
3434
parser.error('buffersize must be at least 1')
3535

36-
callback2disk = queue.Queue(maxsize=1)
37-
disk2callback = queue.Queue(maxsize=1)
36+
q = queue.Queue(maxsize=args.buffersize)
3837
event = threading.Event()
3938

4039

@@ -63,27 +62,20 @@ def stop_callback(msg=''):
6362

6463

6564
def process(frames):
66-
global callback_buffer, callback_counter
6765
if frames != blocksize:
6866
stop_callback('blocksize must not be changed, I quit!')
69-
if callback_counter == 0:
70-
try:
71-
callback2disk.put_nowait(callback_buffer)
72-
callback_buffer, callback_counter = disk2callback.get_nowait()
73-
except (queue.Full, queue.Empty):
74-
stop_callback('Buffer error: increase buffersize?')
75-
if callback_counter == 0: # Playback is finished
76-
stop_callback()
77-
idx = (args.buffersize - callback_counter) * blocksize
78-
block = callback_buffer[idx:idx + blocksize]
79-
for channel, port in zip(block.T, client.outports):
67+
try:
68+
data = q.get_nowait()
69+
except queue.Empty:
70+
stop_callback('Buffer is empty: increase buffersize?')
71+
if data is None:
72+
stop_callback() # Playback is finished
73+
for channel, port in zip(data.T, client.outports):
8074
port.get_array()[:] = channel
81-
callback_counter -= 1
8275

8376

8477
try:
8578
import jack
86-
import numpy as np
8779
import soundfile as sf
8880

8981
client = jack.Client(args.clientname)
@@ -94,28 +86,15 @@ def process(frames):
9486
client.set_process_callback(process)
9587

9688
with sf.SoundFile(args.filename) as f:
97-
block_generator = f.blocks(blocksize=blocksize, dtype='float32',
98-
always_2d=True, fill_value=0)
99-
100-
def fill_buffer(buf):
101-
nr = -1 # For the case that block_generator is already exhausted
102-
for nr, block in zip(range(args.buffersize), block_generator):
103-
idx = nr * blocksize
104-
buf[idx:idx+blocksize] = block
105-
return nr + 1 # Number of valid blocks, the rest is garbage
106-
107-
# Initialize first audio buffer to be played back
108-
buffer = np.empty([blocksize * args.buffersize, f.channels])
109-
valid_blocks = fill_buffer(buffer)
110-
disk2callback.put_nowait((buffer, valid_blocks))
111-
112-
# Initialize second buffer
113-
callback_buffer = np.empty([blocksize * args.buffersize, f.channels])
114-
callback_counter = 0
115-
11689
for ch in range(f.channels):
11790
client.outports.register('out_{0}'.format(ch + 1))
118-
91+
block_generator = f.blocks(blocksize=blocksize, dtype='float32',
92+
always_2d=True, fill_value=0)
93+
try:
94+
for data in block_generator:
95+
q.put_nowait(data)
96+
except queue.Full:
97+
pass
11998
with client:
12099
if not args.manual:
121100
target_ports = client.get_ports(
@@ -127,16 +106,14 @@ def fill_buffer(buf):
127106
else:
128107
for source, target in zip(client.outports, target_ports):
129108
source.connect(target)
130-
131109
timeout = blocksize * args.buffersize / samplerate
132-
while valid_blocks:
133-
buffer = callback2disk.get(timeout=timeout)
134-
valid_blocks = fill_buffer(buffer)
135-
disk2callback.put((buffer, valid_blocks), timeout=timeout)
136-
event.wait()
110+
for data in block_generator:
111+
q.put(data, timeout=timeout)
112+
q.put(None, timeout=timeout) # Signal end of file
113+
event.wait() # Wait until playback is finished
137114
except KeyboardInterrupt:
138115
parser.exit('\nInterrupted by user')
139-
except (queue.Empty, queue.Full):
116+
except (queue.Full):
140117
# A timeout occured, i.e. there was an error in the callback
141118
parser.exit(1)
142119
except Exception as e:

0 commit comments

Comments
 (0)