Compare commits

...

5 Commits

Author SHA1 Message Date
Ciaran Gultnieks 728a5de29e Fix missing comma 2014-04-30 17:43:04 +01:00
Ciaran Gultnieks 48a94ece36 0.5.3-ciarang 2014-04-30 17:30:08 +01:00
Ciaran Gultnieks f31ddb149b Support some more keycodes 2014-04-30 17:29:18 +01:00
Dmitr Rodin 3cd165edd5 version 0.5.2 2010-05-08 18:24:54 +07:00
Dmitr Rodin b510db8d5f version 0.5.1 2010-04-27 09:23:58 +07:00
92 changed files with 12583 additions and 934 deletions

View File

@ -0,0 +1,5 @@
#Sat May 08 18:19:49 ICT 2010
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
org.eclipse.jdt.core.compiler.compliance=1.5
org.eclipse.jdt.core.compiler.source=1.5

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.drodin.zxdroid" android:versionCode="3"
android:versionName="0.4.2">
package="com.drodin.zxdroid" android:versionCode="8"
android:versionName="0.5.3-ciarang">
<supports-screens android:smallScreens="true"
android:normalScreens="true" android:largeScreens="true"
@ -20,6 +20,9 @@
</activity>
<activity android:name=".menu.MenuTop" android:theme="@style/Theme.Translucent" />
<activity android:name=".menu.SelectControl" android:theme="@style/Theme.Translucent.Dialog" />
<activity android:name=".menu.WelcomeMenu" android:theme="@style/Theme.Translucent.Dialog" />
<activity android:name=".menu.HelpView" />
<activity android:name=".menu.FileOpen" />
<activity android:name=".menu.FileSave" />
<activity android:name=".menu.DefineKeys" />
@ -34,4 +37,4 @@
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
<uses-permission android:name="android.permission.INTERNET" />
</manifest>
</manifest>

Binary file not shown.

27
assets/help.txt Normal file
View File

@ -0,0 +1,27 @@
Welcome to ZXdroid - ZX Spectrum Emulator for Android platform by Dmitry Rodin, based on FUSE (the Free Unix Spectrum Emulator) by Philip Kenall.
This emulator can run ZX Spectrum games and applications in various file formats: tapes, snapshots, cartridges & disks. Lots of them you can find at www.worldofspectrum.com in the Archive directory. Download game files and place them on your SD Card.
To get started push 'Menu' button on your phone.
To run a game you have to load its file through 'Menu' > 'Load file'.
If you want to save your current state during the game process, you can do it in 'Menu' > 'Save snapshot'
If your game file doesn't load automatically for some reasons, you can select the Spectrum model under 'Menu' > 'Select machine' and then try to load it once more.
There are two types of controls: on screen touch controls, and hardware keys controls, you can use one of them or combine both.
To switch on screen controls: touch spectrum screen and select appropriate type, or go to 'Menu' > 'On screen controls' and select preferred type there.
To define hardware keys to match some spectrum keys go to 'Menu' > 'Define keys'. You can intercept 'Menu' and 'Back' hardware keys as well, in this case you have to touch spectrum screen to access menu.
If you have trackball it will acts as Dpad you can adjust its sensitivity in the 'Menu' > 'Trackball sensitivity'.
ZXdroid can play spectrum sounds and music, but this feature disabled by default, as it can lead to perfomance downgrade, to enable sound switch 'Menu' > 'Enable sounds'.
If you have problems with perfomance and sound is disabled, you can try to switch skipping of the frames in 'Menu' > 'Skip frames' or disable 'Smooth scaling' under the video options category there.
I you found any mistakes in this help ar any bugs in the emulator mail them to zxdroid@drodin.com, or visit zxdroid.drodin.com and leave your feedbacks there!
Have a good time exploring classic 8bit games, enjoy!

View File

@ -5,7 +5,7 @@ FUSE_PATH := $(ROOT_PATH)/fuse-0.10.0.2
LIBSPECTRUM_PATH := $(ROOT_PATH)/libspectrum-0.5.0.1
FUSEDATADIR := /data/data/com.drodin.zxdroid/files
CURRENT_SNAPSHOT := current.sna
LAST_SNAPSHOT := last.snapshot
PACKAGE_PATH := com/drodin/zxdroid
LIB_CLASS := NativeLib
@ -25,7 +25,7 @@ LOCAL_PATH := $(FUSE_PATH)
LOCAL_CFLAGS := \
-DHAVE_CONFIG_H \
-DFUSEDATADIR=\"$(FUSEDATADIR)\" \
-DCURRENT_SNAPSHOT=\"$(FUSEDATADIR)/$(CURRENT_SNAPSHOT)\" \
-DLAST_SNAPSHOT=\"$(FUSEDATADIR)/$(LAST_SNAPSHOT)\" \
-DLIB_CLASS=\"$(PACKAGE_PATH)/$(LIB_CLASS)\" \
-DAUDIO_CLASS=\"$(PACKAGE_PATH)/$(AUDIO_CLASS)\" \
-I$(FUSE_PATH)/ui/android \
@ -38,6 +38,7 @@ LOCAL_SRC_FILES := \
display.c \
divide.c \
event.c \
fuller.c \
fuse.c \
ide.c \
if1.c \
@ -48,6 +49,7 @@ LOCAL_SRC_FILES := \
keyboard.c \
loader.c \
machine.c \
melodik.c \
memory.c \
mempool.c \
menu.c \
@ -98,6 +100,7 @@ LOCAL_SRC_FILES := \
machines/tc2048.c \
machines/tc2068.c \
machines/ts2068.c \
sound/blipbuffer.c \
timer/timer.c \
ui/android/android.c \
ui/android/androiddisplay.c \
@ -112,7 +115,7 @@ LOCAL_SRC_FILES := \
LOCAL_STATIC_LIBRARIES := spectrum
LOCAL_LDLIBS := -llog -lz -lGLESv1_CM
LOCAL_LDLIBS := -llog -lm -lz -lGLESv1_CM
include $(BUILD_SHARED_LIBRARY)

57
jni/fuse-0.10.0.2/Fuse.pm Normal file
View File

@ -0,0 +1,57 @@
# Fuse.pm: perl modules for autogenerated Fuse code
# $Id: Fuse.pm 2889 2007-05-26 17:45:08Z zubzero $
# This program 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 2 of the License, or
# (at your option) any later version.
# This program 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 this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
# Author contact information:
# E-mail: philip-fuse@shadowmagic.org.uk
package Fuse;
use strict;
sub GPL ($$) {
my( $description, $copyright ) = @_;
return << "CODE";
/* $description
Copyright (c) $copyright
This program 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 2 of the License, or
(at your option) any later version.
This program 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 this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Author contact information:
E-mail: philip-fuse\@shadowmagic.org.uk
*/
CODE
}
1;

View File

@ -1,7 +1,7 @@
/* ay.c: AY-8-3912 routines
Copyright (c) 1999-2004 Philip Kendall
Copyright (c) 1999-2009 Philip Kendall
$Id: ay.c 3494 2008-01-15 16:37:50Z pak21 $
$Id: ay.c 4030 2009-06-07 14:38:38Z fredm $
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -131,22 +131,26 @@ ay_dataport_write( libspectrum_word port GCC_UNUSED, libspectrum_byte b )
if( current == 14 ) printer_serial_write( b );
}
static void
ay_from_snapshot( libspectrum_snap *snap )
void
ay_state_from_snapshot( libspectrum_snap *snap )
{
size_t i;
ay_registerport_write( 0xfffd,
libspectrum_snap_out_ay_registerport( snap ) );
for( i = 0; i < AY_REGISTERS; i++ ) {
machine_current->ay.registers[i] =
libspectrum_snap_ay_registers( snap, i );
sound_ay_write( i, machine_current->ay.registers[i], 0 );
}
}
static void
ay_from_snapshot( libspectrum_snap *snap )
{
if( machine_current->capabilities & LIBSPECTRUM_MACHINE_CAPABILITY_AY ) {
ay_registerport_write( 0xfffd,
libspectrum_snap_out_ay_registerport( snap ) );
for( i = 0; i < AY_REGISTERS; i++ ) {
machine_current->ay.registers[i] =
libspectrum_snap_ay_registers( snap, i );
sound_ay_write( i, machine_current->ay.registers[i], 0 );
}
ay_state_from_snapshot( snap );
}
}

165
jni/fuse-0.10.0.2/ay.c.orig Normal file
View File

@ -0,0 +1,165 @@
/* ay.c: AY-8-3912 routines
Copyright (c) 1999-2004 Philip Kendall
$Id: ay.c 3494 2008-01-15 16:37:50Z pak21 $
This program 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 2 of the License, or
(at your option) any later version.
This program 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 this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Author contact information:
E-mail: philip-fuse@shadowmagic.org.uk
*/
#include <config.h>
#include <string.h>
#include "compat.h"
#include "machine.h"
#include "module.h"
#include "printer.h"
#include "psg.h"
#include "sound.h"
/* Unused bits in the AY registers are silently zeroed out; these masks
accomplish this */
static const libspectrum_byte mask[ AY_REGISTERS ] = {
0xff, 0x0f, 0xff, 0x0f, 0xff, 0x0f, 0x1f, 0xff,
0x1f, 0x1f, 0x1f, 0xff, 0xff, 0x0f, 0xff, 0xff,
};
static void ay_reset( int hard_reset );
static void ay_from_snapshot( libspectrum_snap *snap );
static void ay_to_snapshot( libspectrum_snap *snap );
static module_info_t ay_module_info = {
ay_reset,
NULL,
NULL,
ay_from_snapshot,
ay_to_snapshot,
};
int
ay_init( void )
{
module_register( &ay_module_info );
return 0;
}
static void
ay_reset( int hard_reset GCC_UNUSED )
{
ayinfo *ay = &machine_current->ay;
ay->current_register = 0;
memset( ay->registers, 0, sizeof( ay->registers ) );
}
/* What happens when the AY register port (traditionally 0xfffd on the 128K
machines) is read from */
libspectrum_byte
ay_registerport_read( libspectrum_word port GCC_UNUSED, int *attached )
{
int current;
const libspectrum_byte port_input = 0xbf; /* always allow serial output */
*attached = 1;
current = machine_current->ay.current_register;
/* The AY I/O ports return input directly from the port when in
input mode; but in output mode, they return an AND between the
register value and the port input. So, allow for this when
reading R14... */
if( current == 14 ) {
if(machine_current->ay.registers[7] & 0x40)
return (port_input & machine_current->ay.registers[14]);
else
return port_input;
}
/* R15 is simpler to do, as the 8912 lacks the second I/O port, and
the input-mode input is always 0xff */
if( current == 15 && !( machine_current->ay.registers[7] & 0x80 ) )
return 0xff;
/* Otherwise return register value, appropriately masked */
return machine_current->ay.registers[ current ] & mask[ current ];
}
/* And when it's written to */
void
ay_registerport_write( libspectrum_word port GCC_UNUSED, libspectrum_byte b )
{
machine_current->ay.current_register = (b & 15);
}
/* What happens when the AY data port (traditionally 0xbffd on the 128K
machines) is written to; no corresponding read function as this
always returns 0xff */
void
ay_dataport_write( libspectrum_word port GCC_UNUSED, libspectrum_byte b )
{
int current;
current = machine_current->ay.current_register;
machine_current->ay.registers[ current ] = b & mask[ current ];
sound_ay_write( current, b, tstates );
if( psg_recording ) psg_write_register( current, b );
if( current == 14 ) printer_serial_write( b );
}
static void
ay_from_snapshot( libspectrum_snap *snap )
{
size_t i;
if( machine_current->capabilities & LIBSPECTRUM_MACHINE_CAPABILITY_AY ) {
ay_registerport_write( 0xfffd,
libspectrum_snap_out_ay_registerport( snap ) );
for( i = 0; i < AY_REGISTERS; i++ ) {
machine_current->ay.registers[i] =
libspectrum_snap_ay_registers( snap, i );
sound_ay_write( i, machine_current->ay.registers[i], 0 );
}
}
}
static void
ay_to_snapshot( libspectrum_snap *snap )
{
size_t i;
libspectrum_snap_set_out_ay_registerport(
snap, machine_current->ay.current_register
);
for( i = 0; i < AY_REGISTERS; i++ )
libspectrum_snap_set_ay_registers( snap, i,
machine_current->ay.registers[i] );
}

View File

@ -1,7 +1,7 @@
/* ay.h: AY-8-3912 routines
Copyright (c) 1999-2004 Philip Kendall
Copyright (c) 1999-2009 Philip Kendall
$Id: ay.h 2993 2007-06-17 13:54:49Z pak21 $
$Id: ay.h 4030 2009-06-07 14:38:38Z fredm $
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -42,4 +42,6 @@ void ay_registerport_write( libspectrum_word port, libspectrum_byte b );
void ay_dataport_write( libspectrum_word port, libspectrum_byte b );
void ay_state_from_snapshot( libspectrum_snap *snap );
#endif /* #ifndef FUSE_AY_H */

View File

@ -0,0 +1,45 @@
/* ay.h: AY-8-3912 routines
Copyright (c) 1999-2004 Philip Kendall
$Id: ay.h 2993 2007-06-17 13:54:49Z pak21 $
This program 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 2 of the License, or
(at your option) any later version.
This program 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 this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Author contact information:
E-mail: philip-fuse@shadowmagic.org.uk
*/
#ifndef FUSE_AY_H
#define FUSE_AY_H
#include <libspectrum.h>
#define AY_REGISTERS 16
typedef struct ayinfo {
int current_register;
libspectrum_byte registers[ AY_REGISTERS ];
} ayinfo;
int ay_init( void );
libspectrum_byte ay_registerport_read( libspectrum_word port, int *attached );
void ay_registerport_write( libspectrum_word port, libspectrum_byte b );
void ay_dataport_write( libspectrum_word port, libspectrum_byte b );
#endif /* #ifndef FUSE_AY_H */

View File

@ -0,0 +1,90 @@
/* fuller.c: Routines for handling the Fuller Box
Copyright (c) 2007-2009 Stuart Brady, Fredrick Meunier
$Id: fuller.c 4032 2009-06-10 11:09:44Z fredm $
This program 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 2 of the License, or
(at your option) any later version.
This program 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 this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Author contact information:
Philip: philip-fuse@shadowmagic.org.uk
Stuart: sdbrady@ntlworld.com
*/
#include <config.h>
#include <libspectrum.h>
#include "ay.h"
#include "compat.h"
#include "fuller.h"
#include "joystick.h"
#include "module.h"
#include "periph.h"
#include "settings.h"
static void fuller_enabled_snapshot( libspectrum_snap *snap );
static void fuller_from_snapshot( libspectrum_snap *snap );
static void fuller_to_snapshot( libspectrum_snap *snap );
static module_info_t fuller_module_info = {
NULL,
NULL,
fuller_enabled_snapshot,
fuller_from_snapshot,
fuller_to_snapshot,
};
const periph_t fuller_peripherals[] = {
{ 0x00ff, 0x003f, ay_registerport_read, ay_registerport_write },
{ 0x00ff, 0x005f, NULL, ay_dataport_write },
{ 0x00ff, 0x007f, joystick_fuller_read, NULL },
};
const size_t fuller_peripherals_count =
sizeof( fuller_peripherals ) / sizeof( periph_t );
static void
fuller_enabled_snapshot( libspectrum_snap *snap )
{
if( libspectrum_snap_fuller_box_active( snap ) )
settings_current.fuller = 1;
}
static void
fuller_from_snapshot( libspectrum_snap *snap )
{
if( periph_fuller_active ) {
ay_state_from_snapshot( snap );
}
}
static void
fuller_to_snapshot( libspectrum_snap *snap )
{
libspectrum_snap_set_fuller_box_active( snap, periph_fuller_active );
}
int
fuller_init( void )
{
module_register( &fuller_module_info );
return 0;
}

View File

@ -0,0 +1,40 @@
/* fuller.h: Routines for handling the Fuller Box
Copyright (c) 2007-2009 Stuart Brady, Fredrick Meunier
$Id: fuller.h 4030 2009-06-07 14:38:38Z fredm $
This program 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 2 of the License, or
(at your option) any later version.
This program 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 this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Author contact information:
Philip: philip-fuse@shadowmagic.org.uk
Stuart: sdbrady@ntlworld.com
*/
#ifndef FUSE_FULLER_H
#define FUSE_FULLER_H
#include <libspectrum.h>
#include "periph.h"
extern const periph_t fuller_peripherals[];
extern const size_t fuller_peripherals_count;
int fuller_init( void );
#endif /* #ifndef FUSE_FULLER_H */

View File

