From 1646dfb9159e66c30821a5659e8f0a5eb3d52f05 Mon Sep 17 00:00:00 2001 From: steven-na Date: Wed, 5 Aug 2026 21:23:31 -0700 Subject: Formatting, bug fix, test coverage --- tests/dft.c | 53 +++++++++++++++++++++++++- tests/wav.c | 123 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 175 insertions(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/dft.c b/tests/dft.c index 9c406f5..3f3d7f7 100644 --- a/tests/dft.c +++ b/tests/dft.c @@ -1,6 +1,7 @@ #include "../src/dft.h" #include +#include #include #include @@ -351,6 +352,56 @@ Test(dft, reconstruct_spectrum_mirrors_conjugate) { smrt_arena_destroy(arena); } +Test(dft, data_to_wav_clamps_out_of_range_amplitude) { + smrt_arena_t *arena = smrt_arena_create(KiB(16), KiB(4), false); + + // two in-phase DC-like bins summing to 1.6, well outside [-1, 1] + dft_data_t dft = { .freq_count = 2 }; + dft.frequencies = SMRTA_ALLOC_ARRAY(arena, f64, 2); + dft.amplitudes = SMRTA_ALLOC_ARRAY(arena, f64, 2); + dft.phases = SMRTA_ALLOC_ARRAY(arena, f64, 2); + dft.frequencies[0] = 0.0; dft.amplitudes[0] = 0.8; dft.phases[0] = 0.0; + dft.frequencies[1] = 0.0; dft.amplitudes[1] = 0.8; dft.phases[1] = 0.0; + + wav_data_t wav = dft_data_to_wav(arena, dft, 8, 1.0); + + cr_assert_eq(wav.sample_count, 8); + for (u64 i = 0; i < wav.sample_count; i++) { + // matches the clamped-amp=1.0 case in data_to_wav_varies_with_time: + // (1.0 + 1.0) * (UINT8_MAX/2 truncated to 127) = 254 + cr_expect_eq(wav.samples[i], 254); + } + + smrt_arena_destroy(arena); +} + +Test(dft, stft_rejects_zero_hop_size, .signal = SIGABRT) { + smrt_arena_t *arena = smrt_arena_create(KiB(16), KiB(4), false); + + f64 samples[8] = { 0 }; + short_time_fourier_transform(arena, 8, 0, samples, 8, 8); +} + +Test(dft, stft_rejects_zero_sample_count, .signal = SIGABRT) { + smrt_arena_t *arena = smrt_arena_create(KiB(16), KiB(4), false); + + f64 samples[1] = { 0 }; + short_time_fourier_transform(arena, 8, 4, samples, 0, 8); +} + +Test(dft, reconstruct_spectrum_rejects_mismatched_freq_count, .signal = SIGABRT) { + smrt_arena_t *arena = smrt_arena_create(KiB(16), KiB(4), false); + + // sample_count=8 expects freq_count == 5; give it 3 instead + dft_data_t data = { .freq_count = 3 }; + data.frequencies = SMRTA_ALLOC_ARRAY(arena, f64, 3); + data.amplitudes = SMRTA_ALLOC_ARRAY(arena, f64, 3); + data.phases = SMRTA_ALLOC_ARRAY(arena, f64, 3); + + f64 *real_o, *imag_o; + reconstruct_spectrum(arena, &data, 8, &real_o, &imag_o); +} + Test(dft, istft_round_trip_recovers_samples) { smrt_arena_t *arena = smrt_arena_create(MiB(1), KiB(4), false); @@ -362,7 +413,7 @@ Test(dft, istft_round_trip_recovers_samples) { stft_data_t stft = short_time_fourier_transform(arena, window_size, hop_size, samples, sample_count, sample_rate); cr_assert_eq(stft.segment_count, 7); - f64 *output = inverse_short_time_fourier_transform(arena, stft, window_size, hop_size, NULL, 0); + f64 *output = inverse_short_time_fourier_transform(arena, stft, NULL, 0); for (u64 i = 0; i < sample_count; i++) { cr_expect(F64_EQ(output[i], samples[i], 1e-9)); diff --git a/tests/wav.c b/tests/wav.c index dae2ef1..7635223 100644 --- a/tests/wav.c +++ b/tests/wav.c @@ -340,3 +340,126 @@ Test(wav, write_sine, .init = write_sine_setup, .fini = write_sine_teardown) { smrt_arena_destroy(arena); } + +static char float32_wav_path[] = "/tmp/steez_testwav_f32_XXXXXX"; +static int float32_wav_fd; + +void float32_wav_setup(void) { + float32_wav_fd = mkstemp(float32_wav_path); + cr_assert_geq(float32_wav_fd, 0, "mkstemp failed"); +} + +void float32_wav_teardown(void) { + unlink(float32_wav_path); + close(float32_wav_fd); +} + +Test(wav, read_32bps_float_round_trip, .init = float32_wav_setup, .fini = float32_wav_teardown) { + FILE *wav_file = fdopen(float32_wav_fd, "wb"); + cr_assert_not_null(wav_file); + + smrt_arena_t *arena = smrt_arena_create(KiB(64), KiB(4), false); + + f32 expected[5] = { 0.0f, 0.5f, -0.5f, 1.0f, -1.0f }; + u64 sample_count = 5; + + wav_data_t data; + data.samples = (u8*)expected; + data.sample_count = sample_count; + + wav_fmt_chunk_t fmtchunk = make_wav_fmt_chunk(1, 44100, 32); + fmtchunk.audio_format = 3; // IEEE 754 float + + cr_assert(write_wav_file(wav_file, &fmtchunk, data)); + + fclose(wav_file); + + FILE *readback_file = fopen(float32_wav_path, "rb"); + cr_assert_not_null(readback_file); + + wav_master_chunk_t mchunk; + wav_fmt_chunk_t read_fmtchunk; + + wav_data_t read_data = load_wav_file(arena, readback_file, &mchunk, &read_fmtchunk, sizeof(f64)); + + fclose(readback_file); + + cr_expect_eq(read_fmtchunk.audio_format, 3); + cr_expect_eq(read_fmtchunk.bits_per_sample, 32); + cr_assert_not_null(read_data.samples); + cr_expect_eq(read_data.sample_count, sample_count); + + f64 *decoded = read_32bps_float_data(arena, read_data, 1, 0, sizeof(f64)); + cr_assert_not_null(decoded); + + for (u64 i = 0; i < sample_count; i++) { + cr_expect(F64_EQ(decoded[i], (f64)expected[i], 1e-6)); + } + + smrt_arena_destroy(arena); +} + +static char pcm24_wav_path[] = "/tmp/steez_testwav_24bit_XXXXXX"; +static int pcm24_wav_fd; + +void pcm24_wav_setup(void) { + pcm24_wav_fd = mkstemp(pcm24_wav_path); + cr_assert_geq(pcm24_wav_fd, 0, "mkstemp failed"); +} + +void pcm24_wav_teardown(void) { + unlink(pcm24_wav_path); + close(pcm24_wav_fd); +} + +Test(wav, read_24bps_round_trip, .init = pcm24_wav_setup, .fini = pcm24_wav_teardown) { + FILE *wav_file = fdopen(pcm24_wav_fd, "wb"); + cr_assert_not_null(wav_file); + + smrt_arena_t *arena = smrt_arena_create(KiB(64), KiB(4), false); + + i32 expected[4] = { 0, 4194304 /* +0.5 */, -4194304 /* -0.5 */, 8388607 /* max */ }; + u64 sample_count = 4; + + u8 raw[4*3]; + for (u64 i = 0; i < sample_count; i++) { + i32 v = expected[i]; + raw[i*3+0] = (u8)( v & 0xFF); + raw[i*3+1] = (u8)((v >> 8) & 0xFF); + raw[i*3+2] = (u8)((v >> 16) & 0xFF); + } + + wav_data_t data; + data.samples = raw; + data.sample_count = sample_count; + + wav_fmt_chunk_t fmtchunk = make_wav_fmt_chunk(1, 44100, 24); + + cr_assert(write_wav_file(wav_file, &fmtchunk, data)); + + fclose(wav_file); + + FILE *readback_file = fopen(pcm24_wav_path, "rb"); + cr_assert_not_null(readback_file); + + wav_master_chunk_t mchunk; + wav_fmt_chunk_t read_fmtchunk; + + wav_data_t read_data = load_wav_file(arena, readback_file, &mchunk, &read_fmtchunk, sizeof(f64)); + + fclose(readback_file); + + cr_expect_eq(read_fmtchunk.bits_per_sample, 24); + cr_assert_not_null(read_data.samples); + cr_expect_eq(read_data.sample_count, sample_count); + + f64 *decoded = read_24bps_data(arena, read_data, 1, 0, sizeof(f64)); + cr_assert_not_null(decoded); + + for (u64 i = 0; i < sample_count; i++) { + f64 expected_amplitude = (f64)expected[i] / (f64)(0b1 << 23); + cr_expect(F64_EQ(decoded[i], expected_amplitude, 1e-9)); + } + + smrt_arena_destroy(arena); +} -- cgit v1.2.3