void __StartLogAudio(const std::string& filename) { if (!m_logAudio) { m_logAudio = true; g_wave_writer.Start(filename, 44100); g_wave_writer.SetSkipSilence(false); NOTICE_LOG(SCEAUDIO, "Starting Audio logging"); } else { WARN_LOG(SCEAUDIO, "Audio logging has already been started"); } }
void Wiimote::SpeakerData(wm_speaker_data* sd) { // TODO consider using static max size instead of new s16 *samples = new s16[sd->length * 2]; if (m_reg_speaker.format == 0x40) { // 8 bit PCM for (int i = 0; i < sd->length; ++i) { samples[i] = (s16)(s8)sd->data[i]; } } else if (m_reg_speaker.format == 0x00) { // 4 bit Yamaha ADPCM (same as dreamcast) for (int i = 0; i < sd->length; ++i) { samples[i * 2] = adpcm_yamaha_expand_nibble(m_adpcm_state, (sd->data[i] >> 4) & 0xf); samples[i * 2 + 1] = adpcm_yamaha_expand_nibble(m_adpcm_state, sd->data[i] & 0xf); } } #ifdef WIIMOTE_SPEAKER_DUMP static int num = 0; if (num == 0) { File::Delete("rmtdump.wav"); File::Delete("rmtdump.bin"); atexit(stopdamnwav); OpenFStream(ofile, "rmtdump.bin", ofile.binary | ofile.out); wav.Start("rmtdump.wav", 6000/*Common::swap16(m_reg_speaker.sample_rate)*/); } wav.AddMonoSamples(samples, sd->length*2); if (ofile.good()) { for (int i = 0; i < sd->length; i++) { ofile << sd->data[i]; } } num++; #endif delete[] samples; }
void __StopLogAudio() { if (m_logAudio) { m_logAudio = false; g_wave_writer.Stop(); NOTICE_LOG(SCEAUDIO, "Stopping Audio logging"); } else { WARN_LOG(SCEAUDIO, "Audio logging has already been stopped"); } }
// Mix samples from the various audio channels into a single sample queue. // This single sample queue is where __AudioMix should read from. If the sample queue is full, we should // just sleep the main emulator thread a little. void __AudioUpdate() { // Audio throttle doesn't really work on the PSP since the mixing intervals are so closely tied // to the CPU. Much better to throttle the frame rate on frame display and just throw away audio // if the buffer somehow gets full. bool firstChannel = true; for (u32 i = 0; i < PSP_AUDIO_CHANNEL_MAX + 1; i++) { if (!chans[i].reserved) continue; __AudioWakeThreads(chans[i], 0, hwBlockSize); if (!chans[i].sampleQueue.size()) { continue; } if (hwBlockSize * 2 > (int)chans[i].sampleQueue.size()) { ERROR_LOG(SCEAUDIO, "Channel %i buffer underrun at %i of %i", i, (int)chans[i].sampleQueue.size() / 2, hwBlockSize); } const s16 *buf1 = 0, *buf2 = 0; size_t sz1, sz2; chans[i].sampleQueue.popPointers(hwBlockSize * 2, &buf1, &sz1, &buf2, &sz2); if (firstChannel) { for (size_t s = 0; s < sz1; s++) mixBuffer[s] = buf1[s]; if (buf2) { for (size_t s = 0; s < sz2; s++) mixBuffer[s + sz1] = buf2[s]; } firstChannel = false; } else { // Surprisingly hard to SIMD efficiently on SSE2 due to lack of 16-to-32-bit sign extension. NEON should be straight-forward though, and SSE4.1 can do it nicely. // Actually, the cmple/pack trick should work fine... for (size_t s = 0; s < sz1; s++) mixBuffer[s] += buf1[s]; if (buf2) { for (size_t s = 0; s < sz2; s++) mixBuffer[s + sz1] += buf2[s]; } } } if (firstChannel) { // Nothing was written above, let's memset. memset(mixBuffer, 0, hwBlockSize * 2 * sizeof(s32)); } if (g_Config.bEnableSound) { resampler.PushSamples(mixBuffer, hwBlockSize); #ifndef MOBILE_DEVICE if (!m_logAudio) { if (g_Config.bDumpAudio) { std::string audio_file_name = GetSysDirectory(DIRECTORY_AUDIO) + "audiodump.wav"; // Create the path just in case it doesn't exist File::CreateDir(GetSysDirectory(DIRECTORY_AUDIO)); File::CreateEmptyFile(audio_file_name); __StartLogAudio(audio_file_name); } } else { if (g_Config.bDumpAudio) { for (int i = 0; i < hwBlockSize * 2; i++) { clampedMixBuffer[i] = clamp_s16(mixBuffer[i]); } g_wave_writer.AddStereoSamples(clampedMixBuffer, hwBlockSize); } else { __StopLogAudio(); } } #endif } }
void stopdamnwav(){wav.Stop();ofile.close();}