"Fossies" - the Fresh Open Source Software archive

Member "alsaplayer-0.99.81/input/audiofile/audiofile_engine.c" of archive alsaplayer-0.99.81.tar.gz:


/*
 *  audiofile_engine.cpp (C) 1999 by Michael Pruett <michael@68k.org>
 *
 *  This file is part of AlsaPlayer.
 *
 *  AlsaPlayer 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 3 of the License, or
 *  (at your option) any later version.
 *
 *  AlsaPlayer 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, see <http://www.gnu.org/licenses/>.
 *
 */

#include <stdio.h>
#include <alloca.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>
#include <audiofile.h>
#include "input_plugin.h"

/*
	Audio File Library frames have a different meaning than AlsaPlayer
	frames.  In AlsaPlayer a frame is an array of bytes that make of a
	number of samples where Audio File Library sees a frame as a single
	sample (or sample pair in case of stereo).  Standardizing on one
	definition of "frame" would be good of course.  Comments?
*/

static const int FRAME_COUNT = 8192;
	
struct af_local_data
{
	AFfilehandle	filehandle;
	int		frameSize;
	int		sampleRate;
	char		filename[NAME_MAX];
};

/*
	Take a path as input and return the last part of it as the file name.
*/
static const char *getfilenamefrompath (const char *path)
{
	const char *p = strrchr(path, '/');

	if (p)
		return p + 1;

	return path;
}

static void init_audiofile (void)
{
	return;
}

static int audiofile_open (input_object *obj, const char *name)
{
	static int audiofile_init_done = 0;
	struct af_local_data	*data;

#ifdef DEBUG
	printf("audiofile_open: opening %s\n", name);
#endif

	if (!obj)
		return 0;

	obj->local_data = malloc(sizeof(struct af_local_data));

	if (!obj->local_data)
	{
		return 0;
	}

	data = (struct af_local_data *) obj->local_data;

	data->filehandle = afOpenFile(name, "r", NULL);
	strncpy(data->filename, getfilenamefrompath(name), NAME_MAX);
	data->filename[NAME_MAX - 1] = 0;

	if (data->filehandle == AF_NULL_FILEHANDLE)
	{
		free(obj->local_data);
		return 0;
	}

	if (audiofile_init_done == 0)
	{
		init_audiofile();
		audiofile_init_done = 1;
	}

	data->frameSize = (int) afGetFrameSize(data->filehandle, AF_DEFAULT_TRACK, 1);
	data->sampleRate = (int) afGetRate(data->filehandle, AF_DEFAULT_TRACK);
	obj->nr_frames =
		(afGetFrameCount(data->filehandle, AF_DEFAULT_TRACK) * data->frameSize +
		FRAME_COUNT - 1) / FRAME_COUNT;
	obj->nr_channels = afGetChannels(data->filehandle, AF_DEFAULT_TRACK);
	obj->frame_size = FRAME_COUNT;

#ifdef DEBUG
	printf("data.frameSize = %d\n", data->frameSize);
	printf("data.sampleRate = %d\n", data->sampleRate);
	printf("nr_frames = %d\n", obj->nr_frames);
	printf("nr_channels = %d\n", obj->nr_channels);
	printf("frame_size = %d\n", obj->frame_size);
#endif
	
	obj->flags = P_SEEK;
	
	return 1;
}


void audiofile_close (input_object *obj)
{
#ifdef DEBUG
	printf("audiofile_close\n");
#endif

	if (obj == NULL)
		return;

	if (obj->local_data)
	{
		struct af_local_data *data = 
			(struct af_local_data *) obj->local_data;
		afCloseFile(data->filehandle);
		free(obj->local_data);
		obj->local_data = NULL;
	}
}


static int audiofile_play_frame (input_object *obj, char *buf)
{
	int	bytes_to_read;
	int	frames_read;
	void	*buffer;

	struct af_local_data	*data;

	if (!obj)
		return 0;

	data = (struct af_local_data *) obj->local_data;

	if (!data)
		return 0;

	buffer = alloca(FRAME_COUNT * data->frameSize);

	if (!buffer)
		return 0;

	bytes_to_read = FRAME_COUNT * obj->nr_channels / 2;

	frames_read = afReadFrames(data->filehandle, AF_DEFAULT_TRACK, buffer,
		 bytes_to_read / data->frameSize) * 2 / obj->nr_channels;
	if (buf) {
		if (obj->nr_channels == 2)
			memcpy(buf, buffer,  FRAME_COUNT);
		else { /* mono, so double  */
			int i;
			if (data->frameSize == 1) {
				unsigned char *us = (unsigned char *)buffer;
				short *d = (short *)buf;
				for (i=0; i < FRAME_COUNT; i+=4) {
					short c = *d++ = ((*us ^ 0x80) << 8) | *us;
					us++;
					*d++ = c;
				}
			} else {
				short *s = (short *)buffer;
				short *d = (short *)buf;
				for (i=0; i < FRAME_COUNT; i+=4) {
						*d++ = *s;
						*d++ = *s++; /* Copy twice */
				}
			}
		}
	}

	if (frames_read * data->frameSize < FRAME_COUNT)
		return 0;

	return 1;
}


