~ubuntu-branches/ubuntu/hoary/kdemultimedia/hoary

« back to all changes in this revision

Viewing changes to kmix/mixer_sun.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Martin Schulze
  • Date: 2003-01-22 15:00:51 UTC
  • Revision ID: james.westby@ubuntu.com-20030122150051-uihwkdoxf15mi1tn
Tags: upstream-2.2.2
ImportĀ upstreamĀ versionĀ 2.2.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *              KMix -- KDE's full featured mini mixer
 
3
 *
 
4
 *
 
5
 *              Copyright (C) 1996-2000 Christian Esken <esken@kde.org>
 
6
 *                            2000 Brian Hanson <bhanson@hotmail.com>
 
7
 *
 
8
 * This program is free software; you can redistribute it and/or
 
9
 * modify it under the terms of the GNU Library 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
 * Library General Public License for more details.
 
17
 *
 
18
 * You should have received a copy of the GNU Library General Public
 
19
 * License along with this program; if not, write to the Free
 
20
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
21
 */
 
22
 
 
23
#include <sys/types.h>
 
24
#include <sys/stat.h>
 
25
#include <fcntl.h>
 
26
#include <sys/file.h>
 
27
#include <sys/audioio.h>
 
28
#include <errno.h>
 
29
#include <unistd.h>
 
30
 
 
31
#include "mixer_sun.h"
 
32
 
 
33
 
 
34
//======================================================================
 
35
// CONSTANT/ENUM DEFINITIONS
 
36
//======================================================================
 
37
 
 
38
//
 
39
// Mixer Device Numbers
 
40
//
 
41
// Note: We can't just use the Sun port #defines because :
 
42
// 1) Some logical devices don't correspond to ports (master&recmon)
 
43
// 2) The play and record port definitions reuse the same values
 
44
//
 
45
enum MixerDevs
 
46
{
 
47
   MIXERDEV_MASTER_VOLUME,
 
48
   MIXERDEV_INTERNAL_SPEAKER,
 
49
   MIXERDEV_HEADPHONE,
 
50
   MIXERDEV_LINE_OUT,
 
51
   MIXERDEV_RECORD_MONITOR,
 
52
   MIXERDEV_MICROPHONE,
 
53
   MIXERDEV_LINE_IN,
 
54
   MIXERDEV_CD,
 
55
   // Insert new devices before this marker
 
56
   MIXERDEV_END_MARKER
 
57
};
 
58
const int numDevs = MIXERDEV_END_MARKER;
 
59
 
 
60
//
 
61
// Device name strings
 
62
//
 
63
const char* MixerDevNames[] =
 
64
{
 
65
   I18N_NOOP("Master Volume"),
 
66
   I18N_NOOP("Internal Speaker"),
 
67
   I18N_NOOP("Headphone"),
 
68
   I18N_NOOP("Line Out"),
 
69
   I18N_NOOP("Record Monitor"),
 
70
   I18N_NOOP("Microphone"),
 
71
   I18N_NOOP("Line In"),
 
72
   I18N_NOOP("CD")
 
73
};
 
74
 
 
75
//
 
76
// Channel types (this specifies which icon to display)
 
77
//
 
78
const MixDevice::ChannelType MixerChannelTypes[] =
 
79
{
 
80
   MixDevice::VOLUME,       // MASTER_VOLUME
 
81
   MixDevice::AUDIO,        // INTERNAL_SPEAKER
 
82
   MixDevice::EXTERNAL,     // HEADPHONE (we really need an icon for this)
 
83
   MixDevice::EXTERNAL,     // LINE_OUT
 
84
   MixDevice::RECMONITOR,   // RECORD_MONITOR
 
85
   MixDevice::MICROPHONE,   // MICROPHONE
 
86
   MixDevice::EXTERNAL,     // LINE_IN
 
87
   MixDevice::CD            // CD
 
88
};
 
89
 
 
90
//
 
