This scenario describes how two streams (waveform audio and MIDI) are created and synchronized with each other. The audio stream is the synchronization master stream. The source handler for the waveform stream is the File System Stream Handler DLL. The source handler for the MIDI stream is the File System Stream Handler DLL.
Currently, the audio stream handler does not provide the ability to be a slave to a master stream. It does, however, have the ability to be the master stream handler.
/**************************************************************/ /* M A I N */ /**************************************************************/ main() { RC ulRC; /* Error return code */ SPCBKEY spcbkey; /* Data type to stream */ IMPL_EVCB evcb1, evcb2; /* Event control block for implicit events */ ACB_MMIO acb; /* Associate control block used to assoc */ /* The file to stream (play) */ DCB_AUDIOSH dcb; /* Audio device driver information */ HAND ahand[5]; /* Enumerate handler info */ ULONG ulNumHand = 5; HID hidSource1, hidTarget1, hidunused; /* Handler IDs */ HID hidSource2, hidTarget2 HSTREAM hstream1, hstream2; /* Stream handle */ HEVENT hevent1, hevent2; /* Event handle for implicit events */ HMMIO hmmio1, hmmio2; /* Handle to mmio file open */ SLAVE slave[1]; /* Sync slave structure */ /* Get list of all Stream handlers in system */ if (rc = SpiEnumerateHandlers(&ahand, &ulNumHand)) return(rc); /* error! */ /********************************************************/ /****** CREATE WAVEFORM AUDIO STREAM (Stream # 1) ******/ /********************************************************/ /* Get the stream Handler ID for the file system stream handler */ if (rc = SpiGetHandler("FSSH",&hidSource1,&hidunused)) return(rc); /* error! */ /* Get the stream handler ID for the Audio Stream Handler */ if (rc = SpiGetHandler("AUDIOSH$",&hidunused,&hidTarget1)) return(rc); /* error! */ /* Create a data stream from the file system to */ /* the audio ACPA device connected to speakers. */ spcbkey.ulDataType = DATATYPE_ADPCM_AVC; spcbkey.ulDataSubType = ADPCM_AVC_HQ; spcbkey.ulINtKey = 0; strcpy(dcb.szDevName,"AUDIO1$"); dcb.ulDCBLen = sizeof(dcb); dcb.hSysFileNum = (** hSysFileNum returned by audio dd on audio_init call) if (rc = SpiCreateStream(hidSource1, hidTarget1, &spcbkey, NULL, (PDCB)&dcb, (PEVCB)&evcb1, EventProc, 0, &hstream1, &hevent1)) return(rc); /* error! */ /* USE MMIO to access a waveform audio object */ if ((hmmio1 = mmioOpen("E:\Mygreat\waveform\file\screams.hq" NULL, MMIO_READWRITE| MMIO_DENYNONE)) == NULL) return(ERROR_FILE_NOT_FOUND); /* Fill in acb with data object info */ acb.ulACBLen = sizeof(ACB_MMIO); acb.ulObjType = ACBTYPE_MMIO; acb.hmmio = hmmio1; /* Associate the waveform data object with the source handler */ if (rc = SpiAssociate(hstream1,hidSource1,&acb)) return(rc); /* error! */ /**********************************************/ /****** CREATE MIDI STREAM (Stream # 2) ******/ /**********************************************/ /* Get the stream handler ID for the File System Stream Handler */ if (rc = SpiGetHandler("FSSH",&hidSource2,&hidunused)) return(rc); /* error! */ /* Get the stream handler ID for the MIDI Audio Stream Handler */ if (rc = SpiGetHandler("AUDIOSH$",&hidunused,&hidTarget2)) return(rc); /* error! */ /* Create a data stream from the memory to an */ /* OEM audio device connected to speakers. */ spcbkey.ulDataType = DATATYPE_MIDI; spcbkey.ulDataSubType = SUBTYPE_NONE; spcbkey.ulINtKey = 0; strcpy(dcb.szDevName,"AUDIO99$"); dcb.ulDCBLen = sizeof(dcb); dcb.hSysFileNum = (** hSysFileNum returned by audio dd on audio_init call) if (rc = SpiCreateStream(hidSource2, hidTarget2, &spcbkey, NULL, (PDCB)&dcb, (PEVCB)&evcb2, EventProc, 0, &hstream2, &hevent2)) return(rc); /* error! */ /* USE MMIO to access a waveform audio object */ if ((hmmio2 = mmioOpen("E:Mygreat\midi\file\screams.mid" NULL, MMIO_READWRITE| MMIO_DENYNONE)) == NULL) return(ERROR_FILE_NOT_FOUND); /* Fill in acb with data object info */ acb.ulACBLen = sizeof(ACB_MMIO); acb.ulObjType = ACBTYPE_MMIO; acb.hmmio = hmmio2; /* Associate the waveform data object with the source handler */ if (rc = SpiAssociate(hstream2,hidSource2,&acb)) return(rc); /* error! */ /**************************************************************/ /***** SETUP THE SYNCHRONIZATION BETWEEN THE TWO STREAMS ******/ /**************************************************************/ slave[0].hSlaveStream = hstream2; /* MIDI stream is slave */ slave[0].mmtimeStart = 0; /* Time to start slave */ if (rc = SpiEnableSync(hstream1, /* Audio stream is master */ &slave, 1, /* Number of slaves */ 0)) /* Use spcb sync granularity */ return(rc); /* error! */ /* Start streams by passing the handle to the stream sync master */ if (rc = SpiStartStream(hstream1, SPI_START_SLAVES)) return(rc); /* error! */ /* Do other processing */ . . . /* Create a semaphore and block this thread on the semaphore */ /* until the streaming is complete */ . . . /* Destroy both streams when completed */ if (rc = SpiDestroyStream(hstream1)) return(rc); /* error! */ if (rc = SpiDestroyStream(hstream2)) return(rc); /* error! */ /* Perform other resource cleanup */ } /**************************************************************/ /* E v e n t P r o c e d u r e */ /**************************************************************/ RC EventProc(EVCB *pEVCB) { if (pEVCB == &EVCB1) /* Stream #1 or Stream # 2 event ? */ /* Process Stream #1 events */ else /* Process Stream #2 events */ /* Handle events from the Sync/Stream Manager */ switch (pEVCB->ulType) { case EVENT_IMPLICIT_TYPE: switch (pEVCB->ulSubType) { case EVENT_EOS: /* End of Stream */ /* Clear the semaphore so that the main routine can */ /* continue execution. */ break; case EVENT_ERROR: /* Error occurred */ /* flag error condition in main line application */ break; case EVENT_STREAM_STOPPED: /* Discard/Flush Stop */ /* Do processing while stream stopped */ break; case EVENT_SYNC_PREROLLED: /* Stream is prerolled */ /* Now that the producers are prerolled, do a real start to the stream handlers */ break; default: /* Unknown event, do something */ } break; default: /* Unknown event, do something */ } }