1//============================================================================
2//
3// SSSS tt lll lll
4// SS SS tt ll ll
5// SS tttttt eeee ll ll aaaa
6// SSSS tt ee ee ll ll aa
7// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
8// SS SS tt ee ll ll aa aa
9// SSSS ttt eeeee llll llll aaaaa
10//
11// Copyright (c) 1995-2019 by Bradford W. Mott, Stephen Anthony
12// and the Stella Team
13//
14// See the file "License.txt" for information on usage and redistribution of
15// this file, and for a DISCLAIMER OF ALL WARRANTIES.
16//============================================================================
17
18#include "AudioChannel.hxx"
19
20// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
21AudioChannel::AudioChannel()
22{
23 reset();
24}
25
26// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
27void AudioChannel::reset()
28{
29 myAudc = myAudv = myAudf = 0;
30 myClockEnable = myNoiseFeedback = myNoiseCounterBit4 = myPulseCounterHold = false;
31 myDivCounter = myPulseCounter = myNoiseCounter = 0;
32}
33
34// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
35void AudioChannel::phase0()
36{
37 if (myClockEnable) {
38 myNoiseCounterBit4 = myNoiseCounter & 0x01;
39
40 switch (myAudc & 0x03) {
41 case 0x00:
42 case 0x01:
43 myPulseCounterHold = false;
44 break;
45
46 case 0x02:
47 myPulseCounterHold = (myNoiseCounter & 0x1e) != 0x02;
48 break;
49
50 case 0x03:
51 myPulseCounterHold = !myNoiseCounterBit4;
52 break;
53 }
54
55 switch (myAudc & 0x03) {
56 case 0x00:
57 myNoiseFeedback =
58 ((myPulseCounter ^ myNoiseCounter) & 0x01) ||
59 !(myNoiseCounter || (myPulseCounter != 0x0a)) ||
60 !(myAudc & 0x0c);
61
62 break;
63
64 default:
65 myNoiseFeedback =
66 (((myNoiseCounter & 0x04) ? 1 : 0) ^ (myNoiseCounter & 0x01)) ||
67 myNoiseCounter == 0;
68
69 break;
70 }
71 }
72
73 myClockEnable = myDivCounter == myAudf;
74
75 if (myDivCounter == myAudf || myDivCounter == 0x1f) {
76 myDivCounter = 0;
77 } else {
78 ++myDivCounter;
79 }
80}
81
82// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
83uInt8 AudioChannel::phase1()
84{
85 if (myClockEnable) {
86 bool pulseFeedback = false;
87 switch (myAudc >> 2) {
88 case 0x00:
89 pulseFeedback =
90 (((myPulseCounter & 0x02) ? 1 : 0) ^ (myPulseCounter & 0x01)) &&
91 (myPulseCounter != 0x0a) &&
92 (myAudc & 0x03);
93
94 break;
95
96 case 0x01:
97 pulseFeedback = !(myPulseCounter & 0x08);
98 break;
99
100 case 0x02:
101 pulseFeedback = !myNoiseCounterBit4;
102 break;
103
104 case 0x03:
105 pulseFeedback = !((myPulseCounter & 0x02) || !(myPulseCounter & 0x0e));
106 break;
107 }
108
109 myNoiseCounter >>= 1;
110 if (myNoiseFeedback) {
111 myNoiseCounter |= 0x10;
112 }
113
114 if (!myPulseCounterHold) {
115 myPulseCounter = ~(myPulseCounter >> 1) & 0x07;
116
117 if (pulseFeedback) {
118 myPulseCounter |= 0x08;
119 }
120 }
121 }
122
123 return (myPulseCounter & 0x01) * myAudv;
124}
125
126// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
127void AudioChannel::audc(uInt8 value)
128{
129 myAudc = value & 0x0f;
130}
131
132// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
133void AudioChannel::audv(uInt8 value)
134{
135 myAudv = value & 0x0f;
136}
137
138// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
139void AudioChannel::audf(uInt8 value)
140{
141 myAudf = value & 0x1f;
142}
143
144// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
145bool AudioChannel::save(Serializer& out) const
146{
147 try
148 {
149 out.putInt(myAudc);
150 out.putInt(myAudv);
151 out.putInt(myAudf);
152
153 out.putBool(myClockEnable);
154 out.putBool(myNoiseFeedback);
155 out.putBool(myNoiseCounterBit4);
156 out.putBool(myPulseCounterHold);
157
158 out.putInt(myDivCounter);
159 out.putInt(myPulseCounter);
160 out.putInt(myNoiseCounter);
161 }
162 catch(...)
163 {
164 cerr << "ERROR: TIA_AudioChannel::save" << endl;
165 return false;
166 }
167
168 return true;
169}
170
171// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
172bool AudioChannel::load(Serializer& in)
173{
174 try
175 {
176 myAudc = in.getInt();
177 myAudv = in.getInt();
178 myAudf = in.getInt();
179
180 myClockEnable = in.getBool();
181 myNoiseFeedback = in.getBool();
182 myNoiseCounterBit4 = in.getBool();
183 myPulseCounterHold = in.getBool();
184
185 myDivCounter = in.getInt();
186 myPulseCounter = in.getInt();
187 myNoiseCounter = in.getInt();
188 }
189 catch(...)
190 {
191 cerr << "ERROR: TIA_AudioChannel::load" << endl;
192 return false;
193 }
194
195 return true;
196}
197