1 /*****************************************************************************
2 ** $Source: /cygdrive/d/Private/_SVNROOT/bluemsx/blueMSX/Src/SoundChips/DAC.c,v $
3 **
4 ** $Revision: 1.9 $
5 **
6 ** $Date: 2008-03-30 18:38:45 $
7 **
8 ** More info: http://www.bluemsx.com
9 **
10 ** Copyright (C) 2003-2006 Daniel Vik
11 **
12 ** This program is free software; you can redistribute it and/or modify
13 ** it under the terms of the GNU General Public License as published by
14 ** the Free Software Foundation; either version 2 of the License, or
15 ** (at your option) any later version.
16 **
17 ** This program is distributed in the hope that it will be useful,
18 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 ** GNU General Public License for more details.
21 **
22 ** You should have received a copy of the GNU General Public License
23 ** along with this program; if not, write to the Free Software
24 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 **
26 ******************************************************************************
27 */
28 #include "DAC.h"
29 #include "Board.h"
30 #include <stdlib.h>
31 #include <string.h>
32
33
34 #define OFFSETOF(s, a) ((int)(&((s*)0)->a))
35
36 static Int32* dacSyncMono(DAC* dac, UInt32 count);
37 static Int32* dacSyncStereo(DAC* dac, UInt32 count);
38 static void dacSyncChannel(DAC* dac, UInt32 count, int ch, UInt32 index, UInt32 delta);
39
40 struct DAC
41 {
42 Mixer* mixer;
43 Int32 handle;
44 DacMode mode;
45
46 Int32 enabled;
47 Int32 sampleVolume[2];
48 Int32 oldSampleVolume[2];
49 Int32 sampleVolumeSum[2];
50 Int32 count[2];
51 Int32 ctrlVolume[2];
52 Int32 daVolume[2];
53
54 Int32 defaultBuffer[AUDIO_STEREO_BUFFER_SIZE];
55 Int32 buffer[AUDIO_STEREO_BUFFER_SIZE];
56 };
57
dacReset(DAC * dac)58 void dacReset(DAC* dac) {
59 dac->oldSampleVolume[DAC_CH_LEFT] = 0;
60 dac->sampleVolume[DAC_CH_LEFT] = 0;
61 dac->ctrlVolume[DAC_CH_LEFT] = 0;
62 dac->daVolume[DAC_CH_LEFT] = 0;
63 dac->oldSampleVolume[DAC_CH_RIGHT] = 0;
64 dac->sampleVolume[DAC_CH_RIGHT] = 0;
65 dac->ctrlVolume[DAC_CH_RIGHT] = 0;
66 dac->daVolume[DAC_CH_RIGHT] = 0;
67 }
68
dacCreate(Mixer * mixer,DacMode mode)69 DAC* dacCreate(Mixer* mixer, DacMode mode)
70 {
71 DAC* dac = (DAC*)calloc(1, sizeof(DAC));
72
73 dac->mixer = mixer;
74 dac->mode = mode;
75
76 dacReset(dac);
77
78 if (mode == DAC_MONO) {
79 dac->handle = mixerRegisterChannel(mixer, MIXER_CHANNEL_PCM, 0, dacSyncMono, NULL, dac);
80 }
81 else {
82 dac->handle = mixerRegisterChannel(mixer, MIXER_CHANNEL_PCM, 1, dacSyncStereo, NULL, dac);
83 }
84 return dac;
85 }
86
dacDestroy(DAC * dac)87 void dacDestroy(DAC* dac)
88 {
89 mixerUnregisterChannel(dac->mixer, dac->handle);
90 free(dac);
91 }
92
dacWrite(DAC * dac,DacChannel channel,UInt8 value)93 void dacWrite(DAC* dac, DacChannel channel, UInt8 value)
94 {
95 if (channel == DAC_CH_LEFT || channel == DAC_CH_RIGHT) {
96 Int32 sampleVolume = ((Int32)value - 0x80) * 256;
97 mixerSync(dac->mixer);
98 dac->sampleVolume[channel] = sampleVolume;
99 dac->sampleVolumeSum[channel] += sampleVolume;
100 dac->count[channel]++;
101 dac->enabled = 1;
102 }
103 }
104
dacSyncMono(DAC * dac,UInt32 count)105 static Int32* dacSyncMono(DAC* dac, UInt32 count)
106 {
107 if (!dac->enabled || count == 0) {
108 return dac->defaultBuffer;
109 }
110
111 dacSyncChannel(dac, count, DAC_CH_MONO, 0, 1);
112
113 dac->enabled = dac->buffer[count - 1] != 0;
114
115 return dac->buffer;
116 }
117
dacSyncStereo(DAC * dac,UInt32 count)118 static Int32* dacSyncStereo(DAC* dac, UInt32 count)
119 {
120 if (!dac->enabled || count == 0) {
121 return dac->defaultBuffer;
122 }
123
124 dacSyncChannel(dac, count, DAC_CH_LEFT, 0, 2);
125 dacSyncChannel(dac, count, DAC_CH_RIGHT, 1, 2);
126
127 dac->enabled = dac->buffer[2 * count - 1] != 0 ||
128 dac->buffer[2 * count - 2] != 0;
129
130 return dac->buffer;
131 }
132
dacSyncChannel(DAC * dac,UInt32 count,int ch,UInt32 index,UInt32 delta)133 static void dacSyncChannel(DAC* dac, UInt32 count, int ch, UInt32 index, UInt32 delta)
134 {
135 count *= delta;
136
137 if (dac->count[ch] > 0) {
138 Int32 sampleVolume = dac->sampleVolumeSum[ch] / dac->count[ch];
139 dac->count[ch] = 0;
140 dac->sampleVolumeSum[ch] = 0;
141 dac->ctrlVolume[ch] = sampleVolume - dac->oldSampleVolume[ch] + 0x3fe7 * dac->ctrlVolume[ch] / 0x4000;
142 dac->oldSampleVolume[ch] = sampleVolume;
143 dac->ctrlVolume[ch] = 0x3fe7 * dac->ctrlVolume[ch] / 0x4000;
144
145 dac->daVolume[ch] += 2 * (dac->ctrlVolume[ch] - dac->daVolume[ch]) / 3;
146 dac->buffer[index] = 6 * 9 * dac->daVolume[ch] / 10;
147 index += delta;
148 }
149
150 dac->ctrlVolume[ch] = dac->sampleVolume[ch] - dac->oldSampleVolume[ch] + 0x3fe7 * dac->ctrlVolume[ch] / 0x4000;
151 dac->oldSampleVolume[ch] = dac->sampleVolume[ch];
152
153 for (; index < count; index += delta) {
154 /* Perform DC offset filtering */
155 dac->ctrlVolume[ch] = 0x3fe7 * dac->ctrlVolume[ch] / 0x4000;
156
157 /* Perform simple 1 pole low pass IIR filtering */
158 dac->daVolume[ch] += 2 * (dac->ctrlVolume[ch] - dac->daVolume[ch]) / 3;
159 dac->buffer[index] = 6 * 9 * dac->daVolume[ch] / 10;
160 }
161 }
162
163