xref: /btstack/test/sbc/sbc_decoder.py (revision 5c9bef5ba273d4d18de0f76f9370002de99dfae4)
1d86ce1b2SMilanka Ringwald#!/usr/bin/env python
2d86ce1b2SMilanka Ringwaldimport numpy as np
3d86ce1b2SMilanka Ringwaldimport wave
4d86ce1b2SMilanka Ringwaldimport struct
5d86ce1b2SMilanka Ringwaldimport sys
6c21a9c2fSMilanka Ringwaldfrom sbc import *
7d86ce1b2SMilanka Ringwald
8c21a9c2fSMilanka RingwaldV = np.zeros(shape = (2, 10*2*8))
9d86ce1b2SMilanka Ringwald
105665ea35SMilanka Ringwalddef sbc_unpack_frame(fin, available_bytes, frame):
115665ea35SMilanka Ringwald    if available_bytes == 0:
12f08a674bSMilanka Ringwald        print "no available_bytes"
135665ea35SMilanka Ringwald        raise TypeError
145665ea35SMilanka Ringwald
15d86ce1b2SMilanka Ringwald    frame.syncword = get_bits(fin,8)
16d86ce1b2SMilanka Ringwald    if frame.syncword != 156:
17f08a674bSMilanka Ringwald        print ("out of sync %02x" % frame.syncword)
18d86ce1b2SMilanka Ringwald        return -1
19d86ce1b2SMilanka Ringwald    frame.sampling_frequency = get_bits(fin,2)
20d86ce1b2SMilanka Ringwald    frame.nr_blocks = nr_blocks[get_bits(fin,2)]
21d86ce1b2SMilanka Ringwald    frame.channel_mode = get_bits(fin,2)
22ad470863SMilanka Ringwald
23d86ce1b2SMilanka Ringwald    if frame.channel_mode == MONO:
24d86ce1b2SMilanka Ringwald        frame.nr_channels = 1
25d86ce1b2SMilanka Ringwald    else:
26d86ce1b2SMilanka Ringwald        frame.nr_channels = 2
27d86ce1b2SMilanka Ringwald
28d86ce1b2SMilanka Ringwald    frame.allocation_method = get_bits(fin,1)
29d86ce1b2SMilanka Ringwald    frame.nr_subbands = nr_subbands[get_bits(fin,1)]
30*5c9bef5bSMilanka Ringwald    frame.init(frame.nr_blocks, frame.nr_subbands, frame.nr_channels)
31*5c9bef5bSMilanka Ringwald
32d86ce1b2SMilanka Ringwald    frame.bitpool = get_bits(fin,8)
33d86ce1b2SMilanka Ringwald    frame.crc_check = get_bits(fin,8)
34d86ce1b2SMilanka Ringwald
35*5c9bef5bSMilanka Ringwald
36*5c9bef5bSMilanka Ringwald    # frame.join = np.zeros(frame.nr_subbands, dtype = np.uint8)
37d86ce1b2SMilanka Ringwald
38d86ce1b2SMilanka Ringwald    if frame.channel_mode == JOINT_STEREO:
39d86ce1b2SMilanka Ringwald        frame.join = np.zeros(frame.nr_subbands-1)
40d86ce1b2SMilanka Ringwald        for sb in range(frame.nr_subbands-1):
41d86ce1b2SMilanka Ringwald            frame.join[sb] = get_bits(fin,1)
42d86ce1b2SMilanka Ringwald        get_bits(fin,1) # RFA
43d86ce1b2SMilanka Ringwald
44d86ce1b2SMilanka Ringwald    frame.scale_factor = np.zeros(shape=(frame.nr_channels, frame.nr_subbands), dtype = np.int32)
45d86ce1b2SMilanka Ringwald
46d86ce1b2SMilanka Ringwald    # print frame.audio_sample
47d86ce1b2SMilanka Ringwald
48d86ce1b2SMilanka Ringwald    for ch in range(frame.nr_channels):
49d86ce1b2SMilanka Ringwald        for sb in range(frame.nr_subbands):
50d86ce1b2SMilanka Ringwald            frame.scale_factor[ch][sb] = get_bits(fin, 4)
511522543dSMilanka Ringwald
52c21a9c2fSMilanka Ringwald    crc = calculate_crc(frame)
53c21a9c2fSMilanka Ringwald    if crc != frame.crc_check:
54ad470863SMilanka Ringwald        print frame
55c21a9c2fSMilanka Ringwald        print "error, crc not equal: ", crc, frame.crc_check
56c21a9c2fSMilanka Ringwald        exit(1)
57c21a9c2fSMilanka Ringwald
58ad470863SMilanka Ringwald    frame.scalefactor = np.zeros(shape=(frame.nr_channels, frame.nr_subbands), dtype = np.int32)
59d86ce1b2SMilanka Ringwald    for ch in range(frame.nr_channels):
60d86ce1b2SMilanka Ringwald        for sb in range(frame.nr_subbands):
61d86ce1b2SMilanka Ringwald            frame.scalefactor[ch][sb] = 1 << (frame.scale_factor[ch][sb] + 1)
62d86ce1b2SMilanka Ringwald
63d86ce1b2SMilanka Ringwald
64ad470863SMilanka Ringwald    frame.bits = sbc_bit_allocation(frame)
65ad470863SMilanka Ringwald
66ad470863SMilanka Ringwald    frame.audio_sample = np.ndarray(shape=(frame.nr_blocks, frame.nr_channels, frame.nr_subbands), dtype = np.uint16)
67d86ce1b2SMilanka Ringwald    for blk in range(frame.nr_blocks):
68d86ce1b2SMilanka Ringwald        for ch in range(frame.nr_channels):
69d86ce1b2SMilanka Ringwald            for sb in range(frame.nr_subbands):
70c21a9c2fSMilanka Ringwald                frame.audio_sample[blk][ch][sb] = get_bits(fin, frame.bits[ch][sb])
71d86ce1b2SMilanka Ringwald        #print "block %2d - audio sample: %s" % (blk, frame.audio_sample[blk][0])
72d86ce1b2SMilanka Ringwald
73d86ce1b2SMilanka Ringwald    drop_remaining_bits()
74ad470863SMilanka Ringwald    return 0
75d86ce1b2SMilanka Ringwald
76ad470863SMilanka Ringwalddef sbc_reconstruct_subband_samples(frame):
77c21a9c2fSMilanka Ringwald    frame.levels = np.zeros(shape=(frame.nr_channels, frame.nr_subbands), dtype = np.int32)
78c21a9c2fSMilanka Ringwald    frame.sb_sample = np.zeros(shape=(frame.nr_blocks, frame.nr_channels, frame.nr_subbands))
79d86ce1b2SMilanka Ringwald
80d86ce1b2SMilanka Ringwald    for ch in range(frame.nr_channels):
81d86ce1b2SMilanka Ringwald        for sb in range(frame.nr_subbands):
82c21a9c2fSMilanka Ringwald            frame.levels[ch][sb] = pow(2.0, frame.bits[ch][sb]) - 1
83d86ce1b2SMilanka Ringwald
84d86ce1b2SMilanka Ringwald    for blk in range(frame.nr_blocks):
85d86ce1b2SMilanka Ringwald        for ch in range(frame.nr_channels):
86d86ce1b2SMilanka Ringwald            for sb in range(frame.nr_subbands):
87c21a9c2fSMilanka Ringwald                if frame.levels[ch][sb] > 0:
88c21a9c2fSMilanka Ringwald                    AS = frame.audio_sample[blk][ch][sb]
89c21a9c2fSMilanka Ringwald                    SF = frame.scalefactor[ch][sb]
90c21a9c2fSMilanka Ringwald                    L  = frame.levels[ch][sb]
91c21a9c2fSMilanka Ringwald
9241a4a18dSMilanka Ringwald                    frame.sb_sample[blk][ch][sb] = SF * ((AS*2.0+1.0) / L -1.0 )
93d86ce1b2SMilanka Ringwald                else:
94c21a9c2fSMilanka Ringwald                    frame.sb_sample[blk][ch][sb] = 0
95d86ce1b2SMilanka Ringwald
96d86ce1b2SMilanka Ringwald    # sythesis filter
97d86ce1b2SMilanka Ringwald    if frame.channel_mode == JOINT_STEREO:
98d86ce1b2SMilanka Ringwald        for blk in range(frame.nr_blocks):
99d86ce1b2SMilanka Ringwald            for sb in range(frame.nr_subbands):
100d86ce1b2SMilanka Ringwald                if frame.join[sb]==1:
101c21a9c2fSMilanka Ringwald                    ch_a = frame.sb_sample[blk][0][sb] + frame.sb_sample[blk][1][sb]
102c21a9c2fSMilanka Ringwald                    ch_b = frame.sb_sample[blk][0][sb] - frame.sb_sample[blk][1][sb]
103c21a9c2fSMilanka Ringwald                    frame.sb_sample[blk][0][sb] = ch_a
104c21a9c2fSMilanka Ringwald                    frame.sb_sample[blk][1][sb] = ch_b
105c21a9c2fSMilanka Ringwald
106d86ce1b2SMilanka Ringwald    return 0
107d86ce1b2SMilanka Ringwald
108d86ce1b2SMilanka Ringwald
109ad470863SMilanka Ringwalddef sbc_frame_synthesis(frame, ch, blk, proto_table):
110c21a9c2fSMilanka Ringwald    global V
111d86ce1b2SMilanka Ringwald    M = frame.nr_subbands
112d86ce1b2SMilanka Ringwald    L = 10 * M
113d86ce1b2SMilanka Ringwald    M2 = 2*M
114d86ce1b2SMilanka Ringwald    L2 = 2*L
115d86ce1b2SMilanka Ringwald
116d86ce1b2SMilanka Ringwald    S = np.zeros(M)
117d86ce1b2SMilanka Ringwald    U = np.zeros(L)
118d86ce1b2SMilanka Ringwald    W = np.zeros(L)
119d86ce1b2SMilanka Ringwald    frame.X = np.zeros(M)
120d86ce1b2SMilanka Ringwald
121d86ce1b2SMilanka Ringwald    for i in range(M):
122c21a9c2fSMilanka Ringwald        S[i] = frame.sb_sample[blk][ch][i]
123d86ce1b2SMilanka Ringwald
124d86ce1b2SMilanka Ringwald    for i in range(L2-1, M2-1,-1):
125d86ce1b2SMilanka Ringwald        V[ch][i] = V[ch][i-M2]
126d86ce1b2SMilanka Ringwald
127d86ce1b2SMilanka Ringwald    for k in range(M2):
128d86ce1b2SMilanka Ringwald        V[ch][k] = 0
129d86ce1b2SMilanka Ringwald        for i in range(M):
1304771dcb8SMilanka Ringwald            N = np.cos((i+0.5)*(k+M/2)*np.pi/M)
131d86ce1b2SMilanka Ringwald            V[ch][k] += N * S[i]
132d86ce1b2SMilanka Ringwald
133d86ce1b2SMilanka Ringwald    for i in range(5):
134d86ce1b2SMilanka Ringwald        for j in range(M):
135d86ce1b2SMilanka Ringwald            U[i*M2+j] = V[ch][i*2*M2+j]
136d82cd87cSMilanka Ringwald            U[(i*2+1)*M+j] = V[ch][(i*4+3)*M+j]
137d86ce1b2SMilanka Ringwald
138d86ce1b2SMilanka Ringwald    for i in range(L):
139d86ce1b2SMilanka Ringwald        D = proto_table[i] * (-M)
140d86ce1b2SMilanka Ringwald        W[i] = U[i]*D
141d86ce1b2SMilanka Ringwald
142d86ce1b2SMilanka Ringwald
1431522543dSMilanka Ringwald    offset = blk*M
144d86ce1b2SMilanka Ringwald    for j in range(M):
145d86ce1b2SMilanka Ringwald        for i in range(10):
146d86ce1b2SMilanka Ringwald            frame.X[j] += W[j+M*i]
1471522543dSMilanka Ringwald        frame.pcm[ch][offset + j] = np.int16(frame.X[j])
148d86ce1b2SMilanka Ringwald
149d86ce1b2SMilanka Ringwald
150ad470863SMilanka Ringwalddef sbc_synthesis(frame):
151d86ce1b2SMilanka Ringwald    if frame.nr_subbands == 4:
152d86ce1b2SMilanka Ringwald        proto_table = Proto_4_40
153d86ce1b2SMilanka Ringwald    elif frame.nr_subbands == 8:
154d86ce1b2SMilanka Ringwald        proto_table = Proto_8_80
155d86ce1b2SMilanka Ringwald    else:
156d86ce1b2SMilanka Ringwald        return -1
157d86ce1b2SMilanka Ringwald    for ch in range(frame.nr_channels):
158d86ce1b2SMilanka Ringwald        for blk in range(frame.nr_blocks):
159ad470863SMilanka Ringwald            sbc_frame_synthesis(frame, ch, blk, proto_table)
160d86ce1b2SMilanka Ringwald
161d86ce1b2SMilanka Ringwald    return frame.nr_blocks * frame.nr_subbands
162d86ce1b2SMilanka Ringwald
163ad470863SMilanka Ringwalddef sbc_decode(frame):
164ad470863SMilanka Ringwald    err = sbc_reconstruct_subband_samples(frame)
165ad470863SMilanka Ringwald    if err >= 0:
166ad470863SMilanka Ringwald        err = sbc_synthesis(frame)
167ad470863SMilanka Ringwald    return err
168d86ce1b2SMilanka Ringwald
169ad470863SMilanka Ringwald
170ad470863SMilanka Ringwalddef write_wav_file(fout, frame):
171d86ce1b2SMilanka Ringwald    values = []
1721522543dSMilanka Ringwald
1731522543dSMilanka Ringwald    for i in range(frame.nr_subbands * frame.nr_blocks):
1741522543dSMilanka Ringwald        for ch in range(frame.nr_channels):
175ad470863SMilanka Ringwald            try:
1761522543dSMilanka Ringwald                packed_value = struct.pack('h', frame.pcm[ch][i])
177d86ce1b2SMilanka Ringwald                values.append(packed_value)
178ad470863SMilanka Ringwald            except struct.error:
179ad470863SMilanka Ringwald                print frame
1801522543dSMilanka Ringwald                print i, frame.pcm[ch][i], frame.pcm[ch]
181ad470863SMilanka Ringwald                exit(1)
182d86ce1b2SMilanka Ringwald
183d86ce1b2SMilanka Ringwald    value_str = ''.join(values)
184d86ce1b2SMilanka Ringwald    fout.writeframes(value_str)
185d86ce1b2SMilanka Ringwald
186d86ce1b2SMilanka Ringwald
187ba114a98SMatthias Ringwaldif __name__ == "__main__":
188ba114a98SMatthias Ringwald    usage = '''
189ba114a98SMatthias Ringwald    Usage: ./sbc_decoder.py input.sbc
190ba114a98SMatthias Ringwald    '''
191d86ce1b2SMilanka Ringwald
192ba114a98SMatthias Ringwald    if (len(sys.argv) < 2):
193ba114a98SMatthias Ringwald        print(usage)
194ba114a98SMatthias Ringwald        sys.exit(1)
195ba114a98SMatthias Ringwald    try:
196ba114a98SMatthias Ringwald        infile = sys.argv[1]
197ba114a98SMatthias Ringwald        if not infile.endswith('.sbc'):
198ba114a98SMatthias Ringwald            print(usage)
199ba114a98SMatthias Ringwald            sys.exit(1)
200d86ce1b2SMilanka Ringwald
201ba114a98SMatthias Ringwald        wavfile = infile.replace('.sbc', '-decoded.wav')
202ad470863SMilanka Ringwald        fout = False
203d86ce1b2SMilanka Ringwald
204ba114a98SMatthias Ringwald        with open (infile, 'rb') as fin:
205ba114a98SMatthias Ringwald            try:
2065665ea35SMilanka Ringwald                fin.seek(0, 2)
2075665ea35SMilanka Ringwald                file_size = fin.tell()
2085665ea35SMilanka Ringwald                fin.seek(0, 0)
2095665ea35SMilanka Ringwald
210ba114a98SMatthias Ringwald                frame_count = 0
211ba114a98SMatthias Ringwald                while True:
2125665ea35SMilanka Ringwald                    sbc_decoder_frame = SBCFrame()
213ba114a98SMatthias Ringwald                    if frame_count % 200 == 0:
214f08a674bSMilanka Ringwald                        print "== Frame %d == %d" % (frame_count, fin.tell())
215f08a674bSMilanka Ringwald
216ad470863SMilanka Ringwald
2175665ea35SMilanka Ringwald                    err = sbc_unpack_frame(fin, file_size - fin.tell(), sbc_decoder_frame)
218*5c9bef5bSMilanka Ringwald                    if frame_count == 0:
219*5c9bef5bSMilanka Ringwald                        print sbc_decoder_frame
220ad470863SMilanka Ringwald
221ba114a98SMatthias Ringwald                    if err:
222ba114a98SMatthias Ringwald                        print "error, frame_count: ", frame_count
223ba114a98SMatthias Ringwald                        break
224ba114a98SMatthias Ringwald
225*5c9bef5bSMilanka Ringwald
226ad470863SMilanka Ringwald                    sbc_decode(sbc_decoder_frame)
227ba114a98SMatthias Ringwald
228ba114a98SMatthias Ringwald                    if frame_count == 0:
229ba114a98SMatthias Ringwald                        fout = wave.open(wavfile, 'w')
230ad470863SMilanka Ringwald                        fout.setnchannels(sbc_decoder_frame.nr_channels)
231ba114a98SMatthias Ringwald                        fout.setsampwidth(2)
232d0818c25SMilanka Ringwald                        fout.setframerate(sampling_frequencies[sbc_decoder_frame.sampling_frequency])
233ba114a98SMatthias Ringwald                        fout.setnframes(0)
234ba114a98SMatthias Ringwald                        fout.setcomptype = 'NONE'
235ba114a98SMatthias Ringwald
236ad470863SMilanka Ringwald                    write_wav_file(fout, sbc_decoder_frame)
237ba114a98SMatthias Ringwald                    frame_count += 1
238ba114a98SMatthias Ringwald
239ad470863SMilanka Ringwald            except TypeError as err:
240ad470863SMilanka Ringwald                if not fout:
241ad470863SMilanka Ringwald                    print err
242ad470863SMilanka Ringwald                else:
243ba114a98SMatthias Ringwald                    fout.close()
244ad470863SMilanka Ringwald                    print ("DONE, SBC file %s decoded into WAV file %s " % (infile, wavfile))
245ba114a98SMatthias Ringwald                exit(0)
246d86ce1b2SMilanka Ringwald
247ba114a98SMatthias Ringwald    except IOError as e:
248ba114a98SMatthias Ringwald        print(usage)
249ba114a98SMatthias Ringwald        sys.exit(1)
250d86ce1b2SMilanka Ringwald
251d86ce1b2SMilanka Ringwald
252d86ce1b2SMilanka Ringwald
253d86ce1b2SMilanka Ringwald
254d86ce1b2SMilanka Ringwald
255