You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
573 lines
20 KiB
C
573 lines
20 KiB
C
/*
|
|
* Musepack audio compression
|
|
* Copyright (c) 2005-2009, The Musepack Development Team
|
|
* Copyright (C) 1999-2004 Buschmann/Klemm/Piecha/Wolf
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
# include <string.h>
|
|
#include "mpcenc.h"
|
|
|
|
#ifdef _WIN32
|
|
|
|
static int
|
|
init_in ( const int SampleCount,
|
|
const int SampleFreq,
|
|
const int Channels,
|
|
const int BitsPerSample );
|
|
static size_t
|
|
get_in ( void* DataPtr );
|
|
|
|
#endif
|
|
|
|
#define EXT(x) (0 == strcasecmp (ext, #x))
|
|
|
|
int
|
|
Open_WAV_Header ( wave_t* type, const char* filename )
|
|
{
|
|
const char* ext = strrchr ( filename, '.');
|
|
FILE* fp;
|
|
|
|
type -> raw = 0;
|
|
|
|
if ( 0 == strcmp ( filename, "-") || 0 == strcmp ( filename, "/dev/stdin") ) {
|
|
fp = SETBINARY_IN ( stdin );
|
|
}
|
|
else if ( ext == NULL ) {
|
|
fp = NULL;
|
|
}
|
|
else if ( EXT(.wav) ) {
|
|
fp = fopen ( filename, "rb" );
|
|
}
|
|
else if ( EXT(.wv) ) { // wavpack (www.wavpack.com)
|
|
fp = pipeopen ( "wvunpack # -", filename );
|
|
}
|
|
else if ( EXT(.la) ) { // lossless-audio (www.lossless-audio.com)
|
|
fp = pipeopen ( "la -console #", filename );
|
|
}
|
|
else if ( EXT(.raw) || EXT(.cdr) || EXT(.pcm) ) {
|
|
fp = fopen ( filename, "rb" );
|
|
type->Channels = 2;
|
|
type->BitsPerSample = 16;
|
|
type->BytesPerSample = 2;
|
|
type->SampleFreq = 44100.;
|
|
type->raw = 1;
|
|
type->PCMOffset = 0;
|
|
type->PCMBytes = 0xFFFFFFFF;
|
|
type->PCMSamples = 86400 * type->SampleFreq;
|
|
}
|
|
else if ( EXT(.pac) || EXT(.lpac) || EXT(.lpa) ) {
|
|
fp = pipeopen ( "lpac -o -x #", filename );
|
|
}
|
|
else if ( EXT(.fla) || EXT(.flac) ) {
|
|
#ifdef _WIN32
|
|
stderr_printf ( "*** Install at least version 1.03 of FLAC.EXE. Thanks! ***\n\n" );
|
|
#endif
|
|
fp = pipeopen ( "flac -d -s -c - < #", filename );
|
|
}
|
|
else if ( EXT(.rka) || EXT(.rkau) ) {
|
|
fp = pipeopen ( "rkau # -", filename );
|
|
}
|
|
else if ( EXT(.sz) ) {
|
|
fp = pipeopen ( "szip -d < #", filename );
|
|
}
|
|
else if ( EXT(.sz2) ) {
|
|
fp = pipeopen ( "szip2 -d < #", filename );
|
|
}
|
|
else if ( EXT(.ofr) ) {
|
|
fp = pipeopen ( "optimfrog d # -", filename );
|
|
}
|
|
else if ( EXT(.ape) ) {
|
|
fp = pipeopen ( "mac # - -d", filename );
|
|
}
|
|
else if ( EXT(.shn) || EXT(.shorten) ) {
|
|
#ifdef _WIN32
|
|
stderr_printf ( "*** Install at least version 3.4 of Shorten.exe. Thanks! ***\n\n" );
|
|
#endif
|
|
fp = pipeopen ( "shorten -x # -", filename ); // Test if it's okay !!!!
|
|
if ( fp == NULL )
|
|
fp = pipeopen ( "shortn32 -x # -", filename );
|
|
}
|
|
else if ( EXT(.mod) ) {
|
|
fp = pipeopen ( "xmp -b16 -c -f44100 --stereo -o- #", filename );
|
|
type->Channels = 2;
|
|
type->BitsPerSample = 16;
|
|
type->BytesPerSample = 2;
|
|
type->SampleFreq = 44100.;
|
|
type->raw = 1;
|
|
type->PCMOffset = 0;
|
|
type->PCMBytes = 0xFFFFFFFF;
|
|
type->PCMSamples = 86400 * type->SampleFreq;
|
|
}
|
|
else {
|
|
fp = NULL;
|
|
}
|
|
|
|
type -> fp = fp;
|
|
return fp == NULL ? -1 : 0;
|
|
}
|
|
|
|
#undef EXT
|
|
|
|
|
|
static float f0 ( const void* p )
|
|
{
|
|
return (void)p, 0.;
|
|
}
|
|
|
|
static float f8 ( const void* p )
|
|
{
|
|
return (((unsigned char*)p)[0] - 128) * 256.;
|
|
}
|
|
|
|
static float f16 ( const void* p )
|
|
{
|
|
return ((unsigned char*)p)[0] + 256. * ((signed char*)p)[1];
|
|
}
|
|
|
|
static float f24 ( const void* p )
|
|
{
|
|
return ((unsigned char*)p)[0]*(1./256) + ((unsigned char*)p)[1] + 256 * ((signed char*)p)[2];
|
|
}
|
|
|
|
static float f32 ( const void* p )
|
|
{
|
|
return ((unsigned char*)p)[0]*(1./65536) + ((unsigned char*)p)[1]*(1./256) + ((unsigned char*)p)[2] + 256 * ((signed char*)p)[3];
|
|
}
|
|
|
|
|
|
typedef float (*rf_t) (const void*);
|
|
|
|
static int
|
|
DigitalSilence ( void* buffer, size_t len )
|
|
{
|
|
unsigned long* pl;
|
|
unsigned char* pc;
|
|
size_t loops;
|
|
|
|
for ( pl = buffer, loops = len >> 3; loops--; pl += 2 )
|
|
if ( pl[0] | pl[1] )
|
|
return 0;
|
|
|
|
for ( pc = (unsigned char*)pl, loops = len & 7; loops--; pc++ )
|
|
if ( pc[0] )
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
size_t
|
|
Read_WAV_Samples ( wave_t* t,
|
|
const size_t RequestedSamples,
|
|
PCMDataTyp* data,
|
|
const ptrdiff_t offset,
|
|
const float scalel,
|
|
const float scaler,
|
|
int* Silence )
|
|
{
|
|
static const rf_t rf [5] = { f0, f8, f16, f24, f32 };
|
|
short Buffer [8 * 32/16 * BLOCK]; // read buffer, up to 8 channels, up to 32 bit
|
|
size_t ReadSamples; // returns number of read samples
|
|
size_t i;
|
|
short* b = (short*) Buffer;
|
|
char* c = (char*) Buffer;
|
|
float* l = data -> L + offset;
|
|
float* r = data -> R + offset;
|
|
float* m = data -> M + offset;
|
|
float* s = data -> S + offset;
|
|
|
|
// Read PCM data
|
|
#ifdef _WIN32
|
|
if ( t->fp != (FILE*)-1 ) {
|
|
ReadSamples = fread ( b, t->BytesPerSample * t->Channels, RequestedSamples, t->fp );
|
|
}
|
|
else {
|
|
while (1) {
|
|
ReadSamples = get_in (b) / ( t->Channels * t->BytesPerSample );
|
|
if ( ReadSamples != 0 )
|
|
break;
|
|
Sleep (10);
|
|
}
|
|
}
|
|
#else
|
|
ReadSamples = fread ( b, t->BytesPerSample * t->Channels, RequestedSamples, t->fp );
|
|
#endif
|
|
|
|
|
|
*Silence = DigitalSilence ( b, ReadSamples * t->BytesPerSample * t->Channels );
|
|
|
|
// Add Null Samples if EOF is reached
|
|
if ( ReadSamples != RequestedSamples )
|
|
//memset ( b + ReadSamples * t->Channels, 0, (RequestedSamples - ReadSamples) * (sizeof(short) * t->Channels) );
|
|
memset ( c + ReadSamples * t->Channels * t->BytesPerSample, t->BytesPerSample == 1 ? 0x80 : 0, (RequestedSamples - ReadSamples) * (t->BytesPerSample * t->Channels) );
|
|
|
|
// Convert to float and calculate M=(L+R)/2 and S=(L-R)/2 signals
|
|
#ifndef MPC_BIG_ENDIAN
|
|
if ( t->BytesPerSample == 2 ) {
|
|
switch ( t->Channels ) {
|
|
case 1:
|
|
for ( i = 0; i < RequestedSamples; i++, b++ ) {
|
|
float temp = b[0] * scalel;
|
|
l[i] = temp + MPPENC_DENORMAL_FIX_LEFT;
|
|
r[i] = temp + MPPENC_DENORMAL_FIX_RIGHT;
|
|
m[i] = (l[i] + r[i]) * 0.5f;
|
|
s[i] = (l[i] - r[i]) * 0.5f;
|
|
}
|
|
break;
|
|
case 2:
|
|
for ( i = 0; i < RequestedSamples; i++, b += 2 ) {
|
|
l[i] = b[0] * scalel + MPPENC_DENORMAL_FIX_LEFT; // left
|
|
r[i] = b[1] * scaler + MPPENC_DENORMAL_FIX_RIGHT; // right
|
|
m[i] = (l[i] + r[i]) * 0.5f;
|
|
s[i] = (l[i] - r[i]) * 0.5f;
|
|
}
|
|
break;
|
|
case 5:
|
|
case 6:
|
|
case 7:
|
|
case 8:
|
|
for ( i = 0; i < RequestedSamples; i++, b += t->Channels ) {
|
|
l[i] = (0.4142 * b[0] + 0.2928 * b[1] + 0.2928 * b[3] - 0.1464 * b[4]) * scalel + MPPENC_DENORMAL_FIX_LEFT; // left
|
|
r[i] = (0.4142 * b[2] + 0.2928 * b[1] + 0.2928 * b[4] - 0.1464 * b[3]) * scaler + MPPENC_DENORMAL_FIX_RIGHT; // right
|
|
m[i] = (l[i] + r[i]) * 0.5f;
|
|
s[i] = (l[i] - r[i]) * 0.5f;
|
|
}
|
|
break;
|
|
default:
|
|
for ( i = 0; i < RequestedSamples; i++, b += t->Channels ) {
|
|
l[i] = b[0] * scalel + MPPENC_DENORMAL_FIX_LEFT; // left
|
|
r[i] = b[1] * scaler + MPPENC_DENORMAL_FIX_RIGHT; // right
|
|
m[i] = (l[i] + r[i]) * 0.5f;
|
|
s[i] = (l[i] - r[i]) * 0.5f;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
unsigned int bytes = t->BytesPerSample;
|
|
rf_t f = rf [bytes];
|
|
|
|
c = (char*)b;
|
|
switch ( t->Channels ) {
|
|
case 1:
|
|
for ( i = 0; i < RequestedSamples; i++, c += bytes ) {
|
|
float temp = f(c) * scalel;
|
|
l[i] = temp + MPPENC_DENORMAL_FIX_LEFT;
|
|
r[i] = temp + MPPENC_DENORMAL_FIX_RIGHT;
|
|
m[i] = (l[i] + r[i]) * 0.5f;
|
|
s[i] = (l[i] - r[i]) * 0.5f;
|
|
}
|
|
break;
|
|
case 2:
|
|
for ( i = 0; i < RequestedSamples; i++, c += 2*bytes ) {
|
|
l[i] = f(c) * scalel + MPPENC_DENORMAL_FIX_LEFT; // left
|
|
r[i] = f(c+bytes) * scaler + MPPENC_DENORMAL_FIX_RIGHT; // right
|
|
m[i] = (l[i] + r[i]) * 0.5f;
|
|
s[i] = (l[i] - r[i]) * 0.5f;
|
|
}
|
|
break;
|
|
default:
|
|
for ( i = 0; i < RequestedSamples; i++, c += bytes * t->Channels ) {
|
|
l[i] = f(c) * scalel + MPPENC_DENORMAL_FIX_LEFT; // left
|
|
r[i] = f(c+bytes) * scaler + MPPENC_DENORMAL_FIX_RIGHT; // right
|
|
m[i] = (l[i] + r[i]) * 0.5f;
|
|
s[i] = (l[i] - r[i]) * 0.5f;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return ReadSamples;
|
|
}
|
|
|
|
|
|
// read WAVE header
|
|
|
|
static unsigned short
|
|
Read16 ( FILE* fp )
|
|
{
|
|
unsigned char buff [2];
|
|
|
|
if (fread ( buff, 1, 2, fp ) != 2 )
|
|
return -1;
|
|
return buff[0] | (buff[1] << 8);
|
|
}
|
|
|
|
static unsigned long
|
|
Read32 ( FILE* fp )
|
|
{
|
|
unsigned char buff [4];
|
|
|
|
if ( fread ( buff, 1, 4, fp ) != 4 )
|
|
return -1;
|
|
return (buff[0] | (buff[1] << 8)) | ((unsigned long)(buff[2] | (buff[3] << 8)) << 16);
|
|
}
|
|
|
|
|
|
int
|
|
Read_WAV_Header ( wave_t* type )
|
|
{
|
|
int bytealign;
|
|
|
|
FILE* fp = type->fp;
|
|
|
|
if ( type->raw )
|
|
return 0;
|
|
|
|
fseek ( fp, 0, SEEK_SET );
|
|
if ( Read32 (fp) != 0x46464952 ) { // 4 Byte: check for "RIFF"
|
|
stderr_printf ( Read32(fp) == -1 ? " ERROR: Empty file or no data from coprocess!\n\n"
|
|
: " ERROR: 'RIFF' not found in WAVE header!\n\n");
|
|
return -1;
|
|
}
|
|
Read32 (fp); // 4 Byte: chunk size (ignored)
|
|
if ( Read32 (fp) != 0x45564157 ) { // 4 Byte: check for "WAVE"
|
|
stderr_printf ( " ERROR: 'WAVE' not found in WAVE header!\n\n");
|
|
return -1;
|
|
}
|
|
if ( Read32 (fp) != 0x20746D66 ) { // 4 Byte: check for "fmt "
|
|
stderr_printf ( " ERROR: 'fmt ' not found in WAVE header!\n\n");
|
|
return -1;
|
|
}
|
|
Read32 (fp); // 4 Byte: read chunk-size (ignored)
|
|
if ( Read16 (fp) != 0x0001 ) { // 2 Byte: check for linear PCM
|
|
stderr_printf ( " ERROR: WAVE file has no linear PCM format!\n\n");
|
|
return -1;
|
|
}
|
|
type -> Channels = Read16 (fp); // 2 Byte: read no. of channels
|
|
type -> SampleFreq = Read32 (fp); // 4 Byte: read sampling frequency
|
|
Read32 (fp); // 4 Byte: read avg. blocksize (fs*channels*bytepersample)
|
|
bytealign = Read16 (fp); // 2 Byte: read byte-alignment (channels*bytepersample)
|
|
type->BitsPerSample = Read16 (fp); // 2 Byte: read bits per sample
|
|
type->BytesPerSample= (type->BitsPerSample + 7) / 8;
|
|
while ( 1 ) { // search for "data"
|
|
if ( feof (fp) )
|
|
return -1;
|
|
if ( Read16 (fp) != 0x6164 )
|
|
continue;
|
|
if ( Read16 (fp) == 0x6174 )
|
|
break;
|
|
}
|
|
type->PCMBytes = Read32 (fp); // 4 Byte: no. of byte in file
|
|
if ( feof (fp) ) return -1;
|
|
|
|
// finally calculate number of samples
|
|
if (type->PCMBytes >= 0xFFFFFF00 ||
|
|
type->PCMBytes == 0 ||
|
|
(mpc_uint32_t)type->PCMBytes % (type -> Channels * type->BytesPerSample) != 0) {
|
|
type->PCMSamples = 36000000 * type->SampleFreq;
|
|
}
|
|
else {
|
|
type->PCMSamples = type->PCMBytes / bytealign;
|
|
}
|
|
type->PCMOffset = ftell (fp);
|
|
return 0;
|
|
}
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include <stdio.h>
|
|
#include <windows.h>
|
|
#include <winbase.h>
|
|
#include <mmsystem.h>
|
|
#ifndef __MINGW32__
|
|
#include <mmreg.h>
|
|
#endif
|
|
#include <io.h>
|
|
#include <fcntl.h>
|
|
|
|
|
|
#define NBLK 383 // 10 sec of audio
|
|
|
|
|
|
typedef struct {
|
|
int active;
|
|
char* data;
|
|
size_t datalen;
|
|
WAVEHDR hdr;
|
|
} oblk_t;
|
|
|
|
static HWAVEIN Input_WAVHandle;
|
|
static HWAVEOUT Output_WAVHandle;
|
|
static size_t BufferBytes;
|
|
static WAVEHDR whi [NBLK];
|
|
static char* data [NBLK];
|
|
static oblk_t array [NBLK];
|
|
static unsigned int NextInputIndex;
|
|
static unsigned int NextOutputIndex;
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
int
|
|
init_in ( const int SampleCount,
|
|
const int SampleFreq,
|
|
const int Channels,
|
|
const int BitsPerSample )
|
|
{
|
|
|
|
WAVEFORMATEX pwf;
|
|
MMRESULT r;
|
|
int i;
|
|
|
|
pwf.wFormatTag = WAVE_FORMAT_PCM;
|
|
pwf.nChannels = Channels;
|
|
pwf.nSamplesPerSec = SampleFreq;
|
|
pwf.nAvgBytesPerSec = SampleFreq * Channels * ((BitsPerSample + 7) / 8);
|
|
pwf.nBlockAlign = Channels * ((BitsPerSample + 7) / 8);
|
|
pwf.wBitsPerSample = BitsPerSample;
|
|
pwf.cbSize = 0;
|
|
|
|
r = waveInOpen ( &Input_WAVHandle, WAVE_MAPPER, &pwf, 0, 0, CALLBACK_EVENT );
|
|
if ( r != MMSYSERR_NOERROR ) {
|
|
fprintf ( stderr, "waveInOpen failed: ");
|
|
switch (r) {
|
|
case MMSYSERR_ALLOCATED: fprintf ( stderr, "resource already allocated\n" ); break;
|
|
case MMSYSERR_INVALPARAM: fprintf ( stderr, "invalid Params\n" ); break;
|
|
case MMSYSERR_BADDEVICEID: fprintf ( stderr, "device identifier out of range\n" ); break;
|
|
case MMSYSERR_NODRIVER: fprintf ( stderr, "no device driver present\n" ); break;
|
|
case MMSYSERR_NOMEM: fprintf ( stderr, "unable to allocate or lock memory\n" ); break;
|
|
case WAVERR_BADFORMAT: fprintf ( stderr, "attempted to open with an unsupported waveform-audio format\n" ); break;
|
|
case WAVERR_SYNC: fprintf ( stderr, "device is synchronous but waveOutOpen was\n" ); break;
|
|
default: fprintf ( stderr, "unknown error code: %#X\n", r ); break;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
BufferBytes = SampleCount * Channels * ((BitsPerSample + 7) / 8);
|
|
|
|
for ( i = 0; i < NBLK; i++ ) {
|
|
whi [i].lpData = data [i] = malloc (BufferBytes);
|
|
whi [i].dwBufferLength = BufferBytes;
|
|
whi [i].dwFlags = 0;
|
|
whi [i].dwLoops = 0;
|
|
|
|
r = waveInPrepareHeader ( Input_WAVHandle, whi + i, sizeof (*whi) ); if ( r != MMSYSERR_NOERROR ) { fprintf ( stderr, "waveInPrepareHeader (%u) failed\n", i ); return -1; }
|
|
r = waveInAddBuffer ( Input_WAVHandle, whi + i, sizeof (*whi) ); if ( r != MMSYSERR_NOERROR ) { fprintf ( stderr, "waveInAddBuffer (%u) failed\n", i ); return -1; }
|
|
}
|
|
NextInputIndex = 0;
|
|
waveInStart (Input_WAVHandle);
|
|
return 0;
|
|
}
|
|
|
|
|
|
size_t
|
|
get_in ( void* DataPtr )
|
|
{
|
|
MMRESULT r;
|
|
size_t Bytes;
|
|
|
|
if ( whi [NextInputIndex].dwFlags & WHDR_DONE ) {
|
|
Bytes = whi [NextInputIndex].dwBytesRecorded;
|
|
memcpy ( DataPtr, data [NextInputIndex], Bytes );
|
|
|
|
r = waveInUnprepareHeader ( Input_WAVHandle, whi + NextInputIndex, sizeof (*whi) ); if ( r != MMSYSERR_NOERROR ) { fprintf ( stderr, "waveInUnprepareHeader (%d) failed\n", NextInputIndex ); return -1; }
|
|
whi [NextInputIndex].lpData = data [NextInputIndex];
|
|
whi [NextInputIndex].dwBufferLength = BufferBytes;
|
|
whi [NextInputIndex].dwFlags = 0;
|
|
whi [NextInputIndex].dwLoops = 0;
|
|
r = waveInPrepareHeader ( Input_WAVHandle, whi + NextInputIndex, sizeof (*whi) ); if ( r != MMSYSERR_NOERROR ) { fprintf ( stderr, "waveInPrepareHeader (%d) failed\n", NextInputIndex ); return -1; }
|
|
r = waveInAddBuffer ( Input_WAVHandle, whi + NextInputIndex, sizeof (*whi) ); if ( r != MMSYSERR_NOERROR ) { fprintf ( stderr, "waveInAddBuffer (%d) failed\n", NextInputIndex ); return -1; }
|
|
NextInputIndex = (NextInputIndex + 1) % NBLK;
|
|
return Bytes;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
int
|
|
init_out ( const int SampleCount,
|
|
const int SampleFreq,
|
|
const int Channels,
|
|
const int BitsPerSample )
|
|
{
|
|
WAVEFORMATEX pwf;
|
|
MMRESULT r;
|
|
int i;
|
|
|
|
pwf.wFormatTag = WAVE_FORMAT_PCM;
|
|
pwf.nChannels = Channels;
|
|
pwf.nSamplesPerSec = SampleFreq;
|
|
pwf.nAvgBytesPerSec = SampleFreq * Channels * ((BitsPerSample + 7) / 8);
|
|
pwf.nBlockAlign = Channels * ((BitsPerSample + 7) / 8);
|
|
pwf.wBitsPerSample = BitsPerSample;
|
|
pwf.cbSize = 0;
|
|
|
|
r = waveOutOpen ( &Output_WAVHandle, WAVE_MAPPER, &pwf, 0, 0, CALLBACK_EVENT );
|
|
if ( r != MMSYSERR_NOERROR ) {
|
|
fprintf ( stderr, "waveOutOpen failed\n" );
|
|
switch (r) {
|
|
case MMSYSERR_ALLOCATED: fprintf ( stderr, "resource already allocated\n" ); break;
|
|
case MMSYSERR_INVALPARAM: fprintf ( stderr, "invalid Params\n" ); break;
|
|
case MMSYSERR_BADDEVICEID: fprintf ( stderr, "device identifier out of range\n" ); break;
|
|
case MMSYSERR_NODRIVER: fprintf ( stderr, "no device driver present\n" ); break;
|
|
case MMSYSERR_NOMEM: fprintf ( stderr, "unable to allocate or lock memory\n" ); break;
|
|
case WAVERR_BADFORMAT: fprintf ( stderr, "attempted to open with an unsupported waveform-audio format\n" ); break;
|
|
case WAVERR_SYNC: fprintf ( stderr, "device is synchronous but waveOutOpen was\n" ); break;
|
|
default: fprintf ( stderr, "unknown error code: %#X\n", r ); break;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
BufferBytes = SampleCount * Channels * ((BitsPerSample + 7) / 8);
|
|
|
|
for ( i = 0; i < NBLK; i++ ) {
|
|
array [i].active = 0;
|
|
array [i].data = malloc (BufferBytes);
|
|
}
|
|
NextOutputIndex = 0;
|
|
return 0;
|
|
}
|
|
|
|
|
|
int
|
|
put_out ( const void* DataPtr,
|
|
const size_t Bytes )
|
|
{
|
|
MMRESULT r;
|
|
int i = NextOutputIndex;
|
|
|
|
if ( array [i].active )
|
|
while ( ! (array [i].hdr.dwFlags & WHDR_DONE) )
|
|
Sleep (26);
|
|
|
|
r = waveOutUnprepareHeader ( Output_WAVHandle, &(array [i].hdr), sizeof (array [i].hdr) ); if ( r != MMSYSERR_NOERROR ) { fprintf ( stderr, "waveOutUnprepareHeader (%d) failed\n", i ); return -1; }
|
|
|
|
array [i].active = 1;
|
|
array [i].hdr.lpData = array [i].data;
|
|
array [i].hdr.dwBufferLength = Bytes;
|
|
array [i].hdr.dwFlags = 0;
|
|
array [i].hdr.dwLoops = 0;
|
|
memcpy ( array [i].data, DataPtr, Bytes );
|
|
|
|
r = waveOutPrepareHeader ( Output_WAVHandle, &(array [i].hdr), sizeof (array [i].hdr) ); if ( r != MMSYSERR_NOERROR ) { fprintf ( stderr, "waveOutPrepareHeader (%d) failed\n", i ); return -1; }
|
|
r = waveOutWrite ( Output_WAVHandle, &(array [i].hdr), sizeof (array [i].hdr) ); if ( r != MMSYSERR_NOERROR ) { fprintf ( stderr, "waveOutAddBuffer (%d) failed\n", i ); return -1; }
|
|
|
|
NextInputIndex = (NextInputIndex + 1) % NBLK;
|
|
return Bytes;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#endif
|
|
|
|
/* end of wave_in.c */
|