DEV Community

Alex Creatune
Alex Creatune

Posted on

How to Check Duration When Joining 44.1 kHz and 48 kHz Audio

Two clips can both last two seconds while containing different numbers of sample frames. A 44.1 kHz clip has 88,200 frames; a 48 kHz clip has 96,000. Adding those frame counts and dividing by just one of the input rates gives the wrong expected duration.

For a direct join with no trimming or overlap, calculate the duration of each input first, then add the durations. After export, read the output's own sample rate. Do not assume it matches every input.

I'm Alex from the Creatune team. On October 29, 2026, I joined two synthetic fixtures through the signed-out public interface and inspected the downloaded WAV. This is a file-level duration check, not a listening test or a claim about resampling quality.

Make the mismatch deliberate

This standard-library Python script makes two mono, 16-bit PCM WAV files. Different tone frequencies help keep the fixtures distinct, although the duration test below does not use pitch as evidence.

import math
import struct
import wave

for name, rate, frequency in [
    ("tone-44100.wav", 44100, 440),
    ("tone-48000.wav", 48000, 660),
]:
    samples = b"".join(
        struct.pack("<h", round(5000 * math.sin(2 * math.pi * frequency * i / rate)))
        for i in range(rate * 2)
    )
    with wave.open(name, "wb") as w:
        w.setparams((1, 2, rate, 0, "NONE", "not compressed"))
        w.writeframes(samples)
Enter fullscreen mode Exit fullscreen mode

Each file lasts exactly two seconds. The expected total is therefore four seconds, not (88200 + 96000) / 44100 seconds.

Set up a direct join

Open Creatune Audio Joiner, choose the two files, and keep them in 44.1 kHz then 48 kHz order. Keep both Start values at 0 and both End values at 2. Leave fades disabled and confirm the transition says Direct join.

Two original fixtures loaded with their full two-second ranges and a direct join

Leave Trim silence at joins unchecked. Choose WAV in Output format, then Download. Save the downloaded file as joined.wav for the script below. These controls matter because a trim or overlapping crossfade would change the expected duration independently of sample rate.

WAV selected with silence trimming unchecked and a displayed total of four seconds

The interface showed a total of 0:04.0. That is useful feedback, but its rounded display cannot resolve a one-frame difference.

Measure seconds before comparing frames

Run this in the directory containing the three WAV files:

import wave


def info(name):
    with wave.open(name, "rb") as w:
        return w.getnframes(), w.getframerate(), w.getnchannels(), w.getsampwidth()


inputs = [info("tone-44100.wav"), info("tone-48000.wav")]
expected_seconds = sum(frames / rate for frames, rate, _, _ in inputs)
frames, rate, channels, width = info("joined.wav")
actual_seconds = frames / rate
error_in_output_frames = (actual_seconds - expected_seconds) * rate
print("output:", rate, channels, width, frames)
print(f"expected_seconds={expected_seconds:.9f}")
print(f"actual_seconds={actual_seconds:.9f}")
print(f"difference_in_output_frames={error_in_output_frames:.3f}")
Enter fullscreen mode Exit fullscreen mode

The downloaded file in this run produced:

output: 44100 2 2 176399
expected_seconds=4.000000000
actual_seconds=3.999977324
difference_in_output_frames=-1.000
Enter fullscreen mode Exit fullscreen mode

The export was 44.1 kHz stereo PCM16, one output frame shorter than the four-second calculation: about 22.7 microseconds. I record that difference rather than calling the result sample-exact. The two inputs were mono; the export having two channels does not establish that it contains spatial stereo information.

Decide what this test should catch

A duration near 4.17687 seconds would be consistent with the incorrect calculation of interpreting all 184,200 input frames at 44.1 kHz. That is a diagnostic clue, not proof of a particular implementation bug. A large discrepancy should first lead you to check trim ranges, fades, silence removal, and the actual downloaded file.

For short test fixtures, recording the error in output frames makes rounding visible. For a real delivery, set your tolerance before testing according to the receiving workflow; do not retroactively choose a limit just because an export passed it.

This check does not prove waveform identity, correct pitch, an inaudible seam, or high-quality resampling. Test those separately. A valid duration and a pleasant transition answer different questions.

Related checks

Our earlier note on why a WAV filename is not an audio delivery contract helps define the format requirements before accepting an export. If the result sounds faster or higher, separating a pitch shift from faster playback gives a separate diagnostic procedure. Both are English articles from our team.

Top comments (0)