91
// Mapping from device numbers to Sun port mask values
 
92
//
 
93
const uint_t MixerSunPortMasks[] =
 
94
{
 
95
   0,                  // MASTER_VOLUME - no associated port
 
96
   AUDIO_SPEAKER,
 
97
   AUDIO_HEADPHONE,
 
98
   AUDIO_LINE_OUT,
 
99
   0,                  // RECORD_MONITOR - no associated port
 
100
   AUDIO_MICROPHONE,
 
101
   AUDIO_LINE_IN,
 
102
   AUDIO_CD
 
103
};
 
104
 
 
105
 
 
106
//======================================================================
 
107
// FUNCTION/METHOD DEFINITIONS
 
108
//======================================================================
 
109
 
 
110
 
 
111
//======================================================================
 
112
// FUNCTION    : SUN_getMixer
 
113
// DESCRIPTION : Creates and returns a new mixer object.
 
114
//======================================================================
 
115
Mixer* SUN_getMixer( int devnum, int SetNum )
 
116
{
 
117
   Mixer *l_mixer;
 
118
   l_mixer = new Mixer_SUN( devnum, SetNum );
 
119
   l_mixer->setupMixer();
 
120
   return l_mixer;
 
121
}
 
122
 
 
123
//======================================================================
 
124
// FUNCTION    : SUN_getMixerSet
 
125
// DESCRIPTION : Creates and returns a new mixer object.
 
126
//======================================================================
 
127
Mixer* SUN_getMixerSet( MixSet set, int device, int card )
 
128
{
 
129
   Mixer *l_mixer;
 
130
   l_mixer = new Mixer_SUN( device, card );
 
131
   l_mixer->setupMixer( set );
 
132
   return l_mixer;
 
133
}
 
134
 
 
135
//======================================================================
 
136
// FUNCTION    : Mixer::Mixer
 
137
// DESCRIPTION : Class constructor.
 
138
//======================================================================
 
139
Mixer_SUN::Mixer_SUN(int devnum, int card) : Mixer(devnum, card)
 
140
{
 
141
   if ( devnum == -1 )
 
142
      m_devnum = 0;
 
143
   if ( card == -1 )
 
144
      m_cardnum = 0;
 
145
}
 
146
 
 
147
//======================================================================
 
148
// FUNCTION    : Mixer::openMixer
 
149
// DESCRIPTION : Initialize the mixer and open the hardware driver.
 
150
//======================================================================
 
151
int Mixer_SUN::openMixer()
 
152
{
 
153
   //
 
154
   // We don't support multiple cards or devices
 
155
   //
 
156
   if ( m_cardnum != 0 )
 
157
      return Mixer::ERR_OPEN;
 
158
   if ( m_devnum !=0 )
 
159
      return Mixer::ERR_OPEN;
 
160
 
 
161
   //
 
162
   // Release mixer before (re-)opening
 
163
   //
 
164
   release();
 
165
 
 
166
   //
 
167
   // Open the mixer hardware driver
 
168
   //
 
169
   if ( ( fd = open( "/dev/audioctl", O_RDWR ) ) < 0 )
 
170
   {
 
171
      if ( errno == EACCES )
 
172
         return Mixer::ERR_PERM;
 
173
      else
 
174
         return Mixer::ERR_OPEN;
 
175
   }
 
176
   else
 
177
   {
 
178
      //
 
179
      // Mixer is open. Now define all of the mix devices.
 
180
      //
 
181
 
 
182
      if( m_mixDevices.isEmpty() )
 
183
      {
 
184
         for ( int idx = 0; idx < numDevs; idx++ )
 
185
         {
 
186
            Volume vol( 2, AUDIO_MAX_GAIN );
 
187
            readVolumeFromHW( idx, vol );
 
188
            MixDevice* md = new MixDevice( idx, vol, 0,
 
189
               QString(MixerDevNames[idx]), MixerChannelTypes[idx]);
 
190
            md->setRecsrc( isRecsrcHW( idx ) );
 
191
            m_mixDevices.append( md );
 
192
         }
 
193
     }
 
194
     else
 
195
     {
 
196
        for( unsigned int idx = 0; idx < m_mixDevices.count(); idx++ )
 
197
        {
 
198
           MixDevice* md = m_mixDevices.at( idx );
 
199
           if( !md )
 
200
              return ERR_INCOMPATIBLESET;
 
201
           writeVolumeToHW( idx, md->getVolume() );
 
202
        }
 
203
     }
 
204
 
 
205
     m_mixerName = "SUN Audio Mixer";
 
206
     m_isOpen = true;
 
207
 
 
208
     return 0;
 
209
   }
 
210
}
 
