DMA hangfelvétel mikrofonról.
2009-12-26T15:08:24+01:00
2009-12-30T14:43:46+01:00
2022-08-13T19:10:32+02:00
zoltánka
Szeretnék saját DOS-os programmal hangfelvételt készíteni pascalban vagy assembly-ben (tasm,nasm) úgy hogy a hangkártyát DMA átvitellel akarom programozni.

Bizonyos mértékben értek a DMA-hoz: Tudok 8 bites mono wav file-t lejátszani auto-init DMA-val pascal-ban is és assembly-ben (com file) is.
Mindezt pusztán úgy, hogy portokra küldök ki számokat, így vezérlem a DMA-t és a DSP-t. Átirányítom a megszakítást, a megszakítási rutinban pedig olvasok a file-ból a lefoglalt buffer egyik felébe (felváltva). Ez működik.

A hangkártya bázisportcíme: 220h, a DMA1-es csatornát és az IRQ5-ös megszakítást használja.
Ezeket az environment-ből tudom.
A DSP verziószáma: 2.1. Lekérdeztem a DSP 0e1h utasításával

Ugyanezzel a módszerrel próbálkozom a felvétellel is, de nem akar működni. A megszakítás se kerül sorra, a memóriában sem jelenik meg semmi.

A lényeg az, hogy akárhogyan is, de valahogy megjelenjenek a memóriában a bemenő hangminta (pl.mikrofon) bájtjai, hogy közvetlenül fel tudjam dolgozni.

Írtam egy olyan progit, melynek, ha megadom egy wav file nevét, akkor egy saját FFT algoritmussal megjeleníti a hang spektrumát.
Jelenleg mikrofonról csak az audacity nevű programmal tudok felvenni, csakhogy az file-ba menti a hangot. Roppant kényelmetlen így dolgozni. Az a jó, ha elindítok egy saját programot, bemondok valamit a mikrofonba, és élőben látom a spektrumot.

Már az is elég lenne, ha a DSP 20h-s utasítására lenne egy működő példaprogim.
Ez az ún. közvetlen felvétel. Szóval utasításokkal egyenként olvassuk a hang bájtjait.
Kipróbáltam, nem működik így a lejátszás (DSP 10h) sem, pedig ez egyszerűbb.

Megjegyzés: Valahol olvastam, hogy felvételnél be lehet állítani, hogy honnan akarunk felvenni.
Pl. mikrofon, CD, LineIn. (224h,225h mixer porton keresztül a 0ch regiszter)
De csak az SB Pro-s hangkariknak van olyan. Érdekes, hogy a Windows Media Player le tudja játszani a 16 bites sztereo hangokat, holott a 2.1-es hangkártyának csak 8 bites mono-s utasításai vannak.
Kicsit értek a winapi-hoz is. Az masm32-t tudom használni.

A lényeg, hogy kérek valamilyen forráskódot tasm-ben,nasm-ben,nasmide-ben,vagy pascal-ban.
Ha windowsos, akkor masm32-ben (XP windows), mleyet, ha lefordítok, működik, és kedvemre módosíthatok, bővíthetek.
Egy ilyen őröult célom van, hogy betűket szeretnék a spektromon felismerni, aztán konkrét szavakat, stb. Tudom, soha nem lesz ebből eladható program, csak hobbiból csinálom.
Mutasd a teljes hozzászólást!
A baj még az, hogy több fájlban vannak a rutinok és nem 1-2 oldalas, de neked csak a felvétel memóriában érdekel, hiszen azt írtad az FFT algoritmus már megírtad csak fájlba menti.

Szóval, ha leírom, hogy kell WIN32-ben hangot memóriába menteni, akkor megnézhetem a kis projected FFT részét, mert érdekelne!

Ha nem adsz e-mail címet, akkor a bináris EXE fájlt azért feltöltöm valamilyen oldalra, hogy ilyesmire gondolsz-e.

Akkor kezdődjék a lecke:

Felvételnél (recording) a waveInxxx API hívásokkal lehet hanganyagot memóriába menteni. Mielőtt nekikezdenél a winmm.inc-et és a winmm.lib a szövegbe kell fűznöd, vagyis:

include %PATH%\winmm.inc
includelib %PATH%\winmm.lib


A függvények hívási sorrendje a következő:

1.waveInOpen
Hangkártya "megnyitása"

2.waveInPrepareHeader
A memóriapuffer előkészítése(használj double bufferinget!), ami annyit tesz, hogy amíg az egyik memtartományt analizálod a másikba vesz és fordítva.

3.waveInAddBuffer
A membuffer device-drivernek átadása. Double-buffering miatt 2x

4.waveInStart
A hangfelvétel kezdete

5.waveInUnprepareHeader
A memtartományok "elengedése", "felszabadítása"

6.waveInClose
Az eszöz lezárása

