xref: /btstack/test/sbc/sbc_encoder_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
13ef8a7a12SMilanka Ringwald
14ef8a7a12SMilanka Ringwalddef sbc_compare_subband_samples(frame_count, actual_frame, expected_frame):
155f21c38aSMilanka Ringwald    global error, max_error
16ef8a7a12SMilanka Ringwald    for blk in range(actual_frame.nr_blocks):
175c9bef5bSMilanka Ringwald        for ch in range(actual_frame.nr_channels):
18ef8a7a12SMilanka Ringwald            M = mse(actual_frame.sb_sample[blk][ch], expected_frame.sb_sample[blk][ch])
195f21c38aSMilanka Ringwald            if M > max_error:
205f21c38aSMilanka Ringwald                max_error = M
215f21c38aSMilanka Ringwald
22ef8a7a12SMilanka Ringwald            if max_error > error:
23*6ccd8248SMilanka Ringwald                print ("Frame %d: sb_sample error %f (ch %d, blk %d)" % (frame_count, max_error, ch, blk))
24*6ccd8248SMilanka Ringwald                print (actual_frame.sb_sample[blk])
25*6ccd8248SMilanka Ringwald                print (expected_frame.sb_sample[blk])
26ef8a7a12SMilanka Ringwald                return -1
27ef8a7a12SMilanka Ringwald    return 0
28ef8a7a12SMilanka Ringwald
29ef8a7a12SMilanka Ringwalddef sbc_compare_audio_frames(frame_count, actual_frame, expected_frame):
30ef8a7a12SMilanka Ringwald    global error, max_error
31ef8a7a12SMilanka Ringwald
32ef8a7a12SMilanka Ringwald    for blk in range(actual_frame.nr_blocks):
33ef8a7a12SMilanka Ringwald        for ch in range(actual_frame.nr_channels):
34ef8a7a12SMilanka Ringwald            M = mse(actual_frame.audio_sample[blk][ch], expected_frame.audio_sample[blk][ch])
35ef8a7a12SMilanka Ringwald            if M > max_error:
36ef8a7a12SMilanka Ringwald                max_error = M
37ef8a7a12SMilanka Ringwald
38ef8a7a12SMilanka Ringwald        if max_error > error:
39*6ccd8248SMilanka Ringwald            print ("audio_sample error (%d, %f ) " % (frame_count, max_error))
40*6ccd8248SMilanka Ringwald            print (actual_frame.audio_sample[blk])
41*6ccd8248SMilanka Ringwald            print (expected_frame.audio_sample[blk])
42ef8a7a12SMilanka Ringwald
435f21c38aSMilanka Ringwald            return -1
445f21c38aSMilanka Ringwald    return 0
455f21c38aSMilanka Ringwald
465f21c38aSMilanka Ringwalddef sbc_compare_headers(frame_count, actual_frame, expected_frame):
475f21c38aSMilanka Ringwald    if actual_frame.syncword != expected_frame.syncword:
48*6ccd8248SMilanka Ringwald        print ("syncword wrong ", actual_frame.syncword)
495f21c38aSMilanka Ringwald        return -1
505f21c38aSMilanka Ringwald
515f21c38aSMilanka Ringwald    if actual_frame.sampling_frequency != expected_frame.sampling_frequency:
52*6ccd8248SMilanka Ringwald        print ("sampling_frequency wrong ", actual_frame.sampling_frequency)
535f21c38aSMilanka Ringwald        return -1
545f21c38aSMilanka Ringwald
555f21c38aSMilanka Ringwald    if actual_frame.nr_blocks != expected_frame.nr_blocks:
56*6ccd8248SMilanka Ringwald        print ("nr_blocks wrong ", actual_frame.nr_blocks)
575f21c38aSMilanka Ringwald        return -1
585f21c38aSMilanka Ringwald
595f21c38aSMilanka Ringwald    if actual_frame.channel_mode != expected_frame.channel_mode:
60*6ccd8248SMilanka Ringwald        print ("channel_mode wrong ", actual_frame.channel_mode)
615f21c38aSMilanka Ringwald        return -1
625f21c38aSMilanka Ringwald
635f21c38aSMilanka Ringwald    if actual_frame.nr_channels != expected_frame.nr_channels:
64*6ccd8248SMilanka Ringwald        print ("nr_channels wrong ", actual_frame.nr_channels)
655f21c38aSMilanka Ringwald        return -1
665f21c38aSMilanka Ringwald
675f21c38aSMilanka Ringwald    if actual_frame.allocation_method != expected_frame.allocation_method:
68*6ccd8248SMilanka Ringwald        print ("allocation_method wrong ", actual_frame.allocation_method)
695f21c38aSMilanka Ringwald        return -1
705f21c38aSMilanka Ringwald
715f21c38aSMilanka Ringwald    if actual_frame.nr_subbands != expected_frame.nr_subbands:
72*6ccd8248SMilanka Ringwald        print ("nr_subbands wrong ", actual_frame.nr_subbands)
735f21c38aSMilanka Ringwald        return -1
745f21c38aSMilanka Ringwald
755f21c38aSMilanka Ringwald    if actual_frame.bitpool != expected_frame.bitpool:
76*6ccd8248SMilanka Ringwald        print ("bitpool wrong (E: %d, D: %d)" % (actual_frame.bitpool, expected_frame.bitpool))
775f21c38aSMilanka Ringwald        return -1
785f21c38aSMilanka Ringwald
795f21c38aSMilanka Ringwald    if  mse(actual_frame.join, expected_frame.join) > 0:
80*6ccd8248SMilanka Ringwald        print ("join error \nE:\n %s \nD:\n %s" % (actual_frame.join, expected_frame.join))
815f21c38aSMilanka Ringwald        return -1
825f21c38aSMilanka Ringwald
835c9bef5bSMilanka Ringwald
845f21c38aSMilanka Ringwald    if  mse(actual_frame.scale_factor, expected_frame.scale_factor) > 0:
85*6ccd8248SMilanka Ringwald        print ("scale_factor error %d \nE:\n %s \nD:\n %s" % (frame_count, actual_frame.scale_factor, expected_frame.scale_factor))
865f21c38aSMilanka Ringwald        return -1
875f21c38aSMilanka Ringwald
885f21c38aSMilanka Ringwald    if  mse(actual_frame.scalefactor, expected_frame.scalefactor) > 0:
89*6ccd8248SMilanka Ringwald        print ("scalefactor error %d \nE:\n %s \nD:\n %s" % (frame_count, actual_frame.scalefactor, expected_frame.scalefactor))
905f21c38aSMilanka Ringwald        return -1
915f21c38aSMilanka Ringwald
925f21c38aSMilanka Ringwald    if  mse(actual_frame.bits, expected_frame.bits) > 0:
93*6ccd8248SMilanka Ringwald        print ("bits error %d \nE:\n %s \nD:\n %s" % (frame_count, actual_frame.bits, expected_frame.bits))
945f21c38aSMilanka Ringwald        return -1
955f21c38aSMilanka Ringwald
965f21c38aSMilanka Ringwald    if actual_frame.crc_check != expected_frame.crc_check:
97*6ccd8248SMilanka Ringwald        print ("crc_check wrong (E: %d, D: %d)" % (actual_frame.crc_check, expected_frame.crc_check))
985f21c38aSMilanka Ringwald        return -1
995f21c38aSMilanka Ringwald
1005f21c38aSMilanka Ringwald    return 0
1015f21c38aSMilanka Ringwald
1025f21c38aSMilanka Ringwald
103ef8a7a12SMilanka Ringwalddef get_actual_frame(fin, nr_blocks, nr_subbands, nr_channels, sampling_frequency, bitpool, allocation_method, force_channel_mode):
1045665ea35SMilanka Ringwald    actual_frame = SBCFrame(nr_blocks, nr_subbands, nr_channels, sampling_frequency, bitpool, allocation_method)
1055f21c38aSMilanka Ringwald    fetch_samples_for_next_sbc_frame(fin, actual_frame)
106ef8a7a12SMilanka Ringwald    sbc_encode(actual_frame, force_channel_mode)
1075f21c38aSMilanka Ringwald    return actual_frame
1085f21c38aSMilanka Ringwald
1095665ea35SMilanka Ringwaldfile_size = 0
1105f21c38aSMilanka Ringwalddef get_expected_frame(fin_expected):
1115665ea35SMilanka Ringwald    global file_size
1125f21c38aSMilanka Ringwald    expected_frame = SBCFrame()
1135665ea35SMilanka Ringwald    sbc_unpack_frame(fin_expected, file_size - fin_expected.tell(), expected_frame)
114ef8a7a12SMilanka Ringwald    sbc_reconstruct_subband_samples(expected_frame)
1155f21c38aSMilanka Ringwald    return expected_frame
1165f21c38aSMilanka Ringwald
1175f21c38aSMilanka Ringwaldusage = '''
118ef8a7a12SMilanka RingwaldUsage:      ./sbc_encoder_test.py encoder_input.wav blocks subbands bitpool allocation_method force_channel_mode encoder_expected_output.sbc
119ef8a7a12SMilanka RingwaldExample:    ./sbc_encoder_test.py fanfare.wav 16 4 31 0 2 fanfare-4sb.sbc
1205f21c38aSMilanka Ringwald'''
1215f21c38aSMilanka Ringwald
122ef8a7a12SMilanka Ringwaldif (len(sys.argv) < 8):
1235f21c38aSMilanka Ringwald    print(usage)
1245f21c38aSMilanka Ringwald    sys.exit(1)
1255f21c38aSMilanka Ringwaldtry:
1265f21c38aSMilanka Ringwald    encoder_input_wav = sys.argv[1]
1275f21c38aSMilanka Ringwald    nr_blocks = int(sys.argv[2])
1285f21c38aSMilanka Ringwald    nr_subbands = int(sys.argv[3])
1295f21c38aSMilanka Ringwald    bitpool = int(sys.argv[4])
1305665ea35SMilanka Ringwald    allocation_method = int(sys.argv[5])
1315665ea35SMilanka Ringwald    encoder_expected_sbc = sys.argv[6]
132205be8eaSMilanka Ringwald    force_channel_mode = int(sys.argv[7])
1335f21c38aSMilanka Ringwald    sampling_frequency = 44100
1345f21c38aSMilanka Ringwald
1355f21c38aSMilanka Ringwald    if not encoder_input_wav.endswith('.wav'):
1365f21c38aSMilanka Ringwald        print(usage)
1375f21c38aSMilanka Ringwald        sys.exit(1)
1385f21c38aSMilanka Ringwald
1395f21c38aSMilanka Ringwald    if not encoder_expected_sbc.endswith('.sbc'):
1405f21c38aSMilanka Ringwald        print(usage)
1415f21c38aSMilanka Ringwald        sys.exit(1)
1425f21c38aSMilanka Ringwald
1435f21c38aSMilanka Ringwald    fin = wave.open(encoder_input_wav, 'rb')
1445f21c38aSMilanka Ringwald    nr_channels = fin.getnchannels()
1455f21c38aSMilanka Ringwald    sampling_frequency = fin.getframerate()
1465f21c38aSMilanka Ringwald    nr_audio_frames = fin.getnframes()
1475f21c38aSMilanka Ringwald
1485f21c38aSMilanka Ringwald    fin_expected = open(encoder_expected_sbc, 'rb')
1495665ea35SMilanka Ringwald    fin_expected.seek(0,2)
1505665ea35SMilanka Ringwald    file_size = fin_expected.tell()
1515665ea35SMilanka Ringwald    fin_expected.seek(0,0)
1525665ea35SMilanka Ringwald
1535f21c38aSMilanka Ringwald    subband_frame_count = 0
1545f21c38aSMilanka Ringwald    audio_frame_count = 0
1555f21c38aSMilanka Ringwald    nr_samples = nr_blocks * nr_subbands
1565f21c38aSMilanka Ringwald
1575f21c38aSMilanka Ringwald    while audio_frame_count < nr_audio_frames:
1585f21c38aSMilanka Ringwald        if subband_frame_count % 200 == 0:
1595f21c38aSMilanka Ringwald            print("== Frame %d ==" % (subband_frame_count))
1605f21c38aSMilanka Ringwald
161ef8a7a12SMilanka Ringwald        actual_frame = get_actual_frame(fin, nr_blocks, nr_subbands, nr_channels, bitpool, sampling_frequency, allocation_method, force_channel_mode)
1625f21c38aSMilanka Ringwald        expected_frame = get_expected_frame(fin_expected)
1635f21c38aSMilanka Ringwald
1645f21c38aSMilanka Ringwald        err = sbc_compare_headers(subband_frame_count, actual_frame, expected_frame)
1655f21c38aSMilanka Ringwald        if err < 0:
1665f21c38aSMilanka Ringwald            exit(1)
1675f21c38aSMilanka Ringwald
1685f21c38aSMilanka Ringwald        err = sbc_compare_audio_frames(subband_frame_count, actual_frame, expected_frame)
1695f21c38aSMilanka Ringwald        if err < 0:
1705f21c38aSMilanka Ringwald            exit(1)
1715665ea35SMilanka Ringwald
1725f21c38aSMilanka Ringwald        audio_frame_count += nr_samples
1735f21c38aSMilanka Ringwald        subband_frame_count += 1
1745f21c38aSMilanka Ringwald
175ef8a7a12SMilanka Ringwald    print ("Max MSE audio sample error %f" % max_error)
1765f21c38aSMilanka Ringwald    fin.close()
1775f21c38aSMilanka Ringwald    fin_expected.close()
1785f21c38aSMilanka Ringwald
1795665ea35SMilanka Ringwaldexcept TypeError:
180ef8a7a12SMilanka Ringwald    print ("Max MSE audio sample error %f" % max_error)
1815665ea35SMilanka Ringwald    fin.close()
1825665ea35SMilanka Ringwald    fin_expected.close()
1835665ea35SMilanka Ringwald
1845f21c38aSMilanka Ringwaldexcept IOError:
1855f21c38aSMilanka Ringwald    print(usage)
1865f21c38aSMilanka Ringwald    sys.exit(1)
1875f21c38aSMilanka Ringwald
1885f21c38aSMilanka Ringwald
1895f21c38aSMilanka Ringwald
1905f21c38aSMilanka Ringwald
1915f21c38aSMilanka Ringwald
192