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 8ad470863SMilanka RingwaldX = np.zeros(80, dtype = np.int16) 9c21a9c2fSMilanka Ringwald 10ad470863SMilanka Ringwald 11ad470863SMilanka Ringwalddef fetch_samples_for_next_sbc_frame(fin, frame): 12ad470863SMilanka Ringwald nr_audio_frames = frame.nr_blocks * frame.nr_subbands 13c21a9c2fSMilanka Ringwald raw_data = fin.readframes(nr_audio_frames) # Returns byte data 14c21a9c2fSMilanka Ringwald 15c21a9c2fSMilanka Ringwald total_samples = nr_audio_frames * frame.nr_channels 16ad470863SMilanka Ringwald len_raw_data = len(raw_data) / 2 17c21a9c2fSMilanka Ringwald 18ad470863SMilanka Ringwald padding = np.zeros(total_samples - len_raw_data, dtype=np.int16) 19ad470863SMilanka Ringwald 20ad470863SMilanka Ringwald fmt = "%ih" % len_raw_data # read signed 2 byte shorts 21ad470863SMilanka Ringwald 22ad470863SMilanka Ringwald frame.pcm = np.concatenate([np.array(struct.unpack(fmt, raw_data)), padding]) 23c21a9c2fSMilanka Ringwald del raw_data 24c21a9c2fSMilanka Ringwald 25c21a9c2fSMilanka Ringwald 26ad470863SMilanka Ringwalddef sbc_frame_analysis(frame, ch, blk, C): 27c21a9c2fSMilanka Ringwald global X 28ad470863SMilanka Ringwald 29c21a9c2fSMilanka Ringwald M = frame.nr_subbands 30c21a9c2fSMilanka Ringwald L = 10 * M 31c21a9c2fSMilanka Ringwald M2 = 2*M 32c21a9c2fSMilanka Ringwald L2 = 2*L 33c21a9c2fSMilanka Ringwald 34c21a9c2fSMilanka Ringwald Z = np.zeros(L) 35c21a9c2fSMilanka Ringwald Y = np.zeros(M2) 36c21a9c2fSMilanka Ringwald W = np.zeros(shape=(M, M2)) 37c21a9c2fSMilanka Ringwald S = np.zeros(M) 38c21a9c2fSMilanka Ringwald 39c21a9c2fSMilanka Ringwald for i in range(L-1, M-1, -1): 40c21a9c2fSMilanka Ringwald X[i] = X[i-M] 41c21a9c2fSMilanka Ringwald for i in range(M-1, -1, -1): 42c21a9c2fSMilanka Ringwald X[i] = frame.EX[M-1-i] 43c21a9c2fSMilanka Ringwald 44c21a9c2fSMilanka Ringwald for i in range(L): 45c21a9c2fSMilanka Ringwald Z[i] = X[i] * C[i] 46c21a9c2fSMilanka Ringwald 47c21a9c2fSMilanka Ringwald for i in range(M2): 48c21a9c2fSMilanka Ringwald for k in range(5): 49c21a9c2fSMilanka Ringwald Y[i] += Z[i+k*8] 50c21a9c2fSMilanka Ringwald 51c21a9c2fSMilanka Ringwald for i in range(M): 52c21a9c2fSMilanka Ringwald for k in range(M2): 53c21a9c2fSMilanka Ringwald W[i][k] = np.cos((i+0.5)*(k-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 59ad470863SMilanka Ringwalddef sbc_analysis(frame): 60c21a9c2fSMilanka Ringwald if frame.nr_subbands == 4: 61ad470863SMilanka Ringwald C = Proto_4_40 62c21a9c2fSMilanka Ringwald elif frame.nr_subbands == 8: 63ad470863SMilanka Ringwald C = Proto_8_80 64c21a9c2fSMilanka Ringwald else: 65c21a9c2fSMilanka Ringwald return -1 66c21a9c2fSMilanka Ringwald 67c21a9c2fSMilanka Ringwald frame.sb_sample = np.ndarray(shape=(frame.nr_blocks, frame.nr_channels, frame.nr_subbands)) 68c21a9c2fSMilanka Ringwald index = 0 69c21a9c2fSMilanka Ringwald for ch in range(frame.nr_channels): 70c21a9c2fSMilanka Ringwald for blk in range(frame.nr_blocks): 71c21a9c2fSMilanka Ringwald for sb in range(frame.nr_subbands): 72ad470863SMilanka Ringwald frame.EX[sb] = np.int16(frame.pcm[index]) 73c21a9c2fSMilanka Ringwald index+=1 74ad470863SMilanka Ringwald sbc_frame_analysis(frame, ch, blk, C) 75ad470863SMilanka Ringwald return 0 76c21a9c2fSMilanka Ringwald 77ad470863SMilanka Ringwalddef sbc_encode(frame): 78ad470863SMilanka Ringwald err = sbc_analysis(frame) 79ad470863SMilanka Ringwald if err >= 0: 80ad470863SMilanka Ringwald err = sbc_quantization(frame) 81ad470863SMilanka Ringwald return err 82c21a9c2fSMilanka Ringwald 83ad470863SMilanka Ringwalddef calculate_joint_stereo_signal(frame): 84ad470863SMilanka Ringwald sb_sample = np.zeros(shape = (frame.nr_blocks,frame.nr_channels,frame.nr_subbands), dtype = np.uint32) 85ad470863SMilanka Ringwald scale_factor = np.zeros(shape=(frame.nr_channels, frame.nr_subbands), dtype = np.int32) 86ad470863SMilanka Ringwald scalefactor = np.zeros(shape=(frame.nr_channels, frame.nr_subbands), dtype = np.int32) 87ad470863SMilanka Ringwald 88ad470863SMilanka Ringwald for sb in range(frame.nr_subbands-1): 89ad470863SMilanka Ringwald for blk in range(frame.nr_blocks): 90ad470863SMilanka Ringwald sb_sample[blk][0][sb] = (frame.sb_sample_f[blk][0][sb] + frame.sb_sample_f[blk][1][sb]) >> 1 91ad470863SMilanka Ringwald sb_sample[blk][1][sb] = (frame.sb_sample_f[blk][0][sb] - frame.sb_sample_f[blk][1][sb]) >> 1 92ad470863SMilanka Ringwald 93ad470863SMilanka Ringwald for ch in range(frame.nr_channels): 94ad470863SMilanka Ringwald for sb in range(frame.nr_subbands-1): 95ad470863SMilanka Ringwald frame.scale_factor[ch][sb] = 0 96ad470863SMilanka Ringwald frame.scalefactor[ch][sb] = 2 97ad470863SMilanka Ringwald for blk in range(frame.nr_blocks): 98ad470863SMilanka Ringwald while frame.scalefactor[ch][sb] < abs(frame.sb_sample[blk][ch][sb]): 99ad470863SMilanka Ringwald frame.scale_factor[ch][sb]+=1 100ad470863SMilanka Ringwald frame.scalefactor[ch][sb] *= 2 101ad470863SMilanka Ringwald 102ad470863SMilanka Ringwald for sb in range(frame.nr_subbands-1): 103ad470863SMilanka Ringwald if (frame.scalefactor[0][sb] + frame.scalefactor[1][sb]) > (scalefactor[0][sb] + scalefactor[1][sb]): 104ad470863SMilanka Ringwald frame.join[sb] = 1 105ad470863SMilanka Ringwald frame.scale_factor[0][sb] = scale_factor[0][sb] 106ad470863SMilanka Ringwald frame.scale_factor[1][sb] = scale_factor[1][sb] 107ad470863SMilanka Ringwald frame.scalefactor[0][sb] = scalefactor[0][sb] 108ad470863SMilanka Ringwald frame.scalefactor[1][sb] = scalefactor[1][sb] 109ad470863SMilanka Ringwald for blk in range(frame.nr_blocks): 110ad470863SMilanka Ringwald frame.sb_sample[blk][0][sb] = sb_sample[blk][0][sb] 111ad470863SMilanka Ringwald frame.sb_sample[blk][1][sb] = sb_sample[blk][1][sb] 112c21a9c2fSMilanka Ringwald 113c21a9c2fSMilanka Ringwalddef calculate_scalefactor(max_subbandsample): 114c21a9c2fSMilanka Ringwald x = 0 115c21a9c2fSMilanka Ringwald while True: 116c21a9c2fSMilanka Ringwald y = 1 << x + 1 117c21a9c2fSMilanka Ringwald if y > max_subbandsample: 118c21a9c2fSMilanka Ringwald break 119c21a9c2fSMilanka Ringwald x += 1 120c21a9c2fSMilanka Ringwald return (x,y) 121c21a9c2fSMilanka Ringwald 122c21a9c2fSMilanka Ringwald 123c21a9c2fSMilanka Ringwalddef sbc_quantization(frame): 124c21a9c2fSMilanka Ringwald max_subbandsample = np.zeros(shape = (frame.nr_channels, frame.nr_subbands)) 125c21a9c2fSMilanka Ringwald 126c21a9c2fSMilanka Ringwald for blk in range(frame.nr_blocks): 127c21a9c2fSMilanka Ringwald for ch in range(frame.nr_channels): 128c21a9c2fSMilanka Ringwald for sb in range(frame.nr_subbands): 129c21a9c2fSMilanka Ringwald m = abs(frame.sb_sample[blk][ch][sb]) 130c21a9c2fSMilanka Ringwald if max_subbandsample[ch][sb] < m: 131c21a9c2fSMilanka Ringwald max_subbandsample[ch][sb] = m 132c21a9c2fSMilanka Ringwald 133c21a9c2fSMilanka Ringwald 134c21a9c2fSMilanka Ringwald for ch in range(frame.nr_channels): 135c21a9c2fSMilanka Ringwald for sb in range(frame.nr_subbands): 136ad470863SMilanka Ringwald frame.scale_factor[ch][sb] = 0 137ad470863SMilanka Ringwald frame.scalefactor[ch][sb] = 2 138ad470863SMilanka Ringwald for blk in range(frame.nr_blocks): 139ad470863SMilanka Ringwald while frame.scalefactor[ch][sb] < abs(frame.sb_sample[blk][ch][sb]): 140ad470863SMilanka Ringwald frame.scale_factor[ch][sb]+=1 141ad470863SMilanka Ringwald frame.scalefactor[ch][sb] *= 2 142ad470863SMilanka Ringwald 143ad470863SMilanka Ringwald #(frame.scale_factor[ch][sb], frame.scalefactor[ch][sb]) = calculate_scalefactor(max_subbandsample[ch][sb]) 144c21a9c2fSMilanka Ringwald 145c21a9c2fSMilanka Ringwald frame.bits = sbc_bit_allocation(frame) 146c21a9c2fSMilanka Ringwald 147c21a9c2fSMilanka Ringwald # Reconstruct the Audio Samples 148c21a9c2fSMilanka Ringwald frame.levels = np.zeros(shape=(frame.nr_channels, frame.nr_subbands), dtype = np.int32) 149c21a9c2fSMilanka Ringwald for ch in range(frame.nr_channels): 150c21a9c2fSMilanka Ringwald for sb in range(frame.nr_subbands): 151ad470863SMilanka Ringwald frame.levels[ch][sb] = (1 << frame.bits[ch][sb]) - 1 #pow(2.0, frame.bits[ch][sb]) - 1 152c21a9c2fSMilanka Ringwald 153c21a9c2fSMilanka Ringwald frame.syncword = 156 154c21a9c2fSMilanka Ringwald frame.crc_check = calculate_crc(frame) 155c21a9c2fSMilanka Ringwald 156ad470863SMilanka Ringwald frame.join = np.zeros(frame.nr_subbands, dtype = np.uint8) 157ad470863SMilanka Ringwald if frame.channel_mode == JOINT_STEREO: 158ad470863SMilanka Ringwald calculate_joint_stereo_signal(frame) 159ad470863SMilanka Ringwald 160c21a9c2fSMilanka Ringwald for blk in range(frame.nr_blocks): 161c21a9c2fSMilanka Ringwald for ch in range(frame.nr_channels): 162c21a9c2fSMilanka Ringwald for sb in range(frame.nr_subbands): 163c21a9c2fSMilanka Ringwald if frame.levels[ch][sb] > 0: 164c21a9c2fSMilanka Ringwald SB = frame.sb_sample[blk][ch][sb] 165c21a9c2fSMilanka Ringwald L = frame.levels[ch][sb] 166ad470863SMilanka Ringwald SF = frame.scalefactor[ch][sb] 16741a4a18dSMilanka Ringwald frame.audio_sample[blk][ch][sb] = np.uint16(((SB * L / SF + L) - 1.0)/2.0) 168c21a9c2fSMilanka Ringwald else: 169c21a9c2fSMilanka Ringwald frame.audio_sample[blk][ch][sb] = 0 170c21a9c2fSMilanka Ringwald 171c21a9c2fSMilanka Ringwald return 0 172c21a9c2fSMilanka Ringwald 173ad470863SMilanka Ringwalddef sbc_write_frame(fout, sbc_encoder_frame): 174ad470863SMilanka Ringwald stream = frame_to_bitstream(sbc_encoder_frame) 175ad470863SMilanka Ringwald barray = bytearray(stream) 176ad470863SMilanka Ringwald fout.write(barray) 177ad470863SMilanka Ringwald 178ba114a98SMatthias Ringwaldif __name__ == "__main__": 179ba114a98SMatthias Ringwald usage = ''' 180*5665ea35SMilanka Ringwald Usage: ./sbc_encoder.py input.wav blocks subbands bitpool allocation_method[0-LOUDNESS,1-SNR] 181*5665ea35SMilanka Ringwald Example: ./sbc_encoder.py fanfare.wav 16 4 31 0 182ba114a98SMatthias Ringwald ''' 183ba114a98SMatthias Ringwald nr_blocks = 0 184ba114a98SMatthias Ringwald nr_subbands = 0 185c21a9c2fSMilanka Ringwald 186ad470863SMilanka Ringwald 187*5665ea35SMilanka Ringwald if (len(sys.argv) < 6): 188ba114a98SMatthias Ringwald print(usage) 189ba114a98SMatthias Ringwald sys.exit(1) 190ba114a98SMatthias Ringwald try: 191ba114a98SMatthias Ringwald infile = sys.argv[1] 192ba114a98SMatthias Ringwald if not infile.endswith('.wav'): 193ba114a98SMatthias Ringwald print(usage) 194ba114a98SMatthias Ringwald sys.exit(1) 195ad470863SMilanka Ringwald sbcfile = infile.replace('.wav', '-encoded.sbc') 196ad470863SMilanka Ringwald 197ba114a98SMatthias Ringwald nr_blocks = int(sys.argv[2]) 198ba114a98SMatthias Ringwald nr_subbands = int(sys.argv[3]) 199ba114a98SMatthias Ringwald bitpool = int(sys.argv[4]) 200*5665ea35SMilanka Ringwald allocation_method = int(sys.argv[5]) 201c21a9c2fSMilanka Ringwald 202ba114a98SMatthias Ringwald fin = wave.open(infile, 'rb') 203ad470863SMilanka Ringwald nr_channels = fin.getnchannels() 204ad470863SMilanka Ringwald sampling_frequency = fin.getframerate() 205ad470863SMilanka Ringwald nr_audio_frames = fin.getnframes() 206c21a9c2fSMilanka Ringwald 207ad470863SMilanka Ringwald subband_frame_count = 0 208ba114a98SMatthias Ringwald audio_frame_count = 0 209ad470863SMilanka Ringwald nr_samples = nr_blocks * nr_subbands 210ad470863SMilanka Ringwald fout = open(sbcfile, 'wb') 211ad470863SMilanka Ringwald while audio_frame_count < nr_audio_frames: 212ad470863SMilanka Ringwald if subband_frame_count % 200 == 0: 213ad470863SMilanka Ringwald print("== Frame %d ==" % (subband_frame_count)) 214c21a9c2fSMilanka Ringwald 215*5665ea35SMilanka Ringwald sbc_encoder_frame = SBCFrame(nr_blocks, nr_subbands, nr_channels, bitpool, sampling_frequency, allocation_method) 216ad470863SMilanka Ringwald fetch_samples_for_next_sbc_frame(fin, sbc_encoder_frame) 217c21a9c2fSMilanka Ringwald 218ad470863SMilanka Ringwald sbc_encode(sbc_encoder_frame) 219ad470863SMilanka Ringwald sbc_write_frame(fout, sbc_encoder_frame) 220c21a9c2fSMilanka Ringwald 221ad470863SMilanka Ringwald audio_frame_count += nr_samples 222ad470863SMilanka Ringwald subband_frame_count += 1 223c21a9c2fSMilanka Ringwald 224ad470863SMilanka Ringwald fin.close() 225ad470863SMilanka Ringwald fout.close() 226ad470863SMilanka Ringwald print("DONE, WAV file %s encoded into SBC file %s " % (infile, sbcfile)) 227c21a9c2fSMilanka Ringwald 228c21a9c2fSMilanka Ringwald 229ba114a98SMatthias Ringwald except IOError as e: 230ba114a98SMatthias Ringwald print(usage) 231ba114a98SMatthias Ringwald sys.exit(1) 232c21a9c2fSMilanka Ringwald 233c21a9c2fSMilanka Ringwald 234c21a9c2fSMilanka Ringwald 235c21a9c2fSMilanka Ringwald 236c21a9c2fSMilanka Ringwald 237