ezeken kívül még van a:
waveInStop, ami értelemszerűen lestoppolja a felvételt.
waveInReset, ez meg reseteli.

És akkor most lássuk a paramétereker:

waveInOpen(LPHWAVEIN phwi,
UINT_PTR uDeviceID,
LPWAVEFORMATEX pwfx,
DWORD_PTR dwCallback,
DWORD_PTR dwCallbackInstance,
DWORD fdwOpen

phwi:egy mutató, egy handle-re amit majd az összes waveInxxx függvénnyel kell haszálnod, akácsak a filehandle fájlok írásánál/olvasásánál.

uDeviceID:egy konstans: WAVE_MAPPER

pwfx:megintcsak egy mutató, ami egy WAVEFORMATEX structurára mutat.

dwCallback:itt többféleképpen lehet megoldani. Kettőt mondok:
1.egy mutató egy Callback rutinra vagy
2.Az ablak(window) handle-je (inkább ezt válaszd, mert én is így csináltam és nem volt problémám)

dwCallbackInstance:Felhasználó által használt érték, ami az előbbi 1 módnál működik.

fdwOpen:megnyitási mód, értékei az említett módhoz:
1.CALLBACK_FUNCTION
2.CALLBACK_WINDOW (én ezt magyarázom el)

-------------------------------------------------

waveInPrepareHeader(HWAVEIN hwi,
LPWAVEHDR pwh,
UINT cbwh

hwi:a handle, amit az Opennél első paraméter volt

pwh:mutató, egy WAVEHDR structra

cbwh: sizeof(WAVEHDR)

-------------------------------------------------

waveInAddBuffer(HWAVEIN hwi,
LPWAVEHDR pwh,
UINT cbwh

hwi:szokásos handle

pwh:mutató a WAVEHDR structra

cbwh:sizeof(WAVEHDR)

-------------------------------------------

invoke waveInStart, HWAVEIN hwi

hwi:ismét a handle

-------------------------------------------

waveInUnprepareHeader(HWAVEIN hwi,
LPWAVEHDR pwh,
UINT cbwh

hwi: már nem is írom
pwh:mutató egy WAVEHDR structra
cbwh:ezt se írom már

--------------------------------------------

invoke waveInClose, hwi

kész vagy, kilépés a programból.

-----------------------------------------------

de előtte még

invoke waveInStop, hwi

ami lestoppolja a felvételt

==============================================

Most akkor a structurákat írom:
Bocs, h csak így angolul beillesztem, de így legalább nem hagyok ki semmi fontosat, ha valami nem érthető kérdezz rá.

typedef struct {
WORD wFormatTag;
WORD nChannels;
DWORD nSamplesPerSec;
DWORD nAvgBytesPerSec;
WORD nBlockAlign;
WORD wBitsPerSample;
WORD cbSize;
} WAVEFORMATEX;

wFormatTag
Waveform-audio format type. Format tags are registered with Microsoft Corporation for many compression algorithms. A complete list of format tags can be found in the MMREG.H header file.
nChannels
Number of channels in the waveform-audio data. Monaural data uses one channel and stereo data uses two channels.
nSamplesPerSec
Sample rate, in samples per second (hertz), that each channel should be played or recorded. If wFormatTag is WAVE_FORMAT_PCM, then common values for nSamplesPerSec are 8.0 kHz, 11.025 kHz, 22.05 kHz, and 44.1 kHz. For non-PCM formats, this member must be computed according to the manufacturer's specification of the format tag.
nAvgBytesPerSec
Required average data-transfer rate, in bytes per second, for the format tag. If wFormatTag is WAVE_FORMAT_PCM, nAvgBytesPerSec should be equal to the product of nSamplesPerSec and nBlockAlign. For non-PCM formats, this member must be computed according to the manufacturer's specification of the format tag.
Playback and record software can estimate buffer sizes by using the nAvgBytesPerSec member.

nBlockAlign
Block alignment, in bytes. The block alignment is the minimum atomic unit of data for the wFormatTag format type. If wFormatTag is WAVE_FORMAT_PCM, nBlockAlign should be equal to the product of nChannels and wBitsPerSample divided by 8 (bits per byte). For non-PCM formats, this member must be computed according to the manufacturer's specification of the format tag.
Playback and record software must process a multiple of nBlockAlign bytes of data at a time. Data written and read from a device must always start at the beginning of a block. For example, it is illegal to start playback of PCM data in the middle of a sample (that is, on a non-block-aligned boundary).

wBitsPerSample
Bits per sample for the wFormatTag format type. If wFormatTag is WAVE_FORMAT_PCM, then wBitsPerSample should be equal to 8 or 16. For non-PCM formats, this member must be set according to the manufacturer's specification of the format tag. Note that some compression schemes cannot define a value for wBitsPerSample, so this member can be zero.
cbSize
Size, in bytes, of extra format information appended to the end of the WAVEFORMATEX structure. This information can be used by non-PCM formats to store extra attributes for the wFormatTag. If no extra information is required by the wFormatTag, this member must be set to zero. Note that for WAVE_FORMAT_PCM formats (and only WAVE_FORMAT_PCM formats), this member is ignored.

----------------------------
A WAVEHDR tartalmazza a double-bufferunk memóriacímét például.
Csak a lényeget írom. Itt két WAVEHDR structra lesz szükség!

wh1 WAVEHDR <?>
wh2 WAVEHDR <?>

wh1.lpData, offset ;
wh1.dwBufferLength;
wh1.dwBytesRecorded;
wh1.dwUser;
wh1.dwFlags;
wh1.dwLoops;

lpData
Pointer to the waveform buffer.
dwBufferLength
Length, in bytes, of the buffer.
dwBytesRecorded
When the header is used in input, this member specifies how much data is in the buffer.
dwUser
User data.
dwFlags
Flags supplying information about the buffer. The following values are defined:
WHDR_BEGINLOOP
This buffer is the first buffer in a loop. This flag is used only with output buffers.
WHDR_DONE
Set by the device driver to indicate that it is finished with the buffer and is returning it to the application.
WHDR_ENDLOOP
This buffer is the last buffer in a loop. This flag is used only with output buffers.
WHDR_INQUEUE
Set by Windows to indicate that the buffer is queued for playback.
WHDR_PREPARED
Set by Windows to indicate that the buffer has been prepared with the waveInPrepareHeader or waveOutPrepareHeader function.
dwLoops
Number of times to play the loop. This member is used only with output buffers.

===============================================

Jó, akkor most azt írom le, hogyan váltogatja a Device Driver a buffereket ill. hogy értesülsz(notify) erről.

Mint mondtam az Ablakod handle-jét add át mint paramétert, mert így 3 üzenetet(message) kaphatsz attól függően mi a helyzet.

WIM_OPEN
az eszköz megnyitva, máris hívhatod a xxxPrepareHeadert 2x, a 2 különböző bufferrel, utána pedig a xxxAddBufferrel elküldöd az eszözmeghajtónak.

WIM_CLOSE
az eszöz lezárva, vége.

és a legfontosabb
MM_WIM_DATA
wParam = (WPARAM) hInputDev ; ez a handle
lParam = (LONG) lpwvhdr ; mutató a hanganyaggal "feltöltött" bufferre, amit analizálsz, majd ismét a device drivernek elküldöd a xxxAddBuffer-rel. Lehet, hogy kell preparálni is ezt kikisérletezheted, de azt hiszem nem kell.


====================================================

Na, kb. egyelőre ennyi. Mondjuk, ha 8kHz-en veszel, akkor min. 20msec max. 50sec legyen a periódus, vagyis kb. 160-tól 400byte-os /buffer.

ludasm

u.i. biztos észrevetted, h c++-szal van keverve, mert a Platform SDK-ból néztem ki, de azért érthető, nem?
Mutasd a teljes hozzászólást!

  • Hello!

    Én DOS-ban nem nagyon tudok segíteni(már régen használtam, de ha erre van szükséged...:)

    Mindenképpen Windowst ajánlom inkább, van is pár példaprogramom assemblyben, C++-ban, elküldhetem.

    Microsoft-nál a Windows Multimediánál kell keresni, mégpedig a

    waveInxxx API hívásokat kell MASM32-ben hívogatnod.

    Egyelőre ennyi!
    Mutasd a teljes hozzászólást!
  • Úgy 5 éve, amikor foglalkoztam ilyenekkel, akkor szembekerültem én is ezzel. Ha a gépben nem eredeti SB kártya van, hanem a win által emulált SB, akkor valószínű felvétel nem fog menni. Csak annyira van emulálva, amennyire szükséges, ADLIBot el sem tudtam érni.

    DOSBox alatt nem tudom megy-e, akkoriban win98-at használtam, meg az MS-DOS-t ilyen kísérletezésre.

    Volt régen eredeti SB Live! kártyám 4 csatornás kimenettel, ezen nem kísérleteztem ilyenekkel, mert a mixert nem értem el. SB16-ig volt leírásom a mixerről, de úgy vettem észre, hogy nem érem el azokat a regisztereket, lehet hogy én bénáztam el valamit, de lehet nem volt kompatibilis. Viszont meglepett hogy volt ADLIB

    Összefoglalva:
    - eredeti kártya esetén mennie kéne valódi MS-DOS környezetben, windows alatt lehet hogy a rendszer bekavar.
    - ha nincs eredeti kártya, csak a win emulál SB-t, akkor valószínű csak lejátszásra van lehetőség
    - meg lehet próbálkozni DOSBoxban futtatni, hátha az "normális kártyát" emulál, mellesleg ott van Gravis Ultrasound is emulálva, azzal is lehet kísérletezni.
    - vagy ha nem muszáj a DOS, akkor meg windowsos API

    Forráskóddal sajnos nem szolgálhatok, mert rég foglalkoztam már ilyennel, nem akarok hülyeséget írni. Ajánlani tudom viszont Ezt a könyvet, de a neten is van sok jó leírás.

    szerk:
    A lejátszó lehet a fájlból 16 bites adatot kap 44kHz, de valószínű a kártya lekonvertálva kapja az adatot, ha nem képes a minőségre. Valamint ha nincs eredeti SB, akkor egy hiper- szuper kártyára is ráemulál egy SB Pro kártyát
    Mutasd a teljes hozzászólást!
  • Van példaprogramod asm-ben? Szuper! Légy szíves tedd fel ide!

    Milyen is legyen?
    - kell egy függvény, mellyel elindítom a felvételt, beállítom, hogy mikroforól akarok, továbbá mintavételfrekvencia beállítása... (megelégszem a 8 bites hanggal is, de jöhet 16 bites is)
    - fontos, hogy kapjak egy pointert (32 bites offsetcím), hogy honnan kezdődik a buffer, meg hogy mekkora
    - amikor megtelik a buffer, és újra az elejébe íródik, azt a pillanatot jó lenne érzékelni, ugyanígy a felénél is.
    - a végén kell egy függvény, amivel leállítom a felvételt

    Ennyi az egész. Mindenképpen kell a példaprogi, mert nemtom a függvények paraméterezését, meg hogy pontosan melyik waveIn-t kell használni. Jól jöhet valamilyen leírás is.

    Mutasd a teljes hozzászólást!
  • audi0002:
    Lehet, hogy nekem Windows-emulált hangkarim van.
    Végülis nem külön kártyán van, hanem egyben van az alaplappal, nem lehet kivenni.
    Lehet, hogy ettől függ. Na mindegy.
    Mutasd a teljes hozzászólást!
  • Hello!

    Ide nem lehet feltölteni fájlokat(vagy igen? akkor hogyan?), de ha egy e-mail címet megadsz elküldöm!

    Az msdn.microsoft.com oldalán a keresőbe írd be, hogy "waveIn" és kidob pár számodra fontos linket.Itt van egy:

    Recording and Playing Sound with the Waveform Audio Interface

    Ezen a weboldalon, van példa is, konstansok, flagek, leírás.

    ludasm
    Mutasd a teljes hozzászólást!
  • Filet nem lehet feltölteni, de ami a file-ban van, azt egyszerűen copy-paste fel lehet másolni.
    A leírást majd átnézem.
    Mutasd a teljes hozzászólást!
  • Nem tudom, hogy ez a link segít-e megoldani a problémát, de megnézzni érdemes!

    Üdv.
    Mutasd a teljes hozzászólást!
  • bocsi!!
    itt a link is!
    Programming the SoundBlaster 16 DSP
    Mutasd a teljes hozzászólást!
  • Arról esett szó, hogy jobb ha winapi-t használok, mivelhogy windows emulált kártyám van.
    Szóval nem portokon keresztül, eddig így próbálkoztam.
    Mutasd a teljes hozzászólást!
  • Volt mar itt par lehetoseg, mondok en is még párat:

    DirectSound - szvsz a legtokeletesebb, hangkartyatol fuggetlen cucc, ahol low latency elérheto.

    Bass - Ez directsound-ot hasznal, de sokkal egyszerubb az API-ja.

    KX Project - Ha SB-d van es fanatikus vagy :D akkor ez az a driver, amivel kihasznalhatsz mindent, amit a hangkartyad tud es szinten windows alatt. (Ossze vissza tudod routeolni a be es kimeneteket (az SndVol32.exe ehhez kepest egy nagyon specialis eset), irhatsz kis DSP asm programokat, amit az SB-ben levo DSP proci lefuttat, minden egyes samplére).

    Dos-ban emu chippel ugykodni iszonyat nehez lehet, mondjuk gyakorlasnak nagyon is jo lehet, de ugye hol talalsz rola info-t, amikor egy official drivert is kesz kinszenvedes talalni egy SB Live-hoz.

    mmSystem: a windos-os mmsystem waveXXXX api-val az a baj, hogy ott fel masodpercnel kisebb kesleltetest nehezkes elerni (4chn stereo 16bit 44khz-nel el lehet, de az playback), mert ott van egy minimum buffer meret korlat. Az nem nezne ki szepen, hogy hallod a zenet es a spektrum meg fel masodpercet kesik a hanghoz kepest.

    OpenAL: szinten low latency (sztem DSound-ra epul), hangkartyafuggetlen, de telepiteni kell.

    (Remelem nem kavartalak meg tulzottan, majd' minden cimszo google 1. talalat, szal' nem linkelgetek osszevissza)
    Mutasd a teljes hozzászólást!
  • Mindegy, hogy milyen driver-rel, például waveIn,SirectSound, mmSystem.., vagy akármi.
    Eddig szinte mindig DOS-os progikat írtam, windows-hoz kevésbé értek.

    Ezért nekem most egy konkrét példa kellene. Lehetőleg masm32-ben vagy nasm-ben.
    Fel kellene tenni egy forráskódot. Nem is muszáj egy kész működő programnak lennie.
    Így is el lehet magyarázni, hogy melyik lib-ben vagy dll-ben pontosan milyen függvényeket kell meghívni és milyen paraméterekkel. A paramétereknél pontosan tisztázni kell, hogy mi mit jelent.
    Fontos, hogy tudjam, hogy kapom meg a buffercímet, például valamelyik függvény visszatérési értékéből, vagy valamilyen struktúra egyik eleméből. Innentől kezdve fogok olvasgatni assembly utasításokkal.

    Most nem az a fontos, hogy felsoroljatok egy csomó driver-t, meg linkeket tegyetek fel mindenféle angol tutorokra, még nem vagyok winapiban ilyen gyakorlott. Azokat lehet, hogy később áttanulmányozom.
    De most csak egy konkrét példa kell, amit használni tudok. Lehetőleg minél kevesebb függvényhívással.
    Mutasd a teljes hozzászólást!
  • A baj még az, hogy több fájlban vannak a rutinok és nem 1-2 oldalas, de neked csak a felvétel memóriában érdekel, hiszen azt írtad az FFT algoritmus már megírtad csak fájlba menti.

    Szóval, ha leírom, hogy kell WIN32-ben hangot memóriába menteni, akkor megnézhetem a kis projected FFT részét, mert érdekelne!

    Ha nem adsz e-mail címet, akkor a bináris EXE fájlt azért feltöltöm valamilyen oldalra, hogy ilyesmire gondolsz-e.

    Akkor kezdődjék a lecke:

    Felvételnél (recording) a waveInxxx API hívásokkal lehet hanganyagot memóriába menteni. Mielőtt nekikezdenél a winmm.inc-et és a winmm.lib a szövegbe kell fűznöd, vagyis:

    include %PATH%\winmm.inc
    includelib %PATH%\winmm.lib


    A függvények hívási sorrendje a következő:

    1.waveInOpen
    Hangkártya "megnyitása"

    2.waveInPrepareHeader
    A memóriapuffer előkészítése(használj double bufferinget!), ami annyit tesz, hogy amíg az egyik memtartományt analizálod a másikba vesz és fordítva.

    3.waveInAddBuffer
    A membuffer device-drivernek átadása. Double-buffering miatt 2x

    4.waveInStart
    A hangfelvétel kezdete

    5.waveInUnprepareHeader
    A memtartományok "elengedése", "felszabadítása"

    6.waveInClose
    Az eszöz lezárása

    ezeken kívül még van a:
    waveInStop, ami értelemszerűen lestoppolja a felvételt.
    waveInReset, ez meg reseteli.

    És akkor most lássuk a paramétereker:

    waveInOpen(LPHWAVEIN phwi,
    UINT_PTR uDeviceID,
    LPWAVEFORMATEX pwfx,
    DWORD_PTR dwCallback,
    DWORD_PTR dwCallbackInstance,
    DWORD fdwOpen

    phwi:egy mutató, egy handle-re amit majd az összes waveInxxx függvénnyel kell haszálnod, akácsak a filehandle fájlok írásánál/olvasásánál.

    uDeviceID:egy konstans: WAVE_MAPPER

    pwfx:megintcsak egy mutató, ami egy WAVEFORMATEX structurára mutat.

    dwCallback:itt többféleképpen lehet megoldani. Kettőt mondok:
    1.egy mutató egy Callback rutinra vagy
    2.Az ablak(window) handle-je (inkább ezt válaszd, mert én is így csináltam és nem volt problémám)

    dwCallbackInstance:Felhasználó által használt érték, ami az előbbi 1 módnál működik.

    fdwOpen:megnyitási mód, értékei az említett módhoz:
    1.CALLBACK_FUNCTION
    2.CALLBACK_WINDOW (én ezt magyarázom el)

    -------------------------------------------------

    waveInPrepareHeader(HWAVEIN hwi,
    LPWAVEHDR pwh,
    UINT cbwh

    hwi:a handle, amit az Opennél első paraméter volt

    pwh:mutató, egy WAVEHDR structra

    cbwh: sizeof(WAVEHDR)

    -------------------------------------------------

    waveInAddBuffer(HWAVEIN hwi,
    LPWAVEHDR pwh,
    UINT cbwh

    hwi:szokásos handle

    pwh:mutató a WAVEHDR structra

    cbwh:sizeof(WAVEHDR)

    -------------------------------------------

    invoke waveInStart, HWAVEIN hwi

    hwi:ismét a handle

    -------------------------------------------

    waveInUnprepareHeader(HWAVEIN hwi,
    LPWAVEHDR pwh,
    UINT cbwh

    hwi: már nem is írom
    pwh:mutató egy WAVEHDR structra
    cbwh:ezt se írom már

    --------------------------------------------

    invoke waveInClose, hwi

    kész vagy, kilépés a programból.

    -----------------------------------------------

    de előtte még

    invoke waveInStop, hwi

    ami lestoppolja a felvételt

    ==============================================

    Most akkor a structurákat írom:
    Bocs, h csak így angolul beillesztem, de így legalább nem hagyok ki semmi fontosat, ha valami nem érthető kérdezz rá.

    typedef struct {
    WORD wFormatTag;
    WORD nChannels;
    DWORD nSamplesPerSec;
    DWORD nAvgBytesPerSec;
    WORD nBlockAlign;
    WORD wBitsPerSample;
    WORD cbSize;
    } WAVEFORMATEX;

    wFormatTag
    Waveform-audio format type. Format tags are registered with Microsoft Corporation for many compression algorithms. A complete list of format tags can be found in the MMREG.H header file.
    nChannels
    Number of channels in the waveform-audio data. Monaural data uses one channel and stereo data uses two channels.
    nSamplesPerSec
    Sample rate, in samples per second (hertz), that each channel should be played or recorded. If wFormatTag is WAVE_FORMAT_PCM, then common values for nSamplesPerSec are 8.0 kHz, 11.025 kHz, 22.05 kHz, and 44.1 kHz. For non-PCM formats, this member must be computed according to the manufacturer's specification of the format tag.
    nAvgBytesPerSec
    Required average data-transfer rate, in bytes per second, for the format tag. If wFormatTag is WAVE_FORMAT_PCM, nAvgBytesPerSec should be equal to the product of nSamplesPerSec and nBlockAlign. For non-PCM formats, this member must be computed according to the manufacturer's specification of the format tag.
    Playback and record software can estimate buffer sizes by using the nAvgBytesPerSec member.

    nBlockAlign
    Block alignment, in bytes. The block alignment is the minimum atomic unit of data for the wFormatTag format type. If wFormatTag is WAVE_FORMAT_PCM, nBlockAlign should be equal to the product of nChannels and wBitsPerSample divided by 8 (bits per byte). For non-PCM formats, this member must be computed according to the manufacturer's specification of the format tag.
    Playback and record software must process a multiple of nBlockAlign bytes of data at a time. Data written and read from a device must always start at the beginning of a block. For example, it is illegal to start playback of PCM data in the middle of a sample (that is, on a non-block-aligned boundary).

    wBitsPerSample
    Bits per sample for the wFormatTag format type. If wFormatTag is WAVE_FORMAT_PCM, then wBitsPerSample should be equal to 8 or 16. For non-PCM formats, this member must be set according to the manufacturer's specification of the format tag. Note that some compression schemes cannot define a value for wBitsPerSample, so this member can be zero.
    cbSize
    Size, in bytes, of extra format information appended to the end of the WAVEFORMATEX structure. This information can be used by non-PCM formats to store extra attributes for the wFormatTag. If no extra information is required by the wFormatTag, this member must be set to zero. Note that for WAVE_FORMAT_PCM formats (and only WAVE_FORMAT_PCM formats), this member is ignored.

    ----------------------------
    A WAVEHDR tartalmazza a double-bufferunk memóriacímét például.
    Csak a lényeget írom. Itt két WAVEHDR structra lesz szükség!

    wh1 WAVEHDR <?>
    wh2 WAVEHDR <?>

    wh1.lpData, offset ;
    wh1.dwBufferLength;
    wh1.dwBytesRecorded;
    wh1.dwUser;
    wh1.dwFlags;
    wh1.dwLoops;

    lpData
    Pointer to the waveform buffer.
    dwBufferLength
    Length, in bytes, of the buffer.
    dwBytesRecorded
    When the header is used in input, this member specifies how much data is in the buffer.
    dwUser
    User data.
    dwFlags
    Flags supplying information about the buffer. The following values are defined:
    WHDR_BEGINLOOP
    This buffer is the first buffer in a loop. This flag is used only with output buffers.
    WHDR_DONE
    Set by the device driver to indicate that it is finished with the buffer and is returning it to the application.
    WHDR_ENDLOOP
    This buffer is the last buffer in a loop. This flag is used only with output buffers.
    WHDR_INQUEUE
    Set by Windows to indicate that the buffer is queued for playback.
    WHDR_PREPARED
    Set by Windows to indicate that the buffer has been prepared with the waveInPrepareHeader or waveOutPrepareHeader function.
    dwLoops
    Number of times to play the loop. This member is used only with output buffers.

    ===============================================

    Jó, akkor most azt írom le, hogyan váltogatja a Device Driver a buffereket ill. hogy értesülsz(notify) erről.

    Mint mondtam az Ablakod handle-jét add át mint paramétert, mert így 3 üzenetet(message) kaphatsz attól függően mi a helyzet.

    WIM_OPEN
    az eszköz megnyitva, máris hívhatod a xxxPrepareHeadert 2x, a 2 különböző bufferrel, utána pedig a xxxAddBufferrel elküldöd az eszözmeghajtónak.

    WIM_CLOSE
    az eszöz lezárva, vége.

    és a legfontosabb
    MM_WIM_DATA
    wParam = (WPARAM) hInputDev ; ez a handle
    lParam = (LONG) lpwvhdr ; mutató a hanganyaggal "feltöltött" bufferre, amit analizálsz, majd ismét a device drivernek elküldöd a xxxAddBuffer-rel. Lehet, hogy kell preparálni is ezt kikisérletezheted, de azt hiszem nem kell.


    ====================================================

    Na, kb. egyelőre ennyi. Mondjuk, ha 8kHz-en veszel, akkor min. 20msec max. 50sec legyen a periódus, vagyis kb. 160-tól 400byte-os /buffer.

    ludasm

    u.i. biztos észrevetted, h c++-szal van keverve, mert a Platform SDK-ból néztem ki, de azért érthető, nem?
    Mutasd a teljes hozzászólást!
  • Ez szép!
    Bár kell egy kis idő, míg áttanulmányozom.
    Ha annyira kell az e-mail cím, inkább megadom:
    szkeptikus@citromail.hu

    Küldd el, légy szíves, a címre a forráskódot is!
    Majd ha megvan a címed, elküldöm az FFT progimat, meg leítom az elvét is.
    Ide a topicra azért nem teszem fel, mert eltérünk a témáról és kizárhatnak.

    Annyit azért mégis elmondok, hogy az ingalengés fizikai képletét használom fel.
    És koprocesszor-utasításokkal írtam meg, tisztán assembly-ben DOS alatt (egyszerű com file).
    Úgy műxik, hogy megadok egy wav-file nevét, és grafikusan megjelenik a spektrum (mozgókép).
    Csak még nincs szinkronizálva a sebesség. Szóval, lehet, hogy gyorsabb, vagy lassúbb.
    Mutasd a teljes hozzászólást!
  • Nagyon úgy néz ki, hogy ez működni fog.
    Megírtam a függvényhívásokat. Sok próbálkozással azért, de sikerült lefordítani.

    Ugyebár van ez az "MM_WIM_DATA" üzenet.
    Ennek az üzenetnek a lekezelésére nem írtam semmit, csak egy MessageBoxot (egyelőre). Csak meg akartam győződni, hogy egyáltalán megkapom-e az üzenetet. A MSGbox megjelent kétszer. Bár arra számítottam, hogy folyamatosan fognak megjelenni. De említettél valamit, hogy az üzenetkezelőben kell valami waveInAddBuffer.

    Az üzenet lparam-jában ugyanazt a pointert kapom, mint a kész buffer lpData-jában?
    Az üzenetkezelőben a xxxAddbufferrel ugyanarra a bufferre kell visszajelezni, mint amelyikre kaptuk az üzenetet?
    És ugyanolyan paraméterekkel?

    Megpróbáltam debuggerrel megnézni az lpData és dwBuffersize értékeket még a waveInStart előtt. Ami érdekes, mind nullák.

    Lehet,hogy hülye kérdés a buffermérettel kapcsolatban:
    whd1.dwBufferLength a buffer mérete. Ide nekem kell-e megadnom a méretet a függvényhívás előtt, vagy az oprendszer dönti el a méretet, és olvasnom kell meg ehhez alkalmazkodni?
    Ugyanez a kérdés a buffercímmel kapcsolatban: whd1.lpData.
    Egyáltalán melyik függvény írja/olvalssa ezt a két rekeszt, Preparebuffer vagy az Addbuffer?

    Ha majd tökéletesen működni fog, már csak azt kell ellenőriznem hogy tényleg megjelenik a hang a bufferben. Lesz is erre egy módszerem, mert ismerem a DirectDraw-ot. Az úgy működik, hogy kapok egy buffercímet, oda írogatok, és így fullscreen-ben lehet a pixelekkel cseszekedni. Majd aztán átmásolom a buffert és meglátjuk.
    Mutasd a teljes hozzászólást!
  • Na figyelj! Tovább kísérletezgetek.
    Az üzenetkezelőben a messabebox után hívogatom hívogatom a waveInAddBuffert. Eredmény: Most is 2 msgboxok van, de ráklikkelek valamelyikre, eltűnik, és újra megjelenik, szóval azt az xxxAddbuffert folyamatosan hivogatni kell.

    Egyvalami nem tetszik: A msgbox-ban megjelenítek néhány adatot hexadecimálisan, hogy nyomonkövethessem a progit. Szóval az üzenetküldés pillanatában:

    lparam: váltakozva: 00403000h és 00403100h ;ez a buffercím?
    viszont:
    wh1.lpData: 00000000h
    wh2.lpData: 00000000h
    wh1.dwBufferLength 00000000h
    wh2.dwBufferLength 00000000h

    Meg kell valahogy vitatni, hogy a WAVEHDR rekeszeit az oprendszer bemenetként vagy kimenetként használja.
    Mivelhogy nem jelenik meg semmi, tehát bemenetként.

    Próbálkozok bemenetként használni: pl. lefoglalok 2 buffert:
    buf1 db 512 dup(?)
    buf2 db 512 dup(?)
    mintdkét lpdata-ba megadom a bufferek offsetcímeit, meg a méretet,
    de az üzenetnél az lparam független ezektől, a változókban meg bennük maradt az érték, amit beírtam:
    lparam: 00403000h <-> 00403100h
    wh1.lpData: 00403100h
    wh2.lpData: 00403300h
    wh1.dwBufferLength 00000200h
    wh2.dwBufferLength 00000200h

    Érdekes, ugye? Egyelőre még nem néztem meg, mi van az adott buffercímen.
    Lehet, hogy valami egyszerű megoldás van, amit csak tisztázni kell.
    Mutasd a teljes hozzászólást!
  • Már jó úton jársz.

    wh1.lpData-ba az első, a wh2.lpData-ba a második buffer címét kell állítanod.
    ugyanígy a dwBufferLength az 1. és a 2. buffereid hossza, amit neked kell beállítanod.

    Mit állítottál be a WAVEFORMATEX-re?

    az MM_WIM_DATA message-nél persze h a cím és a hossz ugyanaz, csak "teletöltötte" adattal a device driver, és most a buffer ugyanezzel a címmel, hosszal újra kell küldened, ha nem akarsz fennakadást.

    ludasm
    Mutasd a teljes hozzászólást!
  • Működik. Most már, ahogy én akarom. Köszi az infókat. Tied a pont.

    Megemlítenék valamit:
    Találtam olyan példát is, mely ablak nélkül működik:
    invoke waveInOpen,addr whand,WAVE_MAPPER,addr w_f,0,0,CALLBACK_NULL or WAVE_FORMAT_DIRECT
    A többi ugyanaz. Lefoglaltam GlobalAlloc-kal 10 másodperc hosszú buffert, ezt adtam át.
    A buffer végét, úgy is lehet érzékelni, hogy figyelem a dwFlags megfelelő bitjét, mikor lesz DONE.
    Nem kell üzenetkezelés, de így kényelmetlen.
    Aztán a buffert file-ba mentettem (tettem elé fejlécet, hogy wav legyen), és kiléptem.
    Amikor elindítom, 10 s-ig veszi a hangot anélkül, hogy megjelenne valami, aztán megjelenik a file.
    A Windows Media Playerrel sikerült lejátszani.

    Persze maradok az ablakos módszernél.
    Csak azért említettem meg, mert írtad, hogy az ablak nélkülivel valami problémád van.
    Mutasd a teljes hozzászólást!

  • Na, de várjál. Ha a dwFlags-et figyelgeted(polling), akkor pár milisekundum kiesik az egyes buffereknél, az azért nem jó, ezért mondtam, h használj double-bufferinget.

    Ezek szerint mégis fájlba mentesz egy 10 mp-nyi hangot?

    Most már elküldöd nekem annak a DOS-os kis programnak a forrását?

    Mi a helyzet a küldött fáljaimmal? Hasznodra vált?

    ludasm
    Mutasd a teljes hozzászólást!
  • Én csak azért csináltam így, mert csak kipróbáltam. Így működött először. Először csak arról akartam meggyőződni, hogy egyáltalán megjelenik-e a hang a bufferben (egyszerűbb, mint a directdraw).
    Most már tudom használni a duplabuffert tökéletesen, kiesés nélkül. A kiesést úgy ellenőriztem, hogy egy tiszta szinuszos hangot vettem fel, és a file-ban néztem a görbe rajzolatát, nincs-e benne ugrás. Csak akkor volt, ha kicsi a buffer.

    Ezek után már nem fogom file-ba menteni.
    Az algoritmusomat meg majd átírom 32-bitesre, hogy windowsban is működjön.

    Rájöttem arra, hogy az lparam nem a buffer kezdőcímére, hanem
    a bufferhez tartozó headerre mutat.

    Nem tudsz véletlenül egy olyan függvénynevet, mellyel a programból állítani tudom a mikrofon érzékenységét?

    Azt hittem, elküldtem a progit, elküldöm mégegyszer.
    Mutasd a teljes hozzászólást!
abcd