summaryrefslogtreecommitdiffhomepage
path: root/PCM.h
diff options
context:
space:
mode:
Diffstat (limited to 'PCM.h')
-rw-r--r--PCM.h155
1 files changed, 12 insertions, 143 deletions
diff --git a/PCM.h b/PCM.h
index a9e251c..73cdcc6 100644
--- a/PCM.h
+++ b/PCM.h
@@ -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;