Skip to content

Instantly share code, notes, and snippets.

@HudsonHuang
Created October 11, 2019 15:21
Show Gist options
  • Star 33 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • 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')
@dzubke
Copy link

dzubke commented Jun 7, 2020

Thanks for writing the pcm2float functions! I'm using them in an NLP project where I'm adjusting the pitch and I need to convert PCM16 to float32.

@jerryjazzy
Copy link

nicely coded!

@atlantis414
Copy link

Nice job,very useful!!!

@kikohs
Copy link

kikohs commented May 31, 2022

Very useful, thank you!

@lamnguyenx
Copy link

Thank you! Very nice

@digizimm
Copy link

digizimm commented Feb 7, 2024

Saved my day! <3

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