📄 sndfile-play.c
字号:
audio_data = (MacOSXAudioData*) client_data ; size = data_out->mBuffers [0].mDataByteSize ; sample_count = size / sizeof (float) ; buffer = (float*) data_out->mBuffers [0].mData ; if (audio_data->fake_stereo != 0) { read_count = sf_read_float (audio_data->sndfile, buffer, sample_count / 2) ; for (k = read_count - 1 ; k >= 0 ; k--) { buffer [2 * k ] = buffer [k] ; buffer [2 * k + 1] = buffer [k] ; } ; read_count *= 2 ; } else read_count = sf_read_float (audio_data->sndfile, buffer, sample_count) ; /* Fill the remainder with zeroes. */ if (read_count < sample_count) { if (audio_data->fake_stereo == 0) memset (&(buffer [read_count]), 0, (sample_count - read_count) * sizeof (float)) ; /* Tell the main application to terminate. */ audio_data->done_playing = SF_TRUE ; } ; return noErr ;} /* macosx_audio_out_callback */static voidmacosx_play (int argc, char *argv []){ MacOSXAudioData audio_data ; OSStatus err ; UInt32 count, buffer_size ; int k ; audio_data.fake_stereo = 0 ; audio_data.device = kAudioDeviceUnknown ; /* get the default output device for the HAL */ count = sizeof (AudioDeviceID) ; if ((err = AudioHardwareGetProperty (kAudioHardwarePropertyDefaultOutputDevice, &count, (void *) &(audio_data.device))) != noErr) { printf ("AudioHardwareGetProperty (kAudioDevicePropertyDefaultOutputDevice) failed.\n") ; return ; } ; /* get the buffersize that the default device uses for IO */ count = sizeof (UInt32) ; if ((err = AudioDeviceGetProperty (audio_data.device, 0, false, kAudioDevicePropertyBufferSize, &count, &buffer_size)) != noErr) { printf ("AudioDeviceGetProperty (kAudioDevicePropertyBufferSize) failed.\n") ; return ; } ; /* get a description of the data format used by the default device */ count = sizeof (AudioStreamBasicDescription) ; if ((err = AudioDeviceGetProperty (audio_data.device, 0, false, kAudioDevicePropertyStreamFormat, &count, &(audio_data.format))) != noErr) { printf ("AudioDeviceGetProperty (kAudioDevicePropertyStreamFormat) failed.\n") ; return ; } ; /* Base setup completed. Now play files. */ for (k = 1 ; k < argc ; k++) { printf ("Playing %s\n", argv [k]) ; if (! (audio_data.sndfile = sf_open (argv [k], SFM_READ, &(audio_data.sfinfo)))) { puts (sf_strerror (NULL)) ; continue ; } ; if (audio_data.sfinfo.channels < 1 || audio_data.sfinfo.channels > 2) { printf ("Error : channels = %d.\n", audio_data.sfinfo.channels) ; continue ; } ; audio_data.format.mSampleRate = audio_data.sfinfo.samplerate ; if (audio_data.sfinfo.channels == 1) { audio_data.format.mChannelsPerFrame = 2 ; audio_data.fake_stereo = 1 ; } else audio_data.format.mChannelsPerFrame = audio_data.sfinfo.channels ; if ((err = AudioDeviceSetProperty (audio_data.device, NULL, 0, false, kAudioDevicePropertyStreamFormat, sizeof (AudioStreamBasicDescription), &(audio_data.format))) != noErr) { printf ("AudioDeviceSetProperty (kAudioDevicePropertyStreamFormat) failed.\n") ; return ; } ; /* we want linear pcm */ if (audio_data.format.mFormatID != kAudioFormatLinearPCM) return ; /* Fire off the device. */ if ((err = AudioDeviceAddIOProc (audio_data.device, macosx_audio_out_callback, (void *) &audio_data)) != noErr) { printf ("AudioDeviceAddIOProc failed.\n") ; return ; } ; err = AudioDeviceStart (audio_data.device, macosx_audio_out_callback) ; if (err != noErr) return ; audio_data.done_playing = SF_FALSE ; while (audio_data.done_playing == SF_FALSE) usleep (10 * 1000) ; /* 10 000 milliseconds. */ if ((err = AudioDeviceStop (audio_data.device, macosx_audio_out_callback)) != noErr) { printf ("AudioDeviceStop failed.\n") ; return ; } ; err = AudioDeviceRemoveIOProc (audio_data.device, macosx_audio_out_callback) ; if (err != noErr) { printf ("AudioDeviceRemoveIOProc failed.\n") ; return ; } ; sf_close (audio_data.sndfile) ; } ; return ;} /* macosx_play */#endif /* MacOSX *//*------------------------------------------------------------------------------** Win32 functions for playing a sound.**** This API sucks. Its needlessly complicated and is *WAY* too loose with** passing pointers arounf in integers and and using char* pointers to** point to data instead of short*. It plain sucks!*/#if (OS_IS_WIN32 == 1)#define WIN32_BUFFER_LEN (1<<15)typedef struct{ HWAVEOUT hwave ; WAVEHDR whdr [2] ; CRITICAL_SECTION mutex ; /* to control access to BuffersInUSe */ HANDLE Event ; /* signal that a buffer is free */ short buffer [WIN32_BUFFER_LEN / sizeof (short)] ; int current, bufferlen ; int BuffersInUse ; SNDFILE *sndfile ; SF_INFO sfinfo ; sf_count_t remaining ;} Win32_Audio_Data ;static voidwin32_play_data (Win32_Audio_Data *audio_data){ int thisread, readcount ; /* fill a buffer if there is more data and we can read it sucessfully */ readcount = (audio_data->remaining > audio_data->bufferlen) ? audio_data->bufferlen : (int) audio_data->remaining ; thisread = (int) sf_read_short (audio_data->sndfile, (short *) (audio_data->whdr [audio_data->current].lpData), readcount) ; audio_data->remaining -= thisread ; if (thisread > 0) { /* Fix buffer length if this is only a partial block. */ if (thisread < audio_data->bufferlen) audio_data->whdr [audio_data->current].dwBufferLength = thisread * sizeof (short) ; /* Queue the WAVEHDR */ waveOutWrite (audio_data->hwave, (LPWAVEHDR) &(audio_data->whdr [audio_data->current]), sizeof (WAVEHDR)) ; /* count another buffer in use */ EnterCriticalSection (&audio_data->mutex) ; audio_data->BuffersInUse ++ ; LeaveCriticalSection (&audio_data->mutex) ; /* use the other buffer next time */ audio_data->current = (audio_data->current + 1) % 2 ; } ; return ;} /* win32_play_data */static void CALLBACKwin32_audio_out_callback (HWAVEOUT hwave, UINT msg, DWORD data, DWORD param1, DWORD param2){ Win32_Audio_Data *audio_data ; /* Prevent compiler warnings. */ hwave = hwave ; param1 = param2 ; if (data == 0) return ; /* ** I consider this technique of passing a pointer via an integer as ** fundamentally broken but thats the way microsoft has defined the ** interface. */ audio_data = (Win32_Audio_Data*) data ; /* let main loop know a buffer is free */ if (msg == MM_WOM_DONE) { EnterCriticalSection (&audio_data->mutex) ; audio_data->BuffersInUse -- ; LeaveCriticalSection (&audio_data->mutex) ; SetEvent (audio_data->Event) ; } ; return ;} /* win32_audio_out_callback *//* This is needed for earlier versions of the M$ development tools. */#ifndef DWORD_PTR#define DWORD_PTR DWORD#endifstatic voidwin32_play (int argc, char *argv []){ Win32_Audio_Data audio_data ; WAVEFORMATEX wf ; int k, error ; audio_data.sndfile = NULL ; audio_data.hwave = 0 ; for (k = 1 ; k < argc ; k++) { printf ("Playing %s\n", argv [k]) ; if (! (audio_data.sndfile = sf_open (argv [k], SFM_READ, &(audio_data.sfinfo)))) { puts (sf_strerror (NULL)) ; continue ; } ; audio_data.remaining = audio_data.sfinfo.frames ; audio_data.current = 0 ; InitializeCriticalSection (&audio_data.mutex) ; audio_data.Event = CreateEvent (0, FALSE, FALSE, 0) ; wf.nChannels = audio_data.sfinfo.channels ; wf.wFormatTag = WAVE_FORMAT_PCM ; wf.cbSize = 0 ; wf.wBitsPerSample = 16 ; wf.nSamplesPerSec = audio_data.sfinfo.samplerate ; wf.nBlockAlign = audio_data.sfinfo.channels * sizeof (short) ; wf.nAvgBytesPerSec = wf.nBlockAlign * wf.nSamplesPerSec ; error = waveOutOpen (&(audio_data.hwave), WAVE_MAPPER, &wf, (DWORD_PTR) win32_audio_out_callback, (DWORD_PTR) &audio_data, CALLBACK_FUNCTION) ; if (error) { puts ("waveOutOpen failed.") ; audio_data.hwave = 0 ; continue ; } ; audio_data.whdr [0].lpData = (char*) audio_data.buffer ; audio_data.whdr [1].lpData = ((char*) audio_data.buffer) + sizeof (audio_data.buffer) / 2 ; audio_data.whdr [0].dwBufferLength = sizeof (audio_data.buffer) / 2 ; audio_data.whdr [1].dwBufferLength = sizeof (audio_data.buffer) / 2 ; audio_data.whdr [0].dwFlags = 0 ; audio_data.whdr [1].dwFlags = 0 ; /* length of each audio buffer in samples */ audio_data.bufferlen = sizeof (audio_data.buffer) / 2 / sizeof (short) ; /* Prepare the WAVEHDRs */ if ((error = waveOutPrepareHeader (audio_data.hwave, &(audio_data.whdr [0]), sizeof (WAVEHDR)))) { printf ("waveOutPrepareHeader [0] failed : %08X\n", error) ; waveOutClose (audio_data.hwave) ; continue ; } ; if ((error = waveOutPrepareHeader (audio_data.hwave, &(audio_data.whdr [1]), sizeof (WAVEHDR)))) { printf ("waveOutPrepareHeader [1] failed : %08X\n", error) ; waveOutUnprepareHeader (audio_data.hwave, &(audio_data.whdr [0]), sizeof (WAVEHDR)) ; waveOutClose (audio_data.hwave) ; continue ; } ; /* Fill up both buffers with audio data */ audio_data.BuffersInUse = 0 ; win32_play_data (&audio_data) ; win32_play_data (&audio_data) ; /* loop until both buffers are released */ while (audio_data.BuffersInUse > 0) { /* wait for buffer to be released */ WaitForSingleObject (audio_data.Event, INFINITE) ; /* refill the buffer if there is more data to play */ win32_play_data (&audio_data) ; } ; waveOutUnprepareHeader (audio_data.hwave, &(audio_data.whdr [0]), sizeof (WAVEHDR)) ; waveOutUnprepareHeader (audio_data.hwave, &(audio_data.whdr [1]), sizeof (WAVEHDR)) ; waveOutClose (audio_data.hwave) ; audio_data.hwave = 0 ; DeleteCriticalSection (&audio_data.mutex) ; sf_close (audio_data.sndfile) ; } ;} /* win32_play */#endif /* Win32 *//*------------------------------------------------------------------------------** Solaris.*/#if (defined (sun) && defined (unix)) /* ie Solaris */static voidsolaris_play (int argc, char *argv []){ static short buffer [BUFFER_LEN] ; audio_info_t audio_info ; SNDFILE *sndfile ; SF_INFO sfinfo ; unsigned long delay_time ; long k, start_count, output_count, write_count, read_count ; int audio_fd, error, done ; for (k = 1 ; k < argc ; k++) { 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 ; } ; /* open the audio device - write only, non-blocking */ if ((audio_fd = open ("/dev/audio", O_WRONLY | O_NONBLOCK)) < 0) { perror ("open (/dev/audio) failed") ; return ; } ; /* Retrive standard values. */ AUDIO_INITINFO (&audio_info) ; audio_info.play.sample_rate = sfinfo.samplerate ; audio_info.play.channels = sfinfo.channels ; audio_info.play.precision = 16 ; audio_info.play.encoding = AUDIO_ENCODING_LINEAR ; audio_info.play.gain = AUDIO_MAX_GAIN ; audio_info.play.balance = AUDIO_MID_BALANCE ; if ((error = ioctl (audio_fd, AUDIO_SETINFO, &audio_info))) { perror ("ioctl (AUDIO_SETINFO) failed") ; return ; } ; /* Delay time equal to 1/4 of a buffer in microseconds. */ delay_time = (BUFFER_LEN * 1000000) / (audio_info.play.sample_rate * 4) ; done = 0 ; while (! done) { read_count = sf_read_short (sndfile, buffer, BUFFER_LEN) ; if (read_count < BUFFER_LEN) { memset (&(buffer [read_count]), 0, (BUFFER_LEN - read_count) * sizeof (short)) ; /* Tell the main application to terminate. */ done = SF_TRUE ; } ; start_count = 0 ; output_count = BUFFER_LEN * sizeof (short) ; while (output_count > 0) { /* write as much data as possible */ write_count = write (audio_fd, &(buffer [start_count]), output_count) ; if (write_count > 0) { output_count -= write_count ; start_count += write_count ; } else { /* Give the audio output time to catch up. */ usleep (delay_time) ; } ; } ; /* while (outpur_count > 0) */ } ; /* while (! done) */ close (audio_fd) ; } ; return ;} /* solaris_play */#endif /* Solaris *//*==============================================================================** Main function.*/intmain (int argc, char *argv []){ if (argc < 2) { printf ("\nUsage : %s <input sound file>\n\n", argv [0]) ;#if (OS_IS_WIN32 == 1) printf ("This is a Unix style command line application which\n" "should be run in a MSDOS box or Command Shell window.\n\n") ; printf ("Sleeping for 5 seconds before exiting.\n\n") ; /* This is the officially blessed by microsoft way but I can't get ** it to link. ** Sleep (15) ; ** Instead, use this: */ _sleep (5 * 1000) ;#endif return 1 ; } ;#if defined (__linux__) #if HAVE_ALSA_ASOUNDLIB_H if (access ("/proc/asound/cards", R_OK) == 0) alsa_play (argc, argv) ; else #endif linux_play (argc, argv) ;#elif (defined (__MACH__) && defined (__APPLE__)) macosx_play (argc, argv) ;#elif (defined (sun) && defined (unix)) solaris_play (argc, argv) ;#elif (OS_IS_WIN32 == 1) win32_play (argc, argv) ;#elif defined (__BEOS__) printf ("This program cannot be compiled on BeOS.\n") ; printf ("Instead, compile the file sfplay_beos.cpp.\n") ; return 1 ;#else puts ("*** Playing sound not yet supported on this platform.") ; puts ("*** Please feel free to submit a patch.") ; return 1 ;#endif return 0 ;} /* main *//*** Do not edit or modify anything in this comment block.** The arch-tag line is a file identity tag for the GNU Arch** revision control system.**** arch-tag: 8fc4110d-6cec-4e03-91df-0f384cabedac*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -