// PATest03.cpp : PortAudio Multi Channel WAV file test // #include "stdafx.h" #include #include #include #include #include #include #include #include "pa_win_ds.h" #define SAMPLE_RATE (44100) #define FRAMES_PER_BUFFER (2048) #define NUM_CHANNELS (8) #define DITHER_FLAG (0) /**/ #define PA_SAMPLE_TYPE paInt16 #define SAMPLE_SIZE (2) #define SAMPLE_SILENCE (0) #define CLEAR(a) bzero( (a), FRAMES_PER_BUFFER * NUM_CHANNELS * SAMPLE_SIZE ) #define PRINTF_S_FORMAT "%d" //Read 4 bytes from Wave file headder, return unsigned Long unsigned long read4bytes(FILE *f) { unsigned char buf[4]; if (fread(buf, 4, 1, f) != 1) { fprintf(stderr, "Read error\n"); exit(1); } return ((256LU * buf[3] + buf[2]) * 256LU + buf[1] ) * 256LU + buf[0] ; } //Read 2 bytes from Wave file headder, return unsigned short unsigned read2bytes(FILE *f) { unsigned char buf[2]; if (fread(buf, 2, 1, f) != 1) { fprintf(stderr, "Read error\n"); exit(1); } return 256U * buf[1] + buf[0] ; } //User Data struct used between main routine and CallBack Function typedef struct { unsigned char * p; //Main Data Buffer unsigned long len; //file total length unsigned long pCounter; //current counter int numBytes; //Block Size FILE *f; } paTestData; //Stream CallBack function. //(1) Process Input : not used now //(2) Fill Output Buffer to pass PortAudio //(3) Return Status Flag, Continue or Complete static int patestCallback( const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, void *userData ) { paTestData *data = (paTestData*)userData; char *out = (char *)outputBuffer; (void) timeInfo; /* Prevent unused variable warnings. */ (void) statusFlags; (void) inputBuffer; if (data->pCounter > data->len) { return paComplete; } else { memcpy(out, (data->p)+(data->pCounter),data->numBytes); data->pCounter += data->numBytes; return paContinue; } } // Buffer Function. // In this test, read Wave file(extended only) and eat memory. int PrepareBufferByFile(char * filename, void * userData) { int i, channels, bits; unsigned char s[100]; paTestData *data = (paTestData*)userData; fopen_s(&data->f, filename, "rb"); if (data->f == NULL) { printf("Can not open %s\n", filename); return -1; } printf("finename = '%s'\n", filename); if (fread(s, 4, 1, data->f) != 1) { printf("Read error\n"); fclose(data->f); return -1; } if (memcmp(s, "RIFF", 4) != 0) { printf("Not a RIFF format\n"); fclose(data->f); return -1; } printf("[RIFF] (%lu bytes)\n", read4bytes(data->f)); if (fread(s, 8, 1, data->f) != 1) { printf("Read error\n"); fclose(data->f); return -1; } if (memcmp(s, "WAVEfmt ", 8) != 0) { printf("Not a WAVEfmt format\n"); fclose(data->f); return -1; } data->len = read4bytes(data->f); printf("[WAVEfmt ] (%lu bytes)\n", data->len); if (data->len != 40) { printf("Length of WAVEfmt must be 40 for Extended Wave format.\n"); return -1; } printf(" Data type = %x (0xFFFE = Extended)\n", read2bytes(data->f)); channels = read2bytes(data->f); printf(" Number of channels = %u (should be 8)\n", channels); printf(" Sampling rate = %luHz\n", read4bytes(data->f)); printf(" Bytes per second = %lu\n", read4bytes(data->f)); printf(" Bytes per sample = %u\n", read2bytes(data->f)); bits = read2bytes(data->f); printf(" Bits per sample = %u\n", bits); //read out extended chunk fread(s, (2+2+4+16+4+2+54), 1, data->f); //len,width,chformat,cue ,len,52x00 while (fread(s, 4, 1, data->f) == 1) { data->len = read4bytes(data->f); s[4] = 0; printf("[%s] (%lu bytes)\n", s, data->len); if (memcmp(s, "data", 4) == 0) break; for (i = 0; i < (int)data->len; i++) printf("%02x ", fgetc(data->f)); printf("\n"); } printf("Copying File to Memory...\n"); //get memory for "len" bytes //front 4 frame zero, end 1 frame zero data->p = (unsigned char *)malloc(data->numBytes*4+data->len+data->numBytes); memset( data->p, 0, data->numBytes*4+data->len+data->numBytes ); if(!VirtualLock(data->p, data->numBytes*4+data->len+data->numBytes )) { //Copy File to Memory fread(data->p+(data->numBytes)*4, data->len, 1,data->f); } else { printf("Unable to lock memory.\n"); return -1; } printf("Done Copying.\n"); return 0; } int main( int argc, char** argv) { PaStreamParameters outputParameters; PaStream *stream = NULL; PaError err; int numBytes; int deviceIndex; paTestData data; printf("paTest 8channel WAV\n"); fflush(stdout); //Block size for output buffer. numBytes = FRAMES_PER_BUFFER * NUM_CHANNELS * SAMPLE_SIZE ; err = Pa_Initialize(); if( err != paNoError ) goto error; //Select Device which supports DirectSound API deviceIndex = Pa_GetHostApiInfo( Pa_HostApiTypeIdToHostApiIndex( paDirectSound ) )->defaultOutputDevice; printf( "using device id %d (%s)\n", deviceIndex, Pa_GetDeviceInfo(deviceIndex)->name ); outputParameters.device = deviceIndex; /* DirectSound output device */ printf( "Output device # %d.\n", outputParameters.device ); printf( "Output LL: %g s\n", Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency ); printf( "Output HL: %g s\n", Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency ); outputParameters.channelCount = NUM_CHANNELS; outputParameters.sampleFormat = PA_SAMPLE_TYPE; outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency; //DirectSound Specific Stream setting PaWinDirectSoundStreamInfo WinDSInfo; WinDSInfo.size = sizeof(PaWinDirectSoundStreamInfo); WinDSInfo.hostApiType = paDirectSound; WinDSInfo.version = 1; WinDSInfo.channelMask = PAWIN_SPEAKER_7POINT1_SURROUND; //This is 0x063F channel mask WinDSInfo.flags = paWinDirectSoundUseChannelMask; outputParameters.hostApiSpecificStreamInfo = &WinDSInfo; /* -- check -- */ if( Pa_IsFormatSupported( 0, &outputParameters, SAMPLE_RATE ) == paFormatIsSupported ) { printf( "Pa_IsFormatSupported reports device will support %d channels.\n", NUM_CHANNELS ); } else { printf( "Pa_IsFormatSupported reports device will not support %d channels.\n", NUM_CHANNELS ); goto error; } data.pCounter = 0; data.numBytes = numBytes; char filename[100]; strncpy_s(filename,100, argv[1], strlen(argv[1])); err = PrepareBufferByFile(filename, &data); if( err != 0 ) goto error; int StreamStatus = 1; err = Pa_OpenStream( &stream, NULL, //no input &inputParameters, &outputParameters, SAMPLE_RATE, FRAMES_PER_BUFFER, paClipOff, /* we won't output out of range samples so don't bother clipping them */ patestCallback, &data ); /* userData */ if( err != paNoError ) goto error; err = Pa_StartStream( stream ); if( err != paNoError ) goto error; printf("stream started.\n"); //wait loop until stream completed. while (StreamStatus > 0) { Pa_Sleep( 1000 ); StreamStatus = Pa_IsStreamActive(stream); } printf("loopend, stream ending status: %d .\n", StreamStatus); fclose(data.f); free(data.p); printf("%s\n",Pa_GetErrorText(err)); err = Pa_StopStream( stream ); if( err != paNoError ) goto error; Pa_CloseStream( stream ); Pa_Terminate(); return 0; error: if( stream ) { Pa_AbortStream( stream ); Pa_CloseStream( stream ); } Pa_Terminate(); fprintf( stderr, "An error occured while using the portaudio stream\n" ); fprintf( stderr, "Error number: %d\n", err ); fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); return -1; }