1 /*
2 * AudioSdl.cpp - device-class that performs PCM-output via SDL
3 *
4 * Copyright (c) 2004-2009 Tobias Doerffel <tobydox/at/users.sourceforge.net>
5 *
6 * This file is part of LMMS - https://lmms.io
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public
19 * License along with this program (see COPYING); if not, write to the
20 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301 USA.
22 *
23 */
24
25 #include "AudioSdl.h"
26
27 #ifdef LMMS_HAVE_SDL
28
29 #include <QLabel>
30 #include <QLineEdit>
31
32 #include "Engine.h"
33 #include "ConfigManager.h"
34 #include "gui_templates.h"
35 #include "Mixer.h"
36
37
AudioSdl(bool & _success_ful,Mixer * _mixer)38 AudioSdl::AudioSdl( bool & _success_ful, Mixer* _mixer ) :
39 AudioDevice( DEFAULT_CHANNELS, _mixer ),
40 m_outBuf( new surroundSampleFrame[mixer()->framesPerPeriod()] ),
41 m_convertedBufPos( 0 ),
42 m_convertEndian( false )
43 {
44 _success_ful = false;
45
46 m_convertedBufSize = mixer()->framesPerPeriod() * channels()
47 * sizeof( int_sample_t );
48 m_convertedBuf = new Uint8[m_convertedBufSize];
49
50
51 if( SDL_Init( SDL_INIT_AUDIO | SDL_INIT_NOPARACHUTE ) < 0 )
52 {
53 qCritical( "Couldn't initialize SDL: %s\n", SDL_GetError() );
54 return;
55 }
56
57 m_audioHandle.freq = sampleRate();
58 m_audioHandle.format = AUDIO_S16SYS; // we want it in byte-order
59 // of system, so we don't have
60 // to convert the buffers
61 m_audioHandle.channels = channels();
62 m_audioHandle.samples = qMax( 1024, mixer()->framesPerPeriod()*2 );
63
64 m_audioHandle.callback = sdlAudioCallback;
65 m_audioHandle.userdata = this;
66
67 SDL_AudioSpec actual;
68
69 // open the audio device, forcing the desired format
70 if( SDL_OpenAudio( &m_audioHandle, &actual ) < 0 )
71 {
72 qCritical( "Couldn't open SDL-audio: %s\n", SDL_GetError() );
73 return;
74 }
75 m_convertEndian = ( m_audioHandle.format != actual.format );
76
77 _success_ful = true;
78 }
79
80
81
82
~AudioSdl()83 AudioSdl::~AudioSdl()
84 {
85 stopProcessing();
86
87 SDL_CloseAudio();
88 SDL_Quit();
89 delete[] m_convertedBuf;
90 delete[] m_outBuf;
91 }
92
93
94
95
startProcessing()96 void AudioSdl::startProcessing()
97 {
98 m_stopped = false;
99
100 SDL_PauseAudio( 0 );
101 }
102
103
104
105
stopProcessing()106 void AudioSdl::stopProcessing()
107 {
108 if( SDL_GetAudioStatus() == SDL_AUDIO_PLAYING )
109 {
110 SDL_LockAudio();
111 m_stopped = true;
112 SDL_PauseAudio( 1 );
113 SDL_UnlockAudio();
114 }
115 }
116
117
118
119
applyQualitySettings()120 void AudioSdl::applyQualitySettings()
121 {
122 if( 0 )//hqAudio() )
123 {
124 SDL_CloseAudio();
125
126 setSampleRate( Engine::mixer()->processingSampleRate() );
127
128 m_audioHandle.freq = sampleRate();
129
130 SDL_AudioSpec actual;
131
132 // open the audio device, forcing the desired format
133 if( SDL_OpenAudio( &m_audioHandle, &actual ) < 0 )
134 {
135 qCritical( "Couldn't open SDL-audio: %s\n", SDL_GetError() );
136 }
137 }
138
139 AudioDevice::applyQualitySettings();
140 }
141
142
143
144
sdlAudioCallback(void * _udata,Uint8 * _buf,int _len)145 void AudioSdl::sdlAudioCallback( void * _udata, Uint8 * _buf, int _len )
146 {
147 AudioSdl * _this = static_cast<AudioSdl *>( _udata );
148
149 _this->sdlAudioCallback( _buf, _len );
150 }
151
152
153
154
sdlAudioCallback(Uint8 * _buf,int _len)155 void AudioSdl::sdlAudioCallback( Uint8 * _buf, int _len )
156 {
157 if( m_stopped )
158 {
159 memset( _buf, 0, _len );
160 return;
161 }
162
163 while( _len )
164 {
165 if( m_convertedBufPos == 0 )
166 {
167 // frames depend on the sample rate
168 const fpp_t frames = getNextBuffer( m_outBuf );
169 if( !frames )
170 {
171 m_stopped = true;
172 memset( _buf, 0, _len );
173 return;
174 }
175 m_convertedBufSize = frames * channels()
176 * sizeof( int_sample_t );
177
178 convertToS16( m_outBuf, frames,
179 mixer()->masterGain(),
180 (int_sample_t *)m_convertedBuf,
181 m_convertEndian );
182 }
183 const int min_len = qMin( _len, m_convertedBufSize
184 - m_convertedBufPos );
185 memcpy( _buf, m_convertedBuf + m_convertedBufPos, min_len );
186 _buf += min_len;
187 _len -= min_len;
188 m_convertedBufPos += min_len;
189 m_convertedBufPos %= m_convertedBufSize;
190 }
191 }
192
193
194
195
setupWidget(QWidget * _parent)196 AudioSdl::setupWidget::setupWidget( QWidget * _parent ) :
197 AudioDeviceSetupWidget( AudioSdl::name(), _parent )
198 {
199 QString dev = ConfigManager::inst()->value( "audiosdl", "device" );
200 m_device = new QLineEdit( dev, this );
201 m_device->setGeometry( 10, 20, 160, 20 );
202
203 QLabel * dev_lbl = new QLabel( tr( "DEVICE" ), this );
204 dev_lbl->setFont( pointSize<7>( dev_lbl->font() ) );
205 dev_lbl->setGeometry( 10, 40, 160, 10 );
206
207 }
208
209
210
211
~setupWidget()212 AudioSdl::setupWidget::~setupWidget()
213 {
214 }
215
216
217
218
saveSettings()219 void AudioSdl::setupWidget::saveSettings()
220 {
221 ConfigManager::inst()->setValue( "audiosdl", "device",
222 m_device->text() );
223 }
224
225
226 #endif
227
228