|
这篇文章主要介绍了Python实现将wav转amr,并转换成hex数组方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教% z, U b$ H! ?
. v5 S) E. }) l. } 6 Z* K o* K$ j& s' k
+ 目录! B H2 z' D4 _7 R
! Y; K# D. G+ r1 d7 e9 {
将wav转amr,并转换成hex数组将wav文件快速转为amr,同时将arm文件转为16进制数组,保存在对应.h文件,供嵌入式设备使用(无文件系统产品(⊙o⊙)哦)
; s6 e/ B9 \9 _9 z& K直接上代码generate_audio_file.py - from __future__ import print_function- H! p& A; z& i) `6 C# [- n U7 ^" U
- from builtins import range3 }! l9 y7 ?( E; y4 Q
- import os: p1 e; a7 x0 a* I
- import wave. T# w$ p8 }' e$ s
- import struct
3 y& f$ e: G: X - import time* Z9 n7 B) k4 s+ k/ s0 ]1 O
- import re
$ G; R, H. d- y( d' i) T% l5 F - import subprocess+ h) {$ ^! W7 T: L& }5 \
- import binascii
1 i! N" A) a- _) h: } K8 u$ I - # eric 2020年7月10日; Y$ I @2 F$ T$ q: _2 @
- # wav文件转PCM数组
) y5 N3 _; r: Q/ I2 o3 e - def get_wave_array_str(filename, target_bits):
" K/ o7 s% o9 W* a - wave_read = wave.open(filename, "r")
" m6 M; Z9 g: C. x - array_str = "// start\n\t"
z$ x/ ]) `; L+ W' k/ f+ h n - nchannels, sampwidth, framerate, nframes, comptype, compname = wave_read.getparams()
' p9 w9 O& L7 ]1 d% S3 B - sampwidth *= 84 _" l+ M) O3 d) [
- for i in range(wave_read.getnframes()):- _4 i) s5 n( k. Q$ }
- val, = struct.unpack("<H", wave_read.readframes(1))
7 u" G3 J8 w' \9 m - scale_val = (1 << target_bits) - 1
8 d. t* [1 D8 M {4 _6 w - cur_lim = (1 << sampwidth) - 1
8 i/ }3 a( F; C: T) N9 R- t - # scale current data to 8-bit data, @8 o: U+ k! j3 H7 |, x8 v9 {
- val = val * scale_val / cur_lim
( F" l0 n0 c G) Y. E& G - val = int(val + ((scale_val + 1) // 2)) & scale_val
, o! y. j# M' x8 M - array_str += "0x%02x, " % (val)
+ t5 ^2 L' r4 s. X0 Z - if (i + 1) % 16 == 0:
, x: O: x7 ?5 f/ N: j6 H8 r: A - array_str += "\n\t"
) C1 b+ I4 N! p" R/ \6 J* f/ v. G1 A - return array_str1 ^& [5 ~: N) p8 t# R
- # PCM 数组合并
7 `* a5 p$ j& x/ } - def gen_wave_table(wav_file_list, target_file_name, scale_bits=8):# \' N5 ^ R, K& Y5 M
- with open(target_file_name, "w") as audio_table:
* }" b4 U1 e, f& K - print('#include <stdio.h>', file=audio_table)
0 r* n, S6 p" A5 e - print("// time:{}".format(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))), file=audio_table)
; T; y E+ ~+ X/ C$ e# | - print('const unsigned char audio_table[] = {', file=audio_table)) f2 e2 N4 J6 R w: h. M
- for wav in wav_file_list:. E8 N) S: W- E& x" X! S0 H
- print("processing: {}".format(wav))# G/ z( ?3 `# q# l0 r
- print('//name:{}\n'.format(wav), file=audio_table)' c6 i, L2 `7 r, K( T' O
- print(get_wave_array_str(filename=wav, target_bits=scale_bits), file=audio_table)
2 y" f- j" O% I& q - print('};\n', file=audio_table); P3 S- k* x& @# z/ ?& P9 W
- print("Done...")
! V4 |& v5 o' V5 n - # 获取wav文件信息, w1 S8 k, v [$ o
- def get_wave_info(filename):
* U; `4 d0 X! u/ s2 b& | - wave_read = wave.open(filename, "r")
( ^+ V/ t b V% S0 @ - nchannels, sampwidth, framerate, nframes, comptype, compname = wave_read.getparams()
) O3 z" j) s: e( M" K) `7 \* _ - print('nchannels:{}'.format(nchannels))% U" i& U8 d; W+ o/ q' V& P. Y- @* ]
- print('sampwidth:{}'.format(sampwidth))) O) Z" o2 g, H, F( {7 s( |0 z
- print('framerate:{}Hz'.format(framerate))" C& F- u9 L8 L) ]
- print('nframes:{}'.format(nframes))( _" S* j9 j8 O
- print('comptype:{}'.format(comptype))# F- I7 K2 N. E( D" l& `6 I3 p# {
- print('compname:{}'.format(compname))2 Q+ T) X- V* ~' G$ b! L5 f
- return framerate7 H7 a z% g S9 Y- w: U2 I2 J
- # 二进制文件转数组. ]8 w! l: ?) b$ Z$ I- y
- def file2array(filename,h_filename=None):8 E6 T1 u" C6 G& v5 v4 E8 e
- path, name = os.path.split(filename)
2 ~4 J" T) Z1 V - if h_filename is None:/ J1 \! p0 e" o" t% g3 ]4 p2 J; L
- h_filename = os.path.join(path, name.split('.')[0] +'.h'). }# j5 v7 ?5 f8 H
- array_str = '\n//total len:{} bytes\n'.format(os.path.getsize(filename))2 C! L$ B' @! E3 \
- array_str += 'const unsigned char '+name.split('.')[0]+'[]={\n\t'
$ ?9 B3 c L) {% P - # print(array_str)6 v8 p: a" A( o! [0 R" L! G' `1 H
- h_file = open(h_filename, "w")+ l3 d/ x; N$ P& E' Q. y/ U1 _
- file = open(filename, 'rb')
" ? W' H; z2 @) N - try:5 R8 w" p: C( J# P. Y
- while True:7 p. L' X* i$ p j
- chunk = file.read(16*32) h4 q9 h' V8 G1 E2 c) w$ J2 H
- if not chunk:
7 e) U% K+ a1 Y# G, @# }8 {" L' ^4 E - break& _6 U4 [! ?4 A5 f) }* A# I
- for i in range(len(chunk)):# T7 J/ k& q# F( P, Z! t
- array_str += "0x%02x, " % (chunk[i])( I/ A" _1 K7 L% @8 N# n2 Z4 v
- if (i + 1) % 16 == 0:
. b* O: Z3 r; D3 L! B+ @ - array_str += "\n\t"& c+ A$ \# f; j, n4 C1 m' l+ I0 X3 t
- # print('get:{}'.format(binascii.b2a_hex(chunk)))
4 t* f4 u% z% h W+ z( E$ i- v2 { - except:
' W# Q' h/ b0 L - print('read ERR')7 V! r5 i6 X" \- K1 Z. m [! P
- finally:6 e7 H1 I$ V# K q% n h2 f$ z6 V
- print('read file done!')
/ w5 r/ |" X7 r1 t' ]! p5 q - array_str += '\n};\r\n'
$ b2 _, m2 p4 S ] - # print('array='+array_str)5 z, [ K: }# O# X6 p* e6 U3 h4 {
- print(array_str, file=h_file)1 p+ l3 ~4 A& F1 S u( D! C5 p# L1 d
- h_file.close()7 j1 T8 X# Z. \
- file.close()
& C' \1 {' z2 D: @( L6 n" f* _- B& k - return 0
* R; O4 j) i% G2 t - # ffmpeg路径" e7 ]" Z: s& W
- ffpeg_path = 'D:/Program Files (x86)/QveAudio/'
6 Q5 }8 s1 q J9 [$ |" P' c - # amr文件转MP3, n3 A& p7 a/ Q! W( k
- def amr2mp3(amr_path,mp3_path=None):
9 K/ M& x: [* z" B - path, name = os.path.split(amr_path)2 s0 H6 H+ \( {
- if name.split('.')[-1]!='amr':- }1 P/ K! J1 j
- print('not a amr file')( _9 X5 U2 [* w. k
- return 0/ a. P4 z" t' `" E
- if mp3_path is None or mp3_path.split('.')[-1]!='mp3':5 N" z$ ^. ^; v
- mp3_path = os.path.join(path, name.split('.')[0] +'.mp3')5 I% I) p6 F+ o) `/ O/ @- P7 L
- error = subprocess.call(['ffmpeg/bin/ffmpeg','-i',amr_path,mp3_path])9 q! z2 ^& C" U
- print('ERR:'+error)
+ \6 O) c6 r/ h1 F! o - if error:
) P4 ^; D# P" e9 v - return 0, {+ z: T) ]. Y4 \+ m$ U
- print ('success')
: a: W- p0 m* P% C0 s - return mp3_path
3 ]3 G; n% q+ C1 O/ \/ n - # wav文件转amr,wav必须为8000Hz
/ f, ?7 a& r: l+ J e7 ~0 W - def wave2amr(wave_path,amr_path=None):
$ x$ Z. c. z0 f, x* `) F) A - path, name = os.path.split(wave_path)
& [( ?7 G& Z% F - if name.split('.')[-1]!='wav':
: J. [, Q" C, j% j# {5 M7 r# E - print ('not a wave file')
7 r! L% L! C5 o( Z; ^5 l - return 0) |" t% _5 q& Q/ S A
- if amr_path is None or amr_path.split('.')[-1]!='amr':8 O4 k/ n" T! J9 f$ F% _+ S
- amr_path = os.path.join(path, name.split('.')[0] +'.amr')
1 x% T7 `9 Y9 U9 a7 a( r1 j2 ` - error = subprocess.call([ffpeg_path+'ffmpeg','-i',wave_path,'-y',amr_path])1 i$ b! W9 Y0 g5 y/ D9 s# W- j6 j
- print('ERR:{}'.format(error))
" h3 W$ f- C! R; n1 N" j. Y - if error:3 [: F, G/ A; g* f9 o
- return 0
6 y& i0 V" f3 N! ^ B - print ('amr success'), S. z2 ]# E" n, X% G
- return amr_path' w1 Y2 \' X5 u" E* N, p
- # wav 格式化为8000Hz9 j# r: W) `9 B2 ^; C/ I. \3 r# O
- def wave2Hz8000(wave_path,out_path=None):& R% |0 V5 L2 H$ \9 E
- path, name = os.path.split(wave_path)% }& I" o9 k2 u/ t0 @
- if name.split('.')[-1]!='wav':
/ n+ U, S* }4 \' q) N7 o8 j - print ('not a wave file')6 y$ O8 f2 q* ? k$ A! B6 v
- return 0
& e5 n4 k' b; _% ^' {( Q3 Q, Q9 ?9 G - if out_path is None or wave_path.split('.')[-1]!='wav':5 Q: C! j* e0 o1 y0 j6 X
- out_path = os.path.join(path, name.split('.')[0] +'_8k.wav'); F" e) c2 I: [4 H6 A0 U4 K. N) d4 s
- # error = subprocess.call([ffpeg_path+'ffmpeg','-i',wave_path,'-ar','8000','-y',out_path])* b- S& s: G; m& o* ?) ]
- error = subprocess.call(ffpeg_path+'ffmpeg'+' -i '+wave_path+' -ar 8000 -y '+out_path)
6 s$ V1 D6 | o) ?+ ^; G1 p - print('ERR:{}'.format(error)). O, A9 Q `" O! K4 b
- if error:
. W: F% @; z/ @ - return 07 j: O7 O8 c h# \% V+ m
- print ('wav success')
4 w1 U: L, f9 f2 c - return out_path. l* d" J: \) m5 J% n. l$ e, ?
- # 将目录下所有wav文件转为amr,并转为对应的数组文件
7 o! S, R# Z/ O$ j2 H$ Y/ i - if __name__ == '__main__':2 s5 p) d0 L* i2 M( j; U5 r
- print("Generating audio array...")% J* Q" S, ~ I2 |( M/ t9 V4 [# L
- # wav_list = []7 ~% n% ^" T+ V" q o& M0 i
- for filename in os.listdir("./"):* s% e+ |) p7 w, ~: c1 c
- # print(os.getcwd())
+ q' ~. y1 k4 e# w' Q, F3 F4 E8 Y - if filename.endswith(".wav"):; Q% o- [1 W( L
- print('src_name:',filename)% ~. {4 p1 } f/ p6 y' x e
- framerate = get_wave_info(filename)
. I& a1 {* u( } - if framerate != 8000:, X, R( N1 W2 E% X0 N; N- i
- print('to 8000Hz')" u, l! [4 U8 i5 z
- filename = wave2Hz8000(filename); D5 C5 r F5 H9 f* d
- amr_file = wave2amr(filename)$ x2 ], v. n* o$ G) l! l0 Z
- if amr_file!=0: M4 A4 d6 p8 x4 X* n/ r
- file2array(amr_file)) X# D+ z" f2 H& ^
- # dst_name = "0_"+filename
+ v" E# |8 p9 F+ Q" _, ^# d) u - # print('dst_name:',filename)
3 w: D% x S1 o - # os.rename(filename, dst_name)
! }1 a# o* b: e; ^ x7 ^! Y$ @ - # wav_list.append(filename)7 G2 F9 E5 p# @2 `
- # gen_wave_table(wav_file_list=wav_list, target_file_name="audio_example_file.h")
复制代码
% n. `( X% T) K5 M% S; P L' j/ U以上代码实现的功能: - 将当前目录下的所有wav文件,转为8kHz的wav
- 将对应的8kHz wav,转为amr
- 将对应的amr,转为hex数组,并保存在.h文件中. \7 n4 w# D4 a$ |* E' n
注意:音频的转换用的ffmpeg,使用前需确认对应的路径 - ffpeg_path = 'D:/Program Files (x86)/QveAudio/'
复制代码 3 X D2 t7 o, @8 J* e
/ Z7 w; o* f1 v7 X3 m3 J m
. `7 A. U( J, g& N
& K0 v# a+ g3 J2 W7 G; d; U# x# I, n& F1 {- V
|
|