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)) 9*1bd8157eSMilanka Ringwaldtotal_time_ms = 0 10*1bd8157eSMilanka Ringwaldimplementation = "SIG" 11d86ce1b2SMilanka Ringwald 125665ea35SMilanka Ringwalddef sbc_unpack_frame(fin, available_bytes, frame): 135665ea35SMilanka Ringwald if available_bytes == 0: 14f08a674bSMilanka Ringwald print "no available_bytes" 155665ea35SMilanka Ringwald raise TypeError 165665ea35SMilanka Ringwald 17d86ce1b2SMilanka Ringwald frame.syncword = get_bits(fin,8) 18d86ce1b2SMilanka Ringwald if frame.syncword != 156: 19f08a674bSMilanka Ringwald print ("out of sync %02x" % frame.syncword) 20d86ce1b2SMilanka Ringwald return -1 21d86ce1b2SMilanka Ringwald frame.sampling_frequency = get_bits(fin,2) 22d86ce1b2SMilanka Ringwald frame.nr_blocks = nr_blocks[get_bits(fin,2)] 23ba345fb8SMilanka Ringwald 24d86ce1b2SMilanka Ringwald frame.channel_mode = get_bits(fin,2) 25ad470863SMilanka Ringwald 26d86ce1b2SMilanka Ringwald if frame.channel_mode == MONO: 27d86ce1b2SMilanka Ringwald frame.nr_channels = 1 28d86ce1b2SMilanka Ringwald else: 29d86ce1b2SMilanka Ringwald frame.nr_channels = 2 30d86ce1b2SMilanka Ringwald 31d86ce1b2SMilanka Ringwald frame.allocation_method = get_bits(fin,1) 32d86ce1b2SMilanka Ringwald frame.nr_subbands = nr_subbands[get_bits(fin,1)] 335c9bef5bSMilanka Ringwald frame.init(frame.nr_blocks, frame.nr_subbands, frame.nr_channels) 345c9bef5bSMilanka Ringwald 35d86ce1b2SMilanka Ringwald frame.bitpool = get_bits(fin,8) 36d86ce1b2SMilanka Ringwald frame.crc_check = get_bits(fin,8) 37d86ce1b2SMilanka Ringwald 385c9bef5bSMilanka Ringwald # frame.join = np.zeros(frame.nr_subbands, dtype = np.uint8) 39d86ce1b2SMilanka Ringwald 40d86ce1b2SMilanka Ringwald if frame.channel_mode == JOINT_STEREO: 41d86ce1b2SMilanka Ringwald for sb in range(frame.nr_subbands-1): 42d86ce1b2SMilanka Ringwald frame.join[sb] = get_bits(fin,1) 43d86ce1b2SMilanka Ringwald get_bits(fin,1) # RFA 44d86ce1b2SMilanka Ringwald 45d86ce1b2SMilanka Ringwald frame.scale_factor = np.zeros(shape=(frame.nr_channels, frame.nr_subbands), dtype = np.int32) 46d86ce1b2SMilanka Ringwald 47d86ce1b2SMilanka Ringwald # print frame.audio_sample 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 L = frame.levels[ch][sb] 9057f2bc22SMilanka Ringwald SF = frame.scalefactor[ch][sb] 91ba345fb8SMilanka Ringwald frame.sb_sample[blk][ch][sb] = SF * ((AS*2.0+1.0) / L -1.0 ) 92d86ce1b2SMilanka Ringwald else: 93c21a9c2fSMilanka Ringwald frame.sb_sample[blk][ch][sb] = 0 94d86ce1b2SMilanka Ringwald 95d86ce1b2SMilanka Ringwald # sythesis filter 96d86ce1b2SMilanka Ringwald if frame.channel_mode == JOINT_STEREO: 97d86ce1b2SMilanka Ringwald for blk in range(frame.nr_blocks): 98d86ce1b2SMilanka Ringwald for sb in range(frame.nr_subbands): 99d86ce1b2SMilanka Ringwald if frame.join[sb]==1: 100c21a9c2fSMilanka Ringwald ch_a = frame.sb_sample[blk][0][sb] + frame.sb_sample[blk][1][sb] 101c21a9c2fSMilanka Ringwald ch_b = frame.sb_sample[blk][0][sb] - frame.sb_sample[blk][1][sb] 102ef8a7a12SMilanka Ringwald frame.sb_sample[blk][0][sb] = ch_a 103ef8a7a12SMilanka Ringwald frame.sb_sample[blk][1][sb] = ch_b 104c21a9c2fSMilanka Ringwald 105d86ce1b2SMilanka Ringwald return 0 106d86ce1b2SMilanka Ringwald 107d86ce1b2SMilanka Ringwald 108*1bd8157eSMilanka Ringwalddef sbc_frame_synthesis_sig(frame, ch, blk, proto_table): 109c21a9c2fSMilanka Ringwald global V 110d86ce1b2SMilanka Ringwald M = frame.nr_subbands 111d86ce1b2SMilanka Ringwald L = 10 * M 112d86ce1b2SMilanka Ringwald M2 = 2*M 113d86ce1b2SMilanka Ringwald L2 = 2*L 114d86ce1b2SMilanka Ringwald 115d86ce1b2SMilanka Ringwald S = np.zeros(M) 116d86ce1b2SMilanka Ringwald U = np.zeros(L) 117d86ce1b2SMilanka Ringwald W = np.zeros(L) 118d86ce1b2SMilanka Ringwald frame.X = np.zeros(M) 119d86ce1b2SMilanka Ringwald 120d86ce1b2SMilanka Ringwald for i in range(M): 121c21a9c2fSMilanka Ringwald S[i] = frame.sb_sample[blk][ch][i] 122d86ce1b2SMilanka Ringwald 123d86ce1b2SMilanka Ringwald for i in range(L2-1, M2-1,-1): 124d86ce1b2SMilanka Ringwald V[ch][i] = V[ch][i-M2] 125d86ce1b2SMilanka Ringwald 126d86ce1b2SMilanka Ringwald for k in range(M2): 127d86ce1b2SMilanka Ringwald V[ch][k] = 0 128d86ce1b2SMilanka Ringwald for i in range(M): 1294771dcb8SMilanka Ringwald N = np.cos((i+0.5)*(k+M/2)*np.pi/M) 130d86ce1b2SMilanka Ringwald V[ch][k] += N * S[i] 131d86ce1b2SMilanka Ringwald 132d86ce1b2SMilanka Ringwald for i in range(5): 133d86ce1b2SMilanka Ringwald for j in range(M): 134d86ce1b2SMilanka Ringwald U[i*M2+j] = V[ch][i*2*M2+j] 135d82cd87cSMilanka Ringwald U[(i*2+1)*M+j] = V[ch][(i*4+3)*M+j] 136d86ce1b2SMilanka Ringwald 137d86ce1b2SMilanka Ringwald for i in range(L): 138d86ce1b2SMilanka Ringwald D = proto_table[i] * (-M) 139d86ce1b2SMilanka Ringwald W[i] = U[i]*D 140d86ce1b2SMilanka Ringwald 141d86ce1b2SMilanka Ringwald 1421522543dSMilanka Ringwald offset = blk*M 143d86ce1b2SMilanka Ringwald for j in range(M): 144d86ce1b2SMilanka Ringwald for i in range(10): 145d86ce1b2SMilanka Ringwald frame.X[j] += W[j+M*i] 1461522543dSMilanka Ringwald frame.pcm[ch][offset + j] = np.int16(frame.X[j]) 147d86ce1b2SMilanka Ringwald 148d86ce1b2SMilanka Ringwald 149*1bd8157eSMilanka Ringwalddef sbc_frame_synthesis(frame, ch, blk, proto_table): 150*1bd8157eSMilanka Ringwald global total_time_ms, implementation 151*1bd8157eSMilanka Ringwald 152*1bd8157eSMilanka Ringwald t1 = time_ms() 153*1bd8157eSMilanka Ringwald if implementation == "SIG": 154*1bd8157eSMilanka Ringwald sbc_frame_synthesis_sig(frame, ch, blk, proto_table) 155*1bd8157eSMilanka Ringwald elif implementation == "V1": 156*1bd8157eSMilanka Ringwald sbc_frame_synthesis_v1(frame, ch, blk, proto_table) 157*1bd8157eSMilanka Ringwald else: 158*1bd8157eSMilanka Ringwald print ("synthesis %s not implemented" % implementation) 159*1bd8157eSMilanka Ringwald exit(1) 160*1bd8157eSMilanka Ringwald 161*1bd8157eSMilanka Ringwald t2 = time_ms() 162*1bd8157eSMilanka Ringwald total_time_ms += t2-t1 163*1bd8157eSMilanka Ringwald 164*1bd8157eSMilanka Ringwald 165ad470863SMilanka Ringwalddef sbc_synthesis(frame): 166d86ce1b2SMilanka Ringwald if frame.nr_subbands == 4: 167d86ce1b2SMilanka Ringwald proto_table = Proto_4_40 168d86ce1b2SMilanka Ringwald elif frame.nr_subbands == 8: 169d86ce1b2SMilanka Ringwald proto_table = Proto_8_80 170d86ce1b2SMilanka Ringwald else: 171d86ce1b2SMilanka Ringwald return -1 172d86ce1b2SMilanka Ringwald for ch in range(frame.nr_channels): 173d86ce1b2SMilanka Ringwald for blk in range(frame.nr_blocks): 174ad470863SMilanka Ringwald sbc_frame_synthesis(frame, ch, blk, proto_table) 175d86ce1b2SMilanka Ringwald 176d86ce1b2SMilanka Ringwald return frame.nr_blocks * frame.nr_subbands 177d86ce1b2SMilanka Ringwald 178ad470863SMilanka Ringwalddef sbc_decode(frame): 179ad470863SMilanka Ringwald err = sbc_reconstruct_subband_samples(frame) 180ad470863SMilanka Ringwald if err >= 0: 181ad470863SMilanka Ringwald err = sbc_synthesis(frame) 182ad470863SMilanka Ringwald return err 183d86ce1b2SMilanka Ringwald 184ad470863SMilanka Ringwald 185ad470863SMilanka Ringwalddef write_wav_file(fout, frame): 186d86ce1b2SMilanka Ringwald values = [] 1871522543dSMilanka Ringwald 1881522543dSMilanka Ringwald for i in range(frame.nr_subbands * frame.nr_blocks): 1891522543dSMilanka Ringwald for ch in range(frame.nr_channels): 190ad470863SMilanka Ringwald try: 1911522543dSMilanka Ringwald packed_value = struct.pack('h', frame.pcm[ch][i]) 192d86ce1b2SMilanka Ringwald values.append(packed_value) 193ad470863SMilanka Ringwald except struct.error: 194ad470863SMilanka Ringwald print frame 1951522543dSMilanka Ringwald print i, frame.pcm[ch][i], frame.pcm[ch] 196ad470863SMilanka Ringwald exit(1) 197d86ce1b2SMilanka Ringwald 198d86ce1b2SMilanka Ringwald value_str = ''.join(values) 199d86ce1b2SMilanka Ringwald fout.writeframes(value_str) 200d86ce1b2SMilanka Ringwald 201d86ce1b2SMilanka Ringwald 202ba114a98SMatthias Ringwaldif __name__ == "__main__": 203ba114a98SMatthias Ringwald usage = ''' 204ba114a98SMatthias Ringwald Usage: ./sbc_decoder.py input.sbc 205ba114a98SMatthias Ringwald ''' 206d86ce1b2SMilanka Ringwald 207ba114a98SMatthias Ringwald if (len(sys.argv) < 2): 208ba114a98SMatthias Ringwald print(usage) 209ba114a98SMatthias Ringwald sys.exit(1) 210ba114a98SMatthias Ringwald try: 211ba114a98SMatthias Ringwald infile = sys.argv[1] 212ba114a98SMatthias Ringwald if not infile.endswith('.sbc'): 213ba114a98SMatthias Ringwald print(usage) 214ba114a98SMatthias Ringwald sys.exit(1) 215d86ce1b2SMilanka Ringwald 216ba114a98SMatthias Ringwald wavfile = infile.replace('.sbc', '-decoded.wav') 217ad470863SMilanka Ringwald fout = False 218d86ce1b2SMilanka Ringwald 219ba114a98SMatthias Ringwald with open (infile, 'rb') as fin: 220ba114a98SMatthias Ringwald try: 2215665ea35SMilanka Ringwald fin.seek(0, 2) 2225665ea35SMilanka Ringwald file_size = fin.tell() 2235665ea35SMilanka Ringwald fin.seek(0, 0) 2245665ea35SMilanka Ringwald 225ba114a98SMatthias Ringwald frame_count = 0 226ba114a98SMatthias Ringwald while True: 2275665ea35SMilanka Ringwald sbc_decoder_frame = SBCFrame() 228ba114a98SMatthias Ringwald if frame_count % 200 == 0: 229f08a674bSMilanka Ringwald print "== Frame %d == %d" % (frame_count, fin.tell()) 230f08a674bSMilanka Ringwald 2315665ea35SMilanka Ringwald err = sbc_unpack_frame(fin, file_size - fin.tell(), sbc_decoder_frame) 2325c9bef5bSMilanka Ringwald if frame_count == 0: 2335c9bef5bSMilanka Ringwald print sbc_decoder_frame 234ad470863SMilanka Ringwald 235ba114a98SMatthias Ringwald if err: 236ba114a98SMatthias Ringwald print "error, frame_count: ", frame_count 237ba114a98SMatthias Ringwald break 238ba114a98SMatthias Ringwald 2395c9bef5bSMilanka Ringwald 240ad470863SMilanka Ringwald sbc_decode(sbc_decoder_frame) 241ba114a98SMatthias Ringwald 242ba114a98SMatthias Ringwald if frame_count == 0: 243ba114a98SMatthias Ringwald fout = wave.open(wavfile, 'w') 244ad470863SMilanka Ringwald fout.setnchannels(sbc_decoder_frame.nr_channels) 245ba114a98SMatthias Ringwald fout.setsampwidth(2) 246d0818c25SMilanka Ringwald fout.setframerate(sampling_frequencies[sbc_decoder_frame.sampling_frequency]) 247ba114a98SMatthias Ringwald fout.setnframes(0) 248ba114a98SMatthias Ringwald fout.setcomptype = 'NONE' 249ba114a98SMatthias Ringwald 250ad470863SMilanka Ringwald write_wav_file(fout, sbc_decoder_frame) 251ba114a98SMatthias Ringwald frame_count += 1 252ba114a98SMatthias Ringwald 253*1bd8157eSMilanka Ringwald if frame_count == 1: 254*1bd8157eSMilanka Ringwald break 255*1bd8157eSMilanka Ringwald 256ad470863SMilanka Ringwald except TypeError as err: 257ad470863SMilanka Ringwald if not fout: 258ad470863SMilanka Ringwald print err 259ad470863SMilanka Ringwald else: 260ba114a98SMatthias Ringwald fout.close() 261*1bd8157eSMilanka Ringwald if frame_count > 0: 262ad470863SMilanka Ringwald print ("DONE, SBC file %s decoded into WAV file %s " % (infile, wavfile)) 263*1bd8157eSMilanka Ringwald print ("Sythesis average %d ms/frame", total_time_ms/frame_count) 264*1bd8157eSMilanka Ringwald else: 265*1bd8157eSMilanka Ringwald print ("No frame found") 266ba114a98SMatthias Ringwald exit(0) 267d86ce1b2SMilanka Ringwald 268*1bd8157eSMilanka Ringwald fout.close() 269*1bd8157eSMilanka Ringwald if frame_count > 0: 270*1bd8157eSMilanka Ringwald print ("DONE: SBC file %s decoded into WAV file %s " % (infile, wavfile)) 271*1bd8157eSMilanka Ringwald print ("Average sythesis time per frame: %d ms/frame" % (total_time_ms/frame_count)) 272*1bd8157eSMilanka Ringwald else: 273*1bd8157eSMilanka Ringwald print ("No frame found") 274*1bd8157eSMilanka Ringwald 275ba114a98SMatthias Ringwald except IOError as e: 276ba114a98SMatthias Ringwald print(usage) 277ba114a98SMatthias Ringwald sys.exit(1) 278d86ce1b2SMilanka Ringwald 279d86ce1b2SMilanka Ringwald 280d86ce1b2SMilanka Ringwald 281d86ce1b2SMilanka Ringwald 282d86ce1b2SMilanka Ringwald 283