/** * audio_sdl_write_sound_buffer(): Write the sound buffer to the audio output. * @param dump_buf Sound dumping buffer. * @return 0 on success; non-zero on error. */ static int audio_sdl_write_sound_buffer(short *dump_buf) { if (dump_buf) { if (audio_get_stereo()) audio_dump_sound_stereo(dump_buf, audio_seg_length); else audio_dump_sound_mono(dump_buf, audio_seg_length); return 0; } SDL_LockAudio(); if (audio_get_stereo()) { #ifdef GENS_X86_ASM if (CPU_Flags & MDP_CPUFLAG_X86_MMX) audio_write_sound_stereo_x86_mmx(Seg_L, Seg_R, (short*)(audio_sdl_audiobuf + audio_sdl_len), audio_seg_length); else #endif audio_write_sound_stereo((short*)(audio_sdl_audiobuf + audio_sdl_len), audio_seg_length); } else { #ifdef GENS_X86_ASM if (CPU_Flags & MDP_CPUFLAG_X86_MMX) audio_write_sound_mono_x86_mmx(Seg_L, Seg_R, (short*)(audio_sdl_audiobuf + audio_sdl_len), audio_seg_length); else #endif audio_write_sound_mono((short*)(audio_sdl_audiobuf + audio_sdl_len), audio_seg_length); } if (audio_get_stereo()) audio_sdl_len += audio_seg_length * 4; else audio_sdl_len += audio_seg_length * 2; SDL_UnlockAudio(); // TODO: Figure out if there's a way to get rid of this. while (audio_sdl_len > 1024 * 2 * 2 * 4) { usleep(500); if (fast_forward) audio_sdl_len = 1024; } //SDL_Delay(1); return 0; }
/** * wav_dump_update(): Update the WAV file. * @return 0 on success; non-zero on error. */ int wav_dump_update(void) { if (!WAV_Dumping || !WAV_File) { if (WAV_File) { fclose(WAV_File); WAV_File = 0; } WAV_Dumping = 0; Sync_Gens_Window_SoundMenu(); return 1; } // TODO: Byteswap on big-endian. short buf[(882 * 2) + 16]; audio_write_sound_buffer(buf); unsigned int length = (audio_seg_length * 2); if (audio_get_stereo()) length *= 2; /* Write the sound data. */ fwrite(buf, 1, length, WAV_File); return 0; }
/** * audio_sdl_init(): Initialize the SDL audio subsystem. * @return 0 on success; non-zero on error. */ static int audio_sdl_init(void) { if (audio_initialized) return -1; // Make sure sound is shut down first. audio_sdl_end(); // Attempt to initialize SDL audio. if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) return -1; // Set up the SDL audio specification. SDL_AudioSpec spec; spec.freq = audio_get_sound_rate(); spec.format = AUDIO_S16SYS; spec.channels = !(audio_get_stereo()) ? 1 : 2; // TODO: Initializing 1 channel seems to double-free if it's later changed... spec.samples = 1024; spec.callback = audio_sdl_callback; spec.userdata = NULL; // Initialize the audio buffer. audio_sdl_audiobuf = (unsigned char*)(calloc(1, (spec.samples * spec.channels * 2 * 4) * sizeof(short))); if (SDL_OpenAudio(&spec, 0) != 0) { // Could not open audio. free(audio_sdl_audiobuf); audio_sdl_audiobuf = NULL; return -2; } SDL_PauseAudio(0); // Sound is initialized. audio_initialized = TRUE; return 0; }
/** * wav_dump_start(): Start dumping a WAV file. * @return 0 on success; non-zero on error. */ int wav_dump_start(void) { #ifdef GENS_OS_WIN32 // Make sure relative pathnames are handled correctly on Win32. pSetCurrentDirectoryU(PathNames.Gens_Save_Path); #endif /* A game must be loaded in order to dump a WAV. */ if (!Game) return 0; if (WAV_Dumping) { vdraw_text_write("WAV sound is already dumping.", 1000); return 0; } /* Build the filename. */ char filename[GENS_PATH_MAX]; int num = -1; do { num++; szprintf(filename, sizeof(filename), "%s%s_%03d.wav", PathNames.Dump_WAV_Dir, ROM_Filename, num); } while (!access(filename, F_OK)); /* Open the file. */ WAV_File = fopen(filename, "wb"); if (!WAV_File) { vdraw_text_write("Error opening WAV file.", 1000); return 1; } /* Create the WAV header. */ memset(&WAV_Header, 0x00, sizeof(WAV_Header)); /* "RIFF" header. */ static const char ChunkID_RIFF[4] = {'R', 'I', 'F', 'F'}; static const char FormatID_WAV[4] = {'W', 'A', 'V', 'E'}; memcpy(WAV_Header.riff.ChunkID, ChunkID_RIFF, sizeof(WAV_Header.riff.ChunkID)); memcpy(WAV_Header.riff.Format, FormatID_WAV, sizeof(WAV_Header.riff.Format)); /* "fmt " header. */ static const char SubchunkID_fmt[4] = {'f', 'm', 't', ' '}; memcpy(WAV_Header.fmt.SubchunkID, SubchunkID_fmt, sizeof(WAV_Header.fmt.SubchunkID)); WAV_Header.fmt.SubchunkSize = cpu_to_le32(sizeof(WAV_Header.fmt) - 8); WAV_Header.fmt.AudioFormat = cpu_to_le16(1); /* PCM */ WAV_Header.fmt.NumChannels = cpu_to_le16((audio_get_stereo() ? 2 : 1)); WAV_Header.fmt.SampleRate = cpu_to_le32(audio_get_sound_rate()); WAV_Header.fmt.BitsPerSample = cpu_to_le16(16); /* Gens is currently hard-coded to 16-bit audio. */ /* Calculated fields. */ WAV_Header.fmt.BlockAlign = cpu_to_le16(WAV_Header.fmt.NumChannels * (WAV_Header.fmt.BitsPerSample / 8)); WAV_Header.fmt.ByteRate = cpu_to_le32(WAV_Header.fmt.BlockAlign * WAV_Header.fmt.SampleRate); /* "data" header. */ static const char SubchunkID_data[4] = {'d', 'a', 't', 'a'}; memcpy(WAV_Header.data.SubchunkID, SubchunkID_data, sizeof(WAV_Header.data.SubchunkID)); /* Write the initial header to the file. */ fwrite(&WAV_Header, sizeof(WAV_Header), 1, WAV_File); /* WAV dump started. */ vdraw_text_write("Starting to dump WAV sound.", 1000); WAV_Dumping = 1; Sync_Gens_Window_SoundMenu(); return 0; }