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