Much better sound + improved memory handling

This commit is contained in:
tudnai 2022-06-19 18:59:49 -07:00
parent 12e458116c
commit a97614cba7
11 changed files with 1397 additions and 883 deletions

14
.gitignore vendored
View File

@ -8,3 +8,17 @@
# XCode debugger settings
A2Mac.xcodeproj/xcuserdata/trudnai.xcuserdatad/xcdebugger/
convert_spkr_buf_to_wav.wav
steve2_audio_debug_ema.wav
steve2_audio_debug_raw.wav
steve2_audio_debug.wav
XPS_Aux_Mem_test.txt
XPS_Aux_Mem_test.txt.dis
Resources/rom/Downloads/Apple II ROMs.zip
Resources/rom/Downloads/Apple II ROMs.zip
Resources/rom/Downloads/apple_2e_unenhanced_rom.zip
Resources/rom/Downloads/APPLE_IIe_ROM_KRK.zip
Resources/rom/Downloads/APPLE_IIe_ROM_KRK1.zip
Resources/rom/Downloads/APPLE_IIe_ROM_KRK2.zip
Resources/rom/Downloads/apple_iie_rom.zip
Resources/rom/Downloads/077-0026-0027 for IIe.zip

View File

@ -2016,21 +2016,36 @@
<action selector="trailingEdgeSelected:" target="XfG-lQ-9wD" id="UQ6-Lt-f9t"/>
</connections>
</slider>
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="adp-hx-NvD">
<rect key="frame" x="-2" y="111" width="40" height="16"/>
<textField hidden="YES" focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="adp-hx-NvD">
<rect key="frame" x="-2" y="142" width="40" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" refusesFirstResponder="YES" focusRingType="none" alignment="right" title="WE: 4" id="M1e-h1-C5X">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<slider focusRingType="none" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="alH-N3-GYS">
<rect key="frame" x="-2" y="79" width="92" height="24"/>
<slider hidden="YES" focusRingType="none" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="alH-N3-GYS">
<rect key="frame" x="-2" y="134" width="92" height="24"/>
<sliderCell key="cell" continuous="YES" refusesFirstResponder="YES" state="on" focusRingType="none" alignment="left" maxValue="40" doubleValue="4.1025641025641022" tickMarkPosition="above" numberOfTickMarks="40" allowsTickMarkValuesOnly="YES" sliderType="linear" id="M38-l2-wW3"/>
<connections>
<action selector="wozExtraSelected:" target="XfG-lQ-9wD" id="jyY-27-Hdz"/>
</connections>
</slider>
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="cUp-BM-2iO">
<rect key="frame" x="-2" y="111" width="54" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" refusesFirstResponder="YES" focusRingType="none" alignment="right" title="EMA: 18" id="11J-tH-xLe">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<slider focusRingType="none" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="ND1-4Z-iF3">
<rect key="frame" x="-2" y="79" width="92" height="24"/>
<sliderCell key="cell" continuous="YES" refusesFirstResponder="YES" state="on" focusRingType="none" alignment="left" minValue="1" maxValue="41" doubleValue="18.435897435897434" tickMarkPosition="above" numberOfTickMarks="40" allowsTickMarkValuesOnly="YES" sliderType="linear" id="WQL-gS-1BT"/>
<connections>
<action selector="EMASelected:" target="XfG-lQ-9wD" id="dhd-xf-5TT"/>
</connections>
</slider>
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="FFM-zm-Wjx">
<rect key="frame" x="-2" y="57" width="13" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" refusesFirstResponder="YES" focusRingType="none" alignment="right" title="0" id="yIR-MN-Hdl">
@ -2078,6 +2093,8 @@
<integer value="1000"/>
<integer value="1000"/>
<integer value="1000"/>
<integer value="1000"/>
<integer value="1000"/>
</visibilityPriorities>
<customSpacing>
<real value="3.4028234663852886e+38"/>
@ -2096,6 +2113,8 @@
<real value="3.4028234663852886e+38"/>
<real value="3.4028234663852886e+38"/>
<real value="3.4028234663852886e+38"/>
<real value="3.4028234663852886e+38"/>
<real value="3.4028234663852886e+38"/>
</customSpacing>
</stackView>
</subviews>
@ -2152,6 +2171,7 @@
<connections>
<outlet property="DiskSound_Disk1" destination="5cI-3C-PMM" id="ptG-tm-GZs"/>
<outlet property="DiskSound_Disk2" destination="vmR-CG-qdv" id="22u-xi-nHH"/>
<outlet property="EMALabel" destination="11J-tH-xLe" id="BHX-Gf-xsl"/>
<outlet property="QuickDisk_Disk1" destination="cth-H6-Drg" id="cFI-9E-kYv"/>
<outlet property="QuickDisk_Disk2" destination="yDH-Ob-i3N" id="hvi-ZC-Pk4"/>
<outlet property="hires" destination="LlM-EV-ruZ" id="E60-pA-HM1"/>

View File

