ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/SID_Amiga.h
Revision: 1.2
Committed: 2003-07-01T17:51:17Z (20 years, 9 months ago) by cebix
Content type: text/plain
Branch: MAIN
Changes since 1.1: +1 -1 lines
Log Message:
updated copyright date

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * SID_Amiga.h - 6581 emulation, Amiga specific stuff
3     *
4 cebix 1.2 * Frodo (C) 1994-1997,2002-2003 Christian Bauer
5 cebix 1.1 *
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     }