211
 
 
212
//======================================================================
 
213
// FUNCTION    : Mixer::releaseMixer
 
214
// DESCRIPTION : Close the hardware driver.
 
215
//======================================================================
 
216
int Mixer_SUN::releaseMixer()
 
217
{
 
218
   int l_i_ret = ::close( fd );
 
219
   return l_i_ret;
 
220
}
 
221
 
 
222
//======================================================================
 
223
// FUNCTION    : Mixer::errorText
 
224
// DESCRIPTION : Convert an error code enum to a text string.
 
225
//======================================================================
 
226
QString Mixer_SUN::errorText( int mixer_error )
 
227
{
 
228
   QString errmsg;
 
229
   switch (mixer_error)
 
230
   {
 
231
      case ERR_PERM:
 
232
         errmsg = i18n(
 
233
           "kmix: You do not have permission to access the mixer device.\n"
 
234
           "Ask your system administrator to fix /dev/audioctl to allow access."
 
235
         );
 
236
         break;
 
237
      default:
 
238
         errmsg = Mixer::errorText( mixer_error );
 
239
   }
 
240
   return errmsg;
 
241
}
 
242
 
 
243
 
 
244
//======================================================================
 
245
// FUNCTION    : Mixer::readVolumeFrmoHW
 
246
// DESCRIPTION : Read the audio information from the driver.
 
247
//======================================================================
 
248
int Mixer_SUN::readVolumeFromHW( int devnum, Volume& volume )
 
249
{
 
250
   audio_info_t audioinfo;
 
251
   uint_t devMask = MixerSunPortMasks[devnum];
 
252
 
 
253
   //
 
254
   // Read the current audio information from the driver
 
255
   //
 
256
   if ( ioctl( fd, AUDIO_GETINFO, &audioinfo ) < 0 )
 
257
   {
 
258
      return( Mixer::ERR_READ );
 
259
   }
 
260
   else
 
261
   {
 
262
      //
 
263
      // Extract the appropriate fields based on the requested device
 
264
      //
 
265
      switch ( devnum )
 
266
      {
 
267
         case MIXERDEV_MASTER_VOLUME :
 
268
            volume.setMuted( audioinfo.output_muted );
 
269
            GainBalanceToVolume( audioinfo.play.gain,
 
270
                                 audioinfo.play.balance,
 
271
                                 volume );
 
272
            break;
 
273
 
 
274
         case MIXERDEV_RECORD_MONITOR :
 
275
            volume.setMuted(FALSE);
 
276
            volume.setAllVolumes( audioinfo.monitor_gain );
 
277
            break;
 
278
 
 
279
         case MIXERDEV_INTERNAL_SPEAKER :
 
280
         case MIXERDEV_HEADPHONE :
 
281
         case MIXERDEV_LINE_OUT :
 
282
            volume.setMuted( (audioinfo.play.port & devMask) ? FALSE : TRUE );
 
283
            GainBalanceToVolume( audioinfo.play.gain,
 
284
                                 audioinfo.play.balance,
 
285
                                 volume );
 
286
            break;
 
287
 
 
288
         case MIXERDEV_MICROPHONE :
 
289
         case MIXERDEV_LINE_IN :
 
290
         case MIXERDEV_CD :
 
291
            volume.setMuted( (audioinfo.record.port & devMask) ? FALSE : TRUE );
 
292
            GainBalanceToVolume( audioinfo.record.gain,
 
293
                                 audioinfo.record.balance,
 
294
                                 volume );
 
295
            break;
 
296
 
 
297
         default :
 
298
            return Mixer::ERR_NODEV;
 
299
      }
 
300
      return 0;
 
301
   }
 
302
}
 
