Plan 9 from Bell Labs’s /usr/web/sources/contrib/cnielsen/oggenc/flac.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


/* OggEnc
 **
 ** This program is distributed under the GNU General Public License, version 2.
 ** A copy of this license is included with this source.
 **
 ** Copyright 2002, Stan Seibert <volsung@xiph.org>
 **
 **/


#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <math.h>
#include <FLAC/metadata.h>
#include "audio.h"
#include "flac.h"
#include "i18n.h"
#include "platform.h"
#include "resample.h"

#define DEFAULT_FLAC_FRAME_SIZE 4608

FLAC__StreamDecoderReadStatus easyflac_read_callback(const EasyFLAC__StreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data);
FLAC__StreamDecoderWriteStatus easyflac_write_callback(const EasyFLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);
void easyflac_metadata_callback(const EasyFLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data);
void easyflac_error_callback(const EasyFLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);

void resize_buffer(flacfile *flac, int newchannels, int newsamples);
void copy_comments (vorbis_comment *v_comments, FLAC__StreamMetadata_VorbisComment *f_comments);


int flac_id(unsigned char *buf, int len)
{
	if (len < 4) return 0;

	return memcmp(buf, "fLaC", 4) == 0;
}


int oggflac_id(unsigned char *buf, int len)
{
	if (len < 32) return 0;

	return memcmp(buf, "OggS", 4) == 0 && flac_id(buf+28, len - 28);
}


int flac_open(FILE *in, oe_enc_opt *opt, unsigned char *oldbuf, int buflen)
{
	flacfile *flac = malloc(sizeof(flacfile));

	flac->decoder = NULL;
	flac->channels = 0;
	flac->rate = 0;
	flac->totalsamples = 0;
	flac->comments = NULL;
	flac->in = NULL;
	flac->eos = 0;

	/* Setup empty audio buffer that will be resized on first frame 
	   callback */
	flac->buf = NULL;
	flac->buf_len = 0;
	flac->buf_start = 0;
	flac->buf_fill = 0;

	/* Copy old input data over */
	flac->oldbuf = malloc(buflen);
	flac->oldbuf_len = buflen;
	memcpy(flac->oldbuf, oldbuf, buflen);
	flac->oldbuf_start = 0;

	/* Need to save FILE pointer for read callback */
	flac->in = in;

	/* Setup FLAC decoder */
	flac->decoder = EasyFLAC__stream_decoder_new(oggflac_id(oldbuf, buflen));
	EasyFLAC__set_client_data(flac->decoder, flac);
	EasyFLAC__set_read_callback(flac->decoder, &easyflac_read_callback);
	EasyFLAC__set_write_callback(flac->decoder, &easyflac_write_callback);
	EasyFLAC__set_metadata_callback(flac->decoder, &easyflac_metadata_callback);
	EasyFLAC__set_error_callback(flac->decoder, &easyflac_error_callback);
	EasyFLAC__set_metadata_respond(flac->decoder, FLAC__METADATA_TYPE_STREAMINFO);
	EasyFLAC__set_metadata_respond(flac->decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT);
	EasyFLAC__init(flac->decoder);
	
	/* Callback will set the total samples and sample rate */
	EasyFLAC__process_until_end_of_metadata(flac->decoder);

	/* Callback will set the number of channels and resize the 
	   audio buffer */
	EasyFLAC__process_single(flac->decoder);
	
	/* Copy format info for caller */
	opt->rate = flac->rate;
	opt->channels = flac->channels;
	/* flac->total_samples_per_channel was already set by metadata
	   callback when metadata was processed. */
	opt->total_samples_per_channel = flac->totalsamples;
	/* Copy Vorbis-style comments from FLAC file (read in metadata 
	   callback)*/
	if (flac->comments != NULL && opt->copy_comments)
		copy_comments(opt->comments, &flac->comments->data.vorbis_comment);
	opt->read_samples = flac_read;
	opt->readdata = (void *)flac;

	return 1;
}


long flac_read(void *in, float **buffer, int samples)
{
	flacfile *flac = (flacfile *)in;
	long realsamples = 0;
	FLAC__bool ret;
	int i,j;
	while (realsamples < samples)
	{
		if (flac->buf_fill > 0)
		{
			int copy = flac->buf_fill < (samples - realsamples) ?
				flac->buf_fill : (samples - realsamples);
			
			for (i = 0; i < flac->channels; i++)
				for (j = 0; j < copy; j++)
					buffer[i][j+realsamples] = 
						flac->buf[i][j+flac->buf_start];
			flac->buf_start += copy;
			flac->buf_fill -= copy;
			realsamples += copy;
		}
		else if (!flac->eos)
		{
			ret = EasyFLAC__process_single(flac->decoder);
			if (!ret ||
			    EasyFLAC__get_state(flac->decoder)
			    == FLAC__STREAM_DECODER_END_OF_STREAM)
				flac->eos = 1;  /* Bail out! */
		} else
			break;
	}

	return realsamples;
}


