1 /*-*- Mode: C; c-basic-offset: 8 -*-*/
2
3 /***
4 This file is part of libcanberra.
5
6 Copyright 2008 Lennart Poettering
7
8 libcanberra is free software; you can redistribute it and/or modify
9 it under the terms of the GNU Lesser General Public License as
10 published by the Free Software Foundation, either version 2.1 of the
11 License, or (at your option) any later version.
12
13 libcanberra is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public
19 License along with libcanberra. If not, see
20 <http://www.gnu.org/licenses/>.
21 ***/
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <errno.h>
28
29 #include "read-sound-file.h"
30 #include "read-wav.h"
31 #include "read-vorbis.h"
32 #include "macro.h"
33 #include "malloc.h"
34 #include "canberra.h"
35
36 struct ca_sound_file {
37 ca_wav *wav;
38 ca_vorbis *vorbis;
39 char *filename;
40
41 unsigned nchannels;
42 unsigned rate;
43 ca_sample_type_t type;
44 };
45
ca_sound_file_open(ca_sound_file ** _f,const char * fn)46 int ca_sound_file_open(ca_sound_file **_f, const char *fn) {
47 FILE *file;
48 ca_sound_file *f;
49 int ret;
50
51 ca_return_val_if_fail(_f, CA_ERROR_INVALID);
52 ca_return_val_if_fail(fn, CA_ERROR_INVALID);
53
54 if (!(f = ca_new0(ca_sound_file, 1)))
55 return CA_ERROR_OOM;
56
57 if (!(f->filename = ca_strdup(fn))) {
58 ret = CA_ERROR_OOM;
59 goto fail;
60 }
61
62 if (!(file = fopen(fn, "r"))) {
63 ret = errno == ENOENT ? CA_ERROR_NOTFOUND : CA_ERROR_SYSTEM;
64 goto fail;
65 }
66
67 if ((ret = ca_wav_open(&f->wav, file)) == CA_SUCCESS) {
68 f->nchannels = ca_wav_get_nchannels(f->wav);
69 f->rate = ca_wav_get_rate(f->wav);
70 f->type = ca_wav_get_sample_type(f->wav);
71 *_f = f;
72 return CA_SUCCESS;
73 }
74
75 if (ret == CA_ERROR_CORRUPT) {
76
77 if (fseek(file, 0, SEEK_SET) < 0) {
78 ret = CA_ERROR_SYSTEM;
79 goto fail;
80 }
81
82 if ((ret = ca_vorbis_open(&f->vorbis, file)) == CA_SUCCESS) {
83 f->nchannels = ca_vorbis_get_nchannels(f->vorbis);
84 f->rate = ca_vorbis_get_rate(f->vorbis);
85 f->type = CA_SAMPLE_S16NE;
86 *_f = f;
87 return CA_SUCCESS;
88 }
89 }
90
91 fail:
92
93 ca_free(f->filename);
94 ca_free(f);
95
96 return ret;
97 }
98
ca_sound_file_close(ca_sound_file * f)99 void ca_sound_file_close(ca_sound_file *f) {
100 ca_assert(f);
101
102 if (f->wav)
103 ca_wav_close(f->wav);
104 if (f->vorbis)
105 ca_vorbis_close(f->vorbis);
106
107 ca_free(f->filename);
108 ca_free(f);
109 }
110
ca_sound_file_get_nchannels(ca_sound_file * f)111 unsigned ca_sound_file_get_nchannels(ca_sound_file *f) {
112 ca_assert(f);
113 return f->nchannels;
114 }
115
ca_sound_file_get_rate(ca_sound_file * f)116 unsigned ca_sound_file_get_rate(ca_sound_file *f) {
117 ca_assert(f);
118 return f->rate;
119 }
120
ca_sound_file_get_sample_type(ca_sound_file * f)121 ca_sample_type_t ca_sound_file_get_sample_type(ca_sound_file *f) {
122 ca_assert(f);
123 return f->type;
124 }
125
ca_sound_file_get_channel_map(ca_sound_file * f)126 const ca_channel_position_t* ca_sound_file_get_channel_map(ca_sound_file *f) {
127 ca_assert(f);
128
129 if (f->wav)
130 return ca_wav_get_channel_map(f->wav);
131 else
132 return ca_vorbis_get_channel_map(f->vorbis);
133 }
134
ca_sound_file_read_int16(ca_sound_file * f,int16_t * d,size_t * n)135 int ca_sound_file_read_int16(ca_sound_file *f, int16_t *d, size_t *n) {
136 ca_return_val_if_fail(f, CA_ERROR_INVALID);
137 ca_return_val_if_fail(d, CA_ERROR_INVALID);
138 ca_return_val_if_fail(n, CA_ERROR_INVALID);
139 ca_return_val_if_fail(*n > 0, CA_ERROR_INVALID);
140 ca_return_val_if_fail(f->wav || f->vorbis, CA_ERROR_STATE);
141 ca_return_val_if_fail(f->type == CA_SAMPLE_S16NE || f->type == CA_SAMPLE_S16RE, CA_ERROR_STATE);
142
143 if (f->wav)
144 return ca_wav_read_s16le(f->wav, d, n);
145 else
146 return ca_vorbis_read_s16ne(f->vorbis, d, n);
147 }
148
ca_sound_file_read_uint8(ca_sound_file * f,uint8_t * d,size_t * n)149 int ca_sound_file_read_uint8(ca_sound_file *f, uint8_t *d, size_t *n) {
150 ca_return_val_if_fail(f, CA_ERROR_INVALID);
151 ca_return_val_if_fail(d, CA_ERROR_INVALID);
152 ca_return_val_if_fail(n, CA_ERROR_INVALID);
153 ca_return_val_if_fail(*n > 0, CA_ERROR_INVALID);
154 ca_return_val_if_fail(f->wav && !f->vorbis, CA_ERROR_STATE);
155 ca_return_val_if_fail(f->type == CA_SAMPLE_U8, CA_ERROR_STATE);
156
157 if (f->wav)
158 return ca_wav_read_u8(f->wav, d, n);
159
160 return CA_ERROR_STATE;
161 }
162
ca_sound_file_read_arbitrary(ca_sound_file * f,void * d,size_t * n)163 int ca_sound_file_read_arbitrary(ca_sound_file *f, void *d, size_t *n) {
164 int ret;
165
166 ca_return_val_if_fail(f, CA_ERROR_INVALID);
167 ca_return_val_if_fail(d, CA_ERROR_INVALID);
168 ca_return_val_if_fail(n, CA_ERROR_INVALID);
169 ca_return_val_if_fail(*n > 0, CA_ERROR_INVALID);
170
171 switch (f->type) {
172 case CA_SAMPLE_S16NE:
173 case CA_SAMPLE_S16RE: {
174 size_t k;
175
176 k = *n / sizeof(int16_t);
177 if ((ret = ca_sound_file_read_int16(f, d, &k)) == CA_SUCCESS)
178 *n = k * sizeof(int16_t);
179
180 break;
181 }
182
183 case CA_SAMPLE_U8: {
184 size_t k;
185
186 k = *n;
187 if ((ret = ca_sound_file_read_uint8(f, d, &k)) == CA_SUCCESS)
188 *n = k;
189
190 break;
191 }
192
193 default:
194 ca_assert_not_reached();
195 }
196
197 return ret;
198 }
199
ca_sound_file_get_size(ca_sound_file * f)200 off_t ca_sound_file_get_size(ca_sound_file *f) {
201 ca_return_val_if_fail(f, (off_t) -1);
202
203 if (f->wav)
204 return ca_wav_get_size(f->wav);
205 else
206 return ca_vorbis_get_size(f->vorbis);
207 }
208
ca_sound_file_frame_size(ca_sound_file * f)209 size_t ca_sound_file_frame_size(ca_sound_file *f) {
210 unsigned c;
211
212 ca_assert(f);
213
214 c = ca_sound_file_get_nchannels(f);
215
216 return c * (ca_sound_file_get_sample_type(f) == CA_SAMPLE_U8 ? 1U : 2U);
217 }
218