/**
* @file adinrec.c
*
*
* @brief マイクから一発話をファイルへ記録する
*
*
*
* @brief Record a speech segment from microphone to a file
*
*
* @author Akinobu LEE
* @date Wed Mar 23 20:33:01 2005
*
* $Revision: 1.11 $
*
*/
/*
* Copyright (c) 1991-2012 Kawahara Lab., Kyoto University
* Copyright (c) 2001-2005 Shikano Lab., Nara Institute of Science and Technology
* Copyright (c) 2005-2012 Julius project team, Nagoya Institute of Technology
* All rights reserved
*/
#include
#include
static int speechlen; ///< Total length of recorded sample
static int fd = -1; ///< File descriptor for output
static FILE *fp = NULL; ///< File pointer for WAV output
static int size; ///< Output file size
static int sfreq;
static char *filename = NULL; ///< Output file name
static boolean stout = FALSE; ///< True if output to stdout
static boolean use_raw = FALSE; ///< Output in RAW format if TRUE
/**
* ヘルプを表示して終了する
* Print help and exit
*/
static boolean
opt_help(Jconf *jconf, char *arg[], int argnum)
{
fprintf(stderr, "adinrec --- record one sentence input to a file\n");
fprintf(stderr, "Usage: adinrec [options..] filename\n");
fprintf(stderr, " [-input mic|pulseaudio|alsa|oss|esd|...] input source (mic)\n");
fprintf(stderr, " [-freq frequency] sampling frequency in Hz (%d)\n", jconf->am_root->analysis.para_default.smp_freq);
fprintf(stderr, " [-48] 48000Hz recording with down sampling (16kHz only)\n");
fprintf(stderr, " [-lv unsignedshort] silence cut level threshold (%d)\n", jconf->detect.level_thres);
fprintf(stderr, " [-zc zerocrossnum] silence cut zerocross num (%d)\n", jconf->detect.zero_cross_num);
fprintf(stderr, " [-headmargin msec] head margin length (%d)\n", jconf->detect.head_margin_msec);
fprintf(stderr, " [-tailmargin msec] tail margin length (%d)\n", jconf->detect.tail_margin_msec);
fprintf(stderr, " [-chunksize sample] chunk size for processing (%d)\n", jconf->detect.chunk_size);
fprintf(stderr, " [-nostrip] not strip off zero samples\n");
fprintf(stderr, " [-zmean] remove DC by zero mean\n");
fprintf(stderr, " [-nocutsilence] disable VAD, record all stream\n");
fprintf(stderr, " [-raw] output in RAW format\n");
fprintf(stderr, "\nLibrary configuration: ");
confout_version(stderr);
confout_audio(stderr);
confout_process(stderr);
fprintf(stderr, "\n");
exit(1); /* exit here */
return TRUE;
}
static boolean
opt_raw(Jconf *jconf, char *arg[], int argnum)
{
use_raw = TRUE;
return TRUE;
}
static boolean
opt_freq(Jconf *jconf, char *arg[], int argnum)
{
jconf->amnow->analysis.para.smp_freq = atoi(arg[0]);
jconf->amnow->analysis.para.smp_period = freq2period(jconf->amnow->analysis.para.smp_freq);
return TRUE;
}
/**
*
* 録音されたサンプル列を処理するコールバック関数
*
* @param now [in] 録音されたサンプル列
* @param len [in] 長さ(サンプル数)
*
* @return エラー時 -1,処理成功時 0,処理成功+区間終端検出時 1 を返す.
*
*
* Callback handler of recorded sample fragments
*
* @param now [in] recorded fragments of speech sample
* @param len [in] length of above in samples
*
* @return -1 on device error (require caller to exit and terminate input),
* 0 on success (allow caller to continue),
* 1 on succeeded but segmentation detected (require caller to exit but
* input will continue in the next call.
*
*/
static int
adin_callback_file(SP16 *now, int len, Recog *recog)
{
int count;
/* erase "<<>>" text on tty at trigger up */
if (speechlen == 0) {
fprintf(stderr, "\r \r");
}
/* open output file for the first time */
if (use_raw) {
if (fd == -1) {
if (stout) {
fd = 1;
} else {
if ((fd = open(filename, O_CREAT | O_RDWR
#ifdef O_BINARY
| O_BINARY
#endif
, 0644)) == -1) {
perror("adinrec");
return -1;
}
}
}
} else {
if (fp == NULL) {
if ((fp = wrwav_open(filename, sfreq)) == NULL) {
perror("adinrec");
return -1;
}
}
}
/* write recorded sample to file */
if (use_raw) {
count = wrsamp(fd, now, len);
if (count < 0) {
perror("adinrec: cannot write");
return -1;
}
if (count < len * sizeof(SP16)) {
fprintf(stderr, "adinrec: cannot write more %d bytes\ncurrent length = %d\n", count, speechlen * sizeof(SP16));
return -1;
}
} else {
if (wrwav_data(fp, now, len) == FALSE) {
fprintf(stderr, "adinrec: cannot write\n");
return -1;
}
}
speechlen += len;
/* progress bar in dots */
fprintf(stderr, ".");
return(0);
}
/* close file */
static void
close_file()
{
size = sizeof(SP16) * speechlen;
if (use_raw) {
if (fd >= 0) {
if (close(fd) != 0) {
perror("adinrec");
}
}
} else {
if (fp != NULL) {
if (wrwav_close(fp) == FALSE) {
fprintf(stderr, "adinrec: failed to close file\n");
}
}
}
fprintf(stderr, "\n%d samples (%d bytes, %.2f sec.) recorded\n", speechlen, size, (float)speechlen / (float)sfreq);
}
/* Interrupt signal handling */
static void
interrupt_record(int signum)
{
fprintf(stderr, "[Interrupt]");
/* close files */
close_file();
/* terminate program */
exit(1);
}
/**
*
* メイン関数
*
* @param argc [in] 引数列の長さ
* @param argv [in] 引数列
*
* @return
* エラー時 1,通常終了時 0 を返す.
*
* Main function.
*
* @param argc [in] number of argument.
* @param argv [in] array of arguments.
*
* @return 1 on error, 0 on success.
*
*/
int
main(int argc, char *argv[])
{
Recog *recog;
Jconf *jconf;
/* create instance */
jconf = j_jconf_new();
/* register application options */
j_add_option("-freq", 1, 1, "sampling frequency in Hz", opt_freq);
j_add_option("-raw", 0, 0, "save in raw (BE) format", opt_raw);
j_add_option("-h", 0, 0, "display this help", opt_help);
j_add_option("-help", 0, 0, "display this help", opt_help);
j_add_option("--help", 0, 0, "display this help", opt_help);
/* when no argument, output help and exit */
if (argc <= 1) {
opt_help(jconf, NULL, 0);
return 0;
}
/* regard last arg as filename */
if (strmatch(argv[argc-1], "-")) {
stout = TRUE;
use_raw = TRUE;
} else {
filename = argv[argc-1];
}
/* set default as same as "-input mic" */
jconf->input.type = INPUT_WAVEFORM;
jconf->input.speech_input = SP_MIC;
jconf->input.device = SP_INPUT_DEFAULT;
/* read arguments and set parameters */
if (j_config_load_args(jconf, argc-1, argv) == -1) {
fprintf(stderr, "Error reading arguments\n");
return -1;
}
/* exit if no file name specified */
if (filename == NULL && stout == FALSE) {
opt_help(jconf, NULL, 0);
return -1;
}
/* finalize config */
//if (j_jconf_finalize(jconf) == FALSE) return -1;
/* set Julius default parameters for unspecified acoustic parameters */
apply_para(&(jconf->am_root->analysis.para), &(jconf->am_root->analysis.para_default));
/* set some values */
jconf->input.sfreq = jconf->am_root->analysis.para.smp_freq;
jconf->input.period = jconf->am_root->analysis.para.smp_period;
jconf->input.frameshift = jconf->am_root->analysis.para.frameshift;
jconf->input.framesize = jconf->am_root->analysis.para.framesize;
/* preliminary check of output file */
/* (output file will be opened later when input is triggered) */
if (!stout) {
if (access(filename, F_OK) == 0) {
if (access(filename, W_OK) == 0) {
fprintf(stderr, "Warning: overwriting file \"%s\"\n", filename);
} else {
perror("adinrec");
return(1);
}
}
}
/* set signal handlers to properly close output file */
if (signal(SIGINT, interrupt_record) == SIG_ERR) {
fprintf(stderr, "Warning: signal intterupt may collapse output\n");
}
if (signal(SIGTERM, interrupt_record) == SIG_ERR) {
fprintf(stderr, "Warning: signal intterupt may collapse output\n");
}
#ifdef SIGPIPE
if (signal(SIGPIPE, interrupt_record) == SIG_ERR) {
fprintf(stderr, "Warning: signal intterupt may collapse output\n");
}
#endif
#ifdef SIGQUIT
if (signal(SIGQUIT, interrupt_record) == SIG_ERR) {
fprintf(stderr, "Warning: signal intterupt may collapse output\n");
}
#endif
recog = j_recog_new();
recog->jconf = jconf;
/* initialize input device */
if (j_adin_init(recog) == FALSE) {
fprintf(stderr, "Error in initializing adin device\n");
return -1;
}
/* open device */
if (j_open_stream(recog, NULL) < 0) {
fprintf(stderr, "Error in opening adin device\n");
}
/* do recoding */
speechlen = 0;
sfreq = recog->jconf->input.sfreq;
fprintf(stderr, "<<< please speak >>>"); /* moved from adin-cut.c */
adin_go(adin_callback_file, NULL, recog);
/* close device */
adin_end(recog->adin);
/* close output file */
close_file();
return 0;
}