xref: /btstack/test/sbc/sbc_encoder.py (revision 57f2bc22c3d2b2d1a8fbf0480438b0ce896ec6b5)
1#!/usr/bin/env python
2import numpy as np
3import wave
4import struct
5import sys
6from sbc import *
7
8X = np.zeros(shape=(2,80), dtype = np.int16)
9
10
11def fetch_samples_for_next_sbc_frame(fin, frame):
12    nr_samples = frame.nr_blocks * frame.nr_subbands
13    raw_data = fin.readframes(nr_samples) # Returns byte data
14    fmt = "%ih" % (len(raw_data) / 2)
15    data = struct.unpack(fmt, raw_data)
16
17    if frame.nr_channels == 2:
18        for i in range(len(data)/2):
19            frame.pcm[0][i] = data[2*i]
20            frame.pcm[1][i] = data[2*i+1]
21    else:
22        for i in range(len(data)):
23            frame.pcm[0][i] = data[i]
24
25
26def sbc_frame_analysis(frame, ch, blk, C):
27    global X
28
29    M = frame.nr_subbands
30    L = 10 * M
31    M2 = 2*M
32    L2 = 2*L
33
34    Z = np.zeros(L)
35    Y = np.zeros(M2)
36    W = np.zeros(shape=(M, M2))
37    S = np.zeros(M)
38
39    for i in range(L-1, M-1, -1):
40        X[ch][i] = X[ch][i-M]
41    for i in range(M-1, -1, -1):
42        X[ch][i] = frame.EX[M-1-i]
43    for i in range(L):
44        Z[i] = X[ch][i] * C[i]
45
46    for i in range(M2):
47        for k in range(5):
48            Y[i] += Z[i+k*M2]
49
50    for i in range(M):
51        for k in range(M2):
52            W[i][k] = np.cos((i+0.5)*(k-M/2)*np.pi/M)
53            S[i] += W[i][k] * Y[k]
54
55    for sb in range(M):
56        frame.sb_sample[blk][ch][sb] = S[sb]
57
58def sbc_analysis(frame):
59    if frame.nr_subbands == 4:
60        C = Proto_4_40
61    elif frame.nr_subbands == 8:
62        C = Proto_8_80
63    else:
64        return -1
65
66    frame.sb_sample = np.ndarray(shape=(frame.nr_blocks, frame.nr_channels, frame.nr_subbands))
67    for ch in range(frame.nr_channels):
68        index = 0
69        for blk in range(frame.nr_blocks):
70            for sb in range(frame.nr_subbands):
71                frame.EX[sb] = frame.pcm[ch][index]
72                index+=1
73            sbc_frame_analysis(frame, ch, blk, C)
74    return 0
75
76def sbc_encode(frame):
77    err = sbc_analysis(frame)
78    if err >= 0:
79        err = sbc_quantization(frame)
80    return err
81
82def sbc_quantization(frame):
83    calculate_channel_mode_and_scale_factors(frame)
84    frame.bits = sbc_bit_allocation(frame)
85
86    # Reconstruct the Audio Samples
87    frame.levels = np.zeros(shape=(frame.nr_channels, frame.nr_subbands), dtype = np.int32)
88    for ch in range(frame.nr_channels):
89        for sb in range(frame.nr_subbands):
90            frame.levels[ch][sb] = (1 << frame.bits[ch][sb]) - 1 #pow(2.0, frame.bits[ch][sb]) - 1
91
92    frame.syncword = 0x9c
93    frame.crc_check = calculate_crc(frame)
94
95
96    for blk in range(frame.nr_blocks):
97        for ch in range(frame.nr_channels):
98            for sb in range(frame.nr_subbands):
99                if frame.levels[ch][sb] > 0:
100                    SB = frame.sb_sample[blk][ch][sb]
101                    L  = frame.levels[ch][sb]
102                    SF = frame.scalefactor[ch][sb]
103
104                    # if frame.channel_mode == JOINT_STEREO and frame.join[sb]:
105                    #     SB = SB * 2
106
107                    frame.audio_sample[blk][ch][sb] = np.uint16(((SB * L / SF + L) - 1.0)/2.0)
108                else:
109                    frame.audio_sample[blk][ch][sb] = 0
110
111    return 0
112
113def sbc_write_frame(fout, sbc_encoder_frame):
114    stream = frame_to_bitstream(sbc_encoder_frame)
115    barray = bytearray(stream)
116    fout.write(barray)
117
118if __name__ == "__main__":
119    usage = '''
120    Usage:      ./sbc_encoder.py input.wav blocks subbands bitpool allocation_method[0-LOUDNESS,1-SNR]
121    Example:    ./sbc_encoder.py fanfare.wav 16 4 31 0
122    '''
123    nr_blocks = 0
124    nr_subbands = 0
125
126
127    if (len(sys.argv) < 6):
128        print(usage)
129        sys.exit(1)
130    try:
131        infile = sys.argv[1]
132        if not infile.endswith('.wav'):
133            print(usage)
134            sys.exit(1)
135        sbcfile = infile.replace('.wav', '-encoded.sbc')
136
137        nr_blocks = int(sys.argv[2])
138        nr_subbands = int(sys.argv[3])
139        bitpool = int(sys.argv[4])
140        allocation_method = int(sys.argv[5])
141
142        fin = wave.open(infile, 'rb')
143        nr_channels = fin.getnchannels()
144        sampling_frequency = fin.getframerate()
145        nr_audio_frames = fin.getnframes()
146
147        subband_frame_count = 0
148        audio_frame_count = 0
149        nr_samples = nr_blocks * nr_subbands
150        fout = open(sbcfile, 'wb')
151        while audio_frame_count < nr_audio_frames:
152            if subband_frame_count % 200 == 0:
153                print("== Frame %d ==" % (subband_frame_count))
154
155            sbc_encoder_frame = SBCFrame(nr_blocks, nr_subbands, nr_channels, bitpool, sampling_frequency, allocation_method)
156            fetch_samples_for_next_sbc_frame(fin, sbc_encoder_frame)
157
158            sbc_encode(sbc_encoder_frame)
159            sbc_write_frame(fout, sbc_encoder_frame)
160
161            # if subband_frame_count == 1:
162            #     exit(0)
163            audio_frame_count += nr_samples
164            subband_frame_count += 1
165
166
167        fin.close()
168        fout.close()
169        print("DONE, WAV file %s encoded into SBC file %s " % (infile, sbcfile))
170
171
172    except IOError as e:
173        print(usage)
174        sys.exit(1)
175
176
177
178
179
180