ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/SID_Amiga.h
Revision: 1.4
Committed: 2005-06-27T19:55:48Z (18 years, 9 months ago) by cebix
Content type: text/plain
Branch: MAIN
CVS Tags: VERSION_4_2, HEAD
Changes since 1.3: +1 -1 lines
Log Message:
updated copyright dates

File Contents

# Content
1 /*
2 * SID_Amiga.h - 6581 emulation, Amiga specific stuff
3 *
4 * Frodo (C) 1994-1997,2002-2005 Christian Bauer
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include <dos/dostags.h>
22 #include <hardware/cia.h>
23 #include <proto/exec.h>
24 #include <proto/dos.h>
25 #include <proto/ahi.h>
26 #include <proto/graphics.h>
27
28
29 // Library bases
30 struct Library *AHIBase;
31
32 // CIA-A base
33 extern struct CIA ciaa;
34
35
36 /*
37 * Initialization, create sub-process
38 */
39
40 void DigitalRenderer::init_sound(void)
41 {
42 // Find our (main) task
43 main_task = FindTask(NULL);
44
45 // Create signal for communication
46 main_sig = AllocSignal(-1);
47
48 // Create sub-process and wait until it is ready
49 if ((sound_process = CreateNewProcTags(
50 NP_Entry, (ULONG)&sub_invoc,
51 NP_Name, (ULONG)"Frodo Sound Process",
52 NP_Priority, 1,
53 NP_ExitData, (ULONG)this, // Easiest way to supply sub_invoc with this pointer
54 TAG_DONE)) != NULL)
55 Wait(1 << main_sig);
56 }
57
58
59 /*
60 * Destructor, delete sub-process
61 */
62
63 DigitalRenderer::~DigitalRenderer()
64 {
65 // Tell sub-process to quit and wait for completion
66 if (sound_process != NULL) {
67 Signal(&(sound_process->pr_Task), 1 << quit_sig);
68 Wait(1 << main_sig);
69 }
70
71 // Free signal
72 FreeSignal(main_sig);
73 }
74
75
76 /*
77 * Sample volume (for sampled voice)
78 */
79
80 void DigitalRenderer::EmulateLine(void)
81 {
82 sample_buf[sample_in_ptr] = volume;
83 sample_in_ptr = (sample_in_ptr + 1) % SAMPLE_BUF_SIZE;
84 }
85
86
87 /*
88 * Pause sound output
89 */
90
91 void DigitalRenderer::Pause(void)
92 {
93 if (sound_process != NULL)
94 Signal(&(sound_process->pr_Task), 1 << pause_sig);
95 }
96
97
98 /*
99 * Resume sound output
100 */
101
102 void DigitalRenderer::Resume(void)
103 {
104 if (sound_process != NULL)
105 Signal(&(sound_process->pr_Task), 1 << resume_sig);
106 }
107
108
109 /*
110 * Sound sub-process
111 */
112
113 void DigitalRenderer::sub_invoc(void)
114 {
115 // Get pointer to the DigitalRenderer object and call sub_func()
116 DigitalRenderer *r = (DigitalRenderer *)((struct Process *)FindTask(NULL))->pr_ExitData;
117 r->sub_func();
118 }
119
120 void DigitalRenderer::sub_func(void)
121 {
122 ahi_port = NULL;
123 ahi_io = NULL;
124 ahi_ctrl = NULL;
125 sample[0].ahisi_Address = sample[1].ahisi_Address = NULL;
126 ready = FALSE;
127
128 // Create signals for communication
129 quit_sig = AllocSignal(-1);
130 pause_sig = AllocSignal(-1);
131 resume_sig = AllocSignal(-1);
132 ahi_sig = AllocSignal(-1);
133
134 // Open AHI
135 if ((ahi_port = CreateMsgPort()) == NULL)
136 goto wait_for_quit;
137 if ((ahi_io = (struct AHIRequest *)CreateIORequest(ahi_port, sizeof(struct AHIRequest))) == NULL)
138 goto wait_for_quit;
139 ahi_io->ahir_Version = 2;
140 if (OpenDevice(AHINAME, AHI_NO_UNIT, (struct IORequest *)ahi_io, NULL))
141 goto wait_for_quit;
142 AHIBase = (struct Library *)ahi_io->ahir_Std.io_Device;
143
144 // Initialize callback hook
145 sf_hook.h_Entry = sound_func;
146
147 // Open audio control structure
148 if ((ahi_ctrl = AHI_AllocAudio(
149 AHIA_AudioID, 0x0002000b,
150 AHIA_MixFreq, SAMPLE_FREQ,
151 AHIA_Channels, 1,
152 AHIA_Sounds, 2,
153 AHIA_SoundFunc, (ULONG)&sf_hook,
154 AHIA_UserData, (ULONG)this,
155 TAG_DONE)) == NULL)
156 goto wait_for_quit;
157
158 // Prepare SampleInfos and load sounds (two sounds for double buffering)
159 sample[0].ahisi_Type = AHIST_M16S;
160 sample[0].ahisi_Length = SAMPLE_FREQ / CALC_FREQ;
161 sample[0].ahisi_Address = AllocVec(SAMPLE_FREQ / CALC_FREQ * 2, MEMF_PUBLIC | MEMF_CLEAR);
162 sample[1].ahisi_Type = AHIST_M16S;
163 sample[1].ahisi_Length = SAMPLE_FREQ / CALC_FREQ;
164 sample[1].ahisi_Address = AllocVec(SAMPLE_FREQ / CALC_FREQ * 2, MEMF_PUBLIC | MEMF_CLEAR);
165 if (sample[0].ahisi_Address == NULL || sample[1].ahisi_Address == NULL)
166 goto wait_for_quit;
167 AHI_LoadSound(0, AHIST_DYNAMICSAMPLE, &sample[0], ahi_ctrl);
168 AHI_LoadSound(1, AHIST_DYNAMICSAMPLE, &sample[1], ahi_ctrl);
169
170 // Set parameters
171 play_buf = 0;
172 AHI_SetVol(0, 0x10000, 0x8000, ahi_ctrl, AHISF_IMM);
173 AHI_SetFreq(0, SAMPLE_FREQ, ahi_ctrl, AHISF_IMM);
174 AHI_SetSound(0, play_buf, 0, 0, ahi_ctrl, AHISF_IMM);
175
176 // Start audio output
177 AHI_ControlAudio(ahi_ctrl, AHIC_Play, TRUE, TAG_DONE);
178
179 // We are now ready for commands
180 ready = TRUE;
181 Signal(main_task, 1 << main_sig);
182
183 // Accept and execute commands
184 for (;;) {
185 ULONG sigs = Wait((1 << quit_sig) | (1 << pause_sig) | (1 << resume_sig) | (1 << ahi_sig));
186
187 // Quit sub-process
188 if (sigs & (1 << quit_sig))
189 goto quit;
190
191 // Pause sound output
192 if (sigs & (1 << pause_sig))
193 AHI_ControlAudio(ahi_ctrl, AHIC_Play, FALSE, TAG_DONE);
194
195 // Resume sound output
196 if (sigs & (1 << resume_sig))
197 AHI_ControlAudio(ahi_ctrl, AHIC_Play, TRUE, TAG_DONE);
198
199 // Calculate next buffer
200 if (sigs & (1 << ahi_sig))
201 calc_buffer((int16 *)(sample[play_buf].ahisi_Address), sample[play_buf].ahisi_Length * 2);
202 }
203
204 wait_for_quit:
205 // Initialization failed, wait for quit signal
206 Wait(1 << quit_sig);
207
208 quit:
209 // Free everything
210 if (ahi_ctrl != NULL) {
211 AHI_ControlAudio(ahi_ctrl, AHIC_Play, FALSE, TAG_DONE);
212 AHI_FreeAudio(ahi_ctrl);
213 CloseDevice((struct IORequest *)ahi_io);
214 }
215
216 FreeVec(sample[0].ahisi_Address);
217 FreeVec(sample[1].ahisi_Address);
218
219 if (ahi_io != NULL)
220 DeleteIORequest((struct IORequest *)ahi_io);
221
222 if (ahi_port != NULL)
223 DeleteMsgPort(ahi_port);
224
225 FreeSignal(quit_sig);
226 FreeSignal(pause_sig);
227 FreeSignal(resume_sig);
228 FreeSignal(ahi_sig);
229
230 // Quit (synchronized with main task)
231 Forbid();
232 Signal(main_task, 1 << main_sig);
233 }
234
235
236 /*
237 * AHI sound callback, play next buffer and signal sub-process
238 */
239
240 ULONG DigitalRenderer::sound_func(void)
241 {
242 register struct AHIAudioCtrl *ahi_ctrl asm ("a2");
243 DigitalRenderer *r = (DigitalRenderer *)ahi_ctrl->ahiac_UserData;
244 r->play_buf ^= 1;
245 AHI_SetSound(0, r->play_buf, 0, 0, ahi_ctrl, 0);
246 Signal(&(r->sound_process->pr_Task), 1 << (r->ahi_sig));
247 return 0;
248 }
249
250
251 /*
252 * Renderer for SID card
253 */
254
255 // Renderer class
256 class SIDCardRenderer : public SIDRenderer {
257 public:
258 SIDCardRenderer();
259 virtual ~SIDCardRenderer();
260
261 virtual void Reset(void);
262 virtual void EmulateLine(void) {}
263 virtual void WriteRegister(uint16 adr, uint8 byte);
264 virtual void NewPrefs(Prefs *prefs) {}
265 virtual void Pause(void) {}
266 virtual void Resume(void) {}
267
268 private:
269 UBYTE *sid_base; // SID card base pointer
270 };
271
272 // Constructor: Reset SID
273 SIDCardRenderer::SIDCardRenderer()
274 {
275 sid_base = (UBYTE *)0xa00001;
276 Reset();
277 }
278
279 // Destructor: Reset SID
280 SIDCardRenderer::~SIDCardRenderer()
281 {
282 Reset();
283 }
284
285 // Reset SID
286 void SIDCardRenderer::Reset(void)
287 {
288 WaitTOF();
289 ciaa.ciapra |= CIAF_LED;
290 WaitTOF();
291 ciaa.ciapra &= ~CIAF_LED;
292 }
293
294 // Write to register
295 void SIDCardRenderer::WriteRegister(uint16 adr, uint8 byte)
296 {
297 sid_base[adr << 1] = byte;
298 }