@ -2,7 +2,7 @@
Copyright (c) 2001-2004 Russell Marks, Philip Kendall
Copyright (c) 2003 Darren Salt
$Id: joystick.c 3389 2007-12-03 12:54:17Z fredm $
$Id: joystick.c 4030 2009-06-07 14:38:38Z fredm $
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -65,6 +65,7 @@ static const keyboard_key_name sinclair2_key[5] =
static libspectrum_byte kempston_value;
static libspectrum_byte timex1_value;
static libspectrum_byte timex2_value;
static libspectrum_byte fuller_value;
/* The names of the joysticks we can emulate. Order must correspond to
that of joystick.h:joystick_type_t */
@ -73,7 +74,15 @@ const char *joystick_name[ JOYSTICK_TYPE_COUNT ] = {
"Cursor",
"Kempston",
"Sinclair 1", "Sinclair 2",
"Timex 1", "Timex 2"
"Timex 1", "Timex 2",
"Fuller"
};
const char *joystick_connection[ JOYSTICK_CONN_COUNT ] = {
"None",
"Keyboard",
"Joystick 1",
"Joystick 2",
};
static void joystick_from_snapshot( libspectrum_snap *snap );
@ -96,6 +105,7 @@ fuse_joystick_init (void)
{
joysticks_supported = ui_joystick_init();
kempston_value = timex1_value = timex2_value = 0x00;
fuller_value = 0xff;
module_register( &joystick_module_info );
}
@ -172,6 +182,14 @@ joystick_press( int which, joystick_button button, int press )
}
return 1;
case JOYSTICK_TYPE_FULLER:
if( press ) {
fuller_value &= ~timex_mask[ button ];
} else {
fuller_value |= timex_mask[ button ];
}
return 1;
case JOYSTICK_TYPE_NONE: return 0;
}
@ -198,6 +216,16 @@ joystick_timex_read( libspectrum_word port GCC_UNUSED, libspectrum_byte which )
return which ? timex2_value : timex1_value;
}
libspectrum_byte
joystick_fuller_read( libspectrum_word port GCC_UNUSED, int *attached )
{
if( !periph_fuller_active ) return 0xff;
*attached = 1;
return fuller_value;
}
static void
joystick_from_snapshot( libspectrum_snap *snap )
{
@ -226,6 +254,8 @@ joystick_from_snapshot( libspectrum_snap *snap )
fuse_type = JOYSTICK_TYPE_TIMEX_2;
break;
case LIBSPECTRUM_JOYSTICK_FULLER:
fuse_type = JOYSTICK_TYPE_FULLER;
break;
default:
ui_error( UI_ERROR_INFO, "Ignoring unsupported joystick in snapshot %s",
libspectrum_joystick_name( libspectrum_snap_joystick_list( snap, i ) ));
@ -286,6 +316,9 @@ add_joystick( libspectrum_snap *snap, joystick_type_t fuse_type, int inputs )
case JOYSTICK_TYPE_TIMEX_2:
libspectrum_type = LIBSPECTRUM_JOYSTICK_TIMEX_2;
break;
case JOYSTICK_TYPE_FULLER:
libspectrum_type = LIBSPECTRUM_JOYSTICK_FULLER;
break;
case JOYSTICK_TYPE_NONE:
default:

View File

@ -0,0 +1,322 @@
/* joystick.c: Joystick emulation support
Copyright (c) 2001-2004 Russell Marks, Philip Kendall
Copyright (c) 2003 Darren Salt
$Id: joystick.c 3389 2007-12-03 12:54:17Z fredm $
This program 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 2 of the License, or
(at your option) any later version.
This program 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 this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Author contact information:
E-mail: philip-fuse@shadowmagic.org.uk
*/
#include <config.h>
#include <libspectrum.h>
#include "fuse.h"
#include "joystick.h"
#include "keyboard.h"
#include "module.h"
#include "periph.h"
#include "rzx.h"
#include "settings.h"
#include "spectrum.h"
#include "machine.h"
#include "ui/ui.h"
#include "ui/uijoystick.h"
/* Number of joysticks known about & initialised */
int joysticks_supported = 0;
/* The bit masks used by the various joysticks. The order is the same
as the ordering of buttons in joystick.h:joystick_button (left,
right, up, down, fire ) */
static const libspectrum_byte kempston_mask[5] =
{ 0x02, 0x01, 0x08, 0x04, 0x10 };
static const libspectrum_byte timex_mask[5] =
{ 0x04, 0x08, 0x01, 0x02, 0x80 };
/* The keys used by the Cursor joystick */
static const keyboard_key_name cursor_key[5] =
{ KEYBOARD_5, KEYBOARD_8, KEYBOARD_7, KEYBOARD_6, KEYBOARD_0 };
/* The keys used by the two Sinclair joysticks */
static const keyboard_key_name sinclair1_key[5] =
{ KEYBOARD_6, KEYBOARD_7, KEYBOARD_9, KEYBOARD_8, KEYBOARD_0 };
static const keyboard_key_name sinclair2_key[5] =
{ KEYBOARD_1, KEYBOARD_2, KEYBOARD_4, KEYBOARD_3, KEYBOARD_5 };
/* The current values for the joysticks we can emulate */
static libspectrum_byte kempston_value;
static libspectrum_byte timex1_value;
static libspectrum_byte timex2_value;
/* The names of the joysticks we can emulate. Order must correspond to
that of joystick.h:joystick_type_t */
const char *joystick_name[ JOYSTICK_TYPE_COUNT ] = {
"None",
"Cursor",
"Kempston",
"Sinclair 1", "Sinclair 2",
"Timex 1", "Timex 2"
};
static void joystick_from_snapshot( libspectrum_snap *snap );
static void joystick_to_snapshot( libspectrum_snap *snap );
static module_info_t joystick_module_info = {
NULL,
NULL,
NULL,
joystick_from_snapshot,
joystick_to_snapshot,
};
/* Init/shutdown functions. Errors aren't important here */
void
fuse_joystick_init (void)
{
joysticks_supported = ui_joystick_init();
kempston_value = timex1_value = timex2_value = 0x00;
module_register( &joystick_module_info );
}
void
fuse_joystick_end (void)
{
ui_joystick_end();
}
int
joystick_press( int which, joystick_button button, int press )
{
joystick_type_t type;
switch( which ) {
case 0: type = settings_current.joystick_1_output; break;
case 1: type = settings_current.joystick_2_output; break;
case JOYSTICK_KEYBOARD:
type = settings_current.joystick_keyboard_output; break;
default:
return 0;
}
switch( type ) {
case JOYSTICK_TYPE_CURSOR:
if( press ) {
keyboard_press( cursor_key[ button ] );
} else {
keyboard_release( cursor_key[ button ] );
}
return 1;
case JOYSTICK_TYPE_KEMPSTON:
if( press ) {
kempston_value |= kempston_mask[ button ];
} else {
kempston_value &= ~kempston_mask[ button ];
}
return 1;
case JOYSTICK_TYPE_SINCLAIR_1:
if( press ) {
keyboard_press( sinclair1_key[ button ] );
} else {
keyboard_release( sinclair1_key[ button ] );
}
return 1;
case JOYSTICK_TYPE_SINCLAIR_2:
if( press ) {
keyboard_press( sinclair2_key[ button ] );
} else {
keyboard_release( sinclair2_key[ button ] );
}
return 1;
case JOYSTICK_TYPE_TIMEX_1:
if( press ) {
timex1_value |= timex_mask[ button ];
} else {
timex1_value &= ~timex_mask[ button ];
}
return 1;
case JOYSTICK_TYPE_TIMEX_2:
if( press ) {
timex2_value |= timex_mask[ button ];
} else {
timex2_value &= ~timex_mask[ button ];
}
return 1;
case JOYSTICK_TYPE_NONE: return 0;
}
ui_error( UI_ERROR_ERROR, "%s:joystick_press:unknown joystick type %d",
__FILE__, type );
fuse_abort();
}
/* Read functions for specific interfaces */
libspectrum_byte
joystick_kempston_read( libspectrum_word port GCC_UNUSED, int *attached )
{
if( !periph_kempston_active ) return 0xff;
*attached = 1;
return kempston_value;
}
libspectrum_byte
joystick_timex_read( libspectrum_word port GCC_UNUSED, libspectrum_byte which )
{
return which ? timex2_value : timex1_value;
}
static void
joystick_from_snapshot( libspectrum_snap *snap )
{
size_t i;
size_t num_joysticks = libspectrum_snap_joystick_active_count( snap );
joystick_type_t fuse_type;
for( i = 0; i < num_joysticks; i++ ) {
switch( libspectrum_snap_joystick_list( snap, i ) ) {
case LIBSPECTRUM_JOYSTICK_CURSOR:
fuse_type = JOYSTICK_TYPE_CURSOR;
break;
case LIBSPECTRUM_JOYSTICK_KEMPSTON:
fuse_type = JOYSTICK_TYPE_KEMPSTON;
break;
case LIBSPECTRUM_JOYSTICK_SINCLAIR_1:
fuse_type = JOYSTICK_TYPE_SINCLAIR_1;
break;
case LIBSPECTRUM_JOYSTICK_SINCLAIR_2:
fuse_type = JOYSTICK_TYPE_SINCLAIR_2;
break;
case LIBSPECTRUM_JOYSTICK_TIMEX_1:
fuse_type = JOYSTICK_TYPE_TIMEX_1;
break;
case LIBSPECTRUM_JOYSTICK_TIMEX_2:
fuse_type = JOYSTICK_TYPE_TIMEX_2;
break;
case LIBSPECTRUM_JOYSTICK_FULLER:
default:
ui_error( UI_ERROR_INFO, "Ignoring unsupported joystick in snapshot %s",
libspectrum_joystick_name( libspectrum_snap_joystick_list( snap, i ) ));
continue;
};
if( settings_current.joystick_keyboard_output != fuse_type &&
settings_current.joystick_1_output != fuse_type &&
settings_current.joystick_2_output != fuse_type &&
!rzx_playback ) {
switch( ui_confirm_joystick( libspectrum_snap_joystick_list(snap,i),
libspectrum_snap_joystick_inputs(snap,i)) ) {
case UI_CONFIRM_JOYSTICK_KEYBOARD:
settings_current.joystick_keyboard_output = fuse_type;
break;
case UI_CONFIRM_JOYSTICK_JOYSTICK_1:
settings_current.joystick_1_output = fuse_type;
break;
case UI_CONFIRM_JOYSTICK_JOYSTICK_2:
settings_current.joystick_2_output = fuse_type;
break;
case UI_CONFIRM_JOYSTICK_NONE:
break;
}
}
/* If the snap was configured for a Kempston joystick, enable
our Kempston emulation in case the snap was reading from
the joystick to prevent things going haywire */
if( fuse_type == JOYSTICK_TYPE_KEMPSTON )
settings_current.joy_kempston = 1;
}
}
static void
add_joystick( libspectrum_snap *snap, joystick_type_t fuse_type, int inputs )
{
size_t i;
size_t num_joysticks = libspectrum_snap_joystick_active_count( snap );
libspectrum_joystick libspectrum_type;
switch( fuse_type ) {
case JOYSTICK_TYPE_CURSOR:
libspectrum_type = LIBSPECTRUM_JOYSTICK_CURSOR;
break;
case JOYSTICK_TYPE_KEMPSTON:
libspectrum_type = LIBSPECTRUM_JOYSTICK_KEMPSTON;
break;
case JOYSTICK_TYPE_SINCLAIR_1:
libspectrum_type = LIBSPECTRUM_JOYSTICK_SINCLAIR_1;
break;
case JOYSTICK_TYPE_SINCLAIR_2:
libspectrum_type = LIBSPECTRUM_JOYSTICK_SINCLAIR_2;
break;
case JOYSTICK_TYPE_TIMEX_1:
libspectrum_type = LIBSPECTRUM_JOYSTICK_TIMEX_1;
break;
case JOYSTICK_TYPE_TIMEX_2:
libspectrum_type = LIBSPECTRUM_JOYSTICK_TIMEX_2;
break;
case JOYSTICK_TYPE_NONE:
default:
return;
break;
}
for( i = 0; i < num_joysticks; i++ ) {
if( libspectrum_snap_joystick_list( snap, i ) == libspectrum_type ) {
libspectrum_snap_set_joystick_inputs( snap, i, inputs |
libspectrum_snap_joystick_inputs( snap, i ) );
return;
}
}
libspectrum_snap_set_joystick_list( snap, num_joysticks, libspectrum_type );
libspectrum_snap_set_joystick_inputs( snap, num_joysticks, inputs );
libspectrum_snap_set_joystick_active_count( snap, num_joysticks + 1 );
}
static void
joystick_to_snapshot( libspectrum_snap *snap )
{
if( settings_current.joy_kempston ) {
add_joystick( snap, JOYSTICK_TYPE_KEMPSTON,
LIBSPECTRUM_JOYSTICK_INPUT_NONE );
}
add_joystick( snap, settings_current.joystick_keyboard_output,
LIBSPECTRUM_JOYSTICK_INPUT_KEYBOARD );
add_joystick( snap, settings_current.joystick_1_output,
LIBSPECTRUM_JOYSTICK_INPUT_JOYSTICK_1 );
add_joystick( snap, settings_current.joystick_2_output,
LIBSPECTRUM_JOYSTICK_INPUT_JOYSTICK_2 );
}

View File

@ -2,7 +2,7 @@
Copyright (c) 2001-2004 Russell Marks, Philip Kendall
Copyright (c) 2003 Darren Salt
$Id: joystick.h 2993 2007-06-17 13:54:49Z pak21 $
$Id: joystick.h 4030 2009-06-07 14:38:38Z fredm $
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -49,12 +49,15 @@ typedef enum joystick_type_t {
JOYSTICK_TYPE_SINCLAIR_2,
JOYSTICK_TYPE_TIMEX_1,
JOYSTICK_TYPE_TIMEX_2,
JOYSTICK_TYPE_FULLER,
} joystick_type_t;
#define JOYSTICK_TYPE_COUNT 7
#define JOYSTICK_TYPE_COUNT 8
extern const char *joystick_name[];
extern const char *joystick_connection[];
#define JOYSTICK_CONN_COUNT 4
typedef enum joystick_button {
@ -75,5 +78,7 @@ libspectrum_byte joystick_kempston_read ( libspectrum_word port,
int *attached );
libspectrum_byte joystick_timex_read ( libspectrum_word port,
libspectrum_byte which );
libspectrum_byte joystick_fuller_read ( libspectrum_word port,
int *attached );
#endif /* #ifndef FUSE_JOYSTICK_H */

View File

@ -0,0 +1,79 @@
/* joystick.h: Joystick emulation support
Copyright (c) 2001-2004 Russell Marks, Philip Kendall
Copyright (c) 2003 Darren Salt
$Id: joystick.h 2993 2007-06-17 13:54:49Z pak21 $
This program 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 2 of the License, or
(at your option) any later version.
This program 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 this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Author contact information:
E-mail: philip-fuse@shadowmagic.org.uk
*/
#ifndef FUSE_JOYSTICK_H
#define FUSE_JOYSTICK_H
#include <libspectrum.h>
/* Number of joysticks known about & initialised */
extern int joysticks_supported;
/* Init/shutdown functions. Errors aren't important here */
void fuse_joystick_init( void );
void fuse_joystick_end( void );
/* A constant to identify the joystick emulated via the keyboard */
#define JOYSTICK_KEYBOARD 2
typedef enum joystick_type_t {
JOYSTICK_TYPE_NONE = 0,
JOYSTICK_TYPE_CURSOR,
JOYSTICK_TYPE_KEMPSTON,
JOYSTICK_TYPE_SINCLAIR_1,
JOYSTICK_TYPE_SINCLAIR_2,
JOYSTICK_TYPE_TIMEX_1,
JOYSTICK_TYPE_TIMEX_2,
} joystick_type_t;
#define JOYSTICK_TYPE_COUNT 7
extern const char *joystick_name[];
typedef enum joystick_button {
JOYSTICK_BUTTON_LEFT = 0,
JOYSTICK_BUTTON_RIGHT,
JOYSTICK_BUTTON_UP,
JOYSTICK_BUTTON_DOWN,
JOYSTICK_BUTTON_FIRE,
} joystick_button;
/* Called whenever the (Spectrum) joystick is moved or the fire button
pressed */
int joystick_press( int which, joystick_button button, int press );
/* Interface-specific read functions */
libspectrum_byte joystick_kempston_read ( libspectrum_word port,
int *attached );
libspectrum_byte joystick_timex_read ( libspectrum_word port,
libspectrum_byte which );
#endif /* #ifndef FUSE_JOYSTICK_H */

View File

@ -1,7 +1,7 @@
/* spec16.c: Spectrum 16K specific routines
Copyright (c) 1999-2007 Philip Kendall
Copyright (c) 1999-2009 Philip Kendall
$Id: spec16.c 3566 2008-03-18 12:59:16Z pak21 $
$Id: spec16.c 4038 2009-06-24 14:25:23Z fredm $
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -82,7 +82,6 @@ int spec16_init( fuse_machine_info *machine )
machine->memory_map = spec48_memory_map;
return 0;
}
static int
@ -101,6 +100,8 @@ spec16_reset( void )
periph_setup_interface1( PERIPH_PRESENT_OPTIONAL );
periph_setup_interface2( PERIPH_PRESENT_OPTIONAL );
periph_setup_plusd( PERIPH_PRESENT_OPTIONAL );
periph_setup_fuller( PERIPH_PRESENT_OPTIONAL );
periph_setup_melodik( PERIPH_PRESENT_OPTIONAL );
periph_update();
/* ROM 0, RAM 5, nothing, nothing */

View File

@ -0,0 +1,129 @@
/* spec16.c: Spectrum 16K specific routines
Copyright (c) 1999-2007 Philip Kendall
$Id: spec16.c 3566 2008-03-18 12:59:16Z pak21 $
This program 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 2 of the License, or
(at your option) any later version.
This program 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 this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Author contact information:
E-mail: philip-fuse@shadowmagic.org.uk
*/
#include <config.h>
#include <stdio.h>
#include <string.h>
#include <libspectrum.h>
#include "joystick.h"
#include "machine.h"
#include "machines.h"
#include "memory.h"
#include "periph.h"
#include "printer.h"
#include "settings.h"
#include "spec48.h"
#include "ula.h"
#include "if1.h"
static int spec16_reset( void );
static libspectrum_byte empty_chunk[ MEMORY_PAGE_SIZE ];
static memory_page empty_mapping;
static const periph_t peripherals[] = {
{ 0x0001, 0x0000, ula_read, ula_write },
{ 0x0004, 0x0000, printer_zxp_read, printer_zxp_write },
{ 0x00e0, 0x0000, joystick_kempston_read, NULL },
};
static const size_t peripherals_count =
sizeof( peripherals ) / sizeof( periph_t );
int spec16_init( fuse_machine_info *machine )
{
machine->machine = LIBSPECTRUM_MACHINE_16;
machine->id = "16";
machine->reset = spec16_reset;
machine->timex = 0;
machine->ram.port_from_ula = spec48_port_from_ula;
machine->ram.contend_delay = spectrum_contend_delay_65432100;
machine->ram.contend_delay_no_mreq = spectrum_contend_delay_65432100;
memset( empty_chunk, 0xff, MEMORY_PAGE_SIZE );
empty_mapping.page = empty_chunk;
empty_mapping.writable = 0;
empty_mapping.contended = 0;
empty_mapping.bank = MEMORY_BANK_NONE;
empty_mapping.source = MEMORY_SOURCE_SYSTEM;
machine->unattached_port = spectrum_unattached_port;
machine->shutdown = NULL;
machine->memory_map = spec48_memory_map;
return 0;
}
static int
spec16_reset( void )
{
int error;
size_t i;
error = machine_load_rom( 0, 0, settings_current.rom_16,
settings_default.rom_16, 0x4000 );
if( error ) return error;
error = periph_setup( peripherals, peripherals_count );
if( error ) return error;
periph_setup_kempston( PERIPH_PRESENT_OPTIONAL );
periph_setup_interface1( PERIPH_PRESENT_OPTIONAL );
periph_setup_interface2( PERIPH_PRESENT_OPTIONAL );
periph_setup_plusd( PERIPH_PRESENT_OPTIONAL );
periph_update();
/* ROM 0, RAM 5, nothing, nothing */
memory_map_home[0] = &memory_map_rom[ 0];
memory_map_home[1] = &memory_map_rom[ 1];
memory_map_home[2] = &memory_map_ram[10];
memory_map_home[3] = &memory_map_ram[11];
memory_map_home[4] = memory_map_home[5] = &empty_mapping;
memory_map_home[6] = memory_map_home[7] = &empty_mapping;
/* The RAM page is present/writable and contended */
for( i = 2; i <= 3; i++ ) {
memory_map_home[ i ]->writable = 1;
memory_map_home[ i ]->contended = 1;
}
for( i = 0; i < 8; i++ )
memory_map_read[i] = memory_map_write[i] = *memory_map_home[i];
memory_current_screen = 5;
memory_screen_mask = 0xffff;
return 0;
}

View File

@ -1,7 +1,7 @@
/* spec48.c: Spectrum 48K specific routines
Copyright (c) 1999-2007 Philip Kendall
Copyright (c) 1999-2009 Philip Kendall
$Id: spec48.c 3566 2008-03-18 12:59:16Z pak21 $
$Id: spec48.c 4038 2009-06-24 14:25:23Z fredm $
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -29,6 +29,7 @@
#include <libspectrum.h>
#include "disk/beta.h"
#include "joystick.h"
#include "machine.h"
#include "memory.h"
@ -77,7 +78,6 @@ int spec48_init( fuse_machine_info *machine )
machine->memory_map = spec48_memory_map;
return 0;
}
static int
@ -95,8 +95,14 @@ spec48_reset( void )
periph_setup_interface1( PERIPH_PRESENT_OPTIONAL );
periph_setup_interface2( PERIPH_PRESENT_OPTIONAL );
periph_setup_plusd( PERIPH_PRESENT_OPTIONAL );
periph_setup_beta128( PERIPH_PRESENT_OPTIONAL );
periph_setup_fuller( PERIPH_PRESENT_OPTIONAL );
periph_setup_melodik( PERIPH_PRESENT_OPTIONAL );
periph_update();
periph_register_beta128();
beta_builtin = 0;
memory_current_screen = 5;
memory_screen_mask = 0xffff;

View File

@ -0,0 +1,151 @@
/* spec48.c: Spectrum 48K specific routines
Copyright (c) 1999-2007 Philip Kendall
$Id: spec48.c 3566 2008-03-18 12:59:16Z pak21 $
This program 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 2 of the License, or
(at your option) any later version.
This program 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 this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Author contact information:
E-mail: philip-fuse@shadowmagic.org.uk
*/
#include <config.h>
#include <stdio.h>
#include <libspectrum.h>
#include "joystick.h"
#include "machine.h"
#include "memory.h"
#include "periph.h"
#include "printer.h"
#include "settings.h"
#include "spec48.h"
#include "spectrum.h"
#include "ula.h"
#include "if1.h"
static int spec48_reset( void );
static const periph_t peripherals[] = {
{ 0x0001, 0x0000, ula_read, ula_write },
{ 0x0004, 0x0000, printer_zxp_read, printer_zxp_write },
{ 0x00e0, 0x0000, joystick_kempston_read, NULL },
};
static const size_t peripherals_count =
sizeof( peripherals ) / sizeof( periph_t );
int
spec48_port_from_ula( libspectrum_word port )
{
/* All even ports supplied by ULA */
return !( port & 0x0001 );
}
int spec48_init( fuse_machine_info *machine )
{
machine->machine = LIBSPECTRUM_MACHINE_48;
machine->id = "48";
machine->reset = spec48_reset;
machine->timex = 0;
machine->ram.port_from_ula = spec48_port_from_ula;
machine->ram.contend_delay = spectrum_contend_delay_65432100;
machine->ram.contend_delay_no_mreq = spectrum_contend_delay_65432100;
machine->unattached_port = spectrum_unattached_port;
machine->shutdown = NULL;
machine->memory_map = spec48_memory_map;
return 0;
}
static int
spec48_reset( void )
{
int error;
error = machine_load_rom( 0, 0, settings_current.rom_48,
settings_default.rom_48, 0x4000 );
if( error ) return error;
error = periph_setup( peripherals, peripherals_count );
if( error ) return error;
periph_setup_kempston( PERIPH_PRESENT_OPTIONAL );
periph_setup_interface1( PERIPH_PRESENT_OPTIONAL );
periph_setup_interface2( PERIPH_PRESENT_OPTIONAL );
periph_setup_plusd( PERIPH_PRESENT_OPTIONAL );
periph_update();
memory_current_screen = 5;
memory_screen_mask = 0xffff;
return spec48_common_reset();
}
int
spec48_common_reset( void )
{
size_t i;
/* ROM 0, RAM 5, RAM 2, RAM 0 */
memory_map_home[0] = &memory_map_rom[ 0];
memory_map_home[1] = &memory_map_rom[ 1];
memory_map_home[2] = &memory_map_ram[10];
memory_map_home[3] = &memory_map_ram[11];
memory_map_home[4] = &memory_map_ram[ 4];
memory_map_home[5] = &memory_map_ram[ 5];
memory_map_home[6] = &memory_map_ram[ 0];
memory_map_home[7] = &memory_map_ram[ 1];
/* 0x4000 - 0x7fff contended */
memory_map_home[2]->contended = memory_map_home[3]->contended = 1;
/* 0x8000 - 0xffff not contended */
memory_map_home[ 4]->contended = memory_map_home[ 5]->contended = 0;
memory_map_home[ 6]->contended = memory_map_home[ 7]->contended = 0;
/* Mark as present/writeable */
for( i = 2; i < 8; ++i )
memory_map_home[i]->writable = 1;
for( i = 0; i < 8; i++ )
memory_map_read[i] = memory_map_write[i] = *memory_map_home[i];
return 0;
}
int
spec48_memory_map( void )
{
/* By default, 0x0000 to 0x3fff come from the home bank */
memory_map_read[0] = memory_map_write[0] = *memory_map_home[0];
memory_map_read[1] = memory_map_write[1] = *memory_map_home[1];
memory_romcs_map();
return 0;
}

View File

@ -1,8 +1,8 @@
/* tc2048.c: Timex TC2048 specific routines
Copyright (c) 1999-2005 Philip Kendall
Copyright (c) 2002-2004 Fredrick Meunier
Copyright (c) 2002-2009 Fredrick Meunier
$Id: tc2048.c 3566 2008-03-18 12:59:16Z pak21 $
$Id: tc2048.c 4038 2009-06-24 14:25:23Z fredm $
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -30,6 +30,7 @@
#include <libspectrum.h>
#include "disk/beta.h"
#include "joystick.h"
#include "machine.h"
#include "machines.h"
@ -96,7 +97,6 @@ int tc2048_init( fuse_machine_info *machine )
machine->memory_map = tc2068_memory_map;
return 0;
}
static int
@ -115,8 +115,14 @@ tc2048_reset( void )
periph_setup_interface1( PERIPH_PRESENT_OPTIONAL );
periph_setup_interface2( PERIPH_PRESENT_OPTIONAL );
periph_setup_plusd( PERIPH_PRESENT_OPTIONAL );
periph_setup_beta128( PERIPH_PRESENT_OPTIONAL );
periph_setup_fuller( PERIPH_PRESENT_OPTIONAL );
periph_setup_melodik( PERIPH_PRESENT_OPTIONAL );
periph_update();
periph_register_beta128();
beta_builtin = 0;
for( i = 0; i < 8; i++ ) {
timex_dock[i] = fake_mapping;

View File

@ -0,0 +1,137 @@
/* tc2048.c: Timex TC2048 specific routines
Copyright (c) 1999-2005 Philip Kendall
Copyright (c) 2002-2004 Fredrick Meunier
$Id: tc2048.c 3566 2008-03-18 12:59:16Z pak21 $
This program 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 2 of the License, or
(at your option) any later version.
This program 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 this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Author contact information:
E-mail: philip-fuse@shadowmagic.org.uk
*/
#include <config.h>
#include <string.h>
#include <libspectrum.h>
#include "joystick.h"
#include "machine.h"
#include "machines.h"
#include "memory.h"
#include "periph.h"
#include "printer.h"
#include "settings.h"
#include "scld.h"
#include "spec48.h"
#include "tc2068.h"
#include "ula.h"
#include "if1.h"
static int tc2048_reset( void );
static const periph_t peripherals[] = {
{ 0x0020, 0x0000, joystick_kempston_read, NULL },
{ 0x00ff, 0x00f4, scld_hsr_read, scld_hsr_write },
/* TS2040/Alphacom printer */
{ 0x00ff, 0x00fb, printer_zxp_read, printer_zxp_write },
/* Lower 8 bits of Timex ports are fully decoded */
{ 0x00ff, 0x00fe, ula_read, ula_write },
{ 0x00ff, 0x00ff, scld_dec_read, scld_dec_write },
};
static const size_t peripherals_count =
sizeof( peripherals ) / sizeof( periph_t );
int
tc2048_port_from_ula( libspectrum_word port )
{
/* Ports F4 (HSR), FE (SCLD) and FF (DEC) supplied by ULA */
port &= 0xff;
return( port == 0xf4 || port == 0xfe || port == 0xff );
}
int tc2048_init( fuse_machine_info *machine )
{
machine->machine = LIBSPECTRUM_MACHINE_TC2048;
machine->id = "2048";
machine->reset = tc2048_reset;
machine->timex = 1;
machine->ram.port_from_ula = tc2048_port_from_ula;
machine->ram.contend_delay = spectrum_contend_delay_65432100;
machine->ram.contend_delay_no_mreq = spectrum_contend_delay_65432100;
memset( fake_bank, 0xff, MEMORY_PAGE_SIZE );
fake_mapping.page = fake_bank;
fake_mapping.writable = 0;
fake_mapping.contended = 0;
fake_mapping.offset = 0x0000;
machine->unattached_port = spectrum_unattached_port_none;
machine->shutdown = NULL;
machine->memory_map = tc2068_memory_map;
return 0;
}
static int
tc2048_reset( void )
{
size_t i;
int error;
error = machine_load_rom( 0, 0, settings_current.rom_tc2048,
settings_default.rom_tc2048, 0x4000 );
if( error ) return error;
error = periph_setup( peripherals, peripherals_count );
if( error ) return error;
periph_setup_kempston( PERIPH_PRESENT_ALWAYS );
periph_setup_interface1( PERIPH_PRESENT_OPTIONAL );
periph_setup_interface2( PERIPH_PRESENT_OPTIONAL );
periph_setup_plusd( PERIPH_PRESENT_OPTIONAL );
periph_update();
for( i = 0; i < 8; i++ ) {
timex_dock[i] = fake_mapping;
timex_dock[i].bank= MEMORY_BANK_DOCK;
timex_dock[i].page_num = i;
timex_dock[i].source= MEMORY_SOURCE_SYSTEM;
memory_map_dock[i] = &timex_dock[i];
timex_exrom[i] = fake_mapping;
timex_exrom[i].bank = MEMORY_BANK_EXROM;
timex_exrom[i].page_num = i;
timex_exrom[i].source= MEMORY_SOURCE_SYSTEM;
memory_map_exrom[i] = &timex_exrom[i];
}
return tc2068_tc2048_common_reset();
}

View File

@ -0,0 +1,86 @@
/* melodik.c: Routines for handling the Fuller Box
Copyright (c) 2009 Fredrick Meunier
$Id: melodik.c 4032 2009-06-10 11:09:44Z fredm $
This program 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 2 of the License, or
(at your option) any later version.
This program 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 this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Author contact information:
Philip: philip-fuse@shadowmagic.org.uk
*/
#include <config.h>
#include <libspectrum.h>
#include "ay.h"
#include "compat.h"
#include "melodik.h"
#include "module.h"
#include "periph.h"
#include "settings.h"
static void melodik_enabled_snapshot( libspectrum_snap *snap );
static void melodik_from_snapshot( libspectrum_snap *snap );
static void melodik_to_snapshot( libspectrum_snap *snap );
static module_info_t melodik_module_info = {
NULL,
NULL,
melodik_enabled_snapshot,
melodik_from_snapshot,
melodik_to_snapshot,
};
const periph_t melodik_peripherals[] = {
{ 0xc002, 0xc000, ay_registerport_read, ay_registerport_write },
{ 0xc002, 0x8000, NULL, ay_dataport_write },
};
const size_t melodik_peripherals_count =
sizeof( melodik_peripherals ) / sizeof( periph_t );
static void
melodik_enabled_snapshot( libspectrum_snap *snap )
{
if( libspectrum_snap_melodik_active( snap ) )
settings_current.melodik = 1;
}
static void
melodik_from_snapshot( libspectrum_snap *snap )
{
if( periph_melodik_active ) {
ay_state_from_snapshot( snap );
}
}
static void
melodik_to_snapshot( libspectrum_snap *snap )
{
libspectrum_snap_set_melodik_active( snap, periph_melodik_active );
}
int
melodik_init( void )
{
module_register( &melodik_module_info );
return 0;
}

View File

@ -0,0 +1,38 @@
/* melodik.h: Routines for handling the Fuller Box
Copyright (c) 2009 Fredrick Meunier
$Id: melodik.h 4032 2009-06-10 11:09:44Z fredm $
This program 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 2 of the License, or
(at your option) any later version.
This program 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 this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Author contact information:
Philip: philip-fuse@shadowmagic.org.uk
*/
#ifndef FUSE_MELODIK_H
#define FUSE_MELODIK_H
#include <libspectrum.h>
#include "periph.h"
extern const periph_t melodik_peripherals[];
extern const size_t melodik_peripherals_count;
int melodik_init( void );
#endif /* #ifndef FUSE_FULLER_H */

View File

@ -1,7 +1,7 @@
/* periph.c: code for handling peripherals
Copyright (c) 2005-2007 Philip Kendall
Copyright (c) 2005-2009 Philip Kendall
$Id: periph.c 3681 2008-06-16 09:40:29Z pak21 $
$Id: periph.c 4114 2010-01-15 13:45:51Z fredm $
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -30,10 +30,12 @@
#include "debugger/debugger.h"
#include "divide.h"
#include "event.h"
#include "fuller.h"
#include "if1.h"
#include "if2.h"
#include "joystick.h"
#include "kempmouse.h"
#include "melodik.h"
#include "periph.h"
#include "rzx.h"
#include "settings.h"
@ -321,6 +323,17 @@ periph_present beta128_present;
/* Is the Beta 128 currently active */
int periph_beta128_active;
/* What sort of Fuller Box does the current machine have */
periph_present fuller_present;
/* Is the Fuller Box currently active */
int periph_fuller_active;
/* What sort of Melodik does the current machine have */
periph_present melodik_present;
/* Is the Melodik currently active */
int periph_melodik_active;
int
periph_setup( const periph_t *peripherals_list, size_t n )
@ -348,6 +361,8 @@ periph_setup( const periph_t *peripherals_list, size_t n )
interface2_present = PERIPH_PRESENT_NEVER;
plusd_present = PERIPH_PRESENT_NEVER;
beta128_present = PERIPH_PRESENT_NEVER;
fuller_present = PERIPH_PRESENT_NEVER;
melodik_present = PERIPH_PRESENT_NEVER;
return 0;
}
@ -382,6 +397,16 @@ periph_register_beta128( void ) {
periph_register_n( beta_peripherals, beta_peripherals_count );
}
void
periph_setup_fuller( periph_present present ) {
fuller_present = present;
}
void
periph_setup_melodik( periph_present present ) {
melodik_present = present;
}
static void
update_cartridge_menu( void )
{
@ -475,6 +500,28 @@ periph_update( void )
}
}
switch( fuller_present ) {
case PERIPH_PRESENT_NEVER: periph_fuller_active = 0; break;
case PERIPH_PRESENT_OPTIONAL:
periph_fuller_active = settings_current.fuller; break;
case PERIPH_PRESENT_ALWAYS: periph_fuller_active = 1; break;
}
if( periph_fuller_active ) {
periph_register_n( fuller_peripherals, fuller_peripherals_count );
}
switch( melodik_present ) {
case PERIPH_PRESENT_NEVER: periph_melodik_active = 0; break;
case PERIPH_PRESENT_OPTIONAL:
periph_melodik_active = settings_current.melodik; break;
case PERIPH_PRESENT_ALWAYS: periph_melodik_active = 1; break;
}
if( periph_melodik_active ) {
periph_register_n( melodik_peripherals, melodik_peripherals_count );
}
update_cartridge_menu();
update_ide_menu();
if1_update_menu();

View File

@ -0,0 +1,493 @@
/* periph.c: code for handling peripherals
Copyright (c) 2005-2007 Philip Kendall
$Id: periph.c 3681 2008-06-16 09:40:29Z pak21 $
This program 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 2 of the License, or
(at your option) any later version.
This program 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 this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Author contact information:
E-mail: philip-fuse@shadowmagic.org.uk
*/
#include <config.h>
#include <libspectrum.h>
#include "debugger/debugger.h"
#include "divide.h"
#include "event.h"
#include "if1.h"
#include "if2.h"
#include "joystick.h"
#include "kempmouse.h"
#include "periph.h"
#include "rzx.h"
#include "settings.h"
#include "simpleide.h"
#include "ui/ui.h"
#include "ula.h"
#include "zxatasp.h"
#include "zxcf.h"
/*
* General peripheral list handling routines
*/
/* Full information about a peripheral */
typedef struct periph_private_t {
int id;
int active;
periph_t peripheral;
} periph_private_t;
static GSList *peripherals = NULL;
static int last_id = 0;
/* The strings used for debugger events */
static const char *page_event_string = "page",
*unpage_event_string = "unpage";
static gint find_by_id( gconstpointer data, gconstpointer id );
static void free_peripheral( gpointer data, gpointer user_data );
/* Register a peripheral. Returns -1 on error or a peripheral ID if
successful */
int
periph_register( const periph_t *peripheral )
{
periph_private_t *private;
private = malloc( sizeof( periph_private_t ) );
if( !private ) {
ui_error( UI_ERROR_ERROR, "Out of memory at %s:%d", __FILE__, __LINE__ );
return -1;
}
private->id = last_id++;
private->active = 1;
private->peripheral = *peripheral;
peripherals = g_slist_append( peripherals, private );
return private->id;
}
/* Register many peripherals */
int
periph_register_n( const periph_t *peripherals_list, size_t n )
{
const periph_t *ptr;
for( ptr = peripherals_list; n--; ptr++ ) {
int id;
id = periph_register( ptr ); if( id == -1 ) return -1;
}
return 0;
}
/* (De)activate a specific peripheral */
int
periph_set_active( int id, int active )
{
GSList *ptr;
periph_private_t *private;
ptr = g_slist_find_custom( peripherals, &id, find_by_id );
if( !ptr ) {
ui_error( UI_ERROR_ERROR, "couldn't find peripheral ID %d", id );
return 1;
}
private = ptr->data;
private->active = active;
return 0;
}
static gint
find_by_id( gconstpointer data, gconstpointer user_data )
{
const periph_private_t *private = data;
int id = *(const int*)user_data;
return private->id - id;
}
/* Clear all peripherals */
void
periph_clear( void )
{
g_slist_foreach( peripherals, free_peripheral, NULL );
g_slist_free( peripherals );
peripherals = NULL;
last_id = 0;
}
static void
free_peripheral( gpointer data, gpointer user_data GCC_UNUSED )
{
periph_t *private = data;
free( private );
}
/*
* The actual routines to read and write a port
*/
static void read_peripheral( gpointer data, gpointer user_data );
static void write_peripheral( gpointer data, gpointer user_data );
/* Internal type used for passing to read_peripheral and write_peripheral */
struct peripheral_data_t {
libspectrum_word port;
int attached;
libspectrum_byte value;
};
libspectrum_byte
readport( libspectrum_word port )
{
libspectrum_byte b;
ula_contend_port_early( port );
ula_contend_port_late( port );
b = readport_internal( port );
/* Very ugly to put this here, but unless anything else needs this
"writeback" mechanism, no point producing a general framework */
if( ( port & 0x8002 ) == 0 &&
( machine_current->machine == LIBSPECTRUM_MACHINE_128 ||
machine_current->machine == LIBSPECTRUM_MACHINE_PLUS2 ) )
writeport_internal( 0x7ffd, b );
tstates++;
return b;
}
libspectrum_byte
readport_internal( libspectrum_word port )
{
struct peripheral_data_t callback_info;
/* Trigger the debugger if wanted */
if( debugger_mode != DEBUGGER_MODE_INACTIVE )
debugger_check( DEBUGGER_BREAKPOINT_TYPE_PORT_READ, port );
/* If we're doing RZX playback, get a byte from the RZX file */
if( rzx_playback ) {
libspectrum_error error;
libspectrum_byte value;
error = libspectrum_rzx_playback( rzx, &value );
if( error ) {
rzx_stop_playback( 1 );
/* Add a null event to mean we pick up the RZX state change in
z80_do_opcodes() */
event_add( tstates, event_type_null );
return readport_internal( port );
}
return value;
}
/* If we're not doing RZX playback, get the byte normally */
callback_info.port = port;
callback_info.attached = 0;
callback_info.value = 0xff;
g_slist_foreach( peripherals, read_peripheral, &callback_info );
if( !callback_info.attached )
callback_info.value = machine_current->unattached_port();
/* If we're RZX recording, store this byte */
if( rzx_recording ) rzx_store_byte( callback_info.value );
return callback_info.value;
}
static void
read_peripheral( gpointer data, gpointer user_data )
{
periph_private_t *private = data;
struct peripheral_data_t *callback_info = user_data;
periph_t *peripheral;
peripheral = &( private->peripheral );
if( private->active && peripheral->read &&
( ( callback_info->port & peripheral->mask ) == peripheral->value ) ) {
callback_info->value &= peripheral->read( callback_info->port,
&( callback_info->attached ) );
}
}
void
writeport( libspectrum_word port, libspectrum_byte b )
{
ula_contend_port_early( port );
writeport_internal( port, b );
ula_contend_port_late( port ); tstates++;
}
void
writeport_internal( libspectrum_word port, libspectrum_byte b )
{
struct peripheral_data_t callback_info;
/* Trigger the debugger if wanted */
if( debugger_mode != DEBUGGER_MODE_INACTIVE )
debugger_check( DEBUGGER_BREAKPOINT_TYPE_PORT_WRITE, port );
callback_info.port = port;
callback_info.value = b;
g_slist_foreach( peripherals, write_peripheral, &callback_info );
}
static void
write_peripheral( gpointer data, gpointer user_data )
{
periph_private_t *private = data;
struct peripheral_data_t *callback_info = user_data;
periph_t *peripheral;
peripheral = &( private->peripheral );
if( private->active && peripheral->write &&
( ( callback_info->port & peripheral->mask ) == peripheral->value ) )
peripheral->write( callback_info->port, callback_info->value );
}
/*
* The more Fuse-specific peripheral handling routines
*/
/* What sort of Kempston interface does the current machine have */
static periph_present kempston_present;
/* Is the Kempston interface currently active */
int periph_kempston_active;
/* What sort of Interface I does the current machine have */
periph_present interface1_present;
/* Is the Interface I currently active */
int periph_interface1_active;
/* What sort of Interface II does the current machine have */
periph_present interface2_present;
/* Is the Interface II currently active */
int periph_interface2_active;
/* What sort of +D interface does the current machine have */
periph_present plusd_present;
/* Is the +D currently active */
int periph_plusd_active;
/* What sort of Beta 128 interface does the current machine have */
periph_present beta128_present;
/* Is the Beta 128 currently active */
int periph_beta128_active;
int
periph_setup( const periph_t *peripherals_list, size_t n )
{
int error;
periph_clear();
error =
periph_register_n( simpleide_peripherals, simpleide_peripherals_count );
if( error ) return error;
periph_register_n( zxatasp_peripherals, zxatasp_peripherals_count );
periph_register_n( zxcf_peripherals, zxcf_peripherals_count );
periph_register_n( divide_peripherals, divide_peripherals_count );
periph_register_n( plusd_peripherals, plusd_peripherals_count );
periph_register_n( if1_peripherals, if1_peripherals_count );
periph_register_n( kempmouse_peripherals, kempmouse_peripherals_count );
error = periph_register_n( peripherals_list, n ); if( error ) return error;
kempston_present = PERIPH_PRESENT_NEVER;
interface1_present = PERIPH_PRESENT_NEVER;
interface2_present = PERIPH_PRESENT_NEVER;
plusd_present = PERIPH_PRESENT_NEVER;
beta128_present = PERIPH_PRESENT_NEVER;
return 0;
}
void
periph_setup_kempston( periph_present present ) {
kempston_present = present;
}
void
periph_setup_interface1( periph_present present ) {
interface1_present = present;
}
void
periph_setup_interface2( periph_present present ) {
interface2_present = present;
}
void
periph_setup_plusd( periph_present present ) {
plusd_present = present;
}
void
periph_setup_beta128( periph_present present ) {
beta128_present = present;
}
void
periph_register_beta128( void ) {
periph_register_n( beta_peripherals, beta_peripherals_count );
}
static void
update_cartridge_menu( void )
{
int cartridge, dock;
dock = machine_current->capabilities &
LIBSPECTRUM_MACHINE_CAPABILITY_TIMEX_DOCK;
cartridge = dock || periph_interface2_active;
ui_menu_activate( UI_MENU_ITEM_MEDIA_CARTRIDGE, cartridge );
ui_menu_activate( UI_MENU_ITEM_MEDIA_CARTRIDGE_DOCK, dock );
ui_menu_activate( UI_MENU_ITEM_MEDIA_CARTRIDGE_IF2, periph_interface2_active );
}
static void
update_ide_menu( void )
{
int ide, simpleide, zxatasp, zxcf, divide;
simpleide = settings_current.simpleide_active;
zxatasp = settings_current.zxatasp_active;
zxcf = settings_current.zxcf_active;
divide = settings_current.divide_enabled;
ide = simpleide || zxatasp || zxcf || divide;
ui_menu_activate( UI_MENU_ITEM_MEDIA_IDE, ide );
ui_menu_activate( UI_MENU_ITEM_MEDIA_IDE_SIMPLE8BIT, simpleide );
ui_menu_activate( UI_MENU_ITEM_MEDIA_IDE_ZXATASP, zxatasp );
ui_menu_activate( UI_MENU_ITEM_MEDIA_IDE_ZXCF, zxcf );
ui_menu_activate( UI_MENU_ITEM_MEDIA_IDE_DIVIDE, divide );
}
void
periph_update( void )
{
switch( kempston_present ) {
case PERIPH_PRESENT_NEVER: periph_kempston_active = 0; break;
case PERIPH_PRESENT_OPTIONAL:
periph_kempston_active = settings_current.joy_kempston; break;
case PERIPH_PRESENT_ALWAYS: periph_kempston_active = 1; break;
}
switch( interface1_present ) {
case PERIPH_PRESENT_NEVER: periph_interface1_active = 0; break;
case PERIPH_PRESENT_OPTIONAL:
periph_interface1_active = settings_current.interface1; break;
case PERIPH_PRESENT_ALWAYS: periph_interface1_active = 1; break;
}
switch( interface2_present ) {
case PERIPH_PRESENT_NEVER:
periph_interface2_active = 0;
break;
case PERIPH_PRESENT_OPTIONAL:
periph_interface2_active = settings_current.interface2;
break;
case PERIPH_PRESENT_ALWAYS:
periph_interface2_active = 1;
break;
}
ui_menu_activate( UI_MENU_ITEM_MEDIA_IF1,
periph_interface1_active );
ui_menu_activate( UI_MENU_ITEM_MEDIA_CARTRIDGE_IF2,
periph_interface2_active );
switch( plusd_present ) {
case PERIPH_PRESENT_NEVER: periph_plusd_active = 0; break;
case PERIPH_PRESENT_OPTIONAL:
periph_plusd_active = settings_current.plusd; break;
case PERIPH_PRESENT_ALWAYS: periph_plusd_active = 1; break;
}
switch( beta128_present ) {
case PERIPH_PRESENT_NEVER: periph_beta128_active = 0; break;
case PERIPH_PRESENT_OPTIONAL:
periph_beta128_active = settings_current.beta128; break;
case PERIPH_PRESENT_ALWAYS: periph_beta128_active = 1;
break;
}
if( ui_mouse_present ) {
if( settings_current.kempston_mouse ) {
if( !ui_mouse_grabbed ) ui_mouse_grabbed = ui_mouse_grab( 1 );
} else {
if( ui_mouse_grabbed ) ui_mouse_grabbed = ui_mouse_release( 1 );
}
}
update_cartridge_menu();
update_ide_menu();
if1_update_menu();
machine_current->memory_map();
}
int
periph_register_paging_events( const char *type_string, int *page_event,
int *unpage_event )
{
*page_event = debugger_event_register( type_string, page_event_string );
*unpage_event = debugger_event_register( type_string, unpage_event_string );
if( *page_event == -1 || *unpage_event == -1 ) return 1;
return 0;
}

View File

@ -1,7 +1,7 @@
/* periph.h: code for handling peripherals
Copyright (c) 2004 Philip Kendall
Copyright (c) 2004-2009 Philip Kendall
$Id: periph.h 3648 2008-06-01 17:42:03Z pak21 $
$Id: periph.h 4060 2009-07-30 13:21:38Z fredm $
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -98,12 +98,20 @@ extern int periph_plusd_active;
/* Is the Beta 128 active */
extern int periph_beta128_active;
/* Is the Fuller Box active */
extern int periph_fuller_active;
/* Is the Melodik active */
extern int periph_melodik_active;
int periph_setup( const periph_t *peripherals_list, size_t n );
void periph_setup_kempston( periph_present present );
void periph_setup_interface1( periph_present present );
void periph_setup_interface2( periph_present present );
void periph_setup_plusd( periph_present present );
void periph_setup_beta128( periph_present present );
void periph_setup_fuller( periph_present present );
void periph_setup_melodik( periph_present present );
void periph_update( void );
void periph_register_beta128( void );

View File

@ -0,0 +1,111 @@
/* periph.h: code for handling peripherals
Copyright (c) 2004 Philip Kendall
$Id: periph.h 3648 2008-06-01 17:42:03Z pak21 $
This program 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 2 of the License, or
(at your option) any later version.
This program 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 this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Author contact information:
E-mail: philip-fuse@shadowmagic.org.uk
*/
#ifndef FUSE_PERIPH_H
#define FUSE_PERIPH_H
#include <libspectrum.h>
/*
* General peripheral list handling routines
*/
typedef libspectrum_byte (*periph_port_read_function)( libspectrum_word port,
int *attached );
typedef void (*periph_port_write_function)( libspectrum_word port,
libspectrum_byte data );
/* Information about a peripheral */
typedef struct periph_t {
/* This peripheral responds to all port values where
<port> & mask == value */
libspectrum_word mask;
libspectrum_word value;
periph_port_read_function read;
periph_port_write_function write;
} periph_t;
int periph_register( const periph_t *peripheral );
int periph_register_n( const periph_t *peripherals_list, size_t n );
int periph_set_active( int id, int active );
void periph_clear( void );
/* Register debugger page/unpage events for a peripheral */
int periph_register_paging_events( const char *type_string, int *page_event,
int *unpage_event );
/*
* The actual routines to read and write a port
*/
libspectrum_byte readport( libspectrum_word port );
libspectrum_byte readport_internal( libspectrum_word port );
void writeport( libspectrum_word port, libspectrum_byte b );
void writeport_internal( libspectrum_word port, libspectrum_byte b );
/*
* The more Fuse-specific peripheral handling routines
*/
/* For indicating the (optional) presence or absence of a peripheral */
typedef enum periph_present {
PERIPH_PRESENT_NEVER, /* Never present */
PERIPH_PRESENT_OPTIONAL, /* Optionally present */
PERIPH_PRESENT_ALWAYS, /* Always present */
} periph_present;
/* Is the Kempston interface active */
extern int periph_kempston_active;
/* Is the Interface I active */
extern int periph_interface1_active;
/* Is the Interface II active */
extern int periph_interface2_active;
/* Is the +D active */
extern int periph_plusd_active;
/* Is the Beta 128 active */
extern int periph_beta128_active;
int periph_setup( const periph_t *peripherals_list, size_t n );
void periph_setup_kempston( periph_present present );
void periph_setup_interface1( periph_present present );
void periph_setup_interface2( periph_present present );
void periph_setup_plusd( periph_present present );
void periph_setup_beta128( periph_present present );
void periph_update( void );
void periph_register_beta128( void );
#endif /* #ifndef FUSE_PERIPH_H */

View File

