1 /*
2 * A FLAC decoder plugin for the Audacious Media Player
3 * Copyright (C) 2005 Ralf Ertzinger
4 * Copyright (C) 2010-2012 Michał Lipski
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20
21 #include <string.h>
22
23 #include <libaudcore/runtime.h>
24
25 #include "flacng.h"
26
27 EXPORT FLACng aud_plugin_instance;
28
29 static FLAC__StreamDecoder *decoder;
30 static callback_info *cinfo;
31
init()32 bool FLACng::init()
33 {
34 FLAC__StreamDecoderInitStatus ret;
35
36 /* Callback structure and decoder for main decoding loop */
37
38 cinfo = new callback_info;
39
40 if ((decoder = FLAC__stream_decoder_new()) == nullptr)
41 {
42 AUDERR("Could not create the main FLAC decoder instance!\n");
43 return false;
44 }
45
46 if (FLAC__STREAM_DECODER_INIT_STATUS_OK != (ret = FLAC__stream_decoder_init_stream(
47 decoder,
48 read_callback,
49 seek_callback,
50 tell_callback,
51 length_callback,
52 eof_callback,
53 write_callback,
54 metadata_callback,
55 error_callback,
56 cinfo)))
57 {
58 AUDERR("Could not initialize the main FLAC decoder: %s(%d)\n",
59 FLAC__StreamDecoderInitStatusString[ret], ret);
60 return false;
61 }
62
63 AUDDBG("Plugin initialized.\n");
64 return true;
65 }
66
cleanup()67 void FLACng::cleanup()
68 {
69 FLAC__stream_decoder_delete(decoder);
70 delete cinfo;
71 }
72
is_our_file(const char * filename,VFSFile & file)73 bool FLACng::is_our_file(const char *filename, VFSFile &file)
74 {
75 AUDDBG("Probe for FLAC.\n");
76
77 char buf[4];
78 if (file.fread (buf, 1, sizeof buf) != sizeof buf)
79 return false;
80
81 return ! strncmp (buf, "fLaC", sizeof buf);
82 }
83
squeeze_audio(int32_t * src,void * dst,unsigned count,unsigned res)84 static void squeeze_audio(int32_t* src, void* dst, unsigned count, unsigned res)
85 {
86 int32_t* rp = src;
87 int8_t* wp = (int8_t*) dst;
88 int16_t* wp2 = (int16_t*) dst;
89 int32_t* wp4 = (int32_t*) dst;
90
91 switch (res)
92 {
93 case 8:
94 for (unsigned i = 0; i < count; i++, wp++, rp++)
95 *wp = *rp & 0xff;
96 break;
97
98 case 16:
99 for (unsigned i = 0; i < count; i++, wp2++, rp++)
100 *wp2 = *rp & 0xffff;
101 break;
102
103 case 24:
104 case 32:
105 for (unsigned i = 0; i < count; i++, wp4++, rp++)
106 *wp4 = *rp;
107 break;
108
109 default:
110 AUDERR("Can not convert to %u bps\n", res);
111 }
112 }
113
play(const char * filename,VFSFile & file)114 bool FLACng::play(const char *filename, VFSFile &file)
115 {
116 Index<char> play_buffer;
117 bool error = false;
118
119 cinfo->fd = &file;
120
121 if (read_metadata(decoder, cinfo) == false)
122 {
123 AUDERR("Could not prepare file for playing!\n");
124 error = true;
125 goto ERR_NO_CLOSE;
126 }
127
128 play_buffer.resize(BUFFER_SIZE_BYTE);
129
130 set_stream_bitrate(cinfo->bitrate);
131 open_audio(SAMPLE_FMT(cinfo->bits_per_sample), cinfo->sample_rate, cinfo->channels);
132
133 while (FLAC__stream_decoder_get_state(decoder) != FLAC__STREAM_DECODER_END_OF_STREAM)
134 {
135 if (check_stop ())
136 break;
137
138 int seek_value = check_seek ();
139 if (seek_value >= 0)
140 FLAC__stream_decoder_seek_absolute (decoder, (int64_t)
141 seek_value * cinfo->sample_rate / 1000);
142
143 /* Try to decode a single frame of audio */
144 if (FLAC__stream_decoder_process_single(decoder) == false)
145 {
146 AUDERR("Error while decoding!\n");
147 error = true;
148 break;
149 }
150
151 squeeze_audio(cinfo->output_buffer.begin(), play_buffer.begin(),
152 cinfo->buffer_used, cinfo->bits_per_sample);
153 write_audio(play_buffer.begin(), cinfo->buffer_used *
154 SAMPLE_SIZE(cinfo->bits_per_sample));
155
156 cinfo->reset();
157 }
158
159 ERR_NO_CLOSE:
160 cinfo->reset();
161
162 if (FLAC__stream_decoder_flush(decoder) == false)
163 AUDERR("Could not flush decoder state!\n");
164
165 return ! error;
166 }
167
168 const char FLACng::about[] =
169 N_("Original code by\n"
170 "Ralf Ertzinger <ralf@skytale.net>\n\n"
171 "http://www.skytale.net/projects/bmp-flac2/");
172
173 const char *const FLACng::exts[] = { "flac", "fla", nullptr };
174
175 const char *const FLACng::mimes[] = { "audio/flac", "audio/x-flac", nullptr };
176