-
1 Attachment(s)
Re: Sugestions or Comments about my Sound Tutorial
Michael,
I've attached some (crude) code via which I am trying to generate 7 notes, each of which is .25 seconds long (11025/44100). When I play the sounds back, they are indeed .25 seconds long, but each file itself still plays for 2 seconds. Can you tell me where/how I'm creating this phenomenom?
Thanks!
Bryce
-
Re: Sugestions or Comments about my Sound Tutorial
I am at work now, and our firewall blocks the downloads of files other than html.
I will check it out when I get home.
-
1 Attachment(s)
Re: Sugestions or Comments about my Sound Tutorial
CVMichael,
Thanks again for your tutes. I am using your subs to accomplish the following things:
1. load a wav file into an array
2. process the sound data in the array with various DSP routines, such as reverse, filter, distort etc
3. load the processed array in a sound buffer
4. play the sound
5. enable the 'usual' abilities of changing frequency and volume of the sound in the buffer.
Trouble is, everything is working upto 4. However, trying to do either of the following on the buffer:
DSSecBuffer.SetFrequency 11000
DSSecBuffer.SetVolume -1500
results in a '-2005401570 (8878001e) Automation error' being thrown.
I am so eager for a solution for this, that I am willing to pay $ for your assistance (which we can negotiate offline if desired)
I attach the code for your reference (it should look familiar as I have tried to follow your tutorial precisely)
(BTW I solved the problem in my previous post of 28 September 2008 - the answer was in your tutorial if one looked hard enough :-)
Regards,
DocNash
-
Re: Sugestions or Comments about my Sound Tutorial
Please post the code in the post not as attachment, because I am at work and the firewall here blocks attachments.
You just have to encapsulate your code with [HIGHLIGHT="vbcode"]your code here[/HIGHLIGHT] tags.
The answer is in my tutorial if one looked hard enough ;) , You are probably missing this:
vbcode Code:
' allow frequency changes and volume changes
BuffDesc.lFlags = DSBCAPS_CTRLFREQUENCY Or DSBCAPS_CTRLVOLUME
If you have other flags in there, remember you have to use "Or" or "+" to mix flags.
Also, read the lFlags documentation because not all flags can be mixed with one another
-
Re: Sugestions or Comments about my Sound Tutorial
I do have:
BuffDesc.lFlags = DSBCAPS_CTRLFREQUENCY Or DSBCAPS_CTRLVOLUME in the code
Code is attached.
Simply create a form with two command buttons: CmdLoad, CmdPlay, and two text boxes: Text1, Text2, and one check box: Check1
Copy the code into the form, set a reference to DirectX8 For Visual Basic Type Library. Under Sub Form_Load, Text2 is loaded with the path to a wav file. Change path to suit - I've been loading 8 bit mono files. Now when you press CmdLoad, the wav file in Text2 is loaded and the datalength of the file is shown in Text1. If you tick the checkbox before pressing CmdLoad, the wav file is reversed then loaded. Pressing CmdPlay plays the load in the buffer. All good.
Now problem is that if if you uncomment either of the DSSecBuffer.SetFrequency 11000 or DSSecBuffer.SetVolume -1500 under CmdPlay_Click, the error is thrown.
Regards,
DocNash
vbcode Code:
Option Explicit
Private Type FileHeader
lRiff As Long
lFileSize As Long
lWave As Long
lFormat As Long
lFormatLength As Long
End Type
Private Type WaveFormat
wFormatTag As Integer
nChannels As Integer
nSamplesPerSec As Long
nAvgBytesPerSec As Long
nBlockAlign As Integer
wBitsPerSample As Integer
End Type
Private Type ChunkHeader
lType As Long
lLen As Long
End Type
Private DX As New DirectX8
Private DSEnum As DirectSoundEnum8
Private DIS As DirectSound8
Dim DSSecBuffer As DirectSoundSecondaryBuffer8
Dim WaveData() As Byte
Dim RevAr()
Dim WaveFmt As WaveFormat
Dim DataLength As Long
Private Sub CmdLoad_Click()
Dim BuffDesc As DSBUFFERDESC
Set DSEnum = DX.GetDSEnum
Set DIS = DX.DirectSoundCreate(DSEnum.GetGuid(1))
DIS.SetCooperativeLevel Me.hWnd, DSSCL_NORMAL
BuffDesc.lFlags = DSBCAPS_CTRLFREQUENCY Or DSBCAPS_CTRLVOLUME
Set DSSecBuffer = CreateSoundBufferFromFile(Text2.Text, BuffDesc)
End Sub
Private Sub CmdPlay_Click()
'DSSecBuffer.SetFrequency 11000
'DSSecBuffer.SetVolume -1500
DSSecBuffer.Play DSBPLAY_DEFAULT
End Sub
Private Sub Form_Load()
Text2.Text = "C:\vbsequencer19_midi\data\beback.wav"
End Sub
Private Function CreateSoundBufferFromFile(ByVal FileName As String, ByRef BuffDesc As DSBUFFERDESC) As DirectSoundSecondaryBuffer8
Dim SecBuff As DirectSoundSecondaryBuffer8
Dim FileNum As Integer
Dim F As Long
FileNum = FreeFile
Open FileName For Binary Access Read Lock Write As #1 ' open file
WaveFmt = WaveReadFormat(FileNum, DataLength) ' read format
' copy the wave format values into the WAVEFORMATEX of the DSBUFFERDESC structure
With BuffDesc.fxFormat
.nFormatTag = WaveFmt.wFormatTag
.nChannels = WaveFmt.nChannels
.nBitsPerSample = WaveFmt.wBitsPerSample
.lSamplesPerSec = WaveFmt.nSamplesPerSec
.nBlockAlign = WaveFmt.nBlockAlign
.lAvgBytesPerSec = WaveFmt.nAvgBytesPerSec
End With
BuffDesc.lFlags = DSBCAPS_STICKYFOCUS Or DSBCAPS_STATIC
BuffDesc.lBufferBytes = DataLength
Text1.Text = DataLength
Set SecBuff = DIS.CreateSoundBuffer(BuffDesc)
ReDim WaveData(DataLength - 1)
' read the wave data
Get FileNum, , WaveData
If Check1.Value = vbChecked Then
Call ReverseWavData
End If
' copy our array to the DirectX Sound buffer
SecBuff.WriteBuffer 0, DataLength, WaveData(0), DSBLOCK_DEFAULT
Close FileNum ' close file
' return the DirectX Sound Buffer
Set CreateSoundBufferFromFile = SecBuff
End Function
Private Function WaveReadFormat(ByVal InFileNum As Integer, ByRef lDataLength As Long) As WaveFormat
Dim header As FileHeader
Dim HdrFormat As WaveFormat
Dim chunk As ChunkHeader
Dim by As Byte
Dim i As Long
Get #InFileNum, 1, header
If header.lRiff <> &H46464952 Then Exit Function ' Check for "RIFF" tag and exit if not found.
If header.lWave <> &H45564157 Then Exit Function ' Check for "WAVE" tag and exit if not found.
If header.lFormat <> &H20746D66 Then Exit Function ' Check for "fmt " tag and exit if not found.
'MsgBox header.lFileSize & ";" & header.lFormat
' Check format chunk length; if less than 16, it's not PCM data so we can't use it.
If header.lFormatLength < 16 Then Exit Function
Get #InFileNum, , HdrFormat ' Retrieve format.
' Seek to next chunk by discarding any format bytes.
For i = 1 To header.lFormatLength - 16
Get #InFileNum, , by
Next
' Ignore chunks until we get to the "data" chunk.
Get #InFileNum, , chunk
Do While chunk.lType <> &H61746164
For i = 1 To chunk.lLen
Get #InFileNum, , by
Next
Get #InFileNum, , chunk
Loop
lDataLength = chunk.lLen ' Retrieve the size of the data.
WaveReadFormat = HdrFormat
End Function
Sub ReverseWavData()
Dim i As Long
ReDim RevAr(UBound(WaveData))
For i = UBound(WaveData) To 0 Step -1
RevAr(UBound(WaveData) - i) = WaveData(i)
Next i
For i = 0 To UBound(WaveData)
WaveData(i) = RevAr(i)
Next i
End Sub
-
Re: Sugestions or Comments about my Sound Tutorial
Actually no, you don't...
let me put it this way
if you have variable "Dim my_varible As Integer"
and you execute this code:
my_varible = 5
my_varible = 7
What does the my_varible contain ?
You have:
BuffDesc.lFlags = DSBCAPS_CTRLFREQUENCY Or DSBCAPS_CTRLVOLUME
and then later on:
BuffDesc.lFlags = DSBCAPS_STICKYFOCUS Or DSBCAPS_STATIC
What you have to do, is to "Or" both those lines together
-
Re: Sugestions or Comments about my Sound Tutorial
Brilliant!
I removed the
BuffDesc.lFlags = DSBCAPS_CTRLFREQUENCY Or DSBCAPS_CTRLVOLUME
line from the CmdLoad sub
and put this line in the CreateBufferFromFile sub:
BuffDesc.lFlags = DSBCAPS_STICKYFOCUS Or DSBCAPS_STATIC Or DSBCAPS_CTRLFREQUENCY Or DSBCAPS_CTRLVOLUME
Now works. Thanks again!
Regards,
DocNash
-
Re: Sugestions or Comments about my Sound Tutorial
Two Questions in One if you please:
1. Is there any way to specify upto where the sound in the buffer should play TO, similar to the way one can specify where it should start play FROM thusly:
Sound(Index).DSBuffer.SetCurrentPosition X?
The reason I ask, is that it would seem the only way to constrain the TO is in the creation of the buffer itself using:
BuffDesc.lBufferBytes = X
2. Let us say I have WaveData() filled with 8 bit sound. Would the following be appropriate to
a) make it signed
b) cast into the range -1 to +1 (so I can apply signal processing algorithms to the sound which require the input to be in that range)
c) write back to WaveData() as unsigned 8-bit again:
(PS this works, but I am not sure whether the approach is mathematically correct in dealing with +127 to -128):
dim K as Long
dim Sample as Long
dim r as Single
dim f as Single
For K = LBound(WaveData) to UBound(WaveData)
r = (WaveData(K) - 127) / 127
f = Apply Signal Processing(r)
Sample = (CLng(f * 127)) + 127
WaveData(K) = Sample
Next K
Thanking you!
-
Re: Sugestions or Comments about my Sound Tutorial
1) Your question does not make sense, maybe you should say why you want to do it like this ?
Why can't you just put in the buffer what you want to play, instead of putting everything (i guess), then stop it at a certain point ?
2) What you did is correct...
Just a note:
You don't have to PM me on a thread where I am posting already, because any new reply in threads where I am subscribed show up in my "User CP".
If you make a NEW thread, and you want me to reply, then send me a PM with the link so I am aware of your thread, but if I already posted in that thread then I am aware as soon as you post (as soon as I log-in), you don't have to send PM...
-
Re: Sugestions or Comments about my Sound Tutorial
CVMichael,
Thanks for your validation of 2).
Re 1) the context is I'm building a sampling drum machine, with extensive sound editing options for each instrument sample, such as add the sample to synthesized waves, or AM or FM the sample with synthesized waves, filter, add effects or dynamically (while the pattern is playing) specify via sliders the start and end points of the sound. It is to satisfy this latter requirement that I'm asking the question.
In other words, enablement of real-time 'segment' manipulation of the sound in each channel while the rhythm loop is playing is what I'm aiming for. It's all about 'zero-latency tactility'.
So, envision a horizontal slider bar with a 'start handle' and a 'stop handle' that can be independently moved on the bar - the sound snipet that plays is what's between the handles.
It'd be neat then if the start and stop handles set something like this:
Sound(Index).DSBuffer.SetStartPosition X
Sound(Index).DSBuffer.SetEndPosition Y
Just wanted to validate that DirectSound doesn't offer anything like the above, and that the only option I've got is for first handle to do this:
Sound(Index).DSBuffer.SetCurrentPosition X
and the second handle to do this:
BuffDesc.lBufferBytes = X
where X is a subset of DataLength, and the buffer is loaded anew each time the second handle is moved...
Regards,
DocNash
-
Re: Sugestions or Comments about my Sound Tutorial
OK...
I think the best way is to set up events. I never actually tried to do this, but theoretically it should work...
If you look at my tutorial, at post #4, you will see how to set up an event in the Initialize function:
Code:
EventID = DX.CreateEvent(Me)
EventsNotify(0).hEventNotify = EventID
EventsNotify(0).lOffset = event_position
' Assign the notification points to the buffer
Buff.SetNotificationPositions 1, EventsNotify()
And every time you move the slider, you have to delete the event, then re-make it with a new position, to remove it:
Code:
DX.DestroyEvent EventID
You will receive the event in the DirectXEvent8_DXCallback, and you can execute the code there to stop playing
So you can use Sound(Index).DSBuffer.SetStartPosition X for the starting position, and an event for the end position
Let me know how it works...
-
Re: Sugestions or Comments about my Sound Tutorial
CVMichael,
Thanks for the suggestion. Attached is the code core I'm using. A form with a textbox Text1 (simply shows the wav file being loaded), CmdLoad button, CmdPlay button, and the following sliders: HscrollVol, HscrollFreq, HscrollPlayFrom, HscrollPlayTo.
The code core has been working fine. Then I added to it to be able to do the 'stop play event' processing. What I added is shown suffixed by '****
Am now getting a runtime error 430 'Class does not support automation or does not support expected interface' on the DSSecBuffer.SetNotificationPositions line (and it doesn't matter whether the line is under the HScrollPlayTo_Change event, or under the CmdLoad event - which I've commented out)
Any advice would be greatly appreciated.
Regards,
DocNash
vbcode Code:
Option Explicit
Private Type FileHeader
lRiff As Long
lFileSize As Long
lWave As Long
lFormat As Long
lFormatLength As Long
End Type
Private Type WaveFormat
wFormatTag As Integer
nChannels As Integer
nSamplesPerSec As Long
nAvgBytesPerSec As Long
nBlockAlign As Integer
wBitsPerSample As Integer
End Type
Private Type ChunkHeader
lType As Long
lLen As Long
End Type
Private DX As New DirectX8
Private DSEnum As DirectSoundEnum8
Private DIS As DirectSound8
Dim DSSecBuffer As DirectSoundSecondaryBuffer8
Private EventsNotify(0) As DSBPOSITIONNOTIFY '*****
Private StopEvent As Long '*****
Implements DirectXEvent8 '*****
Dim WaveData() As Byte
Dim WaveFmt As WaveFormat
Dim DataLength As Long
Private Sub CmdLoad_Click()
Dim BuffDesc As DSBUFFERDESC
Set DSEnum = DX.GetDSEnum
Set DIS = DX.DirectSoundCreate(DSEnum.GetGuid(1))
DIS.SetCooperativeLevel Me.hWnd, DSSCL_NORMAL
Set DSSecBuffer = CreateSoundBufferFromFile(Text1.Text, BuffDesc)
HScrollFreq.Value = DSSecBuffer.GetFrequency() / 3
StopEvent = DX.CreateEvent(Me) '****
'EventsNotify(0).hEventNotify = StopEvent '****
'EventsNotify(0).lOffset = CLng(DataLength / 2) '****
'DSSecBuffer.SetNotificationPositions 1, EventsNotify() '****
End Sub
Private Sub CmdPlay_Click()
DSSecBuffer.SetFrequency (3 * Val(HScrollFreq.Value))
DSSecBuffer.SetVolume HScrollVol.Value
DSSecBuffer.SetCurrentPosition (HScrollPlayFrom.Value / 100) * DataLength
DSSecBuffer.Play DSBPLAY_DEFAULT
End Sub
Private Sub Form_Load()
Text1.Text = "C:\vbsequencer10\data\3816.wav"
End Sub
Private Function CreateSoundBufferFromFile(ByVal FileName As String, ByRef BuffDesc As DSBUFFERDESC) As DirectSoundSecondaryBuffer8
Dim SecBuff As DirectSoundSecondaryBuffer8
Dim FileNum As Integer
Dim f As Long
FileNum = FreeFile
Open FileName For Binary Access Read Lock Write As #1
WaveFmt = WaveReadFormat(FileNum, DataLength)
With BuffDesc.fxFormat
.nFormatTag = WaveFmt.wFormatTag
.nChannels = WaveFmt.nChannels
.nBitsPerSample = WaveFmt.wBitsPerSample
.lSamplesPerSec = WaveFmt.nSamplesPerSec
.nBlockAlign = WaveFmt.nBlockAlign
.lAvgBytesPerSec = WaveFmt.nAvgBytesPerSec
End With
ReDim WaveData(DataLength - 1)
Get FileNum, , WaveData
BuffDesc.lFlags = DSBCAPS_STICKYFOCUS Or DSBCAPS_STATIC Or DSBCAPS_CTRLFREQUENCY Or DSBCAPS_CTRLVOLUME
BuffDesc.lBufferBytes = DataLength
Set SecBuff = DIS.CreateSoundBuffer(BuffDesc)
SecBuff.WriteBuffer 0, DataLength, WaveData(0), DSBLOCK_DEFAULT
Close FileNum
Set CreateSoundBufferFromFile = SecBuff
End Function
Private Function WaveReadFormat(ByVal InFileNum As Integer, ByRef lDataLength As Long) As WaveFormat
Dim header As FileHeader
Dim HdrFormat As WaveFormat
Dim chunk As ChunkHeader
Dim by As Byte
Dim i As Long
Get #InFileNum, 1, header
If header.lRiff <> &H46464952 Then Exit Function
If header.lWave <> &H45564157 Then Exit Function
If header.lFormat <> &H20746D66 Then Exit Function
If header.lFormatLength < 16 Then Exit Function
Get #InFileNum, , HdrFormat
For i = 1 To header.lFormatLength - 16
Get #InFileNum, , by
Next
Get #InFileNum, , chunk
Do While chunk.lType <> &H61746164
For i = 1 To chunk.lLen
Get #InFileNum, , by
Next
Get #InFileNum, , chunk
Loop
lDataLength = chunk.lLen
WaveReadFormat = HdrFormat
End Function
Private Sub DirectXEvent8_DXCallback(ByVal eventid As Long) '****
Select Case eventid '****
Case StopEvent '****
DSSecBuffer.Stop '****
End Select '****
End Sub
Private Sub HScrollPlayTo_Change() '****
DX.DestroyEvent StopEvent '****
StopEvent = DX.CreateEvent(Me) '****
EventsNotify(0).hEventNotify = StopEvent '****
EventsNotify(0).lOffset = ((HScrollPlayTo.Value / 100) * DataLength) '****
DSSecBuffer.SetNotificationPositions 1, EventsNotify() '****
End Sub
-
Re: Sugestions or Comments about my Sound Tutorial
In the flags, you also have to add DSBCAPS_CTRLPOSITIONNOTIFY
Also, you may have to stop the sound before you remove and re-create the event... (but I'm not sure about that...)
-
Re: Sugestions or Comments about my Sound Tutorial
CVMichael,
Yep, it needed the DSBCAPS_CTRLPOSITIONNOTIFY.
Also, looks like the sound DOES need to be stopped before removing and re-creating the event. If I do DSSecBuffer.Stop before destroying and re-creating event, everything works fine, but if I comment out that line, a runtime 'Automation error' gets thrown at the DSSecBuffer.SetNotificationPositions line.
I am astounded not only by your prodigious knowledge of directsound (what was your motivation/incentive to gain this comprehensive know-how by the way?), but also your willingness to share your experience AND to top it all off, your responsiveness to questions and issues.
Thanks so much!
Regards,
DocNash
-
Re: Sugestions or Comments about my Sound Tutorial
A few years ago, I plaied with sound quite a lot. I made a few applications that used sound, the best one I made was a voice chat application, but it was not just a 1 to 1 conversation, anyone in the chat room could talk at the same time, therefore I had to mix sounds. Also because I had to send the sound over the internet I had to encode the sound "on the fly", and send it, and do the reverse on the receiving side.
I learned a lot by making that application (even though I did not finish it).
If you search on the forums, you will see I tried to do quite a few things with sound, like this tone recognition, for example.
There was a time (when I was in school) that I had a whole lot of free time to play & discover, but not anymore.
Regarding your question, I did not have to re-create events in the sound buffer before, that's why I was not sure if it will work, but apparently it did :)
After you work with it for so long, you have a fealing of the possibilities and problems you might encounter, even though you did not actually did it before.
It feels good/gratifying to help someone/anyone, if I did not have my full time job, I would do this more often, but latelly I rarelly have free time. If you look back in this thread you will see a few questions that I left unanswered, that's because I was too busy at that time...
-
Re: Sugestions or Comments about my Sound Tutorial
I would like to begin your tutorial. Seems interesting.
I have DirectX 10 on my vista desktop. I am using VB6.
How can I properly reference this so I can run your zip files? When I run them, of course, I get a compile error: can't find project or library.
Then it opens the reference box, and says: "Missing: DirectX 8 for Visual Basic Type Library."
I do not have a directx reference though to select. I ran the dxdiag from 'run' and I see I have directx 10.
I look forward to your tutorial.
-
Re: Sugestions or Comments about my Sound Tutorial
DirectX 8 and lower is for VB6
DirectX 9 (and up) is for .NET
So you have to use DirectX 8 for VB6
And my tutorial is for DirectX 8...
-
Re: Sugestions or Comments about my Sound Tutorial
I see.... thanks. If I download DirectX 8 for this tutorial, does it replace the directx on my computer? Is it not recommended with Vista?
Thanks again.
-
Re: Sugestions or Comments about my Sound Tutorial
Quote:
Originally Posted by chris.cavage
I see.... thanks. If I download DirectX 8 for this tutorial, does it replace the directx on my computer? Is it not recommended with Vista?
Thanks again.
I don't know much about Vista (I'm still happy with XP)
But I know that you can have more than one DirectX version at the same time... so it won't replace the existing one.
But you should investigate more, I don't want to be blamed is something goes wrong :ehh:
-
Re: Sugestions or Comments about my Sound Tutorial
-
Re: Sugestions or Comments about my Sound Tutorial
CVMichael,
Looked in the Tute for anything on bit-depth reduction. Of course, found the 16 bit to 8 bit converter, but was wondering whether you'd be able to advise steps to fulfil the following requirement:
'Allow user to reduce the bit depth of the sound from the bit depth of the loaded wav file, to whatever the user sets - in steps of 1 bit, and down to 1 bit'
Looked around for some guidance on the 'net, and found this in the write-up for 'CMT Bitcrusher - a free VST plug-in for PC':
'You can reduce the bit-depth all the way to 1-bit if you like. The bit-reduction is done by scaling and rounding the input signal to the target bit-depth in integers and then back to floats. For example in four bits, you have to multiply the input signal by eight (2^bits-1) to floats between [-8.0, 8.0]. The actual bit-reduction (or bitcrushing) is done when the floats are rounded to integers and scaled back to [-1.0, 1.0]. This process reduces the resolution of the floats and produces audible bitcrushing-effect'.
So, would the idea be:
1. Scale Wavedata() to between -1 and 1
2. Multiply each sample by 2^(UserBits-1) where UserBits < BitsPerSample of Wavedata
3. Round each sample to Integers
4. Scale each sample back to between -1 and 1
5. Convert back to Bytes and load back in Wavedata()
-
Re: Sugestions or Comments about my Sound Tutorial
If I understood you right, the formula is:
New_Sample = CLng(CSng(Sample) / (2 ^ (BitsPerSample - UserBits))) * (2 ^ (BitsPerSample - UserBits))
Therefore the functions that you need are (I did not test the functions):
vb Code:
Public Function ConvertWaveBits8(Buffer() As Byte, UserBits As Integer) As Byte()
Dim K As Long
Dim RetBuff() As Byte
Dim New_Sample As Long
Dim Divisor As Single
ReDim RetBuff(UBound(Buffer))
Divisor = 2 ^ (8 - UserBits)
For K = 0 To UBound(Buffer)
New_Sample = CLng(CSng(Buffer(K)) / Divisor) * Divisor
If New_Sample < 0 Then New_Sample = 0
If New_Sample > 255 Then New_Sample = 255
RetBuff(K) = New_Sample
Next K
ConvertWaveBits8 = RetBuff
End Function
Public Function ConvertWaveBits16(Buffer() As Integer, UserBits As Integer) As Integer()
Dim K As Long
Dim RetBuff() As Integer
Dim Sample As Long
Dim New_Sample As Long
Dim Divisor As Single
ReDim RetBuff(UBound(Buffer))
Divisor = 2 ^ (16 - UserBits)
For K = 0 To UBound(Buffer)
Sample = Buffer(K) + 32768
New_Sample = CLng(CSng(Sample) / Divisor) * Divisor
If New_Sample < 0 Then New_Sample = 0
If New_Sample > 65535 Then New_Sample = 65535
RetBuff(K) = New_Sample - 32768
Next K
ConvertWaveBits8 = RetBuff
End Function
The only thing is when your input is 16 bits, and you convert to 7 bits (for example), what will the output be ? 16 bit wave file or 8 bit wave file ?
-
Re: Sugestions or Comments about my Sound Tutorial
I am still investigating this directx thing with my vista computer. I am very anxious to work on your tutorial, as I believe I could learn a lot from it.
Can you tell me please: in your tutorial, is there a way to control fade-in and fade-out times for a wav file?
Would be great. Thanks.
-
Re: Sugestions or Comments about my Sound Tutorial
There is no built in function for that, but you can do it through coding.
There is an example in the tutorial that shows how to change the volume of the buffer, you can modify it for fading in/out.
[Edit]
Also, what kind of fade do you need ?
For example, this is a link I found on the net about the types of fading:
http://www.xowave.com/doc/window/fade.shtml
Linear fading is the easiest to do...
-
Re: Sugestions or Comments about my Sound Tutorial
I guess linear fading would be ok.
I would just like to control how long it would take to reach a certain volume level.
Say 100 milliseconds to get full on volume.
-
Re: Sugestions or Comments about my Sound Tutorial
To give you a head start, I wrote this function for you.
This is for a 16 bit buffer, and you have to calculate the start sample and end sample positions in the buffer.
For example if you want to Fade Out the last 250 milliseconds, then you do it like this
TotalSamples = SamplesPerSecond * (250 / 1000#)
EndSample = UBound(Buffer)
StartSample = EndSample - TotalSamples
WaveFade16 Buffer, StartSample, EndSample
And if you want to Fade In:
TotalSamples = SamplesPerSecond * (250 / 1000#)
StartSample = 0
EndSample = TotalSamples
WaveFade16 Buffer, StartSample, EndSample, False
I did not test the function ! I just wrote it...
vb Code:
Public Function WaveFade16(Buffer() As Integer, StartSample As Long, EndSample As Long, Optional FadeOut As Boolean = True) As Integer()
Dim K As Long
Dim RetBuffer() As Integer
Dim TotalSamples As Long
Dim Vol As Single
ReDim RetBuffer(UBound(Buffer))
For K = LBound(Buffer) To StartSample - 1
RetBuffer(K) = Buffer(K)
Next K
TotalSamples = EndSample - StartSample
If FadeOut Then
For K = StartSample To EndSample
Vol = 1# - (CSng(K - StartSample) / TotalSamples)
RetBuffer(K) = Buffer(K) * Vol
Next K
Else
For K = StartSample To EndSample
Vol = CSng(K - StartSample) / TotalSamples
RetBuffer(K) = Buffer(K) * Vol
Next K
End If
For K = EndSample + 1 To UBound(Buffer)
RetBuffer(K) = Buffer(K)
Next K
WaveFade16 = RetBuffer
End Function
-
Re: Sugestions or Comments about my Sound Tutorial
-
Re: Sugestions or Comments about my Sound Tutorial
Would like to do some downsampling. Here are some definitions I found for downsampling vs decimation:
"Decimation" is the process of reducing the sampling rate. In practice, this usually implies lowpass-filtering a signal, then throwing away some of its samples. "Downsampling" is a more specific term which refers to just the process of throwing away samples, without the lowpass filtering operation. To implement downsampling (by a downsampling factor of "M") simply keep every Mth sample, and throw away the M-1 samples in between.
Now, what does this 'throwing away' actually mean? I implemented a function where in an array of 16 bit samples, I make the amplitude of 'M-1 samples in between' equal 0. This then I load the result into Wavedata(), then load Wavedata() in the buffer and play it. The higher M goes, the harsher/lo-fi the sound.
However, I notice in your ConvertWave16DivideSamplesBy2 function which halves the sampling frequency, you are creating an array with half the samples of the source array - every second sample of the source array is not included - correct? Is this what is actually meant by 'throwing away' samples rather than what I did? And before this 'half array' is loaded in the buffer, would some 'redimensioning' of the buffer parameters be required first eg .lSamplesPerSec? .lAvgBytesPerSec? BuffDesc.lBufferBytes? Could you advise which would need to change and how?
-
Re: Sugestions or Comments about my Sound Tutorial
Yes, ConvertWave16DivideSamplesBy2 ignores every second sample.
And Yes again, when you save the buffer to a wave file, you have to save with the new parameters, depending on what changes you made to it.
If it's divisible by 2 then use ConvertWave16DivideSamplesBy2, otherwise use ConvertWave16ReSample
-
Re: Sugestions or Comments about my Sound Tutorial
General question: can someone please provide the link for me to download the correct directx to use this tutorial?
Also, since this is the BEST place to ask this question: is it possible for sound files to change their volume on their own when played back on windows media player?
If a wav file is played throughout the day, randomly and always with the computer volume control at the same position, can the output of that wav file change/fluctuate to make it just slightly louder or softer?
If yes, what would make it fluctuate: computer activity, processes, ...? How can one control it?
Or is it guaranteed that if you program the wav volume at a given level and play it back at the same volume level, the output would not change?
-
Re: Sugestions or Comments about my Sound Tutorial
CVMIchael
Loved your tutorial...
Although there is your code examples "which are great" and some code to find a frequency, even some FT code, I don't seem to be able to figure out how to put those together.
The buffer that is read to create the scope visuals, what has to be done to it so that it can be passed to a FFT procedure? Most of the procedures ask for real, imaginary and and another number)sample rate?). I would like to be able to use FFT to find the amplitude of a particular frequency(range) in the buffer.
Thanks again for posting the tutorial, it has helped me a lot so far.
cheers!
-
Re: Sugestions or Comments about my Sound Tutorial
To the FFT function, give only the real numbers, set all 0 to imaginary. The samples parameter is how many samples you pass to the function and it has to be the power of 2, for example 256, 512, 1024 samples, etc...
See post #13, right in this thread for code on FFT by rm_03
-
Re: Sugestions or Comments about my Sound Tutorial
Sorry Michael, I am probably being a little dumb... information on this subject is very scarce.
Do I convert the buffer into an array and pass that?
The imagenary data - I am assuming this is another array that I just fill with 0, does the FFT sub write results to that array. If so what gets written?
Thanks in advance for your help.
-
Re: Sugestions or Comments about my Sound Tutorial
Ok
I have figured it out - my code doesn't work yet but when I pass my RealInput to an online FFT calculator web site the results are correct.
One thing I have noticed with FFT is that it picks up harmonics - a peak of 1000Hz shows another peak at 2500, 4000 (for example) etc...
-
Re: Sugestions or Comments about my Sound Tutorial
CV michael .... i happen to take a look into your sound tutorial and i was curious, (i dont know if this has been asked before but i'll ask anyway) is there
a way i could, when before pressing record, start off with a clear/empty buffer everytime? or record to a specified length then save to wav ? or have a function within it where i press a button to start over. with the way the split buffer operates i end up playing back the sound and on the end of the playback i'm hearing the sound of a previous recording in the file and i don't want that. as i looked into the source code i found it difficult to sift through and adjust the source code to fit my need. so far i have a variation of the project built where i have the recordstart/recordstop & sound play & stop buttons on the frmMain with the frmDX_record hidden from view.
-
Re: Sugestions or Comments about my Sound Tutorial
since my last post i've been able to figure some things out ... though i still need to understand how to (within a common dialogbox control) just rename temp.wav to cd0.filename. (the common dialogbox fielname) basically recreate/duplicate or copy the temp.wav but with a new name.
-
Re: Sugestions or Comments about my Sound Tutorial
To copy a file (including renaming) use the FileCopy statement, eg:
Code:
FileCopy "c:\folder\temp.wav", cd0.filename
to rename an existing file (and/or move it to a new folder) use the Name statement, eg:
Code:
Name "c:\folder\temp.wav" As cd0.filename
-
Re: Sugestions or Comments about my Sound Tutorial
thank you Si ... i tried the code & it works like a charm. thank you so much! and big thanks to CVmichael for the split buffer record/play tutorial,...
its given me immense insight on more dx8 i can accomplish.
-
Re: Sugestions or Comments about my Sound Tutorial
CVMichael
In your tutorial, you say this:
Set DSEnum = DX.GetDSEnum
' select the first sound device, and create the Direct Sound object
Set DIS = DX.DirectSoundCreate(DSEnum.GetGuid(1))
Would you be able to adivse please how to return a list of all sound devices on the system, and enable the user to choose one (ie not just default to the first sound device).
I'm not up with my C++, but a seemingly relevant description of how to do this appears here:
http://edn.embarcadero.com/article/20941
Thanks in advance!
-
Re: Sugestions or Comments about my Sound Tutorial
The DSEnum holds all the sound devices, just check the properties there.
You should have a Count, and other properties, like the name, etc...
In the example you gave, the Index is 1, therefore it's getting the first one...
-
Re: Sugestions or Comments about my Sound Tutorial
OK CVMichael. So a mod to your 'minimum code to play a wav file' to allow user to pick a sound device to play the sound through, would look like this (command button and listbox on a form):
vbcode Code:
Option Explicit
Dim DX As New DirectX8
Dim DSEnum as DirectSoundEnum8
Dim Dis as DirectSound8
Dim DSSecBuffer As DirectSoundSecondaryBuffer8
Dim BuffDesc as DSBUFFERDESC
Private Sub Command1_Click()
Dim A as Integer
Dim N as Integer
A = DX.GetDSEnum.GetCount
For N = 1 To A
List1.AddItem DX.GetDSEnum.GetDescription(N)
Next N
End Sub
Private Sub List1_Click()
Dim V As Integer
V = List1.ListIndex + 1
Set DSEnum = DX.GetDSEnum
Set DIS = DX.DirectSoundCreate(DSEnum.GetGuid(V))
DIS.SetCooperativeLevel Me.hwnd, DSSCL_NORMAL
Set DSSecBuffer = DIS.CreateSoundBufferFromFile("C:\Windows\Media\tada.wav", BuffDesc)
DSSecBuffer.Play DSBPLAY_DEFAULT
End Sub
Questions:
-The list gets populated with 'Primary Sound Driver' and 'Realtek HD Audio output' on my system, but Windows Control Panel shows just 'Realtek HD Audio output'. Does the 'Primary Sound Driver' actually mean the 'Realtek HD Audio output' in this case (and so is a redundant entry - the appear to play identically when chosen?)
-Once a wav file is loaded into the directsound routine, should the listbox be disabled and enabled only when no sound is yet loaded?
-The sound device would be selected JUST for this app, and not globally across the system for all other apps, right?
Regards,
DocNash
-
1 Attachment(s)
Re: Sugestions or Comments about my Sound Tutorial
The first device is the default one that you choose here (in your windows):
Attachment 71726
Then it lists the actual devices. If you have only one, then it basically lists the same thing... I have 2 sound cards, and a voice modem, so for me I have 3 devices + the default one. So DSEnum gives a count of 4.
I don't get your second question, it todally depends on what you want to do...
Yes, the selection is only for that sound buffer, so technically, if you have 2 (or more) sound cards, you can play (or record) on both sound cards at the same time, from the same application.
-
Re: Sugestions or Comments about my Sound Tutorial
Thanks CVMichael for your explanation! :bigyello:
Re the second question, you're absolutely right that it depends on the application scenario, and I hadn't explained the context.
I've built a drum machine application that can load wav files into 10 channels, allows the sounds in each channel to be heavily modified/processed or even synthesized from scratch (additive, subtractive or fm synthesis), and allows sequencing of the sounds thru a built-in X0X interface, and it can be synced to midi. I was wondering when should the 'audio setup' menu item be enabled/disabled?
-Should it only be disabled when the application is actually playing at least one sound?
-Or should it be enabled only when no sounds are loaded into any of the channels (which means when the application is first launched or when 'clear all' menu item is selected)?
I've opted for the latter, as firstly I think in such an application it makes sense for the whole sequence to be sent to the one audio device or another, and secondly once a sound is loaded many things get set up (and the user can also configure many things) all of which would need to be erased/reversed if the user chooses another audio device when a sound is already loaded.
I've noticed different applications behave differently when it comes to enablement/disablement of 'audio setup'. For example:
-Audacity keeps 'audio setup' enabled even when the waveform is loaded and graphically displayed, but disables 'audio setup' whilst the waveform is playing
-Anvil Studio (a free audio/midi sequencer) always keeps 'audio setup' enabled but as soon as you open the 'audio setup' panel, the sequence stops playing and the play cursor goes back to the start of the sequence
Regards,
DocNash
-
Re: Sugestions or Comments about my Sound Tutorial
Well, you can also let the user change the sound device at any time, but apply the changes only next time the "Play" button is pressed...
Since there is no standard way, I guess any way you choose is OK...
-
Re: Sugestions or Comments about my Sound Tutorial
Hi. I have a question re. support for VB6 + DirectX8 applications in newer OS's.
This discussion:
<http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1223939&SiteID=1>
is fascinating. From what I can tell, it took place in '07, so I don't know where this has landed over the past couple of years. But a summary is:
-DX8VB.DLL is not included in Vista
-But applications which rely on DX8VB.DLL will work fine if this DLL is copied from a XP installation and registered on a Vista PC (using regsvr32 dx8vb.dll)
-But doing so breaches the Direct Redist package EULA
-MS were aware of the issue, but clearly stated VB6 & DX8 are no longer supported so would not include DX8VB.DLL in Vista
-So where does that leave us who are still developing applications in VB6 relying on DX8? Should we not include registration of DX8VB.DLL in our application installers and instead advise end users to obtain and register the DLL themselves if they get a certain error when trying to run the application?
-Can the two DLLs (DX10 and DX8), happily co-exist on Vista such that applications relying on either are not disrupted?
Thanks!
DocNash
-
Re: Sugestions or Comments about my Sound Tutorial
Not sure if this was voiced yet, but when adjusting the volume of a wav file from your code, how can one know what percentage adjustment corresponds to 1 db increments for any selected tone generated?
To comment on the above: I am in the same position as you, DoctorNash, it seems, would love to hear comments.
-
Re: Sugestions or Comments about my Sound Tutorial
Quote:
Originally Posted by
chris.cavage
.... from your code, how can one know what percentage adjustment corresponds to 1 db increments for any selected tone generated?
The most accurate and reliable way of determining that is by measurement. Hang a Voltmeter on the ext speaker jack and measure it. This and many other links will save you the trouble of doing the math. ;)
http://www.geocities.com/pa2ohh/jsdblin.htm
-
Re: Sugestions or Comments about my Sound Tutorial
After reading/searching around, I am putting together the following VB6 code to create a 250 ms, 1000 Hz tone.
I can get it to work well. I have one command on the form, called Play.
I am trying to incorporate your code from thread #86, but do not know what is the problem.
I currently get this error:
"Compile Error: Type Mismatch: Array or user-defined type expected" when I click play.
I am trying to fade the tone in 250 ms.
Here is my code:
vb Code:
Option Explicit
'
' DirectSound access
Dim DX As DirectX8
Dim DS As DirectSound8
Dim dsToneBuffer As DirectSoundSecondaryBuffer8
Dim desc As DSBUFFERDESC
'
' Global variables
Const PI = 3.14159265358979
Const SRATE = 44100 ' Sampling Rate
Const DUR = 0.25 ' Tone duration
Const FREQ = 1000 ' Tone frequency
Dim sbuf(0 To DUR * SRATE) As Integer
Private Sub Form_Load()
'
' initialise DirectSound
Set DX = New DirectX8
Set DS = DX.DirectSoundCreate("")
DS.SetCooperativeLevel Me.hWnd, DSSCL_NORMAL
desc.lFlags = DSBCAPS_CTRLVOLUME
'
' create a buffer
desc.fxFormat.nFormatTag = WAVE_FORMAT_PCM
desc.fxFormat.nSize = 0
desc.fxFormat.lExtra = 0
desc.fxFormat.nChannels = 1
desc.fxFormat.lSamplesPerSec = SRATE
desc.fxFormat.nBitsPerSample = 16
desc.fxFormat.nBlockAlign = 2
desc.fxFormat.lAvgBytesPerSec = 2 * SRATE
desc.lFlags = 0
desc.lBufferBytes = 2 * DUR * SRATE
Set dsToneBuffer = DS.CreateSoundBuffer(desc)
'
' create a tone
Dim i
For i = 0 To DUR * SRATE
sbuf(i) = 10000 * Sin(2 * PI * FREQ * i / SRATE)
Next i
'
' copy tone to buffer
dsToneBuffer.WriteBuffer 0, 2 * DUR * SRATE, sbuf(0), DSBLOCK_DEFAULT
'
End Sub
Private Sub Play_Click()
'
' play the tone
'dsToneBuffer.SetVolume 0
Dim TotalSamples As Long
Dim StartSample As Long
Dim EndSample As Long
TotalSamples = SRATE * (250 / 1000#)
StartSample = 0
EndSample = TotalSamples
WaveFade16 dsToneBuffer, StartSample, EndSample, False
dsToneBuffer.Play DSBPLAY_DEFAULT
End Sub
Public Function WaveFade16(Buffer() As Integer, StartSample As Long, EndSample As Long, Optional FadeOut As Boolean = True) As Integer()
Dim K As Long
Dim RetBuffer() As Integer
Dim TotalSamples As Long
Dim Vol As Single
ReDim RetBuffer(UBound(Buffer))
For K = LBound(Buffer) To StartSample - 1
RetBuffer(K) = Buffer(K)
Next K
TotalSamples = EndSample - StartSample
If FadeOut Then
For K = StartSample To EndSample
Vol = 1# - (CSng(K - StartSample) / TotalSamples)
RetBuffer(K) = Buffer(K) * Vol
Next K
Else
For K = StartSample To EndSample
Vol = CSng(K - StartSample) / TotalSamples
RetBuffer(K) = Buffer(K) * Vol
Next K
End If
For K = EndSample + 1 To UBound(Buffer)
RetBuffer(K) = Buffer(K)
Next K
WaveFade16 = RetBuffer
End Function
-
Re: Sugestions or Comments about my Sound Tutorial
Quote:
Originally Posted by
chris.cavage
After reading/searching around, I am putting together the following VB6 code to create a 250 ms, 1000 Hz tone.
Are you aware that you can do that with the Beep API?
Code:
Option Explicit
Private Declare Function Beep Lib "kernel32" (ByVal dwFreq As Long, ByVal dwDuration As Long) As Long
Private Sub Form_Click()
Beep 1000, 250
End Sub
-
Re: Sugestions or Comments about my Sound Tutorial
Yes, I did know that. Thanks for that suggestion though.
I need to work on fade in/fade out with a given tone... along with changing the volume. All of this, I didn't think I could do with the Beep API, so I am working on Directx8.
Thanks also for your previous link... I had a look at it. Once I get the basics down, I will resort to that.
-
Re: Sugestions or Comments about my Sound Tutorial
Firstly CVMichael, what a fantastic job you've done with that tutorial. Congratulations.
I have quickly gone over the tutorial and the posts here, but have not quite found what i'm looking for as I guessed that if I'm going to get an answer, it'll be here!
Before noticing this great thread, I posted this elsewhere on the forum, which explains what im looking for.
http://www.vbforums.com/showthread.php?t=585646
I would greatly appreaciate any help on the subject.
Thanks in anticipation, and again, a really useful thread.
-
Re: Sugestions or Comments about my Sound Tutorial
I already posted this message somewhere but probably in the wrong place.
---------
Loved the sound tutorial CVMichael :) I use DirectX8 (in post #3 of the tutorial) to play a wave file:
Code:
Set DSSecBuffer = DIS.CreateSoundBufferFromFile("C:\WINDOWS\Media\tada.wav", BuffDesc, WaveFormat)
DSSecBuffer.Play DSBPLAY_DEFAULT
Works just fine!
I'd like the button to change color as soon as the wave file ends. How can I determin if the tada.wav has come to an end? Is there an easy way to find out?
Thanks, Floyd
-
Re: Sugestions or Comments about my Sound Tutorial
Hi Floyd,
In post #4 in the sound tutorial http://www.vbforums.com/showpost.php...99&postcount=4
You will find how to set events.
See this:
Code:
' create the event to signal the sound has stopped
EndEvent = DX.CreateEvent(Me)
EventsNotify(2).hEventNotify = EndEvent
EventsNotify(2).lOffset = DSBPN_OFFSETSTOP
Then in the next code, you can see how to "Implements DirectXEvent8" to get the events.
-
Re: Sugestions or Comments about my Sound Tutorial
Thanks for this fantastic tutorial.
I have a request.
Using the recording code is there any way of recording each channel of the sterio independently. IE seperate wav files for each channel and starting and stopping at different times.
I think the only way to do this is to record all the time into a buffer then seperating them out into two different arrays, but if this can be done on the card itself it would be much easier.
Geoff.
-
Re: Sugestions or Comments about my Sound Tutorial
You got it, you have to record all the time, split the stereo sound into 2 mono sounds (buffers).
So basically when you click record on one of the channels, then you actually begin saving on that channel.
-
Re: Sugestions or Comments about my Sound Tutorial
Thought as much, trouble is I have got myself a little confussed as to how to actually split the chanels.
I think its in here somewhere:
With WaveFmt
.wFormatTag = 1 ' PCM
.nChannels = 1
.nSamplesPerSec = 8000
.wBitsPerSample = 16
.nBlockAlign = .wBitsPerSample * .nChannels / 8
.nAvgBytesPerSec = .nBlockAlign * .nSamplesPerSec
but I dont know how to select either right or left.
Geoff.
-
Re: Sugestions or Comments about my Sound Tutorial
-
Re: Sugestions or Comments about my Sound Tutorial
Yes I have looked at that thread already, but what I cant fathom is how to turn the two channels into seperate soundfiles.
I don't know if im being a little thick here, but I cant work out which part of the programme the split refers to. Is it the buffer from the directsound or is it the finished file. I am not too good with binary files I think that is where I am loosing it.
Geoff.
-
Re: Sugestions or Comments about my Sound Tutorial
Wow... wonderful tutorial... Thanks for creating and sharing it.... :wave:
-
Re: Sugestions or Comments about my Sound Tutorial
I have tried changing the sound card, but it only seems to work on playback, the recording card stays as the default primary card. Any ideas what I am doing wrong.