1*6ccd8248SMilanka Ringwald#!/usr/bin/env python3 2c21a9c2fSMilanka Ringwaldimport numpy as np 3c21a9c2fSMilanka Ringwaldimport wave 4c21a9c2fSMilanka Ringwaldimport struct 5c21a9c2fSMilanka Ringwaldimport sys 6c21a9c2fSMilanka Ringwaldfrom sbc import * 7c21a9c2fSMilanka Ringwald 85c9bef5bSMilanka RingwaldX = np.zeros(shape=(2,80), dtype = np.int16) 91bd8157eSMilanka Ringwaldimplementation = "SIG" 10a7e6f4ddSMilanka Ringwaldmsbc_enabled = 0 11a7e6f4ddSMilanka Ringwaldtotal_time_ms = 0 12c21a9c2fSMilanka Ringwald 13ad470863SMilanka Ringwalddef fetch_samples_for_next_sbc_frame(fin, frame): 14ef8a7a12SMilanka Ringwald raw_data = fin.readframes(frame.nr_blocks * frame.nr_subbands) 155c9bef5bSMilanka Ringwald fmt = "%ih" % (len(raw_data) / 2) 161522543dSMilanka Ringwald data = struct.unpack(fmt, raw_data) 171522543dSMilanka Ringwald 185c9bef5bSMilanka Ringwald if frame.nr_channels == 2: 199462b3daSMilanka Ringwald for i in range(len(data)/2): 205c9bef5bSMilanka Ringwald frame.pcm[0][i] = data[2*i] 215c9bef5bSMilanka Ringwald frame.pcm[1][i] = data[2*i+1] 221522543dSMilanka Ringwald else: 235c9bef5bSMilanka Ringwald for i in range(len(data)): 245c9bef5bSMilanka Ringwald frame.pcm[0][i] = data[i] 25c21a9c2fSMilanka Ringwald 26c21a9c2fSMilanka Ringwald 27a7e6f4ddSMilanka Ringwalddef sbc_frame_analysis_sig(frame, ch, blk, C): 28c21a9c2fSMilanka Ringwald global X 29ad470863SMilanka Ringwald 30c21a9c2fSMilanka Ringwald M = frame.nr_subbands 31c21a9c2fSMilanka Ringwald L = 10 * M 32c21a9c2fSMilanka Ringwald M2 = 2*M 33c21a9c2fSMilanka Ringwald L2 = 2*L 34c21a9c2fSMilanka Ringwald 35c21a9c2fSMilanka Ringwald Z = np.zeros(L) 36c21a9c2fSMilanka Ringwald Y = np.zeros(M2) 37c21a9c2fSMilanka Ringwald W = np.zeros(shape=(M, M2)) 38c21a9c2fSMilanka Ringwald S = np.zeros(M) 39c21a9c2fSMilanka Ringwald 40c21a9c2fSMilanka Ringwald for i in range(L-1, M-1, -1): 415c9bef5bSMilanka Ringwald X[ch][i] = X[ch][i-M] 42c21a9c2fSMilanka Ringwald for i in range(M-1, -1, -1): 435c9bef5bSMilanka Ringwald X[ch][i] = frame.EX[M-1-i] 44c21a9c2fSMilanka Ringwald for i in range(L): 455c9bef5bSMilanka Ringwald Z[i] = X[ch][i] * C[i] 46c21a9c2fSMilanka Ringwald 47c21a9c2fSMilanka Ringwald for i in range(M2): 48c21a9c2fSMilanka Ringwald for k in range(5): 49af086c98SMilanka Ringwald Y[i] += Z[i+k*M2] 50c21a9c2fSMilanka Ringwald 51c21a9c2fSMilanka Ringwald for i in range(M): 52c21a9c2fSMilanka Ringwald for k in range(M2): 53af086c98SMilanka Ringwald W[i][k] = np.cos((i+0.5)*(k-M/2)*np.pi/M) 54c21a9c2fSMilanka Ringwald S[i] += W[i][k] * Y[k] 55c21a9c2fSMilanka Ringwald 56c21a9c2fSMilanka Ringwald for sb in range(M): 57c21a9c2fSMilanka Ringwald frame.sb_sample[blk][ch][sb] = S[sb] 58c21a9c2fSMilanka Ringwald 591bd8157eSMilanka Ringwald 601bd8157eSMilanka Ringwalddef sbc_frame_analysis(frame, ch, blk, proto_table): 611bd8157eSMilanka Ringwald global total_time_ms, implementation 621bd8157eSMilanka Ringwald 631bd8157eSMilanka Ringwald t1 = time_ms() 641bd8157eSMilanka Ringwald if implementation == "SIG": 651bd8157eSMilanka Ringwald sbc_frame_analysis_sig(frame, ch, blk, proto_table) 661bd8157eSMilanka Ringwald else: 671bd8157eSMilanka Ringwald print ("Analysis %s not implemented" % implementation) 681bd8157eSMilanka Ringwald exit(1) 691bd8157eSMilanka Ringwald 701bd8157eSMilanka Ringwald t2 = time_ms() 711bd8157eSMilanka Ringwald total_time_ms += t2-t1 721bd8157eSMilanka Ringwald 731bd8157eSMilanka Ringwald 74ad470863SMilanka Ringwalddef sbc_analysis(frame): 75c21a9c2fSMilanka Ringwald if frame.nr_subbands == 4: 76ad470863SMilanka Ringwald C = Proto_4_40 77c21a9c2fSMilanka Ringwald elif frame.nr_subbands == 8: 78ad470863SMilanka Ringwald C = Proto_8_80 79c21a9c2fSMilanka Ringwald else: 80c21a9c2fSMilanka Ringwald return -1 81c21a9c2fSMilanka Ringwald 82c21a9c2fSMilanka Ringwald frame.sb_sample = np.ndarray(shape=(frame.nr_blocks, frame.nr_channels, frame.nr_subbands)) 83c21a9c2fSMilanka Ringwald for ch in range(frame.nr_channels): 845c9bef5bSMilanka Ringwald index = 0 85c21a9c2fSMilanka Ringwald for blk in range(frame.nr_blocks): 86c21a9c2fSMilanka Ringwald for sb in range(frame.nr_subbands): 87c9498b12SMilanka Ringwald frame.EX[sb] = frame.pcm[ch][index] 88c21a9c2fSMilanka Ringwald index+=1 89ad470863SMilanka Ringwald sbc_frame_analysis(frame, ch, blk, C) 90ad470863SMilanka Ringwald return 0 91c21a9c2fSMilanka Ringwald 92ef8a7a12SMilanka Ringwalddef sbc_encode(frame, force_channel_mode): 93ad470863SMilanka Ringwald err = sbc_analysis(frame) 94ad470863SMilanka Ringwald if err >= 0: 95ef8a7a12SMilanka Ringwald err = sbc_quantization(frame, force_channel_mode) 96ad470863SMilanka Ringwald return err 97c21a9c2fSMilanka Ringwald 98ef8a7a12SMilanka Ringwalddef sbc_quantization(frame, force_channel_mode): 99a7e6f4ddSMilanka Ringwald global msbc_enabled 100ef8a7a12SMilanka Ringwald calculate_channel_mode_and_scale_factors(frame, force_channel_mode) 101c21a9c2fSMilanka Ringwald frame.bits = sbc_bit_allocation(frame) 102c21a9c2fSMilanka Ringwald 103c21a9c2fSMilanka Ringwald # Reconstruct the Audio Samples 104c21a9c2fSMilanka Ringwald frame.levels = np.zeros(shape=(frame.nr_channels, frame.nr_subbands), dtype = np.int32) 105c21a9c2fSMilanka Ringwald for ch in range(frame.nr_channels): 106c21a9c2fSMilanka Ringwald for sb in range(frame.nr_subbands): 107ad470863SMilanka Ringwald frame.levels[ch][sb] = (1 << frame.bits[ch][sb]) - 1 #pow(2.0, frame.bits[ch][sb]) - 1 108c21a9c2fSMilanka Ringwald 109a7e6f4ddSMilanka Ringwald if msbc_enabled: 110a7e6f4ddSMilanka Ringwald frame.syncword = 0xad 111a7e6f4ddSMilanka Ringwald else: 11257f2bc22SMilanka Ringwald frame.syncword = 0x9c 113a7e6f4ddSMilanka Ringwald 114c21a9c2fSMilanka Ringwald frame.crc_check = calculate_crc(frame) 115c21a9c2fSMilanka Ringwald 11657f2bc22SMilanka Ringwald 117c21a9c2fSMilanka Ringwald for blk in range(frame.nr_blocks): 118c21a9c2fSMilanka Ringwald for ch in range(frame.nr_channels): 119c21a9c2fSMilanka Ringwald for sb in range(frame.nr_subbands): 120c21a9c2fSMilanka Ringwald if frame.levels[ch][sb] > 0: 121c21a9c2fSMilanka Ringwald SB = frame.sb_sample[blk][ch][sb] 122c21a9c2fSMilanka Ringwald L = frame.levels[ch][sb] 123ad470863SMilanka Ringwald SF = frame.scalefactor[ch][sb] 12441a4a18dSMilanka Ringwald frame.audio_sample[blk][ch][sb] = np.uint16(((SB * L / SF + L) - 1.0)/2.0) 125c21a9c2fSMilanka Ringwald else: 126c21a9c2fSMilanka Ringwald frame.audio_sample[blk][ch][sb] = 0 127c21a9c2fSMilanka Ringwald 128c21a9c2fSMilanka Ringwald return 0 129c21a9c2fSMilanka Ringwald 130ad470863SMilanka Ringwalddef sbc_write_frame(fout, sbc_encoder_frame): 131ad470863SMilanka Ringwald stream = frame_to_bitstream(sbc_encoder_frame) 132ad470863SMilanka Ringwald barray = bytearray(stream) 133ad470863SMilanka Ringwald fout.write(barray) 134ad470863SMilanka Ringwald 135ba114a98SMatthias Ringwaldif __name__ == "__main__": 136ba114a98SMatthias Ringwald usage = ''' 137a7e6f4ddSMilanka Ringwald Usage: ./sbc_encoder.py input.wav blocks subbands bitpool allocation_method[0-LOUDNESS,1-SNR] force_channel_mode[2-STEREO,3-JOINT_STEREO] [0-sbc|1-msbc] 138a7e6f4ddSMilanka Ringwald Example: ./sbc_encoder.py fanfare.wav 16 4 31 0 0 139ba114a98SMatthias Ringwald ''' 140ba114a98SMatthias Ringwald nr_blocks = 0 141ba114a98SMatthias Ringwald nr_subbands = 0 142c21a9c2fSMilanka Ringwald 143a7e6f4ddSMilanka Ringwald if (len(sys.argv) < 7): 144ba114a98SMatthias Ringwald print(usage) 145ba114a98SMatthias Ringwald sys.exit(1) 146ba114a98SMatthias Ringwald try: 147ba114a98SMatthias Ringwald infile = sys.argv[1] 148ba114a98SMatthias Ringwald if not infile.endswith('.wav'): 149ba114a98SMatthias Ringwald print(usage) 150ba114a98SMatthias Ringwald sys.exit(1) 151a7e6f4ddSMilanka Ringwald 152a7e6f4ddSMilanka Ringwald msbc_enabled = int(sys.argv[7]) 153164f5121SMilanka Ringwald print("msbc_enabled %d"%msbc_enabled) 154a7e6f4ddSMilanka Ringwald if msbc_enabled: 155a7e6f4ddSMilanka Ringwald sbcfile = infile.replace('.wav', '-encoded.msbc') 156a7e6f4ddSMilanka Ringwald else: 157ad470863SMilanka Ringwald sbcfile = infile.replace('.wav', '-encoded.sbc') 158ad470863SMilanka Ringwald 159ba114a98SMatthias Ringwald nr_blocks = int(sys.argv[2]) 160ba114a98SMatthias Ringwald nr_subbands = int(sys.argv[3]) 161ba114a98SMatthias Ringwald bitpool = int(sys.argv[4]) 1625665ea35SMilanka Ringwald allocation_method = int(sys.argv[5]) 163a7e6f4ddSMilanka Ringwald 164ef8a7a12SMilanka Ringwald force_channel_mode = int(sys.argv[6]) 165164f5121SMilanka Ringwald print("force_channel_mode %d"%force_channel_mode) 166164f5121SMilanka Ringwald 167c21a9c2fSMilanka Ringwald 168ba114a98SMatthias Ringwald fin = wave.open(infile, 'rb') 169ad470863SMilanka Ringwald nr_channels = fin.getnchannels() 170a7e6f4ddSMilanka Ringwald if msbc_enabled: 171a7e6f4ddSMilanka Ringwald sampling_frequency = 16000 172a7e6f4ddSMilanka Ringwald nr_channels = 1 173a7e6f4ddSMilanka Ringwald bitpool = 26 174a7e6f4ddSMilanka Ringwald nr_subbands = 8 175a7e6f4ddSMilanka Ringwald allocation_method = 0 176a7e6f4ddSMilanka Ringwald force_channel_mode = 0 177a7e6f4ddSMilanka Ringwald else: 178ad470863SMilanka Ringwald sampling_frequency = fin.getframerate() 179a7e6f4ddSMilanka Ringwald nr_channels = fin.getnchannels() 180ad470863SMilanka Ringwald nr_audio_frames = fin.getnframes() 181c21a9c2fSMilanka Ringwald 182ad470863SMilanka Ringwald subband_frame_count = 0 183ba114a98SMatthias Ringwald audio_frame_count = 0 184ad470863SMilanka Ringwald nr_samples = nr_blocks * nr_subbands 185ad470863SMilanka Ringwald fout = open(sbcfile, 'wb') 186ad470863SMilanka Ringwald while audio_frame_count < nr_audio_frames: 187ad470863SMilanka Ringwald if subband_frame_count % 200 == 0: 188ad470863SMilanka Ringwald print("== Frame %d == " % (subband_frame_count)) 189c21a9c2fSMilanka Ringwald 190164f5121SMilanka Ringwald sbc_encoder_frame = SBCFrame(nr_blocks, nr_subbands, nr_channels, bitpool, sampling_frequency, allocation_method, force_channel_mode) 191164f5121SMilanka Ringwald 192a7e6f4ddSMilanka Ringwald if subband_frame_count == 0: 193*6ccd8248SMilanka Ringwald print (sbc_encoder_frame) 194ad470863SMilanka Ringwald fetch_samples_for_next_sbc_frame(fin, sbc_encoder_frame) 195c21a9c2fSMilanka Ringwald 196ef8a7a12SMilanka Ringwald sbc_encode(sbc_encoder_frame, force_channel_mode) 197ad470863SMilanka Ringwald sbc_write_frame(fout, sbc_encoder_frame) 198c21a9c2fSMilanka Ringwald 199ad470863SMilanka Ringwald audio_frame_count += nr_samples 200ad470863SMilanka Ringwald subband_frame_count += 1 201c21a9c2fSMilanka Ringwald 202ad470863SMilanka Ringwald fin.close() 203ad470863SMilanka Ringwald fout.close() 204ad470863SMilanka Ringwald print("DONE, WAV file %s encoded into SBC file %s " % (infile, sbcfile)) 205a7e6f4ddSMilanka Ringwald if subband_frame_count > 0: 206a7e6f4ddSMilanka Ringwald print ("Average analysis time per frame: %d ms/frame" % (total_time_ms/subband_frame_count)) 2071bd8157eSMilanka Ringwald else: 2081bd8157eSMilanka Ringwald print ("No frame found") 209c21a9c2fSMilanka Ringwald 210c21a9c2fSMilanka Ringwald 211ba114a98SMatthias Ringwald except IOError as e: 212ba114a98SMatthias Ringwald print(usage) 213ba114a98SMatthias Ringwald sys.exit(1) 214c21a9c2fSMilanka Ringwald 215c21a9c2fSMilanka Ringwald 216c21a9c2fSMilanka Ringwald 217c21a9c2fSMilanka Ringwald 218c21a9c2fSMilanka Ringwald 219