88from typing import Iterable
99import numpy as np
1010import time
11+ from pathlib import Path
1112
1213from .generator import WaveSamplesBuilder
1314from .effects import *
@@ -411,6 +412,27 @@ def play_abc(self, abc_string: str, volume: float = None) -> Iterable[tuple[byte
411412 data = self ._apply_sound_effects (data , frequency )
412413 yield (self ._to_bytes (data ), duration )
413414
415+ def play_wav (self , wav_file : str ) -> tuple [bytes , float ]:
416+ """
417+ Play a WAV audio data block.
418+ Args:
419+ wav_file (str): The WAV audio file path.
420+ Returns:
421+ tuple[bytes, float]: The audio block of the WAV file (float32) and its duration in seconds.
422+ """
423+ import wave
424+
425+ file_path = Path (wav_file )
426+ if not file_path .exists () or not file_path .is_file ():
427+ raise FileNotFoundError (f"WAV file not found: { wav_file } " )
428+
429+ with wave .open (wav_file , "rb" ) as wav :
430+ # Read all frames (raw PCM data)
431+ duration = wav .getnframes () / wav .getframerate ()
432+ return (wav .readframes (wav .getnframes ()), duration )
433+
434+ return (None , None )
435+
414436
415437@brick
416438class SoundGenerator (SoundGeneratorStreamer ):
@@ -482,7 +504,7 @@ def set_effects(self, effects: list):
482504 """
483505 super ().set_effects (effects )
484506
485- def play_polyphonic (self , notes : list [list [tuple [str , float ]]], as_tone : bool = False , volume : float = None , wait_completion : bool = False ):
507+ def play_polyphonic (self , notes : list [list [tuple [str , float ]]], as_tone : bool = False , volume : float = None , block : bool = False ):
486508 """
487509 Play multiple sequences of musical notes simultaneously (poliphony).
488510 It is possible to play multi track music by providing a list of sequences,
@@ -492,53 +514,66 @@ def play_polyphonic(self, notes: list[list[tuple[str, float]]], as_tone: bool =
492514 notes (list[list[tuple[str, float]]]): List of sequences, each sequence is a list of tuples (note, duration).
493515 as_tone (bool): If True, play as tones, considering duration in seconds
494516 volume (float, optional): Volume level (0.0 to 1.0). If None, uses master volume.
495- wait_completion (bool): If True, block until the entire sequence has been played.
517+ block (bool): If True, block until the entire sequence has been played.
496518 """
497519 blk , duration = super ().play_polyphonic (notes , as_tone , volume )
498520 self ._output_device .play (blk , block_on_queue = False )
499- if wait_completion and duration > 0.0 :
521+ if block and duration > 0.0 :
500522 time .sleep (duration )
501523
502- def play_chord (self , notes : list [str ], note_duration : float | str = 1 / 4 , volume : float = None ):
524+ def play_chord (self , notes : list [str ], note_duration : float | str = 1 / 4 , volume : float = None , block : bool = False ):
503525 """
504526 Play a chord consisting of multiple musical notes simultaneously for a specified duration and volume.
505527 Args:
506528 notes (list[str]): List of musical notes to play (e.g., ['A4', 'C#5', 'E5']).
507529 note_duration (float | str): Duration of the chord as a float (like 1/4, 1/8) or a symbol ('W', 'H', 'Q', etc.).
508530 volume (float, optional): Volume level (0.0 to 1.0). If None, uses master volume.
531+ block (bool): If True, block until the entire chord has been played.
509532 """
510533 blk = super ().play_chord (notes , note_duration , volume )
511534 self ._output_device .play (blk , block_on_queue = False )
535+ if block :
536+ duration = self ._note_duration (note_duration )
537+ if duration > 0.0 :
538+ time .sleep (duration )
512539
513- def play (self , note : str , note_duration : float | str = 1 / 4 , volume : float = None ):
540+ def play (self , note : str , note_duration : float | str = 1 / 4 , volume : float = None , block : bool = False ):
514541 """
515542 Play a musical note for a specified duration and volume.
516543 Args:
517544 note (str): The musical note to play (e.g., 'A4', 'C#5', 'REST').
518545 note_duration (float | str): Duration of the note as a float (like 1/4, 1/8) or a symbol ('W', 'H', 'Q', etc.).
519546 volume (float, optional): Volume level (0.0 to 1.0). If None, uses master volume.
547+ block (bool): If True, block until the entire note has been played.
520548 """
521549 data = super ().play (note , note_duration , volume )
522550 self ._output_device .play (data , block_on_queue = False )
551+ if block :
552+ duration = self ._note_duration (note_duration )
553+ if duration > 0.0 :
554+ time .sleep (duration )
523555
524- def play_tone (self , note : str , duration : float = 0.25 , volume : float = None ):
556+ def play_tone (self , note : str , duration : float = 0.25 , volume : float = None , block : bool = False ):
525557 """
526558 Play a musical note for a specified duration and volume.
527559 Args:
528560 note (str): The musical note to play (e.g., 'A4', 'C#5', 'REST').
529561 duration (float): Duration of the note as a float in seconds.
530562 volume (float, optional): Volume level (0.0 to 1.0). If None, uses master volume.
563+ block (bool): If True, block until the entire note has been played.
531564 """
532565 data = super ().play_tone (note , duration , volume )
533566 self ._output_device .play (data , block_on_queue = False )
567+ if block and duration > 0.0 :
568+ time .sleep (duration )
534569
535- def play_abc (self , abc_string : str , volume : float = None , wait_completion : bool = False ):
570+ def play_abc (self , abc_string : str , volume : float = None , block : bool = False ):
536571 """
537572 Play a sequence of musical notes defined in ABC notation.
538573 Args:
539574 abc_string (str): ABC notation string defining the sequence of notes.
540575 volume (float, optional): Volume level (0.0 to 1.0). If None, uses master volume.
541- wait_completion (bool): If True, block until the entire sequence has been played.
576+ block (bool): If True, block until the entire sequence has been played.
542577 """
543578 if not abc_string or abc_string .strip () == "" :
544579 return
@@ -547,9 +582,15 @@ def play_abc(self, abc_string: str, volume: float = None, wait_completion: bool
547582 for data , duration in player :
548583 self ._output_device .play (data , block_on_queue = True )
549584 overall_duration += duration
550- if wait_completion :
585+ if block :
551586 time .sleep (overall_duration )
552587
588+ def play_wav (self , wav_file : str , volume : float = None , block : bool = False ):
589+ to_play , duration = super ().play_wav (wav_file )
590+ self ._output_device .play (to_play , block_on_queue = False )
591+ if block and duration > 0.0 :
592+ time .sleep (duration )
593+
553594 def clear_playback_queue (self ):
554595 """
555596 Clear the playback queue of the output device.
0 commit comments