view src/libsamplerate-0.1.8/examples/varispeed-play.c @ 83:ae30d91d2ffe

Replace these with versions built using an older toolset (so as to avoid ABI compatibilities when linking on Ubuntu 14.04 for packaging purposes)
author Chris Cannam
date Fri, 07 Feb 2020 11:51:13 +0000
parents c7265573341e
children
line wrap: on
line source
/*
** Copyright (C) 2002-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** 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.
*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#include "config.h"

#include <float_cast.h>

#if (HAVE_SNDFILE)

#include <samplerate.h>
#include <sndfile.h>

#include "audio_out.h"

#define ARRAY_LEN(x)	((int) (sizeof (x) / sizeof ((x) [0])))

#define	BUFFER_LEN		4096
#define	INPUT_FRAMES	100

#define	MIN(a,b)		((a) < (b) ? (a) : (b))

#define	MAGIC_NUMBER	((int) ('S' << 16) + ('R' << 8) + ('C'))

#ifndef	M_PI
#define	M_PI			3.14159265358979323846264338
#endif


typedef struct
{	int			magic ;

	SNDFILE 	*sndfile ;
	SF_INFO 	sfinfo ;

	SRC_STATE	*src_state ;
	SRC_DATA	src_data ;

	int			freq_point ;
	int			buffer_out_start, buffer_out_end ;

	float		buffer_in	[BUFFER_LEN] ;
	float		buffer_out	[BUFFER_LEN] ;
} CALLBACK_DATA ;

static int varispeed_get_data (CALLBACK_DATA *data, float *samples, int frames) ;
static void varispeed_play (const char *filename, int converter) ;

int
main (int argc, char *argv [])
{	const char	*cptr, *progname, *filename ;
	int			k, converter ;

	converter = SRC_SINC_FASTEST ;

	progname = argv [0] ;

	if ((cptr = strrchr (progname, '/')) != NULL)
		progname = cptr + 1 ;

	if ((cptr = strrchr (progname, '\\')) != NULL)
		progname = cptr + 1 ;

	printf ("\n"
		"  %s\n"
		"\n"
		"  This is a demo program which plays the given file at a slowly \n"
		"  varying speed. Lots of fun with drum loops and full mixes.\n"
		"\n"
		"  It uses Secret Rabbit Code (aka libsamplerate) to perform the \n"
		"  vari-speeding and libsndfile for file I/O.\n"
		"\n", progname) ;

	if (argc == 2)
		filename = argv [1] ;
	else if (argc == 4 && strcmp (argv [1], "-c") == 0)
	{	filename = argv [3] ;
		converter = atoi (argv [2]) ;
		}
	else
	{	printf ("  Usage :\n\n       %s [-c <number>] <input file>\n\n", progname) ;
		puts (
			"  The optional -c argument allows the converter type to be chosen from\n"
			"  the following list :"
			"\n"
			) ;

		for (k = 0 ; (cptr = src_get_name (k)) != NULL ; k++)
			printf ("       %d : %s\n", k, cptr) ;

		puts ("") ;
		exit (1) ;
		} ;

	varispeed_play (filename, converter) ;

	return 0 ;
} /* main */

/*==============================================================================
*/

static void
varispeed_play (const char *filename, int converter)
{	CALLBACK_DATA	*data ;
	AUDIO_OUT		*audio_out ;
	int				error ;

	/* Allocate memory for the callback data. */
	if ((data = calloc (1, sizeof (CALLBACK_DATA))) == NULL)
	{	printf ("\n\n%s:%d Calloc failed!\n", __FILE__, __LINE__) ;
		exit (1) ;
		} ;

	data->magic = MAGIC_NUMBER ;

	if ((data->sndfile = sf_open (filename, SFM_READ, &data->sfinfo)) == NULL)
	{	puts (sf_strerror (NULL)) ;
		exit (1) ;
		} ;

	/* Initialize the sample rate converter. */
	if ((data->src_state = src_new (converter, data->sfinfo.channels, &error)) == NULL)
	{	printf ("\n\nError : src_new() failed : %s.\n\n", src_strerror (error)) ;
		exit (1) ;
		} ;

	printf (

		"  Playing   : %s\n"
		"  Converter : %s\n"
		"\n"
		"  Press <control-c> to exit.\n"
		"\n",
		filename, src_get_name (converter)) ;

	if ((audio_out = audio_open (data->sfinfo.channels, data->sfinfo.samplerate)) == NULL)
	{	printf ("\n\nError : audio_open () failed.\n") ;
		exit (1) ;
		} ;

	/* Set up sample rate converter info. */
	data->src_data.end_of_input = 0 ; /* Set this later. */

	/* Start with zero to force load in while loop. */
	data->src_data.input_frames = 0 ;
	data->src_data.data_in = data->buffer_in ;

	/* Start with output frames also zero. */
	data->src_data.output_frames_gen = 0 ;

	data->buffer_out_start = data->buffer_out_end = 0 ;
	data->src_data.src_ratio = 1.0 ;

	/* Pass the data and the callbacl function to audio_play */
	audio_play ((get_audio_callback_t) varispeed_get_data, audio_out, data) ;

	/* Cleanup */
	audio_close (audio_out) ;
	sf_close (data->sndfile) ;
	src_delete (data->src_state) ;

	free (data) ;

} /* varispeed_play */

