static int SB_thread(int args, void *argp) { static int whichBuffer = 0; int port = sceAudioOutOpenPort(SCE_AUDIO_OUT_PORT_TYPE_BGM, BUF_SIZE / 4, 44100, SCE_AUDIO_OUT_MODE_STEREO); sceAudioOutSetVolume(port, SCE_AUDIO_VOLUME_FLAG_L_CH | SCE_AUDIO_VOLUME_FLAG_R_CH, (int[]){SCE_AUDIO_VOLUME_0DB, SCE_AUDIO_VOLUME_0DB});
static THREAD_ENTRY _audioThread(void* context) { struct mPSP2AudioContext* audio = (struct mPSP2AudioContext*) context; uint32_t zeroBuffer[PSP2_SAMPLES] = {0}; void* buffer = zeroBuffer; int audioPort = sceAudioOutOpenPort(SCE_AUDIO_OUT_PORT_TYPE_MAIN, PSP2_SAMPLES, 48000, SCE_AUDIO_OUT_MODE_STEREO); while (audio->running) { MutexLock(&audio->mutex); if (buffer != zeroBuffer) { // Can only happen in successive iterations audio->samples -= PSP2_SAMPLES; ConditionWake(&audio->cond); } if (audio->samples >= PSP2_SAMPLES) { buffer = &audio->buffer[audio->readOffset]; audio->readOffset += PSP2_SAMPLES; if (audio->readOffset >= PSP2_AUDIO_BUFFER_SIZE) { audio->readOffset = 0; } // Don't mark samples as read until the next loop iteration to prevent // writing to the buffer while being read (see above) } else { buffer = zeroBuffer; } MutexUnlock(&audio->mutex); sceAudioOutOutput(audioPort, buffer); } sceAudioOutReleasePort(audioPort); return 0; }
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); } }
int main(void) { psvDebugScreenInit(); int freqs[] = {8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000}; int size = 256; int freq = 8; int mode = SCE_AUDIO_OUT_MODE_MONO; int vol = SCE_AUDIO_VOLUME_0DB; int port = sceAudioOutOpenPort(SCE_AUDIO_OUT_PORT_TYPE_BGM, size, freqs[freq], mode); sceAudioOutSetVolume(port, SCE_AUDIO_VOLUME_FLAG_L_CH |SCE_AUDIO_VOLUME_FLAG_R_CH, (int[]){vol,vol});
static int audioMainLoop(SceSize args, void* argp) { psp_audio_t* psp = *((psp_audio_t**)argp); #ifdef VITA int port = sceAudioOutOpenPort(PSP2_AUDIO_OUT_PORT_TYPE_MAIN, AUDIO_OUT_COUNT, psp->rate, PSP2_AUDIO_OUT_MODE_STEREO); #else sceAudioSRCChReserve(AUDIO_OUT_COUNT, psp->rate, 2); #endif while (psp->running) { /* Get a non-volatile copy. */ uint16_t readPos = psp->readPos; bool cond = ((uint16_t)(psp->writePos - readPos) & AUDIO_BUFFER_SIZE_MASK) < (AUDIO_OUT_COUNT * 2); #ifdef VITA sceAudioOutOutput(port, cond ? psp->zeroBuffer : (psp->buffer + readPos)); #else sceAudioSRCOutputBlocking(PSP_AUDIO_VOLUME_MAX, cond ? (psp->zeroBuffer) : (psp->buffer + readPos)); #endif if (!cond) { readPos += AUDIO_OUT_COUNT; readPos &= AUDIO_BUFFER_SIZE_MASK; psp->readPos = readPos; } } #ifdef VITA sceAudioOutReleasePort(port); #else sceAudioSRCChRelease(); #endif sceKernelExitThread(0); return 0; }
/*** * Initializes the audio buffers and a callback thread for each channel. */ int setup_audio() { int i, j, failed; stop_audio = 0; for (i = 0; i < AUDIO_CHANNELS; i++) { audio_status[i].Handle = -1; audio_status[i].ThreadHandle = -1; audio_status[i].LeftVolume = PSP_AUDIO_MAX_VOLUME; audio_status[i].RightVolume = PSP_AUDIO_MAX_VOLUME; audio_status[i].Callback = NULL; audio_status[i].Userdata = NULL; for (j = 0; j < 2; j++) { audio_buffer[i][j] = NULL; audio_buffer_samples[i][j] = 0; } } /* Initialize buffers */ for (i = 0; i < AUDIO_CHANNELS; i++) { for (j = 0; j < 2; j++) { if (!(audio_buffer[i][j] = (short*)malloc(AUDIO_SAMPLE_COUNT * sizeof(PspStereoSample)))) { printf("Couldn't initialize audio buffer for channel %i, bailing.", i); free_buffers(); sceKernelExitProcess(0); return 0; } audio_buffer_samples[i][j] = AUDIO_SAMPLE_COUNT; } } /* Initialize channels */ for (i = 0, failed = 0; i < AUDIO_CHANNELS; i++) { audio_status[i].Handle = sceAudioOutOpenPort(SCE_AUDIO_OUT_PORT_TYPE_VOICE, AUDIO_SAMPLE_COUNT, AUDIO_OUTPUT_RATE, SCE_AUDIO_OUT_MODE_STEREO); if (audio_status[i].Handle < 0) { failed = 1; break; } } if (failed) { for (i = 0; i < AUDIO_CHANNELS; i++) { if (audio_status[i].Handle != -1) { sceAudioOutReleasePort(audio_status[i].Handle); audio_status[i].Handle = -1; } } printf("Couldn't open audio port for the device, bailing."); free_buffers(); sceKernelExitProcess(0); return 0; } char label[16]; strcpy(label, "audiotX"); for (i = 0; i < AUDIO_CHANNELS; i++) { label[6] = '0' + i; audio_status[i].ThreadHandle = sceKernelCreateThread(label, (void*)&audio_channel_thread, 0x10000100, 0x10000, 0, 0, NULL); if (audio_status[i].ThreadHandle < 0) { audio_status[i].ThreadHandle = -1; failed = 1; break; } if (sceKernelStartThread(audio_status[i].ThreadHandle, sizeof(i), &i) != 0) { failed = 1; break; } } if (failed) { stop_audio = 1; for (i = 0; i < AUDIO_CHANNELS; i++) { if (audio_status[i].ThreadHandle != -1) { sceKernelDeleteThread(audio_status[i].ThreadHandle); } audio_status[i].ThreadHandle = -1; } printf("Couldn't initialize audio callback thread. Bailing."); sceKernelExitProcess(0); return 0; } // initialize the buffer our libretro audio callback will fill with data as it's available retro_audio_callback_buffer = (int16_t*)malloc(sizeof(int16_t) * AUDIO_SAMPLE_COUNT * 4); if (!retro_audio_callback_buffer) { printf("Couldn't initialize retro_audio_callback_buffer. Bailing."); sceKernelExitProcess(0); } curr_buffer_frames = 0; // setup our callbacks set_audio_channel_callback(0, audio_callback, 0); // initialize the audio buffer mutex audio_mutex = sceKernelCreateMutex("AudioMutex", 0, 1, 0); return AUDIO_SAMPLE_COUNT; }
static int VITAAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { int format, mixlen, i; this->hidden = (struct SDL_PrivateAudioData *) SDL_malloc(sizeof(*this->hidden)); if (this->hidden == NULL) { return SDL_OutOfMemory(); } SDL_memset(this->hidden, 0, sizeof(*this->hidden)); switch (this->spec.format & 0xff) { case 8: case 16: this->spec.format = AUDIO_S16LSB; break; default: return SDL_SetError("Unsupported audio format"); } /* The sample count must be a multiple of 64. */ this->spec.samples = SCE_AUDIO_SAMPLE_ALIGN(this->spec.samples); this->spec.freq = 48000; /* Update the fragment size as size in bytes. */ /* SDL_CalculateAudioSpec(this->spec); MOD */ switch (this->spec.format) { case AUDIO_U8: this->spec.silence = 0x80; break; default: this->spec.silence = 0x00; break; } this->spec.size = SDL_AUDIO_BITSIZE(this->spec.format) / 8; this->spec.size *= this->spec.channels; this->spec.size *= this->spec.samples; /* ========================================== */ /* Allocate the mixing buffer. Its size and starting address must be a multiple of 64 bytes. Our sample count is already a multiple of 64, so spec->size should be a multiple of 64 as well. */ mixlen = this->spec.size * NUM_BUFFERS; this->hidden->rawbuf = (Uint8 *) memalign(64, mixlen); if (this->hidden->rawbuf == NULL) { return SDL_SetError("Couldn't allocate mixing buffer"); } /* Setup the hardware channel. */ if (this->spec.channels == 1) { format = SCE_AUDIO_OUT_MODE_MONO; } else { format = SCE_AUDIO_OUT_MODE_STEREO; } this->hidden->channel = sceAudioOutOpenPort(SCE_AUDIO_OUT_PORT_TYPE_MAIN, this->spec.samples, this->spec.freq, format); if (this->hidden->channel < 0) { free(this->hidden->rawbuf); this->hidden->rawbuf = NULL; return SDL_SetError("Couldn't reserve hardware channel"); } memset(this->hidden->rawbuf, 0, mixlen); for (i = 0; i < NUM_BUFFERS; i++) { this->hidden->mixbufs[i] = &this->hidden->rawbuf[i * this->spec.size]; } this->hidden->next_buffer = 0; return 0; }
// 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); } } } }
int pl_snd_init(int sample_count, int stereo) { int i, j, failed; sound_stop = 0; sound_ready = 0; /* Check sample count */ if (sample_count <= 0) sample_count = DEFAULT_SAMPLES; sample_count = PL_SND_ALIGN_SAMPLE(sample_count); pl_snd_channel_info *ch_info; for (i = 0; i < AUDIO_CHANNELS; i++) { ch_info = &sound_stream[i]; ch_info->sound_ch_handle = -1; ch_info->thread_handle = -1; ch_info->left_vol = VOLUME_MAX; ch_info->right_vol = VOLUME_MAX; ch_info->callback = NULL; ch_info->user_data = NULL; ch_info->paused = 1; ch_info->stereo = stereo; for (j = 0; j < 2; j++) { ch_info->sample_buffer[j] = NULL; ch_info->samples[j] = 0; } } /* Initialize buffers */ for (i = 0; i < AUDIO_CHANNELS; i++) { ch_info = &sound_stream[i]; for (j = 0; j < 2; j++) { if (!(ch_info->sample_buffer[j] = (short*)malloc(sample_count * get_bytes_per_sample(i)))) { free_buffers(); return 0; } ch_info->samples[j] = sample_count; } } /* Initialize channels */ for (i = 0, failed = 0; i < AUDIO_CHANNELS; i++) { sound_stream[i].sound_ch_handle = sceAudioOutOpenPort(PSP2_AUDIO_OUT_PORT_TYPE_MAIN, sample_count, 48000, (stereo) ? PSP2_AUDIO_OUT_MODE_STEREO : PSP2_AUDIO_OUT_MODE_MONO); if (sound_stream[i].sound_ch_handle < 0) { failed = 1; break; } } if (failed) { for (i = 0; i < AUDIO_CHANNELS; i++) { if (sound_stream[i].sound_ch_handle != -1) { sceAudioOutReleasePort(sound_stream[i].sound_ch_handle); sound_stream[i].sound_ch_handle = -1; } } free_buffers(); return 0; } sound_ready = 1; char label[16]; strcpy(label, "audiotX"); for (i = 0; i < AUDIO_CHANNELS; i++) { label[6] = '0' + i; sound_stream[i].thread_handle = sceKernelCreateThread(label, (void*)&channel_thread, 0x10000100, 0x10000, 0, 0, NULL); if (sound_stream[i].thread_handle < 0) { sound_stream[i].thread_handle = -1; failed = 1; break; } if (sceKernelStartThread(sound_stream[i].thread_handle, sizeof(i), &i) != 0) { failed = 1; break; } } if (failed) { sound_stop = 1; for (i = 0; i < AUDIO_CHANNELS; i++) { if (sound_stream[i].thread_handle != -1) { //sceKernelWaitThreadEnd(sound_stream[i].threadhandle,NULL); sceKernelDeleteThread(sound_stream[i].thread_handle); } sound_stream[i].thread_handle = -1; } sound_ready = 0; free_buffers(); return 0; } return sample_count; }
static int audioMainLoop(SceSize args, void* argp) { psp_audio_t* psp = *((psp_audio_t**)argp); #ifdef VITA int port = sceAudioOutOpenPort(SCE_AUDIO_OUT_PORT_TYPE_MAIN, AUDIO_OUT_COUNT, psp->rate, SCE_AUDIO_OUT_MODE_STEREO); #else sceAudioSRCChReserve(AUDIO_OUT_COUNT, psp->rate, 2); #endif while (psp->running) { #ifdef VITA //sys_event_queue_receive(id, &event, SYS_NO_TIMEOUT); sceKernelLockLwMutex((struct SceKernelLwMutexWork*)&psp->lock, 1, 0); uint16_t readPos = psp->readPos; uint16_t readPos2 = psp->readPos; bool cond = ((uint16_t)(psp->writePos - readPos) & AUDIO_BUFFER_SIZE_MASK) < (AUDIO_OUT_COUNT * 2); if (!cond) { readPos += AUDIO_OUT_COUNT; readPos &= AUDIO_BUFFER_SIZE_MASK; psp->readPos = readPos; } sceKernelUnlockLwMutex((struct SceKernelLwMutexWork*)&psp->lock, 1); sceKernelSignalLwCond(&psp->cond); sceAudioOutOutput(port, cond ? (psp->zeroBuffer) : (psp->buffer + readPos2)); #else /* Get a non-volatile copy. */ uint16_t readPos = psp->readPos; bool cond = ((uint16_t)(psp->writePos - readPos) & AUDIO_BUFFER_SIZE_MASK) < (AUDIO_OUT_COUNT * 2); sceAudioSRCOutputBlocking(PSP_AUDIO_VOLUME_MAX, cond ? (psp->zeroBuffer) : (psp->buffer + readPos)); if (!cond) { readPos += AUDIO_OUT_COUNT; readPos &= AUDIO_BUFFER_SIZE_MASK; psp->readPos = readPos; } #endif } #ifdef VITA sceAudioOutReleasePort(port); #else sceAudioSRCChRelease(); sceKernelExitThread(0); #endif return 0; }
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; } } } }