|
-
Mar 16th, 2006, 10:15 AM
#7
Re: Tutorial under construction
Here is an example on how it looks like when you convert by the nearest index:

In the previous image it's converting from 8000 Hz sample rate to 22050 Hz sample rate.
The black line (with black dots) is the original sound that is at 8000 Hz, and the yellow is the converted sound at 22050 Hz.
The better way to do it, is by calculating the value by using the line intersection formula, like this:

Using the line intersection formula, you can find the exact value that it should be even when the destination sample position does not match the source sample position.
Here is a sample image on how it looks like when you use line intersection formula:

And here is the code to convert using the line intersection formula:
VB Code:
Public Function FindYForX(ByVal X As Double, ByVal X1 As Double, ByVal Y1 As Double, _
ByVal X2 As Double, ByVal Y2 As Double) As Double
Dim M As Double, B As Double
M = (Y1 - Y2) / (X1 - X2)
B = Y1 - M * X1
FindYForX = M * X + B
End Function
Public Function ConvertWave16ReSample(Buff() As Integer, ByVal FromSample As Long, ByVal ToSample As Long, ByVal Stereo As Boolean) As Integer()
Dim K As Long, Lx As Long, RX As Long
Dim Ret() As Integer, Per As Double, NewSize As Long
If Not Stereo Then
NewSize = Fix((UBound(Buff) + 1) * ToSample / FromSample + 0.5)
ReDim Ret(NewSize - 1)
For K = 0 To UBound(Ret) - 1
Per = K / UBound(Ret)
Lx = Fix(UBound(Buff) * Per)
Ret(K) = FindYForX(UBound(Buff) * Per, Lx, Buff(Lx), Lx + 1, Buff(Lx + 1))
Next K
Ret(UBound(Ret)) = Buff(UBound(Buff))
Else
NewSize = Fix((UBound(Buff) + 1) * ToSample / FromSample + 0.5)
NewSize = NewSize - (NewSize Mod 2)
ReDim Ret(NewSize - 1)
For K = 0 To UBound(Ret) Step 2
Per = K / (UBound(Ret) + 2)
' Left channel
Lx = Fix(UBound(Buff) * Per / 2#) * 2
Ret(K + 0) = FindYForX(UBound(Buff) * Per, Lx, Buff(Lx), Lx + 2, Buff(Lx + 2))
' Right channel
RX = Lx + 1
Ret(K + 1) = FindYForX(UBound(Buff) * Per + 1, RX, Buff(RX), RX + 2, Buff(RX + 2))
Next K
Ret(UBound(Ret) - 1) = Buff(UBound(Buff) - 1)
Ret(UBound(Ret)) = Buff(UBound(Buff))
End If
ConvertWave16ReSample = Ret
End Function
Public Function ConvertWave8ReSample(Buff() As Byte, ByVal FromSample As Long, ByVal ToSample As Long, ByVal Stereo As Boolean) As Byte()
Dim K As Long, Lx As Long, RX As Long
Dim Ret() As Byte, Per As Double, NewSize As Long
If Not Stereo Then
NewSize = Fix((UBound(Buff) + 1) * ToSample / FromSample + 0.5)
ReDim Ret(NewSize - 1)
For K = 0 To UBound(Ret) - 1
Per = K / UBound(Ret)
Lx = Fix(UBound(Buff) * Per)
Ret(K) = FindYForX(UBound(Buff) * Per, Lx, Buff(Lx), Lx + 1, Buff(Lx + 1))
Next K
Ret(UBound(Ret)) = Buff(UBound(Buff))
Else
NewSize = Fix((UBound(Buff) + 1) * ToSample / FromSample + 0.5)
NewSize = NewSize - (NewSize Mod 2)
ReDim Ret(NewSize - 1)
For K = 0 To UBound(Ret) Step 2
Per = K / (UBound(Ret) + 2)
' Left channel
Lx = Fix(UBound(Buff) * Per / 2#) * 2
Ret(K + 0) = FindYForX(UBound(Buff) * Per, Lx, Buff(Lx), Lx + 2, Buff(Lx + 2))
' Right channel
RX = Lx + 1
Ret(K + 1) = FindYForX(UBound(Buff) * Per + 1, RX, Buff(RX), RX + 2, Buff(RX + 2))
Next K
Ret(UBound(Ret) - 1) = Buff(UBound(Buff) - 1)
Ret(UBound(Ret)) = Buff(UBound(Buff))
End If
ConvertWave8ReSample = Ret
End Function
Converting from any format to any other format
With all the functions together from this post and previous post, you can convert from any format to any other format. They work fine if the format is static, but if the format changes often, it is difficult to make a lot of if statements to choose what function to call in each case.
That's why I made things easier. The following function converts to all formats possible using all the previous functions.
The input must be a Byte Array to Integer Array regardless of the Bits Per Sample for the sound. The return array will always be Byte Array for 8 bit return sound, and Integer Array for 16 bit return sound.
VB Code:
Public Function ConvertWave(Buffer As Variant, FromFormat As WAVEFORMATEX, ToFormat As WAVEFORMATEX) As Variant
Dim Buffer16() As Integer
Dim Buffer8() As Byte
Dim RetBuff16() As Integer
Dim RetBuff8() As Byte
If FromFormat.nBitsPerSample = 16 Then
Select Case VarType(Buffer)
Case (vbArray Or vbByte)
Buffer8 = Buffer
Buffer16 = Convert16_8To16(Buffer8)
Erase Buffer8
Case (vbArray Or vbInteger)
Buffer16 = Buffer
Case Else
ConvertWave = vbEmpty
Exit Function
End Select
If ToFormat.nBitsPerSample = 8 Then
RetBuff8 = ConvertWave16to8(Buffer16)
Erase Buffer16
GoTo To8Bit ' JUMP TO 8 BIT
ElseIf ToFormat.nBitsPerSample = 16 Then
RetBuff16 = Buffer16
Erase Buffer16
Else
ConvertWave = vbEmpty
Exit Function
End If
To16Bit:
If FromFormat.nChannels = 1 And ToFormat.nChannels = 2 Then
RetBuff16 = ConvertWaveMonoToStereo16(RetBuff16)
ElseIf FromFormat.nChannels = 2 And ToFormat.nChannels = 1 Then
RetBuff16 = ConvertWaveStereoToMono16(RetBuff16)
ElseIf FromFormat.nChannels <> ToFormat.nChannels Then
ConvertWave = vbEmpty
Exit Function
End If
If FromFormat.lSamplesPerSec <> ToFormat.lSamplesPerSec Then
Select Case FromFormat.lSamplesPerSec / ToFormat.lSamplesPerSec
Case 0.25
RetBuff16 = ConvertWave16MultiplySamplesBy2(RetBuff16, ToFormat.nChannels = 2)
RetBuff16 = ConvertWave16MultiplySamplesBy2(RetBuff16, ToFormat.nChannels = 2)
Case 0.5
RetBuff16 = ConvertWave16MultiplySamplesBy2(RetBuff16, ToFormat.nChannels = 2)
Case 2
RetBuff16 = ConvertWave16DivideSamplesBy2(RetBuff16, ToFormat.nChannels = 2)
Case 4
RetBuff16 = ConvertWave16DivideSamplesBy2(RetBuff16, ToFormat.nChannels = 2)
RetBuff16 = ConvertWave16DivideSamplesBy2(RetBuff16, ToFormat.nChannels = 2)
Case Else
RetBuff16 = ConvertWave16ReSample(RetBuff16, FromFormat.lSamplesPerSec, ToFormat.lSamplesPerSec, ToFormat.nChannels = 2)
End Select
End If
ConvertWave = RetBuff16
ElseIf FromFormat.nBitsPerSample = 8 Then
Select Case VarType(Buffer)
Case (vbArray Or vbByte)
Buffer8 = Buffer
Case (vbArray Or vbInteger)
Buffer16 = Buffer
ReDim Buffer8((UBound(Buffer16) + 1) * 2 - 1)
CopyMemory Buffer8(0), Buffer(16), UBound(Buffer8) + 1
Erase Buffer16
Case Else
ConvertWave = vbEmpty
Exit Function
End Select
If ToFormat.nBitsPerSample = 16 Then
RetBuff16 = ConvertWave8to16(Buffer8)
Erase Buffer8
GoTo To16Bit ' JUMP TO 16 BIT
ElseIf ToFormat.nBitsPerSample = 8 Then
RetBuff8 = Buffer8
Erase Buffer8
Else
ConvertWave = vbEmpty
Exit Function
End If
To8Bit:
If FromFormat.nChannels = 1 And ToFormat.nChannels = 2 Then
RetBuff8 = ConvertWaveMonoToStereo8(RetBuff8)
ElseIf FromFormat.nChannels = 2 And ToFormat.nChannels = 1 Then
RetBuff8 = ConvertWaveStereoToMono8(RetBuff8)
ElseIf FromFormat.nChannels <> ToFormat.nChannels Then
ConvertWave = vbEmpty
Exit Function
End If
If FromFormat.lSamplesPerSec <> ToFormat.lSamplesPerSec Then
Select Case FromFormat.lSamplesPerSec / ToFormat.lSamplesPerSec
Case 0.25
RetBuff8 = ConvertWave8MultiplySamplesBy2(RetBuff8, ToFormat.nChannels = 2)
RetBuff8 = ConvertWave8MultiplySamplesBy2(RetBuff8, ToFormat.nChannels = 2)
Case 0.5
RetBuff8 = ConvertWave8MultiplySamplesBy2(RetBuff8, ToFormat.nChannels = 2)
Case 2
RetBuff8 = ConvertWave8DivideSamplesBy2(RetBuff8, ToFormat.nChannels = 2)
Case 4
RetBuff8 = ConvertWave8DivideSamplesBy2(RetBuff8, ToFormat.nChannels = 2)
RetBuff8 = ConvertWave8DivideSamplesBy2(RetBuff8, ToFormat.nChannels = 2)
Case Else
RetBuff8 = ConvertWave8ReSample(RetBuff8, FromFormat.lSamplesPerSec, ToFormat.lSamplesPerSec, ToFormat.nChannels = 2)
End Select
End If
ConvertWave = RetBuff8
Else
ConvertWave = vbEmpty
Exit Function
End If
End Function
Last edited by CVMichael; Mar 19th, 2008 at 09:29 PM.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|