303
 
 
304
//======================================================================
 
305
// FUNCTION    : Mixer::writeVolumeToHW
 
306
// DESCRIPTION : Write the specified audio settings to the hardware.
 
307
//======================================================================
 
308
int Mixer_SUN::writeVolumeToHW( int devnum, Volume volume )
 
309
{
 
310
   uint_t gain;
 
311
   uchar_t balance;
 
312
   uchar_t mute;
 
313
 
 
314
   //
 
315
   // Convert the Volume(left vol, right vol) to the Gain/Balance Sun uses
 
316
   //
 
317
   VolumeToGainBalance( volume, gain, balance );
 
318
   mute = volume.isMuted() ? 1 : 0;
 
319
 
 
320
   //
 
321
   // Read the current audio settings from the hardware
 
322
   //
 
323
   audio_info_t audioinfo;
 
324
   if ( ioctl( fd, AUDIO_GETINFO, &audioinfo ) < 0 )
 
325
   {
 
326
      return( Mixer::ERR_READ );
 
327
   }
 
328
 
 
329
   //
 
330
   // Now, based on the devnum that we are writing to, update the appropriate
 
331
   // volume field and twiddle the appropriate bitmask to enable/mute the
 
332
   // device as necessary.
 
333
   //
 
334
   switch ( devnum )
 
335
   {
 
336
      case MIXERDEV_MASTER_VOLUME :
 
337
         audioinfo.play.gain = gain;
 
338
         audioinfo.play.balance = balance;
 
339
         audioinfo.output_muted = mute;
 
340
         break;
 
341
 
 
342
      case MIXERDEV_RECORD_MONITOR :
 
343
         audioinfo.monitor_gain = gain;
 
344
         // no mute or balance for record monitor
 
345
         break;
 
346
 
 
347
      case MIXERDEV_INTERNAL_SPEAKER :
 
348
      case MIXERDEV_HEADPHONE :
 
349
      case MIXERDEV_LINE_OUT :
 
350
         audioinfo.play.gain = gain;
 
351
         audioinfo.play.balance = balance;
 
352
         if ( mute )
 
353
            audioinfo.play.port &= ~MixerSunPortMasks[devnum];
 
354
         else
 
355
            audioinfo.play.port |= MixerSunPortMasks[devnum];
 
356
         break;
 
357
 
 
358
      case MIXERDEV_MICROPHONE :
 
359
      case MIXERDEV_LINE_IN :
 
360
      case MIXERDEV_CD :
 
361
         audioinfo.record.gain = gain;
 
362
         audioinfo.record.balance = balance;
 
363
         if ( mute )
 
364
            audioinfo.record.port &= ~MixerSunPortMasks[devnum];
 
365
         else
 
366
            audioinfo.record.port |= MixerSunPortMasks[devnum];
 
367
         break;
 
368
 
 
369
      default :
 
370
         return Mixer::ERR_NODEV;
 
371
   }
 
372
 
 
373
   //
 
374
   // Now that we've updated the audioinfo struct, write it back to the hardware
 
375
   //
 
376
   if ( ioctl( fd, AUDIO_SETINFO, &audioinfo ) < 0 )
 
377
   {
 
378
      return( Mixer::ERR_WRITE );
 
379
   }
 
380
   else
 
381
   {
 
382
      return 0;
 
383
   }
 
384
}
 
385
 
 
386
//======================================================================
 
387
// FUNCTION    : Mixer::setRecsrcHW
 
