Skip to content

Commit

Permalink
Attempt at calculating peaks for wavesurfer to improve browser memory…
Browse files Browse the repository at this point in the history
…. Didn't really work
  • Loading branch information
mstratford committed Apr 20, 2024
1 parent 7d88d33 commit d6a898a
Show file tree
Hide file tree
Showing 3 changed files with 13,838 additions and 4 deletions.
92 changes: 92 additions & 0 deletions helpers/audio_tools.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from pydub import AudioSegment
import os
import math
from helpers.normalisation import get_original_filename_from_normalised

def generate_silence_file(filename: str):
Expand Down Expand Up @@ -31,6 +32,97 @@ def generate_silence_file(filename: str):
silent_file.export(silent_filename, bitrate="64k", format="mp3")
return silent_filename

def generate_peaks_from_filename(filename: str):
if not (isinstance(filename, str) and filename.endswith(".mp3")):
raise ValueError("Invalid filename given.")

audio: AudioSegment = AudioSegment.from_file(filename, "mp3")

# Returns the raw audio data as an array of (numeric) samples.
# Note: if the audio has multiple channels, the samples for each channel will be serialized
# for example, stereo audio would look like [sample_1_L, sample_1_R, sample_2_L, sample_2_R, …].
samples: list[int] = list(audio.get_array_of_samples())

channels: int = audio.channels if audio.channels else 1
samples_per_channel = [[]]*channels



if not samples:
return []

if channels > 0:
for channel in range(channels):
samples_per_channel[channel] = samples[channel::channels]






number_of_segments = math.floor(len(samples)/2205)
first = 0
last = math.floor(number_of_segments - 1)


sampleSize = math.floor(len(samples) / number_of_segments)
sampleStep = max(math.floor(sampleSize / 10),1)

peak_entries_per_channel = int(sampleSize*2/channels)

peaks_per_channel = [[0]*peak_entries_per_channel]*channels
c = 0
merged_peaks = [0]*(peak_entries_per_channel*channels)


for c in range(channels):
peaks = [0]*peak_entries_per_channel
chan = samples_per_channel[c]

for i in range(first,last):
start = math.floor(i * sampleSize)
end = min(len(chan)-1, math.floor(start + sampleSize))
if start > len(chan):
break
minimum = chan[start]
maximum = minimum

for j in range(start, end, sampleStep):
value = chan[j]

if (value > maximum):
maximum = value

if (value < maximum):
minimum = value

if 2*i+1 >= len(peaks):
break
if peaks[2 * i] != 0:
raise Exception("Overwriting peaks at ", 2 * i)
peaks[2 * i] = maximum
peaks[2 * i + 1] = minimum

if (c == 0 or maximum > merged_peaks[2 * i]):
merged_peaks[2 * i] = maximum

if (c == 0 or minimum< merged_peaks[2 * i + 1]):
merged_peaks[2 * i + 1] = minimum
peaks_per_channel[c] = peaks

merged = True
return {
"sample_rate": audio.frame_rate,
"number_of_segments": number_of_segments,
"version":2,
"channels":channels,
"samples": len(samples),
"samples_per_segment":sampleSize,
"bits": 8,
"length": len(merged_peaks) if merged else len(peaks_per_channel[0]),
"data": merged_peaks if merged else peaks_per_channel
}

# Returns either a silence file path for the UI (based on filename), or the original if not available.
def get_silence_filename_if_available(filename: str):
if not (isinstance(filename, str) and filename.endswith(".mp3")):
Expand Down
Loading

0 comments on commit d6a898a

Please sign in to comment.