Fixed sound issues and resource leaks related to that

This commit is contained in:
tudnai 2020-06-27 16:54:02 -07:00
parent 4751c59fad
commit cb498c415c
6 changed files with 132 additions and 64 deletions

View File

@ -126,9 +126,6 @@
32F8A8A724A3A98D00EE6735 /* XPS Diagnostic IIe.woz in Copy Disk Images */ = {isa = PBXBuildFile; fileRef = 32440B8B247F86D5000F9DA1 /* XPS Diagnostic IIe.woz */; };
32F8A8A824A3A98D00EE6735 /* LOCKSMITH_V7_REV_B.woz in Copy Disk Images */ = {isa = PBXBuildFile; fileRef = 32440BA0247F9F99000F9DA1 /* LOCKSMITH_V7_REV_B.woz */; };
32F8A8A924A3A98D00EE6735 /* locksmith_v6.0.woz in Copy Disk Images */ = {isa = PBXBuildFile; fileRef = 32F2C144249218A400FDC61B /* locksmith_v6.0.woz */; };
32F8A8AB24A3AAD300EE6735 /* diskmotor.sfx in Copy SFX Files */ = {isa = PBXBuildFile; fileRef = 323D043D248F70930086A901 /* diskmotor.sfx */; };
32F8A8AC24A3AAD300EE6735 /* diskarm.sfx in Copy SFX Files */ = {isa = PBXBuildFile; fileRef = 323D0441248F711F0086A901 /* diskarm.sfx */; };
32F8A8AD24A3AAD300EE6735 /* diskioerr.sfx in Copy SFX Files */ = {isa = PBXBuildFile; fileRef = 323D043F248F70A10086A901 /* diskioerr.sfx */; };
32F8A8AF24A3AB5900EE6735 /* apple-rainbow.png in Copy Image Files */ = {isa = PBXBuildFile; fileRef = 32E21BE62491BF8B006C0C72 /* apple-rainbow.png */; };
32F8A8B024A3AB5D00EE6735 /* scanlines.png in Copy Image Files */ = {isa = PBXBuildFile; fileRef = 323D04452490BA1E0086A901 /* scanlines.png */; };
/* End PBXBuildFile section */
@ -247,9 +244,6 @@
32E3126724A7194900E61891 /* disk_ii_arm.sfx in Copy SFX Files */,
3296223A24A710E5002DEB78 /* disk_ii_io_error.sfx in Copy SFX Files */,
3296223624A709EE002DEB78 /* disk_ii_motor_w_floppy.sfx in Copy SFX Files */,
32F8A8AB24A3AAD300EE6735 /* diskmotor.sfx in Copy SFX Files */,
32F8A8AC24A3AAD300EE6735 /* diskarm.sfx in Copy SFX Files */,
32F8A8AD24A3AAD300EE6735 /* diskioerr.sfx in Copy SFX Files */,
);
name = "Copy SFX Files";
runOnlyForDeploymentPostprocessing = 0;

View File

@ -181,8 +181,8 @@ extern double mhz;
#define DEF_VIDEO_DIV 1U
#define DEF_SPKR_DIV 1U
#define GAME_FPS 300U
#define GAME_VIDEO_DIV 5U // 300 / 5 = 60 FPS
#define GAME_FPS 600U
#define GAME_VIDEO_DIV 10U // 600 / 10 = 60 FPS
extern unsigned int video_fps_divider;
extern unsigned int fps;

View File

@ -58,6 +58,7 @@ int spkr_level = SPKR_LEVEL_ZERO;
#define BUFFER_COUNT 256
#define SOURCES_COUNT 4
#define SPKR_CHANNELS 2
ALuint spkr_src [SOURCES_COUNT] = { 0, 0, 0, 0 };
@ -77,9 +78,9 @@ const unsigned spkr_sample_rate = 44100;
const unsigned sfx_sample_rate = 22050; // original sample rate
//const unsigned sfx_sample_rate = 26000; // bit higher pitch
int spkr_extra_buf = 0; // 800 / spkr_fps;
const unsigned spkr_buf_alloc_size = spkr_seconds * spkr_sample_rate * 2 / DEFAULT_FPS;
const unsigned spkr_buf_alloc_size = spkr_seconds * spkr_sample_rate * SPKR_CHANNELS / DEFAULT_FPS;
unsigned spkr_buf_size = spkr_buf_alloc_size;
int16_t spkr_samples [ spkr_buf_alloc_size * DEFAULT_FPS * BUFFER_COUNT * 2]; // stereo
int16_t spkr_samples [ spkr_buf_alloc_size * DEFAULT_FPS * BUFFER_COUNT * SPKR_CHANNELS]; // stereo
unsigned spkr_sample_idx = 0;
unsigned spkr_play_timeout = 8; // increase to 32 for 240 fps, normally 8 for 30 fps
@ -95,6 +96,8 @@ int diskarm_sfx_len = 0;
uint8_t * diskioerr_sfx = NULL;
int diskioerr_sfx_len = 0;
ALint freeBuffers = BUFFER_COUNT;
static int load_sfx( const char * bundlePath, const char * filename, uint8_t ** buf ) {
char fullPath[256];
@ -237,11 +240,48 @@ void spkr_init() {
freeBuffers = BUFFER_COUNT;
}
int spkr_unqueue( ALuint src ) {
ALint processed = 0;
alGetSourcei ( src, AL_BUFFERS_PROCESSED, &processed );
al_check_error();
printf("%s alGetSourcei(%d)\n", __FUNCTION__, src);
if ( processed ) {
alSourceUnqueueBuffers( src, processed, &spkr_buffers[freeBuffers]);
al_check_error();
}
return processed;
}
void spkr_unqueueAll() {
for ( int i = 0; i < SOURCES_COUNT; i++ ) {
spkr_unqueue( spkr_src[i] );
}
}
// Dealloc OpenAL
void spkr_exit() {
if ( spkr_src[SPKR_SRC_GAME_SFX] ) {
alSourceStop( spkr_src[SPKR_SRC_GAME_SFX] );
spkr_stopAll();
spkr_unqueueAll();
// delete buffers
alDeleteBuffers(BUFFER_COUNT, spkr_buffers);
al_check_error();
alDeleteBuffers(1, &spkr_disk_motor_buf);
al_check_error();
alDeleteBuffers(1, &spkr_disk_arm_buf);
al_check_error();
// delete sound source and play buffer
alDeleteSources(SOURCES_COUNT, spkr_src);
al_check_error();
ALCdevice *dev = NULL;
ALCcontext *ctx = NULL;
ctx = alcGetCurrentContext();
@ -280,7 +320,7 @@ void spkr_toggle() {
// push a click into the speaker buffer
// (we will play the entire buffer at the end of the frame)
spkr_sample_idx = ( (spkr_clk + clkfrm) / ( MHZ(default_MHz_6502) / spkr_sample_rate)) * 2;
spkr_sample_idx = ( (spkr_clk + clkfrm) / ( MHZ(default_MHz_6502) / spkr_sample_rate)) * SPKR_CHANNELS;
if ( spkr_state ) {
// down edge
@ -290,7 +330,7 @@ void spkr_toggle() {
while ( fadeLevel > +1 ) {
spkr_samples[ spkr_sample_idx++ ] = SPKR_LEVEL_MIN + fadeLevel;
spkr_samples[ spkr_sample_idx++ ] = SPKR_LEVEL_MIN + fadeLevel;
spkr_samples[ spkr_sample_idx++ ] = SPKR_LEVEL_MIN + fadeLevel; // stereo
// how smooth we want the speeker to decay, so we will hear no pops and crackles
// 0.9 gives you a kind of saw wave at 1KHz (beep)
@ -307,7 +347,7 @@ void spkr_toggle() {
while ( fadeLevel < -1 ) {
spkr_samples[ spkr_sample_idx++ ] = SPKR_LEVEL_MAX + fadeLevel;
spkr_samples[ spkr_sample_idx++ ] = SPKR_LEVEL_MAX + fadeLevel;
spkr_samples[ spkr_sample_idx++ ] = SPKR_LEVEL_MAX + fadeLevel; // stereo
// how smooth we want the speeker to decay, so we will hear no pops and crackles
// 0.9 gives you a kind of saw wave at 1KHz (beep)
@ -328,25 +368,8 @@ void spkr_toggle() {
}
ALint freeBuffers = BUFFER_COUNT;
//ALuint alBuffers[BUFFER_COUNT];
int spkr_unqueue( ALuint src ) {
ALint processed = 0;
alGetSourcei ( src, AL_BUFFERS_PROCESSED, &processed );
al_check_error();
if ( processed ) {
alSourceUnqueueBuffers( src, processed, &spkr_buffers[freeBuffers]);
al_check_error();
}
return processed;
}
int playDelay = 4;
#define SPKR_PLAY_DELAY 2
int playDelay = SPKR_PLAY_DELAY;
void spkr_update() {
@ -354,12 +377,7 @@ void spkr_update() {
spkr_frame_cntr = 0;
if ( spkr_play_time ) {
// free up unused buffers
freeBuffers += spkr_unqueue( spkr_src[SPKR_SRC_GAME_SFX] );
freeBuffers = clamp( 1, freeBuffers, BUFFER_COUNT );
if ( freeBuffers ) {
// in Game Mode do not fade out and stop playing
if ( ( cpuMode_game != cpuMode ) && ( --spkr_play_time == 0 ) ) {
float fadeLevel = spkr_level - SPKR_LEVEL_ZERO;
@ -369,7 +387,7 @@ void spkr_update() {
while ( ( fadeLevel < -1 ) || ( fadeLevel > 1 ) ) {
spkr_samples[ spkr_sample_idx++ ] = SPKR_LEVEL_ZERO + fadeLevel;
spkr_samples[ spkr_sample_idx++ ] = SPKR_LEVEL_ZERO + fadeLevel;
spkr_samples[ spkr_sample_idx++ ] = SPKR_LEVEL_ZERO + fadeLevel; // stereo
// how smooth we want the speeker to decay, so we will hear no pops and crackles
fadeLevel *= 0.999;
@ -402,7 +420,7 @@ void spkr_update() {
case AL_PAUSED:
if ( --playDelay <= 0 ) {
alSourcePlay(spkr_src[SPKR_SRC_GAME_SFX]);
playDelay = 4;
playDelay = SPKR_PLAY_DELAY;
}
break;
@ -429,6 +447,10 @@ void spkr_update() {
}
spkr_clk = 0;
// free up unused buffers
freeBuffers += spkr_unqueue( spkr_src[SPKR_SRC_GAME_SFX] );
freeBuffers = clamp( 1, freeBuffers, BUFFER_COUNT );
}
else {
spkr_clk += clkfrm;
@ -438,15 +460,16 @@ void spkr_update() {
void spkr_playqueue_sfx( ALuint src, uint8_t * sfx, int len ) {
// freeBuffers += spkr_unqueue( src );
// freeBuffers = clamp( 1, freeBuffers, BUFFER_COUNT );
// printf("%s freeBuffers:%d\n", __FUNCTION__, freeBuffers);
if ( freeBuffers ) {
ALenum queued;
alGetSourcei( src, AL_BUFFERS_QUEUED, &queued );
// printf("Q:%u\n", queued);
if ( queued < 32 ) {
// printf("%s queued:%d\n", __FUNCTION__, queued);
if ( queued < 16 ) {
freeBuffers--;
alBufferData( spkr_buffers[freeBuffers], AL_FORMAT_STEREO16, sfx, len, sfx_sample_rate );
al_check_error();
@ -472,6 +495,9 @@ void spkr_playqueue_sfx( ALuint src, uint8_t * sfx, int len ) {
void spkr_play_sfx( ALuint src, uint8_t * sfx, int len ) {
// printf("%s freeBuffers:%d\n", __FUNCTION__, freeBuffers);
if ( freeBuffers ) {
ALenum state;
alGetSourcei( src, AL_SOURCE_STATE, &state );
@ -509,13 +535,16 @@ void spkr_stop_sfx( ALuint src ) {
case AL_PAUSED:
case AL_PLAYING:
alSourceStop( src );
freeBuffers += spkr_unqueue( src );
freeBuffers = clamp( 1, freeBuffers, BUFFER_COUNT );
break;
default:
break;
}
// free up unused buffers
freeBuffers += spkr_unqueue( src );
freeBuffers = clamp( 1, freeBuffers, BUFFER_COUNT );
}
@ -577,12 +606,7 @@ void spkr_update_disk_sfx() {
update_disk_sfx( &spkr_play_disk_motor_time, spkr_src[SPKR_SRC_DISK_MOTOR_SFX] );
update_disk_sfx( &spkr_play_disk_arm_time, spkr_src[SPKR_SRC_DISK_ARM_SFX] );
update_disk_sfx( &spkr_play_disk_ioerr_time, spkr_src[SPKR_SRC_DISK_IOERR_SFX] );
// we do not need to stop playing,
// however, counter needed to eliminate arm movement noise while in io error
if ( spkr_play_disk_ioerr_time ) {
spkr_play_disk_ioerr_time--;
}
}

View File

@ -517,7 +517,22 @@ int woz_loadFile( const char * filename ) {
fread( woz_file_buffer, woz_file_size, 1, f);
fclose(f);
if ( woz_header->magic != WOZ1_MAGIC ) {
// if this really a WOZ file?
switch ( woz_header->magic ) {
case WOZ1_MAGIC:
break;
case WOZ2_MAGIC:
break;
default:
woz_free_buffer();
return WOZ_ERR_NOT_WOZ_FILE;
}
// check if bits and line ends not been altered by data transmission protocols
if ( woz_header->bit_correctness != 0x0A0D0AFF ) {
woz_free_buffer();
return WOZ_ERR_NOT_WOZ_FILE;
}

View File

@ -24,6 +24,7 @@
#define WOZ_TMAP_CHUNK_ID 0x50414D54
#define WOZ_TRKS_CHUNK_ID 0x534B5254
#define WOZ_META_CHUNK_ID 0x4154454D
#define WOZ_WRIT_CHUNK_ID 0x54495257
#define WOZ_ERR_OK 0
#define WOZ_ERR_FILE_NOT_FOUND -1
@ -37,8 +38,13 @@
typedef struct woz_header_s {
uint32_t magic;
uint8_t no7;
char lineend [3];
union {
struct {
uint8_t no7;
char lineend [3];
};
uint32_t bit_correctness;
};
uint32_t crc;
} woz_header_t;
@ -49,12 +55,39 @@ typedef struct woz_chunk_header_s {
// chunk data only
typedef struct woz_info_s {
uint8_t version;
uint8_t version; // Version number of the INFO chunk.
// WOZ1 version is 1
// WOZ2 version is 2
uint8_t disk_type; // 1 = 5.25, 2 = 3.5
uint8_t is_write_protected;
uint8_t is_write_protected; // 1 = Floppy is write protected
uint8_t sync; // 1 = Cross track sync
uint8_t cleaned; // 1 = MC3470 fake bits removed
char creator [32]; // Name of software created this file (UTF-8, 0x20 padded, NOT zero terminated)
uint8_t disk_sides; // The number of disk sides contained within this image. A 5.25 disk will always be 1. A 3.5 disk can be 1 or 2.
uint8_t boot_sec_format; // The type of boot sector found on this disk. This is only for 5.25 disks. 3.5 disks should just set this to 0.
// 0 = Unknown
// 1 = Contains boot sector for 16-sector
// 2 = Contains boot sector for 13-sector
// 3 = Contains boot sectors for both
uint8_t opt_bit_timing; // The ideal rate that bits should be delivered to the disk controller card.
// This value is in 125 nanosecond increments, so 8 is equal to 1 microsecond.
// And a standard bit rate for a 5.25 disk would be 32 (4µs).
uint16_t compatible_hw; // Bit field with a 1 indicating known compatibility. Multiple compatibility flags are possible.
// A 0 value represents that the compatible hardware list is unknown.
// 0x0001 = Apple ][
// 0x0002 = Apple ][ Plus
// 0x0004 = Apple //e (unenhanced)
// 0x0008 = Apple //c
// 0x0010 = Apple //e Enhanced
// 0x0020 = Apple IIgs
// 0x0040 = Apple //c Plus
// 0x0080 = Apple ///
// 0x0100 = Apple /// Plus
uint16_t required_ram; // Minimum RAM size needed for this software. This value is in K (1024 bytes).
// If the minimum size is unknown, this value should be set to 0. So, a requirement
// of 64K would be indicated by the value 64 here.
uint16_t largest_track; // The number of blocks (512 bytes) used by the largest track.
// Can be used to allocate a buffer with a size safe for all tracks.
} woz_info_t;
// chunk data only
@ -108,6 +141,7 @@ typedef struct woz_flags_s {
extern WOZread_t WOZread;
extern WOZread_t WOZwrite;
extern uint8_t WOZlatch;
extern char woz_filename[MAXFILENAME];
extern woz_flags_t woz_flags;

View File

@ -741,34 +741,34 @@ INLINE uint8_t ioRead( uint16_t addr ) {
case (uint8_t)io_DISK_PHASE2_OFF + SLOT6:
case (uint8_t)io_DISK_PHASE3_OFF + SLOT6:
disk_phase_off( (addr - io_DISK_PHASE0_OFF - SLOT6) / 2 );
return 0;
return disk_read();
case (uint8_t)io_DISK_PHASE0_ON + SLOT6:
case (uint8_t)io_DISK_PHASE1_ON + SLOT6:
case (uint8_t)io_DISK_PHASE2_ON + SLOT6:
case (uint8_t)io_DISK_PHASE3_ON + SLOT6:
disk_phase_on( (addr - io_DISK_PHASE0_ON - SLOT6) / 2 );
return 0;
return disk_read();
case (uint8_t)io_DISK_POWER_OFF + SLOT6:
dbgPrintf2("io_DISK_POWER_OFF (S%u)\n", 6);
disk_motor_off();
return 0;
return disk_read();
case (uint8_t)io_DISK_POWER_ON + SLOT6:
dbgPrintf2("io_DISK_POWER_ON (S%u)\n", 6);
disk_motor_on();
return 0;
return disk_read();
case (uint8_t)io_DISK_SELECT_1 + SLOT6:
dbgPrintf2("io_DISK_SELECT_1 (S%u)\n", 6);
disk.drive = 0;
return 0;
return disk_read();
case (uint8_t)io_DISK_SELECT_2 + SLOT6:
dbgPrintf2("io_DISK_SELECT_2 (S%u)\n", 6);
disk.drive = 1;
return 0;
return disk_read();
case (uint8_t)io_DISK_READ + SLOT6:
if ( writeState ) {
@ -784,6 +784,7 @@ INLINE uint8_t ioRead( uint16_t addr ) {
case (uint8_t)io_DISK_WRITE + SLOT6:
dbgPrintf2("io_DISK_WRITE (S%u)\n", 6);
// Apple2_64K_RAM[io_DISK_CLEAR + SLOT6] |= 1 << 7; // mark disk as write protected
WOZwrite.latch = WOZread.latch = 0;
Apple2_64K_RAM[io_DISK_CLEAR + SLOT6] &= ~(1 << 7); // mark disk as write enabled
return Apple2_64K_RAM[io_DISK_WRITE + SLOT6];
@ -793,7 +794,7 @@ INLINE uint8_t ioRead( uint16_t addr ) {
case (uint8_t)io_DISK_SHIFT + SLOT6:
dbgPrintf2("io_DISK_SHIFT (S%u)\n", 6);
return 0;
return disk_read();