diff options
Diffstat (limited to 'PCM.h')
-rw-r--r-- | PCM.h | 155 |
1 files changed, 12 insertions, 143 deletions
@@ -18,153 +18,22 @@ using namespace std::string_literals; class PCM { public: - PCM(): m_phase(1000000) - { - // prepare the sample - std::string data_s = Reichwein::File::getFile("media/click.s16le"); - m_data.resize(data_s.size() / 2); // src is in bytes - memcpy(m_data.data(), data_s.data(), data_s.size()); - - // non-blocking - if ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) < 0) { - throw std::runtime_error(fmt::format("Playback open error: {}", snd_strerror(err))); - } - if ((err = snd_pcm_set_params(handle, - SND_PCM_FORMAT_S16_LE, - SND_PCM_ACCESS_RW_INTERLEAVED, - 1, - f_sample, - 1, - pcm_latency_us)) < 0) { // latency in us - throw std::runtime_error(fmt::format("Playback open error: {}", snd_strerror(err))); - } - - generate(); - - npfd = snd_pcm_poll_descriptors_count(handle); - if (npfd < 0) { - throw std::runtime_error("snd_pcm_poll_descriptors_count() failed"); - } - pfd = (struct pollfd *)malloc(npfd * sizeof(struct pollfd)); - if (pfd == nullptr) { - throw std::runtime_error("alloca() error for PCM"); - } - if (0 > snd_pcm_poll_descriptors(handle, pfd, npfd)) - { - throw std::runtime_error("snd_pcm_poll_descriptors() failure"); - } - - if (0 > snd_pcm_start(handle)) - { - throw std::runtime_error("PCM could not be started"); - } - - if (npfd != 1) { - std::cout << "Warning: " << std::to_string(npfd) << " poll fds for pcm" << std::endl; - } else if (fd() <= 2) { - std::cout << "Warning: Bad PCM fd: " << std::to_string(fd()) << std::endl; - } - } - - ~PCM() - { - // pass the remaining samples, otherwise they're dropped in close - err = snd_pcm_drain(handle); - if (err < 0) - std::cerr << fmt::format("snd_pcm_drain failed: {}", snd_strerror(err)) << std::endl; - snd_pcm_close(handle); - - free(pfd); - } - - void click() - { - snd_pcm_sframes_t delay; - if (0 > snd_pcm_delay(handle, &delay)) { - } - - m_phase = - click_latency_frames + delay; - } + PCM(); + ~PCM(); + + void click(); // generate 1 buffer size - void generate() - { - int i; - - for (i = 0; i < nframes; i++) { - if (m_phase < 0 || m_phase >= m_data.size()) - { - buffer[i] = 0; - } - else - { - buffer[i] = m_data[m_phase]; - } - m_phase++; - } - } - - int fd() - { - return pfd->fd; - } + void generate(); + + int fd(); // write from buffer to ALSA PCM - void write() - { - snd_pcm_sframes_t written = snd_pcm_writei(handle, buffer, nframes); - if (written < 0) { - if (written == -EPIPE) { - std::cout << "Warning: PCM underrun" << std::endl; - } - std::cout << "Recovering." << std::endl; - written = snd_pcm_recover(handle, written, 0); - } - if (written < 0) { - throw std::runtime_error("snd_pcm_writei failed: "s + snd_strerror(written)); - } - - if (written != nframes) { - std::cout << "Warning: written " << std::to_string(written) << " frames instead of "<< std::to_string(nframes) << std::endl; - } - - snd_pcm_sframes_t avail; - snd_pcm_sframes_t delay; - if (0 > snd_pcm_avail_delay(handle, &avail, &delay)) { - log_cout << "Error detecting avail and delay" << std::endl; - } else { - debug_cout << fmt::format("Delay: {}, avail. buffer; {} frames", delay, avail) << std::endl; - } - - generate(); - } - - bool wait_for_event() - { - int result = poll(pfd, npfd, 10000); - if (result > 0) - { - // event - return true; - } - else if (result == 0) { - // timeout - return false; - } else { - throw std::runtime_error("Poll unsuccessful"); - } - } - - bool write_available() - { - snd_pcm_sframes_t result = snd_pcm_avail(handle); - if (0 > result) { - std::cerr << "Error: snd_pcm_avail()" << std::endl; - //throw std::runtime_error("snd_pcm_avail()"); - } - - return result >= nframes; - } + void write(); + + bool wait_for_event(); + + bool write_available(); private: int err; |