Zekeriya Akgül
Zekeriya Akgül

Reputation: 318

Rhythm detection with python

i want to detect the rhythm of the given music or sound with python. And then print the rhythm time points to a file for using in my unity game. I've made some progress on this, but it's still not where I want it. It's missing some of notes. Here is my python code for this. I am currently using librosa module for this. My question is, am I on the right way? If yes then how can i improve my code? If no then what should i do?

import librosa
import numpy as np
from os import listdir, path, remove
from os.path import isfile, join
from pydub import AudioSegment

SONGS_PATH = "./songs"
PS_FILES_PATH = "./ps_files"
detection_mode = "full"

# Get the song files from given dir
song_files = [f for f in listdir(SONGS_PATH) if isfile(join(SONGS_PATH, f))]


count = len(song_files)
# Process each song file
for i, song_file in enumerate(song_files):
    print(str(i+1) + "/" + str(count) + " Processing song: ", song_file)
    song_file_path = SONGS_PATH + "/" + song_file
    output_file = PS_FILES_PATH + "/" + song_file.replace(".mp3", "").replace(".wav", "")

    # If file type is mp3 then convert it to wav and remove mp3 file
    if ".mp3" in song_file:
        print("Not supported format. Converting to wav...")
        sound = AudioSegment.from_mp3(song_file_path)
        sound.export(song_file_path.replace("mp3", "wav"), format="wav")
        print("File converted. Deleting old one...")
        remove(song_file_path)
        song_file_path = song_file_path.replace("mp3", "wav")

    # Load file
    xy, sr = librosa.load(song_file_path)
    # Find onsets
    onset_frames = librosa.onset.onset_detect(xy, sr=sr, wait=1, pre_avg=1, post_avg=1, pre_max=1, post_max=1)
    # Get the onset times
    onset_times = librosa.frames_to_time(onset_frames)
    onset_clicks = librosa.clicks(frames=onset_frames, sr=sr, length=len(xy))

    # find tempo and beats
    tempo, beat_frames = librosa.beat.beat_track(y=xy, sr=sr)
    # Get the beat times
    beat_times = librosa.frames_to_time(beat_frames)
    beat_clicks = librosa.clicks(frames=beat_frames, sr=sr, length=len(xy))

    # Generate a txt file which is contains times, and create a audio file with click effect.
    print("Generating ps file...")
    if detection_mode == "only-onsets":
        librosa.output.write_wav(output_file + "onset_clicks.wav", xy + onset_clicks, sr)
        file = open(output_file + "_onset_times.txt","ab")
        np.savetxt(file, onset_times, '%.2f') 
    elif detection_mode == "only-beats":
        librosa.output.write_wav(output_file + "beat_clicks.wav", xy + beat_clicks, sr)
        file = open(output_file + "_beat_times.txt","ab")
        np.savetxt(file, beat_times, '%.2f') 
    else:
        librosa.output.write_wav(output_file + "full_clicks.wav", xy + onset_clicks + beat_clicks, sr)
        file = open(output_file + "_full_times.txt","ab")
        np.savetxt(file, np.concatenate(beat_times, onset_times), '%.2f') 
    print("Done.\n")

And here is one of my generated sound files with click effect: Sound files

EDIT:

Im actually making a game like piano tiles, gitar hero. But my game will not contain 3 line, it gonna have only one line for hit the notes so that means i need a only one event to trigger my mechanism.

Here is the example video for event mechanism what i want: Example video

Upvotes: 1

Views: 4446

Answers (0)

Related Questions