202 lines
5.9 KiB
C
202 lines
5.9 KiB
C
/*
|
|
* Copyright (c) 2012, 2013, Joel Bodenmann aka Tectu <joel@unormal.org>
|
|
* Copyright (c) 2012, 2013, Andrew Hannam aka inmarket
|
|
*
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* * Neither the name of the <organization> nor the
|
|
* names of its contributors may be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
/**
|
|
* This demo demonstrates the use of the GAUDOUT module to play a wave file.
|
|
*
|
|
*/
|
|
#include "gfx.h"
|
|
|
|
/* Specify our timing parameters */
|
|
#define MY_AUDIO_CHANNEL 0 /* Use channel 0 */
|
|
#define MY_AUDIO_CHANNEL_IS_STEREO GAUDOUT_CHANNEL0_IS_STEREO /* Is it stereo? */
|
|
|
|
// Storage for the wave header
|
|
static char whdr[32];
|
|
|
|
|
|
/*
|
|
* Application entry point.
|
|
*/
|
|
int main(void) {
|
|
gFont font;
|
|
GFILE *f;
|
|
char *errmsg;
|
|
gU32 toplay;
|
|
gU32 frequency;
|
|
ArrayDataFormat datafmt;
|
|
gU32 len;
|
|
GDataBuffer *pd;
|
|
|
|
// Initialise everything
|
|
gfxInit();
|
|
errmsg = 0;
|
|
|
|
// Any font will do
|
|
font = gdispOpenFont("*");
|
|
|
|
// Allocate audio buffers - 4 x 512 byte buffers.
|
|
// You may need to increase this for slower cpu's.
|
|
// You may be able to decrease this for low latency operating systems.
|
|
if (!gfxBufferAlloc(4, 512)) {
|
|
errmsg = "Err: No Memory";
|
|
goto theend;
|
|
}
|
|
|
|
repeatplay:
|
|
// Open the wave file
|
|
if (!(f = gfileOpen("allwrong.wav", "r"))) {
|
|
errmsg = "Err: Open WAV";
|
|
goto theend;
|
|
}
|
|
|
|
// Read the wave header
|
|
if (gfileRead(f, whdr, 20) != 20) {
|
|
errmsg = "Err: Read hdr";
|
|
goto theend;
|
|
}
|
|
|
|
// Check the wave header
|
|
if (whdr[0] != 'R' || whdr[1] != 'I' || whdr[2] != 'F' || whdr[3] != 'F' // RIFF label
|
|
|| whdr[8] != 'W' || whdr[9] != 'A' || whdr[10] != 'V' || whdr[11] != 'E' // WAVE label
|
|
|| whdr[12] != 'f' || whdr[13] != 'm' || whdr[14] != 't' || whdr[15] != ' ' // fmt label
|
|
) {
|
|
errmsg = "Err: Bad header";
|
|
goto theend;
|
|
}
|
|
|
|
// Read the fmt block
|
|
len = (((gU32)(gU8)whdr[16])<<0) | (((gU32)(gU8)whdr[17])<<8)
|
|
| (((gU32)(gU8)whdr[18])<<16) | (((gU32)(gU8)whdr[19])<<24);
|
|
if (len > sizeof(whdr) || len < 16) {
|
|
errmsg = "Err: Bad fmt len";
|
|
goto theend;
|
|
}
|
|
if (gfileRead(f, whdr, len) != len) {
|
|
errmsg = "Err: Read fmt block";
|
|
goto theend;
|
|
}
|
|
if (whdr[0] != 1 || whdr[1] != 0 // PCM format
|
|
|| (whdr[14] != 8 && whdr[14] != 16) || whdr[15] != 0 // 8 or 16 bits per sample
|
|
) {
|
|
errmsg = "Err: Bad fmt block";
|
|
goto theend;
|
|
}
|
|
|
|
// Check stereo/mono
|
|
#if MY_AUDIO_CHANNEL_IS_STEREO
|
|
if (whdr[2] != 2 || whdr[3] != 0) {
|
|
errmsg = "Err: Not stereo";
|
|
goto theend;
|
|
}
|
|
#else
|
|
if (whdr[2] != 1 || whdr[3] != 0) {
|
|
errmsg = "Err: Not mono";
|
|
goto theend;
|
|
}
|
|
#endif
|
|
|
|
// Get the sample frequency (little endian format) and format
|
|
frequency = (((gU32)(gU8)whdr[4])<<0) | (((gU32)(gU8)whdr[5])<<8)
|
|
| (((gU32)(gU8)whdr[6])<<16) | (((gU32)(gU8)whdr[7])<<24);
|
|
datafmt = whdr[14] == 8 ? ARRAY_DATA_8BITUNSIGNED : ARRAY_DATA_16BITSIGNED;
|
|
|
|
// Initialise the audio output device
|
|
if (!gaudioPlayInit(MY_AUDIO_CHANNEL, frequency, datafmt)) {
|
|
// For this demo we don't try and do any format conversions if the driver won't accept
|
|
// what we initially request.
|
|
errmsg = "Err: Bad format/freq";
|
|
goto theend;
|
|
}
|
|
|
|
// Get our current file position
|
|
len += 20;
|
|
|
|
// Read RIFF blocks until we get to the data RIFF block (contains the audio)
|
|
while(1) {
|
|
if (gfileRead(f, whdr, 8) != 8) {
|
|
errmsg = "Err: Read block";
|
|
goto theend;
|
|
}
|
|
|
|
// Get the block length (little endian format)
|
|
toplay = (((gU32)(gU8)whdr[4])<<0) | (((gU32)(gU8)whdr[5])<<8)
|
|
| (((gU32)(gU8)whdr[6])<<16) | (((gU32)(gU8)whdr[7])<<24);
|
|
|
|
// Stop scanning when this is a data block
|
|
if (whdr[0] == 'd' && whdr[1] == 'a' && whdr[2] == 't' && whdr[3] == 'a')
|
|
break;
|
|
|
|
// Seek to the next block header
|
|
len += toplay + 8;
|
|
if (!gfileSetPos(f, len)) {
|
|
errmsg = "Err: No data";
|
|
goto theend;
|
|
}
|
|
}
|
|
|
|
// Play the file
|
|
gdispDrawString(0, gdispGetHeight()/2, "Playing...", font, GFX_YELLOW);
|
|
while(toplay) {
|
|
// Get a buffer to put the data into
|
|
pd = gfxBufferGet(gDelayForever); // This should never fail as we are waiting forever
|
|
|
|
// How much data can we put in
|
|
len = toplay > pd->size ? pd->size : toplay;
|
|
pd->len = len;
|
|
toplay -= len;
|
|
|
|
// Read the data
|
|
if (gfileRead(f, pd+1, len) != len) {
|
|
errmsg = "Err: Read fail";
|
|
goto theend;
|
|
}
|
|
|
|
gaudioPlay(pd);
|
|
}
|
|
gfileClose(f);
|
|
|
|
// Wait for the play to finish
|
|
gaudioPlayWait(gDelayForever);
|
|
gdispDrawString(0, gdispGetHeight()/2+10, "Done", font, GFX_GREEN);
|
|
|
|
// Repeat the whole thing
|
|
gfxSleepMilliseconds(1500);
|
|
gdispClear(GFX_BLACK);
|
|
goto repeatplay;
|
|
|
|
// The end
|
|
theend:
|
|
if (errmsg)
|
|
gdispDrawString(0, gdispGetHeight()/2, errmsg, font, GFX_RED);
|
|
|
|
while(1)
|
|
gfxSleepMilliseconds(1000);
|
|
}
|