]> git.sesse.net Git - pistorm/blob - a314/software-amiga/piaudio_pistorm/piaudio.c
Adapt piaudio to work on PiStorm + A314 emulation
[pistorm] / a314 / software-amiga / piaudio_pistorm / piaudio.c
1 #include <exec/types.h>
2 #include <exec/memory.h>
3
4 #include <libraries/dos.h>
5
6 #include <devices/audio.h>
7
8 #include <proto/exec.h>
9
10 #include <stdio.h>
11 #include <string.h>
12 #include <time.h>
13
14 #include "../../a314device/a314.h"
15 #include "../../a314device/proto_a314.h"
16
17 #include <clib/alib_protos.h>
18
19 #define SERVICE_NAME "piaudio"
20
21 #define FREQ 18000
22 #define BUFFER_LEN_MS 50
23 #define SAMPLES (FREQ * BUFFER_LEN_MS / 1000)
24
25 #define R0              1
26 #define L0              2
27 #define L1              4
28 #define R1              8
29
30 #define LEFT_CHAN_MASK  (L0 | L1)
31 #define RIGHT_CHAN_MASK (R0 | R1)
32
33 #define LEFT 0
34 #define RIGHT 1
35
36 struct MsgPort *sync_mp = NULL;
37 struct MsgPort *async_mp = NULL;
38
39 struct A314_IORequest *sync_a314_req = NULL;
40 struct A314_IORequest *write_a314_req = NULL;
41
42 struct Library *A314Base;
43
44 char *audio_buffers[4] = { NULL, NULL, NULL, NULL };
45
46 struct IOAudio *sync_audio_req = NULL;
47 struct IOAudio *async_audio_req[4] = { NULL, NULL, NULL, NULL };
48
49 ULONG allocated_channels;
50
51 BOOL a314_device_open = FALSE;
52 BOOL audio_device_open = FALSE;
53 BOOL stream_open = FALSE;
54 BOOL pending_a314_write = FALSE;
55
56 ULONG socket;
57 int back_index = 0;
58 char awbuf[8];
59
60 void start_a314_cmd(struct MsgPort *reply_port, struct A314_IORequest *ior, UWORD cmd, char *buffer, int length)
61 {
62         ior->a314_Request.io_Message.mn_ReplyPort = reply_port;
63         ior->a314_Request.io_Command = cmd;
64         ior->a314_Request.io_Error = 0;
65         ior->a314_Socket = socket;
66         ior->a314_Buffer = buffer;
67         ior->a314_Length = length;
68         SendIO((struct IORequest *)ior);
69 }
70
71 BYTE a314_connect(char *name)
72 {
73         socket = time(NULL);
74         start_a314_cmd(sync_mp, sync_a314_req, A314_CONNECT, name, strlen(name));
75         Wait(1L << sync_mp->mp_SigBit);
76         GetMsg(sync_mp);
77         return sync_a314_req->a314_Request.io_Error;
78 }
79
80 BYTE a314_write(char *buffer, int length)
81 {
82         start_a314_cmd(sync_mp, sync_a314_req, A314_WRITE, buffer, length);
83         Wait(1L << sync_mp->mp_SigBit);
84         GetMsg(sync_mp);
85         return sync_a314_req->a314_Request.io_Error;
86 }
87
88 BYTE a314_eos()
89 {
90         start_a314_cmd(sync_mp, sync_a314_req, A314_EOS, NULL, 0);
91         Wait(1L << sync_mp->mp_SigBit);
92         GetMsg(sync_mp);
93         return sync_a314_req->a314_Request.io_Error;
94 }
95
96 BYTE a314_reset()
97 {
98         start_a314_cmd(sync_mp, sync_a314_req, A314_RESET, NULL, 0);
99         Wait(1L << sync_mp->mp_SigBit);
100         GetMsg(sync_mp);
101         return sync_a314_req->a314_Request.io_Error;
102 }
103
104 void start_a314_write(char *buffer, int length)
105 {
106         start_a314_cmd(async_mp, write_a314_req, A314_WRITE, buffer, length);
107         pending_a314_write = TRUE;
108 }
109
110 void submit_async_audio_req(int index)
111 {
112         ULONG mask = ((index & 1) == LEFT) ? LEFT_CHAN_MASK : RIGHT_CHAN_MASK;
113         ULONG unit = allocated_channels & mask;
114
115         async_audio_req[index]->ioa_Request.io_Message.mn_ReplyPort = async_mp;
116         async_audio_req[index]->ioa_Request.io_Command = CMD_WRITE;
117         async_audio_req[index]->ioa_Request.io_Flags = ADIOF_PERVOL;
118         async_audio_req[index]->ioa_Request.io_Unit = (void*)unit;
119         async_audio_req[index]->ioa_Data = audio_buffers[index];
120         async_audio_req[index]->ioa_Length = SAMPLES;
121         async_audio_req[index]->ioa_Period = 197;
122         async_audio_req[index]->ioa_Volume = 64;
123         async_audio_req[index]->ioa_Cycles = 1;
124         BeginIO((struct IORequest *)async_audio_req[index]);
125 }
126
127 int main()
128 {
129         SetTaskPri(FindTask(NULL), 50);
130
131         sync_mp = CreatePort(NULL, 0);
132         if (!sync_mp)
133         {
134                 printf("Unable to create sync reply message port\n");
135                 goto cleanup;
136         }
137
138         async_mp = CreatePort(NULL, 0);
139         if (!async_mp)
140         {
141                 printf("Unable to create async reply message port\n");
142                 goto cleanup;
143         }
144
145         sync_a314_req = (struct A314_IORequest *)CreateExtIO(sync_mp, sizeof(struct A314_IORequest));
146         write_a314_req = (struct A314_IORequest *)CreateExtIO(sync_mp, sizeof(struct A314_IORequest));
147         if (!sync_a314_req || !write_a314_req)
148         {
149                 printf("Unable to create A314_IORequest\n");
150                 goto cleanup;
151         }
152
153         if (OpenDevice(A314_NAME, 0, (struct IORequest *)sync_a314_req, 0))
154         {
155                 printf("Unable to open a314.device\n");
156                 goto cleanup;
157         }
158
159         a314_device_open = TRUE;
160
161         A314Base = &(sync_a314_req->a314_Request.io_Device->dd_Library);
162
163         memcpy(write_a314_req, sync_a314_req, sizeof(struct A314_IORequest));
164
165         audio_buffers[0] = AllocMem(SAMPLES * 2, MEMF_FAST | MEMF_CHIP | MEMF_CLEAR);
166         audio_buffers[2] = AllocMem(SAMPLES * 2, MEMF_FAST | MEMF_CHIP | MEMF_CLEAR);
167         if (!audio_buffers[0] || !audio_buffers[2])
168         {
169                 printf("Unable to allocate audio buffers in A314 chip memory\n");
170                 goto cleanup;
171         }
172
173         audio_buffers[1] = audio_buffers[0] + SAMPLES;
174         audio_buffers[3] = audio_buffers[2] + SAMPLES;
175
176         sync_audio_req = (struct IOAudio *)CreateExtIO(sync_mp, sizeof(struct IOAudio));
177         if (!sync_audio_req)
178         {
179                 printf("Unable to allocate sync audio request\n");
180                 goto cleanup;
181         }
182
183         int i;
184         for (i = 0; i < 4; i++)
185         {
186                 async_audio_req[i] = AllocMem(sizeof(struct IOAudio), MEMF_PUBLIC);
187                 if (!async_audio_req[i])
188                 {
189                         printf("Unable to allocate async audio request\n");
190                         goto cleanup;
191                 }
192         }
193
194         UBYTE which_channels[] = { L0 | R0, L0 | R1, L1 | R0, L1 | R1 };
195
196         sync_audio_req->ioa_Request.io_Message.mn_ReplyPort = sync_mp;
197         sync_audio_req->ioa_Request.io_Message.mn_Node.ln_Pri = 127;
198         sync_audio_req->ioa_Request.io_Command = ADCMD_ALLOCATE;
199         sync_audio_req->ioa_Request.io_Flags = ADIOF_NOWAIT;
200         sync_audio_req->ioa_AllocKey = 0;
201         sync_audio_req->ioa_Data = which_channels;
202         sync_audio_req->ioa_Length = sizeof(which_channels);
203
204         if (OpenDevice(AUDIONAME, 0, (struct IORequest *)sync_audio_req, 0))
205         {
206                 printf("Unable to open audio.device\n");
207                 goto cleanup;
208         }
209
210         audio_device_open = TRUE;
211
212         allocated_channels = (ULONG)sync_audio_req->ioa_Request.io_Unit;
213
214         for (i = 0; i < 4; i++)
215                 memcpy(async_audio_req[i], sync_audio_req, sizeof(struct IOAudio));
216
217         if (a314_connect(SERVICE_NAME) != A314_CONNECT_OK)
218         {
219                 printf("Unable to connect to piaudio service\n");
220                 goto cleanup;
221         }
222
223         stream_open = TRUE;
224
225         ULONG *buf_ptrs = (ULONG *)awbuf;
226         buf_ptrs[0] = TranslateAddressA314(audio_buffers[0]);
227         buf_ptrs[1] = TranslateAddressA314(audio_buffers[2]);
228         if (a314_write(awbuf, 8) != A314_WRITE_OK)
229         {
230                 printf("Unable to write buffer pointers\n");
231                 goto cleanup;
232         }
233
234         printf("PiAudio started, allocated channels: L%d, R%d\n",
235                 (allocated_channels & LEFT_CHAN_MASK) == L0 ? 0 : 1,
236                 (allocated_channels & RIGHT_CHAN_MASK) == R0 ? 0 : 1);
237
238         sync_audio_req->ioa_Request.io_Command = CMD_STOP;
239         DoIO((struct IORequest *)sync_audio_req);
240
241         submit_async_audio_req(back_index + LEFT);
242         submit_async_audio_req(back_index + RIGHT);
243
244         sync_audio_req->ioa_Request.io_Command = CMD_START;
245         DoIO((struct IORequest *)sync_audio_req);
246
247         int pending_audio_reqs = 2;
248
249         ULONG portsig = 1L << async_mp->mp_SigBit;
250
251         printf("Press ctrl-c to exit...\n");
252
253         while (TRUE)
254         {
255                 if (pending_audio_reqs <= 2)
256                 {
257                         back_index ^= 2;
258
259                         submit_async_audio_req(back_index + LEFT);
260                         submit_async_audio_req(back_index + RIGHT);
261
262                         pending_audio_reqs += 2;
263
264                         if (!pending_a314_write)
265                         {
266                                 awbuf[0] = back_index == 0 ? 0 : 1;
267                                 start_a314_write(awbuf, 1);
268                         }
269                 }
270
271                 ULONG signal = Wait(SIGBREAKF_CTRL_C | portsig);
272
273                 if (signal & SIGBREAKF_CTRL_C)
274                         break;
275                 else if (signal & portsig)
276                 {
277                         struct Message *msg;
278                         while (msg = GetMsg(async_mp))
279                         {
280                                 if (msg == (struct Message *)write_a314_req)
281                                 {
282                                         if (write_a314_req->a314_Request.io_Error == A314_WRITE_OK)
283                                                 pending_a314_write = FALSE;
284                                         else
285                                                 goto cleanup;
286                                 }
287                                 else
288                                         pending_audio_reqs--;
289                         }
290                 }
291         }
292
293 cleanup:
294         if (stream_open)
295                 a314_reset();
296         if (audio_device_open)
297                 CloseDevice((struct IORequest *)sync_audio_req);
298         for (i = 3; i >= 0; i--)
299                 if (async_audio_req[i])
300                         FreeMem(async_audio_req[i], sizeof(struct IOAudio));
301         if (sync_audio_req)
302                 DeleteExtIO((struct IORequest *)sync_audio_req);
303         if (audio_buffers[2])
304                 FreeMem(audio_buffers[2], SAMPLES * 2);
305         if (audio_buffers[0])
306                 FreeMem(audio_buffers[0], SAMPLES * 2);
307         if (a314_device_open)
308                 CloseDevice((struct IORequest *)sync_a314_req);
309         if (write_a314_req)
310                 DeleteExtIO((struct IORequest *)write_a314_req);
311         if (sync_a314_req)
312                 DeleteExtIO((struct IORequest *)sync_a314_req);
313         if (async_mp)
314                 DeletePort(async_mp);
315         if (sync_mp)
316                 DeletePort(sync_mp);
317
318         return 0;
319 }