Blame src/audio.c

Packit c32a2d
/*
Packit c32a2d
	audio: audio output interface
Packit c32a2d
Packit c32a2d
	copyright ?-2016 by the mpg123 project - free software under the terms of the LGPL 2.1
Packit c32a2d
	see COPYING and AUTHORS files in distribution or http://mpg123.org
Packit c32a2d
	initially written by Michael Hipp
Packit c32a2d
*/
Packit c32a2d
Packit c32a2d
#include <errno.h>
Packit c32a2d
#include "mpg123app.h"
Packit c32a2d
#include "audio.h"
Packit c32a2d
#include "out123.h"
Packit c32a2d
#include "common.h"
Packit c32a2d
#include "sysutil.h"
Packit c32a2d
Packit c32a2d
#ifdef HAVE_SYS_WAIT_H
Packit c32a2d
#include <sys/wait.h>
Packit c32a2d
#endif
Packit c32a2d
Packit c32a2d
#include "debug.h"
Packit c32a2d
Packit c32a2d
mpg123_string* audio_enclist(void)
Packit c32a2d
{
Packit c32a2d
	int i;
Packit c32a2d
	mpg123_string *list;
Packit c32a2d
	size_t enc_count = 0;
Packit c32a2d
	const int *enc_codes = NULL;
Packit c32a2d
Packit c32a2d
	/* Only the encodings supported by libmpg123 build
Packit c32a2d
	   Those returned by out123_enc_list() are a superset. */
Packit c32a2d
	mpg123_encodings(&enc_codes, &enc_count);
Packit c32a2d
	if((list = malloc(sizeof(*list))))
Packit c32a2d
		mpg123_init_string(list);
Packit c32a2d
	/* Further calls to mpg123 string lib are hardened against NULL. */
Packit c32a2d
	for(i=0;i
Packit c32a2d
	{
Packit c32a2d
		if(i>0)
Packit c32a2d
			mpg123_add_string(list, " ");
Packit c32a2d
		mpg123_add_string(list, out123_enc_name(enc_codes[i]));
Packit c32a2d
	}
Packit c32a2d
	return list;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
static void capline(mpg123_handle *mh, long rate)
Packit c32a2d
{
Packit c32a2d
	int enci;
Packit c32a2d
	const int  *encs;
Packit c32a2d
	size_t      num_encs;
Packit c32a2d
	mpg123_encodings(&encs, &num_encs);
Packit c32a2d
	fprintf(stderr," %5ld |", pitch_rate(rate));
Packit c32a2d
	for(enci=0; enci
Packit c32a2d
	{
Packit c32a2d
		switch(mpg123_format_support(mh, rate, encs[enci]))
Packit c32a2d
		{
Packit c32a2d
			case MPG123_MONO:               fprintf(stderr, "   M   |"); break;
Packit c32a2d
			case MPG123_STEREO:             fprintf(stderr, "   S   |"); break;
Packit c32a2d
			case MPG123_MONO|MPG123_STEREO: fprintf(stderr, "  M/S  |"); break;
Packit c32a2d
			default:                        fprintf(stderr, "       |");
Packit c32a2d
		}
Packit c32a2d
	}
Packit c32a2d
	fprintf(stderr, "\n");
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
void print_capabilities(out123_handle *ao, mpg123_handle *mh)
Packit c32a2d
{
Packit c32a2d
	int r,e;
Packit c32a2d
	const long *rates;
Packit c32a2d
	size_t      num_rates;
Packit c32a2d
	const int  *encs;
Packit c32a2d
	size_t      num_encs;
Packit c32a2d
	char *name;
Packit c32a2d
	char *dev;
Packit c32a2d
	out123_driver_info(ao, &name, &dev;;
Packit c32a2d
	mpg123_rates(&rates, &num_rates);
Packit c32a2d
	mpg123_encodings(&encs, &num_encs);
Packit c32a2d
	fprintf(stderr,"\nAudio driver: %s\nAudio device: %s\nAudio capabilities:\n(matrix of [S]tereo or [M]ono support for sample format and rate in Hz)\n       |", name, dev);
Packit c32a2d
	for(e=0;e
Packit c32a2d
	{
Packit c32a2d
		const char *encname = out123_enc_name(encs[e]);
Packit c32a2d
		fprintf(stderr," %5s |", encname ? encname : "???");
Packit c32a2d
	}
Packit c32a2d
Packit c32a2d
	fprintf(stderr,"\n ------|");
Packit c32a2d
	for(e=0;e
Packit c32a2d
Packit c32a2d
	fprintf(stderr, "\n");
Packit c32a2d
	for(r=0; r
Packit c32a2d
Packit c32a2d
	if(param.force_rate) capline(mh, param.force_rate);
Packit c32a2d
Packit c32a2d
	fprintf(stderr,"\n");
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* Quick-shot paired table setup with remembering search in it.
Packit c32a2d
   this is for storing pairs of output sampling rate and decoding
Packit c32a2d
   sampling rate. */
Packit c32a2d
struct ratepair { long a; long b; };
Packit c32a2d
Packit c32a2d
long brate(struct ratepair *table, long arate, int count, int *last)
Packit c32a2d
{
Packit c32a2d
	int i = 0;
Packit c32a2d
	int j;
Packit c32a2d
	for(j=0; j<2; ++j)
Packit c32a2d
	{
Packit c32a2d
		i = i ? 0 : *last;
Packit c32a2d
		for(; i
Packit c32a2d
		{
Packit c32a2d
			*last = i;
Packit c32a2d
			return table[i].b;
Packit c32a2d
		}
Packit c32a2d
	}
Packit c32a2d
	return 0;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* This uses the currently opened audio device, queries its caps.
Packit c32a2d
   In case of buffered playback, this works _once_ by querying the buffer for the caps before entering the main loop. */
Packit c32a2d
void audio_capabilities(out123_handle *ao, mpg123_handle *mh)
Packit c32a2d
{
Packit c32a2d
	int force_fmt = 0;
Packit c32a2d
	size_t ri;
Packit c32a2d
	/* Pitching introduces a difference between decoder rate and playback rate. */
Packit c32a2d
	long decode_rate;
Packit c32a2d
	const long *rates;
Packit c32a2d
	long *outrates;
Packit c32a2d
	struct ratepair *unpitch;
Packit c32a2d
	struct mpg123_fmt *outfmts = NULL;
Packit c32a2d
	int fmtcount;
Packit c32a2d
	size_t num_rates, rlimit;
Packit c32a2d
Packit c32a2d
	debug("audio_capabilities");
Packit c32a2d
	mpg123_rates(&rates, &num_rates);
Packit c32a2d
Packit c32a2d
	mpg123_format_none(mh); /* Start with nothing. */
Packit c32a2d
Packit c32a2d
	if(param.force_encoding != NULL)
Packit c32a2d
	{
Packit c32a2d
		if(!param.quiet)
Packit c32a2d
			fprintf(stderr, "Note: forcing output encoding %s\n", param.force_encoding);
Packit c32a2d
Packit c32a2d
		force_fmt = out123_enc_byname(param.force_encoding);
Packit c32a2d
		if(!force_fmt)
Packit c32a2d
		{
Packit c32a2d
			error1("Failed to find an encoding to match requested \"%s\"!\n"
Packit c32a2d
			,	param.force_encoding);
Packit c32a2d
			return; /* No capabilities at all... */
Packit c32a2d
		}
Packit c32a2d
		else if(param.verbose > 2)
Packit c32a2d
			fprintf(stderr, "Note: forcing encoding code 0x%x (%s)\n"
Packit c32a2d
			,	force_fmt, out123_enc_name(force_fmt));
Packit c32a2d
	}
Packit c32a2d
	/* Lots of preparation of rate lists. */
Packit c32a2d
	rlimit = param.force_rate > 0 ? num_rates+1 : num_rates;
Packit c32a2d
	outrates = malloc(sizeof(*rates)*rlimit);
Packit c32a2d
	unpitch  = malloc(sizeof(*unpitch)*rlimit);
Packit c32a2d
	if(!outrates || !unpitch)
Packit c32a2d
	{
Packit c32a2d
		if(!param.quiet)
Packit c32a2d
			error("DOOM");
Packit c32a2d
		return;
Packit c32a2d
	}
Packit c32a2d
	for(ri = 0; ri
Packit c32a2d
	{
Packit c32a2d
		decode_rate = ri < num_rates ? rates[ri] : param.force_rate;
Packit c32a2d
		outrates[ri] = pitch_rate(decode_rate);
Packit c32a2d
		unpitch[ri].a = outrates[ri];
Packit c32a2d
		unpitch[ri].b = decode_rate;
Packit c32a2d
	}
Packit c32a2d
	/* Actually query formats possible with given rates. */
Packit c32a2d
	fmtcount = out123_formats(ao, outrates, rlimit, 1, 2, &outfmts);
Packit c32a2d
	free(outrates);
Packit c32a2d
	if(fmtcount > 0)
Packit c32a2d
	{
Packit c32a2d
		int fi;
Packit c32a2d
		int unpitch_i = 0;
Packit c32a2d
		if(param.verbose > 1 && outfmts[0].encoding > 0)
Packit c32a2d
		{
Packit c32a2d
			const char *encname = out123_enc_name(outfmts[0].encoding);
Packit c32a2d
			fprintf(stderr, "Note: default format %li Hz, %i channels, %s\n"
Packit c32a2d
			,	outfmts[0].rate, outfmts[0].channels
Packit c32a2d
			,	encname ? encname : "???" );
Packit c32a2d
		}
Packit c32a2d
		for(fi=1; fi
Packit c32a2d
		{
Packit c32a2d
			int fmts = outfmts[fi].encoding;
Packit c32a2d
			if(param.verbose > 2)
Packit c32a2d
				fprintf( stderr
Packit c32a2d
				,	"Note: output support for %li Hz, %i channels: 0x%x\n"
Packit c32a2d
				,	outfmts[fi].rate, outfmts[fi].channels, outfmts[fi].encoding );
Packit c32a2d
			if(force_fmt)
Packit c32a2d
			{ /* Filter for forced encoding. */
Packit c32a2d
				if((fmts & force_fmt) == force_fmt)
Packit c32a2d
					fmts = force_fmt;
Packit c32a2d
				else /* Nothing else! */
Packit c32a2d
					fmts = 0;
Packit c32a2d
			}
Packit c32a2d
			mpg123_format( mh
Packit c32a2d
			,	brate(unpitch, outfmts[fi].rate, rlimit, &unpitch_i)
Packit c32a2d
			,	outfmts[fi].channels, fmts );
Packit c32a2d
		}
Packit c32a2d
	}
Packit c32a2d
	free(outfmts);
Packit c32a2d
	free(unpitch);
Packit c32a2d
Packit c32a2d
	if(param.verbose > 1) print_capabilities(ao, mh);
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
int set_pitch(mpg123_handle *fr, out123_handle *ao, double new_pitch)
Packit c32a2d
{
Packit c32a2d
	double old_pitch = param.pitch;
Packit c32a2d
	long rate;
Packit c32a2d
	int channels, format;
Packit c32a2d
	int smode = 0;
Packit c32a2d
Packit c32a2d
	/* Be safe, check support. */
Packit c32a2d
	if(mpg123_getformat(fr, &rate, &channels, &format) != MPG123_OK)
Packit c32a2d
	{
Packit c32a2d
		/* We might just not have a track handy. */
Packit c32a2d
		error("There is no current audio format, cannot apply pitch. This might get fixed in future.");
Packit c32a2d
		return 0;
Packit c32a2d
	}
Packit c32a2d
Packit c32a2d
	param.pitch = new_pitch;
Packit c32a2d
	if(param.pitch < -0.99) param.pitch = -0.99;
Packit c32a2d
Packit c32a2d
	if(channels == 1) smode = MPG123_MONO;
Packit c32a2d
	if(channels == 2) smode = MPG123_STEREO;
Packit c32a2d
Packit c32a2d
	out123_stop(ao);
Packit c32a2d
	/* Remember: This takes param.pitch into account. */
Packit c32a2d
	audio_capabilities(ao, fr);
Packit c32a2d
	if(!(mpg123_format_support(fr, rate, format) & smode))
Packit c32a2d
	{
Packit c32a2d
		/* Note: When using --pitch command line parameter, you can go higher
Packit c32a2d
		   because a lower decoder sample rate is automagically chosen.
Packit c32a2d
		   Here, we'd need to switch decoder rate during track... good? */
Packit c32a2d
		error("Reached a hardware limit there with pitch!");
Packit c32a2d
		param.pitch = old_pitch;
Packit c32a2d
		audio_capabilities(ao, fr);
Packit c32a2d
	}
Packit c32a2d
	return out123_start(ao, pitch_rate(rate), channels, format);
Packit c32a2d
}