/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set et sw=2 ts=2: */ /*************************************************************************** * aiorecord.cc * * Fri Oct 3 09:58:45 CEST 2014 * Copyright 2014 Bent Bisballe Nyeng * deva@aasimon.org ****************************************************************************/ /* * This file is part of LibAudioIO. * * LibAudioIO 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. * * LibAudioIO 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 LibAudioIO; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include "device.h" #include "mixer.h" static const char version_str[] = "aiomixer v" VERSION "\n" ; static const char copyright_str[] = "Copyright (C) 2014 Bent Bisballe Nyeng - Aasimon.org.\n" "This is free software. You may redistribute copies of it under the terms of\n" "the GNU Lesser General Public License " ".\n" "There is NO WARRANTY, to the extent permitted by law.\n" "\n" "Written by Bent Bisballe Nyeng (deva@aasimon.org)\n" ; static const char usage_str[] = "Usage: %s options\n" "Options:\n" " -L, --list List cards.\n" " -d, --device s Set device to s (default 'default').\n" " -c, --channels n Set number of channels to n (default 2).\n" " -s, --samplerate n Set samplerate to n (default 48000).\n" " -f, --file s Set output file to s (default '/dev/stdout').\n" " -v, --verbose Print info while working\n" " -V, --version Print version information and exit.\n" " -h, --help Print this message and exit.\n" ; typedef enum { MODE_UNKNOWN, MODE_RECORD, MODE_PLAY, } aiomode_t; volatile bool running = true; void ctrl_c(int) { running = false; } void vu(const char *pcm, size_t size) { static double avg = 0; short *p = (short*)pcm; size_t sz = size / sizeof(short); short max = 0; for(int i = 0; i < (int)sz; i++) { if(abs(p[i]) > max) max = abs(p[i]); } avg = avg * 0.95 + (double)max * 0.05; size_t pos = (int)avg / 1000; if(pos > 32) pos = 32; if(pos < 0) pos = 0; char bar[33]; char spc[33]; memset(bar, '#', sizeof(bar)); memset(spc, ' ', sizeof(spc)); bar[pos] = '\0'; spc[sizeof(spc) - pos] = '\0'; printf("\rVU [% 6d]: |%s>%s|", (int)avg, bar, spc); fflush(stdout); } int main(int argc, char *argv[]) { // This program acts as both a recorder and a player depending on which name // it is called by. aiomode_t mode = MODE_UNKNOWN; char *prog = strrchr(argv[0], '/'); if(prog) prog++; // skip '/' if(prog == NULL) prog = argv[0]; if(!strcmp(prog, "aiorecord")) mode = MODE_RECORD; if(!strcmp(prog, "aioplay")) mode = MODE_PLAY; printf("prog: '%s'\n", prog); std::string device = "default"; std::string file = "/dev/stdout"; int samplerate = 48000; int channels = 2; bool list = false; bool verbose = false; int c; int option_index = 0; while(1) { static struct option long_options[] = { {"list", no_argument, 0, 'L'}, {"device", required_argument, 0, 'd'}, {"channels", required_argument, 0, 'c'}, {"samplerate", required_argument, 0, 's'}, {"file", required_argument, 0, 'f'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0} }; c = getopt_long (argc, argv, "hvLd:c:s:f:V", long_options, &option_index); if (c == -1) break; switch(c) { case 'L': list = true; break; case 'd': device = optarg; break; case 'c': channels = atoi(optarg); break; case 's': samplerate = atoi(optarg); break; case 'f': file = optarg; break; case 'v': verbose = true; break; case '?': case 'h': printf("%s", version_str); printf(usage_str, argv[0]); return 0; case 'V': printf("%s", version_str); printf("%s", copyright_str); return 0; default: break; } } if(list) { // TODO } signal(SIGINT, ctrl_c); Device dev(device); switch(mode) { case MODE_RECORD: { Source *src = dev.getSource(device, samplerate, channels); if(!src) { printf("Could not find source device: %s\n", device.c_str()); } FILE *fp = fopen(file.c_str(), "w"); if(!fp) { printf("Could not open %s for writing: ", file.c_str()); perror(""); return 1; } while(running) { char pcm[1024]; int size = src->readSamples(pcm, sizeof(pcm)); if(size < 0) { printf("PCM read error: %d\n", size); break; } size_t w = fwrite(pcm, size, 1, fp); (void)w; if(verbose) vu(pcm, size); } fclose(fp); printf("\ndone\n"); } break; case MODE_PLAY: { Sink *sink = dev.getSink(device, samplerate, channels); if(!sink) { printf("Could not find sink device: %s\n", device.c_str()); } FILE *fp = fopen(file.c_str(), "r"); if(!fp) { printf("Could not open %s for reading: ", file.c_str()); perror(""); return 1; } while(running && !feof(fp)) { char pcm[1024]; size_t size = fread(pcm, 1, sizeof(pcm), fp); int err = sink->writeSamples(pcm, size); if(err < 0) { printf("PCM write error: %d - size: %d\n", err, size); break; } if(verbose) vu(pcm, size); } fclose(fp); printf("\ndone\n"); } break; case MODE_UNKNOWN: printf("Unknown mode '%s'.\n", prog); return 1; } return 0; }