VB.NET implementation DirectSound9 (7) recording

xiaoxiao2021-03-06  42

Keywords: VB.NET DirectX 9 DirectSound audio file format riff Author: Dong Jun afternoon saw with the example provided by Microsoft, actually taped positioned Beginner level Yune, although I think this case is the most "direct" example provided by Microsoft, However, the steps are too much. And also involve multi-threaded open buffer callback RIFF file format IO output. Due to the complexity of the recording, the directness of Microsoft's example, I adhere to the original, I finally copied a lot of code. ( I hope not to ....) OK, let's talk about the steps of recording, involve Riff or use skills, have a comment. I only say steps. A screenshot first needs to explain the concept of different concepts 1 sound card (Or Windows) divides the audio equipment into two parts, one is a recording device, and the other is playback 2 we use Device to create playback devices, this time you need to create a recording device, recording device Unlike playback, the ability of the equipment is often critical (the playback is also critical, but the equipment capability is basically different), so it cannot be used only one by default, and the user needs to be specified, and even the way to use the enumeration. Test performance (see See whether to support this format) 3 After using DIM Caplist As New CaptureDevicesCollection, DIM INFO As DeviceInformation '' 'first gets the information you can use' '' device information by this collection provides for Each Info in Caplist ListBox1.Items.Add ( Info.description) Next Make All Device 4 When you create Capture, you need to specify that device, (you can specify when playback, but we use the default) 'Use the selected device CAP = New Capture (Caplist) (Listbox1.selected) .Driverguid) 5 Try all supported types is a TRY statement in a for loop Trycap = new capture (....) catch '' '' Failure, continue to try the next end try

6 After completing the device's preparation, DirectSound initialize 7 recording, the first step to create RIFF (Understand Riff) Second steps to create recorded buffers (including file buffers and CaptureBuffer) Step 3 Create new threads Used to capture data 8 Stop Capture Speaking Buffer Content Write Disk Modify Riff File Information Release Resource 9 Play, using the simplest way to play files Body steps to these, the relationship between functions between the functions is more complicated. But no Similar approach. Comment is more detailed, there is also a comment inside the file operation method of Riff. Or directly copy to your program directly. The following is the source code

Imports Microsoft.directx.directSound

Imports system.io

Imports system.threading

Public Class Form1

Inherits System.Windows.Forms.form

Private structure formatinfo

Public Format As WaveFormat

Public overrides function toString () AS STRING

Return ConvertwaveFormattostring (Format)

End Function 'TOSTRING

End structure 'Formatinfo

DIM DevPlay As New Device

DIM BUFPLAY As SecondaryBuffer

Dim Formats as new arraylist

DIM CAP As Capture

DIM Caplist As New CaptureDejectCollection

Private InputFormatSupported (19) as booleanpublic InputFormat As Waveformat

Private Wavefile as filestream = Nothing

Private Writer as binaryWriter = Nothing

Public ApplicationNotify As Notify = Nothing

Public ApplicationBuffer as CaptureBuffer = Nothing

Public Notify As INTEGER = 0

Private notifythread as thread = Nothing

Public NotificationEvent As AutoreteTevent = Nothing

Public PositionNotify (NumberRecordnotification) as bufferpositionNOTIFY

Public const numberRecordNotifications as integer = 16

Public CaptureBuffersize As INTEGER = 0

Public nextcaptureoffset as integer = 0

Private SampleCount as integer = 0

#Region "Windows Form Designer Generated Code"

Public Sub New ()

Mybase.new ()

'This call is required for the Windows Form Designer.

InitializeComponent ()

'Add any initialization after INITIALIZECOMPONENT ()

End Sub

'Form rewriting Dispose to clean up the list of components.

Protected Overloads Overrides Sub Dispose (Byval Disposing as Boolean)

IF Disposing then

IF not (Components Is Nothing) THEN

Components.dispose ()

END IF

END IF

Mybase.dispose (Disposing)

End Sub

'Windows Form Designer

