AudioSdl: Add support for full SDL2 with float samples and recording

(with backward compatibility for SDL1).

Cherry-picked from dcc442411f
This commit is contained in:
Shmuel H
2017-11-07 12:59:49 +02:00
committed by Lukas W
parent 8165152552
commit ec28a65c89
2 changed files with 148 additions and 9 deletions

View File

@@ -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

View File

@@ -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,25 @@ 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<AudioSdl *>( _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);
}
#endif
AudioSdl::setupWidget::setupWidget( QWidget * _parent ) :
AudioDeviceSetupWidget( AudioSdl::name(), _parent )