diff options
| author | yo mama <pepper@scannerjammer.com> | 2015-06-19 16:24:27 -0400 |
|---|---|---|
| committer | yo mama <pepper@scannerjammer.com> | 2015-06-19 16:24:27 -0400 |
| commit | 8adfb3bd99b4dcff2459756af090a640fd7a4b4a (patch) | |
| tree | c1e6adddda335f4d36a98039ccc5ac867ae7296d /pysoundtouch/README.md | |
clone
Diffstat (limited to 'pysoundtouch/README.md')
| -rw-r--r-- | pysoundtouch/README.md | 240 |
1 files changed, 240 insertions, 0 deletions
diff --git a/pysoundtouch/README.md b/pysoundtouch/README.md new file mode 100644 index 0000000..a63e2a6 --- /dev/null +++ b/pysoundtouch/README.md @@ -0,0 +1,240 @@ +pysoundtouch +============ + +Python Wrapper for the SoundTouch Library + +SoundTouch is a library for changing the pitch and tempo of audio +files and detecting beat rates. See the website at +http://www.surina.net/soundtouch/ + +This module exposes the pitch shifting and beat detection algorithms +in SoundTouch to Python. + +Installation +------------ + +First compile and install SoundTouch using integer samples. + +To compile on Linux and MacOS: + +You may need to get autoconf and libtool. + +``` +./bootstap +./configure --enable-integer-samples CXXFLAGS="-fPIC" +make +sudo make install +``` + +Then, run setup.py + +``` +sudo python setup.py install +``` + +Finally, check that you can import soundtouch + +``` +>>> import soundtouch +>>> soundtouch.__version__ +'1.4.0' +``` + +Simple Examples +--------------- + +To use the library directly, audio must already be in an uncompressed, 2-byte-per-sample format. For all other audio files, see the AudioReader Tool and Shifter Tool sections below. + +Detecting the BPM of a .WAV file: + +``` +import wave +# Open a .WAV file +wf = wave.open(FILEPATH) + +# Create the BPMDetect object +bd = soundtouch.BPMDetect(wf.getframerate(), wf.getnchannels()) + +# Feed samples from the file into BPMDetect +while True: + buf = wf.readframes(4000) + if not buf: + break + + bd.put_samples(buf) + +# Clean up +wf.close() +print bd.get_bpm() +``` + +Shifting the pitch of a .WAV file: + +``` +import wave +# Open a .WAV file +wf = wave.open(FILEPATH) + +# Create the SoundTouch object +st = soundtouch.SoundTouch(wf.getframerate(), wf.getnchannels()) +# Specify the shift, as 1 whole step +st.set_pitch_shift(2) + +# Feed in samples and add processed samples to resstr +resstr = "" +while True: + buf = wf.readframes(4000) + if not buf: + break + + st.put_samples(buf) + while st.ready_count() > 0: + resstr += st.get_samples(4000) + +# Flush any additional samples +waiting = st.waiting_count() +ready = st.ready_count() +flushed = "" + +# Add silence until another chunk is pushed out +silence = array('h', [0] * 64) +while st.ready_count() == ready: + st.put_samples(silence) + +# Get all of the additional samples +while st.ready_count() > 0: + flushed += st.get_samples(4000) + +st.clear() + +if len(flushed) > 2 * wf.getnchannels() * waiting: + flushed = flushed[0:(2 * wf.getnchannels() * waiting)] + +resstr += flushed + +# Clean up +wf.close() +del st +``` + +AudioReader Tool +---------------- + +AudioReader is an abstraction around the audio handling tools in python, to make it easier to handle audio from many different formats. + +Currently MP3, WAV, AIF, and AU files are supported. + +All subclasses of AudioReader override the following methods: + +* sampling_rate(): Return the samples (frames) per second. +* duration(): Return the duration in ms. +* current_time(): Return the current time in ms. +* seek_time(time): Set the read pointer to the specified time (in ms). +* raw_width(): Return the width in bytes of raw samples. +* raw_read(): Return some amount of data as a raw audio string. +* has_unsigned_singles(): Is the raw data when this has a width of 1 stored in unsigned bytes (but not for higher widths). +* read(): Return some number of frames of an channel-interleaved array (len = NxC) of the appropriate sample depth. +* close(): Perform any necessary cleanup on deallocation. + +In addition, the following methods are provided based on these: +* random_read(start, end): Return the frames between start and end +* continue_read(end): Continue reading from the current read head. +* length_read(lenout): Read a given number of samples, by repeated calls to read(). +* raw_random_read(start, end): Return the raw samples between start and end +* audio_to_image(filename, width, height): Construct a graph of the samples and save to filepath. + +Use the AudioReader.open(filepath) method to get a reader object: + +``` +from ReadAudio import AudioReader + +reader = AudioReader.open("mysong.mp3") +print reader.duration() +``` + +In addition, AudioReader classes can be used to transparently make changes to audio. The following classes are provided: +* ConvertReader(source, set_channels=None, set_sampling_rate=None, set_raw_width=None): Convert the samples from one AudioReader into another format, changing the number of channels, sampling rate, and/or raw byte width. +* ScaleReader(source, scale=1.0, bias=0): Scale the audio (volume) in an AudioReader; scale is > 1 to increase volume; bias is inaudible but can be changed to remove clicks. +* AppendReader(one_path, two_path): Concatenate two audio files; the second will be converted to have the same format as the first. + +Here's how it can be combined with the SoundTouch library: + +``` +# Open the file and convert it to have SoundTouch's required 2-byte samples +reader = AudioReader.open(srcpath) +reader2 = ConvertReader(reader, set_raw_width=2) + +# Create the SoundTouch object and set the given shift +st = soundtouch.SoundTouch(reader2.sampling_rate(), reader2.channels()) +st.set_pitch_shift(shift) + +# Create the .WAV file to write the result to +writer = wave.open(dstpath, 'w') +writer.setnchannels(reader2.channels()) +writer.setframerate(reader2.sampling_rate()) +writer.setsampwidth(reader2.raw_width()) + +# Read values and feed them into SoundTouch +while True: + data = reader2.raw_read() + if not data: + break + + print len(data) + st.put_samples(data) + + while st.ready_count() > 0: + writer.writeframes(st.get_samples(11025)) + +# Flush any remaining samples +waiting = st.waiting_count() +ready = st.ready_count() +flushed = "" + +# Add silence until another chunk is pushed out +silence = array('h', [0] * 64) +while st.ready_count() == ready: + st.put_samples(silence) + +# Get all of the additional samples +while st.ready_count() > 0: + flushed += st.get_samples(4000) + +st.clear() + +if len(flushed) > 2 * reader2.getnchannels() * waiting: + flushed = flushed[0:(2 * reader2.getnchannels() * waiting)] + +writer.writeframes(flushed) + +# Clean up +writer.close() +reader2.close() +``` + +Shifter Tool +------------ + +The Shifter class provides a set of tools for using SoundTouch with the AudioReader system. + +Tools for Shifting Audio +* shift_chunk(chunk, sampling_rate, channels, shift): Shift the pitch of a chunk of audio up or down +* many_shift_chunk(chunk, sampling_rate, channels, shifts): Produce harmonies by shifting a chunk of audio more than once and combining them. +* raw_shift_reader(srcpath, dstpath, shift): Shift an entire file up or down + +Example: + +``` +raw_shift_reader("mysong.mp3", "shifted_mysong.wav", 2) +``` + +Note that raw_shift_reader always produces a .WAV file. + +Tools for detected beats: +* bpm_detect_file(fullpath): Detect the beat from an entire file +* beats_to_ms(bpm, beats): Convert from bpm at a given beat rate to ms between beats. +* find_division_start(fullpath, bpm, beats_per): Identify the start of the beats, by finding segments that fit together + +Other SoundTouch tools +* get_flush(st, channels, fade=0): Get all additional chunks, and optionally fade out the volume on these samples. +* echocancel(outputdata, inputdata): Try to identify an echo and remove it. |
