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 10c21a9c2fSMilanka Ringwalddef sbc_unpack_frame(fin, frame): 11d86ce1b2SMilanka Ringwald frame.syncword = get_bits(fin,8) 12d86ce1b2SMilanka Ringwald if frame.syncword != 156: 13d86ce1b2SMilanka Ringwald print "incorrect syncword ", frame.syncword 14d86ce1b2SMilanka Ringwald return -1 15d86ce1b2SMilanka Ringwald frame.sampling_frequency = get_bits(fin,2) 16d86ce1b2SMilanka Ringwald frame.nr_blocks = nr_blocks[get_bits(fin,2)] 17d86ce1b2SMilanka Ringwald frame.channel_mode = get_bits(fin,2) 18*ad470863SMilanka Ringwald 19d86ce1b2SMilanka Ringwald if frame.channel_mode == MONO: 20d86ce1b2SMilanka Ringwald frame.nr_channels = 1 21d86ce1b2SMilanka Ringwald else: 22d86ce1b2SMilanka Ringwald frame.nr_channels = 2 23d86ce1b2SMilanka Ringwald 24d86ce1b2SMilanka Ringwald frame.allocation_method = get_bits(fin,1) 25d86ce1b2SMilanka Ringwald frame.nr_subbands = nr_subbands[get_bits(fin,1)] 26d86ce1b2SMilanka Ringwald frame.bitpool = get_bits(fin,8) 27d86ce1b2SMilanka Ringwald frame.crc_check = get_bits(fin,8) 28d86ce1b2SMilanka Ringwald 29d86ce1b2SMilanka Ringwald frame.join = np.zeros(frame.nr_subbands, dtype = np.uint8) 30d86ce1b2SMilanka Ringwald 31d86ce1b2SMilanka Ringwald if frame.channel_mode == JOINT_STEREO: 32d86ce1b2SMilanka Ringwald frame.join = np.zeros(frame.nr_subbands-1) 33d86ce1b2SMilanka Ringwald for sb in range(frame.nr_subbands-1): 34d86ce1b2SMilanka Ringwald frame.join[sb] = get_bits(fin,1) 35d86ce1b2SMilanka Ringwald get_bits(fin,1) # RFA 36d86ce1b2SMilanka Ringwald 37d86ce1b2SMilanka Ringwald frame.scale_factor = np.zeros(shape=(frame.nr_channels, frame.nr_subbands), dtype = np.int32) 38d86ce1b2SMilanka Ringwald 39d86ce1b2SMilanka Ringwald # print frame.audio_sample 40d86ce1b2SMilanka Ringwald 41d86ce1b2SMilanka Ringwald for ch in range(frame.nr_channels): 42d86ce1b2SMilanka Ringwald for sb in range(frame.nr_subbands): 43d86ce1b2SMilanka Ringwald frame.scale_factor[ch][sb] = get_bits(fin, 4) 44c21a9c2fSMilanka Ringwald crc = calculate_crc(frame) 45c21a9c2fSMilanka Ringwald if crc != frame.crc_check: 46*ad470863SMilanka Ringwald print frame 47c21a9c2fSMilanka Ringwald print "error, crc not equal: ", crc, frame.crc_check 48c21a9c2fSMilanka Ringwald exit(1) 49c21a9c2fSMilanka Ringwald 50*ad470863SMilanka Ringwald frame.scalefactor = np.zeros(shape=(frame.nr_channels, frame.nr_subbands), dtype = np.int32) 51d86ce1b2SMilanka Ringwald for ch in range(frame.nr_channels): 52d86ce1b2SMilanka Ringwald for sb in range(frame.nr_subbands): 53d86ce1b2SMilanka Ringwald frame.scalefactor[ch][sb] = 1 << (frame.scale_factor[ch][sb] + 1) 54d86ce1b2SMilanka Ringwald 55d86ce1b2SMilanka Ringwald 56*ad470863SMilanka Ringwald frame.bits = sbc_bit_allocation(frame) 57*ad470863SMilanka Ringwald 58*ad470863SMilanka Ringwald frame.audio_sample = np.ndarray(shape=(frame.nr_blocks, frame.nr_channels, frame.nr_subbands), dtype = np.uint16) 59d86ce1b2SMilanka Ringwald for blk in range(frame.nr_blocks): 60d86ce1b2SMilanka Ringwald for ch in range(frame.nr_channels): 61d86ce1b2SMilanka Ringwald for sb in range(frame.nr_subbands): 62c21a9c2fSMilanka Ringwald frame.audio_sample[blk][ch][sb] = get_bits(fin, frame.bits[ch][sb]) 63d86ce1b2SMilanka Ringwald # print "block %2d - audio sample: %s" % (blk, frame.audio_sample[blk][0]) 64d86ce1b2SMilanka Ringwald 65d86ce1b2SMilanka Ringwald # add padding 66d86ce1b2SMilanka Ringwald drop_remaining_bits() 67*ad470863SMilanka Ringwald return 0 68d86ce1b2SMilanka Ringwald 69*ad470863SMilanka Ringwalddef sbc_reconstruct_subband_samples(frame): 70c21a9c2fSMilanka Ringwald frame.levels = np.zeros(shape=(frame.nr_channels, frame.nr_subbands), dtype = np.int32) 71c21a9c2fSMilanka Ringwald frame.sb_sample = np.zeros(shape=(frame.nr_blocks, frame.nr_channels, frame.nr_subbands)) 72d86ce1b2SMilanka Ringwald 73d86ce1b2SMilanka Ringwald for ch in range(frame.nr_channels): 74d86ce1b2SMilanka Ringwald for sb in range(frame.nr_subbands): 75c21a9c2fSMilanka Ringwald frame.levels[ch][sb] = pow(2.0, frame.bits[ch][sb]) - 1 76d86ce1b2SMilanka Ringwald 77d86ce1b2SMilanka Ringwald for blk in range(frame.nr_blocks): 78d86ce1b2SMilanka Ringwald for ch in range(frame.nr_channels): 79d86ce1b2SMilanka Ringwald for sb in range(frame.nr_subbands): 80c21a9c2fSMilanka Ringwald if frame.levels[ch][sb] > 0: 81c21a9c2fSMilanka Ringwald AS = frame.audio_sample[blk][ch][sb] 82c21a9c2fSMilanka Ringwald SF = frame.scalefactor[ch][sb] 83c21a9c2fSMilanka Ringwald L = frame.levels[ch][sb] 84c21a9c2fSMilanka Ringwald 8541a4a18dSMilanka Ringwald frame.sb_sample[blk][ch][sb] = SF * ((AS*2.0+1.0) / L -1.0 ) 86d86ce1b2SMilanka Ringwald else: 87c21a9c2fSMilanka Ringwald frame.sb_sample[blk][ch][sb] = 0 88d86ce1b2SMilanka Ringwald 89d86ce1b2SMilanka Ringwald # sythesis filter 90d86ce1b2SMilanka Ringwald if frame.channel_mode == JOINT_STEREO: 91d86ce1b2SMilanka Ringwald for blk in range(frame.nr_blocks): 92d86ce1b2SMilanka Ringwald for sb in range(frame.nr_subbands): 93d86ce1b2SMilanka Ringwald if frame.join[sb]==1: 94c21a9c2fSMilanka Ringwald ch_a = frame.sb_sample[blk][0][sb] + frame.sb_sample[blk][1][sb] 95c21a9c2fSMilanka Ringwald ch_b = frame.sb_sample[blk][0][sb] - frame.sb_sample[blk][1][sb] 96c21a9c2fSMilanka Ringwald frame.sb_sample[blk][0][sb] = ch_a 97c21a9c2fSMilanka Ringwald frame.sb_sample[blk][1][sb] = ch_b 98c21a9c2fSMilanka Ringwald 99d86ce1b2SMilanka Ringwald return 0 100d86ce1b2SMilanka Ringwald 101d86ce1b2SMilanka Ringwald 102*ad470863SMilanka Ringwalddef sbc_frame_synthesis(frame, ch, blk, proto_table): 103c21a9c2fSMilanka Ringwald global V 104d86ce1b2SMilanka Ringwald M = frame.nr_subbands 105d86ce1b2SMilanka Ringwald L = 10 * M 106d86ce1b2SMilanka Ringwald M2 = 2*M 107d86ce1b2SMilanka Ringwald L2 = 2*L 108d86ce1b2SMilanka Ringwald 109d86ce1b2SMilanka Ringwald S = np.zeros(M) 110d86ce1b2SMilanka Ringwald U = np.zeros(L) 111d86ce1b2SMilanka Ringwald W = np.zeros(L) 112d86ce1b2SMilanka Ringwald frame.X = np.zeros(M) 113d86ce1b2SMilanka Ringwald 114d86ce1b2SMilanka Ringwald for i in range(M): 115c21a9c2fSMilanka Ringwald S[i] = frame.sb_sample[blk][ch][i] 116d86ce1b2SMilanka Ringwald 117d86ce1b2SMilanka Ringwald for i in range(L2-1, M2-1,-1): 118d86ce1b2SMilanka Ringwald V[ch][i] = V[ch][i-M2] 119d86ce1b2SMilanka Ringwald 120d86ce1b2SMilanka Ringwald for k in range(M2): 121d86ce1b2SMilanka Ringwald V[ch][k] = 0 122d86ce1b2SMilanka Ringwald for i in range(M): 123d86ce1b2SMilanka Ringwald N = np.cos((i+0.5)*(k+2)*np.pi/M) 124d86ce1b2SMilanka Ringwald V[ch][k] += N * S[i] 125d86ce1b2SMilanka Ringwald 126d86ce1b2SMilanka Ringwald for i in range(5): 127d86ce1b2SMilanka Ringwald for j in range(M): 128d86ce1b2SMilanka Ringwald U[i*M2+j] = V[ch][i*2*M2+j] 129d82cd87cSMilanka Ringwald U[(i*2+1)*M+j] = V[ch][(i*4+3)*M+j] 130d86ce1b2SMilanka Ringwald 131d86ce1b2SMilanka Ringwald for i in range(L): 132d86ce1b2SMilanka Ringwald D = proto_table[i] * (-M) 133d86ce1b2SMilanka Ringwald W[i] = U[i]*D 134d86ce1b2SMilanka Ringwald 135d86ce1b2SMilanka Ringwald 136d86ce1b2SMilanka Ringwald for j in range(M): 137d86ce1b2SMilanka Ringwald for i in range(10): 138d86ce1b2SMilanka Ringwald frame.X[j] += W[j+M*i] 139d86ce1b2SMilanka Ringwald 140*ad470863SMilanka Ringwald frame.pcm = np.concatenate([frame.pcm, np.int16(frame.X)]) 141d86ce1b2SMilanka Ringwald 142d86ce1b2SMilanka Ringwald 143*ad470863SMilanka Ringwalddef sbc_synthesis(frame): 144d86ce1b2SMilanka Ringwald if frame.nr_subbands == 4: 145d86ce1b2SMilanka Ringwald proto_table = Proto_4_40 146d86ce1b2SMilanka Ringwald elif frame.nr_subbands == 8: 147d86ce1b2SMilanka Ringwald proto_table = Proto_8_80 148d86ce1b2SMilanka Ringwald else: 149d86ce1b2SMilanka Ringwald return -1 150d86ce1b2SMilanka Ringwald 151d86ce1b2SMilanka Ringwald for ch in range(frame.nr_channels): 152d86ce1b2SMilanka Ringwald for blk in range(frame.nr_blocks): 153*ad470863SMilanka Ringwald sbc_frame_synthesis(frame, ch, blk, proto_table) 154d86ce1b2SMilanka Ringwald 155d86ce1b2SMilanka Ringwald return frame.nr_blocks * frame.nr_subbands 156d86ce1b2SMilanka Ringwald 157*ad470863SMilanka Ringwalddef sbc_decode(frame): 158*ad470863SMilanka Ringwald err = sbc_reconstruct_subband_samples(frame) 159*ad470863SMilanka Ringwald if err >= 0: 160*ad470863SMilanka Ringwald err = sbc_synthesis(frame) 161*ad470863SMilanka Ringwald return err 162d86ce1b2SMilanka Ringwald 163*ad470863SMilanka Ringwald 164*ad470863SMilanka Ringwalddef write_wav_file(fout, frame): 165d86ce1b2SMilanka Ringwald values = [] 166*ad470863SMilanka Ringwald for i in range(len(frame.pcm)): 167*ad470863SMilanka Ringwald try: 168*ad470863SMilanka Ringwald packed_value = struct.pack('h', frame.pcm[i]) 169d86ce1b2SMilanka Ringwald values.append(packed_value) 170*ad470863SMilanka Ringwald except struct.error: 171*ad470863SMilanka Ringwald print frame 172*ad470863SMilanka Ringwald print i, frame.pcm[i], frame.pcm 173*ad470863SMilanka Ringwald exit(1) 174d86ce1b2SMilanka Ringwald 175d86ce1b2SMilanka Ringwald value_str = ''.join(values) 176d86ce1b2SMilanka Ringwald fout.writeframes(value_str) 177d86ce1b2SMilanka Ringwald 178d86ce1b2SMilanka Ringwald 179ba114a98SMatthias Ringwaldif __name__ == "__main__": 180ba114a98SMatthias Ringwald usage = ''' 181ba114a98SMatthias Ringwald Usage: ./sbc_decoder.py input.sbc 182ba114a98SMatthias Ringwald ''' 183d86ce1b2SMilanka Ringwald 184ba114a98SMatthias Ringwald if (len(sys.argv) < 2): 185ba114a98SMatthias Ringwald print(usage) 186ba114a98SMatthias Ringwald sys.exit(1) 187ba114a98SMatthias Ringwald try: 188ba114a98SMatthias Ringwald infile = sys.argv[1] 189ba114a98SMatthias Ringwald if not infile.endswith('.sbc'): 190ba114a98SMatthias Ringwald print(usage) 191ba114a98SMatthias Ringwald sys.exit(1) 192d86ce1b2SMilanka Ringwald 193ba114a98SMatthias Ringwald wavfile = infile.replace('.sbc', '-decoded.wav') 194*ad470863SMilanka Ringwald fout = False 195d86ce1b2SMilanka Ringwald 196ba114a98SMatthias Ringwald with open (infile, 'rb') as fin: 197ba114a98SMatthias Ringwald try: 198ba114a98SMatthias Ringwald frame_count = 0 199ba114a98SMatthias Ringwald while True: 200*ad470863SMilanka Ringwald sbc_decoder_frame = SBCFrame(0,0,0,0,0) 201ba114a98SMatthias Ringwald if frame_count % 200 == 0: 202ba114a98SMatthias Ringwald print "== Frame %d ==" % (frame_count) 203*ad470863SMilanka Ringwald 204*ad470863SMilanka Ringwald err = sbc_unpack_frame(fin, sbc_decoder_frame) 205*ad470863SMilanka Ringwald 206ba114a98SMatthias Ringwald if err: 207ba114a98SMatthias Ringwald print "error, frame_count: ", frame_count 208ba114a98SMatthias Ringwald break 209ba114a98SMatthias Ringwald 210*ad470863SMilanka Ringwald sbc_decode(sbc_decoder_frame) 211ba114a98SMatthias Ringwald 212ba114a98SMatthias Ringwald if frame_count == 0: 213*ad470863SMilanka Ringwald print sbc_decoder_frame 214ba114a98SMatthias Ringwald fout = wave.open(wavfile, 'w') 215*ad470863SMilanka Ringwald fout.setnchannels(sbc_decoder_frame.nr_channels) 216ba114a98SMatthias Ringwald fout.setsampwidth(2) 217*ad470863SMilanka Ringwald fout.setframerate(sampling_frequency[sbc_decoder_frame.sampling_frequency]) 218ba114a98SMatthias Ringwald fout.setnframes(0) 219ba114a98SMatthias Ringwald fout.setcomptype = 'NONE' 220ba114a98SMatthias Ringwald 221*ad470863SMilanka Ringwald write_wav_file(fout, sbc_decoder_frame) 222ba114a98SMatthias Ringwald frame_count += 1 223ba114a98SMatthias Ringwald 224*ad470863SMilanka Ringwald except TypeError as err: 225*ad470863SMilanka Ringwald if not fout: 226*ad470863SMilanka Ringwald print err 227*ad470863SMilanka Ringwald else: 228ba114a98SMatthias Ringwald fout.close() 229*ad470863SMilanka Ringwald print ("DONE, SBC file %s decoded into WAV file %s " % (infile, wavfile)) 230ba114a98SMatthias Ringwald exit(0) 231d86ce1b2SMilanka Ringwald 232ba114a98SMatthias Ringwald except IOError as e: 233ba114a98SMatthias Ringwald print(usage) 234ba114a98SMatthias Ringwald sys.exit(1) 235d86ce1b2SMilanka Ringwald 236d86ce1b2SMilanka Ringwald 237d86ce1b2SMilanka Ringwald 238d86ce1b2SMilanka Ringwald 239d86ce1b2SMilanka Ringwald 240