src/mess/formats/jupi_tap.c
| r0 | r3264 | |
| 1 | /******************************************************************** |
| 2 | |
| 3 | Support for Jupiter Ace .tap cassette images |
| 4 | |
| 5 | For more information see: |
| 6 | - http://www.jupiter-ace.co.uk/faq_ace_tap_format.html |
| 7 | - http://www.jupiter-ace.co.uk/doc_AceTapeFormat.html |
| 8 | |
| 9 | ********************************************************************/ |
| 10 | #include "jupi_tap.h" |
| 11 | |
| 12 | |
| 13 | #define SMPLO -32768 |
| 14 | #define SILENCE 0 |
| 15 | #define SMPHI 32767 |
| 16 | |
| 17 | |
| 18 | static int cas_size; |
| 19 | |
| 20 | |
| 21 | /******************************************************************* |
| 22 | Generate one high-low cycle of sample data |
| 23 | ********************************************************************/ |
| 24 | INLINE int jupiter_tap_cycle(INT16 *buffer, int sample_pos, int high, int low) |
| 25 | { |
| 26 | int i = 0; |
| 27 | |
| 28 | if ( buffer ) |
| 29 | { |
| 30 | while( i < high) |
| 31 | { |
| 32 | buffer[ sample_pos + i ] = SMPHI; |
| 33 | i++; |
| 34 | } |
| 35 | |
| 36 | while( i < high + low ) |
| 37 | { |
| 38 | buffer[ sample_pos + i ] = SMPLO; |
| 39 | i++; |
| 40 | } |
| 41 | } |
| 42 | return high + low; |
| 43 | } |
| 44 | |
| 45 | |
| 46 | INLINE int jupiter_tap_silence(INT16 *buffer, int sample_pos, int samples) |
| 47 | { |
| 48 | int i = 0; |
| 49 | |
| 50 | if ( buffer ) |
| 51 | { |
| 52 | while( i < samples ) |
| 53 | { |
| 54 | buffer[ sample_pos + i ] = SILENCE; |
| 55 | i++; |
| 56 | } |
| 57 | } |
| 58 | return samples; |
| 59 | } |
| 60 | |
| 61 | |
| 62 | static int jupiter_handle_tap(INT16 *buffer, const UINT8 *casdata) |
| 63 | { |
| 64 | int data_pos, sample_count; |
| 65 | |
| 66 | /* Make sure the file starts with a valid header */ |
| 67 | if ( cas_size < 0x1C ) |
| 68 | return -1; |
| 69 | if ( casdata[0] != 0x1A || casdata[1] != 0x00 ) |
| 70 | return -1; |
| 71 | |
| 72 | data_pos = 0; |
| 73 | sample_count = 0; |
| 74 | |
| 75 | while( data_pos < cas_size ) |
| 76 | { |
| 77 | UINT16 block_size; |
| 78 | int i; |
| 79 | |
| 80 | /* Handle a block of tape data */ |
| 81 | block_size = casdata[data_pos] + ( casdata[data_pos + 1] << 8 ); |
| 82 | data_pos += 2; |
| 83 | |
| 84 | /* Make sure there are enough bytes left */ |
| 85 | if ( data_pos > cas_size ) |
| 86 | return -1; |
| 87 | |
| 88 | /* 2 seconds silence */ |
| 89 | sample_count += jupiter_tap_silence( buffer, sample_count, 2 * 44100 ); |
| 90 | |
| 91 | /* Add pilot tone samples: 4096 for header, 512 for data */ |
| 92 | for( i = ( block_size == 0x001A ) ? 4096 : 512; i; i-- ) |
| 93 | sample_count += jupiter_tap_cycle( buffer, sample_count, 27, 27 ); |
| 94 | |
| 95 | /* Sync samples */ |
| 96 | sample_count += jupiter_tap_cycle( buffer, sample_count, 8, 11 ); |
| 97 | |
| 98 | /* Data samples */ |
| 99 | for ( ; block_size ; data_pos++, block_size-- ) |
| 100 | { |
| 101 | UINT8 data = casdata[data_pos]; |
| 102 | |
| 103 | for ( i = 0; i < 8; i++ ) |
| 104 | { |
| 105 | if ( data & 0x80 ) |
| 106 | sample_count += jupiter_tap_cycle( buffer, sample_count, 21, 22 ); |
| 107 | else |
| 108 | sample_count += jupiter_tap_cycle( buffer, sample_count, 10, 11 ); |
| 109 | |
| 110 | data <<= 1; |
| 111 | } |
| 112 | } |
| 113 | |
| 114 | /* End mark samples */ |
| 115 | sample_count += jupiter_tap_cycle( buffer, sample_count, 12, 57 ); |
| 116 | |
| 117 | /* 3 seconds silence */ |
| 118 | sample_count += jupiter_tap_silence( buffer, sample_count, 3 * 44100 ); |
| 119 | } |
| 120 | return sample_count; |
| 121 | } |
| 122 | |
| 123 | |
| 124 | /******************************************************************* |
| 125 | Generate samples for the tape image |
| 126 | ********************************************************************/ |
| 127 | static int jupiter_tap_fill_wave(INT16 *buffer, int sample_count, UINT8 *bytes) |
| 128 | { |
| 129 | return jupiter_handle_tap( buffer, bytes ); |
| 130 | } |
| 131 | |
| 132 | |
| 133 | /******************************************************************* |
| 134 | Calculate the number of samples needed for this tape image |
| 135 | ********************************************************************/ |
| 136 | static int jupiter_tap_to_wav_size(const UINT8 *casdata, int caslen) |
| 137 | { |
| 138 | cas_size = caslen; |
| 139 | |
| 140 | return jupiter_handle_tap( NULL, casdata ); |
| 141 | } |
| 142 | |
| 143 | |
| 144 | static const struct CassetteLegacyWaveFiller jupiter_legacy_fill_wave = |
| 145 | { |
| 146 | jupiter_tap_fill_wave, /* fill_wave */ |
| 147 | -1, /* chunk_size */ |
| 148 | 0, /* chunk_samples */ |
| 149 | jupiter_tap_to_wav_size, /* chunk_sample_calc */ |
| 150 | 44100, /* sample_frequency */ |
| 151 | 0, /* header_samples */ |
| 152 | 0 /* trailer_samples */ |
| 153 | }; |
| 154 | |
| 155 | |
| 156 | static casserr_t jupiter_tap_identify(cassette_image *cassette, struct CassetteOptions *opts) |
| 157 | { |
| 158 | return cassette_legacy_identify(cassette, opts, &jupiter_legacy_fill_wave); |
| 159 | } |
| 160 | |
| 161 | |
| 162 | static casserr_t jupiter_tap_load(cassette_image *cassette) |
| 163 | { |
| 164 | return cassette_legacy_construct(cassette, &jupiter_legacy_fill_wave); |
| 165 | } |
| 166 | |
| 167 | |
| 168 | static const struct CassetteFormat jupiter_tap_format = |
| 169 | { |
| 170 | "tap", |
| 171 | jupiter_tap_identify, |
| 172 | jupiter_tap_load, |
| 173 | NULL |
| 174 | }; |
| 175 | |
| 176 | |
| 177 | CASSETTE_FORMATLIST_START(jupiter_cassette_formats) |
| 178 | CASSETTE_FORMAT(jupiter_tap_format) |
| 179 | CASSETTE_FORMATLIST_END |
src/mess/drivers/jupiter.c
| r3263 | r3264 | |
| 32 | 32 | #include "devices/cartslot.h" |
| 33 | 33 | #include "devices/cassette.h" |
| 34 | 34 | #include "sound/speaker.h" |
| 35 | #include "formats/jupi_tap.h" |
| 35 | 36 | |
| 37 | |
| 36 | 38 | /* This needs to be moved to drivers/xtal */ |
| 37 | 39 | #define XTAL_6_5MHz 6500000 |
| 38 | 40 | |
| r3263 | r3264 | |
| 289 | 291 | return 0; |
| 290 | 292 | } |
| 291 | 293 | |
| 294 | |
| 295 | static cassette_config jupiter_cassette_config = |
| 296 | { |
| 297 | jupiter_cassette_formats, |
| 298 | NULL, |
| 299 | CASSETTE_STOPPED |
| 300 | }; |
| 301 | |
| 292 | 302 | /* machine definition */ |
| 293 | 303 | static MACHINE_DRIVER_START( jupiter ) |
| 294 | 304 | /* basic machine hardware */ |
| r3263 | r3264 | |
| 316 | 326 | MDRV_SOUND_ADD("speaker", SPEAKER, 0) |
| 317 | 327 | MDRV_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.00) |
| 318 | 328 | |
| 319 | | MDRV_CASSETTE_ADD( "cassette", default_cassette_config ) |
| 329 | MDRV_CASSETTE_ADD( "cassette", jupiter_cassette_config ) |
| 320 | 330 | MACHINE_DRIVER_END |
| 321 | 331 | |
| 322 | 332 | |