Julius 4.1.5
libsent/src/adin/adin_portaudio.c
説明を見る。
00001 
00062 /*
00063  * Copyright (c) 2004-2005 Shikano Lab., Nara Institute of Science and Technology
00064  * Copyright (c) 2005-2007 Julius project team, Nagoya Institute of Technology
00065  * All rights reserved
00066  */
00067 
00068 #include <sent/stddefs.h>
00069 #include <sent/speech.h>
00070 #include <sent/adin.h>
00071 
00072 /* sound header */
00073 #include <portaudio.h>
00074 
00075 #ifndef paNonInterleaved
00076 #define OLDVER
00077 #endif
00078 
00079 #undef DDEBUG
00080 
00094 #ifndef OLDVER
00095 #define CHOOSE_HOST_API
00096 #endif
00097 
00107 #ifdef OLDVER
00108 #define MAX_FRAGMENT_MSEC 128
00109 #endif
00110 
00111 /* temporal buffer */
00112 static SP16 *speech;            
00113 static int current;             
00114 static int processed;           
00115 static boolean buffer_overflowed = FALSE; 
00116 static int cycle_buffer_len;    
00117 
00130 static int
00131 #ifdef OLDVER
00132 Callback(void *inbuf, void *outbuf, unsigned long len, PaTimestamp outTime, void *userdata)
00133 #else
00134 Callback(const void *inbuf, void *outbuf, unsigned long len, const PaStreamCallbackTimeInfo *outTime, PaStreamCallbackFlags statusFlags, void *userdata)
00135 #endif
00136 {
00137 #ifdef OLDVER
00138   SP16 *now;
00139   int avail;
00140 #else
00141   const SP16 *now;
00142   unsigned long avail;
00143 #endif
00144   int processed_local;
00145   int written;
00146 
00147   now = inbuf;
00148 
00149   processed_local = processed;
00150 
00151 #ifdef DDEBUG
00152   printf("callback-1: processed=%d, current=%d: recordlen=%d\n", processed_local, current, len);
00153 #endif
00154 
00155   /* check overflow */
00156   if (processed_local > current) {
00157     avail = processed_local - current;
00158   } else {
00159     avail = cycle_buffer_len + processed_local - current;
00160   }
00161   if (len > avail) {
00162 #ifdef DDEBUG
00163     printf("callback-*: buffer overflow!\n");
00164 #endif
00165     buffer_overflowed = TRUE;
00166     len = avail;
00167   }
00168 
00169   /* store to buffer */
00170   if (current + len <= cycle_buffer_len) {
00171     memcpy(&(speech[current]), now, len * sizeof(SP16));
00172 #ifdef DDEBUG
00173     printf("callback-2: [%d..%d] %d samples written\n", current, current+len, len);
00174 #endif
00175   } else {
00176     written = cycle_buffer_len - current;
00177     memcpy(&(speech[current]), now, written * sizeof(SP16));
00178 #ifdef DDEBUG
00179     printf("callback-2-1: [%d..%d] %d samples written\n", current, current+written, written);
00180 #endif
00181     memcpy(&(speech[0]), &(now[written]), (len - written) * sizeof(SP16));
00182 #ifdef DDEBUG
00183     printf("callback-2-2: ->[%d..%d] %d samples written (total %d samples)\n", 0, len-written, len-written, len);
00184 #endif
00185   }
00186   current += len;
00187   if (current >= cycle_buffer_len) current -= cycle_buffer_len;
00188 #ifdef DDEBUG
00189   printf("callback-3: new current: %d\n", current);
00190 #endif
00191 
00192   return(0);
00193 }
00194 
00195 #ifdef OLDVER
00196 static PortAudioStream *stream;         
00197 #else
00198 static PaStream *stream;                
00199 #endif
00200 
00209 boolean
00210 adin_mic_standby(int sfreq, void *dummy)
00211 {
00212   PaError err;
00213 #ifdef OLDVER
00214   int frames_per_buffer;
00215   int num_buffer;
00216 #endif
00217   int latency;
00218   char *p;
00219 
00220   /* set cycle buffer length */
00221   cycle_buffer_len = INPUT_DELAY_SEC * sfreq;
00222   jlog("Stat: adin_portaudio: INPUT_DELAY_SEC = %d\n", INPUT_DELAY_SEC);
00223   jlog("Stat: adin_portaudio: audio cycle buffer length = %d bytes\n", cycle_buffer_len * sizeof(SP16));
00224 
00225 #ifdef OLDVER
00226   /* for safety... */
00227   if (sizeof(SP16) != paInt16) {
00228     jlog("Error: adin_portaudio: SP16 != paInt16 !!\n");
00229     return FALSE;
00230   }
00231   /* set buffer parameter*/
00232   frames_per_buffer = 256;
00233 #endif
00234 
00235   /* allocate and init */
00236   current = processed = 0;
00237   speech = (SP16 *)mymalloc(sizeof(SP16) * cycle_buffer_len);
00238   buffer_overflowed = FALSE;
00239 
00240 
00241   /* get user-specified latency parameter */
00242   latency = 0;
00243   if ((p = getenv("LATENCY_MSEC")) != NULL) {
00244     latency = atoi(p);
00245     jlog("Stat: adin_portaudio: setting latency to %d msec (obtained from LATENCY_MSEC)\n", latency);
00246   }
00247 #ifdef OLDVER
00248   if (latency == 0) {
00249     latency = MAX_FRAGMENT_MSEC;
00250     jlog("Stat: adin_portaudio: setting latency to %d msec\n", latency);
00251   }
00252   num_buffer = sfreq * latency / (frames_per_buffer * 1000);
00253   jlog("Stat: adin_portaudio: framesPerBuffer=%d, NumBuffers(guess)=%d\n",
00254        frames_per_buffer, num_buffer);
00255   jlog("Stat: adin_portaudio: audio I/O Latency = %d msec (data fragment = %d frames)\n",
00256            (frames_per_buffer * num_buffer) * 1000 / sfreq, 
00257            (frames_per_buffer * num_buffer));
00258 #endif
00259 
00260   /* initialize device */
00261   err = Pa_Initialize();
00262   if (err != paNoError) {
00263     jlog("Error: adin_portaudio: failed to initialize: %s\n", Pa_GetErrorText(err));
00264     return(FALSE);
00265   }
00266 
00267 #ifdef CHOOSE_HOST_API
00268 
00269   {
00270     // choose a device to open
00271     // For win32, preference order is WASAPI > ASIO > DirectSound > MME
00272     // If several device matches the first found one will be used.
00273     int devId;
00274     PaDeviceIndex numDevice = Pa_GetDeviceCount(), i;
00275     const PaDeviceInfo *deviceInfo;
00276     const PaHostApiInfo *apiInfo;
00277     PaStreamParameters param;
00278     char *devname;
00279     static char buf[256];
00280 #ifdef _WIN32
00281     // at win32, force preference order: iWASAPI > ASIO > DirectSound > MME > Other
00282     int iMME = -1, iDS = -1, iASIO = -1, iWASAPI = -1;
00283 #endif
00284 
00285         // if PORTAUDIO_DEV is specified, match it against available APIs
00286     devname = getenv("PORTAUDIO_DEV");
00287     devId = -1;
00288 
00289         // get list of available capture devices
00290     jlog("Stat: adin_portaudio: available capture devices:\n");
00291     for(i=0;i<numDevice;i++) {
00292       deviceInfo = Pa_GetDeviceInfo(i);
00293       if (!deviceInfo) continue;
00294       if (deviceInfo->maxInputChannels <= 0) continue;
00295       apiInfo = Pa_GetHostApiInfo(deviceInfo->hostApi);
00296       if (!apiInfo) continue;
00297       snprintf(buf, 255, "%s: %s", apiInfo->name, deviceInfo->name);
00298       buf[255] = '\0';
00299       jlog("  #%d [%s]\n", i+1, buf);
00300       if (devname && !strncmp(devname, buf, strlen(devname))) {
00301                   // device name (partially) matches PORTAUDIO_DEV
00302         devId = i;
00303       }
00304 #ifdef _WIN32
00305           // store the device ID for each API
00306       switch(apiInfo->type) {
00307           case paWASAPI: if (iWASAPI < 0) iWASAPI = i; break;
00308       case paMME:if (iMME   < 0) iMME   = i; break;
00309       case paDirectSound:if (iDS    < 0) iDS    = i; break;
00310       case paASIO:if (iASIO  < 0) iASIO  = i; break;
00311       }
00312 #endif
00313     }
00314     if (devId != -1) {
00315       jlog("  --> #%d matches PORTAUDIO_DEV, use it\n", devId + 1);
00316     }
00317     if (devId == -1) {
00318       if (getenv("PORTAUDIO_DEV_NUM")) {
00319         devId = atoi(getenv("PORTAUDIO_DEV_NUM")) - 1;
00320         jlog("  --> use #%d, specified by PORTAUDIO_DEV_NUM\n", devId + 1);
00321       }
00322     }
00323 #ifdef _WIN32
00324     if (devId == -1) {
00325       // if PORTAUDIO_DEV not specified or not matched, use device in the preference order.
00326       if (iWASAPI >= 0) devId = iWASAPI;
00327       else if (iASIO >= 0) devId = iASIO;
00328       else if (iDS >= 0) devId = iDS;
00329       else if (iMME >= 0) devId = iMME;
00330       else devId = -1;
00331     }
00332 #endif
00333         if (devId == -1) {
00334       // No device has been found, try to get the default input device
00335       devId = Pa_GetDefaultInputDevice();
00336           if (devId == paNoDevice) {
00337                   jlog("Error: adin_portaudio: no default input device is available or an error was encountered\n");
00338                   return FALSE;
00339           }
00340     }
00341     // output device information
00342     deviceInfo = Pa_GetDeviceInfo(devId);
00343     apiInfo = Pa_GetHostApiInfo(deviceInfo->hostApi);
00344     snprintf(buf, 255, "%s: %s", apiInfo->name, deviceInfo->name);
00345     buf[255] = '\0';
00346     jlog("Stat: adin_portaudio: get input from: [%s]\n", buf);
00347     jlog("Info: adin_portaudio: set \"PORTAUDIO_DEV\" to the string in \"[]\" above to change\n");
00348 
00349         // open the device
00350       memset( &param, 0, sizeof(param));
00351       param.channelCount = 1;
00352       param.device = devId;
00353       param.sampleFormat = paInt16;
00354           if (latency == 0) {
00355               param.suggestedLatency = Pa_GetDeviceInfo(devId)->defaultLowInputLatency;
00356                   jlog("Stat: adin_portaudio: try to set default low latency from portaudio: %d msec\n", param.suggestedLatency * 1000.0);
00357           } else {
00358               param.suggestedLatency = latency / 1000.0;
00359                   jlog("Stat: adin_portaudio: try to set latency to %d msec\n", param.suggestedLatency * 1000.0);
00360           }
00361       err = Pa_OpenStream(&stream, &param, NULL, sfreq, 
00362                           0, paNoFlag,
00363                           Callback, NULL);
00364       if (err != paNoError) {
00365         jlog("Error: adin_portaudio: error in opening stream: %s\n", Pa_GetErrorText(err));
00366         return(FALSE);
00367       }
00368     {
00369       const PaStreamInfo *stinfo;
00370       stinfo = Pa_GetStreamInfo(stream);
00371       jlog("Stat: adin_portaudio: latency was set to %f msec\n", stinfo->inputLatency * 1000.0);
00372     }
00373   }
00374 
00375 #else
00376 
00377   err = Pa_OpenDefaultStream(&stream, 1, 0, paInt16, sfreq, 
00378 #ifdef OLDVER
00379                              frames_per_buffer,
00380                              num_buffer, 
00381 #else
00382                                  0,
00383 #endif
00384                              Callback, NULL);
00385   if (err != paNoError) {
00386     jlog("Error: adin_portaudio: error in opening stream: %s\n", Pa_GetErrorText(err));
00387     return(FALSE);
00388   }
00389 
00390 #endif /* CHOOSE_HOST_API */
00391 
00392   return(TRUE);
00393 }
00394 
00402 boolean
00403 adin_mic_begin(char *pathname)
00404 {
00405   PaError err;
00406 
00407   /* start stream */
00408   err = Pa_StartStream(stream);
00409   if (err != paNoError) {
00410     jlog("Error: adin_portaudio: failed to begin stream: %s\n", Pa_GetErrorText(err));
00411     return(FALSE);
00412   }
00413   
00414   return(TRUE);
00415 }
00416 
00422 boolean
00423 adin_mic_end()
00424 {
00425   PaError err;
00426 
00427   /* stop stream */
00428   err = Pa_StopStream(stream);
00429   if (err != paNoError) {
00430     jlog("Error: adin_portaudio: failed to stop stream: %s\n", Pa_GetErrorText(err));
00431     return(FALSE);
00432   }
00433   
00434   return TRUE;
00435 }
00436 
00449 int
00450 adin_mic_read(SP16 *buf, int sampnum)
00451 {
00452   int current_local;
00453   int avail;
00454   int len;
00455 
00456   if (buffer_overflowed) {
00457     jlog("Error: adin_portaudio: input buffer OVERFLOW, increase INPUT_DELAY_SEC in sent/speech.h\n");
00458     buffer_overflowed = FALSE;
00459   }
00460 
00461   while (current == processed) {
00462 #ifdef DDEBUG
00463     printf("process  : current == processed: %d: wait\n", current);
00464 #endif
00465     Pa_Sleep(20); /* wait till some input comes */
00466   }
00467 
00468   current_local = current;
00469 
00470 #ifdef DDEBUG
00471   printf("process-1: processed=%d, current=%d\n", processed, current_local);
00472 #endif
00473 
00474   if (processed < current_local) {
00475     avail = current_local - processed;
00476     if (avail > sampnum) avail = sampnum;
00477     memcpy(buf, &(speech[processed]), avail * sizeof(SP16));
00478 #ifdef DDEBUG
00479     printf("process-2: [%d..%d] %d samples read\n", processed, processed+avail, avail);
00480 #endif
00481     len = avail;
00482     processed += avail;
00483   } else {
00484     avail = cycle_buffer_len - processed;
00485     if (avail > sampnum) avail = sampnum;
00486     memcpy(buf, &(speech[processed]), avail * sizeof(SP16));
00487 #ifdef DDEBUG
00488     printf("process-2-1: [%d..%d] %d samples read\n", processed, processed+avail, avail);
00489 #endif
00490     len = avail;
00491     processed += avail;
00492     if (processed >= cycle_buffer_len) processed -= cycle_buffer_len;
00493     if (sampnum - avail > 0) {
00494       if (sampnum - avail < current_local) {
00495         avail = sampnum - avail;
00496       } else {
00497         avail = current_local;
00498       }
00499       if (avail > 0) {
00500         memcpy(&(buf[len]), &(speech[0]), avail * sizeof(SP16));
00501 #ifdef DDEBUG
00502         printf("process-2-2: [%d..%d] %d samples read (total %d)\n", 0, avail, avail, len + avail);
00503 #endif
00504         len += avail;
00505         processed += avail;
00506         if (processed >= cycle_buffer_len) processed -= cycle_buffer_len;
00507       }
00508     }
00509   }
00510 #ifdef DDEBUG
00511   printf("process-3: new processed: %d\n", processed);
00512 #endif
00513   return len;
00514 }
00515 
00523 char *
00524 adin_mic_input_name()
00525 {
00526   return("Portaudio default device");
00527 }