summaryrefslogtreecommitdiffstats
path: root/src/lib/formats/orao_cas.cpp
blob: a580fdef07768479d7d691c02d988e3857c5094e (plain) (blame)
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
123
124
125
126
127
128
129
130
// license:BSD-3-Clause
// copyright-holders:Olivier Galibert
/*

    Tape support for Orao  TAP format

*/

#include "orao_cas.h"


#define ORAO_WAV_FREQUENCY  44100
#define WAVE_HIGH       -24576
#define WAVE_LOW        24576

#define ORAO_WAVE_ONE   17
#define ORAO_WAVE_ZERO  9

#define ORAO_HEADER_SIZE 360

static int16_t    wave_data; // FIXME: global variables prevent multiple instances
static int        len;
static int        startpos;
static bool       newformat;

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;
	startpos = 0;
	newformat = true;
	if (casdata[0]==0x68 && casdata[1]==0x01 && casdata[2]==0x00) {
		startpos = ORAO_HEADER_SIZE;
		newformat = false;
	}
	for (i=startpos;i<caslen-startpos;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,k;
	uint8_t b;
	size = 0;
	if (bytes == nullptr) return -1;
	for (i=startpos;i<len-startpos;i++) {
		for (j=0;j<8;j++) {
			k = newformat ? (7-j) : j;
			b = (bytes[i] >> k) & 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 cassette_image::LegacyWaveFiller 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, cassette_image::Options *opts ) {
	return cassette->legacy_identify( opts, &orao_legacy_fill_wave );
}



static cassette_image::error orao_cassette_load( cassette_image *cassette ) {
	return cassette->legacy_construct( &orao_legacy_fill_wave );
}



static const cassette_image::Format 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