Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/openal-0.0.8/src/backends/alc_backend_morphos.c @ 17

Last change on this file since 17 was 17, checked in by landauf, 16 years ago

added openal

File size: 16.2 KB
Line 
1/*
2 * morphos_native.c
3 *
4 * MorphOS backend for OpenAL
5 * using AHI for sound output
6 */
7
8#include "al_siteconfig.h"
9#include "backends/alc_backend.h"
10
11#include <fcntl.h>
12#include <stdlib.h>
13#include <stdio.h>
14#include <string.h>
15
16#include "al_main.h"
17#include "al_debug.h"
18#include "al_rcvar.h"
19#include "alc/alc_context.h"
20
21#include <clib/ddebug_protos.h>
22#include <dos/dostags.h>
23
24#include <proto/exec.h>
25#include <proto/dos.h>
26
27#include <devices/ahi.h>
28#include <proto/ahi.h>
29
30#include <exec/lists.h>
31#include <exec/ports.h>
32#include <exec/semaphores.h>
33
34struct DispatcherStartupMsg
35{
36        struct Message dsm_Msg;
37        LONG                            dsm_Result;
38};
39
40struct Buffer
41{
42        struct AHISampleInfo    bn_SampleInfo;
43        struct SignalSemaphore  bn_Semaphore;
44        ULONG                                              bn_SampleNo;
45        ULONG                                              bn_FillSize;
46};
47
48struct MOSWriteHandle
49{
50        ULONG                            wh_SampleType;
51        ULONG                            wh_Frequency;
52        ULONG                            wh_Channels;
53        struct Buffer*  wh_Buffers;
54        ULONG                            wh_BufSize;
55        UWORD                            wh_WriteBuf;
56        UWORD                            wh_ReadBuf;
57        BOOL                             wh_FirstBufSent;
58        struct DispatcherStartupMsg *wh_StartupMsg;
59        struct MsgPort *wh_StartupPort;
60        struct Process *wh_DispatcherThread;
61        struct MsgPort *wh_DispatcherPort;
62        ULONG                            wh_SwitchSignal;
63};
64
65#define Handle(h)               ((struct MOSWriteHandle*) h)
66
67struct DispatcherInitReport
68{
69        struct Message dir_Msg;
70        ULONG                           dir_RealFrequency;
71        ULONG                           dir_RealBufSize;
72};
73
74#define DISPATCHER_CMD_BREAK            1
75#define DISPATCHER_CMD_START            2
76#define DISPATCHER_CMD_PAUSE            3
77#define DISPATCHER_CMD_RESUME           4
78
79struct DispatcherMsg
80{
81        struct Message dm_Msg;
82        ULONG                           dm_Command;
83};
84
85#define AHI_BUFFERS             4
86#define AHI_BUF_SIZE    _ALC_DEF_BUFSIZ*4
87
88static VOID DispatcherThread(struct MOSWriteHandle*);
89static BOOL start_sound_thread(struct MOSWriteHandle* h, ALuint *bufsiz, ALuint *speed);
90static void stop_sound_thread(struct MOSWriteHandle* h);
91
92static void do_command(struct MOSWriteHandle* h, ULONG cmd)
93{
94        struct DispatcherMsg msg;
95        struct MsgPort *reply_port = CreateMsgPort();
96
97        if (reply_port)
98        {
99                msg.dm_Msg.mn_Node.ln_Type = NT_MESSAGE;
100                msg.dm_Msg.mn_ReplyPort = reply_port;
101                msg.dm_Msg.mn_Length = sizeof (struct DispatcherMsg);
102                msg.dm_Command = cmd;
103                PutMsg(h->wh_DispatcherPort, (struct Message*) &msg);
104                WaitPort(reply_port);
105                GetMsg(reply_port);
106                DeleteMsgPort(reply_port);
107        }
108}
109
110static void *grab_read_native(void)
111{
112        /* Not implemented yet */
113        return NULL;
114}
115
116static void *grab_write_native(void)
117{
118        struct MOSWriteHandle* h;
119
120        h = Handle(AllocVec(sizeof (struct MOSWriteHandle), MEMF_PUBLIC | MEMF_CLEAR));
121
122        if (h == NULL)
123        {
124                /*dprintf("No handle\n");*/
125                return NULL;
126        }
127
128        h->wh_SampleType = AHIST_S16S;
129        h->wh_Channels = 2;
130        h->wh_Frequency = _ALC_CANON_SPEED;
131        h->wh_Buffers = (struct Buffer*) AllocVec(sizeof (struct Buffer)*AHI_BUFFERS, MEMF_PUBLIC | MEMF_CLEAR);
132        h->wh_BufSize = AHI_BUF_SIZE;
133        h->wh_WriteBuf = 0;
134        h->wh_DispatcherThread = NULL;
135        h->wh_DispatcherPort = NULL;
136        h->wh_FirstBufSent = FALSE;
137        h->wh_StartupMsg = (struct DispatcherStartupMsg *) AllocVec(sizeof (struct DispatcherStartupMsg), MEMF_PUBLIC | MEMF_CLEAR);
138        h->wh_StartupPort = CreateMsgPort();
139
140        if (h->wh_Buffers == NULL || h->wh_StartupMsg == NULL || h->wh_StartupPort == NULL)
141        {
142                /*dprintf("No resources\n");*/
143                release_native(h);
144                return NULL;
145        }
146
147        if (start_sound_thread(h, NULL, NULL))
148                return h;
149        /*dprintf("No sound thread\n");*/
150
151        return NULL;
152}
153
154void *
155alcBackendOpenNative_( ALC_OpenMode mode )
156{
157        return mode == ALC_OPEN_INPUT_ ? grab_read_native() : grab_write_native();
158}
159
160static ALboolean set_write_native(void *h,
161                                  ALuint *bufsiz,
162                                  ALenum *fmt,
163                                  ALuint *speed)
164{
165        ULONG sample_type;
166        ULONG channels;
167
168        if (h == NULL)
169                return AL_FALSE;
170
171        /*dprintf("set_write_native(%d, %d, %d)\n", *bufsiz, *fmt, *speed);*/
172
173        switch(*fmt)
174        {
175                case AL_FORMAT_MONO16:
176                        sample_type = AHIST_M16S;
177                        channels = 1;
178                        break;
179                case AL_FORMAT_STEREO16:
180                case AL_FORMAT_QUAD16_LOKI:
181                        sample_type = AHIST_S16S;
182                        channels = 2;
183                        break;
184                case AL_FORMAT_MONO8:
185                        sample_type = AHIST_M8S;
186                        channels = 1;
187                        break;
188                case AL_FORMAT_STEREO8:
189                case AL_FORMAT_QUAD8_LOKI:
190                        sample_type = AHIST_S8S;
191                        channels = 2;
192                        break;
193                default:
194#ifdef DEBUG_MAXIMUS
195                        dprintf("OpenAL: unknown format 0x%x\n", fmt);
196#endif
197                        sample_type = AHIST_S16S;
198                        channels = 2;
199                        *fmt = AL_FORMAT_STEREO16;
200                        break;
201        }
202
203        stop_sound_thread(Handle(h));
204
205        Handle(h)->wh_SampleType = sample_type;
206        Handle(h)->wh_Frequency = *speed;
207        Handle(h)->wh_BufSize = *bufsiz;
208        Handle(h)->wh_Channels = channels;
209        Handle(h)->wh_ReadBuf = 0;
210        Handle(h)->wh_WriteBuf = 0;
211        Handle(h)->wh_FirstBufSent = FALSE;
212
213        return start_sound_thread(Handle(h), bufsiz, speed);
214}
215
216static BOOL start_sound_thread(struct MOSWriteHandle* h, ALuint *bufsiz, ALuint *speed)
217{
218        h->wh_StartupMsg->dsm_Msg.mn_Node.ln_Type = NT_MESSAGE;
219        h->wh_StartupMsg->dsm_Msg.mn_ReplyPort = h->wh_StartupPort;
220        h->wh_StartupMsg->dsm_Msg.mn_Length = sizeof (struct DispatcherStartupMsg);
221
222        if ((h->wh_DispatcherThread = CreateNewProcTags(NP_CodeType,  CODETYPE_PPC,
223                                                                                                                                        NP_Entry,         (ULONG) &DispatcherThread,
224                                                                                                                                        NP_Name,      (ULONG) "OpenAL Sound Thread",
225                                                                                                                                        NP_StackSize, 32000,
226                                                                                                                                        NP_StartupMsg,(ULONG) h->wh_StartupMsg,
227                                                                                                                                        NP_TaskMsgPort,(ULONG) &h->wh_DispatcherPort,
228                                                                                                                                        NP_PPC_Arg1,  (ULONG) h,
229                                                                                                                                        TAG_DONE)))
230        {
231                struct DispatcherInitReport *init_report;
232                WaitPort(h->wh_StartupPort);
233                init_report = (struct DispatcherInitReport *) GetMsg(h->wh_StartupPort);
234                if (init_report->dir_Msg.mn_Length == sizeof (struct DispatcherInitReport))
235                {
236                        if (bufsiz)     *bufsiz = init_report->dir_RealBufSize;
237                        if (speed)      *speed  = init_report->dir_RealFrequency;
238                        ReplyMsg((struct Message*) init_report);
239                        return AL_TRUE;
240                }
241
242                /*
243                 * Otherwise we got the startup message back.
244                 * This means the thread has exited already because something went wrong
245                 * during initialisation.
246                 */
247                h->wh_DispatcherThread = NULL;
248        }
249
250        release_native(h);
251
252        return AL_FALSE;
253}
254
255static void stop_sound_thread(struct MOSWriteHandle* h)
256{
257        if (h && h->wh_DispatcherThread)
258        {
259                do_command(h, DISPATCHER_CMD_BREAK);
260
261                /* Wait until thread has quit */
262                WaitPort(h->wh_StartupPort);
263                GetMsg(h->wh_StartupPort);
264                h->wh_DispatcherThread = NULL;
265                h->wh_DispatcherPort = NULL;
266        }
267}
268
269void release_native(void *h)
270{
271        if (h)
272        {
273                stop_sound_thread(Handle(h));
274
275                if (Handle(h)->wh_Buffers)
276                {
277                        FreeVec(Handle(h)->wh_Buffers);
278                        Handle(h)->wh_Buffers = NULL;
279                }
280                if (Handle(h)->wh_StartupMsg)
281                {
282                        FreeVec(Handle(h)->wh_StartupMsg);
283                        Handle(h)->wh_StartupMsg = NULL;
284                }
285                if (Handle(h)->wh_StartupPort)
286                {
287                        DeleteMsgPort(Handle(h)->wh_StartupPort);
288                        Handle(h)->wh_StartupPort = NULL;
289                }
290                FreeVec(h);
291        }
292}
293
294static ALboolean set_read_native(UNUSED(void *handle),
295                                 UNUSED(ALuint *bufsiz),
296                                 UNUSED(ALenum *fmt),
297                                 UNUSED(ALuint *speed))
298{
299        /* Not yet implemented */
300        return AL_FALSE;
301}
302
303ALboolean
304alcBackendSetAttributesNative_(ALC_OpenMode mode, void *handle, ALuint *bufsiz, ALenum *fmt, ALuint *speed)
305{
306        return mode == ALC_OPEN_INPUT_ ?
307                set_read_native(handle, bufsiz, fmt, speed) :
308                set_write_native(handle, bufsiz, fmt, speed);
309}
310
311void native_blitbuffer(void *h, void *data, int bytes)
312{
313        UWORD next_buf;
314
315        /* Prepare buffer */
316        next_buf = Handle(h)->wh_WriteBuf;
317        ObtainSemaphore(&Handle(h)->wh_Buffers[next_buf].bn_Semaphore);
318        CopyMem(data, Handle(h)->wh_Buffers[next_buf].bn_SampleInfo.ahisi_Address, bytes);
319        Handle(h)->wh_Buffers[next_buf].bn_FillSize = bytes;
320        ReleaseSemaphore(&Handle(h)->wh_Buffers[next_buf].bn_Semaphore);
321
322        if (!Handle(h)->wh_FirstBufSent)
323        {
324                do_command(Handle(h), DISPATCHER_CMD_START);
325                Handle(h)->wh_FirstBufSent = TRUE;
326        }
327        next_buf++;
328        if (next_buf >= AHI_BUFFERS)
329                next_buf = 0;
330        Handle(h)->wh_WriteBuf = next_buf;
331}
332
333ALfloat get_nativechannel(UNUSED(void *h), UNUSED(ALuint channel))
334{
335        /* Not yet implemented */
336        return 0.0;
337}
338
339int set_nativechannel(UNUSED(void *h),UNUSED(ALuint channel),UNUSED(ALfloat volume))
340{
341        /* Not yet implemented */
342        return 0;
343}
344
345void pause_nativedevice(UNUSED(void *h))
346{
347        /* Not tested */
348        dprintf("pause_nativedevice\n");
349//        do_command(Handle(h), DISPATCHER_CMD_PAUSE);
350}
351
352void resume_nativedevice(UNUSED(void *h))
353{
354        /* Not tested */
355        dprintf("resume_nativedevice\n");
356//        do_command(Handle(h), DISPATCHER_CMD_RESUME);
357}
358
359ALsizei capture_nativedevice(UNUSED(void *h), UNUSED(void *capture_buffer), UNUSED(int bufsiz))
360{
361        /* Not yet implemented */
362        return NULL;
363}
364
365/******************************************************************************/
366
367static ULONG OpenAL_SoundFunc(VOID)
368{
369        struct AHIAudioCtrl* ctrl = (struct AHIAudioCtrl*) REG_A2;
370        struct AHISoundMessage* sm = (struct AHISoundMessage*) REG_A1;
371        struct MOSWriteHandle* h = Handle(ctrl->ahiac_UserData);
372        struct ExecBase *SysBase = *(struct ExecBase **) 4;
373
374        AHI_SetSound(sm->ahism_Channel, h->wh_ReadBuf, 0, 0, ctrl, 0);
375
376        /* When last channel has been started, request switching to next buffer */
377        if (sm->ahism_Channel == h->wh_Channels-1)
378                Signal((struct Task*) h->wh_DispatcherThread, h->wh_SwitchSignal);
379
380        return 0;
381}
382
383static struct EmulLibEntry OpenAL_SoundGate = { TRAP_LIB, 0, (void (*)(void)) OpenAL_SoundFunc };
384static struct Hook OpenAL_SoundHook = { { NULL, NULL }, (ULONG (*)(void)) &OpenAL_SoundGate, NULL, NULL }; \
385
386struct Library*   AHIBase = NULL;
387
388static VOID DispatcherThread(struct MOSWriteHandle* h)
389{
390        struct MsgPort*   ahi_port = NULL;
391        struct AHIRequest*  ahi_request = NULL;
392        struct AHIAudioCtrl*ahi_control = NULL;
393        BYTE*                                     sample_bufs = NULL;
394        ULONG                                     sample_size = 2;
395        BYTE                                      ahi_device = -1;
396        LONG                                      switch_sig_bit = -1;
397        LONG                                 locked_buf = -1;
398        struct DispatcherStartupMsg *startup_msg;
399        struct DispatcherInitReport *init_report;
400        struct MsgPort     *task_port = NULL;
401        struct ExecBase *SysBase = *(struct ExecBase **) 4;
402
403        init_report = (struct DispatcherInitReport *) AllocVec(sizeof (struct DispatcherInitReport), MEMF_PUBLIC | MEMF_CLEAR);
404        if (init_report == NULL)
405                return;
406
407        NewGetTaskAttrsA(NULL, &task_port, sizeof (task_port), TASKINFOTYPE_TASKMSGPORT, NULL);
408        NewGetTaskAttrsA(NULL, &startup_msg, sizeof (startup_msg), TASKINFOTYPE_STARTUPMSG, NULL);
409
410        if (task_port == NULL || startup_msg == NULL)
411        {
412                FreeVec(init_report);
413                return;
414        }
415
416        startup_msg->dsm_Result = -1;
417        switch_sig_bit = AllocSignal(-1);
418
419        if (switch_sig_bit != -1 && (ahi_port = CreateMsgPort()))
420        {
421                if ((ahi_request = (struct AHIRequest *) CreateIORequest(ahi_port, sizeof (struct AHIRequest))))
422                {
423                        ahi_request->ahir_Version = 4;
424                        if ((ahi_device = OpenDevice(AHINAME, AHI_NO_UNIT, (struct IORequest *) ahi_request, 0)) == 0)
425                        {
426                                AHIBase = (struct Library*) ahi_request->ahir_Std.io_Device;
427
428                                /*dprintf("AllocAudio with %d channels, %d sounds and frequency %d\n", h->wh_Channels, AHI_BUFFERS, h->wh_Frequency);*/
429                                ahi_control = AHI_AllocAudio(AHIA_AudioID,   AHI_DEFAULT_ID,
430                                                                                                          AHIA_Channels,  h->wh_Channels,
431                                                                                                          AHIA_Sounds,     AHI_BUFFERS,
432                                                                                                          AHIA_MixFreq,   h->wh_Frequency,
433                                                                                                          AHIA_SoundFunc, (ULONG) &OpenAL_SoundHook,
434                                                                                                          AHIA_UserData,        (ULONG) h,
435                                                                                                          TAG_DONE
436                                                                                                         );
437                                if (ahi_control)
438                                {
439                                        ULONG buf_size;
440                                        ULONG samples, fs, fm;
441
442                                        AHI_GetAudioAttrs(AHI_INVALID_ID, ahi_control, AHIDB_MaxPlaySamples, (ULONG) &samples, TAG_DONE);
443                                        AHI_ControlAudio(ahi_control, AHIC_MixFreq_Query, (ULONG) &fm, TAG_DONE);
444                                        fs = h->wh_Frequency;
445
446                                        buf_size = samples*fs/fm;
447                                        /*dprintf("OpenAL: Minimum buffer size is %d, requested buffer size is %d\n", buf_size, h->wh_BufSize);*/
448                                        if (buf_size > h->wh_BufSize)
449                                                h->wh_BufSize = buf_size;
450
451                                        sample_bufs = AllocVec(h->wh_BufSize*AHI_BUFFERS, MEMF_PUBLIC | MEMF_CLEAR);
452                                        if (sample_bufs)
453                                        {
454                                                struct Buffer* bn;
455                                                ULONG   buf;
456                                                LONG err = AHIE_OK;
457
458                                                sample_size = AHI_SampleFrameSize(h->wh_SampleType);
459
460                                                for (buf = 0; buf < AHI_BUFFERS && err == AHIE_OK; buf++)
461                                                {
462                                                        bn = &h->wh_Buffers[buf];
463                                                        bn->bn_SampleNo = buf;
464                                                        bn->bn_SampleInfo.ahisi_Type = h->wh_SampleType;
465                                                        bn->bn_SampleInfo.ahisi_Address = &sample_bufs[buf*h->wh_BufSize];
466                                                        bn->bn_SampleInfo.ahisi_Length = h->wh_BufSize/sample_size;
467                                                        InitSemaphore(&bn->bn_Semaphore);
468                                                        bn->bn_FillSize = 0;
469                                                        err = AHI_LoadSound(buf, AHIST_DYNAMICSAMPLE, &bn->bn_SampleInfo, ahi_control);
470                                                }
471
472                                                if (err != AHIE_OK)
473                                                {
474                                                        FreeVec(sample_bufs);
475                                                        sample_bufs = NULL;
476                                                }
477                                        }
478                                }
479                        }
480                }
481        }
482
483        if (sample_bufs)
484        {
485                BOOL dispatcher_running = TRUE;
486                ULONG signal_mask = 1 << task_port->mp_SigBit;
487                ULONG signal_set;
488                struct MsgPort *reply_port;
489
490                reply_port = CreateMsgPort();
491                if (reply_port == NULL)
492                        reply_port = task_port;
493
494                if (startup_msg)
495                        startup_msg->dsm_Result = 0;
496                init_report->dir_Msg.mn_Node.ln_Type = NT_MESSAGE;
497                init_report->dir_Msg.mn_ReplyPort = reply_port;
498                init_report->dir_Msg.mn_Length = sizeof (struct DispatcherInitReport);
499                AHI_ControlAudio(ahi_control, AHIC_MixFreq_Query, (ULONG) &init_report->dir_RealFrequency, TAG_DONE);
500                init_report->dir_RealBufSize = h->wh_BufSize;
501                PutMsg(startup_msg->dsm_Msg.mn_ReplyPort, (struct Message*) init_report);
502                WaitPort(reply_port);
503                GetMsg(reply_port);
504                FreeVec(init_report);
505                init_report = NULL;
506
507                if (reply_port != task_port)
508                        DeleteMsgPort(reply_port);
509
510                h->wh_SwitchSignal = 1UL << switch_sig_bit;
511                h->wh_ReadBuf = 0;
512                while (dispatcher_running)
513                {
514                        signal_set = Wait(signal_mask);
515
516                        if (signal_set & (1 << task_port->mp_SigBit))
517                        {
518                                struct DispatcherMsg *msg;
519
520                                while ((msg = (struct DispatcherMsg *) GetMsg(task_port)))
521                                {
522                                        if (msg->dm_Msg.mn_Length == sizeof (struct DispatcherMsg))
523                                        {
524                                                switch (msg->dm_Command)
525                                                {
526                                                        case DISPATCHER_CMD_START:
527                                                        {
528                                                                /*
529                                                                 * First buffer has been filled and we were previously not
530                                                                 * playing any sound yet
531                                                                 */
532                                                                ULONG chan;
533                                                                ULONG cur_buf;
534
535                                                                cur_buf = h->wh_ReadBuf;
536                                                                AHI_ControlAudio(ahi_control, AHIC_Play, TRUE, TAG_DONE);
537
538                                                                /* Lock first audio buffer */
539                                                                ObtainSemaphore(&h->wh_Buffers[cur_buf].bn_Semaphore);
540                                                                locked_buf = cur_buf;
541
542                                                                for (chan = 0; chan < h->wh_Channels; chan++)
543                                                                {
544                                                                        AHI_SetFreq(chan, h->wh_Frequency, ahi_control, AHISF_IMM);
545                                                                        AHI_SetVol(chan, 0x10000L, -0x8000L, ahi_control, AHISF_IMM);
546                                                                        AHI_SetSound(chan, cur_buf, 0, 0, ahi_control, AHISF_IMM);
547                                                                }
548
549                                                                Wait(1 << switch_sig_bit);
550                                                                cur_buf++;
551                                                                if (cur_buf >= AHI_BUFFERS)
552                                                                        cur_buf = 0;
553                                                                h->wh_ReadBuf = cur_buf;
554
555                                                                signal_mask |= 1UL << switch_sig_bit;
556                                                                break;
557                                                        }
558
559                                                        case DISPATCHER_CMD_PAUSE:
560                                                        case DISPATCHER_CMD_RESUME:
561                                                                AHI_ControlAudio(ahi_control, AHIC_Play, msg->dm_Command == DISPATCHER_CMD_RESUME, TAG_DONE);
562                                                                break;
563
564                                                        case DISPATCHER_CMD_BREAK:
565                                                                /* Break requests and quit */
566                                                                /*dprintf("Dispatcher thread: break requested\n");*/
567                                                                AHI_ControlAudio(ahi_control, AHIC_Play, FALSE, TAG_DONE);
568                                                                dispatcher_running = FALSE;
569                                                                break;
570                                                }
571                                        }
572
573                                        ReplyMsg((struct Message *) msg);
574                                }
575                        }
576
577                        if (signal_set & (1UL << switch_sig_bit))
578                        {
579                                /* Switch to next read buffer */
580                                ULONG cur_buf;
581
582                                cur_buf = h->wh_ReadBuf;
583                                /*dprintf("Dispatcher thread: buffer switch requested. Releasing lock on %d, locking %d\n", locked_buf, cur_buf);*/
584                                memset(h->wh_Buffers[locked_buf].bn_SampleInfo.ahisi_Address, 0, h->wh_BufSize);
585                                ReleaseSemaphore(&h->wh_Buffers[locked_buf].bn_Semaphore);
586                                cur_buf++;
587                                if (cur_buf >= AHI_BUFFERS)
588                                        cur_buf = 0;
589                                ObtainSemaphore(&h->wh_Buffers[cur_buf].bn_Semaphore);
590                                locked_buf = cur_buf;
591                                h->wh_ReadBuf = cur_buf;
592                                /*dprintf("Dispatcher thread: buffer switch done\n");*/
593                        }
594                }
595        }
596
597        /* Cleanup */
598        if (init_report)
599        {
600                FreeVec(init_report);
601                init_report = NULL;
602        }
603
604        if (locked_buf != -1)
605        {
606                ReleaseSemaphore(&h->wh_Buffers[locked_buf].bn_Semaphore);
607                locked_buf = -1;
608        }
609
610        if (switch_sig_bit != -1)
611        {
612                FreeSignal(switch_sig_bit);
613                switch_sig_bit = -1;
614        }
615
616        if (ahi_control)
617        {
618                AHI_FreeAudio(ahi_control);  /* Also unloads all sounds */
619                ahi_control = NULL;
620        }
621
622        if (ahi_request)
623        {
624                CloseDevice((struct IORequest*) ahi_request);
625                DeleteIORequest((struct IORequest*) ahi_request);
626                ahi_request = NULL;
627                ahi_device = -1;
628        }
629
630        if (sample_bufs)
631        {
632                FreeVec(sample_bufs);
633                sample_bufs = NULL;
634        }
635
636        if (ahi_port)
637        {
638                DeleteMsgPort(ahi_port);
639                ahi_port = NULL;
640        }
641}
Note: See TracBrowser for help on using the repository browser.