import numpy as np
import ctypes
import wave
replaygain = ctypes.CDLL('libreplaygain.so')
def string_to_samples(string, channel_count):
"""
Takes a byte string of raw PCM data and returns a float32 numpy array containing
audio data in range [-1, 1].
"""
samples = np.fromstring(string, dtype='int16')
samples = samples / float(2**15)
samples.astype(np.float32)
frame_count = samples.size / channel_count
return samples.reshape([frame_count, channel_count])
def read_wav(f, start=None, end=None):
# Opening the file and getting infos
raw = wave.open(f, 'rb')
channel_count = raw.getnchannels()
sample_width = raw.getsampwidth() # Sample width in byte
if sample_width != 2: raise ValueError('Wave format not supported')
frame_rate = raw.getframerate()
# Calculating start position and end position
# for reading the data
if start is None: start = 0
start_frame = start * frame_rate
if end is None: end_frame = raw.getnframes()
else: end_frame = end * frame_rate
frame_count = end_frame - start_frame
# Reading only the data between `start` and `end`,
# putting this data to a numpy array
raw.setpos(int(start_frame))
data = raw.readframes(int(frame_count))
data = string_to_samples(data, channel_count)
return data, {'frame_rate': frame_rate, 'channel_count': channel_count}
def calculate_replaygain(samples, frame_rate=44100):
"""
pass in a generator that produces audio samples
returns the maximum sample.
https://github.com/vontrapp/replaygain
"""
replaygain.gain_init_analysis(frame_rate)
block_size = 10000
channel_count = samples.shape[1]
i = 0
samples = samples.astype(np.float64)
while i * block_size < samples.shape[0]:
channel_left = samples[i*block_size:(i+1)*block_size,0]
channel_right = samples[i*block_size:(i+1)*block_size,1]
samples_p_left = channel_left.ctypes.data_as(ctypes.POINTER(ctypes.c_double))
samples_p_right = channel_right.ctypes.data_as(ctypes.POINTER(ctypes.c_double))
replaygain.gain_analyze_samples(samples_p_left, samples_p_right, channel_left.shape[0], channel_count)
i += 1
return replaygain.gain_get_chapter()
if __name__ == '__main__':
samples, infos = read_wav('directions.wav')
gain = calculate_replaygain(samples, frame_rate=infos['frame_rate'])
print "Recommended gain: %f dB" % gain
gain = calculate_replaygain(np.random.random((441000, 2)) * 2 - 1, frame_rate=44100)
print "Recommended gain: %f dB" % gain