hydrogen 1.2.6
OssDriver.cpp
Go to the documentation of this file.
1/*
2 * Hydrogen
3 * Copyright(c) 2002-2008 by Alex >Comix< Cominu [comix@users.sourceforge.net]
4 * Copyright(c) 2008-2025 The hydrogen development team [hydrogen-devel@lists.sourceforge.net]
5 *
6 * http://www.hydrogen-music.org
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (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
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see https://www.gnu.org/licenses
20 *
21 */
22
23#include <core/IO/OssDriver.h>
24
25// check if OSS support is enabled
26#if defined(H2CORE_HAVE_OSS) || _DOXYGEN_
27
29
30#include <pthread.h>
31
32namespace H2Core
33{
34
40
41unsigned nNextFrames = 0;
42
43void* ossDriver_processCaller( void* param )
44{
45 Base * __object = ( Base * )param;
46 // stolen from amSynth
47 struct sched_param sched;
48 sched.sched_priority = 50;
49 int res = sched_setscheduler( 0, SCHED_FIFO, &sched );
50 sched_getparam( 0, &sched );
51 if ( res ) {
52 __WARNINGLOG( "Can't set realtime scheduling for OSS Driver" );
53 }
54 __INFOLOG( QString( "Scheduling priority = %1" ).arg( sched.sched_priority ) );
55
56 OssDriver *ossDriver = ( OssDriver* )param;
57
58 sleep( 1 );
59
60 while ( ossDriver_running ) {
62 ossDriver->write();
63 }
64
65 pthread_exit( NULL );
66 return NULL;
67}
68
69
79
80
81
82
83
84
87
88
89
90int OssDriver::init( unsigned nBufferSize )
91{
92 oss_driver_bufferSize = nBufferSize;
93
94 delete[] audioBuffer;
95 audioBuffer = NULL;
96
97 audioBuffer = new short[nBufferSize * 2];
98
99 out_L = new float[nBufferSize];
100 out_R = new float[nBufferSize];
101
102 // clear buffers
103 memset( out_L, 0, nBufferSize * sizeof( float ) );
104 memset( out_R, 0, nBufferSize * sizeof( float ) );
105
106 return 0;
107}
108
109
110
115{
116 INFOLOG( "connect" );
117
118 Preferences *preferencesMng = Preferences::get_instance();
119
120 // initialize OSS
121 int bits = 16;
122 int speed = preferencesMng->m_nSampleRate;
123 int stereo = 1;
124 int bs;
125
126 QString audioDevice;
127#ifdef __NetBSD__
128 audioDevice = "/dev/audio";
129#else
130 audioDevice = preferencesMng->m_sOSSDevice;
131#endif
132
133 // Non blocking OSS open code stolen from GLAME
134 fd = open( audioDevice.toLocal8Bit(), O_WRONLY | O_NONBLOCK ); // test with non blocking open
135 int arg = fcntl( fd, F_GETFL, 0 );
136 if ( arg != -1 ) { // back to blocking mode...
137 fcntl( fd, F_SETFL, arg & ~O_NONBLOCK );
138 }
139
140 if ( fd == -1 ) {
141 ERRORLOG( "DSP ERROR_OPEN" );
142 return 1;
143 }
144 if ( ioctl( fd, SNDCTL_DSP_SYNC, NULL ) < 0 ) {
145 ERRORLOG( "ERROR_IOCTL" );
146 close( fd );
147 return 1;
148 }
149 if ( ioctl( fd, SNDCTL_DSP_SAMPLESIZE, &bits ) < 0 ) {
150 ERRORLOG( "ERROR_IOCTL" );
151 close( fd );
152 return 1;
153 }
154 if ( ioctl( fd, SNDCTL_DSP_SPEED, &speed ) < 0 ) {
155 ERRORLOG( "ERROR_IOCTL" );
156 close( fd );
157 return 1;
158 }
159 if ( ioctl( fd, SNDCTL_DSP_STEREO, &stereo ) < 0 ) {
160 ERRORLOG( "ERROR_IOCTL" );
161 close( fd );
162 return 1;
163 }
164
165 unsigned bufferBits = log2( speed / 60 );
166 int fragSize = 0x00200000 | bufferBits;
167
168 ioctl( fd, SNDCTL_DSP_SETFRAGMENT, &fragSize );
169
170 if ( ioctl( fd, SNDCTL_DSP_GETBLKSIZE, &bs ) < 0 ) {
171 ERRORLOG( "ERROR_IOCTL" );
172 close( fd );
173 return 1;
174 }
175
176 INFOLOG( QString( "Blocksize audio = %1" ).arg( bs ) );
177
178 /* commenting this is a fix against buffersize problems described in ticket 119
179 if ( bs != ( 1 << bufferBits ) ) {
180 ERRORLOG( "ERROR_IOCTL: unable to set BlockSize" );
181 close( fd );
182 return 1;
183 }
184 */// end comment
185
186 int format = AFMT_S16_LE;
187 if ( ioctl( fd, SNDCTL_DSP_SETFMT, &format ) == -1 ) {
188 ERRORLOG( "ERROR_IOCTL unable to set format" );
189 close( fd );
190 return 1;
191 }
192
193 // start main thread
194 ossDriver_running = true;
195 pthread_attr_t attr;
196 pthread_attr_init( &attr );
197
198 pthread_create( &ossDriverThread, &attr, ossDriver_processCaller, this );
199
200 return 0;
201}
202
203
204
205
207{
208 INFOLOG( "disconnect" );
209
210 ossDriver_running = false;
211
212 // join ossDriverThread
213 pthread_join( ossDriverThread, NULL );
214
215 if ( fd != -1 ) {
216 if ( close( fd ) ) {
217 ERRORLOG( "Error closing audio device" );
218 }
219 }
220
221 delete [] out_L;
222 out_L = NULL;
223
224 delete [] out_R;
225 out_R = NULL;
226
227 delete[] audioBuffer;
228 audioBuffer = NULL;
229}
230
231
232
233
236{
237// infoLog("write");
238 unsigned size = oss_driver_bufferSize * 2;
239
240 // prepare the 2-channel array of short
241 for ( unsigned i = 0; i < ( unsigned )oss_driver_bufferSize; ++i ) {
242 audioBuffer[i * 2] = ( short )( out_L[i] * 32768.0 );
243 audioBuffer[i * 2 + 1] = ( short )( out_R[i] * 32768.0 );
244 }
245
246 unsigned long written = ::write( fd, audioBuffer, size * 2 );
247
248 if ( written != ( size * 2 ) ) {
249 ERRORLOG( "OssDriver: Error writing samples to audio device." );
250// std::cerr << "written = " << written << " of " << (size*2) << endl;
251 }
252}
253
254
255
256
257
258int OssDriver::log2( int n )
259{
260 int result = 0;
261 while ( ( n >>= 1 ) > 0 )
262 result++;
263 return result;
264}
265
266
267
268
270{
272}
273
274
276{
277 Preferences *preferencesMng = Preferences::get_instance();
278 return preferencesMng->m_nSampleRate;
279}
280
281
283{
284 return out_L;
285}
287{
288 return out_R;
289}
290};
291
292#endif // OSS support
293
#define sleep(SECONDS)
#define INFOLOG(x)
Definition Object.h:240
#define __WARNINGLOG(x)
Definition Object.h:253
#define __INFOLOG(x)
Definition Object.h:252
#define ERRORLOG(x)
Definition Object.h:242
Base class.
Definition Object.h:62
OSS Audio Driver.
Definition OssDriver.h:65
audioProcessCallback processCallback
Definition OssDriver.h:89
int connect()
Connect return 0: Ok return 1: Generic error.
int fd
file descriptor, for writing to /dev/dsp
Definition OssDriver.h:83
int init(unsigned bufferSize)
Definition OssDriver.cpp:90
unsigned getBufferSize()
OssDriver(audioProcessCallback processCallback)
Definition OssDriver.cpp:70
void write()
Write the audio data.
short * audioBuffer
Definition OssDriver.h:85
unsigned getSampleRate()
Manager for User Preferences File (singleton)
Definition Preferences.h:79
static Preferences * get_instance()
Returns a pointer to the current Preferences singleton stored in __instance.
unsigned m_nSampleRate
Sample rate of the audio.
QString m_sOSSDevice
Device used for output.
int(* audioProcessCallback)(uint32_t, void *)
Definition AudioOutput.h:32
bool ossDriver_running
Definition OssDriver.cpp:36
int oss_driver_bufferSize
Definition OssDriver.cpp:38
pthread_t ossDriverThread
Definition OssDriver.cpp:37
OssDriver * m_pOssDriverInstance
Definition OssDriver.cpp:39
audioProcessCallback ossDriver_audioProcessCallback
Definition OssDriver.cpp:35
void * ossDriver_processCaller(void *param)
Definition OssDriver.cpp:43
unsigned nNextFrames
Definition OssDriver.cpp:41