static int audiofile_frame_seek (input_object *obj, int frame)
{
	AFframecount	currentFrame;
	int				result = 0;

	struct af_local_data	*data;

#ifdef DEBUG
	printf("audiofile_frame_seek: %d\n", frame);
#endif

	if (!obj)
			return result;

	data = (struct af_local_data *) obj->local_data;

	if (data->filehandle == AF_NULL_FILEHANDLE)
	{
		return result;
	}

	currentFrame = afSeekFrame(data->filehandle, AF_DEFAULT_TRACK,
		frame * FRAME_COUNT / data->frameSize);

	result = (currentFrame >= 0);

#ifdef DEBUG
	printf("audiofile_frame_seek: result %d\n", result);
#endif

	return result;
}


static int audiofile_frame_size (input_object *obj)
{
	return FRAME_COUNT;
}


static int audiofile_nr_frames (input_object *obj)
{
	if (!obj)
		return 0;

	return obj->nr_frames;
}


static int audiofile_sample_rate (input_object *obj)
{
	struct af_local_data *data;

	if (!obj)
		return 0;

	data = (struct af_local_data *) obj->local_data;

	return data->sampleRate;
}


static int audiofile_channels (input_object *obj)
{
	if (!obj)
		return 0;

	return obj->nr_channels;
}


static long audiofile_frame_to_sec (input_object *obj, int frame)
{
	long	result = 0;

	struct af_local_data	*data;

#ifdef DEBUG
	printf("audiofile_frame_to_sec: %d\n", frame);
#endif

	if (!obj)
		return result;

	data = (struct af_local_data *) obj->local_data;

	if (!data)
		return result;
	
	result = (frame * FRAME_COUNT /
		(data->frameSize * data->sampleRate / 100));

#ifdef DEBUG
	printf("audiofile_frame_to_sec: result %ld\n", result);
#endif

	return result;
}

static float audiofile_can_handle (const char *name)
{
	const char *fname = strrchr(name, '/');

	if (!fname)
		fname = name;
	if (strstr(fname, ".wav") ||
		strstr(fname, ".WAV") ||
		strstr(fname, ".au") ||
		strstr(fname, ".AU") ||
		strstr(fname, ".aiff") ||
		strstr(fname, ".AIFF")) {
		/*	
			file = afOpenFile(name, "r", NULL);
			if (file == AF_NULL_FILEHANDLE)
				return 0.0;
			afCloseFile(file);
		*/
			return 1.0;
	}
	return 0.0;
}

static int audiofile_stream_info (input_object *obj, stream_info *info)
{
	int				sampleWidth;
	double			sampleRate;
	char			*fileType;
	struct af_local_data	*data;

	if (!obj || !info)
			return 0;

	data = (struct af_local_data *) obj->local_data;

	if (data->filehandle == AF_NULL_FILEHANDLE)
	{
			return 0;
	}

	afGetSampleFormat(data->filehandle, AF_DEFAULT_TRACK, NULL, &sampleWidth);
	sampleRate = afGetRate(data->filehandle, AF_DEFAULT_TRACK);
	fileType = (char *) afQueryPointer(AF_QUERYTYPE_FILEFMT, AF_QUERY_NAME,
		afGetFileFormat(data->filehandle, NULL), 0, 0);

	sprintf(info->stream_type, "%d-bit %dkHz %s %s",
		sampleWidth,
		(int) (sampleRate / 1000),
		obj->nr_channels == 2 ? "stereo" : "mono",
		fileType);
	strcpy(info->status, "");
	strcpy(info->artist, "");
	strcpy(info->title, data->filename);

	return 1;
}

static int audiofile_init (void)
{
	return 1;
}

static void audiofile_shutdown(void)
{
	return;
}


input_plugin audiofile_plugin =
{
	INPUT_PLUGIN_VERSION,
	0,
	"Audio File Library player v0.2.1",
	"Michael Pruett",
	NULL,
	audiofile_init,
	audiofile_shutdown,
	NULL,
	audiofile_can_handle,
	audiofile_open,
	audiofile_close,
	audiofile_play_frame,
	audiofile_frame_seek,
	audiofile_frame_size,
	audiofile_nr_frames,
	audiofile_frame_to_sec,
	audiofile_sample_rate,
	audiofile_channels,
	audiofile_stream_info,
	NULL,
	NULL
};

input_plugin *input_plugin_info (void)
{
	return &audiofile_plugin;
}