Re: Sugestions or Comments about my Sound Tutorial
You select the sound card to use for recording in these lines:
Code:
Set SEnum = DX.GetDSCaptureEnum ' get the device enumeration object
' if GUID is empty, then assign the first sound device
If Len(GUID) = 0 Then GUID = SEnum.GetGuid(1)
' choose the sound device, and create the Direct Sound object
Set DISCap = DX.DirectSoundCaptureCreate(GUID)
Just change the 1 to 2, or you can display the list of the enum items in a drop down so that the user can select the sound card to record from the application.
Re: Sugestions or Comments about my Sound Tutorial
Well, right now this code "If Len(GUID) = 0 Then" checks to see if you pass the GUID in the Initialize function, and if you don't pass anything then it will choose the default one.
I don't have VB6 at the comptuer I am working right now, so you have to check this for me: If you press "F2" to open the object browser, do a search for "GetDSCaptureEnum", and tell me the object type name that it returns.
If the object type is "DirectSoundEnum8", then I really don't know where the problem could be. Maybe if you post your project and I will check it when I get home.
Re: Sugestions or Comments about my Sound Tutorial
Anyways, I figured out how to check using VBA in Excel... I took a print screen of what I was talking about.
SO...... it seems that the return object is correct (to what I have in my code in the tutorial), so in that case, I don't know what is wrong.
I will need to see your project. Even then I might not figure out the problem because I don't have the same system and sound card(s) as you have, but still, posting the code you have might help...
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDest As Any, pSrc As Any, ByVal ByteLen As Long)
Public startt As Integer
Public stopped As Integer
Public timerr As Integer
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 WithEvents DirectSoundRecord As frmDX_Record
Private FileNum As Integer
Dim DX As New DirectX8
Dim DSEnum As DirectSoundEnum8
Dim Dis As DirectSound8
Dim DSSecBuffer As DirectSoundSecondaryBuffer8
Dim BuffDesc As DSBUFFERDESC
'Private SEnum As DirectSoundEnum8
Private SEnum As DirectSoundEnum8
Private DISCap As DirectSoundCapture8
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 DirectSoundRecord_GotWaveData(Buffer() As Byte, BitsPerSample As Integer, Channels As Integer)
' make sure that there is a file opened
If FileNum <> 0 Then
' write the wave data to the file
Put FileNum, , Buffer
If BitsPerSample = 8 Then
DisplayWaveData8 Buffer, picWave, Channels = 2
ElseIf BitsPerSample = 16 Then
DisplayWaveData16_8 Buffer, picWave, Channels = 2
End If
End If
End Sub
Private Sub cmdStartRec_Click()
Dim ErrReturn As String
Dim WaveFmt As WaveFormat
' fill in the Wave Format
With WaveFmt
.wFormatTag = 1 ' PCM
.nBlockAlign = .wBitsPerSample * .nChannels / 8
.nAvgBytesPerSec = .nBlockAlign * .nSamplesPerSec
End With
' Create the wave tile
FileNum = FreeFile
Open "C:\Recording.WAV" For Binary Access Write Lock Write As FileNum
WaveWriteHeader FileNum, WaveFmt ' write the wave headers
With DirectSoundRecord
' initialize DirectSound with exactly the same sound format as you expect to write in the file
ErrReturn = .Initialize(WaveFmt.nSamplesPerSec, WaveFmt.wBitsPerSample, WaveFmt.nChannels)
If Len(ErrReturn) = 0 Then
' if there was no error
' start recording
.SoundPlay
cmdStopRec.Enabled = True
cmdStartRec.Enabled = False
Else
MsgBox ErrReturn, vbExclamation, "DirectSound Error"
End If
End With
End Sub
Private Sub cmdStopRec_Click()
With DirectSoundRecord
' stop recording
.SoundStop
' un-initialize DirectSound
.UninitializeSound
End With
' complete the header values (file length, and chunk length)
WaveWriteHeaderEnd FileNum
' close the file
Close FileNum
FileNum = 0
cmdStopRec.Enabled = False
cmdStartRec.Enabled = True
End Sub
Private Sub Form_Load()
Dim x As Integer
Set DirectSoundRecord = New frmDX_Record
Dim V As Integer
Dim guid As String
'With DirectSoundRecord
Set SEnum = DX.GetDSCaptureEnum ' get the device enumeration object
' if GUID is empty, then assign the first sound device
If Len(guid) = 0 Then guid = SEnum.GetGuid(2)
' choose the sound device, and create the Direct Sound object
Set DISCap = DX.DirectSoundCaptureCreate(guid)
Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
DirectSoundRecord.SoundStop
Unload DirectSoundRecord
Set DirectSoundRecord = Nothing
End Sub
Private Sub WaveWriteHeader(ByVal OutFileNum As Integer, WaveFmt As WaveFormat)
Dim header As FileHeader
Dim chunk As ChunkHeader
With header
.lRiff = &H46464952 ' "RIFF"
.lFileSize = 0
.lWave = &H45564157 ' "WAVE"
.lFormat = &H20746D66 ' "fmt "
.lFormatLength = Len(WaveFmt)
End With
chunk.lType = &H61746164 ' "data"
chunk.lLen = 0
Put #OutFileNum, 1, header
Put #OutFileNum, , WaveFmt
Put #OutFileNum, , chunk
End Sub
Private Sub WaveWriteHeaderEnd(ByVal OutFileNum As Integer)
Dim header As FileHeader
Dim HdrFormat As WaveFormat
Dim chunk As ChunkHeader
Dim Lng As Long
Lng = LOF(OutFileNum)
Put #OutFileNum, 5, Lng ' write the FileHeader.lFileSize value
Lng = LOF(OutFileNum) - (Len(header) + Len(HdrFormat) + Len(chunk))
Put #OutFileNum, Len(header) + Len(HdrFormat) + 5, Lng ' write the ChunkHeader.lLen value
End Sub
Private Sub DisplayWaveData8(DataBuff() As Byte, Pic As PictureBox, Stereo As Boolean)
Dim Stp As Single, HBuffer As Long, Q As Single
Dim LX As Single, LY As Single, RX As Single, RY As Single
Dim LVal As Single, RVal As Single, K As Long
If Not Stereo Then
HBuffer = UBound(DataBuff)
Stp = HBuffer / (Pic.Width / 15)
' the sound is 16 bit, but it comes in Bytes, not Integer
Private Sub DisplayWaveData16_8(DataBuff() As Byte, Pic As PictureBox, Stereo As Boolean)
Dim Buff() As Integer
Private Sub DisplayWaveData16(DataBuff() As Integer, Pic As PictureBox, Stereo As Boolean)
Dim Stp As Single, HBuffer As Long, Q As Single
Dim LX As Single, LY As Single, RX As Single, RY As Single
Dim LVal As Single, RVal As Single, K As Long
Dim retval
Dim x As String
If DataBuff(0) < 0 Then GoTo skip
Text1.Text = timerr
If DataBuff(0) > 1000 And startt = 0 Then
With DirectSoundRecord
' stop recording
.SoundStop
' un-initialize DirectSound
.UninitializeSound
End With
' complete the header values (file length, and chunk length)
WaveWriteHeaderEnd FileNum
' close the file
Close FileNum
FileNum = 0
Kill ("c:\Recording.wav")
cmdStartRec_Click
startt = 1
End If
If DataBuff(0) < 1000 And startt = 1 Then timerr = timerr + 1
If timerr > 40 Then
stopped = 1
timerr = 0
startt = 0
With DirectSoundRecord
' stop recording
.SoundStop
' un-initialize DirectSound
.UninitializeSound
End With
' complete the header values (file length, and chunk length)
WaveWriteHeaderEnd FileNum
' close the file
Close FileNum
FileNum = 0
x = "c:\" + Mid$(Time, 7, 2) + Mid$(Time, 4, 2) + Mid$(Time, 1, 2) + Mid$(Date, 7, 4) + Mid$(Date, 4, 2) + Mid$(Date, 1, 2) + ".wav"
FileCopy "C:\recording.wav", x
cmdStartRec_Click
End If
'If Val(Text1.Text) > DataBuff(0) Then Text1.Text = DataBuff(0)
'If Val(Text2.Text) < DataBuff(0) Then Text2.Text = DataBuff(0)
skip:
If Not Stereo Then
HBuffer = UBound(DataBuff)
Stp = HBuffer / (Pic.Width / 15)
Re: Sugestions or Comments about my Sound Tutorial
You did not post the code in vbcode tags, so it is hard for me to read that left aligned code (to see what modifications you made to my code).
So in the future, please encapsulate the code in [vbcode]your code here[/vbcode] tags.
But how DO you know that you are not recording from the right sound card ?
Does it record silence ?
Are you sure you selected the correct input for that sound device ? (see screen shot attached of windows volume control)
What input do you want to record from ? (microphone ?, line in ?, wave ?)
Re: Sugestions or Comments about my Sound Tutorial
I am recording from the line in but I have changed this in the sound card config.
The reason I know it is recording (and this could be the problem) is becasue there is wave display on the pic box. I am assuming that the recording sound card and the pic box is one and the same.
So just to reitterate. I change the guid to 2 or 3 but the pic box still shows data even though I should have changed to a different card. If this is the case then I need to change the pic box to the different card also.
Sorry for not using the forum correctly this is the first forum I have used.
Re: Sugestions or Comments about my Sound Tutorial
The picture displays whatever you are recording...
But you cannot change the sound card while it is recording. If you want to change the sound card input, then you should first un-initialize the sound, then call the initialize function with the new GUID.
Can you ZIP the entire project you are playing with, and attach it so I can look and see if you are doing everything correctly ?
Re: Sugestions or Comments about my Sound Tutorial
I don't have VB6 here, so I opened the form in Notepad.
From what I see, this is wrong:
Code:
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
As I said before, you have to Uninitialize the sound, then re-initialize it when you change the sound card device.
Try this instead:
Code:
Private Sub List1_Click()
DirectSoundRecord.UninitializeSound
cmdStartRec_Click()
End Sub
Then modify the code in the cmdStartRec_Click() to this
Code:
With DirectSoundRecord
Dim V As Integer
V = List1.ListIndex + 1
Set DSEnum = DX.GetDSEnum
' initialize DirectSound with exactly the same sound format as you expect to write in the file
ErrReturn = .Initialize(WaveFmt.nSamplesPerSec, WaveFmt.wBitsPerSample, WaveFmt.nChannels, , DSEnum.GetGuid(V))
If Len(ErrReturn) = 0 Then
' if there was no error
' start recording
.SoundPlay
cmdStopRec.Enabled = True
cmdStartRec.Enabled = False
Else
MsgBox ErrReturn, vbExclamation, "DirectSound Error"
End If
End With
Re: Sugestions or Comments about my Sound Tutorial
Thanks.
That listbox was just something I was trying it is not being used anymore for changing the sound settings, I think it is only for playback also not for recording (I think), however I have been assuming that the sound card uninitialises on programme exit, if this is not the case then that would be why it is not changing so I will try that when I get home.
Thanks for your assistance.
Re: Sugestions or Comments about my Sound Tutorial
Tried this but I get an automation error:
Error -2005401480
Source TutDS_SplitBuffRecord
It errors on this line:
' choose the sound device, and create the Direct Sound object
Set DISCap = DX.DirectSoundCaptureCreate(guid)
and the GUID is correct.
Tried it on the other sound card and get the same error.
But what is very strange is that if I put in the initialize routine:
guid = SEnum.GetGuid(2) for sound card 1
or
guid = SEnum.GetGuid(3) for sound card 2
Re: Sugestions or Comments about my Sound Tutorial
Now that I got my head around that (sort of) I wonder is there a way of recording just the left channel without going through the conversion of stereo to mono?
Re: Sugestions or Comments about my Sound Tutorial
Hi Michael,
What a wonderful (and unique) work you have done. Congratulations, it is the most complete tutorial I could find after serching the the web for several month.
I need some code done (several small codes in VB) some could take a few hours to write and some of them could take several days. It would be great to have you or perhaps some one like you to write them. Let me know if it is some thing that you would do, or if you know some one that would a job like that.
Re: Sugestions or Comments about my Sound Tutorial
Hi Katus, welcome to the vbforums
I wish I could give you good news, but I can't... the problem is that I barely have time for my own projects.
There are a few more knowledgeable people on this subject on this forum, so just post your questions one at a time. Not too much at once because everyone here gets scared when they see too much at once.
Also don't expect anyone to just write code for you. You will have to write the code, and we will help you fix the problems you may have.
Re: Sugestions or Comments about my Sound Tutorial
Thank you Michael,
I am working on a project that will record audio continuously (non-stop, forever). Most of it (about 99% will be a SQL code. However, it needs VB to capture the audio and save it into SQL (and playback from SQL).
I saw your tutorial "How to record/play with DirectXSound using split buffer for very long sounds"
It records audio from the main sound device, and saves the wave data into a wave file. The only change I would need to do is save the data to SQL (not into a wave file).
I do not know much about VB and did not want to get involved for such a small use, that is why I would like to pay some one to do it. However, I will take your advice and start writting some VB code. It would be good if at some point down the road we could make a donnation for the help I get as I will not be contributing with any thing, as most of the users.
My first question:
Would you know if saving the data (chunk data) to SQL is as much fast as saving it into a wave file? (so we do not overflow the buffer?)
Re: Sugestions or Comments about my Sound Tutorial
It will save RAW wave data to SQL. I believe that saving the data into one endless column (SQL Server 2008) will work like one endless chunk. However, SQL can manipulate stored data much faster than VB using a regular file (there will be lots of simultaneous data indexing and retrieving in real time).
All data will be converted and indexed after saved in SQL. However, I intend to do that after it is saved into SQL to prevent slowing the data retrieving (reading) process and consequently buffer overflow.
Re: Sugestions or Comments about my Sound Tutorial
Half of the things you are saying don't make any sense to me, but if you are wondering about speed, saving the wave data to a file will be much faster than sending the data to SQL.
Also, I am still wondering what this has to do with my sound tutorial. I think you should have started your own thread.
Also... posting this question in my thread in the electronics forum that has absolutelly nothing to do with sound is just mind blowing to me.
Re: Sugestions or Comments about my Sound Tutorial
I think I know what Katus is getting at. I think he wants a continuous stream of data saved, (in his case SQL which is a bit odd) so as he can extract chunks of it without stopping the recording, perhaps for telephone recording or something like that. Sounds like quite a good idea, rather than stopping and starting and converting, just extracting parts of it.
Re: Sugestions or Comments about my Sound Tutorial
Hi CVMichael,
I live in Brazil (South America) and English is not my native language, peharps, I might have said some thing wrong that got you upset. However, it was not my intention at all. I am sorry for that.
The reason for a continuous stream of data rely on the need of extraction and comparision of chuncks in real time, you are correct UKnod.
Microsoft has not developed a Speech recognition in Portuguese language yet and as the systems available in other laguages are not good enough yet it may a long time before it gets here. We have created a phoneme comparison SQL algorithm and need VB to handle the input/output.
I understood that it was a public thread and this subject had to do with sound but I guess I was wrong and will not post any more messages again.
Re: Sugestions or Comments about my Sound Tutorial
Hello Michael, and thank you for the great code. I've been working on some sound software for a while, and I'm so glad you posted that resampling code. I've been calling up r8brain to resample my sounds, and that takes forever.
Anyway, as thanks, here are some basic sound functions that I've written. They include fade, distortion, phase inversion, and reversal.
Also, I don't know if rm_03 is still around, but I get a problem with this line of the DSPEcho code:
Is norm a function I'm supposed to figure out, a typo, or what?
EDIT: I rewrote the code a little bit to work around that missing function. This works for me:
Code:
Private intEcho() As Long
Private lngSamples() As Long
Private lngEchoPos As Long
Private lngEchoLength As Single
Public Sub DSPEcho(intSamples() As Integer, ByVal datalength As Long)
Dim i As Long, lngPeak As Long
ReDim lngSamples(LBound(intSamples()) To UBound(intSamples()))
For i = 0 To datalength
lngSamples(i) = CLng(intSamples(i)) + intEcho(lngEchoPos)
intEcho(lngEchoPos) = lngSamples(i) * lngEchoLength
lngEchoPos = lngEchoPos + 1
If Abs(lngSamples(i)) > lngPeak Then lngPeak = Abs(lngSamples(i))
If lngEchoPos > UBound(intEcho) Then
lngEchoPos = 0
End If
Next
'Stop
Dim Ratio As Double
Ratio = 3276700 / lngPeak
For i = 0 To datalength
intSamples(i) = CInt(lngSamples(i) * Ratio \ 100)
Next
End Sub
Code:
Option Explicit
Dim intCurSnd As Integer
Dim Modif As Integer
Dim X As Long
Public Sub DistortSound(Buff() As Integer, StartPoint As Long, EndPoint As Long, Optional ByVal DistAmnt As Integer = 100)
'Feed it values from -100 to 100
'Negative values induce negative distortion
'Negative values can sometimes remove distortion
'from a signal.
Dim TempLng() As Long
ReDim TempLng(StartPoint To EndPoint)
Dim BiggestNum As Long
If DistAmnt = 0 Then DistAmnt = 1
For intCurSnd = StartPoint To EndPoint
If Buff(intCurSnd) < 0 Then TempLng(intCurSnd) = -32768 \ DistAmnt
If Buff(intCurSnd) > 0 Then TempLng(intCurSnd) = 32767 \ DistAmnt
Next intCurSnd
For intCurSnd = StartPoint To EndPoint
TempLng(intCurSnd) = Buff(intCurSnd) + TempLng(intCurSnd)
If Abs(TempLng(intCurSnd)) > BiggestNum Then BiggestNum = Abs(TempLng(intCurSnd))
Next intCurSnd
For intCurSnd = StartPoint To EndPoint
Buff(intCurSnd) = TempLng(intCurSnd) * (3276700 / BiggestNum) \ 100
Next intCurSnd
End Sub
Private Sub FadeSound(Buff() As Integer, StartPoint As Long, EndPoint As Long)
'Make StartPoint bigger than EndPoint to fade backwards
Dim H As Long
H = 0
Dim Modif As Integer
Modif = 1
If StartPoint > EndPoint Then Modif = -1
For intCurSnd = StartPoint To EndPoint Step Modif
H = H + 1
If Buff(intCurSnd) > 0 Then
Buff(intCurSnd) = (Buff(intCurSnd) - ((Buff(intCurSnd) / (EndPoint - StartPoint)) * H))
If Buff(intCurSnd) < 0 Then Buff(intCurSnd) = 0
End If
If Buff(intCurSnd) < 0 Then
Buff(intCurSnd) = (Buff(intCurSnd) - ((Buff(intCurSnd) / (EndPoint - StartPoint)) * H))
If Buff(intCurSnd) > 0 Then Buff(intCurSnd) = 0
End If
Next intCurSnd
End Sub
Private Sub InvertPhase(Buff() As Integer, StartPoint As Long, EndPoint As Long)
Modif = 1
If StartPoint > EndPoint Then Modif = -1
For X = StartPoint To EndPoint Step Modif
Buff(X) = Buff(X) * -1
Next X
End Sub
Private Sub ReverseSound(Buff() As Integer, StartPoint As Long, EndPoint As Long)
Dim TempBuff() As Integer
Dim T As Long
If StartPoint > EndPoint Then T = StartPoint: StartPoint = EndPoint: EndPoint = T
ReDim TempBuff(StartPoint To EndPoint)
Dim P As Long
P = StartPoint
For X = EndPoint To StartPoint Step -1
TempBuff(X) = Buff(P)
P = P + 1
Next X
For X = StartPoint To EndPoint
Buff(X) = TempBuff(X)
Next X
End Sub
Last edited by Tillinghast; Apr 14th, 2010 at 11:31 PM.
Re: Sugestions or Comments about my Sound Tutorial
Hi Michael
I have run a lot of your tutorial now, but have an odd problem. The volume input (line in) seems to be much lower than for other programms. Could it be because I am using 8 bit or is there a setting to turn up the volume. I have the sound card line in volume to maximum.
Re: Sugestions or Comments about my Sound Tutorial
Unfortunatly the sound input is fixed so I cant amplify it any furthur other than adding a external amp which I would rather not do.
The strange thing is that if I use an external recorder, like windows sound recorder, there is pleanty of signal, but using drect sound there isn't.
On sound recorder the input level is about a quarter up, on direct sound the volume is on maximum.
Very odd.
Re: Sugestions or Comments about my Sound Tutorial
Scratch the sound recorder bit. That is the same as direct sound, it is another product which I have tried which boosts the volume by about 400%.
So I am not sure how they do it.
Re: Sugestions or Comments about my Sound Tutorial
Yes that worked a treat, ok, now my next problem, lol.
It seems better these days to be using MP3 rather than WAVs. I have tried joining wavs with problems with headers getting in the way, but it is quite easy to join MP3. So it would be better if I had mp3 in the first place.
I have tried your blazemp3 section and tried to convert the recorder using that, and the lame version but with no luck, could you give us some pointers on how to do this.
So to recap. Using the same code as in your example but saving in MP3 format instead of WAV.
Re: Sugestions or Comments about my Sound Tutorial
Hi UKnod,
If you want to join 2 wave files, you don't have to convert to MP3. And by the way, even MP3 has headers, some MP3 have a header at the beginning of the file and also at the end of the file. Except the player is smart enough to skeep those headers when you join the 2 files.
In post #2 of my tutorial you can see how to write a wave file, then how to read a wave file.
So, to join 2 files, read each file, then you will get 2 arrays of data from each file, join the arrays, then write it back to one wave file.
Re: Sugestions or Comments about my Sound Tutorial
When the sound card converts from analog to digital, it takes “samples” of the wave, and it does it really fast
this means there is a way to get the volume level from a usb microphone at intervals lower than 40milisecond, please tell me how to do it in vb.net
and what is &H46464952 ?
other than that, as a representor of the 'just give me the walkthrough to actually do stuff' progremmers I have no idea how to use stuff with that tutorial, and it should have a vb.net version.
Re: Sugestions or Comments about my Sound Tutorial
Originally Posted by moti barski
this means there is a way to get the volume level from a usb microphone at intervals lower than 40milisecond, please tell me how to do it in vb.net
What you quoted and this has nothing in common. In the text you quoted I was explaining how the sound card converts the sound to digital.
What you are asking can be done by recording with a very small buffer, averaging and displaying the sound level for each buffer. I have a sample in my tutorial that does that, you just have to change the buffer size.
The number you are referring to is 4 characters "RIFF" converted to a Long that is shown as HEX. Same thing as "WAVE" and "fmt ".
When I created this tutorial .NET was still new, and at that time I was not too interested in .NET. Now it's the opposite, I'm not really interested in VB6, but now I'm also not interested in sound stuff anymore as I already explored this toppic and I find no interest in it anymore. Lately my interests are in electronics, databases and ASP.NET.
I go with the flow, and I don't like to look back.
You are welcome to make your own sound tutorial for .NET.
Re: Sugestions or Comments about my Sound Tutorial
so first I :
go to the "Project" menu, and click on "References" and add directX8 or higher
at the code start line what import statement is to be used ?
then post #4 yes ? :
Choose the sound device to record from : how ?
how do I align the buffers ?
then I use the code to initialize (and UnInitialize) the Direct Sound for recording but the variables are for DX8 and the code is vb6 so how can I convert'em ?
then I add paste the next code with the line Implements DirectXEvent8 ?
then I paste add the code in post #5 ?
now how do I get the volume and set the buffer time ?