shout_mp3.c 4.55 KB
Newer Older
Eric Wollesen's avatar
Eric Wollesen committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/* the Music Player Daemon (MPD)
 * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
 * This project's homepage is: http://www.musicpd.org
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

19
#include "shout_plugin.h"
20

Eric Wollesen's avatar
Eric Wollesen committed
21
#include <lame/lame.h>
22
#include <stdlib.h>
Eric Wollesen's avatar
Eric Wollesen committed
23

24
struct lame_data {
Eric Wollesen's avatar
Eric Wollesen committed
25
	lame_global_flags *gfp;
26
};
Eric Wollesen's avatar
Eric Wollesen committed
27 28


29
static int shout_mp3_encoder_init(struct shout_data *sd)
Eric Wollesen's avatar
Eric Wollesen committed
30
{
31
	struct lame_data *ld = g_new(struct lame_data, 1);
Eric Wollesen's avatar
Eric Wollesen committed
32 33 34 35 36 37

	sd->encoder_data = ld;

	return 0;
}

38
static int shout_mp3_encoder_clear_encoder(struct shout_data *sd)
Eric Wollesen's avatar
Eric Wollesen committed
39
{
40 41
	struct lame_data *ld = (struct lame_data *)sd->encoder_data;
	struct shout_buffer *buf = &sd->buf;
Eric Wollesen's avatar
Eric Wollesen committed
42 43 44 45
	int ret;

	if ((ret = lame_encode_flush(ld->gfp, buf->data + buf->len,
				     buf->len)) < 0)
46
		g_warning("error flushing lame buffers\n");
Eric Wollesen's avatar
Eric Wollesen committed
47 48 49 50

	return (ret > 0);
}

51
static void shout_mp3_encoder_finish(struct shout_data *sd)
Eric Wollesen's avatar
Eric Wollesen committed
52
{
53
	struct lame_data *ld = (struct lame_data *)sd->encoder_data;
Eric Wollesen's avatar
Eric Wollesen committed
54 55 56 57 58

	lame_close(ld->gfp);
	ld->gfp = NULL;
}

59
static int shout_mp3_encoder_init_encoder(struct shout_data *sd)
Eric Wollesen's avatar
Eric Wollesen committed
60
{
61
	struct lame_data *ld = (struct lame_data *)sd->encoder_data;
Eric Wollesen's avatar
Eric Wollesen committed
62 63

	if (NULL == (ld->gfp = lame_init())) {
64
		g_warning("error initializing lame encoder for shout\n");
Eric Wollesen's avatar
Eric Wollesen committed
65 66 67 68 69
		return -1;
	}

	if (sd->quality >= -1.0) {
		if (0 != lame_set_VBR(ld->gfp, vbr_rh)) {
70
			g_warning("error setting lame VBR mode\n");
Eric Wollesen's avatar
Eric Wollesen committed
71 72 73
			return -1;
		}
		if (0 != lame_set_VBR_q(ld->gfp, sd->quality)) {
74
			g_warning("error setting lame VBR quality\n");
Eric Wollesen's avatar
Eric Wollesen committed
75 76 77 78
			return -1;
		}
	} else {
		if (0 != lame_set_brate(ld->gfp, sd->bitrate)) {
79
			g_warning("error setting lame bitrate\n");
Eric Wollesen's avatar
Eric Wollesen committed
80 81 82 83 84 85
			return -1;
		}
	}

	if (0 != lame_set_num_channels(ld->gfp,
				       sd->audio_format.channels)) {
86
		g_warning("error setting lame num channels\n");
Eric Wollesen's avatar
Eric Wollesen committed
87 88 89 90
		return -1;
	}

	if (0 != lame_set_in_samplerate(ld->gfp,
91
					sd->audio_format.sample_rate)) {
92
		g_warning("error setting lame sample rate\n");
Eric Wollesen's avatar
Eric Wollesen committed
93 94 95 96
		return -1;
	}

	if (0 > lame_init_params(ld->gfp))
97
		g_error("error initializing lame params\n");
Eric Wollesen's avatar
Eric Wollesen committed
98 99 100 101

	return 0;
}

102
static int shout_mp3_encoder_send_metadata(struct shout_data *sd,
Eric Wollesen's avatar
Eric Wollesen committed
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
					   char * song, size_t size)
{
	char artist[size];
	char title[size];
	int i;
	struct tag *tag = sd->tag;

	strncpy(artist, "", size);
	strncpy(title, "", size);

	for (i = 0; i < tag->numOfItems; i++) {
		switch (tag->items[i]->type) {
		case TAG_ITEM_ARTIST:
			strncpy(artist, tag->items[i]->value, size);
			break;
		case TAG_ITEM_TITLE:
			strncpy(title, tag->items[i]->value, size);
			break;

		default:
			break;
		}
	}
	snprintf(song, size, "%s - %s", title, artist);

	return 1;
}

131
static int shout_mp3_encoder_encode(struct shout_data *sd,
Eric Wollesen's avatar
Eric Wollesen committed
132 133
				    const char * chunk, size_t len)
{
134
	const int16_t *src = (const int16_t*)chunk;
Eric Wollesen's avatar
Eric Wollesen committed
135
	unsigned int i;
136
	float *left, *right;
137
	struct shout_buffer *buf = &(sd->buf);
Eric Wollesen's avatar
Eric Wollesen committed
138
	unsigned int samples;
139
	int bytes = audio_format_sample_size(&sd->audio_format);
140
	struct lame_data *ld = (struct lame_data *)sd->encoder_data;
Eric Wollesen's avatar
Eric Wollesen committed
141 142 143
	int bytes_out;

	samples = len / (bytes * sd->audio_format.channels);
144 145 146 147 148
	left = g_malloc(sizeof(left[0]) * samples);
	if (sd->audio_format.channels > 1)
		right = g_malloc(sizeof(left[0]) * samples);
	else
		right = left;
Eric Wollesen's avatar
Eric Wollesen committed
149 150 151 152

	/* this is for only 16-bit audio */

	for (i = 0; i < samples; i++) {
153 154 155 156
		left[i] = src[0];
		if (right != left)
			right[i] = src[1];
		src += sd->audio_format.channels;
Eric Wollesen's avatar
Eric Wollesen committed
157 158
	}

159
	bytes_out = lame_encode_buffer_float(ld->gfp, left, right,
Eric Wollesen's avatar
Eric Wollesen committed
160
					     samples, buf->data,
161
					     sizeof(buf->data) - buf->len);
162 163 164 165

	g_free(left);
	if (right != left)
		g_free(right);
Eric Wollesen's avatar
Eric Wollesen committed
166 167

	if (0 > bytes_out) {
168
		g_warning("error encoding lame buffer for shout\n");
Eric Wollesen's avatar
Eric Wollesen committed
169 170 171 172 173 174 175 176 177
		lame_close(ld->gfp);
		ld->gfp = NULL;
		return -1;
	} else
		buf->len = bytes_out; /* signed to unsigned conversion */

	return 0;
}

178
const struct shout_encoder_plugin shout_mp3_encoder = {
Eric Wollesen's avatar
Eric Wollesen committed
179 180 181 182 183 184 185 186 187 188
	"mp3",
	SHOUT_FORMAT_MP3,

	shout_mp3_encoder_clear_encoder,
	shout_mp3_encoder_encode,
	shout_mp3_encoder_finish,
	shout_mp3_encoder_init,
	shout_mp3_encoder_init_encoder,
	shout_mp3_encoder_send_metadata,
};