Skip to content

Instantly share code, notes, and snippets.

@zeffii
Forked from anonymous/wave_test3.py
Last active December 16, 2015 05:09
Show Gist options
  • Select an option

  • Save zeffii/5382324 to your computer and use it in GitHub Desktop.

Select an option

Save zeffii/5382324 to your computer and use it in GitHub Desktop.
'''
wave_test.py v 0.0.6
python 2.7 doesn't support 'with' on the wave module
original wave:
https://dl.dropboxusercontent.com/u/3397495/wav/we_must_build_upwards.wav
original label file, generated by audacity:
https://dl.dropboxusercontent.com/u/3397495/wav/wmbu_labels
example of eventual output (graphical representation):
https://dl.dropboxusercontent.com/u/3397495/wav/typer_demo_audio.png
restriction: markers/labels must not overlap, this code doesn't handle that.
'''
import wave
import struct
import collections
filename = "we_must_build_upwards.wav"
info_filename = 'wmbu_labels'
def get_params_object(wave_params):
'''returns a namedtuple object to allow attribute access'''
wparams = 'nchannels sampwidth frate nframes comptype compname'
param_dict = dict(zip(wparams.split(), wave_params))
param_object = collections.namedtuple('file_params', wparams)
return param_object(**param_dict)
def get_sample_markers(info_filename):
'''read info file'''
def clean(i):
strs = i.split('\t')[:2]
return [float(i) for i in strs]
with open(info_filename) as f:
sample_markers = [clean(i) for i in f.readlines()]
return sample_markers
def get_duration_from_fparams():
duration_seconds = float(f_params.nframes)/float(f_params.frate)
print(f_params.frate, f_params.nframes, duration_seconds)
return duration_seconds
def generate_silence(duration):
'''
input: duration in seconds,
output: wave.struct binary string of the length in frames as a
function of duration.
particulars:
forced to be divisible by nchannels assuming here nchannels is 2
which is fine for my needs
'''
nchannels = f_params.nchannels
dframes = int(f_params.frate * nchannels * duration)
silent_frames = dframes if dframes % nchannels == 0 else dframes+1
return "".join((wave.struct.pack('h', 0) for i in range(silent_frames)))
def frame_from_time(mark):
return int(mark * f_params.frate)
def frames_from_marks(marks):
return [frame_from_time(mark) for mark in marks]
def get_slice_details(marks):
start_frame, end_frame = frames_from_marks(marks)
n = end_frame - start_frame
print(start_frame, end_frame, n)
return start_frame, end_frame, n
def insert_silence(duration):
'''this also moves the wf.tell() indicator forward'''
silent_data = generate_silence(duration)
wf.writeframes(silent_data)
sample_markers = get_sample_markers(info_filename)
'''read original file'''
f = wave.open(filename)
wave_params = f.getparams()
f_params = get_params_object(wave_params)
duration_seconds = get_duration_from_fparams()
'''open destination for writing'''
wf = wave.open('destination.wav', 'wb')
wf.setparams(wave_params) # for stretched destination wave, modfiy nframes
# check first sample marker, does it begin at 0? if not
# generate silence from 0 to start of first marker
first_mark_start = sample_markers[0][0]
if not first_mark_start == 0:
marks = (0.0, first_mark_start)
_s, _e, n = get_slice_details(marks)
silence_duration = float(n) / f_params.frate
insert_silence(silence_duration)
for idx, (mark_start, mark_end) in enumerate(sample_markers):
marks = (mark_start, mark_end)
start_frame, end_frame, n = get_slice_details(marks)
f.setpos(start_frame)
data = f.readframes(n)
wf.writeframes(data)
'''get the difference between end_frame of this marker and start_frame
for the next marker, then generate silence for that duration. this skips
the wf position to the next correct frame.'''
if idx < len(sample_markers)-1:
next_mark_start, _ = sample_markers[idx+1]
duration_till_next_marker = next_mark_start - mark_end
if duration_till_next_marker > 0.0:
insert_silence(duration_till_next_marker)
# deal with last label/marker, till end of sample
last_mark_end = sample_markers[-1][1]
final_slice = duration_seconds - last_mark_end
if not final_slice == 0:
insert_silence(final_slice)
wf.close()
f.close()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment