Compare commits
5 Commits
c806579f78
...
728a5de29e
Author | SHA1 | Date |
---|---|---|
Ciaran Gultnieks | 728a5de29e | |
Ciaran Gultnieks | 48a94ece36 | |
Ciaran Gultnieks | f31ddb149b | |
Dmitr Rodin | 3cd165edd5 | |
Dmitr Rodin | b510db8d5f |
|
@ -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
|
|
@ -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" />
|
||||
|
|
BIN
assets/files.zip
BIN
assets/files.zip
Binary file not shown.
|
@ -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!
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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;
|
|
@ -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,13 +131,11 @@ 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;
|
||||
|
||||
if( machine_current->capabilities & LIBSPECTRUM_MACHINE_CAPABILITY_AY ) {
|
||||
|
||||
ay_registerport_write( 0xfffd,
|
||||
libspectrum_snap_out_ay_registerport( snap ) );
|
||||
|
||||
|
@ -146,7 +144,13 @@ ay_from_snapshot( libspectrum_snap *snap )
|
|||
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_state_from_snapshot( snap );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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] );
|
||||
}
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
|
@ -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:
|
||||
|
|
|
@ -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 );
|
||||
}
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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 );
|
||||
|
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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,14 +37,23 @@ 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));
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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 */
|
|
@ -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
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
@ -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 |
|
@ -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>
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
||||
|
|
|
@ -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,16 +9,22 @@
|
|||
<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 & 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>
|
||||
<string name="save_ext">.sna</string>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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,19 +132,33 @@ public class MainActivity extends Activity implements AdListener {
|
|||
mInnerLayout.addView(mMainView,
|
||||
new LayoutParams(NativeLib.mWidth, NativeLib.mHeight));
|
||||
mMainLayout.addView(mInnerLayout);
|
||||
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);
|
||||
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.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);
|
||||
}
|
||||
|
||||
|
@ -170,8 +174,13 @@ public class MainActivity extends Activity implements AdListener {
|
|||
|
||||
@Override
|
||||
public void onConfigurationChanged (Configuration newConfig) {
|
||||
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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
@ -46,6 +46,8 @@ public class MainView extends GLSurfaceView {
|
|||
public MainView(Context context) {
|
||||
super(context);
|
||||
|
||||
mMainActivity = MainActivity.currentInstance;
|
||||
|
||||
setId((int)Math.random()*100);
|
||||
|
||||
setFocusable(true);
|
||||
|
@ -60,22 +62,52 @@ 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) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
E-mail: rodin.dmitry@gmail.com
|
||||
|
||||
*/
|
||||
*/
|
||||
|
||||
package com.drodin.zxdroid;
|
||||
|
||||
|
@ -36,6 +36,8 @@ public class NativeLib {
|
|||
public static volatile String openFileName = "";
|
||||
public static volatile String saveFileName = "";
|
||||
|
||||
public static boolean skipFrames;
|
||||
|
||||
public static boolean smoothScaling;
|
||||
|
||||
public static boolean soundEnabled;
|
||||
|
@ -45,27 +47,28 @@ public class NativeLib {
|
|||
|
||||
public static String currentMachine;
|
||||
|
||||
public static void setCurrentMachine(String machine) {
|
||||
currentMachine = machine;
|
||||
}
|
||||
|
||||
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 int spectrumScreenWidth = 320;
|
||||
public static int spectrumScreenHeight = 240;
|
||||
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;
|
||||
|
||||
|
@ -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 = {
|
||||
|
@ -109,10 +117,18 @@ public class NativeLib {
|
|||
"KEMPSTON UP", "KEMPSTON DOWN", "KEMPSTON LEFT", "KEMPSTON RIGHT", "KEMPSTON FIRE"
|
||||
};
|
||||
|
||||
public static int spectrumKeyCap = 59;
|
||||
public static int spectrumKeySym = 58;
|
||||
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];
|
||||
public static String defaultDefinedKeys = "19:101;20:102;21:103;22:104;23:105;"; //DPAD as Kempston
|
||||
// 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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onRelease(final int primaryCode) {
|
||||
if (primaryCode!=Keyboard.KEYCODE_SHIFT && primaryCode!=Keyboard.KEYCODE_ALT) {
|
||||
if (lastKeyCode1!=0)
|
||||
if (lastKeyCode1!=0) {
|
||||
NativeLib.eventQueue.add(NativeLib.KEY_RELEASE + lastKeyCode1);
|
||||
if (lastKeyCode2!=0)
|
||||
NativeLib.eventQueue.add(NativeLib.KEY_RELEASE + lastKeyCode2);
|
||||
lastKeyCode1 = 0;
|
||||
}
|
||||
if (lastKeyCode2!=0) {
|
||||
NativeLib.eventQueue.add(NativeLib.KEY_RELEASE + lastKeyCode2);
|
||||
lastKeyCode2 = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onText(CharSequence text) {
|
||||
}
|
||||
|
||||
|
|
|
@ -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,6 +53,8 @@ import com.drodin.zxdroid.R;
|
|||
|
||||
public class FileOpen extends ListActivity {
|
||||
|
||||
private String startDir;
|
||||
|
||||
private final static String PARENT_DIR = "..";
|
||||
|
||||
private TextView pathView;
|
||||
|
@ -66,13 +74,23 @@ public class FileOpen extends ListActivity {
|
|||
|
||||
pathView = (TextView) findViewById(R.id.file_tv);
|
||||
|
||||
startDir = getIntent().getStringExtra("startDir");
|
||||
|
||||
try {
|
||||
if(startDir != null)
|
||||
showDirectory(startDir);
|
||||
else
|
||||
showDirectory(NativeLib.startDir);
|
||||
} catch (NullPointerException e) {
|
||||
try {
|
||||
showDirectory(NativeLib.sdcardDir);
|
||||
} catch (NullPointerException e2) {
|
||||
showDirectory("/");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onListItemClick(final ListView l, final View v, final int position, final long id) {
|
||||
if (position == 0 && PARENT_DIR.equals(this.currentFiles.get(0))) {
|
||||
|
@ -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) {
|
||||
|
|
|
@ -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,9 +104,13 @@ public class FileSave extends ListActivity {
|
|||
try {
|
||||
showDirectory(NativeLib.startDir);
|
||||
} catch (NullPointerException e) {
|
||||
try {
|
||||
showDirectory(NativeLib.sdcardDir);
|
||||
} catch (NullPointerException e2) {
|
||||
showDirectory("/");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onListItemClick(final ListView l, final View v, final int position, final long id) {
|
||||
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -89,11 +89,20 @@ public class KeySelect extends Activity {
|
|||
|
||||
@Override
|
||||
public boolean onKeyPreIme (int keyCode, KeyEvent event) {
|
||||
if (keyCode>0 && keyCode<NativeLib.androidKeys.length)
|
||||
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;
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
final LinearLayout parentContainer = new LinearLayout(this) {
|
||||
|
|
|
@ -54,17 +54,17 @@ implements Preference.OnPreferenceChangeListener {
|
|||
|
||||
settings = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
|
||||
if (NativeLib.spectrumScreenWidth == NativeLib.mWidth)
|
||||
findPreference("smoothScaling").setEnabled(false);
|
||||
else
|
||||
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);
|
||||
|
||||
NativeLib.currentMachine = NativeLib.cmachine();
|
||||
findPreference("interceptMenuBack").setOnPreferenceChangeListener(this);
|
||||
|
||||
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();
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue