| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440 |
- /*
- * Copyright (c) 1983-2023 Richard Dobson and Composers Desktop Project Ltd
- * http://www.rwdobson.com
- * http://www.composersdesktop.com
- * This file is part of the CDP System.
- * The CDP System 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.
- *
- * The CDP System 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 the CDP System; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
- /* pvplay.cpp
- * Play a soundfile or analysis file using PortAudio
- *
- * Yes yes, I know, this is iffy C++, and there are some gotos to boot. Work in progress...
- * and I may yet redo the whole thing in plain C anyway, like paplay.
- */
- /* OCT 2009 rebuilt with updated pvfileio.c for faster performance on G4 */
- /* Feb 2010 rebuilt with new stable portaudio */
- /* June 2012 new portaudio, settable audio block size */
- /* Jan 2013 changed (as also paplay), at last, to use threaded portaudio ringbuffer code (etc) */
- /* Jan 2014: completed pvx support */
- #include "pvplay.h"
- typedef enum {PLAY_SFILE,PLAY_ANAFILE,PLAY_PVXFILE} PLAYTYPE;
- enum {FM_MONO,FM_STEREO,FM_SQUARE,FM_QUAD,FM_PENT,DM_5_0,DM_5_1,FM_HEX,FM_OCT1,FM_OCT2,FM_CUBE,FM_QUADCUBE,FM_NLAYOUTS};
- #define NUM_ANALFRAMES (1)
- #define RINGBUF_NFRAMES (32768)
- #define NUM_WRITES_PER_BUFFER (4)
- #ifndef min
- #define min(x,y) ((x) < (y) ? (x) : (y))
- #endif
- #ifdef unix
- #include <ctype.h>
- int stricmp(const char *a, const char *b);
- int strnicmp(const char *a, const char *b, const int length);
- #endif
- #ifdef WIN32
- HANDLE ghEvent;
- #endif
- int file_playing;
- psfdata *g_pdata = NULL;
- void playhandler(int sig)
- {
- if(sig == SIGINT) {
- if(file_playing) {
- file_playing = 0;
- g_pdata->flag = 1;
- Pa_Sleep(5);
- }
- }
- }
- #ifdef unix
- void alarm_wakeup (int i)
- {
- struct itimerval tout_val;
-
- signal(SIGALRM,alarm_wakeup);
- if(file_playing && g_pdata->stream) {
- //printf("%.4f secs\r",(float)(g_pdata->frames_played /(double) g_pdata->srate));
- g_pdata->lastTime = Pa_GetStreamTime(g_pdata->stream ) - g_pdata->startTime;
- printf("%.2f secs\r", g_pdata->lastTime);
- fflush(stdout);
- }
- tout_val.it_interval.tv_sec = 0;
- tout_val.it_interval.tv_usec = 0;
- tout_val.it_value.tv_sec = 0;
- tout_val.it_value.tv_usec = 200000;
- setitimer(ITIMER_REAL, &tout_val,0);
- }
- #endif
- void finishedCallback(void *userData)
- {
- psfdata *pdata = (psfdata*) userData;
- //printf("stream finished!\n");
- pdata->finished = 1;
- file_playing = 0;
- }
- #ifdef WIN32
- VOID CALLBACK TimerCallback(PVOID lpParam, BOOLEAN TimerOrWaitFired)
- {
- psfdata *pdata = (psfdata*) lpParam;
-
- if(file_playing && pdata->stream) {
- //printf("%.4f secs\r",(float)(g_pdata->frames_played /(double) g_pdata->srate));
- pdata->lastTime = Pa_GetStreamTime(pdata->stream ) - pdata->startTime;
- printf("%.2f secs\r", pdata->lastTime);
- fflush(stdout);
- }
- SetEvent(ghEvent);
- }
- #endif
- /* This routine will be called by the PortAudio engine when audio is needed.
- ** It may called at interrupt level on some machines so don't do anything
- ** that could mess up the system like calling malloc() or free().
- */
- #ifdef NOTDEF
- // need this?
- static void porttimeCallback(PtTimestamp timestamp, void *userData)
- {
- PtTimestamp curtime = Pt_Time();
- double timesecs = (double) curtime * 0.001;
- printf("%.3lf\r",timesecs);
- }
- #endif
- /* Start up a new thread for given function */
- static PaError startThread( psfdata* pdata, threadfunc fn )
- {
- pdata->flag = 1;
- #ifdef WIN32
- pdata->hThread = (void*)_beginthreadex(NULL, 0, fn, pdata, 0, NULL);
- if (pdata->hThread == NULL)
- return paUnanticipatedHostError;
- /* Wait for thread to startup */
- while (pdata->flag) {
- Pa_Sleep(10);
- }
- /* Set file thread to a little higher priority than normal */
- SetThreadPriority(pdata->hThread, THREAD_PRIORITY_ABOVE_NORMAL);
- //#endif
-
- #else
- #if defined(__APPLE__) || defined(__GNUC__)
- if(pthread_create(&pdata->hThread,NULL,/*(void*)*/ fn,pdata))
- return -1;
- /* Wait for thread to startup */
- while (pdata->flag) {
- Pa_Sleep(10);
- }
- #endif
- #endif
-
- return paNoError;
- }
- #if 0
- static int stopThread( psfdata* pdata )
- {
- // just called when all data played; must be called before StopStream
- // pdata->flag = 1;
- /* Wait for thread to stop */
- while (pdata->flag==0) {
- Pa_Sleep(10);
- }
- #ifdef WIN32
- CloseHandle(pdata->hThread);
- pdata->hThread = 0;
- #else
- #if defined(__APPLE__) || defined(__GNUC__)
- pthread_cancel(pdata->hThread);
- #endif
- #endif
- return paNoError;
- }
- #endif
- static int paplayCallback(const void *inputBuffer, void *outputBuffer,
- unsigned long framesPerBuffer,
- const PaStreamCallbackTimeInfo* timeInfo,
- PaStreamCallbackFlags statusFlags,
- void *userData )
- {
- psfdata *data = (psfdata *)userData;
- ring_buffer_size_t sampsAvailable = PaUtil_GetRingBufferReadAvailable(&data->ringbuf) * data->outchans;
- ring_buffer_size_t sampsToPlay = min(sampsAvailable, (ring_buffer_size_t)(framesPerBuffer * data->outchans));
- float *out = (float*) outputBuffer;
- int framesToPlay = sampsToPlay / data->outchans;
- int played;
-
- // if framestoplay < framesPerBuffer, need to clean up the remainder
- memset(out,0,framesPerBuffer * data->outchans * sizeof(float));
- played = PaUtil_ReadRingBuffer(&data->ringbuf, out, framesToPlay);
-
- data->frames_played += played;
- if(data->flag) {
- //printf("callback - complete\n");
- return paComplete;
- }
- return paContinue;
- }
- static int MemCallback(const void *inputBuffer, void *outputBuffer,
- unsigned long framesPerBuffer,
- const PaStreamCallbackTimeInfo* timeInfo,
- PaStreamCallbackFlags statusFlags,
- void *userData )
- {
- psfdata *pdata = (psfdata *)userData;
-
- float *out = (float*) outputBuffer;
- unsigned long inSamps,outSamps, inSampPos;
- unsigned long i;
- unsigned long framesToPlay = framesPerBuffer;
-
- // if framesToPlay < framesPerBuffer, need to clean up the remainder
- memset(out,0,framesPerBuffer * pdata->outchans * sizeof(float));
- inSamps = pdata->memFramelength * pdata->inchans;
- outSamps = framesPerBuffer * pdata->inchans;
- inSampPos = pdata->memFramePos * pdata->inchans;
-
- if(pdata->play_looped){
- for(i=0;i < outSamps; i++){
- pdata->inbuf[i] = pdata->membuf[inSampPos++] * pdata->gain;
- if(inSampPos == inSamps)
- inSampPos = 0;
- }
- }
- else {
- for(i=0;i < outSamps; i++){
- pdata->inbuf[i] = pdata->membuf[inSampPos++] * pdata->gain;
- if(inSampPos == inSamps)
- break;
- }
- framesToPlay = i / pdata->inchans;
- for(; i < outSamps;i++){
- pdata->inbuf[i] = 0.0;
- }
-
- }
- // write to output
- // everything now in inbuf
- if(pdata->do_decode) {
- ABFSAMPLE abfsamp;
- unsigned long j;
- for(j=0; j < framesToPlay; j++){
- pdata->copyfunc(&abfsamp,pdata->inbuf + (j * pdata->inchans));
- pdata->decodefunc(&abfsamp,out + (j * pdata->outchans), 1);
- }
- }
- else { // inchans = outchans
- memcpy(out,pdata->inbuf,framesToPlay * sizeof(float) * pdata->inchans);
- }
- pdata->memFramePos = inSampPos / pdata->inchans;
- pdata->frames_played += framesToPlay;
- if(framesToPlay < framesPerBuffer)
- pdata->flag = 1; // end of stream
- if(pdata->flag) {
- return paComplete;
- }
- return paContinue;
- }
- static unsigned NextPowerOf2(unsigned val)
- {
- val--;
- val = (val >> 1) | val;
- val = (val >> 2) | val;
- val = (val >> 4) | val;
- val = (val >> 8) | val;
- val = (val >> 16) | val;
- return ++val;
- }
- #define N_BFORMATS (10)
- // static const int bformats[N_BFORMATS] = {2,3,4,5,6,7,8,9,11,16};
- // static const int layout_chans[] = {1,2,4,4,5,5,6,6,8,8,8,8};
- /* no M flag here */
- enum {FLAG_B = 0, FLAG_BM, FLAG_D, FLAG_G, FLAG_H, FLAG_I, FLAG_L, FLAG_NFLAGS};
- void usage(void){
- #ifdef WIN32
- printf("usage:\n pvplay [-BN][-dN][-gN]-hN][-i][-l][-b[N]][-u][-x] infile [from] [to] \n"
- #else
- printf("usage:\n pvplay [-BN][-dN][-gN]-hN][-i][-l][-b[N]][-u] infile [from] [to]\n"
- #endif
- " -dN : use output Device N.\n"
- " -gN : apply gain factor N to input.\n"
- " -BN : set memory buffer size to N frames (default: %d).\n"
- " N must be a power of 2 (e.g 4096, 8192, 16384 etc).\n"
- " -hN : set hardware blocksize to N frames (32 < N <= BN/4), default is set internally.\n"
- " (N recommended to be a power of two size).\n"
- " : NB: for sample rates > 48KHz, buffer sizes are doubled internally.\n"
- " -i : play immediately (do not wait for keypress).\n"
- " -l : loop file continuously, from start-time to end-time.\n"
- " -u : suppress elapsed time updates\n"
- #ifdef WIN32
- " -x : Apply WAVE_EX infile channel mask to DS audio stream\n"
- " (ignored if -m or -b used)\n"
- #endif
- " from : set start time (secs) for playback and looping. Default: 0.\n"
- " to : set end time (secs) for playback and looping. Default: EOF.\n"
- " -b[N]: apply 1st-order B-Format decoding to standard soundfile.\n"
- " (file must have at least 3 channels)\n"
- " B-Format files (.amb) will be decoded automatically.\n"
- " N sets speaker layout to one of the following:\n"
- " 1 : * mono (= W signal only)\n"
- " 2 : * stereo (quasi mid/side, = W +- Y)\n"
- " 3 : square\n"
- " 4 : * quad FL,FR,RL,RR order (default)\n"
- " 5 : pentagon\n"
- " 6 : * 5.0 surround (WAVEX order)\n"
- " 7 : * 5.1 surround (WAVEX order, silent LFE)\n"
- " 8 : hexagon\n"
- " 9 : octagon 1 (front pair, 45deg)\n"
- " 10 : octagon 2 (front centre speaker)\n"
- " 11 : cube (as 3, low-high interleaved. Csound-compatible.)\n"
- " 12 : * cube (as 4, low quad followed by high quad).\n"
- " Default decode layout is 4 (quad).\n"
- " NB: no decoding is performed if -m flag used.\n"
- " pvplay reads PEAK chunk if present to rescale over-range floatsam files.\n\n"
- ,RINGBUF_NFRAMES);
- }
-
- /*******************************************************************/
- int main(int argc,char **argv)
- {
- PaStreamParameters outputParameters;
- #ifdef WIN32
- /* portaudio sets default channel masks we can't use; we must do all this to set default mask = 0! */
- PaWinDirectSoundStreamInfo directSoundStreamInfo;
- // PaWinMmeStreamInfo winmmeStreamInfo;
- #endif
- PaDeviceInfo *devinfo = NULL;
- PaStream *stream = NULL;
- PaStreamCallback *playcallback = paplayCallback;
- PaError err = paNoError;
- SFPROPS props;
- psfdata sfdata;
- CHPEAK *fpeaks = NULL;
- //ABFSAMPLE *abf_frame = NULL;
- int res,inorder = 1;
- time_t in_peaktime = 0;
- int waitkey = 1;
- //int play_looped = 0;
- double fromdur = 0.0;
- double totime = 0.0;
- int from_frame = 0, to_frame = 0;
- unsigned int i=0;
- long anal_nframes;
- PaDeviceIndex device;
- //long framesread;
- long filesize;
- //long framesize = 0;
- unsigned long ringframelen = RINGBUF_NFRAMES; // length of ring buffer in m/c frames
- unsigned long frames_per_buffer = 0; // default is to let portaudio decide
- unsigned long nFramesToPlay = 0;
- double gain = 1.0;
- unsigned int inchans = 0,outchans = 0; // may be different if decoding B-Format
- int layout = 4; // default, quad decode */
- fmhcopyfunc copyfunc = NULL;
- fmhdecodefunc decodefunc = NULL;
- /* chorder facility not included in pvplay - use paplay! */
- unsigned int flags[FLAG_NFLAGS] = {0};
- #ifdef WIN32
- int speakermask = 0;
- int do_speakermask = 0;
- #endif
- int do_updatemessages = 1;
- #ifdef unix
- struct itimerval tout_val;
- tout_val.it_interval.tv_sec = 0;
- tout_val.it_interval.tv_usec = 0;
- tout_val.it_value.tv_sec = 0;
- tout_val.it_value.tv_usec = 200000;
- #endif
- char* ext = 0;
- PVOCDATA *p_pvdata = NULL;
- WAVEFORMATEX *p_wfx = NULL;
- //int pvfile = -1;
- //pvoc_frametype inframetype;
- pvoc_windowtype wtype;
-
- //double oneovrsr;
- int anal_buflen,overlap,winlen;
- // for sfiles only, for now
- //int framesize_factor = 0;
- //phasevocoder *pv = NULL, *pv_r = NULL;
- PLAYTYPE playtype = PLAY_SFILE;
-
-
- #ifdef WIN32
- HANDLE hTimerQueue;
- ghEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
- if(ghEvent==NULL){
- printf("Failed to start internal timer (1).\n");
- return 1;
- }
- hTimerQueue = CreateTimerQueue();
- if(hTimerQueue == NULL){
- printf("Failed to start internal timer (2).\n");
- return 1;
- }
- #endif
-
-
- /* CDP version number; now set for release 7 */
- if(argc==2 && (stricmp(argv[1],"--version")==0)){
- printf("7.1.0\n");
- return 0;
- }
-
- signal(SIGINT,playhandler);
- //sf_frames = FRAMESIZE; // need this for pvoc playback reporting
- sfdata.inbuf = NULL;
- sfdata.membuf = NULL;
- sfdata.memFramelength = 0;
- sfdata.memFramePos = 0;
- sfdata.current_frame = 0;
- sfdata.ringbufData = NULL;
- sfdata.outbuf_l = NULL;
- sfdata.outbuf_r = NULL;
- sfdata.pvfile = -1;
-
- printf("PvPlay: play multi-channel PCM and analysis files (.ana, .pvx). V7.0.0 RWD,CDP 2014\n");
- file_playing = 0;
- err = Pa_Initialize();
- if( err != paNoError ) {
- fprintf(stderr,"Portaudio startup error.\n");
- return 1;
- }
- device = Pa_GetDefaultOutputDevice();
- if(device < 0){
- fprintf(stderr,"Cannot find any audio output device\n");
- return 1;
- }
- if(argc < 2){
- usage();
- show_devices();
- Pa_Terminate();
- return 1;
- }
- while(argv[1][0]=='-'){
- unsigned long userbuflen;
- switch(argv[1][1]){
- case('b'):
- if(flags[FLAG_B]){
- printf("error: multiple -b flags\n");
- Pa_Terminate();
- return 1;
- }
- if(argv[1][2] != '\0'){
- layout = atoi(&argv[1][2]);
- if(layout < 1 || layout > 12){
- fprintf(stderr,"value for -b flag out of range.\n");
- Pa_Terminate();
- return 1;
- }
- }
- flags[FLAG_B] = 1;
- break;
- case('d'):
- if(flags[FLAG_D]){
- printf("error: multiple -d flags\n");
- Pa_Terminate();
- return 1;
- }
- if(argv[1][2]=='\0'){
- printf("-d flag requires parameter\n");
- Pa_Terminate();
- return 1;
- }
- device = atoi(&(argv[1][2]));
- flags[FLAG_D] = 1;
- break;
- case('g'):
- if(flags[FLAG_G]){
- printf("error: multiple -g flags\n");
- Pa_Terminate();
- return 1;
- }
- if(argv[1][2]=='\0'){
- printf("-g flag requires parameter\n");
- Pa_Terminate();
- return 1;
- }
- gain = atof(&(argv[1][2]));
- if(gain <= 0.0){
- fprintf(stderr,"gain value must be positive.\n");
- Pa_Terminate();
- return 1;
- }
- flags[FLAG_G] = 1;
- break;
- case 'h':
- if(flags[FLAG_H]){
- printf("error: multiple -h flags\n");
- Pa_Terminate();
- return 1;
- }
- if(argv[1][2]=='\0'){
- printf("-h flag requires parameter\n");
- Pa_Terminate();
- return 1;
- }
- frames_per_buffer = atoi(&(argv[1][2]));
- if((frames_per_buffer > 0) && (frames_per_buffer < 32)){
- printf("-h value too small: must be at least 32.\n");
- Pa_Terminate();
- return 1;
- }
- flags[FLAG_H] = 1;
- break;
- case('i'):
- if(flags[FLAG_I]){
- printf("error: multiple -i flags\n");
- Pa_Terminate();
- return 1;
- }
- flags[FLAG_I] = 1;
- waitkey = 0;
- break;
- case ('l'):
- flags[FLAG_L] = 1;
- break;
- case 'u':
- do_updatemessages = 0;
- break;
- #ifdef WIN32
- case 'x':
- do_speakermask = 1;
- break;
- #endif
- case 'B':
- if(flags[FLAG_BM]){
- printf("error: multiple -B flags\n");
- Pa_Terminate();
- return 1;
- }
- if(argv[1][2]=='\0'){
- printf("-B flag requires parameter\n");
- Pa_Terminate();
- return 1;
- }
-
- ringframelen = atoi(&(argv[1][2]));
- if(ringframelen <= 1024){
- printf("-B: framesize value must be >=1024!n");
- Pa_Terminate();
- return 1;
- }
- userbuflen = NextPowerOf2(ringframelen);
- if(userbuflen != ringframelen){
- printf("-B: framesize value must be power of 2 size\n");
- Pa_Terminate();
- return 1;
- }
- flags[FLAG_BM] = 1;
- break;
- default:
- printf("unrecognised flag option\n");
- Pa_Terminate();
- return 1;
- }
- argv++; argc--;
- }
-
- if(frames_per_buffer > ringframelen/4){
- printf(" hardware (-h) framesize %lu too large for file buffer (-B) size %lu\n",
- frames_per_buffer,ringframelen);
- Pa_Terminate();
- return 1;
- }
-
- if(argc < 2 || argc > 4){
- usage();
- show_devices();
- Pa_Terminate();
- return 1;
- }
-
- if(argc>=3){
- fromdur = atof(argv[2]);
- if(fromdur < 0.0){
- printf("Error: start position must be positive\n");
- Pa_Terminate();
- return 1;
- }
- }
- if(argc==4){
- totime = atof(argv[3]);
- if(totime <= fromdur){
- printf("Error: end time must be after from time\n");
- Pa_Terminate();
- return 1;
- }
- }
-
- if(!init_pvsys()){
- puts("\nUnable to start pvsys.");
- return 1;
- }
- if(sflinit("pvplay")){
- puts("\nUnable to start sfsys.");
- return 1;
- }
-
- /* get pvocex filetype from extension */
- ext = strrchr(argv[1],'.');
- if(ext && stricmp(ext,".pvx")==0){
- p_pvdata = new PVOCDATA;
- if(p_pvdata==NULL){
- puts("\nNo Memory!");
- return 1;
- }
- p_wfx = new WAVEFORMATEX;
- if(p_wfx==NULL){
- puts("\nNo Memory!");
- return 1;
- }
- sfdata.pvfile = pvoc_openfile(argv[1],p_pvdata,p_wfx);
- if(sfdata.pvfile< 0){
- fprintf(stderr,"\npvplay: unable to open pvx file: %s",pvoc_errorstr());
- return 1;
- }
- props.srate = p_wfx->nSamplesPerSec;
- if(props.srate <=0){
- fprintf(stderr,"\nbad srate found: corrupted file?\n");
- return 1;
- }
- sfdata.srate = props.srate;
- /*stick to mono/stereo for now */
- if(p_wfx->nChannels > 2){
- fprintf(stderr,"\nSorry: can only read mono or stereo pvx files.");
- return 1;
- }
- inchans = p_wfx->nChannels;
- props.chans = inchans;
- outchans = inchans;
- /* calc size in m/c analysis frames of this analysis file */
- filesize = pvoc_framecount(sfdata.pvfile) / inchans;
- double dur = (double) filesize / (double)(p_pvdata->fAnalysisRate);
- filesize = (long)(dur * props.srate);
- sfdata.anal_framesize = (p_pvdata->nAnalysisBins/*- 1*/) * 2;
- sfdata.fftsize = sfdata.anal_framesize-2;
- winlen = p_pvdata->dwWinlen;
- overlap = p_pvdata->dwOverlap;
- sfdata.inframetype = (pvoc_frametype) p_pvdata->wAnalFormat;
-
- // oneovrsr = 1.0 / (double) props.srate;
- wtype = (pvoc_windowtype) p_pvdata->wWindowType;
-
- /* adjust buffer size to multiple of overlap */
- anal_buflen = sfdata.anal_framesize * NUM_ANALFRAMES;
- anal_buflen = (anal_buflen / overlap) * overlap;
- /* mono */
- sfdata.analframe1 = new float[sfdata.anal_framesize];
- memset(sfdata.analframe1,0,sfdata.anal_framesize * sizeof(float));
- sfdata.pv_l = new phasevocoder();
- if(!sfdata.pv_l->init(props.srate,sfdata.anal_framesize-2,winlen,overlap,1.0,PVOC_S_NONE,wtype,PVPP_STREAMING)){
- fprintf(stderr,"\nUnable to initialize pvoc Channel 1.");
- //delete sfdata.pv_l;
- //delete sfdata.analframe1;
- return 1;
- }
- if(inchans==2){
- /* need two intermediate buffers, to be interleaved into sampbuf */
- sfdata.analframe2 = new float[sfdata.anal_framesize];
- memset(sfdata.analframe2,0,sfdata.anal_framesize * sizeof(float));
- sfdata.pv_r = new phasevocoder();
- if(!sfdata.pv_r->init(props.srate,sfdata.anal_framesize-2,winlen,overlap,1.0,PVOC_S_NONE,wtype,PVPP_STREAMING)){
- fprintf(stderr,"\nUnable to initialize pvoc Channel 2.");
- //delete sfdata.pv_l;
- //delete sfdata.pv_r;
- //delete sfdata.outbuf_l;
- //delete sfdata.outbuf_r;
- //delete sfdata.analframe1;
- //delete sfdata.analframe2;
- return 1;
- }
- }
- to_frame = (pvoc_framecount(sfdata.pvfile) / inchans) - 1;
- if(fromdur > 0.0){
- //printf("SORRY: from parameter ignored: not yet supported for pvx files\n");
- from_frame = (long)(fromdur * (props.srate/overlap));
- if(from_frame >= to_frame){
- printf("Error: start frame %d is beyond end of file\n", from_frame);
- goto error;
- }
- if(pvoc_seek_mcframe(sfdata.pvfile,from_frame,SEEK_SET)){
- printf("Error: from: failed to seek to frame %d\n",from_frame);
- goto error;
- }
- }
-
- if(totime > 0.0){
- long targetframe = (long)(totime * (props.srate/overlap));
- if(targetframe >= to_frame){
- printf("Error: end time is beyond end of file\n");
- goto error;
- }
-
- if(targetframe <= from_frame){
- printf("Start time must be less than end time.\n");
- goto error;
- }
- to_frame = targetframe;
- if(to_frame - from_frame < 1){
- to_frame = from_frame+1; // maybe we can in fact freeze on a single frame!
- // but we will not use in-memory system in this case
- }
- nFramesToPlay = to_frame - from_frame;
-
- printf("Playing %d analysis frames\n",(int) nFramesToPlay);
- }
- playtype = PLAY_PVXFILE;
- }
- /* soundfile or anafile*/
- else {
- /* allow auto rescaling of overrange floats via PEAK chunk */
- sfdata.ifd = sndopenEx(argv[1],1,CDP_OPEN_RDONLY);
- if(sfdata.ifd < 0) {
- printf("unable to open soundfile %s : %s\n",argv[1],sferrstr());
- return 1;
- }
- if(!snd_headread(sfdata.ifd,&props)) {
- fprintf(stderr,"\nError reading sfile header");
- fprintf(stderr,"\n%s",props_errstr);
- return 1;
- }
- inchans = props.chans;
- filesize = sndsizeEx(sfdata.ifd); // get size in frames
- if(filesize == 0){
- printf("File is empty!\n");
- return 1;
- }
-
- bool adjusted = false; // in case we have to increase ringframelen for huge FFT size
- switch(props.type){
- case wt_analysis:
- sfdata.anal_framesize = props.chans;
- outchans = inchans = props.chans = 1;
- props.srate = props.origrate;
- anal_nframes = filesize / sfdata.anal_framesize ; // * chans ?
- if(anal_nframes <= 1){
- fprintf(stderr,"Bad analysis file - not enough frames\n");
- return 1;
- }
- sfdata.analframe1 = new float[sfdata.anal_framesize];
- winlen = props.winlen;
- /* TODO: match ringbuf length to multiple of FFT size */
- sfdata.fftsize = sfdata.anal_framesize - 2;
-
- sfdata.pv_l = new phasevocoder;
- if(!sfdata.pv_l->init(props.origrate,sfdata.anal_framesize-2,props.winlen,props.decfac,1.0,
- PVOC_S_NONE,PVOC_HAMMING,PVPP_STREAMING)){
- fprintf(stderr,"Error: unable to initialize pvoc engine.\n");
- return 1;
- }
- overlap = sfdata.pv_l->anal_overlap();
- //anal_buflen = /*FRAMESIZE * NUM_ANALFRAMES*/ anal_framesize; // always mono
- //anal_buflen = (anal_buflen / overlap) * overlap;
- // buflen = anal_buflen;
- from_frame = (long)(fromdur * props.arate);
- if(from_frame >= anal_nframes){
- printf("Error: start is beyond end of file\n");
- goto error;
- }
-
- to_frame = anal_nframes -1;
-
- if(totime > 0.0){
- to_frame = (long)(totime * props.arate + 0.5);
- if(to_frame >= anal_nframes){
- printf("Error: end time is beyond end of file\n");
- goto error;
- }
-
- if(to_frame <= from_frame){
- printf("Start time must be less than end time.\n");
- goto error;
- }
-
- if(to_frame - from_frame < 1){
- to_frame = from_frame +1; // maybe we can in fact freeze on a single frame!
- // but we will not use in-memory system in this case
- }
- nFramesToPlay = to_frame - from_frame;
-
- printf("Playing %d analysis frames\n",(int) nFramesToPlay);
- }
- if(from_frame > 0){
- if(sndseekEx(sfdata.ifd,from_frame * sfdata.anal_framesize,SEEK_SET) < 0) {
- printf("Error setting start position to frame %d\n", from_frame);
- printf("%s", sferrstr());
- goto error;
- }
- sfdata.current_frame = from_frame;
- }
- // ensure ring buffer is large enough even for huge FFT lengths!
- adjusted = false;
- while(ringframelen < (unsigned long)(sfdata.fftsize * 4)) {
- ringframelen <<= 1;
- adjusted = true;
- }
-
- //printf("from = %d, to = %d\n",from_frame, to_frame);
- playtype = PLAY_ANAFILE;
- printf("Opened %s: %ld frames, %d channels\n",argv[1],anal_nframes,props.chans);
- if(adjusted)
- printf("FFT frame size = %d, expanding buffer to suit...\n", sfdata.fftsize);
- break;
- case wt_wave:
- playtype = PLAY_SFILE;
- printf("Opened %s: %ld frames, %d channels\n",argv[1],filesize,props.chans);
- //framesize_factor = (long) (48000/ props.srate);
- //framesize_factor += 1;
- filesize /= inchans;
- #ifdef WIN32
- if(props.format == WAVE_EX){
- if(do_speakermask){
- int mask;
- if(flags[FLAG_B]){
- printf("-x flag ignored if -B used\n");
- }
- else {
- mask = sndgetchanmask(sfdata.ifd);
- if(mask < 0){
- printf("Could not read speaker mask. Using 0\n");
- }
- else
- speakermask = mask;
- }
- }
- }
- #endif
- from_frame = (long)(fromdur * props.srate);
- if(from_frame >= filesize){
- printf("Error: start is beyond end of file\n");
- goto error;
- }
- nFramesToPlay = filesize - from_frame;
- to_frame = filesize -1;
- if(totime > 0.0){
- to_frame = (long)(totime * props.srate);
- if(to_frame >= filesize){
- printf("Error: end time is beyond end of file\n");
- goto error;
- }
- //printf("fromframe = %d, toframe = %d\n",(int)from_frame,(int) to_frame);
- if(to_frame <= from_frame){
- printf("End time must be later than from time\n");
- goto error;
- }
- nFramesToPlay = to_frame - from_frame;
- printf("Playing %d frames\n",(int) nFramesToPlay);
- }
- if(from_frame > 0){
- if(sndseekEx(sfdata.ifd,from_frame * inchans,SEEK_SET) < 0) {
- printf("Error setting start position\n");
- goto error;
- }
- sfdata.current_frame = from_frame;
- }
-
-
- outchans = inchans = props.chans;
- if(props.chformat==MC_BFMT){
- flags[FLAG_B] = 1;
- if(inchans > 4) {
- inorder = 2;
- printf("%u-channel input: performing 2nd-order decode.\n",inchans);
- }
- switch(inchans){
- case 3:
- copyfunc = fmhcopy_3;
- break;
- case 4:
- copyfunc = fmhcopy_4;
- break;
- case 5:
- copyfunc = fmhcopy_5;
- break;
- case 6:
- copyfunc = fmhcopy_6;
- break;
- case 9:
- copyfunc = fmhcopy_9;
- break;
- case 11:
- copyfunc = fmhcopy_11;
- break;
- case 16:
- copyfunc = fmhcopy_16;
- break;
- default:
- fprintf(stderr,"Unsupported channel count (%u) for B-format file.\n",inchans);
- return 1;
- }
-
- switch(layout-1) {
- case FM_MONO:
- printf("Decoding to Mono\n");
- decodefunc = fm_i1_mono;
- outchans = 1;
- break;
- case FM_STEREO:
- printf("Decoding to Stereo\n");
- decodefunc = fm_i1_stereo;
- outchans = 2;
- break;
- case FM_SQUARE:
- printf("Decoding to Square\n");
- if(inorder == 1)
- decodefunc = fm_i1_square;
- else
- decodefunc = fm_i2_square;
- outchans = 4;
- break;
- case FM_PENT:
- printf("Decoding to pentagon\n");
- if(inorder==1)
- decodefunc = fm_i1_pent;
- else
- decodefunc = fm_i2_pent;
- outchans = 5;
- break;
- case DM_5_0:
- printf("Decoding to 5.0 surround (David Moore)\n");
- if(inorder==1)
- decodefunc = dm_i1_surr;
- else
- decodefunc = dm_i2_surr;
- outchans = 5;
- break;
- case DM_5_1:
- printf("Decoding to 5.1 surround (David Moore)\n");
- if(inorder==1)
- decodefunc = dm_i1_surr6;
- else
- decodefunc = dm_i2_surr6;
- outchans = 6;
- break;
- case FM_HEX:
- printf("Decoding to Hexagon\n");
- if(inorder==1)
- decodefunc = fm_i1_hex;
- else
- decodefunc = fm_i2_hex;
- outchans = 6;
- break;
- case FM_OCT1:
- printf("Decoding to Octagon 1\n");
- if(inorder==1)
- decodefunc = fm_i1_oct1;
- else
- decodefunc = fm_i2_oct1;
- outchans = 8;
- break;
- case FM_OCT2:
- printf("Decoding to Octagon 2\n");
- if(inorder==1)
- decodefunc = fm_i1_oct2;
- else
- decodefunc = fm_i2_oct2;
- outchans = 8;
- break;
- case FM_CUBE:
- printf("Decoding to Cube (FM interleaved)\n");
- if(inorder==1)
- decodefunc = fm_i1_cube;
- else
- decodefunc = fm_i2_cube;
- outchans = 8;
- break;
- case FM_QUADCUBE:
- printf("Decoding to Octagon 1 (WAVEX order)\n");
- if(inorder==1)
- decodefunc = fm_i1_cubex;
- else
- decodefunc = fm_i2_cubex;
- outchans = 8;
- break;
- default:
- //quad
- printf("Decoding to quad surround (WAVEX order)\n");
- if(inorder == 1)
- decodefunc = fm_i1_quad;
- else
- decodefunc = fm_i2_quad;
- outchans = 4;
- break;
- }
- } // MC_BFMT
-
- /* just read peaks for soundfile */
- fpeaks = (CHPEAK *) calloc(inchans,sizeof(CHPEAK));
- if(fpeaks==NULL){
- puts("No memory for PEAK data\n");
- goto error;
- }
- int thispeaktime;
- res = sndreadpeaks(sfdata.ifd,inchans,fpeaks, &thispeaktime);
- in_peaktime = (time_t) thispeaktime;
- if(res==0){
- printf("No PEAK data in this file\n");
- }
- if(res > 0) {
- printf("PEAK data:\ncreation time: %s",ctime( &in_peaktime));
-
- for(i=0;i < inchans;i++){
- printf("CH %d: %.4f at frame %u: \t%.4f secs\n",
- i,fpeaks[i].value,fpeaks[i].position,(double)(fpeaks[i].position / (double) props.srate));
- }
- }
- break;
- default:
- fprintf(stderr,"\nSorry: Pvplay can only play soundfiles and analysis files.");
- return 1;
- }
- }
- /* memory playback mode? */
- if(playtype == PLAY_SFILE && nFramesToPlay <= ringframelen){
- sfdata.membuf = (float *) PaUtil_AllocateMemory(nFramesToPlay * sizeof(float) * /*inchans*/ outchans);
- if( sfdata.membuf == NULL ) {
- puts("Could not allocate memory play buffer.\n");
- goto error;
- }
- sfdata.memFramelength = nFramesToPlay;
- sfdata.memFramePos = 0;
- playcallback = MemCallback;
- printf("RAM block size = %lu\n",nFramesToPlay);
-
- }
- else {
- // set up pcm ring buffer NB must be power of 2 size
- if(props.srate > 48000)
- ringframelen <<= 1;
- printf("File buffer size set to %ld sample frames\n",ringframelen);
- // NB ring buffer sized for decoded data, hence outchans here; otherwise inchans = outchans
- sfdata.ringbufData = (float *) PaUtil_AllocateMemory( ringframelen * sizeof(float) * outchans); /* From now on, recordedSamples is initialised. */
- if( sfdata.ringbufData == NULL ) {
- puts("Could not allocate play buffer.\n");
- goto error;
- }
- // number of elements has to be a power of two, so each element has to be a full m/c frame
- if (PaUtil_InitializeRingBuffer(&sfdata.ringbuf, sizeof(float) * outchans, ringframelen , sfdata.ringbufData) < 0) {
- puts("Could not initialise play buffer.\n");
- goto error;
- }
- }
-
-
- /* create input side workspace buffer, used for both soundfiles and analysis files! */
- sfdata.inbuf = (float *) PaUtil_AllocateMemory(ringframelen * sizeof(float) * inchans);
- if(sfdata.inbuf==NULL){
- puts("No memory for read buffer\n");
- goto error;
- }
- sfdata.inbuflen = ringframelen;
-
- if(playtype == PLAY_PVXFILE && (inchans==2)){
- sfdata.outbuf_l = (float *) PaUtil_AllocateMemory(ringframelen * sizeof(float) );
- sfdata.outbuf_r = (float *) PaUtil_AllocateMemory(ringframelen * sizeof(float) );
-
- }
-
- if(props.srate > 48000)
- frames_per_buffer *= 2;
- if(frames_per_buffer > 0)
- printf("Audio buffer size = %lu\n",frames_per_buffer);
-
- sfdata.inchans = inchans;
- sfdata.outchans = outchans;
- sfdata.frames_played = 0;
- sfdata.gain = gain;
- sfdata.copyfunc = copyfunc;
- sfdata.decodefunc = decodefunc;
- sfdata.do_decode = flags[FLAG_B];
- sfdata.from_frame = from_frame; // interpreted according to Play Type
- sfdata.to_frame = to_frame;
- sfdata.play_looped = flags[FLAG_L];
- sfdata.srate = props.srate;
- sfdata.finished = 0;
- g_pdata = &sfdata;
-
- outputParameters.device = device; /*Pa_GetDefaultOutputDevice(); */ /* default output device */
- outputParameters.channelCount = outchans;
- outputParameters.sampleFormat = paFloat32; /* 32 bit floating point output */
- outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency;
- outputParameters.hostApiSpecificStreamInfo = NULL;
-
- devinfo = (PaDeviceInfo *) Pa_GetDeviceInfo(device);
- #if defined MAC || defined unix
- if(devinfo){
- printf("Using device %d: %s\n",device,devinfo->name);
- }
- #endif
-
- #ifdef WIN32
-
- # ifdef NOTDEF
- if(devinfo){
- if(apiinfo->type == paMME ){
- winmmeStreamInfo.size = sizeof(winmmeStreamInfo);
- winmmeStreamInfo.hostApiType = paMME;
- winmmeStreamInfo.version = 1;
- winmmeStreamInfo.flags = paWinMmeUseChannelMask;
- winmmeStreamInfo.channelMask = 0;
- outputParameters.hostApiSpecificStreamInfo = &winmmeStreamInfo;
- # ifdef _DEBUG
- printf("WIN DEBUG: WinMME device channel mask set to 0.\n");
- # endif
- }
- }
- # endif
- /* change val to 1 if also using MME */
- if(devinfo){
- int apitype = devinfo->hostApi; // get index of api type
- const PaHostApiInfo *apiinfo = Pa_GetHostApiInfo( apitype );
- printf("Using device %d: %s:",device,devinfo->name);
- if(apiinfo->type == paDirectSound) {
- printf ("(DS)\n");
- /* set this IF we are using Dsound device. */
- directSoundStreamInfo.size = sizeof(PaWinDirectSoundStreamInfo);
- directSoundStreamInfo.hostApiType = paDirectSound;
- directSoundStreamInfo.version = 2;
- directSoundStreamInfo.flags = paWinDirectSoundUseChannelMask;
- directSoundStreamInfo.channelMask = speakermask;
- outputParameters.hostApiSpecificStreamInfo = &directSoundStreamInfo;
- }
- else if(apiinfo->type == paASIO)
- printf("(ASIO)\n");
- // else
- // printf("API unknown!);
- }
- #endif
-
-
- err = Pa_OpenStream(
- &stream,
- NULL, /* No input */
- &outputParameters, /* As above. */
- props.srate,
- frames_per_buffer, /* Frames per buffer. */
- paClipOff, /* we won't output out of range samples so don't bother clipping them */
- playcallback,
- &sfdata );
-
- if( err != paNoError ){
- fprintf(stderr,"Unable to open audio device: err = %d\n", err);
- exit(1);
- }
- err = Pa_SetStreamFinishedCallback( stream, finishedCallback );
- if( err != paNoError ) {
- printf("Unable to set finish callback\n");
- goto error;
- }
- sfdata.stream = stream;
- file_playing = 1;
- if(waitkey){
- printf("Press any key to start:\n");
- printf("Hit CTRL-C to stop.\n");
- fflush(stdout);
- while (!kbhit()){
- if(!file_playing) //check for instant CTRL-C
- goto error;
- };
- #ifdef _WIN32
- if(kbhit())
- _getch(); //prevent display of char
- #endif
- }
- // should this go in read thread func too?
-
-
- #ifdef NOTDEF
- // TODO: any benefits in using this?
- pterror = Pt_Start(200, porttimeCallback, NULL);
- if(pterror != ptNoError){
- printf("porttime timer failed to initialise!\n");
- return 1;
- }
- #endif
-
- /* if small block, read it all into memory
- NB not doing paplay channel mapping */
- if(sfdata.memFramelength > 0){
- //if(psf_sndReadFloatFrames(sfdata.ifd,sfdata.membuf,sfdata.memFramelength)
- if(fgetfbufEx(sfdata.membuf,sfdata.memFramelength*sfdata.inchans,sfdata.ifd,0)
- != (int) sfdata.memFramelength*sfdata.inchans) {
- printf("Error reading soundfile into memory\n");
- goto error;
- }
- }
-
- // set up timer
- #ifdef unix
- if(do_updatemessages) {
- setitimer(ITIMER_REAL, &tout_val,0);
- signal(SIGALRM,alarm_wakeup); /* set the Alarm signal capture */
- }
- #endif
- //#ifdef _WIN32
- // not sure of the best position for this
- //if(!CreateTimerQueueTimer(&sfdata.hTimer, hTimerQueue,
- // (WAITORTIMERCALLBACK) TimerCallback, &sfdata,250,250,0)) {
- // printf("failed to start timer (3).\n");
- // return 1;
- // }
- //#endif
- /* Start the file reading thread */
-
- sfdata.startTime = Pa_GetStreamTime(stream );
-
- switch(playtype){
- case PLAY_SFILE:
- if(sfdata.memFramelength == 0){
- err = startThread(&sfdata, threadFunctionReadFromRawFile);
- if( err != paNoError ) goto error;
- }
- else {
- sfdata.flag = 0;
- }
- break;
- case PLAY_ANAFILE:
- err = startThread(&sfdata, threadFunctionReadFromAnalFile);
- if( err != paNoError ) goto error;
- break;
- case PLAY_PVXFILE:
- err = startThread(&sfdata, threadFunctionReadFromPVXFile);
- if( err != paNoError ) goto error;
- break;
- default:
- printf("Internal error: no playback file type!\n");
- return 1;
-
- }
-
- #ifdef _WIN32
- if(do_updatemessages){
- if(!CreateTimerQueueTimer(&sfdata.hTimer, hTimerQueue,
- (WAITORTIMERCALLBACK) TimerCallback, &sfdata,200,200,0)) {
- printf("failed to start timer (3).\n");
- return 1;
- }
- }
- #endif
- err = Pa_StartStream( stream );
- if( err != paNoError ) {
- fprintf(stderr,"Unable to start playback.\n");
- goto error;
- }
-
- while((!sfdata.finished) && file_playing){
- // nothing to do!
- Pa_Sleep(20);
- }
- // note to the curious: any bug in audio buffer arithmetic will likely cause crash here!
- err = Pa_StopStream( stream );
- if( err != paNoError ) {
- printf("Error stopping stream\n");
- goto error;
- }
- /* read thread should exit always, no need to Stop it here */
-
- err = Pa_CloseStream( stream );
- if( err != paNoError ) {
- printf("Error closing stream\n");
- goto error;
- }
- printf("%.2f secs\n",(float)(sfdata.lastTime));
- fflush(stdout);
- printf("Playback finished.\n");
- error:
- Pa_Terminate();
- #ifdef _WIN32
- CloseHandle(ghEvent);
- DeleteTimerQueue(hTimerQueue);
- #endif
- if( sfdata.ringbufData )
- PaUtil_FreeMemory(sfdata.ringbufData);
-
- if(sfdata.inbuf)
- PaUtil_FreeMemory(sfdata.inbuf);
-
- if(sfdata.membuf)
- PaUtil_FreeMemory(sfdata.membuf);
-
- if(sfdata.outbuf_l)
- PaUtil_FreeMemory(sfdata.outbuf_l);
-
- if(sfdata.outbuf_r)
- PaUtil_FreeMemory(sfdata.outbuf_r);
-
- if(sfdata.ifd >= 0)
- sndcloseEx(sfdata.ifd);
-
- if(sfdata.pvfile >= 0)
- pvoc_closefile(sfdata.pvfile);
-
- if(fpeaks)
- free(fpeaks);
-
- // sffinish();
-
- pvsys_release();
-
- if(err != paNoError){
- 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 err;
- }
- return 0;
- }
- int show_devices(void)
- {
- // int i,j;
- PaDeviceIndex numDevices,p;
- const PaDeviceInfo *pdi;
- #ifdef _WIN32
- const PaHostApiInfo* api_info;
- #endif
- PaError err;
- // int nOutputDevices = 0;
-
- #ifdef USE_ASIO
- printf("For ASIO multi-channel, you may need to select the highest device no.\n");
- #endif
- /*Pa_Initialize();*/
- numDevices = Pa_GetDeviceCount();
- if( numDevices < 0 )
- {
- printf("ERROR: Pa_CountDevices returned 0x%x\n", numDevices );
- err = numDevices;
- return err;
- }
- #ifdef WIN32
- printf("Driver\tDevice\tInput\tOutput\tName\n");
- #else
- printf("Device\tInput\tOutput\tName\n");
- #endif
- //printf("Number of devices = %d\n", numDevices );
- for( p=0; p<numDevices; p++ )
- {
- pdi = Pa_GetDeviceInfo( p );
- // nOutputDevices++;
-
- if( p == Pa_GetDefaultOutputDevice() )
- printf("*");
- else
- printf(" ");
- #ifdef WIN32
- api_info = Pa_GetHostApiInfo(pdi->hostApi);
- const char *apiname = api_info->name;
- if(strcmp(apiname,"Windows DirectSound")==0)
- apiname = "DS ";
- printf("(%s)\t%d\t%d\t%d\t%s\n",apiname,p,
- pdi->maxInputChannels,
- pdi->maxOutputChannels,
- pdi->name);
- #else
- printf("%d\t%d\t%d\t%s\n",p,
- pdi->maxInputChannels,
- pdi->maxOutputChannels,
- pdi->name);
- #endif
- }
- /*Pa_Terminate();*/
- return 0;
- }
- #ifdef unix
- int stricmp(const char *a, const char *b)
- {
- while(*a != '\0' && *b != '\0') {
- int ca = islower(*a) ? toupper(*a) : *a;
- int cb = islower(*b) ? toupper(*b) : *b;
-
- if(ca < cb)
- return -1;
- if(ca > cb)
- return 1;
-
- a++;
- b++;
- }
- if(*a == '\0' && *b == '\0')
- return 0;
- if(*a != '\0')
- return 1;
- return -1;
- }
- int
- strnicmp(const char *a, const char *b, const int length)
- {
- int len = length;
-
- while(*a != '\0' && *b != '\0') {
- int ca = islower(*a) ? toupper(*a) : *a;
- int cb = islower(*b) ? toupper(*b) : *b;
-
- if(len-- < 1)
- return 0;
-
- if(ca < cb)
- return -1;
- if(ca > cb)
- return 1;
-
- a++;
- b++;
- }
- if(*a == '\0' && *b == '\0')
- return 0;
- if(*a != '\0')
- return 1;
- return -1;
- }
- #endif
|