... | ... |
@@ -16,6 +16,14 @@ WITH REGARD TO THIS SOFTWARE. |
16 | 16 |
#define NOTE_PERIOD (SAMPLE_FREQUENCY * 0x4000 / 11025) |
17 | 17 |
#define ADSR_STEP (SAMPLE_FREQUENCY / 0xf) |
18 | 18 |
|
19 |
+typedef struct { |
|
20 |
+ Uint8 *addr; |
|
21 |
+ Uint32 count, advance, period, age, a, d, s, r; |
|
22 |
+ Uint16 i, len; |
|
23 |
+ Sint8 volume[2]; |
|
24 |
+ Uint8 pitch, repeat; |
|
25 |
+} UxnAudio; |
|
26 |
+ |
|
19 | 27 |
/* clang-format off */ |
20 | 28 |
|
21 | 29 |
static Uint32 advances[12] = { |
... | ... |
@@ -23,7 +31,7 @@ static Uint32 advances[12] = { |
23 | 31 |
0xb504f, 0xbfc88, 0xcb2ff, 0xd7450, 0xe411f, 0xf1a1c |
24 | 32 |
}; |
25 | 33 |
|
26 |
-UxnAudio uxn_audio[POLYPHONY]; |
|
34 |
+static UxnAudio uxn_audio[POLYPHONY]; |
|
27 | 35 |
|
28 | 36 |
/* clang-format on */ |
29 | 37 |
|
... | ... |
@@ -40,8 +48,9 @@ envelope(UxnAudio *c, Uint32 age) |
40 | 48 |
} |
41 | 49 |
|
42 | 50 |
int |
43 |
-audio_render(UxnAudio *c, Sint16 *sample, Sint16 *end) |
|
51 |
+audio_render(int instance, Sint16 *sample, Sint16 *end) |
|
44 | 52 |
{ |
53 |
+ UxnAudio *c = &uxn_audio[instance]; |
|
45 | 54 |
Sint32 s; |
46 | 55 |
if(!c->advance || !c->period) return 0; |
47 | 56 |
while(sample < end) { |
... | ... |
@@ -59,13 +68,26 @@ audio_render(UxnAudio *c, Sint16 *sample, Sint16 *end) |
59 | 68 |
*sample++ += s * c->volume[0] / 0x180; |
60 | 69 |
*sample++ += s * c->volume[1] / 0x180; |
61 | 70 |
} |
62 |
- if(!c->advance) audio_finished_handler(c); |
|
71 |
+ if(!c->advance) audio_finished_handler(instance); |
|
63 | 72 |
return 1; |
64 | 73 |
} |
65 | 74 |
|
66 | 75 |
void |
67 |
-audio_start(UxnAudio *c, Uint16 adsr, Uint8 pitch) |
|
76 |
+audio_start(int instance, Device *d) |
|
68 | 77 |
{ |
78 |
+ UxnAudio *c = &uxn_audio[instance]; |
|
79 |
+ Uint16 addr, adsr; |
|
80 |
+ Uint8 pitch; |
|
81 |
+ DEVPEEK16(adsr, 0x8); |
|
82 |
+ DEVPEEK16(c->len, 0xa); |
|
83 |
+ DEVPEEK16(addr, 0xc); |
|
84 |
+ if(c->len > 0x10000 - addr) |
|
85 |
+ c->len = 0x10000 - addr; |
|
86 |
+ c->addr = &d->u->ram[addr]; |
|
87 |
+ c->volume[0] = d->dat[0xe] >> 4; |
|
88 |
+ c->volume[1] = d->dat[0xe] & 0xf; |
|
89 |
+ c->repeat = !(d->dat[0xf] & 0x80); |
|
90 |
+ pitch = d->dat[0xf] & 0x7f; |
|
69 | 91 |
if(pitch < 108 && c->len) |
70 | 92 |
c->advance = advances[pitch % 12] >> (8 - pitch / 12); |
71 | 93 |
else { |
... | ... |
@@ -85,8 +107,9 @@ audio_start(UxnAudio *c, Uint16 adsr, Uint8 pitch) |
85 | 107 |
} |
86 | 108 |
|
87 | 109 |
Uint8 |
88 |
-audio_get_vu(UxnAudio *c) |
|
110 |
+audio_get_vu(int instance) |
|
89 | 111 |
{ |
112 |
+ UxnAudio *c = &uxn_audio[instance]; |
|
90 | 113 |
int i; |
91 | 114 |
Sint32 sum[2] = {0, 0}; |
92 | 115 |
if(!c->advance || !c->period) return 0; |
... | ... |
@@ -97,3 +120,10 @@ audio_get_vu(UxnAudio *c) |
97 | 120 |
} |
98 | 121 |
return (sum[0] << 4) | sum[1]; |
99 | 122 |
} |
123 |
+ |
|
124 |
+Uint16 |
|
125 |
+audio_get_position(int instance) |
|
126 |
+{ |
|
127 |
+ UxnAudio *c = &uxn_audio[instance]; |
|
128 |
+ return c->i; |
|
129 |
+} |
... | ... |
@@ -15,17 +15,8 @@ typedef signed int Sint32; |
15 | 15 |
#define SAMPLE_FREQUENCY 44100 |
16 | 16 |
#define POLYPHONY 4 |
17 | 17 |
|
18 |
-typedef struct { |
|
19 |
- Uint8 *addr; |
|
20 |
- Uint32 count, advance, period, age, a, d, s, r; |
|
21 |
- Uint16 i, len; |
|
22 |
- Sint8 volume[2]; |
|
23 |
- Uint8 pitch, repeat; |
|
24 |
-} UxnAudio; |
|
25 |
- |
|
26 |
-extern UxnAudio uxn_audio[POLYPHONY]; |
|
27 |
- |
|
28 |
-Uint8 audio_get_vu(UxnAudio *c); |
|
29 |
-int audio_render(UxnAudio *c, Sint16 *sample, Sint16 *end); |
|
30 |
-void audio_start(UxnAudio *c, Uint16 adsr, Uint8 pitch); |
|
31 |
-void audio_finished_handler(UxnAudio *c); |
|
18 |
+Uint8 audio_get_vu(int instance); |
|
19 |
+Uint16 audio_get_position(int instance); |
|
20 |
+int audio_render(int instance, Sint16 *sample, Sint16 *end); |
|
21 |
+void audio_start(int instance, Device *d); |
|
22 |
+void audio_finished_handler(int instance); |
... | ... |
@@ -19,29 +19,32 @@ WITH REGARD TO THIS SOFTWARE. |
19 | 19 |
#include <sys/stat.h> |
20 | 20 |
#include <unistd.h> |
21 | 21 |
|
22 |
-static FILE *f; |
|
23 |
-static DIR *dir; |
|
24 |
-static char *current_filename = ""; |
|
25 |
-static struct dirent *de; |
|
26 |
- |
|
27 |
-static enum { IDLE, |
|
28 |
- FILE_READ, |
|
29 |
- FILE_WRITE, |
|
30 |
- DIR_READ } state; |
|
22 |
+typedef struct { |
|
23 |
+ FILE *f; |
|
24 |
+ DIR *dir; |
|
25 |
+ char current_filename[4096]; |
|
26 |
+ struct dirent *de; |
|
27 |
+ enum { IDLE, |
|
28 |
+ FILE_READ, |
|
29 |
+ FILE_WRITE, |
|
30 |
+ DIR_READ } state; |
|
31 |
+} UxnFile; |
|
32 |
+ |
|
33 |
+static UxnFile uxn_file[POLYFILEY]; |
|
31 | 34 |
|
32 | 35 |
static void |
33 |
-reset(void) |
|
36 |
+reset(UxnFile *c) |
|
34 | 37 |
{ |
35 |
- if(f != NULL) { |
|
36 |
- fclose(f); |
|
37 |
- f = NULL; |
|
38 |
+ if(c->f != NULL) { |
|
39 |
+ fclose(c->f); |
|
40 |
+ c->f = NULL; |
|
38 | 41 |
} |
39 |
- if(dir != NULL) { |
|
40 |
- closedir(dir); |
|
41 |
- dir = NULL; |
|
42 |
+ if(c->dir != NULL) { |
|
43 |
+ closedir(c->dir); |
|
44 |
+ c->dir = NULL; |
|
42 | 45 |
} |
43 |
- de = NULL; |
|
44 |
- state = IDLE; |
|
46 |
+ c->de = NULL; |
|
47 |
+ c->state = IDLE; |
|
45 | 48 |
} |
46 | 49 |
|
47 | 50 |
static Uint16 |
... | ... |
@@ -61,20 +64,20 @@ get_entry(char *p, Uint16 len, const char *pathname, const char *basename, int f |
61 | 64 |
} |
62 | 65 |
|
63 | 66 |
static Uint16 |
64 |
-file_read_dir(char *dest, Uint16 len) |
|
67 |
+file_read_dir(UxnFile *c, char *dest, Uint16 len) |
|
65 | 68 |
{ |
66 |
- static char pathname[4096]; |
|
69 |
+ static char pathname[4352]; |
|
67 | 70 |
char *p = dest; |
68 |
- if(de == NULL) de = readdir(dir); |
|
69 |
- for(; de != NULL; de = readdir(dir)) { |
|
71 |
+ if(c->de == NULL) c->de = readdir(c->dir); |
|
72 |
+ for(; c->de != NULL; c->de = readdir(c->dir)) { |
|
70 | 73 |
Uint16 n; |
71 |
- if(de->d_name[0] == '.' && de->d_name[1] == '\0') |
|
74 |
+ if(c->de->d_name[0] == '.' && c->de->d_name[1] == '\0') |
|
72 | 75 |
continue; |
73 |
- if(strlen(current_filename) + 1 + strlen(de->d_name) < sizeof(pathname)) |
|
74 |
- sprintf(pathname, "%s/%s", current_filename, de->d_name); |
|
76 |
+ if(strlen(c->current_filename) + 1 + strlen(c->de->d_name) < sizeof(pathname)) |
|
77 |
+ sprintf(pathname, "%s/%s", c->current_filename, c->de->d_name); |
|
75 | 78 |
else |
76 | 79 |
pathname[0] = '\0'; |
77 |
- n = get_entry(p, len, pathname, de->d_name, 1); |
|
80 |
+ n = get_entry(p, len, pathname, c->de->d_name, 1); |
|
78 | 81 |
if(!n) break; |
79 | 82 |
p += n; |
80 | 83 |
len -= n; |
... | ... |
@@ -83,102 +86,126 @@ file_read_dir(char *dest, Uint16 len) |
83 | 86 |
} |
84 | 87 |
|
85 | 88 |
static Uint16 |
86 |
-file_init(void *filename) |
|
89 |
+file_init(UxnFile *c, char *filename, size_t max_len) |
|
87 | 90 |
{ |
88 |
- reset(); |
|
89 |
- current_filename = filename; |
|
91 |
+ char *p = c->current_filename; |
|
92 |
+ size_t len = sizeof(c->current_filename); |
|
93 |
+ reset(c); |
|
94 |
+ if(len > max_len) len = max_len; |
|
95 |
+ while(len) { |
|
96 |
+ if((*p++ = *filename++) == '\0') |
|
97 |
+ return 0; |
|
98 |
+ len--; |
|
99 |
+ } |
|
100 |
+ c->current_filename[0] = '\0'; |
|
90 | 101 |
return 0; |
91 | 102 |
} |
92 | 103 |
|
93 | 104 |
static Uint16 |
94 |
-file_read(void *dest, Uint16 len) |
|
105 |
+file_read(UxnFile *c, void *dest, Uint16 len) |
|
95 | 106 |
{ |
96 |
- if(state != FILE_READ && state != DIR_READ) { |
|
97 |
- reset(); |
|
98 |
- if((dir = opendir(current_filename)) != NULL) |
|
99 |
- state = DIR_READ; |
|
100 |
- else if((f = fopen(current_filename, "rb")) != NULL) |
|
101 |
- state = FILE_READ; |
|
107 |
+ if(c->state != FILE_READ && c->state != DIR_READ) { |
|
108 |
+ reset(c); |
|
109 |
+ if((c->dir = opendir(c->current_filename)) != NULL) |
|
110 |
+ c->state = DIR_READ; |
|
111 |
+ else if((c->f = fopen(c->current_filename, "rb")) != NULL) |
|
112 |
+ c->state = FILE_READ; |
|
102 | 113 |
} |
103 |
- if(state == FILE_READ) |
|
104 |
- return fread(dest, 1, len, f); |
|
105 |
- if(state == DIR_READ) |
|
106 |
- return file_read_dir(dest, len); |
|
114 |
+ if(c->state == FILE_READ) |
|
115 |
+ return fread(dest, 1, len, c->f); |
|
116 |
+ if(c->state == DIR_READ) |
|
117 |
+ return file_read_dir(c, dest, len); |
|
107 | 118 |
return 0; |
108 | 119 |
} |
109 | 120 |
|
110 | 121 |
static Uint16 |
111 |
-file_write(void *src, Uint16 len, Uint8 flags) |
|
122 |
+file_write(UxnFile *c, void *src, Uint16 len, Uint8 flags) |
|
112 | 123 |
{ |
113 | 124 |
Uint16 ret = 0; |
114 |
- if(state != FILE_WRITE) { |
|
115 |
- reset(); |
|
116 |
- if((f = fopen(current_filename, (flags & 0x01) ? "ab" : "wb")) != NULL) |
|
117 |
- state = FILE_WRITE; |
|
125 |
+ if(c->state != FILE_WRITE) { |
|
126 |
+ reset(c); |
|
127 |
+ if((c->f = fopen(c->current_filename, (flags & 0x01) ? "ab" : "wb")) != NULL) |
|
128 |
+ c->state = FILE_WRITE; |
|
118 | 129 |
} |
119 |
- if(state == FILE_WRITE) { |
|
120 |
- if((ret = fwrite(src, 1, len, f)) > 0 && fflush(f) != 0) |
|
130 |
+ if(c->state == FILE_WRITE) { |
|
131 |
+ if((ret = fwrite(src, 1, len, c->f)) > 0 && fflush(c->f) != 0) |
|
121 | 132 |
ret = 0; |
122 | 133 |
} |
123 | 134 |
return ret; |
124 | 135 |
} |
125 | 136 |
|
126 | 137 |
static Uint16 |
127 |
-file_stat(void *dest, Uint16 len) |
|
138 |
+file_stat(UxnFile *c, void *dest, Uint16 len) |
|
128 | 139 |
{ |
129 |
- char *basename = strrchr(current_filename, '/'); |
|
140 |
+ char *basename = strrchr(c->current_filename, '/'); |
|
130 | 141 |
if(basename != NULL) |
131 | 142 |
basename++; |
132 | 143 |
else |
133 |
- basename = current_filename; |
|
134 |
- return get_entry(dest, len, current_filename, basename, 0); |
|
144 |
+ basename = c->current_filename; |
|
145 |
+ return get_entry(dest, len, c->current_filename, basename, 0); |
|
135 | 146 |
} |
136 | 147 |
|
137 | 148 |
static Uint16 |
138 |
-file_delete(void) |
|
149 |
+file_delete(UxnFile *c) |
|
139 | 150 |
{ |
140 |
- return unlink(current_filename); |
|
151 |
+ return unlink(c->current_filename); |
|
141 | 152 |
} |
142 | 153 |
|
143 | 154 |
/* IO */ |
144 | 155 |
|
145 | 156 |
void |
146 |
-file_deo(Device *d, Uint8 port) |
|
157 |
+file_i_deo(int instance, Device *d, Uint8 port) |
|
147 | 158 |
{ |
148 |
- Uint16 a, b, res; |
|
159 |
+ UxnFile *c = &uxn_file[instance]; |
|
160 |
+ Uint16 addr, len, res; |
|
149 | 161 |
switch(port) { |
150 | 162 |
case 0x5: |
151 |
- DEVPEEK16(a, 0x4); |
|
152 |
- DEVPEEK16(b, 0xa); |
|
153 |
- if(b > 0x10000 - a) |
|
154 |
- b = 0x10000 - a; |
|
155 |
- res = file_stat(&d->u->ram[a], b); |
|
163 |
+ DEVPEEK16(addr, 0x4); |
|
164 |
+ DEVPEEK16(len, 0xa); |
|
165 |
+ if(len > 0x10000 - addr) |
|
166 |
+ len = 0x10000 - addr; |
|
167 |
+ res = file_stat(c, &d->u->ram[addr], len); |
|
156 | 168 |
DEVPOKE16(0x2, res); |
157 | 169 |
break; |
158 | 170 |
case 0x6: |
159 |
- res = file_delete(); |
|
171 |
+ res = file_delete(c); |
|
160 | 172 |
DEVPOKE16(0x2, res); |
161 | 173 |
break; |
162 | 174 |
case 0x9: |
163 |
- DEVPEEK16(a, 0x8); |
|
164 |
- res = file_init(&d->u->ram[a]); |
|
175 |
+ DEVPEEK16(addr, 0x8); |
|
176 |
+ res = file_init(c, (char *)&d->u->ram[addr], 0x10000 - addr); |
|
165 | 177 |
DEVPOKE16(0x2, res); |
166 | 178 |
break; |
167 | 179 |
case 0xd: |
168 |
- DEVPEEK16(a, 0xc); |
|
169 |
- DEVPEEK16(b, 0xa); |
|
170 |
- if(b > 0x10000 - a) |
|
171 |
- b = 0x10000 - a; |
|
172 |
- res = file_read(&d->u->ram[a], b); |
|
180 |
+ DEVPEEK16(addr, 0xc); |
|
181 |
+ DEVPEEK16(len, 0xa); |
|
182 |
+ if(len > 0x10000 - addr) |
|
183 |
+ len = 0x10000 - addr; |
|
184 |
+ res = file_read(c, &d->u->ram[addr], len); |
|
173 | 185 |
DEVPOKE16(0x2, res); |
174 | 186 |
break; |
175 | 187 |
case 0xf: |
176 |
- DEVPEEK16(a, 0xe); |
|
177 |
- DEVPEEK16(b, 0xa); |
|
178 |
- if(b > 0x10000 - a) |
|
179 |
- b = 0x10000 - a; |
|
180 |
- res = file_write(&d->u->ram[a], b, d->dat[0x7]); |
|
188 |
+ DEVPEEK16(addr, 0xe); |
|
189 |
+ DEVPEEK16(len, 0xa); |
|
190 |
+ if(len > 0x10000 - addr) |
|
191 |
+ len = 0x10000 - addr; |
|
192 |
+ res = file_write(c, &d->u->ram[addr], len, d->dat[0x7]); |
|
193 |
+ DEVPOKE16(0x2, res); |
|
194 |
+ break; |
|
195 |
+ } |
|
196 |
+} |
|
197 |
+ |
|
198 |
+Uint8 |
|
199 |
+file_i_dei(int instance, Device *d, Uint8 port) |
|
200 |
+{ |
|
201 |
+ UxnFile *c = &uxn_file[instance]; |
|
202 |
+ Uint16 res; |
|
203 |
+ switch(port) { |
|
204 |
+ case 0xc: |
|
205 |
+ case 0xd: |
|
206 |
+ res = file_read(c, &d->dat[port], 1); |
|
181 | 207 |
DEVPOKE16(0x2, res); |
182 | 208 |
break; |
183 | 209 |
} |
210 |
+ return d->dat[port]; |
|
184 | 211 |
} |
... | ... |
@@ -10,4 +10,7 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
10 | 10 |
WITH REGARD TO THIS SOFTWARE. |
11 | 11 |
*/ |
12 | 12 |
|
13 |
-void file_deo(Device *d, Uint8 port); |
|
13 |
+#define POLYFILEY 1 |
|
14 |
+ |
|
15 |
+void file_i_deo(int instance, Device *d, Uint8 port); |
|
16 |
+Uint8 file_i_dei(int instance, Device *d, Uint8 port); |
... | ... |
@@ -17,6 +17,8 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
17 | 17 |
WITH REGARD TO THIS SOFTWARE. |
18 | 18 |
*/ |
19 | 19 |
|
20 |
+static Device *devfile0; |
|
21 |
+ |
|
20 | 22 |
static int |
21 | 23 |
error(char *msg, const char *err) |
22 | 24 |
{ |
... | ... |
@@ -42,6 +44,18 @@ console_deo(Device *d, Uint8 port) |
42 | 44 |
} |
43 | 45 |
} |
44 | 46 |
|
47 |
+static void |
|
48 |
+file_deo(Device *d, Uint8 port) |
|
49 |
+{ |
|
50 |
+ file_i_deo(d - devfile0, d, port); |
|
51 |
+} |
|
52 |
+ |
|
53 |
+static Uint8 |
|
54 |
+file_dei(Device *d, Uint8 port) |
|
55 |
+{ |
|
56 |
+ return file_i_dei(d - devfile0, d, port); |
|
57 |
+} |
|
58 |
+ |
|
45 | 59 |
static Uint8 |
46 | 60 |
nil_dei(Device *d, Uint8 port) |
47 | 61 |
{ |
... | ... |
@@ -102,7 +116,7 @@ start(Uxn *u) |
102 | 116 |
/* empty */ uxn_port(u, 0x7, nil_dei, nil_deo); |
103 | 117 |
/* empty */ uxn_port(u, 0x8, nil_dei, nil_deo); |
104 | 118 |
/* empty */ uxn_port(u, 0x9, nil_dei, nil_deo); |
105 |
- /* file */ uxn_port(u, 0xa, nil_dei, file_deo); |
|
119 |
+ /* file */ devfile0 = uxn_port(u, 0xa, file_dei, file_deo); |
|
106 | 120 |
/* datetime */ uxn_port(u, 0xb, datetime_dei, nil_deo); |
107 | 121 |
/* empty */ uxn_port(u, 0xc, nil_dei, nil_deo); |
108 | 122 |
/* empty */ uxn_port(u, 0xd, nil_dei, nil_deo); |
... | ... |
@@ -42,7 +42,7 @@ static SDL_Rect gRect; |
42 | 42 |
|
43 | 43 |
/* devices */ |
44 | 44 |
|
45 |
-static Device *devscreen, *devmouse, *devctrl, *devaudio0; |
|
45 |
+static Device *devscreen, *devmouse, *devctrl, *devaudio0, *devfile0; |
|
46 | 46 |
static Uint8 zoom = 1; |
47 | 47 |
static Uint32 stdin_event, audio0_event; |
48 | 48 |
|
... | ... |
@@ -58,21 +58,21 @@ error(char *msg, const char *err) |
58 | 58 |
static void |
59 | 59 |
audio_callback(void *u, Uint8 *stream, int len) |
60 | 60 |
{ |
61 |
- int i, running = 0; |
|
61 |
+ int instance, running = 0; |
|
62 | 62 |
Sint16 *samples = (Sint16 *)stream; |
63 | 63 |
SDL_memset(stream, 0, len); |
64 |
- for(i = 0; i < POLYPHONY; i++) |
|
65 |
- running += audio_render(&uxn_audio[i], samples, samples + len / 2); |
|
64 |
+ for(instance = 0; instance < POLYPHONY; instance++) |
|
65 |
+ running += audio_render(instance, samples, samples + len / 2); |
|
66 | 66 |
if(!running) |
67 | 67 |
SDL_PauseAudioDevice(audio_id, 1); |
68 | 68 |
(void)u; |
69 | 69 |
} |
70 | 70 |
|
71 | 71 |
void |
72 |
-audio_finished_handler(UxnAudio *c) |
|
72 |
+audio_finished_handler(int instance) |
|
73 | 73 |
{ |
74 | 74 |
SDL_Event event; |
75 |
- event.type = audio0_event + (c - uxn_audio); |
|
75 |
+ event.type = audio0_event + instance; |
|
76 | 76 |
SDL_PushEvent(&event); |
77 | 77 |
} |
78 | 78 |
|
... | ... |
@@ -185,11 +185,11 @@ console_deo(Device *d, Uint8 port) |
185 | 185 |
static Uint8 |
186 | 186 |
audio_dei(Device *d, Uint8 port) |
187 | 187 |
{ |
188 |
- UxnAudio *c = &uxn_audio[d - devaudio0]; |
|
188 |
+ int instance = d - devaudio0; |
|
189 | 189 |
if(!audio_id) return d->dat[port]; |
190 | 190 |
switch(port) { |
191 |
- case 0x4: return audio_get_vu(c); |
|
192 |
- case 0x2: DEVPOKE16(0x2, c->i); /* fall through */ |
|
191 |
+ case 0x4: return audio_get_vu(instance); |
|
192 |
+ case 0x2: DEVPOKE16(0x2, audio_get_position(instance)); /* fall through */ |
|
193 | 193 |
default: return d->dat[port]; |
194 | 194 |
} |
195 | 195 |
} |
... | ... |
@@ -197,26 +197,28 @@ audio_dei(Device *d, Uint8 port) |
197 | 197 |
static void |
198 | 198 |
audio_deo(Device *d, Uint8 port) |
199 | 199 |
{ |
200 |
- UxnAudio *c = &uxn_audio[d - devaudio0]; |
|
200 |
+ int instance = d - devaudio0; |
|
201 | 201 |
if(!audio_id) return; |
202 | 202 |
if(port == 0xf) { |
203 |
- Uint16 addr, adsr; |
|
204 | 203 |
SDL_LockAudioDevice(audio_id); |
205 |
- DEVPEEK16(adsr, 0x8); |
|
206 |
- DEVPEEK16(c->len, 0xa); |
|
207 |
- DEVPEEK16(addr, 0xc); |
|
208 |
- if(c->len > 0x10000 - addr) |
|
209 |
- c->len = 0x10000 - addr; |
|
210 |
- c->addr = &d->u->ram[addr]; |
|
211 |
- c->volume[0] = d->dat[0xe] >> 4; |
|
212 |
- c->volume[1] = d->dat[0xe] & 0xf; |
|
213 |
- c->repeat = !(d->dat[0xf] & 0x80); |
|
214 |
- audio_start(c, adsr, d->dat[0xf] & 0x7f); |
|
204 |
+ audio_start(instance, d); |
|
215 | 205 |
SDL_UnlockAudioDevice(audio_id); |
216 | 206 |
SDL_PauseAudioDevice(audio_id, 0); |
217 | 207 |
} |
218 | 208 |
} |
219 | 209 |
|
210 |
+static void |
|
211 |
+file_deo(Device *d, Uint8 port) |
|
212 |
+{ |
|
213 |
+ file_i_deo(d - devfile0, d, port); |
|
214 |
+} |
|
215 |
+ |
|
216 |
+static Uint8 |
|
217 |
+file_dei(Device *d, Uint8 port) |
|
218 |
+{ |
|
219 |
+ return file_i_dei(d - devfile0, d, port); |
|
220 |
+} |
|
221 |
+ |
|
220 | 222 |
static Uint8 |
221 | 223 |
nil_dei(Device *d, Uint8 port) |
222 | 224 |
{ |
... | ... |
@@ -263,7 +265,7 @@ start(Uxn *u, char *rom) |
263 | 265 |
/* unused */ uxn_port(u, 0x7, nil_dei, nil_deo); |
264 | 266 |
/* control */ devctrl = uxn_port(u, 0x8, nil_dei, nil_deo); |
265 | 267 |
/* mouse */ devmouse = uxn_port(u, 0x9, nil_dei, nil_deo); |
266 |
- /* file */ uxn_port(u, 0xa, nil_dei, file_deo); |
|
268 |
+ /* file */ devfile0 = uxn_port(u, 0xa, file_dei, file_deo); |
|
267 | 269 |
/* datetime */ uxn_port(u, 0xb, datetime_dei, nil_deo); |
268 | 270 |
/* unused */ uxn_port(u, 0xc, nil_dei, nil_deo); |
269 | 271 |
/* unused */ uxn_port(u, 0xd, nil_dei, nil_deo); |