Private Components as System.comPonentModel.icontainer

'Note: The following process is necessary for the Windows Form Designer.

'You can modify this process using the Windows Form Designer.

'Don't modify it using the code editor.

Friend Withevents ListBox1 As System.Windows.Forms.Listbox

Friend Withevents ListBox2 as System.Windows.Forms.Listbox

Friend Withevents TextBox1 As System.Windows.Forms.TextBox

Friend Withevents Button1 As System.Windows.Forms.Button

Friend Withevents Button2 As System.Windows.Forms.Button

Friend Withevents Button3 As System.Windows.Forms.Button

Friend Withevents Button4 As System.Windows.Forms.Button

Friend Withevents Label1 As System.Windows.Forms.Label

private subinitizecomponent () me.listbox1 = new system.windows.Forms.Listbox

Me.Listbox2 = new system.windows.forms.listbox

Me.TextBox1 = new system.windows.Forms.TextBox

Me.Button1 = new system.windows.Forms.Button

Me.Button2 = new system.windows.Forms.Button

Me.Button3 = new system.windows.Forms.Button

Me.Button4 = new system.windows.Forms.Button

Me.label1 = new system.windows.forms.label

Me.suspendlayout ()

'

'ListBox1

'

Me.ListBox1.ItemHeight = 12

Me.Listbox1.location = new system.drawing.point (16, 16)

Me.ListBox1.name = "listbox1"

Me.Listbox1.size = new system.drawing.size (216, 64)

Me.ListBox1.tabindex = 1

'

'ListBox2

'

Me.ListBox2.ItemHeight = 12

Me.Listbox2.Location = new system.drawing.point (16, 88)

Me.ListBox2.name = "listbox2"

Me.Listbox2.size = new system.drawing.size (216, 100)

Me.Listbox2.tabindex = 2

'

'TextBox1

'

Me.TextBox1.Location = new system.drawing.point (24, 208)

Me.TextBox1.name = "textbox1"

Me.TextBox1.size = new system.drawing.size (208, 21)

Me.TextBox1.tabindex = 3

Me.TextBox1.text = "c: /0001.wav"

'

'Button1

'

Me.button1.location = new system.drawing.point (24, 240)

Me.Button1.name = "button1"

Me.button1.size = new system.drawing.size (64, 24)

Me.button1.tabindex = 4

Me.Button1.text = "recode"

'

'Button2

'

Me.Button2.Location = new system.drawing.point (96, 240)

Me.Button2.name = "button2"

Me.Button2.size = new system.drawing.size (72, 24)

Me.Button2.tabindex = 5

Me.Button2.text = "stop" '

'Button3

'

Me.Button3.Location = new system.drawing.point (176, 240)

Me.Button3.name = "button3"

Me.Button3.Size = new system.drawing.size (80, 24)

Me.button3.tabindex = 6

Me.Button3.text = "play"

'

'Button4

'

Me.button4.location = new system.drawing.point (272, 240)

Me.Button4.name = "Button4"

Me.button4.size = new system.drawing.size (96, 24)

Me.button4.tabindex = 7

Me.Button4.text = "Disposebuff"

'

'Label1

'

Me.Label1.Location = new system.drawing.point (248, 16)

Me.Label1.name = "label1"

Me.label1.size = new system.drawing.size (264, 160)

Me.label1.tabindex = 8

Me.Label1.Text = "Sound Format"

'

'Form1

'

Me.autoscalebasesize = new system.drawing.size (6, 14)

Me.ClientSize = new system.drawing.size (536, 277)

Me.Controls.add (me.label1)

Me.Controls.add (me.button4)

Me.Controls.add (me.button3)

Me.Controls.add (me.button2)

Me.Controls.add (me.button1)

Me.Controls.add (Me.TextBox1)

Me.Controls.add (me.listbox2)

Me.Controls.add (me.listbox1)

Me.Name = "Form1"

Me.Text = "Form1"

Me.ResumeLayout (false)

End Sub

#End region

