From dcc442411fd66328a971969f37cadcc142206865 Mon Sep 17 00:00:00 2001 From: Shmuel H Date: Tue, 7 Nov 2017 12:59:49 +0200 Subject: [PATCH] AudioSdl: Add support for full SDL2 with float samples and recording (with backward compatibility for SDL1). --- include/AudioSdl.h | 20 +++++- src/core/audio/AudioSdl.cpp | 138 +++++++++++++++++++++++++++++++++--- 2 files changed, 149 insertions(+), 9 deletions(-) diff --git a/include/AudioSdl.h b/include/AudioSdl.h index 11942efda..19d9606eb 100644 --- a/include/AudioSdl.h +++ b/include/AudioSdl.h @@ -78,17 +78,35 @@ private: static void sdlAudioCallback( void * _udata, Uint8 * _buf, int _len ); void sdlAudioCallback( Uint8 * _buf, int _len ); +#ifdef LMMS_HAVE_SDL2 + static void sdlInputAudioCallback( void * _udata, Uint8 * _buf, int _len ); + void sdlInputAudioCallback( Uint8 * _buf, int _len ); +#endif + SDL_AudioSpec m_audioHandle; surroundSampleFrame * m_outBuf; + +#ifdef LMMS_HAVE_SDL2 + uint64_t m_currentBufferFramePos; + uint64_t m_currentBufferFramesCount; +#else Uint8 * m_convertedBuf; int m_convertedBufPos; int m_convertedBufSize; + bool m_outConvertEndian; +#endif - bool m_convertEndian; bool m_stopped; +#ifdef LMMS_HAVE_SDL2 + SDL_AudioDeviceID m_outputDevice; + + SDL_AudioSpec m_inputAudioHandle; + SDL_AudioDeviceID m_inputDevice; +#endif + } ; #endif diff --git a/src/core/audio/AudioSdl.cpp b/src/core/audio/AudioSdl.cpp index 2b810e913..9408dd3e2 100644 --- a/src/core/audio/AudioSdl.cpp +++ b/src/core/audio/AudioSdl.cpp @@ -34,19 +34,21 @@ #include "gui_templates.h" #include "Mixer.h" - AudioSdl::AudioSdl( bool & _success_ful, Mixer* _mixer ) : AudioDevice( DEFAULT_CHANNELS, _mixer ), - m_outBuf( new surroundSampleFrame[mixer()->framesPerPeriod()] ), - m_convertedBufPos( 0 ), - m_convertEndian( false ) + m_outBuf( new surroundSampleFrame[mixer()->framesPerPeriod()] ) { _success_ful = false; +#ifdef LMMS_HAVE_SDL2 + m_currentBufferFramesCount = 0; + m_currentBufferFramePos = 0; +#else m_convertedBufSize = mixer()->framesPerPeriod() * channels() * sizeof( int_sample_t ); + m_convertedBufPos = 0; m_convertedBuf = new Uint8[m_convertedBufSize]; - +#endif if( SDL_Init( SDL_INIT_AUDIO | SDL_INIT_NOPARACHUTE ) < 0 ) { @@ -55,9 +57,15 @@ AudioSdl::AudioSdl( bool & _success_ful, Mixer* _mixer ) : } m_audioHandle.freq = sampleRate(); +#ifdef LMMS_HAVE_SDL2 + m_audioHandle.format = AUDIO_F32SYS; // we want it in byte-order + // of system, so we don't have + // to convert the buffers +#else m_audioHandle.format = AUDIO_S16SYS; // we want it in byte-order // of system, so we don't have // to convert the buffers +#endif m_audioHandle.channels = channels(); m_audioHandle.samples = qMax( 1024, mixer()->framesPerPeriod()*2 ); @@ -66,15 +74,47 @@ AudioSdl::AudioSdl( bool & _success_ful, Mixer* _mixer ) : SDL_AudioSpec actual; +#ifdef LMMS_HAVE_SDL2 + m_outputDevice = SDL_OpenAudioDevice (SDL_GetAudioDeviceName(0, 2), + 0, + &m_audioHandle, + &actual, + 0); + if (m_outputDevice == 0) { + qCritical( "Couldn't open SDL-audio: %s\n", SDL_GetError() ); + return; + } +#else // open the audio device, forcing the desired format if( SDL_OpenAudio( &m_audioHandle, &actual ) < 0 ) { qCritical( "Couldn't open SDL-audio: %s\n", SDL_GetError() ); return; } - m_convertEndian = ( m_audioHandle.format != actual.format ); + + m_outConvertEndian = ( m_audioHandle.format != actual.format ); +#endif + _success_ful = true; + +#ifdef LMMS_HAVE_SDL2 + m_inputAudioHandle = m_audioHandle; + m_inputAudioHandle.callback = sdlInputAudioCallback; + + m_inputDevice = SDL_OpenAudioDevice (SDL_GetAudioDeviceName(0, 1), + 1, + &m_inputAudioHandle, + &actual, + 0); + if (m_inputDevice != 0) { + m_supportsCapture = true; + } else { + m_supportsCapture = false; + qWarning ( "Couldn't open SDL capture device: %s\n", SDL_GetError ()); + } + +#endif } @@ -84,9 +124,18 @@ AudioSdl::~AudioSdl() { stopProcessing(); +#ifdef LMMS_HAVE_SDL2 + if (m_inputDevice != 0) + SDL_CloseAudioDevice(m_inputDevice); + if (m_outputDevice != 0) + SDL_CloseAudioDevice(m_outputDevice); +#else SDL_CloseAudio(); - SDL_Quit(); delete[] m_convertedBuf; +#endif + + SDL_Quit(); + delete[] m_outBuf; } @@ -97,7 +146,12 @@ void AudioSdl::startProcessing() { m_stopped = false; +#ifdef LMMS_HAVE_SDL2 + SDL_PauseAudioDevice (m_outputDevice, 0); + SDL_PauseAudioDevice (m_inputDevice, 0); +#else SDL_PauseAudio( 0 ); +#endif } @@ -107,10 +161,24 @@ void AudioSdl::stopProcessing() { if( SDL_GetAudioStatus() == SDL_AUDIO_PLAYING ) { +#ifdef LMMS_HAVE_SDL2 + SDL_LockAudioDevice (m_inputDevice); + SDL_LockAudioDevice (m_outputDevice); + + m_stopped = true; + + SDL_PauseAudioDevice (m_inputDevice, 1); + SDL_PauseAudioDevice (m_outputDevice, 1); + + SDL_UnlockAudioDevice (m_inputDevice); + SDL_UnlockAudioDevice (m_outputDevice); +#else SDL_LockAudio(); m_stopped = true; SDL_PauseAudio( 1 ); SDL_UnlockAudio(); +#endif + } } @@ -119,6 +187,8 @@ void AudioSdl::stopProcessing() void AudioSdl::applyQualitySettings() { + // Better than if (0) +#if 0 if( 0 )//hqAudio() ) { SDL_CloseAudio(); @@ -135,6 +205,7 @@ void AudioSdl::applyQualitySettings() qCritical( "Couldn't open SDL-audio: %s\n", SDL_GetError() ); } } +#endif AudioDevice::applyQualitySettings(); } @@ -160,6 +231,41 @@ void AudioSdl::sdlAudioCallback( Uint8 * _buf, int _len ) return; } + // SDL2: process float samples +#ifdef LMMS_HAVE_SDL2 + while( _len ) + { + if( m_currentBufferFramePos == 0 ) + { + // frames depend on the sample rate + const fpp_t frames = getNextBuffer( m_outBuf ); + if( !frames ) + { + memset( _buf, 0, _len ); + return; + } + m_currentBufferFramesCount = frames; + + } + const uint min_frames_count = qMin( _len/sizeof(sampleFrame), + m_currentBufferFramesCount + - m_currentBufferFramePos ); + + const float gain = mixer()->masterGain(); + for (uint f = 0; f < min_frames_count; f++) + { + (m_outBuf + m_currentBufferFramePos)[f][0] *= gain; + (m_outBuf + m_currentBufferFramePos)[f][1] *= gain; + } + + memcpy( _buf, m_outBuf + m_currentBufferFramePos, min_frames_count*sizeof(sampleFrame) ); + _buf += min_frames_count*sizeof(sampleFrame); + _len -= min_frames_count*sizeof(sampleFrame); + m_currentBufferFramePos += min_frames_count; + + m_currentBufferFramePos %= m_currentBufferFramesCount; + } +#else while( _len ) { if( m_convertedBufPos == 0 ) @@ -177,7 +283,7 @@ void AudioSdl::sdlAudioCallback( Uint8 * _buf, int _len ) convertToS16( m_outBuf, frames, mixer()->masterGain(), (int_sample_t *)m_convertedBuf, - m_convertEndian ); + m_outConvertEndian ); } const int min_len = qMin( _len, m_convertedBufSize - m_convertedBufPos ); @@ -187,10 +293,26 @@ void AudioSdl::sdlAudioCallback( Uint8 * _buf, int _len ) m_convertedBufPos += min_len; m_convertedBufPos %= m_convertedBufSize; } +#endif } +#ifdef LMMS_HAVE_SDL2 +void AudioSdl::sdlInputAudioCallback(void *_udata, Uint8 *_buf, int _len) { + AudioSdl * _this = static_cast( _udata ); + _this->sdlInputAudioCallback( _buf, _len ); +} + +void AudioSdl::sdlInputAudioCallback(Uint8 *_buf, int _len) { + sampleFrame *samples_buffer = (sampleFrame *) _buf; + fpp_t frames = _len / sizeof ( sampleFrame ); + + mixer()->pushInputFrames (samples_buffer, frames, + true /* applyGain */); +} + +#endif AudioSdl::setupWidget::setupWidget( QWidget * _parent ) : AudioDeviceSetupWidget( AudioSdl::name(), _parent )