void flac_close(void *info)
{
	int i;
	flacfile *flac =  (flacfile *) info;

	for (i = 0; i < flac->channels; i++)
		free(flac->buf[i]);

	free(flac->buf);
	free(flac->oldbuf);
	free(flac->comments);
	EasyFLAC__finish(flac->decoder);
	EasyFLAC__stream_decoder_delete(flac->decoder);
	free(flac);
}


FLAC__StreamDecoderReadStatus easyflac_read_callback(const EasyFLAC__StreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data)
{
	flacfile *flac = (flacfile *) client_data;
	int i = 0;
	int oldbuf_fill = flac->oldbuf_len - flac->oldbuf_start;
	
	/* Immediately return if errors occured */
	if(feof(flac->in))
	{
		*bytes = 0;
		return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
	}
	else if(ferror(flac->in))
	{
		*bytes = 0;
		return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
	}


	if(oldbuf_fill > 0) 
	{
		int copy;
		
		copy = oldbuf_fill < (*bytes - i) ? oldbuf_fill : (*bytes - i);
		memcpy(buffer + i, flac->oldbuf, copy);
		i += copy;
		flac->oldbuf_start += copy;
	}
	
	if(i < *bytes)
		i += fread(buffer+i, sizeof(FLAC__byte), *bytes - i, flac->in);

	*bytes = i;
	
	return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;	 
}

FLAC__StreamDecoderWriteStatus easyflac_write_callback(const EasyFLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
{
	flacfile *flac = (flacfile *) client_data;
	int samples = frame->header.blocksize;
	int channels = frame->header.channels;
	int bits_per_sample = frame->header.bits_per_sample;
	int i, j;

	resize_buffer(flac, channels, samples);

	for (i = 0; i < channels; i++)
		for (j = 0; j < samples; j++)
			flac->buf[i][j] = buffer[i][j] / 
				 (float) (1 << (bits_per_sample - 1));

	flac->buf_start = 0;
	flac->buf_fill = samples;
 
	return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
}

void easyflac_metadata_callback(const EasyFLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
{
	flacfile *flac = (flacfile *) client_data;

	switch (metadata->type)
	{
	case FLAC__METADATA_TYPE_STREAMINFO:
		flac->totalsamples = metadata->data.stream_info.total_samples;
		flac->rate = metadata->data.stream_info.sample_rate;
		break;

	case FLAC__METADATA_TYPE_VORBIS_COMMENT:
		flac->comments = FLAC__metadata_object_clone(metadata);
		break;
	default:
		break;
	}
}

void easyflac_error_callback(const EasyFLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
{
	flacfile *flac = (flacfile *) client_data;

}


void resize_buffer(flacfile *flac, int newchannels, int newsamples)
{
	int i;

	if (newchannels == flac->channels && newsamples == flac->buf_len)
	{
		flac->buf_start = 0;
		flac->buf_fill = 0;
		return;
	}


	/* Not the most efficient approach, but it is easy to follow */
	if(newchannels != flac->channels)
	{
		/* Deallocate all of the sample vectors */
		for (i = 0; i < flac->channels; i++)
			free(flac->buf[i]);

		flac->buf = realloc(flac->buf, sizeof(float*) * newchannels);
		flac->channels = newchannels;

	}

	for (i = 0; i < newchannels; i++)
		flac->buf[i] = malloc(sizeof(float) * newsamples);

	flac->buf_len = newsamples;
	flac->buf_start = 0;
	flac->buf_fill = 0;
}

void copy_comments (vorbis_comment *v_comments, FLAC__StreamMetadata_VorbisComment *f_comments)
{
	int i;

	for (i = 0; i < f_comments->num_comments; i++)
	{
		char *comment = malloc(f_comments->comments[i].length + 1);
		memset(comment, '\0', f_comments->comments[i].length + 1);
		strncpy((char *)comment, (char *)f_comments->comments[i].entry, f_comments->comments[i].length);
		vorbis_comment_add(v_comments, comment);
		free(comment);
	}
}


Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.