Private Sub Form1_Load (Byval E AS System.Object, Byval E AS System.Eventargs) Handles MyBase.Load

DIM INFO As DeviceInformation

'' 'First get the information you can use

'' Device information is provided by this collection

For Each Info in Caplist

ListBox1.Items.add (Info.description)

NEXT

End Sub

Private sub listbox1_selected Indexchanged (Byval e as system.EventArgs) Handles ListBox1.Selected IndexChanged

'Using the selected device

CAP = New Capture (Caplist (listbox1.selectedIndex) .driverguid) '' enumeration support format

'' 'Try a variety of formats, you can only use TRY CATCH.

DIM FMT As Waveformat

DIM Testcapture as CaptureBuffer

DIM CaptureDesc As New CaptureBufferDescription

'ListBox2.Items.clear ()

ScanavailableinputFormats (CAP)

FillFormatListbox ()

End Sub

Sub ScanavailableinputFormats (Byval Cap As Capture)

'------------------------------------- ----------------------------

'Name: ScanavailableinputFormats ()

'DESC: TESTS TO SEE IF 20 DIFFERENT Standard Wave Formats Aresu Supported by

'The Capture Device

'------------------------------------- ----------------------------

DIM FORMAT AS New WaveFormat

DIM DSCHECKBOXD AS New CaptureBufferDescription

Dim PdscaptureBuffer as CaptureBuffer = Nothing

'This Might Take a Second Or Two, So Throw up The Hourglass

Cursor = CURSORS.WAITCURSOR

Format.formattag = Waveformattag.pcm

'Try 20 Different Standard Formats to See eti the is more supplies

DIM IIndex as INTEGER

For IIndex = 0 to 19

GetWaveFormatFromindex (IIndex, Format)

'Test IF a Capture Format Is Supported, Try to Create A

'New Capture Buffer Using A Specific Format. if IT Works

'Ten the format is supported, OtherWise Not.

DSCHECKBOXD.BufferBytes = format.averageBytespersecond

DSCHECKBOXD.FORMAT = Format

Try

PDScaptureBuffer = New CaptureBuffer (DSCHECKBOXD, CAP)

InputFormatSupported (IIndex) = TRUE

Catch

InputFormatsupported (IIndex) = false

END TRY

pdscapturebuffer.dispose ()

Next IIndex

Cursor = Cursors.default

End Sub 'ScanavailableInputFormats

Private sub getwaveformatfromindex (byval index as itformat) ----------------------------------- ------------------------------------------

'Name: getWaveformatFromindex ()

'DESC: RETURns 20 Different Wave Formats Based on Index

'------------------------------------- ----------------------------

DIM SampleRate As Integer = Index / 4

DIM ITYPE AS INTEGER = INDEX MOD 4

Select Case SampleRate

Case 0

Format.samplespersecond = 48000

Case 1

Format.samplespersecond = 44100

Case 2

Format.samplespersecond = 22050

Case 3

Format.samplespersecond = 11025

Case 4

Format.samplespersecond = 8000

End SELECT

Select Case ITYPE

Case 0

Format.BitsPersample = 8

Format.Channels = 1

Case 1

Format.BitsPersample = 16

Format.Channels = 1

Case 2

Format.BitsPersample = 8

Format.Channels = 2

Case 3

Format.BitsPersample = 16

Format.Channels = 2

End SELECT

Format.BlockAlign = cshort (Format.Channels * (Format.BitsPersample / 8))

Format.averageBytespersecond = format.blockalign * format.samplesperspersecond

End Sub 'getWaveformatFromindex

Private Shared Function ConvertWaveFormattostring (Byval Format As Waveformat) AS String

'------------------------------------- ----------------------------

'Name: convertWaveformattostring ()

'DESC: Converts a Wave Format to a Text String

'------------------------------------- ----------------------------

Return format.samplesperspersecond.toString () "hz," format.bitsPersample.toString () "-bit" Iif (Format.Channels = 1, "MONO", "STEREO")

End function 'ConvertWaveFormattostringsub FillFormatListbox ()

