国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > .NET > 正文

VB.NET實現DirectSound9 (7) 錄音

2024-07-10 13:00:50
字體:
來源:轉載
供稿:網友
  • 本文來源于網頁設計愛好者web開發社區http://www.html.org.cn收集整理,歡迎訪問。
  • 關鍵字: vb.net directx 9 directsound 錄音 riff文件格式 作者:董含君

    下午看了微軟提供的例子,居然把錄音定位成beginner級別
    暈哦,雖說我認為這個例子是微軟提供的最”直接”的例子,但是步驟超多.而且還牽扯到多線程開辟緩沖區回調riff文件格式 io 輸出等等.由于錄音的復雜性,以及微軟這個例子的直接性,堅持原創的我最終還是復制了大量的代碼.(希望不要罵我....)

    ok,先來說錄音的步驟,里面牽扯到riff或者使用技巧的地方,有注釋.我僅僅說步驟.附帶截圖一張



    首先需要說明與往常不同的概念

    1 聲卡(或者windows)把音頻設備分成2個部分,一個是錄音設備(capture),另一個是回放設備(playback)

    2 前面我們用的是device創建回放設備,這次需要使用capture創建錄音設備,錄音設備不像回放,設備的能力往往很關鍵(回放雖說也很關鍵,但是設備能力基本上差別不大),所以不能單單使用一個默認就行,需要用戶指定,甚至用枚舉的辦法逐個測試性能(看看是否支持這種格式)

    3 利用 dim caplist as new capturedevicescollection
    得到list之后
    dim info as deviceinformation
    '''先得到可以使用的信息
    ''' 設備信息由這個集合提供
    for each info in caplist
    listbox1.items.add(info.description)
    next
    枚舉出所有設備

    4 創建capture的時候,需要指定使用那個設備了,(回放的時候也可以指定,但是我們用的是默認的)
    '利用選擇的設備
    cap = new capture(caplist(listbox1.selectedindex).driverguid)

    5 嘗試所有支持的類型
    就是一個for 循環里面嵌套下面的try語句
    try
    cap=new capture(....)
    catch
    '''''失敗的時候繼續嘗試下一個
    end try

    6 完成設備的準備工作之后,directsound初始化完成

    7 錄音,
    第一步創建riff(理解成riff即可)
    第二步創建錄音用的緩沖區(包括文件緩沖區以及capturebuffer)
    第三步創建新的線程用于捕獲數據

    8 停止
    停止capture
    講緩沖區內容寫入磁盤
    修改riff的文件信息
    釋放資源

    9 播放,利用最簡單的辦法播放文件


    大體步驟就這些,錄音的時候函數之間的關系比較復雜.但是沒有更簡單的辦法.

    注釋比較詳細,關于riff的文件操作方法內部也有注釋.或者直接復制到你的程序直接用也行.

    以下是源代碼



    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 capturedevicescollection

    private inputformatsupported(19) as boolean

    public inputformat as waveformat

    private wavefile as filestream = nothing

    private writer as binarywriter = nothing

    public applicationnotify as notify = nothing

    public applicationbuffer as capturebuffer = nothing

    public notifysize as integer = 0

    private notifythread as thread = nothing

    public notificationevent as autoresetevent = nothing

    public positionnotify(numberrecordnotifications) 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 窗體設計器生成的代碼 "



    public sub new()

    mybase.new()



    '該調用是 windows 窗體設計器所必需的。

    initializecomponent()



    '在 initializecomponent() 調用之后添加任何初始化



    end sub



    '窗體重寫 dispose 以清理組件列表。

    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 窗體設計器所必需的

    private components as system.componentmodel.icontainer



    '注意: 以下過程是 windows 窗體設計器所必需的

    '可以使用 windows 窗體設計器修改此過程。

    '不要使用代碼編輯器修改它。

    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

    <system.diagnostics.debuggerstepthrough()> private sub initializecomponent()

    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 = "聲音格式"

    '

    '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 sender as system.object, byval e as system.eventargs) handles mybase.load

    dim info as deviceinformation

    '''先得到可以使用的信息

    ''' 設備信息由這個集合提供

    for each info in caplist

    listbox1.items.add(info.description)

    next

    end sub



    private sub listbox1_selectedindexchanged(byval sender as system.object, byval e as system.eventargs) handles listbox1.selectedindexchanged

    '利用選擇的設備

    cap = new capture(caplist(listbox1.selectedindex).driverguid)

    '''枚舉支持的格式

    '''嘗試各種格式,只能用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 are 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 if they are supported

    dim iindex as integer

    for iindex = 0 to 19

    getwaveformatfromindex(iindex, format)



    ' to test if a capture format is supported, try to create a

    ' new capture buffer using a specific format. if it works

    ' then 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 integer, byref format as waveformat)

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

    ' 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.samplespersecond

    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.samplespersecond.tostring() + " hz, " + format.bitspersample.tostring() + "-bit " + iif(format.channels = 1, "mono", "stereo")

    end function 'convertwaveformattostring

    sub 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 = inputformatsupported(iindex) then

    ' turn the index into a waveformat then 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 that 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 shbytespersample 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.samplespersecond)

    writer.write(inputformat.averagebytespersecond)

    writer.write(shbytespersample)

    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 then

    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 sizes

    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 then

    throw new argumentnullexception

    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 autoresetevent(false)

    end if



    ' setup the notification positions

    dim i as integer

    for i = 0 to numberrecordnotifications - 1

    positionnotify(i).offset = notifysize * i + 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

    ' 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.length

    nextcaptureoffset = nextcaptureoffset mod capturebuffersize ' circular buffer

    end sub 'recordcaptureddata



    private sub listbox2_selectedindexchanged(byval sender as system.object, byval e as system.eventargs) handles listbox2.selectedindexchanged

    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 startrecording 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 then

    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(byval sender as system.object, byval e as system.eventargs) handles button1.click

    createriff()

    startorstoprecord(true)



    end sub



    private sub button2_click(byval sender as system.object, 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.setcooperativelevel(me, cooperativelevel.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 sender as object, byval e as system.componentmodel.canceleventargs) handles mybase.closing

    if not nothing is notificationevent then

    notificationevent.set()

    end if

    if not nothing is applicationbuffer then

    if applicationbuffer.capturing then

    startorstoprecord(false)

    end if

    end if

    end

    end sub 'mainform_closing



    end class



    =======================================
    ok directsound最后的部分寫完了.總體感覺微軟的封裝還是有道理的

    既要體現出易用性,而且還要充分發揮硬件的能力.如果你覺得某些特性用不到(很多其實都用不到)

    你可以自己在directsound的基礎上制作自己的聲效引擎方便自己使用.

    現在也存在不少優秀的聲效引擎(在模擬器里面經常見到),至于是否自己開發,就要看你的興趣了

    如果您對directsound感興趣,可以來我的blog或者留言版發表看法.

    http://blog.csdn.net/a11s

    下一個目標,托管的directplay
    (可能跟dsound中間插入ddraw一樣,dplay的時候順便搞定dinput)

    ==========end directsound 9==================



    發表評論 共有條評論
    用戶名: 密碼:
    驗證碼: 匿名發表
    主站蜘蛛池模板: 兰考县| 吉安县| 尼勒克县| 南靖县| 淳化县| 泾阳县| 平利县| 石台县| 平顺县| 攀枝花市| 扬州市| 神木县| 土默特右旗| 江川县| 黄骅市| 新干县| 绥棱县| 本溪| 灵台县| 怀集县| 土默特右旗| 崇礼县| 长葛市| 和林格尔县| 监利县| 奈曼旗| 额敏县| 徐水县| 嫩江县| 闽清县| 简阳市| 武定县| 遵义县| 康平县| 芷江| 湘潭县| 鹰潭市| 河西区| 邓州市| 京山县| 苍山县|