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