Baby Language Lab Scripts
A collection of data processing tools.
 All Classes Namespaces Files Functions Variables Pages
wav_parser.py
Go to the documentation of this file.
1 ## @package parsers.wav_parser
2 
3 import pyaudio
4 import wave
5 import logging
6 import traceback
7 
8 ## This class manipulates and plays WAV audio files.
9 # This class requires the PyAudio library.
10 class WavParser(object):
11  ## Constructor
12  # @param self
13  # @param filename (string) full path to a WAV file
14  def __init__(self, filename):
15  self.logger = logging.getLogger(__name__)
16  self.total_sec = -1
17 
18  #attempt to open the wav file and determine its length in seconds
19  try:
20  self.wav_in = wave.open(filename, 'rb')
21  except Exception as e:
22  logging.error("Unable to open WAV file. Exception: %s" % e)
23  traceback.print_exc()
24 
25  ## Returns a sound's length, in seconds.
26  # @param self
27  # @returns (float) The length of the sound in seconds, or zero if there was an error opening the WAV file.
28  def get_sound_len(self):
29  if self.total_sec < 0:
30  self.total_sec = self.wav_in.getnframes() / float(self.wav_in.getframerate())
31 
32  return self.total_sec
33 
34  ## Plays a segment's corresponding audio clip.
35  # Audio is played from (seg.start - context_len) to (seg.end + context_len).
36  # @param self
37  # @param seg (Segment) The Segment object for which to play a clip
38  # @param context_len (int=0) the padding length, in seconds, to be applied to both sides.
39  def play_seg(self, seg, context_len=0):
40  start = max(0, seg.start - context_len)
41  end = min(self.get_sound_len(), seg.end + context_len)
42 
43  self.play_clip(start, end)
44 
45  ## Plays an utterance's corresponding audio clip.
46  # Audio is played from (utter.start - context_len) to (utter.end + context_len).
47  # @param self
48  # @param utter (Utterance) The Utterance object for which to play a clip
49  # @param context_len (int=0) the padding length, in seconds, to be applied to both sides
50  # @param play_linked (boolean=False) If true, the entire Utterance chain will be played. Otherwise only a single utternace will be played.
51  def play_utter(self, utter, context_len=0, play_linked=False):
52  start_utter = utter
53  end_utter = utter
54 
55  if play_linked:
56  while start_utter.prev:
57  start_utter = start_utter.prev
58  while end_utter.next:
59  end_utter = end_utter.next
60 
61  start = max(0, start_utter.start - context_len)
62  end = min(end_utter.end + context_len, self.get_sound_len())
63 
64  self.play_clip(start, end)
65 
66  def extract_clip(self, start_time, end_time, filename):
67  #initialize the audio library
68  audio = pyaudio.PyAudio()
69  wav_out = wave.open(filename, 'wb')
70  wav_out.setnchannels(self.wav_in.getnchannels())
71  wav_out.setsampwidth(self.wav_in.getsampwidth())
72  wav_out.setframerate(self.wav_in.getframerate())
73 
74  #extract the chunk of the sound that we want to save
75  start_frame = int(start_time * self.wav_in.getframerate())
76  end_frame = int(end_time * self.wav_in.getframerate())
77  num_frames = end_frame - start_frame + 1
78 
79  self.wav_in.setpos(start_frame)
80  data = self.wav_in.readframes(num_frames)
81  wav_out.writeframes(data)
82  wav_out.close()
83  audio.terminate()
84 
85  ## Extracts a specified chunk of audio from the wav file and plays it through the default audio device.
86  # @param self
87  # @param start_time (float) absolute start time of the clip to play, in seconds
88  # @param end_time (float) absolute end time of the clip to play, in seconds
89  def play_clip(self, start_time, end_time):
90  self.logger.info("Playing clip: [%f, %f]\n" % (start_time, end_time))
91 
92  #initialize the audio library
93  audio = pyaudio.PyAudio()
94 
95  #extract the chunk of the sound that we want to play
96  start_frame = int(start_time * self.wav_in.getframerate())
97  end_frame = int(end_time * self.wav_in.getframerate())
98  num_frames = end_frame - start_frame + 1
99 
100  #construct and audio stream and write the sound chunk to it
101  stream = audio.open(format=audio.get_format_from_width(self.wav_in.getsampwidth()),
102  channels=self.wav_in.getnchannels(),
103  rate=self.wav_in.getframerate(),
104  output=True,
105  )
106  self.wav_in.setpos(start_frame)
107  data = self.wav_in.readframes(num_frames)
108  stream.write(data)
109 
110  #clean up
111  stream.stop_stream()
112  stream.close()
113  audio.terminate()
114 
115  ## Closes any files or other resources used by this parser.
116  # This should always be called after you're done with the parser!
117  # @param self
118  def close(self):
119  self.wav_in.close()