python-schdoc/altium_crap/Soft Designs/Audio/NB3000 Audio Service/Embedded/wave.c

300 lines
8.2 KiB
C

/*****************************************************************************\
|*
|* VERSION CONTROL: $Version$ $Date$
|*
|* IN PACKAGE:
|*
|* COPYRIGHT: Copyright (c) 2007, Altium
|*
|* DESCRIPTION:
|*
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <audio.h>
#include "wave.h"
static uint8_t wavbuf[4096];
#define WAV_RIFF 0x46464952 // "RIFF"
#define WAV_WAVE 0x45564157 // "WAVE"
#define WAV_FMT 0x20746D66 // "fmt "
#define WAV_DATA 0x61746164 // "data"
// copied from util_endian.h in the software platform
/*
* Functions to convert from a little endian entity to host format or vice versa
*/
inline uint16_t little16( uint16_t val )
{
#ifdef __BIG_ENDIAN__
return (val << 8) | (val >> 8);
#else
return val;
#endif
}
inline uint32_t little32( uint32_t val )
{
#ifdef __BIG_ENDIAN__
return (( (uint32_t)little16( (uint16_t)val )) << 16 ) | ( (uint32_t)little16( val >> 16 ));
#else
return val;
#endif
}
/*
* Functions to read a little endian value from an 8-bit aligned address
*/
inline uint8_t read_little8from8( const void * ptr )
{
return *(uint8_t *)ptr;
}
inline uint16_t read_little16from8( const void * ptr )
{
return read_little8from8( ptr ) | ( (uint16_t)read_little8from8( (uint8_t *)ptr+1 ) << 8 );
}
inline uint32_t read_little32from8( const void * ptr )
{
return read_little16from8( ptr ) | ( (uint32_t)read_little16from8( (uint8_t *)ptr+2 ) << 16 );
}
// fix up endianness and play buffer through the audio service
static void decode_and_play( audio_t * restrict audio, wav_header_t info, void *buffer, unsigned size )
{
uint8_t * buf8;
uint16_t * buf16;
uint32_t * buf32;
unsigned i;
if ( info.samplesize == 8 )
{
buf8 = buffer;
for( i = 0; i < size; i++ )
{
// Convert sample to signed int
buf8[i] = (((int)buf8[i]) - 0x80) & 0xFF;
}
while( size )
{
i = audio_play( audio, buf8, size );
buf8 += i;
size -= i;
}
}
else if ( info.samplesize == 16 )
{
size /= 2;
buf16 = (uint16_t*)buffer;
for( i = 0; i < size; i++ )
{
// Convert to native endianess. Do we need to convert from unsigned to signed?
buf16[i] = little16( buf16[i] );
}
while( size )
{
i = audio_play( audio, buf16, size );
buf16 += i;
size -= i;
}
}
else if ( info.samplesize == 32 )
{
size /= 4;
buf32 = (uint32_t*)buffer;
for( i = 0; i < size; i++ )
{
// Convert to native endianess. Do we need to convert from unsigned to signed?
buf32[i] = little32( buf32[i] );
}
while( size )
{
i = audio_play( audio, buf32, size );
buf32 += i;
size -= i;
}
}
}
/**********************************************************************
|*
|* FUNCTION : wav_playfile
|*
|* PARAMETERS : info = wave file information structure
|* filename = name of file to be played
|*
|* RETURNS : None
|*
|* DESCRIPTION : Play a wav file using the generic audio service
*/
void wav_playfile( audio_t * audio, wav_header_t info, uintptr_t bufstart, uintptr_t bufend )
{
uint32_t chunksize;
uint32_t chunktype;
uint32_t bufsize;
uint32_t minsize;
audio_set_format( audio, info.samplerate, info.channels, info.samplesize );
bufsize = bufend - bufstart;
minsize = 3 * sizeof(uint32_t); // size of header
if ( bufsize < minsize ) return;
if ( read_little32from8( (void*)bufstart ) == WAV_RIFF && read_little32from8( (void*)(bufstart + 8) ) == WAV_WAVE )
{
bufstart += minsize;
bufsize -= minsize;
minsize = 2 * sizeof(uint32_t); // size of chunk
while (bufstart < bufend)
{
if ( bufsize < minsize ) break;
chunktype = read_little32from8( (void*)bufstart );
chunksize = read_little32from8( (void*)(bufstart + 4) );
bufstart += minsize;
bufsize -= minsize;
if ( chunktype == WAV_DATA )
{
printf( "Playing %d samples...", chunksize * 8 / info.samplesize );
while( sizeof( wavbuf ) < chunksize )
{
if ( bufsize < sizeof( wavbuf ) ) break;
if ( memcpy( wavbuf, (void*)bufstart, sizeof( wavbuf ) ) == NULL ) break;
bufstart += sizeof( wavbuf );
bufsize -= sizeof( wavbuf );
decode_and_play( audio, info, wavbuf, sizeof( wavbuf ) );
chunksize -= sizeof( wavbuf );
}
if ( chunksize )
{
if ( bufsize < chunksize ) break;
if ( memcpy( wavbuf, (void*)bufstart, chunksize ) == NULL ) break;
bufstart += chunksize;
bufsize -= chunksize;
decode_and_play( audio, info, wavbuf, chunksize );
}
puts( "done" );
}
else
{
bufstart += chunksize;
bufsize -= chunksize;
}
}
}
}
/**********************************************************************
|*
|* FUNCTION : wav_parseheader
|*
|* PARAMETERS : filename = name of file to be checked
|*
|* RETURNS : WAVE information
|*
|* DESCRIPTION : Get WAVE information of said file
*/
extern wav_header_t wav_parseheader( uintptr_t bufstart, uintptr_t bufend )
{
wav_header_t wavinfo = { 0 } ;
uint32_t chunksize;
uint32_t chunktype;
uint32_t bufsize;
uint32_t minsize;
bufsize = 1 + bufend - bufstart;
minsize = 3 * sizeof(uint32_t); // // uint32_t hdr[3]
if ( bufsize < minsize ) return wavinfo;
if ( read_little32from8( (void*)bufstart ) == WAV_RIFF && read_little32from8( (void*)(bufstart + 8) ) == WAV_WAVE )
{
wavinfo.playtime = read_little32from8( (void*)(bufstart + 4) );
bufstart += minsize;
bufsize -= minsize;
minsize = 2 * sizeof(uint32_t); // uint32_t chunk[2]
while (bufstart < bufend)
{
if ( bufsize < minsize ) break;
chunktype = read_little32from8( (void*)bufstart );
chunksize = read_little32from8( (void*)(bufstart + 4) );
bufstart += minsize;
bufsize -= minsize;
if ( chunktype == WAV_FMT )
{
minsize = 7 * sizeof(uint16_t); // uint16_t fmt[7]
if ( bufsize < minsize ) break;
wavinfo.format = read_little16from8( (void*)(bufstart + 0) ); // fmt[0]
wavinfo.channels = read_little16from8( (void*)(bufstart + 2) ); // fmt[1]
wavinfo.samplerate = (uint16_t)read_little32from8( (void*)(bufstart + 4) ); // fmt[2]
wavinfo.samplesize = read_little16from8( (void*)(bufstart + 12) ) * 8 / wavinfo.channels; // fmt[6]
break;
}
else
{
bufstart += chunksize;
bufsize -= chunksize;
}
}
}
if ( wavinfo.channels && wavinfo.samplerate && wavinfo.samplesize )
{
wavinfo.playtime /= wavinfo.channels * wavinfo.samplerate * wavinfo.samplesize / 8;
}
else
{
wavinfo.playtime = 0;
}
return wavinfo;
}
/**********************************************************************
|*
|* FUNCTION : wav_testsupported
|*
|* PARAMETERS : header = wave file information structure
|*
|* RETURNS : False if not supported, true otherwise
|*
|* DESCRIPTION : Check if this is a file we support (PCM encoded WAV, mono or stereo, 8 or 16 bits per sample only)
*/
bool wav_testsupported( wav_header_t header )
{
bool supported = true;
if ( header.format != WAVE_FORMAT_PCM ) supported = false;
if ( header.channels != 1 && header.channels != 2 ) supported = false;
if ( header.samplesize != 8 && header.samplesize != 16 ) supported = false;
return supported;
}