Fix whitespace inconsistencies.
[herrie-working.git] / herrie / src / audio_format_modplug.c
blob0fcb3e4bb436093e3a78061d663e49c973158a50
1 /*
2 * Copyright (c) 2006-2011 Ed Schouten <ed@80386.nl>
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
26 /**
27 * @file audio_format_modplug.c
28 * @brief libmodplug decompression routines.
31 #include "stdinc.h"
33 #include <sys/mman.h>
34 #include <modplug.h>
36 #include "audio_file.h"
37 #include "audio_format.h"
38 #include "audio_output.h"
40 /**
41 * @brief Sample rate we want to use.
43 #define SAMPLERATE 44100
44 /**
45 * @brief The number of bytes used by a single frame.
47 #define BYTESPERSAMPLE 4
49 /**
50 * @brief Private data for libmodplug stored in the audio file structure.
52 struct modplug_drv_data {
53 /**
54 * @brief Base address of our memory map.
56 void *map_base;
57 /**
58 * @brief Length of our memory map.
60 size_t map_len;
61 /**
62 * @brief libmodplug handle.
64 ModPlugFile *modplug;
65 /**
66 * @brief Decoded sample offset.
68 off_t sample;
71 /**
72 * @brief Set proper parameters in the Modplug library.
74 static void
75 modplug_init(void)
77 ModPlug_Settings mset;
79 ModPlug_GetSettings(&mset);
80 mset.mChannels = 2;
81 mset.mBits = 16;
82 mset.mFrequency = SAMPLERATE;
83 ModPlug_SetSettings(&mset);
86 int
87 modplug_open(struct audio_file *fd, const char *ext)
89 struct modplug_drv_data *data;
90 const char *title;
92 /* libmodplug doesn't have good magic. Match by extension */
93 if (ext == NULL)
94 return (-1);
95 if (g_ascii_strcasecmp(ext, "mod") != 0 &&
96 g_ascii_strcasecmp(ext, "s3m") != 0 &&
97 g_ascii_strcasecmp(ext, "it") != 0 &&
98 g_ascii_strcasecmp(ext, "xm") != 0)
99 return (-1);
101 /* If only we could memory map the internet... */
102 if (fd->stream)
103 return (-1);
105 data = g_slice_new(struct modplug_drv_data);
107 /* Calculate file length */
108 fseek(fd->fp, 0, SEEK_END);
109 data->map_len = ftello(fd->fp);
111 /* Memory map the entire file */
112 data->map_base = mmap(NULL, data->map_len, PROT_READ,
113 MAP_PRIVATE, fileno(fd->fp), 0);
114 if (data->map_base == MAP_FAILED)
115 goto free;
117 /* Now feed it to modplug */
118 modplug_init();
119 data->modplug = ModPlug_Load(data->map_base, data->map_len);
120 if (data->modplug != NULL) {
121 data->sample = 0;
122 fd->drv_data = data;
123 fd->srate = SAMPLERATE;
124 fd->channels = 2;
126 fd->time_len = ModPlug_GetLength(data->modplug) / 1000;
127 title = ModPlug_GetName(data->modplug);
128 if (title != NULL && title[0] != '\0')
129 fd->title = g_strdup(title);
130 return (0);
133 munmap(data->map_base, data->map_len);
134 free: g_slice_free(struct modplug_drv_data, data);
135 return (1);
138 void
139 modplug_close(struct audio_file *fd)
141 struct modplug_drv_data *data = fd->drv_data;
143 ModPlug_Unload(data->modplug);
144 munmap(data->map_base, data->map_len);
145 g_slice_free(struct modplug_drv_data, data);
148 size_t
149 modplug_read(struct audio_file *fd, int16_t *buf, size_t len)
151 struct modplug_drv_data *data = fd->drv_data;
152 int rlen;
154 rlen = ModPlug_Read(data->modplug, buf, len * sizeof(int16_t));
155 data->sample += rlen / BYTESPERSAMPLE;
156 fd->time_cur = data->sample / SAMPLERATE;
158 return (rlen / sizeof(int16_t));
161 void
162 modplug_seek(struct audio_file *fd, int len, int rel)
164 struct modplug_drv_data *data = fd->drv_data;
165 size_t off;
167 off = len * SAMPLERATE;
168 if (rel)
169 off += data->sample;
170 /* Don't seek out of reach */
171 off = CLAMP(off, 0, (fd->time_len - 1) * SAMPLERATE);
173 ModPlug_Seek(data->modplug, (off * 10) / (SAMPLERATE / 100));
174 data->sample = off;
175 fd->time_cur = data->sample / SAMPLERATE;