diff --git a/paulstretch_mono.py b/paulstretch_mono.py old mode 100644 new mode 100755 index 3f6236a..533659d --- a/paulstretch_mono.py +++ b/paulstretch_mono.py @@ -12,12 +12,12 @@ import sys from numpy import * -import scipy.io.wavfile +import wavfile import wave def load_wav(filename): try: - wavedata=scipy.io.wavfile.read(filename) + wavedata=wavfile.read(filename) samplerate=int(wavedata[0]) smp=wavedata[1]*(1.0/32768.0) if len(smp.shape)>1: #convert to mono diff --git a/paulstretch_newmethod.py b/paulstretch_newmethod.py old mode 100644 new mode 100755 index efa6309..0d856e7 --- a/paulstretch_newmethod.py +++ b/paulstretch_newmethod.py @@ -14,7 +14,7 @@ import sys from numpy import * -import scipy.io.wavfile +import wavfile import wave from optparse import OptionParser @@ -25,7 +25,7 @@ def load_wav(filename): try: - wavedata=scipy.io.wavfile.read(filename) + wavedata=wavfile.read(filename) samplerate=int(wavedata[0]) smp=wavedata[1]*(1.0/32768.0) smp=smp.transpose() diff --git a/paulstretch_stereo.py b/paulstretch_stereo.py index df7797c..d73a142 100755 --- a/paulstretch_stereo.py +++ b/paulstretch_stereo.py @@ -14,20 +14,21 @@ import sys from numpy import * -import scipy.io.wavfile +import wavfile import wave from optparse import OptionParser def load_wav(filename): try: - wavedata=scipy.io.wavfile.read(filename) + wavedata=wavfile.read(filename) samplerate=int(wavedata[0]) smp=wavedata[1]*(1.0/32768.0) smp=smp.transpose() if len(smp.shape)==1: #convert to stereo smp=tile(smp,(2,1)) return (samplerate,smp) - except: + except(e): + print("error: "+e) print ("Error loading wav: "+filename) return None @@ -146,6 +147,7 @@ def paulstretch(samplerate,smp,stretch,windowsize_seconds,outfilename): print ("stretch amount = %g" % options.stretch) print ("window size = %g seconds" % options.window_size) +print args (samplerate,smp)=load_wav(args[0]) paulstretch(samplerate,smp,options.stretch,options.window_size,args[1]) diff --git a/wavfile.py b/wavfile.py new file mode 100644 index 0000000..1f7a9c7 --- /dev/null +++ b/wavfile.py @@ -0,0 +1,408 @@ +# wavfile.py (Enhanced) +# +# Mod by X-Raym +# Date: 20181906_1222 +# * corrected loops +# * unsupported chunk read and write +# * LIST-INFO support +# * renamed variables to avoid conflict with python native functions +# * correct bytes error +# * correct write function +# +# URL: https://gist.github.com/josephernest/3f22c5ed5dabf1815f16efa8fa53d476 +# Source: scipy/io/wavfile.py +# +# Mod by Joseph Basquin +# Date: 20180430_2335 +# * read: also returns bitrate, cue markers + cue marker labels (sorted), loops, pitch +# * read: 24 bit & 32 bit IEEE files support (inspired from wavio_weckesser.py from Warren Weckesser) +# * read: added normalized (default False) that returns everything as float in [-1, 1] +# * read: added forcestereo that returns a 2-dimensional array even if input is mono +# +# * write: can write cue markers, cue marker labels, loops, pitch +# * write: 24 bit support +# * write: can write from a float normalized in [-1, 1] +# * write: 20180430_2335: bug fixed when size of data chunk is odd (previously, metadata could become unreadable because of this) +# +# * removed RIFX support (big-endian) (never seen one in 10+ years of audio production/audio programming), only RIFF (little-endian) are supported +# * removed read(..., mmap) +# +# +# Test: +# ..\wav\____wavfile_demo.py + + +""" +Module to read / write wav files using numpy arrays + +Functions +--------- +`read`: Return the sample rate (in samples/sec) and data from a WAV file. + +`write`: Write a numpy array as a WAV file. + +""" +#from __future__ import division, print_function, absolute_import + +import numpy +import struct +import warnings +import collections +#from operator import itemgetter + +class WavFileWarning(UserWarning): + pass + +_ieee = False + +# assumes file pointer is immediately +# after the 'fmt ' id +def _read_fmt_chunk(fid): + res = struct.unpack(' 16): + if (comp == 3): + global _ieee + _ieee = True + #warnings.warn("IEEE format not supported", WavFileWarning) + else: + warnings.warn("Unfamiliar format bytes", WavFileWarning) + if (size>16): + fid.read(size-16) + return size, comp, noc, rate, sbytes, ba, bits + +# assumes file pointer is immediately +# after the 'data' id +def _read_data_chunk(fid, noc, bits, normalized=False): + size = struct.unpack('> 7) * 255 + data = a.view(' 1: + data = data.reshape(-1,noc) + + if bool(size & 1): # if odd number of bytes, move 1 byte further (data chunk is word-aligned) + fid.seek(1,1) + + if normalized: + if bits == 8 or bits == 16 or bits == 24: + normfactor = 2 ** (bits-1) + data = numpy.float32(data) * 1.0 / normfactor + + return data + +def _skip_unknown_chunk(fid): + data = fid.read(4) + size = struct.unpack('16, 23=>24 + label = fid.read(size-4).rstrip(bytes('\x00')) # remove the trailing null characters + #_cuelabels.append(label) + _markersdict[idx]['label'] = label # needed to match labels and markers + + elif chunk_id == b'smpl': + str1 = fid.read(40) + size, manuf, prod, sampleperiod, midiunitynote, midipitchfraction, smptefmt, smpteoffs, numsampleloops, samplerdata = struct.unpack(' 1.0] = 1.0 + data[data < -1.0] = -1.0 + a32 = numpy.asarray(data * (2 ** 23 - 1), dtype=numpy.int32) + else: + a32 = numpy.asarray(data, dtype=numpy.int32) + if a32.ndim == 1: + a32.shape = a32.shape + (1,) # Convert to a 2D array with a single column. + a8 = (a32.reshape(a32.shape + (1,)) >> numpy.array([0, 8, 16])) & 255 # By shifting first 0 bits, then 8, then 16, the resulting output is 24 bit little-endian. + data = a8.astype(numpy.uint8) + else: + if normalized: # default to 32 bit int + data[data > 1.0] = 1.0 + data[data < -1.0] = -1.0 + data = numpy.asarray(data * (2 ** 31 - 1), dtype=numpy.int32) + + fid = open(filename, 'wb') + fid.write(b'RIFF') + fid.write(b'\x00\x00\x00\x00') + fid.write(b'WAVE') + + # fmt chunk + fid.write(b'fmt ') + if data.ndim == 1: + noc = 1 + else: + noc = data.shape[1] + bits = data.dtype.itemsize * 8 if bitrate != 24 else 24 + sbytes = rate * (bits // 8) * noc + ba = noc * (bits // 8) + fid.write(struct.pack('' or (data.dtype.byteorder == '=' and sys.byteorder == 'big'): + data = data.byteswap() + + data.tofile(fid) + + if data.nbytes % 2 == 1: # add an extra padding byte if data.nbytes is odd: https://web.archive.org/web/20141226210234/http://www.sonicspot.com/guide/wavefiles.html#data + fid.write('\x00') + + # This need to be made modular ! + if infos: + info = b'' + for key, val in infos.items(): + key = bytes(key, 'UTF-8') + val = bytes(val, 'UTF-8') + #val += b'\x00' # Note: Fix windows display error. Is this valid ? + size = len(val) # because \x00 + if len(val) % 2 == 1: + val += b'\x00' + info += key + info += struct.pack('