@@ -31,6 +31,7 @@ def __init__(self, device=None, sample_rate=16000, channels=1, format="FLOAT_LE"
3131 self .format = format
3232 self ._is_started = False
3333 self ._played_data = []
34+ self ._mixer = FakeMixer ()
3435
3536 def start (self ):
3637 self ._is_started = True
@@ -42,6 +43,9 @@ def play(self, data, block_on_queue=False):
4243 if self ._is_started :
4344 self ._played_data .append (data )
4445
46+ def set_volume (self , volume : int ):
47+ self ._mixer .setvolume (volume )
48+
4549 def is_started (self ):
4650 return self ._is_started
4751
@@ -52,6 +56,16 @@ def __exit__(self, exc_type, exc_val, exc_tb):
5256 self .stop ()
5357 return False
5458
59+ class FakeMixer :
60+ def __init__ (self ):
61+ self ._volume = 100
62+
63+ def setvolume (self , volume : int ):
64+ self ._volume = max (0 , min (100 , volume ))
65+
66+ def getvolume (self ):
67+ return [self ._volume ]
68+
5569 # Patch Speaker in the wave_generator module
5670 monkeypatch .setattr ("arduino.app_bricks.wave_generator.wave_generator.Speaker" , FakeSpeaker )
5771 return FakeSpeaker
@@ -67,7 +81,6 @@ def test_wave_generator_initialization_default(mock_speaker):
6781 assert wave_gen .attack == 0.01
6882 assert wave_gen .release == 0.03
6983 assert wave_gen .glide == 0.02
70- assert wave_gen .master_volume == 0.8
7184 assert wave_gen ._speaker is not None
7285 assert wave_gen ._speaker .sample_rate == 16000
7386
@@ -181,21 +194,20 @@ def test_set_wave_type(mock_speaker):
181194
182195
183196def test_set_volume (mock_speaker ):
184- """Test setting master volume."""
197+ """Test setting hardware volume."""
185198 wave_gen = WaveGenerator ()
186199
187- wave_gen .set_volume (0.7 )
188- assert wave_gen .master_volume == 0.7
200+ wave_gen .set_volume (70 )
201+ assert wave_gen ._speaker . _mixer . _volume == 70
189202
190- wave_gen .set_volume (1.0 )
191- assert wave_gen .master_volume == 1.0
203+ wave_gen .set_volume (100 )
204+ assert wave_gen ._speaker . _mixer . _volume == 100
192205
193- # Test out of range (should be clamped)
194- wave_gen .set_volume (1.5 )
195- assert wave_gen .master_volume == 1.0
206+ # Test get_volume
207+ assert wave_gen .get_volume () == 100
196208
197- wave_gen .set_volume (- 0.2 )
198- assert wave_gen .master_volume == 0.0
209+ wave_gen .set_volume (50 )
210+ assert wave_gen .get_volume () == 50
199211
200212
201213def test_set_envelope_params (mock_speaker ):
@@ -229,16 +241,16 @@ def test_get_state(mock_speaker):
229241 wave_gen .set_frequency (440.0 )
230242 wave_gen .set_amplitude (0.8 )
231243 wave_gen .set_wave_type ("square" )
232- wave_gen .set_volume (0.9 )
244+ wave_gen .set_volume (90 )
233245
234246 state = wave_gen .get_state ()
235247
236248 assert "frequency" in state
237249 assert "amplitude" in state
238250 assert "wave_type" in state
239251 assert state ["wave_type" ] == "square"
240- assert "master_volume " in state
241- assert state ["master_volume " ] == 0.9
252+ assert "volume " in state
253+ assert state ["volume " ] == 90
242254 assert "phase" in state
243255
244256
@@ -247,7 +259,7 @@ def test_generate_block_sine(mock_speaker):
247259 wave_gen = WaveGenerator (sample_rate = 16000 )
248260
249261 # Generate a block
250- block = wave_gen ._generate_block (freq_target = 440.0 , amp_target = 0.5 , wave_type = "sine" , master_volume = 1.0 )
262+ block = wave_gen ._generate_block (freq_target = 440.0 , amp_target = 0.5 , wave_type = "sine" )
251263
252264 # Check block properties
253265 assert isinstance (block , np .ndarray )
@@ -262,7 +274,7 @@ def test_generate_block_square(mock_speaker):
262274 """Test generating a square wave block."""
263275 wave_gen = WaveGenerator (sample_rate = 16000 )
264276
265- block = wave_gen ._generate_block (freq_target = 440.0 , amp_target = 0.5 , wave_type = "square" , master_volume = 1.0 )
277+ block = wave_gen ._generate_block (freq_target = 440.0 , amp_target = 0.5 , wave_type = "square" )
266278
267279 assert isinstance (block , np .ndarray )
268280 # Square wave has envelope applied, so check amplitude range
@@ -273,7 +285,7 @@ def test_generate_block_sawtooth(mock_speaker):
273285 """Test generating a sawtooth wave block."""
274286 wave_gen = WaveGenerator (sample_rate = 16000 )
275287
276- _ = wave_gen ._generate_block (freq_target = 440.0 , amp_target = 0.5 , wave_type = "sawtooth" , master_volume = 1.0 )
288+ _ = wave_gen ._generate_block (freq_target = 440.0 , amp_target = 0.5 , wave_type = "sawtooth" )
277289
278290 # Verify internal state updated correctly
279291 assert wave_gen ._buf_samples is not None
@@ -283,7 +295,7 @@ def test_generate_block_triangle(mock_speaker):
283295 """Test generating a triangle wave block."""
284296 wave_gen = WaveGenerator (sample_rate = 16000 )
285297
286- _ = wave_gen ._generate_block (freq_target = 440.0 , amp_target = 0.5 , wave_type = "triangle" , master_volume = 1.0 )
298+ _ = wave_gen ._generate_block (freq_target = 440.0 , amp_target = 0.5 , wave_type = "triangle" )
287299
288300 # Verify internal state updated correctly
289301 assert wave_gen ._buf_samples is not None
@@ -297,7 +309,7 @@ def test_frequency_glide(mock_speaker):
297309 wave_gen ._current_freq = 220.0
298310
299311 # Generate block with new target frequency
300- _ = wave_gen ._generate_block (freq_target = 440.0 , amp_target = 0.5 , wave_type = "sine" , master_volume = 1.0 )
312+ _ = wave_gen ._generate_block (freq_target = 440.0 , amp_target = 0.5 , wave_type = "sine" )
301313
302314 # Current frequency should have moved towards target but not reached it
303315 # (because glide time is longer than block duration)
@@ -313,35 +325,13 @@ def test_amplitude_envelope(mock_speaker):
313325 wave_gen ._current_amp = 0.0
314326
315327 # Generate block with new target amplitude
316- _ = wave_gen ._generate_block (freq_target = 440.0 , amp_target = 0.8 , wave_type = "sine" , master_volume = 1.0 )
328+ _ = wave_gen ._generate_block (freq_target = 440.0 , amp_target = 0.8 , wave_type = "sine" )
317329
318330 # Current amplitude should have moved towards target but not reached it
319331 assert wave_gen ._current_amp > 0.0
320332 assert wave_gen ._current_amp < 0.8
321333
322334
323- def test_master_volume_scaling (mock_speaker ):
324- """Test master volume affects output amplitude."""
325- # Create two separate generators to avoid state interference
326- wave_gen_full = WaveGenerator (sample_rate = 16000 )
327- wave_gen_full ._current_amp = 1.0
328- wave_gen_full ._current_freq = 440.0
329-
330- block_full = wave_gen_full ._generate_block (freq_target = 440.0 , amp_target = 1.0 , wave_type = "sine" , master_volume = 1.0 )
331-
332- wave_gen_half = WaveGenerator (sample_rate = 16000 )
333- wave_gen_half ._current_amp = 1.0
334- wave_gen_half ._current_freq = 440.0
335-
336- block_half = wave_gen_half ._generate_block (freq_target = 440.0 , amp_target = 1.0 , wave_type = "sine" , master_volume = 0.5 )
337-
338- # Half volume block should have approximately half the amplitude
339- max_full = np .max (np .abs (block_full ))
340- max_half = np .max (np .abs (block_half ))
341- assert max_half < max_full
342- assert 0.4 < (max_half / max_full ) < 0.6 # Should be roughly 0.5
343-
344-
345335def test_producer_loop_generates_audio (app_instance , mock_speaker ):
346336 """Test that producer loop generates and plays audio."""
347337 wave_gen = WaveGenerator ()
@@ -397,7 +387,7 @@ def test_buffer_preallocation(mock_speaker):
397387 wave_gen = WaveGenerator (sample_rate = 16000 )
398388
399389 # Generate first block
400- block1 = wave_gen ._generate_block (freq_target = 440.0 , amp_target = 0.5 , wave_type = "sine" , master_volume = 1.0 )
390+ block1 = wave_gen ._generate_block (freq_target = 440.0 , amp_target = 0.5 , wave_type = "sine" )
401391
402392 # Check buffers are allocated
403393 assert wave_gen ._buf_N > 0
@@ -407,7 +397,7 @@ def test_buffer_preallocation(mock_speaker):
407397 assert wave_gen ._buf_samples is not None
408398
409399 # Generate second block
410- _ = wave_gen ._generate_block (freq_target = 440.0 , amp_target = 0.5 , wave_type = "sine" , master_volume = 1.0 )
400+ _ = wave_gen ._generate_block (freq_target = 440.0 , amp_target = 0.5 , wave_type = "sine" )
411401
412402 # Buffers should still be the same size (reused)
413403 assert wave_gen ._buf_N == len (block1 )
@@ -421,7 +411,7 @@ def test_phase_continuity(mock_speaker):
421411
422412 # Generate multiple blocks
423413 for _ in range (10 ):
424- wave_gen ._generate_block (freq_target = 440.0 , amp_target = 0.5 , wave_type = "sine" , master_volume = 1.0 )
414+ wave_gen ._generate_block (freq_target = 440.0 , amp_target = 0.5 , wave_type = "sine" )
425415
426416 # Phase should have advanced
427417 assert wave_gen ._phase != initial_phase
@@ -433,7 +423,7 @@ def test_zero_amplitude_produces_silence(mock_speaker):
433423 """Test that zero amplitude produces silent output."""
434424 wave_gen = WaveGenerator (sample_rate = 16000 )
435425
436- block = wave_gen ._generate_block (freq_target = 440.0 , amp_target = 0.0 , wave_type = "sine" , master_volume = 1.0 )
426+ block = wave_gen ._generate_block (freq_target = 440.0 , amp_target = 0.0 , wave_type = "sine" )
437427
438428 # All samples should be zero or very close to zero
439429 assert np .allclose (block , 0.0 , atol = 1e-6 )
0 commit comments