@ -1318,6 +1318,13 @@ class ViewController: NSViewController {
}
@IBOutlet weak var EMALabel: NSTextFieldCell!
@IBAction func EMASelected(_ sender: NSSlider) {
spkr_ema_len = Int32(sender.floatValue)
EMALabel.title = "EMA: " + String( spkr_ema_len )
}
func setSimulationMode( mode : String ) {
switch ( mode ) {
case "Eco":

View File

@ -0,0 +1,291 @@
//
// main.c
// 6502
//
// Created by Tamas Rudnai on 7/14/19.
// Copyright © 2019, 2020 Tamas Rudnai. All rights reserved.
//
// This file is part of Steve ][ -- The Apple ][ Emulator.
//
// Steve ][ is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Steve ][ is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Steve ][. If not, see <https://www.gnu.org/licenses/>.
//
#ifndef __6502_INSTR_BRANCH_H__
#define __6502_INSTR_BRANCH_H__
INLINE void BRA( int8_t reladdr ) {
m6502.PC += reladdr;
//#ifdef CLK_ABSOLUTE_PRECISE
uint8_t pg = m6502.PC >> 8;
m6502.clkfrm += m6502.PC >> 8 == pg ? 1 : 2;
// if ( m6502.PC >> 8 != pg ) {
// m6502.clkfrm += 1;
// }
//#else
// m6502.clktime++;
//#endif
#ifdef DEBUG
if ( reladdr == -2 ) {
dbgPrintf2("Infinite Loop at %04X!\n", m6502.PC);
}
#endif
dbgPrintf("BRA %04X ", m6502.PC);
}
/**
BCC Branch on Carry Clear
branch on C = 0 N Z C I D V
- - - - - -
addressing assembler opc bytes cyles
--------------------------------------------
relative BCC oper 90 2 2**
**/
INLINE void BCC( int8_t reladdr ) {
dbgPrintf("BCC ");
disPrintf(disassembly.inst, "BCC");
if ( ! m6502.C ) {
BRA( reladdr );
}
else {
dbgPrintf("-no-");
}
}
/**
BCS Branch on Carry Set
branch on C = 1 N Z C I D V
- - - - - -
addressing assembler opc bytes cyles
--------------------------------------------
relative BCS oper B0 2 2**
**/
INLINE void BCS( int8_t reladdr ) {
dbgPrintf("BCS ");
disPrintf(disassembly.inst, "BCS");
if ( m6502.C ) {
BRA( reladdr );
}
else {
dbgPrintf("-no-");
}
}
/**
BNE Branch on Result not Zero
branch on Z = 0 N Z C I D V
- - - - - -
addressing assembler opc bytes cyles
--------------------------------------------
relative BNE oper D0 2 2**
**/
INLINE void BNE( int8_t reladdr ) {
dbgPrintf("BNE ");
disPrintf(disassembly.inst, "BNE");
if ( ! m6502.Z ) {
BRA( reladdr );
}
else {
dbgPrintf("-no-");
}
}
/**
BEQ Branch on Result Zero
branch on Z = 1 N Z C I D V
- - - - - -
addressing assembler opc bytes cyles
--------------------------------------------
relative BEQ oper F0 2 2**
**/
INLINE void BEQ( int8_t reladdr ) {
dbgPrintf("BEQ ");
disPrintf(disassembly.inst, "BEQ");
if ( m6502.Z ) {
BRA( reladdr );
}
else {
dbgPrintf("-no-");
}
}
/**
BPL Branch on Result Plus
branch on N = 0 N Z C I D V
- - - - - -
addressing assembler opc bytes cyles
--------------------------------------------
relative BPL oper 10 2 2**
**/
INLINE void BPL( int8_t reladdr ) {
dbgPrintf("BPL ");
disPrintf(disassembly.inst, "BPL");
if ( ! m6502.N ) {
BRA( reladdr );
}
else {
dbgPrintf("-no-");
}
}
/**
BMI Branch on Result Minus
branch on N = 1 N Z C I D V
- - - - - -
addressing assembler opc bytes cyles
--------------------------------------------
relative BMI oper 30 2 2**
**/
INLINE void BMI( int8_t reladdr ) {
dbgPrintf("BMI ");
disPrintf(disassembly.inst, "BMI");
if ( m6502.N ) {
BRA( reladdr );
}
else {
dbgPrintf("-no-");
}
}
/**
BVC Branch on Overflow Clear
branch on V = 0 N Z C I D V
- - - - - -
addressing assembler opc bytes cyles
--------------------------------------------
relative BVC oper 50 2 2**
**/
INLINE void BVC( int8_t reladdr ) {
dbgPrintf("BVC ");
disPrintf(disassembly.inst, "BVC");
if ( ! m6502.V ) {
BRA( reladdr );
}
else {
dbgPrintf("-no-");
}
}
/**
BVS Branch on Overflow Set
branch on V = 1 N Z C I D V
- - - - - -
addressing assembler opc bytes cyles
--------------------------------------------
relative BVC oper 70 2 2**
**/
INLINE void BVS( int8_t reladdr ) {
dbgPrintf("BVS ");
disPrintf(disassembly.inst, "BVS");
if ( m6502.V ) {
BRA( reladdr );
}
else {
dbgPrintf("-no-");
}
}
/**
BBR BBS - Branch on Bit Reset or Set
BBR and BBS test the specified zero page location and branch if the specified bit is clear (BBR) or set (BBS).
Note that as with TRB, the term reset in BBR is used to mean clear.
On the 6502 and 65C02, bit 7 is typically the most convenient bit to use for I/O and software flags because
it can be tested by several instructions, such as BIT and LDA. BBR and BBS can test any of the 8 bits without
affecting any flags or using any registers. Unlike other branch instructions, BBR and BBS always take the same
number of cycles (five) whether the branch is taken or not. It is often useful to test bit 0, for example, to test
whether a byte is even or odd. However, the usefulness of BBR and BBS is somewhat limited for a couple of reasons.
First, there is only a single addressing mode for these instructions -- no indexing by X or Y, for instance.
Second, they are restricted to zero page locations. For software flags this may be just fine, but it may not be very
convenient (or cost effective) to add any additional address decoding hardware that may be necessary to
map I/O locations to the zero page.
The addressing mode is a combination of zero page addressing and relative addressing -- really just a juxtaposition of the two.
The bit to test is typically specified as part of the instruction name rather than the operand, i.e.
Flags affected: none
OP LEN CYC MODE FLAGS SYNTAX
-- --- --- ---- ----- ------
0F 3 5 zp,rel ........ BBR0 $12,LABEL
1F 3 5 zp,rel ........ BBR1 $12,LABEL
2F 3 5 zp,rel ........ BBR2 $12,LABEL
3F 3 5 zp,rel ........ BBR3 $12,LABEL
4F 3 5 zp,rel ........ BBR4 $12,LABEL
5F 3 5 zp,rel ........ BBR5 $12,LABEL
6F 3 5 zp,rel ........ BBR6 $12,LABEL
7F 3 5 zp,rel ........ BBR7 $12,LABEL
8F 3 5 zp,rel ........ BBS0 $12,LABEL
9F 3 5 zp,rel ........ BBS1 $12,LABEL
AF 3 5 zp,rel ........ BBS2 $12,LABEL
BF 3 5 zp,rel ........ BBS3 $12,LABEL
CF 3 5 zp,rel ........ BBS4 $12,LABEL
DF 3 5 zp,rel ........ BBS5 $12,LABEL
EF 3 5 zp,rel ........ BBS6 $12,LABEL
FF 3 5 zp,rel ........ BBS7 $12,LABEL
**/
#define BBR(n) INLINE void BBR##n( uint8_t src, int8_t reladdr ) { \
dbgPrintf("BBR"#n" "); \
disPrintf(disassembly.inst, "BBR"#n); \
if ( ! (src & (1 << n) ) ) { \
BRA( reladdr ); \
} \
}
BBR(0)
BBR(1)
BBR(2)
BBR(3)
BBR(4)
BBR(5)
BBR(6)
BBR(7)
#define BBS(n) INLINE void BBS##n( uint8_t src, int8_t reladdr ) { \
dbgPrintf("BBS"#n" "); \
disPrintf(disassembly.inst, "BBS"#n); \
if ( (src & (1 << n) ) ) { \
BRA( reladdr ); \
} \
}
BBS(0)
BBS(1)
BBS(2)
BBS(3)
BBS(4)
BBS(5)
BBS(6)
BBS(7)
#endif // __6502_INSTR_BRANCH_H__

View File

@ -153,6 +153,8 @@ typedef struct MEMcfg_s {
unsigned RD_AUX_MEM : 1;
unsigned WR_AUX_MEM : 1;
unsigned ALT_ZP : 1;
unsigned WR_RAM_cntr; // min 2 I/O to enable mem write
} MEMcfg_t;

View File

@ -41,12 +41,12 @@
#define CASE_RETURN(err) case (err): return #err
const char* al_err_str(ALenum err) {
switch(err) {
CASE_RETURN(AL_NO_ERROR);
CASE_RETURN(AL_INVALID_NAME);
CASE_RETURN(AL_INVALID_ENUM);
CASE_RETURN(AL_INVALID_VALUE);
CASE_RETURN(AL_INVALID_OPERATION);
CASE_RETURN(AL_OUT_OF_MEMORY);
CASE_RETURN(AL_NO_ERROR);
CASE_RETURN(AL_INVALID_NAME);
CASE_RETURN(AL_INVALID_ENUM);
CASE_RETURN(AL_INVALID_VALUE);
CASE_RETURN(AL_INVALID_OPERATION);
CASE_RETURN(AL_OUT_OF_MEMORY);
}
printf("alError: 0x%04X\n", err);
return "AL_UNKNOWN_ERROR";
@ -55,13 +55,22 @@ const char* al_err_str(ALenum err) {
#define __al_check_error(file,line) \
for( ALenum err = alGetError(); err != AL_NO_ERROR; err = alGetError() ) { \
printf( "AL Error %s at %s:%d\n", al_err_str(err), file, line ); \
printf( "AL Error %s at %s:%d\n", al_err_str(err), file, line ); \
}
#define al_check_error() \
__al_check_error(__FILE__, __LINE__)
#define __al_check_error2(file,line,src) \
for( ALenum err = alGetError(); err != AL_NO_ERROR; err = alGetError() ) { \
printf( "AL Error %s at %s:%d (%u)\n", al_err_str(err), file, line, src ); \
}
#define al_check_error2(src) \
__al_check_error2(__FILE__, __LINE__, src)
ALCdevice *dev = NULL;
ALCcontext *ctx = NULL;
@ -74,6 +83,15 @@ int spkr_level_dema = SPKR_LEVEL_ZERO;
int spkr_level_tema = SPKR_LEVEL_ZERO;
int spkr_last_level = SPKR_LEVEL_ZERO;
static const int ema_len_sharper = 7;
static const int ema_len_sharp = 14;
static const int ema_len_normal = 18;
static const int ema_len_soft = 20;
static const int ema_len_supersoft = 40;
int spkr_ema_len = ema_len_normal;
#define BUFFER_COUNT 256
#define SPKR_CHANNELS 2
@ -93,6 +111,8 @@ unsigned spkr_fps_divider = 1;
unsigned spkr_frame_cntr = 0;
unsigned spkr_clk = 0;
#define SPKR_BUF_SLOT(n) ( spkr_buf_size * DEFAULT_FPS * (n) )
const unsigned spkr_seconds = 1;
const unsigned spkr_sample_rate = 192000;
const unsigned sfx_sample_rate = 22050; // original sample rate
@ -101,7 +121,7 @@ int spkr_extra_buf = 0; // 26; // 800 / spkr_fps;
typedef int16_t spkr_sample_t;
const unsigned spkr_buf_size = spkr_seconds * spkr_sample_rate * SPKR_CHANNELS / DEFAULT_FPS; // stereo
const unsigned spkr_buf_alloc_size = spkr_buf_size * sizeof(spkr_sample_t);
const unsigned sample_buf_array_len = spkr_buf_size * DEFAULT_FPS * BUFFER_COUNT;
const unsigned sample_buf_array_len = SPKR_BUF_SLOT(BUFFER_COUNT);
spkr_sample_t spkr_samples [ sample_buf_array_len ]; // can store up to 1 sec of sound
unsigned spkr_sample_idx = 0;
unsigned spkr_sample_last_idx = 0;
@ -369,7 +389,9 @@ int spkr_unqueue( ALuint src ) {
if ( src ) {
alGetSourcei ( src, AL_BUFFERS_PROCESSED, &processed );
al_check_error();
// al_check_error();
al_check_error2(src);
// printf("%s alGetSourcei(%d)\n", __FUNCTION__, src);
// printf("p:%d\n", processed);
@ -567,18 +589,18 @@ INLINE static void spkr_filter(int buf_len) {
// static const int ema_len_supersoft = 200;
// to use with TEMA
static const int ema_len_sharper = 7;
static const int ema_len_sharp = 14;
static const int ema_len_normal = 18;
static const int ema_len_soft = 20;
static const int ema_len_supersoft = 40;
static const int ema_len = ema_len_normal;
// static const int ema_len_sharper = 7;
// static const int ema_len_sharp = 14;
// static const int ema_len_normal = 18;
// static const int ema_len_soft = 20;
// static const int ema_len_supersoft = 40;
//
// static const int ema_len = ema_len_soft;
for ( int i = 0; i < spkr_buf_size; ) {
spkr_level_ema = ema(spkr_samples[i], spkr_level_ema, ema_len);
spkr_level_dema = ema(spkr_level_ema, spkr_level_dema, ema_len);
spkr_level_tema = ema(spkr_level_dema, spkr_level_tema, ema_len);
spkr_level_ema = ema(spkr_samples[i], spkr_level_ema, spkr_ema_len);
spkr_level_dema = ema(spkr_level_ema, spkr_level_dema, spkr_ema_len);
spkr_level_tema = ema(spkr_level_dema, spkr_level_tema, spkr_ema_len);
// smoothing with Tripple EMA
spkr_samples[i++] = spkr_level_tema;
@ -601,6 +623,27 @@ INLINE void spkr_debug_spike() {
}
void spkr_play() {
ALenum state;
alGetSourcei( spkr_src[SPKR_SRC_GAME_SFX], AL_SOURCE_STATE, &state );
// al_check_error();
switch (state) {
case AL_PLAYING:
// already playing, no need to do anything
break;
case AL_INITIAL:
case AL_STOPPED:
case AL_PAUSED:
default:
// no we can play this empty buffer first and then later on the real one
alSourcePlay(spkr_src[SPKR_SRC_GAME_SFX]);
break;
}
}
void spkr_play_with_prebuf() {
ALenum state;
alGetSourcei( spkr_src[SPKR_SRC_GAME_SFX], AL_SOURCE_STATE, &state );
@ -652,6 +695,7 @@ void spkr_play_with_pause() {
switch (state) {
case AL_PAUSED:
if ( --playDelay < 0 ) {
printf("spkr_play_with_pause: PLAY\n");
alSourcePlay(spkr_src[SPKR_SRC_GAME_SFX]);
playDelay = SPKR_PLAY_DELAY;
}
@ -664,6 +708,7 @@ void spkr_play_with_pause() {
case AL_INITIAL:
case AL_STOPPED:
default:
printf("spkr_play_with_pause: PLAY-DELAY\n");
alSourcePlay(spkr_src[SPKR_SRC_GAME_SFX]);
// this is so we will set state to AL_PAUSED immediately
// As a result there will be an extra queued buffer
@ -675,6 +720,41 @@ void spkr_play_with_pause() {
}
void spkr_buffer_with_pause(int buf_len) {
ALenum state;
alGetSourcei( spkr_src[SPKR_SRC_GAME_SFX], AL_SOURCE_STATE, &state );
// al_check_error();
switch (state) {
case AL_PAUSED:
case AL_PLAYING:
// already playing
break;
case AL_INITIAL:
case AL_STOPPED:
default:
alBufferData(spkr_buffers[freeBuffers], AL_FORMAT_STEREO16, spkr_samples + SPKR_BUF_SLOT(BUFFER_COUNT - 2), buf_len * 2, spkr_sample_rate);
al_check_error();
alSourceQueueBuffers(spkr_src[SPKR_SRC_GAME_SFX], 1, &spkr_buffers[freeBuffers]);
al_check_error();
if (--freeBuffers < 0) {
printf("freeBuffer < 0 (%i)\n", freeBuffers);
freeBuffers = 0;
}
break;
}
alBufferData(spkr_buffers[freeBuffers], AL_FORMAT_STEREO16, spkr_samples, buf_len, spkr_sample_rate);
al_check_error();
alSourceQueueBuffers(spkr_src[SPKR_SRC_GAME_SFX], 1, &spkr_buffers[freeBuffers]);
al_check_error();
}
void spkr_update() {
if ( ++spkr_frame_cntr >= spkr_fps_divider ) {
spkr_frame_cntr = 0;
@ -688,7 +768,7 @@ void spkr_update() {
// printf("q:%d clkfrm:%d frm:%llu max:%llu\n", queued, clkfrm, clk_6502_per_frm, clk_6502_per_frm_max);
if ( queued < SPKR_MAX_QUEUED ) {
if ( spkr_play_time ) {
if ( spkr_play_time > 0) {
if ( freeBuffers ) {
// double multiplier = 1;
// #ifdef SPKR_KEEP_PITCH
@ -698,7 +778,7 @@ void spkr_update() {
// #endif
// in Game Mode do not fade out and stop playing
if ( /*( cpuMode_game != cpuMode ) && */( --spkr_play_time == 0 ) ) {
if ( /*( cpuMode_game != cpuMode ) && */( --spkr_play_time == SPKR_PLAY_QUIET ) ) {
if (--freeBuffers < 0) {
printf("freeBuffer < 0 (%i)\n", freeBuffers);
@ -743,8 +823,8 @@ void spkr_update() {
// //spkr_samples[sample_idx] = spkr_level;
// memset(spkr_samples + spkr_sample_idx, spkr_level, spkr_buf_alloc_size * DEFAULT_FPS - spkr_sample_idx);
spkr_play_with_prebuf();
// spkr_play_with_prebuf();
if (--freeBuffers < 0) {
printf("freeBuffer < 0 (%i)\n", freeBuffers);
freeBuffers = 0;
@ -763,13 +843,11 @@ void spkr_update() {
// digital filtering the audio stream -- most notably smoothing
spkr_filter(buf_len);
alBufferData(spkr_buffers[freeBuffers], AL_FORMAT_STEREO16, spkr_samples, buf_len, spkr_sample_rate);
al_check_error();
alSourceQueueBuffers(spkr_src[SPKR_SRC_GAME_SFX], 1, &spkr_buffers[freeBuffers]);
al_check_error();
spkr_buffer_with_pause(buf_len);
}
}
spkr_play();
// spkr_play_with_pause();
// int dst = 0;
@ -785,6 +863,11 @@ void spkr_update() {
spkr_sample_idx = 0;
spkr_sample_last_idx = 0;
// make sure it never goes below 0 (never overflows)
if ( (int)spkr_play_time < 0 ) {
spkr_play_time = 0;
}
}
else {
printf("Warning: No FreeBuffers!\n");

View File

@ -44,6 +44,8 @@
#define SPKR_LEVEL_MAX 32767 // 8192
#define SPKR_LEVEL_MIN (-SPKR_LEVEL_MAX)
#define SPKR_PLAY_TIMEOUT 8U
#define SPKR_PLAY_QUIET 0
//#define SPKR_PLAY_QUIET (SPKR_PLAY_TIMEOUT - 2)
// quiet
//#define SPKR_LEVEL_MIN (-1000)
@ -60,6 +62,8 @@ extern float SPKR_FADE_TRAILING_EDGE;
extern float SPKR_INITIAL_LEADING_EDGE; // leading edge should be pretty steep to get sharp sound plus to avoid Wavy Navy high pitch sound
extern float SPKR_INITIAL_TRAILING_EDGE; // need a bit of slope to get Xonix sound good
extern int spkr_ema_len;
#define SPKR_SAMPLE_PWM_THRESHOLD 32 // to detect PWM controlled speaker control like in Wavy Navy or Xonix

View File

@ -88,9 +88,10 @@ uint8_t * currentLowWRMEM = Apple2_64K_RAM;
/// No writing (Readonly), and mark it as NO need to commit from Shadow RAM
INLINE void set_MEM_readonly() {
printf("NOWR_AUX\n");
printf("NOWR_AUX (pc:$%04X)\n", m6502.PC);
MEMcfg.WR_RAM = 0;
MEMcfg.WR_RAM_cntr = 0;
WRD0MEM = Apple2_Dummy_RAM; // for Discarding any writes to $D000 - $DFFF - BANK X
WRHIMEM = Apple2_Dummy_RAM; // for Discarding any writes to $E000 - $FFFF
}
@ -99,11 +100,13 @@ INLINE void set_MEM_readonly() {
/// Returns TRUE if already writeable or second of the "two consecutive" reads on appropriate soft switches
INLINE int is_wr_enabled() {
uint64_t clk = m6502.clktime + m6502.clkfrm;
uint64_t elapsed = clk - m6502.clk_wrenable;
int is_enabled = ( elapsed < 16 ) || MEMcfg.WR_RAM;
printf("is_wr_enabled elapsed:%llu was_enabled:%i to_be_enabled:%i\n", elapsed, MEMcfg.WR_RAM, is_enabled);
// uint64_t elapsed = clk - m6502.clk_wrenable;
// int is_enabled = ( elapsed < 16 ) || MEMcfg.WR_RAM;
int is_enabled = ++MEMcfg.WR_RAM_cntr >= 1 || MEMcfg.WR_RAM;
// printf("is_wr_enabled elapsed:%llu was_enabled:%i to_be_enabled:%i\n", elapsed, MEMcfg.WR_RAM, is_enabled);
printf("is_wr_enabled WR_RAM_cntr:%u was_enabled:%i to_be_enabled:%i\n", MEMcfg.WR_RAM_cntr, MEMcfg.WR_RAM, is_enabled);
m6502.clk_wrenable = clk;
return is_enabled;
}
@ -115,7 +118,7 @@ INLINE void set_AUX_read_write() {
// two consecutive read or write needs for write enable
// Note: if it is already writeable and was previously a ROM read + RAM write, then we also need to bound AUX to MEM
if ( is_wr_enabled() ) {
printf("WR_MEM\n");
printf("WR_MEM (pc:$%04X)\n", m6502.PC);
// will write to Shadow RAM, and mark it as need to commit from Shadow RAM
MEMcfg.WR_RAM = 1;
@ -131,7 +134,7 @@ INLINE void set_AUX_write() {
// will write directly to Auxiliary RAM, and mark it as NO need to commit from Shadow RAM
// Note: if it is already writeable and was previously a RAM read + RAM write, then we also need to bound AUX to MEM
if ( is_wr_enabled() ) {
printf("WR_AUX\n");
printf("WR_AUX (pc:$%04X)\n", m6502.PC);
MEMcfg.WR_RAM = 1;
if ( MEMcfg.RAM_BANK_2 ) {
@ -148,8 +151,10 @@ INLINE void set_AUX_write() {
// save the content of Shadow Memory in needed
INLINE void save_AUX() {
if ( MEMcfg.WR_RAM && MEMcfg.RD_INT_RAM ) {
// printf("Saving RAM Bank %d to %p\n", MEMcfg.RAM_BANK_2 + 1, current_RAM_bank);
printf("Saving RAM Bank %d to %d (pc:$%04X)\n", MEMcfg.RAM_BANK_2 + 1, (current_RAM_bank == Apple2_64K_AUX + 0xD000) + 1, m6502.PC);
// save LC Bank 1 or 2
memcpy(current_RAM_bank, Apple2_64K_MEM + 0xD000, 0x1000);
// save rest of LC RAM
memcpy(Apple2_64K_AUX + 0xE000, Apple2_64K_MEM + 0xE000, 0x2000);
}
}
@ -168,14 +173,14 @@ INLINE void select_RAM_BANK( uint16_t addr ) {
case (uint8_t)io_MEM_RDROM_NOWR_2_:
case (uint8_t)io_MEM_RDRAM_WRAM_2_:
printf("RAM_BANK_2\n");
printf("RAM_BANK_2 (pc:$%04X)\n", m6502.PC);
MEMcfg.RAM_BANK_2 = 1;
current_RAM_bank = Apple2_64K_AUX + 0xD000;
break;
default:
printf("RAM_BANK_1\n");
printf("RAM_BANK_1 (pc:$%04X)\n", m6502.PC);
MEMcfg.RAM_BANK_2 = 0;
current_RAM_bank = Apple2_64K_AUX + 0xC000;
@ -197,7 +202,7 @@ INLINE void read_RAM_or_ROM( uint16_t addr ) {
case (uint8_t)io_MEM_RDRAM_NOWR_1_:
case (uint8_t)io_MEM_RDRAM_WRAM_1_:
printf("RD_RAM\n");
printf("RD_RAM (pc:$%04X)\n", m6502.PC);
MEMcfg.RD_INT_RAM = 1;
@ -209,7 +214,7 @@ INLINE void read_RAM_or_ROM( uint16_t addr ) {
break;
default:
printf("RD_ROM\n");
printf("RD_ROM (pc:$%04X)\n", m6502.PC);
MEMcfg.RD_INT_RAM = 0;
@ -232,7 +237,7 @@ INLINE void write_RAM_or_NOT( uint16_t addr ) {
case (uint8_t)io_MEM_RDROM_WRAM_2_:
case (uint8_t)io_MEM_RDROM_WRAM_1_:
printf("RD_ROM + WR_AUX\n");
printf("RD_ROM + WR_AUX (pc:$%04X)\n", m6502.PC);
set_AUX_write();
@ -244,14 +249,14 @@ INLINE void write_RAM_or_NOT( uint16_t addr ) {
case (uint8_t)io_MEM_RDRAM_WRAM_2_:
case (uint8_t)io_MEM_RDRAM_WRAM_1_:
printf("RD_RAM + WR_RAM\n");
printf("RD_RAM + WR_RAM (pc:$%04X)\n", m6502.PC);
set_AUX_read_write();
break;
default:
printf("RD_ROM + NO_WR\n");
printf("NO_WR (pc:$%04X)\n", m6502.PC);
set_MEM_readonly();
@ -275,7 +280,7 @@ INLINE void io_RAM_EXP( uint16_t addr ) {
}
INLINE int is_io_interesting(addr) {
INLINE int is_io_interesting( uint16_t addr ) {
switch(addr) {
case io_KBD:
case io_KBDSTRB:
@ -354,13 +359,12 @@ INLINE uint8_t ioRead( uint16_t addr ) {
return Apple2_64K_RAM[io_KBDSTRB];
case (uint8_t)io_TAPEOUT:
// TODO: 1. Sound problem in Castle Wolfensein if we output this to speaker all the time
// 2. Implement Tape
return rand(); // no tape, floating I/O
// TODO: 1. Implement Tape
return rand(); // Floating I/O -- used for random number generation in Games
case (uint8_t)io_SPKR:
spkr_toggle();
return rand(); // Floating I/O -- used for random number genet=ration in Games
return rand(); // Floating I/O -- used for random number generation in Games
case (uint8_t)io_STROBE:
case (uint8_t)io_CLRAN0:
@ -375,7 +379,7 @@ INLINE uint8_t ioRead( uint16_t addr ) {
return rand(); // Apple2_64K_RAM[io_SPKR];
case (uint8_t)io_VID_RDVBL:
return (m6502.clkfrm < 4550) ? 0x80 : 0;
return (m6502.clkfrm > 4550) ? 0x80 : 0;
case (uint8_t)io_VID_RDTEXT:
return videoMode.text << 7;
@ -463,35 +467,35 @@ INLINE uint8_t ioRead( uint16_t addr ) {
case (uint8_t)io_PDL1:
case (uint8_t)io_PDL2:
case (uint8_t)io_PDL3:
// printf("PDL%d: %d\n", addr - io_PDL0, pdl_read( addr - io_PDL0 ));
// printf("PDL%d: %d\n", addr - io_PDL0, pdl_read( addr - io_PDL0 ));
return pdl_read( addr - io_PDL0 );
case (uint8_t)io_PDL_STROBE:
return pdl_reset();
case (uint8_t)io_RDMAINRAM:
// printf("io_RDMAINRAM\n");
printf("R:io_RDMAINRAM (pc:$%04X)\n", m6502.PC);
newMEMcfg = MEMcfg;
newMEMcfg.RD_AUX_MEM = 0;
auxMemorySelect(newMEMcfg);
break;
case (uint8_t)io_RDCARDRAM:
// printf("io_RDCARDRAM\n");
printf("R:io_RDCARDRAM (pc:$%04X)\n", m6502.PC);
newMEMcfg = MEMcfg;
newMEMcfg.RD_AUX_MEM = 1;
auxMemorySelect(newMEMcfg);
break;
case (uint8_t)io_WRMAINRAM:
// printf("io_WRMAINRAM\n");
printf("R:io_WRMAINRAM (pc:$%04X)\n", m6502.PC);
newMEMcfg = MEMcfg;
newMEMcfg.WR_AUX_MEM = 0;
auxMemorySelect(newMEMcfg);
break;
case (uint8_t)io_WRCARDRAM:
// printf("io_WRCARDRAM\n");
printf("R:io_WRCARDRAM (pc:$%04X)\n", m6502.PC);
newMEMcfg = MEMcfg;
newMEMcfg.WR_AUX_MEM = 1;
auxMemorySelect(newMEMcfg);
@ -519,7 +523,7 @@ INLINE uint8_t ioRead( uint16_t addr ) {
io_RAM_EXP(addr);
break;
// TODO: Make code "card insertable to slot" / aka slot independent and dynamically add/remove
// TODO: Make code "card insertable to slot" / aka slot independent and dynamically add/remove
case (uint8_t)io_DISK_PHASE0_OFF + SLOT6:
case (uint8_t)io_DISK_PHASE1_OFF + SLOT6:
case (uint8_t)io_DISK_PHASE2_OFF + SLOT6:
@ -617,49 +621,47 @@ INLINE void ioWrite( uint16_t addr, uint8_t val ) {
break;
case (uint8_t)io_RDMAINRAM:
// printf("io_RDMAINRAM\n");
printf("W:io_RDMAINRAM (pc:$%04X)\n", m6502.PC);
newMEMcfg = MEMcfg;
newMEMcfg.RD_AUX_MEM = 0;
auxMemorySelect(newMEMcfg);
break;
case (uint8_t)io_RDCARDRAM:
// printf("io_RDCARDRAM\n");
printf("W:io_RDCARDRAM (pc:$%04X)\n", m6502.PC);
newMEMcfg = MEMcfg;
newMEMcfg.RD_AUX_MEM = 1;
auxMemorySelect(newMEMcfg);
break;
case (uint8_t)io_WRMAINRAM:
// printf("io_WRMAINRAM\n");
printf("W:io_WRMAINRAM (pc:$%04X)\n", m6502.PC);
newMEMcfg = MEMcfg;
newMEMcfg.WR_AUX_MEM = 0;
auxMemorySelect(newMEMcfg);
break;
case (uint8_t)io_WRCARDRAM:
// printf("io_WRCARDRAM\n");
printf("W:io_WRCARDRAM (pc:$%04X)\n", m6502.PC);
newMEMcfg = MEMcfg;
newMEMcfg.WR_AUX_MEM = 1;
auxMemorySelect(newMEMcfg);
break;
case (uint8_t)io_SETSTDZP:
printf("INT ZP (pc:$%04X)\n", m6502.PC);
newMEMcfg = MEMcfg;
newMEMcfg.ALT_ZP = 0;
auxMemorySelect(newMEMcfg);
// TODO: set zero page table to RAM
printf("TODO: set zero page table to RAM\n");
break;
case (uint8_t)io_SETALTZP:
printf("AUX ZP (pc:$%04X)\n", m6502.PC);
newMEMcfg = MEMcfg;
newMEMcfg.ALT_ZP = 1;
auxMemorySelect(newMEMcfg);
// TODO: set zero page table to AUX
printf("TODO: set zero page table to AUX\n");
break;
case (uint8_t)io_SETSLOTCXROM:
@ -716,25 +718,25 @@ INLINE void ioWrite( uint16_t addr, uint8_t val ) {
break;
case (uint8_t)io_80STOREOFF:
// printf("io_80STOREOFF\n");
printf("io_80STOREOFF (pc:$%04X)\n", m6502.PC);
MEMcfg.is_80STORE = 0;
textPageSelect();
break;
case (uint8_t)io_80STOREON:
// printf("io_80STOREON\n");
printf("io_80STOREON (pc:$%04X)\n", m6502.PC);
MEMcfg.is_80STORE = 1;
textPageSelect();
break;
case (uint8_t)io_VID_TXTPAGE1:
// printf("io_VID_TXTPAGE1\n");
printf("io_VID_TXTPAGE1 (pc:$%04X)\n", m6502.PC);
MEMcfg.txt_page_2 = 0;
textPageSelect();
break;
case (uint8_t)io_VID_TXTPAGE2:
// printf("io_VID_TXTPAGE2\n");
printf("io_VID_TXTPAGE2 (pc:$%04X)\n", m6502.PC);
MEMcfg.txt_page_2 = 1;
textPageSelect();
break;
@ -785,7 +787,7 @@ INLINE void ioWrite( uint16_t addr, uint8_t val ) {
io_RAM_EXP(addr);
break;
// TODO: Make code "card insertable to slot" / aka slot independent and dynamically add/remove
// TODO: Make code "card insertable to slot" / aka slot independent and dynamically add/remove
case (uint8_t)io_DISK_PHASE0_OFF + SLOT6:
case (uint8_t)io_DISK_PHASE1_OFF + SLOT6:
case (uint8_t)io_DISK_PHASE2_OFF + SLOT6:
@ -1182,25 +1184,26 @@ INLINE uint8_t src_zp_Y() {
void auxMemorySelect( MEMcfg_t newMEMcfg ) {
const uint8_t * newReadMEM = currentLowRDMEM;
uint8_t * newWriteMEM = currentLowWRMEM;
// TODO: Check if this is supposed to be the opposite
if ( newMEMcfg.is_80STORE ) {
if ( newMEMcfg.RD_AUX_MEM ) {
newReadMEM = Apple2_64K_AUX + 0x200;
}
else {
newReadMEM = Apple2_64K_RAM + 0x200;
newReadMEM = Apple2_64K_MEM + 0x200;
}
if ( newMEMcfg.WR_AUX_MEM ) {
newWriteMEM = Apple2_64K_AUX;
}
else {
newWriteMEM = Apple2_64K_RAM;
newWriteMEM = Apple2_64K_MEM;
}
}
else {
newReadMEM = Apple2_64K_RAM + 0x200;
newWriteMEM = Apple2_64K_RAM;
newReadMEM = Apple2_64K_MEM + 0x200;
newWriteMEM = Apple2_64K_MEM;
}
@ -1251,7 +1254,7 @@ void auxMemorySelect( MEMcfg_t newMEMcfg ) {
}
// load content of SP & Stack
memcpy( shadowZPSTCKMEM, (void*) currentZPSTCKMEM, 0x200);
memcpy( (void*) shadowZPSTCKMEM, (void*) currentZPSTCKMEM, 0x200);
}
// finally we can mark change

View File

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>ATSApplicationFontsPath</key>
<string>fnt</string>
<key>BuildMachineOSBuild</key>
<string>18G5033</string>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>Steve ][</string>
<key>CFBundleIconFile</key>
<string>Steve2Icon.icns</string>
<key>CFBundleIdentifier</key>
<string>com.trudnai.steveii</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>Steve ][</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>0.84</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>MacOSX</string>
</array>
<key>CFBundleVersion</key>
<string>1</string>
<key>DTCompiler</key>
<string>com.apple.compilers.llvm.clang.1_0</string>
<key>DTPlatformBuild</key>
<string>11C504</string>
<key>DTPlatformVersion</key>
<string>GM</string>
<key>DTSDKBuild</key>
<string>19B90</string>
<key>DTSDKName</key>
<string>macosx10.15</string>
<key>DTXcode</key>
<string>1130</string>
<key>DTXcodeBuild</key>
<string>11C504</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.education</string>
<key>LSMinimumSystemVersion</key>
<string>10.14</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2019, 2020 Tamas Rudnai. All rights reserved.</string>
<key>NSMainStoryboardFile</key>
<string>Main</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
</dict>
</plist>

View File

@ -0,0 +1 @@
APPL????