Skip to content

Commit f8a430b

Browse files
Add wave playback example
1 parent 9c87c93 commit f8a430b

File tree

3 files changed

+170
-0
lines changed

3 files changed

+170
-0
lines changed

examples/WaveFileReader.php

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
<?php
2+
/**
3+
* WaveFileReader; a simple class to read/parse WAVE file
4+
* (c)2012 Rob Janssen / https://github.com/RobThree
5+
*
6+
* Based on https://ccrma.stanford.edu/courses/422/projects/WaveFormat/
7+
*
8+
* USAGE:
9+
*
10+
* $wav = WaveFileReader::ReadFile('/path/to/test.wav');
11+
* var_dump($wav);
12+
* var_dump(WaveFileReader::GetAudioFormat($wav['subchunk1']['audioformat']));
13+
*/
14+
class WaveFileReader {
15+
16+
private static $HEADER_LENGTH = 44; //Header size is fixed
17+
18+
/**
19+
* ReadFile reads the headers (and optionally the data) from a wave file
20+
*
21+
* @param string $filename The wave file to read the header from
22+
* @param bool $readdata (OPTIONAL) Pass TRUE to read the actual audio data from the file; defaults to FALSE
23+
*
24+
* @return mixed Information parsed from the file; FALSE when file doesn't exists or not readable
25+
*/
26+
public static function ReadFile($filename, $readdata = false) {
27+
//Make sure file is readable and exists
28+
if (is_readable($filename)) {
29+
$filesize = filesize($filename);
30+
31+
//Make sure filesize is sane; e.g. at least the headers should be able to fit in it
32+
if ($filesize<self::$HEADER_LENGTH)
33+
return false;
34+
35+
//Read the header and stuff all info in an array
36+
$handle = fopen($filename, 'rb');
37+
$wav = array(
38+
'header' => array(
39+
'chunkid' => self::readString($handle, 4),
40+
'chunksize' => self::readLong($handle),
41+
'format' => self::readString($handle, 4)
42+
),
43+
'subchunk1' => array(
44+
'id' => self::readString($handle, 4),
45+
'size' => self::readLong($handle),
46+
'audioformat' => self::readWord($handle),
47+
'numchannels' => self::readWord($handle),
48+
'samplerate' => self::readLong($handle),
49+
'byterate' => self::readLong($handle),
50+
'blockalign' => self::readWord($handle),
51+
'bitspersample' => self::readWord($handle)
52+
),
53+
'subchunk2' => array(
54+
'id' => self::readString($handle, 4),
55+
'size' => self::readLong($handle),
56+
'data' => null
57+
)
58+
);
59+
60+
//Do we need to read the data and, if so, does the specified size in subchunk2 match the actual size?
61+
if ($readdata && ($filesize - self::$HEADER_LENGTH) == $wav['subchunk2']['size'])
62+
$wav['subchunk2']['data'] = fread($handle, $filesize - self::$HEADER_LENGTH);
63+
64+
//...aaaaand we're done!
65+
fclose($handle);
66+
return $wav;
67+
}
68+
//File is not readable or doesn't exist
69+
return false;
70+
}
71+
72+
/**
73+
* Returns a string representation of an audioformat "id"
74+
*
75+
* @param int $audiofmtid The audioformat "id" to get the string representation of
76+
*
77+
* @return string The audioformat as a string (e.g. "PCM", "ALAW", "ULAW", ...), NULL when an
78+
* unknown audioformat "id" is passed
79+
*/
80+
public static function GetAudioFormat($audiofmtid) {
81+
switch($audiofmtid) {
82+
case 1:
83+
return 'PCM';
84+
case 6:
85+
return 'ALAW';
86+
case 7:
87+
return 'ULAW';
88+
default:
89+
return null;
90+
}
91+
}
92+
93+
/**
94+
* Reads a string from the specified file handle
95+
*
96+
* @param int $handle The filehandle to read the string from
97+
* @param int $length The number of bytes to read
98+
*
99+
* @return string The string read from the file
100+
*/
101+
private static function readString($handle, $length) {
102+
return self::readUnpacked($handle, 'a*', $length);
103+
}
104+
105+
/**
106+
* Reads a 32bit unsigned integer from the specified file handle
107+
*
108+
* @param int $handle The filehandle to read the 32bit unsigned integer from
109+
*
110+
* @return int The 32bit unsigned integer read from the file
111+
*/
112+
private static function readLong($handle) {
113+
return self::readUnpacked($handle, 'V', 4);
114+
}
115+
116+
/**
117+
* Reads a 16bit unsigned integer from the specified file handle
118+
*
119+
* @param int $handle The filehandle to read the 16bit unsigned integer from
120+
*
121+
* @return int The 16bit unsigned integer read from the file
122+
*/
123+
private static function readWord($handle) {
124+
return self::readUnpacked($handle, 'v', 2);
125+
}
126+
127+
/**
128+
* Reads the specified number of bytes from a specified file handle and unpacks it accoring to the specified type
129+
*
130+
* @param int $handle The filehandle to read the data from
131+
* @param int $type The type of data being read (see PHP's Pack() documentation)
132+
* @param int $length The number of bytes to read
133+
*
134+
* @return mixed The unpacked data read from the file
135+
*/
136+
private static function readUnpacked($handle, $type, $length) {
137+
$r = unpack($type, fread($handle, $length));
138+
return array_pop($r);
139+
}
140+
}

examples/example.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php declare(strict_types=1);
2+
3+
dl('openal.so');
4+
5+
require 'WaveFileReader.php';
6+
7+
// https://freesound.org/people/Ironi%20Alef/sounds/32226/
8+
$wave = WaveFileReader::ReadFile('sound.wav', true);
9+
$waveData = $wave['subchunk2']['data'];
10+
$waveSampleRate = $wave['subchunk1']['samplerate'];
11+
$waveLength = ceil(strlen($waveData) / ($waveSampleRate * $wave['subchunk1']['numchannels'] * $wave['subchunk1']['bitspersample'] /8));
12+
13+
$device = openal_device_open();
14+
$context = openal_context_create($device);
15+
openal_context_current($context);
16+
17+
$source = openal_source_create();
18+
$buffer = openal_buffer_create();
19+
openal_buffer_data($buffer, AL_FORMAT_STEREO16, $waveData, $waveSampleRate);
20+
21+
openal_source_set($source, AL_BUFFER, $buffer);
22+
openal_source_set($source, AL_LOOPING, true);
23+
24+
openal_source_play($source);
25+
sleep((int)$waveLength);
26+
openal_source_stop($source);
27+
28+
openal_context_destroy($context);
29+
openal_device_close($device);
30+

examples/sound.wav

6.34 MB
Binary file not shown.

0 commit comments

Comments
 (0)