1 /*
2 * datasette-sound.c - Sound of a cassette being played by the Datasette
3 *
4 * Written by
5 * Fabrizio Gennari <fabrizio.ge@tiscali.it>
6 *
7 * This file is part of VICE, the Versatile Commodore Emulator.
8 * See README for copyright notice.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
23 * 02111-1307 USA.
24 *
25 */
26
27 #include "vice.h"
28
29 #include "sound.h"
30 #include "maincpu.h"
31
32 static sound_chip_t datasette_sound;
33
34 static CLOCK gap_circular_buffer[200];
35 static const int gap_circular_buffer_size =
36 sizeof(gap_circular_buffer) / sizeof(gap_circular_buffer[0]);
37 static int gap_circular_buffer_start = 0;
38 static int gap_circular_buffer_end = 0;
39 static char last_was_split_in_two = 0;
40 static CLOCK sound_start_maincpu_clk;
41 static char datasette_square_sign = 1;
42 static char datasette_halfwaves;
43
44
45 /* resources */
46 extern int datasette_sound_emulation;
47 extern int datasette_sound_emulation_volume;
48
datasette_sound_flush_circular_buffer(void)49 static void datasette_sound_flush_circular_buffer(void)
50 {
51 datasette_sound.chip_enabled = 0;
52 gap_circular_buffer_end = gap_circular_buffer_start;
53 }
54
datasette_sound_set_halfwaves(char halfwaves)55 void datasette_sound_set_halfwaves(char halfwaves)
56 {
57 datasette_halfwaves = halfwaves;
58 }
59
datasette_sound_add_to_circular_buffer(CLOCK gap)60 void datasette_sound_add_to_circular_buffer(CLOCK gap)
61 {
62 if (!datasette_sound_emulation) {
63 datasette_sound_flush_circular_buffer();
64 return;
65 }
66 gap_circular_buffer[gap_circular_buffer_end] = gap;
67 if (datasette_sound.chip_enabled == 0) {
68 sound_start_maincpu_clk = maincpu_clk;
69 datasette_sound.chip_enabled = 1;
70 }
71 gap_circular_buffer_end =
72 (gap_circular_buffer_end + 1) % gap_circular_buffer_size;
73 if (gap_circular_buffer_end == gap_circular_buffer_start) {
74 gap_circular_buffer_start =
75 (gap_circular_buffer_start + 1) % gap_circular_buffer_size;
76 }
77 }
78
datasette_sound_remove_from_circular_buffer(CLOCK max_amount_to_remove,char divide_by_two,char * must_flip)79 static CLOCK datasette_sound_remove_from_circular_buffer(
80 CLOCK max_amount_to_remove, char divide_by_two, char *must_flip)
81 {
82 CLOCK gap = 0;
83 *must_flip = 0;
84 if (gap_circular_buffer_end != gap_circular_buffer_start) {
85 char try_again;
86 do {
87 try_again = 0;
88 gap = gap_circular_buffer[gap_circular_buffer_start];
89 if (divide_by_two && !last_was_split_in_two) {
90 gap /= 2;
91 }
92 if (gap > max_amount_to_remove) {
93 if (divide_by_two && !last_was_split_in_two) {
94 if (gap_circular_buffer_start == ((gap_circular_buffer_end + 1)
95 % gap_circular_buffer_size)) {
96 gap_circular_buffer_start = (gap_circular_buffer_start + 1)
97 % gap_circular_buffer_size;
98 try_again = 1;
99 continue;
100 }
101 gap_circular_buffer[gap_circular_buffer_start] -= gap;
102 gap_circular_buffer_start = gap_circular_buffer_start
103 ? gap_circular_buffer_start - 1
104 : gap_circular_buffer_size - 1;
105 gap_circular_buffer[gap_circular_buffer_start] = gap;
106 last_was_split_in_two = 1;
107 }
108 gap = max_amount_to_remove;
109 } else {
110 *must_flip = 1;
111 last_was_split_in_two = 0;
112 }
113 } while (try_again);
114 gap_circular_buffer[gap_circular_buffer_start] -= gap;
115 if (!gap_circular_buffer[gap_circular_buffer_start]) {
116 gap_circular_buffer_start = (gap_circular_buffer_start + 1)
117 % gap_circular_buffer_size;
118 if (gap_circular_buffer_end == gap_circular_buffer_start) {
119 datasette_sound.chip_enabled = 0;
120 }
121 }
122 }
123 return gap;
124 }
125
datasette_sound_machine_calculate_samples(sound_t ** psid,int16_t * pbuf,int nr,int soc,int scc,int * delta_t)126 static int datasette_sound_machine_calculate_samples(sound_t **psid,
127 int16_t *pbuf, int nr, int soc, int scc, int *delta_t)
128 {
129 int i = 0, j, num_samples;
130 int cycles_to_be_consumed = *delta_t;
131 double factor = (double)cycles_to_be_consumed / nr;
132 char must_flip;
133
134 if (sound_start_maincpu_clk) {
135 int initial_zero_samples =
136 (cycles_to_be_consumed + sound_start_maincpu_clk - maincpu_clk) / factor;
137 while (i < initial_zero_samples) {
138 pbuf[i++] = 0;
139 }
140 cycles_to_be_consumed = maincpu_clk - sound_start_maincpu_clk;
141 sound_start_maincpu_clk = 0;
142 }
143 while (cycles_to_be_consumed) {
144 CLOCK max_amount_to_consume = cycles_to_be_consumed;
145 CLOCK cycles_to_consume_now =
146 datasette_sound_remove_from_circular_buffer(max_amount_to_consume,
147 datasette_square_sign == 1 && !datasette_halfwaves, &must_flip);
148 if (!cycles_to_consume_now) {
149 break;
150 }
151 cycles_to_be_consumed -= cycles_to_consume_now;
152 if (i < nr) {
153 if (cycles_to_be_consumed == 0) {
154 num_samples = nr - i;
155 } else {
156 num_samples = cycles_to_consume_now / factor;
157 if (i + num_samples < nr - 1
158 && cycles_to_be_consumed * 1.0 / (nr-i-num_samples) < factor) {
159 num_samples++;
160 }
161 }
162 for (j = 0; j < num_samples; j++) {
163 pbuf[i++] =
164 datasette_sound_emulation_volume * datasette_square_sign;
165 }
166 }
167 if (must_flip)
168 datasette_square_sign = -datasette_square_sign;
169 }
170 while (i < nr) {
171 pbuf[i++] = 0;
172 }
173 return nr;
174 }
175
datasette_sound_machine_cycle_based(void)176 static int datasette_sound_machine_cycle_based(void)
177 {
178 return 0;
179 }
180
datasette_sound_machine_channels(void)181 static int datasette_sound_machine_channels(void)
182 {
183 return 1;
184 }
185
186 /* Drive sound 'chip', emulates the sound of a 1541 disk drive */
187 static sound_chip_t datasette_sound = {
188 NULL, /* NO sound chip open function */
189 NULL, /* NO sound chip init function */
190 NULL, /* NO sound chip close function */
191 datasette_sound_machine_calculate_samples, /* sound chip calculate samples function */
192 NULL, /* NO sound chip store function */
193 NULL, /* NO sound chip read function */
194 NULL, /* NO sound chip reset function */
195 datasette_sound_machine_cycle_based, /* sound chip 'is_cycle_based()' function, chip is NOT cycle based */
196 datasette_sound_machine_channels, /* sound chip 'get_amount_of_channels()' function, sound chip has 1 channel */
197 0 /* sound chip enabled flag, toggled upon device (de-)activation */
198 };
199
datasette_sound_init(void)200 void datasette_sound_init(void)
201 {
202 sound_chip_register(&datasette_sound);
203 }
204