Blob


1 /*
2 * Copyright (c) 2022 Omar Polo <op@openbsd.org>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
17 #include <sys/mman.h>
18 #include <sys/stat.h>
19 #include <sys/types.h>
20 #include <sys/queue.h>
21 #include <sys/uio.h>
23 #include <err.h>
24 #include <event.h>
25 #include <fcntl.h>
26 #include <limits.h>
27 #include <sndio.h>
28 #include <stdio.h>
29 #include <stdint.h>
30 #include <imsg.h>
31 #include <unistd.h>
33 #include <mad.h>
35 #include "amused.h"
37 struct mad_stream mad_stream;
38 struct mad_frame mad_frame;
39 struct mad_synth mad_synth;
41 struct buffer {
42 const void *start;
43 size_t length;
44 int sample_rate;
45 };
47 static enum mad_flow
48 input(void *d, struct mad_stream *stream)
49 {
50 struct buffer *buffer = d;
52 if (buffer->length == 0)
53 return MAD_FLOW_STOP;
55 printf("decode time! start=%p, len=%zu\n", buffer->start, buffer->length);
56 mad_stream_buffer(stream, buffer->start, buffer->length);
57 buffer->length = 0;
58 buffer->sample_rate = 0;
59 return MAD_FLOW_CONTINUE;
60 }
62 /* scale a mad sample to 16 bits */
63 static inline int
64 scale(mad_fixed_t sample)
65 {
66 /* round */
67 sample += (1L << (MAD_F_FRACBITS - 16));
69 /* clip */
70 if (sample >= MAD_F_ONE)
71 sample = MAD_F_ONE - 1;
72 else if (sample < -MAD_F_ONE)
73 sample -= MAD_F_ONE;
75 /* quantize */
76 return sample >> (MAD_F_FRACBITS + 1 - 16);
77 }
79 static enum mad_flow
80 output(void *data, const struct mad_header *header, struct mad_pcm *pcm)
81 {
82 static uint8_t buf[BUFSIZ];
83 size_t len;
84 struct buffer *buffer = data;
85 int nsamples, i;
86 uint16_t sample;
87 const mad_fixed_t *leftch, *rightch;
89 if (player_shouldstop())
90 return MAD_FLOW_STOP;
92 nsamples = pcm->length;
93 leftch = pcm->samples[0];
94 rightch = pcm->samples[1];
96 if (buffer->sample_rate != pcm->samplerate) {
97 buffer->sample_rate = pcm->samplerate;
98 if (player_setup(pcm->samplerate, 2) == -1)
99 err(1, "player_setrate");
102 if (pcm->channels != 2) {
103 printf("mono not supported!\n");
104 return MAD_FLOW_STOP;
107 for (i = 0, len = 0; i < nsamples; ++i) {
108 if (len+4 >= sizeof(buf)) {
109 sio_write(hdl, buf, len);
110 /* fwrite(buf, 1, len, stdout); */
111 len = 0;
114 sample = scale(*leftch++);
115 buf[len++] = sample & 0xff;
116 buf[len++] = (sample >> 8) & 0xff;
118 sample = scale(*rightch++);
119 buf[len++] = sample & 0xff;
120 buf[len++] = (sample >> 8) & 0xff;
123 if (len != 0)
124 /* fwrite(buf, 1, len, stdout); */
125 sio_write(hdl, buf, len);
127 return MAD_FLOW_CONTINUE;
130 static enum mad_flow
131 error(void *d, struct mad_stream *stream, struct mad_frame *frame)
133 struct buffer *buffer = d;
135 warnx("decoding error 0x%04x (%s) at byte offset %zu",
136 stream->error, mad_stream_errorstr(stream),
137 stream->this_frame - (const unsigned char *)buffer->start);
139 return MAD_FLOW_CONTINUE;
142 static int
143 decode(void *m, size_t len)
145 struct buffer buffer;
146 struct mad_decoder decoder;
147 int result;
149 /* initialize our private message structure; */
150 buffer.start = m;
151 buffer.length = len;
153 /* configure input, output and error functions */
154 mad_decoder_init(&decoder, &buffer, input, 0 /* header */,
155 0 /* filter */, output, error, 0 /* message */);
157 /* start decoding */
158 result = mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC);
160 /* release the decoder */
161 mad_decoder_finish(&decoder);
163 return result;
166 void
167 play_mp3(int fd)
169 struct stat stat;
170 void *m;
172 if (fstat(fd, &stat) == -1)
173 err(1, "fstat");
174 warnx("file size %lld", stat.st_size);
176 m = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
177 if (m == MAP_FAILED)
178 err(1, "mmap");
180 decode(m, stat.st_size);
181 munmap(m, stat.st_size);