⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sndfile-play.c

📁 Audacity是一款用於錄音和編輯聲音的、免費的開放源碼軟體。它可以執行於Mac OS X、Microsoft Windows、GNU/Linux和其它作業系統
💻 C
📖 第 1 页 / 共 2 页
字号:
/*** Copyright (C) 1999-2004 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 "config.h"#include <stdio.h>#include <stdlib.h>#include <string.h>#include <errno.h>#if HAVE_UNISTD_H#include <unistd.h>#endif#if HAVE_ALSA_ASOUNDLIB_H	#define ALSA_PCM_NEW_HW_PARAMS_API	#define ALSA_PCM_NEW_SW_PARAMS_API	#include <alsa/asoundlib.h>	#include <sys/time.h>#endif#if defined (__linux__)	#include 	<fcntl.h>	#include 	<sys/ioctl.h>	#include 	<sys/soundcard.h>#elif (defined (__MACH__) && defined (__APPLE__))	#include <Carbon.h>	#include <CoreAudio/AudioHardware.h>#elif (defined (sun) && defined (unix))	#include <fcntl.h>	#include <sys/ioctl.h>	#include <sys/audioio.h>#elif (OS_IS_WIN32 == 1)	#include <windows.h>	#include <mmsystem.h>#endif#include	<sndfile.h>#define	SIGNED_SIZEOF(x)	((int) sizeof (x))#define	BUFFER_LEN			(2048)/*------------------------------------------------------------------------------**	Linux/OSS functions for playing a sound.*/#if HAVE_ALSA_ASOUNDLIB_Hstatic snd_pcm_t * alsa_open (int channels, int srate) ;static int alsa_write_float (snd_pcm_t *alsa_dev, float *data, int frames, int channels) ;static voidalsa_play (int argc, char *argv []){	static float buffer [BUFFER_LEN] ;	SNDFILE *sndfile ;	SF_INFO sfinfo ;	snd_pcm_t * alsa_dev ;	int		k, readcount, subformat ;	for (k = 1 ; k < argc ; k++)	{	memset (&sfinfo, 0, sizeof (sfinfo)) ;		printf ("Playing %s\n", argv [k]) ;		if (! (sndfile = sf_open (argv [k], SFM_READ, &sfinfo)))		{	puts (sf_strerror (NULL)) ;			continue ;			} ;		if (sfinfo.channels < 1 || sfinfo.channels > 2)		{	printf ("Error : channels = %d.\n", sfinfo.channels) ;			continue ;			} ;		alsa_dev = alsa_open (sfinfo.channels, sfinfo.samplerate) ;		subformat = sfinfo.format & SF_FORMAT_SUBMASK ;		if (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE)		{	double	scale ;			int 	m ;			sf_command (sndfile, SFC_CALC_SIGNAL_MAX, &scale, sizeof (scale)) ;			if (scale < 1e-10)				scale = 1.0 ;			else				scale = 32700.0 / scale ;			while ((readcount = sf_read_float (sndfile, buffer, BUFFER_LEN)))			{	for (m = 0 ; m < readcount ; m++)					buffer [m] *= scale ;				alsa_write_float (alsa_dev, buffer, BUFFER_LEN / sfinfo.channels, sfinfo.channels) ;				} ;			}		else		{	while ((readcount = sf_read_float (sndfile, buffer, BUFFER_LEN)))				alsa_write_float (alsa_dev, buffer, BUFFER_LEN / sfinfo.channels, sfinfo.channels) ;			} ;		snd_pcm_close (alsa_dev) ;		sf_close (sndfile) ;		} ;	return ;} /* alsa_play */static snd_pcm_t *alsa_open (int channels, int samplerate){	const char * device = "plughw:0" ;	snd_pcm_t *alsa_dev ;	snd_pcm_hw_params_t *hw_params ;	snd_pcm_uframes_t buffer_size, xfer_align, start_threshold ;	snd_pcm_uframes_t alsa_period_size, alsa_buffer_frames ;	snd_pcm_sw_params_t *sw_params ;	int err ;	alsa_period_size = 512 ;	alsa_buffer_frames = 3 * alsa_period_size ;	if ((err = snd_pcm_open (&alsa_dev, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0)	{	fprintf (stderr, "cannot open audio device \"%s\" (%s)\n", device, snd_strerror (err)) ;		return NULL ;		} ;	snd_pcm_nonblock (alsa_dev, 0) ;	if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0)	{	fprintf (stderr, "cannot allocate hardware parameter structure (%s)\n", snd_strerror (err)) ;		return NULL ;		} ;	if ((err = snd_pcm_hw_params_any (alsa_dev, hw_params)) < 0)	{	fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n", snd_strerror (err)) ;		return NULL ;		} ;	if ((err = snd_pcm_hw_params_set_access (alsa_dev, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)	{	fprintf (stderr, "cannot set access type (%s)\n", snd_strerror (err)) ;		return NULL ;		} ;	if ((err = snd_pcm_hw_params_set_format (alsa_dev, hw_params, SND_PCM_FORMAT_FLOAT)) < 0)	{	fprintf (stderr, "cannot set sample format (%s)\n", snd_strerror (err)) ;		return NULL ;		} ;	if ((err = snd_pcm_hw_params_set_rate_near (alsa_dev, hw_params, &samplerate, 0)) < 0)	{	fprintf (stderr, "cannot set sample rate (%s)\n", snd_strerror (err)) ;		return NULL ;		} ;	if ((err = snd_pcm_hw_params_set_channels (alsa_dev, hw_params, channels)) < 0)	{	fprintf (stderr, "cannot set channel count (%s)\n", snd_strerror (err)) ;		return NULL ;		} ;	if ((err = snd_pcm_hw_params_set_buffer_size_near (alsa_dev, hw_params, &alsa_buffer_frames)) < 0)	{	fprintf (stderr, "cannot set buffer size (%s)\n", snd_strerror (err)) ;		return NULL ;		} ;	if ((err = snd_pcm_hw_params_set_period_size_near (alsa_dev, hw_params, &alsa_period_size, 0)) < 0)	{	fprintf (stderr, "cannot set period size (%s)\n", snd_strerror (err)) ;		return NULL ;		} ;	if ((err = snd_pcm_hw_params (alsa_dev, hw_params)) < 0)	{	fprintf (stderr, "cannot set parameters (%s)\n", snd_strerror (err)) ;		return NULL ;		} ;	/* extra check: if we have only one period, this code won't work */	snd_pcm_hw_params_get_period_size (hw_params, &alsa_period_size, 0) ;	snd_pcm_hw_params_get_buffer_size (hw_params, &buffer_size) ;	if (alsa_period_size == buffer_size)	{	fprintf (stderr, "Can't use period equal to buffer size (%lu == %lu)", alsa_period_size, buffer_size) ;		return NULL ;		} ;	snd_pcm_hw_params_free (hw_params) ;	if ((err = snd_pcm_sw_params_malloc (&sw_params)) != 0)	{	fprintf (stderr, "%s: snd_pcm_sw_params_malloc: %s", __func__, snd_strerror (err)) ;		return NULL ;		} ;	if ((err = snd_pcm_sw_params_current (alsa_dev, sw_params)) != 0)	{	fprintf (stderr, "%s: snd_pcm_sw_params_current: %s", __func__, snd_strerror (err)) ;		return NULL ;		} ;	/* note: set start threshold to delay start until the ring buffer is full */	snd_pcm_sw_params_current (alsa_dev, sw_params) ;	if ((err = snd_pcm_sw_params_get_xfer_align (sw_params, &xfer_align)) < 0)	{	fprintf (stderr, "cannot get xfer align (%s)\n", snd_strerror (err)) ;		return NULL ;		} ;	/* round up to closest transfer boundary */	start_threshold = (buffer_size / xfer_align) * xfer_align ;	if (start_threshold < 1)		start_threshold = 1 ;	if ((err = snd_pcm_sw_params_set_start_threshold (alsa_dev, sw_params, start_threshold)) < 0)	{	fprintf (stderr, "cannot set start threshold (%s)\n", snd_strerror (err)) ;		return NULL ;		} ;	if ((err = snd_pcm_sw_params (alsa_dev, sw_params)) != 0)	{	fprintf (stderr, "%s: snd_pcm_sw_params: %s", __func__, snd_strerror (err)) ;		return NULL ;		} ;	snd_pcm_sw_params_free (sw_params) ;	snd_pcm_reset (alsa_dev) ;	return alsa_dev ;} /* alsa_open */static intalsa_write_float (snd_pcm_t *alsa_dev, float *data, int frames, int channels){	static	int epipe_count = 0 ;	snd_pcm_status_t *status ;	int total = 0 ;	int retval ;	if (epipe_count > 0)		epipe_count -- ;	while (total < frames)	{	retval = snd_pcm_writei (alsa_dev, data + total * channels, frames - total) ;		if (retval >= 0)		{	total += retval ;			if (total == frames)				return total ;			continue ;			} ;		switch (retval)		{	case -EAGAIN :					puts ("alsa_write_float: EAGAIN") ;					continue ;					break ;			case -EPIPE :					if (epipe_count > 0)					{	printf ("alsa_write_float: EPIPE %d\n", epipe_count) ;						if (epipe_count > 140)							return retval ;						} ;					epipe_count += 100 ;					if (0)					{	snd_pcm_status_alloca (&status) ;						if ((retval = snd_pcm_status (alsa_dev, status)) < 0)							fprintf (stderr, "alsa_out: xrun. can't determine length\n") ;						else if (snd_pcm_status_get_state (status) == SND_PCM_STATE_XRUN)						{	struct timeval now, diff, tstamp ;							gettimeofday (&now, 0) ;							snd_pcm_status_get_trigger_tstamp (status, &tstamp) ;							timersub (&now, &tstamp, &diff) ;							fprintf (stderr, "alsa_write_float xrun: of at least %.3f msecs. resetting stream\n",									diff.tv_sec * 1000 + diff.tv_usec / 1000.0) ;							}						else							fprintf (stderr, "alsa_write_float: xrun. can't determine length\n") ;						} ;					snd_pcm_prepare (alsa_dev) ;					break ;			case -EBADFD :					fprintf (stderr, "alsa_write_float: Bad PCM state.n") ;					return 0 ;					break ;			case -ESTRPIPE :					fprintf (stderr, "alsa_write_float: Suspend event.n") ;					return 0 ;					break ;			case -EIO :					puts ("alsa_write_float: EIO") ;					return 0 ;			default :					fprintf (stderr, "alsa_write_float: retval = %d\n", retval) ;					return 0 ;					break ;			} ; /* switch */		} ; /* while */	return total ;} /* alsa_write_float */#endif /* HAVE_ALSA_ASOUNDLIB_H *//*------------------------------------------------------------------------------**	Linux/OSS functions for playing a sound.*/#if defined (__linux__)static	int	linux_open_dsp_device (int channels, int srate) ;static voidlinux_play (int argc, char *argv []){	static short buffer [BUFFER_LEN] ;	SNDFILE *sndfile ;	SF_INFO sfinfo ;	int		k, audio_device, readcount, subformat ;	for (k = 1 ; k < argc ; k++)	{	memset (&sfinfo, 0, sizeof (sfinfo)) ;		printf ("Playing %s\n", argv [k]) ;		if (! (sndfile = sf_open (argv [k], SFM_READ, &sfinfo)))		{	puts (sf_strerror (NULL)) ;			continue ;			} ;		if (sfinfo.channels < 1 || sfinfo.channels > 2)		{	printf ("Error : channels = %d.\n", sfinfo.channels) ;			continue ;			} ;		audio_device = linux_open_dsp_device (sfinfo.channels, sfinfo.samplerate) ;		subformat = sfinfo.format & SF_FORMAT_SUBMASK ;		if (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE)		{	static float float_buffer [BUFFER_LEN] ;			double	scale ;			int 	m ;			sf_command (sndfile, SFC_CALC_SIGNAL_MAX, &scale, sizeof (scale)) ;			if (scale < 1e-10)				scale = 1.0 ;			else				scale = 32700.0 / scale ;			while ((readcount = sf_read_float (sndfile, float_buffer, BUFFER_LEN)))			{	for (m = 0 ; m < readcount ; m++)					buffer [m] = scale * float_buffer [m] ;				write (audio_device, buffer, readcount * sizeof (short)) ;				} ;			}		else		{	while ((readcount = sf_read_short (sndfile, buffer, BUFFER_LEN)))				write (audio_device, buffer, readcount * sizeof (short)) ;			} ;		close (audio_device) ;		sf_close (sndfile) ;		} ;	return ;} /* linux_play */static intlinux_open_dsp_device (int channels, int srate){	int fd, stereo, temp, error ;	if ((fd = open ("/dev/dsp", O_WRONLY, 0)) == -1 &&		(fd = open ("/dev/sound/dsp", O_WRONLY, 0)) == -1)	{	perror ("linux_open_dsp_device : open ") ;		exit (1) ;		} ;	stereo = 0 ;	if (ioctl (fd, SNDCTL_DSP_STEREO, &stereo) == -1)	{ 	/* Fatal error */		perror ("linux_open_dsp_device : stereo ") ;		exit (1) ;		} ;	if (ioctl (fd, SNDCTL_DSP_RESET, 0))	{	perror ("linux_open_dsp_device : reset ") ;		exit (1) ;		} ;	temp = 16 ;	if ((error = ioctl (fd, SOUND_PCM_WRITE_BITS, &temp)) != 0)	{	perror ("linux_open_dsp_device : bitwidth ") ;		exit (1) ;		} ;	if ((error = ioctl (fd, SOUND_PCM_WRITE_CHANNELS, &channels)) != 0)	{	perror ("linux_open_dsp_device : channels ") ;		exit (1) ;		} ;	if ((error = ioctl (fd, SOUND_PCM_WRITE_RATE, &srate)) != 0)	{	perror ("linux_open_dsp_device : sample rate ") ;		exit (1) ;		} ;	if ((error = ioctl (fd, SNDCTL_DSP_SYNC, 0)) != 0)	{	perror ("linux_open_dsp_device : sync ") ;		exit (1) ;		} ;	return 	fd ;} /* linux_open_dsp_device */#endif /* __linux__ *//*------------------------------------------------------------------------------**	Mac OS X functions for playing a sound.*/#if (defined (__MACH__) && defined (__APPLE__)) /* MacOSX */typedef struct{	AudioStreamBasicDescription		format ;	UInt32 			buf_size ;	AudioDeviceID 	device ;	SNDFILE 		*sndfile ;	SF_INFO 		sfinfo ;	int				fake_stereo ;	int				done_playing ;} MacOSXAudioData ;#include <math.h>static OSStatusmacosx_audio_out_callback (AudioDeviceID device, const AudioTimeStamp* current_time,	const AudioBufferList* data_in, const AudioTimeStamp* time_in,	AudioBufferList*	data_out, const AudioTimeStamp* time_out,	void* client_data){	MacOSXAudioData	*audio_data ;	int		size, sample_count, read_count, k ;	float	*buffer ;	/* Prevent compiler warnings. */	device = device ;	current_time = current_time ;	data_in = data_in ;	time_in = time_in ;	time_out = time_out ;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -