static void RemPlayers ( struct List *list, struct AHIDevUnit *iounit, struct AHIBase *AHIBase ) { struct AHIRequest *ioreq, *node; node = (struct AHIRequest *) list->lh_Head; while(node->ahir_Std.io_Message.mn_Node.ln_Succ) { ioreq = node; node = (struct AHIRequest *) node->ahir_Std.io_Message.mn_Node.ln_Succ; if(ioreq->ahir_Std.io_Command == AHICMD_WRITTEN) { Remove((struct Node *) ioreq); if(ioreq->ahir_Link) { // Move the attached one to the list Remove((struct Node *) ioreq->ahir_Link); GetExtras(ioreq->ahir_Link)->Channel = GetExtras(ioreq)->Channel; Enqueue(list, (struct Node *) ioreq->ahir_Link); // We have to go through the whole procedure again, in case // the child is finished, too. node = (struct AHIRequest *) list->lh_Head; } ioreq->ahir_Std.io_Error = AHIE_OK; ioreq->ahir_Std.io_Command = CMD_WRITE; ioreq->ahir_Std.io_Actual = ioreq->ahir_Std.io_Length * AHI_SampleFrameSize(ioreq->ahir_Type); TermIO(ioreq, AHIBase); } } }
VOID DispatcherThread(struct MOSWriteHandle* h) { struct MsgPort* ahi_port = NULL; struct AHIRequest* ahi_request = NULL; struct AHIAudioCtrl*ahi_control = NULL; BYTE* sample_bufs = NULL; ULONG sample_size = 2; BYTE ahi_device = -1; LONG switch_sig_bit = -1; LONG locked_buf = -1; struct DispatcherStartupMsg *startup_msg; struct DispatcherInitReport *init_report; struct MsgPort *task_port = NULL; struct ExecBase *SysBase = *(struct ExecBase **) 4; init_report = (struct DispatcherInitReport *) AllocVec(sizeof (struct DispatcherInitReport), MEMF_PUBLIC | MEMF_CLEAR); if (init_report == NULL) return; NewGetTaskAttrsA(NULL, &task_port, sizeof (task_port), TASKINFOTYPE_TASKMSGPORT, NULL); NewGetTaskAttrsA(NULL, &startup_msg, sizeof (startup_msg), TASKINFOTYPE_STARTUPMSG, NULL); if (task_port == NULL || startup_msg == NULL) { FreeVec(init_report); return; } startup_msg->dsm_Result = -1; switch_sig_bit = AllocSignal(-1); if (switch_sig_bit != -1 && (ahi_port = CreateMsgPort())) { if ((ahi_request = (struct AHIRequest *) CreateIORequest(ahi_port, sizeof (struct AHIRequest)))) { ahi_request->ahir_Version = 4; if ((ahi_device = OpenDevice(AHINAME, AHI_NO_UNIT, (struct IORequest *) ahi_request, 0)) == 0) { AHIBase = (struct Library*) ahi_request->ahir_Std.io_Device; /*dprintf("AllocAudio with %d channels, %d sounds and frequency %d\n", h->wh_Channels, AHI_BUFFERS, h->wh_Frequency);*/ ahi_control = AHI_AllocAudio(AHIA_AudioID, AHI_DEFAULT_ID, AHIA_Channels, h->wh_Channels, AHIA_Sounds, AHI_BUFFERS, AHIA_MixFreq, h->wh_Frequency, AHIA_SoundFunc, (ULONG) &OpenAL_SoundHook, AHIA_UserData, (ULONG) h, TAG_DONE ); if (ahi_control) { ULONG buf_size; ULONG samples, fs, fm; AHI_GetAudioAttrs(AHI_INVALID_ID, ahi_control, AHIDB_MaxPlaySamples, (ULONG) &samples, TAG_DONE); AHI_ControlAudio(ahi_control, AHIC_MixFreq_Query, (ULONG) &fm, TAG_DONE); fs = h->wh_Frequency; buf_size = samples*fs/fm; /*dprintf("OpenAL: Minimum buffer size is %d, requested buffer size is %d\n", buf_size, h->wh_BufSize);*/ if (buf_size > h->wh_BufSize) h->wh_BufSize = buf_size; sample_bufs = AllocVec(h->wh_BufSize*AHI_BUFFERS, MEMF_PUBLIC | MEMF_CLEAR); if (sample_bufs) { struct Buffer* bn; ULONG buf; LONG err = AHIE_OK; sample_size = AHI_SampleFrameSize(h->wh_SampleType); for (buf = 0; buf < AHI_BUFFERS && err == AHIE_OK; buf++) { bn = &h->wh_Buffers[buf]; bn->bn_SampleNo = buf; bn->bn_SampleInfo.ahisi_Type = h->wh_SampleType; bn->bn_SampleInfo.ahisi_Address = &sample_bufs[buf*h->wh_BufSize]; bn->bn_SampleInfo.ahisi_Length = h->wh_BufSize/sample_size; InitSemaphore(&bn->bn_Semaphore); bn->bn_FillSize = 0; err = AHI_LoadSound(buf, AHIST_DYNAMICSAMPLE, &bn->bn_SampleInfo, ahi_control); } if (err != AHIE_OK) { FreeVec(sample_bufs); sample_bufs = NULL; } } } } } } if (sample_bufs) { BOOL dispatcher_running = TRUE; ULONG signal_mask = 1 << task_port->mp_SigBit; ULONG signal_set; struct MsgPort *reply_port; reply_port = CreateMsgPort(); if (reply_port == NULL) reply_port = task_port; if (startup_msg) startup_msg->dsm_Result = 0; init_report->dir_Msg.mn_Node.ln_Type = NT_MESSAGE; init_report->dir_Msg.mn_ReplyPort = reply_port; init_report->dir_Msg.mn_Length = sizeof (struct DispatcherInitReport); AHI_ControlAudio(ahi_control, AHIC_MixFreq_Query, (ULONG) &init_report->dir_RealFrequency, TAG_DONE); init_report->dir_RealBufSize = h->wh_BufSize; PutMsg(startup_msg->dsm_Msg.mn_ReplyPort, (struct Message*) init_report); WaitPort(reply_port); GetMsg(reply_port); FreeVec(init_report); init_report = NULL; if (reply_port != task_port) DeleteMsgPort(reply_port); h->wh_SwitchSignal = 1UL << switch_sig_bit; h->wh_ReadBuf = 0; while (dispatcher_running) { signal_set = Wait(signal_mask); if (signal_set & (1 << task_port->mp_SigBit)) { struct DispatcherMsg *msg; while ((msg = (struct DispatcherMsg *) GetMsg(task_port))) { if (msg->dm_Msg.mn_Length == sizeof (struct DispatcherMsg)) { switch (msg->dm_Command) { case DISPATCHER_CMD_START: { /* * First buffer has been filled and we were previously not * playing any sound yet */ ULONG chan; ULONG cur_buf; cur_buf = h->wh_ReadBuf; AHI_ControlAudio(ahi_control, AHIC_Play, TRUE, TAG_DONE); /* Lock first audio buffer */ ObtainSemaphore(&h->wh_Buffers[cur_buf].bn_Semaphore); locked_buf = cur_buf; for (chan = 0; chan < h->wh_Channels; chan++) { AHI_SetFreq(chan, h->wh_Frequency, ahi_control, AHISF_IMM); AHI_SetVol(chan, 0x10000L, -0x8000L, ahi_control, AHISF_IMM); AHI_SetSound(chan, cur_buf, 0, 0, ahi_control, AHISF_IMM); } Wait(1 << switch_sig_bit); cur_buf++; if (cur_buf >= AHI_BUFFERS) cur_buf = 0; h->wh_ReadBuf = cur_buf; signal_mask |= 1UL << switch_sig_bit; break; } case DISPATCHER_CMD_PAUSE: case DISPATCHER_CMD_RESUME: AHI_ControlAudio(ahi_control, AHIC_Play, msg->dm_Command == DISPATCHER_CMD_RESUME, TAG_DONE); break; case DISPATCHER_CMD_BREAK: /* Break requests and quit */ /*dprintf("Dispatcher thread: break requested\n");*/ AHI_ControlAudio(ahi_control, AHIC_Play, FALSE, TAG_DONE); dispatcher_running = FALSE; break; } } ReplyMsg((struct Message *) msg); } } if (signal_set & (1UL << switch_sig_bit)) { /* Switch to next read buffer */ ULONG cur_buf; cur_buf = h->wh_ReadBuf; /*dprintf("Dispatcher thread: buffer switch requested. Releasing lock on %d, locking %d\n", locked_buf, cur_buf);*/ memset(h->wh_Buffers[locked_buf].bn_SampleInfo.ahisi_Address, 0, h->wh_BufSize); ReleaseSemaphore(&h->wh_Buffers[locked_buf].bn_Semaphore); cur_buf++; if (cur_buf >= AHI_BUFFERS) cur_buf = 0; ObtainSemaphore(&h->wh_Buffers[cur_buf].bn_Semaphore); locked_buf = cur_buf; h->wh_ReadBuf = cur_buf; /*dprintf("Dispatcher thread: buffer switch done\n");*/ } } } /* Cleanup */ if (init_report) { FreeVec(init_report); init_report = NULL; } if (locked_buf != -1) { ReleaseSemaphore(&h->wh_Buffers[locked_buf].bn_Semaphore); locked_buf = -1; } if (switch_sig_bit != -1) { FreeSignal(switch_sig_bit); switch_sig_bit = -1; } if (ahi_control) { AHI_FreeAudio(ahi_control); /* Also unloads all sounds */ ahi_control = NULL; } if (ahi_request) { CloseDevice((struct IORequest*) ahi_request); DeleteIORequest((struct IORequest*) ahi_request); ahi_request = NULL; ahi_device = -1; } if (sample_bufs) { FreeVec(sample_bufs); sample_bufs = NULL; } if (ahi_port) { DeleteMsgPort(ahi_port); ahi_port = NULL; } }
static void Slave( struct ExecBase* SysBase ) { struct AHIAudioCtrlDrv* AudioCtrl; struct DriverBase* AHIsubBase; struct DeviceBase* DeviceBase; BOOL running; ULONG signals; AudioCtrl = (struct AHIAudioCtrlDrv*) FindTask( NULL )->tc_UserData; AHIsubBase = (struct DriverBase*) dd->ahisubbase; DeviceBase = (struct DeviceBase*) AHIsubBase; dd->slavesignal = AllocSignal( -1 ); if( dd->slavesignal != -1 ) { struct MsgPort* ahi_mp = NULL; struct AHIRequest* ahi_iorequest = NULL; APTR ahi_iocopy = NULL; BYTE ahi_device = -1; struct AHIRequest* ahi_io[ 2 ] = { NULL, NULL }; BOOL ahi_io_used[ 2 ] = { FALSE, FALSE }; ULONG frame_length = 0; ahi_mp = CreateMsgPort(); if( ahi_mp != NULL ) { ahi_iorequest = CreateIORequest( ahi_mp, sizeof( struct AHIRequest ) ); if( ahi_iorequest != NULL ) { ahi_iorequest->ahir_Version = 4; ahi_device = OpenDevice( AHINAME, dd->unit, (struct IORequest*) ahi_iorequest, 0 ); if( ahi_device == 0 ) { struct Library* AHIBase = (struct Library*) ahi_iorequest->ahir_Std.io_Device; ahi_iocopy = AllocVec( sizeof( *ahi_iorequest ), MEMF_ANY ); if( ahi_iocopy != NULL ) { bcopy( ahi_iorequest, ahi_iocopy, sizeof( *ahi_iorequest ) ); ahi_io[ 0 ] = ahi_iorequest; ahi_io[ 1 ] = ahi_iocopy; // Everything set up. Tell Master we're alive and healthy. Signal( (struct Task*) dd->mastertask, 1L << dd->mastersignal ); running = TRUE; // The main playback loop follow while( running ) { int skip_mix; APTR tmp_buff; struct AHIRequest* tmp_io; if( ahi_io_used[ 0 ] ) { LONG err; ULONG mask = ( SIGBREAKF_CTRL_C | (1L << dd->slavesignal) | (1L << ahi_mp->mp_SigBit) ); signals = Wait( mask ); if( signals & ( SIGBREAKF_CTRL_C | (1L << dd->slavesignal) ) ) { running = FALSE; break; } err = WaitIO( (struct IORequest*) ahi_io[ 0 ] ); if( err != 0 ) { KPrintF( DRIVER ": AHI device error %ld\n", err ); // running = FALSE; break; } } skip_mix = CallHookPkt( AudioCtrl->ahiac_PreTimerFunc, (Object*) AudioCtrl, 0 ); CallHookPkt( AudioCtrl->ahiac_PlayerFunc, AudioCtrl, NULL ); if( ! skip_mix ) { CallHookPkt( AudioCtrl->ahiac_MixerFunc, AudioCtrl, dd->mixbuffers[ 0 ] ); } CallHookPkt( AudioCtrl->ahiac_PostTimerFunc, (Object*) AudioCtrl, 0 ); if( frame_length == 0 ) { frame_length = AHI_SampleFrameSize( AudioCtrl->ahiac_BuffType ); } ahi_io[ 0 ]->ahir_Std.io_Command = CMD_WRITE; ahi_io[ 0 ]->ahir_Std.io_Data = dd->mixbuffers[ 0 ]; ahi_io[ 0 ]->ahir_Std.io_Length = ( AudioCtrl->ahiac_BuffSamples * frame_length ); ahi_io[ 0 ]->ahir_Std.io_Offset = 0; ahi_io[ 0 ]->ahir_Frequency = AudioCtrl->ahiac_MixFreq; ahi_io[ 0 ]->ahir_Type = AudioCtrl->ahiac_BuffType; ahi_io[ 0 ]->ahir_Volume = 0x10000; ahi_io[ 0 ]->ahir_Position = 0x08000; ahi_io[ 0 ]->ahir_Link = ( ahi_io_used[ 1 ] ? ahi_io[ 1 ] : NULL ); SendIO( (struct IORequest*) ahi_io[ 0 ] ); tmp_io = ahi_io[ 0 ]; ahi_io[ 0 ] = ahi_io[ 1 ]; ahi_io[ 1 ] = tmp_io; tmp_buff = dd->mixbuffers[ 0 ]; dd->mixbuffers[ 0 ] = dd->mixbuffers[ 1 ]; dd->mixbuffers[ 1 ] = tmp_buff; ahi_io_used[ 0 ] = ahi_io_used[ 1 ]; ahi_io_used[ 1 ] = TRUE; } if( ahi_io_used[ 0 ] ) { AbortIO( (struct IORequest*) ahi_io[ 0 ] ); WaitIO( (struct IORequest*) ahi_io[ 0 ] ); } if( ahi_io_used[ 1 ] ) { AbortIO( (struct IORequest*) ahi_io[ 1 ] ); WaitIO( (struct IORequest*) ahi_io[ 1 ] ); } FreeVec( ahi_iocopy ); } CloseDevice( (struct IORequest*) ahi_iorequest ); } DeleteIORequest( (struct IORequest*) ahi_iorequest ); } DeleteMsgPort( ahi_mp ); } } FreeSignal( dd->slavesignal ); dd->slavesignal = -1; Forbid(); // Tell the Master we're dying Signal( (struct Task*) dd->mastertask, 1L << dd->mastersignal ); dd->slavetask = NULL; // Multitaking will resume when we are dead. }
static void FillReadBuffer ( struct AHIRequest *ioreq, struct AHIDevUnit *iounit, struct AHIBase *AHIBase ) { ULONG length,length2; APTR oldaddress; BOOL remove; if(iounit->ValidRecord) // Make sure we have a valid source buffer { oldaddress = ioreq->ahir_Std.io_Data; length = (ioreq->ahir_Std.io_Length - ioreq->ahir_Std.io_Actual) / AHI_SampleFrameSize(ioreq->ahir_Type); length2 = (iounit->RecordSize - ioreq->ahir_Std.io_Offset) / AHI_SampleFrameSize(AHIST_S16S); length2 = MultFixed(length2, (Fixed) ioreq->ahir_Frequency); if(length <= length2) { remove=TRUE; } else { length = length2; remove = FALSE; } switch (ioreq->ahir_Type) { #if 0 case AHIST_M8S: RecM8S(length,ioreq->ahir_Frequency, iounit->RecordBuffer, &ioreq->ahir_Std.io_Offset, &ioreq->ahir_Std.io_Data); break; case AHIST_S8S: RecS8S(length,ioreq->ahir_Frequency, iounit->RecordBuffer, &ioreq->ahir_Std.io_Offset, &ioreq->ahir_Std.io_Data); break; case AHIST_M16S: RecM16S(length,ioreq->ahir_Frequency, iounit->RecordBuffer, &ioreq->ahir_Std.io_Offset, &ioreq->ahir_Std.io_Data); break; case AHIST_S16S: RecS16S(length,ioreq->ahir_Frequency, iounit->RecordBuffer, &ioreq->ahir_Std.io_Offset, &ioreq->ahir_Std.io_Data); break; case AHIST_M32S: RecM32S(length,ioreq->ahir_Frequency, iounit->RecordBuffer, &ioreq->ahir_Std.io_Offset, &ioreq->ahir_Std.io_Data); break; case AHIST_S32S: RecS32S(length,ioreq->ahir_Frequency, iounit->RecordBuffer, &ioreq->ahir_Std.io_Offset, &ioreq->ahir_Std.io_Data); break; #endif default: ioreq->ahir_Std.io_Error = AHIE_BADSAMPLETYPE; remove = TRUE; break; } ioreq->ahir_Std.io_Actual += ((ULONG) ioreq->ahir_Std.io_Data - (ULONG) oldaddress); if(remove) { Remove((struct Node *) ioreq); TermIO(ioreq, AHIBase); } else { ioreq->ahir_Std.io_Offset = 0; } } else { ioreq->ahir_Std.io_Offset = 0; } }
static void WriteCmd ( struct AHIRequest *ioreq, struct AHIBase *AHIBase ) { struct AHIDevUnit *iounit; ULONG error = 0; if(AHIBase->ahib_DebugLevel >= AHI_DEBUG_HIGH) { KPrintF("CMD_WRITE\n"); } iounit = (struct AHIDevUnit *) ioreq->ahir_Std.io_Unit; /* Start playback if neccessary */ if( ! iounit->IsPlaying) { if( (! iounit->FullDuplex) && iounit->IsRecording) { error = AHIE_HALFDUPLEX; // FIXIT! } else { error = AHI_ControlAudio(iounit->AudioCtrl, AHIC_Play,TRUE, TAG_DONE); } if( ! error) { iounit->IsPlaying = TRUE; } } ioreq->ahir_Extras = (ULONG) AllocVec(sizeof(struct Extras), MEMF_PUBLIC|MEMF_CLEAR); if(ioreq->ahir_Extras == NULL) { error = AHIE_NOMEM; } else { // Initialize the structure GetExtras(ioreq)->Channel = NOCHANNEL; GetExtras(ioreq)->Sound = AHI_NOSOUND; GetExtras(ioreq)->Count = 2; } if(iounit->IsPlaying && !error) { ioreq->ahir_Std.io_Actual = 0; // Convert length in bytes to length in samples ioreq->ahir_Std.io_Length /= AHI_SampleFrameSize(ioreq->ahir_Type); switch(ioreq->ahir_Type) { case AHIST_M8S: case AHIST_S8S: case AHIST_M16S: case AHIST_S16S: break; case AHIST_M32S: case AHIST_S32S: default: error = AHIE_BADSAMPLETYPE; } if(! error) { NewWriter(ioreq, iounit, AHIBase); } } if(error) { ioreq->ahir_Std.io_Error = error; TermIO(ioreq, AHIBase); } }