1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
// license:BSD-3-Clause
// copyright-holders:Olivier Galibert
/*
Tape support for Orao TAP format
*/
#include <cassert>
#include "orao_cas.h"
#define ORAO_WAV_FREQUENCY 44100
#define WAVE_HIGH -32768
#define WAVE_LOW 0
#define ORAO_WAVE_ONE 24
#define ORAO_WAVE_ZERO 11
#define ORAO_HEADER_SIZE 360
static int16_t wave_data;
static int len;
static void orao_output_wave( int16_t **buffer, int length ) {
if ( buffer == nullptr ) {
return;
}
for( ; length > 0; length-- ) {
**buffer = wave_data;
*buffer = *buffer + 1;
}
}
static int orao_cas_to_wav_size( const uint8_t *casdata, int caslen ) {
int i,j,size;
uint8_t b;
if (casdata == nullptr) return -1;
if (caslen <= ORAO_HEADER_SIZE) {
return -1;
}
size = 0;
for (i=ORAO_HEADER_SIZE;i<caslen-ORAO_HEADER_SIZE;i++) {
for (j=0;j<8;j++) {
b = (casdata[i] >> j) & 1;
if (b==0) {
size += 2*ORAO_WAVE_ZERO;
} else {
size += 2*ORAO_WAVE_ONE;
}
}
}
len = caslen;
return size;
}
static int orao_cas_fill_wave( int16_t *buffer, int length, uint8_t *bytes ) {
int i,j,size;
uint8_t b;
size = 0;
if (bytes == nullptr) return -1;
for (i=ORAO_HEADER_SIZE;i<len-ORAO_HEADER_SIZE;i++) {
for (j=0;j<8;j++) {
b = (bytes[i] >> j) & 1;
if (b==0) {
wave_data = WAVE_LOW;
orao_output_wave(&buffer,ORAO_WAVE_ZERO);
wave_data = WAVE_HIGH;
orao_output_wave(&buffer,ORAO_WAVE_ZERO);
size += 2 *ORAO_WAVE_ZERO;
} else {
wave_data = WAVE_LOW;
orao_output_wave(&buffer,ORAO_WAVE_ONE);
wave_data = WAVE_HIGH;
orao_output_wave(&buffer,ORAO_WAVE_ONE);
size += 2 * ORAO_WAVE_ONE;
}
}
}
return size;
}
static const struct CassetteLegacyWaveFiller orao_legacy_fill_wave = {
orao_cas_fill_wave, /* fill_wave */
-1, /* chunk_size */
0, /* chunk_samples */
orao_cas_to_wav_size, /* chunk_sample_calc */
ORAO_WAV_FREQUENCY, /* sample_frequency */
0, /* header_samples */
0 /* trailer_samples */
};
static cassette_image::error orao_cassette_identify( cassette_image *cassette, struct CassetteOptions *opts ) {
return cassette_legacy_identify( cassette, opts, &orao_legacy_fill_wave );
}
static cassette_image::error orao_cassette_load( cassette_image *cassette ) {
return cassette_legacy_construct( cassette, &orao_legacy_fill_wave );
}
static const struct CassetteFormat orao_cassette_format = {
"tap",
orao_cassette_identify,
orao_cassette_load,
nullptr
};
CASSETTE_FORMATLIST_START(orao_cassette_formats)
CASSETTE_FORMAT(orao_cassette_format)
CASSETTE_FORMATLIST_END
|