rlm@0
|
1 /* Loads "test.spc", skips 5 seconds, saves exact emulator state to "state.bin",
|
rlm@0
|
2 hen records 5 seconds to "first.wav". When run again, loads this state back into
|
rlm@0
|
3 emulator and records 5 seconds to "second.wav". These two wave files should
|
rlm@0
|
4 be identical.
|
rlm@0
|
5
|
rlm@0
|
6 Usage: save_state [test.spc]
|
rlm@0
|
7 */
|
rlm@0
|
8
|
rlm@0
|
9 #include "snes_spc/spc.h"
|
rlm@0
|
10
|
rlm@0
|
11 #include "wave_writer.h"
|
rlm@0
|
12 #include "demo_util.h" /* error(), load_file() */
|
rlm@0
|
13
|
rlm@0
|
14 static SNES_SPC* snes_spc;
|
rlm@0
|
15
|
rlm@0
|
16 void record_wav( const char* path, int secs )
|
rlm@0
|
17 {
|
rlm@0
|
18 /* Start writing wave file */
|
rlm@0
|
19 wave_open( spc_sample_rate, path );
|
rlm@0
|
20 wave_enable_stereo();
|
rlm@0
|
21 while ( wave_sample_count() < secs * spc_sample_rate * 2 )
|
rlm@0
|
22 {
|
rlm@0
|
23 /* Play into buffer */
|
rlm@0
|
24 #define BUF_SIZE 2048
|
rlm@0
|
25 short buf [BUF_SIZE];
|
rlm@0
|
26 error( spc_play( snes_spc, BUF_SIZE, buf ) );
|
rlm@0
|
27
|
rlm@0
|
28 wave_write( buf, BUF_SIZE );
|
rlm@0
|
29 }
|
rlm@0
|
30 wave_close();
|
rlm@0
|
31 }
|
rlm@0
|
32
|
rlm@0
|
33 void state_save( unsigned char** out, void* in, size_t size )
|
rlm@0
|
34 {
|
rlm@0
|
35 memcpy( *out, in, size );
|
rlm@0
|
36 *out += size;
|
rlm@0
|
37 }
|
rlm@0
|
38
|
rlm@0
|
39 void make_save_state( const char* path )
|
rlm@0
|
40 {
|
rlm@0
|
41 /* Load SPC */
|
rlm@0
|
42 long spc_size;
|
rlm@0
|
43 void* spc = load_file( path, &spc_size );
|
rlm@0
|
44 error( spc_load_spc( snes_spc, spc, spc_size ) );
|
rlm@0
|
45 free( spc );
|
rlm@0
|
46 spc_clear_echo( snes_spc );
|
rlm@0
|
47
|
rlm@0
|
48 /* Skip several seconds */
|
rlm@0
|
49 error( spc_play( snes_spc, 5 * spc_sample_rate * 2, 0 ) );
|
rlm@0
|
50
|
rlm@0
|
51 /* Save state to file */
|
rlm@0
|
52 {
|
rlm@0
|
53 static unsigned char state [spc_state_size]; /* buffer large enough for data */
|
rlm@0
|
54 unsigned char* out = state;
|
rlm@0
|
55 spc_copy_state( snes_spc, &out, state_save );
|
rlm@0
|
56 write_file( "state.bin", state, out - state );
|
rlm@0
|
57 }
|
rlm@0
|
58
|
rlm@0
|
59 record_wav( "first.wav", 5 );
|
rlm@0
|
60 }
|
rlm@0
|
61
|
rlm@0
|
62 void state_load( unsigned char** in, void* out, size_t size )
|
rlm@0
|
63 {
|
rlm@0
|
64 memcpy( out, *in, size );
|
rlm@0
|
65 *in += size;
|
rlm@0
|
66 }
|
rlm@0
|
67
|
rlm@0
|
68 void use_save_state()
|
rlm@0
|
69 {
|
rlm@0
|
70 /* Load state into memory */
|
rlm@0
|
71 long state_size;
|
rlm@0
|
72 unsigned char* state = load_file( "state.bin", &state_size );
|
rlm@0
|
73
|
rlm@0
|
74 /* Load into emulator */
|
rlm@0
|
75 unsigned char* in = state;
|
rlm@0
|
76 spc_copy_state( snes_spc, &in, state_load );
|
rlm@0
|
77 assert( in - state <= state_size ); /* be sure it didn't read past end */
|
rlm@0
|
78
|
rlm@0
|
79 record_wav( "second.wav", 5 );
|
rlm@0
|
80 }
|
rlm@0
|
81
|
rlm@0
|
82 int file_exists( const char* path )
|
rlm@0
|
83 {
|
rlm@0
|
84 FILE* file = fopen( path, "rb" );
|
rlm@0
|
85 if ( !file )
|
rlm@0
|
86 return 0;
|
rlm@0
|
87
|
rlm@0
|
88 fclose( file );
|
rlm@0
|
89 return 1;
|
rlm@0
|
90 }
|
rlm@0
|
91
|
rlm@0
|
92 int main( int argc, char** argv )
|
rlm@0
|
93 {
|
rlm@0
|
94 snes_spc = spc_new();
|
rlm@0
|
95 if ( !snes_spc ) error( "Out of memory" );
|
rlm@0
|
96
|
rlm@0
|
97 /* Make new state if it doesn't exist, otherwise load it and
|
rlm@0
|
98 record to wave file */
|
rlm@0
|
99 if ( !file_exists( "state.bin" ) )
|
rlm@0
|
100 make_save_state( (argc > 1) ? argv [1] : "test.spc" );
|
rlm@0
|
101 else
|
rlm@0
|
102 use_save_state();
|
rlm@0
|
103
|
rlm@0
|
104 spc_delete( snes_spc );
|
rlm@0
|
105
|
rlm@0
|
106 return 0;
|
rlm@0
|
107 }
|