-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathtapdecoder.c
135 lines (115 loc) · 4.12 KB
/
tapdecoder.c
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
131
132
133
134
135
/* TAP shared library: a library for converting audio data (as a stream of
* PCM signed 32-bit samples, mono) to raw TAP data and back
*
* TAP specification was written by Per Håkan Sundell and is available at
* http://www.computerbrains.com/tapformat.html
*
* The algorithm to decode TAP data into square, sine or triangular waves
* is by Fabrizio Gennari.
*
* Copyright (c) Fabrizio Gennari, 2003-2012
*
* The program is distributed under the GNU Lesser General Public License.
* See file LESSER-LICENSE.TXT for details.
*/
#include <stdlib.h>
#include <sys/types.h>
/* When using GNU libc, math.h requires linking
with the additional library libm. Therefore,
HAVE_SINE_WAVE is disabled by default,
but it can be activated by setting a
Makefile variable */
#if (!defined __GNU_LIBRARY__ && (!defined _MSC_VER || _MSC_VER > 1200))
#define HAVE_SINE_WAVE
#endif
#ifdef HAVE_SINE_WAVE
#ifdef _MSC_VER
#define _USE_MATH_DEFINES
#endif /* _MSC_VER */
#include <math.h>
#endif /*HAVE_SINE_WAVE*/
#include "tapdecoder.h"
struct tap_dec_t{
uint8_t halfwaves;
uint32_t first_consumed, second_consumed, first_semiwave, second_semiwave, volume;
unsigned char negative;
int32_t (*get_val)(uint32_t to_be_consumed, uint32_t this_pulse_len, uint32_t volume);
};
static int32_t tap_get_triangle_val(uint32_t to_be_consumed, uint32_t this_pulse_len, uint32_t volume){
int64_t in;
to_be_consumed = (to_be_consumed < this_pulse_len / 2) ?
to_be_consumed + 1 :
this_pulse_len - 1 - to_be_consumed;
in = ((int64_t)to_be_consumed)*volume*2;
return (int32_t)(in / this_pulse_len);
}
#ifdef HAVE_SINE_WAVE
static int32_t tap_get_sinewave_val(uint32_t to_be_consumed, uint32_t this_pulse_len, uint32_t volume){
double angle=(M_PI*(to_be_consumed+1))/this_pulse_len;
return (int32_t)(volume*sin(angle));
}
#endif
static int32_t tap_get_squarewave_val(uint32_t this_pulse_len, uint32_t to_be_consumed, uint32_t volume){
return volume;
}
static uint32_t tap_semiwave(int32_t **buffer
,uint32_t *buflen
,uint32_t semiwave_len
,uint32_t *consumed
,uint32_t volume
,int32_t (*get_val_func)(uint32_t, uint32_t, uint32_t)
,unsigned char *negative
){
uint32_t samples_done = 0;
for(;*buflen > 0 && *consumed < semiwave_len; (*buffer)++, (*buflen)--, (*consumed)++, samples_done++){
**buffer = get_val_func(*consumed, semiwave_len, volume);
if (*negative)
**buffer = ~(**buffer);
}
if (*consumed == semiwave_len && samples_done != 0)
*negative = !(*negative);
return samples_done;
}
struct tap_dec_t *tapdec_init2(uint8_t volume, uint8_t inverted, enum tapdec_waveform waveform){
struct tap_dec_t *tap;
tap = (struct tap_dec_t *)malloc(sizeof(struct tap_dec_t));
if (tap==NULL)
return NULL;
tap->halfwaves = 0;
tap->volume=volume<<23;
tap->negative=inverted;
switch (waveform){
case TAPDEC_TRIANGLE:
default:
tap->get_val = tap_get_triangle_val;
break;
case TAPDEC_SQUARE:
tap->get_val = tap_get_squarewave_val;
break;
#ifdef HAVE_SINE_WAVE
case TAPDEC_SINE:
tap->get_val = tap_get_sinewave_val;
break;
#endif
}
return tap;
}
void tapdec_set_pulse(struct tap_dec_t *tap, uint32_t pulse){
tap->first_consumed=tap->second_consumed=0;
if (pulse==1 && !tap->halfwaves)
pulse=0;
tap->second_semiwave = tap->halfwaves ? 0 : pulse / 2;
tap->first_semiwave=pulse - tap->second_semiwave;
}
uint32_t tapdec_get_buffer(struct tap_dec_t *tap, int32_t *buffer, uint32_t buflen){
uint32_t samples_done_first = tap_semiwave(&buffer, &buflen, tap->first_semiwave, &tap->first_consumed, tap->volume, tap->get_val, &tap->negative);
uint32_t samples_done_second = tap_semiwave(&buffer, &buflen, tap->second_semiwave, &tap->second_consumed, tap->volume, tap->get_val, &tap->negative);
return samples_done_first + samples_done_second;
}
void tapdec_enable_halfwaves(struct tap_dec_t *tap, uint8_t halfwaves){
tap->halfwaves = halfwaves;
}
void tapdec_exit(struct tap_dec_t *tap)
{
free(tap);
}