3

I was hoping I could find a way to get the amplitude data from an mp3 in python. Similar to audacity but I do not want a visual, a simple array of values will do. I want my code to react to sound at certain points when it gets louder. I am using pygame to play the audio and was trying to convert it to a sndarray but it was only giving me the first 0.00018 seconds. Anyway I can get the whole mp3? It does not have to be real time as I would like to be able to react ahead of time anyway and will keep track of my position using pygame.

I am building this cloud using a raspberry pi instead for other features. I already have the lighting work and need it to react to the lightning, lightshowpi is not an option sadly. Any help would be greatly appreciated

Edit: So this is what I have so far thanks to coder-don. It works, but i hangs on the while loop. I do not know why. The mp3 I am using is rather long, could that be the issue?

import os, sys
from gi.repository import Gst, GObject
Gst.init()
GObject.threads_init()

def get_peaks(filename):
global do_run

pipeline_txt = (
    'filesrc location="%s" ! decodebin ! audioconvert ! '
    'audio/x-raw,channels=1,rate=22050,endianness=1234,'
    'width=32,depth=32,signed=(bool)TRUE !'
    'level name=level interval=1000000000 !'
    'fakesink' % filename)
pipeline = Gst.parse_launch(pipeline_txt)

level = pipeline.get_by_name('level')
bus = pipeline.get_bus()
bus.add_signal_watch()

peaks = []
do_run = True

def show_peak(bus, message):
    global do_run
    if message.type == Gst.MESSAGE_EOS:
        pipeline.set_state(Gst.State.NULL)
        do_run = False
        return
    # filter only on level messages
    if message.src is not level or \
       not message.structure.has_key('peak'):
        return
    peaks.append(message.structure['peak'][0])

# connect the callback
bus.connect('message', show_peak)

# run the pipeline until we got eos
pipeline.set_state(Gst.State.PLAYING)
ctx = GObject.MainContext()
while ctx and do_run:
    ctx.iteration()

return peaks

def normalize(peaks):
    _min = min(peaks)
    print(_min)
    _max = max(peaks)
    print(_max)
    d = _max - _min
    return [(x - _min) / d for x in peaks]

if __name__ == '__main__':
    filename = os.path.realpath(sys.argv[1])
    peaks = get_peaks(filename)

    print('Sample is %d seconds' % len(peaks))
    print('Minimum is', min(peaks))
    print('Maximum is', max(peaks))

    peaks = normalize(peaks)
    print(peaks)
NickPomroy
  • 65
  • 1
  • 8
  • I think this has been asked already - http://stackoverflow.com/questions/9344888/getting-max-amplitude-for-an-audio-file-per-second?lq=1 http://stackoverflow.com/questions/10304495/python-getting-the-amplitudes-of-a-sound-file – coder-don May 16 '16 at 00:39
  • Possible duplicate of [get the amplitude data from an mp3 audio files using python](https://stackoverflow.com/questions/38797934/get-the-amplitude-data-from-an-mp3-audio-files-using-python) – Pro Q Jun 24 '19 at 22:46

1 Answers1

5

Using pydub, you can get loudness and highest amplitude of an mp3 file very easily. You can then use one of these parameters to make code/light react to that.

From the pydub website,

AudioSegment(…).max

The highest amplitude of any sample in the AudioSegment. Useful for things like normalization (which is provided in pydub.effects.normalize).

from pydub import AudioSegment
sound = AudioSegment.from_file("/path/to/sound.mp3", format="mp3")    
peak_amplitude = sound.max

AudioSegment(…).dBFS

Returns the loudness of the AudioSegment in dBFS (db relative to the maximum possible loudness). A Square wave at maximum amplitude will be roughly 0 dBFS (maximum loudness), whereas a Sine Wave at maximum amplitude will be roughly -3 dBFS.

from pydub import AudioSegment
sound = AudioSegment.from_file("/path/to/sound.mp3", format="mp3")
loudness = sound.dBFS
Anil_M
  • 10,893
  • 6
  • 47
  • 74