Adapted to recent changes of %build_linklib.
[AROS-Contrib.git] / FryingPan / framework / Generic / AHI.cpp
blob664929a49981ad6df4b3ca856f6b09b8c22925ea
1 /*
2 * Amiga Generic Set - set of libraries and includes to ease sw development for all Amiga platforms
3 * Copyright (C) 2001-2011 Tomasz Wiszkowski Tomasz.Wiszkowski at gmail.com.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 #include "LibrarySpool.h"
21 #include "AHI.h"
22 #include "Thread.h"
23 #include <exec/io.h>
24 #include <libclass/exec.h>
25 #include <exec/ports.h>
26 #include <devices/ahi.h>
27 #include <dos/dos.h>
28 #include <LibC/LibC.h>
30 using namespace GenNS;
32 AHI::AHI(short channels)
34 pCurrentMode = 0;
35 pAudio.Assign(0);
37 numChannels = channels;
38 if (numChannels > 32)
39 numChannels = 32;
41 for (int i=0; i<256; i++)
43 smpSample[i] = 0;
46 for (int i=0; i<32; i++)
48 smpChan[i] = 0;
49 smpWaits[i] = 0;
52 hHkProc.Initialize(this, &AHI::subProcess);
53 hHkCmd.Initialize(this, &AHI::procCommand);
54 hHkSound.Initialize(this, &AHI::procSoundMessage);
55 hHkMusic.Initialize(this, &AHI::procMusicMessage);
57 pThread = new Thread("AHI Process", hHkProc.GetHook(), NULL);
58 pThread->SetHandler(hHkCmd.GetHook());
59 // ensure everything is up and running
60 pThread->DoSync(cmd_NoOp, 0);
63 AHI::~AHI()
65 if (NULL != pThread)
67 delete pThread;
68 pThread = 0;
71 hModes.ForEach(&freeAudioID);
74 bool AHI::freeAudioID(AudioID* const &id)
76 delete id;
77 return true;
80 unsigned long AHI::GetModeCount()
82 return hModes.Count();
85 const AHI::AudioID *AHI::GetMode(unsigned long id)
87 return hModes[id];
90 bool AHI::SetAudioMode(const AHI::AudioID *id)
92 return (bool)pThread->DoSync(cmd_SetAudio, const_cast<AudioID*>(id));
95 AHI::AudioID *AHI::GetAudioMode()
97 return pCurrentMode;
100 void AHI::FreeAudio()
102 pThread->DoAsync(cmd_FreeAudio, 0);
105 unsigned short AHI::CreateDynamicSample(AHISampleType type, int freq, const Hook* func, int bufflen)
107 ahi_CreateDynamicSample dyn = { type, freq, func, bufflen };
108 return pThread->DoSync(cmd_CreateDynamicSample, &dyn);
111 unsigned short AHI::CreateStaticSample(AHISampleType type, int freq, void* buffer, int length)
113 ahi_CreateStaticSample stat = { type, freq, buffer, length };
114 return pThread->DoSync(cmd_CreateStaticSample, &stat);
117 void AHI::FreeSample(unsigned short idx)
119 ahi_FreeSample fre = { idx };
120 pThread->DoSync(cmd_FreeSample, &fre);
123 bool AHI::PlaySample(unsigned short idx)
125 ahi_PlaySample fre = { idx };
126 return pThread->DoSync(cmd_PlaySample, &fre);
129 const AHI::AudioID *AHI::FindMode(unsigned long id)
131 unsigned long idx;
132 for (idx=0; idx<GetModeCount(); idx++)
134 if (GetMode(idx)->id == id)
135 return GetMode(idx);
137 return 0;
140 unsigned long AHI::subProcess(Thread *pThis, void*)
142 pAHI = AHIIFace::GetInstance();
144 if (pAHI != 0)
146 for (unsigned long i = pAHI->AHI_NextAudioID(AHI_INVALID_ID);
147 i != AHI_INVALID_ID;
148 i = pAHI->AHI_NextAudioID(i))
150 AudioID *pID = new AudioID;
152 pAHI->AHI_GetAudioAttrsA(i, 0, (TagItem*)ARRAY(
153 AHIDB_Name, (int)&pID->name,
154 AHIDB_BufferLen, 63,
155 0, 0));
157 pID->id = i;
158 hModes << pID;
163 pThis->HandleSignals(0xffffffff);
165 do_FreeAudio();
167 pAHI->FreeInstance();
168 return 0;
171 unsigned long AHI::procCommand(AHICommand aCmd, void* pData)
173 switch (aCmd)
175 case cmd_NoOp:
176 return true;
178 case cmd_SetAudio:
179 return do_SetAudio((AudioID*)pData);
181 case cmd_FreeAudio:
182 do_FreeAudio();
183 break;
185 case cmd_CreateDynamicSample:
186 return do_CreateDynamicSample((ahi_CreateDynamicSample*)pData);
188 case cmd_CreateStaticSample:
189 return do_CreateStaticSample((ahi_CreateStaticSample*)pData);
191 case cmd_FreeSample:
192 do_FreeSample(((ahi_FreeSample*)pData)->sample);
193 break;
195 case cmd_PlaySample:
196 return do_PlaySample((ahi_PlaySample*)pData);
198 case cmd_SoundStop:
199 do_SoundStop((ahi_SoundInfo*)pData);
200 break;
202 case cmd_SoundLoop:
203 do_SoundLoop((ahi_SoundInfo*)pData);
204 break;
206 return 0;
209 unsigned long AHI::procSoundMessage(AHIAudioCtrl* pCtl, AHISoundMessage*msg)
211 ExtAHISampleInfo *pExt = smpChan[msg->ahism_Channel];
213 // if this is not true we started nosound
214 if (0 != pExt)
216 if (pExt->dynamic == true)
218 if (pExt->fndsample->ahisi_Length)
220 pThread->DoAsync(cmd_SoundLoop, new ahi_SoundInfo(msg->ahism_Channel));
222 else
224 pThread->DoAsync(cmd_SoundStop, new ahi_SoundInfo(msg->ahism_Channel));
227 else
229 pThread->DoAsync(cmd_SoundStop, new ahi_SoundInfo(msg->ahism_Channel));
232 return 0;
235 unsigned long AHI::procMusicMessage(long cmd, ExtAHISampleInfo* pExt)
237 switch (cmd)
239 case cmd_SoundLoop:
240 pExt->ahisi_Length = pExt->hData(pExt->ahisi_Address, pExt->maxlen);// / pExt->bps;
241 //Generic::MessageBox("Info", "Passing data\n%ld bytes requested,\n%ld bytes received.", "Ok", ARRAY(pExt->maxlen, pExt->ahisi_Length));
242 break;
245 return 0;
248 bool AHI::do_SetAudio(AudioID* newID)
250 AHIAudioCtrl *pCtl = 0;
251 int err;
253 if ((pCurrentMode !=0) && (pCurrentMode->id == newID->id))
254 return true;
255 do_FreeAudio();
256 if (0 == pAHI)
257 return false;
258 if (0 == newID)
259 return true;
261 pCtl = pAHI->AHI_AllocAudioA((TagItem*)ARRAY(
262 AHIA_AudioID, newID->id,
263 AHIA_MixFreq, 44100,
264 AHIA_Channels, numChannels,
265 AHIA_Sounds, 256,
266 AHIA_SoundFunc, (int)hHkSound.GetHook(),
267 TAG_DONE, 0
270 if (0 != pCtl)
272 pAudio.Assign(pCtl);
273 pCurrentMode = newID;
274 err = pAHI->AHI_ControlAudioA(pCtl, (TagItem*)ARRAY(AHIC_Play, true, 0, 0));
275 if (0 != err)
277 request("Error", "Unable to start audio device.\nError code %ld", "Proceed", ARRAY(err));
279 return true;
281 return false;
284 void AHI::do_FreeAudio()
286 AHIAudioCtrl *pCtl = 0;
288 if (pCurrentMode == 0)
289 return;
290 if (0 == pAHI)
291 return;
293 pCtl = pAudio.Assign(0);
294 if (0 != pCtl)
296 for (int i=0; i<256; i++)
298 if (0 != smpSample[i])
300 do_FreeSample(i);
303 pAHI->AHI_FreeAudio(pCtl);
305 pCurrentMode = 0;
308 unsigned short AHI::do_CreateDynamicSample(ahi_CreateDynamicSample *dat)
310 ExtAHISampleInfo *pExt1 = do_AllocSample(true, dat->type, 0, dat->buflen);
311 ExtAHISampleInfo *pExt2 = do_AllocSample(true, dat->type, 0, dat->buflen);
313 if ((0 == pExt1) ||
314 (0 == pExt2))
316 if (0 != pExt1)
317 do_FreeSample(pExt1->id);
318 if (0 != pExt2)
319 do_FreeSample(pExt2->id);
321 return AHI_NOSOUND;
324 pExt1->fndsample = pExt2;
325 pExt2->fndsample = pExt1;
327 pExt1->freq = dat->freq;
328 pExt2->freq = dat->freq;
330 pExt1->update = new Thread("AHI Music");
331 pExt2->update = pExt1->update;
333 pExt1->update->SetHandler(hHkMusic.GetHook());
335 pExt1->hData = dat->func;
336 pExt2->hData = dat->func;
338 return pExt1->id;
341 unsigned short AHI::do_CreateStaticSample(ahi_CreateStaticSample *dat)
343 ExtAHISampleInfo *pExt = do_AllocSample(false, dat->type, dat->buffer, dat->buflen);
344 if (pExt != NULL)
346 pExt->freq = dat->freq;
347 return pExt->id;
349 return AHI_NOSOUND;
352 AHI::ExtAHISampleInfo *AHI::do_AllocSample(bool dynamic, AHISampleType type, void* buffer, int buflen)
354 if (NULL == pAHI)
355 return 0;
357 smpSync.Acquire();
359 ExtAHISampleInfo *pInfo = 0;
360 int i;
361 AHIAudioCtrl *pCtl = 0;
363 for (i=0; i<256; i++)
365 if (smpSample[i] == 0)
366 break;
369 if (i < 256)
371 pInfo = new ExtAHISampleInfo;
373 if (dynamic)
375 buffer = new char[buflen];
378 switch (type)
380 case AHI_Mono8:
381 pInfo->bps = 1;
382 break;
383 case AHI_Mono16:
384 pInfo->bps = 2;
385 break;
386 case AHI_Mono32:
387 pInfo->bps = 4;
388 break;
389 case AHI_Stereo8:
390 pInfo->bps = 2;
391 break;
392 case AHI_Stereo16:
393 pInfo->bps = 4;
394 break;
395 case AHI_Stereo32:
396 pInfo->bps = 8;
397 break;
398 default:
399 pInfo->bps = 1;
401 pInfo->ahisi_Address = buffer;
402 pInfo->ahisi_Length = buflen / pInfo->bps;
403 pInfo->ahisi_Type = type;
404 pInfo->id = i;
405 pInfo->freq = 0;
406 pInfo->dynamic = dynamic;
407 pInfo->fndsample = 0;
408 pInfo->update = 0;
409 pInfo->maxlen = buflen;
411 pCtl = pAudio.ObtainRead();
412 if (NULL != pCtl)
414 pAHI->AHI_LoadSound(i, (dynamic ? AHIST_DYNAMICSAMPLE : AHIST_SAMPLE), pInfo, pCtl);
416 pAudio.Release();
418 smpSample[i] = pInfo;
421 smpSync.Release();
423 return pInfo;
426 void AHI::do_FreeSample(short idx)
428 if (idx >= 256)
429 return;
431 if (0 == pAHI)
432 return;
434 smpSync.Acquire();
435 if (0 != smpSample[idx])
437 ExtAHISampleInfo *pExt1 = smpSample[idx];
438 ExtAHISampleInfo *pExt2 = pExt1->fndsample;
440 // 1 CLEAR SAMPLE AND ITS FRIEND
441 smpSample[idx] = 0;
442 if (NULL != pExt2)
443 smpSample[pExt2->id] = 0;
445 delete pExt1->update;
446 pExt1->update = 0;
447 pExt2->update = 0;
449 // 2 UNLOAD SAMPLE AND ITS FRIEND
450 AHIAudioCtrl *pCtl = pAudio.ObtainRead();
451 if (pCtl)
453 pAHI->AHI_UnloadSound(idx, pCtl);
454 if (NULL != pExt2)
455 pAHI->AHI_UnloadSound(pExt2->id, pCtl);
457 pAudio.Release();
459 // 3 FREE MEMORY BUFFER FOR SAMPLE AND ITS FRIEND
460 if (pExt1->dynamic == true)
461 delete [] ((char*)pExt1->ahisi_Address);
462 if ((NULL != pExt2) &&
463 (pExt2->dynamic == true))
464 delete [] ((char*)pExt2->ahisi_Address);
466 // 4 FREE SAMPLE AND ITS FRIEND
467 delete pExt1;
468 if (NULL != pExt2)
469 delete pExt2;
471 smpSync.Release();
474 bool AHI::do_PlaySample(ahi_PlaySample *dat)
476 int idx = dat->sample;
477 AHIAudioCtrl *pCtl;
478 bool res = false;
479 int err;
480 int chan;
482 if (idx > 255)
483 return false;
484 if (idx < 0)
485 return false;
487 if (0 == smpSample[idx])
488 return false;
490 pCtl = pAudio.ObtainRead();
491 if (pCtl != 0)
493 for (chan=0; chan<numChannels; chan++)
495 if (smpChan[chan] == 0)
496 break;
499 if (chan != numChannels)
501 smpChan[chan] = smpSample[idx];
503 if (smpSample[idx]->dynamic != false)
505 memset(smpSample[idx]->ahisi_Address, 0, smpSample[idx]->maxlen);
506 memset(smpSample[idx]->fndsample->ahisi_Address, 0, smpSample[idx]->maxlen);
509 err = pAHI->AHI_PlayA(pCtl, (TagItem*)ARRAY(
510 AHIP_BeginChannel, chan,
511 AHIP_Freq, smpSample[idx]->freq,
512 AHIP_Vol, 0x10000,
513 AHIP_Pan, 0x8000,
514 AHIP_Sound, idx,
515 AHIP_EndChannel, 0,
516 TAG_DONE, 0));
518 if (err != 0)
520 smpChan[chan] = 0;
521 res = false;
523 else
525 res = true;
529 pAudio.Release();
531 return res;
534 void AHI::do_SoundStop(ahi_SoundInfo* dat)
536 int chan = dat->channel;
537 AHIAudioCtrl *pCtl;
539 delete dat;
541 if (chan > numChannels)
542 return;
543 if (chan < 0)
544 return;
546 smpSync.Acquire();
547 pCtl = pAudio.ObtainRead();
549 if (pCtl != NULL)
551 smpChan[chan] = 0;
552 pAHI->AHI_PlayA(pCtl, (TagItem*)ARRAY(
553 AHIP_BeginChannel, chan,
554 AHIP_Sound, AHI_NOSOUND,
555 AHIP_Vol, 65536,
556 AHIP_Pan, 32768,
557 AHIP_LoopSound, 0,
558 AHIP_EndChannel, 0,
559 TAG_DONE, 0));
560 pAHI->AHI_SetSound(chan, AHI_NOSOUND, 0, 0, pCtl, 0);
562 if (smpWaits[chan] != NULL)
564 Exec->Signal(smpWaits[chan], 1 << (smpSignals[chan]));
565 smpWaits[chan] = 0;
568 pAudio.Release();
569 smpSync.Release();
572 void AHI::WaitSample(unsigned short sample)
574 bool bWait = false;
575 int sig = Exec->AllocSignal(-1);
577 smpSync.Acquire();
579 for (int i=0; i<numChannels; i++)
581 if ((smpChan[i] != 0) &&
582 (smpChan[i]->id == sample))
584 smpWaits[i] = Exec->FindTask(0);
585 smpSignals[i] = sig;
586 bWait = true;
590 smpSync.Release();
592 if (true == bWait)
594 Exec->Wait(1 << sig);
596 Exec->FreeSignal(sig);
599 void AHI::do_SoundLoop(ahi_SoundInfo* info)
601 ExtAHISampleInfo *pExt = smpChan[info->channel];
602 AHIAudioCtrl *pCtl = pAudio.ObtainRead();
604 smpChan[info->channel] = pExt->fndsample;
605 pExt->update->DoAsync(cmd_SoundLoop, pExt->fndsample);
606 pAHI->AHI_SetSound(info->channel, pExt->fndsample->id, 0, 0, pCtl, 0);
607 pAudio.Release();
608 return;