import wave
import numpy as np
import struct
import matplotlib.pyplot as plt
import math
import ctypes
#from compiler.ast import flatten
import soundfile as sf
def calculate_db(xdb):
db = math.pow(10, xdb/20)
return db
def calculate_db_test(xdb):
#db = 0
print ("math.pow(10, -12/20) : ", math.pow(10, -12/20)) # 0.251188643150958
print ("math.pow(10, -6/20) : ", math.pow(10, -6/20)) #0.5011872336272722
print ("math.pow(10, -3/20) : ", math.pow(10, -3/20)) #0.7079457843841379
print ("math.pow(10, -1/20) : ", math.pow(10, -1/20)) #0.8912509381337456
print ("math.pow(10, 0/20) : ", math.pow(10, 0/20)) #1.0
print ("math.pow(10, 1/20) : ", math.pow(10, 1/20)) #1.1220184543019633
print ('math.pow(10, 3/20) : ', math.pow(10, 3/20)) #1.4125375446227544
print ('math.pow(10, 6/20) : ', math.pow(10, 6/20)) #1.9952623149688795
print ('math.pow(10, 9/20) : ', math.pow(10, 9/20)) #2.8183829312644537
print ('math.pow(10, 12/20) : ', math.pow(10, 12/20)) #3.9810717055349722
db = math.pow(10, xdb/20)
return db
def generial_sinewave(samplerate,ch_num,bytes_width,xdb,sinwav_freq_l,sinwav_freq_r,duration, file_name):
# volume xdb
db = calculate_db(xdb)
# sample/every second
framerate = samplerate
# channel_num
channel_num = ch_num
# bytes needed every sample
sample_width = bytes_width
bits_width = sample_width*8
# seconds, long of data
duration = duration
# frequeny of sinewave
sinewave_frequency_l = sinwav_freq_l
sinewave_frequency_r = sinwav_freq_r
# max value of samples, depends on bits_width
max_val = 2**(bits_width-1) - 1
print ('max_val : ', max_val)
#volume = 32767*db #0x7FFF=32767
volume = max_val*db #2**(bits_width-1) - 1
#多个声道生成波形数据
x = np.linspace(0, duration, num=duration*framerate)
y_l = np.sin(2 * np.pi * sinewave_frequency_l * x) * volume
y_r = np.sin(2 * np.pi * sinewave_frequency_r * x) * volume
# 将多个声道的波形数据转换成数组
y = zip(y_l,y_r)
##print("zip y", y)
y = list(y)
##print("list y",y)
y = np.array(y,dtype=np.int)
#print("array y",y)
y = y.reshape(-1)
##print("reshap array y",y)
#plt.subplot(122)
#plt.plot(x, y_l, color='r', linestyle='-', marker='+')
#plt.show()
# 最终生成的一维数组
sine_wave = y
print("type(sine_wave)=",type(sine_wave))
#open wav file
wf = wave.open(file_name, 'wb')#wf = wave.open("sine.wav", 'wb')
wf.setnchannels(channel_num)
wf.setframerate(framerate)
wf.setsampwidth(sample_width)
#if (sample_width == 3):
# wf.setsampwidth(sample_width+1)
for v in sine_wave:
if (sample_width == 4):
data = struct.pack('<l', int(v))
elif (sample_width == 3):
#data = struct.pack('<l', int(v*2**8))
d = int(v)
dc = getComplement_24bits(d)
data = dc.to_bytes(3,'little')
elif (sample_width == 2):
data = struct.pack('<h', int(v))
elif (sample_width == 1):
d = int(v)
dc = getComplement_8bits(d)
data = dc.to_bytes(1,'little')
#print("d=%x,dc=%x"%(d,dc), data)
#data = struct.pack('<c', chr(dc)) #error
else:
data = struct.pack('<b', int(v))
#print("v=%x"%(v), data)
wf.writeframesraw(data)
#print(struct.pack('<i', int(y[2])))
#print(struct.pack('<i', int(y[4])))
wf.close()
def readWavFile(file_name):
sig, sample_rate = sf.read(file_name)
print("采样率:%d" % sample_rate)
#print(sig) #data, 2ch, 2 dimension matrix
return 0
def getComplement_24bits(v): #求24bis数据的补码
v_int = int(v)
if (v_int >= 0):
#print('param is positive')
return v_int
c = (-1)*v
c = ~c + 1
c &= 0xFFFFFF
c |= 0x800000
return c
def getComplement_8bits(v): #求8bis数据的补码
#todo, ???
if(v<0):
v = v + 0x80
else:
v = v - 0x80
v_int = int(v)
if (v_int >= 0):
#print('param is positive')
return v_int
c = (-1)*v
c = ~c + 1
c &= 0xFF
c |= 0x80
return c
def readWavFileAndPlotIt():
return 0
def float2split(fdata):
#print(type(fdata))
#print("fdata_string=", str(fdata))
#print("fdata_value=", fdata)
split = math.modf(fdata)
fraction_part = split[0]
decimal_part = split[1]
#print ("fraction_part=",fraction_part)
#print ("decimal_part=",decimal_part)
return split
#Keep 9 DecimalPlaces
def float2crop_str(fdata):
b = round(fdata, 9)
print("round(b)=",b)
b_str = str(b)
print("bstr=",b_str)
c = float(b_str)
print("c=",c)
if(fdata>c):
print("fdata>c,c=",c)
else:
c = fdata
print("fdata<=c,c=",c)
return str(c)
def float2crop(fdata):
b = round(fdata, 9)
#print("round(b)=",b)
b_str = str(b)
#print("bstr=",b_str)
c = float(b_str)
#print("c=",c)
if(fdata==c):
c = fdata
return c
def struct_pack_test(v):
v = -0x41aa
print("test:%x"%(v), struct.pack('<h', int(v)))
v = -54
print("test:%x"%(v), struct.pack('<b', int(v)))
v = -0x6a1aa
print("test:%x"%(v), struct.pack('<i', int(v)))
return 0
def sinewave_info_print(framerate,channel_num, sample_width, xdb, sinewave_frequency_l, sinewave_frequency_r, duration, file_name):
print("wav_file_name: ", file_name)
print("samplerate: ", framerate)
print("channel_num: ", channel_num)
print("bits_width: ", sample_width*8)
print("volume: %db"%(xdb))
print("sine_freq_ch_l: ", sinewave_frequency_l)
print("sine_freq_ch_r: ", sinewave_frequency_r)
print("sine_freq_duration: ", duration)
return 0
def general_sinewave_filename(framerate,channel_num,sample_width, xdb, sinewave_frequency_l, sinewave_frequency_r, duration):
# wav file_name
bits_width = sample_width*8
duration_cropped = float2crop(duration)
file_name = "sine_"+str(framerate)+"_"+str(channel_num)+"ch_"+str(bits_width)+"bits_"+str(xdb)+"db"
file_name += "_l"+str(sinewave_frequency_l)+"_r"+str(sinewave_frequency_r)+"_"+str(duration_cropped)+"s.wav"
print("samplerate: ", framerate)
print("channel_num: ", channel_num)
print("bits_width: ", sample_width*8)
print("volume: %db"%(xdb))
print("sine_freq_ch_l: ", sinewave_frequency_l)
print("sine_freq_ch_r: ", sinewave_frequency_r)
print("sine_freq_duration: ", duration)
print ('file_name: ', file_name)
return file_name
def main():
# volume x_db
db = -3
#db = calculate_db(db_v)#db = math.pow(10, -3/20)
# sample/every second
framerate = 48000
# channel_num
channel_num = 2
# bytes needed every sample
sample_width = 4
bits_width = sample_width*8
# frequeny of sinewave
sinewave_frequency_l = 2000
sinewave_frequency_r = 2000
# seconds, long of data
#duration = 40/framerate #used to test float2crop() function
duration = (2*(framerate/sinewave_frequency_r))/framerate
if sample_width not in [1,2,3,4]: ##[1,3]has some errors,resolved
return 0
file_name = general_sinewave_filename(framerate, channel_num, sample_width, db, sinewave_frequency_l, sinewave_frequency_r, duration)
#sinewave_info_print(framerate,channel_num, sample_width, db, sinewave_frequency_l, sinewave_frequency_r, duration, file_name)
generial_sinewave(framerate,channel_num, sample_width, db, sinewave_frequency_l, sinewave_frequency_r, duration, file_name)
return 0
main()
python生成特定频率、特定音量的正弦波wav文件(升级版v1.231)
猜你喜欢
转载自blog.csdn.net/qingfengjuechen/article/details/102897574
今日推荐
周排行