poseidon: Fix a number of BPTR issues
[AROS.git] / rom / usb / classes / audio / usbaudio.class.c
blob1fc9906ff75da26b39c530834ba02f436d3e6b18
1 /*
2 *----------------------------------------------------------------------------
3 * usbaudio class for poseidon
4 *----------------------------------------------------------------------------
5 * By Chris Hodges <chrisly@platon42.de>
6 */
8 #include "debug.h"
10 #include "numtostr.h"
11 #include "usbaudio.class.h"
13 #include <proto/ahi.h>
15 #define SUBLIBNAME "usbaudio.audio"
17 /* /// "Lib Stuff" */
18 static const STRPTR libname = MOD_NAME_STRING;
20 static
21 const APTR SubLibFuncTable[] =
23 &AROS_SLIB_ENTRY(subLibOpen, nep, 1),
24 &AROS_SLIB_ENTRY(subLibClose, nep, 2),
25 &AROS_SLIB_ENTRY(subLibExpunge, nep, 3),
26 &AROS_SLIB_ENTRY(subLibReserved, nep, 4),
27 &AROS_SLIB_ENTRY(subLibAllocAudio, nep, 5),
28 &AROS_SLIB_ENTRY(subLibFreeAudio, nep, 6),
29 &AROS_SLIB_ENTRY(subLibDisable, nep, 7),
30 &AROS_SLIB_ENTRY(subLibEnable, nep, 8),
31 &AROS_SLIB_ENTRY(subLibStart, nep, 9),
32 &AROS_SLIB_ENTRY(subLibUpdate, nep, 10),
33 &AROS_SLIB_ENTRY(subLibStop, nep, 11),
34 &AROS_SLIB_ENTRY(subLibSetVol, nep, 12),
35 &AROS_SLIB_ENTRY(subLibSetFreq, nep, 13),
36 &AROS_SLIB_ENTRY(subLibSetSound, nep, 14),
37 &AROS_SLIB_ENTRY(subLibSetEffect, nep, 15),
38 &AROS_SLIB_ENTRY(subLibLoadSound, nep, 16),
39 &AROS_SLIB_ENTRY(subLibUnloadSound, nep, 17),
40 &AROS_SLIB_ENTRY(subLibGetAttr, nep, 18),
41 &AROS_SLIB_ENTRY(subLibHardwareControl, nep, 19),
42 (APTR) -1,
45 static int libInit(LIBBASETYPEPTR nh)
47 struct NepAudioBase *ret = NULL;
49 KPRINTF(10, ("libInit nh: 0x%08lx SysBase: 0x%08lx\n", nh, SysBase));
51 nh->nh_UtilityBase = OpenLibrary("utility.library", 39);
53 #define UtilityBase nh->nh_UtilityBase
55 if(UtilityBase)
57 /* Create default config */
58 nh->nh_CurrentCGC.cgc_ChunkID = AROS_LONG2BE(MAKE_ID('U','A','U','D'));
59 nh->nh_CurrentCGC.cgc_Length = AROS_LONG2BE(sizeof(struct ClsGlobalCfg)-8);
61 NewList(&nh->nh_Units);
63 KPRINTF(1, ("Before MakeLibrary\n"));
64 if((nh->nh_SubLibBase = (struct NepAudioSubLibBase *) MakeLibrary((APTR) SubLibFuncTable,
65 NULL,
66 (APTR) subLibInit,
67 sizeof(struct NepAudioSubLibBase), NULL)))
69 KPRINTF(1, ("After MakeLibrary\n"));
71 nh->nh_SubLibBase->nas_ClsBase = nh;
72 Forbid();
73 AddLibrary((struct Library *) nh->nh_SubLibBase);
74 nh->nh_SubLibBase->nas_Library.lib_OpenCnt++;
75 Permit();
76 ret = nh;
77 } else {
78 KPRINTF(20, ("failed to create usbaudio.audio\n"));
80 } else {
81 KPRINTF(20, ("libInit: OpenLibrary(\"utility.library\", 39) failed!\n"));
84 KPRINTF(10, ("libInit: Ok\n"));
85 return(ret ? TRUE : FALSE);
88 static int libOpen(LIBBASETYPEPTR nh)
90 KPRINTF(10, ("libOpen nh: 0x%08lx\n", nh));
91 nLoadClassConfig(nh);
92 return(TRUE);
95 static int libExpunge(LIBBASETYPEPTR nh)
97 struct NepClassAudio *nch;
98 struct NepAudioMode *nam;
100 KPRINTF(10, ("libExpunge nh: 0x%08lx\n", nh));
102 if(nh->nh_SubLibBase->nas_Library.lib_OpenCnt == 1)
104 KPRINTF(1, ("libExpunge: closelibrary utilitybase 0x%08lx\n",
105 UtilityBase));
106 CloseLibrary((struct Library *) UtilityBase);
108 nch = (struct NepClassAudio *) nh->nh_Units.lh_Head;
109 while(nch->nch_Node.ln_Succ)
111 Remove((struct Node *) nch);
112 nam = (struct NepAudioMode *) nch->nch_AudioModes.lh_Head;
113 while(nam->nam_Node.ln_Succ)
115 Remove(&nam->nam_Node);
116 FreeVec(nam);
117 nam = (struct NepAudioMode *) nch->nch_AudioModes.lh_Head;
120 FreeVec(nch);
121 nch = (struct NepClassAudio *) nh->nh_Units.lh_Head;
124 nh->nh_SubLibBase->nas_Library.lib_OpenCnt--;
125 RemLibrary((struct Library *) nh->nh_SubLibBase);
126 KPRINTF(5, ("libExpunge: Unloading done! usbaudio.class expunged!\n\n"));
127 } else {
128 KPRINTF(5, ("libExpunge: Could not expunge, LIBF_DELEXP set!\n"));
129 return(FALSE);
132 return(TRUE);
135 ADD2INITLIB(libInit, 0)
136 ADD2OPENLIB(libOpen, 0)
137 ADD2EXPUNGELIB(libExpunge, 0)
138 /* \\\ */
142 * ***********************************************************************
143 * * Library functions *
144 * ***********************************************************************
147 #undef UtilityBase
148 #define UtilityBase nh->nh_UtilityBase
150 /* /// "nVerifyAudioStreamClass()" */
151 BOOL nVerifyAudioStreamDevice(struct Library *ps, struct PsdInterface *pif)
153 struct PsdConfig *pc;
154 struct PsdDevice *pd;
155 struct PsdInterface *subpif;
156 struct UsbAudioHeaderDesc10 *header = NULL;
157 IPTR ifclass;
158 IPTR subclass;
159 IPTR proto;
160 UWORD bcdvers;
161 UWORD cnt;
162 APTR desc;
164 psdGetAttrs(PGA_INTERFACE, pif,
165 IFA_Config, &pc,
166 IFA_Class, &ifclass,
167 IFA_SubClass, &subclass,
168 IFA_Protocol, &proto,
169 TAG_DONE);
171 psdGetAttrs(PGA_CONFIG, pc, CA_Device, &pd, TAG_END);
173 if((ifclass == AUDIO_CLASSCODE) && (subclass == AUDIO_CTRL_SUBCLASS))
175 desc = psdFindDescriptor(pd, NULL,
176 DDA_Interface, pif,
177 DDA_DescriptorType, UDT_CS_INTERFACE,
178 DDA_CS_SubType, UDST_AUDIO_CTRL_HEADER,
179 TAG_END);
181 if(desc)
183 psdGetAttrs(PGA_DESCRIPTOR, desc, DDA_DescriptorData, &header, TAG_END);
184 bcdvers = (header->bcdADC0|(header->bcdADC1<<8));
185 if(bcdvers == 0x0100)
187 for(cnt = 0; cnt < header->bInCollection; cnt++)
189 subpif = psdFindInterface(pd, NULL,
190 IFA_InterfaceNum, header->baInterfaceNr[cnt],
191 IFA_Class, AUDIO_CLASSCODE,
192 IFA_SubClass, AUDIO_STREAM_SUBCLASS,
193 TAG_END);
194 if(subpif)
196 return(TRUE);
199 } else {
200 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "Unsupported audio class spec version %lx.%2lx", bcdvers>>8, bcdvers & 0xff);
204 return(FALSE);
206 /* \\\ */
208 /* /// "usbAttemptInterfaceBinding()" */
209 struct NepClassAudio * usbAttemptInterfaceBinding(struct NepAudioBase *nh, struct PsdInterface *pif)
211 struct Library *ps;
212 BOOL isaudio;
214 KPRINTF(1, ("nepAudioAttemptInterfaceBinding(%08lx)\n", pif));
215 if((ps = OpenLibrary("poseidon.library", 4)))
217 isaudio = nVerifyAudioStreamDevice(ps, pif);
218 CloseLibrary(ps);
219 if(isaudio)
221 return(usbForceInterfaceBinding(nh, pif));
224 return(NULL);
226 /* \\\ */
228 /* /// "usbForceInterfaceBinding()" */
229 struct NepClassAudio * usbForceInterfaceBinding(struct NepAudioBase *nh, struct PsdInterface *pif)
231 struct Library *ps;
232 struct NepClassAudio *nch;
233 struct PsdConfig *pc;
234 struct PsdDevice *pd;
235 STRPTR devname;
236 IPTR altifnum;
237 IPTR ifnum;
238 IPTR cfgnum;
239 IPTR prodid;
240 IPTR vendid;
241 ULONG unitno;
242 BOOL unitfound;
243 UBYTE buf[64];
244 struct Task *tmptask;
246 KPRINTF(1, ("nepAudioAttemptInterfaceBinding(%08lx)\n", pif));
247 if((ps = OpenLibrary("poseidon.library", 4)))
249 psdGetAttrs(PGA_INTERFACE, pif,
250 IFA_InterfaceNum, &ifnum,
251 IFA_AlternateNum, &altifnum,
252 IFA_Config, &pc,
253 TAG_DONE);
254 psdGetAttrs(PGA_CONFIG, pc,
255 CA_Device, &pd,
256 CA_ConfigNum, &cfgnum,
257 TAG_END);
258 psdGetAttrs(PGA_DEVICE, pd,
259 DA_ProductID, &prodid,
260 DA_VendorID, &vendid,
261 DA_ProductName, &devname,
262 TAG_END);
263 unitno = 0;
264 nch = (struct NepClassAudio *) nh->nh_Units.lh_Head;
265 while(nch->nch_Node.ln_Succ)
267 if(nch->nch_UnitNo == unitno)
269 unitno++;
270 nch = (struct NepClassAudio *) nh->nh_Units.lh_Head;
271 } else {
272 nch = (struct NepClassAudio *) nch->nch_Node.ln_Succ;
275 unitfound = FALSE;
276 nch = (struct NepClassAudio *) nh->nh_Units.lh_Head;
277 while(nch->nch_Node.ln_Succ)
279 if((nch->nch_UnitAltIfNum == altifnum) && (nch->nch_UnitIfNum == ifnum) &&
280 (nch->nch_UnitProdID == prodid) && (nch->nch_UnitVendorID == vendid))
282 unitno = nch->nch_UnitNo;
283 unitfound = TRUE;
284 break;
286 nch = (struct NepClassAudio *) nch->nch_Node.ln_Succ;
288 if(!unitfound)
290 /* as units are freed in the expunge-vector, the memory is
291 outside the scope of the poseidon library */
292 if(!(nch = AllocVec(sizeof(struct NepClassAudio), MEMF_PUBLIC|MEMF_CLEAR)))
294 Permit();
295 CloseLibrary(ps);
296 return(NULL);
298 nch->nch_ClsBase = nh;
299 nch->nch_Device = NULL;
300 nch->nch_Interface = pif;
301 nch->nch_UnitNo = unitno;
302 NewList(&nch->nch_AudioModes);
303 NewList(&nch->nch_AudioUnits);
304 Forbid();
305 AddTail(&nh->nh_Units, &nch->nch_Node);
306 Permit();
308 nch->nch_DenyRequests = TRUE;
310 nLoadClassConfig(nh);
312 psdSafeRawDoFmt(buf, 64, "usbaudio.class<%08lx>", nch);
313 nch->nch_ReadySignal = SIGB_SINGLE;
314 nch->nch_ReadySigTask = FindTask(NULL);
315 SetSignal(0, SIGF_SINGLE);
316 if((tmptask = psdSpawnSubTask(buf, nAudioTask, nch)))
318 psdBorrowLocksWait(tmptask, 1UL<<nch->nch_ReadySignal);
319 if(nch->nch_Task)
321 nch->nch_ReadySigTask = NULL;
322 //FreeSignal(nch->nch_ReadySignal);
324 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
325 "Play it again, '%s'!",
326 devname);
327 CloseLibrary(ps);
328 return(nch);
331 nch->nch_ReadySigTask = NULL;
332 //FreeSignal(nch->nch_ReadySignal);
333 CloseLibrary(ps);
335 return(NULL);
337 /* \\\ */
339 /* /// "usbReleaseInterfaceBinding()" */
340 void usbReleaseInterfaceBinding(struct NepAudioBase *nh, struct NepClassAudio *nch)
342 struct Library *ps;
343 struct PsdConfig *pc;
344 struct PsdDevice *pd;
345 STRPTR devname;
347 KPRINTF(1, ("nepAudioReleaseInterfaceBinding(%08lx)\n", nch));
348 if((ps = OpenLibrary("poseidon.library", 4)))
350 Forbid();
351 nch->nch_DenyRequests = TRUE;
352 Remove(&nch->nch_Node);
353 nch->nch_ReadySignal = SIGB_SINGLE;
354 nch->nch_ReadySigTask = FindTask(NULL);
355 if(nch->nch_Task)
357 Signal(nch->nch_Task, SIGBREAKF_CTRL_C);
359 Permit();
360 while(nch->nch_Task)
362 Wait(1L<<nch->nch_ReadySignal);
364 //FreeSignal(nch->nch_ReadySignal);
365 psdGetAttrs(PGA_INTERFACE, nch->nch_Interface, IFA_Config, &pc, TAG_END);
366 psdGetAttrs(PGA_CONFIG, pc, CA_Device, &pd, TAG_END);
367 psdGetAttrs(PGA_DEVICE, pd, DA_ProductName, &devname, TAG_END);
368 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
369 "'%s' fell silent!",
370 devname);
371 CloseLibrary(ps);
374 /* \\\ */
376 /* /// "usbGetAttrsA()" */
377 AROS_LH3(LONG, usbGetAttrsA,
378 AROS_LHA(ULONG, type, D0),
379 AROS_LHA(APTR, usbstruct, A0),
380 AROS_LHA(struct TagItem *, tags, A1),
381 LIBBASETYPEPTR, nh, 5, nep)
383 AROS_LIBFUNC_INIT
385 struct TagItem *ti;
386 LONG count = 0;
388 KPRINTF(1, ("nepAudioGetAttrsA(%ld, %08lx, %08lx)\n", type, usbstruct, tags));
389 switch(type)
391 case UGA_CLASS:
392 if((ti = FindTagItem(UCCA_Priority, tags)))
394 *((SIPTR *) ti->ti_Data) = 0;
395 count++;
397 if((ti = FindTagItem(UCCA_Description, tags)))
399 *((STRPTR *) ti->ti_Data) = "USB Audio Streaming Interface class";
400 count++;
402 if((ti = FindTagItem(UCCA_HasClassCfgGUI, tags)))
404 *((IPTR *) ti->ti_Data) = TRUE;
405 count++;
407 if((ti = FindTagItem(UCCA_HasBindingCfgGUI, tags)))
409 *((IPTR *) ti->ti_Data) = FALSE;
410 count++;
412 if((ti = FindTagItem(UCCA_AfterDOSRestart, tags)))
414 *((IPTR *) ti->ti_Data) = FALSE;
415 count++;
417 if((ti = FindTagItem(UCCA_UsingDefaultCfg, tags)))
419 *((IPTR *) ti->ti_Data) = nh->nh_UsingDefaultCfg;
420 count++;
422 if((ti = FindTagItem(UCCA_SupportsSuspend, tags)))
424 *((IPTR *) ti->ti_Data) = TRUE;
425 count++;
427 break;
429 case UGA_BINDING:
430 if((ti = FindTagItem(UCCA_UsingDefaultCfg, tags)))
432 *((IPTR *) ti->ti_Data) = FALSE;
433 count++;
435 break;
437 return(count);
438 AROS_LIBFUNC_EXIT
440 /* \\\ */
442 /* /// "usbSetAttrsA()" */
443 AROS_LH3(LONG, usbSetAttrsA,
444 AROS_LHA(ULONG, type, D0),
445 AROS_LHA(APTR, usbstruct, A0),
446 AROS_LHA(struct TagItem *, tags, A1),
447 LIBBASETYPEPTR, nh, 6, nep)
449 AROS_LIBFUNC_INIT
450 return(0);
451 AROS_LIBFUNC_EXIT
453 /* \\\ */
455 /* /// "usbDoMethodA()" */
456 AROS_LH2(IPTR, usbDoMethodA,
457 AROS_LHA(ULONG, methodid, D0),
458 AROS_LHA(IPTR *, methoddata, A1),
459 LIBBASETYPEPTR, nh, 7, nep)
461 AROS_LIBFUNC_INIT
463 struct NepClassAudio *nch;
464 KPRINTF(10, ("Do Method %ld\n", methodid));
465 switch(methodid)
467 case UCM_AttemptInterfaceBinding:
468 return((IPTR) usbAttemptInterfaceBinding(nh, (struct PsdInterface *) methoddata[0]));
470 case UCM_ForceInterfaceBinding:
471 return((IPTR) usbForceInterfaceBinding(nh, (struct PsdInterface *) methoddata[0]));
473 case UCM_ReleaseInterfaceBinding:
474 usbReleaseInterfaceBinding(nh, (struct NepClassAudio *) methoddata[0]);
475 return(TRUE);
477 case UCM_OpenCfgWindow:
478 return(nOpenCfgWindow(nh));
480 case UCM_ConfigChangedEvent:
481 nLoadClassConfig(nh);
482 return(TRUE);
484 case UCM_AttemptSuspendDevice:
485 nch = (struct NepClassAudio *) methoddata[0];
486 return(nch->nch_CurrentMode ? FALSE : TRUE);
488 case UCM_AttemptResumeDevice:
489 nch = (struct NepClassAudio *) methoddata[0];
490 Signal(nch->nch_Task, (1L<<nch->nch_TaskMsgPort->mp_SigBit));
491 return(TRUE);
493 default:
494 break;
496 return(0);
497 AROS_LIBFUNC_EXIT
499 /* \\\ */
501 /**************************************************************************/
503 #undef ps
504 #define ps nch->nch_Base
505 #undef AHIBase
506 #define AHIBase nch->nch_AHIBase
508 static const ULONG commonFreqs[] =
510 4410, 4800, 5513, 6000, 7350, 8000, 9600,
511 11025, 12000, 14700, 16000, 17640, 18900, 19200,
512 22050, 24000, 29400, 32000, 33075, 37800, 44100,
513 48000, 52000, 56000, 60000, 64000,
514 // AHI doesn't support freqs > 65535 Hz
515 /*72000, 80000, 88200, 96000, */
519 /*static UWORD volumeTableLog[256] =
521 0x0000, 0xFFE9, 0xFFD1, 0xFFBA, 0xFFA2, 0xFF8B, 0xFF72, 0xFF5A,
522 0xFF41, 0xFF28, 0xFF0F, 0xFEF5, 0xFEDB, 0xFEC1, 0xFEA7, 0xFE8C,
523 0xFE71, 0xFE56, 0xFE3A, 0xFE1E, 0xFE02, 0xFDE5, 0xFDC8, 0xFDAB,
524 0xFD8E, 0xFD70, 0xFD52, 0xFD33, 0xFD14, 0xFCF5, 0xFCD5, 0xFCB5,
525 0xFC95, 0xFC74, 0xFC53, 0xFC32, 0xFC10, 0xFBEE, 0xFBCC, 0xFBA9,
526 0xFB85, 0xFB62, 0xFB3E, 0xFB19, 0xFAF4, 0xFACF, 0xFAA9, 0xFA83,
527 0xFA5D, 0xFA36, 0xFA0E, 0xF9E6, 0xF9BE, 0xF995, 0xF96C, 0xF942,
528 0xF918, 0xF8ED, 0xF8C2, 0xF897, 0xF86B, 0xF83E, 0xF811, 0xF7E3,
529 0xF7B5, 0xF787, 0xF758, 0xF728, 0xF6F8, 0xF6C7, 0xF696, 0xF664,
530 0xF632, 0xF5FF, 0xF5CB, 0xF597, 0xF563, 0xF52D, 0xF4F8, 0xF4C1,
531 0xF48A, 0xF452, 0xF41A, 0xF3E1, 0xF3A8, 0xF36E, 0xF333, 0xF2F7,
532 0xF2BB, 0xF27E, 0xF241, 0xF203, 0xF1C4, 0xF184, 0xF144, 0xF103,
533 0xF0C1, 0xF07E, 0xF03B, 0xEFF7, 0xEFB3, 0xEF6D, 0xEF27, 0xEEE0,
534 0xEE98, 0xEE4F, 0xEE06, 0xEDBB, 0xED70, 0xED24, 0xECD7, 0xEC8A,
535 0xEC3B, 0xEBEC, 0xEB9C, 0xEB4A, 0xEAF8, 0xEAA5, 0xEA51, 0xE9FC,
536 0xE9A7, 0xE950, 0xE8F8, 0xE89F, 0xE845, 0xE7EB, 0xE78F, 0xE732,
537 0xE6D4, 0xE675, 0xE616, 0xE5B5, 0xE552, 0xE4EF, 0xE48B, 0xE426,
538 0xE3BF, 0xE357, 0xE2EF, 0xE285, 0xE219, 0xE1AD, 0xE13F, 0xE0D0,
539 0xE060, 0xDFEF, 0xDF7C, 0xDF09, 0xDE93, 0xDE1D, 0xDDA5, 0xDD2C,
540 0xDCB2, 0xDC36, 0xDBB8, 0xDB3A, 0xDABA, 0xDA38, 0xD9B5, 0xD931,
541 0xD8AB, 0xD824, 0xD79B, 0xD710, 0xD684, 0xD5F7, 0xD568, 0xD4D7,
542 0xD445, 0xD3B1, 0xD31B, 0xD284, 0xD1EB, 0xD150, 0xD0B4, 0xD016,
543 0xCF76, 0xCED4, 0xCE31, 0xCD8B, 0xCCE4, 0xCC3B, 0xCB90, 0xCAE3,
544 0xCA34, 0xC984, 0xC8D1, 0xC81C, 0xC765, 0xC6AD, 0xC5F2, 0xC535,
545 0xC476, 0xC3B5, 0xC2F1, 0xC22C, 0xC164, 0xC09A, 0xBFCE, 0xBF00,
546 0xBE2F, 0xBD5C, 0xBC86, 0xBBAE, 0xBAD4, 0xB9F7, 0xB918, 0xB836,
547 0xB752, 0xB66B, 0xB582, 0xB496, 0xB3A8, 0xB2B6, 0xB1C2, 0xB0CC,
548 0xAFD2, 0xAED6, 0xADD7, 0xACD5, 0xABD1, 0xAAC9, 0xA9BE, 0xA8B1,
549 0xA7A0, 0xA68C, 0xA576, 0xA45C, 0xA33F, 0xA21F, 0xA0FB, 0x9FD5,
550 0x9EAB, 0x9D7D, 0x9C4D, 0x9B19, 0x99E1, 0x98A6, 0x9768, 0x9626,
551 0x94E0, 0x9397, 0x924A, 0x90F9, 0x8FA5, 0x8E4D, 0x8CF1, 0x8B91,
552 0x8A2D, 0x88C5, 0x8759, 0x85E9, 0x8475, 0x82FD, 0x8180, 0x8000
553 };*/
555 /* /// "nGetInputUnit()" */
556 struct NepAudioUnit * nGetInputUnit(struct NepAudioMode *nam)
558 struct NepAudioUnit *nau = NULL;
559 if(nam->nam_Sibling)
561 if(nam->nam_Sibling->nam_RootUnit->nau_SelectorUnit)
563 nau = nam->nam_Sibling->nam_RootUnit->nau_SelectorUnit->nau_InputUnit[nam->nam_CurrInput]->nau_RootUnit;
564 } else {
565 nau = nam->nam_Sibling->nam_RootUnit;
568 return(nau);
570 /* \\\ */
572 /* /// "nAudioTask()" */
573 AROS_UFH0(void, nAudioTask)
575 AROS_USERFUNC_INIT
577 struct NepClassAudio *nch;
578 struct NepAudioMode *nam;
579 struct NepAudioUnit *innau;
580 ULONG sigmask;
581 ULONG sigs;
582 UBYTE buf[2];
583 LONG ioerr;
585 if((nch = nAllocAudio()))
587 Forbid();
588 if(nch->nch_ReadySigTask)
590 Signal(nch->nch_ReadySigTask, 1L<<nch->nch_ReadySignal);
592 Permit();
593 sigmask = (1L<<nch->nch_TaskMsgPort->mp_SigBit)|SIGBREAKF_CTRL_C;
596 //psdDoPipe(nch->nch_CurrentMode->nam_EPPipe, nch, 1024);
597 sigs = Wait(sigmask);
598 if(nch->nch_UpdateFlags)
600 nam = nch->nch_CurrentMode;
601 if((nch->nch_UpdateFlags & UAF_SELECT_OUTPUT) && nam->nam_RootUnit->nau_SelectorUnit)
603 struct NepAudioUnit *nau = nam->nam_RootUnit->nau_SelectorUnit;
604 KPRINTF(10, ("Setting output %ld to %08lx\n", nau->nau_UnitID, nam->nam_CurrOutput));
605 buf[0] = nam->nam_CurrOutput + 1;
606 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_INTERFACE, UAUDR_SET_CUR, 0, (nau->nau_UnitID<<8)|nch->nch_IfNum);
607 ioerr = psdDoPipe(nch->nch_EP0Pipe, buf, 1);
608 if(ioerr)
610 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
611 "Could not select output source: %s (%ld)!",
612 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
615 if((nch->nch_UpdateFlags & UAF_SELECT_INPUT) && nam->nam_Sibling && nam->nam_Sibling->nam_RootUnit->nau_SelectorUnit)
617 struct NepAudioUnit *nau = nam->nam_Sibling->nam_RootUnit->nau_SelectorUnit;
618 KPRINTF(10, ("Setting input %ld to %08lx\n", nau->nau_UnitID, nam->nam_CurrInput));
619 buf[0] = nam->nam_CurrInput + 1;
620 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_INTERFACE, UAUDR_SET_CUR, 0, (nau->nau_UnitID<<8)|nch->nch_IfNum);
621 ioerr = psdDoPipe(nch->nch_EP0Pipe, buf, 1);
622 if(ioerr)
624 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
625 "Could not select input source: %s (%ld)!",
626 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
629 if((nch->nch_UpdateFlags & UAF_MASTER_VOLUME) && nam->nam_RootUnit->nau_VolumeControl)
631 struct NepAudioUnit *nau = nam->nam_RootUnit->nau_VolumeUnit;
632 Fixed vol;
633 UWORD cnt;
635 vol = (nam->nam_MasterVol * (nau->nau_MaxVolDb - nau->nau_MinVolDb)>>16) + nau->nau_MinVolDb;
636 if(vol < nau->nau_MinVolDb)
638 // we should rather MUTE this channel completely.
639 vol = nau->nau_MinVolDb;
641 else if(vol > nau->nau_MaxVolDb)
643 vol = nau->nau_MaxVolDb;
645 KPRINTF(10, ("Setting master volume %ld to %08lx (%04lx)\n", nau->nau_UnitID, nam->nam_MasterVol, vol));
646 buf[0] = vol;
647 buf[1] = vol>>8;
648 for(cnt = 0; cnt < 3; cnt++)
650 if(nau->nau_VolCtrlMask & (1<<cnt))
652 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_INTERFACE, UAUDR_SET_CUR, (ULONG) (UAFUCS_VOLUME<<8)|cnt, (nau->nau_UnitID<<8)|nch->nch_IfNum);
653 ioerr = psdDoPipe(nch->nch_EP0Pipe, buf, 2);
654 if(ioerr)
656 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
657 "Could not set master volume (%ld): %s (%ld)!",
658 cnt,
659 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
660 } else {
661 KPRINTF(10, ("Chan %ld okay!\n", cnt));
663 } else {
664 KPRINTF(10, ("Chan %ld ignored\n", cnt));
668 innau = nGetInputUnit(nam);
669 if((nch->nch_UpdateFlags & UAF_INPUT_GAIN) && innau && innau->nau_VolumeControl)
671 struct NepAudioUnit *nau = innau->nau_VolumeUnit;
672 Fixed vol;
673 UWORD cnt;
675 vol = (nam->nam_InputGain * (nau->nau_MaxVolDb - nau->nau_MinVolDb)>>16) + nau->nau_MinVolDb;
676 if(vol < nau->nau_MinVolDb)
678 // we should rather MUTE this channel completely.
679 vol = nau->nau_MinVolDb;
681 else if(vol > nau->nau_MaxVolDb)
683 vol = nau->nau_MaxVolDb;
685 KPRINTF(10, ("Setting input gain %ld to %08lx (%04lx)\n", nau->nau_UnitID, nam->nam_InputGain, vol));
686 buf[0] = vol;
687 buf[1] = vol>>8;
688 for(cnt = 0; cnt < 3; cnt++)
690 if(nau->nau_VolCtrlMask & (1<<cnt))
692 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_INTERFACE, UAUDR_SET_CUR, (ULONG) (UAFUCS_VOLUME<<8)|cnt, (nau->nau_UnitID<<8)|nch->nch_IfNum);
693 ioerr = psdDoPipe(nch->nch_EP0Pipe, buf, 2);
694 if(ioerr)
696 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
697 "Could not set input gain (%ld): %s (%ld)!",
698 cnt,
699 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
700 } else {
701 KPRINTF(10, ("Chan %ld okay!\n", cnt));
703 } else {
704 KPRINTF(10, ("Chan %ld ignored\n", cnt));
708 if((nch->nch_UpdateFlags & UAF_MONITOR_VOLUME) && innau && innau->nau_Monitor)
710 struct NepAudioUnit *nau = innau->nau_MonitorUnit;
711 Fixed vol;
712 UWORD cnt;
714 vol = (nam->nam_MonitorVol * (nau->nau_MaxVolDb - nau->nau_MinVolDb)>>16) + nau->nau_MinVolDb;
715 if(vol < nau->nau_MinVolDb)
717 // we should rather MUTE this channel completely.
718 vol = nau->nau_MinVolDb;
720 else if(vol > nau->nau_MaxVolDb)
722 vol = nau->nau_MaxVolDb;
724 KPRINTF(10, ("Setting monitor %ld to %08lx (%04lx)\n", nau->nau_UnitID, nam->nam_MonitorVol, vol));
725 buf[0] = vol;
726 buf[1] = vol>>8;
727 for(cnt = 0; cnt < 3; cnt++)
729 if(nau->nau_VolCtrlMask & (1<<cnt))
731 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_INTERFACE, UAUDR_SET_CUR, (ULONG) (UAFUCS_VOLUME<<8)|cnt, (nau->nau_UnitID<<8)|nch->nch_IfNum);
732 ioerr = psdDoPipe(nch->nch_EP0Pipe, buf, 2);
733 if(ioerr)
735 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
736 "Could not set monitor volume (%ld): %s (%ld)!",
737 cnt,
738 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
739 } else {
740 KPRINTF(10, ("Chan %ld okay!\n", cnt));
742 } else {
743 KPRINTF(10, ("Chan %ld ignored\n", cnt));
747 nch->nch_UpdateFlags = 0;
749 } while(!(sigs & SIGBREAKF_CTRL_C));
750 if(nch->nch_CurrentMode)
752 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "Cannot exit yet, audio playback still active!");
753 while(nch->nch_CurrentMode)
755 psdDelayMS(500);
758 KPRINTF(20, ("Going down the river!\n"));
759 nFreeAudio(nch);
762 AROS_USERFUNC_EXIT
764 /* \\\ */
766 /* /// "nFindAudioUnit()" */
767 struct NepAudioUnit * nFindAudioUnit(struct NepClassAudio *nch, ULONG unitid)
769 struct NepAudioUnit *nau;
771 nau = (struct NepAudioUnit *) nch->nch_AudioUnits.lh_Head;
772 while(nau->nau_Node.ln_Succ)
774 if(nau->nau_UnitID == unitid)
776 return(nau);
778 nau = (struct NepAudioUnit *) nau->nau_Node.ln_Succ;
780 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "Requested Unit %02lx not found.", unitid);
781 return(NULL);
783 /* \\\ */
785 /* /// "nFindAndConnectAudioUnit()" */
786 void nFindAndConnectAudioUnit(struct NepClassAudio *nch, struct NepAudioUnit *targetnau, ULONG unitid)
788 struct NepAudioUnit *sourcenau = nFindAudioUnit(nch, unitid);
789 KPRINTF(10, ("Connecting unit %02lx to %02lx\n", unitid, targetnau->nau_UnitID));
790 if(!sourcenau)
792 return;
794 if(sourcenau->nau_NumOutputs < 8)
796 sourcenau->nau_OutputUnit[sourcenau->nau_NumOutputs] = targetnau;
797 sourcenau->nau_NumOutputs++;
799 if(targetnau->nau_NumInputs < 8)
801 targetnau->nau_InputUnit[targetnau->nau_NumInputs] = sourcenau;
802 targetnau->nau_NumInputs++;
805 /* \\\ */
807 /* /// "nFlowDown()" */
808 void nFlowDown(struct NepClassAudio *nch, struct NepAudioUnit *nau)
810 UWORD cnt;
812 KPRINTF(10, ("FlowDown %02lx\n", nau->nau_UnitID));
814 if(nau->nau_InputUnit[0]->nau_RootUnit && ((nau->nau_Type != UDST_AUDIO_CTRL_OUTPUT_TERMINAL) || (nau->nau_TermType != UAUTT_STREAMING)))
816 // use parent audio mode for flow down
817 nau->nau_RootUnit = nau->nau_InputUnit[0]->nau_RootUnit;
819 for(cnt = 0; cnt < nau->nau_NumOutputs; cnt++)
821 nFlowDown(nch, nau->nau_OutputUnit[cnt]);
824 /* \\\ */
826 /* /// "nFlowDownToUSBSink()" */
827 struct NepAudioUnit * nFlowDownToUSBSink(struct NepClassAudio *nch, struct NepAudioUnit *nau)
829 UWORD cnt;
830 struct NepAudioUnit *resnau = NULL;
831 KPRINTF(10, ("FlowDownToUSBSink %02lx\n", nau->nau_UnitID));
833 if((nau->nau_Type == UDST_AUDIO_CTRL_OUTPUT_TERMINAL) && (nau->nau_TermType == UAUTT_STREAMING))
835 KPRINTF(10, ("USB Outterm found\n"));
836 nau->nau_SinkUnit = nau;
837 return nau;
839 for(cnt = 0; cnt < nau->nau_NumOutputs; cnt++)
841 nau->nau_SinkUnit = nFlowDownToUSBSink(nch, nau->nau_OutputUnit[cnt]);
842 if((resnau = nau->nau_SinkUnit))
844 break;
847 return(resnau);
849 /* \\\ */
851 /* /// "nFlowUpToUSBSource()" */
852 struct NepAudioUnit * nFlowUpToUSBSource(struct NepClassAudio *nch, struct NepAudioUnit *nau)
854 UWORD cnt;
855 struct NepAudioUnit *resnau = NULL;
856 KPRINTF(10, ("FlowsDownToUSB %02lx\n", nau->nau_UnitID));
858 if((nau->nau_Type == UDST_AUDIO_CTRL_INPUT_TERMINAL) && (nau->nau_TermType == UAUTT_STREAMING))
860 KPRINTF(10, ("USB interm found\n"));
861 nau->nau_SourceUnit = nau;
862 return nau;
864 for(cnt = 0; cnt < nau->nau_NumInputs; cnt++)
866 nau->nau_SourceUnit = nFlowUpToUSBSource(nch, nau->nau_InputUnit[cnt]);
867 if((resnau = nau->nau_SourceUnit))
869 break;
872 return(resnau);
874 /* \\\ */
876 /* /// "nFlowUp()" */
877 void nFlowUp(struct NepClassAudio *nch, struct NepAudioUnit *nau)
879 UWORD cnt;
880 UBYTE *descdata = nau->nau_Descriptor;
882 KPRINTF(10, ("FlowUp %02lx\n", nau->nau_UnitID));
884 if(nau->nau_Name)
886 return;
889 // use downlink audio mode for flow up
890 for(cnt = 0; cnt < nau->nau_NumInputs; cnt++)
892 if(nau->nau_RootUnit)
894 if(!nau->nau_InputUnit[cnt]->nau_RootUnit)
896 nau->nau_InputUnit[cnt]->nau_RootUnit = nau->nau_RootUnit;
899 nFlowUp(nch, nau->nau_InputUnit[cnt]);
902 switch(nau->nau_Type)
905 case UDST_AUDIO_CTRL_INPUT_TERMINAL:
907 struct UsbAudioInputTermDesc10 *uait = (struct UsbAudioInputTermDesc10 *) descdata;
908 ULONG termtype = AROS_WORD2LE(uait->wTerminalType);
909 UWORD channelcfg = AROS_WORD2LE(uait->wChannelConfig);
910 STRPTR spacial = nConcatBitsStr(nch, NTS_SPATIALLOCATION, (ULONG) channelcfg);
911 nau->nau_Name = psdCopyStrFmt("%s (%s)", nNumToStr(nch, NTS_TERMINALTYPE, termtype, "Unknown"), spacial);
912 psdFreeVec(spacial);
913 break;
916 case UDST_AUDIO_CTRL_OUTPUT_TERMINAL:
917 nau->nau_Name = psdCopyStrFmt("%s-Output from %s",
918 nNumToStr(nch, NTS_TERMINALTYPE, (ULONG) nau->nau_TermType, "Unknown"),
919 nau->nau_InputUnit[0]->nau_Name);
920 nau->nau_OutChannels = nau->nau_InputUnit[0]->nau_OutChannels;
921 nau->nau_ChannelCfg = nau->nau_InputUnit[0]->nau_ChannelCfg;
922 break;
924 case UDST_AUDIO_CTRL_FEATURE_UNIT:
926 UWORD features = 0;
927 UWORD featsize = descdata[5];
928 UWORD feat;
929 UBYTE *featptr = descdata + 6;
930 UWORD featsizecnt;
931 STRPTR featstr;
933 nau->nau_TermType = nau->nau_InputUnit[0]->nau_TermType;
934 nau->nau_OutChannels = nau->nau_InputUnit[0]->nau_OutChannels;
935 nau->nau_ChannelCfg = nau->nau_InputUnit[0]->nau_ChannelCfg;
937 for(cnt = 0; cnt <= nau->nau_InputUnit[0]->nau_OutChannels; cnt++)
939 feat = 0;
940 for(featsizecnt = 0; featsizecnt < featsize; featsizecnt++)
942 feat |= (*featptr++)<<(featsizecnt<<3);
944 KPRINTF(10, ("Feature Unit %02lx, Channel %ld: %04lx\n", nau->nau_UnitID, cnt, feat));
945 features |= feat;
947 featstr = nConcatBitsStr(nch, NTS_FEATURE, (ULONG) features);
948 nau->nau_Name = psdCopyStrFmt("%s for %s", featstr, nau->nau_InputUnit[0]->nau_Name);
949 psdFreeVec(featstr);
950 break;
953 case UDST_AUDIO_CTRL_SELECTOR_UNIT:
954 for(cnt = 0; cnt < nau->nau_NumInputs; cnt++)
956 UWORD taroutch = nau->nau_InputUnit[cnt]->nau_OutChannels;
957 if(cnt)
959 if(nau->nau_OutChannels != taroutch)
961 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "Selector channels %ld != %ld conflict.",
962 nau->nau_OutChannels, taroutch);
965 nau->nau_OutChannels = taroutch;
966 nau->nau_ChannelCfg = nau->nau_InputUnit[cnt]->nau_ChannelCfg;
968 // fall through
970 case UDST_AUDIO_CTRL_MIXER_UNIT:
971 case UDST_AUDIO_CTRL_PROCESSING_UNIT:
972 case UDST_AUDIO_CTRL_EXTENSION_UNIT:
974 UBYTE buf[64];
975 UBYTE *bufptr = buf;
976 ULONG buflen = 63;
977 UBYTE *srcptr;
979 if(nau->nau_NumInputs == 1)
981 // not ambigious, so lets copy the input.
982 nau->nau_TermType = nau->nau_InputUnit[0]->nau_TermType;
984 for(cnt = 0; buflen && (cnt < nau->nau_NumInputs); cnt++)
986 if(cnt && buflen)
988 if(nau->nau_Type == UDST_AUDIO_CTRL_SELECTOR_UNIT)
990 *bufptr++ = '/';
991 } else {
992 *bufptr++ = '+';
994 if(!(--buflen))
996 break;
999 /*if(nau->nau_InputUnit[cnt]->nau_TermType == UAUTT_STREAMING)
1001 srcptr = "Loopback";
1002 } else {*/
1003 srcptr = nNumToStr(nch, NTS_TERMINALTYPE, (ULONG) nau->nau_InputUnit[cnt]->nau_TermType, "Unknown");
1005 while((*bufptr++ = *srcptr++))
1007 if(!(--buflen))
1009 break;
1012 bufptr--;
1014 *bufptr = 0;
1015 nau->nau_Name = psdCopyStrFmt("%s (%s)", nNumToStr(nch, NTS_UNITTYPE, (ULONG) nau->nau_Type, "Unknown"), buf);
1016 break;
1020 /* \\\ */
1022 /* /// "nExamineAudioDescriptors()" */
1023 void nExamineAudioDescriptors(struct NepClassAudio *nch)
1025 APTR desc;
1026 UBYTE *descdata;
1027 IPTR ifnum;
1028 struct NepAudioMode *nam;
1029 struct PsdInterface *streampif;
1030 APTR subdesc;
1031 UWORD cnt;
1032 struct UsbAudioHeaderDesc10 *header;
1033 struct UsbAudioGeneralIFDesc *uagi;
1034 struct UsbAudioType1FormatDesc *uat1f;
1035 struct UsbAudioGeneralEPDesc *uage;
1036 ULONG audioformat;
1037 ULONG ahisamtype = 0;
1038 BOOL typegood;
1039 BOOL freqctrl = FALSE;
1040 BOOL pitchctrl = FALSE;
1041 ULONG ahimodeid = AHI_USB_MODE_BASE + (nch->nch_UnitNo<<12);
1043 KPRINTF(10, ("ExamineAudioDesc Stage 1\n"));
1045 desc = psdFindDescriptor(nch->nch_Device, NULL,
1046 DDA_Interface, nch->nch_Interface,
1047 DDA_DescriptorType, UDT_CS_INTERFACE,
1048 DDA_CS_SubType, UDST_AUDIO_CTRL_HEADER,
1049 TAG_END);
1050 if(!desc)
1052 return;
1054 psdGetAttrs(PGA_DESCRIPTOR, desc,
1055 DDA_DescriptorData, &descdata,
1056 TAG_END);
1057 header = (struct UsbAudioHeaderDesc10 *) descdata;
1059 for(cnt = 0; cnt < header->bInCollection; cnt++)
1061 streampif = NULL;
1062 while((streampif = psdFindInterface(nch->nch_Device, streampif,
1063 IFA_InterfaceNum, header->baInterfaceNr[cnt],
1064 IFA_AlternateNum, 0xffffffff,
1065 IFA_Class, AUDIO_CLASSCODE,
1066 IFA_SubClass, AUDIO_STREAM_SUBCLASS,
1067 TAG_END)))
1069 psdGetAttrs(PGA_INTERFACE, streampif,
1070 IFA_InterfaceNum, &ifnum,
1071 TAG_END);
1072 subdesc = psdFindDescriptor(nch->nch_Device, NULL,
1073 DDA_Interface, streampif,
1074 DDA_DescriptorType, UDT_CS_INTERFACE,
1075 DDA_CS_SubType, UDST_AUDIO_STREAM_GENERAL,
1076 TAG_END);
1077 if(subdesc)
1079 psdGetAttrs(PGA_DESCRIPTOR, subdesc,
1080 DDA_DescriptorData, &uagi,
1081 TAG_END);
1082 audioformat = uagi->wFormatTag0|(uagi->wFormatTag1<<8);
1083 psdAddErrorMsg(RETURN_OK, (STRPTR) libname, "Terminal %02lx (%ld delay) of Format %s",
1084 uagi->bTerminalLink,
1085 uagi->bDelay,
1086 nNumToStr(nch, NTS_AUDIOFORMAT, audioformat, "Unknown"));
1087 if(audioformat == UAADF_PCM)
1089 subdesc = psdFindDescriptor(nch->nch_Device, NULL,
1090 DDA_Interface, streampif,
1091 DDA_DescriptorType, UDT_CS_INTERFACE,
1092 DDA_CS_SubType, UDST_AUDIO_STREAM_FMT_TYPE,
1093 TAG_END);
1094 if(subdesc)
1096 psdGetAttrs(PGA_DESCRIPTOR, subdesc,
1097 DDA_DescriptorData, &uat1f,
1098 TAG_END);
1100 subdesc = psdFindDescriptor(nch->nch_Device, NULL,
1101 DDA_Interface, streampif,
1102 DDA_DescriptorType, UDT_CS_ENDPOINT,
1103 TAG_END);
1104 pitchctrl = freqctrl = FALSE;
1105 if(subdesc)
1107 psdGetAttrs(PGA_DESCRIPTOR, subdesc,
1108 DDA_DescriptorData, &uage,
1109 TAG_END);
1111 if(uage->bmAttributes & UAECS_SAMPLE_FREQ) // actually, should check the bit, but the control selector has the right value by incident ;)
1113 freqctrl = TRUE;
1114 /*psdAddErrorMsg(RETURN_OK, (STRPTR) libname, "Terminal %02lx has frequency control.",
1115 uagi->bTerminalLink);*/
1117 if(uage->bmAttributes & UAECS_PITCH) // actually, should check the bit, but the control selector has the right value by incident ;)
1119 pitchctrl = TRUE;
1120 /*psdAddErrorMsg(RETURN_OK, (STRPTR) libname, "Terminal %02lx has pitch control.",
1121 uagi->bTerminalLink);*/
1125 typegood = TRUE;
1126 if(uat1f->bNrChannels == 1)
1128 if(uat1f->bBitResolution == 8)
1130 ahisamtype = AHIST_M8S;
1132 else if(uat1f->bBitResolution == 16)
1134 ahisamtype = AHIST_M16S;
1136 else if((uat1f->bBitResolution > 16) && (uat1f->bBitResolution <= 24))
1138 ahisamtype = 0; // no AHI representation of this mode
1140 else if((uat1f->bBitResolution > 24) && (uat1f->bBitResolution <= 32))
1142 ahisamtype = AHIST_M32S;
1143 } else {
1144 typegood = FALSE;
1147 else if(uat1f->bNrChannels == 2)
1149 if(uat1f->bBitResolution == 8)
1151 ahisamtype = AHIST_S8S;
1153 else if(uat1f->bBitResolution == 16)
1155 ahisamtype = AHIST_S16S;
1157 else if((uat1f->bBitResolution > 16) && (uat1f->bBitResolution <= 24))
1159 ahisamtype = 0; // no AHI representation of this mode
1161 else if((uat1f->bBitResolution > 24) && (uat1f->bBitResolution <= 32))
1163 ahisamtype = AHIST_S32S;
1164 } else {
1165 typegood = FALSE;
1167 } else {
1168 typegood = FALSE;
1170 if(!typegood)
1172 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "Unsupported mode '%s' with %ld bits x %ld channels ignored.",
1173 nNumToStr(nch, NTS_AUDIOFORMAT, audioformat, "Unknown"),
1174 uat1f->bBitResolution,
1175 uat1f->bNrChannels);
1176 } else {
1177 if((nam = AllocVec(sizeof(struct NepAudioMode), MEMF_CLEAR|MEMF_PUBLIC)))
1179 nam->nam_SubLibBase = nch->nch_ClsBase->nh_SubLibBase;
1180 nam->nam_Unit = nch;
1181 nam->nam_Interface = streampif;
1182 nam->nam_ZeroBWIF = psdFindInterface(nch->nch_Device, NULL,
1183 IFA_InterfaceNum, ifnum,
1184 IFA_AlternateNum, 0xffffffff,
1185 IFA_Class, AUDIO_CLASSCODE,
1186 IFA_SubClass, AUDIO_STREAM_SUBCLASS,
1187 IFA_NumEndpoints, 0,
1188 TAG_END);
1189 if(!nam->nam_ZeroBWIF)
1191 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "Zero Bandwidth endpoint not found!");
1194 nam->nam_IfNum = ifnum;
1195 nam->nam_SampleType = ahisamtype;
1196 nam->nam_NumChannels = uat1f->bNrChannels;
1197 nam->nam_FrameSize = uat1f->bSubframeSize * nam->nam_NumChannels;
1198 nam->nam_SampleSize = uat1f->bSubframeSize;
1199 nam->nam_Resolution = uat1f->bBitResolution;
1200 nam->nam_TerminalID = uagi->bTerminalLink;
1201 nam->nam_HasFreqCtrl = freqctrl;
1202 nam->nam_HasPitchCtrl = pitchctrl;
1204 AddTail(&nch->nch_AudioModes, &nam->nam_Node);
1205 if(uat1f->bSamFreqType)
1207 UWORD cnt;
1208 UWORD cnt2;
1209 ULONG freq;
1210 UBYTE *fptr = uat1f->tSamFreq0;
1211 nam->nam_MinFreq = 100000;
1212 nam->nam_MaxFreq = 1;
1213 nam->nam_NumFrequencies = (uat1f->bSamFreqType < 64) ? uat1f->bSamFreqType : 64;
1214 for(cnt = 0; cnt < nam->nam_NumFrequencies; cnt++)
1216 freq = fptr[0]|(fptr[1]<<8)|(fptr[2]<<16);
1217 if(freq < nam->nam_MinFreq)
1219 nam->nam_MinFreq = freq;
1221 if(freq > 64000)
1223 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "AHI does not support %ld Hz as it is above 65 KHz, sorry.", freq);
1224 nam->nam_NumFrequencies--;
1225 cnt--;
1226 fptr += 3;
1227 continue;
1229 if(freq > nam->nam_MaxFreq)
1231 nam->nam_MaxFreq = freq;
1233 nam->nam_FreqArray[cnt] = freq;
1234 fptr += 3;
1236 /* sort array (yeah, lazy bubble sort) */
1237 for(cnt = 0; cnt < nam->nam_NumFrequencies; cnt++)
1239 for(cnt2 = cnt + 1; cnt2 < nam->nam_NumFrequencies; cnt2++)
1241 if(nam->nam_FreqArray[cnt] > nam->nam_FreqArray[cnt2])
1243 freq = nam->nam_FreqArray[cnt2];
1244 nam->nam_FreqArray[cnt2] = nam->nam_FreqArray[cnt];
1245 nam->nam_FreqArray[cnt] = freq;
1249 } else {
1250 const ULONG *freqtab = commonFreqs;
1251 nam->nam_MinFreq = uat1f->tSamFreq0[0]|(uat1f->tSamFreq0[1]<<8)|(uat1f->tSamFreq0[2]<<16);
1252 nam->nam_MaxFreq = uat1f->tSamFreq0[3]|(uat1f->tSamFreq0[4]<<8)|(uat1f->tSamFreq0[5]<<16);
1253 if(nam->nam_MaxFreq > 64000)
1255 nam->nam_MaxFreq = 64000;
1256 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "AHI does not support frequencies above 65 KHz, sorry.");
1258 nam->nam_NumFrequencies = 0;
1259 while(*freqtab && (nam->nam_NumFrequencies < 64))
1261 if((*freqtab >= nam->nam_MinFreq) && (*freqtab <= nam->nam_MaxFreq))
1263 nam->nam_FreqArray[nam->nam_NumFrequencies++] = *freqtab;
1265 freqtab++;
1268 nam->nam_AHIModeID = ++ahimodeid;
1269 psdAddErrorMsg(RETURN_OK, (STRPTR) libname, "Found mode with %ld channel(s) (%ld byte(s) per frame) and %ld bits",
1270 uat1f->bNrChannels,
1271 uat1f->bSubframeSize,
1272 uat1f->bBitResolution);
1277 /*if(!uat1f->bSamFreqType)
1279 ULONG lowfreq = uat1f->tSamFreq0[0]|(uat1f->tSamFreq0[1]<<8)|(uat1f->tSamFreq0[2]<<16);
1280 ULONG highfreq = uat1f->tSamFreq0[3]|(uat1f->tSamFreq0[4]<<8)|(uat1f->tSamFreq0[5]<<16);
1281 psdAddErrorMsg(RETURN_OK, (STRPTR) libname, "Continuous frequency from %ld Hz to %ld Hz",
1282 lowfreq, highfreq);
1283 } else {
1284 ULONG freq = uat1f->tSamFreq0[0]|(uat1f->tSamFreq0[1]<<8)|(uat1f->tSamFreq0[2]<<16);
1285 psdAddErrorMsg(RETURN_OK, (STRPTR) libname, "%ld frequencies supported (first one being %ld Hz)",
1286 uat1f->bSamFreqType, freq);
1289 } else {
1290 psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, "Interface %ld is missing type 1 format descriptor!", header->baInterfaceNr[cnt]);
1292 } else {
1293 psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, "Terminal %02lx with Format '%s' is not supported!",
1294 uagi->bTerminalLink,
1295 nNumToStr(nch, NTS_AUDIOFORMAT, audioformat, "Unknown"));
1301 /* \\\ */
1303 /* /// "nFindLogVolume()" */
1304 void nFindLogVolume(struct NepClassAudio *nch, struct NepAudioUnit *nau)
1306 /*WORD cnt;
1307 WORD *tab = (WORD *) volumeTableLog;
1308 if((nau->nau_MinVolDb < 0) && (nau->nau_MaxVolDb <= 0))
1310 KPRINTF(10, ("negative DB range\n"));
1311 nau->nau_MinVolume = 0x10000;
1312 for(cnt = 0; cnt < 256; cnt++)
1314 if(nau->nau_MinVolDb > tab[cnt])
1316 break;
1318 nau->nau_MinVolume = (255 - cnt)<<8;
1320 KPRINTF(10, ("Minimum volume linearized: %04lx\n", nau->nau_MinVolume));
1321 for(cnt = 255; cnt >= 0; cnt--)
1323 nau->nau_MaxVolume = (255 - cnt)<<8;
1324 if(nau->nau_MaxVolDb < tab[cnt])
1326 break;
1329 KPRINTF(10, ("Maximum volume linearized: %04lx\n", nau->nau_MaxVolume));
1331 else if((nau->nau_MinVolDb >= 0) && (nau->nau_MaxVolDb > 0))
1333 KPRINTF(10, ("positive DB range\n"));
1334 nau->nau_MinVolume = 0x20000;
1335 for(cnt = 255; cnt >= 0; cnt--)
1337 if(-nau->nau_MinVolDb < tab[cnt])
1339 break;
1341 nau->nau_MinVolume = (cnt+256)<<8;
1343 KPRINTF(10, ("Minimum volume linearized: %04lx\n", nau->nau_MinVolume));
1344 for(cnt = 0; cnt < 256; cnt++)
1346 nau->nau_MaxVolume = (cnt+256)<<8;
1347 if(-nau->nau_MaxVolDb > tab[cnt])
1349 break;
1352 KPRINTF(10, ("Maximum volume linearized: %04lx\n", nau->nau_MaxVolume));
1353 } else {
1354 KPRINTF(10, ("unsupported DB range\n"));
1356 nau->nau_MinVolume = 0;//(((Fixed) nau->nau_MinVolDb) + 0x8000)<<1;
1357 nau->nau_MaxVolume = 0x10000;//(((Fixed) nau->nau_MaxVolDb) + 0x8000)<<1;
1359 /* \\\ */
1361 /* /// "nExamineAudioUnits()" */
1362 void nExamineAudioUnits(struct NepClassAudio *nch)
1364 APTR desc;
1365 UBYTE *descdata;
1366 IPTR subtype;
1367 struct NepAudioMode *nam;
1368 struct NepAudioMode *sibnam;
1369 struct NepAudioUnit *nau;
1370 KPRINTF(10, ("ExamineAudioDesc Stage 2\n"));
1372 desc = NULL;
1373 while((desc = psdFindDescriptor(nch->nch_Device, desc,
1374 DDA_Interface, nch->nch_Interface,
1375 DDA_DescriptorType, UDT_CS_INTERFACE,
1376 TAG_END)))
1378 psdGetAttrs(PGA_DESCRIPTOR, desc,
1379 DDA_DescriptorData, &descdata,
1380 DDA_CS_SubType, &subtype,
1381 TAG_END);
1382 switch(subtype)
1384 case UDST_AUDIO_CTRL_INPUT_TERMINAL:
1385 case UDST_AUDIO_CTRL_OUTPUT_TERMINAL:
1386 case UDST_AUDIO_CTRL_MIXER_UNIT:
1387 case UDST_AUDIO_CTRL_SELECTOR_UNIT:
1388 case UDST_AUDIO_CTRL_FEATURE_UNIT:
1389 case UDST_AUDIO_CTRL_PROCESSING_UNIT:
1390 case UDST_AUDIO_CTRL_EXTENSION_UNIT:
1391 nau = psdAllocVec(sizeof(struct NepAudioUnit));
1392 if(!nau)
1394 break;
1396 nau->nau_Type = subtype;
1397 nau->nau_UnitID = descdata[3];
1398 nau->nau_Descriptor = descdata;
1399 AddTail(&nch->nch_AudioUnits, &nau->nau_Node);
1400 break;
1404 // connect units together
1405 nau = (struct NepAudioUnit *) nch->nch_AudioUnits.lh_Head;
1406 while(nau->nau_Node.ln_Succ)
1408 descdata = nau->nau_Descriptor;
1409 switch(nau->nau_Type)
1411 case UDST_AUDIO_CTRL_OUTPUT_TERMINAL:
1412 nFindAndConnectAudioUnit(nch, nau, (ULONG) ((struct UsbAudioOutputTermDesc10 *) descdata)->bSourceID);
1413 break;
1415 case UDST_AUDIO_CTRL_MIXER_UNIT:
1416 case UDST_AUDIO_CTRL_SELECTOR_UNIT:
1418 struct UsbAudioMixerUnitDesc10 *uamu = (struct UsbAudioMixerUnitDesc10 *) descdata;
1419 UWORD inputpins = uamu->bNrInPins;
1420 UWORD cnt;
1422 if(inputpins > 8)
1424 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "On Mixer / Selector Unit %02lx with %ld input pins only 8 are supported.",
1425 uamu->bUnitID,
1426 inputpins);
1427 inputpins = 8;
1430 for(cnt = 0; cnt < inputpins; cnt++)
1432 nFindAndConnectAudioUnit(nch, nau, (ULONG) descdata[5+cnt]);
1434 break;
1437 case UDST_AUDIO_CTRL_FEATURE_UNIT:
1438 nFindAndConnectAudioUnit(nch, nau, (ULONG) ((struct UsbAudioFeatureUnitDesc10 *) descdata)->bSourceID);
1439 break;
1441 case UDST_AUDIO_CTRL_PROCESSING_UNIT:
1442 case UDST_AUDIO_CTRL_EXTENSION_UNIT:
1444 struct UsbAudioProcessingUnitDesc10 *uapu = (struct UsbAudioProcessingUnitDesc10 *) descdata;
1445 UWORD inputpins = uapu->bNrInPins;
1446 UWORD cnt;
1448 if(inputpins > 8)
1450 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "On Processing / Extension Unit %02lx with %ld input pins only 8 are supported.",
1451 uapu->bUnitID,
1452 inputpins);
1453 inputpins = 8;
1456 for(cnt = 0; cnt < inputpins; cnt++)
1458 nFindAndConnectAudioUnit(nch, nau, (ULONG) descdata[7+cnt]);
1460 break;
1464 nau = (struct NepAudioUnit *) nau->nau_Node.ln_Succ;
1467 KPRINTF(10, ("ExamineAudioDesc Stage 3\n"));
1469 // obtain output channels and configs where known (the rest is done on flow recursion next step)
1470 nau = (struct NepAudioUnit *) nch->nch_AudioUnits.lh_Head;
1471 while(nau->nau_Node.ln_Succ)
1473 descdata = nau->nau_Descriptor;
1474 switch(nau->nau_Type)
1476 case UDST_AUDIO_CTRL_OUTPUT_TERMINAL:
1478 struct UsbAudioOutputTermDesc10 *uaot = (struct UsbAudioOutputTermDesc10 *) descdata;
1479 ULONG termtype = AROS_WORD2LE(uaot->wTerminalType);
1480 nau->nau_TermType = termtype;
1481 if(termtype == UAUTT_STREAMING)
1483 nau->nau_RootUnit = nau;
1484 // try to locate audio mode, which is obviously an input
1485 nam = (struct NepAudioMode *) nch->nch_AudioModes.lh_Head;
1486 while(nam->nam_Node.ln_Succ)
1488 if(nam->nam_TerminalID == uaot->bTerminalID)
1490 nam->nam_IsInput = TRUE;
1491 nam->nam_RootUnit = nau;
1492 //psdAddErrorMsg(RETURN_OK, (STRPTR) libname, "Terminal %02lx assigned to IN audio mode!", nam->nam_TerminalID);
1494 nam = (struct NepAudioMode *) nam->nam_Node.ln_Succ;
1497 break;
1500 case UDST_AUDIO_CTRL_INPUT_TERMINAL:
1502 struct UsbAudioInputTermDesc10 *uait = (struct UsbAudioInputTermDesc10 *) descdata;
1503 UWORD channelcfg = AROS_WORD2LE(uait->wChannelConfig);
1504 ULONG termtype = AROS_WORD2LE(uait->wTerminalType);
1506 nau->nau_OutChannels = uait->bNrChannels;
1507 nau->nau_ChannelCfg = channelcfg;
1508 nau->nau_TermType = termtype;
1509 nau->nau_RootUnit = nau;
1510 if(termtype == UAUTT_STREAMING)
1512 // try to locate audio mode, which is obviously an output
1513 nam = (struct NepAudioMode *) nch->nch_AudioModes.lh_Head;
1514 while(nam->nam_Node.ln_Succ)
1516 if(nam->nam_TerminalID == uait->bTerminalID)
1518 nam->nam_IsInput = FALSE;
1519 nam->nam_RootUnit = nau;
1520 //psdAddErrorMsg(RETURN_OK, (STRPTR) libname, "Terminal %02lx assigned to OUT audio mode!", nam->nam_TerminalID);
1522 nam = (struct NepAudioMode *) nam->nam_Node.ln_Succ;
1525 break;
1528 case UDST_AUDIO_CTRL_MIXER_UNIT:
1530 struct UsbAudioMixerUnitDesc10 *uamu = (struct UsbAudioMixerUnitDesc10 *) descdata;
1531 UWORD inputpins = uamu->bNrInPins;
1532 UWORD outchannels = descdata[5+inputpins];
1533 UWORD channelcfg = descdata[6+inputpins]|(descdata[7+inputpins]<<8);
1535 nau->nau_OutChannels = outchannels;
1536 nau->nau_ChannelCfg = channelcfg;
1537 break;
1540 case UDST_AUDIO_CTRL_PROCESSING_UNIT:
1541 case UDST_AUDIO_CTRL_EXTENSION_UNIT:
1543 struct UsbAudioProcessingUnitDesc10 *uapu = (struct UsbAudioProcessingUnitDesc10 *) descdata;
1544 UWORD inputpins = uapu->bNrInPins;
1545 UWORD outchannels = descdata[7+inputpins];
1546 UWORD channelcfg = descdata[8+inputpins]|(descdata[9+inputpins]<<8);
1548 nau->nau_OutChannels = outchannels;
1549 nau->nau_ChannelCfg = channelcfg;
1550 break;
1553 nau = (struct NepAudioUnit *) nau->nau_Node.ln_Succ;
1556 KPRINTF(10, ("ExamineAudioDesc Stage 4\n"));
1558 // recurse over output terminals, flow up the chain
1559 nau = (struct NepAudioUnit *) nch->nch_AudioUnits.lh_Head;
1560 while(nau->nau_Node.ln_Succ)
1562 descdata = nau->nau_Descriptor;
1563 if(nau->nau_Type == UDST_AUDIO_CTRL_OUTPUT_TERMINAL)
1565 nFlowUp(nch, nau);
1566 nau->nau_SourceUnit = nFlowUpToUSBSource(nch, nau);
1568 nau = (struct NepAudioUnit *) nau->nau_Node.ln_Succ;
1571 // recurse over input terminals, flow down the chain
1572 nau = (struct NepAudioUnit *) nch->nch_AudioUnits.lh_Head;
1573 while(nau->nau_Node.ln_Succ)
1575 descdata = nau->nau_Descriptor;
1576 if(nau->nau_Type == UDST_AUDIO_CTRL_INPUT_TERMINAL)
1578 UWORD cnt;
1579 for(cnt = 0; cnt < nau->nau_NumOutputs; cnt++)
1581 nFlowDown(nch, nau->nau_OutputUnit[cnt]);
1583 nau->nau_SinkUnit = nFlowDownToUSBSink(nch, nau);
1585 nau = (struct NepAudioUnit *) nau->nau_Node.ln_Succ;
1588 KPRINTF(10, ("ExamineAudioDesc Stage 5\n"));
1590 // do the some more magic
1591 nau = (struct NepAudioUnit *) nch->nch_AudioUnits.lh_Head;
1592 while(nau->nau_Node.ln_Succ)
1594 descdata = nau->nau_Descriptor;
1595 switch(nau->nau_Type)
1597 case UDST_AUDIO_CTRL_MIXER_UNIT:
1599 struct UsbAudioMixerUnitDesc10 *uamu = (struct UsbAudioMixerUnitDesc10 *) descdata;
1600 UWORD inputpins = uamu->bNrInPins;
1601 //UWORD outchannels = descdata[5+inputpins];
1602 UWORD channelcfg = descdata[6+inputpins]|(descdata[7+inputpins]<<8);
1603 STRPTR spacial = nConcatBitsStr(nch, NTS_SPATIALLOCATION, (ULONG) channelcfg);
1605 /*psdAddErrorMsg(RETURN_OK, (STRPTR) libname, "Mixer Unit %02lx with %ld input pins and %ld output channels (%s).",
1606 uamu->bUnitID,
1607 inputpins,
1608 outchannels,
1609 spacial);*/
1610 psdFreeVec(spacial);
1611 break;
1614 case UDST_AUDIO_CTRL_SELECTOR_UNIT:
1616 //struct UsbAudioSelectorUnitDesc10 *uasu = (struct UsbAudioSelectorUnitDesc10 *) descdata;
1617 //UWORD inputpins = uasu->bNrInPins;
1618 //UWORD cnt;
1620 /*psdAddErrorMsg(RETURN_OK, (STRPTR) libname, "Selector Unit %02lx with %ld input pins.",
1621 uasu->bUnitID,
1622 inputpins);*/
1624 if(nau->nau_SinkUnit)
1626 KPRINTF(10, ("Assigning Selector to Unit %02lx", nau->nau_SinkUnit->nau_UnitID));
1627 nau->nau_SinkUnit->nau_SelectorUnit = nau;
1628 } else {
1629 KPRINTF(10, ("Error: No Sink unit!\n"));
1632 /*nam = (struct NepAudioMode *) nch->nch_AudioModes.lh_Head;
1633 while(nam->nam_Node.ln_Succ)
1635 if(nam->nam_TerminalID == nau->nau_RootUnit->nau_UnitID)
1637 KPRINTF(10, ("Terminal ID %02lx matched\n", nam->nam_TerminalID));
1638 if(nau->nau_RootUnit->nau_Type == UDST_AUDIO_CTRL_INPUT_TERMINAL)
1640 for(cnt = 0; cnt < nau->nau_NumInputs; cnt++)
1642 if(nam->nam_NumOutputs < 8)
1644 KPRINTF(10, ("Adding output selector %s\n", nNumToStr(nch, NTS_TERMINALTYPE, (ULONG) nau->nau_InputUnit[cnt]->nau_TermType, "Unknown")));
1645 nam->nam_OutputNames[nam->nam_NumOutputs++] = nNumToStr(nch, NTS_TERMINALTYPE, (ULONG) nau->nau_InputUnit[cnt]->nau_TermType, "Unknown");
1648 } else {
1649 for(cnt = 0; cnt < nau->nau_NumInputs; cnt++)
1651 if(nam->nam_NumInputs < 8)
1653 KPRINTF(10, ("Adding input selector %s\n", nNumToStr(nch, NTS_TERMINALTYPE, (ULONG) nau->nau_InputUnit[cnt]->nau_TermType, "Unknown")));
1654 nam->nam_InputNames[nam->nam_NumInputs++] = nNumToStr(nch, NTS_TERMINALTYPE, (ULONG) nau->nau_InputUnit[cnt]->nau_TermType, "Unknown");
1659 nam = (struct NepAudioMode *) nam->nam_Node.ln_Succ;
1661 break;
1664 case UDST_AUDIO_CTRL_FEATURE_UNIT:
1666 UWORD featsize = descdata[5];
1667 UWORD feat;
1668 UWORD masterfeat = 0;
1669 UWORD leftfeat = 0;
1670 UWORD rightfeat = 0;
1671 UBYTE *featptr = descdata + 6;
1672 UWORD featsizecnt;
1673 UWORD cnt;
1674 UWORD firstchan = 0;
1676 nau->nau_TermType = nau->nau_InputUnit[0]->nau_TermType;
1677 nau->nau_OutChannels = nau->nau_InputUnit[0]->nau_OutChannels;
1678 nau->nau_ChannelCfg = nau->nau_InputUnit[0]->nau_ChannelCfg;
1680 KPRINTF(10, ("Feature Unit %ld, Root unit %ld\n", nau->nau_UnitID, nau->nau_RootUnit->nau_UnitID));
1682 for(cnt = 0; cnt <= nau->nau_InputUnit[0]->nau_OutChannels; cnt++)
1684 feat = 0;
1685 for(featsizecnt = 0; featsizecnt < featsize; featsizecnt++)
1687 feat |= (*featptr++)<<(featsizecnt<<3);
1689 if(cnt == 0)
1691 masterfeat = feat;
1693 else if(cnt == 1)
1695 leftfeat = feat;
1697 else if(cnt == 2)
1699 rightfeat = feat;
1703 if((masterfeat & UAFUF_VOLUME) ||
1704 ((nau->nau_OutChannels == 1) && (leftfeat & UAFUF_VOLUME)) ||
1705 (leftfeat & rightfeat & UAFUF_VOLUME))
1707 KPRINTF(10, ("Master volume control supported\n"));
1708 if(nau->nau_SourceUnit)
1710 KPRINTF(10, ("Volume roots from USB input streaming, assuming Master Volume!\n"));
1711 nau->nau_RootUnit->nau_VolumeControl = TRUE;
1712 nau->nau_RootUnit->nau_VolumeUnit = nau;
1713 if(leftfeat & rightfeat & UAFUF_VOLUME)
1715 KPRINTF(10, ("Balance control supported\n"));
1716 nau->nau_RootUnit->nau_Balance = TRUE;
1719 else if(nau->nau_SinkUnit)
1721 KPRINTF(10, ("Flows to USB stream, assuming input gain!\n"));
1722 nau->nau_RootUnit->nau_VolumeControl = TRUE;
1723 nau->nau_RootUnit->nau_VolumeUnit = nau;
1724 if(leftfeat & rightfeat & UAFUF_VOLUME)
1726 KPRINTF(10, ("Input Balance control supported\n"));
1727 nau->nau_RootUnit->nau_Balance = TRUE;
1729 } else {
1730 KPRINTF(10, ("Flows to something else, assuming monitor!\n"));
1731 nau->nau_RootUnit->nau_Monitor = TRUE;
1732 nau->nau_RootUnit->nau_MonitorUnit = nau;
1735 if(rightfeat & UAFUF_VOLUME)
1737 firstchan = 2;
1738 nau->nau_VolCtrlMask |= 4;
1739 nau->nau_VolCtrlCount++;
1741 if(leftfeat & UAFUF_VOLUME)
1743 firstchan = 1;
1744 nau->nau_VolCtrlMask |= 2;
1745 nau->nau_VolCtrlCount++;
1747 if((masterfeat & UAFUF_VOLUME))
1749 firstchan = 0;
1750 nau->nau_VolCtrlMask |= 1;
1751 nau->nau_VolCtrlCount++;
1753 KPRINTF(10, ("Volume Feature Mask %04lx\n", nau->nau_VolCtrlMask));
1755 if(nau->nau_VolCtrlCount)
1757 UBYTE buf[2];
1758 LONG ioerr;
1759 psdPipeSetup(nch->nch_EP0Pipe, URTF_IN|URTF_CLASS|URTF_INTERFACE, UAUDR_GET_MIN, (ULONG) (UAFUCS_VOLUME<<8)|firstchan, (nau->nau_UnitID<<8)|nch->nch_IfNum);
1760 ioerr = psdDoPipe(nch->nch_EP0Pipe, buf, 2);
1761 if(ioerr)
1763 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1764 "Could not get min volume: %s (%ld)!",
1765 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1766 } else {
1767 KPRINTF(10, ("Minimum volume: %04lx\n", buf[0]|(buf[1]<<8)));
1768 nau->nau_MinVolDb = (WORD) (buf[0]|(buf[1]<<8));
1770 psdPipeSetup(nch->nch_EP0Pipe, URTF_IN|URTF_CLASS|URTF_INTERFACE, UAUDR_GET_MAX, (ULONG) (UAFUCS_VOLUME<<8)|firstchan, (nau->nau_UnitID<<8)|nch->nch_IfNum);
1771 ioerr = psdDoPipe(nch->nch_EP0Pipe, buf, 2);
1772 if(ioerr)
1774 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1775 "Could not get max volume: %s (%ld)!",
1776 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1777 } else {
1778 KPRINTF(10, ("Maximum volume: %04lx\n", buf[0]|(buf[1]<<8)));
1779 nau->nau_MaxVolDb = (WORD) (buf[0]|(buf[1]<<8));
1781 nFindLogVolume(nch, nau);
1783 break;
1786 /*psdAddErrorMsg(RETURN_OK, (STRPTR) libname, "%s Unit (%s) ID=%02lx, In/Out=%ld/%ld, Chans=%ld, Cfg=%ld, TermType=%s, Root=%02lx, Source=%02lx, Sink=%02lx",
1787 nNumToStr(nch, NTS_UNITTYPE, (ULONG) nau->nau_Type, "Unknown"),
1788 nau->nau_Name,
1789 nau->nau_UnitID,
1790 nau->nau_NumInputs,
1791 nau->nau_NumOutputs,
1792 nau->nau_OutChannels,
1793 nau->nau_ChannelCfg,
1794 nNumToStr(nch, NTS_TERMINALTYPE, (ULONG) nau->nau_TermType, "Unknown"),
1795 nau->nau_RootUnit->nau_UnitID,
1796 nau->nau_SourceUnit ? nau->nau_SourceUnit->nau_UnitID : 0,
1797 nau->nau_SinkUnit ? nau->nau_SinkUnit->nau_UnitID : 0);*/
1799 nau = (struct NepAudioUnit *) nau->nau_Node.ln_Succ;
1802 // if no selectors were found, make sure we have names for at least one input source and output sink
1803 nam = (struct NepAudioMode *) nch->nch_AudioModes.lh_Head;
1804 while(nam->nam_Node.ln_Succ)
1806 if(!nam->nam_NumOutputs)
1808 nau = (struct NepAudioUnit *) nch->nch_AudioUnits.lh_Head;
1809 while(nau->nau_Node.ln_Succ)
1811 if((nau->nau_Type == UDST_AUDIO_CTRL_OUTPUT_TERMINAL) && (nau->nau_TermType != UAUTT_STREAMING))
1813 nam->nam_OutputNames[nam->nam_NumOutputs++] = nNumToStr(nch, NTS_TERMINALTYPE, (ULONG) nau->nau_TermType, "Unknown");
1814 //break;
1816 nau = (struct NepAudioUnit *) nau->nau_Node.ln_Succ;
1819 if(!nam->nam_NumInputs)
1821 nau = (struct NepAudioUnit *) nch->nch_AudioUnits.lh_Head;
1822 while(nau->nau_Node.ln_Succ)
1824 if((nau->nau_Type == UDST_AUDIO_CTRL_INPUT_TERMINAL) && (nau->nau_TermType != UAUTT_STREAMING))
1826 nam->nam_InputNames[nam->nam_NumInputs++] = nNumToStr(nch, NTS_TERMINALTYPE, (ULONG) nau->nau_TermType, "Unknown");
1827 //break;
1829 nau = (struct NepAudioUnit *) nau->nau_Node.ln_Succ;
1832 nam = (struct NepAudioMode *) nam->nam_Node.ln_Succ;
1835 // find recording modes and assign as sibling
1836 nam = (struct NepAudioMode *) nch->nch_AudioModes.lh_Head;
1837 while(nam->nam_Node.ln_Succ)
1839 if(nam->nam_IsInput)
1841 KPRINTF(10, ("Trying to find matching record mode for %ld channel(s) and %ld bits.\n", nam->nam_NumChannels, nam->nam_Resolution));
1842 sibnam = (struct NepAudioMode *) nch->nch_AudioModes.lh_Head;
1843 while(sibnam->nam_Node.ln_Succ)
1845 if(!sibnam->nam_IsInput)
1847 if((sibnam->nam_Resolution == nam->nam_Resolution) &&
1848 (sibnam->nam_NumChannels == nam->nam_NumChannels) &&
1849 (sibnam->nam_FrameSize == nam->nam_FrameSize) &&
1850 (sibnam->nam_NumFrequencies == nam->nam_NumFrequencies) &&
1851 (sibnam->nam_MinFreq == nam->nam_MinFreq) &&
1852 (sibnam->nam_MaxFreq == nam->nam_MaxFreq) &&
1853 (sibnam->nam_FreqArray[0] == nam->nam_FreqArray[0]))
1855 KPRINTF(10, ("Recording mode with %ld channel(s) and %ld bits matched.\n", nam->nam_NumChannels, nam->nam_Resolution));
1856 if(sibnam->nam_Sibling)
1858 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "Matching playback mode with %ld channel(s) and %ld bits is already occupied.",
1859 sibnam->nam_NumChannels,
1860 sibnam->nam_Resolution);
1861 } else {
1862 nam->nam_Sibling = sibnam;
1863 sibnam->nam_Sibling = nam;
1864 break;
1868 sibnam = (struct NepAudioMode *) sibnam->nam_Node.ln_Succ;
1870 if(!sibnam->nam_Node.ln_Succ)
1872 KPRINTF(10, ("Recording mode with %ld channel(s) and %ld bits could not be matched to an input mode.\n", nam->nam_NumChannels, nam->nam_Resolution));
1873 sibnam = (struct NepAudioMode *) nch->nch_AudioModes.lh_Head;
1874 while(sibnam->nam_Node.ln_Succ)
1876 if(!sibnam->nam_IsInput)
1878 if((sibnam->nam_NumFrequencies == nam->nam_NumFrequencies) &&
1879 (sibnam->nam_MinFreq == nam->nam_MinFreq) &&
1880 (sibnam->nam_MaxFreq == nam->nam_MaxFreq) &&
1881 (sibnam->nam_FreqArray[0] == nam->nam_FreqArray[0]))
1883 KPRINTF(10, ("Recording mode partially matched.\n"));
1884 if(sibnam->nam_Sibling)
1886 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "Partially matching playback mode with %ld channel(s) and %ld bits is already occupied.",
1887 sibnam->nam_NumChannels,
1888 sibnam->nam_Resolution);
1889 } else {
1890 nam->nam_Sibling = sibnam;
1891 sibnam->nam_Sibling = nam;
1892 break;
1896 sibnam = (struct NepAudioMode *) sibnam->nam_Node.ln_Succ;
1898 if(!sibnam->nam_Node.ln_Succ)
1900 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "Recording mode with %ld channel(s) and %ld bits could not be matched to an output mode.",
1901 nam->nam_NumChannels,
1902 nam->nam_Resolution);
1903 } else {
1904 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "Recording mode with %ld ch@%ldb was assigned to %ld ch@%ldb output mode.",
1905 nam->nam_NumChannels,
1906 nam->nam_Resolution,
1907 sibnam->nam_NumChannels,
1908 sibnam->nam_Resolution);
1912 nam = (struct NepAudioMode *) nam->nam_Node.ln_Succ;
1915 KPRINTF(10, ("ExamineAudioUnits finished\n"));
1917 /* \\\ */
1919 /* /// "nAddAudioModes()" */
1920 void nAddAudioModes(struct NepClassAudio *nch)
1922 struct NepAudioMode *nam;
1923 STRPTR devname;
1924 STRPTR ahimodename;
1926 psdGetAttrs(PGA_DEVICE, nch->nch_Device, DA_ProductName, &devname, TAG_END);
1927 nam = (struct NepAudioMode *) nch->nch_AudioModes.lh_Head;
1928 while(nam->nam_Node.ln_Succ)
1930 if(!nam->nam_IsInput)
1932 struct TagItem *tags = nam->nam_Tags;
1933 ahimodename = psdCopyStrFmt("%.20s: %s%ld bit %s (%ld bpf)",
1934 devname,
1935 (nam->nam_Resolution > 16) ? "HiFi " : "",
1936 nam->nam_Resolution,
1937 (nam->nam_NumChannels > 1) ? "stereo++" : "mono",
1938 nam->nam_FrameSize);
1940 KPRINTF(10, ("AHI Mode %s NumInput=%ld, NumOutput=%ld, Sib=%08lx\n",
1941 ahimodename, nam->nam_NumInputs, nam->nam_NumOutputs, nam->nam_Sibling));
1943 // AHI samples are always 16 bit, except for HiFi mode, which returns 32 bit
1944 nam->nam_AHIFrameSize = nam->nam_NumChannels * ((nam->nam_Resolution > 16) ? 4 : 2);
1946 tags->ti_Tag = AHIDB_AudioID;
1947 tags->ti_Data = nam->nam_AHIModeID;
1948 tags++;
1949 tags->ti_Tag = AHIDB_Name;
1950 tags->ti_Data = (IPTR) ahimodename;
1951 tags++;
1952 tags->ti_Tag = AHIDB_Driver;
1953 tags->ti_Data = (IPTR) "usbaudio";
1954 tags++;
1955 /*tags->ti_Tag = AHIDB_DriverBaseName;
1956 tags->ti_Data = (ULONG) "";
1957 tags++;*/
1958 tags->ti_Tag = AHIDB_Volume;
1959 tags->ti_Data = nam->nam_RootUnit->nau_VolumeControl;
1960 tags++;
1961 tags->ti_Tag = AHIDB_Panning;
1962 tags->ti_Data = (nam->nam_NumChannels > 1) ? TRUE : FALSE;
1963 tags++;
1964 tags->ti_Tag = AHIDB_Stereo;
1965 tags->ti_Data = (nam->nam_NumChannels > 1) ? TRUE : FALSE;
1966 tags++;
1967 tags->ti_Tag = AHIDB_HiFi;
1968 tags->ti_Data = (nam->nam_Resolution > 16) ? TRUE : FALSE;
1969 tags++;
1970 tags->ti_Tag = AHIDB_MultTable;
1971 tags->ti_Data = FALSE;
1972 tags++;
1973 tags->ti_Tag = AHIDB_NepAudioMode;
1974 tags->ti_Data = (IPTR) nam;
1975 tags++;
1976 tags->ti_Tag = TAG_END;
1977 AHI_AddAudioMode(nam->nam_Tags);
1978 psdFreeVec(ahimodename);
1980 nam = (struct NepAudioMode *) nam->nam_Node.ln_Succ;
1983 /* \\\ */
1985 /* /// "nAllocAudio()" */
1986 struct NepClassAudio * nAllocAudio(void)
1988 struct Task *thistask;
1989 struct NepClassAudio *nch;
1991 thistask = FindTask(NULL);
1992 nch = thistask->tc_UserData;
1995 if(!(nch->nch_Base = OpenLibrary("poseidon.library", 4)))
1997 Alert(AG_OpenLib);
1998 break;
2001 if(!(nch->nch_AHIMsgPort = CreateMsgPort()))
2003 break;
2006 if(!(nch->nch_AHIReq = (struct AHIRequest *) CreateIORequest(nch->nch_AHIMsgPort, sizeof(struct AHIRequest))))
2008 break;
2011 //if(OpenDevice("ahi.device", AHI_NO_UNIT, (struct IORequest *) nch->nch_AHIReq, AHIDF_NOMODESCAN))
2012 if(OpenDevice("ahi.device", AHI_NO_UNIT, (struct IORequest *) nch->nch_AHIReq, 0))
2014 psdAddErrorMsg(RETURN_FAIL, (STRPTR) libname, "Unable to open AHI device");
2015 break;
2018 AHIBase = (struct Library *) nch->nch_AHIReq->ahir_Std.io_Device;
2020 psdGetAttrs(PGA_INTERFACE, nch->nch_Interface,
2021 IFA_Config, &nch->nch_Config,
2022 IFA_InterfaceNum, &nch->nch_IfNum,
2023 TAG_END);
2024 psdGetAttrs(PGA_CONFIG, nch->nch_Config,
2025 CA_Device, &nch->nch_Device,
2026 TAG_END);
2028 if(!nch->nch_AudioModes.lh_Head->ln_Succ)
2030 nExamineAudioDescriptors(nch);
2032 if(nch->nch_AudioModes.lh_Head->ln_Succ)
2034 if((nch->nch_TaskMsgPort = CreateMsgPort()))
2036 if((nch->nch_EP0Pipe = psdAllocPipe(nch->nch_Device, nch->nch_TaskMsgPort, NULL)))
2038 nExamineAudioUnits(nch);
2039 nAddAudioModes(nch);
2041 nch->nch_Task = thistask;
2042 return(nch);
2044 DeleteMsgPort(nch->nch_TaskMsgPort);
2045 nch->nch_TaskMsgPort = NULL;
2047 } else {
2048 psdAddErrorMsg(RETURN_FAIL, (STRPTR) libname, "No suitable audio modes found for this audio device. Very sorry, dude.");
2050 } while(FALSE);
2051 if(AHIBase)
2053 CloseDevice((struct IORequest *) nch->nch_AHIReq);
2054 AHIBase = NULL;
2056 DeleteIORequest((struct IORequest *) nch->nch_AHIReq);
2057 nch->nch_AHIReq = NULL;
2058 DeleteMsgPort(nch->nch_AHIMsgPort);
2059 nch->nch_AHIMsgPort = NULL;
2060 CloseLibrary(nch->nch_Base);
2061 nch->nch_Base = NULL;
2062 Forbid();
2063 nch->nch_Task = NULL;
2064 if(nch->nch_ReadySigTask)
2066 Signal(nch->nch_ReadySigTask, 1L<<nch->nch_ReadySignal);
2068 return(NULL);
2070 /* \\\ */
2072 /* /// "nFreeAudio()" */
2073 void nFreeAudio(struct NepClassAudio *nch)
2075 struct NepAudioMode *nam;
2076 struct NepAudioUnit *nau;
2078 nam = (struct NepAudioMode *) nch->nch_AudioModes.lh_Head;
2079 while(nam->nam_Node.ln_Succ)
2081 if(nam->nam_AHIModeID)
2083 AHI_RemoveAudioMode(nam->nam_AHIModeID);
2085 nam = (struct NepAudioMode *) nam->nam_Node.ln_Succ;
2087 nau = (struct NepAudioUnit *) nch->nch_AudioUnits.lh_Head;
2088 while(nau->nau_Node.ln_Succ)
2090 Remove((struct Node *) nau);
2091 psdFreeVec(nau->nau_Name);
2092 psdFreeVec(nau);
2093 nau = (struct NepAudioUnit *) nch->nch_AudioUnits.lh_Head;
2095 psdFreePipe(nch->nch_EP0Pipe);
2096 DeleteMsgPort(nch->nch_TaskMsgPort);
2097 nch->nch_TaskMsgPort = NULL;
2099 CloseDevice((struct IORequest *) nch->nch_AHIReq);
2100 AHIBase = NULL;
2101 DeleteIORequest((struct IORequest *) nch->nch_AHIReq);
2102 nch->nch_AHIReq = NULL;
2103 DeleteMsgPort(nch->nch_AHIMsgPort);
2104 nch->nch_AHIMsgPort = NULL;
2105 CloseLibrary(nch->nch_Base);
2106 nch->nch_Base = NULL;
2107 Forbid();
2108 nch->nch_Task = NULL;
2109 if(nch->nch_ReadySigTask)
2111 Signal(nch->nch_ReadySigTask, 1L<<nch->nch_ReadySignal);
2114 /* \\\ */
2116 /**************************************************************************/
2118 #undef ps
2120 /* /// "nLoadClassConfig()" */
2121 BOOL nLoadClassConfig(struct NepAudioBase *nh)
2123 struct Library *ps;
2124 struct ClsGlobalCfg *cgc;
2125 struct PsdIFFContext *pic;
2127 KPRINTF(10, ("Loading Class Config...\n"));
2128 if(!(ps = OpenLibrary("poseidon.library", 4)))
2130 return(FALSE);
2132 Forbid();
2133 nh->nh_UsingDefaultCfg = TRUE;
2134 pic = psdGetClsCfg(libname);
2135 if(pic)
2137 if((cgc = psdGetCfgChunk(pic, AROS_LONG2BE(nh->nh_CurrentCGC.cgc_ChunkID))))
2139 CopyMem(((UBYTE *) cgc) + 8, ((UBYTE *) &nh->nh_CurrentCGC) + 8, min(AROS_LONG2BE(cgc->cgc_Length), AROS_LONG2BE(nh->nh_CurrentCGC.cgc_Length)));
2140 psdFreeVec(cgc);
2141 nh->nh_UsingDefaultCfg = FALSE;
2144 Permit();
2145 CloseLibrary(ps);
2146 return(FALSE);
2148 /* \\\ */
2150 /* /// "nOpenCfgWindow()" */
2151 LONG nOpenCfgWindow(struct NepAudioBase *nh)
2153 struct Library *ps;
2154 KPRINTF(10, ("Opening GUI...\n"));
2155 if(!(ps = OpenLibrary("poseidon.library", 4)))
2157 return(FALSE);
2159 Forbid();
2160 if(!nh->nh_GUITask)
2162 if((nh->nh_GUITask = psdSpawnSubTask(MOD_NAME_STRING " GUI", nGUITask, nh)))
2164 Permit();
2165 CloseLibrary(ps);
2166 return(TRUE);
2169 Permit();
2170 CloseLibrary(ps);
2171 return(FALSE);
2173 /* \\\ */
2175 /* /// "nGUITask()" */
2176 AROS_UFH0(void, nGUITask)
2178 AROS_USERFUNC_INIT
2179 struct Task *thistask;
2180 struct NepAudioBase *nh;
2181 APTR pic;
2183 thistask = FindTask(NULL);
2185 #define ps nh->nh_PsdBase
2186 #undef IntuitionBase
2187 #define IntuitionBase nh->nh_IntBase
2188 #undef MUIMasterBase
2189 #define MUIMasterBase nh->nh_MUIBase
2191 nh = thistask->tc_UserData;
2192 ++nh->nh_Library.lib_OpenCnt;
2193 if(!(MUIMasterBase = OpenLibrary(MUIMASTER_NAME, MUIMASTER_VMIN)))
2195 KPRINTF(10, ("Couldn't open muimaster.library.\n"));
2196 nGUITaskCleanup(nh);
2197 return;
2200 if(!(IntuitionBase = OpenLibrary("intuition.library", 39)))
2202 KPRINTF(10, ("Couldn't open intuition.library.\n"));
2203 nGUITaskCleanup(nh);
2204 return;
2206 if(!(ps = OpenLibrary("poseidon.library", 4)))
2208 KPRINTF(10, ("Couldn't open poseidon.library.\n"));
2209 nGUITaskCleanup(nh);
2210 return;
2213 nh->nh_App = ApplicationObject,
2214 MUIA_Application_Title , (IPTR)libname,
2215 MUIA_Application_Version , (IPTR)VERSION_STRING,
2216 MUIA_Application_Copyright , (IPTR)"©2008-2009 Chris Hodges",
2217 MUIA_Application_Author , (IPTR)"Chris Hodges <chrisly@platon42.de>",
2218 MUIA_Application_Description, (IPTR)"Settings for the usbaudio.class",
2219 MUIA_Application_Base , (IPTR)"USBAUDIO",
2220 MUIA_Application_HelpFile , (IPTR)"HELP:Poseidon.guide",
2221 MUIA_Application_Menustrip , (IPTR)MenustripObject,
2222 Child, (IPTR)MenuObjectT((IPTR)"Project"),
2223 Child, (IPTR)(nh->nh_AboutMI = MenuitemObject,
2224 MUIA_Menuitem_Title, (IPTR)"About...",
2225 MUIA_Menuitem_Shortcut, (IPTR)"?",
2226 End),
2227 End,
2228 Child, (IPTR)MenuObjectT((IPTR)"Settings"),
2229 Child, (IPTR)(nh->nh_UseMI = MenuitemObject,
2230 MUIA_Menuitem_Title, (IPTR)"Save",
2231 MUIA_Menuitem_Shortcut, (IPTR)"S",
2232 End),
2233 Child, (IPTR)MenuitemObject,
2234 MUIA_Menuitem_Title, (IPTR)NM_BARLABEL,
2235 End,
2236 Child, (IPTR)(nh->nh_MUIPrefsMI = MenuitemObject,
2237 MUIA_Menuitem_Title, (IPTR)"MUI Settings",
2238 MUIA_Menuitem_Shortcut, (IPTR)"M",
2239 End),
2240 End,
2241 End,
2243 SubWindow, (IPTR)(nh->nh_MainWindow = WindowObject,
2244 MUIA_Window_ID , MAKE_ID('M','A','I','N'),
2245 MUIA_Window_Title, (IPTR)libname,
2246 MUIA_HelpNode, (IPTR)libname,
2248 WindowContents, (IPTR)VGroup,
2249 Child, (IPTR)ColGroup(2), (IPTR)GroupFrameT((IPTR)"Global Settings"),
2250 Child, (IPTR)Label((IPTR) "None"),
2251 Child, (IPTR)HSpace(0),
2252 End,
2253 Child, (IPTR)VSpace(0),
2254 Child, (IPTR)HGroup,
2255 MUIA_Group_SameWidth, TRUE,
2256 Child, (IPTR)(nh->nh_UseObj = TextObject, ButtonFrame,
2257 MUIA_Background, MUII_ButtonBack,
2258 MUIA_CycleChain, 1,
2259 MUIA_InputMode, MUIV_InputMode_RelVerify,
2260 MUIA_Text_Contents, (IPTR)"\33c Save ",
2261 End),
2262 Child, (IPTR)(nh->nh_CloseObj = TextObject, ButtonFrame,
2263 MUIA_Background, MUII_ButtonBack,
2264 MUIA_CycleChain, 1,
2265 MUIA_InputMode, MUIV_InputMode_RelVerify,
2266 MUIA_Text_Contents, (IPTR)"\33c Use ",
2267 End),
2268 End,
2269 End,
2270 End),
2271 End;
2273 if(!nh->nh_App)
2275 KPRINTF(10, ("Couldn't create application\n"));
2276 nGUITaskCleanup(nh);
2277 return;
2279 DoMethod(nh->nh_MainWindow, MUIM_Notify, MUIA_Window_CloseRequest, TRUE,
2280 nh->nh_App, 2, MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit);
2281 DoMethod(nh->nh_UseObj, MUIM_Notify, MUIA_Pressed, FALSE,
2282 nh->nh_App, 2, MUIM_Application_ReturnID, ID_STORE_CONFIG);
2283 DoMethod(nh->nh_CloseObj, MUIM_Notify, MUIA_Pressed, FALSE,
2284 nh->nh_App, 2, MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit);
2286 DoMethod(nh->nh_AboutMI, MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime,
2287 nh->nh_App, 2, MUIM_Application_ReturnID, ID_ABOUT);
2288 DoMethod(nh->nh_UseMI, MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime,
2289 nh->nh_App, 2, MUIM_Application_ReturnID, ID_STORE_CONFIG);
2290 DoMethod(nh->nh_MUIPrefsMI, MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime,
2291 nh->nh_App, 2, MUIM_Application_OpenConfigWindow, 0);
2294 IPTR isopen = 0;
2295 IPTR iconify = 0;
2296 ULONG sigs;
2297 ULONG sigmask;
2298 LONG retid;
2300 get(nh->nh_App, MUIA_Application_Iconified, &iconify);
2301 set(nh->nh_MainWindow, MUIA_Window_Open, TRUE);
2302 get(nh->nh_MainWindow, MUIA_Window_Open, &isopen);
2303 if(!(isopen || iconify))
2305 nGUITaskCleanup(nh);
2306 return;
2308 sigmask = 0;
2311 retid = DoMethod(nh->nh_App, MUIM_Application_NewInput, &sigs);
2312 switch(retid)
2314 case ID_STORE_CONFIG:
2315 case MUIV_Application_ReturnID_Quit:
2316 pic = psdGetClsCfg(libname);
2317 if(!pic)
2319 psdSetClsCfg(libname, NULL);
2320 pic = psdGetClsCfg(libname);
2322 if(pic)
2324 if(psdAddCfgEntry(pic, &nh->nh_CurrentCGC))
2326 if(retid != MUIV_Application_ReturnID_Quit)
2328 psdSaveCfgToDisk(NULL, FALSE);
2330 retid = MUIV_Application_ReturnID_Quit;
2333 break;
2335 case ID_ABOUT:
2336 MUI_RequestA(nh->nh_App, nh->nh_MainWindow, 0, NULL, "Marvellous!", VERSION_STRING, NULL);
2337 break;
2339 if(retid == MUIV_Application_ReturnID_Quit)
2341 break;
2343 if(sigs)
2345 sigs = Wait(sigs | sigmask | SIGBREAKF_CTRL_C);
2346 if(sigs & SIGBREAKF_CTRL_C)
2348 break;
2351 } while(TRUE);
2352 set(nh->nh_MainWindow, MUIA_Window_Open, FALSE);
2354 nGUITaskCleanup(nh);
2356 AROS_USERFUNC_EXIT
2358 /* \\\ */
2360 /* /// "nGUITaskCleanup()" */
2361 void nGUITaskCleanup(struct NepAudioBase *nh)
2363 if(nh->nh_App)
2365 MUI_DisposeObject(nh->nh_App);
2366 nh->nh_App = NULL;
2368 if(MUIMasterBase)
2370 CloseLibrary(MUIMasterBase);
2371 MUIMasterBase = NULL;
2373 if(IntuitionBase)
2375 CloseLibrary(IntuitionBase);
2376 IntuitionBase = NULL;
2378 if(ps)
2380 CloseLibrary(ps);
2381 ps = NULL;
2383 Forbid();
2384 nh->nh_GUITask = NULL;
2385 --nh->nh_Library.lib_OpenCnt;
2387 /* \\\ */
2389 /**************************************************************************/
2391 #undef UtilityBase
2392 #undef ps
2393 #define ps nam->nam_PsdBase
2395 /* /// "subLib stuff" */
2396 AROS_UFH3(SUBLIBBASETYPEPTR, subLibInit,
2397 AROS_UFHA(SUBLIBBASETYPEPTR, nas, D0),
2398 AROS_UFHA(BPTR, seglist, A0),
2399 AROS_UFHA(struct ExecBase *, SysBase, A6))
2401 AROS_USERFUNC_INIT
2403 KPRINTF(10, ("subLibInit base: 0x%08lx seglist: 0x%08lx SysBase: 0x%08lx\n",
2404 nas, seglist, SysBase));
2406 nas->nas_Library.lib_Node.ln_Type = NT_LIBRARY;
2407 nas->nas_Library.lib_Node.ln_Name = SUBLIBNAME;
2408 nas->nas_Library.lib_Flags = LIBF_SUMUSED | LIBF_CHANGED;
2409 nas->nas_Library.lib_Version = AHI_SUB_LIB_VERSION;
2410 nas->nas_Library.lib_Revision = REVISION_NUMBER;
2411 nas->nas_Library.lib_IdString = VERSION_STRING;
2413 /* Store segment */
2414 nas->nas_SegList = seglist;
2416 #define UtilityBase nas->nas_UtilityBase
2417 if((nas->nas_UtilityBase = OpenLibrary("utility.library", 0)))
2419 KPRINTF(10, ("subLibInit: Ok\n"));
2420 KPRINTF(10, ("subLibInit: openCnt = %ld\n", nas->nas_Library.lib_OpenCnt));
2421 return(nas);
2423 else
2425 return(NULL);
2428 return(nas);
2430 AROS_USERFUNC_EXIT
2433 AROS_LH1(SUBLIBBASETYPEPTR, subLibOpen,
2434 AROS_LHA(ULONG, version, D0),
2435 SUBLIBBASETYPEPTR, nas, 1, nep);
2437 AROS_LIBFUNC_INIT
2439 //struct NepAudioBase *nh = nas->nas_ClsBase;
2441 KPRINTF(10, ("subLibOpen base: 0x%08lx\n", nas));
2443 ++nas->nas_Library.lib_OpenCnt;
2444 nas->nas_Library.lib_Flags &= ~LIBF_DELEXP;
2446 KPRINTF(10, ("subLibOpen: openCnt = %ld\n", nas->nas_Library.lib_OpenCnt));
2448 return(nas);
2450 AROS_LIBFUNC_EXIT
2453 AROS_LH0(BPTR, subLibClose,
2454 SUBLIBBASETYPEPTR, nas, 2, nep);
2456 AROS_LIBFUNC_INIT
2458 BPTR ret;
2460 KPRINTF(10, ("subLibClose base: 0x%08lx\n", nas));
2462 ret = BNULL;
2464 if(--nas->nas_Library.lib_OpenCnt == 0)
2466 if(nas->nas_Library.lib_Flags & LIBF_DELEXP)
2468 KPRINTF(5, ("subLibClose: calling expunge...\n"));
2469 ret = AROS_LC1(BPTR, subLibExpunge,
2470 AROS_LCA(SUBLIBBASETYPEPTR, nas, D0),
2471 SUBLIBBASETYPEPTR, nas, 3, dev);
2475 KPRINTF(5, ("subLibClose: lib_OpenCnt = %ld\n", nas->nas_Library.lib_OpenCnt));
2477 return(ret);
2479 AROS_LIBFUNC_EXIT
2482 AROS_LH1(BPTR, subLibExpunge,
2483 AROS_LHA(SUBLIBBASETYPEPTR, extralh, D0),
2484 SUBLIBBASETYPEPTR, nas, 3, nep)
2486 AROS_LIBFUNC_INIT
2488 BPTR ret;
2490 KPRINTF(10, ("subLibExpunge base: 0x%08lx\n", nas));
2492 ret = BNULL;
2494 if(nas->nas_Library.lib_OpenCnt == 0)
2496 KPRINTF(5, ("subLibExpunge: Unloading...\n"));
2498 CloseLibrary(nas->nas_UtilityBase);
2500 ret = nas->nas_SegList;
2502 KPRINTF(5, ("subLibExpunge: removing library node 0x%08lx\n",
2503 &nas->nas_Library.lib_Node));
2504 Remove(&nas->nas_Library.lib_Node);
2506 KPRINTF(5, ("subLibExpunge: FreeMem()...\n"));
2507 FreeMem((char *) nas - nas->nas_Library.lib_NegSize,
2508 (ULONG) (nas->nas_Library.lib_NegSize + nas->nas_Library.lib_PosSize));
2510 KPRINTF(5, ("subLibExpunge: Unloading done! usbaudio.audio expunged!\n\n"));
2512 return(ret);
2514 else
2516 KPRINTF(5, ("subLibExpunge: Could not expunge, LIBF_DELEXP set!\n"));
2517 nas->nas_Library.lib_Flags |= LIBF_DELEXP;
2520 return(BNULL);
2522 AROS_LIBFUNC_EXIT
2525 AROS_LH0(SUBLIBBASETYPEPTR, subLibReserved,
2526 SUBLIBBASETYPEPTR, nas, 4, nep)
2528 AROS_LIBFUNC_INIT
2529 return NULL;
2530 AROS_LIBFUNC_EXIT
2532 /* \\\ */
2534 /* /// "subLibPlayerIntV4()" */
2535 AROS_INTH1(subLibPlayerIntV4, struct NepAudioMode *, nam)
2537 AROS_INTFUNC_INIT
2539 struct NepAudioSubLibBase *nas = nam->nam_SubLibBase;
2540 struct AHIAudioCtrlDrv *audioctrl = nam->nam_AudioCtrl;
2541 UWORD bufnum = nam->nam_NextBufW;
2543 CallHookPkt(audioctrl->ahiac_PlayerFunc, nam->nam_AudioCtrl, NULL);
2544 //KPRINTF(1, ("%ld F, %ld sam\n", nam->nam_PlayerMS, cnt));
2545 if(!nam->nam_Unit->nch_DenyRequests)
2547 CallHookPkt(audioctrl->ahiac_MixerFunc, nam->nam_AudioCtrl, nam->nam_AHIBuffer);
2548 CallHookPkt(&nam->nam_SamConvHook, nam->nam_USBBuffer[bufnum], (APTR) (IPTR) nam->nam_AudioCtrl->ahiac_BuffSamples);
2549 nam->nam_NextBufR = bufnum;
2550 nam->nam_NextBufW = 1 - bufnum;
2553 return FALSE;
2555 AROS_INTFUNC_EXIT
2557 /* \\\ */
2559 /* /// "subLibPlayerIntV6()" */
2560 AROS_INTH1(subLibPlayerIntV6, struct NepAudioMode *, nam)
2562 AROS_INTFUNC_INIT
2564 struct NepAudioSubLibBase *nas = nam->nam_SubLibBase;
2565 struct AHIAudioCtrlDrv *audioctrl = nam->nam_AudioCtrl;
2566 UWORD bufnum = nam->nam_NextBufW;
2567 BOOL skipit;
2569 CallHookPkt(audioctrl->ahiac_PlayerFunc, nam->nam_AudioCtrl, NULL);
2570 skipit = CallHookPkt(audioctrl->ahiac_PreTimerFunc, nam->nam_AudioCtrl, NULL);
2571 //KPRINTF(1, ("%ld F, %ld sam\n", nam->nam_PlayerMS, cnt));
2572 if(!(skipit || nam->nam_Unit->nch_DenyRequests))
2574 CallHookPkt(audioctrl->ahiac_MixerFunc, nam->nam_AudioCtrl, nam->nam_AHIBuffer);
2575 CallHookPkt(&nam->nam_SamConvHook, nam->nam_USBBuffer[bufnum], (APTR) (IPTR) nam->nam_AudioCtrl->ahiac_BuffSamples);
2576 nam->nam_NextBufR = bufnum;
2577 nam->nam_NextBufW = 1 - bufnum;
2579 CallHookPkt(audioctrl->ahiac_PostTimerFunc, nam->nam_AudioCtrl, NULL);
2581 return FALSE;
2583 AROS_INTFUNC_EXIT
2585 /* \\\ */
2587 /* /// "subLibPlayerIntDummy()" */
2588 AROS_INTH1(subLibPlayerIntDummy, struct NepAudioMode *, nam)
2590 AROS_INTFUNC_INIT
2592 struct NepAudioSubLibBase *nas = nam->nam_SubLibBase;
2593 struct AHIAudioCtrlDrv *audioctrl = nam->nam_AudioCtrl;
2595 CallHookPkt(audioctrl->ahiac_PlayerFunc, nam->nam_AudioCtrl, NULL);
2596 CallHookPkt(audioctrl->ahiac_MixerFunc, nam->nam_AudioCtrl, nam->nam_AHIBuffer);
2598 nam->nam_TimerIOReq->tr_node.io_Command = TR_ADDREQUEST;
2599 nam->nam_TimerIOReq->tr_time.tv_secs = 0;
2600 nam->nam_TimerIOReq->tr_time.tv_micro = 1000000 / (audioctrl->ahiac_PlayerFreq>>16);
2601 SendIO((struct IORequest *) nam->nam_TimerIOReq);
2603 return FALSE;
2605 AROS_INTFUNC_EXIT
2607 /* \\\ */
2609 /* /// "nOutReqHook()" */
2611 AROS_UFH3(void, nOutReqHook,
2612 AROS_UFHA(struct Hook *, hook, A0),
2613 AROS_UFHA(struct IOUsbHWRTIso *, urti, A2),
2614 AROS_UFHA(struct IOUsbHWBufferReq *, ubr, A1))
2616 AROS_USERFUNC_INIT
2618 struct NepAudioMode *nam = (struct NepAudioMode *) hook->h_Data;
2620 nam->nam_PlayerTimer -= nam->nam_Interval;
2621 if(nam->nam_PlayerTimer < 0)
2623 UWORD bufnum = nam->nam_NextBufW;
2624 Fixed cnt = nam->nam_USBBufCnt[bufnum];
2626 nam->nam_PlayerInterval &= 0xffff;
2627 nam->nam_PlayerInterval += nam->nam_PlayerFrac;
2628 nam->nam_PlayerMS = nam->nam_PlayerInterval>>16;
2629 nam->nam_PlayerTimer += nam->nam_PlayerMS;
2631 // calc number of samples to mix
2632 cnt += nam->nam_SampleFrac * nam->nam_PlayerMS;
2633 nam->nam_USBBufCnt[1 - bufnum] = cnt & 0xffff; // start of buffer count for next buffer
2634 cnt >>= 16;
2635 nam->nam_AudioCtrl->ahiac_BuffSamples = cnt;
2636 nam->nam_USBBufLen[bufnum] = cnt * nam->nam_FrameSize;
2638 Cause(&nam->nam_PlayerInt);
2639 /*if(nam->nam_USBCount)
2641 KPRINTF(200, ("narf %ld - %ld, %lx, %lx %ld!\n", nam->nam_USBCount, ubr->ubr_Length, nam->nam_PlayerInterval, nam->nam_BufferCount, nam->nam_PlayerTimer));
2643 nam->nam_USBCount = 0;
2644 //KPRINTF(1, ("NT %ld\n", nam->nam_PlayerTimer));
2646 if(nam->nam_Unit->nch_DenyRequests)
2648 ubr->ubr_Length = 0;
2649 return;
2652 if(nam->nam_USBCount <= 0)
2654 // switching is done via Mixer Int
2655 // ubr_Buffer automatically increases
2656 ubr->ubr_Buffer = (UBYTE *) nam->nam_USBBuffer[nam->nam_NextBufR];
2657 nam->nam_BufferCount = nam->nam_USBBufCnt[nam->nam_NextBufR];
2658 nam->nam_USBCount = nam->nam_USBBufLen[nam->nam_NextBufR];
2660 nam->nam_BufferCount &= 0xffff;
2661 nam->nam_BufferCount += nam->nam_SampleFrac;
2662 ubr->ubr_Length = (nam->nam_BufferCount>>16) * nam->nam_FrameSize;
2663 nam->nam_USBCount -= ubr->ubr_Length;
2665 AROS_USERFUNC_EXIT
2667 /* \\\ */
2669 /* /// "nInReqHook()" */
2670 AROS_UFH3(void, nInReqHook,
2671 AROS_UFHA(struct Hook *, hook, A0),
2672 AROS_UFHA(struct IOUsbHWRTIso *, urti, A2),
2673 AROS_UFHA(struct IOUsbHWBufferReq *, ubr, A1))
2675 AROS_USERFUNC_INIT
2677 struct NepAudioMode *nam = (struct NepAudioMode *) hook->h_Data;
2678 //struct NepAudioSubLibBase *nas = nam->nam_SubLibBase;
2680 //KPRINTF(1, ("IR %ld\n", ubr->ubr_Length));
2681 ubr->ubr_Buffer = (UBYTE *) nam->nam_USBBuffer[0];
2683 AROS_USERFUNC_EXIT
2685 /* \\\ */
2687 /* /// "nInDoneHook()" */
2688 AROS_UFH3(void, nInDoneHook,
2689 AROS_UFHA(struct Hook *, hook, A0),
2690 AROS_UFHA(struct IOUsbHWRTIso *, urti, A2),
2691 AROS_UFHA(struct IOUsbHWBufferReq *, ubr, A1))
2693 AROS_USERFUNC_INIT
2695 struct NepAudioMode *nam = (struct NepAudioMode *) hook->h_Data;
2696 struct NepAudioSubLibBase *nas = nam->nam_SubLibBase;
2698 ULONG cnt = ubr->ubr_Length;
2700 //KPRINTF(1, ("ID %ld\n", cnt));
2701 if(cnt < nam->nam_FrameSize)
2703 return;
2705 switch(nam->nam_FrameSize)
2707 case 2:
2708 cnt >>= 1;
2709 break;
2711 case 3:
2712 cnt /= 3;
2714 case 4:
2715 cnt >>= 2;
2716 break;
2718 case 6:
2719 cnt /= 6;
2720 break;
2722 case 8:
2723 cnt >>= 3;
2724 break;
2726 // target format is always 16 bit stereo
2727 nam->nam_RecMsg.ahirm_Type = AHIST_S16S;
2728 nam->nam_RecMsg.ahirm_Buffer = nam->nam_AHIBuffer;
2729 nam->nam_RecMsg.ahirm_Length = cnt;
2730 CallHookPkt(&nam->nam_SamConvHook, nam->nam_AHIBuffer, (APTR) (IPTR) cnt);
2732 CallHookPkt(nam->nam_AudioCtrl->ahiac_SamplerFunc, nam->nam_AudioCtrl, &nam->nam_RecMsg);
2734 AROS_USERFUNC_EXIT
2736 /* \\\ */
2738 /* /// "nReleaseHook()" */
2739 AROS_UFH3(void, nReleaseHook,
2740 AROS_UFHA(struct Hook *, hook, A0),
2741 AROS_UFHA(APTR, prt, A2),
2742 AROS_UFHA(APTR, unused, A1))
2744 AROS_USERFUNC_INIT
2746 struct NepAudioMode *nam = (struct NepAudioMode *) hook->h_Data;
2747 struct NepClassAudio *nch = nam->nam_Unit;
2749 psdStopRTIso(nam->nam_RTIso);
2750 if(nam->nam_IsInput)
2752 // we can only stop recording, we still need to call the player func until audio is done
2753 psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, "Violently stopped recording!");
2754 } else {
2755 nam->nam_PlayerInt.is_Code = (VOID_FUNC)subLibPlayerIntDummy;
2756 // start timer device
2757 nam->nam_FallbackTimer = TRUE;
2758 Cause(&nam->nam_PlayerInt);
2760 nch->nch_DenyRequests = TRUE;
2761 psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname,
2762 "Removing the soundcard while playing is not very bright!");
2764 AROS_USERFUNC_EXIT
2767 /* \\\ */
2769 /* /// "nConv8BitMono()" */
2770 AROS_UFH3(void, nConv8BitMono,
2771 AROS_UFPA(struct Hook *, hook, A0),
2772 AROS_UFPA(BYTE *, btarptr, A2),
2773 AROS_UFPA(ULONG, cnt, A1))
2775 AROS_USERFUNC_INIT
2777 WORD *srcptr = hook->h_Data;
2780 *btarptr++ = *((BYTE *) srcptr);
2781 srcptr++;
2782 } while(--cnt);
2784 AROS_USERFUNC_EXIT
2786 /* \\\ */
2788 /* /// "nConv8BitStereo()" */
2789 AROS_UFH3(void, nConv8BitStereo,
2790 AROS_UFPA(struct Hook *, hook, A0),
2791 AROS_UFPA(BYTE *, btarptr, A2),
2792 AROS_UFPA(ULONG, cnt, A1))
2794 AROS_USERFUNC_INIT
2796 WORD *srcptr = hook->h_Data;
2799 *btarptr++ = *((BYTE *) srcptr);
2800 srcptr++;
2801 *btarptr++ = *((BYTE *) srcptr);
2802 srcptr++;
2803 } while(--cnt);
2805 AROS_USERFUNC_EXIT
2807 /* \\\ */
2809 /* /// "nConv16BitMono()" */
2810 AROS_UFH3(void, nConv16BitMono,
2811 AROS_UFPA(struct Hook *, hook, A0),
2812 AROS_UFPA(UWORD *, wtarptr, A2),
2813 AROS_UFPA(ULONG, cnt, A1))
2815 AROS_USERFUNC_INIT
2817 UWORD *srcptr = hook->h_Data;
2820 *wtarptr++ = AROS_WORD2LE(*srcptr);
2821 srcptr++;
2822 } while(--cnt);
2824 AROS_USERFUNC_EXIT
2826 /* \\\ */
2828 /* /// "nConv16BitStereo()" */
2829 AROS_UFH3(void, nConv16BitStereo,
2830 AROS_UFPA(struct Hook *, hook, A0),
2831 AROS_UFPA(ULONG *, ltarptr, A2),
2832 AROS_UFPA(ULONG, cnt, A1))
2834 AROS_USERFUNC_INIT
2836 ULONG *lsrcptr = hook->h_Data;
2839 *ltarptr++ = ((*lsrcptr>>8) & 0x00ff00ff)|((*lsrcptr<<8) & 0xff00ff00);
2840 lsrcptr++;
2841 } while(--cnt);
2843 AROS_USERFUNC_EXIT
2845 /* \\\ */
2847 /* /// "nConv24BitMono()" */
2848 AROS_UFH3(void, nConv24BitMono,
2849 AROS_UFPA(struct Hook *, hook, A0),
2850 AROS_UFPA(UBYTE *, btarptr, A2),
2851 AROS_UFPA(ULONG, cnt, A1))
2853 AROS_USERFUNC_INIT
2855 ULONG *lsrcptr = hook->h_Data;
2856 ULONG tmp;
2859 tmp = *lsrcptr++;
2860 tmp >>= 8;
2861 *btarptr++ = tmp;
2862 tmp >>= 8;
2863 *btarptr++ = tmp;
2864 tmp >>= 8;
2865 *btarptr++ = tmp;
2866 } while(--cnt);
2868 AROS_USERFUNC_EXIT
2870 /* \\\ */
2872 /* /// "nConv24BitStereo()" */
2873 AROS_UFH3(void, nConv24BitStereo,
2874 AROS_UFPA(struct Hook *, hook, A0),
2875 AROS_UFPA(UBYTE *, btarptr, A2),
2876 AROS_UFPA(ULONG, cnt, A1))
2878 AROS_USERFUNC_INIT
2880 ULONG *lsrcptr = hook->h_Data;
2881 ULONG tmp;
2884 tmp = *lsrcptr++;
2885 tmp >>= 8;
2886 *btarptr++ = tmp;
2887 tmp >>= 8;
2888 *btarptr++ = tmp;
2889 tmp >>= 8;
2890 *btarptr++ = tmp;
2891 tmp = *lsrcptr++;
2892 tmp >>= 8;
2893 *btarptr++ = tmp;
2894 tmp >>= 8;
2895 *btarptr++ = tmp;
2896 tmp >>= 8;
2897 *btarptr++ = tmp;
2898 } while(--cnt);
2900 AROS_USERFUNC_EXIT
2902 /* \\\ */
2904 /* /// "nConv32BitMono()" */
2905 AROS_UFH3(void, nConv32BitMono,
2906 AROS_UFPA(struct Hook *, hook, A0),
2907 AROS_UFPA(ULONG *, ltarptr, A2),
2908 AROS_UFPA(ULONG, cnt, A1))
2910 AROS_USERFUNC_INIT
2912 UBYTE *bsrcptr = hook->h_Data;
2913 register ULONG tmp;
2916 tmp = *bsrcptr++;
2917 tmp |= (*bsrcptr++)<<8;
2918 tmp |= (*bsrcptr++)<<16;
2919 tmp |= (*bsrcptr++)<<24;
2920 *ltarptr++ = tmp;
2921 } while(--cnt);
2923 AROS_USERFUNC_EXIT
2925 /* \\\ */
2927 /* /// "nConv32BitStereo()" */
2928 AROS_UFH3(void, nConv32BitStereo,
2929 AROS_UFPA(struct Hook *, hook, A0),
2930 AROS_UFPA(ULONG *, ltarptr, A2),
2931 AROS_UFPA(ULONG, cnt, A1))
2933 AROS_USERFUNC_INIT
2935 UBYTE *bsrcptr = hook->h_Data;
2936 register ULONG tmp;
2939 tmp = *bsrcptr++;
2940 tmp |= (*bsrcptr++)<<8;
2941 tmp |= (*bsrcptr++)<<16;
2942 tmp |= (*bsrcptr++)<<24;
2943 *ltarptr++ = tmp;
2944 tmp = *bsrcptr++;
2945 tmp |= (*bsrcptr++)<<8;
2946 tmp |= (*bsrcptr++)<<16;
2947 tmp |= (*bsrcptr++)<<24;
2948 *ltarptr++ = tmp;
2949 } while(--cnt);
2951 AROS_USERFUNC_EXIT
2953 /* \\\ */
2955 /* /// "nRec8BitMono()" */
2956 AROS_UFH3(void, nRec8BitMono,
2957 AROS_UFPA(struct Hook *, hook, A0),
2958 AROS_UFPA(WORD *, tarptr, A2),
2959 AROS_UFPA(ULONG, cnt, A1))
2961 AROS_USERFUNC_INIT
2963 BYTE *srcptr = hook->h_Data;
2966 *tarptr++ = *srcptr;
2967 *tarptr++ = *srcptr++;
2968 } while(--cnt);
2970 AROS_USERFUNC_EXIT
2972 /* \\\ */
2974 /* /// "nRec8BitStereo()" */
2975 AROS_UFH3(void, nRec8BitStereo,
2976 AROS_UFPA(struct Hook *, hook, A0),
2977 AROS_UFPA(WORD *, tarptr, A2),
2978 AROS_UFPA(ULONG, cnt, A1))
2980 AROS_USERFUNC_INIT
2982 BYTE *srcptr = hook->h_Data;
2985 *tarptr++ = *srcptr++;
2986 *tarptr++ = *srcptr++;
2987 } while(--cnt);
2989 AROS_USERFUNC_EXIT
2991 /* \\\ */
2993 /* /// "nRec16BitMono()" */
2994 AROS_UFH3(void, nRec16BitMono,
2995 AROS_UFPA(struct Hook *, hook, A0),
2996 AROS_UFPA(WORD *, tarptr, A2),
2997 AROS_UFPA(ULONG, cnt, A1))
2999 AROS_USERFUNC_INIT
3001 UWORD *srcptr = hook->h_Data;
3004 WORD src = AROS_WORD2LE(*srcptr);
3005 *tarptr++ = src;
3006 *tarptr++ = src;
3007 srcptr++;
3008 } while(--cnt);
3010 AROS_USERFUNC_EXIT
3012 /* \\\ */
3014 /* /// "nRec16BitStereo()" */
3015 AROS_UFH3(void, nRec16BitStereo,
3016 AROS_UFPA(struct Hook *, hook, A0),
3017 AROS_UFPA(WORD *, tarptr, A2),
3018 AROS_UFPA(ULONG, cnt, A1))
3020 AROS_USERFUNC_INIT
3022 UWORD *srcptr = hook->h_Data;
3025 *tarptr++ = AROS_WORD2LE(*srcptr);
3026 srcptr++;
3027 *tarptr++ = AROS_WORD2LE(*srcptr);
3028 srcptr++;
3029 } while(--cnt);
3031 AROS_USERFUNC_EXIT
3033 /* \\\ */
3035 /* /// "nRec24BitMono()" */
3036 AROS_UFH3(void, nRec24BitMono,
3037 AROS_UFPA(struct Hook *, hook, A0),
3038 AROS_UFPA(WORD *, tarptr, A2),
3039 AROS_UFPA(ULONG, cnt, A1))
3041 AROS_USERFUNC_INIT
3043 UBYTE *srcptr = hook->h_Data;
3044 srcptr++;
3047 UWORD src = *srcptr|(srcptr[1]<<8);
3048 *tarptr++ = src;
3049 *tarptr++ = src;
3050 srcptr += 3;
3051 } while(--cnt);
3053 AROS_USERFUNC_EXIT
3055 /* \\\ */
3057 /* /// "nRec24BitStereo()" */
3058 AROS_UFH3(void, nRec24BitStereo,
3059 AROS_UFPA(struct Hook *, hook, A0),
3060 AROS_UFPA(WORD *, tarptr, A2),
3061 AROS_UFPA(ULONG, cnt, A1))
3063 AROS_USERFUNC_INIT
3065 UBYTE *srcptr = hook->h_Data;
3066 srcptr++;
3069 *tarptr++ = *srcptr|(srcptr[1]<<8);
3070 *tarptr++ = srcptr[3]|(srcptr[4]<<8);
3071 srcptr += 6;
3072 } while(--cnt);
3074 AROS_USERFUNC_EXIT
3076 /* \\\ */
3078 /* /// "nRec32BitMono()" */
3079 AROS_UFH3(void, nRec32BitMono,
3080 AROS_UFPA(struct Hook *, hook, A0),
3081 AROS_UFPA(WORD *, tarptr, A2),
3082 AROS_UFPA(ULONG, cnt, A1))
3084 AROS_USERFUNC_INIT
3086 UWORD *srcptr = hook->h_Data;
3087 srcptr++;
3090 UWORD src = AROS_WORD2LE(*srcptr);
3091 *tarptr++ = src;
3092 *tarptr++ = src;
3093 srcptr += 2;
3094 } while(--cnt);
3096 AROS_USERFUNC_EXIT
3098 /* \\\ */
3100 /* /// "nRec32BitStereo()" */
3101 AROS_UFH3(void, nRec32BitStereo,
3102 AROS_UFPA(struct Hook *, hook, A0),
3103 AROS_UFPA(WORD *, tarptr, A2),
3104 AROS_UFPA(ULONG, cnt, A1))
3106 AROS_USERFUNC_INIT
3108 UWORD *srcptr = hook->h_Data;
3109 srcptr++;
3112 *tarptr++ = AROS_WORD2LE(*srcptr);
3113 srcptr += 2;
3114 *tarptr++ = AROS_WORD2LE(*srcptr);
3115 srcptr += 2;
3116 } while(--cnt);
3118 AROS_USERFUNC_EXIT
3120 /* \\\ */
3122 /* /// "nSelectAudioMode()" */
3123 BOOL nSelectAudioMode(struct NepAudioMode *nam)
3125 struct NepClassAudio *nch = nam->nam_Unit;
3126 UBYTE freqbuf[3];
3127 ULONG freq = nam->nam_AudioCtrl->ahiac_MixFreq;
3128 LONG ioerr;
3129 ULONG maxfreq;
3131 KPRINTF(1, ("SelectingAltInterface\n"));
3132 if(!(psdSetAltInterface(nam->nam_EP0Pipe, nam->nam_Interface)))
3134 psdAddErrorMsg(RETURN_FAIL, (STRPTR) libname, "Cannot select alternate interface!");
3135 return(FALSE);
3137 nam->nam_EP = psdFindEndpoint(nam->nam_Interface, NULL,
3138 EA_IsIn, nam->nam_IsInput,
3139 EA_TransferType, USEAF_ISOCHRONOUS,
3140 TAG_END);
3142 if(!nam->nam_EP)
3144 KPRINTF(1, ("Ooops!?! No Endpoints defined?\n"));
3145 psdAddErrorMsg(RETURN_FAIL, (STRPTR) libname,
3146 "No Iso Endpoint!");
3147 return(FALSE);
3149 psdGetAttrs(PGA_ENDPOINT, nam->nam_EP,
3150 EA_EndpointNum, &nam->nam_EPNum,
3151 EA_MaxPktSize, &nam->nam_MaxPktSize,
3152 EA_Interval, &nam->nam_Interval,
3153 TAG_END);
3155 maxfreq = (1000 * nam->nam_MaxPktSize) / (nam->nam_FrameSize * nam->nam_Interval);
3156 if(maxfreq < nam->nam_MaxFreq)
3158 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
3159 "Maximum frequency was indicated as %ld Hz, but bandwidth-wise, only %ld Hz is possible.",
3160 nam->nam_MaxFreq, maxfreq);
3161 nam->nam_MaxFreq = maxfreq;
3164 if(nam->nam_HasFreqCtrl)
3166 KPRINTF(1, ("Setting frequency\n"));
3167 freqbuf[0] = freq;
3168 freqbuf[1] = (freq>>8);
3169 freqbuf[2] = (freq>>16);
3170 psdPipeSetup(nam->nam_EP0Pipe, URTF_CLASS|URTF_ENDPOINT, UAUDR_SET_CUR, UAECS_SAMPLE_FREQ<<8, nam->nam_EPNum);
3171 ioerr = psdDoPipe(nam->nam_EP0Pipe, freqbuf, 3);
3172 if(ioerr)
3174 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
3175 "Could not set current frequency for EP %ld: %s (%ld)!",
3176 nam->nam_EPNum,
3177 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
3180 if(nam->nam_HasPitchCtrl)
3182 KPRINTF(1, ("Setting pitch control\n"));
3183 freqbuf[0] = 1;
3184 psdPipeSetup(nam->nam_EP0Pipe, URTF_CLASS|URTF_ENDPOINT, UAUDR_SET_CUR, UAECS_PITCH<<8, nam->nam_EPNum);
3185 ioerr = psdDoPipe(nam->nam_EP0Pipe, freqbuf, 1);
3186 if(ioerr)
3188 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
3189 "Could not enable pitch control: %s (%ld)!",
3190 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
3193 nam->nam_ReleaseHook.h_Entry = (HOOKFUNC) nReleaseHook;
3194 nam->nam_ReleaseHook.h_Data = nam;
3196 if(nam->nam_IsInput)
3198 KPRINTF(1, ("Input hook\n"));
3199 nch->nch_InReqHook.h_Entry = (HOOKFUNC) nInReqHook;
3200 nch->nch_InReqHook.h_Data = nam;
3201 nch->nch_InDoneHook.h_Entry = (HOOKFUNC) nInDoneHook;
3202 nch->nch_InDoneHook.h_Data = nam;
3204 nam->nam_RTIso = psdAllocRTIsoHandler(nam->nam_EP,
3205 RTA_InRequestHook, &nch->nch_InReqHook,
3206 RTA_InDoneHook, &nch->nch_InDoneHook,
3207 RTA_ReleaseHook, &nam->nam_ReleaseHook,
3208 TAG_END);
3209 } else {
3210 KPRINTF(1, ("Output hook\n"));
3212 nch->nch_OutReqHook.h_Entry = (HOOKFUNC) nOutReqHook;
3213 nch->nch_OutReqHook.h_Data = nam;
3215 nam->nam_RTIso = psdAllocRTIsoHandler(nam->nam_EP,
3216 RTA_OutRequestHook, &nch->nch_OutReqHook,
3217 RTA_ReleaseHook, &nam->nam_ReleaseHook,
3218 TAG_END);
3220 if(!nam->nam_RTIso)
3222 psdAddErrorMsg(RETURN_FAIL, (STRPTR) libname, "Could not allocate RT Iso Handler!");
3223 return(FALSE);
3225 /*psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_ENDPOINT, UAUDR_SET_CUR, UAECS_SAMPLE_FREQ, nam->nam_EPNum);
3226 freq[0] = 44100 & 0xff;
3227 freq[1] = (44100>>8);
3228 freq[2] = (44100>>16);
3229 ioerr = psdDoPipe(nch->nch_EP0Pipe, freq, 3);
3230 if(ioerr)
3232 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
3233 "Could not set current frequency!");
3235 psdPipeSetup(nch->nch_EP0Pipe, URTF_IN|URTF_CLASS|URTF_ENDPOINT, UAUDR_GET_CUR, UAECS_SAMPLE_FREQ, nam->nam_EPNum);
3236 ioerr = psdDoPipe(nch->nch_EP0Pipe, freq, 3);
3237 if(ioerr)
3239 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
3240 "Could not get current frequency!");
3241 } else {
3242 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
3243 "Current frequency: %ld Hz",
3244 freq[0]|(freq[1]<<8)|(freq[2]<<16));
3247 nch->nch_DenyRequests = FALSE;
3248 return(TRUE);
3250 /* \\\ */
3252 /* /// "subLibAllocAudio()" */
3253 AROS_LH2(ULONG, subLibAllocAudio,
3254 AROS_LHA(struct TagItem *, tags, A1),
3255 AROS_LHA(struct AHIAudioCtrlDrv *, audioctrl, A2),
3256 SUBLIBBASETYPEPTR, nas, 5, nep)
3258 AROS_LIBFUNC_INIT
3260 struct NepAudioMode *nam = (struct NepAudioMode *) GetTagData(AHIDB_NepAudioMode, (IPTR) NULL, tags);
3261 struct NepAudioMode *sibnam;
3262 struct NepClassAudio *nch;
3263 ULONG flags;
3264 UWORD cnt;
3265 STRPTR audiomode;
3267 KPRINTF(10, ("subLibAllocAudio(%08lx)\n", audioctrl));
3268 if(!nam)
3270 KPRINTF(20, ("Could not find NepAudioMode in GetAttr call!\n"));
3271 audioctrl->ahiac_DriverData = NULL;
3272 return AHISF_ERROR;
3274 if(nam->nam_RTIso)
3276 KPRINTF(20, ("Already in use!\n"));
3277 return AHISF_ERROR;
3279 audioctrl->ahiac_DriverData = nam;
3280 nam->nam_AudioCtrl = audioctrl;
3281 if(!(nam->nam_PsdBase = OpenLibrary("poseidon.library", 4)))
3283 return AHISF_ERROR;
3286 nam->nam_FallbackTimer = FALSE;
3287 nam->nam_TimerMsgPort.mp_Node.ln_Type = NT_MSGPORT;
3288 nam->nam_TimerMsgPort.mp_Flags = PA_SOFTINT;
3289 nam->nam_TimerMsgPort.mp_SigTask = &nam->nam_PlayerInt;
3290 NewList(&nam->nam_TimerMsgPort.mp_MsgList);
3291 if((nam->nam_TimerIOReq = (struct timerequest *) CreateIORequest(&nam->nam_TimerMsgPort, sizeof(struct timerequest))))
3293 if(!OpenDevice("timer.device", UNIT_MICROHZ, (struct IORequest *) nam->nam_TimerIOReq, 0))
3295 nam->nam_TimerIOReq->tr_node.io_Message.mn_Node.ln_Type = NT_FREEMSG;
3296 } else {
3297 DeleteIORequest((struct IORequest *) nam->nam_TimerIOReq);
3298 nam->nam_TimerIOReq = NULL;
3299 return AHISF_ERROR;
3301 } else {
3302 return AHISF_ERROR;
3305 nch = nam->nam_Unit;
3306 KPRINTF(10, ("CreateMsgPort\n"));
3307 if(!(nam->nam_TaskMsgPort = CreateMsgPort()))
3309 return AHISF_ERROR;
3311 KPRINTF(10, ("AllocPipe\n"));
3312 if(!(nam->nam_EP0Pipe = psdAllocPipe(nch->nch_Device, nam->nam_TaskMsgPort, NULL)))
3314 return AHISF_ERROR;
3316 KPRINTF(10, ("SelectAudioMode\n"));
3317 if(!(nSelectAudioMode(nam)))
3319 return AHISF_ERROR;
3321 nch->nch_CurrentMode = nam;
3323 flags = AHISF_MIXING;
3324 if(nam->nam_NumChannels > 1)
3326 flags |= AHISF_KNOWSTEREO;
3328 if(nam->nam_Resolution > 16)
3330 flags |= AHISF_KNOWHIFI;
3332 KPRINTF(10, ("Freq=%ld, BuffSamples = %ld, BuffSize = %ld\n",
3333 audioctrl->ahiac_MixFreq, audioctrl->ahiac_BuffSamples, audioctrl->ahiac_BuffSize));
3334 KPRINTF(10, ("NumChan=%ld, Sounds=%ld, BuffType=%04lx\n",
3335 audioctrl->ahiac_Channels, audioctrl->ahiac_Sounds, audioctrl->ahiac_BuffType));
3336 KPRINTF(10, ("MinPlayerFreq=%08lx, MaxPlayerFreq=%08lx\n",
3337 audioctrl->ahiac_MinPlayerFreq, audioctrl->ahiac_MaxPlayerFreq));
3339 if(audioctrl->ahiac_PlayerFreq < 0x10000)
3341 audioctrl->ahiac_PlayerFreq <<= 16;
3344 if(audioctrl->ahiac_MinPlayerFreq < 0x10000)
3346 audioctrl->ahiac_MinPlayerFreq <<= 16;
3348 if(audioctrl->ahiac_MinPlayerFreq < 10<<16)
3350 // 100ms intervals max
3351 audioctrl->ahiac_MinPlayerFreq = 10<<16;
3354 if(audioctrl->ahiac_MaxPlayerFreq < 0x10000)
3356 audioctrl->ahiac_MaxPlayerFreq <<= 16;
3359 audioctrl->ahiac_Channels = nam->nam_NumChannels;
3360 /*audioctrl->ahiac_BuffType = nam->nam_SampleType; */
3362 for(cnt = 0; cnt < nam->nam_NumFrequencies; cnt++)
3364 if(audioctrl->ahiac_MixFreq == nam->nam_FreqArray[cnt])
3366 break;
3369 if(cnt == nam->nam_NumFrequencies)
3371 // need rate adaption
3372 ULONG target = audioctrl->ahiac_MixFreq;
3373 ULONG diff = 100000;
3374 for(cnt = 0; cnt < nam->nam_NumFrequencies; cnt++)
3376 if(nam->nam_FreqArray[cnt] > target)
3378 if(nam->nam_FreqArray[cnt] - target < diff)
3380 diff = nam->nam_FreqArray[cnt] - target;
3381 audioctrl->ahiac_MixFreq = nam->nam_FreqArray[cnt];
3383 } else {
3384 if(target - nam->nam_FreqArray[cnt] < diff)
3386 diff = target - nam->nam_FreqArray[cnt];
3387 audioctrl->ahiac_MixFreq = nam->nam_FreqArray[cnt];
3393 // buffer for 100 ms max
3394 audioctrl->ahiac_BuffSamples = (audioctrl->ahiac_MixFreq * nam->nam_Interval) / 10;
3395 audioctrl->ahiac_BuffSize = audioctrl->ahiac_BuffSamples * nam->nam_AHIFrameSize;
3397 nam->nam_AHIBuffer = psdAllocVec(audioctrl->ahiac_BuffSize);
3398 nam->nam_USBBuffer[0] = psdAllocVec(audioctrl->ahiac_BuffSamples * nam->nam_FrameSize);
3399 nam->nam_USBBuffer[1] = psdAllocVec(audioctrl->ahiac_BuffSamples * nam->nam_FrameSize);
3400 if(!(nam->nam_AHIBuffer && nam->nam_USBBuffer[0] && nam->nam_USBBuffer[1]))
3402 return AHISF_ERROR;
3405 // make sure to play silence, if CPU is too slow on first frame
3406 nam->nam_NextBufR = 1;
3407 nam->nam_NextBufW = 0;
3408 nam->nam_BufferCount = 0;
3409 nam->nam_PlayerTimer = 0;
3410 nam->nam_USBCount = 0;
3411 nam->nam_USBBufLen[0] = 0;
3412 nam->nam_USBBufLen[1] = 0;
3414 nam->nam_MasterVol = 0x00010000;
3415 nam->nam_ChannelVol[0] = 0x00010000;
3416 nam->nam_ChannelVol[1] = 0x00010000;
3417 nam->nam_InputGain = 0x00010000;
3418 nam->nam_MonitorVol = 0x00010000;
3420 KPRINTF(10, ("Freq=%ld, BuffSamples = %ld, BuffSize = %ld\n",
3421 audioctrl->ahiac_MixFreq, audioctrl->ahiac_BuffSamples, audioctrl->ahiac_BuffSize));
3423 nam->nam_PlayerInt.is_Node.ln_Type = NT_INTERRUPT;
3424 nam->nam_PlayerInt.is_Node.ln_Name = "Player Interrupt";
3425 nam->nam_PlayerInt.is_Node.ln_Pri = 0;
3426 nam->nam_PlayerInt.is_Data = nam;
3427 if(nam->nam_Unit->nch_AHIBase->lib_Version < 6)
3429 KPRINTF(10, ("Using V4 code\n"));
3430 nam->nam_PlayerInt.is_Code = (VOID_FUNC) subLibPlayerIntV4;
3431 } else {
3432 KPRINTF(10, ("Using V6 code\n"));
3433 nam->nam_PlayerInt.is_Code = (VOID_FUNC) subLibPlayerIntV6;
3435 nam->nam_SamConvHook.h_Data = nam->nam_AHIBuffer;
3437 switch(nam->nam_NumChannels|(nam->nam_SampleSize<<8))
3439 case 1|(1<<8): // 8 bit mono
3440 nam->nam_SamConvHook.h_Entry = (APTR) nConv8BitMono;
3441 break;
3443 case 2|(1<<8): // 8 bit stereo
3444 nam->nam_SamConvHook.h_Entry = (APTR) nConv8BitStereo;
3445 break;
3447 case 1|(2<<8): // 16 bit mono
3448 nam->nam_SamConvHook.h_Entry = (APTR) nConv16BitMono;
3449 break;
3451 case 2|(2<<8): // 16 bit stereo
3452 nam->nam_SamConvHook.h_Entry = (APTR) nConv16BitStereo;
3453 break;
3455 case 1|(3<<8): // 24 bit mono
3456 nam->nam_SamConvHook.h_Entry = (APTR) nConv24BitMono;
3457 break;
3459 case 2|(3<<8): // 24 bit stereo
3460 nam->nam_SamConvHook.h_Entry = (APTR) nConv24BitStereo;
3461 break;
3463 case 1|(4<<8): // 32 bit mono
3464 nam->nam_SamConvHook.h_Entry = (APTR) nConv32BitMono;
3465 break;
3467 case 2|(4<<8): // 32 bit stereo
3468 nam->nam_SamConvHook.h_Entry = (APTR) nConv32BitStereo;
3469 break;
3471 default:
3472 KPRINTF(10, ("Unknown sample format\n"));
3473 return AHISF_ERROR;
3476 if((sibnam = nam->nam_Sibling))
3478 sibnam->nam_PsdBase = nam->nam_PsdBase;
3479 sibnam->nam_AudioCtrl = audioctrl;
3480 if(!(sibnam->nam_TaskMsgPort = CreateMsgPort()))
3482 return AHISF_ERROR;
3484 if(!(sibnam->nam_EP0Pipe = psdAllocPipe(nch->nch_Device, sibnam->nam_TaskMsgPort, NULL)))
3486 return AHISF_ERROR;
3488 if(!(nSelectAudioMode(sibnam)))
3490 return AHISF_ERROR;
3492 sibnam->nam_AHIBuffer = psdAllocVec(audioctrl->ahiac_BuffSize);
3493 sibnam->nam_USBBuffer[0] = psdAllocVec(audioctrl->ahiac_BuffSamples * sibnam->nam_FrameSize);
3494 if(!(sibnam->nam_AHIBuffer && sibnam->nam_USBBuffer[0]))
3496 return AHISF_ERROR;
3498 sibnam->nam_SamConvHook.h_Data = sibnam->nam_USBBuffer[0];
3500 switch(sibnam->nam_NumChannels|(sibnam->nam_SampleSize<<8))
3502 case 1|(1<<8): // 8 bit mono
3503 sibnam->nam_SamConvHook.h_Entry = (APTR) nRec8BitMono;
3504 break;
3506 case 2|(1<<8): // 8 bit stereo
3507 sibnam->nam_SamConvHook.h_Entry = (APTR) nRec8BitStereo;
3508 break;
3510 case 1|(2<<8): // 16 bit mono
3511 sibnam->nam_SamConvHook.h_Entry = (APTR) nRec16BitMono;
3512 break;
3514 case 2|(2<<8): // 16 bit stereo
3515 sibnam->nam_SamConvHook.h_Entry = (APTR) nRec16BitStereo;
3516 break;
3518 case 1|(3<<8): // 24 bit mono
3519 sibnam->nam_SamConvHook.h_Entry = (APTR) nRec24BitMono;
3520 break;
3522 case 2|(3<<8): // 24 bit stereo
3523 sibnam->nam_SamConvHook.h_Entry = (APTR) nRec24BitStereo;
3524 break;
3526 case 1|(4<<8): // 32 bit mono
3527 sibnam->nam_SamConvHook.h_Entry = (APTR) nRec32BitMono;
3528 break;
3530 case 2|(4<<8): // 32 bit stereo
3531 sibnam->nam_SamConvHook.h_Entry = (APTR) nRec32BitStereo;
3532 break;
3534 default:
3535 KPRINTF(10, ("Unknown sample format\n"));
3536 return AHISF_ERROR;
3539 flags |= AHISF_CANRECORD;
3540 audiomode = "Full-Duplex";
3541 } else {
3542 audiomode = "Output-only";
3544 psdAddErrorMsg(RETURN_OK, (STRPTR) libname, "Opening %s audio mode at %ld Hz with %ld channel%s and %ld bits each.",
3545 audiomode,
3546 audioctrl->ahiac_MixFreq,
3547 nam->nam_NumChannels,
3548 (nam->nam_NumChannels > 1) ? "s" : "",
3549 nam->nam_Resolution);
3551 return flags;
3553 AROS_LIBFUNC_EXIT
3555 /* \\\ */
3557 /* /// "subLibFreeAudio()" */
3558 AROS_LH1(void, subLibFreeAudio,
3559 AROS_LHA(struct AHIAudioCtrlDrv *, audioctrl, A2),
3560 SUBLIBBASETYPEPTR, nas, 6, nep)
3562 AROS_LIBFUNC_INIT
3564 struct NepAudioMode *nam = (struct NepAudioMode *) audioctrl->ahiac_DriverData;
3565 struct NepAudioMode *sibnam;
3567 KPRINTF(10, ("subLibFreeAudio(%08lx)\n", audioctrl));
3568 if(!nam)
3570 return;
3572 if(!nam->nam_PsdBase)
3574 return;
3576 nam->nam_Unit->nch_CurrentMode = NULL;
3577 if((sibnam = nam->nam_Sibling))
3579 if(sibnam->nam_RTIso)
3581 psdStopRTIso(sibnam->nam_RTIso);
3582 psdFreeRTIsoHandler(sibnam->nam_RTIso);
3583 sibnam->nam_RTIso = NULL;
3586 psdFreeVec(sibnam->nam_AHIBuffer);
3587 sibnam->nam_AHIBuffer = NULL;
3588 psdFreeVec(sibnam->nam_USBBuffer[0]);
3589 sibnam->nam_USBBuffer[0] = NULL;
3591 if(sibnam->nam_ZeroBWIF)
3593 if(!(psdSetAltInterface(sibnam->nam_EP0Pipe, sibnam->nam_ZeroBWIF)))
3595 psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, "Cannot restore zero bandwidth interface!");
3598 if(sibnam->nam_EP0Pipe)
3600 psdFreePipe(sibnam->nam_EP0Pipe);
3601 sibnam->nam_EP0Pipe = NULL;
3603 DeleteMsgPort(sibnam->nam_TaskMsgPort);
3604 sibnam->nam_TaskMsgPort = NULL;
3605 sibnam->nam_PsdBase = NULL;
3607 if(nam->nam_FallbackTimer)
3609 nam->nam_TimerMsgPort.mp_Flags = PA_IGNORE;
3610 AbortIO((struct IORequest *) nam->nam_TimerIOReq);
3611 WaitIO((struct IORequest *) nam->nam_TimerIOReq);
3613 if(nam->nam_RTIso)
3615 psdStopRTIso(nam->nam_RTIso);
3616 psdFreeRTIsoHandler(nam->nam_RTIso);
3617 nam->nam_RTIso = NULL;
3620 psdFreeVec(nam->nam_AHIBuffer);
3621 nam->nam_AHIBuffer = NULL;
3622 psdFreeVec(nam->nam_USBBuffer[0]);
3623 nam->nam_USBBuffer[0] = NULL;
3624 psdFreeVec(nam->nam_USBBuffer[1]);
3625 nam->nam_USBBuffer[1] = NULL;
3627 if(nam->nam_ZeroBWIF)
3629 if(!(psdSetAltInterface(nam->nam_EP0Pipe, nam->nam_ZeroBWIF)))
3631 psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, "Cannot restore zero bandwidth interface!");
3635 if(nam->nam_EP0Pipe)
3637 psdFreePipe(nam->nam_EP0Pipe);
3638 nam->nam_EP0Pipe = NULL;
3640 DeleteMsgPort(nam->nam_TaskMsgPort);
3641 nam->nam_TaskMsgPort = NULL;
3643 if(nam->nam_TimerIOReq)
3645 CloseDevice((struct IORequest *) nam->nam_TimerIOReq);
3646 DeleteIORequest((struct IORequest *) nam->nam_TimerIOReq);
3647 nam->nam_TimerIOReq = NULL;
3650 CloseLibrary(nam->nam_PsdBase);
3651 nam->nam_PsdBase = NULL;
3653 AROS_LIBFUNC_EXIT
3655 /* \\\ */
3657 /* /// "subLibDisable()" */
3658 AROS_LH1(void, subLibDisable,
3659 AROS_LHA(struct AHIAudioCtrlDrv *, audioctrl, A2),
3660 SUBLIBBASETYPEPTR, nas, 7, nep)
3662 AROS_LIBFUNC_INIT
3663 //KPRINTF(10, ("subLibDisable(%08lx)\n", audioctrl));
3664 AROS_LIBFUNC_EXIT
3666 /* \\\ */
3668 /* /// "subLibEnable()" */
3669 AROS_LH1(void, subLibEnable,
3670 AROS_LHA(struct AHIAudioCtrlDrv *, audioctrl, A2),
3671 SUBLIBBASETYPEPTR, nas, 8, nep)
3673 AROS_LIBFUNC_INIT
3674 //KPRINTF(10, ("subLibEnable(%08lx)\n", audioctrl));
3675 AROS_LIBFUNC_EXIT
3677 /* \\\ */
3679 /* /// "subLibStart()" */
3680 AROS_LH2(ULONG, subLibStart,
3681 AROS_LHA(ULONG, flags, D0),
3682 AROS_LHA(struct AHIAudioCtrlDrv *, audioctrl, A2),
3683 SUBLIBBASETYPEPTR, nas, 9, nep)
3685 AROS_LIBFUNC_INIT
3687 struct NepAudioMode *nam = (struct NepAudioMode *) audioctrl->ahiac_DriverData;
3688 ULONG res = AHIE_UNKNOWN;
3690 KPRINTF(10, ("subLibStart(%08lx, %lx)\n", audioctrl, flags));
3691 if(!nam)
3693 return res;
3695 if(flags & AHISF_PLAY)
3697 KPRINTF(10, ("Freq=%ld, BuffSamples = %ld, BuffSize = %ld, PlayerFreq = %08lx\n",
3698 audioctrl->ahiac_MixFreq, audioctrl->ahiac_BuffSamples, audioctrl->ahiac_BuffSize,
3699 audioctrl->ahiac_PlayerFreq));
3700 KPRINTF(10, ("NumChan=%ld, Sounds=%ld, BuffType=%04lx\n",
3701 audioctrl->ahiac_Channels, audioctrl->ahiac_Sounds, audioctrl->ahiac_BuffType));
3702 KPRINTF(10, ("MinPlayerFreq=%08lx, MaxPlayerFreq=%08lx\n",
3703 audioctrl->ahiac_MinPlayerFreq, audioctrl->ahiac_MaxPlayerFreq));
3704 if(nam->nam_AudioCtrl->ahiac_PlayerFreq < 0x10000)
3706 nam->nam_AudioCtrl->ahiac_PlayerFreq <<= 16;
3708 nam->nam_PlayerFrac = (1000UL<<20) / (nam->nam_AudioCtrl->ahiac_PlayerFreq>>12);
3709 KPRINTF(10, ("Player Frac = %08lx\n", nam->nam_PlayerFrac));
3710 nam->nam_SampleFrac = (((audioctrl->ahiac_MixFreq<<16)) / 1000) * nam->nam_Interval;
3711 if(nam->nam_FallbackTimer)
3713 nam->nam_TimerMsgPort.mp_Flags = PA_SOFTINT;
3714 Cause(&nam->nam_PlayerInt);
3715 } else {
3716 psdStartRTIso(nam->nam_RTIso);
3718 res = AHIE_OK;
3720 if(flags & AHISF_RECORD)
3722 struct NepAudioMode *sibnam = nam->nam_Sibling;
3723 if(sibnam)
3725 sibnam->nam_SampleFrac = ((audioctrl->ahiac_MixFreq<<16) / 1000) * sibnam->nam_Interval;
3726 psdStartRTIso(sibnam->nam_RTIso);
3727 res = AHIE_OK;
3728 } else {
3729 res = AHIE_UNKNOWN;
3732 return res;
3734 AROS_LIBFUNC_EXIT
3736 /* \\\ */
3738 /* /// "subLibUpdate()" */
3739 AROS_LH2(ULONG, subLibUpdate,
3740 AROS_LHA(ULONG, flags, D0),
3741 AROS_LHA(struct AHIAudioCtrlDrv *, audioctrl, A2),
3742 SUBLIBBASETYPEPTR, nas, 10, nep)
3744 AROS_LIBFUNC_INIT
3746 struct NepAudioMode *nam = (struct NepAudioMode *) audioctrl->ahiac_DriverData;
3747 KPRINTF(10, ("subLibUpdate(%08lx, %lx)\n", audioctrl, flags));
3749 if(!nam)
3751 return AHIE_UNKNOWN;
3753 if(nam->nam_AudioCtrl->ahiac_PlayerFreq < 0x10000)
3755 nam->nam_AudioCtrl->ahiac_PlayerFreq <<= 16;
3757 nam->nam_PlayerFrac = (1000UL<<20) / (nam->nam_AudioCtrl->ahiac_PlayerFreq>>12);
3758 return AHIE_OK;
3760 AROS_LIBFUNC_EXIT
3762 /* \\\ */
3764 /* /// "subLibStop()" */
3765 AROS_LH2(ULONG, subLibStop,
3766 AROS_LHA(ULONG, flags, D0),
3767 AROS_LHA(struct AHIAudioCtrlDrv *, audioctrl, A2),
3768 SUBLIBBASETYPEPTR, nas, 11, nep)
3770 AROS_LIBFUNC_INIT
3772 struct NepAudioMode *nam = (struct NepAudioMode *) audioctrl->ahiac_DriverData;
3774 KPRINTF(10, ("subLibStop(%08lx, %lx)\n", audioctrl, flags));
3775 if(!nam)
3777 return AHIE_UNKNOWN;
3779 if(flags & AHISF_PLAY)
3781 if(nam->nam_FallbackTimer)
3783 nam->nam_TimerMsgPort.mp_Flags = PA_IGNORE;
3784 AbortIO((struct IORequest *) nam->nam_TimerIOReq);
3785 } else {
3786 psdStopRTIso(nam->nam_RTIso);
3789 if((flags & AHISF_RECORD) && nam->nam_Sibling)
3791 psdStopRTIso(nam->nam_Sibling->nam_RTIso);
3793 return AHIE_OK;
3795 AROS_LIBFUNC_EXIT
3797 /* \\\ */
3799 /* /// "subLibSetVol()" */
3800 AROS_LH5(ULONG, subLibSetVol,
3801 AROS_LHA(UWORD, channel, D0),
3802 AROS_LHA(Fixed, volume, D1),
3803 AROS_LHA(sposition, pan, D2),
3804 AROS_LHA(struct AHIAudioCtrlDrv *, audioctrl, A2),
3805 AROS_LHA(ULONG, flags, D3),
3806 SUBLIBBASETYPEPTR, nas, 12, nep)
3808 AROS_LIBFUNC_INIT
3809 return AHIS_UNKNOWN;
3810 AROS_LIBFUNC_EXIT
3812 /* \\\ */
3814 /* /// "subLibSetFreq()" */
3815 AROS_LH4(ULONG, subLibSetFreq,
3816 AROS_LHA(UWORD, channel, D0),
3817 AROS_LHA(ULONG, freq, D1),
3818 AROS_LHA(struct AHIAudioCtrlDrv *, audioctrl, A2),
3819 AROS_LHA(ULONG, flags, D2),
3820 SUBLIBBASETYPEPTR, nas, 13, nep)
3822 AROS_LIBFUNC_INIT
3823 return AHIS_UNKNOWN;
3824 AROS_LIBFUNC_EXIT
3826 /* \\\ */
3828 /* /// "subLibSetSound()" */
3829 AROS_LH6(ULONG, subLibSetSound,
3830 AROS_LHA(UWORD, channel, D0),
3831 AROS_LHA(UWORD, sound, D1),
3832 AROS_LHA(ULONG, offset, D2),
3833 AROS_LHA(LONG, length, D3),
3834 AROS_LHA(struct AHIAudioCtrlDrv *, audioctrl, A2),
3835 AROS_LHA(ULONG, flags, D4),
3836 SUBLIBBASETYPEPTR, nas, 14, nep)
3838 AROS_LIBFUNC_INIT
3839 return AHIS_UNKNOWN;
3840 AROS_LIBFUNC_EXIT
3842 /* \\\ */
3844 /* /// "subLibSetEffect()" */
3845 AROS_LH2(ULONG, subLibSetEffect,
3846 AROS_LHA(ULONG *, effect, A0),
3847 AROS_LHA(struct AHIAudioCtrlDrv *, audioctrl, A2),
3848 SUBLIBBASETYPEPTR, nas, 15, nep)
3850 AROS_LIBFUNC_INIT
3851 return AHIS_UNKNOWN;
3852 AROS_LIBFUNC_EXIT
3854 /* \\\ */
3856 /* /// "subLibLoadSound()" */
3857 AROS_LH4(ULONG, subLibLoadSound,
3858 AROS_LHA(UWORD, sound, D0),
3859 AROS_LHA(ULONG, type, D1),
3860 AROS_LHA(APTR, info, A0),
3861 AROS_LHA(struct AHIAudioCtrlDrv *, audioctrl, A2),
3862 SUBLIBBASETYPEPTR, nas, 16, nep)
3864 AROS_LIBFUNC_INIT
3865 return AHIS_UNKNOWN;
3866 AROS_LIBFUNC_EXIT
3868 /* \\\ */
3870 /* /// "subLibUnloadSound()" */
3871 AROS_LH2(ULONG, subLibUnloadSound,
3872 AROS_LHA(UWORD, sound, D0),
3873 AROS_LHA(struct AHIAudioCtrlDrv *, audioctrl, A2),
3874 SUBLIBBASETYPEPTR, nas, 17, nep)
3876 AROS_LIBFUNC_INIT
3877 return AHIS_UNKNOWN;
3878 AROS_LIBFUNC_EXIT
3880 /* \\\ */
3882 /* /// "subLibGetAttr()" */
3883 AROS_LH5(IPTR, subLibGetAttr,
3884 AROS_LHA(ULONG, attr, D0),
3885 AROS_LHA(LONG, arg, D1),
3886 AROS_LHA(LONG, defvalue, D2),
3887 AROS_LHA(struct TagItem *, tags, A1),
3888 AROS_LHA(struct AHIAudioCtrlDrv *, audioctrl, A2),
3889 SUBLIBBASETYPEPTR, nas, 18, nep)
3891 AROS_LIBFUNC_INIT
3893 UWORD cnt;
3894 struct NepAudioMode *nam = (struct NepAudioMode *) GetTagData(AHIDB_NepAudioMode, (IPTR) NULL, tags);
3895 struct NepAudioUnit *nau;
3897 KPRINTF(10, ("subLibGetAttr(%08lx, %08lx, %ld, %ld)\n", audioctrl, attr, arg, defvalue));
3899 if(!nam)
3901 KPRINTF(20, ("Could not find NepAudioMode in GetAttr call!\n"));
3902 return defvalue;
3905 switch(attr)
3907 case AHIDB_Bits:
3908 return (IPTR) nam->nam_Resolution;
3910 /*case AHIDB_MaxChannels:
3911 return (IPTR) nam->nam_NumChannels;
3913 case AHIDB_MinMixFreq:
3914 return (IPTR) nam->nam_MinFreq;
3916 case AHIDB_MaxMixFreq:
3917 return (IPTR) nam->nam_MaxFreq;*/
3919 case AHIDB_Frequencies:
3920 return (IPTR) nam->nam_NumFrequencies;
3922 case AHIDB_Frequency: // Index->Frequency
3923 return (IPTR) nam->nam_FreqArray[arg];
3925 case AHIDB_Index: // Frequency->Index
3927 ULONG diff = 100000;
3928 LONG bestfit = 0;
3929 for(cnt = 0; cnt < nam->nam_NumFrequencies; cnt++)
3931 if(nam->nam_FreqArray[cnt] > arg)
3933 if(nam->nam_FreqArray[cnt] - arg < diff)
3935 diff = nam->nam_FreqArray[cnt] - arg;
3936 bestfit = cnt;
3938 } else {
3939 if(arg - nam->nam_FreqArray[cnt] < diff)
3941 diff = arg - nam->nam_FreqArray[cnt];
3942 bestfit = cnt;
3946 return bestfit;
3949 case AHIDB_Author:
3950 return (IPTR) "Chris Hodges";
3952 case AHIDB_Copyright:
3953 return (IPTR) "2008-2009 Chris Hodges";
3955 case AHIDB_Version:
3956 return (IPTR) VERSION_STRING;
3958 case AHIDB_Annotation:
3959 return (IPTR) "Bye...";
3961 case AHIDB_Record:
3962 return nam->nam_IsInput || nam->nam_Sibling;
3964 case AHIDB_FullDuplex:
3965 return nam->nam_Sibling ? TRUE : FALSE;
3967 case AHIDB_Realtime:
3968 return TRUE;
3970 case AHIDB_MinOutputVolume:
3971 if(nam->nam_RootUnit->nau_VolumeControl)
3973 KPRINTF(10, ("MinOutputVolume %08lx\n", nam->nam_RootUnit->nau_VolumeUnit->nau_MinVolume));
3974 return nam->nam_RootUnit->nau_VolumeUnit->nau_MinVolume;
3976 return 0;
3978 case AHIDB_MaxOutputVolume:
3979 if(nam->nam_RootUnit->nau_VolumeControl)
3981 KPRINTF(10, ("MaxOutputVolume %08lx\n", nam->nam_RootUnit->nau_VolumeUnit->nau_MaxVolume));
3982 return nam->nam_RootUnit->nau_VolumeUnit->nau_MaxVolume;
3984 return 0;
3986 case AHIDB_MinInputGain:
3987 nau = nGetInputUnit(nam);
3988 if(nau)
3990 if(nau->nau_VolumeControl)
3992 KPRINTF(10, ("MinInputGain %08lx\n", nau->nau_VolumeUnit->nau_MinVolume));
3993 return nau->nau_VolumeUnit->nau_MinVolume;
3996 return 0;
3998 case AHIDB_MaxInputGain:
3999 nau = nGetInputUnit(nam);
4000 if(nau)
4002 if(nau->nau_VolumeControl)
4004 KPRINTF(10, ("MaxInputGain %08lx\n", nau->nau_VolumeUnit->nau_MaxVolume));
4005 return nau->nau_VolumeUnit->nau_MaxVolume;
4008 return 0;
4010 case AHIDB_MinMonitorVolume:
4011 nau = nGetInputUnit(nam);
4012 if(nau)
4014 if(nau->nau_Monitor)
4016 KPRINTF(10, ("MinMonitorVol %08lx\n", nau->nau_MonitorUnit->nau_MinVolume));
4017 return nau->nau_MonitorUnit->nau_MinVolume;
4020 return 0;
4022 case AHIDB_MaxMonitorVolume:
4023 nau = nGetInputUnit(nam);
4024 if(nau)
4026 if(nau->nau_Monitor)
4028 KPRINTF(10, ("MaxMonitorVol %08lx\n", nau->nau_MonitorUnit->nau_MaxVolume));
4029 return nau->nau_MonitorUnit->nau_MaxVolume;
4032 return 0;
4034 case AHIDB_Inputs:
4035 if(nam->nam_Sibling && nam->nam_Sibling->nam_RootUnit->nau_SelectorUnit)
4037 return (IPTR) nam->nam_Sibling->nam_RootUnit->nau_SelectorUnit->nau_NumInputs;
4039 return 0;
4041 case AHIDB_Input:
4042 if(nam->nam_Sibling && nam->nam_Sibling->nam_RootUnit->nau_SelectorUnit)
4044 return (IPTR) nam->nam_Sibling->nam_RootUnit->nau_SelectorUnit->nau_InputUnit[arg]->nau_RootUnit->nau_Name;
4046 return (IPTR) NULL;
4048 case AHIDB_Outputs:
4049 if(nam->nam_RootUnit->nau_SelectorUnit)
4051 return (IPTR) nam->nam_RootUnit->nau_SelectorUnit->nau_NumInputs;
4053 return (IPTR) nam->nam_NumOutputs;
4055 case AHIDB_Output:
4056 if(nam->nam_RootUnit->nau_SelectorUnit)
4058 return (IPTR) nam->nam_RootUnit->nau_SelectorUnit->nau_InputUnit[arg]->nau_RootUnit->nau_Name;
4060 return (IPTR) nam->nam_OutputNames[arg];
4062 return defvalue;
4064 AROS_LIBFUNC_EXIT
4066 /* \\\ */
4068 /* /// "subLibHardwareControl()" */
4069 AROS_LH3(IPTR, subLibHardwareControl,
4070 AROS_LHA(ULONG, attr, D0),
4071 AROS_LHA(LONG, arg, D1),
4072 AROS_LHA(struct AHIAudioCtrlDrv *, audioctrl, A2),
4073 SUBLIBBASETYPEPTR, nas, 19, nep)
4075 AROS_LIBFUNC_INIT
4077 struct NepAudioMode *nam = (struct NepAudioMode *) audioctrl->ahiac_DriverData;
4078 struct NepClassAudio *nch;
4079 KPRINTF(10, ("subLibHardwareControl(%08lx, %08lx, %ld)\n", audioctrl, attr, arg));
4081 if(!nam)
4083 return FALSE;
4085 nch = nam->nam_Unit;
4087 switch(attr)
4089 case AHIC_MixFreq_Query:
4090 return (IPTR) audioctrl->ahiac_MixFreq;
4092 case AHIC_InputGain:
4093 nam->nam_InputGain = arg;
4094 nch->nch_UpdateFlags |= UAF_INPUT_GAIN;
4095 Signal(nch->nch_Task, 1UL<<nch->nch_TaskMsgPort->mp_SigBit);
4096 return TRUE;
4098 case AHIC_InputGain_Query:
4099 return nam->nam_InputGain;
4101 case AHIC_MonitorVolume:
4102 nam->nam_MonitorVol = arg;
4103 nch->nch_UpdateFlags |= UAF_MONITOR_VOLUME;
4104 Signal(nch->nch_Task, 1UL<<nch->nch_TaskMsgPort->mp_SigBit);
4105 return TRUE;
4107 case AHIC_MonitorVolume_Query:
4108 return nam->nam_MonitorVol;
4110 case AHIC_OutputVolume:
4111 nam->nam_MasterVol = arg;
4112 nch->nch_UpdateFlags |= UAF_MASTER_VOLUME;
4113 Signal(nch->nch_Task, 1UL<<nch->nch_TaskMsgPort->mp_SigBit);
4114 return TRUE;
4116 case AHIC_OutputVolume_Query:
4117 return nam->nam_MasterVol;
4119 case AHIC_Input:
4120 if(nam->nam_NumInputs < 2)
4122 return TRUE;
4124 nam->nam_CurrInput = arg;
4125 nch->nch_UpdateFlags |= UAF_SELECT_INPUT;
4126 Signal(nch->nch_Task, 1UL<<nch->nch_TaskMsgPort->mp_SigBit);
4127 return TRUE;
4129 case AHIC_Input_Query:
4130 return nam->nam_CurrInput;
4132 case AHIC_Output:
4133 if(nam->nam_NumOutputs < 2)
4135 return TRUE;
4137 nam->nam_CurrOutput = arg;
4138 nch->nch_UpdateFlags |= UAF_SELECT_OUTPUT;
4139 Signal(nch->nch_Task, 1UL<<nch->nch_TaskMsgPort->mp_SigBit);
4140 return TRUE;
4142 case AHIC_Output_Query:
4143 return nam->nam_CurrOutput;
4145 return FALSE;
4147 AROS_LIBFUNC_EXIT
4149 /* \\\ */