/*==============================================================================
*/

static int
varispeed_get_data (CALLBACK_DATA *data, float *samples, int frames)
{	int		error, readframes, frame_count, direct_out ;

	if (data->magic != MAGIC_NUMBER)
	{	printf ("\n\n%s:%d Eeeek, something really bad happened!\n", __FILE__, __LINE__) ;
		exit (1) ;
		} ;

	frame_count = 0 ;

	if (data->buffer_out_start < data->buffer_out_end)
	{	frame_count = MIN (data->buffer_out_end - data->buffer_out_start, frames) ;
		memcpy (samples, data->buffer_out + data->sfinfo.channels * data->buffer_out_start, data->sfinfo.channels * frame_count * sizeof (float)) ;
		data->buffer_out_start += frame_count ;
		} ;

	data->buffer_out_start = data->buffer_out_end = 0 ;

	while (frame_count < frames)
	{
		/* Read INPUT_FRAMES frames worth looping at end of file. */
		for (readframes = 0 ; readframes < INPUT_FRAMES ; )
		{	sf_count_t position ;

			readframes += sf_readf_float (data->sndfile, data->buffer_in + data->sfinfo.channels * readframes, INPUT_FRAMES - readframes) ;

			position = sf_seek (data->sndfile, 0, SEEK_CUR) ;

			if (position < 0 || position == data->sfinfo.frames)
				sf_seek (data->sndfile, 0, SEEK_SET) ;
			} ;

		data->src_data.input_frames = readframes ;

		data->src_data.src_ratio = 1.0 - 0.5 * sin (data->freq_point * 2 * M_PI / 20000) ;
		data->freq_point ++ ;

		direct_out = (data->src_data.src_ratio * readframes < frames - frame_count) ? 1 : 0 ;

		if (direct_out)
		{	data->src_data.data_out = samples + frame_count * data->sfinfo.channels ;
			data->src_data.output_frames = frames - frame_count ;
			}
		else
		{	data->src_data.data_out = data->buffer_out ;
			data->src_data.output_frames = BUFFER_LEN / data->sfinfo.channels ;
			} ;

		if ((error = src_process (data->src_state, &data->src_data)))
		{	printf ("\nError : %s\n\n", src_strerror (error)) ;
			exit (1) ;
			} ;

		if (direct_out)
		{	frame_count += data->src_data.output_frames_gen ;
			continue ;
			} ;

		memcpy (samples + frame_count * data->sfinfo.channels, data->buffer_out, (frames - frame_count) * data->sfinfo.channels * sizeof (float)) ;

		data->buffer_out_start = frames - frame_count ;
		data->buffer_out_end = data->src_data.output_frames_gen ;

		frame_count += frames - frame_count ;
		} ;

	return frame_count ;
} /* varispeed_get_data */

/*==============================================================================
*/

#else /* (HAVE_SNFILE == 0) */

/* Alternative main function when libsndfile is not available. */

int
main (void)
{	puts (
		"\n"
		"****************************************************************\n"
		" This example program was compiled without libsndfile \n"
		" (http://www.zip.com.au/~erikd/libsndfile/).\n"
		" It is therefore completely broken and non-functional.\n"
		"****************************************************************\n"
		"\n"
		) ;

	return 0 ;
} /* main */

#endif