mmio
Strumienie audio
Każdy odtwarzany plik dźwiękowy
musi być przekazywany do strumienia audio. Taki strumień ma swój adres. Plik
jest częściowo ładowany do buforu znajdującego się w pamięci w obrębie
danego strumienia. W miarę dalszego odtwarzania ładowane są następne części
pliku.
Za pomocą VB możemy odtwarzać pliki dźwiękowe za pomocą sndPlaySound w
Windows 32 API, lub innych zewnętrznych bibliotek. Funkcja API nie odgrywa
tylko dźwięk i nie zezwala na żadną inną operację typu zatrzymania czy
zmiany pozycji. Takie operacje są jednak przewidziane w funkcjach obsługi
strumienia audio. Co więcej funkcje te pozwalają na dużo więcej. Często
widziałem (na grupach dyskusyjnych itp.), że ktoś chciałby zrobić widmo dźwięku.
Te funkcje i procedury pozwalają na to, choć jest to proces bardzo
skomplikowany.
Do takich operacji potrzebne nam jest Windows API, tym razem użyjemy funkcji
zawartych w winmm.dll. Ich nazwy zaczynają się od mmio. Muszę na początku
powiedzieć, że deklaracje w API Viewer nie są kompatybilne. Chociaż są
prawidłowe, to jedynie z punktu widzenia składni. VB nie może przekazywać
danych strukturalnych jako wskaźnik o wartości 0, ale zawsze adresu jakiejś
zmiennej, co powoduje, że pewne operacje działałyby błędnie.
Musiałem więc zmienić pewne deklaracje, aby można było przekazać pewne
parametry jako wskaźniki o wartości 0.
Architektura plików multimedialnych
Każdy plik multimedialny Windows typu RIFF (Wave, AVI) składa się z
sekcji zwanych po angielsku Chunk (w skrócie ck). Nazwa sekcji ma zawsze długość
4 znaków ('RIFF','fmt ','data') i przekazywana jest jako zmienna typu long. W
prawdzie (w rozumieniu C++) jest to oddzielny typ zmiennej Four Character Char
FOURCC. I rzeczywiście, konwersja BSTR na FOURCC opiera się na operacjach
logiczno/bitowych w tym także przy pomocy funkcji shr, shl lub operatorów
<< i >>. Pomimo tego, że istnieje funkcja mmioStringToFOURCC
przekształcająca BSTR na FOURCC to ja i tak napisałem własną funkcję
MAKEFOURCC. Pomysł ten podsunął mi plik nagłówkowy VC++ w którym funkcja
ta była przedstawiona (w krótszym zapisie niż w VB, bo w VB trzeba tworzyć
funkcje równe z shr, shl).
Niestety, do widma dźwięku jeszcze nie doszedłem i niestety prawdopodobnie
nie dojdę, bo wywołanie niektórych funkcji powoduje krytyczny błąd. Poniżej
przedstawię jak pobrać informacje o pliku Wave, wbrew pozorom nie jest to
zadanie takie proste jak to się by mogło wydawać.
W module:
Public Declare Function mmioOpen Lib
"winmm.dll" Alias "mmioOpenA" (ByVal
szFileName As String, ByRef lpmmioinfo As
MMIOINFO, ByVal dwOpenFlags As Long) As Long
Public Declare Function mmioClose Lib "winmm.dll" (ByVal
hmmio As Long, ByVal uFlags As Long) As Long
Public Declare Function mmioDescend Lib "winmm.dll" (ByVal
hmmio As Long, ByRef lpck As Any, ByRef
lpckParent As Any, ByVal uFlags As Long) As Long
Public Declare Function mmioStringToFOURCC Lib "winmm.dll" Alias
"mmioStringToFOURCCA" (ByVal sz As String, ByVal
uFlags As Long) As Long
Public Declare Function mmioRead Lib "winmm.dll" (ByVal
hmmio As Long, ByRef pch As Any, ByVal
cch As Long) As Long
Public Declare Function mmioAscend Lib "winmm.dll" (ByVal
hmmio As Long, ByRef lpck As
MMCKINFO, ByVal uFlags As Long) As Long
Public Type MMCKINFO
ckid As Long
ckSize As Long
fccType As Long
dwDataOffset As Long
dwFlags As Long
End Type
Public Type MMIOINFO
dwFlags As Long
fccIOProc As Long
pIOProc As Long
wErrorRet As Long
htask As Long
cchBuffer As Long
pchBuffer As String
pchNext As String
pchEndRead As String
pchEndWrite As String
lBufOffset As Long
lDiskOffset As Long
adwInfo(4) As Long
dwReserved1 As Long
dwReserved2 As Long
hmmio As Long
End Type
Public Type WAVEFORMAT
wFormatTag As Integer
nChannels As Integer
nSamplesPerSec As Long
nAvgBytesPerSec As Long
nBlockAlign As Integer
End Type
Public Type PCMWAVEFORMAT
wf As WAVEFORMAT
wBitsPerSample As Integer
End Type
Public Const MMIO_ALLOCBUF = &H10000
Public Const MMIO_COMPAT = &H0
Public Const MMIO_CREATE = &H1000
Public Const MMIO_CREATELIST = &H40
Public Const MMIO_CREATERIFF = &H20
Public Const MMIO_DEFAULTBUFFER = 8192
Public Const MMIO_DELETE = &H200
Public Const MMIO_DENYNONE = &H40
Public Const MMIO_DENYREAD = &H30
Public Const MMIO_DENYWRITE = &H20
Public Const MMIO_DIRTY = &H10000000
Public Const MMIO_EMPTYBUF = &H10
Public Const MMIO_EXCLUSIVE = &H10
Public Const MMIO_EXIST = &H4000
Public Const MMIO_FHOPEN = &H10
Public Const MMIO_FINDCHUNK = &H10
Public Const MMIO_FINDLIST = &H40
Public Const MMIO_FINDPROC = &H40000
Public Const MMIO_FINDRIFF = &H20
Public Const MMIO_GETTEMP = &H20000
Public Const MMIO_INSTALLPROC = &H10000
Public Const MMIO_OPEN_VALID = &H3FFFF
Public Const MMIO_PARSE = &H100
Public Const MMIO_PUBLICPROC = &H10000000
Public Const MMIO_READ = &H0
Public Const MMIO_READWRITE = &H2
Public Const MMIO_REMOVEPROC = &H20000
Public Const MMIO_RWMODE = &H3
Public Const MMIO_SHAREMODE = &H70
Public Const MMIO_TOUPPER = &H10
Public Const MMIO_UNICODEPROC = &H1000000
Public Const MMIO_VALIDPROC = &H11070000
Public Const MMIO_WRITE = &H1
Public Function LShift(ByVal lThis As
Long, ByVal lBits As
Long) As Long
If (lBits <= 0)
Then
'bledny parametr ...
LShift = lThis
ElseIf (lBits > 31)
Then
'bledny parametr ...
LShift = 0
Else
If (lThis
And (2 ^ (31 - lBits))) = (2 ^ (31 - lBits)) Then
LShift = (lThis
And (2 ^ (31 - lBits) - 1)) * (2 ^ lBits) Or &H80000000
Else
LShift = (lThis
And (2 ^ (31 - lBits) - 1)) * (2 ^ lBits)
End If
End If
End Function
Public Function RShift(ByVal lThis
As Long, ByVal lBits
As Long) As Long
If (lBits <= 0)
Then
'bledny parametr ...
RShift = lThis
ElseIf (lBits > 31)
Then
'bledny parametr ...
RShift = 0
Else
If (lThis
And &H80000000) = &H80000000 Then
RShift = (lThis
And &H7FFFFFFF) \ (2 ^ lBits) Or (2 ^ (31 - lBits))
Else
RShift = lThis \ (2 ^ lBits)
End If
End If
End Function
Function MAKEFOURCC(ch0, ch1, ch2, ch3)
MAKEFOURCC = Asc(ch0) Or LShift(Asc(ch1), 8)
Or LShift(Asc(ch2), 16) Or LShift(Asc(ch3), 24)
End Function
W Form_Load:
Private Sub Form_Load()
Show
' przykładowa aplikacja operująca na plikach WAVE
Dim hmmioBuff As Long
'// bufor strumienia
Dim hmmioinfo As MMIOINFO
'// info
Dim RIFFchunk As MMCKINFO
'// RIFF chunk info (informacje o początkowym ck)
Dim Chunk As MMCKINFO
'// chunk info (tutaj będziemy ładować poszczególne ck)
Dim lRet As Long '// zmienna przyjmująca wartości zwrócone
Dim MyWaveFormat As PCMWAVEFORMAT '// kontekst zmiennej Chunk
Const File = "C:\WINDOWS\MEDIA\ding.wav"
' Teraz ładujemy plik do buforu hmmioBuff, z zezwoleniem na alokowanie buforu i na
' czytanie
hmmioBuff = mmioOpen(File, hmmioinfo, MMIO_ALLOCBUF Or MMIO_READ)
' pobieramy początkowe informacje o pliku do RIFFchunk
lRet = mmioDescend(hmmioBuff, RIFFchunk, 0, MMIO_READ)
' sprawdzamy, czy plik jest typy RIFF WAVE
' gdyby funkcje API deklarowane byłyby tak jak w API Viewer, to poniższy kod
' poinformowałby nas o błędzie.
' spowodowane jest to tym, że nie można przekazać w mmioDescend jako nadrzędny bufor
' wskaźnika = 0, ale należałoby podać jakąś zmienną, która ma wskaźnik i cały
' projekt legnie w gruzach!
If RIFFchunk.ckid <> MAKEFOURCC("R", "I", "F", "F")
_
Or RIFFchunk.fccType <> MAKEFOURCC("W", "A", "V", "E")
Then
MsgBox "Plik nie jest plikiem typu WAVE"
End
End If
' ckid - to chunk ID, identyfikuje się z "nagłówkiem" pliku,
' poprzez jego zmianę, możemy przenieść się do innego jego miejsca
' teraz poszukamy ckid o nazwie 'fmt ', i zapiszemy jego info do Chunk
RIFFchunk.ckid = MAKEFOURCC("f", "m", "t", " ")
lRet = mmioDescend(hmmioBuff, Chunk, RIFFchunk, MMIO_FINDCHUNK)
If lRet <> 0 Then
MsgBox "Plik ma niekompatybilny format (prawdopodobnie została użyta inna kompresja niż PCM)"
End
End If
If Chunk.ckSize < Len(MyWaveFormat) Then
MsgBox "Plik wydaje się być uszkodzony"
End
End If
' ładujemy informacje nagłówka 'fmt ' do MyWaveFormat
lRet = mmioRead(hmmioBuff, MyWaveFormat, Len(MyWaveFormat))
' sprawdzamy, czy nagłówek 'fmt ' jest zgodny z formatem PCM WAVE
If lRet <> Len(MyWaveFormat) Then
MsgBox "Plik wydaje się być uszkodzony"
End
End If
' prawdę mówiąc, nie wiem co robi poniższa użyta funkcja :)
lRet = mmioAscend(hmmioBuff, Chunk, 0)
If lRet <> 0 Then
MsgBox "Krytyczny błąd"
End
End If
' wyświetlamy informacje o pliku (niestety, nie wiem, czemu nie wyświetla próbkowania)
MsgBox "Informacje o pliku " & File & vbCrLf _
& "Format: PCM" & vbCrLf _
& "Ilość kanałów: " & MyWaveFormat.wf.nChannels & vbCrLf _
& "Próbkowanie: " & MyWaveFormat.wBitsPerSample & vbCrLf _
& "Bitów/sekundę: " & MyWaveFormat.wf.nAvgBytesPerSec & vbCrLf
_
& "Próbek/sekundę: " & MyWaveFormat.wf.nSamplesPerSec
' po zrobionej pracy zamykamy plik!
Call mmioClose(hmmioBuff, 0)
End Sub
Chociaż nie wyświetlana jest informacja
o próbkowaniu, to można to obliczyć dzieląc MyWaveFormat.wf.nSamplesPerSec
przez MyWaveFormat.wf.nAvgBytesPerSec.
Marcin Porębski ( Doogie )
marcin.porebski@interia.pl
Wyszukiwarka
Podobne podstrony:
11 (311)ZADANIE (11)Psychologia 27 11 2012359 11 (2)11PJU zagadnienia III WLS 10 11Wybrane przepisy IAAF 10 1106 11 09 (28)info Gios PDF Splitter And Merger 1 11więcej podobnych podstron