388
// DESCRIPTION :
 
389
//======================================================================
 
390
bool Mixer_SUN::setRecsrcHW( int /* devnum */, bool /* on */ )
 
391
{
 
392
   return FALSE;
 
393
}
 
394
 
 
395
//======================================================================
 
396
// FUNCTION    : Mixer::isRecsrcHW
 
397
// DESCRIPTION : Returns true if the specified device is a record source.
 
398
//======================================================================
 
399
bool Mixer_SUN::isRecsrcHW( int devnum )
 
400
{
 
401
   switch ( devnum )
 
402
   {
 
403
      case MIXERDEV_MICROPHONE :
 
404
      case MIXERDEV_LINE_IN :
 
405
      case MIXERDEV_CD :
 
406
         return TRUE;
 
407
 
 
408
      default :
 
409
         return FALSE;
 
410
   }
 
411
}
 
412
 
 
413
//======================================================================
 
414
// FUNCTION    : Mixer::VolumeToGainBalance
 
415
// DESCRIPTION : Converts a Volume(left vol + right vol) into the
 
416
//               Gain/Balance values used by Sun.
 
417
//======================================================================
 
418
void Mixer_SUN::VolumeToGainBalance( Volume& volume, uint_t& gain, uchar_t& balance )
 
419
{
 
420
   if ( ( volume.channels() == 1 ) ||
 
421
        ( volume[Volume::LEFT] == volume[Volume::RIGHT] ) )
 
422
   {
 
423
      gain = volume[Volume::LEFT];
 
424
      balance = AUDIO_MID_BALANCE;
 
425
   }
 
426
   else
 
427
   {
 
428
      if ( volume[Volume::LEFT] > volume[Volume::RIGHT] )
 
429
      {
 
430
         gain = volume[Volume::LEFT];
 
431
         balance = AUDIO_LEFT_BALANCE +
 
432
           ( AUDIO_MID_BALANCE - AUDIO_LEFT_BALANCE ) *
 
433
           volume[Volume::RIGHT] / volume[Volume::LEFT];
 
434
      }
 
435
      else
 
436
      {
 
437
         gain = volume[Volume::RIGHT];
 
438
         balance = AUDIO_RIGHT_BALANCE -
 
439
           ( AUDIO_RIGHT_BALANCE - AUDIO_MID_BALANCE ) *
 
440
           volume[Volume::LEFT] / volume[Volume::RIGHT];
 
441
      }
 
442
   }
 
443
}
 
444
 
 
445
//======================================================================
 
446
// FUNCTION    : Mixer::GainBalanceToVolume
 
447
// DESCRIPTION : Converts Gain/Balance returned by Sun driver to the
 
448
//               Volume(left vol + right vol) format used by kmix.
 
449
//======================================================================
 
450
void Mixer_SUN::GainBalanceToVolume( uint_t& gain, uchar_t& balance, Volume& volume )
 
451
{
 
452
   if ( volume.channels() == 1 )
 
453
   {
 
454
      volume.setVolume( Volume::LEFT, gain );
 
455
   }
 
456
   else
 
457
   {
 
458
      if ( balance <= AUDIO_MID_BALANCE )
 
459
      {
 
460
         volume.setVolume( Volume::LEFT, gain );
 
461
         volume.setVolume( Volume::RIGHT, gain *
 
462
            ( balance - AUDIO_LEFT_BALANCE ) /
 
463
            ( AUDIO_MID_BALANCE - AUDIO_LEFT_BALANCE ) );
 
464
      }
 
465
      else
 
466
      {
 
467
         volume.setVolume( Volume::RIGHT, gain );
 
468
         volume.setVolume( Volume::LEFT, gain *
 
469
            ( AUDIO_RIGHT_BALANCE - balance ) /
 
470
            ( AUDIO_RIGHT_BALANCE - AUDIO_MID_BALANCE ) );
 
471
      }
 
472
   }
 
473
}