static int streamThread(unsigned int args, void* arg){ int vol, dec_vol; for(;;) { // A pretty bad way to close thread if(termStream){ termStream = false; if (bgm_chn != 0xDEAD){ sceAudioOutReleasePort(bgm_chn); bgm_chn = 0xDEAD; } sceKernelExitDeleteThread(0); } sceKernelWaitSema(BGM_Mutex, 1, NULL); if (BGM == NULL || (!BGM->isPlaying)){ sceKernelSignalSema(BGM_Mutex, 1); continue; } // Seems like audio ports are thread dependant on PSVITA :/ if (BGM->isNewTrack){ uint8_t audio_mode = BGM->isStereo ? SCE_AUDIO_OUT_MODE_STEREO : SCE_AUDIO_OUT_MODE_MONO; int nsamples = AUDIO_BUFSIZE / ((audio_mode+1)<<1); if (bgm_chn == 0xDEAD) bgm_chn = sceAudioOutOpenPort(SCE_AUDIO_OUT_PORT_TYPE_MAIN, nsamples, 48000, audio_mode); sceAudioOutSetConfig(bgm_chn, nsamples, 48000, audio_mode); vol = BGM->vol * 327; int vol_stereo[] = {vol, vol}; sceAudioOutSetVolume(bgm_chn, SCE_AUDIO_VOLUME_FLAG_L_CH | SCE_AUDIO_VOLUME_FLAG_R_CH, vol_stereo); BGM->isNewTrack = false; } // Volume changes support dec_vol = audio_decoder->GetVolume(); if (dec_vol != vol){ vol = dec_vol * 327; int vol_stereo[] = {vol, vol}; sceAudioOutSetVolume(bgm_chn, SCE_AUDIO_VOLUME_FLAG_L_CH | SCE_AUDIO_VOLUME_FLAG_R_CH, vol_stereo); vol = dec_vol; } // Audio streaming feature if (BGM->handle != NULL){ if (BGM->cur_audiobuf == BGM->audiobuf) BGM->cur_audiobuf = BGM->audiobuf2; else BGM->cur_audiobuf = BGM->audiobuf; audio_decoder->Decode(BGM->cur_audiobuf, AUDIO_BUFSIZE); if (audio_decoder->GetLoopCount() > 0){ // EoF BGM->endedOnce = true; } int res = sceAudioOutOutput(bgm_chn, BGM->cur_audiobuf); if (res < 0) Output::Error("An error occurred in audio thread (0x%lX)", res); } sceKernelSignalSema(BGM_Mutex, 1); } }
static void VITAAUD_PlayDevice(_THIS) { Uint8 *mixbuf = this->hidden->mixbufs[this->hidden->next_buffer]; int vols[2] = {SCE_AUDIO_MAX_VOLUME, SCE_AUDIO_MAX_VOLUME}; sceAudioOutSetVolume(this->hidden->channel, SCE_AUDIO_VOLUME_FLAG_L_CH|SCE_AUDIO_VOLUME_FLAG_R_CH, vols); sceAudioOutOutput(this->hidden->channel, mixbuf); this->hidden->next_buffer = (this->hidden->next_buffer + 1) % NUM_BUFFERS; }
static inline int play_blocking(unsigned int channel, unsigned int vol1, unsigned int vol2, void *buf) { if (!sound_ready) return -1; if (channel >= AUDIO_CHANNELS) return -1; int vols[2]={vol1,vol2}; sceAudioOutSetVolume(sound_stream[channel].sound_ch_handle,PSP2_AUDIO_VOLUME_FLAG_L_CH|PSP2_AUDIO_VOLUME_FLAG_R_CH,vols); return sceAudioOutOutput(sound_stream[channel].sound_ch_handle, buf); }
/*** * Outputs the given audio data, in a blocking fashion. */ static int output_audio_blocking(unsigned int channel, unsigned int vol1, unsigned int vol2, void *buf, int length) { if (channel >= AUDIO_CHANNELS) return -1; if (vol1 > PSP_AUDIO_MAX_VOLUME) vol1 = PSP_AUDIO_MAX_VOLUME; if (vol2 > PSP_AUDIO_MAX_VOLUME) vol2 = PSP_AUDIO_MAX_VOLUME; int vols[2] = { vol1, vol2 }; sceAudioOutSetConfig(audio_status[channel].Handle, length, -1, -1); sceAudioOutSetVolume(audio_status[channel].Handle, SCE_AUDIO_VOLUME_FLAG_L_CH | SCE_AUDIO_VOLUME_FLAG_R_CH, vols); return sceAudioOutOutput(audio_status[channel].Handle, buf); }
// Audio thread code static int bgmThread(unsigned int args, void* arg){ // Initializing audio port int ch = sceAudioOutOpenPort(SCE_AUDIO_OUT_PORT_TYPE_MAIN, NSAMPLES, 48000, SCE_AUDIO_OUT_MODE_STEREO); sceAudioOutSetConfig(ch, -1, -1, -1); old_vol = bgmvolume.value; int vol = 32767 * bgmvolume.value; int vol_stereo[] = {vol, vol}; sceAudioOutSetVolume(ch, SCE_AUDIO_VOLUME_FLAG_L_CH | SCE_AUDIO_VOLUME_FLAG_R_CH, vol_stereo); DecodedMusic* mus; for (;;){ // Waiting for an audio output request sceKernelWaitSema(Audio_Mutex, 1, NULL); // Fetching track mus = BGM; // Checking if a new track is available if (mus == NULL){ //If we enter here, we probably are in the exiting procedure if (mustExit){ sceAudioOutReleasePort(ch); mustExit = false; sceKernelExitDeleteThread(0); } } // Initializing audio decoder audio_decoder = AudioDecoder::Create(mus->handle, "Track"); audio_decoder->Open(mus->handle); audio_decoder->SetLooping(mus->loop); audio_decoder->SetFormat(48000, AudioDecoder::Format::S16, 2); // Initializing audio buffers mus->audiobuf = (uint8_t*)malloc(BUFSIZE); mus->audiobuf2 = (uint8_t*)malloc(BUFSIZE); mus->cur_audiobuf = mus->audiobuf; // Audio playback loop for (;;){ // Check if the music must be paused if (mus->pauseTrigger || mustExit){ // Check if the music must be closed if (mus->closeTrigger){ free(mus->audiobuf); free(mus->audiobuf2); audio_decoder.reset(); free(mus); BGM = NULL; if (!mustExit){ sceKernelSignalSema(Talk_Mutex, 1); break; } } // Check if the thread must be closed if (mustExit){ // Check if the audio stream has already been closed if (mus != NULL){ mus->closeTrigger = true; continue; } // Recursively closing all the threads sceAudioOutReleasePort(ch); mustExit = false; sceKernelExitThread(0); } mus->isPlaying = !mus->isPlaying; mus->pauseTrigger = false; } // Check if a volume change is required if (mus->changeVol){ old_vol = bgmvolume.value; int vol = 32767 * bgmvolume.value; int vol_stereo[] = {vol, vol}; sceAudioOutSetVolume(ch, SCE_AUDIO_VOLUME_FLAG_L_CH | SCE_AUDIO_VOLUME_FLAG_R_CH, vol_stereo); mus->changeVol = false; } if (mus->isPlaying){ // Check if audio playback finished if ((!mus->loop) && audio_decoder->IsFinished()) mus->isPlaying = false; // Update audio output if (mus->cur_audiobuf == mus->audiobuf) mus->cur_audiobuf = mus->audiobuf2; else mus->cur_audiobuf = mus->audiobuf; audio_decoder->Decode(mus->cur_audiobuf, BUFSIZE); sceAudioOutOutput(ch, mus->cur_audiobuf); } } } }
static int sfxThread(unsigned int args, void* arg){ int ch = sceAudioOutOpenPort(SCE_AUDIO_OUT_PORT_TYPE_MAIN, 64, 48000, SCE_AUDIO_OUT_MODE_STEREO); if (ch < 0){ Output::Warning("SFX Thread: Cannot open audio port"); sceKernelExitDeleteThread(0); } for (;;){ sceKernelWaitSema(SFX_Mutex, 1, NULL); // Check if the thread must be closed if (mustExit){ sfx_exited++; if (sfx_exited < AUDIO_CHANNELS) sceKernelSignalSema(SFX_Mutex, 1); else mustExit = false; sceAudioOutReleasePort(ch); sceKernelExitDeleteThread(0); } // Pick the next SE that wants to be played sceKernelWaitSema(SFX_Mutex_ID, 1, NULL); int idx = -1; for (int i = 0; i < AUDIO_CHANNELS; ++i) { if (!sfx_sounds[i].isPlaying && !sfx_sounds[i].isFinished) { idx = i; break; } } if (idx == -1) { sceKernelSignalSema(SFX_Mutex_ID, 1); // Shouldn't happen... Output::Warning("No pending SE found"); continue; } else { sfx_sounds[idx].isPlaying = true; sceKernelSignalSema(SFX_Mutex_ID, 1); } DecodedSound& sfx = sfx_sounds[idx]; // Preparing audio port uint8_t audio_mode = sfx.isStereo ? SCE_AUDIO_OUT_MODE_STEREO : SCE_AUDIO_OUT_MODE_MONO; int nsamples = AUDIO_BUFSIZE / ((audio_mode+1)<<1); sceAudioOutSetConfig(ch, nsamples, 48000, audio_mode); int vol = sfx.decoder->GetVolume() * 327; int vol_stereo[] = {vol, vol}; sceAudioOutSetVolume(ch, SCE_AUDIO_VOLUME_FLAG_L_CH | SCE_AUDIO_VOLUME_FLAG_R_CH, vol_stereo); // Playing sound while (!sfx.isFinished){ if (sfx.cur_audiobuf == sfx.audiobuf) sfx.cur_audiobuf = sfx.audiobuf2; else sfx.cur_audiobuf = sfx.audiobuf; sfx.decoder->Decode(sfx.cur_audiobuf, AUDIO_BUFSIZE); sceAudioOutOutput(ch, sfx.cur_audiobuf); if (sfx.decoder->IsFinished()) { // EoF // SE slot is free again sfx.isFinished = true; break; } } } }