-
-
Save zeffii/5382324 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ''' | |
| 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