1c21a9c2fSMilanka Ringwald#!/usr/bin/env python 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) 9*1bd8157eSMilanka Ringwaldimplementation = "SIG" 10c21a9c2fSMilanka Ringwald 11ad470863SMilanka Ringwalddef fetch_samples_for_next_sbc_frame(fin, frame): 12ef8a7a12SMilanka Ringwald raw_data = fin.readframes(frame.nr_blocks * frame.nr_subbands) 135c9bef5bSMilanka Ringwald fmt = "%ih" % (len(raw_data) / 2) 141522543dSMilanka Ringwald data = struct.unpack(fmt, raw_data) 151522543dSMilanka Ringwald 165c9bef5bSMilanka Ringwald if frame.nr_channels == 2: 179462b3daSMilanka Ringwald for i in range(len(data)/2): 185c9bef5bSMilanka Ringwald frame.pcm[0][i] = data[2*i] 195c9bef5bSMilanka Ringwald frame.pcm[1][i] = data[2*i+1] 201522543dSMilanka Ringwald else: 215c9bef5bSMilanka Ringwald for i in range(len(data)): 225c9bef5bSMilanka Ringwald frame.pcm[0][i] = data[i] 23c21a9c2fSMilanka Ringwald 24c21a9c2fSMilanka Ringwald 25ad470863SMilanka Ringwalddef sbc_frame_analysis(frame, ch, blk, C): 26c21a9c2fSMilanka Ringwald global X 27ad470863SMilanka Ringwald 28c21a9c2fSMilanka Ringwald M = frame.nr_subbands 29c21a9c2fSMilanka Ringwald L = 10 * M 30c21a9c2fSMilanka Ringwald M2 = 2*M 31c21a9c2fSMilanka Ringwald L2 = 2*L 32c21a9c2fSMilanka Ringwald 33c21a9c2fSMilanka Ringwald Z = np.zeros(L) 34c21a9c2fSMilanka Ringwald Y = np.zeros(M2) 35c21a9c2fSMilanka Ringwald W = np.zeros(shape=(M, M2)) 36c21a9c2fSMilanka Ringwald S = np.zeros(M) 37c21a9c2fSMilanka Ringwald 38c21a9c2fSMilanka Ringwald for i in range(L-1, M-1, -1): 395c9bef5bSMilanka Ringwald X[ch][i] = X[ch][i-M] 40c21a9c2fSMilanka Ringwald for i in range(M-1, -1, -1): 415c9bef5bSMilanka Ringwald X[ch][i] = frame.EX[M-1-i] 42c21a9c2fSMilanka Ringwald for i in range(L): 435c9bef5bSMilanka Ringwald Z[i] = X[ch][i] * C[i] 44c21a9c2fSMilanka Ringwald 45c21a9c2fSMilanka Ringwald for i in range(M2): 46c21a9c2fSMilanka Ringwald for k in range(5): 47af086c98SMilanka Ringwald Y[i] += Z[i+k*M2] 48c21a9c2fSMilanka Ringwald 49c21a9c2fSMilanka Ringwald for i in range(M): 50c21a9c2fSMilanka Ringwald for k in range(M2): 51af086c98SMilanka Ringwald W[i][k] = np.cos((i+0.5)*(k-M/2)*np.pi/M) 52c21a9c2fSMilanka Ringwald S[i] += W[i][k] * Y[k] 53c21a9c2fSMilanka Ringwald 54c21a9c2fSMilanka Ringwald for sb in range(M): 55c21a9c2fSMilanka Ringwald frame.sb_sample[blk][ch][sb] = S[sb] 56c21a9c2fSMilanka Ringwald 57*1bd8157eSMilanka Ringwald 58*1bd8157eSMilanka Ringwalddef sbc_frame_analysis(frame, ch, blk, proto_table): 59*1bd8157eSMilanka Ringwald global total_time_ms, implementation 60*1bd8157eSMilanka Ringwald 61*1bd8157eSMilanka Ringwald t1 = time_ms() 62*1bd8157eSMilanka Ringwald if implementation == "SIG": 63*1bd8157eSMilanka Ringwald sbc_frame_analysis_sig(frame, ch, blk, proto_table) 64*1bd8157eSMilanka Ringwald else: 65*1bd8157eSMilanka Ringwald print ("Analysis %s not implemented" % implementation) 66*1bd8157eSMilanka Ringwald exit(1) 67*1bd8157eSMilanka Ringwald 68*1bd8157eSMilanka Ringwald t2 = time_ms() 69*1bd8157eSMilanka Ringwald total_time_ms += t2-t1 70*1bd8157eSMilanka Ringwald 71*1bd8157eSMilanka Ringwald 72ad470863SMilanka Ringwalddef sbc_analysis(frame): 73c21a9c2fSMilanka Ringwald if frame.nr_subbands == 4: 74ad470863SMilanka Ringwald C = Proto_4_40 75c21a9c2fSMilanka Ringwald elif frame.nr_subbands == 8: 76ad470863SMilanka Ringwald C = Proto_8_80 77c21a9c2fSMilanka Ringwald else: 78c21a9c2fSMilanka Ringwald return -1 79c21a9c2fSMilanka Ringwald 80c21a9c2fSMilanka Ringwald frame.sb_sample = np.ndarray(shape=(frame.nr_blocks, frame.nr_channels, frame.nr_subbands)) 81c21a9c2fSMilanka Ringwald for ch in range(frame.nr_channels): 825c9bef5bSMilanka Ringwald index = 0 83c21a9c2fSMilanka Ringwald for blk in range(frame.nr_blocks): 84c21a9c2fSMilanka Ringwald for sb in range(frame.nr_subbands): 85c9498b12SMilanka Ringwald frame.EX[sb] = frame.pcm[ch][index] 86c21a9c2fSMilanka Ringwald index+=1 87ad470863SMilanka Ringwald sbc_frame_analysis(frame, ch, blk, C) 88ad470863SMilanka Ringwald return 0 89c21a9c2fSMilanka Ringwald 90ef8a7a12SMilanka Ringwalddef sbc_encode(frame, force_channel_mode): 91ad470863SMilanka Ringwald err = sbc_analysis(frame) 92ad470863SMilanka Ringwald if err >= 0: 93ef8a7a12SMilanka Ringwald err = sbc_quantization(frame, force_channel_mode) 94ad470863SMilanka Ringwald return err 95c21a9c2fSMilanka Ringwald 96ef8a7a12SMilanka Ringwalddef sbc_quantization(frame, force_channel_mode): 97ef8a7a12SMilanka Ringwald calculate_channel_mode_and_scale_factors(frame, force_channel_mode) 98c21a9c2fSMilanka Ringwald frame.bits = sbc_bit_allocation(frame) 99c21a9c2fSMilanka Ringwald 100c21a9c2fSMilanka Ringwald # Reconstruct the Audio Samples 101c21a9c2fSMilanka Ringwald frame.levels = np.zeros(shape=(frame.nr_channels, frame.nr_subbands), dtype = np.int32) 102c21a9c2fSMilanka Ringwald for ch in range(frame.nr_channels): 103c21a9c2fSMilanka Ringwald for sb in range(frame.nr_subbands): 104ad470863SMilanka Ringwald frame.levels[ch][sb] = (1 << frame.bits[ch][sb]) - 1 #pow(2.0, frame.bits[ch][sb]) - 1 105c21a9c2fSMilanka Ringwald 10657f2bc22SMilanka Ringwald frame.syncword = 0x9c 107c21a9c2fSMilanka Ringwald frame.crc_check = calculate_crc(frame) 108c21a9c2fSMilanka Ringwald 10957f2bc22SMilanka Ringwald 110c21a9c2fSMilanka Ringwald for blk in range(frame.nr_blocks): 111c21a9c2fSMilanka Ringwald for ch in range(frame.nr_channels): 112c21a9c2fSMilanka Ringwald for sb in range(frame.nr_subbands): 113c21a9c2fSMilanka Ringwald if frame.levels[ch][sb] > 0: 114c21a9c2fSMilanka Ringwald SB = frame.sb_sample[blk][ch][sb] 115c21a9c2fSMilanka Ringwald L = frame.levels[ch][sb] 116ad470863SMilanka Ringwald SF = frame.scalefactor[ch][sb] 11741a4a18dSMilanka Ringwald frame.audio_sample[blk][ch][sb] = np.uint16(((SB * L / SF + L) - 1.0)/2.0) 118c21a9c2fSMilanka Ringwald else: 119c21a9c2fSMilanka Ringwald frame.audio_sample[blk][ch][sb] = 0 120c21a9c2fSMilanka Ringwald 121c21a9c2fSMilanka Ringwald return 0 122c21a9c2fSMilanka Ringwald 123ad470863SMilanka Ringwalddef sbc_write_frame(fout, sbc_encoder_frame): 124ad470863SMilanka Ringwald stream = frame_to_bitstream(sbc_encoder_frame) 125ad470863SMilanka Ringwald barray = bytearray(stream) 126ad470863SMilanka Ringwald fout.write(barray) 127ad470863SMilanka Ringwald 128ba114a98SMatthias Ringwaldif __name__ == "__main__": 129ba114a98SMatthias Ringwald usage = ''' 130ef8a7a12SMilanka Ringwald Usage: ./sbc_encoder.py input.wav blocks subbands bitpool allocation_method[0-LOUDNESS,1-SNR] force_channel_mode[2-STEREO,3-JOINT_STEREO] 1315665ea35SMilanka Ringwald Example: ./sbc_encoder.py fanfare.wav 16 4 31 0 132ba114a98SMatthias Ringwald ''' 133ba114a98SMatthias Ringwald nr_blocks = 0 134ba114a98SMatthias Ringwald nr_subbands = 0 135c21a9c2fSMilanka Ringwald 136ad470863SMilanka Ringwald 1375665ea35SMilanka Ringwald if (len(sys.argv) < 6): 138ba114a98SMatthias Ringwald print(usage) 139ba114a98SMatthias Ringwald sys.exit(1) 140ba114a98SMatthias Ringwald try: 141ba114a98SMatthias Ringwald infile = sys.argv[1] 142ba114a98SMatthias Ringwald if not infile.endswith('.wav'): 143ba114a98SMatthias Ringwald print(usage) 144ba114a98SMatthias Ringwald sys.exit(1) 145ad470863SMilanka Ringwald sbcfile = infile.replace('.wav', '-encoded.sbc') 146ad470863SMilanka Ringwald 147ba114a98SMatthias Ringwald nr_blocks = int(sys.argv[2]) 148ba114a98SMatthias Ringwald nr_subbands = int(sys.argv[3]) 149ba114a98SMatthias Ringwald bitpool = int(sys.argv[4]) 1505665ea35SMilanka Ringwald allocation_method = int(sys.argv[5]) 151ef8a7a12SMilanka Ringwald force_channel_mode = 0 152ef8a7a12SMilanka Ringwald if len(sys.argv) == 6: 153ef8a7a12SMilanka Ringwald force_channel_mode = int(sys.argv[6]) 154ef8a7a12SMilanka Ringwald if force_channel_mode != 2 or force_channel_mode != 3: 155ef8a7a12SMilanka Ringwald print(usage) 156ef8a7a12SMilanka Ringwald sys.exit(1) 157c21a9c2fSMilanka Ringwald 158ba114a98SMatthias Ringwald fin = wave.open(infile, 'rb') 159ad470863SMilanka Ringwald nr_channels = fin.getnchannels() 160ad470863SMilanka Ringwald sampling_frequency = fin.getframerate() 161ad470863SMilanka Ringwald nr_audio_frames = fin.getnframes() 162c21a9c2fSMilanka Ringwald 163ad470863SMilanka Ringwald subband_frame_count = 0 164ba114a98SMatthias Ringwald audio_frame_count = 0 165ad470863SMilanka Ringwald nr_samples = nr_blocks * nr_subbands 166ad470863SMilanka Ringwald fout = open(sbcfile, 'wb') 167ad470863SMilanka Ringwald while audio_frame_count < nr_audio_frames: 168ad470863SMilanka Ringwald if subband_frame_count % 200 == 0: 169ad470863SMilanka Ringwald print("== Frame %d ==" % (subband_frame_count)) 170c21a9c2fSMilanka Ringwald 1715665ea35SMilanka Ringwald sbc_encoder_frame = SBCFrame(nr_blocks, nr_subbands, nr_channels, bitpool, sampling_frequency, allocation_method) 172ad470863SMilanka Ringwald fetch_samples_for_next_sbc_frame(fin, sbc_encoder_frame) 173c21a9c2fSMilanka Ringwald 174ef8a7a12SMilanka Ringwald sbc_encode(sbc_encoder_frame, force_channel_mode) 175ad470863SMilanka Ringwald sbc_write_frame(fout, sbc_encoder_frame) 176c21a9c2fSMilanka Ringwald 177ad470863SMilanka Ringwald audio_frame_count += nr_samples 178ad470863SMilanka Ringwald subband_frame_count += 1 179c21a9c2fSMilanka Ringwald 180ad470863SMilanka Ringwald fin.close() 181ad470863SMilanka Ringwald fout.close() 182ad470863SMilanka Ringwald print("DONE, WAV file %s encoded into SBC file %s " % (infile, sbcfile)) 183*1bd8157eSMilanka Ringwald if frame_count > 0: 184*1bd8157eSMilanka Ringwald print ("Average analysis time per frame: %d ms/frame" % (total_time_ms/frame_count)) 185*1bd8157eSMilanka Ringwald else: 186*1bd8157eSMilanka Ringwald print ("No frame found") 187c21a9c2fSMilanka Ringwald 188c21a9c2fSMilanka Ringwald 189ba114a98SMatthias Ringwald except IOError as e: 190ba114a98SMatthias Ringwald print(usage) 191ba114a98SMatthias Ringwald sys.exit(1) 192c21a9c2fSMilanka Ringwald 193c21a9c2fSMilanka Ringwald 194c21a9c2fSMilanka Ringwald 195c21a9c2fSMilanka Ringwald 196c21a9c2fSMilanka Ringwald 197