libsidplayfp  0.3.5
xsid.h
1 /***************************************************************************
2  xsid.h - Support for Playsids Extended
3  Registers
4  -------------------
5  begin : Tue Jun 20 2000
6  copyright : (C) 2000 by Simon White
7  email : s_a_white@email.com
8  ***************************************************************************/
9 
10 /***************************************************************************
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  ***************************************************************************/
18 /***************************************************************************
19  * $Log: xsid.h,v $
20  * Revision 1.22 2003/10/28 00:22:53 s_a_white
21  * getTime now returns a time with respect to the clocks desired phase.
22  *
23  * Revision 1.21 2002/09/23 19:42:52 s_a_white
24  * Fixed intel compiler warnings.
25  *
26  * Revision 1.20 2002/07/17 19:18:17 s_a_white
27  * Changed bad #if to #ifdef
28  *
29  * Revision 1.19 2002/02/21 20:26:13 s_a_white
30  * Nolonger default to Galway Mode when Noise samples init incorrectly. Fixes
31  * VARIOUS/S-Z/Zyron/Bouncy_Balls.sid (HVSC).
32  *
33  * Revision 1.18 2002/02/17 16:34:39 s_a_white
34  * New reset interface
35  *
36  * Revision 1.17 2001/11/16 19:22:04 s_a_white
37  * Removed compiler warning for unused parameter.
38  *
39  * Revision 1.16 2001/10/18 22:36:16 s_a_white
40  * GCC3 fixes.
41  *
42  * Revision 1.15 2001/07/14 16:48:35 s_a_white
43  * Sync with sidbuilder class project.
44  *
45  * Revision 1.14 2001/07/14 12:59:39 s_a_white
46  * XSID effeciency increased. Now uses new component classes and event
47  * generation.
48  *
49  * Revision 1.13 2001/04/20 22:21:06 s_a_white
50  * inlined updateSidData0x18.
51  *
52  * Revision 1.12 2001/03/25 19:51:23 s_a_white
53  * Performance update.
54  *
55  * Revision 1.11 2001/03/19 23:40:46 s_a_white
56  * Better support for global debug.
57  *
58  * Revision 1.10 2001/03/09 22:27:13 s_a_white
59  * Speed optimisation update.
60  *
61  * Revision 1.9 2001/03/01 23:45:58 s_a_white
62  * Combined both through sid and non-through sid modes. Can be selected
63  * at runtime now.
64  *
65  * Revision 1.8 2001/02/21 21:46:34 s_a_white
66  * 0x1d = 0 now fixed. Limit checking on sid volume. This helps us determine
67  * even better what the sample offset should be (fixes Skate and Die).
68  *
69  * Revision 1.7 2001/02/07 21:02:30 s_a_white
70  * Supported for delaying samples for frame simulation. New alogarithm to
71  * better guess original tunes volume when playing samples.
72  *
73  * Revision 1.6 2000/12/12 22:51:01 s_a_white
74  * Bug Fix #122033.
75  *
76  ***************************************************************************/
77 
78 /*
79 Effectively there is only 1 channel, which can either perform Galway Noise
80 or Sampling. However, to achieve all the effects on a C64, 2 sampling
81 channels are required. No divide by 2 is required and is compensated for
82 automatically in the C64 machine code.
83 
84 Confirmed by Warren Pilkington using the tune Turbo Outrun:
85 A new sample must interrupt an existing sample running on the same channel.
86 
87 Confirmed by Michael Schwendt and Antonia Vera using the tune Game Over:
88 A Galway Sample or Noise sequence cannot interrupt any other. However
89 the last of these new requested sequences will be played after the current
90 sequence ends.
91 
92 Lastly playing samples through the SIDs volume is not as clean as playing
93 them on their own channel. Playing through the SID will effect the volume
94 of the other channels and this will be most noticable at low frequencies.
95 These effects are however present in the original SID music.
96 
97 Some SIDs put values directly into the volume register. Others play samples
98 with respect to the current volume. We can't for definate know which the author
99 has chosen originally. We must just make a guess based on what the volume
100 is initially at the start of a sample sequence and from the details xSID has been
101 programmed with.
102 */
103 
104 #ifndef _xsid_h_
105 #define _xsid_h_
106 
107 #ifdef HAVE_CONFIG_H
108 # include "config.h"
109 #endif
110 
111 #include "sidplayfp/sidbuilder.h"
112 #include "sidplayfp/event.h"
113 
114 // XSID configuration settings
115 //#define XSID_DEBUG 1
116 
117 // Support global debug option
118 #ifdef DEBUG
119 # ifndef XSID_DEBUG
120 # define XSID_DEBUG DEBUG
121 # endif
122 #endif
123 
124 #ifdef XSID_DEBUG
125 # include <stdio.h>
126 #endif
127 
128 class XSID;
129 class channel
130 {
131 private:
132  // General
133  const char * const m_name;
134  EventContext &m_context;
135  event_phase_t m_phase;
136  XSID &m_xsid;
137  friend class XSID;
138 
139  EventCallback<channel> m_sampleEvent;
140  EventCallback<channel> m_galwayEvent;
141 
142  uint_least16_t address;
143  uint_least16_t cycleCount; // Counts to zero and triggers!
144  enum {FM_NONE = 0, FM_HUELS, FM_GALWAY} mode;
145  bool active;
146  uint_least8_t volShift;
147  uint_least8_t sampleLimit;
148  int8_t sample;
149  uint8_t reg[0x10];
150 
151  // Sample Section
152  uint_least16_t samEndAddr;
153  uint_least16_t samRepeatAddr;
154  uint_least16_t samPeriod;
155  uint_least8_t samRepeat;
156  uint_least8_t samScale;
157  enum {SO_LOWHIGH = 0, SO_HIGHLOW = 1};
158  uint_least8_t samOrder;
159  uint_least8_t samNibble;
160 
161  // Galway Section
162  uint_least8_t galTones;
163  uint_least8_t galInitLength;
164  uint_least8_t galLength;
165  uint_least8_t galVolume;
166  uint_least8_t galLoopWait;
167  uint_least8_t galNullWait;
168 
169  // For Debugging
170  event_clock_t cycles;
171  event_clock_t outputs;
172 
173 private:
174  channel (const char * const name, EventContext *context, XSID *xsid);
175  void free (void);
176  void silence (void);
177  void sampleInit (void);
178  void sampleClock (void);
179  void galwayInit (void);
180  void galwayClock (void);
181 
182  // Compress address to not leave so many spaces
183  uint_least8_t convertAddr(uint_least8_t addr)
184  { return ((addr & 0x3) | ((addr >> 3) & 0x0c)); }
185 
186  void reset (void);
187  uint8_t read (uint_least8_t addr)
188  { return reg[convertAddr (addr)]; }
189  void write (uint_least8_t addr, uint8_t data)
190  { reg[convertAddr (addr)] = data; }
191  int8_t output (void);
192  bool isGalway (void)
193  { return mode == FM_GALWAY; }
194 
195  uint_least8_t limit (void)
196  { return sampleLimit; }
197 
198  inline void checkForInit (void);
199  inline int8_t sampleCalculate (void);
200  inline void galwayTonePeriod (void);
201 
202  // Used to indicate if channel is running
203  operator bool() const { return (active); }
204 };
205 
206 
207 class XSID: public sidemu, private Event
208 {
209  friend class channel;
210 
211 private:
212  channel ch4;
213  channel ch5;
214  bool muted;
215  bool suppressed;
216  static const char *credit;
217 
218  uint8_t sidData0x18;
219  bool _sidSamples;
220  int8_t sampleOffset;
221  static const int8_t sampleConvertTable[16];
222  bool wasRunning;
223 
224 private:
225  void event (void);
226  void checkForInit (channel *ch);
227  inline void setSidData0x18 (void);
228  inline void recallSidData0x18 (void);
229  int8_t sampleOutput (void);
230  void sampleOffsetCalc (void);
231  virtual uint8_t readMemByte (uint_least16_t addr) = 0;
232  virtual void writeMemByte (uint8_t data) = 0;
233 
234 public:
235  XSID (EventContext *context);
236 
237  // Standard calls
238  void reset () { sidemu::reset (); }
239  void reset (uint8_t);
240  uint8_t read (uint_least8_t) { return 0; }
241  void write (uint_least8_t, uint8_t) { ; }
242  const char *credits (void) {return credit;}
243 
244  // Specialist calls
245  uint8_t read (uint_least16_t) { return 0; }
246  void write (uint_least16_t addr, uint8_t data);
247  void mute (bool enable);
248  bool isMuted (void) { return muted; }
249  void suppress (bool enable);
250 
251  void sidSamples (bool enable)
252  { _sidSamples = enable; }
253  // Return whether we care it was changed.
254  bool storeSidData0x18 (uint8_t data);
255 };
256 
257 #endif // _xsid_h_