Skip to content

Instantly share code, notes, and snippets.

@HudsonHuang
Created October 11, 2019 15:21
Show Gist options
  • Save HudsonHuang/fbdf8e9af7993fe2a91620d3fb86a182 to your computer and use it in GitHub Desktop.
Save HudsonHuang/fbdf8e9af7993fe2a91620d3fb86a182 to your computer and use it in GitHub Desktop.
Convert audio data of PCM16/float32 to byte, and vice versa.
"""Helper functions for working with audio files in NumPy."""
"""some code borrowed from https://github.com/mgeier/python-audio/blob/master/audio-files/utility.py"""
import numpy as np
import contextlib
import librosa
import struct
import soundfile
def float_to_byte(sig):
# float32 -> int16(PCM_16) -> byte
return float2pcm(sig, dtype='int16').tobytes()
def byte_to_float(byte):
# byte -> int16(PCM_16) -> float32
return pcm2float(np.frombuffer(byte,dtype=np.int16), dtype='float32')
def pcm2float(sig, dtype='float32'):
"""Convert PCM signal to floating point with a range from -1 to 1.
Use dtype='float32' for single precision.
Parameters
----------
sig : array_like
Input array, must have integral type.
dtype : data type, optional
Desired (floating point) data type.
Returns
-------
numpy.ndarray
Normalized floating point data.
See Also
--------
float2pcm, dtype
"""
sig = np.asarray(sig)
if sig.dtype.kind not in 'iu':
raise TypeError("'sig' must be an array of integers")
dtype = np.dtype(dtype)
if dtype.kind != 'f':
raise TypeError("'dtype' must be a floating point type")
i = np.iinfo(sig.dtype)
abs_max = 2 ** (i.bits - 1)
offset = i.min + abs_max
return (sig.astype(dtype) - offset) / abs_max
def float2pcm(sig, dtype='int16'):
"""Convert floating point signal with a range from -1 to 1 to PCM.
Any signal values outside the interval [-1.0, 1.0) are clipped.
No dithering is used.
Note that there are different possibilities for scaling floating
point numbers to PCM numbers, this function implements just one of
them. For an overview of alternatives see
http://blog.bjornroche.com/2009/12/int-float-int-its-jungle-out-there.html
Parameters
----------
sig : array_like
Input array, must have floating point type.
dtype : data type, optional
Desired (integer) data type.
Returns
-------
numpy.ndarray
Integer data, scaled and clipped to the range of the given
*dtype*.
See Also
--------
pcm2float, dtype
"""
sig = np.asarray(sig)
if sig.dtype.kind != 'f':
raise TypeError("'sig' must be a float array")
dtype = np.dtype(dtype)
if dtype.kind not in 'iu':
raise TypeError("'dtype' must be an integer type")
i = np.iinfo(dtype)
abs_max = 2 ** (i.bits - 1)
offset = i.min + abs_max
return (sig * abs_max + offset).clip(i.min, i.max).astype(dtype)
@contextlib.contextmanager
def printoptions(*args, **kwargs):
"""Context manager for temporarily setting NumPy print options.
See http://stackoverflow.com/a/2891805/500098
"""
original = np.get_printoptions()
try:
np.set_printoptions(*args, **kwargs)
yield
finally:
np.set_printoptions(**original)
if __name__ == "__main__":
# load file to float32
y,sr = librosa.load("1.wav",sr=None)
# convert to byte(PCM16)
byt = float_to_byte(y)
# save to pcm file
with open("1.pcm","wb") as f:
f.write(byt)
# read pcm file
with open("1.pcm","rb") as f:
byt = f.read()
# byte(PCM16) to float32
f = byte_to_float(byt)
# save float32 to PCM16 with soundfile
soundfile.write("2.wav",f,sr,'PCM_16')
@digizimm
Copy link

digizimm commented Feb 7, 2024

Saved my day! <3

@lu-wo
Copy link

lu-wo commented May 24, 2024

Very cool, saved us :)

@Epic-Eric
Copy link

THANK YOU!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment