问一个关于WAV的问题

时间:2021-04-18 20:17:30
我想将一个音量较小的WAV文件的音量放大,已经读取到了数据区的数据,以Byte的形式存放在变量中,

这个WAV是双声道、16位的,相关的参数已经取得。

请教高手,Byte的形式存放在变量中的数据,如何分离出来,并提高音量。最好给出代码,谢谢。

31 个解决方案

#1


用DirectX应该要容易些吧,不过我对那个不怎么熟悉,抱歉帮顶了。。。

#2


有人会这个么?谢谢

#3


本帖最后由 bcrun 于 2010-07-30 09:21:06 编辑
参考:
http://blog.csdn.net/BlueSoal/archive/2006/07/17/932395.aspx

#4


楼上的是说WAV格式,要是能调节音量就好了

#5


将 WAV 里面的声道数据按 8bit/16bit 值进行等比放大就是调高音量。

#6


Dim yByte() As Byte         '音乐数据字节数组
ReDim yByte(my_wavData.nSize) 'my_wavData.nSize就是音乐数据的长度

Open App.Path & "\123.wav" For Binary Access Read As #1
Open App.Path & "\456.wav" For Binary Access Write As #2 

X$ = Input(44, #1)        '文件头长度为44
Get #1, , yByte

至此,如果这个WAV已知是16bit、双声道的,如何写入456.WAV,以提高音量? 

#7


该回复于2010-08-03 10:30:13被版主删除

#8


该回复于2010-07-30 16:10:56被版主删除

#9


学习,帮顶!

要研究一下WAV格式,然后再去操作它.

#10


推荐使用NCTAudioStudio控件

#11


最好不用控件,对WAV的数据按字节进行操作不行么?

#12


Private Type WAVERIFF
        sID As String
        nSize As Long
        sType As String
End Type

Private Type WAVEdata
        sID As String
        nSize As Long
        dData As Byte
End Type

Private Type WAVEfact
        sID As String
        nSize As Long
        dData As Long
End Type
Private Type WAVEFORMAT
        nID As String
        nSize  As Long              '值为16或18,为18时则最后又附加信息
        wFormatTag As Integer       '编码方式
        nChannels As Integer        '声道1-单声道;2-双声道
        nSamplesPerSec As Long      '采样频率
        nAvgBytesPerSec As Long     '每秒字节数
        nBlockAlign As Integer      '数据块对齐单位(每个采样需要的字节数)
        nBitsPerSample As Integer   '块调整值=声道数*采样位数/8 (注意数据类型,不是Long,微软的数据结构定义错了)
        nBitsPerSample1 As String   '附加信息
End Type
Dim my_wav As WAVEFORMAT
Dim my_wavfact As WAVEfact
Dim my_wavData As WAVEdata
Dim my_wavRIFF As WAVERIFF
Dim yByte() As Byte      '音乐数据字节数组
Dim waveHDR(43) As Byte

Private Sub Form_Load()
'导入的声音文件Fname
Dim Fname As String
Fname = App.Path & "\888.wav"

Label3.Caption = "修改时间: " & FileDateTime(Fname)
Label1.Caption = "文件: " & Fname

Open Fname For Binary Access Read As #1
Label2.Caption = "大小: " & LOF(1) & " 字节"
Close #1


Open Fname For Binary Access Read As #1
  Get #1, , waveHDR    'WAV文件的头部
Close #1


 
Open Fname For Binary Access Read As #1
    '第一部分“RIFF”
   With my_wavRIFF
     .sID = Input(4, #1)        '格式标志“RIFF”,4个字节
     Get #1, , .nSize            '文件长度LONG类型,大小等于WAV文件大小减去ID和Size所占用的字节
    .sType = Input(4, #1)       '“WAVE”,4个字节
   End With
    
    '第二部分“fmt ”
  With my_wav
              .nID = Input(4, #1)      '“fmt ”,4个字节
    Get #1, , .nSize                   'size,值为16或18,为18时则最后又附加信息
    Get #1, , .wFormatTag              '编码方式
    Get #1, , .nChannels               '声道1-单声道;2-双声道
    Get #1, , .nSamplesPerSec          '采样率(单位:赫兹)典型值:11025、22050、44100、48000Hz
    Get #1, , .nAvgBytesPerSec         '每秒字节数
    Get #1, , .nBlockAlign             '数据块对齐单位(每个采样需要的字节数)设定资料区所占的byte数
    Get #1, , .nBitsPerSample          '块调整值=声道数*采样位数/8
    If .nSize = 18 Then .nBitsPerSample1 = Input(2, #1)
    
  End With

Label8 = my_wav.nID & " 声道:" & my_wav.nChannels & " 采样率:" & my_wav.nSamplesPerSec & _
         " 每秒字节数:" & my_wav.nAvgBytesPerSec & " 每个采样点数:" & my_wav.nBitsPerSample


   '第三部分
With my_wavfact
    .sID = Input(4, #1)                 '标志"fact"
    If .sID = "data" Then GoTo dataA
     Get #1, , .nSize                   '数值为4
     Get #1, , .dData
End With
    

dataA:

  '第四部分
  With my_wavData
  If my_wavfact.sID = "data" Then
  my_wavfact.sID = ""
  .sID = "data"
  Get #1, , .nSize
  'Get #1, , .dData '数据暂时不读取
  End If
  End With

Label4 = my_wavfact.sID & my_wavData.sID & "数据长度:" & my_wavData.nSize



'以下是将相关数据处理后,写入999.WAV文件

Open App.Path & "\999.wav" For Binary Access Write As #2 '打开目标文件
  Put #2, 1, waveHDR       '写入文件头部
  
  Dim a() As Byte
  Dim ii As Long
  Dim b As Byte
   
  ReDim a(my_wavData.nSize) '定义WAV文件的数据长度数组
  
  
  Get #1, , a
  For ii = 45 To my_wavData.nSize + 44
  
  '音频数据以128(8位)或32768(16位)两个数为音频波形中线值
  '我想将音量放大50%,就应该用下边的算法了
  '可以写入后的文件没有一点声音
  
  If a(i) >= 32768 Then
  a(i) = a(i) * 1.5
  Else
  a(i) = a(i) * 0.5
  End If
   Put #2, ii, a(i)
  Next
  
  
Close #1
Close #2
End Sub




我的源程序是这样的,请大家看看。

#13


1)你用 Beyond Compare 2 之类的工具二进制比较两个文件,除了声道数据部分其他是否相同。
2)16位数据是两个字节,a(i) 始终是一个字节,怎么想的?
3)For ii 的循环中 i 没变过,你一直处理始终不变的 a(i)?
4)
Get #1, , a
是从文件头之后开始读取,
Put #2, ii, a(i)
是从文件位置 45 开始写?

#14


16位数据是两个字节
 

Dim q  As Byte
Dim b As Byte

For ii = 45 To my_wavData.nSize + 44
Get #1, , q
'Debug.Print q
'对这个q 进行操作才有效,不过就是音质方面不是很饱满,放大的效果达到了
  If q = 256 Then GoTo aaq
  Select Case q
  Case Is > 128
       b = q * 0.6
 Case Is < 128
       b = q * 1.4
 Case 128
       b = q
 End Select
  
aaq:
  Put #2, ii, b

音质方面还需要改进,请指教了。

#15


音质是没什么办法的,一但达到十六位数的上限值,再想调高肯定就要牺牲音质了

#16


要用 Integer 类型 2 字节一起处理,按照你的做法
&H1280 (  4736) -> &H1980 (  6528)
&H8080 (-32640) -> &H8080 (-32640)
&H7090 ( 28816) -> &H9D56 (-25258)
怎么不失真?

#17


是这样么?


Dim q  As Integer
Dim b As Integer

For ii = 45 To my_wavData.nSize + 44
Get #1, , q
'Debug.Print q
'对这个q 进行操作才有效,不过就是音质方面不是很饱满,放大的效果达到了
  If q = 256 Then GoTo aaq
  Select Case q
  Case Is > 128
       b = q * 0.6
 Case Is < 128
       b = q * 1.4
 Case 128
       b = q
 End Select
  
aaq:
  Put #2, ii, b
next

#18


Integer 的区间是 [-32768, 32767],再仔细想想!

还有要不失真地放大,应该先扫描一遍数据,求出现有波形的振幅,计算
  放大比率 = 32767 / 现有振幅
然后用这个比率去放大波形。
否则波形的峰、谷可能会被切平。

#19


引用 18 楼 tiger_zhao 的回复:
Integer 的区间是 [-32768, 32767],再仔细想想!

还有要不失真地放大,应该先扫描一遍数据,求出现有波形的振幅,计算
  放大比率 = 32767 / 现有振幅
然后用这个比率去放大波形。
否则波形的峰、谷可能会被切平。



说这个原理是很容易的,能给出具体的程序么?
放大比率 = 32767 / 现有振幅

这么做,就是要将声音放大到最大。要是有原码就好了

#20


Dim q           As Integer
Dim b           As Integer
Dim lPosition   As Long
Dim lMax        As Long
Dim dScale      As Double

lPosition = Seek(1)
lMax = 0
For ii = 45 To my_wavData.nSize + 44
    Get #1, , q
    lMax 为 Abs(q) 的最大值
Next
dScale = 32767 / lMax

Seek #1, lPosition
For ii = 45 To my_wavData.nSize + 44
    Get #1, , q
    b 为 q 按 dScale 倍率放大
    Put #2, ii, b
Next

#21


引用 20 楼 tiger_zhao 的回复:
VB code
Dim q           As Integer
Dim b           As Integer
Dim lPosition   As Long
Dim lMax        As Long
Dim dScale      As Double

lPosition = Seek(1)
lMax = 0
For ii = 45 To my_wavData……



lMax 为 Abs(q) 的最大值
b 为 q 按 dScale 倍率放大
这个运行效率可能太低了,要是将这2个过程写出来就好了

#22


每个都只是一行代码,不要太懒了!

#23


已经解决。不过说明一下,用VB写效率不是太高。一段不长的音乐文件,置换一下时间较长。

#24


我也碰到类似的问题,请问楼主是怎么解决音质问题的,急求。

#25


音质问题,实际上讲上没有得到解决,只不过音量是提高了,勉强能听听而已。

就是要做到音质不降低,不知道如何做。或许可能需要插入一些数据才行。

想像那个波形文件,好像应该加上一个数可能不会失真,如果用乘,貌似会出击失真。

#26


我按照Tiger_Zhao说的方法做,得到的是一片杂音。还希望Tiger_Zhao能具体贴一下代码

#27


用Cool Edit Pro软件?

#28


Cool Edit Pro软件应该可以,不过想要的是代码

#29


分是给了,不过Tiger_Zhao说的做法,还是没有做出来。

#30


找到了一份C++的代码,哪位大侠可以改写成VB的代码吗。

/*---------------------------------------
method name : AmplifyPCMData
comment : 对PCM数据的音量进行放大
parameter : 
pData PCM数据
nLen PCM数据的长度
nBitsPerSample 每个Sample的位数,一般为8的整数
multiple 放大倍数
result : S_OK 成功
---------------------------------------*/
int AmplifyPCMData(BYTE* pData, int nLen, int nBitsPerSample, float multiple)
{
int nCur = 0;
if (16 == nBitsPerSample)
{
while (nCur < nLen)
{
short* volum = (short*)(pData + nCur);
*volum = (*volum) * multiple;
if (*volum > SHRT_MAX)//爆音的处理
{
*volum = SHRT_MAX;
}
*(short*)(pData + nCur) = *volum  ;
nCur += 2;
}

}
else if (8 == nBitsPerSample)
{
while (nCur < nLen)
{
BYTE* volum = pData + nCur;
*volum = (*volum) * multiple;
if (*volum > 255)//爆音的处理
{
*volum = 255;
}
*pData  = *volum  ;
nCur ++;
}

}
return S_OK;

}

#31


该回复于2011-01-04 09:17:11被版主删除

#1


用DirectX应该要容易些吧,不过我对那个不怎么熟悉,抱歉帮顶了。。。

#2


有人会这个么?谢谢

#3


本帖最后由 bcrun 于 2010-07-30 09:21:06 编辑
参考:
http://blog.csdn.net/BlueSoal/archive/2006/07/17/932395.aspx

#4


楼上的是说WAV格式,要是能调节音量就好了

#5


将 WAV 里面的声道数据按 8bit/16bit 值进行等比放大就是调高音量。

#6


Dim yByte() As Byte         '音乐数据字节数组
ReDim yByte(my_wavData.nSize) 'my_wavData.nSize就是音乐数据的长度

Open App.Path & "\123.wav" For Binary Access Read As #1
Open App.Path & "\456.wav" For Binary Access Write As #2 

X$ = Input(44, #1)        '文件头长度为44
Get #1, , yByte

至此,如果这个WAV已知是16bit、双声道的,如何写入456.WAV,以提高音量? 

#7


该回复于2010-08-03 10:30:13被版主删除

#8


该回复于2010-07-30 16:10:56被版主删除

#9


学习,帮顶!

要研究一下WAV格式,然后再去操作它.

#10


推荐使用NCTAudioStudio控件

#11


最好不用控件,对WAV的数据按字节进行操作不行么?

#12


Private Type WAVERIFF
        sID As String
        nSize As Long
        sType As String
End Type

Private Type WAVEdata
        sID As String
        nSize As Long
        dData As Byte
End Type

Private Type WAVEfact
        sID As String
        nSize As Long
        dData As Long
End Type
Private Type WAVEFORMAT
        nID As String
        nSize  As Long              '值为16或18,为18时则最后又附加信息
        wFormatTag As Integer       '编码方式
        nChannels As Integer        '声道1-单声道;2-双声道
        nSamplesPerSec As Long      '采样频率
        nAvgBytesPerSec As Long     '每秒字节数
        nBlockAlign As Integer      '数据块对齐单位(每个采样需要的字节数)
        nBitsPerSample As Integer   '块调整值=声道数*采样位数/8 (注意数据类型,不是Long,微软的数据结构定义错了)
        nBitsPerSample1 As String   '附加信息
End Type
Dim my_wav As WAVEFORMAT
Dim my_wavfact As WAVEfact
Dim my_wavData As WAVEdata
Dim my_wavRIFF As WAVERIFF
Dim yByte() As Byte      '音乐数据字节数组
Dim waveHDR(43) As Byte

Private Sub Form_Load()
'导入的声音文件Fname
Dim Fname As String
Fname = App.Path & "\888.wav"

Label3.Caption = "修改时间: " & FileDateTime(Fname)
Label1.Caption = "文件: " & Fname

Open Fname For Binary Access Read As #1
Label2.Caption = "大小: " & LOF(1) & " 字节"
Close #1


Open Fname For Binary Access Read As #1
  Get #1, , waveHDR    'WAV文件的头部
Close #1


 
Open Fname For Binary Access Read As #1
    '第一部分“RIFF”
   With my_wavRIFF
     .sID = Input(4, #1)        '格式标志“RIFF”,4个字节
     Get #1, , .nSize            '文件长度LONG类型,大小等于WAV文件大小减去ID和Size所占用的字节
    .sType = Input(4, #1)       '“WAVE”,4个字节
   End With
    
    '第二部分“fmt ”
  With my_wav
              .nID = Input(4, #1)      '“fmt ”,4个字节
    Get #1, , .nSize                   'size,值为16或18,为18时则最后又附加信息
    Get #1, , .wFormatTag              '编码方式
    Get #1, , .nChannels               '声道1-单声道;2-双声道
    Get #1, , .nSamplesPerSec          '采样率(单位:赫兹)典型值:11025、22050、44100、48000Hz
    Get #1, , .nAvgBytesPerSec         '每秒字节数
    Get #1, , .nBlockAlign             '数据块对齐单位(每个采样需要的字节数)设定资料区所占的byte数
    Get #1, , .nBitsPerSample          '块调整值=声道数*采样位数/8
    If .nSize = 18 Then .nBitsPerSample1 = Input(2, #1)
    
  End With

Label8 = my_wav.nID & " 声道:" & my_wav.nChannels & " 采样率:" & my_wav.nSamplesPerSec & _
         " 每秒字节数:" & my_wav.nAvgBytesPerSec & " 每个采样点数:" & my_wav.nBitsPerSample


   '第三部分
With my_wavfact
    .sID = Input(4, #1)                 '标志"fact"
    If .sID = "data" Then GoTo dataA
     Get #1, , .nSize                   '数值为4
     Get #1, , .dData
End With
    

dataA:

  '第四部分
  With my_wavData
  If my_wavfact.sID = "data" Then
  my_wavfact.sID = ""
  .sID = "data"
  Get #1, , .nSize
  'Get #1, , .dData '数据暂时不读取
  End If
  End With

Label4 = my_wavfact.sID & my_wavData.sID & "数据长度:" & my_wavData.nSize



'以下是将相关数据处理后,写入999.WAV文件

Open App.Path & "\999.wav" For Binary Access Write As #2 '打开目标文件
  Put #2, 1, waveHDR       '写入文件头部
  
  Dim a() As Byte
  Dim ii As Long
  Dim b As Byte
   
  ReDim a(my_wavData.nSize) '定义WAV文件的数据长度数组
  
  
  Get #1, , a
  For ii = 45 To my_wavData.nSize + 44
  
  '音频数据以128(8位)或32768(16位)两个数为音频波形中线值
  '我想将音量放大50%,就应该用下边的算法了
  '可以写入后的文件没有一点声音
  
  If a(i) >= 32768 Then
  a(i) = a(i) * 1.5
  Else
  a(i) = a(i) * 0.5
  End If
   Put #2, ii, a(i)
  Next
  
  
Close #1
Close #2
End Sub




我的源程序是这样的,请大家看看。

#13


1)你用 Beyond Compare 2 之类的工具二进制比较两个文件,除了声道数据部分其他是否相同。
2)16位数据是两个字节,a(i) 始终是一个字节,怎么想的?
3)For ii 的循环中 i 没变过,你一直处理始终不变的 a(i)?
4)
Get #1, , a
是从文件头之后开始读取,
Put #2, ii, a(i)
是从文件位置 45 开始写?

#14


16位数据是两个字节
 

Dim q  As Byte
Dim b As Byte

For ii = 45 To my_wavData.nSize + 44
Get #1, , q
'Debug.Print q
'对这个q 进行操作才有效,不过就是音质方面不是很饱满,放大的效果达到了
  If q = 256 Then GoTo aaq
  Select Case q
  Case Is > 128
       b = q * 0.6
 Case Is < 128
       b = q * 1.4
 Case 128
       b = q
 End Select
  
aaq:
  Put #2, ii, b

音质方面还需要改进,请指教了。

#15


音质是没什么办法的,一但达到十六位数的上限值,再想调高肯定就要牺牲音质了

#16


要用 Integer 类型 2 字节一起处理,按照你的做法
&H1280 (  4736) -> &H1980 (  6528)
&H8080 (-32640) -> &H8080 (-32640)
&H7090 ( 28816) -> &H9D56 (-25258)
怎么不失真?

#17


是这样么?


Dim q  As Integer
Dim b As Integer

For ii = 45 To my_wavData.nSize + 44
Get #1, , q
'Debug.Print q
'对这个q 进行操作才有效,不过就是音质方面不是很饱满,放大的效果达到了
  If q = 256 Then GoTo aaq
  Select Case q
  Case Is > 128
       b = q * 0.6
 Case Is < 128
       b = q * 1.4
 Case 128
       b = q
 End Select
  
aaq:
  Put #2, ii, b
next

#18


Integer 的区间是 [-32768, 32767],再仔细想想!

还有要不失真地放大,应该先扫描一遍数据,求出现有波形的振幅,计算
  放大比率 = 32767 / 现有振幅
然后用这个比率去放大波形。
否则波形的峰、谷可能会被切平。

#19


引用 18 楼 tiger_zhao 的回复:
Integer 的区间是 [-32768, 32767],再仔细想想!

还有要不失真地放大,应该先扫描一遍数据,求出现有波形的振幅,计算
  放大比率 = 32767 / 现有振幅
然后用这个比率去放大波形。
否则波形的峰、谷可能会被切平。



说这个原理是很容易的,能给出具体的程序么?
放大比率 = 32767 / 现有振幅

这么做,就是要将声音放大到最大。要是有原码就好了

#20


Dim q           As Integer
Dim b           As Integer
Dim lPosition   As Long
Dim lMax        As Long
Dim dScale      As Double

lPosition = Seek(1)
lMax = 0
For ii = 45 To my_wavData.nSize + 44
    Get #1, , q
    lMax 为 Abs(q) 的最大值
Next
dScale = 32767 / lMax

Seek #1, lPosition
For ii = 45 To my_wavData.nSize + 44
    Get #1, , q
    b 为 q 按 dScale 倍率放大
    Put #2, ii, b
Next

#21


引用 20 楼 tiger_zhao 的回复:
VB code
Dim q           As Integer
Dim b           As Integer
Dim lPosition   As Long
Dim lMax        As Long
Dim dScale      As Double

lPosition = Seek(1)
lMax = 0
For ii = 45 To my_wavData……



lMax 为 Abs(q) 的最大值
b 为 q 按 dScale 倍率放大
这个运行效率可能太低了,要是将这2个过程写出来就好了

#22


每个都只是一行代码,不要太懒了!

#23


已经解决。不过说明一下,用VB写效率不是太高。一段不长的音乐文件,置换一下时间较长。

#24


我也碰到类似的问题,请问楼主是怎么解决音质问题的,急求。

#25


音质问题,实际上讲上没有得到解决,只不过音量是提高了,勉强能听听而已。

就是要做到音质不降低,不知道如何做。或许可能需要插入一些数据才行。

想像那个波形文件,好像应该加上一个数可能不会失真,如果用乘,貌似会出击失真。

#26


我按照Tiger_Zhao说的方法做,得到的是一片杂音。还希望Tiger_Zhao能具体贴一下代码

#27


用Cool Edit Pro软件?

#28


Cool Edit Pro软件应该可以,不过想要的是代码

#29


分是给了,不过Tiger_Zhao说的做法,还是没有做出来。

#30


找到了一份C++的代码,哪位大侠可以改写成VB的代码吗。

/*---------------------------------------
method name : AmplifyPCMData
comment : 对PCM数据的音量进行放大
parameter : 
pData PCM数据
nLen PCM数据的长度
nBitsPerSample 每个Sample的位数,一般为8的整数
multiple 放大倍数
result : S_OK 成功
---------------------------------------*/
int AmplifyPCMData(BYTE* pData, int nLen, int nBitsPerSample, float multiple)
{
int nCur = 0;
if (16 == nBitsPerSample)
{
while (nCur < nLen)
{
short* volum = (short*)(pData + nCur);
*volum = (*volum) * multiple;
if (*volum > SHRT_MAX)//爆音的处理
{
*volum = SHRT_MAX;
}
*(short*)(pData + nCur) = *volum  ;
nCur += 2;
}

}
else if (8 == nBitsPerSample)
{
while (nCur < nLen)
{
BYTE* volum = pData + nCur;
*volum = (*volum) * multiple;
if (*volum > 255)//爆音的处理
{
*volum = 255;
}
*pData  = *volum  ;
nCur ++;
}

}
return S_OK;

}

#31


该回复于2011-01-04 09:17:11被版主删除