'------------------------------------- ----------------------------

'Name: FillFormatListbox ()

'Desc: Fills the Format List Box Based on The Availible Formats

'------------------------------------- ----------------------------

DIM INFO As New Formatinfo

DIM StrformatName as string = string.empty

DIM FORMAT AS New WaveFormat

DIM IIndex as INTEGER

For IIndex = 0 to InputFormatSupported.Length - 1

If true = infutformatsupported (IINDEX) THEN

'Turn The Index Into a Waveformat Turn That Into A

'String and Put the string in the listbox

GetWaveFormatFromindex (IIndex, Format)

Info.format = Format

Formats.Add (Info)

END IF

Next IIndex

Listbox2.datasource = Formats

End Sub 'FillFormatListBox

SUB CREATERIFF ()

'********************************************************** ***********************

'

'

'Here is where the file will be created. A

'

'Wave File Is A Riff File, Which Has Chunks

'

'of data this describe what the file contains.

'

'A Wave Riff File Is Put Together Like this:

'

'

'

'The 12 byte riff chunk is constructed like this:

'

'Bytes (0 - 3)' R '' I '' F '' F '

'

'Bytes 4 - 7: Length of file, minus the first 8 bytes of the riff description.

'

'(4 bytes for "Wave" 24 Bytes for Format Chunk Length

'

'8 Bytes for Data Chunk Description Actual Sample Data Size.)

'

'Bytes (8 - 11)' W '' A '' V '' E '

'

'

'

'The 24 Byte Format Chunk is Constructed Like this:'

'Bytes (0 - 3)' f '' m '' t '' '

'

'Bytes 4 - 7: The format chunk length. This is always 16.

'

'Bytes 8 - 9: file padding. Always 1.

'

'Bytes 10- 11: Number of channels. Either 1 for mono, or 2 for stereo.

'

'Bytes 12- 15: Sample Rate.

'

'Bytes 16-19: Number of bytes per second.

'

'Bytes 20-21: Bytes Per Sample. 1 for 8 bit mono, 2 for 8 bit stereo or

'

'16 bit mono, 4 for 16 bit stereo.

'

'Bytes 22- 23: Number of Bits Per Sample.

'

'

'

'The Data Chunk is Constructed Like this:

'

'Bytes (0 - 3)' D '' A '' T '' A '

'

'Bytes 4 - 7: Length of data, in bytes.

'

'Bytes 8 -...: actual sample data.

'

'

'

'********************************************************** *******************************

'Open Up The Wave File for Writing.

Wavefile = new filestream (TextBox1.text, filemode.create)

Writer = new binarywriter (Wavefile)

'Set up file with riff chunk info.

DIM chunkriff as char () = {"r", "i", "f", "f"}

DIM chunktype as char () = {"w", "a", "v", "e"}

