// This program tries to record from your sound card, using a chosen sampling // rate. ALSA may give another rate, if the sound card does not support the // requested rate. Two seconds of audio is recorded and the time spent is // measured in order to find the actual rate of the sound card. // Compile with g++ alsarate.cpp -o alsarate -I. -lasound // ... assuming that you have alsa.hpp in the same folder. // Usage: alsarate [ALSA device] [sampling rate] [time in seconds] // GNU GPLv3 or later. #include #include #include #include #include #include #include double getTime() { timeval t; if (gettimeofday(&t, NULL) == -1) throw std::runtime_error("gettimeofday failed"); return t.tv_sec + t.tv_usec * 1e-6; } void test(char const* dev, unsigned long reqRate, double seconds, bool play) { std::cerr << ">>> Testing " << (play ? "playback" : "capture") << std::endl; try { std::cerr << "Opening ALSA device " << dev << " at " << reqRate << " Hz." << std::endl; double time = getTime(); unsigned int rate = reqRate; unsigned int channels = 1; unsigned int period = 1; alsa::PCM alsaHandle(dev, play ? SND_PCM_STREAM_PLAYBACK : SND_PCM_STREAM_CAPTURE); alsa::HWConfig(alsaHandle) .set(SND_PCM_ACCESS_RW_INTERLEAVED) .set(SND_PCM_FORMAT_S16_LE) .rate_near(rate) .channels_near(channels) .period_time_near(period) .commit(); std::cerr << "Got " << rate << " Hz, " << channels << " channels, period " << period * 1e-3 << " ms." << std::endl; int nFrames = 0; size_t len = rate * seconds; std::vector buf(2048 * channels); for (size_t f = 0; f < len; f += nFrames) { unsigned int frames = std::min(buf.size() / channels, len - f); if (play) { nFrames = snd_pcm_writei(alsaHandle, &buf[0], frames); } else { nFrames = snd_pcm_readi(alsaHandle, &buf[0], frames); } if (nFrames < 0) throw std::runtime_error("snd_pcm_readi or snd_pcm_writei failed"); } time = getTime() - time; std::cerr << std::fixed << std::setprecision(2) << time << " seconds, measured rate " << std::setprecision(0) << len / time << " Hz." << std::endl; } catch (std::exception& e) { std::cerr << "FATAL ERROR: " << e.what() << std::endl; } } // Should use Boost, but who has the headers installed? template Out lexical_cast(In val) { std::stringstream ss; Out ret; ss << val; if (ss >> ret) return ret; throw std::runtime_error("Invalid input, lexical cast failed"); } int main(int argc, char** argv) { char const* dev = argc > 1 ? argv[1] : "default"; unsigned int reqRate = argc > 2 ? lexical_cast(argv[2]) : 48000; double time = argc > 3 ? lexical_cast(argv[3]) : 10.0; test(dev, reqRate, time, true); test(dev, reqRate, time, false); }