Search code examples
pythonwav

Why do two different ways of finding out the total amount of chunks in a wav file return different results?


In a seperate project where I stream wav files between sockets, I found a bug where either I'm not reading enough of the wav file, or I'm overcalculating how many chunks I have to send, so I isolated the issue. (ignore the custom_logging module)

from custom_logging import CustomLogger
import logging
import wave
import math
import os

testing_logger = CustomLogger(log_files=["testing.log"])


CHUNK = 4096

def calc_total_chunks(song_dir, song_name, chunk):
    song_path = os.path.join(song_dir, song_name)
    with wave.open(song_path) as mywav:
        nframes = mywav.getnframes()
        
    total_chunks = math.ceil(nframes / chunk)
    return total_chunks


def count_chunks_in_song(song_dir, song_name, chunk):
    song_path = os.path.join(song_dir, song_name)
    chunk_count = 0

    with wave.open(song_path) as mywav:
        while True:
            song_data_chunk = mywav.readframes(chunk)
            if not song_data_chunk:
                break
            chunk_count += 1

    return chunk_count


songs = ["american.wav", "beats.wav", "No_38.wav"]

for song in songs:
    logging.info(f"total chunks calc for {song}: {calc_total_chunks('songs', song, CHUNK)}")
    logging.info(f"total chunks read for {song}: {count_chunks_in_song('songs', song, CHUNK)}")



output:

[13:40:31] <module> INFO total chunks calc for american.wav: 5530
[13:40:31] <module> INFO total chunks read for american.wav: 669
[13:40:31] <module> INFO total chunks calc for beats.wav: 690  
[13:40:31] <module> INFO total chunks read for beats.wav: 690  
[13:40:31] <module> INFO total chunks calc for No_38.wav: 20156
[13:40:31] <module> INFO total chunks read for No_38.wav: 129

I tried a few different methods of reading/calculating, didn't work for me.


Solution

  • I decided to just use pydub instead, this function works just fine:

    from pydub import AudioSegment
    
    def calc_total_chunks(song_dir, song_name, chunk):
        song_path = os.path.join(song_dir, song_name)
        audio = AudioSegment.from_wav(song_path)
        return math.ceil(audio.frame_count() / chunk)