monoceres Posted September 7, 2008 Share Posted September 7, 2008 (edited) Hi all! Here's an example on how to read a wav file and playing the uncompressed PCM audio data inside it. I did some heavy commenting so it should be easy to understand it. expandcollapse popup#include <WINAPI.au3> ; Just a dummy variable I need for WINAPI_ReadFile Global $NULL ; Path to file that is going to be read Global $path = "C:\alive.wav" ; Just the three constants I'm using Global Const $WAVE_MAPPER = 4294967295 Global Const $WAVE_FORMAT_PCM = 0x01 Global Const $WHDR_BEGINLOOP = 0x04 Global $winmm = DllOpen("winmm.dll") Global $WaveDevice Global $Data; A struct that will contain all the raw audio data ; WAVEFORMATEX ; Used to open a wavedevice ; http://msdn.microsoft.com/en-us/library/ms713497(VS.85).aspx Global $WAVEFORMATEX = DllStructCreate("ushort wFormatTag;ushort nChannels;dword nSamplesPerSec;" & _ "dword nAvgBytesPerSec;ushort nBlockAlign;ushort wBitsPerSample;" & _ "ushort cbSize") ; WAVE_HEADER ; The header data that is read from the wav file ; Info found here: http://ccrma.stanford.edu/courses/422/projects/WaveFormat/ Global $WAVE_HEADER = DllStructCreate("char ChunkID[4];int ChunkSize;char Format[4];char Subchunk1ID[4];" & _ "int Subchunk1Size;short AudioFormat;short NumChannels;int SampleRate;" & _ "int ByteRate;short BlockAlign;short BitsPerSample;char Subchunk2ID[4];" & _ "int Subchunk2Size") ; WAVE_HDR ; Struct that contains the pointer to the raw audio data, which is sent to waveOutWrite ; http://msdn.microsoft.com/en-us/library/ms713724(VS.85).aspx Global $WAVE_HDR = DllStructCreate("ptr lpData;dword dwBufferLength;dword dwBytesRecorded;uint dwUser;" & _ "dword dwFlags;dword dwLoops;ptr lpNext;uint reserved") ; Open the file in read mode $fhandle = _WinAPI_CreateFile($path, 2, 2, 2) _WinAPI_ReadFile($fhandle, DllStructGetPtr($WAVE_HEADER, "ChunkID"), 4, $NULL) _WinAPI_ReadFile($fhandle, DllStructGetPtr($WAVE_HEADER, "ChunkSize"), 4, $NULL) _WinAPI_ReadFile($fhandle, DllStructGetPtr($WAVE_HEADER, "Format"), 4, $NULL) _WinAPI_ReadFile($fhandle, DllStructGetPtr($WAVE_HEADER, "Subchunk1ID"), 4, $NULL) _WinAPI_ReadFile($fhandle, DllStructGetPtr($WAVE_HEADER, "Subchunk1Size"), 4, $NULL) _WinAPI_ReadFile($fhandle, DllStructGetPtr($WAVE_HEADER, "AudioFormat"), 2, $NULL) _WinAPI_ReadFile($fhandle, DllStructGetPtr($WAVE_HEADER, "NumChannels"), 2, $NULL) _WinAPI_ReadFile($fhandle, DllStructGetPtr($WAVE_HEADER, "SampleRate"), 4, $NULL) _WinAPI_ReadFile($fhandle, DllStructGetPtr($WAVE_HEADER, "ByteRate"), 4, $NULL) _WinAPI_ReadFile($fhandle, DllStructGetPtr($WAVE_HEADER, "BlockAlign"), 2, $NULL) _WinAPI_ReadFile($fhandle, DllStructGetPtr($WAVE_HEADER, "BitsPerSample"), 2, $NULL) _WinAPI_ReadFile($fhandle, DllStructGetPtr($WAVE_HEADER, "Subchunk2ID"), 4, $NULL) _WinAPI_ReadFile($fhandle, DllStructGetPtr($WAVE_HEADER, "Subchunk2Size"), 4, $NULL) ; Before we read the heavy stuff, lets check if the data is what we expect If Not (DllStructGetData($WAVE_HEADER, "Format") == "WAVE") Then; All wav files should have the Format set to WAVE MsgBox(16, "Error", "This is not a valid wav file!" & @CRLF & "Script will terminate") Exit ElseIf DllStructGetData($WAVE_HEADER, "AudioFormat") <> 1 Then; 1 means PCM (raw audio data) which is the only thing supported MsgBox(16, "Error", "This is wav file is compressed, only uncompressed files are supported" & @CRLF & "Script will terminate") Exit ElseIf DllStructGetData($WAVE_HEADER, "BitsPerSample") <> 16 Then; THis script only deals with 16 bits, not difficult to fix though MsgBox(16, "Error", "This is wav file is has not a sample size of 16 bits, only 16 bits files are supported" & @CRLF & "Script will terminate") Exit EndIf ; Create the buffer for the raw audio data ; Since this implemenetion is made for 16 bit wav files each sample is 16 bit (2 bytes) thus each element is a short. ; Amount of samples is calculated with the total size of the raw audio data divided by the size of each sample $Data = DllStructCreate("ushort [" & DllStructGetData($WAVE_HEADER, "Subchunk2Size") / 2 & "]") _WinAPI_ReadFile($fhandle, DllStructGetPtr($Data), DllStructGetData($WAVE_HEADER, "Subchunk2Size"), $NULL) ; No more reading, the entire file is in memory! _WinAPI_CloseHandle($fhandle) ; Fill the WAVEFORMATEX structure, fortunetly the members are just like the ones we just read into memory ; Sometimes microsoft do make things easy;) DllStructSetData($WAVEFORMATEX, "wFormatTag", $WAVE_FORMAT_PCM) DllStructSetData($WAVEFORMATEX, "nChannels", DllStructGetData($WAVE_HEADER, "NumChannels")) DllStructSetData($WAVEFORMATEX, "nSamplesPerSec", DllStructGetData($WAVE_HEADER, "SampleRate")) DllStructSetData($WAVEFORMATEX, "nAvgBytesperSec", DllStructGetData($WAVE_HEADER, "ByteRate")) DllStructSetData($WAVEFORMATEX, "nBlockAlign", DllStructGetData($WAVE_HEADER, "BlockAlign")) DllStructSetData($WAVEFORMATEX, "wBitsPerSample", DllStructGetData($WAVE_HEADER, "BitsPerSample")) DllStructSetData($WAVEFORMATEX, "cbSize", 0) ; Opens the default wave out device ; The ingored parameters are for callbacks ; http://msdn.microsoft.com/en-us/library/ms713754(VS.85).aspx $call = DllCall($winmm, "int", "waveOutOpen", "ptr*", "", "uint", $WAVE_MAPPER, "ptr", DllStructGetPtr($WAVEFORMATEX), "ulong", 0, "ulong", 0, "dword", 0) $WaveDevice = $call[1] ; Fill the WAVE_HDR structure with the pointer to the raw audio and some playback info DllStructSetData($WAVE_HDR, "lpData", DllStructGetPtr($Data)) DllStructSetData($WAVE_HDR, "dwBufferLength", DllStructGetData($WAVE_HEADER, "Subchunk2Size")) DllStructSetData($WAVE_HDR, "dwFlags", $WHDR_BEGINLOOP) DllStructSetData($WAVE_HDR, "dwLoops", 1) ; Prepare the header for playback ; http://msdn.microsoft.com/en-us/library/ms713756(VS.85).aspx $call = DllCall($winmm, "int", "waveOutPrepareHeader", "ptr", $WaveDevice, "ptr", DllStructGetPtr($WAVE_HDR), "uint", DllStructGetSize($WAVE_HDR)) ; The moment has arrived, tme for p(l)ayback! ; This function is asynchronous so it returns as soon as playback has started ; http://msdn.microsoft.com/en-us/library/ms713764(VS.85).aspx DllCall($winmm, "int", "waveOutWrite", "ptr", $WaveDevice, "ptr", DllStructGetPtr($WAVE_HDR), "uint", DllStructGetSize($WAVE_HDR)) MsgBox(64, "Info", "Wav file is playing!" & @CRLF & "Press OK when you wish to stop playback") To get the playback position you need to use the waveOutGetPosition function, but it involves using a struct in a union which is in another struct and I didn't feel like going into that tonight. However said autoit was easier than c++ was wrong Edited September 7, 2008 by monoceres Broken link? PM me and I'll send you the file! Link to comment Share on other sites More sharing options...
ProgAndy Posted September 7, 2008 Share Posted September 7, 2008 So, this is a func which creates a struct from a union (AutoIt doesn't support unions, so you have to work-around... ) Global Const $TIME_BYTES = 0x4 Global Const $TIME_MIDI = 0x10 Global Const $TIME_MS = 0x1 Global Const $TIME_SAMPLES = 0x2 Global Const $TIME_SMPTE = 0x8 Global Const $TIME_TICKS = 0x20 ; Prog@ndy Func _Create_mmtime_tag_Ex($ptr) Local $type = DllStructCreate("uint",$ptr) Switch DllStructGetData($type,1) Case $TIME_MS Return DllStructCreate("UINT wType; DWORD ms",$ptr) Case $TIME_SAMPLES Return DllStructCreate("UINT wType; DWORD sample",$ptr) Case $TIME_BYTES Return DllStructCreate("UINT wType; DWORD cb",$ptr) Case $TIME_TICKS Return DllStructCreate("UINT wType; DWORD ticks",$ptr) Case $TIME_SMPTE Return DllStructCreate("UINT wType; BYTE hour; BYTE min; BYTE sec; BYTE frame; BYTE fps; BYTE dummy; BYTE pad[2]",$ptr) Case $TIME_MIDI Return DllStructCreate("UINT wType; DWORD midi",$ptr) EndSwitch Return SetError(1,0,0) EndFunc *GERMAN* [note: you are not allowed to remove author / modified info from my UDFs]My UDFs:[_SetImageBinaryToCtrl] [_TaskDialog] [AutoItObject] [Animated GIF (GDI+)] [ClipPut for Image] [FreeImage] [GDI32 UDFs] [GDIPlus Progressbar] [Hotkey-Selector] [Multiline Inputbox] [MySQL without ODBC] [RichEdit UDFs] [SpeechAPI Example] [WinHTTP]UDFs included in AutoIt: FTP_Ex (as FTPEx), _WinAPI_SetLayeredWindowAttributes Link to comment Share on other sites More sharing options...
Loz Posted January 30, 2011 Share Posted January 30, 2011 $Data = DllStructCreate("ushort [" & DllStructGetData($WAVE_HEADER, "Subchunk2Size") / 2 & "]") Throws an "Error Allocating Memory" popup on the above line. This is for a small 30K wave file. DllStructGetData($WAVE_HEADER, "Subchunk2Size") returns 1992319348. Something not right there. ver 3.3.6.1 here Any ideas? .... GOTOs? We don't need no stinkin' GOTOs! .... Link to comment Share on other sites More sharing options...
Moderators Melba23 Posted January 30, 2011 Moderators Share Posted January 30, 2011 cits,This is a very old topic. Take a look at the _Sound_* functions - they will play .wav files with a lot less fuss! M23 Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind Open spoiler to see my UDFs: Spoiler ArrayMultiColSort ---- Sort arrays on multiple columnsChooseFileFolder ---- Single and multiple selections from specified path treeview listingDate_Time_Convert -- Easily convert date/time formats, including the language usedExtMsgBox --------- A highly customisable replacement for MsgBoxGUIExtender -------- Extend and retract multiple sections within a GUIGUIFrame ---------- Subdivide GUIs into many adjustable framesGUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView itemsGUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeViewMarquee ----------- Scrolling tickertape GUIsNoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxesNotify ------------- Small notifications on the edge of the displayScrollbars ----------Automatically sized scrollbars with a single commandStringSize ---------- Automatically size controls to fit textToast -------------- Small GUIs which pop out of the notification area Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now