@ -20,7 +20,7 @@
E-mail: philip-fuse@shadowmagic.org.uk
*/
#line 63"../settings.pl"
#line 63"./settings.pl"
/* This file is autogenerated from settings.dat by settings.pl.
Do not edit unless you know what will happen! */
@ -91,6 +91,7 @@ settings_info settings_default = {
/* fastload */ 1,
/* frame_rate */ 1,
/* full_screen */ 0,
/* fuller */ 0,
/* if2_file */ NULL,
/* interface1 */ 0,
/* interface2 */ 1,
@ -139,6 +140,7 @@ settings_info settings_default = {
/* mdr_file8 */ NULL,
/* mdr_len */ 180,
/* mdr_random_len */ 1,
/* melodik */ 1,
/* pal_tv2x */ 0,
/* playback_file */ NULL,
/* plus3disk_file */ NULL,
@ -209,6 +211,7 @@ settings_info settings_default = {
/* sound_freq */ 32000,
/* sound_hifi */ 0,
/* sound_load */ 1,
/* speaker_type */ 0,
/* start_machine */ "48",
/* start_scaler_mode */ "normal",
/* statusbar */ 1,
@ -219,6 +222,8 @@ settings_info settings_default = {
/* tape_file */ NULL,
/* tape_traps */ 1,
/* unittests */ 0,
/* volume_ay */ 100,
/* volume_beeper */ 100,
/* writable_roms */ 0,
/* zxatasp_active */ 0,
/* zxatasp_master_file */ NULL,
@ -228,7 +233,7 @@ settings_info settings_default = {
/* zxcf_active */ 0,
/* zxcf_pri_file */ NULL,
/* zxcf_upload */ 0,
#line 118"../settings.pl"
#line 118"./settings.pl"
/* show_help */ 0,
/* show_version */ 0,
};
@ -450,6 +455,11 @@ parse_xml( xmlDocPtr doc, settings_info *settings )
settings->full_screen = atoi( (char*)xmlstring );
xmlFree( xmlstring );
} else
if( !strcmp( (const char*)node->name, "fuller" ) ) {
xmlstring = xmlNodeListGetString( doc, node->xmlChildrenNode, 1 );
settings->fuller = atoi( (char*)xmlstring );
xmlFree( xmlstring );
} else
if( !strcmp( (const char*)node->name, "if2cart" ) ) {
xmlstring = xmlNodeListGetString( doc, node->xmlChildrenNode, 1 );
free( settings->if2_file );
@ -701,6 +711,11 @@ parse_xml( xmlDocPtr doc, settings_info *settings )
settings->mdr_random_len = atoi( (char*)xmlstring );
xmlFree( xmlstring );
} else
if( !strcmp( (const char*)node->name, "melodik" ) ) {
xmlstring = xmlNodeListGetString( doc, node->xmlChildrenNode, 1 );
settings->melodik = atoi( (char*)xmlstring );
xmlFree( xmlstring );
} else
if( !strcmp( (const char*)node->name, "paltv2x" ) ) {
xmlstring = xmlNodeListGetString( doc, node->xmlChildrenNode, 1 );
settings->pal_tv2x = atoi( (char*)xmlstring );
@ -1113,6 +1128,11 @@ parse_xml( xmlDocPtr doc, settings_info *settings )
settings->sound_load = atoi( (char*)xmlstring );
xmlFree( xmlstring );
} else
if( !strcmp( (const char*)node->name, "speakertype" ) ) {
xmlstring = xmlNodeListGetString( doc, node->xmlChildrenNode, 1 );
settings->speaker_type = atoi( (char*)xmlstring );
xmlFree( xmlstring );
} else
if( !strcmp( (const char*)node->name, "machine" ) ) {
xmlstring = xmlNodeListGetString( doc, node->xmlChildrenNode, 1 );
free( settings->start_machine );
@ -1166,6 +1186,16 @@ parse_xml( xmlDocPtr doc, settings_info *settings )
settings->unittests = atoi( (char*)xmlstring );
xmlFree( xmlstring );
} else
if( !strcmp( (const char*)node->name, "volumeay" ) ) {
xmlstring = xmlNodeListGetString( doc, node->xmlChildrenNode, 1 );
settings->volume_ay = atoi( (char*)xmlstring );
xmlFree( xmlstring );
} else
if( !strcmp( (const char*)node->name, "volumebeeper" ) ) {
xmlstring = xmlNodeListGetString( doc, node->xmlChildrenNode, 1 );
settings->volume_beeper = atoi( (char*)xmlstring );
xmlFree( xmlstring );
} else
if( !strcmp( (const char*)node->name, "writableroms" ) ) {
xmlstring = xmlNodeListGetString( doc, node->xmlChildrenNode, 1 );
settings->writable_roms = atoi( (char*)xmlstring );
@ -1214,7 +1244,7 @@ parse_xml( xmlDocPtr doc, settings_info *settings )
settings->zxcf_upload = atoi( (char*)xmlstring );
xmlFree( xmlstring );
} else
#line 257"../settings.pl"
#line 257"./settings.pl"
if( !strcmp( (const char*)node->name, "text" ) ) {
/* Do nothing */
} else {
@ -1284,6 +1314,7 @@ settings_write_config( settings_info *settings )
xmlNewTextChild( root, NULL, (const xmlChar*)"rate", (const xmlChar*)buffer );
}
xmlNewTextChild( root, NULL, (const xmlChar*)"fullscreen", (const xmlChar*)(settings->full_screen ? "1" : "0") );
xmlNewTextChild( root, NULL, (const xmlChar*)"fuller", (const xmlChar*)(settings->fuller ? "1" : "0") );
if( settings->if2_file )
xmlNewTextChild( root, NULL, (const xmlChar*)"if2cart", (const xmlChar*)settings->if2_file );
xmlNewTextChild( root, NULL, (const xmlChar*)"interface1", (const xmlChar*)(settings->interface1 ? "1" : "0") );
@ -1430,6 +1461,7 @@ settings_write_config( settings_info *settings )
xmlNewTextChild( root, NULL, (const xmlChar*)"mdrlen", (const xmlChar*)buffer );
}
xmlNewTextChild( root, NULL, (const xmlChar*)"mdrrandomlen", (const xmlChar*)(settings->mdr_random_len ? "1" : "0") );
xmlNewTextChild( root, NULL, (const xmlChar*)"melodik", (const xmlChar*)(settings->melodik ? "1" : "0") );
xmlNewTextChild( root, NULL, (const xmlChar*)"paltv2x", (const xmlChar*)(settings->pal_tv2x ? "1" : "0") );
if( settings->playback_file )
xmlNewTextChild( root, NULL, (const xmlChar*)"playbackfile", (const xmlChar*)settings->playback_file );
@ -1559,6 +1591,10 @@ settings_write_config( settings_info *settings )
}
xmlNewTextChild( root, NULL, (const xmlChar*)"soundhifi", (const xmlChar*)(settings->sound_hifi ? "1" : "0") );
xmlNewTextChild( root, NULL, (const xmlChar*)"loadingsound", (const xmlChar*)(settings->sound_load ? "1" : "0") );
if( settings->speaker_type ) {
snprintf( buffer, 80, "%d", settings->speaker_type );
xmlNewTextChild( root, NULL, (const xmlChar*)"speakertype", (const xmlChar*)buffer );
}
if( settings->start_machine )
xmlNewTextChild( root, NULL, (const xmlChar*)"machine", (const xmlChar*)settings->start_machine );
if( settings->start_scaler_mode )
@ -1575,6 +1611,14 @@ settings_write_config( settings_info *settings )
xmlNewTextChild( root, NULL, (const xmlChar*)"tapefile", (const xmlChar*)settings->tape_file );
xmlNewTextChild( root, NULL, (const xmlChar*)"tapetraps", (const xmlChar*)(settings->tape_traps ? "1" : "0") );
xmlNewTextChild( root, NULL, (const xmlChar*)"unittests", (const xmlChar*)(settings->unittests ? "1" : "0") );
if( settings->volume_ay ) {
snprintf( buffer, 80, "%d", settings->volume_ay );
xmlNewTextChild( root, NULL, (const xmlChar*)"volumeay", (const xmlChar*)buffer );
}
if( settings->volume_beeper ) {
snprintf( buffer, 80, "%d", settings->volume_beeper );
xmlNewTextChild( root, NULL, (const xmlChar*)"volumebeeper", (const xmlChar*)buffer );
}
xmlNewTextChild( root, NULL, (const xmlChar*)"writableroms", (const xmlChar*)(settings->writable_roms ? "1" : "0") );
xmlNewTextChild( root, NULL, (const xmlChar*)"zxatasp", (const xmlChar*)(settings->zxatasp_active ? "1" : "0") );
if( settings->zxatasp_master_file )
@ -1587,7 +1631,7 @@ settings_write_config( settings_info *settings )
if( settings->zxcf_pri_file )
xmlNewTextChild( root, NULL, (const xmlChar*)"zxcfcffile", (const xmlChar*)settings->zxcf_pri_file );
xmlNewTextChild( root, NULL, (const xmlChar*)"zxcfupload", (const xmlChar*)(settings->zxcf_upload ? "1" : "0") );
#line 316"../settings.pl"
#line 316"./settings.pl"
xmlSaveFormatFile( path, doc, 1 );
@ -1643,6 +1687,8 @@ settings_command_line( settings_info *settings, int *first_arg,
{ "rate", 1, NULL, 264 },
{ "full-screen", 0, &(settings->full_screen), 1 },
{ "no-full-screen", 0, &(settings->full_screen), 0 },
{ "fuller", 0, &(settings->fuller), 1 },
{ "no-fuller", 0, &(settings->fuller), 0 },
{ "if2cart", 1, NULL, 265 },
{ "interface1", 0, &(settings->interface1), 1 },
{ "no-interface1", 0, &(settings->interface1), 0 },
@ -1699,6 +1745,8 @@ settings_command_line( settings_info *settings, int *first_arg,
{ "mdr-len", 1, NULL, 303 },
{ "mdr-random-len", 0, &(settings->mdr_random_len), 1 },
{ "no-mdr-random-len", 0, &(settings->mdr_random_len), 0 },
{ "melodik", 0, &(settings->melodik), 1 },
{ "no-melodik", 0, &(settings->melodik), 0 },
{ "pal-tv2x", 0, &(settings->pal_tv2x), 1 },
{ "no-pal-tv2x", 0, &(settings->pal_tv2x), 0 },
{ "playback", 1, NULL, 'p' },
@ -1782,6 +1830,7 @@ settings_command_line( settings_info *settings, int *first_arg,
{ "no-sound-hifi", 0, &(settings->sound_hifi), 0 },
{ "loading-sound", 0, &(settings->sound_load), 1 },
{ "no-loading-sound", 0, &(settings->sound_load), 0 },
{ "speaker-type", 1, NULL, 358 },
{ "machine", 1, NULL, 'm' },
{ "graphics-filter", 1, NULL, 'g' },
{ "statusbar", 0, &(settings->statusbar), 1 },
@ -1798,22 +1847,24 @@ settings_command_line( settings_info *settings, int *first_arg,
{ "no-traps", 0, &(settings->tape_traps), 0 },
{ "unittests", 0, &(settings->unittests), 1 },
{ "no-unittests", 0, &(settings->unittests), 0 },
{ "volume-ay", 1, NULL, 359 },
{ "volume-beeper", 1, NULL, 360 },
{ "writable-roms", 0, &(settings->writable_roms), 1 },
{ "no-writable-roms", 0, &(settings->writable_roms), 0 },
{ "zxatasp", 0, &(settings->zxatasp_active), 1 },
{ "no-zxatasp", 0, &(settings->zxatasp_active), 0 },
{ "zxatasp-masterfile", 1, NULL, 358 },
{ "zxatasp-slavefile", 1, NULL, 359 },
{ "zxatasp-masterfile", 1, NULL, 361 },
{ "zxatasp-slavefile", 1, NULL, 362 },
{ "zxatasp-upload", 0, &(settings->zxatasp_upload), 1 },
{ "no-zxatasp-upload", 0, &(settings->zxatasp_upload), 0 },
{ "zxatasp-write-protect", 0, &(settings->zxatasp_wp), 1 },
{ "no-zxatasp-write-protect", 0, &(settings->zxatasp_wp), 0 },
{ "zxcf", 0, &(settings->zxcf_active), 1 },
{ "no-zxcf", 0, &(settings->zxcf_active), 0 },
{ "zxcf-cffile", 1, NULL, 360 },
{ "zxcf-cffile", 1, NULL, 363 },
{ "zxcf-upload", 0, &(settings->zxcf_upload), 1 },
{ "no-zxcf-upload", 0, &(settings->zxcf_upload), 0 },
#line 363"../settings.pl"
#line 363"./settings.pl"
{ "help", 0, NULL, 'h' },
{ "version", 0, NULL, 'V' },
@ -1945,14 +1996,17 @@ settings_command_line( settings_info *settings, int *first_arg,
case 357: settings_set_string( &settings->snet, optarg ); break;
case 'd': settings_set_string( &settings->sound_device, optarg ); break;
case 'f': settings->sound_freq = atoi( optarg ); break;
case 358: settings->speaker_type = atoi( optarg ); break;
case 'm': settings_set_string( &settings->start_machine, optarg ); break;
case 'g': settings_set_string( &settings->start_scaler_mode, optarg ); break;
case 'v': settings->svga_mode = atoi( optarg ); break;
case 't': settings_set_string( &settings->tape_file, optarg ); break;
case 358: settings_set_string( &settings->zxatasp_master_file, optarg ); break;
case 359: settings_set_string( &settings->zxatasp_slave_file, optarg ); break;
case 360: settings_set_string( &settings->zxcf_pri_file, optarg ); break;
#line 413"../settings.pl"
case 359: settings->volume_ay = atoi( optarg ); break;
case 360: settings->volume_beeper = atoi( optarg ); break;
case 361: settings_set_string( &settings->zxatasp_master_file, optarg ); break;
case 362: settings_set_string( &settings->zxatasp_slave_file, optarg ); break;
case 363: settings_set_string( &settings->zxcf_pri_file, optarg ); break;
#line 413"./settings.pl"
case 'h': settings->show_help = 1; break;
case 'V': settings->show_version = 1; break;
@ -2031,6 +2085,7 @@ settings_copy_internal( settings_info *dest, settings_info *src )
dest->fastload = src->fastload;
dest->frame_rate = src->frame_rate;
dest->full_screen = src->full_screen;
dest->fuller = src->fuller;
dest->if2_file = NULL;
if( src->if2_file ) {
dest->if2_file = strdup( src->if2_file );
@ -2123,6 +2178,7 @@ settings_copy_internal( settings_info *dest, settings_info *src )
}
dest->mdr_len = src->mdr_len;
dest->mdr_random_len = src->mdr_random_len;
dest->melodik = src->melodik;
dest->pal_tv2x = src->pal_tv2x;
dest->playback_file = NULL;
if( src->playback_file ) {
@ -2417,6 +2473,7 @@ settings_copy_internal( settings_info *dest, settings_info *src )
dest->sound_freq = src->sound_freq;
dest->sound_hifi = src->sound_hifi;
dest->sound_load = src->sound_load;
dest->speaker_type = src->speaker_type;
dest->start_machine = NULL;
if( src->start_machine ) {
dest->start_machine = strdup( src->start_machine );
@ -2439,6 +2496,8 @@ settings_copy_internal( settings_info *dest, settings_info *src )
}
dest->tape_traps = src->tape_traps;
dest->unittests = src->unittests;
dest->volume_ay = src->volume_ay;
dest->volume_beeper = src->volume_beeper;
dest->writable_roms = src->writable_roms;
dest->zxatasp_active = src->zxatasp_active;
dest->zxatasp_master_file = NULL;
@ -2460,7 +2519,7 @@ settings_copy_internal( settings_info *dest, settings_info *src )
if( !dest->zxcf_pri_file ) { settings_free( dest ); return 1; }
}
dest->zxcf_upload = src->zxcf_upload;
#line 468"../settings.pl"
#line 468"./settings.pl"
return 0;
}
@ -2621,7 +2680,7 @@ settings_free( settings_info *settings )
if( settings->zxatasp_master_file ) free( settings->zxatasp_master_file );
if( settings->zxatasp_slave_file ) free( settings->zxatasp_slave_file );
if( settings->zxcf_pri_file ) free( settings->zxcf_pri_file );
#line 559"../settings.pl"
#line 559"./settings.pl"
return 0;
}

View File

@ -67,6 +67,8 @@ plusd, boolean, 0
beta128, boolean, 0
late_timings, boolean, 0
unittests, boolean, 0
fuller, boolean, 0
melodik, boolean, 1
sound_device, string, NULL, 'd'
sound, boolean, 1
@ -76,6 +78,9 @@ stereo_beeper, boolean, 0,, beeper-stereo
sound_force_8bit, boolean, 0
sound_freq, numeric, 32000, 'f'
sound_hifi, boolean, 0
speaker_type, numeric, 0
volume_ay, numeric, 100
volume_beeper, numeric, 100
joystick_1, string, NULL, 'j'
joystick_1_output, numeric, 0

View File

@ -0,0 +1,206 @@
# settings.dat: configuration options for Fuse
# Copyright (c) 2002-2008 Philip Kendall
# $Id: settings.dat 3787 2008-10-22 19:10:25Z pak21 $
# This program 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 2 of the License, or
# (at your option) any later version.
# This program 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 this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
# Author contact information:
# E-mail: philip-fuse@shadowmagic.org.uk
# Format is
# <name in settings_info structure>,
# <type>,
# <default value>,
# <short option>,
# <name on command line>, (defaults to <settings_info name> =~ s/_/-/g)
# <name in config file>, (defaults to <command line> =~ s/-//g)
emulation_speed, numeric, 100,, speed
frame_rate, numeric, 1,, rate
issue2, boolean, 0
joy_prompt, boolean, 0,, joystick-prompt
joy_kempston, boolean, 0,, kempston
kempston_mouse, boolean, 0
tape_traps, boolean, 1,, traps, tapetraps
fastload, boolean, 1
auto_load, boolean, 1
detect_loader, boolean, 1
accelerate_loader, boolean, 1
slt_traps, boolean, 1,, slt, slttraps
double_screen, null, 0
full_screen, boolean, 0
writable_roms, boolean, 0
autosave_settings, boolean, 0
bw_tv, boolean, 0
rs232_handshake, boolean, 0
rs232_tx, string, NULL
rs232_rx, string, NULL
raw_rs232, null, 0
raw_s_net, boolean, 0
snet, string, NULL
confirm_actions, boolean, 1
printer, boolean, 0
statusbar, boolean, 1
interface1, boolean, 0
mdr_len, numeric, 180
mdr_random_len, boolean, 1
interface2, boolean, 1
snapsasz80, null, 0
pal_tv2x, boolean, 0
plusd, boolean, 0
beta128, boolean, 0
late_timings, boolean, 0
unittests, boolean, 0
sound_device, string, NULL, 'd'
sound, boolean, 1
sound_load, boolean, 1,, loading-sound
stereo_ay, boolean, 0,, separation
stereo_beeper, boolean, 0,, beeper-stereo
sound_force_8bit, boolean, 0
sound_freq, numeric, 32000, 'f'
sound_hifi, boolean, 0
joystick_1, string, NULL, 'j'
joystick_1_output, numeric, 0
joystick_1_fire_1, numeric, 4096
joystick_1_fire_2, numeric, 4096
joystick_1_fire_3, numeric, 4096
joystick_1_fire_4, numeric, 4096
joystick_1_fire_5, numeric, 4096
joystick_1_fire_6, numeric, 4096
joystick_1_fire_7, numeric, 4096
joystick_1_fire_8, numeric, 4096
joystick_1_fire_9, numeric, 4096
joystick_1_fire_10, numeric, 4096
joystick_2, string, NULL
joystick_2_output, numeric, 0
joystick_2_fire_1, numeric, 4096
joystick_2_fire_2, numeric, 4096
joystick_2_fire_3, numeric, 4096
joystick_2_fire_4, numeric, 4096
joystick_2_fire_5, numeric, 4096
joystick_2_fire_6, numeric, 4096
joystick_2_fire_7, numeric, 4096
joystick_2_fire_8, numeric, 4096
joystick_2_fire_9, numeric, 4096
joystick_2_fire_10, numeric, 4096
joystick_keyboard_output, numeric, 0
joystick_keyboard_up, numeric, 113
joystick_keyboard_down, numeric, 97
joystick_keyboard_left, numeric, 111
joystick_keyboard_right, numeric, 112
joystick_keyboard_fire, numeric, 32
rzx_compression, boolean, 1,, compress-rzx
competition_mode, boolean, 0
competition_code, numeric, 0
embed_snapshot, boolean, 1
rzx_autosaves, boolean, 1
snapshot, string, NULL, 's'
tape_file, string, NULL, 't', tape, tapefile
start_machine, string, "48", 'm', machine
record_file, string, NULL, 'r', record, recordfile
playback_file, string, NULL, 'p', playback, playbackfile
plus3disk_file, string, NULL,, plus3disk
plusddisk_file, string, NULL,, plusddisk
betadisk_file, string, NULL,, betadisk
dck_file, string, NULL,, dock
if2_file, string, NULL,, if2cart
mdr_file, string, NULL,, microdrive-file
mdr_file2, string, NULL,, microdrive-2-file
mdr_file3, string, NULL,, microdrive-3-file
mdr_file4, string, NULL,, microdrive-4-file
mdr_file5, string, NULL,, microdrive-5-file
mdr_file6, string, NULL,, microdrive-6-file
mdr_file7, string, NULL,, microdrive-7-file
mdr_file8, string, NULL,, microdrive-8-file
simpleide_active, boolean, 0,, simpleide
simpleide_master_file, string, NULL,, simpleide-masterfile
simpleide_slave_file, string, NULL,, simpleide-slavefile
zxatasp_active, boolean, 0,, zxatasp
zxatasp_upload, boolean, 0,, zxatasp-upload
zxatasp_wp, boolean, 0,, zxatasp-write-protect
zxatasp_master_file, string, NULL,, zxatasp-masterfile
zxatasp_slave_file, string, NULL,, zxatasp-slavefile
zxcf_active, boolean, 0,, zxcf
zxcf_upload, boolean, 0,, zxcf-upload
zxcf_pri_file, string, NULL,, zxcf-cffile
divide_enabled, boolean, 0,, divide
divide_wp, boolean, 0,, divide-write-protect
divide_master_file, string, NULL,, divide-masterfile
divide_slave_file, string, NULL,, divide-slavefile
printer_graphics_filename, string, "printout.pbm",, graphicsfile
printer_text_filename, string, "printout.txt",, textfile
aspect_hint, boolean, 1
strict_aspect_hint, boolean, 0
svga_mode, numeric, 320, 'v', svgamode
doublescan_mode, numeric, 1, 'D', doublescan-mode
start_scaler_mode, string, "normal", 'g', graphics-filter
rom_16, string, "48.rom",
rom_48, string, "48.rom",
rom_128_0, string, "128-0.rom",
rom_128_1, string, "128-1.rom",
rom_plus2_0, string, "plus2-0.rom",
rom_plus2_1, string, "plus2-1.rom",
rom_plus2a_0, string, "plus3-0.rom",
rom_plus2a_1, string, "plus3-1.rom",
rom_plus2a_2, string, "plus3-2.rom",
rom_plus2a_3, string, "plus3-3.rom",
rom_plus3_0, string, "plus3-0.rom",
rom_plus3_1, string, "plus3-1.rom",
rom_plus3_2, string, "plus3-2.rom",
rom_plus3_3, string, "plus3-3.rom",
rom_plus3e_0, string, "plus3e-0.rom",
rom_plus3e_1, string, "plus3e-1.rom",
rom_plus3e_2, string, "plus3e-2.rom",
rom_plus3e_3, string, "plus3e-3.rom",
rom_tc2048, string, "tc2048.rom",
rom_tc2068_0, string, "tc2068-0.rom",
rom_tc2068_1, string, "tc2068-1.rom",
rom_ts2068_0, string, "tc2068-0.rom",
rom_ts2068_1, string, "tc2068-1.rom",
rom_pentagon_0, string, "128p-0.rom",
rom_pentagon_1, string, "128p-1.rom",
rom_pentagon_2, string, "trdos.rom",
rom_pentagon512_0, string, "128p-0.rom",
rom_pentagon512_1, string, "128p-1.rom",
rom_pentagon512_2, string, "trdos.rom",
rom_pentagon512_3, string, "gluck.rom",
rom_pentagon1024_0, string, "128p-0.rom",
rom_pentagon1024_1, string, "128p-1.rom",
rom_pentagon1024_2, string, "trdos.rom",
rom_pentagon1024_3, string, "gluck.rom",
rom_scorpion_0, string, "256s-0.rom",
rom_scorpion_1, string, "256s-1.rom",
rom_scorpion_2, string, "256s-2.rom",
rom_scorpion_3, string, "256s-3.rom",
rom_spec_se_0, string, "se-0.rom",
rom_spec_se_1, string, "se-1.rom",
rom_interface_i, string, "if1-2.rom",
rom_plusd, string, "plusd.rom",
rom_beta128, string, "trdos.rom",
debugger_command, string, NULL

View File

@ -56,6 +56,7 @@ typedef struct settings_info {
int fastload;
int frame_rate;
int full_screen;
int fuller;
char *if2_file;
int interface1;
int interface2;
@ -104,6 +105,7 @@ typedef struct settings_info {
char *mdr_file8;
int mdr_len;
int mdr_random_len;
int melodik;
int pal_tv2x;
char *playback_file;
char *plus3disk_file;
@ -174,6 +176,7 @@ typedef struct settings_info {
int sound_freq;
int sound_hifi;
int sound_load;
int speaker_type;
char *start_machine;
char *start_scaler_mode;
int statusbar;
@ -184,6 +187,8 @@ typedef struct settings_info {
char *tape_file;
int tape_traps;
int unittests;
int volume_ay;
int volume_beeper;
int writable_roms;
int zxatasp_active;
char *zxatasp_master_file;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,906 @@
/* sound.c: Sound support
Copyright (c) 2000-2007 Russell Marks, Matan Ziv-Av, Philip Kendall,
Fredrick Meunier
$Id: sound.c 3186 2007-10-03 19:07:13Z zubzero $
This program 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 2 of the License, or
(at your option) any later version.
This program 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 this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Author contact information:
E-mail: philip-fuse@shadowmagic.org.uk
*/
/* The AY white noise RNG algorithm is based on info from MAME's ay8910.c -
* MAME's licence explicitly permits free use of info (even encourages it).
*/
/* NB: I know some of this stuff looks fairly CPU-hogging.
* For example, the AY code tracks changes with sub-frame timing
* in a rather hairy way, and there's subsampling here and there.
* But if you measure the CPU use, it doesn't actually seem
* very high at all. And I speak as a Cyrix owner. :-)
*/
#include <config.h>
#include <libspectrum.h>
#ifdef HAVE_SAMPLERATE
#include <samplerate.h>
#endif /* #ifdef HAVE_SAMPLERATE */
#include "fuse.h"
#include "machine.h"
#include "settings.h"
#include "sound.h"
#include "tape.h"
#include "ui/ui.h"
/* Do we have any of our sound devices available? */
/* configuration */
int sound_enabled = 0; /* Are we currently using the sound card */
int sound_enabled_ever = 0; /* if it's *ever* been in use; see
sound_ay_write() and sound_ay_reset() */
int sound_stereo = 0; /* true for stereo *output sample* (only) */
int sound_stereo_ay_abc = 0; /* (AY stereo) true for ABC stereo, else ACB */
int sound_stereo_ay_narrow = 0; /* (AY stereo) true for narrow AY st. sep. */
int sound_stereo_ay = 0; /* local copy of settings_current.stereo_ay */
int sound_stereo_beeper = 0; /* and settings_current.stereo_beeper */
/* assume all three tone channels together match the beeper volume (ish).
* Must be <=127 for all channels; 50+2+(24*3) = 124.
* (Now scaled up for 16-bit.)
*/
#define AMPL_BEEPER ( 50 * 256)
#define AMPL_TAPE ( 2 * 256 )
#define AMPL_AY_TONE ( 24 * 256 ) /* three of these */
/* max. number of sub-frame AY port writes allowed;
* given the number of port writes theoretically possible in a
* 50th I think this should be plenty.
*/
#define AY_CHANGE_MAX 8000
/* frequency to generate sound at for hifi sound */
#define HIFI_FREQ 88200
#ifdef HAVE_SAMPLERATE
static SRC_STATE *src_state;
#endif /* #ifdef HAVE_SAMPLERATE */
int sound_generator_framesiz;
int sound_framesiz;
static int sound_generator_freq;
static int sound_channels;
static unsigned int ay_tone_levels[16];
static libspectrum_signed_word *sound_buf, *tape_buf;
static float *convert_input_buffer, *convert_output_buffer;
/* beeper stuff */
static int sound_oldpos[2], sound_fillpos[2];
static int sound_oldval[2], sound_oldval_orig[2];
/* foo_subcycles are fixed-point with low 16 bits as fractional part.
* The other bits count as the chip does.
*/
static unsigned int ay_tone_tick[3], ay_tone_high[3], ay_noise_tick;
static unsigned int ay_tone_subcycles, ay_env_subcycles;
static unsigned int ay_env_internal_tick, ay_env_tick;
static unsigned int ay_tick_incr;
static unsigned int ay_tone_period[3], ay_noise_period, ay_env_period;
static int beeper_last_subpos[2] = { 0, 0 };
/* Local copy of the AY registers */
static libspectrum_byte sound_ay_registers[16];
struct ay_change_tag
{
libspectrum_dword tstates;
unsigned short ofs;
unsigned char reg, val;
};
static struct ay_change_tag ay_change[ AY_CHANGE_MAX ];
static int ay_change_count;
#define STEREO_BUF_SIZE 4096
static int pstereobuf[ STEREO_BUF_SIZE ];
static int pstereobufsiz, pstereopos;
static int psgap = 250;
static int rstereobuf_l[ STEREO_BUF_SIZE ], rstereobuf_r[ STEREO_BUF_SIZE ];
static int rstereopos, rchan1pos, rchan2pos, rchan3pos;
static void
sound_ay_init( void )
{
/* AY output doesn't match the claimed levels; these levels are based
* on the measurements posted to comp.sys.sinclair in Dec 2001 by
* Matthew Westcott, adjusted as I described in a followup to his post,
* then scaled to 0..0xffff.
*/
static const int levels[16] = {
0x0000, 0x0385, 0x053D, 0x0770,
0x0AD7, 0x0FD5, 0x15B0, 0x230C,
0x2B4C, 0x43C1, 0x5A4B, 0x732F,
0x9204, 0xAFF1, 0xD921, 0xFFFF
};
int f;
/* scale the values down to fit */
for( f = 0; f < 16; f++ )
ay_tone_levels[f] = ( levels[f] * AMPL_AY_TONE + 0x8000 ) / 0xffff;
ay_noise_tick = ay_noise_period = 0;
ay_env_internal_tick = ay_env_tick = ay_env_period = 0;
ay_tone_subcycles = ay_env_subcycles = 0;
for( f = 0; f < 3; f++ )
ay_tone_tick[f] = ay_tone_high[f] = 0, ay_tone_period[f] = 1;
ay_change_count = 0;
}
void
sound_init( const char *device )
{
static int first_init = 1;
int f, ret;
float hz;
#ifdef HAVE_SAMPLERATE
int error;
#endif /* #ifdef HAVE_SAMPLERATE */
/* if we don't have any sound I/O code compiled in, don't do sound */
#ifdef NO_SOUND
return;
#endif
if( !( !sound_enabled && settings_current.sound &&
settings_current.emulation_speed == 100 ) )
return;
sound_stereo_ay = settings_current.stereo_ay;
sound_stereo_beeper = settings_current.stereo_beeper;
/* only try for stereo if we need it */
if( sound_stereo_ay || sound_stereo_beeper )
sound_stereo = 1;
ret =
sound_lowlevel_init( device, &settings_current.sound_freq,
&sound_stereo );
if( ret )
return;
/* important to override these settings if not using stereo
* (it would probably be confusing to mess with the stereo
* settings in settings_current though, which is why we make copies
* rather than using the real ones).
*/
if( !sound_stereo ) {
sound_stereo_ay = 0;
sound_stereo_beeper = 0;
}
sound_enabled = sound_enabled_ever = 1;
sound_channels = ( sound_stereo ? 2 : 1 );
hz = ( float ) machine_current->timings.processor_speed /
machine_current->timings.tstates_per_frame;
sound_generator_freq =
settings_current.sound_hifi ? HIFI_FREQ : settings_current.sound_freq;
sound_generator_framesiz = sound_generator_freq / hz;
if( ( sound_buf = malloc( sizeof( libspectrum_signed_word ) *
sound_generator_framesiz * sound_channels ) ) ==
NULL
|| ( tape_buf =
malloc( sizeof( libspectrum_signed_word ) *
sound_generator_framesiz ) ) == NULL ) {
if( sound_buf ) {
free( sound_buf );
sound_buf = NULL;
}
sound_end();
return;
}
sound_framesiz = ( float ) settings_current.sound_freq / hz;
#ifdef HAVE_SAMPLERATE
if( settings_current.sound_hifi ) {
if( ( convert_input_buffer = malloc( sizeof( float ) *
sound_generator_framesiz *
sound_channels ) ) == NULL
|| ( convert_output_buffer =
malloc( sizeof( float ) * sound_framesiz * sound_channels ) ) ==
NULL ) {
if( convert_input_buffer ) {
free( convert_input_buffer );
convert_input_buffer = NULL;
}
sound_end();
return;
}
}
src_state = src_new( SRC_SINC_MEDIUM_QUALITY, sound_channels, &error );
if( error ) {
ui_error( UI_ERROR_ERROR,
"error initialising sample rate converter %s",
src_strerror( error ) );
sound_end();
return;
}
#endif /* #ifdef HAVE_SAMPLERATE */
/* if we're resuming, we need to be careful about what
* gets reset. The minimum we can do is the beeper
* buffer positions, so that's here.
*/
sound_oldpos[0] = sound_oldpos[1] = -1;
sound_fillpos[0] = sound_fillpos[1] = 0;
/* this stuff should only happen on the initial call.
* (We currently assume the new sample rate will be the
* same as the previous one, hence no need to recalculate
* things dependent on that.)
*/
if( first_init ) {
first_init = 0;
for( f = 0; f < 2; f++ )
sound_oldval[f] = sound_oldval_orig[f] = 0;
}
if( sound_stereo_beeper ) {
for( f = 0; f < STEREO_BUF_SIZE; f++ )
pstereobuf[f] = 0;
pstereopos = 0;
pstereobufsiz = ( sound_generator_freq * psgap ) / 22000;
}
if( sound_stereo_ay ) {
int pos =
( sound_stereo_ay_narrow ? 3 : 6 ) * sound_generator_freq / 8000;
for( f = 0; f < STEREO_BUF_SIZE; f++ )
rstereobuf_l[f] = rstereobuf_r[f] = 0;
rstereopos = 0;
/* the actual ACB/ABC bit :-) */
rchan1pos = -pos;
if( sound_stereo_ay_abc )
rchan2pos = 0, rchan3pos = pos;
else
rchan2pos = pos, rchan3pos = 0;
}
ay_tick_incr = ( int ) ( 65536. *
libspectrum_timings_ay_speed( machine_current->
machine ) /
sound_generator_freq );
}
void
sound_pause( void )
{
if( sound_enabled )
sound_end();
}
void
sound_unpause( void )
{
/* No sound if fastloading in progress */
if( settings_current.fastload && tape_is_playing() )
return;
sound_init( settings_current.sound_device );
}
void
sound_end( void )
{
if( sound_enabled ) {
if( sound_buf ) {
free( sound_buf );
sound_buf = NULL;
free( tape_buf );
tape_buf = NULL;
}
if( convert_input_buffer ) {
free( convert_input_buffer );
convert_input_buffer = NULL;
}
if( convert_output_buffer ) {
free( convert_output_buffer );
convert_output_buffer = NULL;
}
#ifdef HAVE_SAMPLERATE
if( src_state )
src_state = src_delete( src_state );
#endif /* #ifdef HAVE_SAMPLERATE */
sound_lowlevel_end();
sound_enabled = 0;
}
}
/* write sample to buffer as pseudo-stereo */
static void
sound_write_buf_pstereo( libspectrum_signed_word * out, int c )
{
int bl = ( c - pstereobuf[ pstereopos ] ) / 2;
int br = ( c + pstereobuf[ pstereopos ] ) / 2;
if( bl < -AMPL_BEEPER )
bl = -AMPL_BEEPER;
if( br < -AMPL_BEEPER )
br = -AMPL_BEEPER;
if( bl > AMPL_BEEPER )
bl = AMPL_BEEPER;
if( br > AMPL_BEEPER )
br = AMPL_BEEPER;
*out = bl;
out[1] = br;
pstereobuf[ pstereopos ] = c;
pstereopos++;
if( pstereopos >= pstereobufsiz )
pstereopos = 0;
}
/* not great having this as a macro to inline it, but it's only
* a fairly short routine, and it saves messing about.
* (XXX ummm, possibly not so true any more :-))
*/
#define AY_GET_SUBVAL( chan ) \
( level * 2 * ay_tone_tick[ chan ] / tone_count )
#define AY_DO_TONE( var, chan ) \
( var ) = 0; \
is_low = 0; \
if( level ) { \
if( ay_tone_high[ chan ] ) \
( var ) = ( level ); \
else { \
( var ) = -( level ); \
is_low = 1; \
} \
} \
\
ay_tone_tick[ chan ] += tone_count; \
count = 0; \
while( ay_tone_tick[ chan ] >= ay_tone_period[ chan ] ) { \
count++; \
ay_tone_tick[ chan ] -= ay_tone_period[ chan ]; \
ay_tone_high[ chan ] = !ay_tone_high[ chan ]; \
\
/* has to be here, unfortunately... */ \
if( count == 1 && level && ay_tone_tick[ chan ] < tone_count ) { \
if( is_low ) \
( var ) += AY_GET_SUBVAL( chan ); \
else \
( var ) -= AY_GET_SUBVAL( chan ); \
} \
} \
\
/* if it's changed more than once during the sample, we can't */ \
/* represent it faithfully. So, just hope it's a sample. */ \
/* (That said, this should also help avoid aliasing noise.) */ \
if( count > 1 ) \
( var ) = -( level )
/* add val, correctly delayed on either left or right buffer,
* to add the AY stereo positioning. This doesn't actually put
* anything directly in sound_buf, though.
*/
#define GEN_STEREO( pos, val ) \
if( ( pos ) < 0 ) { \
rstereobuf_l[ rstereopos ] += ( val ); \
rstereobuf_r[ ( rstereopos - pos ) % STEREO_BUF_SIZE ] += ( val ); \
} else { \
rstereobuf_l[ ( rstereopos + pos ) % STEREO_BUF_SIZE ] += ( val ); \
rstereobuf_r[ rstereopos ] += ( val ); \
}
/* bitmasks for envelope */
#define AY_ENV_CONT 8
#define AY_ENV_ATTACK 4
#define AY_ENV_ALT 2
#define AY_ENV_HOLD 1
#define HZ_COMMON_DENOMINATOR 50
static void
sound_ay_overlay( void )
{
static int rng = 1;
static int noise_toggle = 0;
static int env_first = 1, env_rev = 0, env_counter = 15;
int tone_level[3];
int mixer, envshape;
int f, g, level, count;
libspectrum_signed_word *ptr;
struct ay_change_tag *change_ptr = ay_change;
int changes_left = ay_change_count;
int reg, r;
int is_low;
int chan1, chan2, chan3;
unsigned int tone_count, noise_count;
libspectrum_dword sfreq, cpufreq;
/* If no AY chip, don't produce any AY sound (!) */
if( !machine_current->capabilities & LIBSPECTRUM_MACHINE_CAPABILITY_AY )
return;
/* convert change times to sample offsets, use common denominator of 50 to
avoid overflowing a dword */
sfreq = sound_generator_freq / HZ_COMMON_DENOMINATOR;
cpufreq = machine_current->timings.processor_speed / HZ_COMMON_DENOMINATOR;
for( f = 0; f < ay_change_count; f++ )
ay_change[f].ofs = ( ay_change[f].tstates * sfreq ) / cpufreq;
for( f = 0, ptr = sound_buf; f < sound_generator_framesiz; f++ ) {
/* update ay registers. All this sub-frame change stuff
* is pretty hairy, but how else would you handle the
* samples in Robocop? :-) It also clears up some other
* glitches.
*/
while( changes_left && f >= change_ptr->ofs ) {
sound_ay_registers[ reg = change_ptr->reg ] = change_ptr->val;
change_ptr++;
changes_left--;
/* fix things as needed for some register changes */
switch ( reg ) {
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
r = reg >> 1;
/* a zero-len period is the same as 1 */
ay_tone_period[r] = ( sound_ay_registers[ reg & ~1 ] |
( sound_ay_registers[ reg | 1 ] & 15 ) << 8 );
if( !ay_tone_period[r] )
ay_tone_period[r]++;
/* important to get this right, otherwise e.g. Ghouls 'n' Ghosts
* has really scratchy, horrible-sounding vibrato.
*/
if( ay_tone_tick[r] >= ay_tone_period[r] * 2 )
ay_tone_tick[r] %= ay_tone_period[r] * 2;
break;
case 6:
ay_noise_tick = 0;
ay_noise_period = ( sound_ay_registers[ reg ] & 31 );
break;
case 11:
case 12:
/* this one *isn't* fixed-point */
ay_env_period =
sound_ay_registers[11] | ( sound_ay_registers[12] << 8 );
break;
case 13:
ay_env_internal_tick = ay_env_tick = ay_env_subcycles = 0;
env_first = 1;
env_rev = 0;
env_counter = ( sound_ay_registers[13] & AY_ENV_ATTACK ) ? 0 : 15;
break;
}
}
/* the tone level if no enveloping is being used */
for( g = 0; g < 3; g++ )
tone_level[g] = ay_tone_levels[ sound_ay_registers[ 8 + g ] & 15 ];
/* envelope */
envshape = sound_ay_registers[13];
level = ay_tone_levels[ env_counter ];
for( g = 0; g < 3; g++ )
if( sound_ay_registers[ 8 + g ] & 16 )
tone_level[g] = level;
/* envelope output counter gets incr'd every 16 AY cycles.
* Has to be a while, as this is sub-output-sample res.
*/
ay_env_subcycles += ay_tick_incr;
noise_count = 0;
while( ay_env_subcycles >= ( 16 << 16 ) ) {
ay_env_subcycles -= ( 16 << 16 );
noise_count++;
ay_env_tick++;
while( ay_env_tick >= ay_env_period ) {
ay_env_tick -= ay_env_period;
/* do a 1/16th-of-period incr/decr if needed */
if( env_first ||
( ( envshape & AY_ENV_CONT ) && !( envshape & AY_ENV_HOLD ) ) ) {
if( env_rev )
env_counter -= ( envshape & AY_ENV_ATTACK ) ? 1 : -1;
else
env_counter += ( envshape & AY_ENV_ATTACK ) ? 1 : -1;
if( env_counter < 0 )
env_counter = 0;
if( env_counter > 15 )
env_counter = 15;
}
ay_env_internal_tick++;
while( ay_env_internal_tick >= 16 ) {
ay_env_internal_tick -= 16;
/* end of cycle */
if( !( envshape & AY_ENV_CONT ) )
env_counter = 0;
else {
if( envshape & AY_ENV_HOLD ) {
if( env_first && ( envshape & AY_ENV_ALT ) )
env_counter = ( env_counter ? 0 : 15 );
} else {
/* non-hold */
if( envshape & AY_ENV_ALT )
env_rev = !env_rev;
else
env_counter = ( envshape & AY_ENV_ATTACK ) ? 0 : 15;
}
}
env_first = 0;
}
/* don't keep trying if period is zero */
if( !ay_env_period )
break;
}
}
/* generate tone+noise... or neither.
* (if no tone/noise is selected, the chip just shoves the
* level out unmodified. This is used by some sample-playing
* stuff.)
*/
chan1 = tone_level[0];
chan2 = tone_level[1];
chan3 = tone_level[2];
mixer = sound_ay_registers[7];
ay_tone_subcycles += ay_tick_incr;
tone_count = ay_tone_subcycles >> ( 3 + 16 );
ay_tone_subcycles &= ( 8 << 16 ) - 1;
if( ( mixer & 1 ) == 0 ) {
level = chan1;
AY_DO_TONE( chan1, 0 );
}
if( ( mixer & 0x08 ) == 0 && noise_toggle )
chan1 = 0;
if( ( mixer & 2 ) == 0 ) {
level = chan2;
AY_DO_TONE( chan2, 1 );
}
if( ( mixer & 0x10 ) == 0 && noise_toggle )
chan2 = 0;
if( ( mixer & 4 ) == 0 ) {
level = chan3;
AY_DO_TONE( chan3, 2 );
}
if( ( mixer & 0x20 ) == 0 && noise_toggle )
chan3 = 0;
/* write the sample(s) */
if( !sound_stereo ) {
/* mono */
( *ptr++ ) += chan1 + chan2 + chan3;
} else {
if( !sound_stereo_ay ) {
/* stereo output, but mono AY sound; still,
* incr separately in case of beeper pseudostereo.
*/
( *ptr++ ) += chan1 + chan2 + chan3;
( *ptr++ ) += chan1 + chan2 + chan3;
} else {
/* stereo with ACB/ABC AY positioning.
* Here we use real stereo positions for the channels.
* Just because, y'know, it's cool and stuff. No, really. :-)
* This is a little tricky, as it works by delaying sounds
* on the left or right channels to model the delay you get
* in the real world when sounds originate at different places.
*/
GEN_STEREO( rchan1pos, chan1 );
GEN_STEREO( rchan2pos, chan2 );
GEN_STEREO( rchan3pos, chan3 );
( *ptr++ ) += rstereobuf_l[ rstereopos ];
( *ptr++ ) += rstereobuf_r[ rstereopos ];
rstereobuf_l[ rstereopos ] = rstereobuf_r[ rstereopos ] = 0;
rstereopos++;
if( rstereopos >= STEREO_BUF_SIZE )
rstereopos = 0;
}
}
/* update noise RNG/filter */
ay_noise_tick += noise_count;
while( ay_noise_tick >= ay_noise_period ) {
ay_noise_tick -= ay_noise_period;
if( ( rng & 1 ) ^ ( ( rng & 2 ) ? 1 : 0 ) )
noise_toggle = !noise_toggle;
/* rng is 17-bit shift reg, bit 0 is output.
* input is bit 0 xor bit 2.
*/
rng |= ( ( rng & 1 ) ^ ( ( rng & 4 ) ? 1 : 0 ) ) ? 0x20000 : 0;
rng >>= 1;
/* don't keep trying if period is zero */
if( !ay_noise_period )
break;
}
}
}
/* don't make the change immediately; record it for later,
* to be made by sound_frame() (via sound_ay_overlay()).
*/
void
sound_ay_write( int reg, int val, libspectrum_dword now )
{
if( ay_change_count < AY_CHANGE_MAX ) {
ay_change[ ay_change_count ].tstates = now;
ay_change[ ay_change_count ].reg = ( reg & 15 );
ay_change[ ay_change_count ].val = val;
ay_change_count++;
}
}
/* no need to call this initially, but should be called
* on reset otherwise.
*/
void
sound_ay_reset( void )
{
int f;
/* recalculate timings based on new machines ay clock */
sound_ay_init();
ay_change_count = 0;
for( f = 0; f < 16; f++ )
sound_ay_write( f, 0, 0 );
for( f = 0; f < 3; f++ )
ay_tone_high[f] = 0;
ay_tone_subcycles = ay_env_subcycles = 0;
}
/* write stereo or mono beeper sample, and incr ptr */
#define SOUND_WRITE_BUF_BEEPER( ptr, val ) \
do { \
if( sound_stereo_beeper ) { \
sound_write_buf_pstereo( ( ptr ), ( val ) ); \
( ptr ) += 2; \
} else { \
*( ptr )++ = ( val ); \
if( sound_stereo ) \
*( ptr )++ = ( val ); \
} \
} while(0)
/* the tape version works by writing to a separate mono buffer,
* which gets added after being generated.
*/
#define SOUND_WRITE_BUF( is_tape, ptr, val ) \
if( is_tape ) \
*( ptr )++ = ( val ); \
else \
SOUND_WRITE_BUF_BEEPER( ptr, val )
#ifdef HAVE_SAMPLERATE
static void
sound_resample( void )
{
int error;
SRC_DATA data;
data.data_in = convert_input_buffer;
data.input_frames = sound_generator_framesiz;
data.data_out = convert_output_buffer;
data.output_frames = sound_framesiz;
data.src_ratio =
( double ) settings_current.sound_freq / sound_generator_freq;
data.end_of_input = 0;
src_short_to_float_array( ( const short * ) sound_buf, convert_input_buffer,
sound_generator_framesiz * sound_channels );
while( data.input_frames ) {
error = src_process( src_state, &data );
if( error ) {
ui_error( UI_ERROR_ERROR, "hifi sound downsample error %s",
src_strerror( error ) );
sound_end();
return;
}
src_float_to_short_array( convert_output_buffer, ( short * ) sound_buf,
data.output_frames_gen * sound_channels );
sound_lowlevel_frame( sound_buf,
data.output_frames_gen * sound_channels );
data.data_in += data.input_frames_used * sound_channels;
data.input_frames -= data.input_frames_used;
}
}
#endif /* #ifdef HAVE_SAMPLERATE */
void
sound_frame( void )
{
libspectrum_signed_word *ptr, *tptr;
int f, bchan;
int ampl = AMPL_BEEPER;
if( !sound_enabled )
return;
/* fill in remaining beeper/tape sound */
ptr =
sound_buf + ( sound_stereo ? sound_fillpos[0] * 2 : sound_fillpos[0] );
for( bchan = 0; bchan < 2; bchan++ ) {
for( f = sound_fillpos[ bchan ]; f < sound_generator_framesiz; f++ )
SOUND_WRITE_BUF( bchan, ptr, sound_oldval[ bchan ] );
ptr = tape_buf + sound_fillpos[1];
ampl = AMPL_TAPE;
}
/* overlay tape sound */
ptr = sound_buf;
tptr = tape_buf;
for( f = 0; f < sound_generator_framesiz; f++, tptr++ ) {
( *ptr++ ) += *tptr;
if( sound_stereo )
( *ptr++ ) += *tptr;
}
/* overlay AY sound */
sound_ay_overlay();
#ifdef HAVE_SAMPLERATE
/* resample from generated frequency down to output frequency if required */
if( settings_current.sound_hifi )
sound_resample();
else
#endif /* #ifdef HAVE_SAMPLERATE */
sound_lowlevel_frame( sound_buf,
sound_generator_framesiz * sound_channels );
sound_oldpos[0] = sound_oldpos[1] = -1;
sound_fillpos[0] = sound_fillpos[1] = 0;
ay_change_count = 0;
}
/* two beepers are supported - the real beeper (call with is_tape==0)
* and a `fake' beeper which lets you hear when a tape is being played.
*/
void
sound_beeper( int is_tape, int on )
{
libspectrum_signed_word *ptr;
int newpos, subpos;
int val, subval;
int f;
int bchan = ( is_tape ? 1 : 0 );
int ampl = ( is_tape ? AMPL_TAPE : AMPL_BEEPER );
int vol = ampl * 2;
if( !sound_enabled )
return;
val = ( on ? -ampl : ampl );
if( val == sound_oldval_orig[ bchan ] )
return;
/* XXX a lookup table might help here, but would need to regenerate it
* whenever cycles_per_frame were changed (i.e. when machine type changed).
*/
newpos =
( tstates * sound_generator_framesiz ) /
machine_current->timings.tstates_per_frame;
subpos =
( ( ( libspectrum_signed_qword ) tstates ) * sound_generator_framesiz *
vol ) / ( machine_current->timings.tstates_per_frame ) - vol * newpos;
/* if we already wrote here, adjust the level.
*/
if( newpos == sound_oldpos[ bchan ] ) {
/* adjust it as if the rest of the sample period were all in
* the new state. (Often it will be, but if not, we'll fix
* it later by doing this again.)
*/
if( on )
beeper_last_subpos[ bchan ] += vol - subpos;
else
beeper_last_subpos[ bchan ] -= vol - subpos;
} else
beeper_last_subpos[ bchan ] = ( on ? vol - subpos : subpos );
subval = ampl - beeper_last_subpos[ bchan ];
if( newpos >= 0 ) {
/* fill gap from previous position */
if( is_tape )
ptr = tape_buf + sound_fillpos[1];
else
ptr =
sound_buf +
( sound_stereo ? sound_fillpos[0] * 2 : sound_fillpos[0] );
for( f = sound_fillpos[ bchan ];
f < newpos && f < sound_generator_framesiz;
f++ )
SOUND_WRITE_BUF( bchan, ptr, sound_oldval[ bchan ] );
if( newpos < sound_generator_framesiz ) {
/* newpos may be less than sound_fillpos, so... */
if( is_tape )
ptr = tape_buf + newpos;
else
ptr = sound_buf + ( sound_stereo ? newpos * 2 : newpos );
/* write subsample value */
SOUND_WRITE_BUF( bchan, ptr, subval );
}
}
sound_oldpos[ bchan ] = newpos;
sound_fillpos[ bchan ] = newpos + 1;
sound_oldval[ bchan ] = sound_oldval_orig[ bchan ] = val;
}

View File

@ -1,7 +1,7 @@
/* sound.h: Sound support
Copyright (c) 2000-2004 Russell Marks, Matan Ziv-Av, Philip Kendall
$Id: sound.h 2889 2007-05-26 17:45:08Z zubzero $
$Id: sound.h 4031 2009-06-08 00:33:53Z fredm $
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -35,7 +35,8 @@ void sound_end( void );
void sound_ay_write( int reg, int val, libspectrum_dword now );
void sound_ay_reset( void );
void sound_frame( void );
void sound_beeper( int is_tape, int on );
void sound_beeper( int on );
libspectrum_dword sound_get_effective_processor_speed( void );
extern int sound_enabled;
extern int sound_enabled_ever;

View File

@ -0,0 +1,56 @@
/* sound.h: Sound support
Copyright (c) 2000-2004 Russell Marks, Matan Ziv-Av, Philip Kendall
$Id: sound.h 2889 2007-05-26 17:45:08Z zubzero $
This program 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 2 of the License, or
(at your option) any later version.
This program 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 this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Author contact information:
E-mail: philip-fuse@shadowmagic.org.uk
*/
#ifndef FUSE_SOUND_H
#define FUSE_SOUND_H
#include <libspectrum.h>
void sound_init( const char *device );
void sound_pause( void );
void sound_unpause( void );
void sound_end( void );
void sound_ay_write( int reg, int val, libspectrum_dword now );
void sound_ay_reset( void );
void sound_frame( void );
void sound_beeper( int is_tape, int on );
extern int sound_enabled;
extern int sound_enabled_ever;
extern int sound_freq;
extern int sound_framesiz;
extern int sound_stereo;
extern int sound_stereo_beeper;
extern int sound_stereo_ay;
extern int sound_stereo_ay_abc;
extern int sound_stereo_ay_narrow;
/* The low-level sound interface */
int sound_lowlevel_init( const char *device, int *freqptr, int *stereoptr );
void sound_lowlevel_end( void );
void sound_lowlevel_frame( libspectrum_signed_word *data, int len );
#endif /* #ifndef FUSE_SOUND_H */

View File

@ -0,0 +1,615 @@
/* blipbuffer.c
Copyright (C) 2003-2006 Shay Green. This module is free software; you
can redistribute it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. This
module 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 Lesser General Public License for
more details. You should have received a copy of the GNU Lesser General
Public License along with this module; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Original C++ source:
Blip_Buffer 0.4.0. http:www.slack.net/~ant/
partially reimplemented in C by Gergely Szasz for FUSE
*/
#include <limits.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include "blipbuffer.h"
static void _blip_synth_init( Blip_Synth_ * synth_, short *impulses );
inline void
blip_buffer_set_clock_rate( Blip_Buffer * buff, long cps )
{
buff->factor_ = blip_buffer_clock_rate_factor( buff, buff->clock_rate_ =
cps );
}
inline long
blip_buffer_samples_avail( Blip_Buffer * buff )
{
return ( long )( buff->offset_ >> BLIP_BUFFER_ACCURACY );
}
void
blip_synth_set_output( Blip_Synth * synth, Blip_Buffer * b )
{
synth->impl.buf = b;
synth->impl.last_amp = 0;
}
void
blip_synth_set_volume( Blip_Synth * synth, double v )
{
_blip_synth_volume_unit( &synth->impl,
v * ( 1.0 /
( BLIP_SYNTH_RANGE <
0 ? -( BLIP_SYNTH_RANGE ) :
BLIP_SYNTH_RANGE ) ) );
}
#define BLIP_FWD( i ) \
t0 = i0 * delta + buf[fwd + i]; \
t1 = imp[BLIP_RES * (i + 1)] * delta + buf[fwd + 1 + i]; \
i0 = imp[BLIP_RES * (i + 2)]; \
buf[fwd + i] = t0; \
buf[fwd + 1 + i] = t1
#define BLIP_REV( r ) \
t0 = i0 * delta + buf[rev - r]; \
t1 = imp[BLIP_RES * r] * delta + buf[rev + 1 - r]; \
i0 = imp[BLIP_RES * (r - 1)]; \
buf[rev - r] = t0; \
buf[rev + 1 - r] = t1
inline void
blip_synth_offset_resampled( Blip_Synth * synth, blip_resampled_time_t time,
int delta, Blip_Buffer * blip_buf )
{
int phase, fwd, rev, mid;
imp_t *imp;
long *buf, i0, t0, t1;
delta *= synth->impl.delta_factor;
phase =
( int )( time >> ( BLIP_BUFFER_ACCURACY - BLIP_PHASE_BITS ) &
( BLIP_RES - 1 ) );
imp = synth->impulses + BLIP_RES - phase;
buf = blip_buf->buffer_ + ( time >> BLIP_BUFFER_ACCURACY );
i0 = *imp;
fwd = ( BLIP_WIDEST_IMPULSE_ - BLIP_SYNTH_QUALITY ) / 2;
rev = fwd + BLIP_SYNTH_QUALITY - 2;
BLIP_FWD( 0 );
if( BLIP_SYNTH_QUALITY > 8 ) {
BLIP_FWD( 2 );
}
if( BLIP_SYNTH_QUALITY > 12 ) {
BLIP_FWD( 4 );
}
mid = BLIP_SYNTH_QUALITY / 2 - 1;
t0 = i0 * delta + buf[fwd + mid - 1];
t1 = imp[BLIP_RES * mid] * delta + buf[fwd + mid];
imp = synth->impulses + phase;
i0 = imp[BLIP_RES * mid];
buf[fwd + mid - 1] = t0;
buf[fwd + mid] = t1;
if( BLIP_SYNTH_QUALITY > 12 ) {
BLIP_REV( 6 );
}
if( BLIP_SYNTH_QUALITY > 8 ) {
BLIP_REV( 4 );
}
BLIP_REV( 2 );
t0 = i0 * delta + buf[rev];
t1 = *imp * delta + buf[rev + 1];
buf[rev] = t0;
buf[rev + 1] = t1;
}
#undef BLIP_FWD
#undef BLIP_REV
void
blip_synth_update( Blip_Synth * synth, blip_time_t t, int amp )
{
int delta = amp - synth->impl.last_amp;
synth->impl.last_amp = amp;
blip_synth_offset_resampled( synth,
t * synth->impl.buf->factor_ +
synth->impl.buf->offset_, delta,
synth->impl.buf );
}
int
_blip_synth_impulses_size( Blip_Synth_ * synth_ )
{
return BLIP_RES / 2 * BLIP_SYNTH_WIDTH + 1;
}
void
blip_synth_set_treble_eq( Blip_Synth * synth, double treble )
{
blip_eq_t eq = { 0.0, 0, 44100, 0 };
eq.treble = treble;
_blip_synth_treble_eq( &synth->impl, &eq );
}
#define BUFFER_EXTRA ( BLIP_WIDEST_IMPULSE_ + 2 )
static void
blip_buffer_init( Blip_Buffer * buff )
{
buff->factor_ = LONG_MAX;
buff->offset_ = 0;
buff->buffer_ = NULL;
buff->buffer_size_ = 0;
buff->sample_rate_ = 0;
buff->reader_accum = 0;
buff->bass_shift = 0;
buff->clock_rate_ = 0;
buff->bass_freq_ = 16;
buff->length_ = 0;
}
static void
blip_buffer_end( Blip_Buffer * buff )
{
if( buff->buffer_ )
free( buff->buffer_ );
buff->buffer_ = NULL;
}
Blip_Buffer *
new_Blip_Buffer( void )
{
Blip_Buffer *ret;
ret = malloc( sizeof( Blip_Buffer ) );
if( ret ) {
blip_buffer_init( ret );
}
return ret;
}
void
delete_Blip_Buffer( Blip_Buffer ** buff )
{
if( !*buff )
return;
blip_buffer_end( *buff );
free( *buff );
*buff = NULL;
}
static void
blip_synth_init( Blip_Synth * synth )
{
synth->impulses =
malloc( ( BLIP_RES * ( BLIP_SYNTH_QUALITY / 2 ) +
1 ) * sizeof( imp_t ) * 4 );
if( synth->impulses ) {
_blip_synth_init( &synth->impl, ( short * )synth->impulses ); /* sorry, somewhere imp_t, somewhere short ???? */
}
}
static void
blip_synth_end( Blip_Synth * synth )
{
if( synth->impulses ) {
free( synth->impulses );
synth->impulses = NULL;
}
}
Blip_Synth *
new_Blip_Synth( void )
{
Blip_Synth *ret;
ret = malloc( sizeof( Blip_Synth ) );
if( ret ) {
blip_synth_init( ret );
if( !ret->impulses ) {
free( ret );
return NULL;
}
}
return ret;
}
void
delete_Blip_Synth( Blip_Synth ** synth )
{
if( !*synth )
return;
blip_synth_end( *synth );
free( *synth );
*synth = NULL;
}
void
blip_buffer_clear( Blip_Buffer * buff, int entire_buffer )
{
buff->offset_ = 0;
buff->reader_accum = 0;
if( buff->buffer_ ) {
long count =
( entire_buffer ? buff->
buffer_size_ : blip_buffer_samples_avail( buff ) );
memset( buff->buffer_, 0, ( count + BUFFER_EXTRA ) * sizeof( buf_t_ ) );
}
}
blargg_err_t
blip_buffer_set_sample_rate( Blip_Buffer * buff, long new_rate, int msec )
{
/* start with maximum length that resampled time can represent */
long new_size = ( ULONG_MAX >> BLIP_BUFFER_ACCURACY ) - BUFFER_EXTRA - 64;
if( msec != BLIP_MAX_LENGTH ) {
long s = ( new_rate * ( msec + 1 ) + 999 ) / 1000;
if( s < new_size )
new_size = s;
}
if( buff->buffer_size_ != new_size ) {
void *p =
realloc( buff->buffer_,
( new_size + BUFFER_EXTRA ) * sizeof( buf_t_ ) );
if( !p )
return "Out of memory";
buff->buffer_ = ( buf_t_ * ) p;
}
buff->buffer_size_ = new_size;
/* update things based on the sample rate */
buff->sample_rate_ = new_rate;
buff->length_ = new_size * 1000 / new_rate - 1;
if( buff->clock_rate_ )
blip_buffer_set_clock_rate( buff, buff->clock_rate_ );
blip_buffer_set_bass_freq( buff, buff->bass_freq_ );
blip_buffer_clear( buff, BLIP_BUFFER_DEF_ENTIRE_BUFF );
return 0; /* success */
}
blip_resampled_time_t
blip_buffer_clock_rate_factor( Blip_Buffer * buff, long clock_rate )
{
double ratio = ( double )buff->sample_rate_ / clock_rate;
long factor = ( long )floor( ratio * ( 1L << BLIP_BUFFER_ACCURACY ) + 0.5 );
return ( blip_resampled_time_t ) factor;
}
void
blip_buffer_set_bass_freq( Blip_Buffer * buff, int freq )
{
int shift = 31;
long f;
buff->bass_freq_ = freq;
if( freq > 0 ) {
shift = 13;
f = ( freq << 16 ) / buff->sample_rate_;
while( ( f >>= 1 ) && --shift ) {};
}
buff->bass_shift = shift;
}
void
blip_buffer_end_frame( Blip_Buffer * buff, blip_time_t t )
{
buff->offset_ += t * buff->factor_;
}
inline void
blip_buffer_remove_silence( Blip_Buffer * buff, long count )
{
buff->offset_ -= ( blip_resampled_time_t ) count << BLIP_BUFFER_ACCURACY;
}
inline void
blip_buffer_remove_samples( Blip_Buffer * buff, long count )
{
long remain;
if( count ) {
blip_buffer_remove_silence( buff, count );
/* copy remaining samples to beginning and clear old samples */
remain = blip_buffer_samples_avail( buff ) + BUFFER_EXTRA;
memmove( buff->buffer_, buff->buffer_ + count,
remain * sizeof( buf_t_ ) );
memset( buff->buffer_ + remain, 0, count * sizeof( buf_t_ ) );
}
}
/* Blip_Synth_ */
void
_blip_synth_init( Blip_Synth_ * synth_, short *p )
{
synth_->impulses = p;
synth_->volume_unit_ = 0.0;
synth_->kernel_unit = 0;
synth_->buf = NULL;
synth_->last_amp = 0;
synth_->delta_factor = 0;
}
#define PI 3.1415926535897932384626433832795029
static void
gen_sinc( float *out, int count, double oversample, double treble,
double cutoff )
{
int i;
double maxh, rolloff, pow_a_n, to_angle;
if( cutoff > 0.999 )
cutoff = 0.999;
if( treble < -300.0 )
treble = -300.0;
if( treble > 5.0 )
treble = 5.0;
maxh = 4096.0;
rolloff = pow( 10.0, 1.0 / ( maxh * 20.0 ) * treble / ( 1.0 - cutoff ) );
pow_a_n = pow( rolloff, maxh - maxh * cutoff );
to_angle = PI / 2 / maxh / oversample;
for( i = 0; i < count; i++ ) {
double angle, c, cos_nc_angle, cos_nc1_angle, cos_angle, d, b, a;
angle = ( ( i - count ) * 2 + 1 ) * to_angle;
c = rolloff * cos( ( maxh - 1.0 ) * angle ) - cos( maxh * angle );
cos_nc_angle = cos( maxh * cutoff * angle );
cos_nc1_angle = cos( ( maxh * cutoff - 1.0 ) * angle );
cos_angle = cos( angle );
c = c * pow_a_n - rolloff * cos_nc1_angle + cos_nc_angle;
d = 1.0 + rolloff * ( rolloff - cos_angle - cos_angle );
b = 2.0 - cos_angle - cos_angle;
a = 1.0 - cos_angle - cos_nc_angle + cos_nc1_angle;
out[i] = ( float )( ( a * d + c * b ) / ( b * d ) ); /* a / b + c / d */
}
}
void
blip_eq_generate( blip_eq_t * eq, float *out, int count )
{
/* lower cutoff freq for narrow kernels with their wider transition band
(8 points->1.49, 16 points->1.15) */
int i;
double to_fraction, cutoff;
double oversample = BLIP_RES * 2.25 / count + 0.85;
double half_rate = eq->sample_rate * 0.5;
if( eq->cutoff_freq )
oversample = half_rate / eq->cutoff_freq;
cutoff = eq->rolloff_freq * oversample / half_rate;
gen_sinc( out, count, BLIP_RES * oversample, eq->treble, cutoff );
/* apply (half of) hamming window */
to_fraction = PI / ( count - 1 );
for( i = count; i--; )
out[i] *= 0.54 - 0.46 * cos( i * to_fraction );
}
void
_blip_synth_adjust_impulse( Blip_Synth_ * synth_ )
{
/* sum pairs for each phase and add error correction to end of first half */
int size = _blip_synth_impulses_size( synth_ );
int i, p, p2, error;
for( p = BLIP_RES; p-- >= BLIP_RES / 2; ) {
error = synth_->kernel_unit;
p2 = BLIP_RES - 2 - p;
for( i = 1; i < size; i += BLIP_RES ) {
error -= synth_->impulses[i + p];
error -= synth_->impulses[i + p2];
}
if( p == p2 )
error /= 2; /* phase = 0.5 impulse uses same half for both sides */
synth_->impulses[size - BLIP_RES + p] += error;
}
}
void
_blip_synth_treble_eq( Blip_Synth_ * synth_, blip_eq_t * eq )
{
double total, base_unit, rescale, sum, next, vol;
int impulses_size, i;
float fimpulse[BLIP_RES / 2 * ( BLIP_WIDEST_IMPULSE_ - 1 ) + BLIP_RES * 2];
int half_size = BLIP_RES / 2 * ( BLIP_SYNTH_WIDTH - 1 );
blip_eq_generate( eq, &fimpulse[BLIP_RES], half_size );
/* need mirror slightly past center for calculation */
for( i = BLIP_RES; i--; )
fimpulse[BLIP_RES + half_size + i] =
fimpulse[BLIP_RES + half_size - 1 - i];
/* starts at 0 */
for( i = 0; i < BLIP_RES; i++ )
fimpulse[i] = 0.0f;
/* find rescale factor */
total = 0.0;
for( i = 0; i < half_size; i++ )
total += fimpulse[BLIP_RES + i];
/* double const base_unit = 44800.0 - 128 * 18; allows treble up to +0 dB
double const base_unit = 37888.0; allows treble to +5 dB */
base_unit = 32768.0; /* necessary for blip_unscaled to work */
rescale = base_unit / 2 / total;
synth_->kernel_unit = ( long )base_unit;
/* integrate, first difference, rescale, convert to int */
sum = 0.0;
next = 0.0;
impulses_size = _blip_synth_impulses_size( synth_ );
for( i = 0; i < impulses_size; i++ ) {
synth_->impulses[i] = ( short )floor( ( next - sum ) * rescale + 0.5 );
sum += fimpulse[i];
next += fimpulse[i + BLIP_RES];
}
_blip_synth_adjust_impulse( synth_ );
/* volume might require rescaling */
vol = synth_->volume_unit_;
if( vol ) {
synth_->volume_unit_ = 0.0;
_blip_synth_volume_unit( synth_, vol );
}
}
void
_blip_synth_volume_unit( Blip_Synth_ * synth_, double new_unit )
{
if( new_unit != synth_->volume_unit_ ) {
double factor;
/* use default eq if it hasn't been set yet */
if( !synth_->kernel_unit ) {
blip_eq_t eq = { -8.0, 0, 44100, 0 };
_blip_synth_treble_eq( synth_, &eq );
}
synth_->volume_unit_ = new_unit;
factor = new_unit * ( 1L << BLIP_SAMPLE_BITS ) / synth_->kernel_unit;
if( factor > 0.0 ) {
int shift = 0;
/* if unit is really small, might need to attenuate kernel */
while( factor < 2.0 ) {
shift++;
factor *= 2.0;
}
if( shift ) {
/* keep values positive to avoid round-towards-zero of sign-preserving
* right shift for negative values */
long offset = 0x8000 + ( 1 << ( shift - 1 ) );
long offset2 = 0x8000 >> shift;
int i;
synth_->kernel_unit >>= shift;
for( i = _blip_synth_impulses_size( synth_ ); i--; )
synth_->impulses[i] =
( short )( ( ( synth_->impulses[i] + offset ) >> shift ) -
offset2 );
_blip_synth_adjust_impulse( synth_ );
}
}
synth_->delta_factor = ( int )floor( factor + 0.5 );
}
}
long
blip_buffer_read_samples( Blip_Buffer * buff, blip_sample_t * out,
long max_samples, int stereo )
{
long count = blip_buffer_samples_avail( buff );
if( count > max_samples )
count = max_samples;
if( count ) {
int sample_shift = BLIP_SAMPLE_BITS - 16;
int my_bass_shift = buff->bass_shift;
long accum = buff->reader_accum;
buf_t_ *in = buff->buffer_;
if( !stereo ) {
int n;
for( n = count; n--; ) {
long s = accum >> sample_shift;
accum -= accum >> my_bass_shift;
accum += *in++;
*out++ = ( blip_sample_t ) s;
/* clamp sample */
if( ( blip_sample_t ) s != s )
out[-1] = ( blip_sample_t ) ( 0x7FFF - ( s >> 24 ) );
}
} else {
int n;
for( n = count; n--; ) {
long s = accum >> sample_shift;
accum -= accum >> my_bass_shift;
accum += *in++;
*out = ( blip_sample_t ) s;
out += 2;
/* clamp sample */
if( ( blip_sample_t ) s != s )
out[-2] = ( blip_sample_t ) ( 0x7FFF - ( s >> 24 ) );
}
}
buff->reader_accum = accum;
blip_buffer_remove_samples( buff, count );
}
return count;
}

View File

@ -0,0 +1,238 @@
/* blipbuffer.h
Band-limited sound synthesis and buffering
Blip_Buffer 0.4.0
Original C++ source:
Blip_Buffer 0.4.0. http:www.slack.net/~ant/
Copyright (C) 2003-2006 Shay Green. This module is free software; you
can redistribute it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. This
module 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 Lesser General Public License for
more details. You should have received a copy of the GNU Lesser General
Public License along with this module; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
partially reimplemented in C by Gergely Szasz
There is a lot of ambiguous thing in the original C++ source, some of them `rectified'
(e.g. `int const blahblah = xxx` in the header translated to #define ), others not
(e.g. blip_sample_t/imp_t/short or Blip_Synth_ in Blip_Synth, or the whole
blip_eq_t struct ...).
Functions originally implemented in the header are moved to .c.
Classes converted to structs, member functions prefixed with: blip_buff_
_blip_synth_ and blip_synth_ resp.
set_treble_eq() implemented with last argument as `double` instead
of `blip_eq_t` because this function always call just with treble value,
and C lack of `plain' type -> `struct' magic conversion/construction
capabilities.
The source now almost according to C89. (except of course `inline')
*/
#ifndef BLIP_BUFFER_H
#define BLIP_BUFFER_H
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
/*
Time unit at source clock rate
*/
typedef long blip_time_t;
/* Output samples are 16-bit signed, with a range of -32767 to 32767 */
typedef short blip_sample_t;
typedef const char *blargg_err_t;
typedef long buf_t_;
typedef unsigned long blip_resampled_time_t;
# define BLIP_BUFFER_DEF_MSEC_LENGTH ( 1000 / 4 )
# define BLIP_BUFFER_DEF_STEREO 0
# define BLIP_BUFFER_DEF_ENTIRE_BUFF 1
typedef struct Blip_Buffer_s {
unsigned long factor_;
blip_resampled_time_t offset_;
buf_t_ *buffer_;
long buffer_size_;
long reader_accum;
int bass_shift;
long sample_rate_;
long clock_rate_;
int bass_freq_;
int length_;
} Blip_Buffer;
Blip_Buffer *new_Blip_Buffer( void );
void delete_Blip_Buffer( Blip_Buffer ** buff );
/* Set output sample rate and buffer length in milliseconds (1/1000 sec, defaults
to 1/4 second), then clear buffer. Returns NULL on success, otherwise if there
isn't enough memory, returns error without affecting current buffer setup.
*/
blargg_err_t blip_buffer_set_sample_rate( Blip_Buffer * buff,
long samples_per_sec,
int msec_length );
/* Set number of source time units per second
*/
void blip_buffer_set_clock_rate( Blip_Buffer * buff, long rate );
/* End current time frame of specified duration and make its samples available
(along with any still-unread samples) for reading with read_samples(). Begins
a new time frame at the end of the current frame.
*/
void blip_buffer_end_frame( Blip_Buffer * buff, blip_time_t time );
/* Read at most 'max_samples' out of buffer into 'dest', removing them from from
the buffer. Returns number of samples actually read and removed. If stereo is
true, increments 'dest' one extra time after writing each sample, to allow
easy interleving of two channels into a stereo output buffer.
*/
long blip_buffer_read_samples( Blip_Buffer * buff, blip_sample_t * dest,
long max_samples, int stereo );
/* Additional optional features */
/* Set frequency high-pass filter frequency, where higher values reduce bass more */
void blip_buffer_set_bass_freq( Blip_Buffer * buff, int frequency );
/* Remove all available samples and clear buffer to silence. If 'entire_buffer' is
false, just clears out any samples waiting rather than the entire buffer.
*/
void blip_buffer_clear( Blip_Buffer * buff, int entire_buffer );
/* Number of samples available for reading with read_samples()
*/
long
blip_buffer_samples_avail( Blip_Buffer * buff );
/* Remove 'count' samples from those waiting to be read
*/
void blip_buffer_remove_samples( Blip_Buffer * buff, long count );
/* Experimental features */
void blip_buffer_remove_silence( Blip_Buffer * buff, long count );
blip_resampled_time_t blip_buffer_clock_rate_factor( Blip_Buffer * buff,
long clock_rate );
/*
Number of bits in resample ratio fraction. Higher values give a more accurate ratio
but reduce maximum buffer size.
*/
#ifndef BLIP_BUFFER_ACCURACY
#define BLIP_BUFFER_ACCURACY 16
#endif
/*
Number bits in phase offset. Fewer than 6 bits (64 phase offsets) results in
noticeable broadband noise when synthesizing high frequency square waves.
Affects size of Blip_Synth objects since they store the waveform directly.
*/
#ifndef BLIP_PHASE_BITS
#define BLIP_PHASE_BITS 6
#endif
/* Internal */
#define BLIP_WIDEST_IMPULSE_ 16
#define BLIP_RES (1 << BLIP_PHASE_BITS)
struct blip_eq_s;
typedef struct Blip_Synth_s_ {
double volume_unit_;
short *impulses;
long kernel_unit;
Blip_Buffer *buf;
int last_amp;
int delta_factor;
} Blip_Synth_;
int _blip_synth_impulses_size( Blip_Synth_ * synth_ );
void _blip_synth_adjust_impulse( Blip_Synth_ * synth_ );
void _blip_synth_treble_eq( Blip_Synth_ * synth_, struct blip_eq_s *eq );
void _blip_synth_volume_unit( Blip_Synth_ * synth_, double v );
/* Quality level. Start with blip_good_quality. */
#define BLIP_MED_QUALITY 8
#define BLIP_GOOD_QUALITY 12
#define BLIP_HIGH_QUALITY 16
/* Range specifies the greatest expected change in amplitude. Calculate it
by finding the difference between the maximum and minimum expected
amplitudes (max - min). */
typedef short imp_t;
typedef struct Blip_Synth_s {
imp_t *impulses;
Blip_Synth_ impl;
} Blip_Synth;
void blip_synth_set_volume( Blip_Synth * synth, double v );
/* Configure low-pass filter (see notes.txt)*/
void blip_synth_set_treble_eq( Blip_Synth * synth, double treble );
/* Get/set Blip_Buffer used for output */
void blip_synth_set_output( Blip_Synth * synth, Blip_Buffer * b );
/* Update amplitude of waveform at given time. Using this requires a separate
Blip_Synth for each waveform. */
void blip_synth_update( Blip_Synth * synth, blip_time_t time,
int amplitude );
/* Low-level interface */
void blip_synth_offset_resampled( Blip_Synth * synth,
blip_resampled_time_t, int delta,
Blip_Buffer * buff );
Blip_Synth *new_Blip_Synth( void );
void delete_Blip_Synth( Blip_Synth ** synth );
#define BLIP_EQ_DEF_CUTOFF 0
/* Low-pass equalization parameters */
typedef struct blip_eq_s {
double treble;
long rolloff_freq;
long sample_rate;
long cutoff_freq;
} blip_eq_t;
#define BLIP_SAMPLE_BITS 30
/* End of public interface */
#define BLIP_UNSCALED 65535
inline long blip_buffer_samples_avail( Blip_Buffer * buff );
inline void blip_buffer_set_clock_rate( Blip_Buffer * buff, long cps );
#define BLIP_MAX_LENGTH 0
#define BLIP_SYNTH_QUALITY BLIP_MED_QUALITY
#define BLIP_SYNTH_RANGE BLIP_UNSCALED
#define BLIP_SYNTH_WIDTH BLIP_SYNTH_QUALITY /* `quality' of synth as `width' of synth_ */
#endif

View File

@ -0,0 +1,238 @@
/* blipbuffer.h
Band-limited sound synthesis and buffering
Blip_Buffer 0.4.0
Original C++ source:
Blip_Buffer 0.4.0. http:www.slack.net/~ant/
Copyright (C) 2003-2006 Shay Green. This module is free software; you
can redistribute it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. This
module 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 Lesser General Public License for
more details. You should have received a copy of the GNU Lesser General
Public License along with this module; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
partially reimplemented in C by Gergely Szasz
There is a lot of ambiguous thing in the original C++ source, some of them `rectified'
(e.g. `int const blahblah = xxx` in the header translated to #define ), others not
(e.g. blip_sample_t/imp_t/short or Blip_Synth_ in Blip_Synth, or the whole
blip_eq_t struct ...).
Functions originally implemented in the header are moved to .c.
Classes converted to structs, member functions prefixed with: blip_buff_
_blip_synth_ and blip_synth_ resp.
set_treble_eq() implemented with last argument as `double` instead
of `blip_eq_t` because this function always call just with treble value,
and C lack of `plain' type -> `struct' magic conversion/construction
capabilities.
The source now almost according to C89. (except of course `inline')
*/
#ifndef BLIP_BUFFER_H
#define BLIP_BUFFER_H
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
/*
Time unit at source clock rate
*/
typedef long blip_time_t;
/* Output samples are 16-bit signed, with a range of -32767 to 32767 */
typedef short blip_sample_t;
typedef const char *blargg_err_t;
typedef long buf_t_;
typedef unsigned long blip_resampled_time_t;
# define BLIP_BUFFER_DEF_MSEC_LENGTH ( 1000 / 4 )
# define BLIP_BUFFER_DEF_STEREO 0
# define BLIP_BUFFER_DEF_ENTIRE_BUFF 1
typedef struct Blip_Buffer_s {
unsigned long factor_;
blip_resampled_time_t offset_;
buf_t_ *buffer_;
long buffer_size_;
long reader_accum;
int bass_shift;
long sample_rate_;
long clock_rate_;
int bass_freq_;
int length_;
} Blip_Buffer;
Blip_Buffer *new_Blip_Buffer( void );
void delete_Blip_Buffer( Blip_Buffer ** buff );
/* Set output sample rate and buffer length in milliseconds (1/1000 sec, defaults
to 1/4 second), then clear buffer. Returns NULL on success, otherwise if there
isn't enough memory, returns error without affecting current buffer setup.
*/
blargg_err_t blip_buffer_set_sample_rate( Blip_Buffer * buff,
long samples_per_sec,
int msec_length );
/* Set number of source time units per second
*/
void blip_buffer_set_clock_rate( Blip_Buffer * buff, long rate );
/* End current time frame of specified duration and make its samples available
(along with any still-unread samples) for reading with read_samples(). Begins
a new time frame at the end of the current frame.
*/
void blip_buffer_end_frame( Blip_Buffer * buff, blip_time_t time );
/* Read at most 'max_samples' out of buffer into 'dest', removing them from from
the buffer. Returns number of samples actually read and removed. If stereo is
true, increments 'dest' one extra time after writing each sample, to allow
easy interleving of two channels into a stereo output buffer.
*/
long blip_buffer_read_samples( Blip_Buffer * buff, blip_sample_t * dest,
long max_samples, int stereo );
/* Additional optional features */
/* Set frequency high-pass filter frequency, where higher values reduce bass more */
void blip_buffer_set_bass_freq( Blip_Buffer * buff, int frequency );
/* Remove all available samples and clear buffer to silence. If 'entire_buffer' is
false, just clears out any samples waiting rather than the entire buffer.
*/
void blip_buffer_clear( Blip_Buffer * buff, int entire_buffer );
/* Number of samples available for reading with read_samples()
*/
long
blip_buffer_samples_avail( Blip_Buffer * buff );
/* Remove 'count' samples from those waiting to be read
*/
void blip_buffer_remove_samples( Blip_Buffer * buff, long count );
/* Experimental features */
void blip_buffer_remove_silence( Blip_Buffer * buff, long count );
blip_resampled_time_t blip_buffer_clock_rate_factor( Blip_Buffer * buff,
long clock_rate );
/*
Number of bits in resample ratio fraction. Higher values give a more accurate ratio
but reduce maximum buffer size.
*/
#ifndef BLIP_BUFFER_ACCURACY
#define BLIP_BUFFER_ACCURACY 16
#endif
/*
Number bits in phase offset. Fewer than 6 bits (64 phase offsets) results in
noticeable broadband noise when synthesizing high frequency square waves.
Affects size of Blip_Synth objects since they store the waveform directly.
*/
#ifndef BLIP_PHASE_BITS
#define BLIP_PHASE_BITS 6
#endif
/* Internal */
#define BLIP_WIDEST_IMPULSE_ 16
#define BLIP_RES (1 << BLIP_PHASE_BITS)
struct blip_eq_s;
typedef struct Blip_Synth_s_ {
double volume_unit_;
short *impulses;
long kernel_unit;
Blip_Buffer *buf;
int last_amp;
int delta_factor;
} Blip_Synth_;
int _blip_synth_impulses_size( Blip_Synth_ * synth_ );
void _blip_synth_adjust_impulse( Blip_Synth_ * synth_ );
void _blip_synth_treble_eq( Blip_Synth_ * synth_, struct blip_eq_s *eq );
void _blip_synth_volume_unit( Blip_Synth_ * synth_, double v );
/* Quality level. Start with blip_good_quality. */
#define BLIP_MED_QUALITY 8
#define BLIP_GOOD_QUALITY 12
#define BLIP_HIGH_QUALITY 16
/* Range specifies the greatest expected change in amplitude. Calculate it
by finding the difference between the maximum and minimum expected
amplitudes (max - min). */
typedef short imp_t;
typedef struct Blip_Synth_s {
imp_t *impulses;
Blip_Synth_ impl;
} Blip_Synth;
void blip_synth_set_volume( Blip_Synth * synth, double v );
/* Configure low-pass filter (see notes.txt)*/
void blip_synth_set_treble_eq( Blip_Synth * synth, double treble );
/* Get/set Blip_Buffer used for output */
void blip_synth_set_output( Blip_Synth * synth, Blip_Buffer * b );
/* Update amplitude of waveform at given time. Using this requires a separate
Blip_Synth for each waveform. */
void blip_synth_update( Blip_Synth * synth, blip_time_t time,
int amplitude );
/* Low-level interface */
void blip_synth_offset_resampled( Blip_Synth * synth,
blip_resampled_time_t, int delta,
Blip_Buffer * buff );
Blip_Synth *new_Blip_Synth( void );
void delete_Blip_Synth( Blip_Synth ** synth );
#define BLIP_EQ_DEF_CUTOFF 0
/* Low-pass equalization parameters */
typedef struct blip_eq_s {
double treble;
long rolloff_freq;
long sample_rate;
long cutoff_freq;
} blip_eq_t;
#define BLIP_SAMPLE_BITS 30
/* End of public interface */
#define BLIP_UNSCALED 65535
inline long blip_buffer_samples_avail( Blip_Buffer * buff );
inline void blip_buffer_set_clock_rate( Blip_Buffer * buff, long cps );
#define BLIP_MAX_LENGTH 0
#define BLIP_SYNTH_QUALITY BLIP_GOOD_QUALITY
#define BLIP_SYNTH_RANGE BLIP_UNSCALED
#define BLIP_SYNTH_WIDTH BLIP_SYNTH_QUALITY /* `quality' of synth as `width' of synth_ */
#endif

View File

@ -114,7 +114,6 @@ int tape_init( void )
so we can't update the statusbar */
tape_playing = 0;
tape_microphone = 0;
if( settings_current.sound_load ) sound_beeper( 1, tape_microphone );
return 0;
}
@ -620,10 +619,6 @@ tape_play( int autoplay )
/* Update the status bar */
ui_statusbar_update( UI_STATUSBAR_ITEM_TAPE, UI_STATUSBAR_STATE_ACTIVE );
/* Timex machines have no loading noise */
if( ( !( machine_current->timex ) ) && settings_current.sound_load )
sound_beeper( 1, tape_microphone );
/* If we're fastloading, turn sound off */
if( settings_current.fastload ) sound_pause();
@ -854,10 +849,6 @@ tape_next_edge( libspectrum_dword last_tstates, int type, void *user_data )
} else {
tape_microphone = !tape_microphone;
}
/* Timex machines have no loading noise */
if( !machine_current->timex && settings_current.sound_load )
sound_beeper( 1, tape_microphone );
}
/* If we've been requested to stop the tape, do so and then

File diff suppressed because it is too large Load Diff

View File

@ -41,10 +41,13 @@ static const char *classPathName = LIB_CLASS;
int fuse_init_done = 0;
JNIEnv* cenv = NULL;
int needRedraw = 0;
int global_event_type;
int global_event_value;
int global_event_type = 0;
int global_event_value = 0;
JNIEnv* cenv = NULL;
jclass nclass;
int mWidth = 0;
int mHeight = 0;
@ -63,18 +66,22 @@ resize(JNIEnv *env, jobject thiz, jint width, jint height, jboolean scaling) {
mHeight = height;
mScaling = scaling;
jclass cls = (*cenv)->FindClass(cenv, classPathName);
jfieldID sfid = (*cenv)->GetStaticFieldID(cenv, cls, "soundEnabled", "Z");
settings_current.sound = (*cenv)->GetStaticBooleanField(cenv, cls, sfid);
nclass = (*cenv)->FindClass(cenv, classPathName);
jfieldID sfid = (*cenv)->GetStaticFieldID(cenv, nclass, "soundEnabled", "Z");
settings_current.sound = (*cenv)->GetStaticBooleanField(cenv, nclass, sfid);
jfieldID rfid = (*cenv)->GetStaticFieldID(cenv, nclass, "skipFrames", "Z");
settings_current.frame_rate = (*cenv)->GetStaticBooleanField(cenv, nclass, rfid) + 1;
jboolean isCopy;
jfieldID mfid = (*cenv)->GetStaticFieldID(cenv, cls, "currentMachine", "Ljava/lang/String;");
jstring machineId = (*cenv)->GetStaticObjectField(cenv, cls, mfid);
jfieldID mfid = (*cenv)->GetStaticFieldID(cenv, nclass, "currentMachine", "Ljava/lang/String;");
jstring machineId = (*cenv)->GetStaticObjectField(cenv, nclass, mfid);
char *current_machine = (char*) (*cenv)->GetStringUTFChars(cenv, machineId, &isCopy);
if (!fuse_init_done) {
char * argv[8] = { "fuse", "--kempston", "--sound-freq", "11025", "--machine", current_machine };
char * argv[16] = { "fuse", "--kempston", "--sound-freq", "11025", "--machine", current_machine };
int argc = 6;
if (!settings_current.sound) {
@ -82,15 +89,6 @@ resize(JNIEnv *env, jobject thiz, jint width, jint height, jboolean scaling) {
argc++;
}
/*
FILE *fp = fopen(CURRENT_SNAPSHOT, "r");
if( fp ) {
argv[argc] = CURRENT_SNAPSHOT;
argc++;
fclose(fp);
}
*/
fuse_init_done = !fuse_init(argc,argv);
} else {
@ -110,6 +108,7 @@ resize(JNIEnv *env, jobject thiz, jint width, jint height, jboolean scaling) {
void
render(JNIEnv *env, jobject thiz, jint event) {
if (event) {
global_event_type = ((int)event/1000)*1000;
global_event_value = event%1000;
@ -126,23 +125,17 @@ render(JNIEnv *env, jobject thiz, jint event) {
void
quit(JNIEnv *env, jobject thiz) {
cenv = env;
//snapshot_write(CURRENT_SNAPSHOT);
fuse_emulation_pause();
snapshot_write(LAST_SNAPSHOT);
fuse_end();
fuse_init_done = 0;
exit(0);
}
jstring
cmachine(JNIEnv *env, jobject thiz) {
return (*env)->NewStringUTF(env, machine_current->id);
}
static JNINativeMethod methods[] = {
{"resize", "(IIZ)V", (void*)resize },
{"render", "(I)V", (void*)render },
{"quit", "()V", (void*)quit },
{"cmachine", "()Ljava/lang/String;", (void*)cmachine },
};
static int registerNativeMethods(JNIEnv* env, const char* className, JNINativeMethod* gMethods, int numMethods)

View File

@ -28,8 +28,10 @@
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, "zxdroid", __VA_ARGS__)
extern JNIEnv* cenv;
extern jclass nclass;
extern int global_event_type;
extern int global_event_value;
extern int needRedraw;
int mWidth, mHeight, mScaling;
extern int global_event_type, global_event_value;
extern int mWidth, mHeight, mScaling;

View File

@ -53,8 +53,6 @@ uint16_t *display_screen=NULL;
int ip, cx, cy, mx, my, mw, mh;
uint16_t *part_screen=NULL;
int needRedraw;
static int image_width = 320;
static int image_height = 240;
@ -166,7 +164,6 @@ static int androiddisplay_load_gfx_mode( void ) {
/* Redraw the entire screen... */
display_refresh_all();
return 0;
}
@ -176,7 +173,9 @@ void uidisplay_frame_end( void ) {
mh -= my;
if (mx==-1 || my==-1 || mw==-1 || mh==-1) {
//noop
} else if (mx==0 && my==0 && mw==image_width && mh==image_height) {
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, image_width, image_height, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, display_screen);

View File

@ -32,7 +32,6 @@ typedef struct ANDROID_Color {
int8_t unused;
} ANDROID_Color;
extern int needRedraw;
extern int uidisplay_init( int width, int height );
#endif /* #ifndef FUSE_ANDROIDDISPLAY_H */

View File

@ -26,7 +26,8 @@
#include "settings.h"
#include "machine.h"
#define HIFI_FREQ 88200
jclass aclass;
jmethodID ainit, adestroy, awrite;
jshortArray sndBuff;
jint sndBuffSize;
@ -36,15 +37,24 @@ static const char *aclassPathName = AUDIO_CLASS;
int
sound_lowlevel_init( const char *device, int *freqptr, int *stereoptr )
{
jclass aclass = (*cenv)->FindClass(cenv, aclassPathName);
jmethodID ainit = (*cenv)->GetStaticMethodID(cenv, aclass, "init", "(II)I");
float hz;
aclass = (*cenv)->FindClass(cenv, aclassPathName);
ainit = (*cenv)->GetStaticMethodID(cenv, aclass, "init", "(II)I");
adestroy = (*cenv)->GetStaticMethodID(cenv, aclass, "destroy", "()V");
awrite = (*cenv)->GetStaticMethodID(cenv, aclass, "write", "([SI)V");
(*cenv)->CallStaticIntMethod(cenv, aclass, ainit, *freqptr, *stereoptr);
sndBuffSize = (settings_current.sound_hifi ? HIFI_FREQ : settings_current.sound_freq) /
(( float ) machine_current->timings.processor_speed / machine_current->timings.tstates_per_frame) *
( *stereoptr ? 2 : 1 );
hz = (float)sound_get_effective_processor_speed() /
machine_current->timings.tstates_per_frame;
if( hz > 100.0 ) hz = 100.0;
sndBuffSize = *freqptr / hz * ( *stereoptr ? 2 : 1 );
sndBuffSize++;
LOGI("freqptr %i, stereoptr %i, hz %f, sndBuffSize %i:", *freqptr, *stereoptr, hz, sndBuffSize);
sndBuff = (*cenv)->NewGlobalRef(cenv, (*cenv)->NewShortArray(cenv, sndBuffSize));
return 0;
@ -53,11 +63,7 @@ sound_lowlevel_init( const char *device, int *freqptr, int *stereoptr )
void
sound_lowlevel_end( void )
{
jclass aclass = (*cenv)->FindClass(cenv, aclassPathName);
jmethodID adestroy = (*cenv)->GetStaticMethodID(cenv, aclass, "destroy", "()V");
(*cenv)->CallStaticVoidMethod(cenv, aclass, adestroy);
(*cenv)->DeleteGlobalRef(cenv, sndBuff);
sndBuffSize = 0;
}
@ -65,9 +71,8 @@ sound_lowlevel_end( void )
void
sound_lowlevel_frame( libspectrum_signed_word *data, int len )
{
jclass aclass = (*cenv)->FindClass(cenv, aclassPathName);
jmethodID awrite = (*cenv)->GetStaticMethodID(cenv, aclass, "write", "([SI)V");
// LOGI("len %i", len);
// LOGI("data: %i %i %i %i %i %i %i", data[0], data[1], data[2], data[3], data[4], data[5], data[6]);
(*cenv)->SetShortArrayRegion(cenv, sndBuff, 0, len, (jshort*) data);
(*cenv)->CallStaticVoidMethod(cenv, aclass, awrite, sndBuff, len);
}

View File

@ -41,6 +41,11 @@
#include "androidui.h"
#include "menu.h"
void ui_set_current_machine() {
jmethodID mid = (*cenv)->GetStaticMethodID(cenv, nclass, "setCurrentMachine", "(Ljava/lang/String;)V");
(*cenv)->CallStaticVoidMethod(cenv, nclass, mid, (*cenv)->NewStringUTF(cenv, machine_current->id));
}
int
ui_init( int *argc, char ***argv )
{
@ -63,8 +68,12 @@ ui_event( void ) {
break;
case MENU_EVENT:
switch (global_event_value) {
case 0:
needRedraw = 1;
break;
case MENU_FILE_OPEN:
menu_file_open(0);
ui_set_current_machine();
break;
case MENU_FILE_SAVESNAPSHOT:
menu_file_savesnapshot(0);
@ -89,27 +98,21 @@ ui_event( void ) {
}
char * ui_get_open_filename( const char *title ) {
static const char *classPathName = LIB_CLASS;
jboolean isCopy;
jstring openFileName;
jclass cls = (*cenv)->FindClass(cenv, classPathName);
jfieldID fid = (*cenv)->GetStaticFieldID(cenv, cls, "openFileName", "Ljava/lang/String;");
openFileName = (*cenv)->GetStaticObjectField(cenv, cls, fid);
jfieldID fid = (*cenv)->GetStaticFieldID(cenv, nclass, "openFileName", "Ljava/lang/String;");
openFileName = (*cenv)->GetStaticObjectField(cenv, nclass, fid);
return (char*) (*cenv)->GetStringUTFChars(cenv, openFileName, &isCopy);
}
char * ui_get_save_filename( const char *title ) {
static const char *classPathName = LIB_CLASS;
jboolean isCopy;
jstring saveFileName;
jclass cls = (*cenv)->FindClass(cenv, classPathName);
jfieldID fid = (*cenv)->GetStaticFieldID(cenv, cls, "saveFileName", "Ljava/lang/String;");
saveFileName = (*cenv)->GetStaticObjectField(cenv, cls, fid);
jfieldID fid = (*cenv)->GetStaticFieldID(cenv, nclass, "saveFileName", "Ljava/lang/String;");
saveFileName = (*cenv)->GetStaticObjectField(cenv, nclass, fid);
return (char*) (*cenv)->GetStringUTFChars(cenv, saveFileName, &isCopy);
}
@ -130,7 +133,7 @@ ui_end( void )
}
int ui_statusbar_update_speed( float speed ) {
LOGI("%f", speed);
//LOGI("%f", speed);
return 0;
}

View File

@ -1,7 +1,7 @@
/* ula.c: ULA routines
Copyright (c) 1999-2008 Philip Kendall, Darren Salt
$Id: ula.c 3532 2008-02-28 14:21:50Z pak21 $
$Id: ula.c 4021 2009-05-29 13:39:51Z fredm $
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -93,12 +93,7 @@ ula_write( libspectrum_word port GCC_UNUSED, libspectrum_byte b )
last_byte = b;
display_set_lores_border( b & 0x07 );
sound_beeper( 0, b & 0x10 );
/* FIXME: I don't think we should have to worry about whether the tape
is playing here, but if we don't do this and use normal speed tape
loading with tape noise, this will intefere with the generation of
the normal loading noises at the moment */
if( !tape_playing ) sound_beeper( 1, b & 0x8 );
sound_beeper( (!!(b & 0x10) << 1) + ( !(b & 0x8) | tape_microphone ) );
/* FIXME: shouldn't really be using the memory capabilities here */

View File

@ -0,0 +1,182 @@
/* ula.c: ULA routines
Copyright (c) 1999-2008 Philip Kendall, Darren Salt
$Id: ula.c 3532 2008-02-28 14:21:50Z pak21 $
This program 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 2 of the License, or
(at your option) any later version.
This program 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 this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Author contact information:
E-mail: philip-fuse@shadowmagic.org.uk
*/
#include <config.h>
#include <libspectrum.h>
#include "compat.h"
#include "keyboard.h"
#include "loader.h"
#include "machine.h"
#include "module.h"
#include "settings.h"
#include "sound.h"
#include "spectrum.h"
#include "tape.h"
#include "ula.h"
static libspectrum_byte last_byte;
libspectrum_byte ula_contention[ ULA_CONTENTION_SIZE ];
libspectrum_byte ula_contention_no_mreq[ ULA_CONTENTION_SIZE ];
/* What to return if no other input pressed; depends on the last byte
output to the ULA; see CSS FAQ | Technical Information | Port #FE
for full details */
libspectrum_byte ula_default_value;
static void ula_from_snapshot( libspectrum_snap *snap );
static void ula_to_snapshot( libspectrum_snap *snap );
static module_info_t ula_module_info = {
NULL,
NULL,
NULL,
ula_from_snapshot,
ula_to_snapshot,
};
int
ula_init( void )
{
module_register( &ula_module_info );
ula_default_value = 0xff;
return 0;
}
libspectrum_byte
ula_read( libspectrum_word port, int *attached )
{
libspectrum_byte r = ula_default_value;
*attached = 1;
loader_detect_loader();
r &= keyboard_read( port >> 8 );
if( tape_microphone ) r ^= 0x40;
return r;
}
/* What happens when we write to the ULA? */
void
ula_write( libspectrum_word port GCC_UNUSED, libspectrum_byte b )
{
last_byte = b;
display_set_lores_border( b & 0x07 );
sound_beeper( 0, b & 0x10 );
/* FIXME: I don't think we should have to worry about whether the tape
is playing here, but if we don't do this and use normal speed tape
loading with tape noise, this will intefere with the generation of
the normal loading noises at the moment */
if( !tape_playing ) sound_beeper( 1, b & 0x8 );
/* FIXME: shouldn't really be using the memory capabilities here */
if( machine_current->timex ) {
ula_default_value = 0x5f;
} else if( machine_current->capabilities & LIBSPECTRUM_MACHINE_CAPABILITY_PLUS3_MEMORY ) {
ula_default_value = 0xbf;
} else if( machine_current->capabilities & LIBSPECTRUM_MACHINE_CAPABILITY_128_MEMORY || !settings_current.issue2 ) {
/* 128K always acts like an Issue 3 */
ula_default_value = b & 0x10 ? 0xff : 0xbf;
} else {
/* Issue 2 */
ula_default_value = b & 0x18 ? 0xff : 0xbf;
}
}
libspectrum_byte
ula_last_byte( void )
{
return last_byte;
}
libspectrum_byte
ula_tape_level( void )
{
return last_byte & 0x8;
}
static void
ula_from_snapshot( libspectrum_snap *snap )
{
ula_write( 0x00fe, libspectrum_snap_out_ula( snap ) );
tstates = libspectrum_snap_tstates( snap );
settings_current.issue2 = libspectrum_snap_issue2( snap );
}
static void
ula_to_snapshot( libspectrum_snap *snap )
{
libspectrum_snap_set_out_ula( snap, last_byte );
libspectrum_snap_set_tstates( snap, tstates );
libspectrum_snap_set_issue2( snap, settings_current.issue2 );
}
void
ula_contend_port_early( libspectrum_word port )
{
if( memory_map_read[ port >> 13 ].contended )
tstates += ula_contention_no_mreq[ tstates ];
tstates++;
}
void
ula_contend_port_late( libspectrum_word port )
{
if( machine_current->ram.port_from_ula( port ) ) {
tstates += ula_contention_no_mreq[ tstates ]; tstates += 2;
} else {
if( memory_map_read[ port >> 13 ].contended ) {
tstates += ula_contention_no_mreq[ tstates ]; tstates++;
tstates += ula_contention_no_mreq[ tstates ]; tstates++;
tstates += ula_contention_no_mreq[ tstates ];
} else {
tstates += 2;
}
}
}

View File

@ -1,48 +0,0 @@
--- fuse.c 2010-03-20 08:55:12.000000000 +0700
+++ fuse.c~ 2010-03-25 07:57:57.000000000 +0700
@@ -126,10 +126,7 @@
} start_files_t;
-#ifdef ANDROID
-#else
static int fuse_init(int argc, char **argv);
-#endif
static int creator_init( void );
static void fuse_show_copyright(void);
@@ -141,10 +138,7 @@
start_files_t *start_files );
static int do_start_files( start_files_t *start_files );
-#ifdef ANDROID
-#else
static int fuse_end(void);
-#endif
#ifdef UI_WIN32
int fuse_main(int argc, char **argv)
@@ -184,11 +178,7 @@
#include "mempool.h"
-#ifdef ANDROID
-int fuse_init(int argc, char **argv)
-#else
static int fuse_init(int argc, char **argv)
-#endif
{
int error, first_arg;
char *start_scaler;
@@ -772,11 +762,7 @@
}
/* Tidy-up function called at end of emulation */
-#ifdef ANDROID
-fuse_end(void)
-#else
static int fuse_end(void)
-#endif
{
/* Must happen before memory is deallocated as we read the character
set from memory for the text output */

View File

@ -798,6 +798,11 @@ libspectrum_byte WIN32_DLL * libspectrum_snap_divide_eprom( libspectrum_snap *sn
void WIN32_DLL libspectrum_snap_set_divide_eprom( libspectrum_snap *snap, int idx, libspectrum_byte* divide_eprom );
libspectrum_byte WIN32_DLL * libspectrum_snap_divide_ram( libspectrum_snap *snap, int idx );
void WIN32_DLL libspectrum_snap_set_divide_ram( libspectrum_snap *snap, int idx, libspectrum_byte* divide_ram );
int WIN32_DLL libspectrum_snap_fuller_box_active( libspectrum_snap *snap );
void WIN32_DLL libspectrum_snap_set_fuller_box_active( libspectrum_snap *snap, int fuller_box_active );
int WIN32_DLL libspectrum_snap_melodik_active( libspectrum_snap *snap );
void WIN32_DLL libspectrum_snap_set_melodik_active( libspectrum_snap *snap, int
melodik_active );
/*
* Tape handling routines

View File

@ -1,7 +1,7 @@
/* sna.c: Routines for handling .sna snapshots
Copyright (c) 2001-2002 Philip Kendall
$Id: sna.c 3784 2008-10-22 12:36:07Z fredm $
$Id: sna.c 4034 2009-06-11 12:58:26Z fredm $
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -318,6 +318,11 @@ libspectrum_sna_write( libspectrum_byte **buffer, size_t *length,
if( libspectrum_snap_custom_rom( snap ) )
*out_flags |= LIBSPECTRUM_FLAG_SNAPSHOT_MAJOR_INFO_LOSS;
/* We don't save AY interfaces at all */
if( libspectrum_snap_fuller_box_active( snap ) ||
libspectrum_snap_melodik_active( snap ) )
*out_flags |= LIBSPECTRUM_FLAG_SNAPSHOT_MAJOR_INFO_LOSS;
ptr = *buffer;
write_header( buffer, &ptr, length, snap );

View File

@ -0,0 +1,482 @@
/* sna.c: Routines for handling .sna snapshots
Copyright (c) 2001-2002 Philip Kendall
$Id: sna.c 3784 2008-10-22 12:36:07Z fredm $
This program 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 2 of the License, or
(at your option) any later version.
This program 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 this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Author contact information:
E-mail: philip-fuse@shadowmagic.org.uk
*/
#include <config.h>
#include <string.h>
#include "internals.h"
#define LIBSPECTRUM_SNA_HEADER_LENGTH 27
#define LIBSPECTRUM_SNA_128_HEADER_LENGTH 4
#define SNA_OFFSET_SP 23
static int identify_machine( size_t buffer_length, libspectrum_snap *snap );
static int libspectrum_sna_read_header( const libspectrum_byte *buffer,
size_t buffer_length,
libspectrum_snap *snap );
static int libspectrum_sna_read_data( const libspectrum_byte *buffer,
size_t buffer_length,
libspectrum_snap *snap );
static int libspectrum_sna_read_128_header( const libspectrum_byte *buffer,
size_t buffer_length,
libspectrum_snap *snap );
static int libspectrum_sna_read_128_data( const libspectrum_byte *buffer,
size_t buffer_length,
libspectrum_snap *snap );
static void
write_header( libspectrum_byte **buffer, libspectrum_byte **ptr,
size_t *length, libspectrum_snap *snap );
static libspectrum_error
write_48k_sna( libspectrum_byte **buffer, libspectrum_byte **ptr,
size_t *length, libspectrum_snap *snap );
static libspectrum_error
write_128k_sna( libspectrum_byte **buffer, libspectrum_byte **ptr,
size_t *length, libspectrum_snap *snap );
static libspectrum_error
write_page( libspectrum_byte *buffer, libspectrum_snap *snap, int page );
libspectrum_error
internal_sna_read( libspectrum_snap *snap,
const libspectrum_byte *buffer, size_t buffer_length )
{
int error;
error = identify_machine( buffer_length, snap );
if( error != LIBSPECTRUM_ERROR_NONE ) return error;
error = libspectrum_sna_read_header( buffer, buffer_length, snap );
if( error != LIBSPECTRUM_ERROR_NONE ) return error;
error = libspectrum_sna_read_data(
&buffer[LIBSPECTRUM_SNA_HEADER_LENGTH],
buffer_length - LIBSPECTRUM_SNA_HEADER_LENGTH, snap );
if( error != LIBSPECTRUM_ERROR_NONE ) return error;
return LIBSPECTRUM_ERROR_NONE;
}
static int
identify_machine( size_t buffer_length, libspectrum_snap *snap )
{
switch( buffer_length ) {
case 49179:
libspectrum_snap_set_machine( snap, LIBSPECTRUM_MACHINE_48 );
break;
case 131103:
case 147487:
libspectrum_snap_set_machine( snap, LIBSPECTRUM_MACHINE_PENT );
break;
default:
libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
"libspectrum_sna_identify: unknown length" );
return LIBSPECTRUM_ERROR_CORRUPT;
}
return LIBSPECTRUM_ERROR_NONE;
}
static int
libspectrum_sna_read_header( const libspectrum_byte *buffer,
size_t buffer_length, libspectrum_snap *snap )
{
int iff;
if( buffer_length < LIBSPECTRUM_SNA_HEADER_LENGTH ) {
libspectrum_print_error(
LIBSPECTRUM_ERROR_CORRUPT,
"libspectrum_sna_read_header: not enough data in buffer"
);
return LIBSPECTRUM_ERROR_CORRUPT;
}
libspectrum_snap_set_a ( snap, buffer[22] );
libspectrum_snap_set_f ( snap, buffer[21] );
libspectrum_snap_set_bc ( snap, buffer[13] + buffer[14]*0x100 );
libspectrum_snap_set_de ( snap, buffer[11] + buffer[12]*0x100 );
libspectrum_snap_set_hl ( snap, buffer[ 9] + buffer[10]*0x100 );
libspectrum_snap_set_a_ ( snap, buffer[ 8] );
libspectrum_snap_set_f_ ( snap, buffer[ 7] );
libspectrum_snap_set_bc_( snap, buffer[ 5] + buffer[ 6]*0x100 );
libspectrum_snap_set_de_( snap, buffer[ 3] + buffer[ 4]*0x100 );
libspectrum_snap_set_hl_( snap, buffer[ 1] + buffer[ 2]*0x100 );
libspectrum_snap_set_ix ( snap, buffer[17] + buffer[18]*0x100 );
libspectrum_snap_set_iy ( snap, buffer[15] + buffer[16]*0x100 );
libspectrum_snap_set_i ( snap, buffer[ 0] );
libspectrum_snap_set_r ( snap, buffer[20] );
libspectrum_snap_set_pc ( snap, buffer[ 6] + buffer[ 7]*0x100 );
libspectrum_snap_set_sp ( snap, buffer[23] + buffer[24]*0x100 );
iff = ( buffer[19] & 0x04 ) ? 1 : 0;
libspectrum_snap_set_iff1( snap, iff );
libspectrum_snap_set_iff2( snap, iff );
libspectrum_snap_set_im( snap, buffer[25] & 0x03 );
libspectrum_snap_set_out_ula( snap, buffer[26] & 0x07 );
return LIBSPECTRUM_ERROR_NONE;
}
static int
libspectrum_sna_read_data( const libspectrum_byte *buffer,
size_t buffer_length, libspectrum_snap *snap )
{
int error, page, i;
libspectrum_word sp, offset;
if( buffer_length < 0xc000 ) {
libspectrum_print_error(
LIBSPECTRUM_ERROR_CORRUPT,
"libspectrum_sna_read_data: not enough data in buffer"
);
return LIBSPECTRUM_ERROR_CORRUPT;
}
switch( libspectrum_snap_machine( snap ) ) {
case LIBSPECTRUM_MACHINE_48:
sp = libspectrum_snap_sp( snap );
if( sp < 0x4000 || sp == 0xffff ) {
libspectrum_print_error(
LIBSPECTRUM_ERROR_CORRUPT,
"libspectrum_sna_read_data: SP invalid (0x%04x)", sp
);
return LIBSPECTRUM_ERROR_CORRUPT;
}
/* Rescue PC from the stack */
offset = sp - 0x4000;
libspectrum_snap_set_pc( snap, buffer[offset] + 0x100 * buffer[offset+1] );
/* Increase SP as PC has been unstacked */
libspectrum_snap_set_sp( snap, libspectrum_snap_sp( snap ) + 2 );
/* And split the pages up */
error = libspectrum_split_to_48k_pages( snap, buffer );
if( error != LIBSPECTRUM_ERROR_NONE ) return error;
break;
case LIBSPECTRUM_MACHINE_PENT:
for( i=0; i<8; i++ ) {
libspectrum_byte *ram = libspectrum_malloc( 0x4000 * sizeof( *ram ) );
libspectrum_snap_set_pages( snap, i, ram );
}
memcpy( libspectrum_snap_pages( snap, 5 ), &buffer[0x0000], 0x4000 );
memcpy( libspectrum_snap_pages( snap, 2 ), &buffer[0x4000], 0x4000 );
error = libspectrum_sna_read_128_header( buffer + 0xc000,
buffer_length - 0xc000, snap );
if( error != LIBSPECTRUM_ERROR_NONE ) return error;
page = libspectrum_snap_out_128_memoryport( snap ) & 0x07;
if( page == 5 || page == 2 ) {
if( memcmp( libspectrum_snap_pages( snap, page ),
&buffer[0x8000], 0x4000 ) ) {
libspectrum_print_error(
LIBSPECTRUM_ERROR_CORRUPT,
"libspectrum_sna_read_data: duplicated page not identical"
);
return LIBSPECTRUM_ERROR_CORRUPT;
}
} else {
memcpy( libspectrum_snap_pages( snap, page ), &buffer[0x8000], 0x4000 );
}
buffer += 0xc000 + LIBSPECTRUM_SNA_128_HEADER_LENGTH;
buffer_length -= 0xc000 + LIBSPECTRUM_SNA_128_HEADER_LENGTH;
error = libspectrum_sna_read_128_data( buffer, buffer_length, snap );
if( error != LIBSPECTRUM_ERROR_NONE ) return error;
break;
default:
libspectrum_print_error( LIBSPECTRUM_ERROR_LOGIC,
"libspectrum_sna_read_data: unknown machine" );
return LIBSPECTRUM_ERROR_LOGIC;
}
return LIBSPECTRUM_ERROR_NONE;
}
static int
libspectrum_sna_read_128_header( const libspectrum_byte *buffer,
size_t buffer_length, libspectrum_snap *snap )
{
if( buffer_length < 4 ) {
libspectrum_print_error(
LIBSPECTRUM_ERROR_CORRUPT,
"libspectrum_sna_read_128_header: not enough data in buffer"
);
return LIBSPECTRUM_ERROR_CORRUPT;
}
libspectrum_snap_set_pc( snap, buffer[0] + 0x100 * buffer[1] );
libspectrum_snap_set_out_128_memoryport( snap, buffer[2] );
return LIBSPECTRUM_ERROR_NONE;
}
static int
libspectrum_sna_read_128_data( const libspectrum_byte *buffer,
size_t buffer_length, libspectrum_snap *snap )
{
int i, page;
page = libspectrum_snap_out_128_memoryport( snap ) & 0x07;
for( i=0; i<=7; i++ ) {
if( i==2 || i==5 || i==page ) continue; /* Already got this page */
/* Check we've still got some data to read */
if( buffer_length < 0x4000 ) {
libspectrum_print_error(
LIBSPECTRUM_ERROR_CORRUPT,
"libspectrum_sna_read_128_data: not enough data in buffer"
);
return LIBSPECTRUM_ERROR_CORRUPT;
}
/* Copy the data across */
memcpy( libspectrum_snap_pages( snap, i ), buffer, 0x4000 );
/* And update what we're looking at here */
buffer += 0x4000; buffer_length -= 0x4000;
}
return LIBSPECTRUM_ERROR_NONE;
}
libspectrum_error
libspectrum_sna_write( libspectrum_byte **buffer, size_t *length,
int *out_flags, libspectrum_snap *snap,
int in_flags GCC_UNUSED )
{
libspectrum_error error = LIBSPECTRUM_ERROR_NONE;
libspectrum_byte *ptr;
/* Minor info loss already due to things like tstate count, halted state,
etc which are not stored in .sna format */
*out_flags = LIBSPECTRUM_FLAG_SNAPSHOT_MINOR_INFO_LOSS;
/* We don't store +D info at all */
if( libspectrum_snap_plusd_active( snap ) )
*out_flags |= LIBSPECTRUM_FLAG_SNAPSHOT_MAJOR_INFO_LOSS;
/* We don't store Beta info at all */
if( libspectrum_snap_beta_active( snap ) )
*out_flags |= LIBSPECTRUM_FLAG_SNAPSHOT_MAJOR_INFO_LOSS;
/* We don't save IDE interface info at all */
if( libspectrum_snap_zxatasp_active( snap ) )
*out_flags |= LIBSPECTRUM_FLAG_SNAPSHOT_MAJOR_INFO_LOSS;
if( libspectrum_snap_zxcf_active( snap ) )
*out_flags |= LIBSPECTRUM_FLAG_SNAPSHOT_MAJOR_INFO_LOSS;
if( libspectrum_snap_simpleide_active( snap ) )
*out_flags |= LIBSPECTRUM_FLAG_SNAPSHOT_MAJOR_INFO_LOSS;
if( libspectrum_snap_divide_active( snap ) )
*out_flags |= LIBSPECTRUM_FLAG_SNAPSHOT_MAJOR_INFO_LOSS;
/* We don't save the Interface II ROM at all */
if( libspectrum_snap_interface2_active( snap ) )
*out_flags |= LIBSPECTRUM_FLAG_SNAPSHOT_MAJOR_INFO_LOSS;
/* We don't save the Timex Dock at all */
if( libspectrum_snap_dock_active( snap ) )
*out_flags |= LIBSPECTRUM_FLAG_SNAPSHOT_MAJOR_INFO_LOSS;
/* We don't save custom ROMs at all */
if( libspectrum_snap_custom_rom( snap ) )
*out_flags |= LIBSPECTRUM_FLAG_SNAPSHOT_MAJOR_INFO_LOSS;
ptr = *buffer;
write_header( buffer, &ptr, length, snap );
switch( libspectrum_snap_machine( snap ) ) {
case LIBSPECTRUM_MACHINE_TC2048:
case LIBSPECTRUM_MACHINE_TC2068:
case LIBSPECTRUM_MACHINE_TS2068:
*out_flags |= LIBSPECTRUM_FLAG_SNAPSHOT_MAJOR_INFO_LOSS;
/* Fall through */
case LIBSPECTRUM_MACHINE_16:
case LIBSPECTRUM_MACHINE_48:
error = write_48k_sna( buffer, &ptr, length, snap );
break;
case LIBSPECTRUM_MACHINE_128:
case LIBSPECTRUM_MACHINE_PENT512:
case LIBSPECTRUM_MACHINE_PENT1024:
case LIBSPECTRUM_MACHINE_PLUS2:
case LIBSPECTRUM_MACHINE_PLUS2A:
case LIBSPECTRUM_MACHINE_PLUS3:
case LIBSPECTRUM_MACHINE_PLUS3E:
case LIBSPECTRUM_MACHINE_SCORP:
case LIBSPECTRUM_MACHINE_SE:
*out_flags |= LIBSPECTRUM_FLAG_SNAPSHOT_MAJOR_INFO_LOSS;
/* Fall through */
case LIBSPECTRUM_MACHINE_PENT:
error = write_128k_sna( buffer, &ptr, length, snap );
break;
case LIBSPECTRUM_MACHINE_UNKNOWN:
libspectrum_print_error( LIBSPECTRUM_ERROR_LOGIC,
"Emulated machine type is set to 'unknown'!" );
return LIBSPECTRUM_ERROR_LOGIC;
}
if( error ) return error;
/* Set length to be actual length, not allocated length */
*length = ptr - *buffer;
return LIBSPECTRUM_ERROR_NONE;
}
static void
write_header( libspectrum_byte **buffer, libspectrum_byte **ptr,
size_t *length, libspectrum_snap *snap )
{
libspectrum_make_room( buffer, LIBSPECTRUM_SNA_HEADER_LENGTH, ptr, length );
*(*ptr)++ = libspectrum_snap_i ( snap );
libspectrum_write_word( ptr, libspectrum_snap_hl_( snap ) );
libspectrum_write_word( ptr, libspectrum_snap_de_( snap ) );
libspectrum_write_word( ptr, libspectrum_snap_bc_( snap ) );
*(*ptr)++ = libspectrum_snap_f_( snap );
*(*ptr)++ = libspectrum_snap_a_( snap );
libspectrum_write_word( ptr, libspectrum_snap_hl ( snap ) );
libspectrum_write_word( ptr, libspectrum_snap_de ( snap ) );
libspectrum_write_word( ptr, libspectrum_snap_bc ( snap ) );
libspectrum_write_word( ptr, libspectrum_snap_iy ( snap ) );
libspectrum_write_word( ptr, libspectrum_snap_ix ( snap ) );
*(*ptr)++ = libspectrum_snap_iff2( snap ) ? 0x04 : 0x00;
*(*ptr)++ = libspectrum_snap_r ( snap );
*(*ptr)++ = libspectrum_snap_f ( snap );
*(*ptr)++ = libspectrum_snap_a ( snap );
libspectrum_write_word( ptr, libspectrum_snap_sp ( snap ) );
*(*ptr)++ = libspectrum_snap_im( snap );
*(*ptr)++ = libspectrum_snap_out_ula( snap ) & 0x07;
}
static libspectrum_error
write_48k_sna( libspectrum_byte **buffer, libspectrum_byte **ptr,
size_t *length, libspectrum_snap *snap )
{
libspectrum_error error;
libspectrum_byte *stack, *sp;
/* Must have somewhere in RAM to store PC */
if( libspectrum_snap_sp( snap ) < 0x4002 ) {
libspectrum_print_error( LIBSPECTRUM_ERROR_INVALID,
"SP is too low (0x%04x) to stack PC",
libspectrum_snap_sp( snap ) );
return LIBSPECTRUM_ERROR_INVALID;
}
libspectrum_make_room( buffer, 0xc000, ptr, length );
error = write_page( &( (*ptr)[ 0x0000 ] ), snap, 5 );
if( error ) return error;
error = write_page( &( (*ptr)[ 0x4000 ] ), snap, 2 );
if( error ) return error;
error = write_page( &( (*ptr)[ 0x8000 ] ), snap, 0 );
if( error ) return error;
/* Place PC on the stack */
stack = &( (*ptr)[ libspectrum_snap_sp( snap ) - 0x4000 - 2 ] );
libspectrum_write_word( &stack, libspectrum_snap_pc( snap ) );
*ptr += 0xc000;
/* Store the new value of SP */
sp = *buffer + SNA_OFFSET_SP;
libspectrum_write_word( &sp, libspectrum_snap_sp( snap ) - 2 );
return LIBSPECTRUM_ERROR_NONE;
}
static libspectrum_error
write_128k_sna( libspectrum_byte **buffer, libspectrum_byte **ptr,
size_t *length, libspectrum_snap *snap )
{
size_t i, page; libspectrum_error error;
page = libspectrum_snap_out_128_memoryport( snap ) & 0x07;
libspectrum_make_room( buffer, 0xc000 + LIBSPECTRUM_SNA_128_HEADER_LENGTH,
ptr, length );
error = write_page( *ptr, snap, 5 ); (*ptr) += 0x4000;
if( error ) return error;
error = write_page( *ptr, snap, 2 ); (*ptr) += 0x4000;
if( error ) return error;
error = write_page( *ptr, snap, page ); (*ptr) += 0x4000;
if( error ) return error;
libspectrum_write_word( ptr, libspectrum_snap_pc( snap ) );
*(*ptr)++ = libspectrum_snap_out_128_memoryport( snap );
*(*ptr)++ = '\0';
for( i = 0; i < 8; i++ ) {
/* Already written pages 5, 2 and whatever's paged in */
if( i == 5 || i == 2 || i == page ) continue;
libspectrum_make_room( buffer, 0x4000, ptr, length );
error = write_page( *ptr, snap, i ); (*ptr) += 0x4000;
if( error ) return error;
}
return LIBSPECTRUM_ERROR_NONE;
}
static libspectrum_error
write_page( libspectrum_byte *buffer, libspectrum_snap *snap, int page )
{
libspectrum_byte *ram;
ram = libspectrum_snap_pages( snap, page );
if( ram ) {
memcpy( buffer, ram, 0x4000 );
} else {
memset( buffer, 0xff, 0x4000 );
}
return LIBSPECTRUM_ERROR_NONE;
}

View File

@ -161,6 +161,10 @@ struct libspectrum_snap {
size_t divide_pages;
libspectrum_byte* divide_eprom[ 1 ];
libspectrum_byte* divide_ram[ SNAPSHOT_DIVIDE_PAGES ];
int fuller_box_active;
int melodik_active;
};
/* Initialise a libspectrum_snap structure */
@ -1381,3 +1385,28 @@ libspectrum_snap_set_divide_ram( libspectrum_snap *snap, int idx, libspectrum_by
{
snap->divide_ram[idx] = divide_ram;
}
int
libspectrum_snap_melodik_active( libspectrum_snap *snap )
{
return snap->melodik_active;
}
int
libspectrum_snap_fuller_box_active( libspectrum_snap *snap )
{
return snap->fuller_box_active;
}
void
libspectrum_snap_set_melodik_active( libspectrum_snap *snap, int melodik_active )
{
snap->melodik_active = melodik_active;
}
void
libspectrum_snap_set_fuller_box_active( libspectrum_snap *snap, int fuller_box_active )
{
snap->fuller_box_active = fuller_box_active;
}

View File

@ -144,3 +144,8 @@ libspectrum_byte divide_control
size_t divide_pages
libspectrum_byte* divide_eprom 1
libspectrum_byte* divide_ram 1
int fuller_box_active
int melodik_active

View File

@ -0,0 +1,147 @@
# snap_accessors.txt: simple accessors for libspectrum_snap
# Copyright (c) 2003-2008 Philip Kendall
# $Id: snap_accessors.txt 3608 2008-04-25 01:59:46Z fredm $
# This program 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 2 of the License, or
# (at your option) any later version.
# This program 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 this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
# Author contact information:
# E-mail: philip-fuse@shadowmagic.org.uk
libspectrum_machine machine
libspectrum_byte a
libspectrum_byte f
libspectrum_word bc
libspectrum_word de
libspectrum_word hl
libspectrum_byte a_
libspectrum_byte f_
libspectrum_word bc_
libspectrum_word de_
libspectrum_word hl_
libspectrum_word ix
libspectrum_word iy
libspectrum_byte i
libspectrum_byte r
libspectrum_word sp
libspectrum_word pc
libspectrum_byte iff1
libspectrum_byte iff2
libspectrum_byte im
libspectrum_dword tstates
int halted
int last_instruction_ei
libspectrum_byte out_ula
libspectrum_byte out_128_memoryport
libspectrum_byte out_plus3_memoryport
libspectrum_byte out_ay_registerport
libspectrum_byte ay_registers 1
libspectrum_byte out_scld_hsr
libspectrum_byte out_scld_dec
int interface1_active
int interface1_paged
int interface1_drive_count
int interface1_custom_rom
libspectrum_byte* interface1_rom 1
size_t interface1_rom_length 1
int beta_active
int beta_paged
int beta_custom_rom
int beta_direction
libspectrum_byte beta_system
libspectrum_byte beta_track
libspectrum_byte beta_sector
libspectrum_byte beta_data
libspectrum_byte beta_status
libspectrum_byte* beta_rom 1
int plusd_active
int plusd_paged
int plusd_custom_rom
int plusd_direction
libspectrum_byte plusd_control
libspectrum_byte plusd_track
libspectrum_byte plusd_sector
libspectrum_byte plusd_data
libspectrum_byte plusd_status
libspectrum_byte* plusd_rom 1
libspectrum_byte* plusd_ram 1
int custom_rom
size_t custom_rom_pages
libspectrum_byte* roms 1
size_t rom_length 1
libspectrum_byte* pages 1
libspectrum_byte* slt 1
size_t slt_length 1
libspectrum_byte* slt_screen
int slt_screen_level
int zxatasp_active
int zxatasp_upload
int zxatasp_writeprotect
libspectrum_byte zxatasp_port_a
libspectrum_byte zxatasp_port_b
libspectrum_byte zxatasp_port_c
libspectrum_byte zxatasp_control
size_t zxatasp_pages
size_t zxatasp_current_page
libspectrum_byte* zxatasp_ram 1
int zxcf_active
int zxcf_upload
libspectrum_byte zxcf_memctl
size_t zxcf_pages
libspectrum_byte* zxcf_ram 1
int interface2_active
libspectrum_byte* interface2_rom 1
int dock_active
libspectrum_byte exrom_ram 1
libspectrum_byte* exrom_cart 1
libspectrum_byte dock_ram 1
libspectrum_byte* dock_cart 1
int issue2
size_t joystick_active_count
libspectrum_joystick joystick_list 1
int joystick_inputs 1
int kempston_mouse_active
int simpleide_active
int divide_active
int divide_eprom_writeprotect
int divide_paged
libspectrum_byte divide_control
size_t divide_pages
libspectrum_byte* divide_eprom 1
libspectrum_byte* divide_ram 1

View File

@ -1,7 +1,7 @@
/* snapshot.c: Snapshot handling routines
Copyright (c) 2001-2008 Philip Kendall, Darren Salt
Copyright (c) 2001-2009 Philip Kendall, Darren Salt
$Id: snapshot.c 3701 2008-06-30 20:32:56Z pak21 $
$Id: snapshot.c 4032 2009-06-10 11:09:44Z fredm $
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -182,6 +182,10 @@ libspectrum_snap_alloc( void )
libspectrum_snap_set_divide_ram( snap, i, NULL );
}
libspectrum_snap_set_fuller_box_active( snap, 0 );
libspectrum_snap_set_melodik_active( snap, 0 );
return snap;
}

View File

@ -0,0 +1,392 @@
/* snapshot.c: Snapshot handling routines
Copyright (c) 2001-2008 Philip Kendall, Darren Salt
$Id: snapshot.c 3701 2008-06-30 20:32:56Z pak21 $
This program 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 2 of the License, or
(at your option) any later version.
This program 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 this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Author contact information:
E-mail: philip-fuse@shadowmagic.org.uk
*/
#include <config.h>
#include <string.h>
#include "internals.h"
/* Some flags which may be given to libspectrum_snap_write() */
const int LIBSPECTRUM_FLAG_SNAPSHOT_NO_COMPRESSION = 1 << 0;
const int LIBSPECTRUM_FLAG_SNAPSHOT_ALWAYS_COMPRESS = 1 << 1;
/* Some flags which may be returned from libspectrum_snap_write() */
const int LIBSPECTRUM_FLAG_SNAPSHOT_MINOR_INFO_LOSS = 1 << 0;
const int LIBSPECTRUM_FLAG_SNAPSHOT_MAJOR_INFO_LOSS = 1 << 1;
/* Initialise a libspectrum_snap structure */
libspectrum_snap*
libspectrum_snap_alloc( void )
{
libspectrum_snap *snap;
size_t i;
snap = libspectrum_snap_alloc_internal();
libspectrum_snap_set_a ( snap, 0x00 );
libspectrum_snap_set_f ( snap, 0x00 );
libspectrum_snap_set_bc ( snap, 0x0000 );
libspectrum_snap_set_de ( snap, 0x0000 );
libspectrum_snap_set_hl ( snap, 0x0000 );
libspectrum_snap_set_a_ ( snap, 0x00 );
libspectrum_snap_set_f_ ( snap, 0x00 );
libspectrum_snap_set_bc_ ( snap, 0x0000 );
libspectrum_snap_set_de_ ( snap, 0x0000 );
libspectrum_snap_set_hl_ ( snap, 0x0000 );
libspectrum_snap_set_ix ( snap, 0x0000 );
libspectrum_snap_set_iy ( snap, 0x0000 );
libspectrum_snap_set_i ( snap, 0x00 );
libspectrum_snap_set_r ( snap, 0x00 );
libspectrum_snap_set_sp ( snap, 0x0000 );
libspectrum_snap_set_pc ( snap, 0x0000 );
libspectrum_snap_set_iff1( snap, 1 );
libspectrum_snap_set_iff2( snap, 1 );
libspectrum_snap_set_im ( snap, 1 );
libspectrum_snap_set_halted( snap, 0 );
libspectrum_snap_set_last_instruction_ei( snap, 0 );
libspectrum_snap_set_custom_rom( snap, 0 );
libspectrum_snap_set_custom_rom_pages( snap, 0 );
for( i = 0; i < 4; i++ ) {
libspectrum_snap_set_roms( snap, i, NULL );
libspectrum_snap_set_rom_length( snap, i, 0 );
}
for( i = 0; i < SNAPSHOT_RAM_PAGES; i++ )
libspectrum_snap_set_pages( snap, i, NULL );
for( i = 0; i < SNAPSHOT_SLT_PAGES; i++ ) {
libspectrum_snap_set_slt( snap, i, NULL );
libspectrum_snap_set_slt_length( snap, i, 0 );
}
libspectrum_snap_set_slt_screen( snap, NULL );
libspectrum_snap_set_slt_screen_level( snap, 0 );
libspectrum_snap_set_out_ula( snap, 0x00 );
libspectrum_snap_set_tstates( snap, 69664 );
libspectrum_snap_set_out_128_memoryport( snap, 0x07 );
libspectrum_snap_set_out_ay_registerport( snap, 0x0e );
for( i = 0; i < 16; i++ ) libspectrum_snap_set_ay_registers( snap, i, 0 );
libspectrum_snap_set_out_plus3_memoryport( snap, 0x08 );
libspectrum_snap_set_out_scld_hsr( snap, 0x00 );
libspectrum_snap_set_out_scld_dec( snap, 0x00 );
libspectrum_snap_set_interface1_active( snap, 0 );
libspectrum_snap_set_interface1_paged( snap, 0 );
libspectrum_snap_set_interface1_drive_count( snap, 0 );
libspectrum_snap_set_interface1_custom_rom( snap, 0 );
libspectrum_snap_set_interface1_rom( snap, 0, NULL );
libspectrum_snap_set_interface1_rom_length( snap, 0, 0 );
libspectrum_snap_set_beta_active( snap, 0 );
libspectrum_snap_set_beta_paged( snap, 0 );
libspectrum_snap_set_beta_custom_rom( snap, 0 );
libspectrum_snap_set_beta_direction( snap, 0 );
libspectrum_snap_set_beta_system( snap, 0 );
libspectrum_snap_set_beta_track ( snap, 0 );
libspectrum_snap_set_beta_sector( snap, 0 );
libspectrum_snap_set_beta_data ( snap, 0 );
libspectrum_snap_set_beta_status( snap, 0 );
libspectrum_snap_set_beta_rom( snap, 0, NULL );
libspectrum_snap_set_plusd_active( snap, 0 );
libspectrum_snap_set_plusd_paged( snap, 0 );
libspectrum_snap_set_plusd_custom_rom( snap, 0 );
libspectrum_snap_set_plusd_direction( snap, 0 );
libspectrum_snap_set_plusd_control( snap, 0 );
libspectrum_snap_set_plusd_track ( snap, 0 );
libspectrum_snap_set_plusd_sector( snap, 0 );
libspectrum_snap_set_plusd_data ( snap, 0 );
libspectrum_snap_set_plusd_status( snap, 0 );
libspectrum_snap_set_plusd_rom( snap, 0, NULL );
libspectrum_snap_set_plusd_ram( snap, 0, NULL );
libspectrum_snap_set_zxatasp_active( snap, 0 );
libspectrum_snap_set_zxatasp_upload( snap, 0 );
libspectrum_snap_set_zxatasp_writeprotect( snap, 0 );
libspectrum_snap_set_zxatasp_port_a( snap, 0 );
libspectrum_snap_set_zxatasp_port_b( snap, 0 );
libspectrum_snap_set_zxatasp_port_c( snap, 0 );
libspectrum_snap_set_zxatasp_control( snap, 0 );
libspectrum_snap_set_zxatasp_pages( snap, 0 );
libspectrum_snap_set_zxatasp_current_page( snap, 0 );
for( i = 0; i < SNAPSHOT_ZXATASP_PAGES; i++ )
libspectrum_snap_set_zxatasp_ram( snap, i, NULL );
libspectrum_snap_set_zxcf_active( snap, 0 );
libspectrum_snap_set_zxcf_upload( snap, 0 );
libspectrum_snap_set_zxcf_memctl( snap, 0x00 );
libspectrum_snap_set_zxcf_pages( snap, 0 );
for( i = 0; i < SNAPSHOT_ZXCF_PAGES; i++ )
libspectrum_snap_set_zxcf_ram( snap, i, NULL );
libspectrum_snap_set_interface2_active( snap, 0 );
libspectrum_snap_set_interface2_rom( snap, 0, NULL );
libspectrum_snap_set_dock_active( snap, 0 );
for( i = 0; i < SNAPSHOT_DOCK_EXROM_PAGES; i++ ) {
libspectrum_snap_set_exrom_ram( snap, i, 0 );
libspectrum_snap_set_exrom_cart( snap, i, NULL );
libspectrum_snap_set_dock_ram( snap, i, 0 );
libspectrum_snap_set_dock_cart( snap, i, NULL );
}
libspectrum_snap_set_issue2( snap, 0 );
libspectrum_snap_set_joystick_active_count( snap, 0 );
for( i = 0; i < SNAPSHOT_JOYSTICKS; i++ ) {
libspectrum_snap_set_joystick_list( snap, i, LIBSPECTRUM_JOYSTICK_NONE );
libspectrum_snap_set_joystick_inputs( snap, i, 0 );
}
libspectrum_snap_set_kempston_mouse_active( snap, 0 );
libspectrum_snap_set_simpleide_active( snap, 0 );
libspectrum_snap_set_divide_active( snap, 0 );
libspectrum_snap_set_divide_eprom_writeprotect( snap, 0 );
libspectrum_snap_set_divide_paged( snap, 0 );
libspectrum_snap_set_divide_control( snap, 0 );
libspectrum_snap_set_divide_pages( snap, 0 );
libspectrum_snap_set_divide_eprom( snap, 0, NULL );
for( i = 0; i < SNAPSHOT_DIVIDE_PAGES; i++ ) {
libspectrum_snap_set_divide_ram( snap, i, NULL );
}
return snap;
}
/* Free all memory used by a libspectrum_snap structure (destructor...) */
libspectrum_error
libspectrum_snap_free( libspectrum_snap *snap )
{
size_t i;
for( i = 0; i < 4; i++ )
libspectrum_free( libspectrum_snap_roms( snap, i ) );
for( i = 0; i < SNAPSHOT_RAM_PAGES; i++ )
libspectrum_free( libspectrum_snap_pages( snap, i ) );
for( i = 0; i < SNAPSHOT_SLT_PAGES; i++ )
libspectrum_free( libspectrum_snap_slt( snap, i ) );
libspectrum_free( libspectrum_snap_slt_screen( snap ) );
for( i = 0; i < SNAPSHOT_ZXCF_PAGES; i++ )
libspectrum_free( libspectrum_snap_zxcf_ram( snap, i ) );
libspectrum_free( libspectrum_snap_interface2_rom( snap, 0 ) );
for( i = 0; i < SNAPSHOT_DOCK_EXROM_PAGES; i++ ) {
libspectrum_free( libspectrum_snap_dock_cart( snap, i ) );
libspectrum_free( libspectrum_snap_exrom_cart( snap, i ) );
}
if( libspectrum_snap_beta_rom( snap, 0 ) )
libspectrum_free( libspectrum_snap_beta_rom( snap, 0 ) );
if( libspectrum_snap_plusd_rom( snap, 0 ) )
libspectrum_free( libspectrum_snap_plusd_rom( snap, 0 ) );
if( libspectrum_snap_plusd_ram( snap, 0 ) )
libspectrum_free( libspectrum_snap_plusd_ram( snap, 0 ) );
if( libspectrum_snap_interface1_rom( snap, 0 ) )
libspectrum_free( libspectrum_snap_interface1_rom( snap, 0 ) );
libspectrum_free( snap );
return LIBSPECTRUM_ERROR_NONE;
}
/* Read in a snapshot, optionally guessing what type it is */
libspectrum_error
libspectrum_snap_read( libspectrum_snap *snap, const libspectrum_byte *buffer,
size_t length, libspectrum_id_t type,
const char *filename )
{
libspectrum_id_t raw_type;
libspectrum_class_t class;
libspectrum_byte *new_buffer;
libspectrum_error error;
int uncompressed;
/* If we don't know what sort of file this is, make a best guess */
if( type == LIBSPECTRUM_ID_UNKNOWN ) {
error = libspectrum_identify_file( &type, filename, buffer, length );
if( error ) return error;
/* If we still can't identify it, give up */
if( type == LIBSPECTRUM_ID_UNKNOWN ) {
libspectrum_print_error(
LIBSPECTRUM_ERROR_UNKNOWN,
"libspectrum_snap_read: couldn't identify file"
);
return LIBSPECTRUM_ERROR_UNKNOWN;
}
}
error = libspectrum_identify_class( &class, type );
if( error ) return error;
if( class != LIBSPECTRUM_CLASS_SNAPSHOT ) {
libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
"libspectrum_snap_read: not a snapshot file" );
return LIBSPECTRUM_ERROR_CORRUPT;
}
/* Find out if this file needs decompression */
uncompressed = 0; new_buffer = NULL;
error = libspectrum_identify_file_raw( &raw_type, filename, buffer, length );
if( error ) return error;
error = libspectrum_identify_class( &class, raw_type );
if( error ) return error;
if( class == LIBSPECTRUM_CLASS_COMPRESSED ) {
size_t new_length;
error = libspectrum_uncompress_file( &new_buffer, &new_length, NULL,
raw_type, buffer, length, NULL );
buffer = new_buffer; length = new_length;
uncompressed = 1;
}
switch( type ) {
case LIBSPECTRUM_ID_SNAPSHOT_PLUSD:
error = libspectrum_plusd_read( snap, buffer, length ); break;
case LIBSPECTRUM_ID_SNAPSHOT_SNA:
error = internal_sna_read( snap, buffer, length ); break;
case LIBSPECTRUM_ID_SNAPSHOT_SNP:
error = libspectrum_snp_read( snap, buffer, length ); break;
case LIBSPECTRUM_ID_SNAPSHOT_SP:
error = libspectrum_sp_read( snap, buffer, length ); break;
case LIBSPECTRUM_ID_SNAPSHOT_SZX:
error = libspectrum_szx_read( snap, buffer, length ); break;
case LIBSPECTRUM_ID_SNAPSHOT_Z80:
error = internal_z80_read( snap, buffer, length ); break;
case LIBSPECTRUM_ID_SNAPSHOT_ZXS:
error = libspectrum_zxs_read( snap, buffer, length ); break;
default:
libspectrum_print_error( LIBSPECTRUM_ERROR_LOGIC,
"libspectrum_snap_read: unknown snapshot type %d",
type );
libspectrum_free( new_buffer );
return LIBSPECTRUM_ERROR_LOGIC;
}
libspectrum_free( new_buffer );
return error;
}
libspectrum_error
libspectrum_snap_write( libspectrum_byte **buffer, size_t *length,
int *out_flags, libspectrum_snap *snap,
libspectrum_id_t type, libspectrum_creator *creator,
int in_flags )
{
libspectrum_class_t class;
libspectrum_error error;
error = libspectrum_identify_class( &class, type );
if( error ) return error;
if( class != LIBSPECTRUM_CLASS_SNAPSHOT ) {
libspectrum_print_error( LIBSPECTRUM_ERROR_INVALID,
"libspectrum_snap_write: not a snapshot format" );
return LIBSPECTRUM_ERROR_INVALID;
}
switch( type ) {
case LIBSPECTRUM_ID_SNAPSHOT_SNA:
return libspectrum_sna_write( buffer, length, out_flags, snap, in_flags );
case LIBSPECTRUM_ID_SNAPSHOT_SZX:
return libspectrum_szx_write( buffer, length, out_flags, snap, creator,
in_flags );
case LIBSPECTRUM_ID_SNAPSHOT_Z80:
return libspectrum_z80_write2( buffer, length, out_flags, snap, in_flags );
default:
libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
"libspectrum_snap_write: format not supported" );
return LIBSPECTRUM_ERROR_UNKNOWN;
}
}
/* Given a 48K memory dump `data', place it into the
appropriate bits of `snap' for a 48K machine */
libspectrum_error
libspectrum_split_to_48k_pages( libspectrum_snap *snap,
const libspectrum_byte* data )
{
libspectrum_byte *buffer[3];
size_t i;
/* If any of the three pages are already occupied, barf */
if( libspectrum_snap_pages( snap, 5 ) ||
libspectrum_snap_pages( snap, 2 ) ||
libspectrum_snap_pages( snap, 0 ) ) {
libspectrum_print_error(
LIBSPECTRUM_ERROR_LOGIC,
"libspectrum_split_to_48k_pages: RAM page already in use"
);
return LIBSPECTRUM_ERROR_LOGIC;
}
for( i = 0; i < 3; i++ )
buffer[i] = libspectrum_malloc( 0x4000 * sizeof( libspectrum_byte ) );
libspectrum_snap_set_pages( snap, 5, buffer[0] );
libspectrum_snap_set_pages( snap, 2, buffer[1] );
libspectrum_snap_set_pages( snap, 0, buffer[2] );
/* Finally, do the copies... */
memcpy( libspectrum_snap_pages( snap, 5 ), &data[0x0000], 0x4000 );
memcpy( libspectrum_snap_pages( snap, 2 ), &data[0x4000], 0x4000 );
memcpy( libspectrum_snap_pages( snap, 0 ), &data[0x8000], 0x4000 );
return LIBSPECTRUM_ERROR_NONE;
}

View File

@ -1,7 +1,7 @@
/* szx.c: Routines for .szx snapshots
Copyright (c) 1998-2008 Philip Kendall, Fredrick Meunier, Stuart Brady
Copyright (c) 1998-2009 Philip Kendall, Fredrick Meunier, Stuart Brady
$Id: szx.c 3698 2008-06-30 15:12:02Z pak21 $
$Id: szx.c 4032 2009-06-10 11:09:44Z fredm $
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -71,6 +71,9 @@ static const libspectrum_byte ZXSTZF_HALTED = 2;
static const libspectrum_word ZXSTRF_COMPRESSED = 1;
#define ZXSTBID_AY "AY\0\0"
static const libspectrum_byte ZXSTAYF_FULLERBOX = 1;
static const libspectrum_byte ZXSTAYF_128AY = 2;
#define ZXSTBID_MULTIFACE "MFCE"
#define ZXSTBID_USPEECH "USPE"
#define ZXSTBID_SPECDRUM "DRUM"
@ -367,6 +370,7 @@ read_ay_chunk( libspectrum_snap *snap, libspectrum_word version GCC_UNUSED,
const libspectrum_byte *end GCC_UNUSED, size_t data_length )
{
size_t i;
libspectrum_byte flags;
if( data_length != 18 ) {
libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
@ -375,7 +379,9 @@ read_ay_chunk( libspectrum_snap *snap, libspectrum_word version GCC_UNUSED,
return LIBSPECTRUM_ERROR_UNKNOWN;
}
(*buffer)++; /* Skip the flags */
flags = **buffer; (*buffer)++;
libspectrum_snap_set_fuller_box_active( snap, flags & ZXSTAYF_FULLERBOX );
libspectrum_snap_set_melodik_active( snap, !!( flags & ZXSTAYF_128AY ) );
libspectrum_snap_set_out_ay_registerport( snap, **buffer ); (*buffer)++;
@ -1841,7 +1847,9 @@ libspectrum_szx_write( libspectrum_byte **buffer, size_t *length,
error = write_ram_pages( buffer, &ptr, length, snap, compress );
if( error ) return error;
if( capabilities & LIBSPECTRUM_MACHINE_CAPABILITY_AY ) {
if( libspectrum_snap_fuller_box_active( snap ) ||
libspectrum_snap_melodik_active( snap ) ||
capabilities & LIBSPECTRUM_MACHINE_CAPABILITY_AY ) {
error = write_ay_chunk( buffer, &ptr, length, snap );
if( error ) return error;
}
@ -2486,10 +2494,15 @@ write_ay_chunk( libspectrum_byte **buffer, libspectrum_byte **ptr,
size_t *length, libspectrum_snap *snap )
{
size_t i;
libspectrum_byte flags;
write_chunk_header( buffer, ptr, length, ZXSTBID_AY, 18 );
*(*ptr)++ = '\0'; /* Flags */
flags = 0;
if( libspectrum_snap_fuller_box_active( snap ) ) flags |= ZXSTAYF_FULLERBOX;
if( libspectrum_snap_melodik_active( snap ) ) flags |= ZXSTAYF_128AY;
*(*ptr)++ = flags;
*(*ptr)++ = libspectrum_snap_out_ay_registerport( snap );
for( i = 0; i < 16; i++ )

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
/* z80.c: Routines for handling .z80 snapshots
Copyright (c) 2001-2004 Philip Kendall, Darren Salt, Fredrick Meunier
Copyright (c) 2001-2009 Philip Kendall, Darren Salt, Fredrick Meunier
$Id: z80.c 3784 2008-10-22 12:36:07Z fredm $
$Id: z80.c 4032 2009-06-10 11:09:44Z fredm $
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -110,6 +110,12 @@ static const libspectrum_word if2_left_f = '5';
static libspectrum_byte slt_signature[] = "\0\0\0SLT";
static size_t slt_signature_length = 6;
/* Bits used in extended header to flag that a Fuller Box is in use */
static const libspectrum_byte fuller_box_flags = 0x44;
/* Bits used in extended header to flag that a Melodik is in use */
static const libspectrum_byte melodik_flags = 0x04;
static libspectrum_error
read_header( const libspectrum_byte *buffer, libspectrum_snap *snap,
const libspectrum_byte **data, int *version, int *compressed );
@ -329,7 +335,7 @@ read_header( const libspectrum_byte *buffer, libspectrum_snap *snap,
b.. Any valid 128k identifier should be taken as +2
c.. Any valid +3 identifier (7 or 8) should be taken as +2A
Support for Fuller Box / AY sound in 48k mode (not implemented)
Support for Fuller Box / AY sound in 48k mode
Spectaculator recognises xzx's extension of setting bit 2 of byte 37 to
specify AY sound in 48k mode. In addition, if this and also bit 6 is
@ -353,6 +359,12 @@ read_header( const libspectrum_byte *buffer, libspectrum_snap *snap,
}
}
if( ( extra_header[5] & fuller_box_flags ) == fuller_box_flags ) {
libspectrum_snap_set_fuller_box_active( snap, 1 );
} else if( ( extra_header[5] & melodik_flags ) == melodik_flags ) {
libspectrum_snap_set_melodik_active( snap, 1 );
}
capabilities =
libspectrum_machine_capabilities( libspectrum_snap_machine( snap ) );
@ -366,7 +378,9 @@ read_header( const libspectrum_byte *buffer, libspectrum_snap *snap,
libspectrum_snap_set_out_scld_dec( snap, extra_header[4] );
}
if( capabilities & LIBSPECTRUM_MACHINE_CAPABILITY_AY ) {
if( libspectrum_snap_fuller_box_active( snap ) ||
libspectrum_snap_melodik_active( snap ) ||
capabilities & LIBSPECTRUM_MACHINE_CAPABILITY_AY ) {
libspectrum_snap_set_out_ay_registerport( snap, extra_header[ 6] );
for( i = 0; i < 16; i++ ) {
libspectrum_snap_set_ay_registers( snap, i, extra_header[ 7 + i ] );
@ -1250,6 +1264,7 @@ write_extended_header( libspectrum_byte **buffer, libspectrum_byte **ptr,
size_t *length, int *flags, libspectrum_snap *snap )
{
int i, bottom_16kb_ram;
libspectrum_byte hardware_flag = 0; /* No special emulation features */
libspectrum_dword quarter_states;
@ -1344,11 +1359,23 @@ write_extended_header( libspectrum_byte **buffer, libspectrum_byte **ptr,
/* Support 16K snapshots via Spectaculator's extension; see the
comment in read_header for details */
if( libspectrum_snap_machine( snap ) == LIBSPECTRUM_MACHINE_16 ) {
*(*ptr)++ = 0x80;
} else {
*(*ptr)++ = '\0'; /* No special emulation features */
hardware_flag |= 0x80;
}
/* Support Fuller Box in snapshots via Spectaculator's extension; see the
comment in read_header for details */
if( libspectrum_snap_fuller_box_active( snap ) ) {
/* Fuller is set by having bit 2 and 6 on */
hardware_flag |= fuller_box_flags;
}
if( libspectrum_snap_melodik_active( snap ) ) {
/* Melodik is set by having bit 2 on */
hardware_flag |= melodik_flags;
}
*(*ptr)++ = hardware_flag;
*(*ptr)++ = libspectrum_snap_out_ay_registerport( snap );
for( i = 0; i < 16; i++ )
*(*ptr)++ = libspectrum_snap_ay_registers( snap, i );

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 740 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -6,7 +6,7 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<stroke android:width="2dp" android:color="#202020" />
<gradient android:startColor="#007000" android:endColor="#003000"
<gradient android:startColor="#ff7000" android:endColor="#ff3000"
android:angle="270" />
<corners android:radius="4dp" />
</shape>

15
res/layout/help.xml Normal file
View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="fill_parent">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView android:id="@+id/help_tv" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:padding="5dip"
android:textSize="15sp" />
</LinearLayout>
</ScrollView>

View File

@ -45,4 +45,12 @@
<item>se</item>
</string-array>
<string-array name="welcome_menu">
<item>Load last state</item>
<item>Load game file</item>
<item>* Demo games</item>
<item>Continue booting</item>
<item>Help</item>
</string-array>
</resources>

View File

@ -10,5 +10,6 @@
<drawable name="black">#ff000000</drawable>
<drawable name="translucent">#c0000000</drawable>
<drawable name="transparent">#00000000</drawable>
<drawable name="dimmed">#40000000</drawable>
</resources>

View File

@ -2,17 +2,6 @@
<resources>
<string name="app_name">ZXdroid</string>
<string name="welcome_title">Welcome to ZXdroid!</string>
<string name="welcome_message">
A ZX Spectrum emulator for Android platform
based on Fuse (the Free Unix Spectrum Emulator).
\n\nCoded by Dmitry Rodin.
\n\nTAP SPECTRUM SCREEN FOR MENU!
(Read it carefully)
\n\nDpad/trackball is definied as Kempston
joystick by default - you can change it in
Menu > Define keys.</string>
<string name="emulator_state">Emulator state</string>
<string name="load_file">Load file</string>
<string name="save_snapshot">Save snapshot</string>
@ -20,15 +9,21 @@
<string name="exit">Exit</string>
<string name="video_settings">Video settings</string>
<string name="frame_skip">Skip frames</string>
<string name="smooth_scaling">Smooth scaling</string>
<string name="audio_settings">Audio settings</string>
<string name="enable_sound">Enable sounds</string>
<string name="control_settings">Control settings</string>
<string name="hide_controls">Hide Controls</string>
<string name="onscreen_controls">OnScreen controls</string>
<string name="define_keys">Define Keys</string>
<string name="intercept_menu_back">Intercept Menu &amp; Back</string>
<string name="intercept_warning">Touch spectrum screen for menu!</string>
<string name="trackball_sensitivity">Trackball sensitivity</string>
<string name="help">Help</string>
<string name="save_btn">Save</string>
<string name="default_save_fn">current</string>

View File

@ -4,8 +4,8 @@
<style name="Theme" parent="android:Theme.Black.NoTitleBar.Fullscreen">
<item name="android:textAppearanceLarge">@style/ListText</item>
<item name="android:textAppearanceMedium">@style/ListTextSmall</item>
<item name="android:textAppearanceSmall">@style/ListTextSmall</item>
<item name="android:textAppearanceMedium">@style/ListTextSmall</item>
<item name="android:textAppearanceSmall">@style/ListTextSmall</item>
<item name="android:listPreferredItemHeight">40sp</item>
<item name="android:listViewStyle">@style/ListView</item>
</style>
@ -16,6 +16,29 @@
<item name="android:windowAnimationStyle">@android:style/Animation.Translucent</item>
</style>
<style name="Theme.Translucent.Dialog" parent="android:Theme.Dialog">
<item name="android:windowTitleStyle">@style/DialogWindowTitle</item>
<item name="android:listViewStyle">@style/ListViewDialog</item>
</style>
<style name="DialogWindowTitle">
<item name="android:maxLines">1</item>
<item name="android:textAppearance">@style/ListText</item>
<item name="android:gravity">center_vertical|center_horizontal</item>
</style>
<style name="ListViewDialog">
<item name="android:scrollbars">vertical</item>
<item name="android:fadingEdge">vertical</item>
<item name="android:scrollbarStyle">outsideInset</item>
<item name="android:paddingLeft">30dp</item>
<item name="android:paddingRight">30dp</item>
<item name="android:background">@drawable/dimmed</item>
<item name="android:divider">@drawable/black</item>
<item name="android:dividerHeight">1dp</item>
<item name="android:footerDividersEnabled">false</item>
</style>
<style name="ListView">
<item name="android:background">@drawable/transparent</item>
<item name="android:scrollbars">vertical</item>

View File

@ -22,8 +22,8 @@
<Key android:codes="12013" android:keyIcon="@drawable/zxkb_down_left" />
<Key android:codes="13" android:keyIcon="@drawable/zxkb_down" />
<Key android:codes="15013" android:keyIcon="@drawable/zxkb_down_right" />
<Key android:codes="62" android:keyIcon="@drawable/zxkb_space"
android:horizontalGap="60dip" />
<Key android:codes="1007" android:keyIcon="@drawable/zxkb_fire_lock"
android:isSticky="true" android:horizontalGap="60dip" />
</Row>
</Keyboard>

View File

@ -23,7 +23,8 @@
</Row>
<Row>
<Key android:codes="62" android:keyIcon="@drawable/zxkb_space" />
<Key android:codes="1007" android:keyIcon="@drawable/zxkb_fire_lock"
android:isSticky="true" />
<Key android:codes="7" android:keyIcon="@drawable/zxkb_fire"
android:horizontalGap="50dip" />
</Row>

View File

@ -22,8 +22,8 @@
<Key android:codes="103102" android:keyIcon="@drawable/zxkb_down_left" />
<Key android:codes="102" android:keyIcon="@drawable/zxkb_down" />
<Key android:codes="104102" android:keyIcon="@drawable/zxkb_down_right" />
<Key android:codes="62" android:keyIcon="@drawable/zxkb_space"
android:horizontalGap="60dip" />
<Key android:codes="1105" android:keyIcon="@drawable/zxkb_fire_lock"
android:isSticky="true" android:horizontalGap="60dip" />
</Row>
</Keyboard>

View File

@ -23,7 +23,8 @@
</Row>
<Row>
<Key android:codes="62" android:keyIcon="@drawable/zxkb_space" />
<Key android:codes="1105" android:keyIcon="@drawable/zxkb_fire_lock"
android:isSticky="true" />
<Key android:codes="105" android:keyIcon="@drawable/zxkb_fire"
android:horizontalGap="50dip" />
</Row>

View File

@ -16,11 +16,15 @@
</PreferenceCategory>
<PreferenceCategory android:title="@string/control_settings">
<CheckBoxPreference android:key="hideControls"
android:title="@string/hide_controls" android:defaultValue="false" />
<ListPreference android:key="onScreenControls"
android:title="@string/onscreen_controls" android:entries="@array/control_entries"
android:entryValues="@array/control_entries" android:defaultValue="Keyboard" />
<PreferenceScreen android:key="defineKeys"
android:title="@string/define_keys" />
<CheckBoxPreference android:key="interceptMenuBack"
android:title="@string/intercept_menu_back" android:defaultValue="false" />
<com.drodin.zxdroid.menu.TrackballSens
android:key="trackballSensitivity" android:title="@string/trackball_sensitivity"
androidemu:minValue="1" androidemu:maxValue="10"
@ -33,8 +37,15 @@
</PreferenceCategory>
<PreferenceCategory android:title="@string/video_settings">
<CheckBoxPreference android:key="skipFrames"
android:title="@string/frame_skip" android:defaultValue="true" />
<CheckBoxPreference android:key="smoothScaling"
android:title="@string/smooth_scaling" android:defaultValue="true" />
</PreferenceCategory>
<PreferenceCategory android:title="@string/help">
<PreferenceScreen android:key="help"
android:title="@string/help" />
</PreferenceCategory>
</PreferenceScreen>

View File

@ -22,8 +22,8 @@
<Key android:codes="8010" android:keyIcon="@drawable/zxkb_down_left" />
<Key android:codes="10" android:keyIcon="@drawable/zxkb_down" />
<Key android:codes="9010" android:keyIcon="@drawable/zxkb_down_right" />
<Key android:codes="62" android:keyIcon="@drawable/zxkb_space"
android:horizontalGap="60dip" />
<Key android:codes="1012" android:keyIcon="@drawable/zxkb_fire_lock"
android:isSticky="true" android:horizontalGap="60dip" />
</Row>
</Keyboard>

View File

@ -23,7 +23,8 @@
</Row>
<Row>
<Key android:codes="62" android:keyIcon="@drawable/zxkb_space" />
<Key android:codes="1012" android:keyIcon="@drawable/zxkb_fire_lock"
android:isSticky="true" />
<Key android:codes="12" android:keyIcon="@drawable/zxkb_fire"
android:horizontalGap="50dip" />
</Row>

View File

@ -22,8 +22,8 @@
<Key android:codes="13015" android:keyIcon="@drawable/zxkb_down_left" />
<Key android:codes="15" android:keyIcon="@drawable/zxkb_down" />
<Key android:codes="14015" android:keyIcon="@drawable/zxkb_down_right" />
<Key android:codes="62" android:keyIcon="@drawable/zxkb_space"
android:horizontalGap="60dip" />
<Key android:codes="1007" android:keyIcon="@drawable/zxkb_fire_lock"
android:isSticky="true" android:horizontalGap="60dip" />
</Row>
</Keyboard>

View File

@ -23,7 +23,8 @@
</Row>
<Row>
<Key android:codes="62" android:keyIcon="@drawable/zxkb_space" />
<Key android:codes="1007" android:keyIcon="@drawable/zxkb_fire_lock"
android:isSticky="true" />
<Key android:codes="7" android:keyIcon="@drawable/zxkb_fire"
android:horizontalGap="50dip" />
</Row>

View File

@ -20,7 +20,7 @@
E-mail: rodin.dmitry@gmail.com
*/
*/
package com.drodin.zxdroid;
@ -31,14 +31,13 @@ import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.AssetManager;
import android.content.res.Configuration;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.Display;
import android.view.Gravity;
import android.view.View;
@ -49,12 +48,17 @@ import com.admob.android.ads.AdListener;
import com.admob.android.ads.AdManager;
import com.admob.android.ads.AdView;
import com.drodin.zxdroid.menu.MenuTop;
import com.drodin.zxdroid.menu.SelectControl;
import com.drodin.zxdroid.menu.WelcomeMenu;
public class MainActivity extends Activity implements AdListener {
private static Display mDispaly;
public static MainActivity currentInstance = null;
public static boolean firstRun = true;
private static SharedPreferences settings = null;
private static LinearLayout mMainLayout = null;
private static LinearLayout mInnerLayout = null;
@ -66,13 +70,12 @@ public class MainActivity extends Activity implements AdListener {
private static boolean menuOnTop = false;
private static boolean firstStart = false;
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
currentInstance = this;
settings = PreferenceManager.getDefaultSharedPreferences(this);
InstallFiles();
@ -98,19 +101,6 @@ public class MainActivity extends Activity implements AdListener {
createScreen();
if (firstStart) {
new AlertDialog.Builder(this)
.setTitle(R.string.welcome_title)
.setMessage(R.string.welcome_message)
.setNegativeButton(R.string.df_btn_cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
}
})
.create()
.show();
firstStart = false;
}
}
private void createScreen() {
@ -142,26 +132,40 @@ public class MainActivity extends Activity implements AdListener {
mInnerLayout.addView(mMainView,
new LayoutParams(NativeLib.mWidth, NativeLib.mHeight));
mMainLayout.addView(mInnerLayout);
mMainLayout.addView(mControlsView,
new LayoutParams(NativeLib.mWidth, mSoftControls.mControl.getHeight()));
if (!NativeLib.hideControls) {
mMainLayout.addView(mControlsView,
new LayoutParams(NativeLib.mWidth, mSoftControls.mControl.getHeight()));
}
mMainLayout.addView(adView,
new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.FILL_PARENT));
} else {
mMainLayout.setOrientation(LinearLayout.HORIZONTAL);
mMainLayout.addView(mControlsView,
new LayoutParams(NativeLib.displayHeight-NativeLib.mWidth, NativeLib.mWidth));
mInnerLayout.setLayoutParams(new LayoutParams(NativeLib.mWidth, LayoutParams.FILL_PARENT));
mInnerLayout.addView(mMainView,
new LayoutParams(NativeLib.mWidth, NativeLib.mHeight));
mInnerLayout.addView(adView,
new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.FILL_PARENT));
if (NativeLib.hideControls) {
mInnerLayout.setLayoutParams(
new LayoutParams(
NativeLib.mWidth*NativeLib.spectrumScreenWidth/NativeLib.spectrumScreenHeight,
NativeLib.mWidth));
mInnerLayout.addView(mMainView,
new LayoutParams(
NativeLib.mWidth*NativeLib.spectrumScreenWidth/NativeLib.spectrumScreenHeight,
NativeLib.mWidth));
} else {
mMainLayout.addView(mControlsView,
new LayoutParams(NativeLib.displayHeight-NativeLib.mWidth, NativeLib.mWidth));
mInnerLayout.setLayoutParams(
new LayoutParams(NativeLib.mWidth, LayoutParams.FILL_PARENT));
mInnerLayout.addView(mMainView,
new LayoutParams(NativeLib.mWidth, NativeLib.mHeight));
mInnerLayout.addView(adView,
new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.FILL_PARENT));
}
mMainLayout.addView(mInnerLayout);
}
System.gc();
setContentView(mMainLayout);
mSoftControls.setControlName();
if (mMainView != null && menuOnTop == false)
@ -170,8 +174,13 @@ public class MainActivity extends Activity implements AdListener {
@Override
public void onConfigurationChanged (Configuration newConfig) {
NativeLib.eventQueue.add(NativeLib.KEY_RELEASE + NativeLib.spectrumKeyCap);
NativeLib.eventQueue.add(NativeLib.KEY_RELEASE + NativeLib.spectrumKeySym);
Log.i("zxdroid","congig changed");
if (mSoftControls.capPressed)
NativeLib.eventQueue.add(NativeLib.KEY_RELEASE + NativeLib.spectrumKeyCap);
if(mSoftControls.symPressed)
NativeLib.eventQueue.add(NativeLib.KEY_RELEASE + NativeLib.spectrumKeySym);
if (mSoftControls.fireLock != 0 )
NativeLib.eventQueue.add(NativeLib.KEY_RELEASE + mSoftControls.fireLock);
super.onConfigurationChanged(newConfig);
createScreen();
}
@ -194,6 +203,15 @@ public class MainActivity extends Activity implements AdListener {
protected void onDestroy() {
super.onDestroy();
if (NativeLib.tmpUncompressedFN != null) {
File tmpFile = new File(NativeLib.tmpUncompressedFN);
tmpFile.delete();
}
SharedPreferences.Editor editor = settings.edit();
editor.putString("startDir", NativeLib.startDir);
editor.commit();
NativeLib.quit();
if (mMainView != null)
@ -211,10 +229,29 @@ public class MainActivity extends Activity implements AdListener {
}
}
public void showSelectControl () {
if (!menuOnTop) {
menuOnTop = true;
startActivityForResult(new Intent(this, SelectControl.class), 0);
}
}
public void showWelcomeMenu () {
if (!menuOnTop) {
menuOnTop = true;
startActivityForResult(new Intent(this, WelcomeMenu.class), 0);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(NativeLib.hideControls != NativeLib.controlsHidden) {
NativeLib.controlsHidden = NativeLib.hideControls;
createScreen();
}
if (resultCode == RESULT_OK && requestCode == 0) {
final String openFileName = data.getStringExtra("openFileName");
@ -239,7 +276,6 @@ public class MainActivity extends Activity implements AdListener {
}
private void LoadSettings() {
final SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);
final String definedKeys = settings.getString("definedKeys", NativeLib.defaultDefinedKeys);
if (definedKeys.contains(";")) {
final String[] keyPairs = definedKeys.split(";");
@ -248,11 +284,17 @@ public class MainActivity extends Activity implements AdListener {
= Integer.parseInt(keyPairs[i].split(":")[1]);
}
NativeLib.skipFrames = settings.getBoolean("skipFrames", true);
NativeLib.smoothScaling = settings.getBoolean("smoothScaling", true);
NativeLib.soundEnabled = settings.getBoolean("soundEnabled", false);
NativeLib.trackballSensitivity = settings.getInt("trackballSensitivity", 3);
NativeLib.onScreenControls = settings.getString("onScreenControls", "Keyboard");
NativeLib.currentMachine = settings.getString("currentMachine", "48");
NativeLib.hideControls = settings.getBoolean("hideControls", false);
NativeLib.controlsHidden = NativeLib.hideControls;
NativeLib.interceptMenuBack = settings.getBoolean("interceptMenuBack", false);
NativeLib.onScreenControls = settings.getString("onScreenControls", "Kempston");
//NativeLib.currentMachine = settings.getString("currentMachine", "128");
NativeLib.currentMachine = "128";
NativeLib.startDir = settings.getString("startDir", NativeLib.sdcardDir);
}
@ -265,7 +307,6 @@ public class MainActivity extends Activity implements AdListener {
File dir = new File(outdir);
if (!dir.exists()) {
dir.mkdir();
firstStart = true;
}
ZipInputStream zs = new ZipInputStream(mAssetManager.open("files.zip", AssetManager.ACCESS_BUFFER));
ZipEntry ze;
@ -288,25 +329,21 @@ public class MainActivity extends Activity implements AdListener {
} catch(IOException e) { }
}
@Override
public void onFailedToReceiveAd(AdView arg0) {
// TODO Auto-generated method stub
}
@Override
public void onFailedToReceiveRefreshedAd(AdView arg0) {
// TODO Auto-generated method stub
}
@Override
public void onReceiveAd(AdView arg0) {
// TODO Auto-generated method stub
}
@Override
public void onReceiveRefreshedAd(AdView arg0) {
// TODO Auto-generated method stub

View File

@ -46,7 +46,7 @@ public class MainAudio {
mAudio.play();
return bufSize;
}
public static void destroy() {
if( mAudio != null )
{

View File

@ -20,7 +20,7 @@
E-mail: rodin.dmitry@gmail.com
*/
*/
package com.drodin.zxdroid;
@ -34,7 +34,7 @@ import android.view.MotionEvent;
public class MainView extends GLSurfaceView {
MainActivity mMainActivity = null;
private MainActivity mMainActivity = null;
private static boolean trackballUsed = false;
private static long trackUp = 0;
@ -45,6 +45,8 @@ public class MainView extends GLSurfaceView {
public MainView(Context context) {
super(context);
mMainActivity = MainActivity.currentInstance;
setId((int)Math.random()*100);
@ -60,23 +62,53 @@ public class MainView extends GLSurfaceView {
public boolean onTouchEvent (MotionEvent event) {
if (
event.getX()>NativeLib.menuTouchDelta &&
event.getX()<(float)NativeLib.mWidth-NativeLib.menuTouchDelta &&
event.getX()<(float)getWidth()-NativeLib.menuTouchDelta &&
event.getY()>NativeLib.menuTouchDelta &&
event.getY()<(float)NativeLib.mHeight-NativeLib.menuTouchDelta
)
MainActivity.currentInstance.showMenu();
event.getY()<(float)getHeight()-NativeLib.menuTouchDelta
) {
if (NativeLib.interceptMenuBack || NativeLib.hideControls)
post(new Runnable() {
public void run() {
mMainActivity.showMenu();
}
});
else
post(new Runnable() {
public void run() {
mMainActivity.showSelectControl();
}
});
}
return true;
}
@Override
public boolean onKeyPreIme (int keyCode, KeyEvent event) {
public boolean dispatchKeyEventPreIme (KeyEvent event) {
final int keyCode = event.getKeyCode();
if (event.getRepeatCount() == 0 && keyCode > 0 && keyCode < NativeLib.androidKeys.length) {
NativeLib.eventQueue.add(
((event.getAction() == KeyEvent.ACTION_DOWN)?NativeLib.KEY_PRESS:NativeLib.KEY_RELEASE)
+ ((NativeLib.definiedKeys[keyCode]==0)?keyCode:NativeLib.definiedKeys[keyCode])
);
}
return true;
if (!NativeLib.interceptMenuBack && keyCode==KeyEvent.KEYCODE_MENU) {
post(new Runnable() {
public void run() {
mMainActivity.showMenu();
}
}); return true;
} else if (!NativeLib.interceptMenuBack && keyCode==KeyEvent.KEYCODE_BACK) {
return false;
} else if (keyCode==KeyEvent.KEYCODE_VOLUME_UP &&
NativeLib.definiedKeys[KeyEvent.KEYCODE_VOLUME_UP]==0 && NativeLib.soundEnabled) {
return false;
} else if (keyCode==KeyEvent.KEYCODE_VOLUME_DOWN &&
NativeLib.definiedKeys[KeyEvent.KEYCODE_VOLUME_DOWN]==0 && NativeLib.soundEnabled) {
return false;
} else {
NativeLib.eventQueue.add(
((event.getAction() == KeyEvent.ACTION_DOWN)?NativeLib.KEY_PRESS:NativeLib.KEY_RELEASE)
+ ((NativeLib.definiedKeys[keyCode]==0)?keyCode:NativeLib.definiedKeys[keyCode])
);
return true;
}
} else
return true;
}
@Override
@ -201,27 +233,32 @@ public class MainView extends GLSurfaceView {
public class MainRenderer implements GLSurfaceView.Renderer {
@Override
public void onDrawFrame(GL10 gl) {
if (trackballUsed)
finishTrackballEvents();
if (NativeLib.eventQueue.size()<=0) {
NativeLib.render(0);
} else {
if (NativeLib.eventQueue.size()>0)
NativeLib.render(NativeLib.eventQueue.remove(0));
}
else
NativeLib.render(0);
requestRender();
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
NativeLib.resize(NativeLib.mWidth, NativeLib.mHeight, NativeLib.smoothScaling);
NativeLib.resize(width, height, NativeLib.smoothScaling);
if (MainActivity.firstRun) {
post(new Runnable() {
public void run() {
mMainActivity.showWelcomeMenu();
}
});
MainActivity.firstRun = false;
}
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
//Process.setThreadPriority(Process.THREAD_PRIORITY_DISPLAY);

View File

@ -20,7 +20,7 @@
E-mail: rodin.dmitry@gmail.com
*/
*/
package com.drodin.zxdroid;
@ -35,9 +35,11 @@ public class NativeLib {
public static volatile ArrayList<Integer> eventQueue = new ArrayList<Integer>(256);
public static volatile String openFileName = "";
public static volatile String saveFileName = "";
public static boolean skipFrames;
public static boolean smoothScaling;
public static boolean soundEnabled;
public static String onScreenControls;
@ -45,28 +47,29 @@ public class NativeLib {
public static String currentMachine;
public static native void resize(int width, int height, boolean scaling);
public static native void render(int event);
public static native void quit();
public static native String cmachine();
public static void setCurrentMachine(String machine) {
currentMachine = machine;
}
public static int spectrumScreenWidth = 320;
public static int spectrumScreenHeight = 240;
public static native void resize(int width, int height, boolean scaling);
public static native void render(int event);
public static native void quit();
public static final int spectrumScreenWidth = 320;
public static final int spectrumScreenHeight = 240;
public static int mWidth, mHeight;
public static int displayWidth, displayHeight, displayOrientation;
public static final String startDir = "/sdcard";
public static final String supportExt = "" +
" dck rom" +
" dsk fdi sad scl trd td0 udi" +
" hdf" +
" mdf mdr" +
" rzx" +
" sna snp sp szx z80 zxs" +
" csw tap tzx spc sta ltp" +
" gz";
public static final String sdcardDir = "/sdcard";
public static String startDir;
public static final String supportExt = "" + " dck rom"
+ " dsk fdi sad scl trd td0 udi" + " hdf" + " mdf mdr" + " rzx"
+ " sna snp sp szx z80 zxs" + " csw tap tzx spc sta ltp"
+ " gz zip";
public static final float menuTouchDelta = 20.0f;
public static final int KEY_PRESS = 1000;
@ -76,7 +79,7 @@ public class NativeLib {
public static final int MENU_FILE_OPEN = 101;
public static final int MENU_FILE_SAVESNAPSHOT = 102;
public static final int MENU_FILE_EXIT = 123;
public static final String[] androidKeys = {
"UNKNOWN", "SOFT_LEFT", "SOFT_RIGHT", "HOME", "BACK", "CALL", "ENDCALL",
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
@ -89,7 +92,12 @@ public class NativeLib {
"MINUS", "EQUALS", "LEFT_BRACKET", "RIGHT_BRACKET", "BACKSLASH", "SEMICOLON",
"APOSTROPHE", "SLASH", "AT", "NUM", "HEADSETHOOK", "FOCUS", "PLUS", "MENU",
"NOTIFICATION", "SEARCH", "MEDIA_PLAY_PAUSE", "MEDIA_STOP", "MEDIA_NEXT",
"MEDIA_PREVIOUS", "MEDIA_REWIND", "MEDIA_FAST_FORWARD", "MUTE"
"MEDIA_PREVIOUS", "MEDIA_REWIND", "MEDIA_FAST_FORWARD", "MUTE",
"PAGE_UP", "PAGE_DOWN", "PICTSYMBOLS", "SWITCH_CHARSET", "BUTTON_A",
"BUTTON_B", "BUTTON_C", "BUTTON_X", "BUTTON_Y", "BUTTON_Z",
"BUTTON_L1", "BUTTON_R1", "BUTTON_L2", "BUTTON_R2",
"BUTTON_THUMBL", "BUTTON_THUMBR",
"BUTTON_START", "BUTTON_SELECT"
};
public static final String[] spectrumKeys = {
@ -108,11 +116,19 @@ public class NativeLib {
null, null, null, null, null, null, null, null, null,
"KEMPSTON UP", "KEMPSTON DOWN", "KEMPSTON LEFT", "KEMPSTON RIGHT", "KEMPSTON FIRE"
};
public static int spectrumKeyCap = 59;
public static int spectrumKeySym = 58;
public static int[] definiedKeys = new int[androidKeys.length];
public static String defaultDefinedKeys = "19:101;20:102;21:103;22:104;23:105;"; //DPAD as Kempston
public static final int spectrumKeyCap = 59;
public static final int spectrumKeySym = 58;
public static final int spectrumModFireLock = 1000;
public static boolean interceptMenuBack;
public static int[] definiedKeys = new int[androidKeys.length];
// DPAD as Kempston
public static String defaultDefinedKeys = "19:101;20:102;21:103;22:104;23:105;";
public static final String tmpFilePrefix = "zxdroid_tmp_";
public static String tmpUncompressedFN = null;
public static boolean hideControls;
public static boolean controlsHidden;
}

View File

@ -20,7 +20,7 @@
E-mail: rodin.dmitry@gmail.com
*/
*/
package com.drodin.zxdroid;
@ -47,8 +47,9 @@ public class SoftControls extends KeyboardView implements KeyboardView.OnKeyboar
private int lastKeyCode1 = 0;
private int lastKeyCode2 = 0;
private boolean capPressed = false;
private boolean symPressed = false;
public boolean capPressed = false;
public boolean symPressed = false;
public int fireLock = 0;
public SoftControls(Context context, AttributeSet attr) {
super(context, attr);
@ -129,7 +130,6 @@ public class SoftControls extends KeyboardView implements KeyboardView.OnKeyboar
}
}
@Override
public void onKey(int primaryCode, int[] keyCodes) {
if (primaryCode == Keyboard.KEYCODE_SHIFT) {
@ -172,36 +172,41 @@ public class SoftControls extends KeyboardView implements KeyboardView.OnKeyboar
}
@Override
public void onPress(final int primaryCode) {
if (primaryCode!=Keyboard.KEYCODE_SHIFT && primaryCode!=Keyboard.KEYCODE_ALT) {
if (primaryCode > 200) {
if (primaryCode > NativeLib.spectrumModFireLock + NativeLib.spectrumKeys.length) {
lastKeyCode1 = (int)(primaryCode/1000);
lastKeyCode2 = primaryCode - lastKeyCode1*1000;
NativeLib.eventQueue.add(NativeLib.KEY_PRESS + lastKeyCode1);
NativeLib.eventQueue.add(NativeLib.KEY_PRESS + lastKeyCode2);
} else if (primaryCode >= NativeLib.spectrumModFireLock && fireLock==0) {
fireLock = primaryCode-NativeLib.spectrumModFireLock;
NativeLib.eventQueue.add(NativeLib.KEY_PRESS + fireLock);
} else if (primaryCode >= NativeLib.spectrumModFireLock && fireLock!=0) {
NativeLib.eventQueue.add(NativeLib.KEY_RELEASE + fireLock);
fireLock = 0;
} else {
lastKeyCode1 = primaryCode;
lastKeyCode1 = (primaryCode==fireLock)?0:primaryCode;
lastKeyCode2 = 0;
if (lastKeyCode1!=0)
NativeLib.eventQueue.add(NativeLib.KEY_PRESS + lastKeyCode1);
}
}
}
public void onRelease(final int primaryCode) {
if (primaryCode!=Keyboard.KEYCODE_SHIFT && primaryCode!=Keyboard.KEYCODE_ALT) {
if (lastKeyCode1!=0) {
NativeLib.eventQueue.add(NativeLib.KEY_RELEASE + lastKeyCode1);
lastKeyCode1 = 0;
}
if (lastKeyCode2!=0) {
NativeLib.eventQueue.add(NativeLib.KEY_RELEASE + lastKeyCode2);
lastKeyCode2 = 0;
NativeLib.eventQueue.add(NativeLib.KEY_PRESS + lastKeyCode1);
}
}
}
@Override
public void onRelease(final int primaryCode) {
if (primaryCode!=Keyboard.KEYCODE_SHIFT && primaryCode!=Keyboard.KEYCODE_ALT) {
if (lastKeyCode1!=0)
NativeLib.eventQueue.add(NativeLib.KEY_RELEASE + lastKeyCode1);
if (lastKeyCode2!=0)
NativeLib.eventQueue.add(NativeLib.KEY_RELEASE + lastKeyCode2);
lastKeyCode1 = 0;
lastKeyCode2 = 0;
}
}
@Override
public void onText(CharSequence text) {
}

View File

@ -20,15 +20,21 @@
E-mail: rodin.dmitry@gmail.com
*/
*/
package com.drodin.zxdroid.menu;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import android.app.ListActivity;
import android.content.Context;
@ -47,10 +53,12 @@ import com.drodin.zxdroid.R;
public class FileOpen extends ListActivity {
private String startDir;
private final static String PARENT_DIR = "..";
private TextView pathView;
protected final List<String> currentFiles = new ArrayList<String>();
private File currentDir = null;
@ -63,14 +71,24 @@ public class FileOpen extends ListActivity {
getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
pathView = (TextView) findViewById(R.id.file_tv);
startDir = getIntent().getStringExtra("startDir");
try {
showDirectory(NativeLib.startDir);
if(startDir != null)
showDirectory(startDir);
else
showDirectory(NativeLib.startDir);
} catch (NullPointerException e) {
showDirectory("/");
try {
showDirectory(NativeLib.sdcardDir);
} catch (NullPointerException e2) {
showDirectory("/");
}
}
}
@Override
@ -83,9 +101,15 @@ public class FileOpen extends ListActivity {
if (file.isDirectory()) {
showDirectory(file.getAbsolutePath());
} else {
String name = this.currentFiles.get(position);
String extension = name.indexOf('.') > 0 ? name.substring(name.lastIndexOf('.') + 1) : "";
if (extension.toLowerCase().equals("zip"))
name = handleZip(name);
final Intent extras = new Intent();
extras.putExtra("menuEventValue", NativeLib.MENU_FILE_OPEN);
extras.putExtra("openFileName", this.currentFiles.get(position));
extras.putExtra("openFileName", name);
setResult(RESULT_OK, extras);
finish();
}
@ -93,12 +117,15 @@ public class FileOpen extends ListActivity {
}
private void showDirectory(final String path) {
if (startDir == null)
NativeLib.startDir = path;
this.currentFiles.clear();
this.currentDir = new File(path);
pathView.setText(currentDir.getAbsolutePath()+"/");
if (this.currentDir.getParentFile() != null ) {
if (this.currentDir.getParentFile() != null && !path.equals(startDir)) {
this.currentFiles.add(PARENT_DIR);
}
@ -114,10 +141,16 @@ public class FileOpen extends ListActivity {
} else {
final String extension = name.indexOf('.') > 0 ? name.substring(name.lastIndexOf('.') + 1) : "";
if (NativeLib.supportExt.contains(extension.toLowerCase())) {
if (
startDir == null &&
NativeLib.supportExt.contains(extension.toLowerCase()) &&
!(name.contains(NativeLib.tmpFilePrefix))
) {
sortedFiles.add(name);
} else if (startDir != null && extension.toLowerCase().equals("sna")) {
sortedFiles.add(name);
}
}
}
this.currentFiles.addAll(sortedDirs);
@ -135,6 +168,44 @@ public class FileOpen extends ListActivity {
setListAdapter(filenamesAdapter);
}
private String handleZip(String name) {
if (NativeLib.tmpUncompressedFN!=null) {
File oldFile = new File(NativeLib.tmpUncompressedFN);
oldFile.delete();
}
try {
boolean handled = false;
ZipFile zf = new ZipFile(name);
Enumeration<? extends ZipEntry> zes = zf.entries();
while(zes.hasMoreElements() && !handled) {
ZipEntry ze = zes.nextElement();
String zename = ze.getName();
String zeext = zename.indexOf('.') > 0 ? zename.substring(zename.lastIndexOf('.') + 1) : "";
if (NativeLib.supportExt.contains(zeext.toLowerCase())) {
InputStream is = zf.getInputStream(ze);
int offset = 0;
long filesize = ze.getSize();
byte[] tempdata = new byte[(int)filesize];
while (offset<filesize)
offset += is.read(tempdata, offset, (int)filesize-offset);
is.close();
name = NativeLib.tmpUncompressedFN =
NativeLib.sdcardDir + "/" + NativeLib.tmpFilePrefix + zename;
File outfile = new File(NativeLib.tmpUncompressedFN);
outfile.delete();
outfile.createNewFile();
FileOutputStream fo = new FileOutputStream(outfile);
fo.write(tempdata);
fo.close();
handled = true;
}
}
zf.close();
} catch (IOException e) { }
System.gc();
return name;
}
class ModifiedTextLayout extends LinearLayout {
public ModifiedTextLayout(final Context context, final String path, final int position) {
@ -146,14 +217,14 @@ public class FileOpen extends ListActivity {
final TextView textView = new TextView(context);
textView.setTextAppearance(context, R.style.ListText);
if (file.isDirectory()) {
textView.setText("/" + file.getName());
} else {
textView.setText(file.getName());
}
addView(textView, new LinearLayout.LayoutParams(
LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
}

View File

@ -89,8 +89,6 @@ public class FileSave extends ListActivity {
saveButton = (Button) findViewById(R.id.save_btn);
saveButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final Intent extras = new Intent();
extras.putExtra("menuEventValue", NativeLib.MENU_FILE_SAVESNAPSHOT);
@ -106,7 +104,11 @@ public class FileSave extends ListActivity {
try {
showDirectory(NativeLib.startDir);
} catch (NullPointerException e) {
showDirectory("/");
try {
showDirectory(NativeLib.sdcardDir);
} catch (NullPointerException e2) {
showDirectory("/");
}
}
}
@ -128,6 +130,8 @@ public class FileSave extends ListActivity {
}
private void showDirectory(final String path) {
NativeLib.startDir = path;
this.currentFiles.clear();
this.currentDir = new File(path);

View File

@ -0,0 +1,43 @@
package com.drodin.zxdroid.menu;
import java.io.IOException;
import java.io.InputStream;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
import com.drodin.zxdroid.R;
public class HelpView extends Activity
{
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
try {
InputStream is = getAssets().open("help.txt");
int size = is.available();
byte[] buffer = new byte[size];
is.read(buffer);
is.close();
String text = new String(buffer);
setContentView(R.layout.help);
TextView tv = (TextView)findViewById(R.id.help_tv);
tv.setText(text);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -89,10 +89,19 @@ public class KeySelect extends Activity {
@Override
public boolean onKeyPreIme (int keyCode, KeyEvent event) {
if (keyCode>0 && keyCode<NativeLib.androidKeys.length)
setResult(RESULT_OK, new Intent().putExtra("androidKeyCode", keyCode));
finish();
return true;
if (event.getRepeatCount() == 0 && keyCode > 0 && keyCode < NativeLib.androidKeys.length) {
if (!NativeLib.interceptMenuBack && keyCode==KeyEvent.KEYCODE_MENU) {
return true;
} else if (!NativeLib.interceptMenuBack && keyCode==KeyEvent.KEYCODE_BACK) {
return false;
} else {
setResult(RESULT_OK, new Intent().putExtra("androidKeyCode", keyCode));
finish();
return true;
}
} else
return true;
}
};

View File

@ -54,17 +54,17 @@ implements Preference.OnPreferenceChangeListener {
settings = PreferenceManager.getDefaultSharedPreferences(this);
if (NativeLib.spectrumScreenWidth == NativeLib.mWidth)
findPreference("smoothScaling").setEnabled(false);
else
findPreference("smoothScaling").setOnPreferenceChangeListener(this);
findPreference("skipFrames").setOnPreferenceChangeListener(this);
findPreference("smoothScaling").setOnPreferenceChangeListener(this);
findPreference("soundEnabled").setOnPreferenceChangeListener(this);
findPreference("hideControls").setOnPreferenceChangeListener(this);
findPreference("onScreenControls").setSummary(NativeLib.onScreenControls);
findPreference("onScreenControls").setOnPreferenceChangeListener(this);
findPreference("interceptMenuBack").setOnPreferenceChangeListener(this);
NativeLib.currentMachine = NativeLib.cmachine();
SharedPreferences.Editor editor = settings.edit();
editor.putString("currentMachine", NativeLib.currentMachine);
editor.commit();
@ -81,6 +81,7 @@ implements Preference.OnPreferenceChangeListener {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK && requestCode == 0) {
setResult(RESULT_OK, data);
finish();
}
else if (requestCode == 1) {
SharedPreferences.Editor editor = settings.edit();
@ -91,7 +92,6 @@ implements Preference.OnPreferenceChangeListener {
editor.putString("definedKeys", definedKeysStr);
editor.commit();
}
finish();
}
@Override
@ -109,11 +109,17 @@ implements Preference.OnPreferenceChangeListener {
if (pref.getKey().equals("defineKeys")) {
startActivityForResult(new Intent(this, DefineKeys.class), 1);
}
if (pref.getKey().equals("help")) {
startActivityForResult(new Intent(this, HelpView.class), 0);
}
return super.onPreferenceTreeClick(screen, pref);
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
if (preference.getKey().equals("skipFrames")) {
NativeLib.skipFrames = (newValue.equals(false))?false:true;
finish();
}
if (preference.getKey().equals("smoothScaling")) {
NativeLib.smoothScaling = (newValue.equals(false))?false:true;
finish();
@ -122,6 +128,18 @@ implements Preference.OnPreferenceChangeListener {
NativeLib.soundEnabled = (newValue.equals(false))?false:true;
finish();
}
if (preference.getKey().equals("hideControls")) {
NativeLib.hideControls = (newValue.equals(false))?false:true;
finish();
}
if (preference.getKey().equals("interceptMenuBack")) {
NativeLib.interceptMenuBack = (newValue.equals(false))?false:true;
if (newValue.equals(true)) {
preference.setSummary(getString(R.string.intercept_warning));
} else {
preference.setSummary(null);
}
}
if (preference.getKey().equals("onScreenControls")) {
if (!NativeLib.onScreenControls.equals(newValue.toString())) {
NativeLib.onScreenControls = newValue.toString();

View File

@ -0,0 +1,59 @@
/***
Copyright (c) 2008-2009 CommonsWare, LLC
Licensed under the Apache License, Version 2.0 (the "License"); you may
not use this file except in compliance with the License. You may obtain
a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package com.drodin.zxdroid.menu;
import android.app.ListActivity;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.View;
import android.view.WindowManager;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import com.drodin.zxdroid.MainActivity;
import com.drodin.zxdroid.NativeLib;
import com.drodin.zxdroid.R;
public class SelectControl extends ListActivity {
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setTitle(R.string.onscreen_controls);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
setListAdapter(ArrayAdapter.createFromResource(
this, R.array.control_entries, android.R.layout.simple_list_item_1));
}
@Override
public void onListItemClick(ListView parent, View v, int position, long id) {
NativeLib.onScreenControls = getResources().getStringArray(R.array.control_entries)[position];
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);
SharedPreferences.Editor editor = settings.edit();
editor.putString("onScreenControls", NativeLib.onScreenControls);
editor.commit();
MainActivity.mSoftControls.switchControl(NativeLib.onScreenControls);
MainActivity.mSoftControls.setControlName();
finish();
}
}

View File

@ -0,0 +1,100 @@
/***
Copyright (c) 2008-2009 CommonsWare, LLC
Licensed under the Apache License, Version 2.0 (the "License"); you may
not use this file except in compliance with the License. You may obtain
a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package com.drodin.zxdroid.menu;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import android.app.ListActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.WindowManager;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import com.drodin.zxdroid.NativeLib;
import com.drodin.zxdroid.R;
public class WelcomeMenu extends ListActivity {
private int positionDelta = 0;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
ArrayList<String> menuItems =
new ArrayList<String>(Arrays.asList(getResources().getStringArray(R.array.welcome_menu)));
File lastSnapshot = new File("/data/data/" + getPackageName() + "/files/last.snapshot");
if (!lastSnapshot.exists()) {
menuItems.remove(0);
positionDelta++;
}
ArrayAdapter<String> menuItemsAdapter =
new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, menuItems);
setListAdapter(menuItemsAdapter);
}
@Override
public void onListItemClick(ListView parent, View v, int position, long id) {
position += positionDelta;
switch (position) {
case 0:
final Intent extras = new Intent();
extras.putExtra("menuEventValue", NativeLib.MENU_FILE_OPEN);
extras.putExtra("openFileName", "/data/data/" + getPackageName() + "/files/last.snapshot");
setResult(RESULT_OK, extras);
finish();
break;
case 1:
startActivityForResult(new Intent(this, FileOpen.class), 0);
break;
case 2:
startActivityForResult(new Intent(this, FileOpen.class).
putExtra("startDir", "/data/data/" + getPackageName() + "/files"), 0);
break;
case 3:
finish();
break;
case 4:
startActivityForResult(new Intent(this, HelpView.class), 0);
break;
default:
finish();
break;
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK && requestCode == 0) {
setResult(RESULT_OK, data);
}
finish();
}
}