xref: /btstack/test/sbc/sbc_decoder_test.py (revision 6ccd8248590f666db07dd7add13fecb4f5664fb5)
1*6ccd8248SMilanka Ringwald#!/usr/bin/env python3
25f21c38aSMilanka Ringwaldimport numpy as np
35f21c38aSMilanka Ringwaldimport wave
45f21c38aSMilanka Ringwaldimport struct
55f21c38aSMilanka Ringwaldimport sys
65f21c38aSMilanka Ringwaldfrom sbc import *
75f21c38aSMilanka Ringwaldfrom sbc_encoder import *
85f21c38aSMilanka Ringwaldfrom sbc_decoder import *
95f21c38aSMilanka Ringwald
105f21c38aSMilanka Ringwalderror = 0.99
115f21c38aSMilanka Ringwaldmax_error = -1
125f21c38aSMilanka Ringwald
135f21c38aSMilanka Ringwalddef sbc_compare_pcm(frame_count, actual_frame, expected_frame):
145f21c38aSMilanka Ringwald    global error, max_error
151522543dSMilanka Ringwald    for ch in range(actual_frame.nr_channels):
161522543dSMilanka Ringwald        M = mse(actual_frame.pcm[ch], expected_frame.pcm[ch])
175f21c38aSMilanka Ringwald        if M > max_error:
185f21c38aSMilanka Ringwald            max_error = M
195f21c38aSMilanka Ringwald
20ef8a7a12SMilanka Ringwald        if max_error > error:
21*6ccd8248SMilanka Ringwald            print("pcm error (%d, %f ) " % (frame_count, max_error))
225f21c38aSMilanka Ringwald            return -1
235f21c38aSMilanka Ringwald    return 0
245f21c38aSMilanka Ringwald
255f21c38aSMilanka Ringwald
265f21c38aSMilanka Ringwalddef sbc_compare_headers(frame_count, actual_frame, expected_frame):
275f21c38aSMilanka Ringwald    if actual_frame.sampling_frequency != expected_frame.sampling_frequency:
28*6ccd8248SMilanka Ringwald        print("sampling_frequency wrong ", actual_frame.sampling_frequency)
295f21c38aSMilanka Ringwald        return -1
305f21c38aSMilanka Ringwald
315f21c38aSMilanka Ringwald    if actual_frame.nr_blocks != expected_frame.nr_blocks:
32*6ccd8248SMilanka Ringwald        print("nr_blocks wrong ", actual_frame.nr_blocks)
335f21c38aSMilanka Ringwald        return -1
345f21c38aSMilanka Ringwald
355f21c38aSMilanka Ringwald    if actual_frame.channel_mode != expected_frame.channel_mode:
36*6ccd8248SMilanka Ringwald        print("channel_mode wrong ", actual_frame.channel_mode)
375f21c38aSMilanka Ringwald        return -1
385f21c38aSMilanka Ringwald
395f21c38aSMilanka Ringwald    if actual_frame.nr_channels != expected_frame.nr_channels:
40*6ccd8248SMilanka Ringwald        print("nr_channels wrong ", actual_frame.nr_channels)
415f21c38aSMilanka Ringwald        return -1
425f21c38aSMilanka Ringwald
435f21c38aSMilanka Ringwald    if actual_frame.allocation_method != expected_frame.allocation_method:
44*6ccd8248SMilanka Ringwald        print("allocation_method wrong ", actual_frame.allocation_method)
455f21c38aSMilanka Ringwald        return -1
465f21c38aSMilanka Ringwald
475f21c38aSMilanka Ringwald    if actual_frame.nr_subbands != expected_frame.nr_subbands:
48*6ccd8248SMilanka Ringwald        print("nr_subbands wrong ", actual_frame.nr_subbands)
495f21c38aSMilanka Ringwald        return -1
505f21c38aSMilanka Ringwald
515f21c38aSMilanka Ringwald    if actual_frame.bitpool != expected_frame.bitpool:
52*6ccd8248SMilanka Ringwald        print("bitpool wrong (E: %d, D: %d)" % (actual_frame.bitpool, expected_frame.bitpool))
535f21c38aSMilanka Ringwald        return -1
545f21c38aSMilanka Ringwald
555f21c38aSMilanka Ringwald    return 0
565f21c38aSMilanka Ringwald
574771dcb8SMilanka Ringwaldfile_size = 0
58205be8eaSMilanka Ringwalddef get_actual_frame(fin, implementation, frame_count):
594771dcb8SMilanka Ringwald    global file_size
605f21c38aSMilanka Ringwald    actual_frame = SBCFrame()
614771dcb8SMilanka Ringwald    sbc_unpack_frame(fin, file_size - fin.tell(), actual_frame)
625f21c38aSMilanka Ringwald    sbc_reconstruct_subband_samples(actual_frame)
63205be8eaSMilanka Ringwald    if subband_frame_count == 0:
64205be8eaSMilanka Ringwald        sbc_init_sythesis(actual_frame.nr_subbands, implementation)
65*6ccd8248SMilanka Ringwald        print(actual_frame)
66205be8eaSMilanka Ringwald    sbc_synthesis(actual_frame, implementation)
675f21c38aSMilanka Ringwald    return actual_frame
685f21c38aSMilanka Ringwald
695665ea35SMilanka Ringwalddef get_expected_frame(fin_expected, nr_blocks, nr_subbands, nr_channels, sampling_frequency, bitpool, allocation_method):
705665ea35SMilanka Ringwald    expected_frame = SBCFrame(nr_blocks, nr_subbands, nr_channels, sampling_frequency, bitpool, allocation_method)
715f21c38aSMilanka Ringwald    fetch_samples_for_next_sbc_frame(fin_expected, expected_frame)
72205be8eaSMilanka Ringwald    calculate_channel_mode_and_scale_factors(expected_frame, 0)
735f21c38aSMilanka Ringwald    return expected_frame
745f21c38aSMilanka Ringwald
755f21c38aSMilanka Ringwaldusage = '''
76205be8eaSMilanka RingwaldUsage:      ./sbc_decoder_test.py decoder_input.sbc force_channel_mode[No=0, Stereo=2, Joint Stereo=3] implementation[SIG, V1] decoder_expected_output.wav
77205be8eaSMilanka RingwaldExample:    ./sbc_decoder_test.py fanfare-4sb.sbc 0 fanfare-4sb-decoded.wav
785f21c38aSMilanka Ringwald'''
795f21c38aSMilanka Ringwald
80205be8eaSMilanka Ringwaldif (len(sys.argv) < 5):
815f21c38aSMilanka Ringwald    print(usage)
825f21c38aSMilanka Ringwald    sys.exit(1)
835f21c38aSMilanka Ringwaldtry:
845f21c38aSMilanka Ringwald    decoder_input_sbc = sys.argv[1]
85205be8eaSMilanka Ringwald    force_channel_mode = int(sys.argv[2])
86205be8eaSMilanka Ringwald    implementation = sys.argv[3]
87205be8eaSMilanka Ringwald    decoder_expected_wav = sys.argv[4]
885f21c38aSMilanka Ringwald
895f21c38aSMilanka Ringwald    if not decoder_input_sbc.endswith('.sbc'):
905f21c38aSMilanka Ringwald        print(usage)
915f21c38aSMilanka Ringwald        sys.exit(1)
925f21c38aSMilanka Ringwald
935f21c38aSMilanka Ringwald    if not decoder_expected_wav.endswith('.wav'):
945f21c38aSMilanka Ringwald        print(usage)
955f21c38aSMilanka Ringwald        sys.exit(1)
965f21c38aSMilanka Ringwald
97205be8eaSMilanka Ringwald
98205be8eaSMilanka Ringwald
995f21c38aSMilanka Ringwald    fin_expected = wave.open(decoder_expected_wav, 'rb')
1005f21c38aSMilanka Ringwald    nr_channels, sampwidth, sampling_frequency, nr_audio_frames, comptype, compname =  fin_expected.getparams()
1015f21c38aSMilanka Ringwald
1025f21c38aSMilanka Ringwald    with open(decoder_input_sbc, 'rb') as fin:
1035f21c38aSMilanka Ringwald        try:
1045f21c38aSMilanka Ringwald            subband_frame_count = 0
1054771dcb8SMilanka Ringwald            fin.seek(0,2)
1064771dcb8SMilanka Ringwald            file_size = fin.tell()
1074771dcb8SMilanka Ringwald            fin.seek(0,0)
1084771dcb8SMilanka Ringwald
1095f21c38aSMilanka Ringwald            while True:
1105f21c38aSMilanka Ringwald                if subband_frame_count % 200 == 0:
1114771dcb8SMilanka Ringwald                    print("== Frame %d ==" % subband_frame_count)
1125f21c38aSMilanka Ringwald
113f08a674bSMilanka Ringwald
114205be8eaSMilanka Ringwald                actual_frame = get_actual_frame(fin, implementation, subband_frame_count)
1154771dcb8SMilanka Ringwald
1165f21c38aSMilanka Ringwald                expected_frame = get_expected_frame(fin_expected, actual_frame.nr_blocks,
1175f21c38aSMilanka Ringwald                                                actual_frame.nr_subbands, nr_channels,
1185665ea35SMilanka Ringwald                                                actual_frame.bitpool, sampling_frequency,
1195665ea35SMilanka Ringwald                                                actual_frame.allocation_method)
1205f21c38aSMilanka Ringwald
1215f21c38aSMilanka Ringwald                err = sbc_compare_headers(subband_frame_count, actual_frame, expected_frame)
122f08a674bSMilanka Ringwald
1235f21c38aSMilanka Ringwald                if err < 0:
124205be8eaSMilanka Ringwald                    print("Frame %d: Headers differ \n%s\n%s" % (subband_frame_count, actual_frame, expected_frame))
125ef8a7a12SMilanka Ringwald                    sys.exit(1)
1265f21c38aSMilanka Ringwald
1275f21c38aSMilanka Ringwald                err = sbc_compare_pcm(subband_frame_count, actual_frame, expected_frame)
1285f21c38aSMilanka Ringwald                if err < 0:
129205be8eaSMilanka Ringwald                    print("Frame %d: PCMs differ %f \n%s\n%s" % (subband_frame_count, max_error, actual_frame.pcm, expected_frame.pcm))
130ef8a7a12SMilanka Ringwald                    sys.exit(1)
1315f21c38aSMilanka Ringwald
1325665ea35SMilanka Ringwald
1335f21c38aSMilanka Ringwald                subband_frame_count += 1
1345f21c38aSMilanka Ringwald
1355f21c38aSMilanka Ringwald        except TypeError:
1365f21c38aSMilanka Ringwald            fin_expected.close()
1375f21c38aSMilanka Ringwald            fin.close()
138f08a674bSMilanka Ringwald            print("DONE, max MSE PCM error %f" % max_error)
1395f21c38aSMilanka Ringwald
1405f21c38aSMilanka Ringwaldexcept IOError as e:
1415f21c38aSMilanka Ringwald    print(usage)
1425f21c38aSMilanka Ringwald    sys.exit(1)
1435f21c38aSMilanka Ringwald
1445f21c38aSMilanka Ringwald
1455f21c38aSMilanka Ringwald
1465f21c38aSMilanka Ringwald
1475f21c38aSMilanka Ringwald
148