Skip to content

Instantly share code, notes, and snippets.

@Oldes
Created September 14, 2015 14:23
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Oldes/2ead960c4134a9799b0a to your computer and use it in GitHub Desktop.
Save Oldes/2ead960c4134a9799b0a to your computer and use it in GitHub Desktop.
Experimental WAV file parser
Red/System [
Title: "Red/System stream-io test - WAV reader"
Author: "Oldes"
]
#define handle! [pointer! [integer!]]
#define GENERIC_WRITE 40000000h
#define GENERIC_READ 80000000h
#define FILE_SHARE_READ 00000001h
#define FILE_SHARE_WRITE 00000002h
#define OPEN_ALWAYS 00000004h
#define OPEN_EXISTING 00000003h
#define CREATE_ALWAYS 00000002h
#define FILE_ATTRIBUTE_NORMAL 00000080h
#define FILE_ATTRIBUTE_DIRECTORY 00000010h
#import [
"kernel32.dll" stdcall [
CreateFileA: "CreateFileA" [ ;-- temporary needed by Red/System
filename [c-string!]
access [integer!]
share [integer!]
security [int-ptr!]
disposition [integer!]
flags [integer!]
template [int-ptr!]
return: [handle!]
]
ReadFile: "ReadFile" [
file [handle!]
buffer [byte-ptr!]
bytes [integer!]
read [int-ptr!]
overlapped [int-ptr!]
return: [integer!]
]
CloseHandle: "CloseHandle" [
obj [handle!]
return: [integer!]
]
GetFileSize: "GetFileSize" [
file [handle!]
FileSizeHigh [int-ptr!] ;A pointer to the variable where the high-order doubleword of the file size is returned. This parameter can be NULL if the application does not require the high-order doubleword.
return: [integer!]
]
]
]
#define ID_RIFF 46464952h
#define ID_WAVE 45564157h
#define ID_WAVE_FMT 20746D66h
#define ID_WAVE_DATA 61746164h
#define ID_WAVE_CUE 20657563h
#define ID_WAVE_LIST 5453494Ch
io: context [
port: as handle! 0
buffer: as byte-ptr! 0
buffer-head: as byte-ptr! 0
buffer-tail: as byte-ptr! 0
buffer-size: 0
open: func[
filename [c-string!]
/local
read-sz [integer!]
res [integer!]
][
port: CreateFileA filename GENERIC_READ FILE_SHARE_READ NULL OPEN_EXISTING FILE_ATTRIBUTE_NORMAL null
buffer-size: GetFileSize port null
buffer: allocate buffer-size
buffer-tail: buffer + buffer-size
read-sz: -1
res: ReadFile port buffer buffer-size :read-sz null
buffer-head: buffer
]
close: does [
CloseHandle port
free buffer
buffer: as byte-ptr! 0
buffer-head: as byte-ptr! 0
buffer-tail: as byte-ptr! 0
buffer-size: 0
]
readUI16: func[
return: [integer!]
][
buffer: buffer + 2
(as integer! buffer/-1) + ((as integer! buffer/0) << 8)
]
readUI32: func[
return: [integer!]
/local ptr [pointer! [integer!]]
][
ptr: as pointer! [integer!] buffer
buffer: buffer + 4
ptr/1
]
tail?: func[return: [logic!]][buffer >= buffer-tail]
seek-to-RIFF: func[
return: [logic!]
][
while [buffer < buffer-tail][
if ID_RIFF = readUI32 [
print-line "RIFF"
return true
]
]
false
]
parse-WAV: func[
return: [logic!]
/local
id [integer!]
size [integer!]
compression [integer!]
channels [integer!]
sampleRate [integer!]
bytesPerSec [integer!]
blockAlign [integer!]
bitsPerSample [integer!]
][
if not seek-to-RIFF [
print-line "RIFF not found"
return false
]
size: readUI32
id: readUI32
if ID_WAVE <> id [
print-line "WAV not found"
return false
]
while [buffer < (buffer-tail - 8)][
id: readUI32
size: readUI32
assert buffer-tail >= (buffer + size) ;-- security check
switch id [
ID_WAVE_FMT [
print-line "fmt"
compression: readUI16
channels: readUI16
sampleRate: readUI32
bytesPerSec: readUI32
blockAlign: readUI16
bitsPerSample: readUI16
buffer: buffer + size - 16 ;skip extra bytes
print-line ["channels: " channels " sampleRate: " sampleRate " bytesPerSec: " bytesPerSec " blockAlign: " blockAlign " bitsPerSample: " bitsPerSample]
]
ID_WAVE_DATA [
print-line "DATA"
print-line ["samples:" size / (bitsPerSample / 8)]
buffer: buffer + size
]
ID_WAVE_LIST [
print-line "LIST"
buffer: buffer + size
]
ID_WAVE_CUE [
print-line "cue"
buffer: buffer + size
]
default [
buffer: buffer + size
]
]
]
true
]
]
io/open "test.wav"
io/parse-WAV
io/close
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment