/* can be used as time stamp for interactive MIDI events */ INT64 XGetRealTimeSyncCount() { INT64 ret = g_checkpointSyncCount + (XMicroseconds() - g_checkpointMicros) + (HAE_GetSliceTimeInMicroseconds() * HAE_GetAudioBufferCount()); return ret; }
// $$kk: 08.12.98 merge: changed this method to do convert to unsigned data if required by audio hardware void PV_AudioWaveOutFrameThread(void* context) { audio_info_t sunAudioHeader; char *pFillBuffer; INT32 count, currentPos, lastPos, sampleFrameSize; UINT32 startTime, stopTime, fillTime; int i; int rc; int bytesWritten; int bytesToWrite; ioctl(g_waveDevice, AUDIO_GETINFO, &sunAudioHeader); // calculate sample size for convertion of bytes to sample frames sampleFrameSize = 1; if (g_bitSize == 16) { sampleFrameSize *= 2; } if (g_channels == 2) { sampleFrameSize *= 2; } lastPos = sunAudioHeader.play.samples - ((g_audioByteBufferSize * HAE_SOLARIS_FRAMES_PER_BLOCK * 2) / sampleFrameSize); if (g_audioBufferBlock) { while ( (g_activeDoubleBuffer) && (g_shutDownDoubleBuffer == FALSE) ) { /* put sync count and XMicroseconds into relation */ /* could be improved by using actual device sample count */ g_checkpointMicros = XMicroseconds(); g_checkpointSyncCount = GM_GetSyncTimeStamp(); // Generate HAE_SOLARIS_FRAMES_PER_BLOCK frames of audio pFillBuffer = (char *)g_audioBufferBlock; for (count = 0; count < HAE_SOLARIS_FRAMES_PER_BLOCK; count++) { // Generate one frame audio HAE_BuildMixerSlice(context, pFillBuffer, g_audioByteBufferSize, g_audioFramesToGenerate); pFillBuffer += g_audioByteBufferSize; if (g_shutDownDoubleBuffer) { break; // time to quit } } // $$kk // for some solaris drivers, we must supply unsigned data when rendering 8 bit data if (g_convertUnsigned && (g_bitSize == 8)) { pFillBuffer = (char *)g_audioBufferBlock; for (i = 0; i < (g_audioByteBufferSize * HAE_SOLARIS_FRAMES_PER_BLOCK); i++) { *pFillBuffer = (*pFillBuffer >= 0) ? (0x80 | *pFillBuffer) : (0x7F & *pFillBuffer); pFillBuffer++; } } // $$jb: Changing the write() loop to handle cases when the // device is unavailable, or we can't write our entire buffer bytesWritten = 0; bytesToWrite = (g_audioByteBufferSize * HAE_SOLARIS_FRAMES_PER_BLOCK); while( bytesToWrite > 0 ) { //$$fb don't write when it's time to quit. if( g_shutDownDoubleBuffer) { break; } rc = write(g_waveDevice, ((char *)g_audioBufferBlock+bytesWritten), (size_t)bytesToWrite); if ( rc > 0 ) { #ifdef USE_RAWDATA_CHECK if (debugrawfile) { HAE_WriteFile(debugrawfile, ((char *)g_audioBufferBlock+bytesWritten), rc); } #endif bytesWritten += rc; bytesToWrite -= rc; } else { // $$jb: This happens when the device buffers cannot // be written to. Make sure we're not shutting down and // sleep a bit so that we don't completely hog the CPU if( g_shutDownDoubleBuffer == FALSE ) { HAE_SleepFrameThread(context, HAE_SOLARIS_SOUND_PERIOD); } else { break; } } } // O.k. We're done for now. // Let the rest of the system know we're done .... ioctl(g_waveDevice, AUDIO_GETINFO, &sunAudioHeader); currentPos = sunAudioHeader.play.samples; // $$jb: We have successfully written all our bytes. // If we encountered a problem while writing, play.error will be 1. // This should be reset. if( sunAudioHeader.play.error != 0 ) { AUDIO_INITINFO(&sunAudioHeader); sunAudioHeader.play.error = 0; ioctl(g_waveDevice, AUDIO_SETINFO, &sunAudioHeader); } // $$kk: 03.21.00: make sure we sleep at least once so that other threads can run. // this is part of the fix for bug #4318062: "MixerSourceLine.drain hangs after // repeated use." //while ((currentPos < lastPos) && (g_shutDownDoubleBuffer == FALSE)) do { HAE_SleepFrameThread(context, HAE_SOLARIS_SOUND_PERIOD); // in ms ioctl(g_waveDevice, AUDIO_GETINFO, &sunAudioHeader); currentPos = sunAudioHeader.play.samples; // $$jb: Removing the bit of code that breaks out // of this timing loop on sunAudioHeader.play.error != 0. } while ((currentPos < lastPos) && (lastPos - currentPos < (1 << 28)) && /* see note A */ (g_shutDownDoubleBuffer == FALSE)); // Note A: $$ay: Additional safeguard for wraparound of sample // ------ count from 1 << 32 - 1. Make sure the difference is // not a huge value lastPos += (g_audioByteBufferSize * HAE_SOLARIS_FRAMES_PER_BLOCK) / sampleFrameSize; // ... and reschedule ourselves. } g_activeDoubleBuffer = FALSE; } }
// $$kk: 08.12.98 merge: changed this method to do convert to unsigned data if required by audio hardware void PV_AudioWaveOutFrameThread(void* context) { char *pFillBuffer; long count, currentPos, lastPos, sampleFrameSize; int i; int rc; int bytesWritten; int bytesToWrite; //int avail; count_info audio_info; ioctl(g_waveDevice, SNDCTL_DSP_GETOPTR, &audio_info); // calculate sample size for convertion of bytes to sample frames sampleFrameSize = 1; if (g_bitSize == 16) { sampleFrameSize *= 2; } if (g_channels == 2) { sampleFrameSize *= 2; } // $$ay - sample count is in bytes for linux and not in samples lastPos = audio_info.bytes - ((g_audioByteBufferSize * HAE_LINUX_FRAMES_PER_BLOCK * 2)); if (g_audioBufferBlock) { while ((g_activeDoubleBuffer) && (g_shutDownDoubleBuffer == FALSE)) { /* put sync count and XMicroseconds into relation */ /* could be improved by using actual device sample count */ g_checkpointMicros = XMicroseconds(); g_checkpointSyncCount = GM_GetSyncTimeStamp(); // Generate HAE_LINUX_FRAMES_PER_BLOCK frames of audio pFillBuffer = (char *)g_audioBufferBlock; for (count = 0; count < HAE_LINUX_FRAMES_PER_BLOCK; count++) { // Generate one frame audio HAE_BuildMixerSlice(context, pFillBuffer, g_audioByteBufferSize, g_audioFramesToGenerate); pFillBuffer += g_audioByteBufferSize; if (g_shutDownDoubleBuffer) { break; // time to quit } } // $$kk // for some solaris drivers, we must supply unsigned data when rendering 8 bit data if (g_convertUnsigned && (g_bitSize == 8)) { pFillBuffer = (char *)g_audioBufferBlock; for (i = 0; i < (g_audioByteBufferSize * HAE_LINUX_FRAMES_PER_BLOCK); i++) { *pFillBuffer = (*pFillBuffer >= 0) ? (0x80 | *pFillBuffer) : (0x7F & *pFillBuffer); pFillBuffer++; } } // $$jb: Changing the write() loop to handle cases when the // device is unavailable, or we can't write our entire buffer bytesWritten = 0; bytesToWrite = (g_audioByteBufferSize * HAE_LINUX_FRAMES_PER_BLOCK); while ( bytesToWrite > 0 ) { #ifdef TODO // $$ay: AARGH!!! Linux forces read to be non-blocking when opened for DUPLEX if (!g_openForCapture && g_supportsDuplex) { int k, avail; ioctl(g_waveDevice, SNDCTL_DSP_GETBLKSIZE, &avail); k = read(g_waveDevice, dummyBuffer, avail); //printf("AvailToRead = %d, Read = %d\n", avail, k); //k = read(g_waveDevice, dummyBuffer, sizeof(dummyBuffer)); //printf("Read = %d\n", k); } ioctl(g_waveDevice, SNDCTL_DSP_GETBLKSIZE, &avail); if (bytesToWrite > avail) rc = write(g_waveDevice, ((char *)g_audioBufferBlock+bytesWritten), avail); else rc = write(g_waveDevice, ((char *)g_audioBufferBlock+bytesWritten), bytesToWrite); //printf("Wrote %d bytes\n", rc); #endif //$$fb don't write when it's time to quit. if( g_shutDownDoubleBuffer) { break; } rc = write(g_waveDevice, ((char *)g_audioBufferBlock+bytesWritten), bytesToWrite); if ( rc > 0 ) { bytesWritten += rc; bytesToWrite -= rc; } else { // $$jb: This happens when the device buffers cannot // be written to. Make sure we're not shutting down and // sleep a bit so that we don't completely hog the CPU if( g_shutDownDoubleBuffer == FALSE ) { HAE_SleepFrameThread(context, HAE_LINUX_SOUND_PERIOD); } else { break; } } } // O.k. We're done for now. // Let the rest of the system know we're done .... ioctl(g_waveDevice, SNDCTL_DSP_GETOPTR, &audio_info); currentPos = audio_info.bytes; // $$jb: We have successfully written all our bytes. // If we encountered a problem while writing, play.error will be 1. // This should be reset. #ifdef TODO if ( sunAudioHeader.play.error != 0 ) { AUDIO_INITINFO(&sunAudioHeader); sunAudioHeader.play.error = 0; ioctl(g_waveDevice, AUDIO_SETINFO, &sunAudioHeader); } #endif while ((currentPos < lastPos) && (g_shutDownDoubleBuffer == FALSE)) { HAE_SleepFrameThread(context, HAE_LINUX_SOUND_PERIOD); // in ms ioctl(g_waveDevice, SNDCTL_DSP_GETOPTR, &audio_info); currentPos = audio_info.bytes; // $$jb: Removing the bit of code that breaks out // of this timing loop on sunAudioHeader.play.error != 0. } lastPos += (g_audioByteBufferSize * HAE_LINUX_FRAMES_PER_BLOCK); // ... and reschedule ourselves. } TRACE0("g_activeDoubleBuffer = FALSE;\n"); g_activeDoubleBuffer = FALSE; } }