#include #include #include int main(void) { // Handle for the PCM device. snd_pcm_t* pcm_handle; // Playback stream. snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK; // This structure contains information about // the hardware and can be used to specify the // configuration to be used for the PCM stream. snd_pcm_hw_params_t* hwparams; // Name of the PCM device, like plughw:0,0. // The first number is the number of the soundcard, // the second number is the number of the device. char const* pcm_name = "plughw:0,0"; // Allocate the snd_pcm_hw_params_t structure on the stack. snd_pcm_hw_params_alloca(&hwparams); // Open PCM. The last parameter of this function is the mode. // If this is set to 0, the standard mode is used. Possible // other values are SND_PCM_NONBLOCK and SND_PCM_ASYNC. // If SND_PCM_NONBLOCK is used, read / write access to the // PCM device will return immediately. If SND_PCM_ASYNC is // specified, SIGIO will be emitted whenever a period has // been completely processed by the soundcard. if (snd_pcm_open(&pcm_handle, pcm_name, stream, 0) < 0) { std::cerr << "Error opening PCM device " << pcm_name << std::endl; return -1; } // Init hwparams with full configuration space. if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) { std::cerr << "Can not configure this PCM device." << std::endl; return -1; } unsigned int rate = 22050; // Sample rate. int exact_rate; // Sample rate returned by snd_pcm_hw_params_set_rate_near. int dir; // exact_rate == rate --> dir = 0 // exact_rate < rate --> dir = -1 // exact_rate > rate --> dir = 1 int periods = 16; // Number of periods. int periodsize = 1024; // Periodsize (bytes). // Set access type. This can be either // SND_PCM_ACCESS_RW_INTERLEAVED or // SND_PCM_ACCESS_RW_NONINTERLEAVED. // There are also access types for MMAPed // access, but this is beyond the scope // of this introduction. if (snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) { std::cerr << "Error setting access." << std::endl; return -1; } // Set sample format to 'Signed 16 bit Little Endian'. if (snd_pcm_hw_params_set_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_LE) < 0) { std::cerr << "Error setting format." << std::endl; return(-1); } // Set sample rate. If the exact rate is not supported // by the hardware, use nearest possible rate. dir = 0; // ??? According to valgrind, this value is USED (read) for a conditional jump! exact_rate = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, rate, &dir); if (rate != exact_rate) { std::cerr << "The rate " << rate << " Hz is not supported by your hardware.\n " "==> Using " << exact_rate << " Hz instead." << std::endl; } // Set number of channels. if (snd_pcm_hw_params_set_channels(pcm_handle, hwparams, 2) < 0) { std::cerr << "Error setting channels." << std::endl; return -1; } // Set number of periods. Periods used to be called fragments. if (snd_pcm_hw_params_set_periods(pcm_handle, hwparams, periods, 0) < 0) { std::cerr << "Error setting periods." << std::endl; return -1; } // Set buffer size (in frames). The resulting latency is given by // latency = periodsize * periods / (rate * bytes_per_frame). if (snd_pcm_hw_params_set_buffer_size(pcm_handle, hwparams, (periodsize * periods) >> 2) < 0) { std::cerr << "Error setting buffersize." << std::endl; return -1; } // Apply HW parameter settings to // PCM device and prepare device. if (snd_pcm_hw_params(pcm_handle, hwparams) < 0) { std::cerr << "Error setting HW params." << std::endl; return -1; } unsigned char* data; int pcmreturn; short s1, s2; int frames; data = (unsigned char*)malloc(periodsize); frames = periodsize >> 2; std::cout << "frames = " << frames << '\n'; for (int l1 = 0; l1 < 100; ++l1) { for (int l2 = 0; l2 < frames; ++l2) { s1 = (l2 % 128) * 100 - 5000; s2 = (l2 % 256) * 100 - 5000; data[4 * l2] = (unsigned char)s1; data[4 * l2 + 1] = s1 >> 8; data[4 * l2 + 2] = (unsigned char)s2; data[4 * l2 + 3] = s2 >> 8; } while ((pcmreturn = snd_pcm_writei(pcm_handle, data, frames)) < 0) { if (pcmreturn == -EPIPE) { std::cout << "<<<<<<<<<<<<<<< Buffer Underrun >>>>>>>>>>>>>>>" << std::endl; snd_pcm_prepare(pcm_handle); } else { std::cout << "snd_pcm_writei: " << strerror(-pcmreturn) << '\n'; break; } } std::cout << "pcmreturn = " << pcmreturn << '\n'; } return 0; }