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