diff --git a/examples/DSPE_examples.h b/examples/DSPE_examples.h index 5bd1f3c5e2806f862dd60ed578223c15d34de1ec..bbaa0df1b52d6a90b66a56fb94fd35cb18e91e78 100644 --- a/examples/DSPE_examples.h +++ b/examples/DSPE_examples.h @@ -9,7 +9,7 @@ #define EXAMPLES_DSPE_EXAMPLES_H_ int test_hello(void); -int test_sound_input(void); +int test_sound_input(bool use_audio_output = true); #endif /* EXAMPLES_DSPE_EXAMPLES_H_ */ diff --git a/examples/sound_input.cpp b/examples/sound_input.cpp index e15d363e1afee5af3f9895d1ae5731608e7b50b1..da1364f234ba12f3b3ab5ae11461f2767f8d751e 100644 --- a/examples/sound_input.cpp +++ b/examples/sound_input.cpp @@ -7,11 +7,14 @@ #ifndef INCLUDE_DSPE_EXAMPLES int main(void) +{ + bool use_audio_output = true; #else #include "DSPE_examples.h" -int test_sound_input(void) -#endif // INCLUDE_DSPE_EXAMPLES +int test_sound_input(bool use_audio_output) { +#endif // INCLUDE_DSPE_EXAMPLES + DSP::Clock_ptr MasterClock, AudioInClock; string tekst; int temp; @@ -25,17 +28,26 @@ int test_sound_input(void) MasterClock=DSP::Clock::CreateMasterClock(); +#ifndef INCLUDE_DSPE_EXAMPLES DSP::u::WaveInput WaveIn(MasterClock, "DSPElib.wav", "."); +#else + DSP::u::WaveInput WaveIn(MasterClock, "DSPElib.wav", "../examples"); +#endif // INCLUDE_DSPE_EXAMPLES + Fp = WaveIn.GetSamplingRate(); - DSP::u::AudioOutput AudioOut(Fp); + std::shared_ptr<DSP::Block> AudioOut = nullptr; + if (use_audio_output == true) + AudioOut.reset(new DSP::u::AudioOutput(Fp)); + else + AudioOut.reset(new DSP::u::Vacuum(1U)); - WaveIn.Output("out") >> AudioOut.Input("in"); + WaveIn.Output("out") >> AudioOut->Input("in"); Fp2 = 8000; long Fp_gcd = DSP::f::gcd(Fp, Fp2); AudioInClock=DSP::Clock::GetClock(MasterClock, Fp2 / Fp_gcd, Fp / Fp_gcd); - DSP::u::AudioInput AudioIn(AudioInClock, 8000, 1); + DSP::u::AudioInput AudioIn(AudioInClock, Fp2, 1); DSP::u::FileOutput WaveOut("captured_sample.wav",DSP::e::SampleType::ST_short, 1, DSP::e::FileType::FT_wav, Fp2); AudioIn.Output("out") >> WaveOut.Input("in"); @@ -51,8 +63,9 @@ int test_sound_input(void) DSP::log << "MAIN" << DSP::e::LogMode::second << temp << endl; temp++; } - while (WaveIn.GetBytesRead() != 0); + while ((temp <= 8) || (WaveIn.GetBytesRead() != 0)); + AudioOut.reset(); DSP::Clock::FreeClocks(); DSP::log << DSP::e::LogMode::Error << "MAIN" << DSP::e::LogMode::second << "end" << endl; diff --git a/src/Main.cpp b/src/Main.cpp index eb68ee86d67e33bfc0599c522f4989e4bedfef81..333f2403aec0ea66342d53119a60e1c013dfc132 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -2977,7 +2977,8 @@ int main(int argc, char*argv[]) DSP::log << DSP::e::LogMode::Error << "Finished test_hello" << endl; DSP::log << "Starting test_sound_input" << endl; - test_sound_input(); + bool use_audio_output = false; + test_sound_input(use_audio_output); DSP::log << DSP::e::LogMode::Error << "Finished test_sound_input" << endl; #endif // INCLUDE_DSPE_EXAMPLES diff --git a/src/cpp/ALSA_support.cpp b/src/cpp/ALSA_support.cpp index d7acc0c313d1621ec75cdafc66f7cceea1ec1607..8ecc999b4884bf913b21ff6454ec2742f82dec9d 100644 --- a/src/cpp/ALSA_support.cpp +++ b/src/cpp/ALSA_support.cpp @@ -43,7 +43,6 @@ DSP::ALSA_object_t::ALSA_object_t() InDevNo = 1; NextBufferOutInd = 0; - NextBufferInInd = 0; /* 44100 bits/second sampling rate (CD quality) */ sampling_rate_alsa = 44100; @@ -51,6 +50,7 @@ DSP::ALSA_object_t::ALSA_object_t() no_of_bytes_in_channel = 2; audio_inbuffer_size_in_frames = 8000; + audio_outbuffer_size_in_frames = 8000; size_b = 32; } @@ -68,6 +68,9 @@ DSP::ALSA_object_t::~ALSA_object_t() buffers_32bit.clear(); buffers_32bit_f.clear(); buffers_64bit.clear(); + + capture_buffer.clear(); + pcm_buffer.clear(); pcm_buffer_size_in_frames.clear(); @@ -148,7 +151,7 @@ int DSP::ALSA_object_t::open_alsa_device(snd_pcm_stream_t stream_type) //! Errors controller in set_snd_pcm_format() function int errc; - //! Local configuration space handler + //! Local configuration space handler snd_pcm_hw_params_t *params; //! For logging @@ -165,7 +168,7 @@ int DSP::ALSA_object_t::open_alsa_device(snd_pcm_stream_t stream_type) //! \TODO Test mode: Open mode (see SND_PCM_NONBLOCK, SND_PCM_ASYNC) - if (stream_type == SND_PCM_STREAM_PLAYBACK) + if (stream_type == SND_PCM_STREAM_PLAYBACK) DSP::log << "Opening PCM device for playback." << endl; else @@ -208,32 +211,69 @@ int DSP::ALSA_object_t::open_alsa_device(snd_pcm_stream_t stream_type) snd_pcm_hw_params_set_rate_near(alsa_handle, params, &sampling_rate_alsa, &dir); - if (audio_inbuffer_size_in_frames <= 0) - audio_inbuffer_size_in_frames = 8000; + if (stream_type == SND_PCM_STREAM_PLAYBACK) + { + if (audio_outbuffer_size_in_frames <= 0) + audio_outbuffer_size_in_frames = 8000; + + size_b = audio_outbuffer_size_in_frames * no_of_channels_alsa * no_of_bytes_in_channel; - rc = snd_pcm_hw_params_set_buffer_size(alsa_handle, params, DSP::NoOfAudioOutputBuffers*audio_inbuffer_size_in_frames); + rc = snd_pcm_hw_params_set_buffer_size(alsa_handle, params, DSP::NoOfAudioOutputBuffers*audio_outbuffer_size_in_frames); - snd_pcm_uframes_t requested_audio_inbuffer_size_in_frames = audio_inbuffer_size_in_frames; + snd_pcm_uframes_t requested_audio_outbuffer_size_in_frames = audio_outbuffer_size_in_frames; - if (rc < 0) - { - DSP::log << "Unable to set a buffer size with error code: " << rc << endl; - return -5; + if (rc < 0) + { + DSP::log << "Unable to set a buffer size with error code: " << rc << endl; + return -5; + } + + /*! Set period size to desired number of frames. */ + snd_pcm_hw_params_set_period_size_near(alsa_handle, params, &audio_outbuffer_size_in_frames, &dir); + + #ifdef AUDIO_DEBUG_MESSAGES_ON + if (audio_outbuffer_size_in_frames != requested_audio_outbuffer_size_in_frames) + { + DSP::log << "Current frames value should be equal: " << requested_audio_outbuffer_size_in_frames << endl; + DSP::log << "Frames is not equal to tmp_frames! Frames: " << audio_outbuffer_size_in_frames << endl; + } + + else + DSP::log << "Frames has been set correctly." << endl; + #endif // AUDIO_DEBUG_MESSAGES_ON } - /*! Set period size to desired number of frames. */ - snd_pcm_hw_params_set_period_size_near(alsa_handle, params, &audio_inbuffer_size_in_frames, &dir); + else // stream_type == SND_PCM_STREAM_CAPTURE + { + if (audio_inbuffer_size_in_frames <= 0) + audio_inbuffer_size_in_frames = 8000; + + size_b = audio_inbuffer_size_in_frames * no_of_channels_alsa * no_of_bytes_in_channel; + + rc = snd_pcm_hw_params_set_buffer_size(alsa_handle, params, size_b); + + snd_pcm_uframes_t requested_audio_inbuffer_size_in_frames = audio_inbuffer_size_in_frames; - #ifdef AUDIO_DEBUG_MESSAGES_ON - if (audio_inbuffer_size_in_frames != requested_audio_inbuffer_size_in_frames) + if (rc < 0) { - DSP::log << "Current frames value should be equal: " << requested_audio_inbuffer_size_in_frames << endl; - DSP::log << "Frames is not equal to tmp_frames! Frames: " << audio_inbuffer_size_in_frames << endl; + DSP::log << "Unable to set a buffer size with error code: " << rc << endl; + return -5; } - else - DSP::log << "Frames has been set correctly." << endl; - #endif // AUDIO_DEBUG_MESSAGES_ON + /*! Set period size to desired number of frames. */ + snd_pcm_hw_params_set_period_size_near(alsa_handle, params, &audio_inbuffer_size_in_frames, &dir); + + #ifdef AUDIO_DEBUG_MESSAGES_ON + if (audio_inbuffer_size_in_frames != requested_audio_inbuffer_size_in_frames) + { + DSP::log << "Current frames value should be equal: " << requested_audio_inbuffer_size_in_frames << endl; + DSP::log << "Frames is not equal to tmp_frames! Frames: " << audio_inbuffer_size_in_frames << endl; + } + + else + DSP::log << "Frames has been set correctly." << endl; + #endif // AUDIO_DEBUG_MESSAGES_ON + } /* Write the parameters to the driver */ rc = snd_pcm_hw_params(alsa_handle, params); @@ -281,8 +321,8 @@ int DSP::ALSA_object_t::open_alsa_device(snd_pcm_stream_t stream_type) snd_pcm_hw_params_get_period_time(hw_params, &val, &dir); DSP::log << "period time = " << val << " us" << endl; - snd_pcm_hw_params_get_period_size(hw_params, &audio_inbuffer_size_in_frames, &dir); - DSP::log << "period size = " << (int) audio_inbuffer_size_in_frames << " frames" << endl; + snd_pcm_hw_params_get_period_size(hw_params, (snd_pcm_uframes_t *)&val, &dir); + DSP::log << "period size = " << val << " frames" << endl; snd_pcm_hw_params_get_buffer_time(hw_params, &val, &dir); DSP::log << "buffer time = " << val << " us" << endl; @@ -353,13 +393,12 @@ int DSP::ALSA_object_t::open_alsa_device(snd_pcm_stream_t stream_type) // Can be useful: // snd_pcm_hw_params_get_period_size(hw_params, &frames, &dir); - - size_b = audio_inbuffer_size_in_frames * no_of_channels_alsa * no_of_bytes_in_channel; if (stream_type == SND_PCM_STREAM_PLAYBACK) { pcm_buffer.resize(DSP::NoOfAudioOutputBuffers); pcm_buffer_size_in_frames.resize(DSP::NoOfAudioOutputBuffers); + switch (no_of_bytes_in_channel) { case 1: @@ -430,73 +469,45 @@ int DSP::ALSA_object_t::open_alsa_device(snd_pcm_stream_t stream_type) } else // (stream_type == SND_PCM_STREAM_CAPTURE) { - pcm_buffer.resize(DSP::NoOfAudioInputBuffers); - pcm_buffer_size_in_frames.resize(DSP::NoOfAudioInputBuffers); - switch (no_of_bytes_in_channel) + pcm_buffer.resize(1); + pcm_buffer_size_in_frames.resize(1); + + capture_buffer.resize(size_b); + + for(unsigned int ind = 0; ind < pcm_buffer.size(); ind++) { - case 1: - buffers_8bit.resize(DSP::NoOfAudioInputBuffers); + pcm_buffer[ind] = (uint8_t *)(capture_buffer.data()); + pcm_buffer_size_in_frames[ind] = (snd_pcm_sframes_t) capture_buffer.size() / no_of_bytes_in_channel / no_of_channels_alsa; + } - for(unsigned int ind = 0; ind < DSP::NoOfAudioInputBuffers; ind++) - { - buffers_8bit[ind].resize(size_b / no_of_bytes_in_channel); - pcm_buffer[ind] = (uint8_t *)(buffers_8bit[ind].data()); - pcm_buffer_size_in_frames[ind] = (snd_pcm_sframes_t) buffers_8bit[ind].size() / no_of_channels_alsa; - } + switch (no_of_bytes_in_channel) + { + case 1: + InSampleTypeALSA = DSP::e::SampleType::ST_uchar; break; case 2: - buffers_16bit.resize(DSP::NoOfAudioInputBuffers); - - for(unsigned int ind = 0; ind < DSP::NoOfAudioInputBuffers; ind++) - { - buffers_16bit[ind].resize(size_b / no_of_bytes_in_channel); - pcm_buffer[ind] = (uint8_t *)(buffers_16bit[ind].data()); - pcm_buffer_size_in_frames[ind] = (snd_pcm_sframes_t) buffers_16bit[ind].size() / no_of_channels_alsa; - } + InSampleTypeALSA = DSP::e::SampleType::ST_short; break; case 3: + InSampleTypeALSA = DSP::e::SampleType::ST_int; + break; + case 4: if (IsHigherQualityMode) - { - buffers_32bit.resize(DSP::NoOfAudioInputBuffers); - - for(unsigned int ind = 0; ind < DSP::NoOfAudioInputBuffers; ind++) - { - buffers_32bit[ind].resize(size_b / no_of_bytes_in_channel); - pcm_buffer[ind] = (uint8_t *)(buffers_32bit[ind].data()); - pcm_buffer_size_in_frames[ind] = (snd_pcm_sframes_t) buffers_32bit[ind].size() / no_of_channels_alsa; - } - } - - else //! native mode - { - buffers_32bit_f.resize(DSP::NoOfAudioInputBuffers); - - for(unsigned int ind = 0; ind < DSP::NoOfAudioInputBuffers; ind++) - { - buffers_32bit_f[ind].resize(size_b / no_of_bytes_in_channel); - pcm_buffer[ind] = (uint8_t *)(buffers_32bit_f[ind].data()); - pcm_buffer_size_in_frames[ind] = (snd_pcm_sframes_t) buffers_32bit_f[ind].size() / no_of_channels_alsa; - } - } + InSampleTypeALSA = DSP::e::SampleType::ST_int; + else + InSampleTypeALSA = DSP::e::SampleType::ST_float; break; case 8: - buffers_64bit.resize(DSP::NoOfAudioInputBuffers); - - for(unsigned int ind = 0; ind < DSP::NoOfAudioInputBuffers; ind++) - { - buffers_64bit[ind].resize(size_b / no_of_bytes_in_channel); - pcm_buffer[ind] = (uint8_t *)(buffers_64bit[ind].data()); - pcm_buffer_size_in_frames[ind] = (snd_pcm_sframes_t) buffers_64bit[ind].size() / no_of_channels_alsa; - } + InSampleTypeALSA = DSP::e::SampleType::ST_double; break; default: DSP::log << "Unsupported no of bytes in channel" << endl; - return -6; + return -9; break; } } @@ -651,7 +662,7 @@ long DSP::ALSA_object_t::open_PCM_device_4_output(const int &no_of_channels, int no_of_channels_alsa = (unsigned int) no_of_channels; no_of_bytes_in_channel = (unsigned int) no_of_bits / 8; sampling_rate_alsa = (unsigned int) sampling_rate; - audio_inbuffer_size_in_frames = (snd_pcm_uframes_t) audio_outbuffer_size; + audio_outbuffer_size_in_frames = (snd_pcm_uframes_t) audio_outbuffer_size; rc = open_alsa_device(SND_PCM_STREAM_PLAYBACK); @@ -883,19 +894,85 @@ bool DSP::ALSA_object_t::stop_recording(void) bool DSP::ALSA_object_t::start_recording(void) { - assert(!"DSP::ALSA_object_t::stop_recording not implemented yet"); + IsRecordingNow = true; return true; } bool DSP::ALSA_object_t::get_wave_in_raw_buffer(DSP::e::SampleType &InSampleType, std::vector<char> &wave_in_raw_buffer) { - assert(!"DSP::ALSA_object_t::get_wave_in_raw_buffer not implemented yet"); - - InSampleTypeALSA = InSampleType; + InSampleType = this->InSampleTypeALSA; snd_pcm_sframes_t rc; - return true; + for (unsigned int ind = 0; ind < pcm_buffer.size(); ind++) + { + while (pcm_buffer_size_in_frames[ind]) + { + rc = snd_pcm_readi(alsa_handle, pcm_buffer[ind], pcm_buffer_size_in_frames[ind]); + + switch (-rc) + { + case EPIPE: + + #ifdef AUDIO_DEBUG_MESSAGES_ON + // EPIPE means underrun + DSP::log << "Underrun occurred" << endl; + #endif // AUDIO_DEBUG_MESSAGES_ON + + snd_pcm_prepare(alsa_handle); + break; + + case EAGAIN: + + #ifdef AUDIO_DEBUG_MESSAGES_ON + DSP::log << "EAGAIN occurred. Waiting for a free buffer." << endl; + #endif // AUDIO_DEBUG_MESSAGES_ON + + DSP::f::Sleep(0); + break; + + default: + if (rc > 0) + { + pcm_buffer_size_in_frames[ind] -= rc; + pcm_buffer[ind] += rc * no_of_channels_alsa * no_of_bytes_in_channel; + + #ifdef AUDIO_DEBUG_MESSAGES_ON + DSP::log << "Short read. Current rc = " << rc << "." << endl; + #endif // AUDIO_DEBUG_MESSAGES_ON + + if (pcm_buffer_size_in_frames[ind] == 0) + { + wave_in_raw_buffer.resize(capture_buffer.size()); + std::swap(wave_in_raw_buffer, capture_buffer); + + #ifdef AUDIO_DEBUG_MESSAGES_ON + DSP::log << "Inbuffer is full." << endl; + #endif // AUDIO_DEBUG_MESSAGES_ON + + pcm_buffer[ind] = (uint8_t *)(capture_buffer.data()); + pcm_buffer_size_in_frames[ind] = (snd_pcm_sframes_t) capture_buffer.size() / no_of_bytes_in_channel / no_of_channels_alsa; + + return true; + } + } + + else + { + #ifdef AUDIO_DEBUG_MESSAGES_ON + // EPIPE means underrun + DSP::log << "Unsupported error." << endl; + DSP::log << "Error from readi: " << snd_strerror(rc) << endl; + #endif // AUDIO_DEBUG_MESSAGES_ON + + pcm_buffer_size_in_frames[ind] = 0; + return false; + } + break; + } + } + } + return false; } snd_pcm_sframes_t DSP::ALSA_object_t::pcm_writei(const void *buffer, const snd_pcm_uframes_t &frames) diff --git a/src/cpp/DSP_IO.cpp b/src/cpp/DSP_IO.cpp index c5a112a7dbd448ff1eea546df12ba3f9647396ad..99fbbee523a308a831774fdc9508561db1da7764 100644 --- a/src/cpp/DSP_IO.cpp +++ b/src/cpp/DSP_IO.cpp @@ -3995,6 +3995,28 @@ bool DSP::u::AudioInput::SOUND_object_callback(const DSP::e::SampleType &InSampl DSP::Float_ptr Sample; unsigned int ind; +#ifdef __DEBUG__ + switch (InSampleType) { + case DSP::e::SampleType::ST_short: { + if (InBufferLen != wave_in_raw_buffer.size() / sizeof(short)) { + DSP::log << "DSP::u::AudioInput::SOUND_object_callback" << DSP::e::LogMode::second << "incorrect wave_in_raw_buffer size: " << + wave_in_raw_buffer.size() << " instead of " << InBufferLen * sizeof(short) << endl; + } + } + break; + case DSP::e::SampleType::ST_uchar: { + if (InBufferLen != wave_in_raw_buffer.size() / sizeof(uint8_t)) { + DSP::log << "DSP::u::AudioInput::SOUND_object_callback" << DSP::e::LogMode::second << "incorrect wave_in_raw_buffer size: " << + wave_in_raw_buffer.size() << " instead of " << InBufferLen * sizeof(uint8_t) << endl; + } + } + break; + default: + DSP::log << "DSP::u::AudioInput::SOUND_object_callback" << DSP::e::LogMode::second << "Unsupported Current->InSampleType" << endl; + break; + } +#endif // __DEBUG__ + // reading sound card input buffer Sample=InBuffers[EmptyBufferIndex].data(); // ************************************************** // @@ -4028,7 +4050,7 @@ bool DSP::u::AudioInput::SOUND_object_callback(const DSP::e::SampleType &InSampl default: #ifdef __DEBUG__ - DSP::log << "DSP::u::AudioInput::waveInProc_short" << DSP::e::LogMode::second << "Unsupported Current->InSampleType" << endl; + DSP::log << "DSP::u::AudioInput::SOUND_object_callback" << DSP::e::LogMode::second << "Unsupported Current->InSampleType" << endl; #endif break; } diff --git a/src/include/ALSA_support.h b/src/include/ALSA_support.h index 0bd6078495c83a692f724e833de484cd1f365e46..e06cc1e469561570fdd11d470847843da517bea8 100644 --- a/src/include/ALSA_support.h +++ b/src/include/ALSA_support.h @@ -37,8 +37,6 @@ namespace DSP { //! keeping track of which outbuffer is currently being filled unsigned int NextBufferOutInd; - //! keeping track of which inbuffer is currently being filled - unsigned int NextBufferInInd; //! sampling rate unsigned int sampling_rate_alsa; @@ -50,12 +48,15 @@ namespace DSP { /*! It is better to use STD containers - they are more convenient, and they mean fewer problems with memory leaks. */ - //! buffers depending on samples type + //! outbuffers depending on samples type std::vector<std::vector<uint8_t>> buffers_8bit; std::vector<std::vector<int16_t>> buffers_16bit; std::vector<std::vector<int32_t>> buffers_32bit; std::vector<std::vector<float>> buffers_32bit_f; std::vector<std::vector<double>> buffers_64bit; + + //! inbuffer + std::vector<char> capture_buffer; //! samples are integers rather than float values bool IsHigherQualityMode; @@ -75,7 +76,8 @@ namespace DSP { bool IsRecordingNow; //! just samples - snd_pcm_uframes_t audio_inbuffer_size_in_frames; // M.B. more meaningful variable name + snd_pcm_uframes_t audio_inbuffer_size_in_frames; + snd_pcm_uframes_t audio_outbuffer_size_in_frames; //! Type of samples in WaveInBuffers DSP::e::SampleType InSampleTypeALSA; @@ -97,6 +99,9 @@ namespace DSP { //! playback snd_pcm_sframes_t pcm_writei(const void *buffer, const snd_pcm_uframes_t &frames); // M.B. this will be more transparent + + //! recording + //snd_pcm_sframes_t DSP::ALSA_object_t::pcm_readi(const void *buffer, const snd_pcm_uframes_t &frames) //! Set SND PCM format depending on no of bytes in channel and CPU endianness int set_snd_pcm_format(snd_pcm_hw_params_t *params);