static void S9xAudioCallback(void*) { S9xFinalizeSamples(); size_t avail = S9xGetSampleCount(); S9xMixSamples((uint8*)audio_buf, avail); for (size_t i = 0; i < avail; i+=2) s9x_audio_cb((uint16_t)audio_buf[i], (uint16_t)audio_buf[i + 1]); }
static void S9xAudioCallback() { size_t avail; /* Just pick a big buffer. We won't use it all. */ static int16_t audio_buf[0x10000]; S9xFinalizeSamples(); avail = S9xGetSampleCount(); S9xMixSamples(audio_buf, avail); audio_batch_cb(audio_buf, avail >> 1); }
static void S9xAudioCallback() { // Just pick a big buffer. We won't use it all. static int16_t audio_buf[0x10000]; S9xFinalizeSamples(); size_t avail = S9xGetSampleCount(); S9xMixSamples(audio_buf, avail); for (size_t i = 0; i < avail; i+=2) s9x_audio_cb((uint16_t)audio_buf[i], (uint16_t)audio_buf[i + 1]); }
static void S9xAudioCallback(void*) { const int BUFFER_SIZE = 256; // This is called every time 128 to 132 samples are generated, which happens about 8 times per frame. A buffer size of 256 samples is enough here. static int16_t audio_buf[BUFFER_SIZE]; S9xFinalizeSamples(); size_t avail = S9xGetSampleCount(); while (avail >= BUFFER_SIZE) { //this loop will never be entered, but handle oversized sample counts just in case S9xMixSamples((uint8*)audio_buf, BUFFER_SIZE); audio_batch_cb(audio_buf, BUFFER_SIZE >> 1); avail -= BUFFER_SIZE; } if (avail > 0) { S9xMixSamples((uint8*)audio_buf, avail); audio_batch_cb(audio_buf, avail >> 1); }
static void AQBufferCallback( void *userdata, AudioQueueRef outQ, AudioQueueBufferRef outQB) { outQB->mAudioDataByteSize = SI_SoundBufferSizeBytes; AudioQueueSetParameter(outQ, kAudioQueueParam_Volume, SI_AudioVolume); if(SI_EmulationPaused || !SI_EmulationRun || !SI_SoundIsInit) { SI_AudioIsOnHold = 1; memset(outQB->mAudioData, 0, SI_SoundBufferSizeBytes); } else { SI_AudioIsOnHold = 0; int available = S9xGetSampleCount()*2; if(available > SI_SoundBufferSizeBytes) available = SI_SoundBufferSizeBytes; S9xMixSamples((unsigned char*)outQB->mAudioData, available/2); if(available < SI_SoundBufferSizeBytes) { if(available == 0) { // do nothing here... we didn't copy anything... scared that if i write something to the output buffer, we'll get chirps and stuff } else { //printf("Fixing\n"); // sounds wiggly memset(((unsigned char*)outQB->mAudioData)+available, ((unsigned char*)outQB->mAudioData)[available-1], SI_SoundBufferSizeBytes-available); // sounds a little skippedly //memset(((unsigned char*)outQB->mAudioData)+available, *(int*)(((unsigned char*)outQB->mAudioData)+(available-3)), SI_SoundBufferSizeBytes-available); } } } AudioQueueEnqueueBuffer(outQ, outQB, 0, NULL); }
FMOD_RESULT F_CALLBACK CFMODEx::FMODExStreamCallback( FMOD_SOUND * sound, void * data, unsigned int datalen ) { int sample_count = datalen; sample_count >>= (Settings.SixteenBitSound?1:0); EnterCriticalSection(&GUI.SoundCritSect); S9xMixSamples((unsigned char *) data, sample_count); LeaveCriticalSection(&GUI.SoundCritSect); SetEvent(GUI.SoundSyncEvent); return FMOD_OK; }
/* get samples ---------------------------------------------------------------- */ void SPC_update(unsigned char *buf) { // APU_LOOP int c, ic, oc; BCOLOR(255, 0, 0); /* VP : rewrote this loop, it was completely wrong in original spcxmms-0.2.1 */ for (c = 0; c < 2048000 / RATE; ) { oc = c; for (ic = c + 256; c < ic; ) { int cycles; cycles = S9xAPUCycleLengths [*IAPU.PC]; (*S9xApuOpcodes[*IAPU.PC]) (); //APU_EXECUTE1(); if (IAPU.Slowdown > 0) { /* VP : in slowdown mode, SPC executes 2^SPC_slowdown_cycle_shift times slower */ c += cycles << SPC_slowdown_cycle_shift; IAPU.Slowdown --; } else { /* VP : no slowdown, normal speed of the SPC */ c += cycles; } } /* VP : Execute timer required number of times */ for (ic = 0; ic < (c / 32) - (oc / 32) ; ic++) { IAPU.TimerErrorCounter ++; DoTimer(); } } BCOLOR(255, 255, 0); S9xMixSamples ((unsigned char *)buf, samples_per_mix); BCOLOR(0, 0, 0); }
/* CXAudio2::ProcessSound The mixing function called by the sound core when new samples are available. SoundBuffer is divided into blockCount blocks. If there are enought available samples and a free block, the block is filled and queued to the source voice. bufferCount is increased by pushbuffer and decreased by the OnBufferComplete callback. */ void CXAudio2::ProcessSound() { S9xFinalizeSamples(); if(!initDone) return; BYTE * curBuffer; UINT32 availableSamples; UINT32 availableBytes; availableSamples = S9xGetSampleCount(); availableBytes = availableSamples * (Settings.SixteenBitSound ? 2 : 1); while(availableSamples > singleBufferSamples && bufferCount < blockCount) { curBuffer = soundBuffer + writeOffset; S9xMixSamples(curBuffer,singleBufferSamples); PushBuffer(singleBufferBytes,curBuffer,NULL); writeOffset+=singleBufferBytes; writeOffset%=sum_bufferSize; } }
/* get samples ---------------------------------------------------------------- */ void SPC_update(unsigned char *buf) { // APU_LOOP int c, ic; #if 1 for (c = 0; c < 2048000 / 32 / RATE; c ++) { for (ic = 0; ic < 32; ic ++) APU_EXECUTE1(); IAPU.TimerErrorCounter ++; DoTimer(); } #else for (APU.Cycles = 0; APU.Cycles < 204800 / RATE; APU.Cycles ++) { APU_EXECUTE1(); ++ IAPU.TimerErrorCounter; if ((IAPU.TimerErrorCounter & 31) == 0) DoTimer(); APURegisters.PC = IAPU.PC - IAPU.RAM; S9xAPUPackStatus(); } #endif S9xMixSamples ((unsigned char *)buf, samples_per_mix); }
int SnesEmu::fillAudioBuffer(char *stream, int streamSize) { int count = qMin(streamSize/4, soundSampleCount); S9xMixSamples((s16 *)stream, count * 2); return count * 4; }
static void AQBufferCallback( void *userdata, AudioQueueRef outQ, AudioQueueBufferRef outQB) { outQB->mAudioDataByteSize = SI_SoundBufferSizeBytes; AudioQueueSetParameter(outQ, kAudioQueueParam_Volume, SI_AudioVolume); if(SI_EmulationPaused || !SI_EmulationRun || !SI_SoundIsInit) { SI_AudioIsOnHold = 1; SI_AudioOffset = 0; memset(outQB->mAudioData, 0, SI_SoundBufferSizeBytes); } else { SI_AudioIsOnHold = 0; //static int i = 0; //printf("willLock %i\n", i); //printf("locked %i\n", i); //i++; int totalSamples = S9xGetSampleCount(); int totalBytes = totalSamples; int samplesToUse = totalSamples; int bytesToUse = totalBytes; if(Settings.SixteenBitSound == true) { bytesToUse *= 2; totalBytes *= 2; } if(bytesToUse > SI_SoundBufferSizeBytes) { bytesToUse = SI_SoundBufferSizeBytes; if(Settings.SixteenBitSound == true) samplesToUse = SI_SoundBufferSizeBytes/2; else samplesToUse = SI_SoundBufferSizeBytes; } // calculating the audio offset int samplesShouldBe = SI_SoundBufferSizeBytes; if(Settings.SixteenBitSound == true) samplesShouldBe = SI_SoundBufferSizeBytes/2; SI_AudioOffset -= (totalSamples-samplesShouldBe)*(1.0/Settings.SoundPlaybackRate)*1000-50; if(SI_AudioOffset > 8000) SI_AudioOffset = 4000; else if(SI_AudioOffset < -8000) SI_AudioOffset = -4000; //SI_AudioOffset = 900; // -900 is the magic number for this emulator running on iOS Simulator on my computer //printf("AudioOffset: %i\n", SI_AudioOffset); if(samplesToUse > 0) S9xMixSamples((unsigned char*)outQB->mAudioData, samplesToUse); if(bytesToUse < SI_SoundBufferSizeBytes) { if(bytesToUse == 0) { // do nothing here... we didn't copy anything... scared that if i write something to the output buffer, we'll get chirps and stuff //printf("0 sampes available\n"); } else { //printf("Fixing %i of %i\n", bytesToUse, SI_SoundBufferSizeBytes); // sounds wiggly memset(((unsigned char*)outQB->mAudioData)+bytesToUse, ((unsigned char*)outQB->mAudioData)[bytesToUse-1], SI_SoundBufferSizeBytes-bytesToUse); } } } AudioQueueEnqueueBuffer(outQ, outQB, 0, NULL); }
static int Run(int sound) { int skip=0, done=0, doneLast=0,aim=0,i; Settings.NextAPUEnabled = Settings.APUEnabled = sound; sal_TimerInit(Settings.FrameTime); done=sal_TimerRead()-1; if (sound) { /* Settings.SoundPlaybackRate = mMenuOptions.soundRate; Settings.Stereo = mMenuOptions.stereo ? TRUE : FALSE; */ Settings.SixteenBitSound=true; sal_AudioInit(mMenuOptions.soundRate, 16, mMenuOptions.stereo, Memory.ROMFramesPerSecond); S9xInitSound (mMenuOptions.soundRate, mMenuOptions.stereo, sal_AudioGetBufferSize()); S9xSetPlaybackRate(mMenuOptions.soundRate); S9xSetSoundMute (FALSE); } else { S9xSetSoundMute (TRUE); } while(!mEnterMenu) { for (i=0;i<10;i++) { aim=sal_TimerRead(); if (done < aim) { done++; if (mMenuOptions.frameSkip == 0) //Auto IPPU.RenderThisFrame = (done >= aim); else if (IPPU.RenderThisFrame = (--skip <= 0)) skip = mMenuOptions.frameSkip; //Run SNES for one glorious frame S9xMainLoop (); if (sound) { S9xMixSamples((uint8 *) sal_GetCurrentAudioBuffer(), sal_AudioGetSampleCount()); sal_SubmitSamples(); } // HandleQuickStateRequests(); } if (done>=aim) break; // Up to date now if (mEnterMenu) break; } done=aim; // Make sure up to date HandleQuickStateRequests(); } if (sound) sal_AudioClose(); mEnterMenu=0; return mEnterMenu; }
void S9xAlsaSoundDriver::samples_available() { snd_pcm_sframes_t frames_written, frames; int bytes; frames = snd_pcm_avail(pcm); if (frames < 0) { frames = snd_pcm_recover(pcm, frames, 1); return; } if (Settings.DynamicRateControl) { S9xUpdateDynamicRate(snd_pcm_frames_to_bytes(pcm, frames), output_buffer_size); } int snes_frames_available = S9xGetSampleCount() >> 1; if (Settings.DynamicRateControl && !Settings.SoundSync) { // Using rate control, we should always keep the emulator's sound buffers empty to // maintain an accurate measurement. if (frames < snes_frames_available) { S9xClearSamples(); return; } } if (Settings.SoundSync && !Settings.TurboMode && !Settings.Mute) { snd_pcm_nonblock(pcm, 0); frames = snes_frames_available; } else { snd_pcm_nonblock(pcm, 1); frames = MIN(frames, snes_frames_available); } bytes = snd_pcm_frames_to_bytes(pcm, frames); if (bytes <= 0) return; if (sound_buffer_size < bytes || sound_buffer == NULL) { sound_buffer = (uint8 *)realloc(sound_buffer, bytes); sound_buffer_size = bytes; } S9xMixSamples(sound_buffer, frames * 2); frames_written = 0; while (frames_written < frames) { int result; result = snd_pcm_writei(pcm, sound_buffer + snd_pcm_frames_to_bytes(pcm, frames_written), frames - frames_written); if (result < 0) { result = snd_pcm_recover(pcm, result, 1); if (result < 0) { break; } } else { frames_written += result; } } }