DIM chunkfmt as char () = {"f", "m", "t", "}

Dim Chunkdata as char () = {"d", "a", "t", "a"}

Dim Shpad as Short = 1 'File Padding

DIM NFORMATCHUNKLENGTH AS INTEGER = & H10 'Format Chunk Length.

Dim NLENGTH AS INTEGER = 0 'File Length, Minus First 8 BYtes of Riff Description. This Will Be Filled In Later.dim Shibytesample AS Short = 0' BYTES Per Sample.

'Figure Out How Many Bytes There Will Be Per Sample.

IF 8 = INPUTFORMAT.BITSPERSAMPLE AND 1 = InputFormat.Channels Then

SHBYTESPERSAMPLE = 1

Elseif 8 = INPUTFORMAT.BITSPERSAMPLE AND 2 = INPUTFORMAT.CHANNELS OR (16 = INPUTFORMAT.BITSPERSAMPLE AND 1 = InputFormat.Channels) THEN

SHBYTESPERSAMPLE = 2

Elseif 16 = INPUTFORMAT.BITSPERSAMPLE AND 2 = INPUTFORMAT.CHANNELS THEN

SHBYTESPERSAMPLE = 4

END IF

'Fill in The Riff Info for the Wave file.

Writer.write (chunkriff)

Writer.write (NLENGTH)

Writer.write (chunktype)

'Fill in The Format Info for the Wave file.

Writer.write (chunkfmt)

Writer.write (nformatchunklength)

Writer.write (SHPAD)

Writer.write (InputFormat.Channels)

Writer.write (InputFormat.SamplespeSpeSecond)

Writer.write (InputFormat.aveRageBytespersecond)

Writer.write (shbytesprite)

Writer.write (InputFormat.BitsPersample)

'Now Fill in the data chunk.

Writer.write (chunkdata)

Writer.write (CINT (0)) 'The Sample Length Will BE Written in Later.

End Sub 'Createriff

SUB CREATECAPTUREBUFFER ()

'------------------------------------- ----------------------------

'Name: CreateCaptureBuffer ()

'DESC: Creates a Capture Buffer and sets the format

'------------------------------------- ----------------------------

DIM DSCHECKBOXD AS New CaptureBufferDescription

IF not nothing is applicationNotify THEN

ApplicationNotify.Dispose ()

ApplicationNotify = Nothing

END IF

IF not nothing is applicationbuffer dam

ApplicationBuffer.dispose () ApplicationBuffer = Nothing

END IF

IF 0 = InputFormat.Channels Then

Return

END IF

'Set the notification size

Notifysize = IIF (1024> InputFormat.averageBytesperSecond / 8, 1024, InputFormat.aveRageBytespersecond / 8)

Notifysize - = notifysize mod inputformat.blockalign

'Set the buffer size

CaptureBuffersize = NotifySize * NumberRecordNotifications

'Create the Capture Buffer

DSCheckBoxd.Bufferbytes = CaptureBuffersize

InputFormat.formattag = Waveformattag.pcm

DSCHECKBOXD.FORMAT = INPUTFORMAT 'SET The Format During Creatation

ApplicationBuffer = New CaptureBuffer (DSCHECKBOXD, CAP)

NextcaptureOffset = 0

INITNOTIFICATIONS ()

End Sub 'CreateCaptureBuffer

Sub initNotifications ()

'------------------------------------- ----------------------------

'Name: initnotifications ()

'DESC: INITS The Notifications on The Capture Buffer Which Are Handled

'In the notify thread.

'------------------------------------- ----------------------------

IF nothing is applicationbuffer dam

Throw New Argumentnullxception

END IF

'Create a Thread to Monitor The Notify Events

If nothing is notifythread then

Notifythread = New Thread (New ThreadStart (Addressof Waitthread))

Notifythread.Start ()

'Create a Notification Event, for When the Sound Stops Playing

NotificationEvent = New AutoreteEvent (False)

END IF

'Setup the notification positions

DIM I as integer

For i = 0 to NumberRecordnotification - 1

POSITIONNOTIFY (i) .offset = notify = notifysize - 1

PositionNotify (i). EventNotifyHandle = NotificationEvent.Handle

Next I

ApplicationNotify = New Notify (ApplicationBuffer) 'Tell DirectSound When to Notify The App. The Notification Will Come in The from THE FROM

'of Signaled Events That Are Handled in The Notify Thread.

ApplicationNotify.setNotificationPositions (PositionNotify, NumberRecordnotifications)

End sub 'initnotifications

Private sub waitthread ()

While created

'Sit Here and Wait for a Message To Arrive

NotificationEvent.waitone (Timeout.Infinite, True)

RecordcapturedData ()

End while

End Sub 'Waitthread

Sub recordcapturedData ()

'------------------------------------- ----------------------------

'Name: RecordcapturedData ()

'DESC: COPIES DATA from The Capture Buffer To The Output Buffer

'------------------------------------- ----------------------------

Dim capturedata as byte () = Nothing

Dim Readpos As Integer

DIM CapturePOS AS Integer

DIM LOCKSIZE AS INTEGER

IF nothing is applicationbuffer or nothing is Wavefile THEN

Return

END IF

ApplicationBuffer.getCurrentPosition (CapturePos, Readpos)

Locksize = readpos - NextCaptureOffset

IF Locksize <0 THEN

Locksize = CaptureBuffersize

END IF

'Block Align Lock Size So That We Are Always Write on a Boundary

Locksize - = LOCKSIZE MOD NOTIFYSIZE

IF 0 = LOCKSIZE THEN

Return

END IF

'Read the Capture Buffer.

CaptureData = ctype (ApplicationBuffer.Read (NextcaptureOffset, GetType (Byte), Lockflag.none, Locksize, Byte ())

'Write the Data Into the WAV File

Writer.write (CaptureData, 0, CaptureData.Length)

'Update The Number of Samples, in Bytes, of The File So Far.

SampleCount = CaptureData.Length

'Move The Capture Offset Along

NextcaptureOffset = CaptureData.LengthnextCaptureOffset = NextcaptureOffset MOD CAPTUREBUFFERSIZE 'CIRCULAR BUFFER

End Sub 'RecordcapturedData

Private sub placebox2_selected IndiedExchanged (Byval e as system.eventArgs) handles listbox2.selectedIndIndexchanged

InputFormat = ctype (formats (listbox2.selectedIndex), formatinfo) .format

Label1.text = ctype (listbox2.selecteditem, formatinfo) .format.toString

End Sub

Sub StartorstopRecord (Byval StartRecording as Boolean)

'------------------------------------- ----------------------------

'Name: startorstoprecord ()

'Desc: Starts or Stops The Capture Buffer from Recording

'------------------------------------- ----------------------------

IF starRecording then

'Create a Capture Buffer, And Tell the Capture

'Buffer to Start Recording

CreateCaptureBuffer ()

ApplicationBuffer.Start (TRUE)

Else

'Stop the Capture and Read Any Data That

'Was Not Caught by a Notification

IF nothing is applicationbuffer dam

Return

END IF

'Stop The Buffer, And Read Any Data That Was Not

'caught by a notification

ApplicationBuffer.Stop ()

RecordcapturedData ()

Writer.seek (4, seekorigin.begin) 'Seek to the length descriptor of the riff file.

Writer.Write (CINT (SampleCount 36)) 'Write the File Length, Minus First 8 BYTES OF RIFF DESCRIPTION.

Writer.seek (40, seekorigin.begin) 'Seek to The Data Length Descriptor of the Riff File.

Writer.write (SampleCount) 'Write the length of the sample data in bytes.

Writer.close () 'close the file now.

Writer = Nothing 'Set The Writer to Null.

Wavefile = Nothing 'set the filestream to null.end IF

End Sub 'StartorstopRecord

Private sub button1_click (byvale as system.object, byval e as system.eventargs) Handles Button1.click

Createriff ()

StartorstopRecord (True)

End Sub

Private sub Button2_click (byvalgend, byval e as system.eventargs) Handles Button2.click

StartorstopRecord (False)

End Sub

Private sub button3_click (byval sender as system.object, byval e as system.eventargs) Handles Button3.click

DevPlay.SetCooperativeelevel (ME, CooperativeElevel.Priority)

BUFPLAY = New SecondaryBuffer (TextBox1.Text, Devplay)

BUFPLAY.PLAY (0, bufferplayflags.default)

End Sub

Private sub button4_click (byval sender as system.object, byval e as system.eventargs) Handles Button4.click

BUFPLAY.STOP ()

BUFPLAY.Dispose ()

End Sub

Private sub mainform_closing (Byval e as system.componentmodel.canceleventargs) Handles mybase.closing

IF not nothing is notificationEventim

NotificationEvent.set ()

END IF

IF not nothing is applicationbuffer dam

IF ApplicationBuffer.capturing the

StartorstopRecord (False)

END IF

END IF

End

End sub 'mainform_closing

END CLASS

转载请注明原文地址:https://www.9cbs.com/read-52998.html

New Post(0)