diff --git a/lib-src/FileDialog/FileDialog.cpp b/lib-src/FileDialog/FileDialog.cpp old mode 100755 new mode 100644 diff --git a/lib-src/FileDialog/FileDialog.h b/lib-src/FileDialog/FileDialog.h old mode 100755 new mode 100644 diff --git a/lib-src/FileDialog/FileDialog.vcproj b/lib-src/FileDialog/FileDialog.vcproj old mode 100755 new mode 100644 index 0d4e0eae9..4db5671da --- a/lib-src/FileDialog/FileDialog.vcproj +++ b/lib-src/FileDialog/FileDialog.vcproj @@ -1,566 +1,566 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib-src/FileDialog/gtk/FileDialogPrivate.cpp b/lib-src/FileDialog/gtk/FileDialogPrivate.cpp old mode 100755 new mode 100644 diff --git a/lib-src/FileDialog/gtk/FileDialogPrivate.h b/lib-src/FileDialog/gtk/FileDialogPrivate.h old mode 100755 new mode 100644 diff --git a/lib-src/FileDialog/gtk/private.h b/lib-src/FileDialog/gtk/private.h old mode 100755 new mode 100644 diff --git a/lib-src/FileDialog/mac/FileDialogPrivate.cpp b/lib-src/FileDialog/mac/FileDialogPrivate.cpp old mode 100755 new mode 100644 diff --git a/lib-src/FileDialog/mac/FileDialogPrivate.h b/lib-src/FileDialog/mac/FileDialogPrivate.h old mode 100755 new mode 100644 diff --git a/lib-src/FileDialog/win/FileDialogPrivate.cpp b/lib-src/FileDialog/win/FileDialogPrivate.cpp old mode 100755 new mode 100644 diff --git a/lib-src/FileDialog/win/FileDialogPrivate.h b/lib-src/FileDialog/win/FileDialogPrivate.h old mode 100755 new mode 100644 diff --git a/lib-src/expat/expat.vcproj b/lib-src/expat/expat.vcproj index d2d4c353e..913b293ab 100644 --- a/lib-src/expat/expat.vcproj +++ b/lib-src/expat/expat.vcproj @@ -1,799 +1,799 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib-src/libflac/include/share/replaygain_analysis.h b/lib-src/libflac/include/share/replaygain_analysis.h index 02067d21f..6aef649e3 100644 --- a/lib-src/libflac/include/share/replaygain_analysis.h +++ b/lib-src/libflac/include/share/replaygain_analysis.h @@ -1,59 +1,59 @@ -/* - * ReplayGainAnalysis - analyzes input samples and give the recommended dB change - * Copyright (C) 2001 David Robinson and Glen Sawyer - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * concept and filter values by David Robinson (David@Robinson.org) - * -- blame him if you think the idea is flawed - * coding by Glen Sawyer (glensawyer@hotmail.com) 442 N 700 E, Provo, UT 84606 USA - * -- blame him if you think this runs too slowly, or the coding is otherwise flawed - * minor cosmetic tweaks to integrate with FLAC by Josh Coalson - * - * For an explanation of the concepts and the basic algorithms involved, go to: - * http://www.replaygain.org/ - */ - -#ifndef GAIN_ANALYSIS_H -#define GAIN_ANALYSIS_H - -#include - -#define GAIN_NOT_ENOUGH_SAMPLES -24601 -#define GAIN_ANALYSIS_ERROR 0 -#define GAIN_ANALYSIS_OK 1 - -#define INIT_GAIN_ANALYSIS_ERROR 0 -#define INIT_GAIN_ANALYSIS_OK 1 - -#ifdef __cplusplus -extern "C" { -#endif - -typedef float Float_t; /* Type used for filtering */ - -extern Float_t ReplayGainReferenceLoudness; /* in dB SPL, currently == 89.0 */ - -int InitGainAnalysis ( long samplefreq ); -int AnalyzeSamples ( const Float_t* left_samples, const Float_t* right_samples, size_t num_samples, int num_channels ); -int ResetSampleFrequency ( long samplefreq ); -Float_t GetTitleGain ( void ); -Float_t GetAlbumGain ( void ); - -#ifdef __cplusplus -} -#endif - -#endif /* GAIN_ANALYSIS_H */ +/* + * ReplayGainAnalysis - analyzes input samples and give the recommended dB change + * Copyright (C) 2001 David Robinson and Glen Sawyer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * concept and filter values by David Robinson (David@Robinson.org) + * -- blame him if you think the idea is flawed + * coding by Glen Sawyer (glensawyer@hotmail.com) 442 N 700 E, Provo, UT 84606 USA + * -- blame him if you think this runs too slowly, or the coding is otherwise flawed + * minor cosmetic tweaks to integrate with FLAC by Josh Coalson + * + * For an explanation of the concepts and the basic algorithms involved, go to: + * http://www.replaygain.org/ + */ + +#ifndef GAIN_ANALYSIS_H +#define GAIN_ANALYSIS_H + +#include + +#define GAIN_NOT_ENOUGH_SAMPLES -24601 +#define GAIN_ANALYSIS_ERROR 0 +#define GAIN_ANALYSIS_OK 1 + +#define INIT_GAIN_ANALYSIS_ERROR 0 +#define INIT_GAIN_ANALYSIS_OK 1 + +#ifdef __cplusplus +extern "C" { +#endif + +typedef float Float_t; /* Type used for filtering */ + +extern Float_t ReplayGainReferenceLoudness; /* in dB SPL, currently == 89.0 */ + +int InitGainAnalysis ( long samplefreq ); +int AnalyzeSamples ( const Float_t* left_samples, const Float_t* right_samples, size_t num_samples, int num_channels ); +int ResetSampleFrequency ( long samplefreq ); +Float_t GetTitleGain ( void ); +Float_t GetAlbumGain ( void ); + +#ifdef __cplusplus +} +#endif + +#endif /* GAIN_ANALYSIS_H */ diff --git a/lib-src/libflac/src/libFLAC++/win32/libflac_cpp.vcproj b/lib-src/libflac/src/libFLAC++/win32/libflac_cpp.vcproj index bcf0f55c9..c810b4b36 100644 --- a/lib-src/libflac/src/libFLAC++/win32/libflac_cpp.vcproj +++ b/lib-src/libflac/src/libFLAC++/win32/libflac_cpp.vcproj @@ -1,546 +1,546 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib-src/libflac/src/libFLAC/bitwriter.c b/lib-src/libflac/src/libFLAC/bitwriter.c old mode 100755 new mode 100644 diff --git a/lib-src/libflac/src/libFLAC/win32/libflac.vcproj b/lib-src/libflac/src/libFLAC/win32/libflac.vcproj index 35d078cf3..03056c1bf 100644 --- a/lib-src/libflac/src/libFLAC/win32/libflac.vcproj +++ b/lib-src/libflac/src/libFLAC/win32/libflac.vcproj @@ -1,1771 +1,1771 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib-src/libid3tag/libid3tag.vcproj b/lib-src/libid3tag/libid3tag.vcproj index 0c6e914ec..130a4092e 100644 --- a/lib-src/libid3tag/libid3tag.vcproj +++ b/lib-src/libid3tag/libid3tag.vcproj @@ -1,1971 +1,1971 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib-src/libid3tag/msvc++/libid3tag.dsp b/lib-src/libid3tag/msvc++/libid3tag.dsp old mode 100755 new mode 100644 diff --git a/lib-src/libmad/libmad.vcproj b/lib-src/libmad/libmad.vcproj index 81d16d2f2..97b74f9b7 100644 --- a/lib-src/libmad/libmad.vcproj +++ b/lib-src/libmad/libmad.vcproj @@ -1,1479 +1,1479 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib-src/libogg/doc/vorbisfile/fileinfo.html b/lib-src/libogg/doc/vorbisfile/fileinfo.html index ab55f1448..7f4605eea 100644 --- a/lib-src/libogg/doc/vorbisfile/fileinfo.html +++ b/lib-src/libogg/doc/vorbisfile/fileinfo.html @@ -1,95 +1,95 @@ - - - -Vorbisfile - File Information - - - - - - - - - -

Vorbisfile documentation

vorbisfile version 1.68 - 20030307

- -

File Information

-

Libvorbisfile contains many functions to get information about bitstream attributes and decoding status. -

-All libvorbisfile file information routines are declared in "vorbis/vorbisfile.h". -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
functionpurpose
ov_bitrateReturns the average bitrate of the current logical bitstream.
ov_bitrate_instantReturns the exact bitrate since the last call of this function, or -1 if at the beginning of the bitream or no new information is available.
ov_streamsGives the number of logical bitstreams within the current physical bitstream.
ov_seekableIndicates whether the bitstream is seekable.
ov_serialnumberReturns the unique serial number of the specified logical bitstream.
ov_raw_totalReturns the total (compressed) bytes in a physical or logical seekable bitstream.
ov_pcm_totalReturns the total number of samples in a physical or logical seekable bitstream.
ov_time_totalReturns the total time length in seconds of a physical or logical seekable bitstream.
ov_raw_tellReturns the byte location of the next sample to be read, giving the approximate location in the stream that the decoding engine has reached.
ov_pcm_tellReturns the sample location of the next sample to be read, giving the approximate location in the stream that the decoding engine has reached.
ov_time_tellReturns the time location of the next sample to be read, giving the approximate location in the stream that the decoding engine has reached.
ov_infoReturns the vorbis_info struct for a specific bitstream section.
ov_commentReturns attached comments for the current bitstream.
- -

-


- - - - - - - - -

copyright © 2003 Xiph.org

Ogg Vorbis

Vorbisfile documentation

vorbisfile version 1.68 - 20030307

- - - - + + + +Vorbisfile - File Information + + + + + + + + + +

Vorbisfile documentation

vorbisfile version 1.68 - 20030307

+ +

File Information

+

Libvorbisfile contains many functions to get information about bitstream attributes and decoding status. +

+All libvorbisfile file information routines are declared in "vorbis/vorbisfile.h". +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
functionpurpose
ov_bitrateReturns the average bitrate of the current logical bitstream.
ov_bitrate_instantReturns the exact bitrate since the last call of this function, or -1 if at the beginning of the bitream or no new information is available.
ov_streamsGives the number of logical bitstreams within the current physical bitstream.
ov_seekableIndicates whether the bitstream is seekable.
ov_serialnumberReturns the unique serial number of the specified logical bitstream.
ov_raw_totalReturns the total (compressed) bytes in a physical or logical seekable bitstream.
ov_pcm_totalReturns the total number of samples in a physical or logical seekable bitstream.
ov_time_totalReturns the total time length in seconds of a physical or logical seekable bitstream.
ov_raw_tellReturns the byte location of the next sample to be read, giving the approximate location in the stream that the decoding engine has reached.
ov_pcm_tellReturns the sample location of the next sample to be read, giving the approximate location in the stream that the decoding engine has reached.
ov_time_tellReturns the time location of the next sample to be read, giving the approximate location in the stream that the decoding engine has reached.
ov_infoReturns the vorbis_info struct for a specific bitstream section.
ov_commentReturns attached comments for the current bitstream.
+ +

+


+ + + + + + + + +

copyright © 2003 Xiph.org

Ogg Vorbis

Vorbisfile documentation

vorbisfile version 1.68 - 20030307

+ + + + diff --git a/lib-src/libogg/doc/vorbisfile/seeking.html b/lib-src/libogg/doc/vorbisfile/seeking.html index e570d5a02..c769a43a7 100644 --- a/lib-src/libogg/doc/vorbisfile/seeking.html +++ b/lib-src/libogg/doc/vorbisfile/seeking.html @@ -1,107 +1,107 @@ - - - -Vorbisfile - Seeking - - - - - - - - - -

Vorbisfile documentation

vorbisfile version 1.68 - 20030307

- -

Seeking

-

Seeking functions allow you to specify a specific point in the stream to begin or continue decoding. -

-All libvorbisfile seeking routines are declared in "vorbis/vorbisfile.h". - -

Certain seeking functions are best suited to different situations. -When speed is important and exact positioning isn't required, -page-level seeking should be used. Note also that Vorbis files do not -necessarily start at a sample number or time offset of zero. Do not -be surprised if a file begins at a positive offset of several minutes -or hours, such as would happen if a large stream (such as a concert -recording) is chopped into multiple separate files. Requesting to -seek to a position before the beginning of such a file will seek to -the position where audio begins. - -

As of vorbisfile version 1.68, seeking also optionally provides -automatic crosslapping to eliminate clicks and other discontinuity -artifacts at seeking boundaries. This fetaure is of particular -interest to player and game developers implementing dynamic music and -audio engines, or others looking for smooth transitions within a -single sample or across multiple samples.

- -

Naturally, seeking is available only within a seekable file or -stream. Seeking functions will return OV_ENOSEEK on -nonseekable files and streams. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
functionpurpose
ov_raw_seekThis function seeks to a position specified in the compressed bitstream, specified in bytes.
ov_pcm_seekThis function seeks to a specific audio sample number, specified in pcm samples.
ov_pcm_seek_pageThis function seeks to the closest page preceding the specified audio sample number, specified in pcm samples.
ov_time_seekThis function seeks to the specific time location in the bitstream, specified in seconds
ov_time_seek_pageThis function seeks to the closest page preceding the specified time position in the bitstream
ov_raw_seek_lapThis function seeks to a position specified in the compressed bitstream, specified in bytes. The boundary between the old and new playback positions is crosslapped to eliminate discontinuities.
ov_pcm_seek_lapThis function seeks to a specific audio sample number, specified in pcm samples. The boundary between the old and new playback positions is crosslapped to eliminate discontinuities.
ov_pcm_seek_page_lapThis function seeks to the closest page preceding the specified audio sample number, specified in pcm samples. The boundary between the old and new playback positions is crosslapped to eliminate discontinuities.
ov_time_seek_lapThis function seeks to the specific time location in the bitstream, specified in seconds. The boundary between the old and new playback positions is crosslapped to eliminate discontinuities.
ov_time_seek_page_lapThis function seeks to the closest page preceding the specified time position in the bitstream. The boundary between the old and new playback positions is crosslapped to eliminate discontinuities.
- -

-


- - - - - - - - -

copyright © 2003 Xiph.org

Ogg Vorbis

Vorbisfile documentation

vorbisfile version 1.68 - 20030307

- - - - + + + +Vorbisfile - Seeking + + + + + + + + + +

Vorbisfile documentation

vorbisfile version 1.68 - 20030307

+ +

Seeking

+

Seeking functions allow you to specify a specific point in the stream to begin or continue decoding. +

+All libvorbisfile seeking routines are declared in "vorbis/vorbisfile.h". + +

Certain seeking functions are best suited to different situations. +When speed is important and exact positioning isn't required, +page-level seeking should be used. Note also that Vorbis files do not +necessarily start at a sample number or time offset of zero. Do not +be surprised if a file begins at a positive offset of several minutes +or hours, such as would happen if a large stream (such as a concert +recording) is chopped into multiple separate files. Requesting to +seek to a position before the beginning of such a file will seek to +the position where audio begins. + +

As of vorbisfile version 1.68, seeking also optionally provides +automatic crosslapping to eliminate clicks and other discontinuity +artifacts at seeking boundaries. This fetaure is of particular +interest to player and game developers implementing dynamic music and +audio engines, or others looking for smooth transitions within a +single sample or across multiple samples.

+ +

Naturally, seeking is available only within a seekable file or +stream. Seeking functions will return OV_ENOSEEK on +nonseekable files and streams. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
functionpurpose
ov_raw_seekThis function seeks to a position specified in the compressed bitstream, specified in bytes.
ov_pcm_seekThis function seeks to a specific audio sample number, specified in pcm samples.
ov_pcm_seek_pageThis function seeks to the closest page preceding the specified audio sample number, specified in pcm samples.
ov_time_seekThis function seeks to the specific time location in the bitstream, specified in seconds
ov_time_seek_pageThis function seeks to the closest page preceding the specified time position in the bitstream
ov_raw_seek_lapThis function seeks to a position specified in the compressed bitstream, specified in bytes. The boundary between the old and new playback positions is crosslapped to eliminate discontinuities.
ov_pcm_seek_lapThis function seeks to a specific audio sample number, specified in pcm samples. The boundary between the old and new playback positions is crosslapped to eliminate discontinuities.
ov_pcm_seek_page_lapThis function seeks to the closest page preceding the specified audio sample number, specified in pcm samples. The boundary between the old and new playback positions is crosslapped to eliminate discontinuities.
ov_time_seek_lapThis function seeks to the specific time location in the bitstream, specified in seconds. The boundary between the old and new playback positions is crosslapped to eliminate discontinuities.
ov_time_seek_page_lapThis function seeks to the closest page preceding the specified time position in the bitstream. The boundary between the old and new playback positions is crosslapped to eliminate discontinuities.
+ +

+


+ + + + + + + + +

copyright © 2003 Xiph.org

Ogg Vorbis

Vorbisfile documentation

vorbisfile version 1.68 - 20030307

+ + + + diff --git a/lib-src/libogg/macos/compat/strdup.c b/lib-src/libogg/macos/compat/strdup.c old mode 100755 new mode 100644 diff --git a/lib-src/libogg/macos/compat/sys/types.h b/lib-src/libogg/macos/compat/sys/types.h old mode 100755 new mode 100644 index b0d4f9202..083eeac2a --- a/lib-src/libogg/macos/compat/sys/types.h +++ b/lib-src/libogg/macos/compat/sys/types.h @@ -1 +1,29 @@ -#ifndef __SYS_TYPES_H__ #define __SYS_TYPES_H__ 1 #include #include #include typedef short int16_t; typedef long int32_t; typedef long long int64_t; #define vorbis_size32_t long #if defined(__cplusplus) extern "C" { #endif #pragma options align=power char *strdup(const char *inStr); #pragma options align=reset #if defined(__cplusplus) } #endif #endif /* __SYS_TYPES_H__ */ \ No newline at end of file +#ifndef __SYS_TYPES_H__ +#define __SYS_TYPES_H__ 1 + +#include +#include +#include + +typedef short int16_t; +typedef long int32_t; +typedef long long int64_t; + +#define vorbis_size32_t long + + +#if defined(__cplusplus) +extern "C" { +#endif + +#pragma options align=power + +char *strdup(const char *inStr); + +#pragma options align=reset + +#if defined(__cplusplus) +} +#endif + +#endif /* __SYS_TYPES_H__ */ diff --git a/lib-src/libogg/win32/ogg_static.vcproj b/lib-src/libogg/win32/ogg_static.vcproj index 5c54860c4..688b97e55 100644 --- a/lib-src/libogg/win32/ogg_static.vcproj +++ b/lib-src/libogg/win32/ogg_static.vcproj @@ -1,729 +1,729 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib-src/libraptor/win32/raptortest.cpp b/lib-src/libraptor/win32/raptortest.cpp index 1c6b825cf..f2792dfe4 100644 --- a/lib-src/libraptor/win32/raptortest.cpp +++ b/lib-src/libraptor/win32/raptortest.cpp @@ -1,82 +1,82 @@ -// raptortest.cpp : Defines the entry point for the console application. -// - -#include -#include -#include "..\raptor.h" - -#define TIMEIT -#define DUMPIT - -int nStmts = 0; - -void dump_statement(void* user_data, const raptor_statement *statement) -{ - nStmts++; -#ifdef DUMPIT - printf("%li, [%s, ", nStmts, statement->subject); - - if(statement->predicate_type == RAPTOR_PREDICATE_TYPE_ORDINAL) - printf("[rdf:_%d]", *((int*)statement->predicate)); - else if(statement->predicate_type == RAPTOR_PREDICATE_TYPE_XML_NAME) - printf("%s", (const char*)statement->predicate); - else - printf("[%s]", (const char*)statement->predicate); - - if(statement->object_type == RAPTOR_OBJECT_TYPE_LITERAL || - statement->object_type == RAPTOR_OBJECT_TYPE_XML_LITERAL) - printf(", \"%s\"]", (const char*)statement->object); - else if(statement->object_type == RAPTOR_OBJECT_TYPE_XML_NAME) - printf(", %s]", (const char*)statement->object); - else - printf(", %s]", statement->object); - - printf("\n"); -#endif -} - -void usage() -{ - printf("Usage: raptortest \nE.g. file:c:\\test.rdf\n"); -} - -int main(int argc, char* argv[]) -{ - if (argc != 2) - { - usage(); - return -1; - } - - - raptor_init(); - - raptor_parser* p = raptor_new(""); - - raptor_set_statement_handler(p, NULL, dump_statement); - -#ifdef TIMEIT - LARGE_INTEGER Start; - QueryPerformanceCounter(&Start); -#endif - raptor_parse_file(p, argv[1], NULL); - -#ifdef TIMEIT - LARGE_INTEGER End; - QueryPerformanceCounter(&End); - LARGE_INTEGER Frec; - QueryPerformanceFrequency(&Frec); - double Total = (End.LowPart-Start.LowPart); - double StmtsPer = Total/nStmts; - - printf("%li statments processed in %g t. %g t/stmts, %li t/s, %g stmts/s", nStmts, Total, StmtsPer, Frec.LowPart, (double)Frec.LowPart/StmtsPer); -#endif - - raptor_free(p); - - raptor_finish(); - - return 0; -} - - +// raptortest.cpp : Defines the entry point for the console application. +// + +#include +#include +#include "..\raptor.h" + +#define TIMEIT +#define DUMPIT + +int nStmts = 0; + +void dump_statement(void* user_data, const raptor_statement *statement) +{ + nStmts++; +#ifdef DUMPIT + printf("%li, [%s, ", nStmts, statement->subject); + + if(statement->predicate_type == RAPTOR_PREDICATE_TYPE_ORDINAL) + printf("[rdf:_%d]", *((int*)statement->predicate)); + else if(statement->predicate_type == RAPTOR_PREDICATE_TYPE_XML_NAME) + printf("%s", (const char*)statement->predicate); + else + printf("[%s]", (const char*)statement->predicate); + + if(statement->object_type == RAPTOR_OBJECT_TYPE_LITERAL || + statement->object_type == RAPTOR_OBJECT_TYPE_XML_LITERAL) + printf(", \"%s\"]", (const char*)statement->object); + else if(statement->object_type == RAPTOR_OBJECT_TYPE_XML_NAME) + printf(", %s]", (const char*)statement->object); + else + printf(", %s]", statement->object); + + printf("\n"); +#endif +} + +void usage() +{ + printf("Usage: raptortest \nE.g. file:c:\\test.rdf\n"); +} + +int main(int argc, char* argv[]) +{ + if (argc != 2) + { + usage(); + return -1; + } + + + raptor_init(); + + raptor_parser* p = raptor_new(""); + + raptor_set_statement_handler(p, NULL, dump_statement); + +#ifdef TIMEIT + LARGE_INTEGER Start; + QueryPerformanceCounter(&Start); +#endif + raptor_parse_file(p, argv[1], NULL); + +#ifdef TIMEIT + LARGE_INTEGER End; + QueryPerformanceCounter(&End); + LARGE_INTEGER Frec; + QueryPerformanceFrequency(&Frec); + double Total = (End.LowPart-Start.LowPart); + double StmtsPer = Total/nStmts; + + printf("%li statments processed in %g t. %g t/stmts, %li t/s, %g stmts/s", nStmts, Total, StmtsPer, Frec.LowPart, (double)Frec.LowPart/StmtsPer); +#endif + + raptor_free(p); + + raptor_finish(); + + return 0; +} + + diff --git a/lib-src/libresample/win/libresample.vcproj b/lib-src/libresample/win/libresample.vcproj index a18bddd2c..5a74163b4 100644 --- a/lib-src/libresample/win/libresample.vcproj +++ b/lib-src/libresample/win/libresample.vcproj @@ -1,776 +1,776 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib-src/libsamplerate/Win32/libsamplerate.vcproj b/lib-src/libsamplerate/Win32/libsamplerate.vcproj index a590742dd..31139716e 100644 --- a/lib-src/libsamplerate/Win32/libsamplerate.vcproj +++ b/lib-src/libsamplerate/Win32/libsamplerate.vcproj @@ -1,901 +1,901 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib-src/libscorealign/libscorealign.vcproj b/lib-src/libscorealign/libscorealign.vcproj index bc91d80dd..5b061bfdc 100644 --- a/lib-src/libscorealign/libscorealign.vcproj +++ b/lib-src/libscorealign/libscorealign.vcproj @@ -1,374 +1,374 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib-src/libscorealign/scorealign.sln b/lib-src/libscorealign/scorealign.sln index 489f005e4..7745c68d0 100644 --- a/lib-src/libscorealign/scorealign.sln +++ b/lib-src/libscorealign/scorealign.sln @@ -1,20 +1,20 @@ - -Microsoft Visual Studio Solution File, Format Version 9.00 -# Visual C++ Express 2005 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "score-align", "score-align.vcproj", "{5F04DE5D-0A34-496E-8A34-BE30BA9C70A1}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {5F04DE5D-0A34-496E-8A34-BE30BA9C70A1}.Debug|Win32.ActiveCfg = Debug|Win32 - {5F04DE5D-0A34-496E-8A34-BE30BA9C70A1}.Debug|Win32.Build.0 = Debug|Win32 - {5F04DE5D-0A34-496E-8A34-BE30BA9C70A1}.Release|Win32.ActiveCfg = Release|Win32 - {5F04DE5D-0A34-496E-8A34-BE30BA9C70A1}.Release|Win32.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual C++ Express 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "score-align", "score-align.vcproj", "{5F04DE5D-0A34-496E-8A34-BE30BA9C70A1}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5F04DE5D-0A34-496E-8A34-BE30BA9C70A1}.Debug|Win32.ActiveCfg = Debug|Win32 + {5F04DE5D-0A34-496E-8A34-BE30BA9C70A1}.Debug|Win32.Build.0 = Debug|Win32 + {5F04DE5D-0A34-496E-8A34-BE30BA9C70A1}.Release|Win32.ActiveCfg = Release|Win32 + {5F04DE5D-0A34-496E-8A34-BE30BA9C70A1}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/lib-src/libvamp/win/libvamp.vcproj b/lib-src/libvamp/win/libvamp.vcproj index 8fe0cad9b..31d55bcb9 100644 --- a/lib-src/libvamp/win/libvamp.vcproj +++ b/lib-src/libvamp/win/libvamp.vcproj @@ -1,624 +1,624 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib-src/libvorbis/macos/compat/sys/types.h b/lib-src/libvorbis/macos/compat/sys/types.h index b0d4f9202..083eeac2a 100644 --- a/lib-src/libvorbis/macos/compat/sys/types.h +++ b/lib-src/libvorbis/macos/compat/sys/types.h @@ -1 +1,29 @@ -#ifndef __SYS_TYPES_H__ #define __SYS_TYPES_H__ 1 #include #include #include typedef short int16_t; typedef long int32_t; typedef long long int64_t; #define vorbis_size32_t long #if defined(__cplusplus) extern "C" { #endif #pragma options align=power char *strdup(const char *inStr); #pragma options align=reset #if defined(__cplusplus) } #endif #endif /* __SYS_TYPES_H__ */ \ No newline at end of file +#ifndef __SYS_TYPES_H__ +#define __SYS_TYPES_H__ 1 + +#include +#include +#include + +typedef short int16_t; +typedef long int32_t; +typedef long long int64_t; + +#define vorbis_size32_t long + + +#if defined(__cplusplus) +extern "C" { +#endif + +#pragma options align=power + +char *strdup(const char *inStr); + +#pragma options align=reset + +#if defined(__cplusplus) +} +#endif + +#endif /* __SYS_TYPES_H__ */ diff --git a/lib-src/libvorbis/symbian/config.h b/lib-src/libvorbis/symbian/config.h index 56d2179ed..8fcd19682 100644 --- a/lib-src/libvorbis/symbian/config.h +++ b/lib-src/libvorbis/symbian/config.h @@ -1,54 +1,54 @@ -/* - Copyright (C) 2003 Commonwealth Scientific and Industrial Research - Organisation (CSIRO) Australia - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - - Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - - Neither the name of CSIRO Australia nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ORGANISATION OR - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef CONFIG_H -#define CONFIG_H - -#ifdef __WINS__ - -/* Disable some warnings */ - -#pragma warning(disable: 4100) /* unreferenced formal parameter */ -#pragma warning(disable: 4127) /* conditional expression is constant */ -#pragma warning(disable: 4189) /* local variable is initialized but not referenced */ -#pragma warning(disable: 4244) /* conversion from '...' to '...', possible loss of data */ -#pragma warning(disable: 4305) /* truncation from '...' to '...' */ -#pragma warning(disable: 4505) /* unreferenced local function has been removed */ -#pragma warning(disable: 4514) /* unreferenced inline function has been removed */ -#pragma warning(disable: 4702) /* unreachable code */ -#pragma warning(disable: 4701) /* local variable may be be used without having been initialized */ -#pragma warning(disable: 4706) /* assignment within conditional expression */ -#pragma warning(disable: 4761) /* integral size mismatch in argument: conversion supplied */ - -#endif - -#endif /* ! CONFIG_H */ +/* + Copyright (C) 2003 Commonwealth Scientific and Industrial Research + Organisation (CSIRO) Australia + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of CSIRO Australia nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ORGANISATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef CONFIG_H +#define CONFIG_H + +#ifdef __WINS__ + +/* Disable some warnings */ + +#pragma warning(disable: 4100) /* unreferenced formal parameter */ +#pragma warning(disable: 4127) /* conditional expression is constant */ +#pragma warning(disable: 4189) /* local variable is initialized but not referenced */ +#pragma warning(disable: 4244) /* conversion from '...' to '...', possible loss of data */ +#pragma warning(disable: 4305) /* truncation from '...' to '...' */ +#pragma warning(disable: 4505) /* unreferenced local function has been removed */ +#pragma warning(disable: 4514) /* unreferenced inline function has been removed */ +#pragma warning(disable: 4702) /* unreachable code */ +#pragma warning(disable: 4701) /* local variable may be be used without having been initialized */ +#pragma warning(disable: 4706) /* assignment within conditional expression */ +#pragma warning(disable: 4761) /* integral size mismatch in argument: conversion supplied */ + +#endif + +#endif /* ! CONFIG_H */ diff --git a/lib-src/libvorbis/win32/vorbis_static.vcproj b/lib-src/libvorbis/win32/vorbis_static.vcproj index eb5d0756b..95bb6eeea 100644 --- a/lib-src/libvorbis/win32/vorbis_static.vcproj +++ b/lib-src/libvorbis/win32/vorbis_static.vcproj @@ -1,2353 +1,2353 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib-src/libvorbis/win32/vorbisfile_static.vcproj b/lib-src/libvorbis/win32/vorbisfile_static.vcproj index 1cf8f800d..69202497d 100644 --- a/lib-src/libvorbis/win32/vorbisfile_static.vcproj +++ b/lib-src/libvorbis/win32/vorbisfile_static.vcproj @@ -1,647 +1,647 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib-src/mod-script-pipe/mod-script-pipe.vcproj b/lib-src/mod-script-pipe/mod-script-pipe.vcproj index e6b9a5f3e..0e1bd8353 100644 --- a/lib-src/mod-script-pipe/mod-script-pipe.vcproj +++ b/lib-src/mod-script-pipe/mod-script-pipe.vcproj @@ -1,186 +1,186 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib-src/portaudio-v19/src/hostapi/asihpi/pa_linux_asihpi.c b/lib-src/portaudio-v19/src/hostapi/asihpi/pa_linux_asihpi.c index a5b2df43c..3ebfafa01 100644 --- a/lib-src/portaudio-v19/src/hostapi/asihpi/pa_linux_asihpi.c +++ b/lib-src/portaudio-v19/src/hostapi/asihpi/pa_linux_asihpi.c @@ -1,2942 +1,2942 @@ -/* - * PortAudio Portable Real-Time Audio Library - * Latest Version at: http://www.portaudio.com - * - * PortAudio v18 version of AudioScience HPI driver by Fred Gleason - * PortAudio v19 version of AudioScience HPI driver by Ludwig Schwardt - * - * Copyright (c) 2003 Fred Gleason - * Copyright (c) 2005,2006 Ludwig Schwardt - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * The text above constitutes the entire PortAudio license; however, - * the PortAudio community also makes the following non-binding requests: - * - * Any person wishing to distribute modifications to the Software is - * requested to send the modifications to the original developer so that - * they can be incorporated into the canonical version. It is also - * requested that these non-binding requests be included along with the - * license above. - */ - -/* - * Modification History - * 12/2003 - Initial version - * 09/2005 - v19 version [rewrite] - */ - -/** @file - @ingroup hostapi_src - @brief Host API implementation supporting AudioScience cards - via the Linux HPI interface. - -

Overview

- - This is a PortAudio implementation for the AudioScience HPI Audio API - on the Linux platform. AudioScience makes a range of audio adapters customised - for the broadcasting industry, with support for both Windows and Linux. - More information on their products can be found on their website: - - http://www.audioscience.com - - Documentation for the HPI API can be found at: - - http://www.audioscience.com/internet/download/sdk/spchpi.pdf - - The Linux HPI driver itself (a kernel module + library) can be downloaded from: - - http://www.audioscience.com/internet/download/linux_drivers.htm - -

Implementation strategy

- - *Note* Ideally, AudioScience cards should be handled by the PortAudio ALSA - implementation on Linux, as ALSA is the preferred Linux soundcard API. The existence - of this host API implementation might therefore seem a bit flawed. Unfortunately, at - the time of the creation of this implementation (June 2006), the PA ALSA implementation - could not make use of the existing AudioScience ALSA driver. PA ALSA uses the - "memory-mapped" (mmap) ALSA access mode to interact with the ALSA library, while the - AudioScience ALSA driver only supports the "read-write" access mode. The appropriate - solution to this problem is to add "read-write" support to PortAudio ALSA, thereby - extending the range of soundcards it supports (AudioScience cards are not the only - ones with this problem). Given the author's limited knowledge of ALSA and the - simplicity of the HPI API, the second-best solution was born... - - The following mapping between HPI and PA was followed: - HPI subsystem => PortAudio host API - HPI adapter => nothing specific - HPI stream => PortAudio device - - Each HPI stream is either input or output (not both), and can support - different channel counts, sampling rates and sample formats. It is therefore - a more natural fit to a PA device. A PA stream can therefore combine two - HPI streams (one input and one output) into a "full-duplex" stream. These - HPI streams can even be on different physical adapters. The two streams ought to be - sample-synchronised when they reside on the same adapter, as most AudioScience adapters - derive their ADC and DAC clocks from one master clock. When combining two adapters - into one full-duplex stream, however, the use of a word clock connection between the - adapters is strongly recommended. - - The HPI interface is inherently blocking, making use of read and write calls to - transfer data between user buffers and driver buffers. The callback interface therefore - requires a helper thread ("callback engine") which periodically transfers data (one thread - per PA stream, in fact). The current implementation explicitly sleeps via Pa_Sleep() until - enough samples can be transferred (select() or poll() would be better, but currently seems - impossible...). The thread implementation makes use of the Unix thread helper functions - and some pthread calls here and there. If a unified PA thread exists, this host API - implementation might also compile on Windows, as this is the only real Linux-specific - part of the code. - - There is no inherent fixed buffer size in the HPI interface, as in some other host APIs. - The PortAudio implementation contains a buffer that is allocated during OpenStream and - used to transfer data between the callback and the HPI driver buffer. The size of this - buffer is quite flexible and is derived from latency suggestions and matched to the - requested callback buffer size as far as possible. It can become quite huge, as the - AudioScience cards are typically geared towards higher-latency applications and contain - large hardware buffers. - - The HPI interface natively supports most common sample formats and sample rates (some - conversion is done on the adapter itself). - - Stream time is measured based on the number of processed frames, which is adjusted by the - number of frames currently buffered by the HPI driver. - - There is basic support for detecting overflow and underflow. The HPI interface does not - explicitly indicate this, so thresholds on buffer levels are used in combination with - stream state. Recovery from overflow and underflow is left to the PA client. - - Blocking streams are also implemented. It makes use of the same polling routines that - the callback interface uses, in order to prevent the allocation of variable-sized - buffers during reading and writing. The framesPerBuffer parameter is therefore still - relevant, and this can be increased in the blocking case to improve efficiency. - - The implementation contains extensive reporting macros (slightly modified PA_ENSURE and - PA_UNLESS versions) and a useful stream dump routine to provide debugging feedback. - - Output buffer priming via the user callback (i.e. paPrimeOutputBuffersUsingStreamCallback - and friends) is not implemented yet. All output is primed with silence. - - Please send bug reports etc. to Ludwig Schwardt - */ - -#include -#include -#include -#include /* strlen() */ -#include /* pthreads and friends */ -#include /* assert */ -#include /* ceil, floor */ - -#include /* HPI API */ - -#include "portaudio.h" /* PortAudio API */ -#include "pa_util.h" /* PA_DEBUG, other small utilities */ -#include "pa_unix_util.h" /* Unix threading utilities */ -#include "pa_allocation.h" /* Group memory allocation */ -#include "pa_hostapi.h" /* Host API structs */ -#include "pa_stream.h" /* Stream interface structs */ -#include "pa_cpuload.h" /* CPU load measurer */ -#include "pa_process.h" /* Buffer processor */ -#include "pa_converters.h" /* PaUtilZeroer */ -#include "pa_debugprint.h" - -/* -------------------------------------------------------------------------- */ - -/* - * Defines - */ - -/* Error reporting and assertions */ - -/** Evaluate expression, and return on any PortAudio errors */ -#define PA_ENSURE_(expr) \ - do { \ - PaError paError = (expr); \ - if( UNLIKELY( paError < paNoError ) ) \ - { \ - PA_DEBUG(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \ - result = paError; \ - goto error; \ - } \ - } while (0); - -/** Assert expression, else return the provided PaError */ -#define PA_UNLESS_(expr, paError) \ - do { \ - if( UNLIKELY( (expr) == 0 ) ) \ - { \ - PA_DEBUG(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \ - result = (paError); \ - goto error; \ - } \ - } while( 0 ); - -/** Check return value of HPI function, and map it to PaError */ -#define PA_ASIHPI_UNLESS_(expr, paError) \ - do { \ - HW16 hpiError = (expr); \ - /* If HPI error occurred */ \ - if( UNLIKELY( hpiError ) ) \ - { \ - char szError[256]; \ - HPI_GetErrorText( hpiError, szError ); \ - PA_DEBUG(( "HPI error %d occurred: %s\n", hpiError, szError )); \ - /* This message will always be displayed, even if debug info is disabled */ \ - PA_DEBUG(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \ - if( (paError) == paUnanticipatedHostError ) \ - { \ - PA_DEBUG(( "Host error description: %s\n", szError )); \ - /* PaUtil_SetLastHostErrorInfo should only be used in the main thread */ \ - if( pthread_equal( pthread_self(), paUnixMainThread ) ) \ - { \ - PaUtil_SetLastHostErrorInfo( paInDevelopment, hpiError, szError ); \ - } \ - } \ - /* If paNoError is specified, continue as usual */ \ - /* (useful if you only want to print out the debug messages above) */ \ - if( (paError) < 0 ) \ - { \ - result = (paError); \ - goto error; \ - } \ - } \ - } while( 0 ); - -/** Report HPI error code and text */ -#define PA_ASIHPI_REPORT_ERROR_(hpiErrorCode) \ - do { \ - char szError[256]; \ - HPI_GetErrorText( hpiError, szError ); \ - PA_DEBUG(( "HPI error %d occurred: %s\n", hpiError, szError )); \ - /* PaUtil_SetLastHostErrorInfo should only be used in the main thread */ \ - if( pthread_equal( pthread_self(), paUnixMainThread ) ) \ - { \ - PaUtil_SetLastHostErrorInfo( paInDevelopment, (hpiErrorCode), szError ); \ - } \ - } while( 0 ); - -/* Defaults */ - -/** Sample formats available natively on AudioScience hardware */ -#define PA_ASIHPI_AVAILABLE_FORMATS_ (paFloat32 | paInt32 | paInt24 | paInt16 | paUInt8) -/** Enable background bus mastering (BBM) for buffer transfers, if available (see HPI docs) */ -#define PA_ASIHPI_USE_BBM_ 1 -/** Minimum number of frames in HPI buffer (for either data or available space). - If buffer contains less data/space, it indicates xrun or completion. */ -#define PA_ASIHPI_MIN_FRAMES_ 1152 -/** Minimum polling interval in milliseconds, which determines minimum host buffer size */ -#define PA_ASIHPI_MIN_POLLING_INTERVAL_ 10 - -/* -------------------------------------------------------------------------- */ - -/* - * Structures - */ - -/** Host API global data */ -typedef struct PaAsiHpiHostApiRepresentation -{ - /* PortAudio "base class" - keep the baseRep first! (C-style inheritance) */ - PaUtilHostApiRepresentation baseHostApiRep; - PaUtilStreamInterface callbackStreamInterface; - PaUtilStreamInterface blockingStreamInterface; - - PaUtilAllocationGroup *allocations; - - /* implementation specific data goes here */ - - PaHostApiIndex hostApiIndex; - /** HPI subsystem pointer */ - HPI_HSUBSYS *subSys; -} -PaAsiHpiHostApiRepresentation; - - -/** Device data */ -typedef struct PaAsiHpiDeviceInfo -{ - /* PortAudio "base class" - keep the baseRep first! (C-style inheritance) */ - /** Common PortAudio device information */ - PaDeviceInfo baseDeviceInfo; - - /* implementation specific data goes here */ - - /** HPI subsystem (required for most HPI calls) */ - HPI_HSUBSYS *subSys; - /** Adapter index */ - HW16 adapterIndex; - /** Adapter model number (hex) */ - HW16 adapterType; - /** Adapter HW/SW version */ - HW16 adapterVersion; - /** Adapter serial number */ - HW32 adapterSerialNumber; - /** Stream number */ - HW16 streamIndex; - /** 0=Input, 1=Output (HPI streams are either input or output but not both) */ - HW16 streamIsOutput; -} -PaAsiHpiDeviceInfo; - - -/** Stream state as defined by PortAudio. - It seems that the host API implementation has to keep track of the PortAudio stream state. - Please note that this is NOT the same as the state of the underlying HPI stream. By separating - these two concepts, a lot of flexibility is gained. There is a rough match between the two, - of course, but forcing a precise match is difficult. For example, HPI_STATE_DRAINED can occur - during the Active state of PortAudio (due to underruns) and also during CallBackFinished in - the case of an output stream. Similarly, HPI_STATE_STOPPED mostly coincides with the Stopped - PortAudio state, by may also occur in the CallbackFinished state when recording is finished. - - Here is a rough match-up: - - PortAudio state => HPI state - --------------- --------- - Active => HPI_STATE_RECORDING, HPI_STATE_PLAYING, (HPI_STATE_DRAINED) - Stopped => HPI_STATE_STOPPED - CallbackFinished => HPI_STATE_STOPPED, HPI_STATE_DRAINED */ -typedef enum PaAsiHpiStreamState -{ - paAsiHpiStoppedState=0, - paAsiHpiActiveState=1, - paAsiHpiCallbackFinishedState=2 -} -PaAsiHpiStreamState; - - -/** Stream component data (associated with one direction, i.e. either input or output) */ -typedef struct PaAsiHpiStreamComponent -{ - /** Device information (HPI handles, etc) */ - PaAsiHpiDeviceInfo *hpiDevice; - /** Stream handle, as passed to HPI interface. - HACK: we assume types HPI_HISTREAM and HPI_HOSTREAM are the same... - (both are HW32 up to version 3.00 of ASIHPI, and hopefully they stay that way) */ - HPI_HISTREAM hpiStream; - /** Stream format, as passed to HPI interface */ - HPI_FORMAT hpiFormat; - /** Number of bytes per frame, derived from hpiFormat and saved for convenience */ - HW32 bytesPerFrame; - /** Size of hardware (on-card) buffer of stream in bytes */ - HW32 hardwareBufferSize; - /** Size of host (BBM) buffer of stream in bytes (if used) */ - HW32 hostBufferSize; - /** Upper limit on the utilization of output stream buffer (both hardware and host). - This prevents large latencies in an output-only stream with a potentially huge buffer - and a fast data generator, which would otherwise keep the hardware buffer filled to - capacity. See also the "Hardware Buffering=off" option in the AudioScience WAV driver. */ - HW32 outputBufferCap; - /** Sample buffer (halfway station between HPI and buffer processor) */ - HW8 *tempBuffer; - /** Sample buffer size, in bytes */ - HW32 tempBufferSize; -} -PaAsiHpiStreamComponent; - - -/** Stream data */ -typedef struct PaAsiHpiStream -{ - /* PortAudio "base class" - keep the baseRep first! (C-style inheritance) */ - PaUtilStreamRepresentation baseStreamRep; - PaUtilCpuLoadMeasurer cpuLoadMeasurer; - PaUtilBufferProcessor bufferProcessor; - - PaUtilAllocationGroup *allocations; - - /* implementation specific data goes here */ - - /** Separate structs for input and output sides of stream */ - PaAsiHpiStreamComponent *input, *output; - - /** Polling interval (in milliseconds) */ - HW32 pollingInterval; - /** Are we running in callback mode? */ - int callbackMode; - /** Number of frames to transfer at a time to/from HPI */ - unsigned long maxFramesPerHostBuffer; - /** Indicates that the stream is in the paNeverDropInput mode */ - int neverDropInput; - /** Contains copy of user buffers, used by blocking interface to transfer non-interleaved data. - It went here instead of to each stream component, as the stream component buffer setup in - PaAsiHpi_SetupBuffers doesn't know the stream details such as callbackMode. - (Maybe a problem later if ReadStream and WriteStream happens concurrently on same stream.) */ - void **blockingUserBufferCopy; - - /* Thread-related variables */ - - /** Helper thread which will deliver data to user callback */ - PaUnixThread thread; - /** PortAudio stream state (Active/Stopped/CallbackFinished) */ - volatile sig_atomic_t state; - /** Hard abort, i.e. drop frames? */ - volatile sig_atomic_t callbackAbort; - /** True if stream stopped via exiting callback with paComplete/paAbort flag - (as opposed to explicit call to StopStream/AbortStream) */ - volatile sig_atomic_t callbackFinished; -} -PaAsiHpiStream; - - -/** Stream state information, collected together for convenience */ -typedef struct PaAsiHpiStreamInfo -{ - /** HPI stream state (HPI_STATE_STOPPED, HPI_STATE_PLAYING, etc.) */ - HW16 state; - /** Size (in bytes) of recording/playback data buffer in HPI driver */ - HW32 bufferSize; - /** Amount of data (in bytes) available in the buffer */ - HW32 dataSize; - /** Number of frames played/recorded since last stream reset */ - HW32 frameCounter; - /** Amount of data (in bytes) in hardware (on-card) buffer. - This differs from dataSize if bus mastering (BBM) is used, which introduces another - driver-level buffer to which dataSize/bufferSize then refers. */ - HW32 auxDataSize; - /** Total number of data frames currently buffered by HPI driver (host + hw buffers) */ - HW32 totalBufferedData; - /** Size of immediately available data (for input) or space (for output) in frames. - This only checks the first-level buffer (typically host buffer). This amount can be - transferred immediately. */ - HW32 availableFrames; - /** Indicates that hardware buffer is getting too full */ - int overflow; - /** Indicates that hardware buffer is getting too empty */ - int underflow; -} -PaAsiHpiStreamInfo; - -/* -------------------------------------------------------------------------- */ - -/* - * Function prototypes - */ - -#ifdef __cplusplus -extern "C" -{ -#endif /* __cplusplus */ - - /* The only exposed function in the entire host API implementation */ - PaError PaAsiHpi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -static void Terminate( struct PaUtilHostApiRepresentation *hostApi ); -static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, - const PaStreamParameters *inputParameters, - const PaStreamParameters *outputParameters, - double sampleRate ); - -/* Stream prototypes */ -static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, - PaStream **s, - const PaStreamParameters *inputParameters, - const PaStreamParameters *outputParameters, - double sampleRate, - unsigned long framesPerBuffer, - PaStreamFlags streamFlags, - PaStreamCallback *streamCallback, - void *userData ); -static PaError CloseStream( PaStream *s ); -static PaError StartStream( PaStream *s ); -static PaError StopStream( PaStream *s ); -static PaError AbortStream( PaStream *s ); -static PaError IsStreamStopped( PaStream *s ); -static PaError IsStreamActive( PaStream *s ); -static PaTime GetStreamTime( PaStream *s ); -static double GetStreamCpuLoad( PaStream *s ); - -/* Blocking prototypes */ -static PaError ReadStream( PaStream *s, void *buffer, unsigned long frames ); -static PaError WriteStream( PaStream *s, const void *buffer, unsigned long frames ); -static signed long GetStreamReadAvailable( PaStream *s ); -static signed long GetStreamWriteAvailable( PaStream *s ); - -/* Callback prototypes */ -static void *CallbackThreadFunc( void *userData ); - -/* Functions specific to this API */ -static PaError PaAsiHpi_BuildDeviceList( PaAsiHpiHostApiRepresentation *hpiHostApi ); -static HW16 PaAsiHpi_PaToHpiFormat( PaSampleFormat paFormat ); -static PaSampleFormat PaAsiHpi_HpiToPaFormat( HW16 hpiFormat ); -static PaError PaAsiHpi_CreateFormat( struct PaUtilHostApiRepresentation *hostApi, - const PaStreamParameters *parameters, double sampleRate, - PaAsiHpiDeviceInfo **hpiDevice, HPI_FORMAT *hpiFormat ); -static PaError PaAsiHpi_OpenInput( struct PaUtilHostApiRepresentation *hostApi, - const PaAsiHpiDeviceInfo *hpiDevice, const HPI_FORMAT *hpiFormat, - HPI_HISTREAM *hpiStream ); -static PaError PaAsiHpi_OpenOutput( struct PaUtilHostApiRepresentation *hostApi, - const PaAsiHpiDeviceInfo *hpiDevice, const HPI_FORMAT *hpiFormat, - HPI_HOSTREAM *hpiStream ); -static PaError PaAsiHpi_GetStreamInfo( PaAsiHpiStreamComponent *streamComp, PaAsiHpiStreamInfo *info ); -static void PaAsiHpi_StreamComponentDump( PaAsiHpiStreamComponent *streamComp, PaAsiHpiStream *stream ); -static void PaAsiHpi_StreamDump( PaAsiHpiStream *stream ); -static PaError PaAsiHpi_SetupBuffers( PaAsiHpiStreamComponent *streamComp, HW32 pollingInterval, - unsigned long framesPerPaHostBuffer, PaTime suggestedLatency ); -static PaError PaAsiHpi_PrimeOutputWithSilence( PaAsiHpiStream *stream ); -static PaError PaAsiHpi_StartStream( PaAsiHpiStream *stream, int outputPrimed ); -static PaError PaAsiHpi_StopStream( PaAsiHpiStream *stream, int abort ); -static PaError PaAsiHpi_ExplicitStop( PaAsiHpiStream *stream, int abort ); -static void PaAsiHpi_OnThreadExit( void *userData ); -static PaError PaAsiHpi_WaitForFrames( PaAsiHpiStream *stream, unsigned long *framesAvail, - PaStreamCallbackFlags *cbFlags ); -static void PaAsiHpi_CalculateTimeInfo( PaAsiHpiStream *stream, PaStreamCallbackTimeInfo *timeInfo ); -static PaError PaAsiHpi_BeginProcessing( PaAsiHpiStream* stream, unsigned long* numFrames, - PaStreamCallbackFlags *cbFlags ); -static PaError PaAsiHpi_EndProcessing( PaAsiHpiStream *stream, unsigned long numFrames, - PaStreamCallbackFlags *cbFlags ); - -/* ========================================================================== - * ============================= IMPLEMENTATION ============================= - * ========================================================================== */ - -/* --------------------------- Host API Interface --------------------------- */ - -/** Enumerate all PA devices (= HPI streams). - This compiles a list of all HPI adapters, and registers a PA device for each input and - output stream it finds. Most errors are ignored, as missing or erroneous devices are - simply skipped. - - @param hpiHostApi Pointer to HPI host API struct - - @return PortAudio error code (only paInsufficientMemory in practice) - */ -static PaError PaAsiHpi_BuildDeviceList( PaAsiHpiHostApiRepresentation *hpiHostApi ) -{ - PaError result = paNoError; - PaUtilHostApiRepresentation *hostApi = &hpiHostApi->baseHostApiRep; - PaHostApiInfo *baseApiInfo = &hostApi->info; - PaAsiHpiDeviceInfo *hpiDeviceList; - HW16 adapterList[ HPI_MAX_ADAPTERS ]; - HW16 numAdapters; - HW16 hpiError = 0; - int i, j, deviceCount = 0, deviceIndex = 0; - - assert( hpiHostApi ); - assert( hpiHostApi->subSys ); - - /* Look for adapters (not strictly necessary, as AdapterOpen can do the same, but this */ - /* way we have less errors since we do not try to open adapters we know aren't there) */ - /* Errors not considered critical here (subsystem may report 0 devices), but report them */ - /* in debug mode. */ - PA_ASIHPI_UNLESS_( HPI_SubSysFindAdapters( hpiHostApi->subSys, &numAdapters, - adapterList, HPI_MAX_ADAPTERS ), paNoError ); - - /* First open and count the number of devices (= number of streams), to ease memory allocation */ - for( i=0; i < HPI_MAX_ADAPTERS; ++i ) - { - HW16 inStreams, outStreams; - HW16 version; - HW32 serial; - HW16 type; - - /* If no adapter found at this index, skip it */ - if( adapterList[i] == 0 ) - continue; - - /* Try to open adapter */ - hpiError = HPI_AdapterOpen( hpiHostApi->subSys, i ); - /* Report error and skip to next device on failure */ - if( hpiError ) - { - PA_ASIHPI_REPORT_ERROR_( hpiError ); - continue; - } - hpiError = HPI_AdapterGetInfo( hpiHostApi->subSys, i, - &outStreams, &inStreams, &version, &serial, &type ); - /* Skip to next device on failure */ - if( hpiError ) - { - PA_ASIHPI_REPORT_ERROR_( hpiError ); - continue; - } - else - { - /* Assign default devices if available and increment device count */ - if( (baseApiInfo->defaultInputDevice == paNoDevice) && (inStreams > 0) ) - baseApiInfo->defaultInputDevice = deviceCount; - deviceCount += inStreams; - if( (baseApiInfo->defaultOutputDevice == paNoDevice) && (outStreams > 0) ) - baseApiInfo->defaultOutputDevice = deviceCount; - deviceCount += outStreams; - } - } - - /* Register any discovered devices */ - if( deviceCount > 0 ) - { - /* Memory allocation */ - PA_UNLESS_( hostApi->deviceInfos = (PaDeviceInfo**) PaUtil_GroupAllocateMemory( - hpiHostApi->allocations, sizeof(PaDeviceInfo*) * deviceCount ), - paInsufficientMemory ); - /* Allocate all device info structs in a contiguous block */ - PA_UNLESS_( hpiDeviceList = (PaAsiHpiDeviceInfo*) PaUtil_GroupAllocateMemory( - hpiHostApi->allocations, sizeof(PaAsiHpiDeviceInfo) * deviceCount ), - paInsufficientMemory ); - - /* Now query devices again for information */ - for( i=0; i < HPI_MAX_ADAPTERS; ++i ) - { - HW16 inStreams, outStreams; - HW16 version; - HW32 serial; - HW16 type; - - /* If no adapter found at this index, skip it */ - if( adapterList[i] == 0 ) - continue; - - /* Assume adapter is still open from previous round */ - hpiError = HPI_AdapterGetInfo( hpiHostApi->subSys, i, - &outStreams, &inStreams, &version, &serial, &type ); - /* Report error and skip to next device on failure */ - if( hpiError ) - { - PA_ASIHPI_REPORT_ERROR_( hpiError ); - continue; - } - else - { - PA_DEBUG(( "Found HPI Adapter ID=%4X Idx=%d #In=%d #Out=%d S/N=%d HWver=%c%d DSPver=%03d\n", - type, i, inStreams, outStreams, serial, - ((version>>3)&0xf)+'A', /* Hw version major */ - version&0x7, /* Hw version minor */ - ((version>>13)*100)+((version>>7)&0x3f) /* DSP code version */ - )); - } - - /* First add all input streams as devices */ - for( j=0; j < inStreams; ++j ) - { - PaAsiHpiDeviceInfo *hpiDevice = &hpiDeviceList[deviceIndex]; - PaDeviceInfo *baseDeviceInfo = &hpiDevice->baseDeviceInfo; - char srcName[72]; - char *deviceName; - - memset( hpiDevice, 0, sizeof(PaAsiHpiDeviceInfo) ); - /* Set implementation-specific device details */ - hpiDevice->subSys = hpiHostApi->subSys; - hpiDevice->adapterIndex = i; - hpiDevice->adapterType = type; - hpiDevice->adapterVersion = version; - hpiDevice->adapterSerialNumber = serial; - hpiDevice->streamIndex = j; - hpiDevice->streamIsOutput = 0; - /* Set common PortAudio device stats */ - baseDeviceInfo->structVersion = 2; - /* Make sure name string is owned by API info structure */ - sprintf( srcName, - "Adapter %d (%4X) - Input Stream %d", i+1, type, j+1 ); - PA_UNLESS_( deviceName = (char *) PaUtil_GroupAllocateMemory( - hpiHostApi->allocations, strlen(srcName) + 1 ), paInsufficientMemory ); - strcpy( deviceName, srcName ); - baseDeviceInfo->name = deviceName; - baseDeviceInfo->hostApi = hpiHostApi->hostApiIndex; - baseDeviceInfo->maxInputChannels = HPI_MAX_CHANNELS; - baseDeviceInfo->maxOutputChannels = 0; - /* Default latency values for interactive performance */ - baseDeviceInfo->defaultLowInputLatency = 0.01; - baseDeviceInfo->defaultLowOutputLatency = -1.0; - /* Default latency values for robust non-interactive applications (eg. playing sound files) */ - baseDeviceInfo->defaultHighInputLatency = 0.2; - baseDeviceInfo->defaultHighOutputLatency = -1.0; - /* HPI interface can actually handle any sampling rate to 1 Hz accuracy, - * so this default is as good as any */ - baseDeviceInfo->defaultSampleRate = 44100; - - /* Store device in global PortAudio list */ - hostApi->deviceInfos[deviceIndex++] = (PaDeviceInfo *) hpiDevice; - } - - /* Now add all output streams as devices (I know, the repetition is painful) */ - for( j=0; j < outStreams; ++j ) - { - PaAsiHpiDeviceInfo *hpiDevice = &hpiDeviceList[deviceIndex]; - PaDeviceInfo *baseDeviceInfo = &hpiDevice->baseDeviceInfo; - char srcName[72]; - char *deviceName; - - memset( hpiDevice, 0, sizeof(PaAsiHpiDeviceInfo) ); - /* Set implementation-specific device details */ - hpiDevice->subSys = hpiHostApi->subSys; - hpiDevice->adapterIndex = i; - hpiDevice->adapterType = type; - hpiDevice->adapterVersion = version; - hpiDevice->adapterSerialNumber = serial; - hpiDevice->streamIndex = j; - hpiDevice->streamIsOutput = 1; - /* Set common PortAudio device stats */ - baseDeviceInfo->structVersion = 2; - /* Make sure name string is owned by API info structure */ - sprintf( srcName, - "Adapter %d (%4X) - Output Stream %d", i+1, type, j+1 ); - PA_UNLESS_( deviceName = (char *) PaUtil_GroupAllocateMemory( - hpiHostApi->allocations, strlen(srcName) + 1 ), paInsufficientMemory ); - strcpy( deviceName, srcName ); - baseDeviceInfo->name = deviceName; - baseDeviceInfo->hostApi = hpiHostApi->hostApiIndex; - baseDeviceInfo->maxInputChannels = 0; - baseDeviceInfo->maxOutputChannels = HPI_MAX_CHANNELS; - /* Default latency values for interactive performance. */ - baseDeviceInfo->defaultLowInputLatency = -1.0; - baseDeviceInfo->defaultLowOutputLatency = 0.01; - /* Default latency values for robust non-interactive applications (eg. playing sound files). */ - baseDeviceInfo->defaultHighInputLatency = -1.0; - baseDeviceInfo->defaultHighOutputLatency = 0.2; - /* HPI interface can actually handle any sampling rate to 1 Hz accuracy, - * so this default is as good as any */ - baseDeviceInfo->defaultSampleRate = 44100; - - /* Store device in global PortAudio list */ - hostApi->deviceInfos[deviceIndex++] = (PaDeviceInfo *) hpiDevice; - } - } - } - - /* Finally acknowledge checked devices */ - baseApiInfo->deviceCount = deviceIndex; - -error: - return result; -} - - -/** Initialize host API implementation. - This is the only function exported beyond this file. It is called by PortAudio to initialize - the host API. It stores API info, finds and registers all devices, and sets up callback and - blocking interfaces. - - @param hostApi Pointer to host API struct - - @param hostApiIndex Index of current (HPI) host API - - @return PortAudio error code - */ -PaError PaAsiHpi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ) -{ - PaError result = paNoError; - PaAsiHpiHostApiRepresentation *hpiHostApi = NULL; - PaHostApiInfo *baseApiInfo; - - /* Allocate host API structure */ - PA_UNLESS_( hpiHostApi = (PaAsiHpiHostApiRepresentation*) PaUtil_AllocateMemory( - sizeof(PaAsiHpiHostApiRepresentation) ), paInsufficientMemory ); - PA_UNLESS_( hpiHostApi->allocations = PaUtil_CreateAllocationGroup(), paInsufficientMemory ); - - hpiHostApi->hostApiIndex = hostApiIndex; - hpiHostApi->subSys = NULL; - - /* Try to initialize HPI subsystem */ - if( ( hpiHostApi->subSys = HPI_SubSysCreate() ) == NULL) - { - /* the V19 development docs say that if an implementation - * detects that it cannot be used, it should return a NULL - * interface and paNoError */ - PA_DEBUG(( "Could not open HPI interface\n" )); - result = paNoError; - *hostApi = NULL; - goto error; - } - else - { - HW32 hpiVersion; - PA_ASIHPI_UNLESS_( HPI_SubSysGetVersion( hpiHostApi->subSys, &hpiVersion ), paUnanticipatedHostError ); - PA_DEBUG(( "HPI interface v%d.%02d\n", - hpiVersion >> 8, 10*((hpiVersion & 0xF0) >> 4) + (hpiVersion & 0x0F) )); - } - - *hostApi = &hpiHostApi->baseHostApiRep; - baseApiInfo = &((*hostApi)->info); - /* Fill in common API details */ - baseApiInfo->structVersion = 1; - baseApiInfo->type = paAudioScienceHPI; - baseApiInfo->name = "AudioScience HPI"; - baseApiInfo->deviceCount = 0; - baseApiInfo->defaultInputDevice = paNoDevice; - baseApiInfo->defaultOutputDevice = paNoDevice; - - PA_ENSURE_( PaAsiHpi_BuildDeviceList( hpiHostApi ) ); - - (*hostApi)->Terminate = Terminate; - (*hostApi)->OpenStream = OpenStream; - (*hostApi)->IsFormatSupported = IsFormatSupported; - - PaUtil_InitializeStreamInterface( &hpiHostApi->callbackStreamInterface, CloseStream, StartStream, - StopStream, AbortStream, IsStreamStopped, IsStreamActive, - GetStreamTime, GetStreamCpuLoad, - PaUtil_DummyRead, PaUtil_DummyWrite, - PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable ); - - PaUtil_InitializeStreamInterface( &hpiHostApi->blockingStreamInterface, CloseStream, StartStream, - StopStream, AbortStream, IsStreamStopped, IsStreamActive, - GetStreamTime, PaUtil_DummyGetCpuLoad, - ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable ); - - /* Store identity of main thread */ - PA_ENSURE_( PaUnixThreading_Initialize() ); - - return result; -error: - /* Clean up memory */ - Terminate( (PaUtilHostApiRepresentation *)hpiHostApi ); - return result; -} - - -/** Terminate host API implementation. - This closes all HPI adapters and frees the HPI subsystem. It also frees the host API struct - memory. It should be called once for every PaAsiHpi_Initialize call. - - @param Pointer to host API struct - */ -static void Terminate( struct PaUtilHostApiRepresentation *hostApi ) -{ - PaAsiHpiHostApiRepresentation *hpiHostApi = (PaAsiHpiHostApiRepresentation*)hostApi; - int i; - PaError result = paNoError; - - if( hpiHostApi ) - { - /* Get rid of HPI-specific structures */ - if( hpiHostApi->subSys ) - { - HW16 lastAdapterIndex = HPI_MAX_ADAPTERS; - /* Iterate through device list and close adapters */ - for( i=0; i < hostApi->info.deviceCount; ++i ) - { - PaAsiHpiDeviceInfo *hpiDevice = (PaAsiHpiDeviceInfo *) hostApi->deviceInfos[ i ]; - /* Close adapter only if it differs from previous one */ - if( hpiDevice->adapterIndex != lastAdapterIndex ) - { - /* Ignore errors (report only during debugging) */ - PA_ASIHPI_UNLESS_( HPI_AdapterClose( hpiHostApi->subSys, - hpiDevice->adapterIndex ), paNoError ); - lastAdapterIndex = hpiDevice->adapterIndex; - } - } - /* Finally dismantle HPI subsystem */ - HPI_SubSysFree( hpiHostApi->subSys ); - } - - if( hpiHostApi->allocations ) - { - PaUtil_FreeAllAllocations( hpiHostApi->allocations ); - PaUtil_DestroyAllocationGroup( hpiHostApi->allocations ); - } - - PaUtil_FreeMemory( hpiHostApi ); - } -error: - return; -} - - -/** Converts PortAudio sample format to equivalent HPI format. - - @param paFormat PortAudio sample format - - @return HPI sample format - */ -static HW16 PaAsiHpi_PaToHpiFormat( PaSampleFormat paFormat ) -{ - /* Ignore interleaving flag */ - switch( paFormat & ~paNonInterleaved ) - { - case paFloat32: - return HPI_FORMAT_PCM32_FLOAT; - - case paInt32: - return HPI_FORMAT_PCM32_SIGNED; - - case paInt24: - return HPI_FORMAT_PCM24_SIGNED; - - case paInt16: - return HPI_FORMAT_PCM16_SIGNED; - - case paUInt8: - return HPI_FORMAT_PCM8_UNSIGNED; - - /* Default is 16-bit signed */ - case paInt8: - default: - return HPI_FORMAT_PCM16_SIGNED; - } -} - - -/** Converts HPI sample format to equivalent PortAudio format. - - @param paFormat HPI sample format - - @return PortAudio sample format - */ -static PaSampleFormat PaAsiHpi_HpiToPaFormat( HW16 hpiFormat ) -{ - switch( hpiFormat ) - { - case HPI_FORMAT_PCM32_FLOAT: - return paFloat32; - - case HPI_FORMAT_PCM32_SIGNED: - return paInt32; - - case HPI_FORMAT_PCM24_SIGNED: - return paInt24; - - case HPI_FORMAT_PCM16_SIGNED: - return paInt16; - - case HPI_FORMAT_PCM8_UNSIGNED: - return paUInt8; - - /* Default is custom format (e.g. for HPI MP3 format) */ - default: - return paCustomFormat; - } -} - - -/** Creates HPI format struct based on PortAudio parameters. - This also does some checks to see whether the desired format is valid, and whether - the device allows it. This only checks the format of one half (input or output) of the - PortAudio stream. - - @param hostApi Pointer to host API struct - - @param parameters Pointer to stream parameter struct - - @param sampleRate Desired sample rate - - @param hpiDevice Pointer to HPI device struct - - @param hpiFormat Resulting HPI format returned here - - @return PortAudio error code (typically indicating a problem with stream format) - */ -static PaError PaAsiHpi_CreateFormat( struct PaUtilHostApiRepresentation *hostApi, - const PaStreamParameters *parameters, double sampleRate, - PaAsiHpiDeviceInfo **hpiDevice, HPI_FORMAT *hpiFormat ) -{ - int maxChannelCount = 0; - PaSampleFormat hostSampleFormat = 0; - HW16 hpiError = 0; - - /* Unless alternate device specification is supported, reject the use of - paUseHostApiSpecificDeviceSpecification */ - if( parameters->device == paUseHostApiSpecificDeviceSpecification ) - return paInvalidDevice; - else - { - assert( parameters->device < hostApi->info.deviceCount ); - *hpiDevice = (PaAsiHpiDeviceInfo*) hostApi->deviceInfos[ parameters->device ]; - } - - /* Validate streamInfo - this implementation doesn't use custom stream info */ - if( parameters->hostApiSpecificStreamInfo ) - return paIncompatibleHostApiSpecificStreamInfo; - - /* Check that device can support channel count */ - if( (*hpiDevice)->streamIsOutput ) - { - maxChannelCount = (*hpiDevice)->baseDeviceInfo.maxOutputChannels; - } - else - { - maxChannelCount = (*hpiDevice)->baseDeviceInfo.maxInputChannels; - } - if( (maxChannelCount == 0) || (parameters->channelCount > maxChannelCount) ) - return paInvalidChannelCount; - - /* All standard sample formats are supported by the buffer adapter, - and this implementation doesn't support any custom sample formats */ - if( parameters->sampleFormat & paCustomFormat ) - return paSampleFormatNotSupported; - - /* Switch to closest HPI native format */ - hostSampleFormat = PaUtil_SelectClosestAvailableFormat(PA_ASIHPI_AVAILABLE_FORMATS_, - parameters->sampleFormat ); - /* Setup format + info objects */ - hpiError = HPI_FormatCreate( hpiFormat, (HW16)parameters->channelCount, - PaAsiHpi_PaToHpiFormat( hostSampleFormat ), - (HW32)sampleRate, 0, 0 ); - if( hpiError ) - { - PA_ASIHPI_REPORT_ERROR_( hpiError ); - switch( hpiError ) - { - case HPI_ERROR_INVALID_FORMAT: - return paSampleFormatNotSupported; - - case HPI_ERROR_INVALID_SAMPLERATE: - case HPI_ERROR_INCOMPATIBLE_SAMPLERATE: - return paInvalidSampleRate; - - case HPI_ERROR_INVALID_CHANNELS: - return paInvalidChannelCount; - } - } - - return paNoError; -} - - -/** Open HPI input stream with given format. - This attempts to open HPI input stream with desired format. If the format is not supported - or the device is unavailable, the stream is closed and a PortAudio error code is returned. - - @param hostApi Pointer to host API struct - - @param hpiDevice Pointer to HPI device struct - - @param hpiFormat Pointer to HPI format struct - - @return PortAudio error code (typically indicating a problem with stream format or device) -*/ -static PaError PaAsiHpi_OpenInput( struct PaUtilHostApiRepresentation *hostApi, - const PaAsiHpiDeviceInfo *hpiDevice, const HPI_FORMAT *hpiFormat, - HPI_HISTREAM *hpiStream ) -{ - PaAsiHpiHostApiRepresentation *hpiHostApi = (PaAsiHpiHostApiRepresentation*)hostApi; - PaError result = paNoError; - HW16 hpiError = 0; - - /* Catch misplaced output devices, as they typically have 0 input channels */ - PA_UNLESS_( !hpiDevice->streamIsOutput, paInvalidChannelCount ); - /* Try to open input stream */ - PA_ASIHPI_UNLESS_( HPI_InStreamOpen( hpiHostApi->subSys, hpiDevice->adapterIndex, - hpiDevice->streamIndex, hpiStream ), paDeviceUnavailable ); - /* Set input format (checking it in the process) */ - /* Could also use HPI_InStreamQueryFormat, but this economizes the process */ - hpiError = HPI_InStreamSetFormat( hpiHostApi->subSys, *hpiStream, (HPI_FORMAT*)hpiFormat ); - if( hpiError ) - { - PA_ASIHPI_REPORT_ERROR_( hpiError ); - PA_ASIHPI_UNLESS_( HPI_InStreamClose( hpiHostApi->subSys, *hpiStream ), paNoError ); - switch( hpiError ) - { - case HPI_ERROR_INVALID_FORMAT: - return paSampleFormatNotSupported; - - case HPI_ERROR_INVALID_SAMPLERATE: - case HPI_ERROR_INCOMPATIBLE_SAMPLERATE: - return paInvalidSampleRate; - - case HPI_ERROR_INVALID_CHANNELS: - return paInvalidChannelCount; - - default: - /* In case anything else went wrong */ - return paInvalidDevice; - } - } - -error: - return result; -} - - -/** Open HPI output stream with given format. - This attempts to open HPI output stream with desired format. If the format is not supported - or the device is unavailable, the stream is closed and a PortAudio error code is returned. - - @param hostApi Pointer to host API struct - - @param hpiDevice Pointer to HPI device struct - - @param hpiFormat Pointer to HPI format struct - - @return PortAudio error code (typically indicating a problem with stream format or device) -*/ -static PaError PaAsiHpi_OpenOutput( struct PaUtilHostApiRepresentation *hostApi, - const PaAsiHpiDeviceInfo *hpiDevice, const HPI_FORMAT *hpiFormat, - HPI_HOSTREAM *hpiStream ) -{ - PaAsiHpiHostApiRepresentation *hpiHostApi = (PaAsiHpiHostApiRepresentation*)hostApi; - PaError result = paNoError; - HW16 hpiError = 0; - - /* Catch misplaced input devices, as they typically have 0 output channels */ - PA_UNLESS_( hpiDevice->streamIsOutput, paInvalidChannelCount ); - /* Try to open output stream */ - PA_ASIHPI_UNLESS_( HPI_OutStreamOpen( hpiHostApi->subSys, hpiDevice->adapterIndex, - hpiDevice->streamIndex, hpiStream ), paDeviceUnavailable ); - - /* Check output format (format is set on first write to output stream) */ - hpiError = HPI_OutStreamQueryFormat( hpiHostApi->subSys, *hpiStream, (HPI_FORMAT*)hpiFormat ); - if( hpiError ) - { - PA_ASIHPI_REPORT_ERROR_( hpiError ); - PA_ASIHPI_UNLESS_( HPI_OutStreamClose( hpiHostApi->subSys, *hpiStream ), paNoError ); - switch( hpiError ) - { - case HPI_ERROR_INVALID_FORMAT: - return paSampleFormatNotSupported; - - case HPI_ERROR_INVALID_SAMPLERATE: - case HPI_ERROR_INCOMPATIBLE_SAMPLERATE: - return paInvalidSampleRate; - - case HPI_ERROR_INVALID_CHANNELS: - return paInvalidChannelCount; - - default: - /* In case anything else went wrong */ - return paInvalidDevice; - } - } - -error: - return result; -} - - -/** Checks whether the desired stream formats and devices are supported - (for both input and output). - This is done by actually opening the appropriate HPI streams and closing them again. - - @param hostApi Pointer to host API struct - - @param inputParameters Pointer to stream parameter struct for input side of stream - - @param outputParameters Pointer to stream parameter struct for output side of stream - - @param sampleRate Desired sample rate - - @return PortAudio error code (paFormatIsSupported on success) - */ -static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, - const PaStreamParameters *inputParameters, - const PaStreamParameters *outputParameters, - double sampleRate ) -{ - PaError result = paFormatIsSupported; - PaAsiHpiHostApiRepresentation *hpiHostApi = (PaAsiHpiHostApiRepresentation*)hostApi; - PaAsiHpiDeviceInfo *hpiDevice = NULL; - HPI_FORMAT hpiFormat; - - /* Input stream */ - if( inputParameters ) - { - HPI_HISTREAM hpiStream; - PA_DEBUG(( "%s: Checking input params: dev=%d, sr=%d, chans=%d, fmt=%d\n", - __FUNCTION__, inputParameters->device, (int)sampleRate, - inputParameters->channelCount, inputParameters->sampleFormat )); - /* Create and validate format */ - PA_ENSURE_( PaAsiHpi_CreateFormat( hostApi, inputParameters, sampleRate, - &hpiDevice, &hpiFormat ) ); - /* Open stream to further check format */ - PA_ENSURE_( PaAsiHpi_OpenInput( hostApi, hpiDevice, &hpiFormat, &hpiStream ) ); - /* Close stream again */ - PA_ASIHPI_UNLESS_( HPI_InStreamClose( hpiHostApi->subSys, hpiStream ), paNoError ); - } - - /* Output stream */ - if( outputParameters ) - { - HPI_HOSTREAM hpiStream; - PA_DEBUG(( "%s: Checking output params: dev=%d, sr=%d, chans=%d, fmt=%d\n", - __FUNCTION__, outputParameters->device, (int)sampleRate, - outputParameters->channelCount, outputParameters->sampleFormat )); - /* Create and validate format */ - PA_ENSURE_( PaAsiHpi_CreateFormat( hostApi, outputParameters, sampleRate, - &hpiDevice, &hpiFormat ) ); - /* Open stream to further check format */ - PA_ENSURE_( PaAsiHpi_OpenOutput( hostApi, hpiDevice, &hpiFormat, &hpiStream ) ); - /* Close stream again */ - PA_ASIHPI_UNLESS_( HPI_OutStreamClose( hpiHostApi->subSys, hpiStream ), paNoError ); - } - -error: - return result; -} - -/* ---------------------------- Stream Interface ---------------------------- */ - -/** Obtain HPI stream information. - This obtains info such as stream state and available data/space in buffers. It also - estimates whether an underflow or overflow occurred. - - @param streamComp Pointer to stream component (input or output) to query - - @param info Pointer to stream info struct that will contain result - - @return PortAudio error code (either paNoError, paDeviceUnavailable or paUnanticipatedHostError) - */ -static PaError PaAsiHpi_GetStreamInfo( PaAsiHpiStreamComponent *streamComp, PaAsiHpiStreamInfo *info ) -{ - PaError result = paDeviceUnavailable; - HW16 state; - HW32 bufferSize, dataSize, frameCounter, auxDataSize, threshold; - HW32 hwBufferSize, hwDataSize; - - assert( streamComp ); - assert( info ); - - /* First blank the stream info struct, in case something goes wrong below. - This saves the caller from initializing the struct. */ - info->state = 0; - info->bufferSize = 0; - info->dataSize = 0; - info->frameCounter = 0; - info->auxDataSize = 0; - info->totalBufferedData = 0; - info->availableFrames = 0; - info->underflow = 0; - info->overflow = 0; - - if( streamComp->hpiDevice && streamComp->hpiStream ) - { - /* Obtain detailed stream info (either input or output) */ - if( streamComp->hpiDevice->streamIsOutput ) - { - PA_ASIHPI_UNLESS_( HPI_OutStreamGetInfoEx( streamComp->hpiDevice->subSys, - streamComp->hpiStream, - &state, &bufferSize, &dataSize, &frameCounter, - &auxDataSize ), paUnanticipatedHostError ); - } - else - { - PA_ASIHPI_UNLESS_( HPI_InStreamGetInfoEx( streamComp->hpiDevice->subSys, - streamComp->hpiStream, - &state, &bufferSize, &dataSize, &frameCounter, - &auxDataSize ), paUnanticipatedHostError ); - } - /* Load stream info */ - info->state = state; - info->bufferSize = bufferSize; - info->dataSize = dataSize; - info->frameCounter = frameCounter; - info->auxDataSize = auxDataSize; - /* Determine total buffered data */ - info->totalBufferedData = dataSize; - if( streamComp->hostBufferSize > 0 ) - info->totalBufferedData += auxDataSize; - info->totalBufferedData /= streamComp->bytesPerFrame; - /* Determine immediately available frames */ - info->availableFrames = streamComp->hpiDevice->streamIsOutput ? - bufferSize - dataSize : dataSize; - info->availableFrames /= streamComp->bytesPerFrame; - /* Minimum space/data required in buffers */ - threshold = PA_MIN( streamComp->tempBufferSize, - streamComp->bytesPerFrame * PA_ASIHPI_MIN_FRAMES_ ); - /* Obtain hardware buffer stats first, to simplify things */ - hwBufferSize = streamComp->hardwareBufferSize; - hwDataSize = streamComp->hostBufferSize > 0 ? auxDataSize : dataSize; - /* Underflow is a bit tricky */ - info->underflow = streamComp->hpiDevice->streamIsOutput ? - /* Stream seems to start in drained state sometimes, so ignore initial underflow */ - (frameCounter > 0) && ( (state == HPI_STATE_DRAINED) || (hwDataSize == 0) ) : - /* Input streams check the first-level (host) buffer for underflow */ - (state != HPI_STATE_STOPPED) && (dataSize < threshold); - /* Check for overflow in second-level (hardware) buffer for both input and output */ - info->overflow = (state != HPI_STATE_STOPPED) && (hwBufferSize - hwDataSize < threshold); - - return paNoError; - } - -error: - return result; -} - - -/** Display stream component information for debugging purposes. - - @param streamComp Pointer to stream component (input or output) to query - - @param stream Pointer to stream struct which contains the component above - */ -static void PaAsiHpi_StreamComponentDump( PaAsiHpiStreamComponent *streamComp, - PaAsiHpiStream *stream ) -{ - PaAsiHpiStreamInfo streamInfo; - - assert( streamComp ); - assert( stream ); - - /* Name of soundcard/device used by component */ - PA_DEBUG(( "device: %s\n", streamComp->hpiDevice->baseDeviceInfo.name )); - /* Unfortunately some overlap between input and output here */ - if( streamComp->hpiDevice->streamIsOutput ) - { - /* Settings on the user side (as experienced by user callback) */ - PA_DEBUG(( "user: %d-bit, %d ", - 8*stream->bufferProcessor.bytesPerUserOutputSample, - stream->bufferProcessor.outputChannelCount)); - if( stream->bufferProcessor.userOutputIsInterleaved ) - { - PA_DEBUG(( "interleaved channels, " )); - } - else - { - PA_DEBUG(( "non-interleaved channels, " )); - } - PA_DEBUG(( "%d frames/buffer, latency = %5.1f ms\n", - stream->bufferProcessor.framesPerUserBuffer, - 1000*stream->baseStreamRep.streamInfo.outputLatency )); - /* Settings on the host side (internal to PortAudio host API) */ - PA_DEBUG(( "host: %d-bit, %d interleaved channels, %d frames/buffer ", - 8*stream->bufferProcessor.bytesPerHostOutputSample, - stream->bufferProcessor.outputChannelCount, - stream->bufferProcessor.framesPerHostBuffer )); - } - else - { - /* Settings on the user side (as experienced by user callback) */ - PA_DEBUG(( "user: %d-bit, %d ", - 8*stream->bufferProcessor.bytesPerUserInputSample, - stream->bufferProcessor.inputChannelCount)); - if( stream->bufferProcessor.userInputIsInterleaved ) - { - PA_DEBUG(( "interleaved channels, " )); - } - else - { - PA_DEBUG(( "non-interleaved channels, " )); - } - PA_DEBUG(( "%d frames/buffer, latency = %5.1f ms\n", - stream->bufferProcessor.framesPerUserBuffer, - 1000*stream->baseStreamRep.streamInfo.inputLatency )); - /* Settings on the host side (internal to PortAudio host API) */ - PA_DEBUG(( "host: %d-bit, %d interleaved channels, %d frames/buffer ", - 8*stream->bufferProcessor.bytesPerHostInputSample, - stream->bufferProcessor.inputChannelCount, - stream->bufferProcessor.framesPerHostBuffer )); - } - switch( stream->bufferProcessor.hostBufferSizeMode ) - { - case paUtilFixedHostBufferSize: - PA_DEBUG(( "[fixed] " )); - break; - case paUtilBoundedHostBufferSize: - PA_DEBUG(( "[bounded] " )); - break; - case paUtilUnknownHostBufferSize: - PA_DEBUG(( "[unknown] " )); - break; - case paUtilVariableHostBufferSizePartialUsageAllowed: - PA_DEBUG(( "[variable] " )); - break; - } - PA_DEBUG(( "(%d max)\n", streamComp->tempBufferSize / streamComp->bytesPerFrame )); - /* HPI hardware settings */ - PA_DEBUG(( "HPI: adapter %d stream %d, %d-bit, %d-channel, %d Hz\n", - streamComp->hpiDevice->adapterIndex, streamComp->hpiDevice->streamIndex, - 8 * streamComp->bytesPerFrame / streamComp->hpiFormat.wChannels, - streamComp->hpiFormat.wChannels, - streamComp->hpiFormat.dwSampleRate )); - /* Stream state and buffer levels */ - PA_DEBUG(( "HPI: " )); - PaAsiHpi_GetStreamInfo( streamComp, &streamInfo ); - switch( streamInfo.state ) - { - case HPI_STATE_STOPPED: - PA_DEBUG(( "[STOPPED] " )); - break; - case HPI_STATE_PLAYING: - PA_DEBUG(( "[PLAYING] " )); - break; - case HPI_STATE_RECORDING: - PA_DEBUG(( "[RECORDING] " )); - break; - case HPI_STATE_DRAINED: - PA_DEBUG(( "[DRAINED] " )); - break; - default: - PA_DEBUG(( "[unknown state] " )); - break; - } - if( streamComp->hostBufferSize ) - { - PA_DEBUG(( "host = %d/%d B, ", streamInfo.dataSize, streamComp->hostBufferSize )); - PA_DEBUG(( "hw = %d/%d (%d) B, ", streamInfo.auxDataSize, - streamComp->hardwareBufferSize, streamComp->outputBufferCap )); - } - else - { - PA_DEBUG(( "hw = %d/%d B, ", streamInfo.dataSize, streamComp->hardwareBufferSize )); - } - PA_DEBUG(( "count = %d", streamInfo.frameCounter )); - if( streamInfo.overflow ) - { - PA_DEBUG(( " [overflow]" )); - } - else if( streamInfo.underflow ) - { - PA_DEBUG(( " [underflow]" )); - } - PA_DEBUG(( "\n" )); -} - - -/** Display stream information for debugging purposes. - - @param stream Pointer to stream to query - */ -static void PaAsiHpi_StreamDump( PaAsiHpiStream *stream ) -{ - assert( stream ); - - PA_DEBUG(( "\n------------------------- STREAM INFO FOR %p ---------------------------\n", stream )); - /* General stream info (input+output) */ - if( stream->baseStreamRep.streamCallback ) - { - PA_DEBUG(( "[callback] " )); - } - else - { - PA_DEBUG(( "[blocking] " )); - } - PA_DEBUG(( "sr=%d Hz, poll=%d ms, max %d frames/buf ", - (int)stream->baseStreamRep.streamInfo.sampleRate, - stream->pollingInterval, stream->maxFramesPerHostBuffer )); - switch( stream->state ) - { - case paAsiHpiStoppedState: - PA_DEBUG(( "[stopped]\n" )); - break; - case paAsiHpiActiveState: - PA_DEBUG(( "[active]\n" )); - break; - case paAsiHpiCallbackFinishedState: - PA_DEBUG(( "[cb fin]\n" )); - break; - default: - PA_DEBUG(( "[unknown state]\n" )); - break; - } - if( stream->callbackMode ) - { - PA_DEBUG(( "cb info: thread=%p, cbAbort=%d, cbFinished=%d\n", - stream->thread.thread, stream->callbackAbort, stream->callbackFinished )); - } - - PA_DEBUG(( "----------------------------------- Input ------------------------------------\n" )); - if( stream->input ) - { - PaAsiHpi_StreamComponentDump( stream->input, stream ); - } - else - { - PA_DEBUG(( "*none*\n" )); - } - - PA_DEBUG(( "----------------------------------- Output ------------------------------------\n" )); - if( stream->output ) - { - PaAsiHpi_StreamComponentDump( stream->output, stream ); - } - else - { - PA_DEBUG(( "*none*\n" )); - } - PA_DEBUG(( "-------------------------------------------------------------------------------\n\n" )); - -} - - -/** Determine buffer sizes and allocate appropriate stream buffers. - This attempts to allocate a BBM (host) buffer for the HPI stream component (either input - or output, as both have similar buffer needs). Not all AudioScience adapters support BBM, - in which case the hardware buffer has to suffice. The size of the HPI host buffer is chosen - as a multiple of framesPerPaHostBuffer, and also influenced by the suggested latency and the - estimated minimum polling interval. The HPI host and hardware buffer sizes are stored, and an - appropriate cap for the hardware buffer is also calculated. Finally, the temporary stream - buffer which serves as the PortAudio host buffer for this implementation is allocated. - This buffer contains an integer number of user buffers, to simplify buffer adaption in the - buffer processor. The function returns paBufferTooBig if the HPI interface cannot allocate - an HPI host buffer of the desired size. - - @param streamComp Pointer to stream component struct - - @param pollingInterval Polling interval for stream, in milliseconds - - @param framesPerPaHostBuffer Size of PortAudio host buffer, in frames - - @param suggestedLatency Suggested latency for stream component, in seconds - - @return PortAudio error code (possibly paBufferTooBig or paInsufficientMemory) - */ -static PaError PaAsiHpi_SetupBuffers( PaAsiHpiStreamComponent *streamComp, HW32 pollingInterval, - unsigned long framesPerPaHostBuffer, PaTime suggestedLatency ) -{ - PaError result = paNoError; - PaAsiHpiStreamInfo streamInfo; - unsigned long hpiBufferSize = 0, paHostBufferSize = 0; - - assert( streamComp ); - assert( streamComp->hpiDevice ); - - /* Obtain size of hardware buffer of HPI stream, since we will be activating BBM shortly - and afterwards the buffer size will refer to the BBM (host-side) buffer. - This is necessary to enable reliable detection of xruns. */ - PA_ENSURE_( PaAsiHpi_GetStreamInfo( streamComp, &streamInfo ) ); - streamComp->hardwareBufferSize = streamInfo.bufferSize; - hpiBufferSize = streamInfo.bufferSize; - - /* Check if BBM (background bus mastering) is to be enabled */ - if( PA_ASIHPI_USE_BBM_ ) - { - HW32 bbmBufferSize = 0, preLatencyBufferSize = 0; - HW16 hpiError = 0; - PaTime pollingOverhead; - - /* Check overhead of Pa_Sleep() call (minimum sleep duration in ms -> OS dependent) */ - pollingOverhead = PaUtil_GetTime(); - Pa_Sleep( 0 ); - pollingOverhead = 1000*(PaUtil_GetTime() - pollingOverhead); - PA_DEBUG(( "polling overhead = %f ms (length of 0-second sleep)\n", pollingOverhead )); - /* Obtain minimum recommended size for host buffer (in bytes) */ - PA_ASIHPI_UNLESS_( HPI_StreamEstimateBufferSize( &streamComp->hpiFormat, - pollingInterval + (HW32)ceil( pollingOverhead ), - &bbmBufferSize ), paUnanticipatedHostError ); - /* BBM places more stringent requirements on buffer size (see description */ - /* of HPI_StreamEstimateBufferSize in HPI API document) */ - bbmBufferSize *= 3; - /* Make sure the BBM buffer contains multiple PA host buffers */ - if( bbmBufferSize < 3 * streamComp->bytesPerFrame * framesPerPaHostBuffer ) - bbmBufferSize = 3 * streamComp->bytesPerFrame * framesPerPaHostBuffer; - /* Try to honor latency suggested by user by growing buffer (no decrease possible) */ - if( suggestedLatency > 0.0 ) - { - PaTime bufferDuration = ((PaTime)bbmBufferSize) / streamComp->bytesPerFrame - / streamComp->hpiFormat.dwSampleRate; - /* Don't decrease buffer */ - if( bufferDuration < suggestedLatency ) - { - /* Save old buffer size, to be retried if new size proves too big */ - preLatencyBufferSize = bbmBufferSize; - bbmBufferSize = (HW32)ceil( suggestedLatency * streamComp->bytesPerFrame - * streamComp->hpiFormat.dwSampleRate ); - } - } - /* Choose closest memory block boundary (HPI API document states that - "a buffer size of Nx4096 - 20 makes the best use of memory" - (under the entry for HPI_StreamEstimateBufferSize)) */ - bbmBufferSize = ((HW32)ceil((bbmBufferSize + 20)/4096.0))*4096 - 20; - streamComp->hostBufferSize = bbmBufferSize; - /* Allocate BBM host buffer (this enables bus mastering transfers in background) */ - if( streamComp->hpiDevice->streamIsOutput ) - hpiError = HPI_OutStreamHostBufferAllocate( streamComp->hpiDevice->subSys, - streamComp->hpiStream, - bbmBufferSize ); - else - hpiError = HPI_InStreamHostBufferAllocate( streamComp->hpiDevice->subSys, - streamComp->hpiStream, - bbmBufferSize ); - if( hpiError ) - { - PA_ASIHPI_REPORT_ERROR_( hpiError ); - /* Indicate that BBM is disabled */ - streamComp->hostBufferSize = 0; - /* Retry with smaller buffer size (transfers will still work, but not via BBM) */ - if( hpiError == HPI_ERROR_INVALID_DATASIZE ) - { - /* Retry BBM allocation with smaller size if requested latency proved too big */ - if( preLatencyBufferSize > 0 ) - { - PA_DEBUG(( "Retrying BBM allocation with smaller size (%d vs. %d bytes)\n", - preLatencyBufferSize, bbmBufferSize )); - bbmBufferSize = preLatencyBufferSize; - if( streamComp->hpiDevice->streamIsOutput ) - hpiError = HPI_OutStreamHostBufferAllocate( streamComp->hpiDevice->subSys, - streamComp->hpiStream, - bbmBufferSize ); - else - hpiError = HPI_InStreamHostBufferAllocate( streamComp->hpiDevice->subSys, - streamComp->hpiStream, - bbmBufferSize ); - /* Another round of error checking */ - if( hpiError ) - { - PA_ASIHPI_REPORT_ERROR_( hpiError ); - /* No escapes this time */ - if( hpiError == HPI_ERROR_INVALID_DATASIZE ) - { - result = paBufferTooBig; - goto error; - } - else if( hpiError != HPI_ERROR_INVALID_OPERATION ) - { - result = paUnanticipatedHostError; - goto error; - } - } - else - { - streamComp->hostBufferSize = bbmBufferSize; - hpiBufferSize = bbmBufferSize; - } - } - else - { - result = paBufferTooBig; - goto error; - } - } - /* If BBM not supported, foreground transfers will be used, but not a show-stopper */ - /* Anything else is an error */ - else if( hpiError != HPI_ERROR_INVALID_OPERATION ) - { - result = paUnanticipatedHostError; - goto error; - } - } - else - { - hpiBufferSize = bbmBufferSize; - } - } - - /* Final check of buffer size */ - paHostBufferSize = streamComp->bytesPerFrame * framesPerPaHostBuffer; - if( hpiBufferSize < 3*paHostBufferSize ) - { - result = paBufferTooBig; - goto error; - } - /* Set cap on output buffer size, based on latency suggestions */ - if( streamComp->hpiDevice->streamIsOutput ) - { - PaTime latency = suggestedLatency > 0.0 ? suggestedLatency : - streamComp->hpiDevice->baseDeviceInfo.defaultHighOutputLatency; - streamComp->outputBufferCap = - (HW32)ceil( latency * streamComp->bytesPerFrame * streamComp->hpiFormat.dwSampleRate ); - /* The cap should not be too small, to prevent underflow */ - if( streamComp->outputBufferCap < 4*paHostBufferSize ) - streamComp->outputBufferCap = 4*paHostBufferSize; - } - else - { - streamComp->outputBufferCap = 0; - } - /* Temp buffer size should be multiple of PA host buffer size (or 1x, if using fixed blocks) */ - streamComp->tempBufferSize = paHostBufferSize; - /* Allocate temp buffer */ - PA_UNLESS_( streamComp->tempBuffer = (HW8 *)PaUtil_AllocateMemory( streamComp->tempBufferSize ), - paInsufficientMemory ); -error: - return result; -} - - -/** Opens PortAudio stream. - This determines a suitable value for framesPerBuffer, if the user didn't specify it, - based on the suggested latency. It then opens each requested stream direction with the - appropriate stream format, and allocates the required stream buffers. It sets up the - various PortAudio structures dealing with streams, and estimates the stream latency. - - See pa_hostapi.h for a list of validity guarantees made about OpenStream parameters. - - @param hostApi Pointer to host API struct - - @param s List of open streams, where successfully opened stream will go - - @param inputParameters Pointer to stream parameter struct for input side of stream - - @param outputParameters Pointer to stream parameter struct for output side of stream - - @param sampleRate Desired sample rate - - @param framesPerBuffer Desired number of frames per buffer passed to user callback - (or chunk size for blocking stream) - - @param streamFlags Stream flags - - @param streamCallback Pointer to user callback function (zero for blocking interface) - - @param userData Pointer to user data that will be passed to callback function along with data - - @return PortAudio error code -*/ -static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, - PaStream **s, - const PaStreamParameters *inputParameters, - const PaStreamParameters *outputParameters, - double sampleRate, - unsigned long framesPerBuffer, - PaStreamFlags streamFlags, - PaStreamCallback *streamCallback, - void *userData ) -{ - PaError result = paNoError; - PaAsiHpiHostApiRepresentation *hpiHostApi = (PaAsiHpiHostApiRepresentation*)hostApi; - PaAsiHpiStream *stream = NULL; - unsigned long framesPerHostBuffer = framesPerBuffer; - int inputChannelCount = 0, outputChannelCount = 0; - PaSampleFormat inputSampleFormat = 0, outputSampleFormat = 0; - PaSampleFormat hostInputSampleFormat = 0, hostOutputSampleFormat = 0; - PaTime maxSuggestedLatency = 0.0; - - /* Validate platform-specific flags -> none expected for HPI */ - if( (streamFlags & paPlatformSpecificFlags) != 0 ) - return paInvalidFlag; /* unexpected platform-specific flag */ - - /* Create blank stream structure */ - PA_UNLESS_( stream = (PaAsiHpiStream *)PaUtil_AllocateMemory( sizeof(PaAsiHpiStream) ), - paInsufficientMemory ); - memset( stream, 0, sizeof(PaAsiHpiStream) ); - - /* If the number of frames per buffer is unspecified, we have to come up with one. */ - if( framesPerHostBuffer == paFramesPerBufferUnspecified ) - { - if( inputParameters ) - maxSuggestedLatency = inputParameters->suggestedLatency; - if( outputParameters && (outputParameters->suggestedLatency > maxSuggestedLatency) ) - maxSuggestedLatency = outputParameters->suggestedLatency; - /* Use suggested latency if available */ - if( maxSuggestedLatency > 0.0 ) - framesPerHostBuffer = (unsigned long)ceil( maxSuggestedLatency * sampleRate ); - else - /* AudioScience cards like BIG buffers by default */ - framesPerHostBuffer = 4096; - } - /* Lower bounds on host buffer size, due to polling and HPI constraints */ - if( 1000.0*framesPerHostBuffer/sampleRate < PA_ASIHPI_MIN_POLLING_INTERVAL_ ) - framesPerHostBuffer = (unsigned long)ceil( sampleRate * PA_ASIHPI_MIN_POLLING_INTERVAL_ / 1000.0 ); - /* if( framesPerHostBuffer < PA_ASIHPI_MIN_FRAMES_ ) - framesPerHostBuffer = PA_ASIHPI_MIN_FRAMES_; */ - /* Efficient if host buffer size is integer multiple of user buffer size */ - if( framesPerBuffer > 0 ) - framesPerHostBuffer = (unsigned long)ceil( (double)framesPerHostBuffer / framesPerBuffer ) * framesPerBuffer; - /* Buffer should always be a multiple of 4 bytes to facilitate 32-bit PCI transfers. - By keeping the frames a multiple of 4, this is ensured even for 8-bit mono sound. */ - framesPerHostBuffer = (framesPerHostBuffer / 4) * 4; - /* Polling is based on time length (in milliseconds) of user-requested block size */ - stream->pollingInterval = (HW32)ceil( 1000.0*framesPerHostBuffer/sampleRate ); - assert( framesPerHostBuffer > 0 ); - - /* Open underlying streams, check formats and allocate buffers */ - if( inputParameters ) - { - /* Create blank stream component structure */ - PA_UNLESS_( stream->input = (PaAsiHpiStreamComponent *)PaUtil_AllocateMemory( sizeof(PaAsiHpiStreamComponent) ), - paInsufficientMemory ); - memset( stream->input, 0, sizeof(PaAsiHpiStreamComponent) ); - /* Create/validate format */ - PA_ENSURE_( PaAsiHpi_CreateFormat( hostApi, inputParameters, sampleRate, - &stream->input->hpiDevice, &stream->input->hpiFormat ) ); - /* Open stream and set format */ - PA_ENSURE_( PaAsiHpi_OpenInput( hostApi, stream->input->hpiDevice, &stream->input->hpiFormat, - &stream->input->hpiStream ) ); - inputChannelCount = inputParameters->channelCount; - inputSampleFormat = inputParameters->sampleFormat; - hostInputSampleFormat = PaAsiHpi_HpiToPaFormat( stream->input->hpiFormat.wFormat ); - stream->input->bytesPerFrame = inputChannelCount * Pa_GetSampleSize( hostInputSampleFormat ); - assert( stream->input->bytesPerFrame > 0 ); - /* Allocate host and temp buffers of appropriate size */ - PA_ENSURE_( PaAsiHpi_SetupBuffers( stream->input, stream->pollingInterval, - framesPerHostBuffer, inputParameters->suggestedLatency ) ); - } - if( outputParameters ) - { - /* Create blank stream component structure */ - PA_UNLESS_( stream->output = (PaAsiHpiStreamComponent *)PaUtil_AllocateMemory( sizeof(PaAsiHpiStreamComponent) ), - paInsufficientMemory ); - memset( stream->output, 0, sizeof(PaAsiHpiStreamComponent) ); - /* Create/validate format */ - PA_ENSURE_( PaAsiHpi_CreateFormat( hostApi, outputParameters, sampleRate, - &stream->output->hpiDevice, &stream->output->hpiFormat ) ); - /* Open stream and check format */ - PA_ENSURE_( PaAsiHpi_OpenOutput( hostApi, stream->output->hpiDevice, - &stream->output->hpiFormat, - &stream->output->hpiStream ) ); - outputChannelCount = outputParameters->channelCount; - outputSampleFormat = outputParameters->sampleFormat; - hostOutputSampleFormat = PaAsiHpi_HpiToPaFormat( stream->output->hpiFormat.wFormat ); - stream->output->bytesPerFrame = outputChannelCount * Pa_GetSampleSize( hostOutputSampleFormat ); - /* Allocate host and temp buffers of appropriate size */ - PA_ENSURE_( PaAsiHpi_SetupBuffers( stream->output, stream->pollingInterval, - framesPerHostBuffer, outputParameters->suggestedLatency ) ); - } - - /* Determine maximum frames per host buffer (least common denominator of input/output) */ - if( inputParameters && outputParameters ) - { - stream->maxFramesPerHostBuffer = PA_MIN( stream->input->tempBufferSize / stream->input->bytesPerFrame, - stream->output->tempBufferSize / stream->output->bytesPerFrame ); - } - else - { - stream->maxFramesPerHostBuffer = inputParameters ? stream->input->tempBufferSize / stream->input->bytesPerFrame - : stream->output->tempBufferSize / stream->output->bytesPerFrame; - } - assert( stream->maxFramesPerHostBuffer > 0 ); - /* Initialize various other stream parameters */ - stream->neverDropInput = streamFlags & paNeverDropInput; - stream->state = paAsiHpiStoppedState; - - /* Initialize either callback or blocking interface */ - if( streamCallback ) - { - PaUtil_InitializeStreamRepresentation( &stream->baseStreamRep, - &hpiHostApi->callbackStreamInterface, - streamCallback, userData ); - stream->callbackMode = 1; - } - else - { - PaUtil_InitializeStreamRepresentation( &stream->baseStreamRep, - &hpiHostApi->blockingStreamInterface, - streamCallback, userData ); - /* Pre-allocate non-interleaved user buffer pointers for blocking interface */ - PA_UNLESS_( stream->blockingUserBufferCopy = - PaUtil_AllocateMemory( sizeof(void *) * PA_MAX( inputChannelCount, outputChannelCount ) ), - paInsufficientMemory ); - stream->callbackMode = 0; - } - PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate ); - - /* Following pa_linux_alsa's lead, we operate with fixed host buffer size by default, */ - /* since other modes will invariably lead to block adaption (maybe Bounded better?) */ - PA_ENSURE_( PaUtil_InitializeBufferProcessor( &stream->bufferProcessor, - inputChannelCount, inputSampleFormat, hostInputSampleFormat, - outputChannelCount, outputSampleFormat, hostOutputSampleFormat, - sampleRate, streamFlags, - framesPerBuffer, framesPerHostBuffer, paUtilFixedHostBufferSize, - streamCallback, userData ) ); - - stream->baseStreamRep.streamInfo.structVersion = 1; - stream->baseStreamRep.streamInfo.sampleRate = sampleRate; - /* Determine input latency from buffer processor and buffer sizes */ - if( stream->input ) - { - PaTime bufferDuration = ( stream->input->hostBufferSize + stream->input->hardwareBufferSize ) - / sampleRate / stream->input->bytesPerFrame; - stream->baseStreamRep.streamInfo.inputLatency = - PaUtil_GetBufferProcessorInputLatency( &stream->bufferProcessor ) + - bufferDuration - stream->maxFramesPerHostBuffer / sampleRate; - assert( stream->baseStreamRep.streamInfo.inputLatency > 0.0 ); - } - /* Determine output latency from buffer processor and buffer sizes */ - if( stream->output ) - { - PaTime bufferDuration = ( stream->output->hostBufferSize + stream->output->hardwareBufferSize ) - / sampleRate / stream->output->bytesPerFrame; - /* Take buffer size cap into account (see PaAsiHpi_WaitForFrames) */ - if( !stream->input && (stream->output->outputBufferCap > 0) ) - { - bufferDuration = PA_MIN( bufferDuration, - stream->output->outputBufferCap / sampleRate / stream->output->bytesPerFrame ); - } - stream->baseStreamRep.streamInfo.outputLatency = - PaUtil_GetBufferProcessorOutputLatency( &stream->bufferProcessor ) + - bufferDuration - stream->maxFramesPerHostBuffer / sampleRate; - assert( stream->baseStreamRep.streamInfo.outputLatency > 0.0 ); - } - - /* Report stream info, for debugging purposes */ - PaAsiHpi_StreamDump( stream ); - - /* Save initialized stream to PA stream list */ - *s = (PaStream*)stream; - return result; - -error: - CloseStream( (PaStream*)stream ); - return result; -} - - -/** Close PortAudio stream. - When CloseStream() is called, the multi-api layer ensures that the stream has already - been stopped or aborted. This closes the underlying HPI streams and deallocates stream - buffers and structs. - - @param s Pointer to PortAudio stream - - @return PortAudio error code -*/ -static PaError CloseStream( PaStream *s ) -{ - PaError result = paNoError; - PaAsiHpiStream *stream = (PaAsiHpiStream*)s; - - /* If stream is already gone, all is well */ - if( stream == NULL ) - return paNoError; - - /* Generic stream cleanup */ - PaUtil_TerminateBufferProcessor( &stream->bufferProcessor ); - PaUtil_TerminateStreamRepresentation( &stream->baseStreamRep ); - - /* Implementation-specific details - close internal streams */ - if( stream->input ) - { - /* Close HPI stream (freeing BBM host buffer in the process, if used) */ - if( stream->input->hpiStream ) - { - PA_ASIHPI_UNLESS_( HPI_InStreamClose( stream->input->hpiDevice->subSys, - stream->input->hpiStream ), paUnanticipatedHostError ); - } - /* Free temp buffer and stream component */ - PaUtil_FreeMemory( stream->input->tempBuffer ); - PaUtil_FreeMemory( stream->input ); - } - if( stream->output ) - { - /* Close HPI stream (freeing BBM host buffer in the process, if used) */ - if( stream->output->hpiStream ) - { - PA_ASIHPI_UNLESS_( HPI_OutStreamClose( stream->output->hpiDevice->subSys, - stream->output->hpiStream ), paUnanticipatedHostError ); - } - /* Free temp buffer and stream component */ - PaUtil_FreeMemory( stream->output->tempBuffer ); - PaUtil_FreeMemory( stream->output ); - } - - PaUtil_FreeMemory( stream->blockingUserBufferCopy ); - PaUtil_FreeMemory( stream ); - -error: - return result; -} - - -/** Prime HPI output stream with silence. - This resets the output stream and uses PortAudio helper routines to fill the - temp buffer with silence. It then writes two host buffers to the stream. This is supposed - to be called before the stream is started. It has no effect on input-only streams. - - @param stream Pointer to stream struct - - @return PortAudio error code - */ -static PaError PaAsiHpi_PrimeOutputWithSilence( PaAsiHpiStream *stream ) -{ - PaError result = paNoError; - PaAsiHpiStreamComponent *out; - PaUtilZeroer *zeroer; - PaSampleFormat outputFormat; -#if (HPI_VER < HPI_VERSION_CONSTRUCTOR( 3, 5, 5 )) - HPI_DATA data; -#endif - assert( stream ); - out = stream->output; - /* Only continue if stream has output channels */ - if( !out ) - return result; - assert( out->tempBuffer ); - - /* Clear all existing data in hardware playback buffer */ - PA_ASIHPI_UNLESS_( HPI_OutStreamReset( out->hpiDevice->subSys, - out->hpiStream ), paUnanticipatedHostError ); - /* Fill temp buffer with silence */ - outputFormat = PaAsiHpi_HpiToPaFormat( out->hpiFormat.wFormat ); - zeroer = PaUtil_SelectZeroer( outputFormat ); - zeroer(out->tempBuffer, 1, out->tempBufferSize / Pa_GetSampleSize(outputFormat) ); - /* Write temp buffer to hardware fifo twice, to get started */ -#if (HPI_VER >= HPI_VERSION_CONSTRUCTOR( 3, 5, 5 )) - PA_ASIHPI_UNLESS_( HPI_OutStreamWriteBuf( out->hpiDevice->subSys, out->hpiStream, - out->tempBuffer, out->tempBufferSize, &out->hpiFormat), - paUnanticipatedHostError ); - PA_ASIHPI_UNLESS_( HPI_OutStreamWriteBuf( out->hpiDevice->subSys, out->hpiStream, - out->tempBuffer, out->tempBufferSize, &out->hpiFormat), - paUnanticipatedHostError ); -#else - PA_ASIHPI_UNLESS_( HPI_DataCreate( &data, &out->hpiFormat, out->tempBuffer, out->tempBufferSize ), - paUnanticipatedHostError ); - PA_ASIHPI_UNLESS_( HPI_OutStreamWrite( out->hpiDevice->subSys, - out->hpiStream, &data ), paUnanticipatedHostError ); - PA_ASIHPI_UNLESS_( HPI_OutStreamWrite( out->hpiDevice->subSys, - out->hpiStream, &data ), paUnanticipatedHostError ); -#endif -error: - return result; -} - - -/** Start HPI streams (both input + output). - This starts all HPI streams in the PortAudio stream. Output streams are first primed with - silence, if required. After this call the PA stream is in the Active state. - - @todo Implement priming via the user callback - - @param stream Pointer to stream struct - - @param outputPrimed True if output is already primed (if false, silence will be loaded before starting) - - @return PortAudio error code - */ -static PaError PaAsiHpi_StartStream( PaAsiHpiStream *stream, int outputPrimed ) -{ - PaError result = paNoError; - - if( stream->input ) - { - PA_ASIHPI_UNLESS_( HPI_InStreamStart( stream->input->hpiDevice->subSys, - stream->input->hpiStream ), paUnanticipatedHostError ); - } - if( stream->output ) - { - if( !outputPrimed ) - { - /* Buffer isn't primed, so load stream with silence */ - PA_ENSURE_( PaAsiHpi_PrimeOutputWithSilence( stream ) ); - } - PA_ASIHPI_UNLESS_( HPI_OutStreamStart( stream->output->hpiDevice->subSys, - stream->output->hpiStream ), paUnanticipatedHostError ); - } - stream->state = paAsiHpiActiveState; - stream->callbackFinished = 0; - - /* Report stream info for debugging purposes */ - /* PaAsiHpi_StreamDump( stream ); */ - -error: - return result; -} - - -/** Start PortAudio stream. - If the stream has a callback interface, this starts a helper thread to feed the user callback. - The thread will then take care of starting the HPI streams, and this function will block - until the streams actually start. In the case of a blocking interface, the HPI streams - are simply started. - - @param s Pointer to PortAudio stream - - @return PortAudio error code -*/ -static PaError StartStream( PaStream *s ) -{ - PaError result = paNoError; - PaAsiHpiStream *stream = (PaAsiHpiStream*)s; - - assert( stream ); - - /* Ready the processor */ - PaUtil_ResetBufferProcessor( &stream->bufferProcessor ); - - if( stream->callbackMode ) - { - /* Create and start callback engine thread */ - /* Also waits 1 second for stream to be started by engine thread (otherwise aborts) */ - PA_ENSURE_( PaUnixThread_New( &stream->thread, &CallbackThreadFunc, stream, 1., 0 /*rtSched*/ ) ); - } - else - { - PA_ENSURE_( PaAsiHpi_StartStream( stream, 0 ) ); - } - -error: - return result; -} - - -/** Stop HPI streams (input + output), either softly or abruptly. - If abort is false, the function blocks until the output stream is drained, otherwise it - stops immediately and discards data in the stream hardware buffers. - - This function is safe to call from the callback engine thread as well as the main thread. - - @param stream Pointer to stream struct - - @param abort True if samples in output buffer should be discarded (otherwise blocks until stream is done) - - @return PortAudio error code - - */ -static PaError PaAsiHpi_StopStream( PaAsiHpiStream *stream, int abort ) -{ - PaError result = paNoError; - - assert( stream ); - - /* Input channels */ - if( stream->input ) - { - PA_ASIHPI_UNLESS_( HPI_InStreamReset( stream->input->hpiDevice->subSys, - stream->input->hpiStream ), paUnanticipatedHostError ); - } - /* Output channels */ - if( stream->output ) - { - if( !abort ) - { - /* Wait until HPI output stream is drained */ - while( 1 ) - { - PaAsiHpiStreamInfo streamInfo; - PaTime timeLeft; - - /* Obtain number of samples waiting to be played */ - PA_ENSURE_( PaAsiHpi_GetStreamInfo( stream->output, &streamInfo ) ); - /* Check if stream is drained */ - if( (streamInfo.state != HPI_STATE_PLAYING) && - (streamInfo.dataSize < stream->output->bytesPerFrame * PA_ASIHPI_MIN_FRAMES_) ) - break; - /* Sleep amount of time represented by remaining samples */ - timeLeft = 1000.0 * streamInfo.dataSize / stream->output->bytesPerFrame - / stream->baseStreamRep.streamInfo.sampleRate; - Pa_Sleep( (long)ceil( timeLeft ) ); - } - } - PA_ASIHPI_UNLESS_( HPI_OutStreamReset( stream->output->hpiDevice->subSys, - stream->output->hpiStream ), paUnanticipatedHostError ); - } - - /* Report stream info for debugging purposes */ - /* PaAsiHpi_StreamDump( stream ); */ - -error: - return result; -} - - -/** Stop or abort PortAudio stream. - - This function is used to explicitly stop the PortAudio stream (via StopStream/AbortStream), - as opposed to the situation when the callback finishes with a result other than paContinue. - If a stream is in callback mode we will have to inspect whether the background thread has - finished, or we will have to take it out. In either case we join the thread before returning. - In blocking mode, we simply tell HPI to stop abruptly (abort) or finish buffers (drain). - The PortAudio stream will be in the Stopped state after a call to this function. - - Don't call this from the callback engine thread! - - @param stream Pointer to stream struct - - @param abort True if samples in output buffer should be discarded (otherwise blocks until stream is done) - - @return PortAudio error code -*/ -static PaError PaAsiHpi_ExplicitStop( PaAsiHpiStream *stream, int abort ) -{ - PaError result = paNoError; - - /* First deal with the callback thread, cancelling and/or joining it if necessary */ - if( stream->callbackMode ) - { - PaError threadRes; - stream->callbackAbort = abort; - if( abort ) - { - PA_DEBUG(( "Aborting callback\n" )); - } - else - { - PA_DEBUG(( "Stopping callback\n" )); - } - PA_ENSURE_( PaUnixThread_Terminate( &stream->thread, !abort, &threadRes ) ); - if( threadRes != paNoError ) - { - PA_DEBUG(( "Callback thread returned: %d\n", threadRes )); - } - } - else - { - PA_ENSURE_( PaAsiHpi_StopStream( stream, abort ) ); - } - - stream->state = paAsiHpiStoppedState; - -error: - return result; -} - - -/** Stop PortAudio stream. - This blocks until the output buffers are drained. - - @param s Pointer to PortAudio stream - - @return PortAudio error code -*/ -static PaError StopStream( PaStream *s ) -{ - return PaAsiHpi_ExplicitStop( (PaAsiHpiStream *) s, 0 ); -} - - -/** Abort PortAudio stream. - This discards any existing data in output buffers and stops the stream immediately. - - @param s Pointer to PortAudio stream - - @return PortAudio error code -*/ -static PaError AbortStream( PaStream *s ) -{ - return PaAsiHpi_ExplicitStop( (PaAsiHpiStream * ) s, 1 ); -} - - -/** Determine whether the stream is stopped. - A stream is considered to be stopped prior to a successful call to StartStream and after - a successful call to StopStream or AbortStream. If a stream callback returns a value other - than paContinue the stream is NOT considered to be stopped (it is in CallbackFinished state). - - @param s Pointer to PortAudio stream - - @return Returns one (1) when the stream is stopped, zero (0) when the stream is running, or - a PaErrorCode (which are always negative) if PortAudio is not initialized or an - error is encountered. -*/ -static PaError IsStreamStopped( PaStream *s ) -{ - PaAsiHpiStream *stream = (PaAsiHpiStream*)s; - - assert( stream ); - return stream->state == paAsiHpiStoppedState ? 1 : 0; -} - - -/** Determine whether the stream is active. - A stream is active after a successful call to StartStream(), until it becomes inactive either - as a result of a call to StopStream() or AbortStream(), or as a result of a return value - other than paContinue from the stream callback. In the latter case, the stream is considered - inactive after the last buffer has finished playing. - - @param s Pointer to PortAudio stream - - @return Returns one (1) when the stream is active (i.e. playing or recording audio), - zero (0) when not playing, or a PaErrorCode (which are always negative) - if PortAudio is not initialized or an error is encountered. -*/ -static PaError IsStreamActive( PaStream *s ) -{ - PaAsiHpiStream *stream = (PaAsiHpiStream*)s; - - assert( stream ); - return stream->state == paAsiHpiActiveState ? 1 : 0; -} - - -/** Returns current stream time. - This corresponds to the system clock. The clock should run continuously while the stream - is open, i.e. between calls to OpenStream() and CloseStream(), therefore a frame counter - is not good enough. - - @param s Pointer to PortAudio stream - - @return Stream time, in seconds - */ -static PaTime GetStreamTime( PaStream *s ) -{ - return PaUtil_GetTime(); -} - - -/** Returns CPU load. - - @param s Pointer to PortAudio stream - - @return CPU load (0.0 if blocking interface is used) - */ -static double GetStreamCpuLoad( PaStream *s ) -{ - PaAsiHpiStream *stream = (PaAsiHpiStream*)s; - - return stream->callbackMode ? PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer ) : 0.0; -} - -/* --------------------------- Callback Interface --------------------------- */ - -/** Exit routine which is called when callback thread quits. - This takes care of stopping the HPI streams (either waiting for output to finish, or - abruptly). It also calls the user-supplied StreamFinished callback, and sets the - stream state to CallbackFinished if it was reached via a non-paContinue return from - the user callback function. - - @param userData A pointer to an open stream previously created with Pa_OpenStream - */ -static void PaAsiHpi_OnThreadExit( void *userData ) -{ - PaAsiHpiStream *stream = (PaAsiHpiStream *) userData; - - assert( stream ); - - PaUtil_ResetCpuLoadMeasurer( &stream->cpuLoadMeasurer ); - - PA_DEBUG(( "%s: Stopping HPI streams\n", __FUNCTION__ )); - PaAsiHpi_StopStream( stream, stream->callbackAbort ); - PA_DEBUG(( "%s: Stoppage\n", __FUNCTION__ )); - - /* Eventually notify user all buffers have played */ - if( stream->baseStreamRep.streamFinishedCallback ) - { - stream->baseStreamRep.streamFinishedCallback( stream->baseStreamRep.userData ); - } - - /* Unfortunately both explicit calls to Stop/AbortStream (leading to Stopped state) - and implicit stops via paComplete/paAbort (leading to CallbackFinished state) - end up here - need another flag to remind us which is the case */ - if( stream->callbackFinished ) - stream->state = paAsiHpiCallbackFinishedState; -} - - -/** Wait until there is enough frames to fill a host buffer. - The routine attempts to sleep until at least a full host buffer can be retrieved from the - input HPI stream and passed to the output HPI stream. It will first sleep until enough - output space is available, as this is usually easily achievable. If it is an output-only - stream, it will also sleep if the hardware buffer is too full, thereby throttling the - filling of the output buffer and reducing output latency. The routine then blocks until - enough input samples are available, unless this will cause an output underflow. In the - process, input overflows and output underflows are indicated. - - @param stream Pointer to stream struct - - @param framesAvail Returns the number of available frames - - @param cbFlags Overflows and underflows indicated in here - - @return PortAudio error code (only paUnanticipatedHostError expected) - */ -static PaError PaAsiHpi_WaitForFrames( PaAsiHpiStream *stream, unsigned long *framesAvail, - PaStreamCallbackFlags *cbFlags ) -{ - PaError result = paNoError; - double sampleRate; - unsigned long framesTarget; - HW32 outputData = 0, outputSpace = 0, inputData = 0, framesLeft = 0; - - assert( stream ); - assert( stream->input || stream->output ); - - sampleRate = stream->baseStreamRep.streamInfo.sampleRate; - /* We have to come up with this much frames on both input and output */ - framesTarget = stream->bufferProcessor.framesPerHostBuffer; - assert( framesTarget > 0 ); - - while( 1 ) - { - PaAsiHpiStreamInfo info; - /* Check output first, as this takes priority in the default full-duplex mode */ - if( stream->output ) - { - PA_ENSURE_( PaAsiHpi_GetStreamInfo( stream->output, &info ) ); - /* Wait until enough space is available in output buffer to receive a full block */ - if( info.availableFrames < framesTarget ) - { - framesLeft = framesTarget - info.availableFrames; - Pa_Sleep( (long)ceil( 1000 * framesLeft / sampleRate ) ); - continue; - } - /* Wait until the data in hardware buffer has dropped to a sensible level. - Without this, the hardware buffer quickly fills up in the absence of an input - stream to regulate its data rate (if data generation is fast). This leads to - large latencies, as the AudioScience hardware buffers are humongous. - This is similar to the default "Hardware Buffering=off" option in the - AudioScience WAV driver. */ - if( !stream->input && (stream->output->outputBufferCap > 0) && - ( info.totalBufferedData > stream->output->outputBufferCap / stream->output->bytesPerFrame ) ) - { - framesLeft = info.totalBufferedData - stream->output->outputBufferCap / stream->output->bytesPerFrame; - Pa_Sleep( (long)ceil( 1000 * framesLeft / sampleRate ) ); - continue; - } - outputData = info.totalBufferedData; - outputSpace = info.availableFrames; - /* Report output underflow to callback */ - if( info.underflow ) - { - *cbFlags |= paOutputUnderflow; - } - } - - /* Now check input side */ - if( stream->input ) - { - PA_ENSURE_( PaAsiHpi_GetStreamInfo( stream->input, &info ) ); - /* If a full block of samples hasn't been recorded yet, wait for it if possible */ - if( info.availableFrames < framesTarget ) - { - framesLeft = framesTarget - info.availableFrames; - /* As long as output is not disrupted in the process, wait for a full - block of input samples */ - if( !stream->output || (outputData > framesLeft) ) - { - Pa_Sleep( (long)ceil( 1000 * framesLeft / sampleRate ) ); - continue; - } - } - inputData = info.availableFrames; - /** @todo The paInputOverflow flag should be set in the callback containing the - first input sample following the overflow. That means the block currently sitting - at the fore-front of recording, i.e. typically the one containing the newest (last) - sample in the HPI buffer system. This is most likely not the same as the current - block of data being passed to the callback. The current overflow should ideally - be noted in an overflow list of sorts, with an indication of when it should be - reported. The trouble starts if there are several separate overflow incidents, - given a big input buffer. Oh well, something to try out later... */ - if( info.overflow ) - { - *cbFlags |= paInputOverflow; - } - } - break; - } - /* Full-duplex stream */ - if( stream->input && stream->output ) - { - if( outputSpace >= framesTarget ) - *framesAvail = outputSpace; - /* If input didn't make the target, keep the output count instead (input underflow) */ - if( (inputData >= framesTarget) && (inputData < outputSpace) ) - *framesAvail = inputData; - } - else - { - *framesAvail = stream->input ? inputData : outputSpace; - } - -error: - return result; -} - - -/** Obtain recording, current and playback timestamps of stream. - The current time is determined by the system clock. This "now" timestamp occurs at the - forefront of recording (and playback in the full-duplex case), which happens later than the - input timestamp by an amount equal to the total number of recorded frames in the input buffer. - The output timestamp indicates when the next generated sample will actually be played. This - happens after all the samples currently in the output buffer are played. The output timestamp - therefore follows the current timestamp by an amount equal to the number of frames yet to be - played back in the output buffer. - - If the current timestamp is the present, the input timestamp is in the past and the output - timestamp is in the future. - - @param stream Pointer to stream struct - - @param timeInfo Pointer to timeInfo struct that will contain timestamps - */ -static void PaAsiHpi_CalculateTimeInfo( PaAsiHpiStream *stream, PaStreamCallbackTimeInfo *timeInfo ) -{ - PaAsiHpiStreamInfo streamInfo; - double sampleRate; - - assert( stream ); - assert( timeInfo ); - sampleRate = stream->baseStreamRep.streamInfo.sampleRate; - - /* The current time ("now") is at the forefront of both recording and playback */ - timeInfo->currentTime = GetStreamTime( (PaStream *)stream ); - /* The last sample in the input buffer was recorded just now, so the first sample - happened (number of recorded samples)/sampleRate ago */ - timeInfo->inputBufferAdcTime = timeInfo->currentTime; - if( stream->input ) - { - PaAsiHpi_GetStreamInfo( stream->input, &streamInfo ); - timeInfo->inputBufferAdcTime -= streamInfo.totalBufferedData / sampleRate; - } - /* The first of the outgoing samples will be played after all the samples in the output - buffer is done */ - timeInfo->outputBufferDacTime = timeInfo->currentTime; - if( stream->output ) - { - PaAsiHpi_GetStreamInfo( stream->output, &streamInfo ); - timeInfo->outputBufferDacTime += streamInfo.totalBufferedData / sampleRate; - } -} - - -/** Read from HPI input stream and register buffers. - This reads data from the HPI input stream (if it exists) and registers the temp stream - buffers of both input and output streams with the buffer processor. In the process it also - handles input underflows in the full-duplex case. - - @param stream Pointer to stream struct - - @param numFrames On entrance the number of available frames, on exit the number of - received frames - - @param cbFlags Indicates overflows and underflows - - @return PortAudio error code - */ -static PaError PaAsiHpi_BeginProcessing( PaAsiHpiStream *stream, unsigned long *numFrames, - PaStreamCallbackFlags *cbFlags ) -{ - PaError result = paNoError; - - assert( stream ); - if( *numFrames > stream->maxFramesPerHostBuffer ) - *numFrames = stream->maxFramesPerHostBuffer; - - if( stream->input ) - { - PaAsiHpiStreamInfo info; - -#if (HPI_VER < HPI_VERSION_CONSTRUCTOR( 3, 5, 5 )) - HPI_DATA data; -#endif - HW32 framesToGet = *numFrames; - - /* Check for overflows and underflows yet again */ - PA_ENSURE_( PaAsiHpi_GetStreamInfo( stream->input, &info ) ); - if( info.overflow ) - { - *cbFlags |= paInputOverflow; - } - /* Input underflow if less than expected number of samples pitch up */ - if( framesToGet > info.availableFrames ) - { - PaUtilZeroer *zeroer; - PaSampleFormat inputFormat; - - /* Never call an input-only stream with InputUnderflow set */ - if( stream->output ) - *cbFlags |= paInputUnderflow; - framesToGet = info.availableFrames; - /* Fill temp buffer with silence (to make up for missing input samples) */ - inputFormat = PaAsiHpi_HpiToPaFormat( stream->input->hpiFormat.wFormat ); - zeroer = PaUtil_SelectZeroer( inputFormat ); - zeroer(stream->input->tempBuffer, 1, - stream->input->tempBufferSize / Pa_GetSampleSize(inputFormat) ); - } - -#if (HPI_VER >= HPI_VERSION_CONSTRUCTOR( 3, 5, 5 )) - /* Read block of data into temp buffer */ - PA_ASIHPI_UNLESS_( HPI_InStreamReadBuf( stream->input->hpiDevice->subSys, - stream->input->hpiStream, - stream->input->tempBuffer, - framesToGet * stream->input->bytesPerFrame), - paUnanticipatedHostError ); -#else - /* Setup HPI data structure around temp buffer */ - HPI_DataCreate( &data, &stream->input->hpiFormat, stream->input->tempBuffer, - framesToGet * stream->input->bytesPerFrame ); - /* Read block of data into temp buffer */ - PA_ASIHPI_UNLESS_( HPI_InStreamRead( stream->input->hpiDevice->subSys, - stream->input->hpiStream, &data ), - paUnanticipatedHostError ); -#endif - /* Register temp buffer with buffer processor (always FULL buffer) */ - PaUtil_SetInputFrameCount( &stream->bufferProcessor, *numFrames ); - /* HPI interface only allows interleaved channels */ - PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, - 0, stream->input->tempBuffer, - stream->input->hpiFormat.wChannels ); - } - if( stream->output ) - { - /* Register temp buffer with buffer processor */ - PaUtil_SetOutputFrameCount( &stream->bufferProcessor, *numFrames ); - /* HPI interface only allows interleaved channels */ - PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, - 0, stream->output->tempBuffer, - stream->output->hpiFormat.wChannels ); - } - -error: - return result; -} - - -/** Flush output buffers to HPI output stream. - This completes the processing cycle by writing the temp buffer to the HPI interface. - Additional output underflows are caught before data is written to the stream, as this - action typically remedies the underflow and hides it in the process. - - @param stream Pointer to stream struct - - @param numFrames The number of frames to write to the output stream - - @param cbFlags Indicates overflows and underflows - */ -static PaError PaAsiHpi_EndProcessing( PaAsiHpiStream *stream, unsigned long numFrames, - PaStreamCallbackFlags *cbFlags ) -{ - PaError result = paNoError; - - assert( stream ); - - if( stream->output ) - { - PaAsiHpiStreamInfo info; -#if (HPI_VER < HPI_VERSION_CONSTRUCTOR( 3, 5, 5 )) - HPI_DATA data; -#endif - /* Check for underflows after the (potentially time-consuming) callback */ - PA_ENSURE_( PaAsiHpi_GetStreamInfo( stream->output, &info ) ); - if( info.underflow ) - { - *cbFlags |= paOutputUnderflow; - } - -#if (HPI_VER >= HPI_VERSION_CONSTRUCTOR( 3, 5, 5 )) - /* Write temp buffer to HPI stream */ - PA_ASIHPI_UNLESS_( HPI_OutStreamWriteBuf( stream->output->hpiDevice->subSys, - stream->output->hpiStream, - stream->output->tempBuffer, - numFrames * stream->output->bytesPerFrame, - &stream->output->hpiFormat), - paUnanticipatedHostError ); -#else - /* Setup HPI data structure around temp buffer */ - HPI_DataCreate( &data, &stream->output->hpiFormat, stream->output->tempBuffer, - numFrames * stream->output->bytesPerFrame ); - /* Write temp buffer to HPI stream */ - PA_ASIHPI_UNLESS_( HPI_OutStreamWrite( stream->output->hpiDevice->subSys, - stream->output->hpiStream, &data ), - paUnanticipatedHostError ); -#endif - } - -error: - return result; -} - - -/** Main callback engine. - This function runs in a separate thread and does all the work of fetching audio data from - the AudioScience card via the HPI interface, feeding it to the user callback via the buffer - processor, and delivering the resulting output data back to the card via HPI calls. - It is started and terminated when the PortAudio stream is started and stopped, and starts - the HPI streams on startup. - - @param userData A pointer to an open stream previously created with Pa_OpenStream. -*/ -static void *CallbackThreadFunc( void *userData ) -{ - PaError result = paNoError; - PaAsiHpiStream *stream = (PaAsiHpiStream *) userData; - int callbackResult = paContinue; - - assert( stream ); - - /* Cleanup routine stops streams on thread exit */ - pthread_cleanup_push( &PaAsiHpi_OnThreadExit, stream ); - - /* Start HPI streams and notify parent when we're done */ - PA_ENSURE_( PaUnixThread_PrepareNotify( &stream->thread ) ); - /* Buffer will be primed with silence */ - PA_ENSURE_( PaAsiHpi_StartStream( stream, 0 ) ); - PA_ENSURE_( PaUnixThread_NotifyParent( &stream->thread ) ); - - /* MAIN LOOP */ - while( 1 ) - { - PaStreamCallbackFlags cbFlags = 0; - unsigned long framesAvail, framesGot; - - pthread_testcancel(); - - /** @concern StreamStop if the main thread has requested a stop and the stream has not - * been effectively stopped we signal this condition by modifying callbackResult - * (we'll want to flush buffered output). */ - if( PaUnixThread_StopRequested( &stream->thread ) && (callbackResult == paContinue) ) - { - PA_DEBUG(( "Setting callbackResult to paComplete\n" )); - callbackResult = paComplete; - } - - /* Start winding down thread if requested */ - if( callbackResult != paContinue ) - { - stream->callbackAbort = (callbackResult == paAbort); - if( stream->callbackAbort || - /** @concern BlockAdaption: Go on if adaption buffers are empty */ - PaUtil_IsBufferProcessorOutputEmpty( &stream->bufferProcessor ) ) - { - goto end; - } - PA_DEBUG(( "%s: Flushing buffer processor\n", __FUNCTION__ )); - /* There is still buffered output that needs to be processed */ - } - - /* SLEEP */ - /* Wait for data (or buffer space) to become available. This basically sleeps and - polls the HPI interface until a full block of frames can be moved. */ - PA_ENSURE_( PaAsiHpi_WaitForFrames( stream, &framesAvail, &cbFlags ) ); - - /* Consume buffer space. Once we have a number of frames available for consumption we - must retrieve the data from the HPI interface and pass it to the PA buffer processor. - We should be prepared to process several chunks successively. */ - while( framesAvail > 0 ) - { - PaStreamCallbackTimeInfo timeInfo = {0, 0, 0}; - - pthread_testcancel(); - - framesGot = framesAvail; - if( stream->bufferProcessor.hostBufferSizeMode == paUtilFixedHostBufferSize ) - { - /* We've committed to a fixed host buffer size, stick to that */ - framesGot = framesGot >= stream->maxFramesPerHostBuffer ? stream->maxFramesPerHostBuffer : 0; - } - else - { - /* We've committed to an upper bound on the size of host buffers */ - assert( stream->bufferProcessor.hostBufferSizeMode == paUtilBoundedHostBufferSize ); - framesGot = PA_MIN( framesGot, stream->maxFramesPerHostBuffer ); - } - - /* Obtain buffer timestamps */ - PaAsiHpi_CalculateTimeInfo( stream, &timeInfo ); - PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, cbFlags ); - /* CPU load measurement should include processing activivity external to the stream callback */ - PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer ); - if( framesGot > 0 ) - { - /* READ FROM HPI INPUT STREAM */ - PA_ENSURE_( PaAsiHpi_BeginProcessing( stream, &framesGot, &cbFlags ) ); - /* Input overflow in a full-duplex stream makes for interesting times */ - if( stream->input && stream->output && (cbFlags & paInputOverflow) ) - { - /* Special full-duplex paNeverDropInput mode */ - if( stream->neverDropInput ) - { - PaUtil_SetNoOutput( &stream->bufferProcessor ); - cbFlags |= paOutputOverflow; - } - } - /* CALL USER CALLBACK WITH INPUT DATA, AND OBTAIN OUTPUT DATA */ - PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult ); - /* Clear overflow and underflow information (but PaAsiHpi_EndProcessing might - still show up output underflow that will carry over to next round) */ - cbFlags = 0; - /* WRITE TO HPI OUTPUT STREAM */ - PA_ENSURE_( PaAsiHpi_EndProcessing( stream, framesGot, &cbFlags ) ); - /* Advance frame counter */ - framesAvail -= framesGot; - } - PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesGot ); - - if( framesGot == 0 ) - { - /* Go back to polling for more frames */ - break; - - } - if( callbackResult != paContinue ) - break; - } - } - - /* This code is unreachable, but important to include regardless because it - * is possibly a macro with a closing brace to match the opening brace in - * pthread_cleanup_push() above. The documentation states that they must - * always occur in pairs. */ - pthread_cleanup_pop( 1 ); - -end: - /* Indicates normal exit of callback, as opposed to the thread getting killed explicitly */ - stream->callbackFinished = 1; - PA_DEBUG(( "%s: Thread %d exiting (callbackResult = %d)\n ", - __FUNCTION__, pthread_self(), callbackResult )); - /* Exit from thread and report any PortAudio error in the process */ - PaUnixThreading_EXIT( result ); -error: - goto end; -} - -/* --------------------------- Blocking Interface --------------------------- */ - -/* As separate stream interfaces are used for blocking and callback streams, the following - functions can be guaranteed to only be called for blocking streams. */ - -/** Read data from input stream. - This reads the indicated number of frames into the supplied buffer from an input stream, - and blocks until this is done. - - @param s Pointer to PortAudio stream - - @param buffer Pointer to buffer that will receive interleaved data (or an array of pointers - to a buffer for each non-interleaved channel) - - @param frames Number of frames to read from stream - - @return PortAudio error code (also indicates overflow via paInputOverflowed) - */ -static PaError ReadStream( PaStream *s, - void *buffer, - unsigned long frames ) -{ - PaError result = paNoError; - PaAsiHpiStream *stream = (PaAsiHpiStream*)s; - PaAsiHpiStreamInfo info; - void *userBuffer; - - assert( stream ); - PA_UNLESS_( stream->input, paCanNotReadFromAnOutputOnlyStream ); - - /* Check for input overflow since previous call to ReadStream */ - PA_ENSURE_( PaAsiHpi_GetStreamInfo( stream->input, &info ) ); - if( info.overflow ) - { - result = paInputOverflowed; - } - - /* NB Make copy of user buffer pointers, since they are advanced by buffer processor */ - if( stream->bufferProcessor.userInputIsInterleaved ) - { - userBuffer = buffer; - } - else - { - /* Copy channels into local array */ - userBuffer = stream->blockingUserBufferCopy; - memcpy( userBuffer, buffer, sizeof (void *) * stream->input->hpiFormat.wChannels ); - } - - while( frames > 0 ) - { - unsigned long framesGot, framesAvail; - PaStreamCallbackFlags cbFlags = 0; - - PA_ENSURE_( PaAsiHpi_WaitForFrames( stream, &framesAvail, &cbFlags ) ); - framesGot = PA_MIN( framesAvail, frames ); - PA_ENSURE_( PaAsiHpi_BeginProcessing( stream, &framesGot, &cbFlags ) ); - - if( framesGot > 0 ) - { - framesGot = PaUtil_CopyInput( &stream->bufferProcessor, &userBuffer, framesGot ); - PA_ENSURE_( PaAsiHpi_EndProcessing( stream, framesGot, &cbFlags ) ); - /* Advance frame counter */ - frames -= framesGot; - } - } - -error: - return result; -} - - -/** Write data to output stream. - This writes the indicated number of frames from the supplied buffer to an output stream, - and blocks until this is done. - - @param s Pointer to PortAudio stream - - @param buffer Pointer to buffer that provides interleaved data (or an array of pointers - to a buffer for each non-interleaved channel) - - @param frames Number of frames to write to stream - - @return PortAudio error code (also indicates underflow via paOutputUnderflowed) - */ -static PaError WriteStream( PaStream *s, - const void *buffer, - unsigned long frames ) -{ - PaError result = paNoError; - PaAsiHpiStream *stream = (PaAsiHpiStream*)s; - PaAsiHpiStreamInfo info; - const void *userBuffer; - - assert( stream ); - PA_UNLESS_( stream->output, paCanNotWriteToAnInputOnlyStream ); - - /* Check for output underflow since previous call to WriteStream */ - PA_ENSURE_( PaAsiHpi_GetStreamInfo( stream->output, &info ) ); - if( info.underflow ) - { - result = paOutputUnderflowed; - } - - /* NB Make copy of user buffer pointers, since they are advanced by buffer processor */ - if( stream->bufferProcessor.userOutputIsInterleaved ) - { - userBuffer = buffer; - } - else - { - /* Copy channels into local array */ - userBuffer = stream->blockingUserBufferCopy; - memcpy( (void *)userBuffer, buffer, sizeof (void *) * stream->output->hpiFormat.wChannels ); - } - - while( frames > 0 ) - { - unsigned long framesGot, framesAvail; - PaStreamCallbackFlags cbFlags = 0; - - PA_ENSURE_( PaAsiHpi_WaitForFrames( stream, &framesAvail, &cbFlags ) ); - framesGot = PA_MIN( framesAvail, frames ); - PA_ENSURE_( PaAsiHpi_BeginProcessing( stream, &framesGot, &cbFlags ) ); - - if( framesGot > 0 ) - { - framesGot = PaUtil_CopyOutput( &stream->bufferProcessor, &userBuffer, framesGot ); - PA_ENSURE_( PaAsiHpi_EndProcessing( stream, framesGot, &cbFlags ) ); - /* Advance frame counter */ - frames -= framesGot; - } - } - -error: - return result; -} - - -/** Number of frames that can be read from input stream without blocking. - - @param s Pointer to PortAudio stream - - @return Number of frames, or PortAudio error code - */ -static signed long GetStreamReadAvailable( PaStream *s ) -{ - PaError result = paNoError; - PaAsiHpiStream *stream = (PaAsiHpiStream*)s; - PaAsiHpiStreamInfo info; - - assert( stream ); - PA_UNLESS_( stream->input, paCanNotReadFromAnOutputOnlyStream ); - - PA_ENSURE_( PaAsiHpi_GetStreamInfo( stream->input, &info ) ); - /* Round down to the nearest host buffer multiple */ - result = (info.availableFrames / stream->maxFramesPerHostBuffer) * stream->maxFramesPerHostBuffer; - if( info.overflow ) - { - result = paInputOverflowed; - } - -error: - return result; -} - - -/** Number of frames that can be written to output stream without blocking. - - @param s Pointer to PortAudio stream - - @return Number of frames, or PortAudio error code - */ -static signed long GetStreamWriteAvailable( PaStream *s ) -{ - PaError result = paNoError; - PaAsiHpiStream *stream = (PaAsiHpiStream*)s; - PaAsiHpiStreamInfo info; - - assert( stream ); - PA_UNLESS_( stream->output, paCanNotWriteToAnInputOnlyStream ); - - PA_ENSURE_( PaAsiHpi_GetStreamInfo( stream->output, &info ) ); - /* Round down to the nearest host buffer multiple */ - result = (info.availableFrames / stream->maxFramesPerHostBuffer) * stream->maxFramesPerHostBuffer; - if( info.underflow ) - { - result = paOutputUnderflowed; - } - -error: - return result; -} +/* + * PortAudio Portable Real-Time Audio Library + * Latest Version at: http://www.portaudio.com + * + * PortAudio v18 version of AudioScience HPI driver by Fred Gleason + * PortAudio v19 version of AudioScience HPI driver by Ludwig Schwardt + * + * Copyright (c) 2003 Fred Gleason + * Copyright (c) 2005,2006 Ludwig Schwardt + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/* + * Modification History + * 12/2003 - Initial version + * 09/2005 - v19 version [rewrite] + */ + +/** @file + @ingroup hostapi_src + @brief Host API implementation supporting AudioScience cards + via the Linux HPI interface. + +

Overview

+ + This is a PortAudio implementation for the AudioScience HPI Audio API + on the Linux platform. AudioScience makes a range of audio adapters customised + for the broadcasting industry, with support for both Windows and Linux. + More information on their products can be found on their website: + + http://www.audioscience.com + + Documentation for the HPI API can be found at: + + http://www.audioscience.com/internet/download/sdk/spchpi.pdf + + The Linux HPI driver itself (a kernel module + library) can be downloaded from: + + http://www.audioscience.com/internet/download/linux_drivers.htm + +

Implementation strategy

+ + *Note* Ideally, AudioScience cards should be handled by the PortAudio ALSA + implementation on Linux, as ALSA is the preferred Linux soundcard API. The existence + of this host API implementation might therefore seem a bit flawed. Unfortunately, at + the time of the creation of this implementation (June 2006), the PA ALSA implementation + could not make use of the existing AudioScience ALSA driver. PA ALSA uses the + "memory-mapped" (mmap) ALSA access mode to interact with the ALSA library, while the + AudioScience ALSA driver only supports the "read-write" access mode. The appropriate + solution to this problem is to add "read-write" support to PortAudio ALSA, thereby + extending the range of soundcards it supports (AudioScience cards are not the only + ones with this problem). Given the author's limited knowledge of ALSA and the + simplicity of the HPI API, the second-best solution was born... + + The following mapping between HPI and PA was followed: + HPI subsystem => PortAudio host API + HPI adapter => nothing specific + HPI stream => PortAudio device + + Each HPI stream is either input or output (not both), and can support + different channel counts, sampling rates and sample formats. It is therefore + a more natural fit to a PA device. A PA stream can therefore combine two + HPI streams (one input and one output) into a "full-duplex" stream. These + HPI streams can even be on different physical adapters. The two streams ought to be + sample-synchronised when they reside on the same adapter, as most AudioScience adapters + derive their ADC and DAC clocks from one master clock. When combining two adapters + into one full-duplex stream, however, the use of a word clock connection between the + adapters is strongly recommended. + + The HPI interface is inherently blocking, making use of read and write calls to + transfer data between user buffers and driver buffers. The callback interface therefore + requires a helper thread ("callback engine") which periodically transfers data (one thread + per PA stream, in fact). The current implementation explicitly sleeps via Pa_Sleep() until + enough samples can be transferred (select() or poll() would be better, but currently seems + impossible...). The thread implementation makes use of the Unix thread helper functions + and some pthread calls here and there. If a unified PA thread exists, this host API + implementation might also compile on Windows, as this is the only real Linux-specific + part of the code. + + There is no inherent fixed buffer size in the HPI interface, as in some other host APIs. + The PortAudio implementation contains a buffer that is allocated during OpenStream and + used to transfer data between the callback and the HPI driver buffer. The size of this + buffer is quite flexible and is derived from latency suggestions and matched to the + requested callback buffer size as far as possible. It can become quite huge, as the + AudioScience cards are typically geared towards higher-latency applications and contain + large hardware buffers. + + The HPI interface natively supports most common sample formats and sample rates (some + conversion is done on the adapter itself). + + Stream time is measured based on the number of processed frames, which is adjusted by the + number of frames currently buffered by the HPI driver. + + There is basic support for detecting overflow and underflow. The HPI interface does not + explicitly indicate this, so thresholds on buffer levels are used in combination with + stream state. Recovery from overflow and underflow is left to the PA client. + + Blocking streams are also implemented. It makes use of the same polling routines that + the callback interface uses, in order to prevent the allocation of variable-sized + buffers during reading and writing. The framesPerBuffer parameter is therefore still + relevant, and this can be increased in the blocking case to improve efficiency. + + The implementation contains extensive reporting macros (slightly modified PA_ENSURE and + PA_UNLESS versions) and a useful stream dump routine to provide debugging feedback. + + Output buffer priming via the user callback (i.e. paPrimeOutputBuffersUsingStreamCallback + and friends) is not implemented yet. All output is primed with silence. + + Please send bug reports etc. to Ludwig Schwardt + */ + +#include +#include +#include +#include /* strlen() */ +#include /* pthreads and friends */ +#include /* assert */ +#include /* ceil, floor */ + +#include /* HPI API */ + +#include "portaudio.h" /* PortAudio API */ +#include "pa_util.h" /* PA_DEBUG, other small utilities */ +#include "pa_unix_util.h" /* Unix threading utilities */ +#include "pa_allocation.h" /* Group memory allocation */ +#include "pa_hostapi.h" /* Host API structs */ +#include "pa_stream.h" /* Stream interface structs */ +#include "pa_cpuload.h" /* CPU load measurer */ +#include "pa_process.h" /* Buffer processor */ +#include "pa_converters.h" /* PaUtilZeroer */ +#include "pa_debugprint.h" + +/* -------------------------------------------------------------------------- */ + +/* + * Defines + */ + +/* Error reporting and assertions */ + +/** Evaluate expression, and return on any PortAudio errors */ +#define PA_ENSURE_(expr) \ + do { \ + PaError paError = (expr); \ + if( UNLIKELY( paError < paNoError ) ) \ + { \ + PA_DEBUG(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \ + result = paError; \ + goto error; \ + } \ + } while (0); + +/** Assert expression, else return the provided PaError */ +#define PA_UNLESS_(expr, paError) \ + do { \ + if( UNLIKELY( (expr) == 0 ) ) \ + { \ + PA_DEBUG(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \ + result = (paError); \ + goto error; \ + } \ + } while( 0 ); + +/** Check return value of HPI function, and map it to PaError */ +#define PA_ASIHPI_UNLESS_(expr, paError) \ + do { \ + HW16 hpiError = (expr); \ + /* If HPI error occurred */ \ + if( UNLIKELY( hpiError ) ) \ + { \ + char szError[256]; \ + HPI_GetErrorText( hpiError, szError ); \ + PA_DEBUG(( "HPI error %d occurred: %s\n", hpiError, szError )); \ + /* This message will always be displayed, even if debug info is disabled */ \ + PA_DEBUG(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \ + if( (paError) == paUnanticipatedHostError ) \ + { \ + PA_DEBUG(( "Host error description: %s\n", szError )); \ + /* PaUtil_SetLastHostErrorInfo should only be used in the main thread */ \ + if( pthread_equal( pthread_self(), paUnixMainThread ) ) \ + { \ + PaUtil_SetLastHostErrorInfo( paInDevelopment, hpiError, szError ); \ + } \ + } \ + /* If paNoError is specified, continue as usual */ \ + /* (useful if you only want to print out the debug messages above) */ \ + if( (paError) < 0 ) \ + { \ + result = (paError); \ + goto error; \ + } \ + } \ + } while( 0 ); + +/** Report HPI error code and text */ +#define PA_ASIHPI_REPORT_ERROR_(hpiErrorCode) \ + do { \ + char szError[256]; \ + HPI_GetErrorText( hpiError, szError ); \ + PA_DEBUG(( "HPI error %d occurred: %s\n", hpiError, szError )); \ + /* PaUtil_SetLastHostErrorInfo should only be used in the main thread */ \ + if( pthread_equal( pthread_self(), paUnixMainThread ) ) \ + { \ + PaUtil_SetLastHostErrorInfo( paInDevelopment, (hpiErrorCode), szError ); \ + } \ + } while( 0 ); + +/* Defaults */ + +/** Sample formats available natively on AudioScience hardware */ +#define PA_ASIHPI_AVAILABLE_FORMATS_ (paFloat32 | paInt32 | paInt24 | paInt16 | paUInt8) +/** Enable background bus mastering (BBM) for buffer transfers, if available (see HPI docs) */ +#define PA_ASIHPI_USE_BBM_ 1 +/** Minimum number of frames in HPI buffer (for either data or available space). + If buffer contains less data/space, it indicates xrun or completion. */ +#define PA_ASIHPI_MIN_FRAMES_ 1152 +/** Minimum polling interval in milliseconds, which determines minimum host buffer size */ +#define PA_ASIHPI_MIN_POLLING_INTERVAL_ 10 + +/* -------------------------------------------------------------------------- */ + +/* + * Structures + */ + +/** Host API global data */ +typedef struct PaAsiHpiHostApiRepresentation +{ + /* PortAudio "base class" - keep the baseRep first! (C-style inheritance) */ + PaUtilHostApiRepresentation baseHostApiRep; + PaUtilStreamInterface callbackStreamInterface; + PaUtilStreamInterface blockingStreamInterface; + + PaUtilAllocationGroup *allocations; + + /* implementation specific data goes here */ + + PaHostApiIndex hostApiIndex; + /** HPI subsystem pointer */ + HPI_HSUBSYS *subSys; +} +PaAsiHpiHostApiRepresentation; + + +/** Device data */ +typedef struct PaAsiHpiDeviceInfo +{ + /* PortAudio "base class" - keep the baseRep first! (C-style inheritance) */ + /** Common PortAudio device information */ + PaDeviceInfo baseDeviceInfo; + + /* implementation specific data goes here */ + + /** HPI subsystem (required for most HPI calls) */ + HPI_HSUBSYS *subSys; + /** Adapter index */ + HW16 adapterIndex; + /** Adapter model number (hex) */ + HW16 adapterType; + /** Adapter HW/SW version */ + HW16 adapterVersion; + /** Adapter serial number */ + HW32 adapterSerialNumber; + /** Stream number */ + HW16 streamIndex; + /** 0=Input, 1=Output (HPI streams are either input or output but not both) */ + HW16 streamIsOutput; +} +PaAsiHpiDeviceInfo; + + +/** Stream state as defined by PortAudio. + It seems that the host API implementation has to keep track of the PortAudio stream state. + Please note that this is NOT the same as the state of the underlying HPI stream. By separating + these two concepts, a lot of flexibility is gained. There is a rough match between the two, + of course, but forcing a precise match is difficult. For example, HPI_STATE_DRAINED can occur + during the Active state of PortAudio (due to underruns) and also during CallBackFinished in + the case of an output stream. Similarly, HPI_STATE_STOPPED mostly coincides with the Stopped + PortAudio state, by may also occur in the CallbackFinished state when recording is finished. + + Here is a rough match-up: + + PortAudio state => HPI state + --------------- --------- + Active => HPI_STATE_RECORDING, HPI_STATE_PLAYING, (HPI_STATE_DRAINED) + Stopped => HPI_STATE_STOPPED + CallbackFinished => HPI_STATE_STOPPED, HPI_STATE_DRAINED */ +typedef enum PaAsiHpiStreamState +{ + paAsiHpiStoppedState=0, + paAsiHpiActiveState=1, + paAsiHpiCallbackFinishedState=2 +} +PaAsiHpiStreamState; + + +/** Stream component data (associated with one direction, i.e. either input or output) */ +typedef struct PaAsiHpiStreamComponent +{ + /** Device information (HPI handles, etc) */ + PaAsiHpiDeviceInfo *hpiDevice; + /** Stream handle, as passed to HPI interface. + HACK: we assume types HPI_HISTREAM and HPI_HOSTREAM are the same... + (both are HW32 up to version 3.00 of ASIHPI, and hopefully they stay that way) */ + HPI_HISTREAM hpiStream; + /** Stream format, as passed to HPI interface */ + HPI_FORMAT hpiFormat; + /** Number of bytes per frame, derived from hpiFormat and saved for convenience */ + HW32 bytesPerFrame; + /** Size of hardware (on-card) buffer of stream in bytes */ + HW32 hardwareBufferSize; + /** Size of host (BBM) buffer of stream in bytes (if used) */ + HW32 hostBufferSize; + /** Upper limit on the utilization of output stream buffer (both hardware and host). + This prevents large latencies in an output-only stream with a potentially huge buffer + and a fast data generator, which would otherwise keep the hardware buffer filled to + capacity. See also the "Hardware Buffering=off" option in the AudioScience WAV driver. */ + HW32 outputBufferCap; + /** Sample buffer (halfway station between HPI and buffer processor) */ + HW8 *tempBuffer; + /** Sample buffer size, in bytes */ + HW32 tempBufferSize; +} +PaAsiHpiStreamComponent; + + +/** Stream data */ +typedef struct PaAsiHpiStream +{ + /* PortAudio "base class" - keep the baseRep first! (C-style inheritance) */ + PaUtilStreamRepresentation baseStreamRep; + PaUtilCpuLoadMeasurer cpuLoadMeasurer; + PaUtilBufferProcessor bufferProcessor; + + PaUtilAllocationGroup *allocations; + + /* implementation specific data goes here */ + + /** Separate structs for input and output sides of stream */ + PaAsiHpiStreamComponent *input, *output; + + /** Polling interval (in milliseconds) */ + HW32 pollingInterval; + /** Are we running in callback mode? */ + int callbackMode; + /** Number of frames to transfer at a time to/from HPI */ + unsigned long maxFramesPerHostBuffer; + /** Indicates that the stream is in the paNeverDropInput mode */ + int neverDropInput; + /** Contains copy of user buffers, used by blocking interface to transfer non-interleaved data. + It went here instead of to each stream component, as the stream component buffer setup in + PaAsiHpi_SetupBuffers doesn't know the stream details such as callbackMode. + (Maybe a problem later if ReadStream and WriteStream happens concurrently on same stream.) */ + void **blockingUserBufferCopy; + + /* Thread-related variables */ + + /** Helper thread which will deliver data to user callback */ + PaUnixThread thread; + /** PortAudio stream state (Active/Stopped/CallbackFinished) */ + volatile sig_atomic_t state; + /** Hard abort, i.e. drop frames? */ + volatile sig_atomic_t callbackAbort; + /** True if stream stopped via exiting callback with paComplete/paAbort flag + (as opposed to explicit call to StopStream/AbortStream) */ + volatile sig_atomic_t callbackFinished; +} +PaAsiHpiStream; + + +/** Stream state information, collected together for convenience */ +typedef struct PaAsiHpiStreamInfo +{ + /** HPI stream state (HPI_STATE_STOPPED, HPI_STATE_PLAYING, etc.) */ + HW16 state; + /** Size (in bytes) of recording/playback data buffer in HPI driver */ + HW32 bufferSize; + /** Amount of data (in bytes) available in the buffer */ + HW32 dataSize; + /** Number of frames played/recorded since last stream reset */ + HW32 frameCounter; + /** Amount of data (in bytes) in hardware (on-card) buffer. + This differs from dataSize if bus mastering (BBM) is used, which introduces another + driver-level buffer to which dataSize/bufferSize then refers. */ + HW32 auxDataSize; + /** Total number of data frames currently buffered by HPI driver (host + hw buffers) */ + HW32 totalBufferedData; + /** Size of immediately available data (for input) or space (for output) in frames. + This only checks the first-level buffer (typically host buffer). This amount can be + transferred immediately. */ + HW32 availableFrames; + /** Indicates that hardware buffer is getting too full */ + int overflow; + /** Indicates that hardware buffer is getting too empty */ + int underflow; +} +PaAsiHpiStreamInfo; + +/* -------------------------------------------------------------------------- */ + +/* + * Function prototypes + */ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + /* The only exposed function in the entire host API implementation */ + PaError PaAsiHpi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +static void Terminate( struct PaUtilHostApiRepresentation *hostApi ); +static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate ); + +/* Stream prototypes */ +static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, + PaStream **s, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate, + unsigned long framesPerBuffer, + PaStreamFlags streamFlags, + PaStreamCallback *streamCallback, + void *userData ); +static PaError CloseStream( PaStream *s ); +static PaError StartStream( PaStream *s ); +static PaError StopStream( PaStream *s ); +static PaError AbortStream( PaStream *s ); +static PaError IsStreamStopped( PaStream *s ); +static PaError IsStreamActive( PaStream *s ); +static PaTime GetStreamTime( PaStream *s ); +static double GetStreamCpuLoad( PaStream *s ); + +/* Blocking prototypes */ +static PaError ReadStream( PaStream *s, void *buffer, unsigned long frames ); +static PaError WriteStream( PaStream *s, const void *buffer, unsigned long frames ); +static signed long GetStreamReadAvailable( PaStream *s ); +static signed long GetStreamWriteAvailable( PaStream *s ); + +/* Callback prototypes */ +static void *CallbackThreadFunc( void *userData ); + +/* Functions specific to this API */ +static PaError PaAsiHpi_BuildDeviceList( PaAsiHpiHostApiRepresentation *hpiHostApi ); +static HW16 PaAsiHpi_PaToHpiFormat( PaSampleFormat paFormat ); +static PaSampleFormat PaAsiHpi_HpiToPaFormat( HW16 hpiFormat ); +static PaError PaAsiHpi_CreateFormat( struct PaUtilHostApiRepresentation *hostApi, + const PaStreamParameters *parameters, double sampleRate, + PaAsiHpiDeviceInfo **hpiDevice, HPI_FORMAT *hpiFormat ); +static PaError PaAsiHpi_OpenInput( struct PaUtilHostApiRepresentation *hostApi, + const PaAsiHpiDeviceInfo *hpiDevice, const HPI_FORMAT *hpiFormat, + HPI_HISTREAM *hpiStream ); +static PaError PaAsiHpi_OpenOutput( struct PaUtilHostApiRepresentation *hostApi, + const PaAsiHpiDeviceInfo *hpiDevice, const HPI_FORMAT *hpiFormat, + HPI_HOSTREAM *hpiStream ); +static PaError PaAsiHpi_GetStreamInfo( PaAsiHpiStreamComponent *streamComp, PaAsiHpiStreamInfo *info ); +static void PaAsiHpi_StreamComponentDump( PaAsiHpiStreamComponent *streamComp, PaAsiHpiStream *stream ); +static void PaAsiHpi_StreamDump( PaAsiHpiStream *stream ); +static PaError PaAsiHpi_SetupBuffers( PaAsiHpiStreamComponent *streamComp, HW32 pollingInterval, + unsigned long framesPerPaHostBuffer, PaTime suggestedLatency ); +static PaError PaAsiHpi_PrimeOutputWithSilence( PaAsiHpiStream *stream ); +static PaError PaAsiHpi_StartStream( PaAsiHpiStream *stream, int outputPrimed ); +static PaError PaAsiHpi_StopStream( PaAsiHpiStream *stream, int abort ); +static PaError PaAsiHpi_ExplicitStop( PaAsiHpiStream *stream, int abort ); +static void PaAsiHpi_OnThreadExit( void *userData ); +static PaError PaAsiHpi_WaitForFrames( PaAsiHpiStream *stream, unsigned long *framesAvail, + PaStreamCallbackFlags *cbFlags ); +static void PaAsiHpi_CalculateTimeInfo( PaAsiHpiStream *stream, PaStreamCallbackTimeInfo *timeInfo ); +static PaError PaAsiHpi_BeginProcessing( PaAsiHpiStream* stream, unsigned long* numFrames, + PaStreamCallbackFlags *cbFlags ); +static PaError PaAsiHpi_EndProcessing( PaAsiHpiStream *stream, unsigned long numFrames, + PaStreamCallbackFlags *cbFlags ); + +/* ========================================================================== + * ============================= IMPLEMENTATION ============================= + * ========================================================================== */ + +/* --------------------------- Host API Interface --------------------------- */ + +/** Enumerate all PA devices (= HPI streams). + This compiles a list of all HPI adapters, and registers a PA device for each input and + output stream it finds. Most errors are ignored, as missing or erroneous devices are + simply skipped. + + @param hpiHostApi Pointer to HPI host API struct + + @return PortAudio error code (only paInsufficientMemory in practice) + */ +static PaError PaAsiHpi_BuildDeviceList( PaAsiHpiHostApiRepresentation *hpiHostApi ) +{ + PaError result = paNoError; + PaUtilHostApiRepresentation *hostApi = &hpiHostApi->baseHostApiRep; + PaHostApiInfo *baseApiInfo = &hostApi->info; + PaAsiHpiDeviceInfo *hpiDeviceList; + HW16 adapterList[ HPI_MAX_ADAPTERS ]; + HW16 numAdapters; + HW16 hpiError = 0; + int i, j, deviceCount = 0, deviceIndex = 0; + + assert( hpiHostApi ); + assert( hpiHostApi->subSys ); + + /* Look for adapters (not strictly necessary, as AdapterOpen can do the same, but this */ + /* way we have less errors since we do not try to open adapters we know aren't there) */ + /* Errors not considered critical here (subsystem may report 0 devices), but report them */ + /* in debug mode. */ + PA_ASIHPI_UNLESS_( HPI_SubSysFindAdapters( hpiHostApi->subSys, &numAdapters, + adapterList, HPI_MAX_ADAPTERS ), paNoError ); + + /* First open and count the number of devices (= number of streams), to ease memory allocation */ + for( i=0; i < HPI_MAX_ADAPTERS; ++i ) + { + HW16 inStreams, outStreams; + HW16 version; + HW32 serial; + HW16 type; + + /* If no adapter found at this index, skip it */ + if( adapterList[i] == 0 ) + continue; + + /* Try to open adapter */ + hpiError = HPI_AdapterOpen( hpiHostApi->subSys, i ); + /* Report error and skip to next device on failure */ + if( hpiError ) + { + PA_ASIHPI_REPORT_ERROR_( hpiError ); + continue; + } + hpiError = HPI_AdapterGetInfo( hpiHostApi->subSys, i, + &outStreams, &inStreams, &version, &serial, &type ); + /* Skip to next device on failure */ + if( hpiError ) + { + PA_ASIHPI_REPORT_ERROR_( hpiError ); + continue; + } + else + { + /* Assign default devices if available and increment device count */ + if( (baseApiInfo->defaultInputDevice == paNoDevice) && (inStreams > 0) ) + baseApiInfo->defaultInputDevice = deviceCount; + deviceCount += inStreams; + if( (baseApiInfo->defaultOutputDevice == paNoDevice) && (outStreams > 0) ) + baseApiInfo->defaultOutputDevice = deviceCount; + deviceCount += outStreams; + } + } + + /* Register any discovered devices */ + if( deviceCount > 0 ) + { + /* Memory allocation */ + PA_UNLESS_( hostApi->deviceInfos = (PaDeviceInfo**) PaUtil_GroupAllocateMemory( + hpiHostApi->allocations, sizeof(PaDeviceInfo*) * deviceCount ), + paInsufficientMemory ); + /* Allocate all device info structs in a contiguous block */ + PA_UNLESS_( hpiDeviceList = (PaAsiHpiDeviceInfo*) PaUtil_GroupAllocateMemory( + hpiHostApi->allocations, sizeof(PaAsiHpiDeviceInfo) * deviceCount ), + paInsufficientMemory ); + + /* Now query devices again for information */ + for( i=0; i < HPI_MAX_ADAPTERS; ++i ) + { + HW16 inStreams, outStreams; + HW16 version; + HW32 serial; + HW16 type; + + /* If no adapter found at this index, skip it */ + if( adapterList[i] == 0 ) + continue; + + /* Assume adapter is still open from previous round */ + hpiError = HPI_AdapterGetInfo( hpiHostApi->subSys, i, + &outStreams, &inStreams, &version, &serial, &type ); + /* Report error and skip to next device on failure */ + if( hpiError ) + { + PA_ASIHPI_REPORT_ERROR_( hpiError ); + continue; + } + else + { + PA_DEBUG(( "Found HPI Adapter ID=%4X Idx=%d #In=%d #Out=%d S/N=%d HWver=%c%d DSPver=%03d\n", + type, i, inStreams, outStreams, serial, + ((version>>3)&0xf)+'A', /* Hw version major */ + version&0x7, /* Hw version minor */ + ((version>>13)*100)+((version>>7)&0x3f) /* DSP code version */ + )); + } + + /* First add all input streams as devices */ + for( j=0; j < inStreams; ++j ) + { + PaAsiHpiDeviceInfo *hpiDevice = &hpiDeviceList[deviceIndex]; + PaDeviceInfo *baseDeviceInfo = &hpiDevice->baseDeviceInfo; + char srcName[72]; + char *deviceName; + + memset( hpiDevice, 0, sizeof(PaAsiHpiDeviceInfo) ); + /* Set implementation-specific device details */ + hpiDevice->subSys = hpiHostApi->subSys; + hpiDevice->adapterIndex = i; + hpiDevice->adapterType = type; + hpiDevice->adapterVersion = version; + hpiDevice->adapterSerialNumber = serial; + hpiDevice->streamIndex = j; + hpiDevice->streamIsOutput = 0; + /* Set common PortAudio device stats */ + baseDeviceInfo->structVersion = 2; + /* Make sure name string is owned by API info structure */ + sprintf( srcName, + "Adapter %d (%4X) - Input Stream %d", i+1, type, j+1 ); + PA_UNLESS_( deviceName = (char *) PaUtil_GroupAllocateMemory( + hpiHostApi->allocations, strlen(srcName) + 1 ), paInsufficientMemory ); + strcpy( deviceName, srcName ); + baseDeviceInfo->name = deviceName; + baseDeviceInfo->hostApi = hpiHostApi->hostApiIndex; + baseDeviceInfo->maxInputChannels = HPI_MAX_CHANNELS; + baseDeviceInfo->maxOutputChannels = 0; + /* Default latency values for interactive performance */ + baseDeviceInfo->defaultLowInputLatency = 0.01; + baseDeviceInfo->defaultLowOutputLatency = -1.0; + /* Default latency values for robust non-interactive applications (eg. playing sound files) */ + baseDeviceInfo->defaultHighInputLatency = 0.2; + baseDeviceInfo->defaultHighOutputLatency = -1.0; + /* HPI interface can actually handle any sampling rate to 1 Hz accuracy, + * so this default is as good as any */ + baseDeviceInfo->defaultSampleRate = 44100; + + /* Store device in global PortAudio list */ + hostApi->deviceInfos[deviceIndex++] = (PaDeviceInfo *) hpiDevice; + } + + /* Now add all output streams as devices (I know, the repetition is painful) */ + for( j=0; j < outStreams; ++j ) + { + PaAsiHpiDeviceInfo *hpiDevice = &hpiDeviceList[deviceIndex]; + PaDeviceInfo *baseDeviceInfo = &hpiDevice->baseDeviceInfo; + char srcName[72]; + char *deviceName; + + memset( hpiDevice, 0, sizeof(PaAsiHpiDeviceInfo) ); + /* Set implementation-specific device details */ + hpiDevice->subSys = hpiHostApi->subSys; + hpiDevice->adapterIndex = i; + hpiDevice->adapterType = type; + hpiDevice->adapterVersion = version; + hpiDevice->adapterSerialNumber = serial; + hpiDevice->streamIndex = j; + hpiDevice->streamIsOutput = 1; + /* Set common PortAudio device stats */ + baseDeviceInfo->structVersion = 2; + /* Make sure name string is owned by API info structure */ + sprintf( srcName, + "Adapter %d (%4X) - Output Stream %d", i+1, type, j+1 ); + PA_UNLESS_( deviceName = (char *) PaUtil_GroupAllocateMemory( + hpiHostApi->allocations, strlen(srcName) + 1 ), paInsufficientMemory ); + strcpy( deviceName, srcName ); + baseDeviceInfo->name = deviceName; + baseDeviceInfo->hostApi = hpiHostApi->hostApiIndex; + baseDeviceInfo->maxInputChannels = 0; + baseDeviceInfo->maxOutputChannels = HPI_MAX_CHANNELS; + /* Default latency values for interactive performance. */ + baseDeviceInfo->defaultLowInputLatency = -1.0; + baseDeviceInfo->defaultLowOutputLatency = 0.01; + /* Default latency values for robust non-interactive applications (eg. playing sound files). */ + baseDeviceInfo->defaultHighInputLatency = -1.0; + baseDeviceInfo->defaultHighOutputLatency = 0.2; + /* HPI interface can actually handle any sampling rate to 1 Hz accuracy, + * so this default is as good as any */ + baseDeviceInfo->defaultSampleRate = 44100; + + /* Store device in global PortAudio list */ + hostApi->deviceInfos[deviceIndex++] = (PaDeviceInfo *) hpiDevice; + } + } + } + + /* Finally acknowledge checked devices */ + baseApiInfo->deviceCount = deviceIndex; + +error: + return result; +} + + +/** Initialize host API implementation. + This is the only function exported beyond this file. It is called by PortAudio to initialize + the host API. It stores API info, finds and registers all devices, and sets up callback and + blocking interfaces. + + @param hostApi Pointer to host API struct + + @param hostApiIndex Index of current (HPI) host API + + @return PortAudio error code + */ +PaError PaAsiHpi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ) +{ + PaError result = paNoError; + PaAsiHpiHostApiRepresentation *hpiHostApi = NULL; + PaHostApiInfo *baseApiInfo; + + /* Allocate host API structure */ + PA_UNLESS_( hpiHostApi = (PaAsiHpiHostApiRepresentation*) PaUtil_AllocateMemory( + sizeof(PaAsiHpiHostApiRepresentation) ), paInsufficientMemory ); + PA_UNLESS_( hpiHostApi->allocations = PaUtil_CreateAllocationGroup(), paInsufficientMemory ); + + hpiHostApi->hostApiIndex = hostApiIndex; + hpiHostApi->subSys = NULL; + + /* Try to initialize HPI subsystem */ + if( ( hpiHostApi->subSys = HPI_SubSysCreate() ) == NULL) + { + /* the V19 development docs say that if an implementation + * detects that it cannot be used, it should return a NULL + * interface and paNoError */ + PA_DEBUG(( "Could not open HPI interface\n" )); + result = paNoError; + *hostApi = NULL; + goto error; + } + else + { + HW32 hpiVersion; + PA_ASIHPI_UNLESS_( HPI_SubSysGetVersion( hpiHostApi->subSys, &hpiVersion ), paUnanticipatedHostError ); + PA_DEBUG(( "HPI interface v%d.%02d\n", + hpiVersion >> 8, 10*((hpiVersion & 0xF0) >> 4) + (hpiVersion & 0x0F) )); + } + + *hostApi = &hpiHostApi->baseHostApiRep; + baseApiInfo = &((*hostApi)->info); + /* Fill in common API details */ + baseApiInfo->structVersion = 1; + baseApiInfo->type = paAudioScienceHPI; + baseApiInfo->name = "AudioScience HPI"; + baseApiInfo->deviceCount = 0; + baseApiInfo->defaultInputDevice = paNoDevice; + baseApiInfo->defaultOutputDevice = paNoDevice; + + PA_ENSURE_( PaAsiHpi_BuildDeviceList( hpiHostApi ) ); + + (*hostApi)->Terminate = Terminate; + (*hostApi)->OpenStream = OpenStream; + (*hostApi)->IsFormatSupported = IsFormatSupported; + + PaUtil_InitializeStreamInterface( &hpiHostApi->callbackStreamInterface, CloseStream, StartStream, + StopStream, AbortStream, IsStreamStopped, IsStreamActive, + GetStreamTime, GetStreamCpuLoad, + PaUtil_DummyRead, PaUtil_DummyWrite, + PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable ); + + PaUtil_InitializeStreamInterface( &hpiHostApi->blockingStreamInterface, CloseStream, StartStream, + StopStream, AbortStream, IsStreamStopped, IsStreamActive, + GetStreamTime, PaUtil_DummyGetCpuLoad, + ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable ); + + /* Store identity of main thread */ + PA_ENSURE_( PaUnixThreading_Initialize() ); + + return result; +error: + /* Clean up memory */ + Terminate( (PaUtilHostApiRepresentation *)hpiHostApi ); + return result; +} + + +/** Terminate host API implementation. + This closes all HPI adapters and frees the HPI subsystem. It also frees the host API struct + memory. It should be called once for every PaAsiHpi_Initialize call. + + @param Pointer to host API struct + */ +static void Terminate( struct PaUtilHostApiRepresentation *hostApi ) +{ + PaAsiHpiHostApiRepresentation *hpiHostApi = (PaAsiHpiHostApiRepresentation*)hostApi; + int i; + PaError result = paNoError; + + if( hpiHostApi ) + { + /* Get rid of HPI-specific structures */ + if( hpiHostApi->subSys ) + { + HW16 lastAdapterIndex = HPI_MAX_ADAPTERS; + /* Iterate through device list and close adapters */ + for( i=0; i < hostApi->info.deviceCount; ++i ) + { + PaAsiHpiDeviceInfo *hpiDevice = (PaAsiHpiDeviceInfo *) hostApi->deviceInfos[ i ]; + /* Close adapter only if it differs from previous one */ + if( hpiDevice->adapterIndex != lastAdapterIndex ) + { + /* Ignore errors (report only during debugging) */ + PA_ASIHPI_UNLESS_( HPI_AdapterClose( hpiHostApi->subSys, + hpiDevice->adapterIndex ), paNoError ); + lastAdapterIndex = hpiDevice->adapterIndex; + } + } + /* Finally dismantle HPI subsystem */ + HPI_SubSysFree( hpiHostApi->subSys ); + } + + if( hpiHostApi->allocations ) + { + PaUtil_FreeAllAllocations( hpiHostApi->allocations ); + PaUtil_DestroyAllocationGroup( hpiHostApi->allocations ); + } + + PaUtil_FreeMemory( hpiHostApi ); + } +error: + return; +} + + +/** Converts PortAudio sample format to equivalent HPI format. + + @param paFormat PortAudio sample format + + @return HPI sample format + */ +static HW16 PaAsiHpi_PaToHpiFormat( PaSampleFormat paFormat ) +{ + /* Ignore interleaving flag */ + switch( paFormat & ~paNonInterleaved ) + { + case paFloat32: + return HPI_FORMAT_PCM32_FLOAT; + + case paInt32: + return HPI_FORMAT_PCM32_SIGNED; + + case paInt24: + return HPI_FORMAT_PCM24_SIGNED; + + case paInt16: + return HPI_FORMAT_PCM16_SIGNED; + + case paUInt8: + return HPI_FORMAT_PCM8_UNSIGNED; + + /* Default is 16-bit signed */ + case paInt8: + default: + return HPI_FORMAT_PCM16_SIGNED; + } +} + + +/** Converts HPI sample format to equivalent PortAudio format. + + @param paFormat HPI sample format + + @return PortAudio sample format + */ +static PaSampleFormat PaAsiHpi_HpiToPaFormat( HW16 hpiFormat ) +{ + switch( hpiFormat ) + { + case HPI_FORMAT_PCM32_FLOAT: + return paFloat32; + + case HPI_FORMAT_PCM32_SIGNED: + return paInt32; + + case HPI_FORMAT_PCM24_SIGNED: + return paInt24; + + case HPI_FORMAT_PCM16_SIGNED: + return paInt16; + + case HPI_FORMAT_PCM8_UNSIGNED: + return paUInt8; + + /* Default is custom format (e.g. for HPI MP3 format) */ + default: + return paCustomFormat; + } +} + + +/** Creates HPI format struct based on PortAudio parameters. + This also does some checks to see whether the desired format is valid, and whether + the device allows it. This only checks the format of one half (input or output) of the + PortAudio stream. + + @param hostApi Pointer to host API struct + + @param parameters Pointer to stream parameter struct + + @param sampleRate Desired sample rate + + @param hpiDevice Pointer to HPI device struct + + @param hpiFormat Resulting HPI format returned here + + @return PortAudio error code (typically indicating a problem with stream format) + */ +static PaError PaAsiHpi_CreateFormat( struct PaUtilHostApiRepresentation *hostApi, + const PaStreamParameters *parameters, double sampleRate, + PaAsiHpiDeviceInfo **hpiDevice, HPI_FORMAT *hpiFormat ) +{ + int maxChannelCount = 0; + PaSampleFormat hostSampleFormat = 0; + HW16 hpiError = 0; + + /* Unless alternate device specification is supported, reject the use of + paUseHostApiSpecificDeviceSpecification */ + if( parameters->device == paUseHostApiSpecificDeviceSpecification ) + return paInvalidDevice; + else + { + assert( parameters->device < hostApi->info.deviceCount ); + *hpiDevice = (PaAsiHpiDeviceInfo*) hostApi->deviceInfos[ parameters->device ]; + } + + /* Validate streamInfo - this implementation doesn't use custom stream info */ + if( parameters->hostApiSpecificStreamInfo ) + return paIncompatibleHostApiSpecificStreamInfo; + + /* Check that device can support channel count */ + if( (*hpiDevice)->streamIsOutput ) + { + maxChannelCount = (*hpiDevice)->baseDeviceInfo.maxOutputChannels; + } + else + { + maxChannelCount = (*hpiDevice)->baseDeviceInfo.maxInputChannels; + } + if( (maxChannelCount == 0) || (parameters->channelCount > maxChannelCount) ) + return paInvalidChannelCount; + + /* All standard sample formats are supported by the buffer adapter, + and this implementation doesn't support any custom sample formats */ + if( parameters->sampleFormat & paCustomFormat ) + return paSampleFormatNotSupported; + + /* Switch to closest HPI native format */ + hostSampleFormat = PaUtil_SelectClosestAvailableFormat(PA_ASIHPI_AVAILABLE_FORMATS_, + parameters->sampleFormat ); + /* Setup format + info objects */ + hpiError = HPI_FormatCreate( hpiFormat, (HW16)parameters->channelCount, + PaAsiHpi_PaToHpiFormat( hostSampleFormat ), + (HW32)sampleRate, 0, 0 ); + if( hpiError ) + { + PA_ASIHPI_REPORT_ERROR_( hpiError ); + switch( hpiError ) + { + case HPI_ERROR_INVALID_FORMAT: + return paSampleFormatNotSupported; + + case HPI_ERROR_INVALID_SAMPLERATE: + case HPI_ERROR_INCOMPATIBLE_SAMPLERATE: + return paInvalidSampleRate; + + case HPI_ERROR_INVALID_CHANNELS: + return paInvalidChannelCount; + } + } + + return paNoError; +} + + +/** Open HPI input stream with given format. + This attempts to open HPI input stream with desired format. If the format is not supported + or the device is unavailable, the stream is closed and a PortAudio error code is returned. + + @param hostApi Pointer to host API struct + + @param hpiDevice Pointer to HPI device struct + + @param hpiFormat Pointer to HPI format struct + + @return PortAudio error code (typically indicating a problem with stream format or device) +*/ +static PaError PaAsiHpi_OpenInput( struct PaUtilHostApiRepresentation *hostApi, + const PaAsiHpiDeviceInfo *hpiDevice, const HPI_FORMAT *hpiFormat, + HPI_HISTREAM *hpiStream ) +{ + PaAsiHpiHostApiRepresentation *hpiHostApi = (PaAsiHpiHostApiRepresentation*)hostApi; + PaError result = paNoError; + HW16 hpiError = 0; + + /* Catch misplaced output devices, as they typically have 0 input channels */ + PA_UNLESS_( !hpiDevice->streamIsOutput, paInvalidChannelCount ); + /* Try to open input stream */ + PA_ASIHPI_UNLESS_( HPI_InStreamOpen( hpiHostApi->subSys, hpiDevice->adapterIndex, + hpiDevice->streamIndex, hpiStream ), paDeviceUnavailable ); + /* Set input format (checking it in the process) */ + /* Could also use HPI_InStreamQueryFormat, but this economizes the process */ + hpiError = HPI_InStreamSetFormat( hpiHostApi->subSys, *hpiStream, (HPI_FORMAT*)hpiFormat ); + if( hpiError ) + { + PA_ASIHPI_REPORT_ERROR_( hpiError ); + PA_ASIHPI_UNLESS_( HPI_InStreamClose( hpiHostApi->subSys, *hpiStream ), paNoError ); + switch( hpiError ) + { + case HPI_ERROR_INVALID_FORMAT: + return paSampleFormatNotSupported; + + case HPI_ERROR_INVALID_SAMPLERATE: + case HPI_ERROR_INCOMPATIBLE_SAMPLERATE: + return paInvalidSampleRate; + + case HPI_ERROR_INVALID_CHANNELS: + return paInvalidChannelCount; + + default: + /* In case anything else went wrong */ + return paInvalidDevice; + } + } + +error: + return result; +} + + +/** Open HPI output stream with given format. + This attempts to open HPI output stream with desired format. If the format is not supported + or the device is unavailable, the stream is closed and a PortAudio error code is returned. + + @param hostApi Pointer to host API struct + + @param hpiDevice Pointer to HPI device struct + + @param hpiFormat Pointer to HPI format struct + + @return PortAudio error code (typically indicating a problem with stream format or device) +*/ +static PaError PaAsiHpi_OpenOutput( struct PaUtilHostApiRepresentation *hostApi, + const PaAsiHpiDeviceInfo *hpiDevice, const HPI_FORMAT *hpiFormat, + HPI_HOSTREAM *hpiStream ) +{ + PaAsiHpiHostApiRepresentation *hpiHostApi = (PaAsiHpiHostApiRepresentation*)hostApi; + PaError result = paNoError; + HW16 hpiError = 0; + + /* Catch misplaced input devices, as they typically have 0 output channels */ + PA_UNLESS_( hpiDevice->streamIsOutput, paInvalidChannelCount ); + /* Try to open output stream */ + PA_ASIHPI_UNLESS_( HPI_OutStreamOpen( hpiHostApi->subSys, hpiDevice->adapterIndex, + hpiDevice->streamIndex, hpiStream ), paDeviceUnavailable ); + + /* Check output format (format is set on first write to output stream) */ + hpiError = HPI_OutStreamQueryFormat( hpiHostApi->subSys, *hpiStream, (HPI_FORMAT*)hpiFormat ); + if( hpiError ) + { + PA_ASIHPI_REPORT_ERROR_( hpiError ); + PA_ASIHPI_UNLESS_( HPI_OutStreamClose( hpiHostApi->subSys, *hpiStream ), paNoError ); + switch( hpiError ) + { + case HPI_ERROR_INVALID_FORMAT: + return paSampleFormatNotSupported; + + case HPI_ERROR_INVALID_SAMPLERATE: + case HPI_ERROR_INCOMPATIBLE_SAMPLERATE: + return paInvalidSampleRate; + + case HPI_ERROR_INVALID_CHANNELS: + return paInvalidChannelCount; + + default: + /* In case anything else went wrong */ + return paInvalidDevice; + } + } + +error: + return result; +} + + +/** Checks whether the desired stream formats and devices are supported + (for both input and output). + This is done by actually opening the appropriate HPI streams and closing them again. + + @param hostApi Pointer to host API struct + + @param inputParameters Pointer to stream parameter struct for input side of stream + + @param outputParameters Pointer to stream parameter struct for output side of stream + + @param sampleRate Desired sample rate + + @return PortAudio error code (paFormatIsSupported on success) + */ +static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate ) +{ + PaError result = paFormatIsSupported; + PaAsiHpiHostApiRepresentation *hpiHostApi = (PaAsiHpiHostApiRepresentation*)hostApi; + PaAsiHpiDeviceInfo *hpiDevice = NULL; + HPI_FORMAT hpiFormat; + + /* Input stream */ + if( inputParameters ) + { + HPI_HISTREAM hpiStream; + PA_DEBUG(( "%s: Checking input params: dev=%d, sr=%d, chans=%d, fmt=%d\n", + __FUNCTION__, inputParameters->device, (int)sampleRate, + inputParameters->channelCount, inputParameters->sampleFormat )); + /* Create and validate format */ + PA_ENSURE_( PaAsiHpi_CreateFormat( hostApi, inputParameters, sampleRate, + &hpiDevice, &hpiFormat ) ); + /* Open stream to further check format */ + PA_ENSURE_( PaAsiHpi_OpenInput( hostApi, hpiDevice, &hpiFormat, &hpiStream ) ); + /* Close stream again */ + PA_ASIHPI_UNLESS_( HPI_InStreamClose( hpiHostApi->subSys, hpiStream ), paNoError ); + } + + /* Output stream */ + if( outputParameters ) + { + HPI_HOSTREAM hpiStream; + PA_DEBUG(( "%s: Checking output params: dev=%d, sr=%d, chans=%d, fmt=%d\n", + __FUNCTION__, outputParameters->device, (int)sampleRate, + outputParameters->channelCount, outputParameters->sampleFormat )); + /* Create and validate format */ + PA_ENSURE_( PaAsiHpi_CreateFormat( hostApi, outputParameters, sampleRate, + &hpiDevice, &hpiFormat ) ); + /* Open stream to further check format */ + PA_ENSURE_( PaAsiHpi_OpenOutput( hostApi, hpiDevice, &hpiFormat, &hpiStream ) ); + /* Close stream again */ + PA_ASIHPI_UNLESS_( HPI_OutStreamClose( hpiHostApi->subSys, hpiStream ), paNoError ); + } + +error: + return result; +} + +/* ---------------------------- Stream Interface ---------------------------- */ + +/** Obtain HPI stream information. + This obtains info such as stream state and available data/space in buffers. It also + estimates whether an underflow or overflow occurred. + + @param streamComp Pointer to stream component (input or output) to query + + @param info Pointer to stream info struct that will contain result + + @return PortAudio error code (either paNoError, paDeviceUnavailable or paUnanticipatedHostError) + */ +static PaError PaAsiHpi_GetStreamInfo( PaAsiHpiStreamComponent *streamComp, PaAsiHpiStreamInfo *info ) +{ + PaError result = paDeviceUnavailable; + HW16 state; + HW32 bufferSize, dataSize, frameCounter, auxDataSize, threshold; + HW32 hwBufferSize, hwDataSize; + + assert( streamComp ); + assert( info ); + + /* First blank the stream info struct, in case something goes wrong below. + This saves the caller from initializing the struct. */ + info->state = 0; + info->bufferSize = 0; + info->dataSize = 0; + info->frameCounter = 0; + info->auxDataSize = 0; + info->totalBufferedData = 0; + info->availableFrames = 0; + info->underflow = 0; + info->overflow = 0; + + if( streamComp->hpiDevice && streamComp->hpiStream ) + { + /* Obtain detailed stream info (either input or output) */ + if( streamComp->hpiDevice->streamIsOutput ) + { + PA_ASIHPI_UNLESS_( HPI_OutStreamGetInfoEx( streamComp->hpiDevice->subSys, + streamComp->hpiStream, + &state, &bufferSize, &dataSize, &frameCounter, + &auxDataSize ), paUnanticipatedHostError ); + } + else + { + PA_ASIHPI_UNLESS_( HPI_InStreamGetInfoEx( streamComp->hpiDevice->subSys, + streamComp->hpiStream, + &state, &bufferSize, &dataSize, &frameCounter, + &auxDataSize ), paUnanticipatedHostError ); + } + /* Load stream info */ + info->state = state; + info->bufferSize = bufferSize; + info->dataSize = dataSize; + info->frameCounter = frameCounter; + info->auxDataSize = auxDataSize; + /* Determine total buffered data */ + info->totalBufferedData = dataSize; + if( streamComp->hostBufferSize > 0 ) + info->totalBufferedData += auxDataSize; + info->totalBufferedData /= streamComp->bytesPerFrame; + /* Determine immediately available frames */ + info->availableFrames = streamComp->hpiDevice->streamIsOutput ? + bufferSize - dataSize : dataSize; + info->availableFrames /= streamComp->bytesPerFrame; + /* Minimum space/data required in buffers */ + threshold = PA_MIN( streamComp->tempBufferSize, + streamComp->bytesPerFrame * PA_ASIHPI_MIN_FRAMES_ ); + /* Obtain hardware buffer stats first, to simplify things */ + hwBufferSize = streamComp->hardwareBufferSize; + hwDataSize = streamComp->hostBufferSize > 0 ? auxDataSize : dataSize; + /* Underflow is a bit tricky */ + info->underflow = streamComp->hpiDevice->streamIsOutput ? + /* Stream seems to start in drained state sometimes, so ignore initial underflow */ + (frameCounter > 0) && ( (state == HPI_STATE_DRAINED) || (hwDataSize == 0) ) : + /* Input streams check the first-level (host) buffer for underflow */ + (state != HPI_STATE_STOPPED) && (dataSize < threshold); + /* Check for overflow in second-level (hardware) buffer for both input and output */ + info->overflow = (state != HPI_STATE_STOPPED) && (hwBufferSize - hwDataSize < threshold); + + return paNoError; + } + +error: + return result; +} + + +/** Display stream component information for debugging purposes. + + @param streamComp Pointer to stream component (input or output) to query + + @param stream Pointer to stream struct which contains the component above + */ +static void PaAsiHpi_StreamComponentDump( PaAsiHpiStreamComponent *streamComp, + PaAsiHpiStream *stream ) +{ + PaAsiHpiStreamInfo streamInfo; + + assert( streamComp ); + assert( stream ); + + /* Name of soundcard/device used by component */ + PA_DEBUG(( "device: %s\n", streamComp->hpiDevice->baseDeviceInfo.name )); + /* Unfortunately some overlap between input and output here */ + if( streamComp->hpiDevice->streamIsOutput ) + { + /* Settings on the user side (as experienced by user callback) */ + PA_DEBUG(( "user: %d-bit, %d ", + 8*stream->bufferProcessor.bytesPerUserOutputSample, + stream->bufferProcessor.outputChannelCount)); + if( stream->bufferProcessor.userOutputIsInterleaved ) + { + PA_DEBUG(( "interleaved channels, " )); + } + else + { + PA_DEBUG(( "non-interleaved channels, " )); + } + PA_DEBUG(( "%d frames/buffer, latency = %5.1f ms\n", + stream->bufferProcessor.framesPerUserBuffer, + 1000*stream->baseStreamRep.streamInfo.outputLatency )); + /* Settings on the host side (internal to PortAudio host API) */ + PA_DEBUG(( "host: %d-bit, %d interleaved channels, %d frames/buffer ", + 8*stream->bufferProcessor.bytesPerHostOutputSample, + stream->bufferProcessor.outputChannelCount, + stream->bufferProcessor.framesPerHostBuffer )); + } + else + { + /* Settings on the user side (as experienced by user callback) */ + PA_DEBUG(( "user: %d-bit, %d ", + 8*stream->bufferProcessor.bytesPerUserInputSample, + stream->bufferProcessor.inputChannelCount)); + if( stream->bufferProcessor.userInputIsInterleaved ) + { + PA_DEBUG(( "interleaved channels, " )); + } + else + { + PA_DEBUG(( "non-interleaved channels, " )); + } + PA_DEBUG(( "%d frames/buffer, latency = %5.1f ms\n", + stream->bufferProcessor.framesPerUserBuffer, + 1000*stream->baseStreamRep.streamInfo.inputLatency )); + /* Settings on the host side (internal to PortAudio host API) */ + PA_DEBUG(( "host: %d-bit, %d interleaved channels, %d frames/buffer ", + 8*stream->bufferProcessor.bytesPerHostInputSample, + stream->bufferProcessor.inputChannelCount, + stream->bufferProcessor.framesPerHostBuffer )); + } + switch( stream->bufferProcessor.hostBufferSizeMode ) + { + case paUtilFixedHostBufferSize: + PA_DEBUG(( "[fixed] " )); + break; + case paUtilBoundedHostBufferSize: + PA_DEBUG(( "[bounded] " )); + break; + case paUtilUnknownHostBufferSize: + PA_DEBUG(( "[unknown] " )); + break; + case paUtilVariableHostBufferSizePartialUsageAllowed: + PA_DEBUG(( "[variable] " )); + break; + } + PA_DEBUG(( "(%d max)\n", streamComp->tempBufferSize / streamComp->bytesPerFrame )); + /* HPI hardware settings */ + PA_DEBUG(( "HPI: adapter %d stream %d, %d-bit, %d-channel, %d Hz\n", + streamComp->hpiDevice->adapterIndex, streamComp->hpiDevice->streamIndex, + 8 * streamComp->bytesPerFrame / streamComp->hpiFormat.wChannels, + streamComp->hpiFormat.wChannels, + streamComp->hpiFormat.dwSampleRate )); + /* Stream state and buffer levels */ + PA_DEBUG(( "HPI: " )); + PaAsiHpi_GetStreamInfo( streamComp, &streamInfo ); + switch( streamInfo.state ) + { + case HPI_STATE_STOPPED: + PA_DEBUG(( "[STOPPED] " )); + break; + case HPI_STATE_PLAYING: + PA_DEBUG(( "[PLAYING] " )); + break; + case HPI_STATE_RECORDING: + PA_DEBUG(( "[RECORDING] " )); + break; + case HPI_STATE_DRAINED: + PA_DEBUG(( "[DRAINED] " )); + break; + default: + PA_DEBUG(( "[unknown state] " )); + break; + } + if( streamComp->hostBufferSize ) + { + PA_DEBUG(( "host = %d/%d B, ", streamInfo.dataSize, streamComp->hostBufferSize )); + PA_DEBUG(( "hw = %d/%d (%d) B, ", streamInfo.auxDataSize, + streamComp->hardwareBufferSize, streamComp->outputBufferCap )); + } + else + { + PA_DEBUG(( "hw = %d/%d B, ", streamInfo.dataSize, streamComp->hardwareBufferSize )); + } + PA_DEBUG(( "count = %d", streamInfo.frameCounter )); + if( streamInfo.overflow ) + { + PA_DEBUG(( " [overflow]" )); + } + else if( streamInfo.underflow ) + { + PA_DEBUG(( " [underflow]" )); + } + PA_DEBUG(( "\n" )); +} + + +/** Display stream information for debugging purposes. + + @param stream Pointer to stream to query + */ +static void PaAsiHpi_StreamDump( PaAsiHpiStream *stream ) +{ + assert( stream ); + + PA_DEBUG(( "\n------------------------- STREAM INFO FOR %p ---------------------------\n", stream )); + /* General stream info (input+output) */ + if( stream->baseStreamRep.streamCallback ) + { + PA_DEBUG(( "[callback] " )); + } + else + { + PA_DEBUG(( "[blocking] " )); + } + PA_DEBUG(( "sr=%d Hz, poll=%d ms, max %d frames/buf ", + (int)stream->baseStreamRep.streamInfo.sampleRate, + stream->pollingInterval, stream->maxFramesPerHostBuffer )); + switch( stream->state ) + { + case paAsiHpiStoppedState: + PA_DEBUG(( "[stopped]\n" )); + break; + case paAsiHpiActiveState: + PA_DEBUG(( "[active]\n" )); + break; + case paAsiHpiCallbackFinishedState: + PA_DEBUG(( "[cb fin]\n" )); + break; + default: + PA_DEBUG(( "[unknown state]\n" )); + break; + } + if( stream->callbackMode ) + { + PA_DEBUG(( "cb info: thread=%p, cbAbort=%d, cbFinished=%d\n", + stream->thread.thread, stream->callbackAbort, stream->callbackFinished )); + } + + PA_DEBUG(( "----------------------------------- Input ------------------------------------\n" )); + if( stream->input ) + { + PaAsiHpi_StreamComponentDump( stream->input, stream ); + } + else + { + PA_DEBUG(( "*none*\n" )); + } + + PA_DEBUG(( "----------------------------------- Output ------------------------------------\n" )); + if( stream->output ) + { + PaAsiHpi_StreamComponentDump( stream->output, stream ); + } + else + { + PA_DEBUG(( "*none*\n" )); + } + PA_DEBUG(( "-------------------------------------------------------------------------------\n\n" )); + +} + + +/** Determine buffer sizes and allocate appropriate stream buffers. + This attempts to allocate a BBM (host) buffer for the HPI stream component (either input + or output, as both have similar buffer needs). Not all AudioScience adapters support BBM, + in which case the hardware buffer has to suffice. The size of the HPI host buffer is chosen + as a multiple of framesPerPaHostBuffer, and also influenced by the suggested latency and the + estimated minimum polling interval. The HPI host and hardware buffer sizes are stored, and an + appropriate cap for the hardware buffer is also calculated. Finally, the temporary stream + buffer which serves as the PortAudio host buffer for this implementation is allocated. + This buffer contains an integer number of user buffers, to simplify buffer adaption in the + buffer processor. The function returns paBufferTooBig if the HPI interface cannot allocate + an HPI host buffer of the desired size. + + @param streamComp Pointer to stream component struct + + @param pollingInterval Polling interval for stream, in milliseconds + + @param framesPerPaHostBuffer Size of PortAudio host buffer, in frames + + @param suggestedLatency Suggested latency for stream component, in seconds + + @return PortAudio error code (possibly paBufferTooBig or paInsufficientMemory) + */ +static PaError PaAsiHpi_SetupBuffers( PaAsiHpiStreamComponent *streamComp, HW32 pollingInterval, + unsigned long framesPerPaHostBuffer, PaTime suggestedLatency ) +{ + PaError result = paNoError; + PaAsiHpiStreamInfo streamInfo; + unsigned long hpiBufferSize = 0, paHostBufferSize = 0; + + assert( streamComp ); + assert( streamComp->hpiDevice ); + + /* Obtain size of hardware buffer of HPI stream, since we will be activating BBM shortly + and afterwards the buffer size will refer to the BBM (host-side) buffer. + This is necessary to enable reliable detection of xruns. */ + PA_ENSURE_( PaAsiHpi_GetStreamInfo( streamComp, &streamInfo ) ); + streamComp->hardwareBufferSize = streamInfo.bufferSize; + hpiBufferSize = streamInfo.bufferSize; + + /* Check if BBM (background bus mastering) is to be enabled */ + if( PA_ASIHPI_USE_BBM_ ) + { + HW32 bbmBufferSize = 0, preLatencyBufferSize = 0; + HW16 hpiError = 0; + PaTime pollingOverhead; + + /* Check overhead of Pa_Sleep() call (minimum sleep duration in ms -> OS dependent) */ + pollingOverhead = PaUtil_GetTime(); + Pa_Sleep( 0 ); + pollingOverhead = 1000*(PaUtil_GetTime() - pollingOverhead); + PA_DEBUG(( "polling overhead = %f ms (length of 0-second sleep)\n", pollingOverhead )); + /* Obtain minimum recommended size for host buffer (in bytes) */ + PA_ASIHPI_UNLESS_( HPI_StreamEstimateBufferSize( &streamComp->hpiFormat, + pollingInterval + (HW32)ceil( pollingOverhead ), + &bbmBufferSize ), paUnanticipatedHostError ); + /* BBM places more stringent requirements on buffer size (see description */ + /* of HPI_StreamEstimateBufferSize in HPI API document) */ + bbmBufferSize *= 3; + /* Make sure the BBM buffer contains multiple PA host buffers */ + if( bbmBufferSize < 3 * streamComp->bytesPerFrame * framesPerPaHostBuffer ) + bbmBufferSize = 3 * streamComp->bytesPerFrame * framesPerPaHostBuffer; + /* Try to honor latency suggested by user by growing buffer (no decrease possible) */ + if( suggestedLatency > 0.0 ) + { + PaTime bufferDuration = ((PaTime)bbmBufferSize) / streamComp->bytesPerFrame + / streamComp->hpiFormat.dwSampleRate; + /* Don't decrease buffer */ + if( bufferDuration < suggestedLatency ) + { + /* Save old buffer size, to be retried if new size proves too big */ + preLatencyBufferSize = bbmBufferSize; + bbmBufferSize = (HW32)ceil( suggestedLatency * streamComp->bytesPerFrame + * streamComp->hpiFormat.dwSampleRate ); + } + } + /* Choose closest memory block boundary (HPI API document states that + "a buffer size of Nx4096 - 20 makes the best use of memory" + (under the entry for HPI_StreamEstimateBufferSize)) */ + bbmBufferSize = ((HW32)ceil((bbmBufferSize + 20)/4096.0))*4096 - 20; + streamComp->hostBufferSize = bbmBufferSize; + /* Allocate BBM host buffer (this enables bus mastering transfers in background) */ + if( streamComp->hpiDevice->streamIsOutput ) + hpiError = HPI_OutStreamHostBufferAllocate( streamComp->hpiDevice->subSys, + streamComp->hpiStream, + bbmBufferSize ); + else + hpiError = HPI_InStreamHostBufferAllocate( streamComp->hpiDevice->subSys, + streamComp->hpiStream, + bbmBufferSize ); + if( hpiError ) + { + PA_ASIHPI_REPORT_ERROR_( hpiError ); + /* Indicate that BBM is disabled */ + streamComp->hostBufferSize = 0; + /* Retry with smaller buffer size (transfers will still work, but not via BBM) */ + if( hpiError == HPI_ERROR_INVALID_DATASIZE ) + { + /* Retry BBM allocation with smaller size if requested latency proved too big */ + if( preLatencyBufferSize > 0 ) + { + PA_DEBUG(( "Retrying BBM allocation with smaller size (%d vs. %d bytes)\n", + preLatencyBufferSize, bbmBufferSize )); + bbmBufferSize = preLatencyBufferSize; + if( streamComp->hpiDevice->streamIsOutput ) + hpiError = HPI_OutStreamHostBufferAllocate( streamComp->hpiDevice->subSys, + streamComp->hpiStream, + bbmBufferSize ); + else + hpiError = HPI_InStreamHostBufferAllocate( streamComp->hpiDevice->subSys, + streamComp->hpiStream, + bbmBufferSize ); + /* Another round of error checking */ + if( hpiError ) + { + PA_ASIHPI_REPORT_ERROR_( hpiError ); + /* No escapes this time */ + if( hpiError == HPI_ERROR_INVALID_DATASIZE ) + { + result = paBufferTooBig; + goto error; + } + else if( hpiError != HPI_ERROR_INVALID_OPERATION ) + { + result = paUnanticipatedHostError; + goto error; + } + } + else + { + streamComp->hostBufferSize = bbmBufferSize; + hpiBufferSize = bbmBufferSize; + } + } + else + { + result = paBufferTooBig; + goto error; + } + } + /* If BBM not supported, foreground transfers will be used, but not a show-stopper */ + /* Anything else is an error */ + else if( hpiError != HPI_ERROR_INVALID_OPERATION ) + { + result = paUnanticipatedHostError; + goto error; + } + } + else + { + hpiBufferSize = bbmBufferSize; + } + } + + /* Final check of buffer size */ + paHostBufferSize = streamComp->bytesPerFrame * framesPerPaHostBuffer; + if( hpiBufferSize < 3*paHostBufferSize ) + { + result = paBufferTooBig; + goto error; + } + /* Set cap on output buffer size, based on latency suggestions */ + if( streamComp->hpiDevice->streamIsOutput ) + { + PaTime latency = suggestedLatency > 0.0 ? suggestedLatency : + streamComp->hpiDevice->baseDeviceInfo.defaultHighOutputLatency; + streamComp->outputBufferCap = + (HW32)ceil( latency * streamComp->bytesPerFrame * streamComp->hpiFormat.dwSampleRate ); + /* The cap should not be too small, to prevent underflow */ + if( streamComp->outputBufferCap < 4*paHostBufferSize ) + streamComp->outputBufferCap = 4*paHostBufferSize; + } + else + { + streamComp->outputBufferCap = 0; + } + /* Temp buffer size should be multiple of PA host buffer size (or 1x, if using fixed blocks) */ + streamComp->tempBufferSize = paHostBufferSize; + /* Allocate temp buffer */ + PA_UNLESS_( streamComp->tempBuffer = (HW8 *)PaUtil_AllocateMemory( streamComp->tempBufferSize ), + paInsufficientMemory ); +error: + return result; +} + + +/** Opens PortAudio stream. + This determines a suitable value for framesPerBuffer, if the user didn't specify it, + based on the suggested latency. It then opens each requested stream direction with the + appropriate stream format, and allocates the required stream buffers. It sets up the + various PortAudio structures dealing with streams, and estimates the stream latency. + + See pa_hostapi.h for a list of validity guarantees made about OpenStream parameters. + + @param hostApi Pointer to host API struct + + @param s List of open streams, where successfully opened stream will go + + @param inputParameters Pointer to stream parameter struct for input side of stream + + @param outputParameters Pointer to stream parameter struct for output side of stream + + @param sampleRate Desired sample rate + + @param framesPerBuffer Desired number of frames per buffer passed to user callback + (or chunk size for blocking stream) + + @param streamFlags Stream flags + + @param streamCallback Pointer to user callback function (zero for blocking interface) + + @param userData Pointer to user data that will be passed to callback function along with data + + @return PortAudio error code +*/ +static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, + PaStream **s, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate, + unsigned long framesPerBuffer, + PaStreamFlags streamFlags, + PaStreamCallback *streamCallback, + void *userData ) +{ + PaError result = paNoError; + PaAsiHpiHostApiRepresentation *hpiHostApi = (PaAsiHpiHostApiRepresentation*)hostApi; + PaAsiHpiStream *stream = NULL; + unsigned long framesPerHostBuffer = framesPerBuffer; + int inputChannelCount = 0, outputChannelCount = 0; + PaSampleFormat inputSampleFormat = 0, outputSampleFormat = 0; + PaSampleFormat hostInputSampleFormat = 0, hostOutputSampleFormat = 0; + PaTime maxSuggestedLatency = 0.0; + + /* Validate platform-specific flags -> none expected for HPI */ + if( (streamFlags & paPlatformSpecificFlags) != 0 ) + return paInvalidFlag; /* unexpected platform-specific flag */ + + /* Create blank stream structure */ + PA_UNLESS_( stream = (PaAsiHpiStream *)PaUtil_AllocateMemory( sizeof(PaAsiHpiStream) ), + paInsufficientMemory ); + memset( stream, 0, sizeof(PaAsiHpiStream) ); + + /* If the number of frames per buffer is unspecified, we have to come up with one. */ + if( framesPerHostBuffer == paFramesPerBufferUnspecified ) + { + if( inputParameters ) + maxSuggestedLatency = inputParameters->suggestedLatency; + if( outputParameters && (outputParameters->suggestedLatency > maxSuggestedLatency) ) + maxSuggestedLatency = outputParameters->suggestedLatency; + /* Use suggested latency if available */ + if( maxSuggestedLatency > 0.0 ) + framesPerHostBuffer = (unsigned long)ceil( maxSuggestedLatency * sampleRate ); + else + /* AudioScience cards like BIG buffers by default */ + framesPerHostBuffer = 4096; + } + /* Lower bounds on host buffer size, due to polling and HPI constraints */ + if( 1000.0*framesPerHostBuffer/sampleRate < PA_ASIHPI_MIN_POLLING_INTERVAL_ ) + framesPerHostBuffer = (unsigned long)ceil( sampleRate * PA_ASIHPI_MIN_POLLING_INTERVAL_ / 1000.0 ); + /* if( framesPerHostBuffer < PA_ASIHPI_MIN_FRAMES_ ) + framesPerHostBuffer = PA_ASIHPI_MIN_FRAMES_; */ + /* Efficient if host buffer size is integer multiple of user buffer size */ + if( framesPerBuffer > 0 ) + framesPerHostBuffer = (unsigned long)ceil( (double)framesPerHostBuffer / framesPerBuffer ) * framesPerBuffer; + /* Buffer should always be a multiple of 4 bytes to facilitate 32-bit PCI transfers. + By keeping the frames a multiple of 4, this is ensured even for 8-bit mono sound. */ + framesPerHostBuffer = (framesPerHostBuffer / 4) * 4; + /* Polling is based on time length (in milliseconds) of user-requested block size */ + stream->pollingInterval = (HW32)ceil( 1000.0*framesPerHostBuffer/sampleRate ); + assert( framesPerHostBuffer > 0 ); + + /* Open underlying streams, check formats and allocate buffers */ + if( inputParameters ) + { + /* Create blank stream component structure */ + PA_UNLESS_( stream->input = (PaAsiHpiStreamComponent *)PaUtil_AllocateMemory( sizeof(PaAsiHpiStreamComponent) ), + paInsufficientMemory ); + memset( stream->input, 0, sizeof(PaAsiHpiStreamComponent) ); + /* Create/validate format */ + PA_ENSURE_( PaAsiHpi_CreateFormat( hostApi, inputParameters, sampleRate, + &stream->input->hpiDevice, &stream->input->hpiFormat ) ); + /* Open stream and set format */ + PA_ENSURE_( PaAsiHpi_OpenInput( hostApi, stream->input->hpiDevice, &stream->input->hpiFormat, + &stream->input->hpiStream ) ); + inputChannelCount = inputParameters->channelCount; + inputSampleFormat = inputParameters->sampleFormat; + hostInputSampleFormat = PaAsiHpi_HpiToPaFormat( stream->input->hpiFormat.wFormat ); + stream->input->bytesPerFrame = inputChannelCount * Pa_GetSampleSize( hostInputSampleFormat ); + assert( stream->input->bytesPerFrame > 0 ); + /* Allocate host and temp buffers of appropriate size */ + PA_ENSURE_( PaAsiHpi_SetupBuffers( stream->input, stream->pollingInterval, + framesPerHostBuffer, inputParameters->suggestedLatency ) ); + } + if( outputParameters ) + { + /* Create blank stream component structure */ + PA_UNLESS_( stream->output = (PaAsiHpiStreamComponent *)PaUtil_AllocateMemory( sizeof(PaAsiHpiStreamComponent) ), + paInsufficientMemory ); + memset( stream->output, 0, sizeof(PaAsiHpiStreamComponent) ); + /* Create/validate format */ + PA_ENSURE_( PaAsiHpi_CreateFormat( hostApi, outputParameters, sampleRate, + &stream->output->hpiDevice, &stream->output->hpiFormat ) ); + /* Open stream and check format */ + PA_ENSURE_( PaAsiHpi_OpenOutput( hostApi, stream->output->hpiDevice, + &stream->output->hpiFormat, + &stream->output->hpiStream ) ); + outputChannelCount = outputParameters->channelCount; + outputSampleFormat = outputParameters->sampleFormat; + hostOutputSampleFormat = PaAsiHpi_HpiToPaFormat( stream->output->hpiFormat.wFormat ); + stream->output->bytesPerFrame = outputChannelCount * Pa_GetSampleSize( hostOutputSampleFormat ); + /* Allocate host and temp buffers of appropriate size */ + PA_ENSURE_( PaAsiHpi_SetupBuffers( stream->output, stream->pollingInterval, + framesPerHostBuffer, outputParameters->suggestedLatency ) ); + } + + /* Determine maximum frames per host buffer (least common denominator of input/output) */ + if( inputParameters && outputParameters ) + { + stream->maxFramesPerHostBuffer = PA_MIN( stream->input->tempBufferSize / stream->input->bytesPerFrame, + stream->output->tempBufferSize / stream->output->bytesPerFrame ); + } + else + { + stream->maxFramesPerHostBuffer = inputParameters ? stream->input->tempBufferSize / stream->input->bytesPerFrame + : stream->output->tempBufferSize / stream->output->bytesPerFrame; + } + assert( stream->maxFramesPerHostBuffer > 0 ); + /* Initialize various other stream parameters */ + stream->neverDropInput = streamFlags & paNeverDropInput; + stream->state = paAsiHpiStoppedState; + + /* Initialize either callback or blocking interface */ + if( streamCallback ) + { + PaUtil_InitializeStreamRepresentation( &stream->baseStreamRep, + &hpiHostApi->callbackStreamInterface, + streamCallback, userData ); + stream->callbackMode = 1; + } + else + { + PaUtil_InitializeStreamRepresentation( &stream->baseStreamRep, + &hpiHostApi->blockingStreamInterface, + streamCallback, userData ); + /* Pre-allocate non-interleaved user buffer pointers for blocking interface */ + PA_UNLESS_( stream->blockingUserBufferCopy = + PaUtil_AllocateMemory( sizeof(void *) * PA_MAX( inputChannelCount, outputChannelCount ) ), + paInsufficientMemory ); + stream->callbackMode = 0; + } + PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate ); + + /* Following pa_linux_alsa's lead, we operate with fixed host buffer size by default, */ + /* since other modes will invariably lead to block adaption (maybe Bounded better?) */ + PA_ENSURE_( PaUtil_InitializeBufferProcessor( &stream->bufferProcessor, + inputChannelCount, inputSampleFormat, hostInputSampleFormat, + outputChannelCount, outputSampleFormat, hostOutputSampleFormat, + sampleRate, streamFlags, + framesPerBuffer, framesPerHostBuffer, paUtilFixedHostBufferSize, + streamCallback, userData ) ); + + stream->baseStreamRep.streamInfo.structVersion = 1; + stream->baseStreamRep.streamInfo.sampleRate = sampleRate; + /* Determine input latency from buffer processor and buffer sizes */ + if( stream->input ) + { + PaTime bufferDuration = ( stream->input->hostBufferSize + stream->input->hardwareBufferSize ) + / sampleRate / stream->input->bytesPerFrame; + stream->baseStreamRep.streamInfo.inputLatency = + PaUtil_GetBufferProcessorInputLatency( &stream->bufferProcessor ) + + bufferDuration - stream->maxFramesPerHostBuffer / sampleRate; + assert( stream->baseStreamRep.streamInfo.inputLatency > 0.0 ); + } + /* Determine output latency from buffer processor and buffer sizes */ + if( stream->output ) + { + PaTime bufferDuration = ( stream->output->hostBufferSize + stream->output->hardwareBufferSize ) + / sampleRate / stream->output->bytesPerFrame; + /* Take buffer size cap into account (see PaAsiHpi_WaitForFrames) */ + if( !stream->input && (stream->output->outputBufferCap > 0) ) + { + bufferDuration = PA_MIN( bufferDuration, + stream->output->outputBufferCap / sampleRate / stream->output->bytesPerFrame ); + } + stream->baseStreamRep.streamInfo.outputLatency = + PaUtil_GetBufferProcessorOutputLatency( &stream->bufferProcessor ) + + bufferDuration - stream->maxFramesPerHostBuffer / sampleRate; + assert( stream->baseStreamRep.streamInfo.outputLatency > 0.0 ); + } + + /* Report stream info, for debugging purposes */ + PaAsiHpi_StreamDump( stream ); + + /* Save initialized stream to PA stream list */ + *s = (PaStream*)stream; + return result; + +error: + CloseStream( (PaStream*)stream ); + return result; +} + + +/** Close PortAudio stream. + When CloseStream() is called, the multi-api layer ensures that the stream has already + been stopped or aborted. This closes the underlying HPI streams and deallocates stream + buffers and structs. + + @param s Pointer to PortAudio stream + + @return PortAudio error code +*/ +static PaError CloseStream( PaStream *s ) +{ + PaError result = paNoError; + PaAsiHpiStream *stream = (PaAsiHpiStream*)s; + + /* If stream is already gone, all is well */ + if( stream == NULL ) + return paNoError; + + /* Generic stream cleanup */ + PaUtil_TerminateBufferProcessor( &stream->bufferProcessor ); + PaUtil_TerminateStreamRepresentation( &stream->baseStreamRep ); + + /* Implementation-specific details - close internal streams */ + if( stream->input ) + { + /* Close HPI stream (freeing BBM host buffer in the process, if used) */ + if( stream->input->hpiStream ) + { + PA_ASIHPI_UNLESS_( HPI_InStreamClose( stream->input->hpiDevice->subSys, + stream->input->hpiStream ), paUnanticipatedHostError ); + } + /* Free temp buffer and stream component */ + PaUtil_FreeMemory( stream->input->tempBuffer ); + PaUtil_FreeMemory( stream->input ); + } + if( stream->output ) + { + /* Close HPI stream (freeing BBM host buffer in the process, if used) */ + if( stream->output->hpiStream ) + { + PA_ASIHPI_UNLESS_( HPI_OutStreamClose( stream->output->hpiDevice->subSys, + stream->output->hpiStream ), paUnanticipatedHostError ); + } + /* Free temp buffer and stream component */ + PaUtil_FreeMemory( stream->output->tempBuffer ); + PaUtil_FreeMemory( stream->output ); + } + + PaUtil_FreeMemory( stream->blockingUserBufferCopy ); + PaUtil_FreeMemory( stream ); + +error: + return result; +} + + +/** Prime HPI output stream with silence. + This resets the output stream and uses PortAudio helper routines to fill the + temp buffer with silence. It then writes two host buffers to the stream. This is supposed + to be called before the stream is started. It has no effect on input-only streams. + + @param stream Pointer to stream struct + + @return PortAudio error code + */ +static PaError PaAsiHpi_PrimeOutputWithSilence( PaAsiHpiStream *stream ) +{ + PaError result = paNoError; + PaAsiHpiStreamComponent *out; + PaUtilZeroer *zeroer; + PaSampleFormat outputFormat; +#if (HPI_VER < HPI_VERSION_CONSTRUCTOR( 3, 5, 5 )) + HPI_DATA data; +#endif + assert( stream ); + out = stream->output; + /* Only continue if stream has output channels */ + if( !out ) + return result; + assert( out->tempBuffer ); + + /* Clear all existing data in hardware playback buffer */ + PA_ASIHPI_UNLESS_( HPI_OutStreamReset( out->hpiDevice->subSys, + out->hpiStream ), paUnanticipatedHostError ); + /* Fill temp buffer with silence */ + outputFormat = PaAsiHpi_HpiToPaFormat( out->hpiFormat.wFormat ); + zeroer = PaUtil_SelectZeroer( outputFormat ); + zeroer(out->tempBuffer, 1, out->tempBufferSize / Pa_GetSampleSize(outputFormat) ); + /* Write temp buffer to hardware fifo twice, to get started */ +#if (HPI_VER >= HPI_VERSION_CONSTRUCTOR( 3, 5, 5 )) + PA_ASIHPI_UNLESS_( HPI_OutStreamWriteBuf( out->hpiDevice->subSys, out->hpiStream, + out->tempBuffer, out->tempBufferSize, &out->hpiFormat), + paUnanticipatedHostError ); + PA_ASIHPI_UNLESS_( HPI_OutStreamWriteBuf( out->hpiDevice->subSys, out->hpiStream, + out->tempBuffer, out->tempBufferSize, &out->hpiFormat), + paUnanticipatedHostError ); +#else + PA_ASIHPI_UNLESS_( HPI_DataCreate( &data, &out->hpiFormat, out->tempBuffer, out->tempBufferSize ), + paUnanticipatedHostError ); + PA_ASIHPI_UNLESS_( HPI_OutStreamWrite( out->hpiDevice->subSys, + out->hpiStream, &data ), paUnanticipatedHostError ); + PA_ASIHPI_UNLESS_( HPI_OutStreamWrite( out->hpiDevice->subSys, + out->hpiStream, &data ), paUnanticipatedHostError ); +#endif +error: + return result; +} + + +/** Start HPI streams (both input + output). + This starts all HPI streams in the PortAudio stream. Output streams are first primed with + silence, if required. After this call the PA stream is in the Active state. + + @todo Implement priming via the user callback + + @param stream Pointer to stream struct + + @param outputPrimed True if output is already primed (if false, silence will be loaded before starting) + + @return PortAudio error code + */ +static PaError PaAsiHpi_StartStream( PaAsiHpiStream *stream, int outputPrimed ) +{ + PaError result = paNoError; + + if( stream->input ) + { + PA_ASIHPI_UNLESS_( HPI_InStreamStart( stream->input->hpiDevice->subSys, + stream->input->hpiStream ), paUnanticipatedHostError ); + } + if( stream->output ) + { + if( !outputPrimed ) + { + /* Buffer isn't primed, so load stream with silence */ + PA_ENSURE_( PaAsiHpi_PrimeOutputWithSilence( stream ) ); + } + PA_ASIHPI_UNLESS_( HPI_OutStreamStart( stream->output->hpiDevice->subSys, + stream->output->hpiStream ), paUnanticipatedHostError ); + } + stream->state = paAsiHpiActiveState; + stream->callbackFinished = 0; + + /* Report stream info for debugging purposes */ + /* PaAsiHpi_StreamDump( stream ); */ + +error: + return result; +} + + +/** Start PortAudio stream. + If the stream has a callback interface, this starts a helper thread to feed the user callback. + The thread will then take care of starting the HPI streams, and this function will block + until the streams actually start. In the case of a blocking interface, the HPI streams + are simply started. + + @param s Pointer to PortAudio stream + + @return PortAudio error code +*/ +static PaError StartStream( PaStream *s ) +{ + PaError result = paNoError; + PaAsiHpiStream *stream = (PaAsiHpiStream*)s; + + assert( stream ); + + /* Ready the processor */ + PaUtil_ResetBufferProcessor( &stream->bufferProcessor ); + + if( stream->callbackMode ) + { + /* Create and start callback engine thread */ + /* Also waits 1 second for stream to be started by engine thread (otherwise aborts) */ + PA_ENSURE_( PaUnixThread_New( &stream->thread, &CallbackThreadFunc, stream, 1., 0 /*rtSched*/ ) ); + } + else + { + PA_ENSURE_( PaAsiHpi_StartStream( stream, 0 ) ); + } + +error: + return result; +} + + +/** Stop HPI streams (input + output), either softly or abruptly. + If abort is false, the function blocks until the output stream is drained, otherwise it + stops immediately and discards data in the stream hardware buffers. + + This function is safe to call from the callback engine thread as well as the main thread. + + @param stream Pointer to stream struct + + @param abort True if samples in output buffer should be discarded (otherwise blocks until stream is done) + + @return PortAudio error code + + */ +static PaError PaAsiHpi_StopStream( PaAsiHpiStream *stream, int abort ) +{ + PaError result = paNoError; + + assert( stream ); + + /* Input channels */ + if( stream->input ) + { + PA_ASIHPI_UNLESS_( HPI_InStreamReset( stream->input->hpiDevice->subSys, + stream->input->hpiStream ), paUnanticipatedHostError ); + } + /* Output channels */ + if( stream->output ) + { + if( !abort ) + { + /* Wait until HPI output stream is drained */ + while( 1 ) + { + PaAsiHpiStreamInfo streamInfo; + PaTime timeLeft; + + /* Obtain number of samples waiting to be played */ + PA_ENSURE_( PaAsiHpi_GetStreamInfo( stream->output, &streamInfo ) ); + /* Check if stream is drained */ + if( (streamInfo.state != HPI_STATE_PLAYING) && + (streamInfo.dataSize < stream->output->bytesPerFrame * PA_ASIHPI_MIN_FRAMES_) ) + break; + /* Sleep amount of time represented by remaining samples */ + timeLeft = 1000.0 * streamInfo.dataSize / stream->output->bytesPerFrame + / stream->baseStreamRep.streamInfo.sampleRate; + Pa_Sleep( (long)ceil( timeLeft ) ); + } + } + PA_ASIHPI_UNLESS_( HPI_OutStreamReset( stream->output->hpiDevice->subSys, + stream->output->hpiStream ), paUnanticipatedHostError ); + } + + /* Report stream info for debugging purposes */ + /* PaAsiHpi_StreamDump( stream ); */ + +error: + return result; +} + + +/** Stop or abort PortAudio stream. + + This function is used to explicitly stop the PortAudio stream (via StopStream/AbortStream), + as opposed to the situation when the callback finishes with a result other than paContinue. + If a stream is in callback mode we will have to inspect whether the background thread has + finished, or we will have to take it out. In either case we join the thread before returning. + In blocking mode, we simply tell HPI to stop abruptly (abort) or finish buffers (drain). + The PortAudio stream will be in the Stopped state after a call to this function. + + Don't call this from the callback engine thread! + + @param stream Pointer to stream struct + + @param abort True if samples in output buffer should be discarded (otherwise blocks until stream is done) + + @return PortAudio error code +*/ +static PaError PaAsiHpi_ExplicitStop( PaAsiHpiStream *stream, int abort ) +{ + PaError result = paNoError; + + /* First deal with the callback thread, cancelling and/or joining it if necessary */ + if( stream->callbackMode ) + { + PaError threadRes; + stream->callbackAbort = abort; + if( abort ) + { + PA_DEBUG(( "Aborting callback\n" )); + } + else + { + PA_DEBUG(( "Stopping callback\n" )); + } + PA_ENSURE_( PaUnixThread_Terminate( &stream->thread, !abort, &threadRes ) ); + if( threadRes != paNoError ) + { + PA_DEBUG(( "Callback thread returned: %d\n", threadRes )); + } + } + else + { + PA_ENSURE_( PaAsiHpi_StopStream( stream, abort ) ); + } + + stream->state = paAsiHpiStoppedState; + +error: + return result; +} + + +/** Stop PortAudio stream. + This blocks until the output buffers are drained. + + @param s Pointer to PortAudio stream + + @return PortAudio error code +*/ +static PaError StopStream( PaStream *s ) +{ + return PaAsiHpi_ExplicitStop( (PaAsiHpiStream *) s, 0 ); +} + + +/** Abort PortAudio stream. + This discards any existing data in output buffers and stops the stream immediately. + + @param s Pointer to PortAudio stream + + @return PortAudio error code +*/ +static PaError AbortStream( PaStream *s ) +{ + return PaAsiHpi_ExplicitStop( (PaAsiHpiStream * ) s, 1 ); +} + + +/** Determine whether the stream is stopped. + A stream is considered to be stopped prior to a successful call to StartStream and after + a successful call to StopStream or AbortStream. If a stream callback returns a value other + than paContinue the stream is NOT considered to be stopped (it is in CallbackFinished state). + + @param s Pointer to PortAudio stream + + @return Returns one (1) when the stream is stopped, zero (0) when the stream is running, or + a PaErrorCode (which are always negative) if PortAudio is not initialized or an + error is encountered. +*/ +static PaError IsStreamStopped( PaStream *s ) +{ + PaAsiHpiStream *stream = (PaAsiHpiStream*)s; + + assert( stream ); + return stream->state == paAsiHpiStoppedState ? 1 : 0; +} + + +/** Determine whether the stream is active. + A stream is active after a successful call to StartStream(), until it becomes inactive either + as a result of a call to StopStream() or AbortStream(), or as a result of a return value + other than paContinue from the stream callback. In the latter case, the stream is considered + inactive after the last buffer has finished playing. + + @param s Pointer to PortAudio stream + + @return Returns one (1) when the stream is active (i.e. playing or recording audio), + zero (0) when not playing, or a PaErrorCode (which are always negative) + if PortAudio is not initialized or an error is encountered. +*/ +static PaError IsStreamActive( PaStream *s ) +{ + PaAsiHpiStream *stream = (PaAsiHpiStream*)s; + + assert( stream ); + return stream->state == paAsiHpiActiveState ? 1 : 0; +} + + +/** Returns current stream time. + This corresponds to the system clock. The clock should run continuously while the stream + is open, i.e. between calls to OpenStream() and CloseStream(), therefore a frame counter + is not good enough. + + @param s Pointer to PortAudio stream + + @return Stream time, in seconds + */ +static PaTime GetStreamTime( PaStream *s ) +{ + return PaUtil_GetTime(); +} + + +/** Returns CPU load. + + @param s Pointer to PortAudio stream + + @return CPU load (0.0 if blocking interface is used) + */ +static double GetStreamCpuLoad( PaStream *s ) +{ + PaAsiHpiStream *stream = (PaAsiHpiStream*)s; + + return stream->callbackMode ? PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer ) : 0.0; +} + +/* --------------------------- Callback Interface --------------------------- */ + +/** Exit routine which is called when callback thread quits. + This takes care of stopping the HPI streams (either waiting for output to finish, or + abruptly). It also calls the user-supplied StreamFinished callback, and sets the + stream state to CallbackFinished if it was reached via a non-paContinue return from + the user callback function. + + @param userData A pointer to an open stream previously created with Pa_OpenStream + */ +static void PaAsiHpi_OnThreadExit( void *userData ) +{ + PaAsiHpiStream *stream = (PaAsiHpiStream *) userData; + + assert( stream ); + + PaUtil_ResetCpuLoadMeasurer( &stream->cpuLoadMeasurer ); + + PA_DEBUG(( "%s: Stopping HPI streams\n", __FUNCTION__ )); + PaAsiHpi_StopStream( stream, stream->callbackAbort ); + PA_DEBUG(( "%s: Stoppage\n", __FUNCTION__ )); + + /* Eventually notify user all buffers have played */ + if( stream->baseStreamRep.streamFinishedCallback ) + { + stream->baseStreamRep.streamFinishedCallback( stream->baseStreamRep.userData ); + } + + /* Unfortunately both explicit calls to Stop/AbortStream (leading to Stopped state) + and implicit stops via paComplete/paAbort (leading to CallbackFinished state) + end up here - need another flag to remind us which is the case */ + if( stream->callbackFinished ) + stream->state = paAsiHpiCallbackFinishedState; +} + + +/** Wait until there is enough frames to fill a host buffer. + The routine attempts to sleep until at least a full host buffer can be retrieved from the + input HPI stream and passed to the output HPI stream. It will first sleep until enough + output space is available, as this is usually easily achievable. If it is an output-only + stream, it will also sleep if the hardware buffer is too full, thereby throttling the + filling of the output buffer and reducing output latency. The routine then blocks until + enough input samples are available, unless this will cause an output underflow. In the + process, input overflows and output underflows are indicated. + + @param stream Pointer to stream struct + + @param framesAvail Returns the number of available frames + + @param cbFlags Overflows and underflows indicated in here + + @return PortAudio error code (only paUnanticipatedHostError expected) + */ +static PaError PaAsiHpi_WaitForFrames( PaAsiHpiStream *stream, unsigned long *framesAvail, + PaStreamCallbackFlags *cbFlags ) +{ + PaError result = paNoError; + double sampleRate; + unsigned long framesTarget; + HW32 outputData = 0, outputSpace = 0, inputData = 0, framesLeft = 0; + + assert( stream ); + assert( stream->input || stream->output ); + + sampleRate = stream->baseStreamRep.streamInfo.sampleRate; + /* We have to come up with this much frames on both input and output */ + framesTarget = stream->bufferProcessor.framesPerHostBuffer; + assert( framesTarget > 0 ); + + while( 1 ) + { + PaAsiHpiStreamInfo info; + /* Check output first, as this takes priority in the default full-duplex mode */ + if( stream->output ) + { + PA_ENSURE_( PaAsiHpi_GetStreamInfo( stream->output, &info ) ); + /* Wait until enough space is available in output buffer to receive a full block */ + if( info.availableFrames < framesTarget ) + { + framesLeft = framesTarget - info.availableFrames; + Pa_Sleep( (long)ceil( 1000 * framesLeft / sampleRate ) ); + continue; + } + /* Wait until the data in hardware buffer has dropped to a sensible level. + Without this, the hardware buffer quickly fills up in the absence of an input + stream to regulate its data rate (if data generation is fast). This leads to + large latencies, as the AudioScience hardware buffers are humongous. + This is similar to the default "Hardware Buffering=off" option in the + AudioScience WAV driver. */ + if( !stream->input && (stream->output->outputBufferCap > 0) && + ( info.totalBufferedData > stream->output->outputBufferCap / stream->output->bytesPerFrame ) ) + { + framesLeft = info.totalBufferedData - stream->output->outputBufferCap / stream->output->bytesPerFrame; + Pa_Sleep( (long)ceil( 1000 * framesLeft / sampleRate ) ); + continue; + } + outputData = info.totalBufferedData; + outputSpace = info.availableFrames; + /* Report output underflow to callback */ + if( info.underflow ) + { + *cbFlags |= paOutputUnderflow; + } + } + + /* Now check input side */ + if( stream->input ) + { + PA_ENSURE_( PaAsiHpi_GetStreamInfo( stream->input, &info ) ); + /* If a full block of samples hasn't been recorded yet, wait for it if possible */ + if( info.availableFrames < framesTarget ) + { + framesLeft = framesTarget - info.availableFrames; + /* As long as output is not disrupted in the process, wait for a full + block of input samples */ + if( !stream->output || (outputData > framesLeft) ) + { + Pa_Sleep( (long)ceil( 1000 * framesLeft / sampleRate ) ); + continue; + } + } + inputData = info.availableFrames; + /** @todo The paInputOverflow flag should be set in the callback containing the + first input sample following the overflow. That means the block currently sitting + at the fore-front of recording, i.e. typically the one containing the newest (last) + sample in the HPI buffer system. This is most likely not the same as the current + block of data being passed to the callback. The current overflow should ideally + be noted in an overflow list of sorts, with an indication of when it should be + reported. The trouble starts if there are several separate overflow incidents, + given a big input buffer. Oh well, something to try out later... */ + if( info.overflow ) + { + *cbFlags |= paInputOverflow; + } + } + break; + } + /* Full-duplex stream */ + if( stream->input && stream->output ) + { + if( outputSpace >= framesTarget ) + *framesAvail = outputSpace; + /* If input didn't make the target, keep the output count instead (input underflow) */ + if( (inputData >= framesTarget) && (inputData < outputSpace) ) + *framesAvail = inputData; + } + else + { + *framesAvail = stream->input ? inputData : outputSpace; + } + +error: + return result; +} + + +/** Obtain recording, current and playback timestamps of stream. + The current time is determined by the system clock. This "now" timestamp occurs at the + forefront of recording (and playback in the full-duplex case), which happens later than the + input timestamp by an amount equal to the total number of recorded frames in the input buffer. + The output timestamp indicates when the next generated sample will actually be played. This + happens after all the samples currently in the output buffer are played. The output timestamp + therefore follows the current timestamp by an amount equal to the number of frames yet to be + played back in the output buffer. + + If the current timestamp is the present, the input timestamp is in the past and the output + timestamp is in the future. + + @param stream Pointer to stream struct + + @param timeInfo Pointer to timeInfo struct that will contain timestamps + */ +static void PaAsiHpi_CalculateTimeInfo( PaAsiHpiStream *stream, PaStreamCallbackTimeInfo *timeInfo ) +{ + PaAsiHpiStreamInfo streamInfo; + double sampleRate; + + assert( stream ); + assert( timeInfo ); + sampleRate = stream->baseStreamRep.streamInfo.sampleRate; + + /* The current time ("now") is at the forefront of both recording and playback */ + timeInfo->currentTime = GetStreamTime( (PaStream *)stream ); + /* The last sample in the input buffer was recorded just now, so the first sample + happened (number of recorded samples)/sampleRate ago */ + timeInfo->inputBufferAdcTime = timeInfo->currentTime; + if( stream->input ) + { + PaAsiHpi_GetStreamInfo( stream->input, &streamInfo ); + timeInfo->inputBufferAdcTime -= streamInfo.totalBufferedData / sampleRate; + } + /* The first of the outgoing samples will be played after all the samples in the output + buffer is done */ + timeInfo->outputBufferDacTime = timeInfo->currentTime; + if( stream->output ) + { + PaAsiHpi_GetStreamInfo( stream->output, &streamInfo ); + timeInfo->outputBufferDacTime += streamInfo.totalBufferedData / sampleRate; + } +} + + +/** Read from HPI input stream and register buffers. + This reads data from the HPI input stream (if it exists) and registers the temp stream + buffers of both input and output streams with the buffer processor. In the process it also + handles input underflows in the full-duplex case. + + @param stream Pointer to stream struct + + @param numFrames On entrance the number of available frames, on exit the number of + received frames + + @param cbFlags Indicates overflows and underflows + + @return PortAudio error code + */ +static PaError PaAsiHpi_BeginProcessing( PaAsiHpiStream *stream, unsigned long *numFrames, + PaStreamCallbackFlags *cbFlags ) +{ + PaError result = paNoError; + + assert( stream ); + if( *numFrames > stream->maxFramesPerHostBuffer ) + *numFrames = stream->maxFramesPerHostBuffer; + + if( stream->input ) + { + PaAsiHpiStreamInfo info; + +#if (HPI_VER < HPI_VERSION_CONSTRUCTOR( 3, 5, 5 )) + HPI_DATA data; +#endif + HW32 framesToGet = *numFrames; + + /* Check for overflows and underflows yet again */ + PA_ENSURE_( PaAsiHpi_GetStreamInfo( stream->input, &info ) ); + if( info.overflow ) + { + *cbFlags |= paInputOverflow; + } + /* Input underflow if less than expected number of samples pitch up */ + if( framesToGet > info.availableFrames ) + { + PaUtilZeroer *zeroer; + PaSampleFormat inputFormat; + + /* Never call an input-only stream with InputUnderflow set */ + if( stream->output ) + *cbFlags |= paInputUnderflow; + framesToGet = info.availableFrames; + /* Fill temp buffer with silence (to make up for missing input samples) */ + inputFormat = PaAsiHpi_HpiToPaFormat( stream->input->hpiFormat.wFormat ); + zeroer = PaUtil_SelectZeroer( inputFormat ); + zeroer(stream->input->tempBuffer, 1, + stream->input->tempBufferSize / Pa_GetSampleSize(inputFormat) ); + } + +#if (HPI_VER >= HPI_VERSION_CONSTRUCTOR( 3, 5, 5 )) + /* Read block of data into temp buffer */ + PA_ASIHPI_UNLESS_( HPI_InStreamReadBuf( stream->input->hpiDevice->subSys, + stream->input->hpiStream, + stream->input->tempBuffer, + framesToGet * stream->input->bytesPerFrame), + paUnanticipatedHostError ); +#else + /* Setup HPI data structure around temp buffer */ + HPI_DataCreate( &data, &stream->input->hpiFormat, stream->input->tempBuffer, + framesToGet * stream->input->bytesPerFrame ); + /* Read block of data into temp buffer */ + PA_ASIHPI_UNLESS_( HPI_InStreamRead( stream->input->hpiDevice->subSys, + stream->input->hpiStream, &data ), + paUnanticipatedHostError ); +#endif + /* Register temp buffer with buffer processor (always FULL buffer) */ + PaUtil_SetInputFrameCount( &stream->bufferProcessor, *numFrames ); + /* HPI interface only allows interleaved channels */ + PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, + 0, stream->input->tempBuffer, + stream->input->hpiFormat.wChannels ); + } + if( stream->output ) + { + /* Register temp buffer with buffer processor */ + PaUtil_SetOutputFrameCount( &stream->bufferProcessor, *numFrames ); + /* HPI interface only allows interleaved channels */ + PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, + 0, stream->output->tempBuffer, + stream->output->hpiFormat.wChannels ); + } + +error: + return result; +} + + +/** Flush output buffers to HPI output stream. + This completes the processing cycle by writing the temp buffer to the HPI interface. + Additional output underflows are caught before data is written to the stream, as this + action typically remedies the underflow and hides it in the process. + + @param stream Pointer to stream struct + + @param numFrames The number of frames to write to the output stream + + @param cbFlags Indicates overflows and underflows + */ +static PaError PaAsiHpi_EndProcessing( PaAsiHpiStream *stream, unsigned long numFrames, + PaStreamCallbackFlags *cbFlags ) +{ + PaError result = paNoError; + + assert( stream ); + + if( stream->output ) + { + PaAsiHpiStreamInfo info; +#if (HPI_VER < HPI_VERSION_CONSTRUCTOR( 3, 5, 5 )) + HPI_DATA data; +#endif + /* Check for underflows after the (potentially time-consuming) callback */ + PA_ENSURE_( PaAsiHpi_GetStreamInfo( stream->output, &info ) ); + if( info.underflow ) + { + *cbFlags |= paOutputUnderflow; + } + +#if (HPI_VER >= HPI_VERSION_CONSTRUCTOR( 3, 5, 5 )) + /* Write temp buffer to HPI stream */ + PA_ASIHPI_UNLESS_( HPI_OutStreamWriteBuf( stream->output->hpiDevice->subSys, + stream->output->hpiStream, + stream->output->tempBuffer, + numFrames * stream->output->bytesPerFrame, + &stream->output->hpiFormat), + paUnanticipatedHostError ); +#else + /* Setup HPI data structure around temp buffer */ + HPI_DataCreate( &data, &stream->output->hpiFormat, stream->output->tempBuffer, + numFrames * stream->output->bytesPerFrame ); + /* Write temp buffer to HPI stream */ + PA_ASIHPI_UNLESS_( HPI_OutStreamWrite( stream->output->hpiDevice->subSys, + stream->output->hpiStream, &data ), + paUnanticipatedHostError ); +#endif + } + +error: + return result; +} + + +/** Main callback engine. + This function runs in a separate thread and does all the work of fetching audio data from + the AudioScience card via the HPI interface, feeding it to the user callback via the buffer + processor, and delivering the resulting output data back to the card via HPI calls. + It is started and terminated when the PortAudio stream is started and stopped, and starts + the HPI streams on startup. + + @param userData A pointer to an open stream previously created with Pa_OpenStream. +*/ +static void *CallbackThreadFunc( void *userData ) +{ + PaError result = paNoError; + PaAsiHpiStream *stream = (PaAsiHpiStream *) userData; + int callbackResult = paContinue; + + assert( stream ); + + /* Cleanup routine stops streams on thread exit */ + pthread_cleanup_push( &PaAsiHpi_OnThreadExit, stream ); + + /* Start HPI streams and notify parent when we're done */ + PA_ENSURE_( PaUnixThread_PrepareNotify( &stream->thread ) ); + /* Buffer will be primed with silence */ + PA_ENSURE_( PaAsiHpi_StartStream( stream, 0 ) ); + PA_ENSURE_( PaUnixThread_NotifyParent( &stream->thread ) ); + + /* MAIN LOOP */ + while( 1 ) + { + PaStreamCallbackFlags cbFlags = 0; + unsigned long framesAvail, framesGot; + + pthread_testcancel(); + + /** @concern StreamStop if the main thread has requested a stop and the stream has not + * been effectively stopped we signal this condition by modifying callbackResult + * (we'll want to flush buffered output). */ + if( PaUnixThread_StopRequested( &stream->thread ) && (callbackResult == paContinue) ) + { + PA_DEBUG(( "Setting callbackResult to paComplete\n" )); + callbackResult = paComplete; + } + + /* Start winding down thread if requested */ + if( callbackResult != paContinue ) + { + stream->callbackAbort = (callbackResult == paAbort); + if( stream->callbackAbort || + /** @concern BlockAdaption: Go on if adaption buffers are empty */ + PaUtil_IsBufferProcessorOutputEmpty( &stream->bufferProcessor ) ) + { + goto end; + } + PA_DEBUG(( "%s: Flushing buffer processor\n", __FUNCTION__ )); + /* There is still buffered output that needs to be processed */ + } + + /* SLEEP */ + /* Wait for data (or buffer space) to become available. This basically sleeps and + polls the HPI interface until a full block of frames can be moved. */ + PA_ENSURE_( PaAsiHpi_WaitForFrames( stream, &framesAvail, &cbFlags ) ); + + /* Consume buffer space. Once we have a number of frames available for consumption we + must retrieve the data from the HPI interface and pass it to the PA buffer processor. + We should be prepared to process several chunks successively. */ + while( framesAvail > 0 ) + { + PaStreamCallbackTimeInfo timeInfo = {0, 0, 0}; + + pthread_testcancel(); + + framesGot = framesAvail; + if( stream->bufferProcessor.hostBufferSizeMode == paUtilFixedHostBufferSize ) + { + /* We've committed to a fixed host buffer size, stick to that */ + framesGot = framesGot >= stream->maxFramesPerHostBuffer ? stream->maxFramesPerHostBuffer : 0; + } + else + { + /* We've committed to an upper bound on the size of host buffers */ + assert( stream->bufferProcessor.hostBufferSizeMode == paUtilBoundedHostBufferSize ); + framesGot = PA_MIN( framesGot, stream->maxFramesPerHostBuffer ); + } + + /* Obtain buffer timestamps */ + PaAsiHpi_CalculateTimeInfo( stream, &timeInfo ); + PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, cbFlags ); + /* CPU load measurement should include processing activivity external to the stream callback */ + PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer ); + if( framesGot > 0 ) + { + /* READ FROM HPI INPUT STREAM */ + PA_ENSURE_( PaAsiHpi_BeginProcessing( stream, &framesGot, &cbFlags ) ); + /* Input overflow in a full-duplex stream makes for interesting times */ + if( stream->input && stream->output && (cbFlags & paInputOverflow) ) + { + /* Special full-duplex paNeverDropInput mode */ + if( stream->neverDropInput ) + { + PaUtil_SetNoOutput( &stream->bufferProcessor ); + cbFlags |= paOutputOverflow; + } + } + /* CALL USER CALLBACK WITH INPUT DATA, AND OBTAIN OUTPUT DATA */ + PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult ); + /* Clear overflow and underflow information (but PaAsiHpi_EndProcessing might + still show up output underflow that will carry over to next round) */ + cbFlags = 0; + /* WRITE TO HPI OUTPUT STREAM */ + PA_ENSURE_( PaAsiHpi_EndProcessing( stream, framesGot, &cbFlags ) ); + /* Advance frame counter */ + framesAvail -= framesGot; + } + PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesGot ); + + if( framesGot == 0 ) + { + /* Go back to polling for more frames */ + break; + + } + if( callbackResult != paContinue ) + break; + } + } + + /* This code is unreachable, but important to include regardless because it + * is possibly a macro with a closing brace to match the opening brace in + * pthread_cleanup_push() above. The documentation states that they must + * always occur in pairs. */ + pthread_cleanup_pop( 1 ); + +end: + /* Indicates normal exit of callback, as opposed to the thread getting killed explicitly */ + stream->callbackFinished = 1; + PA_DEBUG(( "%s: Thread %d exiting (callbackResult = %d)\n ", + __FUNCTION__, pthread_self(), callbackResult )); + /* Exit from thread and report any PortAudio error in the process */ + PaUnixThreading_EXIT( result ); +error: + goto end; +} + +/* --------------------------- Blocking Interface --------------------------- */ + +/* As separate stream interfaces are used for blocking and callback streams, the following + functions can be guaranteed to only be called for blocking streams. */ + +/** Read data from input stream. + This reads the indicated number of frames into the supplied buffer from an input stream, + and blocks until this is done. + + @param s Pointer to PortAudio stream + + @param buffer Pointer to buffer that will receive interleaved data (or an array of pointers + to a buffer for each non-interleaved channel) + + @param frames Number of frames to read from stream + + @return PortAudio error code (also indicates overflow via paInputOverflowed) + */ +static PaError ReadStream( PaStream *s, + void *buffer, + unsigned long frames ) +{ + PaError result = paNoError; + PaAsiHpiStream *stream = (PaAsiHpiStream*)s; + PaAsiHpiStreamInfo info; + void *userBuffer; + + assert( stream ); + PA_UNLESS_( stream->input, paCanNotReadFromAnOutputOnlyStream ); + + /* Check for input overflow since previous call to ReadStream */ + PA_ENSURE_( PaAsiHpi_GetStreamInfo( stream->input, &info ) ); + if( info.overflow ) + { + result = paInputOverflowed; + } + + /* NB Make copy of user buffer pointers, since they are advanced by buffer processor */ + if( stream->bufferProcessor.userInputIsInterleaved ) + { + userBuffer = buffer; + } + else + { + /* Copy channels into local array */ + userBuffer = stream->blockingUserBufferCopy; + memcpy( userBuffer, buffer, sizeof (void *) * stream->input->hpiFormat.wChannels ); + } + + while( frames > 0 ) + { + unsigned long framesGot, framesAvail; + PaStreamCallbackFlags cbFlags = 0; + + PA_ENSURE_( PaAsiHpi_WaitForFrames( stream, &framesAvail, &cbFlags ) ); + framesGot = PA_MIN( framesAvail, frames ); + PA_ENSURE_( PaAsiHpi_BeginProcessing( stream, &framesGot, &cbFlags ) ); + + if( framesGot > 0 ) + { + framesGot = PaUtil_CopyInput( &stream->bufferProcessor, &userBuffer, framesGot ); + PA_ENSURE_( PaAsiHpi_EndProcessing( stream, framesGot, &cbFlags ) ); + /* Advance frame counter */ + frames -= framesGot; + } + } + +error: + return result; +} + + +/** Write data to output stream. + This writes the indicated number of frames from the supplied buffer to an output stream, + and blocks until this is done. + + @param s Pointer to PortAudio stream + + @param buffer Pointer to buffer that provides interleaved data (or an array of pointers + to a buffer for each non-interleaved channel) + + @param frames Number of frames to write to stream + + @return PortAudio error code (also indicates underflow via paOutputUnderflowed) + */ +static PaError WriteStream( PaStream *s, + const void *buffer, + unsigned long frames ) +{ + PaError result = paNoError; + PaAsiHpiStream *stream = (PaAsiHpiStream*)s; + PaAsiHpiStreamInfo info; + const void *userBuffer; + + assert( stream ); + PA_UNLESS_( stream->output, paCanNotWriteToAnInputOnlyStream ); + + /* Check for output underflow since previous call to WriteStream */ + PA_ENSURE_( PaAsiHpi_GetStreamInfo( stream->output, &info ) ); + if( info.underflow ) + { + result = paOutputUnderflowed; + } + + /* NB Make copy of user buffer pointers, since they are advanced by buffer processor */ + if( stream->bufferProcessor.userOutputIsInterleaved ) + { + userBuffer = buffer; + } + else + { + /* Copy channels into local array */ + userBuffer = stream->blockingUserBufferCopy; + memcpy( (void *)userBuffer, buffer, sizeof (void *) * stream->output->hpiFormat.wChannels ); + } + + while( frames > 0 ) + { + unsigned long framesGot, framesAvail; + PaStreamCallbackFlags cbFlags = 0; + + PA_ENSURE_( PaAsiHpi_WaitForFrames( stream, &framesAvail, &cbFlags ) ); + framesGot = PA_MIN( framesAvail, frames ); + PA_ENSURE_( PaAsiHpi_BeginProcessing( stream, &framesGot, &cbFlags ) ); + + if( framesGot > 0 ) + { + framesGot = PaUtil_CopyOutput( &stream->bufferProcessor, &userBuffer, framesGot ); + PA_ENSURE_( PaAsiHpi_EndProcessing( stream, framesGot, &cbFlags ) ); + /* Advance frame counter */ + frames -= framesGot; + } + } + +error: + return result; +} + + +/** Number of frames that can be read from input stream without blocking. + + @param s Pointer to PortAudio stream + + @return Number of frames, or PortAudio error code + */ +static signed long GetStreamReadAvailable( PaStream *s ) +{ + PaError result = paNoError; + PaAsiHpiStream *stream = (PaAsiHpiStream*)s; + PaAsiHpiStreamInfo info; + + assert( stream ); + PA_UNLESS_( stream->input, paCanNotReadFromAnOutputOnlyStream ); + + PA_ENSURE_( PaAsiHpi_GetStreamInfo( stream->input, &info ) ); + /* Round down to the nearest host buffer multiple */ + result = (info.availableFrames / stream->maxFramesPerHostBuffer) * stream->maxFramesPerHostBuffer; + if( info.overflow ) + { + result = paInputOverflowed; + } + +error: + return result; +} + + +/** Number of frames that can be written to output stream without blocking. + + @param s Pointer to PortAudio stream + + @return Number of frames, or PortAudio error code + */ +static signed long GetStreamWriteAvailable( PaStream *s ) +{ + PaError result = paNoError; + PaAsiHpiStream *stream = (PaAsiHpiStream*)s; + PaAsiHpiStreamInfo info; + + assert( stream ); + PA_UNLESS_( stream->output, paCanNotWriteToAnInputOnlyStream ); + + PA_ENSURE_( PaAsiHpi_GetStreamInfo( stream->output, &info ) ); + /* Round down to the nearest host buffer multiple */ + result = (info.availableFrames / stream->maxFramesPerHostBuffer) * stream->maxFramesPerHostBuffer; + if( info.underflow ) + { + result = paOutputUnderflowed; + } + +error: + return result; +} diff --git a/lib-src/portaudio-v19/src/hostapi/coreaudio/pa_mac_core_blocking.c b/lib-src/portaudio-v19/src/hostapi/coreaudio/pa_mac_core_blocking.c index 3ea20fd5b..2c7be983f 100644 --- a/lib-src/portaudio-v19/src/hostapi/coreaudio/pa_mac_core_blocking.c +++ b/lib-src/portaudio-v19/src/hostapi/coreaudio/pa_mac_core_blocking.c @@ -1,595 +1,595 @@ -/* - * Implementation of the PortAudio API for Apple AUHAL - * - * PortAudio Portable Real-Time Audio Library - * Latest Version at: http://www.portaudio.com - * - * Written by Bjorn Roche of XO Audio LLC, from PA skeleton code. - * Portions copied from code by Dominic Mazzoni (who wrote a HAL implementation) - * - * Dominic's code was based on code by Phil Burk, Darren Gibbs, - * Gord Peters, Stephane Letz, and Greg Pfiel. - * - * The following people also deserve acknowledgements: - * - * Olivier Tristan for feedback and testing - * Glenn Zelniker and Z-Systems engineering for sponsoring the Blocking I/O - * interface. - * - * - * Based on the Open Source API proposed by Ross Bencina - * Copyright (c) 1999-2002 Ross Bencina, Phil Burk - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * The text above constitutes the entire PortAudio license; however, - * the PortAudio community also makes the following non-binding requests: - * - * Any person wishing to distribute modifications to the Software is - * requested to send the modifications to the original developer so that - * they can be incorporated into the canonical version. It is also - * requested that these non-binding requests be included along with the - * license above. - */ - -/** - @file - @ingroup hostapi_src - - This file contains the implementation - required for blocking I/O. It is separated from pa_mac_core.c simply to ease - development. -*/ - -#include "pa_mac_core_blocking.h" -#include "pa_mac_core_internal.h" -#include -#ifdef MOSX_USE_NON_ATOMIC_FLAG_BITS -# define OSAtomicOr32( a, b ) ( (*(b)) |= (a) ) -# define OSAtomicAnd32( a, b ) ( (*(b)) &= (a) ) -#elif MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_3 -# define OSAtomicOr32( a, b ) BitOrAtomic( a, (UInt32 *) b ) -# define OSAtomicAnd32( a, b ) BitAndAtomic( a, (UInt32 *) b ) -#else -# include -#endif - -/* - * This fnuction determines the size of a particular sample format. - * if the format is not recognized, this returns zero. - */ -static size_t computeSampleSizeFromFormat( PaSampleFormat format ) -{ - switch( format ) { - case paFloat32: return 4; - case paInt32: return 4; - case paInt24: return 3; - case paInt16: return 2; - case paInt8: case paUInt8: return 1; - default: return 0; - } -} -/* - * Same as computeSampleSizeFromFormat, except that if - * the size is not a power of two, it returns the next power of two up - */ -static size_t computeSampleSizeFromFormatPow2( PaSampleFormat format ) -{ - switch( format ) { - case paFloat32: return 4; - case paInt32: return 4; - case paInt24: return 4; - case paInt16: return 2; - case paInt8: case paUInt8: return 1; - default: return 0; - } -} - - - -/* - * Functions for initializing, resetting, and destroying BLIO structures. - * - */ - -/* This should be called with the relevant info when initializing a stream for - callback. */ -PaError initializeBlioRingBuffers( - PaMacBlio *blio, - PaSampleFormat inputSampleFormat, - PaSampleFormat outputSampleFormat, - size_t framesPerBuffer, - long ringBufferSize, - int inChan, - int outChan ) -{ - void *data; - int result; - OSStatus err; - - /* zeroify things */ - bzero( blio, sizeof( PaMacBlio ) ); - /* this is redundant, but the buffers are used to check - if the bufffers have been initialized, so we do it explicitly. */ - blio->inputRingBuffer.buffer = NULL; - blio->outputRingBuffer.buffer = NULL; - - /* initialize simple data */ - blio->ringBufferFrames = ringBufferSize; - blio->inputSampleFormat = inputSampleFormat; - blio->inputSampleSizeActual = computeSampleSizeFromFormat(inputSampleFormat); - blio->inputSampleSizePow2 = computeSampleSizeFromFormatPow2(inputSampleFormat); - blio->outputSampleFormat = outputSampleFormat; - blio->outputSampleSizeActual = computeSampleSizeFromFormat(outputSampleFormat); - blio->outputSampleSizePow2 = computeSampleSizeFromFormatPow2(outputSampleFormat); - - blio->framesPerBuffer = framesPerBuffer; - blio->inChan = inChan; - blio->outChan = outChan; - blio->statusFlags = 0; - blio->errors = paNoError; -#ifdef PA_MAC_BLIO_MUTEX - blio->isInputEmpty = false; - blio->isOutputFull = false; -#endif - - /* setup ring buffers */ -#ifdef PA_MAC_BLIO_MUTEX - result = PaMacCore_SetUnixError( pthread_mutex_init(&(blio->inputMutex),NULL), 0 ); - if( result ) - goto error; - result = UNIX_ERR( pthread_cond_init( &(blio->inputCond), NULL ) ); - if( result ) - goto error; - result = UNIX_ERR( pthread_mutex_init(&(blio->outputMutex),NULL) ); - if( result ) - goto error; - result = UNIX_ERR( pthread_cond_init( &(blio->outputCond), NULL ) ); -#endif - if( inChan ) { - data = calloc( ringBufferSize, blio->inputSampleSizePow2*inChan ); - if( !data ) - { - result = paInsufficientMemory; - goto error; - } - - err = PaUtil_InitializeRingBuffer( - &blio->inputRingBuffer, - 1, ringBufferSize*blio->inputSampleSizePow2*inChan, - data ); - assert( !err ); - } - if( outChan ) { - data = calloc( ringBufferSize, blio->outputSampleSizePow2*outChan ); - if( !data ) - { - result = paInsufficientMemory; - goto error; - } - - err = PaUtil_InitializeRingBuffer( - &blio->outputRingBuffer, - 1, ringBufferSize*blio->outputSampleSizePow2*outChan, - data ); - assert( !err ); - } - - result = resetBlioRingBuffers( blio ); - if( result ) - goto error; - - return 0; - - error: - destroyBlioRingBuffers( blio ); - return result; -} - -#ifdef PA_MAC_BLIO_MUTEX -PaError blioSetIsInputEmpty( PaMacBlio *blio, bool isEmpty ) -{ - PaError result = paNoError; - if( isEmpty == blio->isInputEmpty ) - goto done; - - /* we need to update the value. Here's what we do: - * - Lock the mutex, so noone else can write. - * - update the value. - * - unlock. - * - broadcast to all listeners. - */ - result = UNIX_ERR( pthread_mutex_lock( &blio->inputMutex ) ); - if( result ) - goto done; - blio->isInputEmpty = isEmpty; - result = UNIX_ERR( pthread_mutex_unlock( &blio->inputMutex ) ); - if( result ) - goto done; - result = UNIX_ERR( pthread_cond_broadcast( &blio->inputCond ) ); - if( result ) - goto done; - - done: - return result; -} -PaError blioSetIsOutputFull( PaMacBlio *blio, bool isFull ) -{ - PaError result = paNoError; - if( isFull == blio->isOutputFull ) - goto done; - - /* we need to update the value. Here's what we do: - * - Lock the mutex, so noone else can write. - * - update the value. - * - unlock. - * - broadcast to all listeners. - */ - result = UNIX_ERR( pthread_mutex_lock( &blio->outputMutex ) ); - if( result ) - goto done; - blio->isOutputFull = isFull; - result = UNIX_ERR( pthread_mutex_unlock( &blio->outputMutex ) ); - if( result ) - goto done; - result = UNIX_ERR( pthread_cond_broadcast( &blio->outputCond ) ); - if( result ) - goto done; - - done: - return result; -} -#endif - -/* This should be called after stopping or aborting the stream, so that on next - start, the buffers will be ready. */ -PaError resetBlioRingBuffers( PaMacBlio *blio ) -{ -#ifdef PA_MAC__BLIO_MUTEX - int result; -#endif - blio->statusFlags = 0; - if( blio->outputRingBuffer.buffer ) { - PaUtil_FlushRingBuffer( &blio->outputRingBuffer ); - bzero( blio->outputRingBuffer.buffer, - blio->outputRingBuffer.bufferSize ); - /* Advance buffer */ - PaUtil_AdvanceRingBufferWriteIndex( &blio->outputRingBuffer, blio->ringBufferFrames*blio->outputSampleSizeActual*blio->outChan ); - //PaUtil_AdvanceRingBufferWriteIndex( &blio->outputRingBuffer, blio->outputRingBuffer.bufferSize ); - - /* Update isOutputFull. */ -#ifdef PA_MAC__BLIO_MUTEX - result = blioSetIsOutputFull( blio, toAdvance == blio->outputRingBuffer.bufferSize ); - if( result ) - goto error; -#endif -/* - printf( "------%d\n" , blio->framesPerBuffer ); - printf( "------%d\n" , blio->outChan ); - printf( "------%d\n" , blio->outputSampleSize ); - printf( "------%d\n" , blio->framesPerBuffer*blio->outChan*blio->outputSampleSize ); -*/ - } - if( blio->inputRingBuffer.buffer ) { - PaUtil_FlushRingBuffer( &blio->inputRingBuffer ); - bzero( blio->inputRingBuffer.buffer, - blio->inputRingBuffer.bufferSize ); - /* Update isInputEmpty. */ -#ifdef PA_MAC__BLIO_MUTEX - result = blioSetIsInputEmpty( blio, true ); - if( result ) - goto error; -#endif - } - return paNoError; -#ifdef PA_MAC__BLIO_MUTEX - error: - return result; -#endif -} - -/*This should be called when you are done with the blio. It can safely be called - multiple times if there are no exceptions. */ -PaError destroyBlioRingBuffers( PaMacBlio *blio ) -{ - PaError result = paNoError; - if( blio->inputRingBuffer.buffer ) { - free( blio->inputRingBuffer.buffer ); -#ifdef PA_MAC__BLIO_MUTEX - result = UNIX_ERR( pthread_mutex_destroy( & blio->inputMutex ) ); - if( result ) return result; - result = UNIX_ERR( pthread_cond_destroy( & blio->inputCond ) ); - if( result ) return result; -#endif - } - blio->inputRingBuffer.buffer = NULL; - if( blio->outputRingBuffer.buffer ) { - free( blio->outputRingBuffer.buffer ); -#ifdef PA_MAC__BLIO_MUTEX - result = UNIX_ERR( pthread_mutex_destroy( & blio->outputMutex ) ); - if( result ) return result; - result = UNIX_ERR( pthread_cond_destroy( & blio->outputCond ) ); - if( result ) return result; -#endif - } - blio->outputRingBuffer.buffer = NULL; - - return result; -} - -/* - * this is the BlioCallback function. It expects to recieve a PaMacBlio Object - * pointer as userData. - * - */ -int BlioCallback( const void *input, void *output, unsigned long frameCount, - const PaStreamCallbackTimeInfo* timeInfo, - PaStreamCallbackFlags statusFlags, - void *userData ) -{ - PaMacBlio *blio = (PaMacBlio*)userData; - long avail; - long toRead; - long toWrite; - long read; - long written; - - /* set flags returned by OS: */ - OSAtomicOr32( statusFlags, &blio->statusFlags ) ; - - /* --- Handle Input Buffer --- */ - if( blio->inChan ) { - avail = PaUtil_GetRingBufferWriteAvailable( &blio->inputRingBuffer ); - - /* check for underflow */ - if( avail < frameCount * blio->inputSampleSizeActual * blio->inChan ) - OSAtomicOr32( paInputOverflow, &blio->statusFlags ); - - toRead = MIN( avail, frameCount * blio->inputSampleSizeActual * blio->inChan ); - - /* copy the data */ - /*printf( "reading %d\n", toRead );*/ - read = PaUtil_WriteRingBuffer( &blio->inputRingBuffer, input, toRead ); - assert( toRead == read ); -#ifdef PA_MAC__BLIO_MUTEX - /* Priority inversion. See notes below. */ - blioSetIsInputEmpty( blio, false ); -#endif - } - - - /* --- Handle Output Buffer --- */ - if( blio->outChan ) { - avail = PaUtil_GetRingBufferReadAvailable( &blio->outputRingBuffer ); - - /* check for underflow */ - if( avail < frameCount * blio->outputSampleSizeActual * blio->outChan ) - OSAtomicOr32( paOutputUnderflow, &blio->statusFlags ); - - toWrite = MIN( avail, frameCount * blio->outputSampleSizeActual * blio->outChan ); - - if( toWrite != frameCount * blio->outputSampleSizeActual * blio->outChan ) - bzero( ((char *)output)+toWrite, - frameCount * blio->outputSampleSizeActual * blio->outChan - toWrite ); - /* copy the data */ - /*printf( "writing %d\n", toWrite );*/ - written = PaUtil_ReadRingBuffer( &blio->outputRingBuffer, output, toWrite ); - assert( toWrite == written ); -#ifdef PA_MAC__BLIO_MUTEX - /* We have a priority inversion here. However, we will only have to - wait if this was true and is now false, which means we've got - some room in the buffer. - Hopefully problems will be minimized. */ - blioSetIsOutputFull( blio, false ); -#endif - } - - return paContinue; -} - -PaError ReadStream( PaStream* stream, - void *buffer, - unsigned long frames ) -{ - PaMacBlio *blio = & ((PaMacCoreStream*)stream) -> blio; - char *cbuf = (char *) buffer; - PaError ret = paNoError; - VVDBUG(("ReadStream()\n")); - - while( frames > 0 ) { - long avail; - long toRead; - do { - avail = PaUtil_GetRingBufferReadAvailable( &blio->inputRingBuffer ); -/* - printf( "Read Buffer is %%%g full: %ld of %ld.\n", - 100 * (float)avail / (float) blio->inputRingBuffer.bufferSize, - avail, blio->inputRingBuffer.bufferSize ); -*/ - if( avail == 0 ) { -#ifdef PA_MAC_BLIO_MUTEX - /**block when empty*/ - ret = UNIX_ERR( pthread_mutex_lock( &blio->inputMutex ) ); - if( ret ) - return ret; - while( blio->isInputEmpty ) { - ret = UNIX_ERR( pthread_cond_wait( &blio->inputCond, &blio->inputMutex ) ); - if( ret ) - return ret; - } - ret = UNIX_ERR( pthread_mutex_unlock( &blio->inputMutex ) ); - if( ret ) - return ret; -#else - Pa_Sleep( PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL ); -#endif - } - } while( avail == 0 ); - toRead = MIN( avail, frames * blio->inputSampleSizeActual * blio->inChan ); - toRead -= toRead % blio->inputSampleSizeActual * blio->inChan ; - PaUtil_ReadRingBuffer( &blio->inputRingBuffer, (void *)cbuf, toRead ); - cbuf += toRead; - frames -= toRead / ( blio->inputSampleSizeActual * blio->inChan ); - - if( toRead == avail ) { -#ifdef PA_MAC_BLIO_MUTEX - /* we just emptied the buffer, so we need to mark it as empty. */ - ret = blioSetIsInputEmpty( blio, true ); - if( ret ) - return ret; - /* of course, in the meantime, the callback may have put some sats - in, so - so check for that, too, to avoid a race condition. */ - if( PaUtil_GetRingBufferReadAvailable( &blio->inputRingBuffer ) ) { - blioSetIsInputEmpty( blio, false ); - if( ret ) - return ret; - } -#endif - } - } - - /* Report either paNoError or paInputOverflowed. */ - /* may also want to report other errors, but this is non-standard. */ - ret = blio->statusFlags & paInputOverflow; - - /* report underflow only once: */ - if( ret ) { - OSAtomicAnd32( (uint32_t)(~paInputOverflow), &blio->statusFlags ); - ret = paInputOverflowed; - } - - return ret; -} - - -PaError WriteStream( PaStream* stream, - const void *buffer, - unsigned long frames ) -{ - PaMacBlio *blio = & ((PaMacCoreStream*)stream) -> blio; - char *cbuf = (char *) buffer; - PaError ret = paNoError; - VVDBUG(("WriteStream()\n")); - - while( frames > 0 ) { - long avail = 0; - long toWrite; - - do { - avail = PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer ); -/* - printf( "Write Buffer is %%%g full: %ld of %ld.\n", - 100 - 100 * (float)avail / (float) blio->outputRingBuffer.bufferSize, - avail, blio->outputRingBuffer.bufferSize ); -*/ - if( avail == 0 ) { -#ifdef PA_MAC_BLIO_MUTEX - /*block while full*/ - ret = UNIX_ERR( pthread_mutex_lock( &blio->outputMutex ) ); - if( ret ) - return ret; - while( blio->isOutputFull ) { - ret = UNIX_ERR( pthread_cond_wait( &blio->outputCond, &blio->outputMutex ) ); - if( ret ) - return ret; - } - ret = UNIX_ERR( pthread_mutex_unlock( &blio->outputMutex ) ); - if( ret ) - return ret; -#else - Pa_Sleep( PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL ); -#endif - } - } while( avail == 0 ); - - toWrite = MIN( avail, frames * blio->outputSampleSizeActual * blio->outChan ); - toWrite -= toWrite % blio->outputSampleSizeActual * blio->outChan ; - PaUtil_WriteRingBuffer( &blio->outputRingBuffer, (void *)cbuf, toWrite ); - cbuf += toWrite; - frames -= toWrite / ( blio->outputSampleSizeActual * blio->outChan ); - -#ifdef PA_MAC_BLIO_MUTEX - if( toWrite == avail ) { - /* we just filled up the buffer, so we need to mark it as filled. */ - ret = blioSetIsOutputFull( blio, true ); - if( ret ) - return ret; - /* of course, in the meantime, we may have emptied the buffer, so - so check for that, too, to avoid a race condition. */ - if( PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer ) ) { - blioSetIsOutputFull( blio, false ); - if( ret ) - return ret; - } - } -#endif - } - - /* Report either paNoError or paOutputUnderflowed. */ - /* may also want to report other errors, but this is non-standard. */ - ret = blio->statusFlags & paOutputUnderflow; - - /* report underflow only once: */ - if( ret ) { - OSAtomicAnd32( (uint32_t)(~paOutputUnderflow), &blio->statusFlags ); - ret = paOutputUnderflowed; - } - - return ret; -} - -/* - * - */ -void waitUntilBlioWriteBufferIsFlushed( PaMacBlio *blio ) -{ - if( blio->outputRingBuffer.buffer ) { - long avail = PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer ); - while( avail != blio->outputRingBuffer.bufferSize ) { - if( avail == 0 ) - Pa_Sleep( PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL ); - avail = PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer ); - } - } -} - - -signed long GetStreamReadAvailable( PaStream* stream ) -{ - PaMacBlio *blio = & ((PaMacCoreStream*)stream) -> blio; - VVDBUG(("GetStreamReadAvailable()\n")); - - return PaUtil_GetRingBufferReadAvailable( &blio->inputRingBuffer ) - / ( blio->inputSampleSizeActual * blio->inChan ); -} - - -signed long GetStreamWriteAvailable( PaStream* stream ) -{ - PaMacBlio *blio = & ((PaMacCoreStream*)stream) -> blio; - VVDBUG(("GetStreamWriteAvailable()\n")); - - return PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer ) - / ( blio->outputSampleSizeActual * blio->outChan ); -} - +/* + * Implementation of the PortAudio API for Apple AUHAL + * + * PortAudio Portable Real-Time Audio Library + * Latest Version at: http://www.portaudio.com + * + * Written by Bjorn Roche of XO Audio LLC, from PA skeleton code. + * Portions copied from code by Dominic Mazzoni (who wrote a HAL implementation) + * + * Dominic's code was based on code by Phil Burk, Darren Gibbs, + * Gord Peters, Stephane Letz, and Greg Pfiel. + * + * The following people also deserve acknowledgements: + * + * Olivier Tristan for feedback and testing + * Glenn Zelniker and Z-Systems engineering for sponsoring the Blocking I/O + * interface. + * + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2002 Ross Bencina, Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** + @file + @ingroup hostapi_src + + This file contains the implementation + required for blocking I/O. It is separated from pa_mac_core.c simply to ease + development. +*/ + +#include "pa_mac_core_blocking.h" +#include "pa_mac_core_internal.h" +#include +#ifdef MOSX_USE_NON_ATOMIC_FLAG_BITS +# define OSAtomicOr32( a, b ) ( (*(b)) |= (a) ) +# define OSAtomicAnd32( a, b ) ( (*(b)) &= (a) ) +#elif MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_3 +# define OSAtomicOr32( a, b ) BitOrAtomic( a, (UInt32 *) b ) +# define OSAtomicAnd32( a, b ) BitAndAtomic( a, (UInt32 *) b ) +#else +# include +#endif + +/* + * This fnuction determines the size of a particular sample format. + * if the format is not recognized, this returns zero. + */ +static size_t computeSampleSizeFromFormat( PaSampleFormat format ) +{ + switch( format ) { + case paFloat32: return 4; + case paInt32: return 4; + case paInt24: return 3; + case paInt16: return 2; + case paInt8: case paUInt8: return 1; + default: return 0; + } +} +/* + * Same as computeSampleSizeFromFormat, except that if + * the size is not a power of two, it returns the next power of two up + */ +static size_t computeSampleSizeFromFormatPow2( PaSampleFormat format ) +{ + switch( format ) { + case paFloat32: return 4; + case paInt32: return 4; + case paInt24: return 4; + case paInt16: return 2; + case paInt8: case paUInt8: return 1; + default: return 0; + } +} + + + +/* + * Functions for initializing, resetting, and destroying BLIO structures. + * + */ + +/* This should be called with the relevant info when initializing a stream for + callback. */ +PaError initializeBlioRingBuffers( + PaMacBlio *blio, + PaSampleFormat inputSampleFormat, + PaSampleFormat outputSampleFormat, + size_t framesPerBuffer, + long ringBufferSize, + int inChan, + int outChan ) +{ + void *data; + int result; + OSStatus err; + + /* zeroify things */ + bzero( blio, sizeof( PaMacBlio ) ); + /* this is redundant, but the buffers are used to check + if the bufffers have been initialized, so we do it explicitly. */ + blio->inputRingBuffer.buffer = NULL; + blio->outputRingBuffer.buffer = NULL; + + /* initialize simple data */ + blio->ringBufferFrames = ringBufferSize; + blio->inputSampleFormat = inputSampleFormat; + blio->inputSampleSizeActual = computeSampleSizeFromFormat(inputSampleFormat); + blio->inputSampleSizePow2 = computeSampleSizeFromFormatPow2(inputSampleFormat); + blio->outputSampleFormat = outputSampleFormat; + blio->outputSampleSizeActual = computeSampleSizeFromFormat(outputSampleFormat); + blio->outputSampleSizePow2 = computeSampleSizeFromFormatPow2(outputSampleFormat); + + blio->framesPerBuffer = framesPerBuffer; + blio->inChan = inChan; + blio->outChan = outChan; + blio->statusFlags = 0; + blio->errors = paNoError; +#ifdef PA_MAC_BLIO_MUTEX + blio->isInputEmpty = false; + blio->isOutputFull = false; +#endif + + /* setup ring buffers */ +#ifdef PA_MAC_BLIO_MUTEX + result = PaMacCore_SetUnixError( pthread_mutex_init(&(blio->inputMutex),NULL), 0 ); + if( result ) + goto error; + result = UNIX_ERR( pthread_cond_init( &(blio->inputCond), NULL ) ); + if( result ) + goto error; + result = UNIX_ERR( pthread_mutex_init(&(blio->outputMutex),NULL) ); + if( result ) + goto error; + result = UNIX_ERR( pthread_cond_init( &(blio->outputCond), NULL ) ); +#endif + if( inChan ) { + data = calloc( ringBufferSize, blio->inputSampleSizePow2*inChan ); + if( !data ) + { + result = paInsufficientMemory; + goto error; + } + + err = PaUtil_InitializeRingBuffer( + &blio->inputRingBuffer, + 1, ringBufferSize*blio->inputSampleSizePow2*inChan, + data ); + assert( !err ); + } + if( outChan ) { + data = calloc( ringBufferSize, blio->outputSampleSizePow2*outChan ); + if( !data ) + { + result = paInsufficientMemory; + goto error; + } + + err = PaUtil_InitializeRingBuffer( + &blio->outputRingBuffer, + 1, ringBufferSize*blio->outputSampleSizePow2*outChan, + data ); + assert( !err ); + } + + result = resetBlioRingBuffers( blio ); + if( result ) + goto error; + + return 0; + + error: + destroyBlioRingBuffers( blio ); + return result; +} + +#ifdef PA_MAC_BLIO_MUTEX +PaError blioSetIsInputEmpty( PaMacBlio *blio, bool isEmpty ) +{ + PaError result = paNoError; + if( isEmpty == blio->isInputEmpty ) + goto done; + + /* we need to update the value. Here's what we do: + * - Lock the mutex, so noone else can write. + * - update the value. + * - unlock. + * - broadcast to all listeners. + */ + result = UNIX_ERR( pthread_mutex_lock( &blio->inputMutex ) ); + if( result ) + goto done; + blio->isInputEmpty = isEmpty; + result = UNIX_ERR( pthread_mutex_unlock( &blio->inputMutex ) ); + if( result ) + goto done; + result = UNIX_ERR( pthread_cond_broadcast( &blio->inputCond ) ); + if( result ) + goto done; + + done: + return result; +} +PaError blioSetIsOutputFull( PaMacBlio *blio, bool isFull ) +{ + PaError result = paNoError; + if( isFull == blio->isOutputFull ) + goto done; + + /* we need to update the value. Here's what we do: + * - Lock the mutex, so noone else can write. + * - update the value. + * - unlock. + * - broadcast to all listeners. + */ + result = UNIX_ERR( pthread_mutex_lock( &blio->outputMutex ) ); + if( result ) + goto done; + blio->isOutputFull = isFull; + result = UNIX_ERR( pthread_mutex_unlock( &blio->outputMutex ) ); + if( result ) + goto done; + result = UNIX_ERR( pthread_cond_broadcast( &blio->outputCond ) ); + if( result ) + goto done; + + done: + return result; +} +#endif + +/* This should be called after stopping or aborting the stream, so that on next + start, the buffers will be ready. */ +PaError resetBlioRingBuffers( PaMacBlio *blio ) +{ +#ifdef PA_MAC__BLIO_MUTEX + int result; +#endif + blio->statusFlags = 0; + if( blio->outputRingBuffer.buffer ) { + PaUtil_FlushRingBuffer( &blio->outputRingBuffer ); + bzero( blio->outputRingBuffer.buffer, + blio->outputRingBuffer.bufferSize ); + /* Advance buffer */ + PaUtil_AdvanceRingBufferWriteIndex( &blio->outputRingBuffer, blio->ringBufferFrames*blio->outputSampleSizeActual*blio->outChan ); + //PaUtil_AdvanceRingBufferWriteIndex( &blio->outputRingBuffer, blio->outputRingBuffer.bufferSize ); + + /* Update isOutputFull. */ +#ifdef PA_MAC__BLIO_MUTEX + result = blioSetIsOutputFull( blio, toAdvance == blio->outputRingBuffer.bufferSize ); + if( result ) + goto error; +#endif +/* + printf( "------%d\n" , blio->framesPerBuffer ); + printf( "------%d\n" , blio->outChan ); + printf( "------%d\n" , blio->outputSampleSize ); + printf( "------%d\n" , blio->framesPerBuffer*blio->outChan*blio->outputSampleSize ); +*/ + } + if( blio->inputRingBuffer.buffer ) { + PaUtil_FlushRingBuffer( &blio->inputRingBuffer ); + bzero( blio->inputRingBuffer.buffer, + blio->inputRingBuffer.bufferSize ); + /* Update isInputEmpty. */ +#ifdef PA_MAC__BLIO_MUTEX + result = blioSetIsInputEmpty( blio, true ); + if( result ) + goto error; +#endif + } + return paNoError; +#ifdef PA_MAC__BLIO_MUTEX + error: + return result; +#endif +} + +/*This should be called when you are done with the blio. It can safely be called + multiple times if there are no exceptions. */ +PaError destroyBlioRingBuffers( PaMacBlio *blio ) +{ + PaError result = paNoError; + if( blio->inputRingBuffer.buffer ) { + free( blio->inputRingBuffer.buffer ); +#ifdef PA_MAC__BLIO_MUTEX + result = UNIX_ERR( pthread_mutex_destroy( & blio->inputMutex ) ); + if( result ) return result; + result = UNIX_ERR( pthread_cond_destroy( & blio->inputCond ) ); + if( result ) return result; +#endif + } + blio->inputRingBuffer.buffer = NULL; + if( blio->outputRingBuffer.buffer ) { + free( blio->outputRingBuffer.buffer ); +#ifdef PA_MAC__BLIO_MUTEX + result = UNIX_ERR( pthread_mutex_destroy( & blio->outputMutex ) ); + if( result ) return result; + result = UNIX_ERR( pthread_cond_destroy( & blio->outputCond ) ); + if( result ) return result; +#endif + } + blio->outputRingBuffer.buffer = NULL; + + return result; +} + +/* + * this is the BlioCallback function. It expects to recieve a PaMacBlio Object + * pointer as userData. + * + */ +int BlioCallback( const void *input, void *output, unsigned long frameCount, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + PaMacBlio *blio = (PaMacBlio*)userData; + long avail; + long toRead; + long toWrite; + long read; + long written; + + /* set flags returned by OS: */ + OSAtomicOr32( statusFlags, &blio->statusFlags ) ; + + /* --- Handle Input Buffer --- */ + if( blio->inChan ) { + avail = PaUtil_GetRingBufferWriteAvailable( &blio->inputRingBuffer ); + + /* check for underflow */ + if( avail < frameCount * blio->inputSampleSizeActual * blio->inChan ) + OSAtomicOr32( paInputOverflow, &blio->statusFlags ); + + toRead = MIN( avail, frameCount * blio->inputSampleSizeActual * blio->inChan ); + + /* copy the data */ + /*printf( "reading %d\n", toRead );*/ + read = PaUtil_WriteRingBuffer( &blio->inputRingBuffer, input, toRead ); + assert( toRead == read ); +#ifdef PA_MAC__BLIO_MUTEX + /* Priority inversion. See notes below. */ + blioSetIsInputEmpty( blio, false ); +#endif + } + + + /* --- Handle Output Buffer --- */ + if( blio->outChan ) { + avail = PaUtil_GetRingBufferReadAvailable( &blio->outputRingBuffer ); + + /* check for underflow */ + if( avail < frameCount * blio->outputSampleSizeActual * blio->outChan ) + OSAtomicOr32( paOutputUnderflow, &blio->statusFlags ); + + toWrite = MIN( avail, frameCount * blio->outputSampleSizeActual * blio->outChan ); + + if( toWrite != frameCount * blio->outputSampleSizeActual * blio->outChan ) + bzero( ((char *)output)+toWrite, + frameCount * blio->outputSampleSizeActual * blio->outChan - toWrite ); + /* copy the data */ + /*printf( "writing %d\n", toWrite );*/ + written = PaUtil_ReadRingBuffer( &blio->outputRingBuffer, output, toWrite ); + assert( toWrite == written ); +#ifdef PA_MAC__BLIO_MUTEX + /* We have a priority inversion here. However, we will only have to + wait if this was true and is now false, which means we've got + some room in the buffer. + Hopefully problems will be minimized. */ + blioSetIsOutputFull( blio, false ); +#endif + } + + return paContinue; +} + +PaError ReadStream( PaStream* stream, + void *buffer, + unsigned long frames ) +{ + PaMacBlio *blio = & ((PaMacCoreStream*)stream) -> blio; + char *cbuf = (char *) buffer; + PaError ret = paNoError; + VVDBUG(("ReadStream()\n")); + + while( frames > 0 ) { + long avail; + long toRead; + do { + avail = PaUtil_GetRingBufferReadAvailable( &blio->inputRingBuffer ); +/* + printf( "Read Buffer is %%%g full: %ld of %ld.\n", + 100 * (float)avail / (float) blio->inputRingBuffer.bufferSize, + avail, blio->inputRingBuffer.bufferSize ); +*/ + if( avail == 0 ) { +#ifdef PA_MAC_BLIO_MUTEX + /**block when empty*/ + ret = UNIX_ERR( pthread_mutex_lock( &blio->inputMutex ) ); + if( ret ) + return ret; + while( blio->isInputEmpty ) { + ret = UNIX_ERR( pthread_cond_wait( &blio->inputCond, &blio->inputMutex ) ); + if( ret ) + return ret; + } + ret = UNIX_ERR( pthread_mutex_unlock( &blio->inputMutex ) ); + if( ret ) + return ret; +#else + Pa_Sleep( PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL ); +#endif + } + } while( avail == 0 ); + toRead = MIN( avail, frames * blio->inputSampleSizeActual * blio->inChan ); + toRead -= toRead % blio->inputSampleSizeActual * blio->inChan ; + PaUtil_ReadRingBuffer( &blio->inputRingBuffer, (void *)cbuf, toRead ); + cbuf += toRead; + frames -= toRead / ( blio->inputSampleSizeActual * blio->inChan ); + + if( toRead == avail ) { +#ifdef PA_MAC_BLIO_MUTEX + /* we just emptied the buffer, so we need to mark it as empty. */ + ret = blioSetIsInputEmpty( blio, true ); + if( ret ) + return ret; + /* of course, in the meantime, the callback may have put some sats + in, so + so check for that, too, to avoid a race condition. */ + if( PaUtil_GetRingBufferReadAvailable( &blio->inputRingBuffer ) ) { + blioSetIsInputEmpty( blio, false ); + if( ret ) + return ret; + } +#endif + } + } + + /* Report either paNoError or paInputOverflowed. */ + /* may also want to report other errors, but this is non-standard. */ + ret = blio->statusFlags & paInputOverflow; + + /* report underflow only once: */ + if( ret ) { + OSAtomicAnd32( (uint32_t)(~paInputOverflow), &blio->statusFlags ); + ret = paInputOverflowed; + } + + return ret; +} + + +PaError WriteStream( PaStream* stream, + const void *buffer, + unsigned long frames ) +{ + PaMacBlio *blio = & ((PaMacCoreStream*)stream) -> blio; + char *cbuf = (char *) buffer; + PaError ret = paNoError; + VVDBUG(("WriteStream()\n")); + + while( frames > 0 ) { + long avail = 0; + long toWrite; + + do { + avail = PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer ); +/* + printf( "Write Buffer is %%%g full: %ld of %ld.\n", + 100 - 100 * (float)avail / (float) blio->outputRingBuffer.bufferSize, + avail, blio->outputRingBuffer.bufferSize ); +*/ + if( avail == 0 ) { +#ifdef PA_MAC_BLIO_MUTEX + /*block while full*/ + ret = UNIX_ERR( pthread_mutex_lock( &blio->outputMutex ) ); + if( ret ) + return ret; + while( blio->isOutputFull ) { + ret = UNIX_ERR( pthread_cond_wait( &blio->outputCond, &blio->outputMutex ) ); + if( ret ) + return ret; + } + ret = UNIX_ERR( pthread_mutex_unlock( &blio->outputMutex ) ); + if( ret ) + return ret; +#else + Pa_Sleep( PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL ); +#endif + } + } while( avail == 0 ); + + toWrite = MIN( avail, frames * blio->outputSampleSizeActual * blio->outChan ); + toWrite -= toWrite % blio->outputSampleSizeActual * blio->outChan ; + PaUtil_WriteRingBuffer( &blio->outputRingBuffer, (void *)cbuf, toWrite ); + cbuf += toWrite; + frames -= toWrite / ( blio->outputSampleSizeActual * blio->outChan ); + +#ifdef PA_MAC_BLIO_MUTEX + if( toWrite == avail ) { + /* we just filled up the buffer, so we need to mark it as filled. */ + ret = blioSetIsOutputFull( blio, true ); + if( ret ) + return ret; + /* of course, in the meantime, we may have emptied the buffer, so + so check for that, too, to avoid a race condition. */ + if( PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer ) ) { + blioSetIsOutputFull( blio, false ); + if( ret ) + return ret; + } + } +#endif + } + + /* Report either paNoError or paOutputUnderflowed. */ + /* may also want to report other errors, but this is non-standard. */ + ret = blio->statusFlags & paOutputUnderflow; + + /* report underflow only once: */ + if( ret ) { + OSAtomicAnd32( (uint32_t)(~paOutputUnderflow), &blio->statusFlags ); + ret = paOutputUnderflowed; + } + + return ret; +} + +/* + * + */ +void waitUntilBlioWriteBufferIsFlushed( PaMacBlio *blio ) +{ + if( blio->outputRingBuffer.buffer ) { + long avail = PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer ); + while( avail != blio->outputRingBuffer.bufferSize ) { + if( avail == 0 ) + Pa_Sleep( PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL ); + avail = PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer ); + } + } +} + + +signed long GetStreamReadAvailable( PaStream* stream ) +{ + PaMacBlio *blio = & ((PaMacCoreStream*)stream) -> blio; + VVDBUG(("GetStreamReadAvailable()\n")); + + return PaUtil_GetRingBufferReadAvailable( &blio->inputRingBuffer ) + / ( blio->inputSampleSizeActual * blio->inChan ); +} + + +signed long GetStreamWriteAvailable( PaStream* stream ) +{ + PaMacBlio *blio = & ((PaMacCoreStream*)stream) -> blio; + VVDBUG(("GetStreamWriteAvailable()\n")); + + return PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer ) + / ( blio->outputSampleSizeActual * blio->outChan ); +} + diff --git a/lib-src/portaudio-v19/src/hostapi/coreaudio/pa_mac_core_blocking.h b/lib-src/portaudio-v19/src/hostapi/coreaudio/pa_mac_core_blocking.h index 971223b3c..a6f0ad5dc 100644 --- a/lib-src/portaudio-v19/src/hostapi/coreaudio/pa_mac_core_blocking.h +++ b/lib-src/portaudio-v19/src/hostapi/coreaudio/pa_mac_core_blocking.h @@ -1,136 +1,136 @@ -/* - * Internal blocking interfaces for PortAudio Apple AUHAL implementation - * - * PortAudio Portable Real-Time Audio Library - * Latest Version at: http://www.portaudio.com - * - * Written by Bjorn Roche of XO Audio LLC, from PA skeleton code. - * Portions copied from code by Dominic Mazzoni (who wrote a HAL implementation) - * - * Dominic's code was based on code by Phil Burk, Darren Gibbs, - * Gord Peters, Stephane Letz, and Greg Pfiel. - * - * The following people also deserve acknowledgements: - * - * Olivier Tristan for feedback and testing - * Glenn Zelniker and Z-Systems engineering for sponsoring the Blocking I/O - * interface. - * - * - * Based on the Open Source API proposed by Ross Bencina - * Copyright (c) 1999-2002 Ross Bencina, Phil Burk - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * The text above constitutes the entire PortAudio license; however, - * the PortAudio community also makes the following non-binding requests: - * - * Any person wishing to distribute modifications to the Software is - * requested to send the modifications to the original developer so that - * they can be incorporated into the canonical version. It is also - * requested that these non-binding requests be included along with the - * license above. - */ - -/** - @file - @ingroup hostapi_src -*/ - -#ifndef PA_MAC_CORE_BLOCKING_H_ -#define PA_MAC_CORE_BLOCKING_H_ - -#include "pa_ringbuffer.h" -#include "portaudio.h" -#include "pa_mac_core_utilities.h" - -/* - * Number of miliseconds to busy wait whil waiting for data in blocking calls. - */ -#define PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL (5) -/* - * Define exactly one of these blocking methods - * PA_MAC_BLIO_MUTEX is not actively maintained. - */ -#define PA_MAC_BLIO_BUSY_WAIT -/* -#define PA_MAC_BLIO_MUTEX -*/ - -typedef struct { - PaUtilRingBuffer inputRingBuffer; - PaUtilRingBuffer outputRingBuffer; - size_t ringBufferFrames; - PaSampleFormat inputSampleFormat; - size_t inputSampleSizeActual; - size_t inputSampleSizePow2; - PaSampleFormat outputSampleFormat; - size_t outputSampleSizeActual; - size_t outputSampleSizePow2; - - size_t framesPerBuffer; - - int inChan; - int outChan; - - //PaStreamCallbackFlags statusFlags; - uint32_t statusFlags; - PaError errors; - - /* Here we handle blocking, using condition variables. */ -#ifdef PA_MAC_BLIO_MUTEX - volatile bool isInputEmpty; - pthread_mutex_t inputMutex; - pthread_cond_t inputCond; - - volatile bool isOutputFull; - pthread_mutex_t outputMutex; - pthread_cond_t outputCond; -#endif -} -PaMacBlio; - -/* - * These functions operate on condition and related variables. - */ - -PaError initializeBlioRingBuffers( - PaMacBlio *blio, - PaSampleFormat inputSampleFormat, - PaSampleFormat outputSampleFormat, - size_t framesPerBuffer, - long ringBufferSize, - int inChan, - int outChan ); -PaError destroyBlioRingBuffers( PaMacBlio *blio ); -PaError resetBlioRingBuffers( PaMacBlio *blio ); - -int BlioCallback( - const void *input, void *output, - unsigned long frameCount, - const PaStreamCallbackTimeInfo* timeInfo, - PaStreamCallbackFlags statusFlags, - void *userData ); - -void waitUntilBlioWriteBufferIsFlushed( PaMacBlio *blio ); - -#endif /*PA_MAC_CORE_BLOCKING_H_*/ +/* + * Internal blocking interfaces for PortAudio Apple AUHAL implementation + * + * PortAudio Portable Real-Time Audio Library + * Latest Version at: http://www.portaudio.com + * + * Written by Bjorn Roche of XO Audio LLC, from PA skeleton code. + * Portions copied from code by Dominic Mazzoni (who wrote a HAL implementation) + * + * Dominic's code was based on code by Phil Burk, Darren Gibbs, + * Gord Peters, Stephane Letz, and Greg Pfiel. + * + * The following people also deserve acknowledgements: + * + * Olivier Tristan for feedback and testing + * Glenn Zelniker and Z-Systems engineering for sponsoring the Blocking I/O + * interface. + * + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2002 Ross Bencina, Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** + @file + @ingroup hostapi_src +*/ + +#ifndef PA_MAC_CORE_BLOCKING_H_ +#define PA_MAC_CORE_BLOCKING_H_ + +#include "pa_ringbuffer.h" +#include "portaudio.h" +#include "pa_mac_core_utilities.h" + +/* + * Number of miliseconds to busy wait whil waiting for data in blocking calls. + */ +#define PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL (5) +/* + * Define exactly one of these blocking methods + * PA_MAC_BLIO_MUTEX is not actively maintained. + */ +#define PA_MAC_BLIO_BUSY_WAIT +/* +#define PA_MAC_BLIO_MUTEX +*/ + +typedef struct { + PaUtilRingBuffer inputRingBuffer; + PaUtilRingBuffer outputRingBuffer; + size_t ringBufferFrames; + PaSampleFormat inputSampleFormat; + size_t inputSampleSizeActual; + size_t inputSampleSizePow2; + PaSampleFormat outputSampleFormat; + size_t outputSampleSizeActual; + size_t outputSampleSizePow2; + + size_t framesPerBuffer; + + int inChan; + int outChan; + + //PaStreamCallbackFlags statusFlags; + uint32_t statusFlags; + PaError errors; + + /* Here we handle blocking, using condition variables. */ +#ifdef PA_MAC_BLIO_MUTEX + volatile bool isInputEmpty; + pthread_mutex_t inputMutex; + pthread_cond_t inputCond; + + volatile bool isOutputFull; + pthread_mutex_t outputMutex; + pthread_cond_t outputCond; +#endif +} +PaMacBlio; + +/* + * These functions operate on condition and related variables. + */ + +PaError initializeBlioRingBuffers( + PaMacBlio *blio, + PaSampleFormat inputSampleFormat, + PaSampleFormat outputSampleFormat, + size_t framesPerBuffer, + long ringBufferSize, + int inChan, + int outChan ); +PaError destroyBlioRingBuffers( PaMacBlio *blio ); +PaError resetBlioRingBuffers( PaMacBlio *blio ); + +int BlioCallback( + const void *input, void *output, + unsigned long frameCount, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ); + +void waitUntilBlioWriteBufferIsFlushed( PaMacBlio *blio ); + +#endif /*PA_MAC_CORE_BLOCKING_H_*/ diff --git a/lib-src/portaudio-v19/src/hostapi/wasapi/pa_win_wasapi.cpp b/lib-src/portaudio-v19/src/hostapi/wasapi/pa_win_wasapi.cpp index 498fc6c44..cd8f93440 100644 --- a/lib-src/portaudio-v19/src/hostapi/wasapi/pa_win_wasapi.cpp +++ b/lib-src/portaudio-v19/src/hostapi/wasapi/pa_win_wasapi.cpp @@ -1,1912 +1,1912 @@ -/* - * Portable Audio I/O Library WASAPI implementation - * Copyright (c) 2006-2007 David Viens - * - * Based on the Open Source API proposed by Ross Bencina - * Copyright (c) 1999-2002 Ross Bencina, Phil Burk - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * The text above constitutes the entire PortAudio license; however, - * the PortAudio community also makes the following non-binding requests: - * - * Any person wishing to distribute modifications to the Software is - * requested to send the modifications to the original developer so that - * they can be incorporated into the canonical version. It is also - * requested that these non-binding requests be included along with the - * license above. - */ - -/** @file - @ingroup hostapi_src - @brief WASAPI implementation of support for a host API. - - @note pa_wasapi currently requires VC 2005, and the latest Vista SDK -*/ - -#if _MSC_VER >= 1400 -#include -#include //must be before other Wasapi headers -#include -#include -#include -#include -#include - -#include -#include // PKEY_Device_FriendlyName -#endif - -#include - -#include "pa_util.h" -#include "pa_allocation.h" -#include "pa_hostapi.h" -#include "pa_stream.h" -#include "pa_cpuload.h" -#include "pa_process.h" -#include "pa_debugprint.h" - - -/* - davidv : work in progress. try using with 48000 , then 44100 - and shared mode FIRST. - */ - -#define PORTAUDIO_SHAREMODE AUDCLNT_SHAREMODE_SHARED -//#define PORTAUDIO_SHAREMODE AUDCLNT_SHAREMODE_EXCLUSIVE - -/* use CreateThread for CYGWIN, _beginthreadex for all others */ -#ifndef __CYGWIN__ -#define CREATE_THREAD (HANDLE) _beginthreadex(NULL, 0, (unsigned (_stdcall *)(void *))ProcThread, (LPVOID) stream, 0, (unsigned *)&stream->dwThreadId) -#else -#define CREATE_THREAD CreateThread(NULL, 0, ProcThread, (LPVOID) stream, 0, &stream->dwThreadId) -#endif - -/* prototypes for functions declared in this file */ - -#ifdef __cplusplus -extern "C" -{ -#endif /* __cplusplus */ - -PaError PaWinWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - - - - -static void Terminate( struct PaUtilHostApiRepresentation *hostApi ); -static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, - const PaStreamParameters *inputParameters, - const PaStreamParameters *outputParameters, - double sampleRate ); -static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, - PaStream** s, - const PaStreamParameters *inputParameters, - const PaStreamParameters *outputParameters, - double sampleRate, - unsigned long framesPerBuffer, - PaStreamFlags streamFlags, - PaStreamCallback *streamCallback, - void *userData ); -static PaError CloseStream( PaStream* stream ); -static PaError StartStream( PaStream *stream ); -static PaError StopStream( PaStream *stream ); -static PaError AbortStream( PaStream *stream ); -static PaError IsStreamStopped( PaStream *s ); -static PaError IsStreamActive( PaStream *stream ); -static PaTime GetStreamTime( PaStream *stream ); -static double GetStreamCpuLoad( PaStream* stream ); -static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames ); -static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames ); -static signed long GetStreamReadAvailable( PaStream* stream ); -static signed long GetStreamWriteAvailable( PaStream* stream ); - - -/* IMPLEMENT ME: a macro like the following one should be used for reporting - host errors */ -#define PA_SKELETON_SET_LAST_HOST_ERROR( errorCode, errorText ) \ - PaUtil_SetLastHostErrorInfo( paInDevelopment, errorCode, errorText ) - -/* PaWinWasapiHostApiRepresentation - host api datastructure specific to this implementation */ - - - -//dummy entry point for other compilers and sdks -//currently built using RC1 SDK (5600) -#if _MSC_VER < 1400 - -PaError PaWinWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ){ - return paNoError; -} - -#else - - - - -#define MAX_STR_LEN 512 - -/* - These are fields that can be gathered from IDevice - and IAudioDevice PRIOR to Initialize, and done in first pass - i assume that neither of these will cause the Driver to "load", - but again, who knows how they implement their stuff - */ -typedef struct PaWinWasapiDeviceInfo -{ - //hmm is it wise to keep a reference until Terminate? - //TODO Check if that interface requires the driver to be loaded! - IMMDevice * device; - - //Fields filled from IDevice - //from GetId - WCHAR szDeviceID[MAX_STR_LEN]; - //from GetState - DWORD state; - - //Fields filled from IMMEndpoint'sGetDataFlow - EDataFlow flow; - - //Fields filled from IAudioDevice (_prior_ to Initialize) - //from GetDevicePeriod( - REFERENCE_TIME DefaultDevicePeriod; - REFERENCE_TIME MinimumDevicePeriod; - //from GetMixFormat - WAVEFORMATEX *MixFormat;//needs to be CoTaskMemFree'd after use! - -} PaWinWasapiDeviceInfo; - - -typedef struct -{ - PaUtilHostApiRepresentation inheritedHostApiRep; - PaUtilStreamInterface callbackStreamInterface; - PaUtilStreamInterface blockingStreamInterface; - - PaUtilAllocationGroup *allocations; - - /* implementation specific data goes here */ - - //in case we later need the synch - IMMDeviceEnumerator * enumerator; - - //this is the REAL number of devices, whether they are usefull to PA or not! - UINT deviceCount; - - WCHAR defaultRenderer [MAX_STR_LEN]; - WCHAR defaultCapturer [MAX_STR_LEN]; - - PaWinWasapiDeviceInfo *devInfo; -}PaWinWasapiHostApiRepresentation; - - -/* PaWinWasapiStream - a stream data structure specifically for this implementation */ - -typedef struct PaWinWasapiSubStream{ - IAudioClient *client; - WAVEFORMATEXTENSIBLE wavex; - UINT32 bufferSize; - REFERENCE_TIME latency; - REFERENCE_TIME period; - unsigned long framesPerHostCallback; /* just an example */ -}PaWinWasapiSubStream; - -typedef struct PaWinWasapiStream -{ /* IMPLEMENT ME: rename this */ - PaUtilStreamRepresentation streamRepresentation; - PaUtilCpuLoadMeasurer cpuLoadMeasurer; - PaUtilBufferProcessor bufferProcessor; - - /* IMPLEMENT ME: - - implementation specific data goes here - */ - - - //input - PaWinWasapiSubStream in; - IAudioCaptureClient *cclient; - IAudioEndpointVolume *inVol; - //output - PaWinWasapiSubStream out; - IAudioRenderClient *rclient; - IAudioEndpointVolume *outVol; - - bool running; - bool closeRequest; - - DWORD dwThreadId; - HANDLE hThread; - HANDLE hNotificationEvent; - - GUID session; - -}PaWinWasapiStream; - -#define PRINT(x) PA_DEBUG(x); - -void -logAUDCLNT_E(HRESULT res){ - - char *text = 0; - switch(res){ - case S_OK: return; break; - case E_POINTER :text ="E_POINTER"; break; - case E_INVALIDARG :text ="E_INVALIDARG"; break; - - case AUDCLNT_E_NOT_INITIALIZED :text ="AUDCLNT_E_NOT_INITIALIZED"; break; - case AUDCLNT_E_ALREADY_INITIALIZED :text ="AUDCLNT_E_ALREADY_INITIALIZED"; break; - case AUDCLNT_E_WRONG_ENDPOINT_TYPE :text ="AUDCLNT_E_WRONG_ENDPOINT_TYPE"; break; - case AUDCLNT_E_DEVICE_INVALIDATED :text ="AUDCLNT_E_DEVICE_INVALIDATED"; break; - case AUDCLNT_E_NOT_STOPPED :text ="AUDCLNT_E_NOT_STOPPED"; break; - case AUDCLNT_E_BUFFER_TOO_LARGE :text ="AUDCLNT_E_BUFFER_TOO_LARGE"; break; - case AUDCLNT_E_OUT_OF_ORDER :text ="AUDCLNT_E_OUT_OF_ORDER"; break; - case AUDCLNT_E_UNSUPPORTED_FORMAT :text ="AUDCLNT_E_UNSUPPORTED_FORMAT"; break; - case AUDCLNT_E_INVALID_SIZE :text ="AUDCLNT_E_INVALID_SIZE"; break; - case AUDCLNT_E_DEVICE_IN_USE :text ="AUDCLNT_E_DEVICE_IN_USE"; break; - case AUDCLNT_E_BUFFER_OPERATION_PENDING :text ="AUDCLNT_E_BUFFER_OPERATION_PENDING"; break; - case AUDCLNT_E_THREAD_NOT_REGISTERED :text ="AUDCLNT_E_THREAD_NOT_REGISTERED"; break; - case AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED :text ="AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED"; break; - case AUDCLNT_E_ENDPOINT_CREATE_FAILED :text ="AUDCLNT_E_ENDPOINT_CREATE_FAILED"; break; - case AUDCLNT_E_SERVICE_NOT_RUNNING :text ="AUDCLNT_E_SERVICE_NOT_RUNNING"; break; - // case AUDCLNT_E_CPUUSAGE_EXCEEDED :text ="AUDCLNT_E_CPUUSAGE_EXCEEDED"; break; - //Header error? - case AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED :text ="AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED"; break; - case AUDCLNT_E_EXCLUSIVE_MODE_ONLY :text ="AUDCLNT_E_EXCLUSIVE_MODE_ONLY"; break; - case AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL :text ="AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL"; break; - case AUDCLNT_E_EVENTHANDLE_NOT_SET :text ="AUDCLNT_E_EVENTHANDLE_NOT_SET"; break; - case AUDCLNT_E_INCORRECT_BUFFER_SIZE :text ="AUDCLNT_E_INCORRECT_BUFFER_SIZE"; break; - case AUDCLNT_E_BUFFER_SIZE_ERROR :text ="AUDCLNT_E_BUFFER_SIZE_ERROR"; break; - case AUDCLNT_S_BUFFER_EMPTY :text ="AUDCLNT_S_BUFFER_EMPTY"; break; - case AUDCLNT_S_THREAD_ALREADY_REGISTERED :text ="AUDCLNT_S_THREAD_ALREADY_REGISTERED"; break; - default: - text =" dunno!"; - return ; - break; - - } - PRINT(("WASAPI ERROR HRESULT: 0x%X : %s\n",res,text)); -} - -inline double -nano100ToMillis(const REFERENCE_TIME &ref){ - // 1 nano = 0.000000001 seconds - //100 nano = 0.0000001 seconds - //100 nano = 0.0001 milliseconds - return ((double)ref)*0.0001; -} - -inline double -nano100ToSeconds(const REFERENCE_TIME &ref){ - // 1 nano = 0.000000001 seconds - //100 nano = 0.0000001 seconds - //100 nano = 0.0001 milliseconds - return ((double)ref)*0.0000001; -} - -#ifndef IF_FAILED_JUMP -#define IF_FAILED_JUMP(hr, label) if(FAILED(hr)) goto label; -#endif - - - -//AVRT is the new "multimedia schedulling stuff" - -typedef BOOL (WINAPI *FAvRtCreateThreadOrderingGroup) (PHANDLE,PLARGE_INTEGER,GUID*,PLARGE_INTEGER); -typedef BOOL (WINAPI *FAvRtDeleteThreadOrderingGroup) (HANDLE); -typedef BOOL (WINAPI *FAvRtWaitOnThreadOrderingGroup) (HANDLE); -typedef HANDLE (WINAPI *FAvSetMmThreadCharacteristics) (LPCTSTR,LPDWORD); -typedef BOOL (WINAPI *FAvSetMmThreadPriority) (HANDLE,AVRT_PRIORITY); - -HMODULE hDInputDLL = 0; -FAvRtCreateThreadOrderingGroup pAvRtCreateThreadOrderingGroup=0; -FAvRtDeleteThreadOrderingGroup pAvRtDeleteThreadOrderingGroup=0; -FAvRtWaitOnThreadOrderingGroup pAvRtWaitOnThreadOrderingGroup=0; -FAvSetMmThreadCharacteristics pAvSetMmThreadCharacteristics=0; -FAvSetMmThreadPriority pAvSetMmThreadPriority=0; - - - -#define setupPTR(fun, type, name) { \ - fun = (type) GetProcAddress(hDInputDLL,name); \ - if(fun == NULL) { \ - PRINT(("GetProcAddr failed for %s" ,name)); \ - return false; \ - } \ - } \ - -bool -setupAVRT(){ - - hDInputDLL = LoadLibraryA("avrt.dll"); - if(hDInputDLL == NULL) - return false; - - setupPTR(pAvRtCreateThreadOrderingGroup, FAvRtCreateThreadOrderingGroup, "AvRtCreateThreadOrderingGroup"); - setupPTR(pAvRtDeleteThreadOrderingGroup, FAvRtDeleteThreadOrderingGroup, "AvRtDeleteThreadOrderingGroup"); - setupPTR(pAvRtWaitOnThreadOrderingGroup, FAvRtWaitOnThreadOrderingGroup, "AvRtWaitOnThreadOrderingGroup"); - setupPTR(pAvSetMmThreadCharacteristics, FAvSetMmThreadCharacteristics, "AvSetMmThreadCharacteristicsA"); - setupPTR(pAvSetMmThreadPriority, FAvSetMmThreadPriority, "AvSetMmThreadPriority"); - - return true; -} - - - -PaError PaWinWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ) -{ - if (!setupAVRT()){ - PRINT(("Windows WASAPI : No AVRT! (not VISTA?)")); - return paNoError; - } - - CoInitialize(NULL); - - PaError result = paNoError; - PaWinWasapiHostApiRepresentation *paWasapi; - PaDeviceInfo *deviceInfoArray; - - paWasapi = (PaWinWasapiHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaWinWasapiHostApiRepresentation) ); - if( !paWasapi ){ - result = paInsufficientMemory; - goto error; - } - - paWasapi->allocations = PaUtil_CreateAllocationGroup(); - if( !paWasapi->allocations ){ - result = paInsufficientMemory; - goto error; - } - - *hostApi = &paWasapi->inheritedHostApiRep; - (*hostApi)->info.structVersion = 1; - (*hostApi)->info.type = paWASAPI; - (*hostApi)->info.name = "Windows WASAPI"; - (*hostApi)->info.deviceCount = 0; //so far, we must investigate each - (*hostApi)->info.defaultInputDevice = paNoDevice; /* IMPLEMENT ME */ - (*hostApi)->info.defaultOutputDevice = paNoDevice; /* IMPLEMENT ME */ - - - HRESULT hResult = S_OK; - IMMDeviceCollection* spEndpoints=0; - paWasapi->enumerator = 0; - - hResult = CoCreateInstance( - __uuidof(MMDeviceEnumerator), NULL,CLSCTX_INPROC_SERVER, - __uuidof(IMMDeviceEnumerator), - (void**)&paWasapi->enumerator); - - IF_FAILED_JUMP(hResult, error); - - //getting default device ids in the eMultimedia "role" - { - { - IMMDevice* defaultRenderer=0; - hResult = paWasapi->enumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, &defaultRenderer); - IF_FAILED_JUMP(hResult, error); - WCHAR* pszDeviceId = NULL; - hResult = defaultRenderer->GetId(&pszDeviceId); - IF_FAILED_JUMP(hResult, error); - StringCchCopyW(paWasapi->defaultRenderer, MAX_STR_LEN-1, pszDeviceId); - CoTaskMemFree(pszDeviceId); - defaultRenderer->Release(); - } - - { - IMMDevice* defaultCapturer=0; - hResult = paWasapi->enumerator->GetDefaultAudioEndpoint(eCapture, eMultimedia, &defaultCapturer); - IF_FAILED_JUMP(hResult, error); - WCHAR* pszDeviceId = NULL; - hResult = defaultCapturer->GetId(&pszDeviceId); - IF_FAILED_JUMP(hResult, error); - StringCchCopyW(paWasapi->defaultCapturer, MAX_STR_LEN-1, pszDeviceId); - CoTaskMemFree(pszDeviceId); - defaultCapturer->Release(); - } - } - - - hResult = paWasapi->enumerator->EnumAudioEndpoints(eAll, DEVICE_STATE_ACTIVE, &spEndpoints); - IF_FAILED_JUMP(hResult, error); - - hResult = spEndpoints->GetCount(&paWasapi->deviceCount); - IF_FAILED_JUMP(hResult, error); - - paWasapi->devInfo = new PaWinWasapiDeviceInfo[paWasapi->deviceCount]; - { - for (size_t step=0;stepdeviceCount;++step) - memset(&paWasapi->devInfo[step],0,sizeof(PaWinWasapiDeviceInfo)); - } - - - - if( paWasapi->deviceCount > 0 ) - { - (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory( - paWasapi->allocations, sizeof(PaDeviceInfo*) * paWasapi->deviceCount ); - if( !(*hostApi)->deviceInfos ){ - result = paInsufficientMemory; - goto error; - } - - /* allocate all device info structs in a contiguous block */ - deviceInfoArray = (PaDeviceInfo*)PaUtil_GroupAllocateMemory( - paWasapi->allocations, sizeof(PaDeviceInfo) * paWasapi->deviceCount ); - if( !deviceInfoArray ){ - result = paInsufficientMemory; - goto error; - } - - for( UINT i=0; i < paWasapi->deviceCount; ++i ){ - - PA_DEBUG(("i:%d\n",i)); - PaDeviceInfo *deviceInfo = &deviceInfoArray[i]; - deviceInfo->structVersion = 2; - deviceInfo->hostApi = hostApiIndex; - - hResult = spEndpoints->Item(i, &paWasapi->devInfo[i].device); - IF_FAILED_JUMP(hResult, error); - - //getting ID - { - WCHAR* pszDeviceId = NULL; - hResult = paWasapi->devInfo[i].device->GetId(&pszDeviceId); - IF_FAILED_JUMP(hResult, error); - StringCchCopyW(paWasapi->devInfo[i].szDeviceID, MAX_STR_LEN-1, pszDeviceId); - CoTaskMemFree(pszDeviceId); - - if (lstrcmpW(paWasapi->devInfo[i].szDeviceID, paWasapi->defaultCapturer)==0){ - //we found the default input! - (*hostApi)->info.defaultInputDevice = (*hostApi)->info.deviceCount; - } - if (lstrcmpW(paWasapi->devInfo[i].szDeviceID, paWasapi->defaultRenderer)==0){ - //we found the default output! - (*hostApi)->info.defaultOutputDevice = (*hostApi)->info.deviceCount; - } - } - - DWORD state=0; - hResult = paWasapi->devInfo[i].device->GetState(&paWasapi->devInfo[i].state); - IF_FAILED_JUMP(hResult, error); - - if (paWasapi->devInfo[i].state != DEVICE_STATE_ACTIVE){ - PRINT(("WASAPI device:%d is not currently available (state:%d)\n",i,state)); - //spDevice->Release(); - //continue; - } - - { - IPropertyStore* spProperties; - hResult = paWasapi->devInfo[i].device->OpenPropertyStore(STGM_READ, &spProperties); - IF_FAILED_JUMP(hResult, error); - - //getting "Friendly" Name - { - PROPVARIANT value; - PropVariantInit(&value); - hResult = spProperties->GetValue(PKEY_Device_FriendlyName, &value); - IF_FAILED_JUMP(hResult, error); - deviceInfo->name = 0; - char* deviceName = (char*)PaUtil_GroupAllocateMemory( paWasapi->allocations, MAX_STR_LEN + 1 ); - if( !deviceName ){ - result = paInsufficientMemory; - goto error; - } - if (value.pwszVal) - wcstombs(deviceName, value.pwszVal,MAX_STR_LEN-1); //todo proper size - else{ - _snprintf_s(deviceName,MAX_STR_LEN-1,MAX_STR_LEN-1,"baddev%d",i); - } - - deviceInfo->name = deviceName; - PropVariantClear(&value); - } - -#if 0 - DWORD numProps = 0; - hResult = spProperties->GetCount(&numProps); - IF_FAILED_JUMP(hResult, error); - { - for (DWORD i=0;iGetAt(i,&pkey); - - PROPVARIANT value; - PropVariantInit(&value); - hResult = spProperties->GetValue(pkey, &value); - - switch(value.vt){ - case 11: - PRINT(("property*%u*\n",value.ulVal)); - break; - case 19: - PRINT(("property*%d*\n",value.boolVal)); - break; - case 31: - { - char temp[512]; - wcstombs(temp, value.pwszVal,MAX_STR_LEN-1); - PRINT(("property*%s*\n",temp)); - } - break; - default:break; - } - - PropVariantClear(&value); - } - } -#endif - - /* These look interresting... but they are undocumented - PKEY_AudioEndpoint_FormFactor - PKEY_AudioEndpoint_ControlPanelPageProvider - PKEY_AudioEndpoint_Association - PKEY_AudioEndpoint_PhysicalSpeakerConfig - PKEY_AudioEngine_DeviceFormat - */ - spProperties->Release(); - } - - - //getting the Endpoint data - { - IMMEndpoint *endpoint=0; - hResult = paWasapi->devInfo[i].device->QueryInterface(__uuidof(IMMEndpoint),(void **)&endpoint); - if (SUCCEEDED(hResult)){ - hResult = endpoint->GetDataFlow(&paWasapi->devInfo[i].flow); - endpoint->Release(); - } - } - - //Getting a temporary IAudioDevice for more fields - //we make sure NOT to call Initialize yet! - { - IAudioClient *myClient=0; - - hResult = paWasapi->devInfo[i].device->Activate(__uuidof(IAudioClient), CLSCTX_INPROC_SERVER, NULL, (void**)&myClient); - IF_FAILED_JUMP(hResult, error); - - hResult = myClient->GetDevicePeriod( - &paWasapi->devInfo[i].DefaultDevicePeriod, - &paWasapi->devInfo[i].MinimumDevicePeriod); - IF_FAILED_JUMP(hResult, error); - - hResult = myClient->GetMixFormat(&paWasapi->devInfo[i].MixFormat); - - if (hResult != S_OK){ - /*davidv: this happened with my hardware, previously for that same device in DirectSound: - Digital Output (Realtek AC'97 Audio)'s GUID: {0x38f2cf50,0x7b4c,0x4740,0x86,0xeb,0xd4,0x38,0x66,0xd8,0xc8, 0x9f} - so something must be _really_ wrong with this device, TODO handle this better. We kind of need GetMixFormat*/ - logAUDCLNT_E(hResult); - goto error; - } - - myClient->Release(); - } - - //we can now fill in portaudio device data - deviceInfo->maxInputChannels = 0; //for now - deviceInfo->maxOutputChannels = 0; //for now - - switch(paWasapi->devInfo[i].flow){ - case eRender: - //hum not exaclty maximum, more like "default" - deviceInfo->maxOutputChannels = paWasapi->devInfo[i].MixFormat->nChannels; - - deviceInfo->defaultHighOutputLatency = nano100ToSeconds(paWasapi->devInfo[i].DefaultDevicePeriod); - deviceInfo->defaultLowOutputLatency = nano100ToSeconds(paWasapi->devInfo[i].MinimumDevicePeriod); - break; - case eCapture: - //hum not exaclty maximum, more like "default" - deviceInfo->maxInputChannels = paWasapi->devInfo[i].MixFormat->nChannels; - - deviceInfo->defaultHighInputLatency = nano100ToSeconds(paWasapi->devInfo[i].DefaultDevicePeriod); - deviceInfo->defaultLowInputLatency = nano100ToSeconds(paWasapi->devInfo[i].MinimumDevicePeriod); - break; - default: - PRINT(("WASAPI device:%d bad Data FLow! \n",i)); - goto error; - break; - } - - deviceInfo->defaultSampleRate = (double)paWasapi->devInfo[i].MixFormat->nSamplesPerSec; - - (*hostApi)->deviceInfos[i] = deviceInfo; - ++(*hostApi)->info.deviceCount; - } - } - - spEndpoints->Release(); - - (*hostApi)->Terminate = Terminate; - (*hostApi)->OpenStream = OpenStream; - (*hostApi)->IsFormatSupported = IsFormatSupported; - - PaUtil_InitializeStreamInterface( &paWasapi->callbackStreamInterface, CloseStream, StartStream, - StopStream, AbortStream, IsStreamStopped, IsStreamActive, - GetStreamTime, GetStreamCpuLoad, - PaUtil_DummyRead, PaUtil_DummyWrite, - PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable ); - - PaUtil_InitializeStreamInterface( &paWasapi->blockingStreamInterface, CloseStream, StartStream, - StopStream, AbortStream, IsStreamStopped, IsStreamActive, - GetStreamTime, PaUtil_DummyGetCpuLoad, - ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable ); - - return result; - -error: - - if (spEndpoints) - spEndpoints->Release(); - - if (paWasapi->enumerator) - paWasapi->enumerator->Release(); - - if( paWasapi ) - { - if( paWasapi->allocations ) - { - PaUtil_FreeAllAllocations( paWasapi->allocations ); - PaUtil_DestroyAllocationGroup( paWasapi->allocations ); - } - - PaUtil_FreeMemory( paWasapi ); - } - return result; -} - - -static void Terminate( struct PaUtilHostApiRepresentation *hostApi ) -{ - PaWinWasapiHostApiRepresentation *paWasapi = (PaWinWasapiHostApiRepresentation*)hostApi; - - paWasapi->enumerator->Release(); - - for (UINT i=0;ideviceCount;++i){ - PaWinWasapiDeviceInfo *info = &paWasapi->devInfo[i]; - - if (info->device) - info->device->Release(); - - if (info->MixFormat) - CoTaskMemFree(info->MixFormat); - } - delete [] paWasapi->devInfo; - - CoUninitialize(); - - if( paWasapi->allocations ){ - PaUtil_FreeAllAllocations( paWasapi->allocations ); - PaUtil_DestroyAllocationGroup( paWasapi->allocations ); - } - - PaUtil_FreeMemory( paWasapi ); -} - -static void -LogWAVEFORMATEXTENSIBLE(const WAVEFORMATEXTENSIBLE *in){ - - const WAVEFORMATEX *old = (WAVEFORMATEX *)in; - - switch (old->wFormatTag){ - case WAVE_FORMAT_EXTENSIBLE:{ - - PRINT(("wFormatTag=WAVE_FORMAT_EXTENSIBLE\n")); - - if (in->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT){ - PRINT(("SubFormat=KSDATAFORMAT_SUBTYPE_IEEE_FLOAT\n")); - } - else if (in->SubFormat == KSDATAFORMAT_SUBTYPE_PCM){ - PRINT(("SubFormat=KSDATAFORMAT_SUBTYPE_PCM\n")); - } - else{ - PRINT(("SubFormat=CUSTOM GUID{%d:%d:%d:%d%d%d%d%d%d%d%d}\n", - in->SubFormat.Data1, - in->SubFormat.Data2, - in->SubFormat.Data3, - (int)in->SubFormat.Data4[0], - (int)in->SubFormat.Data4[1], - (int)in->SubFormat.Data4[2], - (int)in->SubFormat.Data4[3], - (int)in->SubFormat.Data4[4], - (int)in->SubFormat.Data4[5], - (int)in->SubFormat.Data4[6], - (int)in->SubFormat.Data4[7])); - } - PRINT(("Samples.wValidBitsPerSample=%d\n", in->Samples.wValidBitsPerSample)); - PRINT(("dwChannelMask=0x%X\n",in->dwChannelMask)); - }break; - - case WAVE_FORMAT_PCM: PRINT(("wFormatTag=WAVE_FORMAT_PCM\n")); break; - case WAVE_FORMAT_IEEE_FLOAT: PRINT(("wFormatTag=WAVE_FORMAT_IEEE_FLOAT\n")); break; - default : PRINT(("wFormatTag=UNKNOWN(%d)\n",old->wFormatTag)); break; - } - - PRINT(("nChannels =%d\n",old->nChannels)); - PRINT(("nSamplesPerSec =%d\n",old->nSamplesPerSec)); - PRINT(("nAvgBytesPerSec=%d\n",old->nAvgBytesPerSec)); - PRINT(("nBlockAlign =%d\n",old->nBlockAlign)); - PRINT(("wBitsPerSample =%d\n",old->wBitsPerSample)); - PRINT(("cbSize =%d\n",old->cbSize)); -} - - - -/* - WAVEFORMATXXX is always interleaved - */ -static PaSampleFormat -waveformatToPaFormat(const WAVEFORMATEXTENSIBLE *in){ - - const WAVEFORMATEX *old = (WAVEFORMATEX*)in; - - switch (old->wFormatTag){ - - case WAVE_FORMAT_EXTENSIBLE: - { - if (in->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT){ - if (in->Samples.wValidBitsPerSample == 32) - return paFloat32; - else - return paCustomFormat; - } - else if (in->SubFormat == KSDATAFORMAT_SUBTYPE_PCM){ - switch (old->wBitsPerSample){ - case 32: return paInt32; break; - case 24: return paInt24;break; - case 8: return paUInt8;break; - case 16: return paInt16;break; - default: return paCustomFormat;break; - } - } - else - return paCustomFormat; - } - break; - - case WAVE_FORMAT_IEEE_FLOAT: - return paFloat32; - break; - - case WAVE_FORMAT_PCM: - { - switch (old->wBitsPerSample){ - case 32: return paInt32; break; - case 24: return paInt24;break; - case 8: return paUInt8;break; - case 16: return paInt16;break; - default: return paCustomFormat;break; - } - } - break; - - default: - return paCustomFormat; - break; - } - - return paCustomFormat; -} - - - -static PaError -waveformatFromParams(WAVEFORMATEXTENSIBLE*wavex, - const PaStreamParameters * params, - double sampleRate){ - - size_t bytesPerSample = 0; - switch( params->sampleFormat & ~paNonInterleaved ){ - case paFloat32: - case paInt32: bytesPerSample=4;break; - case paInt16: bytesPerSample=2;break; - case paInt24: bytesPerSample=3;break; - case paInt8: - case paUInt8: bytesPerSample=1;break; - case paCustomFormat: - default: return paSampleFormatNotSupported;break; - } - - memset(wavex,0,sizeof(WAVEFORMATEXTENSIBLE)); - - WAVEFORMATEX *old = (WAVEFORMATEX *)wavex; - old->nChannels = (WORD)params->channelCount; - old->nSamplesPerSec = (DWORD)sampleRate; - old->wBitsPerSample = (WORD)(bytesPerSample*8); - old->nAvgBytesPerSec = (DWORD)(old->nSamplesPerSec * old->nChannels * bytesPerSample); - old->nBlockAlign = (WORD)(old->nChannels * bytesPerSample); - - //WAVEFORMATEX - if (params->channelCount <=2 && (bytesPerSample == 2 || bytesPerSample == 1)){ - old->cbSize = 0; - old->wFormatTag = WAVE_FORMAT_PCM; - } - //WAVEFORMATEXTENSIBLE - else{ - old->wFormatTag = WAVE_FORMAT_EXTENSIBLE; - - old->cbSize = sizeof (WAVEFORMATEXTENSIBLE) - sizeof (WAVEFORMATEX); - - if ((params->sampleFormat & ~paNonInterleaved) == paFloat32) - wavex->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; - else - wavex->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - - wavex->Samples.wValidBitsPerSample = old->wBitsPerSample; //no extra padding! - - switch(params->channelCount){ - case 1: wavex->dwChannelMask = SPEAKER_FRONT_CENTER; break; - case 2: wavex->dwChannelMask = 0x1 | 0x2; break; - case 4: wavex->dwChannelMask = 0x1 | 0x2 | 0x10 | 0x20; break; - case 6: wavex->dwChannelMask = 0x1 | 0x2 | 0x4 | 0x8 | 0x10 | 0x20; break; - case 8: wavex->dwChannelMask = 0x1 | 0x2 | 0x4 | 0x8 | 0x10 | 0x20 | 0x40 | 0x80; break; - default: wavex->dwChannelMask = 0; break; - } - } - - return paNoError; -} - - - - - - -/* -#define paFloat32 ((PaSampleFormat) 0x00000001) -#define paInt32 ((PaSampleFormat) 0x00000002) -#define paInt24 ((PaSampleFormat) 0x00000004) -#define paInt16 ((PaSampleFormat) 0x00000008) -*/ -//lifted from pa_wdmks -static void wasapiFillWFEXT( WAVEFORMATEXTENSIBLE* pwfext, PaSampleFormat sampleFormat, double sampleRate, int channelCount) -{ - PA_DEBUG(( "sampleFormat = %lx\n" , sampleFormat )); - PA_DEBUG(( "sampleRate = %f\n" , sampleRate )); - PA_DEBUG(( "chanelCount = %d\n", channelCount )); - - pwfext->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; - pwfext->Format.nChannels = channelCount; - pwfext->Format.nSamplesPerSec = (int)sampleRate; - if(channelCount == 1) - pwfext->dwChannelMask = KSAUDIO_SPEAKER_DIRECTOUT; - else - pwfext->dwChannelMask = KSAUDIO_SPEAKER_STEREO; - if(sampleFormat == paFloat32) - { - pwfext->Format.nBlockAlign = channelCount * 4; - pwfext->Format.wBitsPerSample = 32; - pwfext->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX); - pwfext->Samples.wValidBitsPerSample = 32; - pwfext->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; - } - else if(sampleFormat == paInt32) - { - pwfext->Format.nBlockAlign = channelCount * 4; - pwfext->Format.wBitsPerSample = 32; - pwfext->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX); - pwfext->Samples.wValidBitsPerSample = 32; - pwfext->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - } - else if(sampleFormat == paInt24) - { - pwfext->Format.nBlockAlign = channelCount * 3; - pwfext->Format.wBitsPerSample = 24; - pwfext->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX); - pwfext->Samples.wValidBitsPerSample = 24; - pwfext->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - } - else if(sampleFormat == paInt16) - { - pwfext->Format.nBlockAlign = channelCount * 2; - pwfext->Format.wBitsPerSample = 16; - pwfext->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX); - pwfext->Samples.wValidBitsPerSample = 16; - pwfext->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - } - pwfext->Format.nAvgBytesPerSec = pwfext->Format.nSamplesPerSec * pwfext->Format.nBlockAlign; -} - - - -/* -#define FORMATTESTS 4 -const int BestToWorst[FORMATTESTS]={paFloat32,paInt32,paInt24,paInt16}; -*/ - -#define FORMATTESTS 3 -const int BestToWorst[FORMATTESTS]={paFloat32,paInt24,paInt16}; - - -static PaError -GetClosestFormat(IAudioClient * myClient, double sampleRate,const PaStreamParameters * params, - AUDCLNT_SHAREMODE *shareMode, WAVEFORMATEXTENSIBLE *outWavex) -{ - //TODO we should try exclusive first and shared after - *shareMode = PORTAUDIO_SHAREMODE; - - PaError answer = paInvalidSampleRate; - - waveformatFromParams(outWavex,params,sampleRate); - WAVEFORMATEX *sharedClosestMatch=0; - HRESULT hResult=!S_OK; - - if (*shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE) - hResult = myClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE,&outWavex->Format,NULL); - else - hResult = myClient->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, &outWavex->Format,&sharedClosestMatch); - - if (hResult == S_OK) - answer = paFormatIsSupported; - else if (sharedClosestMatch){ - WAVEFORMATEXTENSIBLE* ext = (WAVEFORMATEXTENSIBLE*)sharedClosestMatch; - - int closestMatchSR = (int)sharedClosestMatch->nSamplesPerSec; - - if (sharedClosestMatch->wFormatTag == WAVE_FORMAT_EXTENSIBLE) - memcpy(outWavex,sharedClosestMatch,sizeof(WAVEFORMATEXTENSIBLE)); - else - memcpy(outWavex,sharedClosestMatch,sizeof(WAVEFORMATEX)); - - CoTaskMemFree(sharedClosestMatch); - - if ((int)sampleRate == closestMatchSR) - answer = paFormatIsSupported; - else - answer = paInvalidSampleRate; - - }else { - - //it doesnt suggest anything?? ok lets show it the MENU! - - //ok fun time as with pa_win_mme, we know only a refusal of the user-requested - //sampleRate+num Channel is disastrous, as the portaudio buffer processor converts between anything - //so lets only use the number - for (int i=0;ichannelCount); - if (*shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE) - hResult = myClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE,&ext.Format,NULL); - else - hResult = myClient->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, &ext.Format,&sharedClosestMatch); - - if (hResult == S_OK){ - memcpy(outWavex,&ext,sizeof(WAVEFORMATEXTENSIBLE)); - answer = paFormatIsSupported; - break; - } - } - - if (answer!=paFormatIsSupported) { - //try MIX format? - //why did it HAVE to come to this .... - WAVEFORMATEX pcm16WaveFormat; - memset(&pcm16WaveFormat,0,sizeof(WAVEFORMATEX)); - pcm16WaveFormat.wFormatTag = WAVE_FORMAT_PCM; - pcm16WaveFormat.nChannels = 2; - pcm16WaveFormat.nSamplesPerSec = (DWORD)sampleRate; - pcm16WaveFormat.nBlockAlign = 4; - pcm16WaveFormat.nAvgBytesPerSec = pcm16WaveFormat.nSamplesPerSec*pcm16WaveFormat.nBlockAlign; - pcm16WaveFormat.wBitsPerSample = 16; - pcm16WaveFormat.cbSize = 0; - - if (*shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE) - hResult = myClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE,&pcm16WaveFormat,NULL); - else - hResult = myClient->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, &pcm16WaveFormat,&sharedClosestMatch); - - if (hResult == S_OK){ - memcpy(outWavex,&pcm16WaveFormat,sizeof(WAVEFORMATEX)); - answer = paFormatIsSupported; - } - } - - logAUDCLNT_E(hResult); - } - - return answer; -} - - -static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, - const PaStreamParameters *inputParameters, - const PaStreamParameters *outputParameters, - double sampleRate ) -{ - - int inputChannelCount, outputChannelCount; - PaSampleFormat inputSampleFormat, outputSampleFormat; - - if( inputParameters ) - { - inputChannelCount = inputParameters->channelCount; - inputSampleFormat = inputParameters->sampleFormat; - - /* all standard sample formats are supported by the buffer adapter, - this implementation doesn't support any custom sample formats */ - if( inputSampleFormat & paCustomFormat ) - return paSampleFormatNotSupported; - - /* unless alternate device specification is supported, reject the use of - paUseHostApiSpecificDeviceSpecification */ - - if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) - return paInvalidDevice; - - /* check that input device can support inputChannelCount */ - if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels ) - return paInvalidChannelCount; - - /* validate inputStreamInfo */ - if( inputParameters->hostApiSpecificStreamInfo ) - return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ - - - PaWinWasapiHostApiRepresentation *paWasapi = (PaWinWasapiHostApiRepresentation*)hostApi; - - - IAudioClient *myClient=0; - HRESULT hResult = paWasapi->devInfo[inputParameters->device].device->Activate( - __uuidof(IAudioClient), CLSCTX_INPROC_SERVER, NULL, (void**)&myClient); - if (hResult != S_OK){ - logAUDCLNT_E(hResult); - return paInvalidDevice; - } - - WAVEFORMATEXTENSIBLE wavex; - AUDCLNT_SHAREMODE shareMode; - PaError answer = GetClosestFormat(myClient,sampleRate,inputParameters,&shareMode,&wavex); - myClient->Release(); - - if (answer !=paFormatIsSupported) - return answer; - } - else - { - inputChannelCount = 0; - } - - if( outputParameters ) - { - outputChannelCount = outputParameters->channelCount; - outputSampleFormat = outputParameters->sampleFormat; - - /* all standard sample formats are supported by the buffer adapter, - this implementation doesn't support any custom sample formats */ - if( outputSampleFormat & paCustomFormat ) - return paSampleFormatNotSupported; - - /* unless alternate device specification is supported, reject the use of - paUseHostApiSpecificDeviceSpecification */ - - if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) - return paInvalidDevice; - - /* check that output device can support outputChannelCount */ - if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels ) - return paInvalidChannelCount; - - /* validate outputStreamInfo */ - if( outputParameters->hostApiSpecificStreamInfo ) - return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ - - - PaWinWasapiHostApiRepresentation *paWasapi = (PaWinWasapiHostApiRepresentation*)hostApi; - - IAudioClient *myClient=0; - HRESULT hResult = paWasapi->devInfo[outputParameters->device].device->Activate( - __uuidof(IAudioClient), CLSCTX_INPROC_SERVER, NULL, (void**)&myClient); - if (hResult != S_OK){ - logAUDCLNT_E(hResult); - return paInvalidDevice; - } - - WAVEFORMATEXTENSIBLE wavex; - AUDCLNT_SHAREMODE shareMode; - PaError answer = GetClosestFormat(myClient,sampleRate,outputParameters,&shareMode,&wavex); - myClient->Release(); - - if (answer !=paFormatIsSupported) - return answer; - } - else - { - outputChannelCount = 0; - } - - - return paFormatIsSupported; -} - - - -/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */ - -static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, - PaStream** s, - const PaStreamParameters *inputParameters, - const PaStreamParameters *outputParameters, - double sampleRate, - unsigned long framesPerBuffer, - PaStreamFlags streamFlags, - PaStreamCallback *streamCallback, - void *userData ) -{ - PaError result = paNoError; - PaWinWasapiHostApiRepresentation *paWasapi = (PaWinWasapiHostApiRepresentation*)hostApi; - PaWinWasapiStream *stream = 0; - int inputChannelCount, outputChannelCount; - PaSampleFormat inputSampleFormat, outputSampleFormat; - PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat; - - - stream = (PaWinWasapiStream*)PaUtil_AllocateMemory( sizeof(PaWinWasapiStream) ); - if( !stream ){ - result = paInsufficientMemory; - goto error; - } - - if( inputParameters ) - { - inputChannelCount = inputParameters->channelCount; - inputSampleFormat = inputParameters->sampleFormat; - - /* unless alternate device specification is supported, reject the use of - paUseHostApiSpecificDeviceSpecification */ - - if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) - return paInvalidDevice; - - /* check that input device can support inputChannelCount */ - if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels ) - return paInvalidChannelCount; - - /* validate inputStreamInfo */ - if( inputParameters->hostApiSpecificStreamInfo ) - return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ - - - PaWinWasapiDeviceInfo &info = paWasapi->devInfo[inputParameters->device]; - - HRESULT hResult = info.device->Activate( - __uuidof(IAudioClient), CLSCTX_INPROC_SERVER, NULL, - (void**)&stream->in.client); - - if (hResult != S_OK) - return paInvalidDevice; - - hResult = info.device->Activate( - __uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, - (void**)&stream->inVol); - - if (hResult != S_OK) - return paInvalidDevice; - - AUDCLNT_SHAREMODE shareMode; - PaError answer = GetClosestFormat(stream->in.client,sampleRate,inputParameters,&shareMode,&stream->in.wavex); - - if (answer !=paFormatIsSupported) - return answer; - - //stream->out.period = info.DefaultDevicePeriod; - stream->in.period = info.MinimumDevicePeriod; - - hResult = stream->in.client->Initialize( - shareMode, - 0, //no flags - stream->in.period, - 0,//stream->out.period, - (WAVEFORMATEX*)&stream->in.wavex, - &stream->session - ); - - if (hResult != S_OK){ - logAUDCLNT_E(hResult); - return paInvalidDevice; - } - - hResult = stream->in.client->GetBufferSize(&stream->in.bufferSize); - if (hResult != S_OK) - return paInvalidDevice; - - hResult = stream->in.client->GetStreamLatency(&stream->in.latency); - if (hResult != S_OK) - return paInvalidDevice; - - double periodsPerSecond = 1.0/nano100ToSeconds(stream->in.period); - double samplesPerPeriod = (double)(stream->in.wavex.Format.nSamplesPerSec)/periodsPerSecond; - - //this is the number of samples that are required at each period - stream->in.framesPerHostCallback = (unsigned long)samplesPerPeriod;//unrelated to channels - - /* IMPLEMENT ME - establish which host formats are available */ - hostInputSampleFormat = - PaUtil_SelectClosestAvailableFormat( waveformatToPaFormat(&stream->in.wavex), inputSampleFormat ); - } - else - { - inputChannelCount = 0; - inputSampleFormat = hostInputSampleFormat = paInt16; /* Surpress 'uninitialised var' warnings. */ - } - - if( outputParameters ) - { - outputChannelCount = outputParameters->channelCount; - outputSampleFormat = outputParameters->sampleFormat; - - /* unless alternate device specification is supported, reject the use of - paUseHostApiSpecificDeviceSpecification */ - - if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) - return paInvalidDevice; - - /* check that output device can support inputChannelCount */ - if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels ) - return paInvalidChannelCount; - - /* validate outputStreamInfo */ - if( outputParameters->hostApiSpecificStreamInfo ) - return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ - - - PaWinWasapiDeviceInfo &info = paWasapi->devInfo[outputParameters->device]; - - HRESULT hResult = info.device->Activate( - __uuidof(IAudioClient), CLSCTX_INPROC_SERVER, NULL, - (void**)&stream->out.client); - - if (hResult != S_OK) - return paInvalidDevice; - - AUDCLNT_SHAREMODE shareMode; - PaError answer = GetClosestFormat(stream->out.client,sampleRate,outputParameters,&shareMode,&stream->out.wavex); - - if (answer !=paFormatIsSupported) - return answer; - LogWAVEFORMATEXTENSIBLE(&stream->out.wavex); - - // stream->out.period = info.DefaultDevicePeriod; - stream->out.period = info.MinimumDevicePeriod; - - /*For an exclusive-mode stream that uses event-driven buffering, - the caller must specify nonzero values for hnsPeriodicity and hnsBufferDuration, - and the values of these two parameters must be equal */ - if (shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE){ - hResult = stream->out.client->Initialize( - shareMode, - AUDCLNT_STREAMFLAGS_EVENTCALLBACK, - stream->out.period, - stream->out.period, - (WAVEFORMATEX*)&stream->out.wavex, - &stream->session - ); - } - else{ - hResult = stream->out.client->Initialize( - shareMode, - AUDCLNT_STREAMFLAGS_EVENTCALLBACK, - 0, - 0, - (WAVEFORMATEX*)&stream->out.wavex, - &stream->session - ); - } - - - if (hResult != S_OK){ - logAUDCLNT_E(hResult); - return paInvalidDevice; - } - - hResult = info.device->Activate( - __uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, - (void**)&stream->outVol); - - if (hResult != S_OK) - return paInvalidDevice; - - hResult = stream->out.client->GetBufferSize(&stream->out.bufferSize); - if (hResult != S_OK) - return paInvalidDevice; - - hResult = stream->out.client->GetStreamLatency(&stream->out.latency); - if (hResult != S_OK) - return paInvalidDevice; - - double periodsPerSecond = 1.0/nano100ToSeconds(stream->out.period); - double samplesPerPeriod = (double)(stream->out.wavex.Format.nSamplesPerSec)/periodsPerSecond; - - //this is the number of samples that are required at each period - stream->out.framesPerHostCallback = stream->out.bufferSize; //(unsigned long)samplesPerPeriod;//unrelated to channels - - /* IMPLEMENT ME - establish which host formats are available */ - hostOutputSampleFormat = PaUtil_SelectClosestAvailableFormat( waveformatToPaFormat(&stream->out.wavex), outputSampleFormat ); - } - else - { - outputChannelCount = 0; - outputSampleFormat = hostOutputSampleFormat = paInt16; /* Surpress 'uninitialized var' warnings. */ - } - - - - /* - IMPLEMENT ME: - - ( the following two checks are taken care of by PaUtil_InitializeBufferProcessor() FIXME - checks needed? ) - - - check that input device can support inputSampleFormat, or that - we have the capability to convert from outputSampleFormat to - a native format - - - check that output device can support outputSampleFormat, or that - we have the capability to convert from outputSampleFormat to - a native format - - - if a full duplex stream is requested, check that the combination - of input and output parameters is supported - - - check that the device supports sampleRate - - - alter sampleRate to a close allowable rate if possible / necessary - - - validate suggestedInputLatency and suggestedOutputLatency parameters, - use default values where necessary - */ - - - - /* validate platform specific flags */ - if( (streamFlags & paPlatformSpecificFlags) != 0 ) - return paInvalidFlag; /* unexpected platform specific flag */ - - - - if( streamCallback ) - { - PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, - &paWasapi->callbackStreamInterface, streamCallback, userData ); - } - else - { - PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, - &paWasapi->blockingStreamInterface, streamCallback, userData ); - } - - PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate ); - - - if (outputParameters && inputParameters){ - - //serious problem #1 - if (stream->in.period != stream->out.period){ - PRINT(("OpenStream: period discrepancy\n")); - goto error; - } - - //serious problem #2 - if (stream->out.framesPerHostCallback != stream->in.framesPerHostCallback){ - PRINT(("OpenStream: framesPerHostCallback discrepancy\n")); - goto error; - } - } - - unsigned long framesPerHostCallback = (outputParameters)? - stream->out.framesPerHostCallback: - stream->in.framesPerHostCallback; - - /* we assume a fixed host buffer size in this example, but the buffer processor - can also support bounded and unknown host buffer sizes by passing - paUtilBoundedHostBufferSize or paUtilUnknownHostBufferSize instead of - paUtilFixedHostBufferSize below. */ - - result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor, - inputChannelCount, inputSampleFormat, hostInputSampleFormat, - outputChannelCount, outputSampleFormat, hostOutputSampleFormat, - sampleRate, streamFlags, framesPerBuffer, - framesPerHostCallback, paUtilFixedHostBufferSize, - streamCallback, userData ); - if( result != paNoError ) - goto error; - - - /* - IMPLEMENT ME: initialise the following fields with estimated or actual - values. - */ - stream->streamRepresentation.streamInfo.inputLatency = - PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor) - + ((inputParameters)?nano100ToSeconds(stream->in.latency) :0); - - stream->streamRepresentation.streamInfo.outputLatency = - PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor) - + ((outputParameters)?nano100ToSeconds(stream->out.latency) :0); - - stream->streamRepresentation.streamInfo.sampleRate = sampleRate; - - - *s = (PaStream*)stream; - - - return result; - -error: - if( stream ) - PaUtil_FreeMemory( stream ); - - return result; -} - - - -/* - When CloseStream() is called, the multi-api layer ensures that - the stream has already been stopped or aborted. -*/ - -#define SAFE_RELEASE(punk) \ - if ((punk) != NULL) \ - { (punk)->Release(); (punk) = NULL; } - -static PaError CloseStream( PaStream* s ) -{ - PaError result = paNoError; - PaWinWasapiStream *stream = (PaWinWasapiStream*)s; - - /* - IMPLEMENT ME: - - additional stream closing + cleanup - */ - - SAFE_RELEASE(stream->out.client); - SAFE_RELEASE(stream->in.client); - SAFE_RELEASE(stream->cclient); - SAFE_RELEASE(stream->rclient); - SAFE_RELEASE(stream->inVol); - SAFE_RELEASE(stream->outVol); - CloseHandle(stream->hThread); - CloseHandle(stream->hNotificationEvent); - - PaUtil_TerminateBufferProcessor( &stream->bufferProcessor ); - PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation ); - PaUtil_FreeMemory( stream ); - - return result; -} - -DWORD WINAPI ProcThread(void *client); - -static PaError StartStream( PaStream *s ) -{ - PaError result = paNoError; - PaWinWasapiStream *stream = (PaWinWasapiStream*)s; - - PaUtil_ResetBufferProcessor( &stream->bufferProcessor ); - - HRESULT hResult=S_OK; - - if (stream->out.client){ - hResult = stream->out.client->GetService(__uuidof(IAudioRenderClient),(void**)&stream->rclient); - logAUDCLNT_E(hResult); - if (hResult!=S_OK) - return paUnanticipatedHostError; - } - - if (stream->in.client){ - hResult = stream->in.client->GetService(__uuidof(IAudioCaptureClient),(void**)&stream->cclient); - logAUDCLNT_E(hResult); - if (hResult!=S_OK) - return paUnanticipatedHostError; - } - - // Create a thread for this client. - stream->hThread = CREATE_THREAD; - - if (stream->hThread == NULL) - return paUnanticipatedHostError; - - return paNoError; -} - - -static PaError StopStream( PaStream *s ) -{ - PaError result = paNoError; - PaWinWasapiStream *stream = (PaWinWasapiStream*)s; - - /* suppress unused variable warnings */ - stream->closeRequest = true; - //todo something MUCH better than this - while(stream->closeRequest) - Sleep(100); - - /* IMPLEMENT ME, see portaudio.h for required behavior */ - - stream->running = false; - - return result; -} - - -static PaError AbortStream( PaStream *s ) -{ - PaError result = paNoError; - PaWinWasapiStream *stream = (PaWinWasapiStream*)s; - - /* suppress unused variable warnings */ - stream->closeRequest = true; - //todo something MUCH better than this - while(stream->closeRequest) - Sleep(100); - - /* IMPLEMENT ME, see portaudio.h for required behavior */ - - return result; -} - - -static PaError IsStreamStopped( PaStream *s ) -{ - PaWinWasapiStream *stream = (PaWinWasapiStream*)s; - - return !stream->running; -} - - -static PaError IsStreamActive( PaStream *s ) -{ - PaWinWasapiStream *stream = (PaWinWasapiStream*)s; - return stream->running; -} - - -static PaTime GetStreamTime( PaStream *s ) -{ - PaWinWasapiStream *stream = (PaWinWasapiStream*)s; - - /* suppress unused variable warnings */ - (void) stream; - - /* IMPLEMENT ME, see portaudio.h for required behavior*/ - - //this is lame ds and mme does the same thing, quite useless method imho - //why dont we fetch the time in the pa callbacks? - //at least its doing to be clocked to something - return PaUtil_GetTime(); -} - - -static double GetStreamCpuLoad( PaStream* s ) -{ - PaWinWasapiStream *stream = (PaWinWasapiStream*)s; - - return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer ); -} - - -/* - As separate stream interfaces are used for blocking and callback - streams, the following functions can be guaranteed to only be called - for blocking streams. -*/ - -static PaError ReadStream( PaStream* s, - void *buffer, - unsigned long frames ) -{ - PaWinWasapiStream *stream = (PaWinWasapiStream*)s; - - /* suppress unused variable warnings */ - (void) buffer; - (void) frames; - (void) stream; - - /* IMPLEMENT ME, see portaudio.h for required behavior*/ - - return paNoError; -} - - -static PaError WriteStream( PaStream* s, - const void *buffer, - unsigned long frames ) -{ - PaWinWasapiStream *stream = (PaWinWasapiStream*)s; - - /* suppress unused variable warnings */ - (void) buffer; - (void) frames; - (void) stream; - - /* IMPLEMENT ME, see portaudio.h for required behavior*/ - - return paNoError; -} - - -static signed long GetStreamReadAvailable( PaStream* s ) -{ - PaWinWasapiStream *stream = (PaWinWasapiStream*)s; - - /* suppress unused variable warnings */ - (void) stream; - - /* IMPLEMENT ME, see portaudio.h for required behavior*/ - - return 0; -} - - -static signed long GetStreamWriteAvailable( PaStream* s ) -{ - PaWinWasapiStream *stream = (PaWinWasapiStream*)s; - - /* suppress unused variable warnings */ - (void) stream; - - /* IMPLEMENT ME, see portaudio.h for required behavior*/ - - return 0; -} - - - -/* - ExampleHostProcessingLoop() illustrates the kind of processing which may - occur in a host implementation. - -*/ -static void WaspiHostProcessingLoop( void *inputBuffer, long inputFrames, - void *outputBuffer, long outputFrames, - void *userData ) -{ - PaWinWasapiStream *stream = (PaWinWasapiStream*)userData; - PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /* IMPLEMENT ME */ - int callbackResult; - unsigned long framesProcessed; - - PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer ); - - - /* - IMPLEMENT ME: - - generate timing information - - handle buffer slips - */ - - /* - If you need to byte swap or shift inputBuffer to convert it into a - portaudio format, do it here. - */ - - - - PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, 0 /* IMPLEMENT ME: pass underflow/overflow flags when necessary */ ); - - /* - depending on whether the host buffers are interleaved, non-interleaved - or a mixture, you will want to call PaUtil_SetInterleaved*Channels(), - PaUtil_SetNonInterleaved*Channel() or PaUtil_Set*Channel() here. - */ - - if( stream->bufferProcessor.inputChannelCount > 0 ) - { - PaUtil_SetInputFrameCount( &stream->bufferProcessor, inputFrames ); - PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, - 0, /* first channel of inputBuffer is channel 0 */ - inputBuffer, - 0 ); /* 0 - use inputChannelCount passed to init buffer processor */ - } - - if( stream->bufferProcessor.outputChannelCount > 0 ) - { - PaUtil_SetOutputFrameCount( &stream->bufferProcessor, outputFrames); - PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, - 0, /* first channel of outputBuffer is channel 0 */ - outputBuffer, - 0 ); /* 0 - use outputChannelCount passed to init buffer processor */ - } - - /* you must pass a valid value of callback result to PaUtil_EndBufferProcessing() - in general you would pass paContinue for normal operation, and - paComplete to drain the buffer processor's internal output buffer. - You can check whether the buffer processor's output buffer is empty - using PaUtil_IsBufferProcessorOuputEmpty( bufferProcessor ) - */ - callbackResult = paContinue; - framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult ); - - - /* - If you need to byte swap or shift outputBuffer to convert it to - host format, do it here. - */ - - PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed ); - - - if( callbackResult == paContinue ) - { - /* nothing special to do */ - } - else if( callbackResult == paAbort ) - { - /* IMPLEMENT ME - finish playback immediately */ - - /* once finished, call the finished callback */ - if( stream->streamRepresentation.streamFinishedCallback != 0 ) - stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData ); - } - else - { - /* User callback has asked us to stop with paComplete or other non-zero value */ - - /* IMPLEMENT ME - finish playback once currently queued audio has completed */ - - /* once finished, call the finished callback */ - if( stream->streamRepresentation.streamFinishedCallback != 0 ) - stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData ); - } -} - - -void -MMCSS_activate(){ - - DWORD stuff=0; - HANDLE thCarac = pAvSetMmThreadCharacteristics("Pro Audio",&stuff); - if (!thCarac){ - PRINT(("AvSetMmThreadCharacteristics failed!\n")); - } - - BOOL prio = pAvSetMmThreadPriority(thCarac,AVRT_PRIORITY_NORMAL); - if (!prio){ - PRINT(("AvSetMmThreadPriority failed!\n")); - } - - //debug - { - HANDLE hh = GetCurrentThread(); - int currprio = GetThreadPriority(hh); - DWORD currclass = GetPriorityClass(GetCurrentProcess()); - PRINT(("currprio 0x%X currclass 0x%X\n",currprio,currclass)); - } -} - - -DWORD WINAPI -ProcThread(void* param){ - HRESULT hResult; - MMCSS_activate(); - - PaWinWasapiStream *stream = (PaWinWasapiStream*)param; - - stream->hNotificationEvent = CreateEvent(NULL, - FALSE, //bManualReset are we sure?? - FALSE, - "PAWASA"); - hResult = stream->out.client->SetEventHandle(stream->hNotificationEvent); - if (hResult != S_OK) - logAUDCLNT_E(hResult); - - if (stream->out.client){ - hResult = stream->out.client->Start(); - if (hResult != S_OK) - logAUDCLNT_E(hResult); - } - - stream->running = true; - bool bOne = false; - - while( !stream->closeRequest ) - { - //lets wait but have a 1 second timeout - DWORD dwResult = WaitForSingleObject(stream->hNotificationEvent, 1000); - switch( dwResult ) { - case WAIT_OBJECT_0: { - - unsigned long usingBS = stream->out.framesPerHostCallback; - - BYTE* indata = 0; - BYTE* outdata = 0; - - hResult = stream->rclient->GetBuffer(usingBS, &outdata); - - if (hResult != S_OK || !outdata) { - //logAUDCLNT_E(hResult); - //most probably shared mode and hResult=AUDCLNT_E_BUFFER_TOO_LARGE - UINT32 padding = 0; - hResult = stream->out.client->GetCurrentPadding(&padding); - if (padding == 0) - break; - usingBS = usingBS-padding; - if (usingBS == 0) - break;//huh? - hResult = stream->rclient->GetBuffer(usingBS, &outdata); - if (hResult != S_OK)//what can we do NOW?? - break; - //logAUDCLNT_E(hResult); - } - - WaspiHostProcessingLoop(indata, usingBS ,outdata, usingBS, stream); - - hResult = stream->rclient->ReleaseBuffer(usingBS, 0); - if (hResult != S_OK) - logAUDCLNT_E(hResult); - - /* This was suggested, but in my tests it doesnt seem to improve the - locking behaviour some drivers have running in exclusive mode. - if(!ResetEvent(stream->hNotificationEvent)){ - logAUDCLNT_E(hResult); - } - */ - - } - break; - - } - } - stream->out.client->Stop(); - stream->closeRequest = false; - - return 0; -} - - - - -#endif //VC 2005 - - - - -#if 0 - if(bFirst) { - float masteur; - hResult = stream->outVol->GetMasterVolumeLevelScalar(&masteur); - if (hResult != S_OK) - logAUDCLNT_E(hResult); - float chan1, chan2; - hResult = stream->outVol->GetChannelVolumeLevelScalar(0, &chan1); - if (hResult != S_OK) - logAUDCLNT_E(hResult); - hResult = stream->outVol->GetChannelVolumeLevelScalar(1, &chan2); - if (hResult != S_OK) - logAUDCLNT_E(hResult); - - BOOL bMute; - hResult = stream->outVol->GetMute(&bMute); - if (hResult != S_OK) - logAUDCLNT_E(hResult); - - stream->outVol->SetMasterVolumeLevelScalar(0.5, NULL); - stream->outVol->SetChannelVolumeLevelScalar(0, 0.5, NULL); - stream->outVol->SetChannelVolumeLevelScalar(1, 0.5, NULL); - stream->outVol->SetMute(FALSE, NULL); - bFirst = false; - } +/* + * Portable Audio I/O Library WASAPI implementation + * Copyright (c) 2006-2007 David Viens + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2002 Ross Bencina, Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup hostapi_src + @brief WASAPI implementation of support for a host API. + + @note pa_wasapi currently requires VC 2005, and the latest Vista SDK +*/ + +#if _MSC_VER >= 1400 +#include +#include //must be before other Wasapi headers +#include +#include +#include +#include +#include + +#include +#include // PKEY_Device_FriendlyName +#endif + +#include + +#include "pa_util.h" +#include "pa_allocation.h" +#include "pa_hostapi.h" +#include "pa_stream.h" +#include "pa_cpuload.h" +#include "pa_process.h" +#include "pa_debugprint.h" + + +/* + davidv : work in progress. try using with 48000 , then 44100 + and shared mode FIRST. + */ + +#define PORTAUDIO_SHAREMODE AUDCLNT_SHAREMODE_SHARED +//#define PORTAUDIO_SHAREMODE AUDCLNT_SHAREMODE_EXCLUSIVE + +/* use CreateThread for CYGWIN, _beginthreadex for all others */ +#ifndef __CYGWIN__ +#define CREATE_THREAD (HANDLE) _beginthreadex(NULL, 0, (unsigned (_stdcall *)(void *))ProcThread, (LPVOID) stream, 0, (unsigned *)&stream->dwThreadId) +#else +#define CREATE_THREAD CreateThread(NULL, 0, ProcThread, (LPVOID) stream, 0, &stream->dwThreadId) +#endif + +/* prototypes for functions declared in this file */ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +PaError PaWinWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + + + +static void Terminate( struct PaUtilHostApiRepresentation *hostApi ); +static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate ); +static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, + PaStream** s, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate, + unsigned long framesPerBuffer, + PaStreamFlags streamFlags, + PaStreamCallback *streamCallback, + void *userData ); +static PaError CloseStream( PaStream* stream ); +static PaError StartStream( PaStream *stream ); +static PaError StopStream( PaStream *stream ); +static PaError AbortStream( PaStream *stream ); +static PaError IsStreamStopped( PaStream *s ); +static PaError IsStreamActive( PaStream *stream ); +static PaTime GetStreamTime( PaStream *stream ); +static double GetStreamCpuLoad( PaStream* stream ); +static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames ); +static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames ); +static signed long GetStreamReadAvailable( PaStream* stream ); +static signed long GetStreamWriteAvailable( PaStream* stream ); + + +/* IMPLEMENT ME: a macro like the following one should be used for reporting + host errors */ +#define PA_SKELETON_SET_LAST_HOST_ERROR( errorCode, errorText ) \ + PaUtil_SetLastHostErrorInfo( paInDevelopment, errorCode, errorText ) + +/* PaWinWasapiHostApiRepresentation - host api datastructure specific to this implementation */ + + + +//dummy entry point for other compilers and sdks +//currently built using RC1 SDK (5600) +#if _MSC_VER < 1400 + +PaError PaWinWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ){ + return paNoError; +} + +#else + + + + +#define MAX_STR_LEN 512 + +/* + These are fields that can be gathered from IDevice + and IAudioDevice PRIOR to Initialize, and done in first pass + i assume that neither of these will cause the Driver to "load", + but again, who knows how they implement their stuff + */ +typedef struct PaWinWasapiDeviceInfo +{ + //hmm is it wise to keep a reference until Terminate? + //TODO Check if that interface requires the driver to be loaded! + IMMDevice * device; + + //Fields filled from IDevice + //from GetId + WCHAR szDeviceID[MAX_STR_LEN]; + //from GetState + DWORD state; + + //Fields filled from IMMEndpoint'sGetDataFlow + EDataFlow flow; + + //Fields filled from IAudioDevice (_prior_ to Initialize) + //from GetDevicePeriod( + REFERENCE_TIME DefaultDevicePeriod; + REFERENCE_TIME MinimumDevicePeriod; + //from GetMixFormat + WAVEFORMATEX *MixFormat;//needs to be CoTaskMemFree'd after use! + +} PaWinWasapiDeviceInfo; + + +typedef struct +{ + PaUtilHostApiRepresentation inheritedHostApiRep; + PaUtilStreamInterface callbackStreamInterface; + PaUtilStreamInterface blockingStreamInterface; + + PaUtilAllocationGroup *allocations; + + /* implementation specific data goes here */ + + //in case we later need the synch + IMMDeviceEnumerator * enumerator; + + //this is the REAL number of devices, whether they are usefull to PA or not! + UINT deviceCount; + + WCHAR defaultRenderer [MAX_STR_LEN]; + WCHAR defaultCapturer [MAX_STR_LEN]; + + PaWinWasapiDeviceInfo *devInfo; +}PaWinWasapiHostApiRepresentation; + + +/* PaWinWasapiStream - a stream data structure specifically for this implementation */ + +typedef struct PaWinWasapiSubStream{ + IAudioClient *client; + WAVEFORMATEXTENSIBLE wavex; + UINT32 bufferSize; + REFERENCE_TIME latency; + REFERENCE_TIME period; + unsigned long framesPerHostCallback; /* just an example */ +}PaWinWasapiSubStream; + +typedef struct PaWinWasapiStream +{ /* IMPLEMENT ME: rename this */ + PaUtilStreamRepresentation streamRepresentation; + PaUtilCpuLoadMeasurer cpuLoadMeasurer; + PaUtilBufferProcessor bufferProcessor; + + /* IMPLEMENT ME: + - implementation specific data goes here + */ + + + //input + PaWinWasapiSubStream in; + IAudioCaptureClient *cclient; + IAudioEndpointVolume *inVol; + //output + PaWinWasapiSubStream out; + IAudioRenderClient *rclient; + IAudioEndpointVolume *outVol; + + bool running; + bool closeRequest; + + DWORD dwThreadId; + HANDLE hThread; + HANDLE hNotificationEvent; + + GUID session; + +}PaWinWasapiStream; + +#define PRINT(x) PA_DEBUG(x); + +void +logAUDCLNT_E(HRESULT res){ + + char *text = 0; + switch(res){ + case S_OK: return; break; + case E_POINTER :text ="E_POINTER"; break; + case E_INVALIDARG :text ="E_INVALIDARG"; break; + + case AUDCLNT_E_NOT_INITIALIZED :text ="AUDCLNT_E_NOT_INITIALIZED"; break; + case AUDCLNT_E_ALREADY_INITIALIZED :text ="AUDCLNT_E_ALREADY_INITIALIZED"; break; + case AUDCLNT_E_WRONG_ENDPOINT_TYPE :text ="AUDCLNT_E_WRONG_ENDPOINT_TYPE"; break; + case AUDCLNT_E_DEVICE_INVALIDATED :text ="AUDCLNT_E_DEVICE_INVALIDATED"; break; + case AUDCLNT_E_NOT_STOPPED :text ="AUDCLNT_E_NOT_STOPPED"; break; + case AUDCLNT_E_BUFFER_TOO_LARGE :text ="AUDCLNT_E_BUFFER_TOO_LARGE"; break; + case AUDCLNT_E_OUT_OF_ORDER :text ="AUDCLNT_E_OUT_OF_ORDER"; break; + case AUDCLNT_E_UNSUPPORTED_FORMAT :text ="AUDCLNT_E_UNSUPPORTED_FORMAT"; break; + case AUDCLNT_E_INVALID_SIZE :text ="AUDCLNT_E_INVALID_SIZE"; break; + case AUDCLNT_E_DEVICE_IN_USE :text ="AUDCLNT_E_DEVICE_IN_USE"; break; + case AUDCLNT_E_BUFFER_OPERATION_PENDING :text ="AUDCLNT_E_BUFFER_OPERATION_PENDING"; break; + case AUDCLNT_E_THREAD_NOT_REGISTERED :text ="AUDCLNT_E_THREAD_NOT_REGISTERED"; break; + case AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED :text ="AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED"; break; + case AUDCLNT_E_ENDPOINT_CREATE_FAILED :text ="AUDCLNT_E_ENDPOINT_CREATE_FAILED"; break; + case AUDCLNT_E_SERVICE_NOT_RUNNING :text ="AUDCLNT_E_SERVICE_NOT_RUNNING"; break; + // case AUDCLNT_E_CPUUSAGE_EXCEEDED :text ="AUDCLNT_E_CPUUSAGE_EXCEEDED"; break; + //Header error? + case AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED :text ="AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED"; break; + case AUDCLNT_E_EXCLUSIVE_MODE_ONLY :text ="AUDCLNT_E_EXCLUSIVE_MODE_ONLY"; break; + case AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL :text ="AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL"; break; + case AUDCLNT_E_EVENTHANDLE_NOT_SET :text ="AUDCLNT_E_EVENTHANDLE_NOT_SET"; break; + case AUDCLNT_E_INCORRECT_BUFFER_SIZE :text ="AUDCLNT_E_INCORRECT_BUFFER_SIZE"; break; + case AUDCLNT_E_BUFFER_SIZE_ERROR :text ="AUDCLNT_E_BUFFER_SIZE_ERROR"; break; + case AUDCLNT_S_BUFFER_EMPTY :text ="AUDCLNT_S_BUFFER_EMPTY"; break; + case AUDCLNT_S_THREAD_ALREADY_REGISTERED :text ="AUDCLNT_S_THREAD_ALREADY_REGISTERED"; break; + default: + text =" dunno!"; + return ; + break; + + } + PRINT(("WASAPI ERROR HRESULT: 0x%X : %s\n",res,text)); +} + +inline double +nano100ToMillis(const REFERENCE_TIME &ref){ + // 1 nano = 0.000000001 seconds + //100 nano = 0.0000001 seconds + //100 nano = 0.0001 milliseconds + return ((double)ref)*0.0001; +} + +inline double +nano100ToSeconds(const REFERENCE_TIME &ref){ + // 1 nano = 0.000000001 seconds + //100 nano = 0.0000001 seconds + //100 nano = 0.0001 milliseconds + return ((double)ref)*0.0000001; +} + +#ifndef IF_FAILED_JUMP +#define IF_FAILED_JUMP(hr, label) if(FAILED(hr)) goto label; +#endif + + + +//AVRT is the new "multimedia schedulling stuff" + +typedef BOOL (WINAPI *FAvRtCreateThreadOrderingGroup) (PHANDLE,PLARGE_INTEGER,GUID*,PLARGE_INTEGER); +typedef BOOL (WINAPI *FAvRtDeleteThreadOrderingGroup) (HANDLE); +typedef BOOL (WINAPI *FAvRtWaitOnThreadOrderingGroup) (HANDLE); +typedef HANDLE (WINAPI *FAvSetMmThreadCharacteristics) (LPCTSTR,LPDWORD); +typedef BOOL (WINAPI *FAvSetMmThreadPriority) (HANDLE,AVRT_PRIORITY); + +HMODULE hDInputDLL = 0; +FAvRtCreateThreadOrderingGroup pAvRtCreateThreadOrderingGroup=0; +FAvRtDeleteThreadOrderingGroup pAvRtDeleteThreadOrderingGroup=0; +FAvRtWaitOnThreadOrderingGroup pAvRtWaitOnThreadOrderingGroup=0; +FAvSetMmThreadCharacteristics pAvSetMmThreadCharacteristics=0; +FAvSetMmThreadPriority pAvSetMmThreadPriority=0; + + + +#define setupPTR(fun, type, name) { \ + fun = (type) GetProcAddress(hDInputDLL,name); \ + if(fun == NULL) { \ + PRINT(("GetProcAddr failed for %s" ,name)); \ + return false; \ + } \ + } \ + +bool +setupAVRT(){ + + hDInputDLL = LoadLibraryA("avrt.dll"); + if(hDInputDLL == NULL) + return false; + + setupPTR(pAvRtCreateThreadOrderingGroup, FAvRtCreateThreadOrderingGroup, "AvRtCreateThreadOrderingGroup"); + setupPTR(pAvRtDeleteThreadOrderingGroup, FAvRtDeleteThreadOrderingGroup, "AvRtDeleteThreadOrderingGroup"); + setupPTR(pAvRtWaitOnThreadOrderingGroup, FAvRtWaitOnThreadOrderingGroup, "AvRtWaitOnThreadOrderingGroup"); + setupPTR(pAvSetMmThreadCharacteristics, FAvSetMmThreadCharacteristics, "AvSetMmThreadCharacteristicsA"); + setupPTR(pAvSetMmThreadPriority, FAvSetMmThreadPriority, "AvSetMmThreadPriority"); + + return true; +} + + + +PaError PaWinWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ) +{ + if (!setupAVRT()){ + PRINT(("Windows WASAPI : No AVRT! (not VISTA?)")); + return paNoError; + } + + CoInitialize(NULL); + + PaError result = paNoError; + PaWinWasapiHostApiRepresentation *paWasapi; + PaDeviceInfo *deviceInfoArray; + + paWasapi = (PaWinWasapiHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaWinWasapiHostApiRepresentation) ); + if( !paWasapi ){ + result = paInsufficientMemory; + goto error; + } + + paWasapi->allocations = PaUtil_CreateAllocationGroup(); + if( !paWasapi->allocations ){ + result = paInsufficientMemory; + goto error; + } + + *hostApi = &paWasapi->inheritedHostApiRep; + (*hostApi)->info.structVersion = 1; + (*hostApi)->info.type = paWASAPI; + (*hostApi)->info.name = "Windows WASAPI"; + (*hostApi)->info.deviceCount = 0; //so far, we must investigate each + (*hostApi)->info.defaultInputDevice = paNoDevice; /* IMPLEMENT ME */ + (*hostApi)->info.defaultOutputDevice = paNoDevice; /* IMPLEMENT ME */ + + + HRESULT hResult = S_OK; + IMMDeviceCollection* spEndpoints=0; + paWasapi->enumerator = 0; + + hResult = CoCreateInstance( + __uuidof(MMDeviceEnumerator), NULL,CLSCTX_INPROC_SERVER, + __uuidof(IMMDeviceEnumerator), + (void**)&paWasapi->enumerator); + + IF_FAILED_JUMP(hResult, error); + + //getting default device ids in the eMultimedia "role" + { + { + IMMDevice* defaultRenderer=0; + hResult = paWasapi->enumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, &defaultRenderer); + IF_FAILED_JUMP(hResult, error); + WCHAR* pszDeviceId = NULL; + hResult = defaultRenderer->GetId(&pszDeviceId); + IF_FAILED_JUMP(hResult, error); + StringCchCopyW(paWasapi->defaultRenderer, MAX_STR_LEN-1, pszDeviceId); + CoTaskMemFree(pszDeviceId); + defaultRenderer->Release(); + } + + { + IMMDevice* defaultCapturer=0; + hResult = paWasapi->enumerator->GetDefaultAudioEndpoint(eCapture, eMultimedia, &defaultCapturer); + IF_FAILED_JUMP(hResult, error); + WCHAR* pszDeviceId = NULL; + hResult = defaultCapturer->GetId(&pszDeviceId); + IF_FAILED_JUMP(hResult, error); + StringCchCopyW(paWasapi->defaultCapturer, MAX_STR_LEN-1, pszDeviceId); + CoTaskMemFree(pszDeviceId); + defaultCapturer->Release(); + } + } + + + hResult = paWasapi->enumerator->EnumAudioEndpoints(eAll, DEVICE_STATE_ACTIVE, &spEndpoints); + IF_FAILED_JUMP(hResult, error); + + hResult = spEndpoints->GetCount(&paWasapi->deviceCount); + IF_FAILED_JUMP(hResult, error); + + paWasapi->devInfo = new PaWinWasapiDeviceInfo[paWasapi->deviceCount]; + { + for (size_t step=0;stepdeviceCount;++step) + memset(&paWasapi->devInfo[step],0,sizeof(PaWinWasapiDeviceInfo)); + } + + + + if( paWasapi->deviceCount > 0 ) + { + (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory( + paWasapi->allocations, sizeof(PaDeviceInfo*) * paWasapi->deviceCount ); + if( !(*hostApi)->deviceInfos ){ + result = paInsufficientMemory; + goto error; + } + + /* allocate all device info structs in a contiguous block */ + deviceInfoArray = (PaDeviceInfo*)PaUtil_GroupAllocateMemory( + paWasapi->allocations, sizeof(PaDeviceInfo) * paWasapi->deviceCount ); + if( !deviceInfoArray ){ + result = paInsufficientMemory; + goto error; + } + + for( UINT i=0; i < paWasapi->deviceCount; ++i ){ + + PA_DEBUG(("i:%d\n",i)); + PaDeviceInfo *deviceInfo = &deviceInfoArray[i]; + deviceInfo->structVersion = 2; + deviceInfo->hostApi = hostApiIndex; + + hResult = spEndpoints->Item(i, &paWasapi->devInfo[i].device); + IF_FAILED_JUMP(hResult, error); + + //getting ID + { + WCHAR* pszDeviceId = NULL; + hResult = paWasapi->devInfo[i].device->GetId(&pszDeviceId); + IF_FAILED_JUMP(hResult, error); + StringCchCopyW(paWasapi->devInfo[i].szDeviceID, MAX_STR_LEN-1, pszDeviceId); + CoTaskMemFree(pszDeviceId); + + if (lstrcmpW(paWasapi->devInfo[i].szDeviceID, paWasapi->defaultCapturer)==0){ + //we found the default input! + (*hostApi)->info.defaultInputDevice = (*hostApi)->info.deviceCount; + } + if (lstrcmpW(paWasapi->devInfo[i].szDeviceID, paWasapi->defaultRenderer)==0){ + //we found the default output! + (*hostApi)->info.defaultOutputDevice = (*hostApi)->info.deviceCount; + } + } + + DWORD state=0; + hResult = paWasapi->devInfo[i].device->GetState(&paWasapi->devInfo[i].state); + IF_FAILED_JUMP(hResult, error); + + if (paWasapi->devInfo[i].state != DEVICE_STATE_ACTIVE){ + PRINT(("WASAPI device:%d is not currently available (state:%d)\n",i,state)); + //spDevice->Release(); + //continue; + } + + { + IPropertyStore* spProperties; + hResult = paWasapi->devInfo[i].device->OpenPropertyStore(STGM_READ, &spProperties); + IF_FAILED_JUMP(hResult, error); + + //getting "Friendly" Name + { + PROPVARIANT value; + PropVariantInit(&value); + hResult = spProperties->GetValue(PKEY_Device_FriendlyName, &value); + IF_FAILED_JUMP(hResult, error); + deviceInfo->name = 0; + char* deviceName = (char*)PaUtil_GroupAllocateMemory( paWasapi->allocations, MAX_STR_LEN + 1 ); + if( !deviceName ){ + result = paInsufficientMemory; + goto error; + } + if (value.pwszVal) + wcstombs(deviceName, value.pwszVal,MAX_STR_LEN-1); //todo proper size + else{ + _snprintf_s(deviceName,MAX_STR_LEN-1,MAX_STR_LEN-1,"baddev%d",i); + } + + deviceInfo->name = deviceName; + PropVariantClear(&value); + } + +#if 0 + DWORD numProps = 0; + hResult = spProperties->GetCount(&numProps); + IF_FAILED_JUMP(hResult, error); + { + for (DWORD i=0;iGetAt(i,&pkey); + + PROPVARIANT value; + PropVariantInit(&value); + hResult = spProperties->GetValue(pkey, &value); + + switch(value.vt){ + case 11: + PRINT(("property*%u*\n",value.ulVal)); + break; + case 19: + PRINT(("property*%d*\n",value.boolVal)); + break; + case 31: + { + char temp[512]; + wcstombs(temp, value.pwszVal,MAX_STR_LEN-1); + PRINT(("property*%s*\n",temp)); + } + break; + default:break; + } + + PropVariantClear(&value); + } + } +#endif + + /* These look interresting... but they are undocumented + PKEY_AudioEndpoint_FormFactor + PKEY_AudioEndpoint_ControlPanelPageProvider + PKEY_AudioEndpoint_Association + PKEY_AudioEndpoint_PhysicalSpeakerConfig + PKEY_AudioEngine_DeviceFormat + */ + spProperties->Release(); + } + + + //getting the Endpoint data + { + IMMEndpoint *endpoint=0; + hResult = paWasapi->devInfo[i].device->QueryInterface(__uuidof(IMMEndpoint),(void **)&endpoint); + if (SUCCEEDED(hResult)){ + hResult = endpoint->GetDataFlow(&paWasapi->devInfo[i].flow); + endpoint->Release(); + } + } + + //Getting a temporary IAudioDevice for more fields + //we make sure NOT to call Initialize yet! + { + IAudioClient *myClient=0; + + hResult = paWasapi->devInfo[i].device->Activate(__uuidof(IAudioClient), CLSCTX_INPROC_SERVER, NULL, (void**)&myClient); + IF_FAILED_JUMP(hResult, error); + + hResult = myClient->GetDevicePeriod( + &paWasapi->devInfo[i].DefaultDevicePeriod, + &paWasapi->devInfo[i].MinimumDevicePeriod); + IF_FAILED_JUMP(hResult, error); + + hResult = myClient->GetMixFormat(&paWasapi->devInfo[i].MixFormat); + + if (hResult != S_OK){ + /*davidv: this happened with my hardware, previously for that same device in DirectSound: + Digital Output (Realtek AC'97 Audio)'s GUID: {0x38f2cf50,0x7b4c,0x4740,0x86,0xeb,0xd4,0x38,0x66,0xd8,0xc8, 0x9f} + so something must be _really_ wrong with this device, TODO handle this better. We kind of need GetMixFormat*/ + logAUDCLNT_E(hResult); + goto error; + } + + myClient->Release(); + } + + //we can now fill in portaudio device data + deviceInfo->maxInputChannels = 0; //for now + deviceInfo->maxOutputChannels = 0; //for now + + switch(paWasapi->devInfo[i].flow){ + case eRender: + //hum not exaclty maximum, more like "default" + deviceInfo->maxOutputChannels = paWasapi->devInfo[i].MixFormat->nChannels; + + deviceInfo->defaultHighOutputLatency = nano100ToSeconds(paWasapi->devInfo[i].DefaultDevicePeriod); + deviceInfo->defaultLowOutputLatency = nano100ToSeconds(paWasapi->devInfo[i].MinimumDevicePeriod); + break; + case eCapture: + //hum not exaclty maximum, more like "default" + deviceInfo->maxInputChannels = paWasapi->devInfo[i].MixFormat->nChannels; + + deviceInfo->defaultHighInputLatency = nano100ToSeconds(paWasapi->devInfo[i].DefaultDevicePeriod); + deviceInfo->defaultLowInputLatency = nano100ToSeconds(paWasapi->devInfo[i].MinimumDevicePeriod); + break; + default: + PRINT(("WASAPI device:%d bad Data FLow! \n",i)); + goto error; + break; + } + + deviceInfo->defaultSampleRate = (double)paWasapi->devInfo[i].MixFormat->nSamplesPerSec; + + (*hostApi)->deviceInfos[i] = deviceInfo; + ++(*hostApi)->info.deviceCount; + } + } + + spEndpoints->Release(); + + (*hostApi)->Terminate = Terminate; + (*hostApi)->OpenStream = OpenStream; + (*hostApi)->IsFormatSupported = IsFormatSupported; + + PaUtil_InitializeStreamInterface( &paWasapi->callbackStreamInterface, CloseStream, StartStream, + StopStream, AbortStream, IsStreamStopped, IsStreamActive, + GetStreamTime, GetStreamCpuLoad, + PaUtil_DummyRead, PaUtil_DummyWrite, + PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable ); + + PaUtil_InitializeStreamInterface( &paWasapi->blockingStreamInterface, CloseStream, StartStream, + StopStream, AbortStream, IsStreamStopped, IsStreamActive, + GetStreamTime, PaUtil_DummyGetCpuLoad, + ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable ); + + return result; + +error: + + if (spEndpoints) + spEndpoints->Release(); + + if (paWasapi->enumerator) + paWasapi->enumerator->Release(); + + if( paWasapi ) + { + if( paWasapi->allocations ) + { + PaUtil_FreeAllAllocations( paWasapi->allocations ); + PaUtil_DestroyAllocationGroup( paWasapi->allocations ); + } + + PaUtil_FreeMemory( paWasapi ); + } + return result; +} + + +static void Terminate( struct PaUtilHostApiRepresentation *hostApi ) +{ + PaWinWasapiHostApiRepresentation *paWasapi = (PaWinWasapiHostApiRepresentation*)hostApi; + + paWasapi->enumerator->Release(); + + for (UINT i=0;ideviceCount;++i){ + PaWinWasapiDeviceInfo *info = &paWasapi->devInfo[i]; + + if (info->device) + info->device->Release(); + + if (info->MixFormat) + CoTaskMemFree(info->MixFormat); + } + delete [] paWasapi->devInfo; + + CoUninitialize(); + + if( paWasapi->allocations ){ + PaUtil_FreeAllAllocations( paWasapi->allocations ); + PaUtil_DestroyAllocationGroup( paWasapi->allocations ); + } + + PaUtil_FreeMemory( paWasapi ); +} + +static void +LogWAVEFORMATEXTENSIBLE(const WAVEFORMATEXTENSIBLE *in){ + + const WAVEFORMATEX *old = (WAVEFORMATEX *)in; + + switch (old->wFormatTag){ + case WAVE_FORMAT_EXTENSIBLE:{ + + PRINT(("wFormatTag=WAVE_FORMAT_EXTENSIBLE\n")); + + if (in->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT){ + PRINT(("SubFormat=KSDATAFORMAT_SUBTYPE_IEEE_FLOAT\n")); + } + else if (in->SubFormat == KSDATAFORMAT_SUBTYPE_PCM){ + PRINT(("SubFormat=KSDATAFORMAT_SUBTYPE_PCM\n")); + } + else{ + PRINT(("SubFormat=CUSTOM GUID{%d:%d:%d:%d%d%d%d%d%d%d%d}\n", + in->SubFormat.Data1, + in->SubFormat.Data2, + in->SubFormat.Data3, + (int)in->SubFormat.Data4[0], + (int)in->SubFormat.Data4[1], + (int)in->SubFormat.Data4[2], + (int)in->SubFormat.Data4[3], + (int)in->SubFormat.Data4[4], + (int)in->SubFormat.Data4[5], + (int)in->SubFormat.Data4[6], + (int)in->SubFormat.Data4[7])); + } + PRINT(("Samples.wValidBitsPerSample=%d\n", in->Samples.wValidBitsPerSample)); + PRINT(("dwChannelMask=0x%X\n",in->dwChannelMask)); + }break; + + case WAVE_FORMAT_PCM: PRINT(("wFormatTag=WAVE_FORMAT_PCM\n")); break; + case WAVE_FORMAT_IEEE_FLOAT: PRINT(("wFormatTag=WAVE_FORMAT_IEEE_FLOAT\n")); break; + default : PRINT(("wFormatTag=UNKNOWN(%d)\n",old->wFormatTag)); break; + } + + PRINT(("nChannels =%d\n",old->nChannels)); + PRINT(("nSamplesPerSec =%d\n",old->nSamplesPerSec)); + PRINT(("nAvgBytesPerSec=%d\n",old->nAvgBytesPerSec)); + PRINT(("nBlockAlign =%d\n",old->nBlockAlign)); + PRINT(("wBitsPerSample =%d\n",old->wBitsPerSample)); + PRINT(("cbSize =%d\n",old->cbSize)); +} + + + +/* + WAVEFORMATXXX is always interleaved + */ +static PaSampleFormat +waveformatToPaFormat(const WAVEFORMATEXTENSIBLE *in){ + + const WAVEFORMATEX *old = (WAVEFORMATEX*)in; + + switch (old->wFormatTag){ + + case WAVE_FORMAT_EXTENSIBLE: + { + if (in->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT){ + if (in->Samples.wValidBitsPerSample == 32) + return paFloat32; + else + return paCustomFormat; + } + else if (in->SubFormat == KSDATAFORMAT_SUBTYPE_PCM){ + switch (old->wBitsPerSample){ + case 32: return paInt32; break; + case 24: return paInt24;break; + case 8: return paUInt8;break; + case 16: return paInt16;break; + default: return paCustomFormat;break; + } + } + else + return paCustomFormat; + } + break; + + case WAVE_FORMAT_IEEE_FLOAT: + return paFloat32; + break; + + case WAVE_FORMAT_PCM: + { + switch (old->wBitsPerSample){ + case 32: return paInt32; break; + case 24: return paInt24;break; + case 8: return paUInt8;break; + case 16: return paInt16;break; + default: return paCustomFormat;break; + } + } + break; + + default: + return paCustomFormat; + break; + } + + return paCustomFormat; +} + + + +static PaError +waveformatFromParams(WAVEFORMATEXTENSIBLE*wavex, + const PaStreamParameters * params, + double sampleRate){ + + size_t bytesPerSample = 0; + switch( params->sampleFormat & ~paNonInterleaved ){ + case paFloat32: + case paInt32: bytesPerSample=4;break; + case paInt16: bytesPerSample=2;break; + case paInt24: bytesPerSample=3;break; + case paInt8: + case paUInt8: bytesPerSample=1;break; + case paCustomFormat: + default: return paSampleFormatNotSupported;break; + } + + memset(wavex,0,sizeof(WAVEFORMATEXTENSIBLE)); + + WAVEFORMATEX *old = (WAVEFORMATEX *)wavex; + old->nChannels = (WORD)params->channelCount; + old->nSamplesPerSec = (DWORD)sampleRate; + old->wBitsPerSample = (WORD)(bytesPerSample*8); + old->nAvgBytesPerSec = (DWORD)(old->nSamplesPerSec * old->nChannels * bytesPerSample); + old->nBlockAlign = (WORD)(old->nChannels * bytesPerSample); + + //WAVEFORMATEX + if (params->channelCount <=2 && (bytesPerSample == 2 || bytesPerSample == 1)){ + old->cbSize = 0; + old->wFormatTag = WAVE_FORMAT_PCM; + } + //WAVEFORMATEXTENSIBLE + else{ + old->wFormatTag = WAVE_FORMAT_EXTENSIBLE; + + old->cbSize = sizeof (WAVEFORMATEXTENSIBLE) - sizeof (WAVEFORMATEX); + + if ((params->sampleFormat & ~paNonInterleaved) == paFloat32) + wavex->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; + else + wavex->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + + wavex->Samples.wValidBitsPerSample = old->wBitsPerSample; //no extra padding! + + switch(params->channelCount){ + case 1: wavex->dwChannelMask = SPEAKER_FRONT_CENTER; break; + case 2: wavex->dwChannelMask = 0x1 | 0x2; break; + case 4: wavex->dwChannelMask = 0x1 | 0x2 | 0x10 | 0x20; break; + case 6: wavex->dwChannelMask = 0x1 | 0x2 | 0x4 | 0x8 | 0x10 | 0x20; break; + case 8: wavex->dwChannelMask = 0x1 | 0x2 | 0x4 | 0x8 | 0x10 | 0x20 | 0x40 | 0x80; break; + default: wavex->dwChannelMask = 0; break; + } + } + + return paNoError; +} + + + + + + +/* +#define paFloat32 ((PaSampleFormat) 0x00000001) +#define paInt32 ((PaSampleFormat) 0x00000002) +#define paInt24 ((PaSampleFormat) 0x00000004) +#define paInt16 ((PaSampleFormat) 0x00000008) +*/ +//lifted from pa_wdmks +static void wasapiFillWFEXT( WAVEFORMATEXTENSIBLE* pwfext, PaSampleFormat sampleFormat, double sampleRate, int channelCount) +{ + PA_DEBUG(( "sampleFormat = %lx\n" , sampleFormat )); + PA_DEBUG(( "sampleRate = %f\n" , sampleRate )); + PA_DEBUG(( "chanelCount = %d\n", channelCount )); + + pwfext->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; + pwfext->Format.nChannels = channelCount; + pwfext->Format.nSamplesPerSec = (int)sampleRate; + if(channelCount == 1) + pwfext->dwChannelMask = KSAUDIO_SPEAKER_DIRECTOUT; + else + pwfext->dwChannelMask = KSAUDIO_SPEAKER_STEREO; + if(sampleFormat == paFloat32) + { + pwfext->Format.nBlockAlign = channelCount * 4; + pwfext->Format.wBitsPerSample = 32; + pwfext->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX); + pwfext->Samples.wValidBitsPerSample = 32; + pwfext->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; + } + else if(sampleFormat == paInt32) + { + pwfext->Format.nBlockAlign = channelCount * 4; + pwfext->Format.wBitsPerSample = 32; + pwfext->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX); + pwfext->Samples.wValidBitsPerSample = 32; + pwfext->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + } + else if(sampleFormat == paInt24) + { + pwfext->Format.nBlockAlign = channelCount * 3; + pwfext->Format.wBitsPerSample = 24; + pwfext->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX); + pwfext->Samples.wValidBitsPerSample = 24; + pwfext->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + } + else if(sampleFormat == paInt16) + { + pwfext->Format.nBlockAlign = channelCount * 2; + pwfext->Format.wBitsPerSample = 16; + pwfext->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX); + pwfext->Samples.wValidBitsPerSample = 16; + pwfext->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + } + pwfext->Format.nAvgBytesPerSec = pwfext->Format.nSamplesPerSec * pwfext->Format.nBlockAlign; +} + + + +/* +#define FORMATTESTS 4 +const int BestToWorst[FORMATTESTS]={paFloat32,paInt32,paInt24,paInt16}; +*/ + +#define FORMATTESTS 3 +const int BestToWorst[FORMATTESTS]={paFloat32,paInt24,paInt16}; + + +static PaError +GetClosestFormat(IAudioClient * myClient, double sampleRate,const PaStreamParameters * params, + AUDCLNT_SHAREMODE *shareMode, WAVEFORMATEXTENSIBLE *outWavex) +{ + //TODO we should try exclusive first and shared after + *shareMode = PORTAUDIO_SHAREMODE; + + PaError answer = paInvalidSampleRate; + + waveformatFromParams(outWavex,params,sampleRate); + WAVEFORMATEX *sharedClosestMatch=0; + HRESULT hResult=!S_OK; + + if (*shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE) + hResult = myClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE,&outWavex->Format,NULL); + else + hResult = myClient->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, &outWavex->Format,&sharedClosestMatch); + + if (hResult == S_OK) + answer = paFormatIsSupported; + else if (sharedClosestMatch){ + WAVEFORMATEXTENSIBLE* ext = (WAVEFORMATEXTENSIBLE*)sharedClosestMatch; + + int closestMatchSR = (int)sharedClosestMatch->nSamplesPerSec; + + if (sharedClosestMatch->wFormatTag == WAVE_FORMAT_EXTENSIBLE) + memcpy(outWavex,sharedClosestMatch,sizeof(WAVEFORMATEXTENSIBLE)); + else + memcpy(outWavex,sharedClosestMatch,sizeof(WAVEFORMATEX)); + + CoTaskMemFree(sharedClosestMatch); + + if ((int)sampleRate == closestMatchSR) + answer = paFormatIsSupported; + else + answer = paInvalidSampleRate; + + }else { + + //it doesnt suggest anything?? ok lets show it the MENU! + + //ok fun time as with pa_win_mme, we know only a refusal of the user-requested + //sampleRate+num Channel is disastrous, as the portaudio buffer processor converts between anything + //so lets only use the number + for (int i=0;ichannelCount); + if (*shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE) + hResult = myClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE,&ext.Format,NULL); + else + hResult = myClient->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, &ext.Format,&sharedClosestMatch); + + if (hResult == S_OK){ + memcpy(outWavex,&ext,sizeof(WAVEFORMATEXTENSIBLE)); + answer = paFormatIsSupported; + break; + } + } + + if (answer!=paFormatIsSupported) { + //try MIX format? + //why did it HAVE to come to this .... + WAVEFORMATEX pcm16WaveFormat; + memset(&pcm16WaveFormat,0,sizeof(WAVEFORMATEX)); + pcm16WaveFormat.wFormatTag = WAVE_FORMAT_PCM; + pcm16WaveFormat.nChannels = 2; + pcm16WaveFormat.nSamplesPerSec = (DWORD)sampleRate; + pcm16WaveFormat.nBlockAlign = 4; + pcm16WaveFormat.nAvgBytesPerSec = pcm16WaveFormat.nSamplesPerSec*pcm16WaveFormat.nBlockAlign; + pcm16WaveFormat.wBitsPerSample = 16; + pcm16WaveFormat.cbSize = 0; + + if (*shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE) + hResult = myClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE,&pcm16WaveFormat,NULL); + else + hResult = myClient->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, &pcm16WaveFormat,&sharedClosestMatch); + + if (hResult == S_OK){ + memcpy(outWavex,&pcm16WaveFormat,sizeof(WAVEFORMATEX)); + answer = paFormatIsSupported; + } + } + + logAUDCLNT_E(hResult); + } + + return answer; +} + + +static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate ) +{ + + int inputChannelCount, outputChannelCount; + PaSampleFormat inputSampleFormat, outputSampleFormat; + + if( inputParameters ) + { + inputChannelCount = inputParameters->channelCount; + inputSampleFormat = inputParameters->sampleFormat; + + /* all standard sample formats are supported by the buffer adapter, + this implementation doesn't support any custom sample formats */ + if( inputSampleFormat & paCustomFormat ) + return paSampleFormatNotSupported; + + /* unless alternate device specification is supported, reject the use of + paUseHostApiSpecificDeviceSpecification */ + + if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) + return paInvalidDevice; + + /* check that input device can support inputChannelCount */ + if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels ) + return paInvalidChannelCount; + + /* validate inputStreamInfo */ + if( inputParameters->hostApiSpecificStreamInfo ) + return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ + + + PaWinWasapiHostApiRepresentation *paWasapi = (PaWinWasapiHostApiRepresentation*)hostApi; + + + IAudioClient *myClient=0; + HRESULT hResult = paWasapi->devInfo[inputParameters->device].device->Activate( + __uuidof(IAudioClient), CLSCTX_INPROC_SERVER, NULL, (void**)&myClient); + if (hResult != S_OK){ + logAUDCLNT_E(hResult); + return paInvalidDevice; + } + + WAVEFORMATEXTENSIBLE wavex; + AUDCLNT_SHAREMODE shareMode; + PaError answer = GetClosestFormat(myClient,sampleRate,inputParameters,&shareMode,&wavex); + myClient->Release(); + + if (answer !=paFormatIsSupported) + return answer; + } + else + { + inputChannelCount = 0; + } + + if( outputParameters ) + { + outputChannelCount = outputParameters->channelCount; + outputSampleFormat = outputParameters->sampleFormat; + + /* all standard sample formats are supported by the buffer adapter, + this implementation doesn't support any custom sample formats */ + if( outputSampleFormat & paCustomFormat ) + return paSampleFormatNotSupported; + + /* unless alternate device specification is supported, reject the use of + paUseHostApiSpecificDeviceSpecification */ + + if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) + return paInvalidDevice; + + /* check that output device can support outputChannelCount */ + if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels ) + return paInvalidChannelCount; + + /* validate outputStreamInfo */ + if( outputParameters->hostApiSpecificStreamInfo ) + return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ + + + PaWinWasapiHostApiRepresentation *paWasapi = (PaWinWasapiHostApiRepresentation*)hostApi; + + IAudioClient *myClient=0; + HRESULT hResult = paWasapi->devInfo[outputParameters->device].device->Activate( + __uuidof(IAudioClient), CLSCTX_INPROC_SERVER, NULL, (void**)&myClient); + if (hResult != S_OK){ + logAUDCLNT_E(hResult); + return paInvalidDevice; + } + + WAVEFORMATEXTENSIBLE wavex; + AUDCLNT_SHAREMODE shareMode; + PaError answer = GetClosestFormat(myClient,sampleRate,outputParameters,&shareMode,&wavex); + myClient->Release(); + + if (answer !=paFormatIsSupported) + return answer; + } + else + { + outputChannelCount = 0; + } + + + return paFormatIsSupported; +} + + + +/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */ + +static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, + PaStream** s, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate, + unsigned long framesPerBuffer, + PaStreamFlags streamFlags, + PaStreamCallback *streamCallback, + void *userData ) +{ + PaError result = paNoError; + PaWinWasapiHostApiRepresentation *paWasapi = (PaWinWasapiHostApiRepresentation*)hostApi; + PaWinWasapiStream *stream = 0; + int inputChannelCount, outputChannelCount; + PaSampleFormat inputSampleFormat, outputSampleFormat; + PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat; + + + stream = (PaWinWasapiStream*)PaUtil_AllocateMemory( sizeof(PaWinWasapiStream) ); + if( !stream ){ + result = paInsufficientMemory; + goto error; + } + + if( inputParameters ) + { + inputChannelCount = inputParameters->channelCount; + inputSampleFormat = inputParameters->sampleFormat; + + /* unless alternate device specification is supported, reject the use of + paUseHostApiSpecificDeviceSpecification */ + + if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) + return paInvalidDevice; + + /* check that input device can support inputChannelCount */ + if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels ) + return paInvalidChannelCount; + + /* validate inputStreamInfo */ + if( inputParameters->hostApiSpecificStreamInfo ) + return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ + + + PaWinWasapiDeviceInfo &info = paWasapi->devInfo[inputParameters->device]; + + HRESULT hResult = info.device->Activate( + __uuidof(IAudioClient), CLSCTX_INPROC_SERVER, NULL, + (void**)&stream->in.client); + + if (hResult != S_OK) + return paInvalidDevice; + + hResult = info.device->Activate( + __uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, + (void**)&stream->inVol); + + if (hResult != S_OK) + return paInvalidDevice; + + AUDCLNT_SHAREMODE shareMode; + PaError answer = GetClosestFormat(stream->in.client,sampleRate,inputParameters,&shareMode,&stream->in.wavex); + + if (answer !=paFormatIsSupported) + return answer; + + //stream->out.period = info.DefaultDevicePeriod; + stream->in.period = info.MinimumDevicePeriod; + + hResult = stream->in.client->Initialize( + shareMode, + 0, //no flags + stream->in.period, + 0,//stream->out.period, + (WAVEFORMATEX*)&stream->in.wavex, + &stream->session + ); + + if (hResult != S_OK){ + logAUDCLNT_E(hResult); + return paInvalidDevice; + } + + hResult = stream->in.client->GetBufferSize(&stream->in.bufferSize); + if (hResult != S_OK) + return paInvalidDevice; + + hResult = stream->in.client->GetStreamLatency(&stream->in.latency); + if (hResult != S_OK) + return paInvalidDevice; + + double periodsPerSecond = 1.0/nano100ToSeconds(stream->in.period); + double samplesPerPeriod = (double)(stream->in.wavex.Format.nSamplesPerSec)/periodsPerSecond; + + //this is the number of samples that are required at each period + stream->in.framesPerHostCallback = (unsigned long)samplesPerPeriod;//unrelated to channels + + /* IMPLEMENT ME - establish which host formats are available */ + hostInputSampleFormat = + PaUtil_SelectClosestAvailableFormat( waveformatToPaFormat(&stream->in.wavex), inputSampleFormat ); + } + else + { + inputChannelCount = 0; + inputSampleFormat = hostInputSampleFormat = paInt16; /* Surpress 'uninitialised var' warnings. */ + } + + if( outputParameters ) + { + outputChannelCount = outputParameters->channelCount; + outputSampleFormat = outputParameters->sampleFormat; + + /* unless alternate device specification is supported, reject the use of + paUseHostApiSpecificDeviceSpecification */ + + if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) + return paInvalidDevice; + + /* check that output device can support inputChannelCount */ + if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels ) + return paInvalidChannelCount; + + /* validate outputStreamInfo */ + if( outputParameters->hostApiSpecificStreamInfo ) + return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ + + + PaWinWasapiDeviceInfo &info = paWasapi->devInfo[outputParameters->device]; + + HRESULT hResult = info.device->Activate( + __uuidof(IAudioClient), CLSCTX_INPROC_SERVER, NULL, + (void**)&stream->out.client); + + if (hResult != S_OK) + return paInvalidDevice; + + AUDCLNT_SHAREMODE shareMode; + PaError answer = GetClosestFormat(stream->out.client,sampleRate,outputParameters,&shareMode,&stream->out.wavex); + + if (answer !=paFormatIsSupported) + return answer; + LogWAVEFORMATEXTENSIBLE(&stream->out.wavex); + + // stream->out.period = info.DefaultDevicePeriod; + stream->out.period = info.MinimumDevicePeriod; + + /*For an exclusive-mode stream that uses event-driven buffering, + the caller must specify nonzero values for hnsPeriodicity and hnsBufferDuration, + and the values of these two parameters must be equal */ + if (shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE){ + hResult = stream->out.client->Initialize( + shareMode, + AUDCLNT_STREAMFLAGS_EVENTCALLBACK, + stream->out.period, + stream->out.period, + (WAVEFORMATEX*)&stream->out.wavex, + &stream->session + ); + } + else{ + hResult = stream->out.client->Initialize( + shareMode, + AUDCLNT_STREAMFLAGS_EVENTCALLBACK, + 0, + 0, + (WAVEFORMATEX*)&stream->out.wavex, + &stream->session + ); + } + + + if (hResult != S_OK){ + logAUDCLNT_E(hResult); + return paInvalidDevice; + } + + hResult = info.device->Activate( + __uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, + (void**)&stream->outVol); + + if (hResult != S_OK) + return paInvalidDevice; + + hResult = stream->out.client->GetBufferSize(&stream->out.bufferSize); + if (hResult != S_OK) + return paInvalidDevice; + + hResult = stream->out.client->GetStreamLatency(&stream->out.latency); + if (hResult != S_OK) + return paInvalidDevice; + + double periodsPerSecond = 1.0/nano100ToSeconds(stream->out.period); + double samplesPerPeriod = (double)(stream->out.wavex.Format.nSamplesPerSec)/periodsPerSecond; + + //this is the number of samples that are required at each period + stream->out.framesPerHostCallback = stream->out.bufferSize; //(unsigned long)samplesPerPeriod;//unrelated to channels + + /* IMPLEMENT ME - establish which host formats are available */ + hostOutputSampleFormat = PaUtil_SelectClosestAvailableFormat( waveformatToPaFormat(&stream->out.wavex), outputSampleFormat ); + } + else + { + outputChannelCount = 0; + outputSampleFormat = hostOutputSampleFormat = paInt16; /* Surpress 'uninitialized var' warnings. */ + } + + + + /* + IMPLEMENT ME: + + ( the following two checks are taken care of by PaUtil_InitializeBufferProcessor() FIXME - checks needed? ) + + - check that input device can support inputSampleFormat, or that + we have the capability to convert from outputSampleFormat to + a native format + + - check that output device can support outputSampleFormat, or that + we have the capability to convert from outputSampleFormat to + a native format + + - if a full duplex stream is requested, check that the combination + of input and output parameters is supported + + - check that the device supports sampleRate + + - alter sampleRate to a close allowable rate if possible / necessary + + - validate suggestedInputLatency and suggestedOutputLatency parameters, + use default values where necessary + */ + + + + /* validate platform specific flags */ + if( (streamFlags & paPlatformSpecificFlags) != 0 ) + return paInvalidFlag; /* unexpected platform specific flag */ + + + + if( streamCallback ) + { + PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, + &paWasapi->callbackStreamInterface, streamCallback, userData ); + } + else + { + PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, + &paWasapi->blockingStreamInterface, streamCallback, userData ); + } + + PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate ); + + + if (outputParameters && inputParameters){ + + //serious problem #1 + if (stream->in.period != stream->out.period){ + PRINT(("OpenStream: period discrepancy\n")); + goto error; + } + + //serious problem #2 + if (stream->out.framesPerHostCallback != stream->in.framesPerHostCallback){ + PRINT(("OpenStream: framesPerHostCallback discrepancy\n")); + goto error; + } + } + + unsigned long framesPerHostCallback = (outputParameters)? + stream->out.framesPerHostCallback: + stream->in.framesPerHostCallback; + + /* we assume a fixed host buffer size in this example, but the buffer processor + can also support bounded and unknown host buffer sizes by passing + paUtilBoundedHostBufferSize or paUtilUnknownHostBufferSize instead of + paUtilFixedHostBufferSize below. */ + + result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor, + inputChannelCount, inputSampleFormat, hostInputSampleFormat, + outputChannelCount, outputSampleFormat, hostOutputSampleFormat, + sampleRate, streamFlags, framesPerBuffer, + framesPerHostCallback, paUtilFixedHostBufferSize, + streamCallback, userData ); + if( result != paNoError ) + goto error; + + + /* + IMPLEMENT ME: initialise the following fields with estimated or actual + values. + */ + stream->streamRepresentation.streamInfo.inputLatency = + PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor) + + ((inputParameters)?nano100ToSeconds(stream->in.latency) :0); + + stream->streamRepresentation.streamInfo.outputLatency = + PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor) + + ((outputParameters)?nano100ToSeconds(stream->out.latency) :0); + + stream->streamRepresentation.streamInfo.sampleRate = sampleRate; + + + *s = (PaStream*)stream; + + + return result; + +error: + if( stream ) + PaUtil_FreeMemory( stream ); + + return result; +} + + + +/* + When CloseStream() is called, the multi-api layer ensures that + the stream has already been stopped or aborted. +*/ + +#define SAFE_RELEASE(punk) \ + if ((punk) != NULL) \ + { (punk)->Release(); (punk) = NULL; } + +static PaError CloseStream( PaStream* s ) +{ + PaError result = paNoError; + PaWinWasapiStream *stream = (PaWinWasapiStream*)s; + + /* + IMPLEMENT ME: + - additional stream closing + cleanup + */ + + SAFE_RELEASE(stream->out.client); + SAFE_RELEASE(stream->in.client); + SAFE_RELEASE(stream->cclient); + SAFE_RELEASE(stream->rclient); + SAFE_RELEASE(stream->inVol); + SAFE_RELEASE(stream->outVol); + CloseHandle(stream->hThread); + CloseHandle(stream->hNotificationEvent); + + PaUtil_TerminateBufferProcessor( &stream->bufferProcessor ); + PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation ); + PaUtil_FreeMemory( stream ); + + return result; +} + +DWORD WINAPI ProcThread(void *client); + +static PaError StartStream( PaStream *s ) +{ + PaError result = paNoError; + PaWinWasapiStream *stream = (PaWinWasapiStream*)s; + + PaUtil_ResetBufferProcessor( &stream->bufferProcessor ); + + HRESULT hResult=S_OK; + + if (stream->out.client){ + hResult = stream->out.client->GetService(__uuidof(IAudioRenderClient),(void**)&stream->rclient); + logAUDCLNT_E(hResult); + if (hResult!=S_OK) + return paUnanticipatedHostError; + } + + if (stream->in.client){ + hResult = stream->in.client->GetService(__uuidof(IAudioCaptureClient),(void**)&stream->cclient); + logAUDCLNT_E(hResult); + if (hResult!=S_OK) + return paUnanticipatedHostError; + } + + // Create a thread for this client. + stream->hThread = CREATE_THREAD; + + if (stream->hThread == NULL) + return paUnanticipatedHostError; + + return paNoError; +} + + +static PaError StopStream( PaStream *s ) +{ + PaError result = paNoError; + PaWinWasapiStream *stream = (PaWinWasapiStream*)s; + + /* suppress unused variable warnings */ + stream->closeRequest = true; + //todo something MUCH better than this + while(stream->closeRequest) + Sleep(100); + + /* IMPLEMENT ME, see portaudio.h for required behavior */ + + stream->running = false; + + return result; +} + + +static PaError AbortStream( PaStream *s ) +{ + PaError result = paNoError; + PaWinWasapiStream *stream = (PaWinWasapiStream*)s; + + /* suppress unused variable warnings */ + stream->closeRequest = true; + //todo something MUCH better than this + while(stream->closeRequest) + Sleep(100); + + /* IMPLEMENT ME, see portaudio.h for required behavior */ + + return result; +} + + +static PaError IsStreamStopped( PaStream *s ) +{ + PaWinWasapiStream *stream = (PaWinWasapiStream*)s; + + return !stream->running; +} + + +static PaError IsStreamActive( PaStream *s ) +{ + PaWinWasapiStream *stream = (PaWinWasapiStream*)s; + return stream->running; +} + + +static PaTime GetStreamTime( PaStream *s ) +{ + PaWinWasapiStream *stream = (PaWinWasapiStream*)s; + + /* suppress unused variable warnings */ + (void) stream; + + /* IMPLEMENT ME, see portaudio.h for required behavior*/ + + //this is lame ds and mme does the same thing, quite useless method imho + //why dont we fetch the time in the pa callbacks? + //at least its doing to be clocked to something + return PaUtil_GetTime(); +} + + +static double GetStreamCpuLoad( PaStream* s ) +{ + PaWinWasapiStream *stream = (PaWinWasapiStream*)s; + + return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer ); +} + + +/* + As separate stream interfaces are used for blocking and callback + streams, the following functions can be guaranteed to only be called + for blocking streams. +*/ + +static PaError ReadStream( PaStream* s, + void *buffer, + unsigned long frames ) +{ + PaWinWasapiStream *stream = (PaWinWasapiStream*)s; + + /* suppress unused variable warnings */ + (void) buffer; + (void) frames; + (void) stream; + + /* IMPLEMENT ME, see portaudio.h for required behavior*/ + + return paNoError; +} + + +static PaError WriteStream( PaStream* s, + const void *buffer, + unsigned long frames ) +{ + PaWinWasapiStream *stream = (PaWinWasapiStream*)s; + + /* suppress unused variable warnings */ + (void) buffer; + (void) frames; + (void) stream; + + /* IMPLEMENT ME, see portaudio.h for required behavior*/ + + return paNoError; +} + + +static signed long GetStreamReadAvailable( PaStream* s ) +{ + PaWinWasapiStream *stream = (PaWinWasapiStream*)s; + + /* suppress unused variable warnings */ + (void) stream; + + /* IMPLEMENT ME, see portaudio.h for required behavior*/ + + return 0; +} + + +static signed long GetStreamWriteAvailable( PaStream* s ) +{ + PaWinWasapiStream *stream = (PaWinWasapiStream*)s; + + /* suppress unused variable warnings */ + (void) stream; + + /* IMPLEMENT ME, see portaudio.h for required behavior*/ + + return 0; +} + + + +/* + ExampleHostProcessingLoop() illustrates the kind of processing which may + occur in a host implementation. + +*/ +static void WaspiHostProcessingLoop( void *inputBuffer, long inputFrames, + void *outputBuffer, long outputFrames, + void *userData ) +{ + PaWinWasapiStream *stream = (PaWinWasapiStream*)userData; + PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /* IMPLEMENT ME */ + int callbackResult; + unsigned long framesProcessed; + + PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer ); + + + /* + IMPLEMENT ME: + - generate timing information + - handle buffer slips + */ + + /* + If you need to byte swap or shift inputBuffer to convert it into a + portaudio format, do it here. + */ + + + + PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, 0 /* IMPLEMENT ME: pass underflow/overflow flags when necessary */ ); + + /* + depending on whether the host buffers are interleaved, non-interleaved + or a mixture, you will want to call PaUtil_SetInterleaved*Channels(), + PaUtil_SetNonInterleaved*Channel() or PaUtil_Set*Channel() here. + */ + + if( stream->bufferProcessor.inputChannelCount > 0 ) + { + PaUtil_SetInputFrameCount( &stream->bufferProcessor, inputFrames ); + PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, + 0, /* first channel of inputBuffer is channel 0 */ + inputBuffer, + 0 ); /* 0 - use inputChannelCount passed to init buffer processor */ + } + + if( stream->bufferProcessor.outputChannelCount > 0 ) + { + PaUtil_SetOutputFrameCount( &stream->bufferProcessor, outputFrames); + PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, + 0, /* first channel of outputBuffer is channel 0 */ + outputBuffer, + 0 ); /* 0 - use outputChannelCount passed to init buffer processor */ + } + + /* you must pass a valid value of callback result to PaUtil_EndBufferProcessing() + in general you would pass paContinue for normal operation, and + paComplete to drain the buffer processor's internal output buffer. + You can check whether the buffer processor's output buffer is empty + using PaUtil_IsBufferProcessorOuputEmpty( bufferProcessor ) + */ + callbackResult = paContinue; + framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult ); + + + /* + If you need to byte swap or shift outputBuffer to convert it to + host format, do it here. + */ + + PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed ); + + + if( callbackResult == paContinue ) + { + /* nothing special to do */ + } + else if( callbackResult == paAbort ) + { + /* IMPLEMENT ME - finish playback immediately */ + + /* once finished, call the finished callback */ + if( stream->streamRepresentation.streamFinishedCallback != 0 ) + stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData ); + } + else + { + /* User callback has asked us to stop with paComplete or other non-zero value */ + + /* IMPLEMENT ME - finish playback once currently queued audio has completed */ + + /* once finished, call the finished callback */ + if( stream->streamRepresentation.streamFinishedCallback != 0 ) + stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData ); + } +} + + +void +MMCSS_activate(){ + + DWORD stuff=0; + HANDLE thCarac = pAvSetMmThreadCharacteristics("Pro Audio",&stuff); + if (!thCarac){ + PRINT(("AvSetMmThreadCharacteristics failed!\n")); + } + + BOOL prio = pAvSetMmThreadPriority(thCarac,AVRT_PRIORITY_NORMAL); + if (!prio){ + PRINT(("AvSetMmThreadPriority failed!\n")); + } + + //debug + { + HANDLE hh = GetCurrentThread(); + int currprio = GetThreadPriority(hh); + DWORD currclass = GetPriorityClass(GetCurrentProcess()); + PRINT(("currprio 0x%X currclass 0x%X\n",currprio,currclass)); + } +} + + +DWORD WINAPI +ProcThread(void* param){ + HRESULT hResult; + MMCSS_activate(); + + PaWinWasapiStream *stream = (PaWinWasapiStream*)param; + + stream->hNotificationEvent = CreateEvent(NULL, + FALSE, //bManualReset are we sure?? + FALSE, + "PAWASA"); + hResult = stream->out.client->SetEventHandle(stream->hNotificationEvent); + if (hResult != S_OK) + logAUDCLNT_E(hResult); + + if (stream->out.client){ + hResult = stream->out.client->Start(); + if (hResult != S_OK) + logAUDCLNT_E(hResult); + } + + stream->running = true; + bool bOne = false; + + while( !stream->closeRequest ) + { + //lets wait but have a 1 second timeout + DWORD dwResult = WaitForSingleObject(stream->hNotificationEvent, 1000); + switch( dwResult ) { + case WAIT_OBJECT_0: { + + unsigned long usingBS = stream->out.framesPerHostCallback; + + BYTE* indata = 0; + BYTE* outdata = 0; + + hResult = stream->rclient->GetBuffer(usingBS, &outdata); + + if (hResult != S_OK || !outdata) { + //logAUDCLNT_E(hResult); + //most probably shared mode and hResult=AUDCLNT_E_BUFFER_TOO_LARGE + UINT32 padding = 0; + hResult = stream->out.client->GetCurrentPadding(&padding); + if (padding == 0) + break; + usingBS = usingBS-padding; + if (usingBS == 0) + break;//huh? + hResult = stream->rclient->GetBuffer(usingBS, &outdata); + if (hResult != S_OK)//what can we do NOW?? + break; + //logAUDCLNT_E(hResult); + } + + WaspiHostProcessingLoop(indata, usingBS ,outdata, usingBS, stream); + + hResult = stream->rclient->ReleaseBuffer(usingBS, 0); + if (hResult != S_OK) + logAUDCLNT_E(hResult); + + /* This was suggested, but in my tests it doesnt seem to improve the + locking behaviour some drivers have running in exclusive mode. + if(!ResetEvent(stream->hNotificationEvent)){ + logAUDCLNT_E(hResult); + } + */ + + } + break; + + } + } + stream->out.client->Stop(); + stream->closeRequest = false; + + return 0; +} + + + + +#endif //VC 2005 + + + + +#if 0 + if(bFirst) { + float masteur; + hResult = stream->outVol->GetMasterVolumeLevelScalar(&masteur); + if (hResult != S_OK) + logAUDCLNT_E(hResult); + float chan1, chan2; + hResult = stream->outVol->GetChannelVolumeLevelScalar(0, &chan1); + if (hResult != S_OK) + logAUDCLNT_E(hResult); + hResult = stream->outVol->GetChannelVolumeLevelScalar(1, &chan2); + if (hResult != S_OK) + logAUDCLNT_E(hResult); + + BOOL bMute; + hResult = stream->outVol->GetMute(&bMute); + if (hResult != S_OK) + logAUDCLNT_E(hResult); + + stream->outVol->SetMasterVolumeLevelScalar(0.5, NULL); + stream->outVol->SetChannelVolumeLevelScalar(0, 0.5, NULL); + stream->outVol->SetChannelVolumeLevelScalar(1, 0.5, NULL); + stream->outVol->SetMute(FALSE, NULL); + bFirst = false; + } #endif \ No newline at end of file diff --git a/lib-src/portaudio-v19/test/patest_converters.c b/lib-src/portaudio-v19/test/patest_converters.c index d4801bc86..01dd90edf 100644 --- a/lib-src/portaudio-v19/test/patest_converters.c +++ b/lib-src/portaudio-v19/test/patest_converters.c @@ -1,392 +1,392 @@ -/** @file patest_converters.c - @ingroup test_src - @brief Tests the converter functions in pa_converters.c - @author Ross Bencina - - Link with pa_dither.c and pa_converters.c - - see http://www.portaudio.com/trac/wiki/V19ConvertersStatus for a discussion of this. -*/ -/* - * $Id: patest_converters.c,v 1.2 2008-12-31 15:38:36 richardash1981 Exp $ - * - * This program uses the PortAudio Portable Audio Library. - * For more information see: http://www.portaudio.com/ - * Copyright (c) 1999-2008 Ross Bencina and Phil Burk - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * The text above constitutes the entire PortAudio license; however, - * the PortAudio community also makes the following non-binding requests: - * - * Any person wishing to distribute modifications to the Software is - * requested to send the modifications to the original developer so that - * they can be incorporated into the canonical version. It is also - * requested that these non-binding requests be included along with the - * license above. - */ -#include -#include -#include -#include - -#include "portaudio.h" -#include "pa_converters.h" -#include "pa_dither.h" -#include "pa_types.h" -#include "pa_endianness.h" - -#ifndef M_PI -#define M_PI (3.14159265) -#endif - -#define MAX_PER_CHANNEL_FRAME_COUNT (2048) -#define MAX_CHANNEL_COUNT (8) - - -#define SAMPLE_FORMAT_COUNT (6) - -static PaSampleFormat sampleFormats_[ SAMPLE_FORMAT_COUNT ] = - { paFloat32, paInt32, paInt24, paInt16, paInt8, paUInt8 }; /* all standard PA sample formats */ - -static const char* sampleFormatNames_[SAMPLE_FORMAT_COUNT] = - { "paFloat32", "paInt32", "paInt24", "paInt16", "paInt8", "paUInt8" }; - - -static const char* abbreviatedSampleFormatNames_[SAMPLE_FORMAT_COUNT] = - { "f32", "i32", "i24", "i16", " i8", "ui8" }; - -/* - available flags are paClipOff and paDitherOff - clipping is usually applied for float -> int conversions - dither is usually applied for all downconversions (ie anything but 8bit->8bit conversions -*/ - -static int CanClip( PaSampleFormat sourceFormat, PaSampleFormat destinationFormat ) -{ - if( sourceFormat == paFloat32 && destinationFormat != sourceFormat ) - return 1; - else - return 0; -} - -static int CanDither( PaSampleFormat sourceFormat, PaSampleFormat destinationFormat ) -{ - if( sourceFormat < destinationFormat && sourceFormat != paInt8 ) - return 1; - else - return 0; -} - -static void GenerateOneCycleSineReference( double *out, int frameCount, int strideFrames ) -{ - int i; - for( i=0; i < frameCount; ++i ){ - *out = sin( ((double)i/(double)frameCount) * 2. * M_PI ); - out += strideFrames; - } -} - - -static void GenerateOneCycleSine( PaSampleFormat format, void *buffer, int frameCount, int strideFrames ) -{ - switch( format ){ - - case paFloat32: - { - int i; - float *out = (float*)buffer; - for( i=0; i < frameCount; ++i ){ - *out = (float).9 * sin( ((double)i/(double)frameCount) * 2. * M_PI ); - out += strideFrames; - } - } - break; - case paInt32: - { - int i; - PaInt32 *out = (PaInt32*)buffer; - for( i=0; i < frameCount; ++i ){ - *out = (PaInt32)(.9 * sin( ((double)i/(double)frameCount) * 2. * M_PI ) * 0x7FFFFFFF); - out += strideFrames; - } - } - break; - case paInt24: - { - int i; - unsigned char *out = (unsigned char*)buffer; - for( i=0; i < frameCount; ++i ){ - signed long temp = (PaInt32)(.9 * sin( ((double)i/(double)frameCount) * 2. * M_PI ) * 0x7FFFFFFF); - - #if defined(PA_LITTLE_ENDIAN) - out[0] = (unsigned char)(temp >> 8) & 0xFF; - out[1] = (unsigned char)(temp >> 16) & 0xFF; - out[2] = (unsigned char)(temp >> 24) & 0xFF; - #elif defined(PA_BIG_ENDIAN) - out[0] = (unsigned char)(temp >> 24) & 0xFF; - out[1] = (unsigned char)(temp >> 16) & 0xFF; - out[2] = (unsigned char)(temp >> 8) & 0xFF; - #endif - out += 3; - } - } - break; - case paInt16: - { - int i; - PaInt16 *out = (PaInt16*)buffer; - for( i=0; i < frameCount; ++i ){ - *out = (PaInt16)(.9 * sin( ((double)i/(double)frameCount) * 2. * M_PI ) * 0x7FFF ); - out += strideFrames; - } - } - break; - case paInt8: - { - int i; - signed char *out = (signed char*)buffer; - for( i=0; i < frameCount; ++i ){ - *out = (signed char)(.9 * sin( ((double)i/(double)frameCount) * 2. * M_PI ) * 0x7F ); - out += strideFrames; - } - } - break; - case paUInt8: - { - int i; - unsigned char *out = (unsigned char*)buffer; - for( i=0; i < frameCount; ++i ){ - *out = (unsigned char)( .5 * (1. + (.9 * sin( ((double)i/(double)frameCount) * 2. * M_PI ))) * 0xFF ); - out += strideFrames; - } - } - break; - } -} - -int TestNonZeroPresent( void *buffer, int size ) -{ - char *p = (char*)buffer; - int i; - - for( i=0; i < size; ++i ){ - - if( *p != 0 ) - return 1; - ++p; - } - - return 0; -} - -float MaximumAbsDifference( float* sourceBuffer, float* referenceBuffer, int count ) -{ - float result = 0; - float difference; - while( count-- ){ - difference = fabs( *sourceBuffer++ - *referenceBuffer++ ); - if( difference > result ) - result = difference; - } - - return result; -} - -int main( const char **argv, int argc ) -{ - PaUtilTriangularDitherGenerator ditherState; - PaUtilConverter *converter; - void *destinationBuffer, *sourceBuffer; - double *referenceBuffer; - int sourceFormatIndex, destinationFormatIndex; - PaSampleFormat sourceFormat, destinationFormat; - PaStreamFlags flags; - int passFailMatrix[SAMPLE_FORMAT_COUNT][SAMPLE_FORMAT_COUNT]; // [source][destination] - float noiseAmplitudeMatrix[SAMPLE_FORMAT_COUNT][SAMPLE_FORMAT_COUNT]; // [source][destination] - float amp; - -#define FLAG_COMBINATION_COUNT (4) - PaStreamFlags flagCombinations[FLAG_COMBINATION_COUNT] = { paNoFlag, paClipOff, paDitherOff, paClipOff | paDitherOff }; - const char *flagCombinationNames[FLAG_COMBINATION_COUNT] = { "paNoFlag", "paClipOff", "paDitherOff", "paClipOff | paDitherOff" }; - int flagCombinationIndex; - - PaUtil_InitializeTriangularDitherState( &ditherState ); - - /* allocate more than enough space, we use sizeof(float) but we need to fit any 32 bit datum */ - - destinationBuffer = (void*)malloc( MAX_PER_CHANNEL_FRAME_COUNT * MAX_CHANNEL_COUNT * sizeof(float) ); - sourceBuffer = (void*)malloc( MAX_PER_CHANNEL_FRAME_COUNT * MAX_CHANNEL_COUNT * sizeof(float) ); - referenceBuffer = (void*)malloc( MAX_PER_CHANNEL_FRAME_COUNT * MAX_CHANNEL_COUNT * sizeof(float) ); - - - /* the first round of tests simply iterates through the buffer combinations testing - that putting something in gives something out */ - - printf( "= Sine wave in, something out =\n" ); - - printf( "\n" ); - - GenerateOneCycleSine( paFloat32, referenceBuffer, MAX_PER_CHANNEL_FRAME_COUNT, 1 ); - - for( flagCombinationIndex = 0; flagCombinationIndex < FLAG_COMBINATION_COUNT; ++flagCombinationIndex ){ - flags = flagCombinations[flagCombinationIndex]; - - printf( "\n" ); - printf( "== flags = %s ==\n", flagCombinationNames[flagCombinationIndex] ); - - for( sourceFormatIndex = 0; sourceFormatIndex < SAMPLE_FORMAT_COUNT; ++sourceFormatIndex ){ - for( destinationFormatIndex = 0; destinationFormatIndex < SAMPLE_FORMAT_COUNT; ++destinationFormatIndex ){ - sourceFormat = sampleFormats_[sourceFormatIndex]; - destinationFormat = sampleFormats_[destinationFormatIndex]; - //printf( "%s -> %s ", sampleFormatNames_[ sourceFormatIndex ], sampleFormatNames_[ destinationFormatIndex ] ); - - converter = PaUtil_SelectConverter( sourceFormat, destinationFormat, flags ); - - /* source is a sinewave */ - GenerateOneCycleSine( sourceFormat, sourceBuffer, MAX_PER_CHANNEL_FRAME_COUNT, 1 ); - - /* zero destination */ - memset( destinationBuffer, 0, MAX_PER_CHANNEL_FRAME_COUNT * My_Pa_GetSampleSize( destinationFormat ) ); - - (*converter)( destinationBuffer, 1, sourceBuffer, 1, MAX_PER_CHANNEL_FRAME_COUNT, &ditherState ); - - /* - Other ways we could test this would be: - - pass a constant, check for a constant (wouldn't work with dither) - - pass alternating +/-, check for the same... - */ - if( TestNonZeroPresent( destinationBuffer, MAX_PER_CHANNEL_FRAME_COUNT * My_Pa_GetSampleSize( destinationFormat ) ) ){ - //printf( "PASSED\n" ); - passFailMatrix[sourceFormatIndex][destinationFormatIndex] = 1; - }else{ - //printf( "FAILED\n" ); - passFailMatrix[sourceFormatIndex][destinationFormatIndex] = 0; - } - - - /* try to measure the noise floor (comparing output signal to a float32 sine wave) */ - - if( passFailMatrix[sourceFormatIndex][destinationFormatIndex] ){ - - /* convert destination back to paFloat32 into source */ - converter = PaUtil_SelectConverter( destinationFormat, paFloat32, paNoFlag ); - - memset( sourceBuffer, 0, MAX_PER_CHANNEL_FRAME_COUNT * My_Pa_GetSampleSize( paFloat32 ) ); - (*converter)( sourceBuffer, 1, destinationBuffer, 1, MAX_PER_CHANNEL_FRAME_COUNT, &ditherState ); - - if( TestNonZeroPresent( sourceBuffer, MAX_PER_CHANNEL_FRAME_COUNT * My_Pa_GetSampleSize( paFloat32 ) ) ){ - - noiseAmplitudeMatrix[sourceFormatIndex][destinationFormatIndex] = MaximumAbsDifference( (float*)sourceBuffer, (float*)referenceBuffer, MAX_PER_CHANNEL_FRAME_COUNT ); - - }else{ - /* can't test noise floor because there is no conversion from dest format to float available */ - noiseAmplitudeMatrix[sourceFormatIndex][destinationFormatIndex] = -1; // mark as failed - } - }else{ - noiseAmplitudeMatrix[sourceFormatIndex][destinationFormatIndex] = -1; // mark as failed - } - } - } - - printf( "\n" ); - printf( "=== Output contains non-zero data ===\n" ); - printf( "Key: . - pass, X - fail\n" ); - printf( "{{{\n" ); // trac preformated text tag - printf( "in| out: " ); - for( destinationFormatIndex = 0; destinationFormatIndex < SAMPLE_FORMAT_COUNT; ++destinationFormatIndex ){ - printf( " %s ", abbreviatedSampleFormatNames_[destinationFormatIndex] ); - } - printf( "\n" ); - - for( sourceFormatIndex = 0; sourceFormatIndex < SAMPLE_FORMAT_COUNT; ++sourceFormatIndex ){ - printf( "%s ", abbreviatedSampleFormatNames_[sourceFormatIndex] ); - for( destinationFormatIndex = 0; destinationFormatIndex < SAMPLE_FORMAT_COUNT; ++destinationFormatIndex ){ - printf( " %s ", (passFailMatrix[sourceFormatIndex][destinationFormatIndex])? " ." : " X" ); - } - printf( "\n" ); - } - printf( "}}}\n" ); // trac preformated text tag - - printf( "\n" ); - printf( "=== Combined dynamic range (src->dest->float32) ===\n" ); - printf( "Key: Noise amplitude in dBfs, X - fail (either above failed or dest->float32 failed)\n" ); - printf( "{{{\n" ); // trac preformated text tag - printf( "in| out: " ); - for( destinationFormatIndex = 0; destinationFormatIndex < SAMPLE_FORMAT_COUNT; ++destinationFormatIndex ){ - printf( " %s ", abbreviatedSampleFormatNames_[destinationFormatIndex] ); - } - printf( "\n" ); - - for( sourceFormatIndex = 0; sourceFormatIndex < SAMPLE_FORMAT_COUNT; ++sourceFormatIndex ){ - printf( " %s ", abbreviatedSampleFormatNames_[sourceFormatIndex] ); - for( destinationFormatIndex = 0; destinationFormatIndex < SAMPLE_FORMAT_COUNT; ++destinationFormatIndex ){ - amp = noiseAmplitudeMatrix[sourceFormatIndex][destinationFormatIndex]; - if( amp < 0. ) - printf( " X " ); - else - printf( " % 6.1f ", 20.*log10(amp) ); - } - printf( "\n" ); - } - printf( "}}}\n" ); // trac preformated text tag - } - - - free( destinationBuffer ); - free( sourceBuffer ); - free( referenceBuffer ); -} - -// copied here for now otherwise we need to include the world just for this function. -PaError My_Pa_GetSampleSize( PaSampleFormat format ) -{ - int result; - - switch( format & ~paNonInterleaved ) - { - - case paUInt8: - case paInt8: - result = 1; - break; - - case paInt16: - result = 2; - break; - - case paInt24: - result = 3; - break; - - case paFloat32: - case paInt32: - result = 4; - break; - - default: - result = paSampleFormatNotSupported; - break; - } - - return (PaError) result; -} +/** @file patest_converters.c + @ingroup test_src + @brief Tests the converter functions in pa_converters.c + @author Ross Bencina + + Link with pa_dither.c and pa_converters.c + + see http://www.portaudio.com/trac/wiki/V19ConvertersStatus for a discussion of this. +*/ +/* + * $Id: patest_converters.c,v 1.2 2008-12-31 15:38:36 richardash1981 Exp $ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com/ + * Copyright (c) 1999-2008 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ +#include +#include +#include +#include + +#include "portaudio.h" +#include "pa_converters.h" +#include "pa_dither.h" +#include "pa_types.h" +#include "pa_endianness.h" + +#ifndef M_PI +#define M_PI (3.14159265) +#endif + +#define MAX_PER_CHANNEL_FRAME_COUNT (2048) +#define MAX_CHANNEL_COUNT (8) + + +#define SAMPLE_FORMAT_COUNT (6) + +static PaSampleFormat sampleFormats_[ SAMPLE_FORMAT_COUNT ] = + { paFloat32, paInt32, paInt24, paInt16, paInt8, paUInt8 }; /* all standard PA sample formats */ + +static const char* sampleFormatNames_[SAMPLE_FORMAT_COUNT] = + { "paFloat32", "paInt32", "paInt24", "paInt16", "paInt8", "paUInt8" }; + + +static const char* abbreviatedSampleFormatNames_[SAMPLE_FORMAT_COUNT] = + { "f32", "i32", "i24", "i16", " i8", "ui8" }; + +/* + available flags are paClipOff and paDitherOff + clipping is usually applied for float -> int conversions + dither is usually applied for all downconversions (ie anything but 8bit->8bit conversions +*/ + +static int CanClip( PaSampleFormat sourceFormat, PaSampleFormat destinationFormat ) +{ + if( sourceFormat == paFloat32 && destinationFormat != sourceFormat ) + return 1; + else + return 0; +} + +static int CanDither( PaSampleFormat sourceFormat, PaSampleFormat destinationFormat ) +{ + if( sourceFormat < destinationFormat && sourceFormat != paInt8 ) + return 1; + else + return 0; +} + +static void GenerateOneCycleSineReference( double *out, int frameCount, int strideFrames ) +{ + int i; + for( i=0; i < frameCount; ++i ){ + *out = sin( ((double)i/(double)frameCount) * 2. * M_PI ); + out += strideFrames; + } +} + + +static void GenerateOneCycleSine( PaSampleFormat format, void *buffer, int frameCount, int strideFrames ) +{ + switch( format ){ + + case paFloat32: + { + int i; + float *out = (float*)buffer; + for( i=0; i < frameCount; ++i ){ + *out = (float).9 * sin( ((double)i/(double)frameCount) * 2. * M_PI ); + out += strideFrames; + } + } + break; + case paInt32: + { + int i; + PaInt32 *out = (PaInt32*)buffer; + for( i=0; i < frameCount; ++i ){ + *out = (PaInt32)(.9 * sin( ((double)i/(double)frameCount) * 2. * M_PI ) * 0x7FFFFFFF); + out += strideFrames; + } + } + break; + case paInt24: + { + int i; + unsigned char *out = (unsigned char*)buffer; + for( i=0; i < frameCount; ++i ){ + signed long temp = (PaInt32)(.9 * sin( ((double)i/(double)frameCount) * 2. * M_PI ) * 0x7FFFFFFF); + + #if defined(PA_LITTLE_ENDIAN) + out[0] = (unsigned char)(temp >> 8) & 0xFF; + out[1] = (unsigned char)(temp >> 16) & 0xFF; + out[2] = (unsigned char)(temp >> 24) & 0xFF; + #elif defined(PA_BIG_ENDIAN) + out[0] = (unsigned char)(temp >> 24) & 0xFF; + out[1] = (unsigned char)(temp >> 16) & 0xFF; + out[2] = (unsigned char)(temp >> 8) & 0xFF; + #endif + out += 3; + } + } + break; + case paInt16: + { + int i; + PaInt16 *out = (PaInt16*)buffer; + for( i=0; i < frameCount; ++i ){ + *out = (PaInt16)(.9 * sin( ((double)i/(double)frameCount) * 2. * M_PI ) * 0x7FFF ); + out += strideFrames; + } + } + break; + case paInt8: + { + int i; + signed char *out = (signed char*)buffer; + for( i=0; i < frameCount; ++i ){ + *out = (signed char)(.9 * sin( ((double)i/(double)frameCount) * 2. * M_PI ) * 0x7F ); + out += strideFrames; + } + } + break; + case paUInt8: + { + int i; + unsigned char *out = (unsigned char*)buffer; + for( i=0; i < frameCount; ++i ){ + *out = (unsigned char)( .5 * (1. + (.9 * sin( ((double)i/(double)frameCount) * 2. * M_PI ))) * 0xFF ); + out += strideFrames; + } + } + break; + } +} + +int TestNonZeroPresent( void *buffer, int size ) +{ + char *p = (char*)buffer; + int i; + + for( i=0; i < size; ++i ){ + + if( *p != 0 ) + return 1; + ++p; + } + + return 0; +} + +float MaximumAbsDifference( float* sourceBuffer, float* referenceBuffer, int count ) +{ + float result = 0; + float difference; + while( count-- ){ + difference = fabs( *sourceBuffer++ - *referenceBuffer++ ); + if( difference > result ) + result = difference; + } + + return result; +} + +int main( const char **argv, int argc ) +{ + PaUtilTriangularDitherGenerator ditherState; + PaUtilConverter *converter; + void *destinationBuffer, *sourceBuffer; + double *referenceBuffer; + int sourceFormatIndex, destinationFormatIndex; + PaSampleFormat sourceFormat, destinationFormat; + PaStreamFlags flags; + int passFailMatrix[SAMPLE_FORMAT_COUNT][SAMPLE_FORMAT_COUNT]; // [source][destination] + float noiseAmplitudeMatrix[SAMPLE_FORMAT_COUNT][SAMPLE_FORMAT_COUNT]; // [source][destination] + float amp; + +#define FLAG_COMBINATION_COUNT (4) + PaStreamFlags flagCombinations[FLAG_COMBINATION_COUNT] = { paNoFlag, paClipOff, paDitherOff, paClipOff | paDitherOff }; + const char *flagCombinationNames[FLAG_COMBINATION_COUNT] = { "paNoFlag", "paClipOff", "paDitherOff", "paClipOff | paDitherOff" }; + int flagCombinationIndex; + + PaUtil_InitializeTriangularDitherState( &ditherState ); + + /* allocate more than enough space, we use sizeof(float) but we need to fit any 32 bit datum */ + + destinationBuffer = (void*)malloc( MAX_PER_CHANNEL_FRAME_COUNT * MAX_CHANNEL_COUNT * sizeof(float) ); + sourceBuffer = (void*)malloc( MAX_PER_CHANNEL_FRAME_COUNT * MAX_CHANNEL_COUNT * sizeof(float) ); + referenceBuffer = (void*)malloc( MAX_PER_CHANNEL_FRAME_COUNT * MAX_CHANNEL_COUNT * sizeof(float) ); + + + /* the first round of tests simply iterates through the buffer combinations testing + that putting something in gives something out */ + + printf( "= Sine wave in, something out =\n" ); + + printf( "\n" ); + + GenerateOneCycleSine( paFloat32, referenceBuffer, MAX_PER_CHANNEL_FRAME_COUNT, 1 ); + + for( flagCombinationIndex = 0; flagCombinationIndex < FLAG_COMBINATION_COUNT; ++flagCombinationIndex ){ + flags = flagCombinations[flagCombinationIndex]; + + printf( "\n" ); + printf( "== flags = %s ==\n", flagCombinationNames[flagCombinationIndex] ); + + for( sourceFormatIndex = 0; sourceFormatIndex < SAMPLE_FORMAT_COUNT; ++sourceFormatIndex ){ + for( destinationFormatIndex = 0; destinationFormatIndex < SAMPLE_FORMAT_COUNT; ++destinationFormatIndex ){ + sourceFormat = sampleFormats_[sourceFormatIndex]; + destinationFormat = sampleFormats_[destinationFormatIndex]; + //printf( "%s -> %s ", sampleFormatNames_[ sourceFormatIndex ], sampleFormatNames_[ destinationFormatIndex ] ); + + converter = PaUtil_SelectConverter( sourceFormat, destinationFormat, flags ); + + /* source is a sinewave */ + GenerateOneCycleSine( sourceFormat, sourceBuffer, MAX_PER_CHANNEL_FRAME_COUNT, 1 ); + + /* zero destination */ + memset( destinationBuffer, 0, MAX_PER_CHANNEL_FRAME_COUNT * My_Pa_GetSampleSize( destinationFormat ) ); + + (*converter)( destinationBuffer, 1, sourceBuffer, 1, MAX_PER_CHANNEL_FRAME_COUNT, &ditherState ); + + /* + Other ways we could test this would be: + - pass a constant, check for a constant (wouldn't work with dither) + - pass alternating +/-, check for the same... + */ + if( TestNonZeroPresent( destinationBuffer, MAX_PER_CHANNEL_FRAME_COUNT * My_Pa_GetSampleSize( destinationFormat ) ) ){ + //printf( "PASSED\n" ); + passFailMatrix[sourceFormatIndex][destinationFormatIndex] = 1; + }else{ + //printf( "FAILED\n" ); + passFailMatrix[sourceFormatIndex][destinationFormatIndex] = 0; + } + + + /* try to measure the noise floor (comparing output signal to a float32 sine wave) */ + + if( passFailMatrix[sourceFormatIndex][destinationFormatIndex] ){ + + /* convert destination back to paFloat32 into source */ + converter = PaUtil_SelectConverter( destinationFormat, paFloat32, paNoFlag ); + + memset( sourceBuffer, 0, MAX_PER_CHANNEL_FRAME_COUNT * My_Pa_GetSampleSize( paFloat32 ) ); + (*converter)( sourceBuffer, 1, destinationBuffer, 1, MAX_PER_CHANNEL_FRAME_COUNT, &ditherState ); + + if( TestNonZeroPresent( sourceBuffer, MAX_PER_CHANNEL_FRAME_COUNT * My_Pa_GetSampleSize( paFloat32 ) ) ){ + + noiseAmplitudeMatrix[sourceFormatIndex][destinationFormatIndex] = MaximumAbsDifference( (float*)sourceBuffer, (float*)referenceBuffer, MAX_PER_CHANNEL_FRAME_COUNT ); + + }else{ + /* can't test noise floor because there is no conversion from dest format to float available */ + noiseAmplitudeMatrix[sourceFormatIndex][destinationFormatIndex] = -1; // mark as failed + } + }else{ + noiseAmplitudeMatrix[sourceFormatIndex][destinationFormatIndex] = -1; // mark as failed + } + } + } + + printf( "\n" ); + printf( "=== Output contains non-zero data ===\n" ); + printf( "Key: . - pass, X - fail\n" ); + printf( "{{{\n" ); // trac preformated text tag + printf( "in| out: " ); + for( destinationFormatIndex = 0; destinationFormatIndex < SAMPLE_FORMAT_COUNT; ++destinationFormatIndex ){ + printf( " %s ", abbreviatedSampleFormatNames_[destinationFormatIndex] ); + } + printf( "\n" ); + + for( sourceFormatIndex = 0; sourceFormatIndex < SAMPLE_FORMAT_COUNT; ++sourceFormatIndex ){ + printf( "%s ", abbreviatedSampleFormatNames_[sourceFormatIndex] ); + for( destinationFormatIndex = 0; destinationFormatIndex < SAMPLE_FORMAT_COUNT; ++destinationFormatIndex ){ + printf( " %s ", (passFailMatrix[sourceFormatIndex][destinationFormatIndex])? " ." : " X" ); + } + printf( "\n" ); + } + printf( "}}}\n" ); // trac preformated text tag + + printf( "\n" ); + printf( "=== Combined dynamic range (src->dest->float32) ===\n" ); + printf( "Key: Noise amplitude in dBfs, X - fail (either above failed or dest->float32 failed)\n" ); + printf( "{{{\n" ); // trac preformated text tag + printf( "in| out: " ); + for( destinationFormatIndex = 0; destinationFormatIndex < SAMPLE_FORMAT_COUNT; ++destinationFormatIndex ){ + printf( " %s ", abbreviatedSampleFormatNames_[destinationFormatIndex] ); + } + printf( "\n" ); + + for( sourceFormatIndex = 0; sourceFormatIndex < SAMPLE_FORMAT_COUNT; ++sourceFormatIndex ){ + printf( " %s ", abbreviatedSampleFormatNames_[sourceFormatIndex] ); + for( destinationFormatIndex = 0; destinationFormatIndex < SAMPLE_FORMAT_COUNT; ++destinationFormatIndex ){ + amp = noiseAmplitudeMatrix[sourceFormatIndex][destinationFormatIndex]; + if( amp < 0. ) + printf( " X " ); + else + printf( " % 6.1f ", 20.*log10(amp) ); + } + printf( "\n" ); + } + printf( "}}}\n" ); // trac preformated text tag + } + + + free( destinationBuffer ); + free( sourceBuffer ); + free( referenceBuffer ); +} + +// copied here for now otherwise we need to include the world just for this function. +PaError My_Pa_GetSampleSize( PaSampleFormat format ) +{ + int result; + + switch( format & ~paNonInterleaved ) + { + + case paUInt8: + case paInt8: + result = 1; + break; + + case paInt16: + result = 2; + break; + + case paInt24: + result = 3; + break; + + case paFloat32: + case paInt32: + result = 4; + break; + + default: + result = paSampleFormatNotSupported; + break; + } + + return (PaError) result; +} diff --git a/lib-src/portaudio-v19/test/patest_dsound_surround.c b/lib-src/portaudio-v19/test/patest_dsound_surround.c index 51300bf37..37c529709 100644 --- a/lib-src/portaudio-v19/test/patest_dsound_surround.c +++ b/lib-src/portaudio-v19/test/patest_dsound_surround.c @@ -1,205 +1,205 @@ -/* - * $Id: patest_dsound_surround.c,v 1.3 2008-12-31 15:38:36 richardash1981 Exp $ - * Portable Audio I/O Library - * Windows DirectSound surround sound output test - * - * Copyright (c) 2007 Ross Bencina - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * The text above constitutes the entire PortAudio license; however, - * the PortAudio community also makes the following non-binding requests: - * - * Any person wishing to distribute modifications to the Software is - * requested to send the modifications to the original developer so that - * they can be incorporated into the canonical version. It is also - * requested that these non-binding requests be included along with the - * license above. - */ - -#include -#include - -#include /* required when using pa_win_wmme.h */ -#include /* required when using pa_win_wmme.h */ - -#include "portaudio.h" -#include "pa_win_ds.h" - -#define NUM_SECONDS (12) -#define SAMPLE_RATE (44100) -#define FRAMES_PER_BUFFER (64) - -#ifndef M_PI -#define M_PI (3.14159265) -#endif - -#define TABLE_SIZE (100) - -#define CHANNEL_COUNT (6) - - - -typedef struct -{ - float sine[TABLE_SIZE]; - int phase; - int currentChannel; - int cycleCount; -} -paTestData; - -/* This routine will be called by the PortAudio engine when audio is needed. -** It may called at interrupt level on some machines so don't do anything -** that could mess up the system like calling malloc() or free(). -*/ -static int patestCallback( const void *inputBuffer, void *outputBuffer, - unsigned long framesPerBuffer, - const PaStreamCallbackTimeInfo* timeInfo, - PaStreamCallbackFlags statusFlags, - void *userData ) -{ - paTestData *data = (paTestData*)userData; - float *out = (float*)outputBuffer; - unsigned long i,j; - - (void) timeInfo; /* Prevent unused variable warnings. */ - (void) statusFlags; - (void) inputBuffer; - - for( i=0; icurrentChannel && data->cycleCount < 4410 ){ - *out++ = data->sine[data->phase]; - data->phase += 1 + j; // play each channel at a different pitch so they can be distinguished - if( data->phase >= TABLE_SIZE ){ - data->phase -= TABLE_SIZE; - } - }else{ - *out++ = 0; - } - } - - data->cycleCount++; - if( data->cycleCount > 44100 ){ - data->cycleCount = 0; - - ++data->currentChannel; - if( data->currentChannel >= CHANNEL_COUNT ) - data->currentChannel -= CHANNEL_COUNT; - } - } - - return paContinue; -} - -/*******************************************************************/ -int main(int argc, char* argv[]) -{ - PaStreamParameters outputParameters; - PaWinDirectSoundStreamInfo directSoundStreamInfo; - PaStream *stream; - PaError err; - paTestData data; - int i; - int deviceIndex; - - printf("PortAudio Test: output a sine blip on each channel. SR = %d, BufSize = %d, Chans = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER, CHANNEL_COUNT); - - err = Pa_Initialize(); - if( err != paNoError ) goto error; - - deviceIndex = Pa_GetHostApiInfo( Pa_HostApiTypeIdToHostApiIndex( paDirectSound ) )->defaultOutputDevice; - if( argc == 2 ){ - sscanf( argv[1], "%d", &deviceIndex ); - } - - printf( "using device id %d (%s)\n", deviceIndex, Pa_GetDeviceInfo(deviceIndex)->name ); - - /* initialise sinusoidal wavetable */ - for( i=0; idefaultLowOutputLatency; - outputParameters.hostApiSpecificStreamInfo = NULL; - - /* it's not strictly necessary to provide a channelMask for surround sound - output. But if you want to be sure which channel mask PortAudio will use - then you should supply one */ - directSoundStreamInfo.size = sizeof(PaWinDirectSoundStreamInfo); - directSoundStreamInfo.hostApiType = paDirectSound; - directSoundStreamInfo.version = 1; - directSoundStreamInfo.flags = paWinDirectSoundUseChannelMask; - directSoundStreamInfo.channelMask = PAWIN_SPEAKER_5POINT1; /* request 5.1 output format */ - outputParameters.hostApiSpecificStreamInfo = &directSoundStreamInfo; - - if( Pa_IsFormatSupported( 0, &outputParameters, SAMPLE_RATE ) == paFormatIsSupported ){ - printf( "Pa_IsFormatSupported reports device will support %d channels.\n", CHANNEL_COUNT ); - }else{ - printf( "Pa_IsFormatSupported reports device will not support %d channels.\n", CHANNEL_COUNT ); - } - - err = Pa_OpenStream( - &stream, - NULL, /* no input */ - &outputParameters, - SAMPLE_RATE, - FRAMES_PER_BUFFER, - paClipOff, /* we won't output out of range samples so don't bother clipping them */ - patestCallback, - &data ); - if( err != paNoError ) goto error; - - err = Pa_StartStream( stream ); - if( err != paNoError ) goto error; - - printf("Play for %d seconds.\n", NUM_SECONDS ); - Pa_Sleep( NUM_SECONDS * 1000 ); - - err = Pa_StopStream( stream ); - if( err != paNoError ) goto error; - - err = Pa_CloseStream( stream ); - if( err != paNoError ) goto error; - - Pa_Terminate(); - printf("Test finished.\n"); - - return err; -error: - Pa_Terminate(); - fprintf( stderr, "An error occured while using the portaudio stream\n" ); - fprintf( stderr, "Error number: %d\n", err ); - fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); - return err; -} - +/* + * $Id: patest_dsound_surround.c,v 1.3 2008-12-31 15:38:36 richardash1981 Exp $ + * Portable Audio I/O Library + * Windows DirectSound surround sound output test + * + * Copyright (c) 2007 Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include + +#include /* required when using pa_win_wmme.h */ +#include /* required when using pa_win_wmme.h */ + +#include "portaudio.h" +#include "pa_win_ds.h" + +#define NUM_SECONDS (12) +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (64) + +#ifndef M_PI +#define M_PI (3.14159265) +#endif + +#define TABLE_SIZE (100) + +#define CHANNEL_COUNT (6) + + + +typedef struct +{ + float sine[TABLE_SIZE]; + int phase; + int currentChannel; + int cycleCount; +} +paTestData; + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + unsigned long i,j; + + (void) timeInfo; /* Prevent unused variable warnings. */ + (void) statusFlags; + (void) inputBuffer; + + for( i=0; icurrentChannel && data->cycleCount < 4410 ){ + *out++ = data->sine[data->phase]; + data->phase += 1 + j; // play each channel at a different pitch so they can be distinguished + if( data->phase >= TABLE_SIZE ){ + data->phase -= TABLE_SIZE; + } + }else{ + *out++ = 0; + } + } + + data->cycleCount++; + if( data->cycleCount > 44100 ){ + data->cycleCount = 0; + + ++data->currentChannel; + if( data->currentChannel >= CHANNEL_COUNT ) + data->currentChannel -= CHANNEL_COUNT; + } + } + + return paContinue; +} + +/*******************************************************************/ +int main(int argc, char* argv[]) +{ + PaStreamParameters outputParameters; + PaWinDirectSoundStreamInfo directSoundStreamInfo; + PaStream *stream; + PaError err; + paTestData data; + int i; + int deviceIndex; + + printf("PortAudio Test: output a sine blip on each channel. SR = %d, BufSize = %d, Chans = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER, CHANNEL_COUNT); + + err = Pa_Initialize(); + if( err != paNoError ) goto error; + + deviceIndex = Pa_GetHostApiInfo( Pa_HostApiTypeIdToHostApiIndex( paDirectSound ) )->defaultOutputDevice; + if( argc == 2 ){ + sscanf( argv[1], "%d", &deviceIndex ); + } + + printf( "using device id %d (%s)\n", deviceIndex, Pa_GetDeviceInfo(deviceIndex)->name ); + + /* initialise sinusoidal wavetable */ + for( i=0; idefaultLowOutputLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + + /* it's not strictly necessary to provide a channelMask for surround sound + output. But if you want to be sure which channel mask PortAudio will use + then you should supply one */ + directSoundStreamInfo.size = sizeof(PaWinDirectSoundStreamInfo); + directSoundStreamInfo.hostApiType = paDirectSound; + directSoundStreamInfo.version = 1; + directSoundStreamInfo.flags = paWinDirectSoundUseChannelMask; + directSoundStreamInfo.channelMask = PAWIN_SPEAKER_5POINT1; /* request 5.1 output format */ + outputParameters.hostApiSpecificStreamInfo = &directSoundStreamInfo; + + if( Pa_IsFormatSupported( 0, &outputParameters, SAMPLE_RATE ) == paFormatIsSupported ){ + printf( "Pa_IsFormatSupported reports device will support %d channels.\n", CHANNEL_COUNT ); + }else{ + printf( "Pa_IsFormatSupported reports device will not support %d channels.\n", CHANNEL_COUNT ); + } + + err = Pa_OpenStream( + &stream, + NULL, /* no input */ + &outputParameters, + SAMPLE_RATE, + FRAMES_PER_BUFFER, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + patestCallback, + &data ); + if( err != paNoError ) goto error; + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + printf("Play for %d seconds.\n", NUM_SECONDS ); + Pa_Sleep( NUM_SECONDS * 1000 ); + + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + + Pa_Terminate(); + printf("Test finished.\n"); + + return err; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} + diff --git a/lib-src/portaudio-v19/test/patest_read_write_wire.c b/lib-src/portaudio-v19/test/patest_read_write_wire.c index 760f9e1b9..32d335448 100644 --- a/lib-src/portaudio-v19/test/patest_read_write_wire.c +++ b/lib-src/portaudio-v19/test/patest_read_write_wire.c @@ -1,215 +1,215 @@ -/** @file patest_read_write_wire.c - @ingroup test_src - @brief Tests full duplex blocking I/O by passing input straight to output. - @author Bjorn Roche. XO Audio LLC for Z-Systems Engineering. - @author based on code by: Phil Burk http://www.softsynth.com - @author based on code by: Ross Bencina rossb@audiomulch.com -*/ -/* - * $Id: patest_read_write_wire.c,v 1.8 2008-12-31 15:38:36 richardash1981 Exp $ - * - * This program uses the PortAudio Portable Audio Library. - * For more information see: http://www.portaudio.com - * Copyright (c) 1999-2000 Ross Bencina and Phil Burk - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * The text above constitutes the entire PortAudio license; however, - * the PortAudio community also makes the following non-binding requests: - * - * Any person wishing to distribute modifications to the Software is - * requested to send the modifications to the original developer so that - * they can be incorporated into the canonical version. It is also - * requested that these non-binding requests be included along with the - * license above. - */ - -#include -#include -#include -#include "portaudio.h" - -/* #define SAMPLE_RATE (17932) // Test failure to open with this value. */ -#define SAMPLE_RATE (44100) -#define FRAMES_PER_BUFFER (1024) -#define NUM_CHANNELS (2) -/* #define DITHER_FLAG (paDitherOff) */ -#define DITHER_FLAG (0) /**/ - -/* Select sample format. */ -#if 0 -#define PA_SAMPLE_TYPE paFloat32 -#define SAMPLE_SIZE (4) -#define SAMPLE_SILENCE (0.0f) -#define CLEAR(a) memset( (a), 0, FRAMES_PER_BUFFER * NUM_CHANNELS * SAMPLE_SIZE ) -#define PRINTF_S_FORMAT "%.8f" -#elif 0 -#define PA_SAMPLE_TYPE paInt16 -#define SAMPLE_SIZE (2) -#define SAMPLE_SILENCE (0) -#define CLEAR(a) memset( (a), 0, FRAMES_PER_BUFFER * NUM_CHANNELS * SAMPLE_SIZE ) -#define PRINTF_S_FORMAT "%d" -#elif 1 -#define PA_SAMPLE_TYPE paInt24 -#define SAMPLE_SIZE (3) -#define SAMPLE_SILENCE (0) -#define CLEAR(a) memset( (a), 0, FRAMES_PER_BUFFER * NUM_CHANNELS * SAMPLE_SIZE ) -#define PRINTF_S_FORMAT "%d" -#elif 0 -#define PA_SAMPLE_TYPE paInt8 -#define SAMPLE_SIZE (1) -#define SAMPLE_SILENCE (0) -#define CLEAR(a) memset( (a), 0, FRAMES_PER_BUFFER * NUM_CHANNELS * SAMPLE_SIZE ) -#define PRINTF_S_FORMAT "%d" -#else -#define PA_SAMPLE_TYPE paUInt8 -#define SAMPLE_SIZE (1) -#define SAMPLE_SILENCE (128) -#define CLEAR( a ) { \ - int i; \ - for( i=0; idefaultLowInputLatency ); - printf( "Input HL: %g s\n", Pa_GetDeviceInfo( inputParameters.device )->defaultHighInputLatency ); - inputParameters.channelCount = NUM_CHANNELS; - inputParameters.sampleFormat = PA_SAMPLE_TYPE; - inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultHighInputLatency ; - inputParameters.hostApiSpecificStreamInfo = NULL; - - outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */ - printf( "Output device # %d.\n", outputParameters.device ); - printf( "Output LL: %g s\n", Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency ); - printf( "Output HL: %g s\n", Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency ); - outputParameters.channelCount = NUM_CHANNELS; - outputParameters.sampleFormat = PA_SAMPLE_TYPE; - outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency; - outputParameters.hostApiSpecificStreamInfo = NULL; - - /* -- setup -- */ - - err = Pa_OpenStream( - &stream, - &inputParameters, - &outputParameters, - SAMPLE_RATE, - FRAMES_PER_BUFFER, - paClipOff, /* we won't output out of range samples so don't bother clipping them */ - NULL, /* no callback, use blocking API */ - NULL ); /* no callback, so no callback userData */ - if( err != paNoError ) goto error; - - err = Pa_StartStream( stream ); - if( err != paNoError ) goto error; - printf("Wire on. Will run one minute.\n"); fflush(stdout); - - for( i=0; i<(60*SAMPLE_RATE)/FRAMES_PER_BUFFER; ++i ) - { - err = Pa_WriteStream( stream, sampleBlock, FRAMES_PER_BUFFER ); - if( err ) goto xrun; - err = Pa_ReadStream( stream, sampleBlock, FRAMES_PER_BUFFER ); - if( err ) goto xrun; - } - err = Pa_StopStream( stream ); - if( err != paNoError ) goto error; - - CLEAR( sampleBlock ); - - err = Pa_StartStream( stream ); - if( err != paNoError ) goto error; - printf("Wire on. Interrupt to stop.\n"); fflush(stdout); - - while( 1 ) - { - err = Pa_WriteStream( stream, sampleBlock, FRAMES_PER_BUFFER ); - if( err ) goto xrun; - err = Pa_ReadStream( stream, sampleBlock, FRAMES_PER_BUFFER ); - if( err ) goto xrun; - } - err = Pa_StopStream( stream ); - if( err != paNoError ) goto error; - - Pa_CloseStream( stream ); - - free( sampleBlock ); - - Pa_Terminate(); - return 0; - -xrun: - if( stream ) { - Pa_AbortStream( stream ); - Pa_CloseStream( stream ); - } - free( sampleBlock ); - Pa_Terminate(); - if( err & paInputOverflow ) - fprintf( stderr, "Input Overflow.\n" ); - if( err & paOutputUnderflow ) - fprintf( stderr, "Output Underflow.\n" ); - return -2; - -error: - if( stream ) { - Pa_AbortStream( stream ); - Pa_CloseStream( stream ); - } - free( sampleBlock ); - Pa_Terminate(); - fprintf( stderr, "An error occured while using the portaudio stream\n" ); - fprintf( stderr, "Error number: %d\n", err ); - fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); - return -1; -} - +/** @file patest_read_write_wire.c + @ingroup test_src + @brief Tests full duplex blocking I/O by passing input straight to output. + @author Bjorn Roche. XO Audio LLC for Z-Systems Engineering. + @author based on code by: Phil Burk http://www.softsynth.com + @author based on code by: Ross Bencina rossb@audiomulch.com +*/ +/* + * $Id: patest_read_write_wire.c,v 1.8 2008-12-31 15:38:36 richardash1981 Exp $ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include +#include "portaudio.h" + +/* #define SAMPLE_RATE (17932) // Test failure to open with this value. */ +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (1024) +#define NUM_CHANNELS (2) +/* #define DITHER_FLAG (paDitherOff) */ +#define DITHER_FLAG (0) /**/ + +/* Select sample format. */ +#if 0 +#define PA_SAMPLE_TYPE paFloat32 +#define SAMPLE_SIZE (4) +#define SAMPLE_SILENCE (0.0f) +#define CLEAR(a) memset( (a), 0, FRAMES_PER_BUFFER * NUM_CHANNELS * SAMPLE_SIZE ) +#define PRINTF_S_FORMAT "%.8f" +#elif 0 +#define PA_SAMPLE_TYPE paInt16 +#define SAMPLE_SIZE (2) +#define SAMPLE_SILENCE (0) +#define CLEAR(a) memset( (a), 0, FRAMES_PER_BUFFER * NUM_CHANNELS * SAMPLE_SIZE ) +#define PRINTF_S_FORMAT "%d" +#elif 1 +#define PA_SAMPLE_TYPE paInt24 +#define SAMPLE_SIZE (3) +#define SAMPLE_SILENCE (0) +#define CLEAR(a) memset( (a), 0, FRAMES_PER_BUFFER * NUM_CHANNELS * SAMPLE_SIZE ) +#define PRINTF_S_FORMAT "%d" +#elif 0 +#define PA_SAMPLE_TYPE paInt8 +#define SAMPLE_SIZE (1) +#define SAMPLE_SILENCE (0) +#define CLEAR(a) memset( (a), 0, FRAMES_PER_BUFFER * NUM_CHANNELS * SAMPLE_SIZE ) +#define PRINTF_S_FORMAT "%d" +#else +#define PA_SAMPLE_TYPE paUInt8 +#define SAMPLE_SIZE (1) +#define SAMPLE_SILENCE (128) +#define CLEAR( a ) { \ + int i; \ + for( i=0; idefaultLowInputLatency ); + printf( "Input HL: %g s\n", Pa_GetDeviceInfo( inputParameters.device )->defaultHighInputLatency ); + inputParameters.channelCount = NUM_CHANNELS; + inputParameters.sampleFormat = PA_SAMPLE_TYPE; + inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultHighInputLatency ; + inputParameters.hostApiSpecificStreamInfo = NULL; + + outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */ + printf( "Output device # %d.\n", outputParameters.device ); + printf( "Output LL: %g s\n", Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency ); + printf( "Output HL: %g s\n", Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency ); + outputParameters.channelCount = NUM_CHANNELS; + outputParameters.sampleFormat = PA_SAMPLE_TYPE; + outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + + /* -- setup -- */ + + err = Pa_OpenStream( + &stream, + &inputParameters, + &outputParameters, + SAMPLE_RATE, + FRAMES_PER_BUFFER, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + NULL, /* no callback, use blocking API */ + NULL ); /* no callback, so no callback userData */ + if( err != paNoError ) goto error; + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + printf("Wire on. Will run one minute.\n"); fflush(stdout); + + for( i=0; i<(60*SAMPLE_RATE)/FRAMES_PER_BUFFER; ++i ) + { + err = Pa_WriteStream( stream, sampleBlock, FRAMES_PER_BUFFER ); + if( err ) goto xrun; + err = Pa_ReadStream( stream, sampleBlock, FRAMES_PER_BUFFER ); + if( err ) goto xrun; + } + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + + CLEAR( sampleBlock ); + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + printf("Wire on. Interrupt to stop.\n"); fflush(stdout); + + while( 1 ) + { + err = Pa_WriteStream( stream, sampleBlock, FRAMES_PER_BUFFER ); + if( err ) goto xrun; + err = Pa_ReadStream( stream, sampleBlock, FRAMES_PER_BUFFER ); + if( err ) goto xrun; + } + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + + Pa_CloseStream( stream ); + + free( sampleBlock ); + + Pa_Terminate(); + return 0; + +xrun: + if( stream ) { + Pa_AbortStream( stream ); + Pa_CloseStream( stream ); + } + free( sampleBlock ); + Pa_Terminate(); + if( err & paInputOverflow ) + fprintf( stderr, "Input Overflow.\n" ); + if( err & paOutputUnderflow ) + fprintf( stderr, "Output Underflow.\n" ); + return -2; + +error: + if( stream ) { + Pa_AbortStream( stream ); + Pa_CloseStream( stream ); + } + free( sampleBlock ); + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return -1; +} + diff --git a/lib-src/portaudio-v19/test/patest_timing.c b/lib-src/portaudio-v19/test/patest_timing.c index 557ccd23a..128a680c6 100644 --- a/lib-src/portaudio-v19/test/patest_timing.c +++ b/lib-src/portaudio-v19/test/patest_timing.c @@ -1,173 +1,173 @@ -/** @file patest_timing.c - @ingroup test_src - @brief Play a sine wave for several seconds, and spits out a ton of timing info while it's at it. Based on patet_sine.c - @author Bjorn Roche - @author Ross Bencina - @author Phil Burk -*/ -/* - * $Id: patest_timing.c,v 1.7 2008-12-31 15:38:36 richardash1981 Exp $ - * - * This program uses the PortAudio Portable Audio Library. - * For more information see: http://www.portaudio.com/ - * Copyright (c) 1999-2000 Ross Bencina and Phil Burk - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * The text above constitutes the entire PortAudio license; however, - * the PortAudio community also makes the following non-binding requests: - * - * Any person wishing to distribute modifications to the Software is - * requested to send the modifications to the original developer so that - * they can be incorporated into the canonical version. It is also - * requested that these non-binding requests be included along with the - * license above. - */ - -#include -#include -#include "portaudio.h" - -#define NUM_SECONDS (5) -#define SAMPLE_RATE (44100) -#define FRAMES_PER_BUFFER (64) - -#ifndef M_PI -#define M_PI (3.14159265) -#endif - -#define TABLE_SIZE (200) -typedef struct -{ - PaStream *stream; - PaTime start; - float sine[TABLE_SIZE]; - int left_phase; - int right_phase; -} -paTestData; - -/* This routine will be called by the PortAudio engine when audio is needed. -** It may called at interrupt level on some machines so don't do anything -** that could mess up the system like calling malloc() or free(). -*/ -static int patestCallback( const void *inputBuffer, void *outputBuffer, - unsigned long framesPerBuffer, - const PaStreamCallbackTimeInfo* timeInfo, - PaStreamCallbackFlags statusFlags, - void *userData ) -{ - paTestData *data = (paTestData*)userData; - float *out = (float*)outputBuffer; - unsigned long i; - - (void) timeInfo; /* Prevent unused variable warnings. */ - (void) statusFlags; - (void) inputBuffer; - - printf( "Timing info given to callback: Adc: %g, Current: %g, Dac: %g\n", - timeInfo->inputBufferAdcTime, - timeInfo->currentTime, - timeInfo->outputBufferDacTime ); - - printf( "getStreamTime() returns: %g\n", Pa_GetStreamTime(data->stream)-data->start ); - - for( i=0; isine[data->left_phase]; /* left */ - *out++ = data->sine[data->right_phase]; /* right */ - data->left_phase += 1; - if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; - data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ - if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; - } - - return paContinue; -} - -/*******************************************************************/ -int main(void); -int main(void) -{ - PaStreamParameters outputParameters; - PaStream *stream; - PaError err; - paTestData data; - int i; - - - printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER); - - /* initialise sinusoidal wavetable */ - for( i=0; idefaultLowOutputLatency; - outputParameters.hostApiSpecificStreamInfo = NULL; - - err = Pa_OpenStream( - &stream, - NULL, /* no input */ - &outputParameters, - SAMPLE_RATE, - FRAMES_PER_BUFFER, - paClipOff, /* we won't output out of range samples so don't bother clipping them */ - patestCallback, - &data ); - data.stream = stream; - data.start = Pa_GetStreamTime(stream); - if( err != paNoError ) goto error; - - err = Pa_StartStream( stream ); - data.start = Pa_GetStreamTime(stream); - if( err != paNoError ) goto error; - - printf("Play for %d seconds.\n", NUM_SECONDS ); - Pa_Sleep( NUM_SECONDS * 1000 ); - - err = Pa_StopStream( stream ); - if( err != paNoError ) goto error; - - err = Pa_CloseStream( stream ); - if( err != paNoError ) goto error; - - Pa_Terminate(); - printf("Test finished.\n"); - printf("The tone should have been heard for about 5 seconds and all the timing info above should report that about 5 seconds elapsed (except Adc, which is undefined since there was no input device opened).\n"); - - return err; -error: - Pa_Terminate(); - fprintf( stderr, "An error occured while using the portaudio stream\n" ); - fprintf( stderr, "Error number: %d\n", err ); - fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); - return err; -} +/** @file patest_timing.c + @ingroup test_src + @brief Play a sine wave for several seconds, and spits out a ton of timing info while it's at it. Based on patet_sine.c + @author Bjorn Roche + @author Ross Bencina + @author Phil Burk +*/ +/* + * $Id: patest_timing.c,v 1.7 2008-12-31 15:38:36 richardash1981 Exp $ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com/ + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include "portaudio.h" + +#define NUM_SECONDS (5) +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (64) + +#ifndef M_PI +#define M_PI (3.14159265) +#endif + +#define TABLE_SIZE (200) +typedef struct +{ + PaStream *stream; + PaTime start; + float sine[TABLE_SIZE]; + int left_phase; + int right_phase; +} +paTestData; + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + unsigned long i; + + (void) timeInfo; /* Prevent unused variable warnings. */ + (void) statusFlags; + (void) inputBuffer; + + printf( "Timing info given to callback: Adc: %g, Current: %g, Dac: %g\n", + timeInfo->inputBufferAdcTime, + timeInfo->currentTime, + timeInfo->outputBufferDacTime ); + + printf( "getStreamTime() returns: %g\n", Pa_GetStreamTime(data->stream)-data->start ); + + for( i=0; isine[data->left_phase]; /* left */ + *out++ = data->sine[data->right_phase]; /* right */ + data->left_phase += 1; + if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; + data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ + if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; + } + + return paContinue; +} + +/*******************************************************************/ +int main(void); +int main(void) +{ + PaStreamParameters outputParameters; + PaStream *stream; + PaError err; + paTestData data; + int i; + + + printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER); + + /* initialise sinusoidal wavetable */ + for( i=0; idefaultLowOutputLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + + err = Pa_OpenStream( + &stream, + NULL, /* no input */ + &outputParameters, + SAMPLE_RATE, + FRAMES_PER_BUFFER, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + patestCallback, + &data ); + data.stream = stream; + data.start = Pa_GetStreamTime(stream); + if( err != paNoError ) goto error; + + err = Pa_StartStream( stream ); + data.start = Pa_GetStreamTime(stream); + if( err != paNoError ) goto error; + + printf("Play for %d seconds.\n", NUM_SECONDS ); + Pa_Sleep( NUM_SECONDS * 1000 ); + + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + + Pa_Terminate(); + printf("Test finished.\n"); + printf("The tone should have been heard for about 5 seconds and all the timing info above should report that about 5 seconds elapsed (except Adc, which is undefined since there was no input device opened).\n"); + + return err; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} diff --git a/lib-src/portaudio-v19/test/patest_wmme_surround.c b/lib-src/portaudio-v19/test/patest_wmme_surround.c index f26e84f8f..bff44f41f 100644 --- a/lib-src/portaudio-v19/test/patest_wmme_surround.c +++ b/lib-src/portaudio-v19/test/patest_wmme_surround.c @@ -1,206 +1,206 @@ -/* - * $Id: patest_wmme_surround.c,v 1.5 2008-12-31 15:38:36 richardash1981 Exp $ - * Portable Audio I/O Library - * Windows MME surround sound output test - * - * Copyright (c) 2007 Ross Bencina - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * The text above constitutes the entire PortAudio license; however, - * the PortAudio community also makes the following non-binding requests: - * - * Any person wishing to distribute modifications to the Software is - * requested to send the modifications to the original developer so that - * they can be incorporated into the canonical version. It is also - * requested that these non-binding requests be included along with the - * license above. - */ - -#include -#include - -#include /* required when using pa_win_wmme.h */ -#include /* required when using pa_win_wmme.h */ - -#include "portaudio.h" -#include "pa_win_wmme.h" - -#define NUM_SECONDS (12) -#define SAMPLE_RATE (44100) -#define FRAMES_PER_BUFFER (64) - -#ifndef M_PI -#define M_PI (3.14159265) -#endif - -#define TABLE_SIZE (100) - -#define CHANNEL_COUNT (6) - - - -typedef struct -{ - float sine[TABLE_SIZE]; - int phase; - int currentChannel; - int cycleCount; -} -paTestData; - -/* This routine will be called by the PortAudio engine when audio is needed. -** It may called at interrupt level on some machines so don't do anything -** that could mess up the system like calling malloc() or free(). -*/ -static int patestCallback( const void *inputBuffer, void *outputBuffer, - unsigned long framesPerBuffer, - const PaStreamCallbackTimeInfo* timeInfo, - PaStreamCallbackFlags statusFlags, - void *userData ) -{ - paTestData *data = (paTestData*)userData; - float *out = (float*)outputBuffer; - unsigned long i,j; - - (void) timeInfo; /* Prevent unused variable warnings. */ - (void) statusFlags; - (void) inputBuffer; - - for( i=0; icurrentChannel && data->cycleCount < 4410 ){ - *out++ = data->sine[data->phase]; - data->phase += 1 + j; // play each channel at a different pitch so they can be distinguished - if( data->phase >= TABLE_SIZE ){ - data->phase -= TABLE_SIZE; - } - }else{ - *out++ = 0; - } - } - - data->cycleCount++; - if( data->cycleCount > 44100 ){ - data->cycleCount = 0; - - ++data->currentChannel; - if( data->currentChannel >= CHANNEL_COUNT ) - data->currentChannel -= CHANNEL_COUNT; - } - } - - return paContinue; -} - -/*******************************************************************/ -int main(int argc, char* argv[]) -{ - PaStreamParameters outputParameters; - PaWinMmeStreamInfo wmmeStreamInfo; - PaStream *stream; - PaError err; - paTestData data; - int i; - int deviceIndex; - - printf("PortAudio Test: output a sine blip on each channel. SR = %d, BufSize = %d, Chans = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER, CHANNEL_COUNT); - - err = Pa_Initialize(); - if( err != paNoError ) goto error; - - deviceIndex = Pa_GetHostApiInfo( Pa_HostApiTypeIdToHostApiIndex( paMME ) )->defaultOutputDevice; - if( argc == 2 ){ - sscanf( argv[1], "%d", &deviceIndex ); - } - - printf( "using device id %d (%s)\n", deviceIndex, Pa_GetDeviceInfo(deviceIndex)->name ); - - /* initialise sinusoidal wavetable */ - for( i=0; idefaultLowOutputLatency; - outputParameters.hostApiSpecificStreamInfo = NULL; - - /* it's not strictly necessary to provide a channelMask for surround sound - output. But if you want to be sure which channel mask PortAudio will use - then you should supply one */ - wmmeStreamInfo.size = sizeof(PaWinMmeStreamInfo); - wmmeStreamInfo.hostApiType = paMME; - wmmeStreamInfo.version = 1; - wmmeStreamInfo.flags = paWinMmeUseChannelMask; - wmmeStreamInfo.channelMask = PAWIN_SPEAKER_5POINT1; /* request 5.1 output format */ - outputParameters.hostApiSpecificStreamInfo = &wmmeStreamInfo; - - - if( Pa_IsFormatSupported( 0, &outputParameters, SAMPLE_RATE ) == paFormatIsSupported ){ - printf( "Pa_IsFormatSupported reports device will support %d channels.\n", CHANNEL_COUNT ); - }else{ - printf( "Pa_IsFormatSupported reports device will not support %d channels.\n", CHANNEL_COUNT ); - } - - err = Pa_OpenStream( - &stream, - NULL, /* no input */ - &outputParameters, - SAMPLE_RATE, - FRAMES_PER_BUFFER, - paClipOff, /* we won't output out of range samples so don't bother clipping them */ - patestCallback, - &data ); - if( err != paNoError ) goto error; - - err = Pa_StartStream( stream ); - if( err != paNoError ) goto error; - - printf("Play for %d seconds.\n", NUM_SECONDS ); - Pa_Sleep( NUM_SECONDS * 1000 ); - - err = Pa_StopStream( stream ); - if( err != paNoError ) goto error; - - err = Pa_CloseStream( stream ); - if( err != paNoError ) goto error; - - Pa_Terminate(); - printf("Test finished.\n"); - - return err; -error: - Pa_Terminate(); - fprintf( stderr, "An error occured while using the portaudio stream\n" ); - fprintf( stderr, "Error number: %d\n", err ); - fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); - return err; -} - +/* + * $Id: patest_wmme_surround.c,v 1.5 2008-12-31 15:38:36 richardash1981 Exp $ + * Portable Audio I/O Library + * Windows MME surround sound output test + * + * Copyright (c) 2007 Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include + +#include /* required when using pa_win_wmme.h */ +#include /* required when using pa_win_wmme.h */ + +#include "portaudio.h" +#include "pa_win_wmme.h" + +#define NUM_SECONDS (12) +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (64) + +#ifndef M_PI +#define M_PI (3.14159265) +#endif + +#define TABLE_SIZE (100) + +#define CHANNEL_COUNT (6) + + + +typedef struct +{ + float sine[TABLE_SIZE]; + int phase; + int currentChannel; + int cycleCount; +} +paTestData; + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + unsigned long i,j; + + (void) timeInfo; /* Prevent unused variable warnings. */ + (void) statusFlags; + (void) inputBuffer; + + for( i=0; icurrentChannel && data->cycleCount < 4410 ){ + *out++ = data->sine[data->phase]; + data->phase += 1 + j; // play each channel at a different pitch so they can be distinguished + if( data->phase >= TABLE_SIZE ){ + data->phase -= TABLE_SIZE; + } + }else{ + *out++ = 0; + } + } + + data->cycleCount++; + if( data->cycleCount > 44100 ){ + data->cycleCount = 0; + + ++data->currentChannel; + if( data->currentChannel >= CHANNEL_COUNT ) + data->currentChannel -= CHANNEL_COUNT; + } + } + + return paContinue; +} + +/*******************************************************************/ +int main(int argc, char* argv[]) +{ + PaStreamParameters outputParameters; + PaWinMmeStreamInfo wmmeStreamInfo; + PaStream *stream; + PaError err; + paTestData data; + int i; + int deviceIndex; + + printf("PortAudio Test: output a sine blip on each channel. SR = %d, BufSize = %d, Chans = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER, CHANNEL_COUNT); + + err = Pa_Initialize(); + if( err != paNoError ) goto error; + + deviceIndex = Pa_GetHostApiInfo( Pa_HostApiTypeIdToHostApiIndex( paMME ) )->defaultOutputDevice; + if( argc == 2 ){ + sscanf( argv[1], "%d", &deviceIndex ); + } + + printf( "using device id %d (%s)\n", deviceIndex, Pa_GetDeviceInfo(deviceIndex)->name ); + + /* initialise sinusoidal wavetable */ + for( i=0; idefaultLowOutputLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + + /* it's not strictly necessary to provide a channelMask for surround sound + output. But if you want to be sure which channel mask PortAudio will use + then you should supply one */ + wmmeStreamInfo.size = sizeof(PaWinMmeStreamInfo); + wmmeStreamInfo.hostApiType = paMME; + wmmeStreamInfo.version = 1; + wmmeStreamInfo.flags = paWinMmeUseChannelMask; + wmmeStreamInfo.channelMask = PAWIN_SPEAKER_5POINT1; /* request 5.1 output format */ + outputParameters.hostApiSpecificStreamInfo = &wmmeStreamInfo; + + + if( Pa_IsFormatSupported( 0, &outputParameters, SAMPLE_RATE ) == paFormatIsSupported ){ + printf( "Pa_IsFormatSupported reports device will support %d channels.\n", CHANNEL_COUNT ); + }else{ + printf( "Pa_IsFormatSupported reports device will not support %d channels.\n", CHANNEL_COUNT ); + } + + err = Pa_OpenStream( + &stream, + NULL, /* no input */ + &outputParameters, + SAMPLE_RATE, + FRAMES_PER_BUFFER, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + patestCallback, + &data ); + if( err != paNoError ) goto error; + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + printf("Play for %d seconds.\n", NUM_SECONDS ); + Pa_Sleep( NUM_SECONDS * 1000 ); + + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + + Pa_Terminate(); + printf("Test finished.\n"); + + return err; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} + diff --git a/lib-src/portaudio/docs/index.html b/lib-src/portaudio/docs/index.html index b9a83c2f3..863fc7362 100644 --- a/lib-src/portaudio/docs/index.html +++ b/lib-src/portaudio/docs/index.html @@ -1,43 +1,43 @@ - - - - - - - - - PortAudio Docs - - -  -
- - - -
-
-

-PortAudio Documentation

-
- -

Copyright 2000 Phil Burk and Ross Bencina -

-Tutorial

- -
Describes how to write audio programs using the PortAudio API.
- -

-Implementation Guide

- -
Describes how to write an implementation of PortAudio for a -new computer platform.
- -

-Paper Presented at ICMC2001 (PDF)

- -
Describes the PortAudio API and discusses implementation issues. -Written July 2001.
- -


Return to PortAudio Home Page - - + + + + + + + + + PortAudio Docs + + +  +

+ + + +
+
+

+PortAudio Documentation

+
+ +

Copyright 2000 Phil Burk and Ross Bencina +

+Tutorial

+ +
Describes how to write audio programs using the PortAudio API.
+ +

+Implementation Guide

+ +
Describes how to write an implementation of PortAudio for a +new computer platform.
+ +

+Paper Presented at ICMC2001 (PDF)

+ +
Describes the PortAudio API and discusses implementation issues. +Written July 2001.
+ +


Return to PortAudio Home Page + + diff --git a/lib-src/portaudio/docs/pa_impl_guide.html b/lib-src/portaudio/docs/pa_impl_guide.html index 042a7174c..6cb1dedaf 100644 --- a/lib-src/portaudio/docs/pa_impl_guide.html +++ b/lib-src/portaudio/docs/pa_impl_guide.html @@ -1,196 +1,196 @@ - - - - - - - - - PortAudio Implementation - Start/Stop - - -  -

- - - -
-
-

-PortAudio Implementation Guide

-
- -

This document describes how to implement the PortAudio API on a new -computer platform. Implementing PortAudio on a new platform, makes it possible -to port many existing audio applications to that platform. -

By Phil Burk -
Copyright 2000 Phil Burk and Ross Bencina -

Note that the license says: "Any person wishing to distribute modifications -to the Software is requested to send the modifications to the original -developer so that they can be incorporated into the canonical version.". -So when you have finished a new implementation, please send it back to -us at  "http://www.portaudio.com" -so that we can make it available for other users. Thank you! -

-Download the Latest PortAudio Implementation

-Always start with the latest implementation available at "http://www.portaudio.com". -

-Select an Existing Implementation as a Basis

-The fastest way to get started is to take an existing implementation and -translate it for your new platform. Choose an implementation whose architecture -is as close as possible to your target. -
    -
  • -DirectSound Implementation - pa_win_ds - Uses a timer callback for the -background "thread". Polls a circular buffer and writes blocks of data -to keep it full.
  • - -
  • -Windows MME - pa_win_wmme - Spawns an actual Win32 thread. Writes blocks -of data to the HW device and waits for events that signal buffer completion.
  • - -
  • -Linux OSS - pa_linux - Spawns a real thread that writes to the "/dev/dsp" -stream using blocking I/O calls.
  • -
-When you write a new implementation, you will be using some code that is -in common with all implementations. This code is in the folder "pa_common". -It provides various functions such as parameter checking, error code to -text conversion, sample format conversion, clipping and dithering, etc. -

The code that you write will go into a separate folder called "pa_{os}_{api}". -For example, code specific to the DirectSound interface for Windows goes -in "pa_win_ds". -

-Read Docs and Code

-Famialiarize yourself with the system by reading the documentation provided. -here is a suggested order: -
    -
  1. -User Programming Tutorial
  2. - -
  3. -Header file "pa_common/portaudio.h" which defines API.
  4. - -
  5. -Header file "pa_common/pa_host.h" for host dependant code. This definces -the routine you will need to provide.
  6. - -
  7. -Shared code in "pa_common/pa_lib.c".
  8. - -
  9. -Docs on Implementation of Start/Stop -code.
  10. -
- -

-Implement  Output to Default Device

-Now we are ready to crank some code. For instant gratification, let's try -to play a sine wave. -
    -
  1. -Link the test program "pa_tests/patest_sine.c" with the file "pa_lib.c" -and the implementation specific file you are creating.
  2. - -
  3. -For now, just stub out the device query code and the audio input code.
  4. - -
  5. -Modify PaHost_OpenStream() to open your default target device and get everything -setup.
  6. - -
  7. -Modify PaHost_StartOutput() to start playing audio.
  8. - -
  9. -Modify PaHost_StopOutput() to stop audio.
  10. - -
  11. -Modify PaHost_CloseStream() to clean up. Free all memory that you allocated -in PaHost_OpenStream().
  12. - -
  13. -Keep cranking until you can play a sine wave using "patest_sine.c".
  14. - -
  15. -Once that works, try "patest_pink.c", "patest_clip.c", "patest_sine8.c".
  16. - -
  17. -To test your Open and Close code, try "patest_many.c".
  18. - -
  19. -Now test to make sure that the three modes of stopping are properly supported -by running "patest_stop.c".
  20. - -
  21. -Test your implementation of time stamping with "patest_sync.c".
  22. -
- -

-Implement Device Queries

-Now that output is working, lets implement the code for querying what devices -are available to the user. Run "pa_tests/pa_devs.c". It should print all -of the devices available and their characteristics. -

-Implement Input

-Implement audio input and test it with: -
    -
  1. -patest_record.c - record in half duplex, play back as recorded.
  2. - -
  3. -patest_wire.c - full duplex, copies input to output. Note that some HW -may not support full duplex.
  4. - -
  5. -patest_fuzz.c - plug in your guitar and get a feel for why latency is an -important issue in computer music.
  6. - -
  7. -paqa_devs.c - try to open every device and use it with every possible format
  8. -
- -

-Debugging Tools

-You generally cannot use printf() calls to debug real-time processes because -they disturb the timing. Also calling printf() from your background thread -or interrupt could crash the machine. So PA includes a tool for capturing -events and storing the information while it is running. It then prints -the events when Pa_Terminate() is called. -
    -
  1. -To enable trace mode, change TRACE_REALTIME_EVENTS in "pa_common/pa_trace.h" -from a (0) to a (1).
  2. - -
  3. -Link with "pa_common/pa_trace.c".
  4. - -
  5. -Add trace messages to your code by calling:
    -   void AddTraceMessage( char *msg, int data );
    -for example
    -   AddTraceMessage("Pa_TimeSlice: past_NumCallbacks ", past->past_NumCallbacks -);
  6. - -
  7. -Run your program. You will get a dump of events at the end.
  8. - -
  9. -You can leave the trace messages in your code. They will turn to NOOPs -when you change TRACE_REALTIME_EVENTS back to (0).
  10. -
- -

-Delivery

-Please send your new code along with notes on the implementation back to -us at "http://www.portaudio.com". -We will review the implementation and post it with your name. If you had -to make any modifications to the code in "pa_common" or "pa_tests" please -send us those modifications and your notes. We will try to merge your changes -so that the "pa_common" code works with all implementations. -

If you have suggestions for how to make future implementations easier, -please let us know. -
THANKS! -
  - - + + + + + + + + + PortAudio Implementation - Start/Stop + + +  +

+ + + +
+
+

+PortAudio Implementation Guide

+
+ +

This document describes how to implement the PortAudio API on a new +computer platform. Implementing PortAudio on a new platform, makes it possible +to port many existing audio applications to that platform. +

By Phil Burk +
Copyright 2000 Phil Burk and Ross Bencina +

Note that the license says: "Any person wishing to distribute modifications +to the Software is requested to send the modifications to the original +developer so that they can be incorporated into the canonical version.". +So when you have finished a new implementation, please send it back to +us at  "http://www.portaudio.com" +so that we can make it available for other users. Thank you! +

+Download the Latest PortAudio Implementation

+Always start with the latest implementation available at "http://www.portaudio.com". +

+Select an Existing Implementation as a Basis

+The fastest way to get started is to take an existing implementation and +translate it for your new platform. Choose an implementation whose architecture +is as close as possible to your target. +
    +
  • +DirectSound Implementation - pa_win_ds - Uses a timer callback for the +background "thread". Polls a circular buffer and writes blocks of data +to keep it full.
  • + +
  • +Windows MME - pa_win_wmme - Spawns an actual Win32 thread. Writes blocks +of data to the HW device and waits for events that signal buffer completion.
  • + +
  • +Linux OSS - pa_linux - Spawns a real thread that writes to the "/dev/dsp" +stream using blocking I/O calls.
  • +
+When you write a new implementation, you will be using some code that is +in common with all implementations. This code is in the folder "pa_common". +It provides various functions such as parameter checking, error code to +text conversion, sample format conversion, clipping and dithering, etc. +

The code that you write will go into a separate folder called "pa_{os}_{api}". +For example, code specific to the DirectSound interface for Windows goes +in "pa_win_ds". +

+Read Docs and Code

+Famialiarize yourself with the system by reading the documentation provided. +here is a suggested order: +
    +
  1. +User Programming Tutorial
  2. + +
  3. +Header file "pa_common/portaudio.h" which defines API.
  4. + +
  5. +Header file "pa_common/pa_host.h" for host dependant code. This definces +the routine you will need to provide.
  6. + +
  7. +Shared code in "pa_common/pa_lib.c".
  8. + +
  9. +Docs on Implementation of Start/Stop +code.
  10. +
+ +

+Implement  Output to Default Device

+Now we are ready to crank some code. For instant gratification, let's try +to play a sine wave. +
    +
  1. +Link the test program "pa_tests/patest_sine.c" with the file "pa_lib.c" +and the implementation specific file you are creating.
  2. + +
  3. +For now, just stub out the device query code and the audio input code.
  4. + +
  5. +Modify PaHost_OpenStream() to open your default target device and get everything +setup.
  6. + +
  7. +Modify PaHost_StartOutput() to start playing audio.
  8. + +
  9. +Modify PaHost_StopOutput() to stop audio.
  10. + +
  11. +Modify PaHost_CloseStream() to clean up. Free all memory that you allocated +in PaHost_OpenStream().
  12. + +
  13. +Keep cranking until you can play a sine wave using "patest_sine.c".
  14. + +
  15. +Once that works, try "patest_pink.c", "patest_clip.c", "patest_sine8.c".
  16. + +
  17. +To test your Open and Close code, try "patest_many.c".
  18. + +
  19. +Now test to make sure that the three modes of stopping are properly supported +by running "patest_stop.c".
  20. + +
  21. +Test your implementation of time stamping with "patest_sync.c".
  22. +
+ +

+Implement Device Queries

+Now that output is working, lets implement the code for querying what devices +are available to the user. Run "pa_tests/pa_devs.c". It should print all +of the devices available and their characteristics. +

+Implement Input

+Implement audio input and test it with: +
    +
  1. +patest_record.c - record in half duplex, play back as recorded.
  2. + +
  3. +patest_wire.c - full duplex, copies input to output. Note that some HW +may not support full duplex.
  4. + +
  5. +patest_fuzz.c - plug in your guitar and get a feel for why latency is an +important issue in computer music.
  6. + +
  7. +paqa_devs.c - try to open every device and use it with every possible format
  8. +
+ +

+Debugging Tools

+You generally cannot use printf() calls to debug real-time processes because +they disturb the timing. Also calling printf() from your background thread +or interrupt could crash the machine. So PA includes a tool for capturing +events and storing the information while it is running. It then prints +the events when Pa_Terminate() is called. +
    +
  1. +To enable trace mode, change TRACE_REALTIME_EVENTS in "pa_common/pa_trace.h" +from a (0) to a (1).
  2. + +
  3. +Link with "pa_common/pa_trace.c".
  4. + +
  5. +Add trace messages to your code by calling:
    +   void AddTraceMessage( char *msg, int data );
    +for example
    +   AddTraceMessage("Pa_TimeSlice: past_NumCallbacks ", past->past_NumCallbacks +);
  6. + +
  7. +Run your program. You will get a dump of events at the end.
  8. + +
  9. +You can leave the trace messages in your code. They will turn to NOOPs +when you change TRACE_REALTIME_EVENTS back to (0).
  10. +
+ +

+Delivery

+Please send your new code along with notes on the implementation back to +us at "http://www.portaudio.com". +We will review the implementation and post it with your name. If you had +to make any modifications to the code in "pa_common" or "pa_tests" please +send us those modifications and your notes. We will try to merge your changes +so that the "pa_common" code works with all implementations. +

If you have suggestions for how to make future implementations easier, +please let us know. +
THANKS! +
  + + diff --git a/lib-src/portaudio/docs/pa_impl_startstop.html b/lib-src/portaudio/docs/pa_impl_startstop.html index a1ee93a77..0f2d0ce51 100644 --- a/lib-src/portaudio/docs/pa_impl_startstop.html +++ b/lib-src/portaudio/docs/pa_impl_startstop.html @@ -1,190 +1,190 @@ - - - - - - - - - PortAudio Implementation - Start/Stop - - -  -

- - - -
-
-

-PortAudio Implementation

-
- -

-Starting and Stopping Streams

-PortAudio is generally executed in two "threads". The foreground thread -is the application thread. The background "thread" may be implemented as -an actual thread, an interrupt handler, or a callback from a timer thread. -

There are three ways that PortAudio can stop a stream. In each case -we look at the sequence of events and the messages sent between the two -threads. The following variables are contained in the internalPortAudioStream. -

int   past_IsActive;     -/* Background is still playing. */ -
int   past_StopSoon;     /* Stop -when last buffer done. */ -
int   past_StopNow;      /* -Stop IMMEDIATELY. */
- -

-Pa_AbortStream()

-This function causes the background thread to terminate as soon as possible -and audio I/O to stop abruptly. -
  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Foreground ThreadBackground Thread
sets StopNow
sees StopNow
clears IsActive, stops thread
waits for thread to exit
turns off audio I/O
- -

-Pa_StopStream()

-This function stops the user callback function from being called and then -waits for all audio data written to the output buffer to be played. In -a system with very low latency, you may not hear any difference between -
  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Foreground ThreadBackground Thread
sets StopSoon
stops calling user callback
continues until output buffer empty
clears IsActive, stops thread
waits for thread to exit
turns off audio I/O
- -

-User callback returns one.

-If the user callback returns one then the user callback function will no -longer be called. Audio output will continue until all audio data written -to the output buffer has been played. Then the audio I/O is stopped, the -background thread terminates, and the stream becomes inactive. -
  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Foreground ThreadBackground Thread
callback returns 1
sets StopSoon
stops calling user callback
continues until output buffer empty
clears IsActive, stops thread
waits for thread to exit
turns off audio I/O
- -
  - - + + + + + + + + + PortAudio Implementation - Start/Stop + + +  +
+ + + +
+
+

+PortAudio Implementation

+
+ +

+Starting and Stopping Streams

+PortAudio is generally executed in two "threads". The foreground thread +is the application thread. The background "thread" may be implemented as +an actual thread, an interrupt handler, or a callback from a timer thread. +

There are three ways that PortAudio can stop a stream. In each case +we look at the sequence of events and the messages sent between the two +threads. The following variables are contained in the internalPortAudioStream. +

int   past_IsActive;     +/* Background is still playing. */ +
int   past_StopSoon;     /* Stop +when last buffer done. */ +
int   past_StopNow;      /* +Stop IMMEDIATELY. */
+ +

+Pa_AbortStream()

+This function causes the background thread to terminate as soon as possible +and audio I/O to stop abruptly. +
  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Foreground ThreadBackground Thread
sets StopNow
sees StopNow
clears IsActive, stops thread
waits for thread to exit
turns off audio I/O
+ +

+Pa_StopStream()

+This function stops the user callback function from being called and then +waits for all audio data written to the output buffer to be played. In +a system with very low latency, you may not hear any difference between +
  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Foreground ThreadBackground Thread
sets StopSoon
stops calling user callback
continues until output buffer empty
clears IsActive, stops thread
waits for thread to exit
turns off audio I/O
+ +

+User callback returns one.

+If the user callback returns one then the user callback function will no +longer be called. Audio output will continue until all audio data written +to the output buffer has been played. Then the audio I/O is stopped, the +background thread terminates, and the stream becomes inactive. +
  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Foreground ThreadBackground Thread
callback returns 1
sets StopSoon
stops calling user callback
continues until output buffer empty
clears IsActive, stops thread
waits for thread to exit
turns off audio I/O
+ +
  + + diff --git a/lib-src/portaudio/docs/pa_tut_asio.html b/lib-src/portaudio/docs/pa_tut_asio.html index 0eb3c5d0f..1c3e5bfa4 100644 --- a/lib-src/portaudio/docs/pa_tut_asio.html +++ b/lib-src/portaudio/docs/pa_tut_asio.html @@ -1,55 +1,55 @@ - - - - - - - - - PortAudio Tutorial - - -  -
- - - -
-
-

-PortAudio Tutorial

-
- -

-Compiling for ASIO (Windows or Macintosh)

- -
ASIO is a low latency audio API from Steinberg. To compile -an ASIO application, you must first download -the ASIO SDK from Steinberg. You also need to obtain ASIO drivers for -your audio device. -

Note: I am using '/' as a file separator below. On Macintosh replace -'/' with ':'. On Windows, replace '/' with '\'. -

 To use ASIO with the PortAudio library add the following source -files to your project: -

-
pa_asio/pa_asio.cpp
-
-and also these files from the ASIO SDK: -
-
common/asio.cpp
-host/asiodrivers.cpp
-host/asiolist.cpp
-
-and add these directories to the path for include files -
-
asiosdk2/host/pc   (for Windows)
-asiosdk2/common
-asiosdk2/host
-
-You may try compiling the "pa_tests/patest_saw.c" file first because it -is the simplest.
-home | -contents -| previousnext - - + + + + + + + + + PortAudio Tutorial + + +  +
+ + + +
+
+

+PortAudio Tutorial

+
+ +

+Compiling for ASIO (Windows or Macintosh)

+ +
ASIO is a low latency audio API from Steinberg. To compile +an ASIO application, you must first download +the ASIO SDK from Steinberg. You also need to obtain ASIO drivers for +your audio device. +

Note: I am using '/' as a file separator below. On Macintosh replace +'/' with ':'. On Windows, replace '/' with '\'. +

 To use ASIO with the PortAudio library add the following source +files to your project: +

+
pa_asio/pa_asio.cpp
+
+and also these files from the ASIO SDK: +
+
common/asio.cpp
+host/asiodrivers.cpp
+host/asiolist.cpp
+
+and add these directories to the path for include files +
+
asiosdk2/host/pc   (for Windows)
+asiosdk2/common
+asiosdk2/host
+
+You may try compiling the "pa_tests/patest_saw.c" file first because it +is the simplest.
+home | +contents +| previousnext + + diff --git a/lib-src/portaudio/docs/pa_tut_callback.html b/lib-src/portaudio/docs/pa_tut_callback.html index fb7b6d7d0..f5ccaf0f1 100644 --- a/lib-src/portaudio/docs/pa_tut_callback.html +++ b/lib-src/portaudio/docs/pa_tut_callback.html @@ -1,91 +1,91 @@ - - - - - - - - - PortAudio Tutorial - - -  -
- - - -
-
-

-PortAudio Tutorial

-
- -

-Writing a Callback Function

- -
To write a program using PortAudio, you must include the "portaudio.h" -include file. You may wish to read "portaudio.h" -because it contains a complete description of the PortAudio functions and -constants. -
-
#include "portaudio.h"
-
-The next task is to write your custom callback function. It is a function -that is called by the PortAudio engine whenever it has captured audio data, -or when it needs more audio data for output. -

Your callback function is often called by an interrupt, or low level -process so you should not do any complex system activities like allocating -memory, or reading or writing files, or printf(). Just crunch numbers and -generate audio signals. What is safe or not safe will vary from platform -to platform. On the Macintosh, for example, you can only call "interrupt -safe" routines. Also do not call any PortAudio functions in the callback -except for Pa_StreamTime() and Pa_GetCPULoad(). -

Your callback function must return an int and accept the exact parameters -specified in this typedef: -

-
typedef int (PortAudioCallback)(
-               void *inputBuffer, void *outputBuffer,
-               unsigned long framesPerBuffer,
-               PaTimestamp outTime, void *userData );
-
-Here is an example callback function from the test file "patests/patest_saw.c". -It calculates a simple left and right sawtooth signal and writes it to -the output buffer. Notice that in this example, the signals are of float -data type. The signals must be between -1.0 and +1.0. You can also use -16 bit integers or other formats which are specified during setup. You -can pass a pointer to your data structure through PortAudio which will -appear as userData. -
-
int patestCallback(  void *inputBuffer, void *outputBuffer,
-                     unsigned long framesPerBuffer,
-                     PaTimestamp outTime, void *userData )
-{
-    unsigned int i;
-/* Cast data passed through stream to our structure type. */
-    paTestData *data = (paTestData*)userData;
-    float *out = (float*)outputBuffer;
-        
-    for( i=0; i<framesPerBuffer; i++ )
-    {
-    /* Stereo channels are interleaved. */
-        *out++ = data->left_phase;              /* left */
-        *out++ = data->right_phase;             /* right */
-
-    /* Generate simple sawtooth phaser that ranges between -1.0 and 1.0. */
-        data->left_phase += 0.01f;
-    /* When signal reaches top, drop back down. */
-        if( data->left_phase >= 1.0f ) data->left_phase -= 2.0f;
-
-    /* higher pitch so we can distinguish left and right. */
-        data->right_phase += 0.03f; 
-        if( data->right_phase >= 1.0f ) data->right_phase -= 2.0f;
-    }
-    return 0;
-}
-
-
-home | -contents -| previousnext - - + + + + + + + + + PortAudio Tutorial + + +  +
+ + + +
+
+

+PortAudio Tutorial

+
+ +

+Writing a Callback Function

+ +
To write a program using PortAudio, you must include the "portaudio.h" +include file. You may wish to read "portaudio.h" +because it contains a complete description of the PortAudio functions and +constants. +
+
#include "portaudio.h"
+
+The next task is to write your custom callback function. It is a function +that is called by the PortAudio engine whenever it has captured audio data, +or when it needs more audio data for output. +

Your callback function is often called by an interrupt, or low level +process so you should not do any complex system activities like allocating +memory, or reading or writing files, or printf(). Just crunch numbers and +generate audio signals. What is safe or not safe will vary from platform +to platform. On the Macintosh, for example, you can only call "interrupt +safe" routines. Also do not call any PortAudio functions in the callback +except for Pa_StreamTime() and Pa_GetCPULoad(). +

Your callback function must return an int and accept the exact parameters +specified in this typedef: +

+
typedef int (PortAudioCallback)(
+               void *inputBuffer, void *outputBuffer,
+               unsigned long framesPerBuffer,
+               PaTimestamp outTime, void *userData );
+
+Here is an example callback function from the test file "patests/patest_saw.c". +It calculates a simple left and right sawtooth signal and writes it to +the output buffer. Notice that in this example, the signals are of float +data type. The signals must be between -1.0 and +1.0. You can also use +16 bit integers or other formats which are specified during setup. You +can pass a pointer to your data structure through PortAudio which will +appear as userData. +
+
int patestCallback(  void *inputBuffer, void *outputBuffer,
+                     unsigned long framesPerBuffer,
+                     PaTimestamp outTime, void *userData )
+{
+    unsigned int i;
+/* Cast data passed through stream to our structure type. */
+    paTestData *data = (paTestData*)userData;
+    float *out = (float*)outputBuffer;
+        
+    for( i=0; i<framesPerBuffer; i++ )
+    {
+    /* Stereo channels are interleaved. */
+        *out++ = data->left_phase;              /* left */
+        *out++ = data->right_phase;             /* right */
+
+    /* Generate simple sawtooth phaser that ranges between -1.0 and 1.0. */
+        data->left_phase += 0.01f;
+    /* When signal reaches top, drop back down. */
+        if( data->left_phase >= 1.0f ) data->left_phase -= 2.0f;
+
+    /* higher pitch so we can distinguish left and right. */
+        data->right_phase += 0.03f; 
+        if( data->right_phase >= 1.0f ) data->right_phase -= 2.0f;
+    }
+    return 0;
+}
+
+
+home | +contents +| previousnext + + diff --git a/lib-src/portaudio/docs/pa_tut_devs.html b/lib-src/portaudio/docs/pa_tut_devs.html index 6a8c08a3d..1756992cb 100644 --- a/lib-src/portaudio/docs/pa_tut_devs.html +++ b/lib-src/portaudio/docs/pa_tut_devs.html @@ -1,65 +1,65 @@ - - - - - - - - - PortAudio Tutorial - - -  -
- - - -
-
-

-PortAudio Tutorial

-
- -

-Querying for Available Devices

- -
There are often several different audio devices available in -a computer with different capabilities. They can differ in the sample rates -supported, bit widths, etc. PortAudio provides a simple way to query for -the available devices, and then pass the selected device to Pa_OpenStream(). -For an example, see the file "pa_tests/pa_devs.c". -

To determine the number of devices: -

-
numDevices = Pa_CountDevices();
-
-You can then query each device in turn by calling Pa_GetDeviceInfo() with -an index. -
-
for( i=0; i<numDevices; i++ ) {
-     pdi = Pa_GetDeviceInfo( i );
-
-It will return a pointer to a PaDeviceInfo structure which is -defined as: -
-
typedef struct{
-    int structVersion; 
-    const char *name;
-    int maxInputChannels;
-    int maxOutputChannels;
-/* Number of discrete rates, or -1 if range supported. */
-    int numSampleRates;
-/* Array of supported sample rates, or {min,max} if range supported. */
-    const double *sampleRates;
-    PaSampleFormat nativeSampleFormat;
-}PaDeviceInfo;
-
-If the device supports a continuous range of sample rates, then numSampleRates -will equal -1, and the sampleRates array will have two values, the minimum  -and maximum rate. -

The device information is allocated by Pa_Initialize() and freed by -Pa_Terminate() so you do not have to free() the structure returned by Pa_GetDeviceInfo().

-home | -contents -| previousnext - - + + + + + + + + + PortAudio Tutorial + + +  +
+ + + +
+
+

+PortAudio Tutorial

+
+ +

+Querying for Available Devices

+ +
There are often several different audio devices available in +a computer with different capabilities. They can differ in the sample rates +supported, bit widths, etc. PortAudio provides a simple way to query for +the available devices, and then pass the selected device to Pa_OpenStream(). +For an example, see the file "pa_tests/pa_devs.c". +

To determine the number of devices: +

+
numDevices = Pa_CountDevices();
+
+You can then query each device in turn by calling Pa_GetDeviceInfo() with +an index. +
+
for( i=0; i<numDevices; i++ ) {
+     pdi = Pa_GetDeviceInfo( i );
+
+It will return a pointer to a PaDeviceInfo structure which is +defined as: +
+
typedef struct{
+    int structVersion; 
+    const char *name;
+    int maxInputChannels;
+    int maxOutputChannels;
+/* Number of discrete rates, or -1 if range supported. */
+    int numSampleRates;
+/* Array of supported sample rates, or {min,max} if range supported. */
+    const double *sampleRates;
+    PaSampleFormat nativeSampleFormat;
+}PaDeviceInfo;
+
+If the device supports a continuous range of sample rates, then numSampleRates +will equal -1, and the sampleRates array will have two values, the minimum  +and maximum rate. +

The device information is allocated by Pa_Initialize() and freed by +Pa_Terminate() so you do not have to free() the structure returned by Pa_GetDeviceInfo().

+home | +contents +| previousnext + + diff --git a/lib-src/portaudio/docs/pa_tut_explore.html b/lib-src/portaudio/docs/pa_tut_explore.html index ea616c154..91c08a5b7 100644 --- a/lib-src/portaudio/docs/pa_tut_explore.html +++ b/lib-src/portaudio/docs/pa_tut_explore.html @@ -1,42 +1,42 @@ - - - - - - - - - PortAudio Tutorial - - -  -
- - - -
-
-

-PortAudio Tutorial

-
- -

-Exploring PortAudio

- -
Now that you have a good idea of how PortAudio works, you can -try out the test programs. -
    -
  • -For an example of playing a sine wave, see "pa_tests/patest_sine.c".
  • - -
  • -For an example of recording and playing back a sound, see  "pa_tests/patest_record.c".
  • -
-I also encourage you to examine the source for the PortAudio libraries. -If you have suggestions on ways to improve them, please let us know. if -you want to implement PortAudio on a new platform, please let us know as -well so we can coordinate people's efforts.
-home | contents -| previous |  next - - + + + + + + + + + PortAudio Tutorial + + +  +
+ + + +
+
+

+PortAudio Tutorial

+
+ +

+Exploring PortAudio

+ +
Now that you have a good idea of how PortAudio works, you can +try out the test programs. +
    +
  • +For an example of playing a sine wave, see "pa_tests/patest_sine.c".
  • + +
  • +For an example of recording and playing back a sound, see  "pa_tests/patest_record.c".
  • +
+I also encourage you to examine the source for the PortAudio libraries. +If you have suggestions on ways to improve them, please let us know. if +you want to implement PortAudio on a new platform, please let us know as +well so we can coordinate people's efforts.
+home | contents +| previous |  next + + diff --git a/lib-src/portaudio/docs/pa_tut_init.html b/lib-src/portaudio/docs/pa_tut_init.html index 876130b08..91bfa8d98 100644 --- a/lib-src/portaudio/docs/pa_tut_init.html +++ b/lib-src/portaudio/docs/pa_tut_init.html @@ -1,43 +1,43 @@ - - - - - - - - - PortAudio Tutorial - - -  -
- - - -
-
-

-PortAudio Tutorial

-
- -

-Initializing PortAudio

- -
Before making any other calls to PortAudio, you must call Pa_Initialize(). -This will trigger a scan of available devices which can be queried later. -Like most PA functions, it will return a result of type paError. -If the result is not paNoError, then an error has occurred. -
-
err = Pa_Initialize();
-if( err != paNoError ) goto error;
-
-You can get a text message that explains the error message by passing it -to -
-
printf(  "PortAudio error: %s\n", Pa_GetErrorText( err ) );
-
-
-home | contents -| previousnext - - + + + + + + + + + PortAudio Tutorial + + +  +
+ + + +
+
+

+PortAudio Tutorial

+
+ +

+Initializing PortAudio

+ +
Before making any other calls to PortAudio, you must call Pa_Initialize(). +This will trigger a scan of available devices which can be queried later. +Like most PA functions, it will return a result of type paError. +If the result is not paNoError, then an error has occurred. +
+
err = Pa_Initialize();
+if( err != paNoError ) goto error;
+
+You can get a text message that explains the error message by passing it +to +
+
printf(  "PortAudio error: %s\n", Pa_GetErrorText( err ) );
+
+
+home | contents +| previousnext + + diff --git a/lib-src/portaudio/docs/pa_tut_mac.html b/lib-src/portaudio/docs/pa_tut_mac.html index 57b6e1da9..bf3dafd1a 100644 --- a/lib-src/portaudio/docs/pa_tut_mac.html +++ b/lib-src/portaudio/docs/pa_tut_mac.html @@ -1,41 +1,41 @@ - - - - - - - - - PortAudio Tutorial - - -  -
- - - -
-
-

-PortAudio Tutorial

-
- -

-Compiling for Macintosh

- -
To compile a Macintosh application with the PortAudio library, -add the following source files to your project: -
-
pa_mac:pa_mac.c
-pa_common:pa_lib.c
-pa_common:portaudio.h
-pa_common:pa_host.h
-
-Also add the Apple SoundLib to your project. -

You may try compiling the "pa_tests:patest_saw.c" file first because -it is the simplest.

-home | -contents -| previousnext - - + + + + + + + + + PortAudio Tutorial + + +  +
+ + + +
+
+

+PortAudio Tutorial

+
+ +

+Compiling for Macintosh

+ +
To compile a Macintosh application with the PortAudio library, +add the following source files to your project: +
+
pa_mac:pa_mac.c
+pa_common:pa_lib.c
+pa_common:portaudio.h
+pa_common:pa_host.h
+
+Also add the Apple SoundLib to your project. +

You may try compiling the "pa_tests:patest_saw.c" file first because +it is the simplest.

+home | +contents +| previousnext + + diff --git a/lib-src/portaudio/docs/pa_tut_open.html b/lib-src/portaudio/docs/pa_tut_open.html index 977d59fc9..1621ef30f 100644 --- a/lib-src/portaudio/docs/pa_tut_open.html +++ b/lib-src/portaudio/docs/pa_tut_open.html @@ -1,52 +1,52 @@ - - - - - - - - - PortAudio Tutorial - - -  -
- - - -
-
-

-PortAudio Tutorial

-
- -

-Opening a Stream using Defaults

- -
The next step is to open a stream which is similar to opening -a file. You can specify whether you want audio input and/or output, how -many channels, the data format, sample rate, etc. There are two calls for -opening streams, Pa_OpenStream() and Pa_OpenDefaultStream(). -

Pa_OpenStream() takes extra  parameters which give you -more control. You can normally just use Pa_OpenDefaultStream() -which just calls Pa_OpenStream() with some reasonable -default values.  Let's open a stream for stereo output, using floating -point data, at 44100 Hz. -

-
err = Pa_OpenDefaultStream(
-    &stream,        /* passes back stream pointer */
-    0,              /* no input channels */
-    2,              /* stereo output */
-    paFloat32,      /* 32 bit floating point output */
-    44100,          /* sample rate */
-    256,            /* frames per buffer */
-    0,              /* number of buffers, if zero then use default minimum */
-    patestCallback, /* specify our custom callback */
-    &data );        /* pass our data through to callback */
-
-If you want to use 16 bit integer data, pass paInt16 instead of -paFloat32.
-home | contents -| previousnext - - + + + + + + + + + PortAudio Tutorial + + +  +
+ + + +
+
+

+PortAudio Tutorial

+
+ +

+Opening a Stream using Defaults

+ +
The next step is to open a stream which is similar to opening +a file. You can specify whether you want audio input and/or output, how +many channels, the data format, sample rate, etc. There are two calls for +opening streams, Pa_OpenStream() and Pa_OpenDefaultStream(). +

Pa_OpenStream() takes extra  parameters which give you +more control. You can normally just use Pa_OpenDefaultStream() +which just calls Pa_OpenStream() with some reasonable +default values.  Let's open a stream for stereo output, using floating +point data, at 44100 Hz. +

+
err = Pa_OpenDefaultStream(
+    &stream,        /* passes back stream pointer */
+    0,              /* no input channels */
+    2,              /* stereo output */
+    paFloat32,      /* 32 bit floating point output */
+    44100,          /* sample rate */
+    256,            /* frames per buffer */
+    0,              /* number of buffers, if zero then use default minimum */
+    patestCallback, /* specify our custom callback */
+    &data );        /* pass our data through to callback */
+
+If you want to use 16 bit integer data, pass paInt16 instead of +paFloat32.
+home | contents +| previousnext + + diff --git a/lib-src/portaudio/docs/pa_tut_oss.html b/lib-src/portaudio/docs/pa_tut_oss.html index 14c55b22c..8a56014d5 100644 --- a/lib-src/portaudio/docs/pa_tut_oss.html +++ b/lib-src/portaudio/docs/pa_tut_oss.html @@ -1,45 +1,45 @@ - - - - - - - - - PortAudio Tutorial - - -  -
- - - -
-
-

-PortAudio Tutorial

-
- -

-Compiling for Linux

- -
[Skip this page if you are not using Linux] -

We currently only support the OSS audio drivers for Linux. We hope to -someday support the newer ALSA drivers. -

    -
  1. -cd to pa_linux_oss directory
  2. - -
  3. -Edit the Makefile and uncomment one of the tests. You may try compiling -the "patest_sine.c" file first because it is very simple.
  4. - -
  5. -gmake run
  6. -
-
-home | -contents -| previousnext - - + + + + + + + + + PortAudio Tutorial + + +  +
+ + + +
+
+

+PortAudio Tutorial

+
+ +

+Compiling for Linux

+ +
[Skip this page if you are not using Linux] +

We currently only support the OSS audio drivers for Linux. We hope to +someday support the newer ALSA drivers. +

    +
  1. +cd to pa_linux_oss directory
  2. + +
  3. +Edit the Makefile and uncomment one of the tests. You may try compiling +the "patest_sine.c" file first because it is very simple.
  4. + +
  5. +gmake run
  6. +
+
+home | +contents +| previousnext + + diff --git a/lib-src/portaudio/docs/pa_tut_over.html b/lib-src/portaudio/docs/pa_tut_over.html index 1de6ec46b..59c5f63bd 100644 --- a/lib-src/portaudio/docs/pa_tut_over.html +++ b/lib-src/portaudio/docs/pa_tut_over.html @@ -1,86 +1,86 @@ - - - - - - - - - PortAudio Tutorial - - -  -
- - - -
-
-

-PortAudio Tutorial

-
- -

-Overview of PortAudio

- -
PortAudio is a library that provides streaming audio input -and output. It is a cross-platform API (Application Programming Interface) -that works on Windows and Macintosh, and perhaps other platforms by the -time you read this. This means that you can write a simple 'C' program -to process or generate an audio signal, and that program can run on several -different computers just by recompiling the source code. -

Here are the steps to writing a PortAudio application: -

    -
  1. -Write a callback function that will be called by PortAudio when audio processing -is needed.
  2. - -
  3. -Initialize the PA library and open a stream for audio I/O.
  4. - -
  5. -Start the stream. Your callback function will be now be called repeatedly -by PA in the background.
  6. - -
  7. -In your callback you can read audio data from the inputBuffer and/or write -data to the outputBuffer.
  8. - -
  9. -Stop the stream by returning 1 from your callback, or by calling a stop -function.
  10. - -
  11. -Close the stream and terminate the library.
  12. -
-
- -
There is also another interface -provided that allows you to generate audio in the foreground. You then -simply write data to the stream and the tool will not return until it is -ready to accept more data. This interface is simpler to use but is usually -not preferred for large applications because it requires that you launch -a thread to perform the synthesis. Launching a thread may be difficult -on non-multi-tasking systems such as the Macintosh prior to MacOS X. -

Let's continue by building a simple application that will play a sawtooth -wave. -

Please select the page for the implementation you would like to use: -

-
-home | -contents -| previous - - + + + + + + + + + PortAudio Tutorial + + +  +
+ + + +
+
+

+PortAudio Tutorial

+
+ +

+Overview of PortAudio

+ +
PortAudio is a library that provides streaming audio input +and output. It is a cross-platform API (Application Programming Interface) +that works on Windows and Macintosh, and perhaps other platforms by the +time you read this. This means that you can write a simple 'C' program +to process or generate an audio signal, and that program can run on several +different computers just by recompiling the source code. +

Here are the steps to writing a PortAudio application: +

    +
  1. +Write a callback function that will be called by PortAudio when audio processing +is needed.
  2. + +
  3. +Initialize the PA library and open a stream for audio I/O.
  4. + +
  5. +Start the stream. Your callback function will be now be called repeatedly +by PA in the background.
  6. + +
  7. +In your callback you can read audio data from the inputBuffer and/or write +data to the outputBuffer.
  8. + +
  9. +Stop the stream by returning 1 from your callback, or by calling a stop +function.
  10. + +
  11. +Close the stream and terminate the library.
  12. +
+
+ +
There is also another interface +provided that allows you to generate audio in the foreground. You then +simply write data to the stream and the tool will not return until it is +ready to accept more data. This interface is simpler to use but is usually +not preferred for large applications because it requires that you launch +a thread to perform the synthesis. Launching a thread may be difficult +on non-multi-tasking systems such as the Macintosh prior to MacOS X. +

Let's continue by building a simple application that will play a sawtooth +wave. +

Please select the page for the implementation you would like to use: +

+
+home | +contents +| previous + + diff --git a/lib-src/portaudio/docs/pa_tut_pc.html b/lib-src/portaudio/docs/pa_tut_pc.html index 8a73a3a41..7169f405a 100644 --- a/lib-src/portaudio/docs/pa_tut_pc.html +++ b/lib-src/portaudio/docs/pa_tut_pc.html @@ -1,63 +1,63 @@ - - - - - - - - - PortAudio Tutorial - - -  -
- - - -
-
-

-PortAudio Tutorial

-
- -

-Compiling for Windows (WMME or DirectSound)

- -
To compile PortAudio for Windows, you can choose between two -options. One implementation uses the DirectSound API. The other uses the -Windows MultiMedia Extensions API (aka WMME or WAVE). -

Some advantages of using DirectSound are that DirectSound may have lower -latency than WMME, and supports effects processing plugins. But one disadvantage -is that DirectSound is not installed on all PCs, and is not well supported -under Windows NT. -

For either implementation add the following source files to your project: -

-
pa_common\pa_lib.c
-pa_common\portaudio.h
-pa_common\pa_host.h
- -
Link with the system library: winmm.lib
-
-WMME - To use the WMME implementation, add the following source -files to your project: -
pa_win_wmme/pa_win_wmme.c
-DirectSound - If you want to use the DirectSound implementation -of PortAudio then you must have a recent copy of the free -DirectX -SDK for Developers from Microsoft installed on your computer. To compile -an application add the following source files to your project: -
-
pa_win_ds\dsound_wrapper.c
-pa_win_ds\pa_dsound.c
-
- -
-
Link with the system library: dsound.lib
-
-You may try compiling the "pa_tests\patest_saw.c" file first because it -is the simplest.
-home | -contents -| previousnext - - + + + + + + + + + PortAudio Tutorial + + +  +
+ + + +
+
+

+PortAudio Tutorial

+
+ +

+Compiling for Windows (WMME or DirectSound)

+ +
To compile PortAudio for Windows, you can choose between two +options. One implementation uses the DirectSound API. The other uses the +Windows MultiMedia Extensions API (aka WMME or WAVE). +

Some advantages of using DirectSound are that DirectSound may have lower +latency than WMME, and supports effects processing plugins. But one disadvantage +is that DirectSound is not installed on all PCs, and is not well supported +under Windows NT. +

For either implementation add the following source files to your project: +

+
pa_common\pa_lib.c
+pa_common\portaudio.h
+pa_common\pa_host.h
+ +
Link with the system library: winmm.lib
+
+WMME - To use the WMME implementation, add the following source +files to your project: +
pa_win_wmme/pa_win_wmme.c
+DirectSound - If you want to use the DirectSound implementation +of PortAudio then you must have a recent copy of the free +DirectX +SDK for Developers from Microsoft installed on your computer. To compile +an application add the following source files to your project: +
+
pa_win_ds\dsound_wrapper.c
+pa_win_ds\pa_dsound.c
+
+ +
+
Link with the system library: dsound.lib
+
+You may try compiling the "pa_tests\patest_saw.c" file first because it +is the simplest.
+home | +contents +| previousnext + + diff --git a/lib-src/portaudio/docs/pa_tut_run.html b/lib-src/portaudio/docs/pa_tut_run.html index 476df6826..5c70d0895 100644 --- a/lib-src/portaudio/docs/pa_tut_run.html +++ b/lib-src/portaudio/docs/pa_tut_run.html @@ -1,56 +1,56 @@ - - - - - - - - - PortAudio Tutorial - - -  -
- - - -
-
-

-PortAudio Tutorial

-
- -

-Starting and Stopping a Stream

- -
The stream will not start running until you call Pa_StartStream(). -Then it will start calling your callback function to perform the audio -processing. -
-
err = Pa_StartStream( stream );
-if( err != paNoError ) goto error;
-
-At this point, audio is being generated. You can communicate to your callback -routine through the data structure you passed in on the open call, or through -global variables, or using other interprocess communication techniques. -Please be aware that your callback function may be called at interrupt -time when your foreground process is least expecting it. So avoid sharing -complex data structures that are easily corrupted like double linked lists. -

In many of the tests we simply sleep for a few seconds so we can hear -the sound. This is easy to do with Pa_Sleep() which will sleep for some -number of milliseconds. Do not rely on this function for accurate scheduling. -it is mostly for writing examples. -

-
/* Sleep for several seconds. */
-Pa_Sleep(NUM_SECONDS*1000);
-
-When you are through, you can stop the stream from the foreground. -
-
err = Pa_StopStream( stream );
-if( err != paNoError ) goto error;
-
-You can also stop the stream by returning 1 from your custom callback function.
-home | contents -| previousnext - - + + + + + + + + + PortAudio Tutorial + + +  +
+ + + +
+
+

+PortAudio Tutorial

+
+ +

+Starting and Stopping a Stream

+ +
The stream will not start running until you call Pa_StartStream(). +Then it will start calling your callback function to perform the audio +processing. +
+
err = Pa_StartStream( stream );
+if( err != paNoError ) goto error;
+
+At this point, audio is being generated. You can communicate to your callback +routine through the data structure you passed in on the open call, or through +global variables, or using other interprocess communication techniques. +Please be aware that your callback function may be called at interrupt +time when your foreground process is least expecting it. So avoid sharing +complex data structures that are easily corrupted like double linked lists. +

In many of the tests we simply sleep for a few seconds so we can hear +the sound. This is easy to do with Pa_Sleep() which will sleep for some +number of milliseconds. Do not rely on this function for accurate scheduling. +it is mostly for writing examples. +

+
/* Sleep for several seconds. */
+Pa_Sleep(NUM_SECONDS*1000);
+
+When you are through, you can stop the stream from the foreground. +
+
err = Pa_StopStream( stream );
+if( err != paNoError ) goto error;
+
+You can also stop the stream by returning 1 from your custom callback function.
+home | contents +| previousnext + + diff --git a/lib-src/portaudio/docs/pa_tut_rw.html b/lib-src/portaudio/docs/pa_tut_rw.html index 89441d7f5..4d1abb6b9 100644 --- a/lib-src/portaudio/docs/pa_tut_rw.html +++ b/lib-src/portaudio/docs/pa_tut_rw.html @@ -1,77 +1,77 @@ - - - - - - - - - PortAudio Tutorial - - -  -
- - - -
-
-

-PortAudio Tutorial

-
- -

-Blocking Read/Write Functions

- -
[Note: These functions are not part of the official PortAudio -API. They are simply built on top of PortAudio as an extra utility. Also -note that they are under evaluation and their definition may change.] -

There are two fundamentally different ways to design an audio API. One -is to use callback functions the way we have already shown. The callback -function operates under an interrupt or background thread This leaves the -foreground application free to do other things while the audio just runs -in the background. But this can sometimes be awkward. -

So we have provided an alternative technique that lets a program generate -audio in the foreground and then just write it to the audio stream as if -it was a file. If there is not enough room in the audio buffer for more -data, then the write function will just block until more room is available. -This can make it very easy to write an audio example. To use this tool, -you must add the files "pablio/pablio.c" and "pablio/ringbuffer.c" to your -project. You must also: -

-
#include "pablio.h"
-
-Here is a short excerpt of a program that opens a stream for input and -output. It then read a pair of samples at a time from input, and writes -them to output, in a loop. The complete example can be found in "pablio/test_rw.c". -
-
    SAMPLE          samples[2];
-    PaError         err;
-    PABLIO_Stream  *aStream;
-
-/* Open simplified blocking I/O layer on top of PortAudio. */
-    err = OpenAudioStream( &rwbl, SAMPLE_RATE, paFloat32,
-                         (PABLIO_READ_WRITE | PABLIO_STEREO) );
-    if( err != paNoError ) goto error;
-
-/* Process samples in the foreground. */
-    for( i=0; i<(NUM_SECONDS * SAMPLE_RATE); i++ )
-    {
-    /* Read one frame of data into sample array from audio input. */
-        ReadAudioStream( aStream, samples, 1 );
-    /*
-    ** At this point you could process the data in samples[0] and samples[1],
-    ** and write the result back to the same samples array.
-    */
-    /* Write that same frame of data to output. */
-        WriteAudioStream( aStream, samples, 1 );
-    }
-
-    CloseAudioStream( aStream );
-
-
-home | -contents -| previousnext - - + + + + + + + + + PortAudio Tutorial + + +  +
+ + + +
+
+

+PortAudio Tutorial

+
+ +

+Blocking Read/Write Functions

+ +
[Note: These functions are not part of the official PortAudio +API. They are simply built on top of PortAudio as an extra utility. Also +note that they are under evaluation and their definition may change.] +

There are two fundamentally different ways to design an audio API. One +is to use callback functions the way we have already shown. The callback +function operates under an interrupt or background thread This leaves the +foreground application free to do other things while the audio just runs +in the background. But this can sometimes be awkward. +

So we have provided an alternative technique that lets a program generate +audio in the foreground and then just write it to the audio stream as if +it was a file. If there is not enough room in the audio buffer for more +data, then the write function will just block until more room is available. +This can make it very easy to write an audio example. To use this tool, +you must add the files "pablio/pablio.c" and "pablio/ringbuffer.c" to your +project. You must also: +

+
#include "pablio.h"
+
+Here is a short excerpt of a program that opens a stream for input and +output. It then read a pair of samples at a time from input, and writes +them to output, in a loop. The complete example can be found in "pablio/test_rw.c". +
+
    SAMPLE          samples[2];
+    PaError         err;
+    PABLIO_Stream  *aStream;
+
+/* Open simplified blocking I/O layer on top of PortAudio. */
+    err = OpenAudioStream( &rwbl, SAMPLE_RATE, paFloat32,
+                         (PABLIO_READ_WRITE | PABLIO_STEREO) );
+    if( err != paNoError ) goto error;
+
+/* Process samples in the foreground. */
+    for( i=0; i<(NUM_SECONDS * SAMPLE_RATE); i++ )
+    {
+    /* Read one frame of data into sample array from audio input. */
+        ReadAudioStream( aStream, samples, 1 );
+    /*
+    ** At this point you could process the data in samples[0] and samples[1],
+    ** and write the result back to the same samples array.
+    */
+    /* Write that same frame of data to output. */
+        WriteAudioStream( aStream, samples, 1 );
+    }
+
+    CloseAudioStream( aStream );
+
+
+home | +contents +| previousnext + + diff --git a/lib-src/portaudio/docs/pa_tut_term.html b/lib-src/portaudio/docs/pa_tut_term.html index f96e62888..1c72209f1 100644 --- a/lib-src/portaudio/docs/pa_tut_term.html +++ b/lib-src/portaudio/docs/pa_tut_term.html @@ -1,47 +1,47 @@ - - - - - - - - - PortAudio Tutorial - - -  -
- - - -
-
-

-PortAudio Tutorial

-
- -

-Terminating PortAudio

- -
You can start and stop a stream as many times as you like. -But when you are done using it, you should close it by calling:
- -
-
-
err = Pa_CloseStream( stream );
-if( err != paNoError ) goto error;
-
-Then when you are done using PortAudio, you should terminate the whole -system by calling: -
-
Pa_Terminate();
-
-That's basically it. You can now write an audio program in 'C' that will -run on multiple platforms, for example PCs and Macintosh. -

In the rest of the tutorial we will look at some additional utility -functions, and a different way of using PortAudio that does not require -the use of a callback function.

-home | contents -| previousnext - - + + + + + + + + + PortAudio Tutorial + + +  +
+ + + +
+
+

+PortAudio Tutorial

+
+ +

+Terminating PortAudio

+ +
You can start and stop a stream as many times as you like. +But when you are done using it, you should close it by calling:
+ +
+
+
err = Pa_CloseStream( stream );
+if( err != paNoError ) goto error;
+
+Then when you are done using PortAudio, you should terminate the whole +system by calling: +
+
Pa_Terminate();
+
+That's basically it. You can now write an audio program in 'C' that will +run on multiple platforms, for example PCs and Macintosh. +

In the rest of the tutorial we will look at some additional utility +functions, and a different way of using PortAudio that does not require +the use of a callback function.

+home | contents +| previousnext + + diff --git a/lib-src/portaudio/docs/pa_tut_util.html b/lib-src/portaudio/docs/pa_tut_util.html index ddf7de822..f4b547501 100644 --- a/lib-src/portaudio/docs/pa_tut_util.html +++ b/lib-src/portaudio/docs/pa_tut_util.html @@ -1,55 +1,55 @@ - - - - - - - - - PortAudio Tutorial - - -  -
- - - -
-
-

-PortAudio Tutorial

-
- -

-Utility Functions

- -
Here are several more functions that are not critical, but -may be handy when using PortAudio. -

Pa_StreamActive() returns one when the stream in playing audio, zero -when not playing, or a negative error number if the stream is invalid. -The stream is active between calls to Pa_StartStream() and Pa_StopStream(), -but may also become inactive if the callback returns a non-zero value. -In the latter case, the stream is considered inactive after the last buffer -has finished playing. -

-
PaError Pa_StreamActive( PortAudioStream *stream );
-
-Pa_StreamTime() returns the number of samples that have been generated. -PaTimeStamp is a double precision number which is a convenient way to pass -big numbers around even though we only need integers. -
-
PaTimestamp Pa_StreamTime( PortAudioStream *stream );
-
-The "CPU Load" is a fraction of total CPU time consumed by the stream's -audio processing. A value of 0.5 would imply that PortAudio and the sound -generating callback was consuming roughly 50% of the available CPU time. -This function may be called from the callback function or the application. -
-
double Pa_GetCPULoad( PortAudioStream* stream );
-
-
-home | -contents | previous -|  next - - + + + + + + + + + PortAudio Tutorial + + +  +
+ + + +
+
+

+PortAudio Tutorial

+
+ +

+Utility Functions

+ +
Here are several more functions that are not critical, but +may be handy when using PortAudio. +

Pa_StreamActive() returns one when the stream in playing audio, zero +when not playing, or a negative error number if the stream is invalid. +The stream is active between calls to Pa_StartStream() and Pa_StopStream(), +but may also become inactive if the callback returns a non-zero value. +In the latter case, the stream is considered inactive after the last buffer +has finished playing. +

+
PaError Pa_StreamActive( PortAudioStream *stream );
+
+Pa_StreamTime() returns the number of samples that have been generated. +PaTimeStamp is a double precision number which is a convenient way to pass +big numbers around even though we only need integers. +
+
PaTimestamp Pa_StreamTime( PortAudioStream *stream );
+
+The "CPU Load" is a fraction of total CPU time consumed by the stream's +audio processing. A value of 0.5 would imply that PortAudio and the sound +generating callback was consuming roughly 50% of the available CPU time. +This function may be called from the callback function or the application. +
+
double Pa_GetCPULoad( PortAudioStream* stream );
+
+
+home | +contents | previous +|  next + + diff --git a/lib-src/portaudio/docs/pa_tutorial.html b/lib-src/portaudio/docs/pa_tutorial.html index b3b7d0ee9..9428bad1f 100644 --- a/lib-src/portaudio/docs/pa_tutorial.html +++ b/lib-src/portaudio/docs/pa_tutorial.html @@ -1,44 +1,44 @@ - - - - - - - - - PortAudio Tutorial - - -  -
- - - -
-
-

-PortAudio Tutorial

-
- -

Copyright 2000 Phil Burk and Ross Bencina -

-Table of Contents

- -
Overview of PortAudio -
Compiling for Macintosh -
Compiling for Windows (DirectSound and WMME) -
Compiling for ASIO on Windows or Macintosh -
Compiling for Unix OSS -
Writing a Callback Function -
Initializing PortAudio -
Opening a Stream using Defaults -
Starting and Stopping a Stream -
Cleaning Up -
Utilities -
Querying for Devices -
Blocking Read/Write Functions -
Exploring the PortAudio Package
-home | contents | -previous |  next - - + + + + + + + + + PortAudio Tutorial + + +  +
+ + + +
+
+

+PortAudio Tutorial

+
+ +

Copyright 2000 Phil Burk and Ross Bencina +

+Table of Contents

+ +
Overview of PortAudio +
Compiling for Macintosh +
Compiling for Windows (DirectSound and WMME) +
Compiling for ASIO on Windows or Macintosh +
Compiling for Unix OSS +
Writing a Callback Function +
Initializing PortAudio +
Opening a Stream using Defaults +
Starting and Stopping a Stream +
Cleaning Up +
Utilities +
Querying for Devices +
Blocking Read/Write Functions +
Exploring the PortAudio Package
+home | contents | +previous |  next + + diff --git a/lib-src/portaudio/docs/releases.html b/lib-src/portaudio/docs/releases.html index a97440796..a38567409 100644 --- a/lib-src/portaudio/docs/releases.html +++ b/lib-src/portaudio/docs/releases.html @@ -1,226 +1,226 @@ - - - - - - - - - PortAudio Implementations for DirectSound - - -  -
- - - -
-
-

-PortAudio - Release Notes

-
- -

Link to PortAudio Home Page -

-V17 - 10/15/01

- -
Unix OSS -
    -
  • -Set num channels back to two after device query for ALSA. This fixed a -bug in V16 that sometimes caused a failure when querying for the sample -rates. Thanks Stweart Greenhill.
  • -
-
- -
-

-Macintosh Sound Manager

- -
    -
  • -Use NewSndCallBackUPP() for CARBON compatibility.
  • -
-
- -

-V16 - 9/27/01

- -
Added Alpha implementations for ASIO, SGI, and BeOS! -
  -
  • -CPULoad is now calculated based on the time spent to generate a known number -of frames. This is more accurate than a simple percentage of real-time. -Implemented in pa_unix_oss, pa_win_wmme and pa_win_ds.
  • - -
  • -Fix dither and shift for recording PaUInt8 format data.
  • - -
  • -Added "patest_maxsines.c" which tests Pa_GetCPULoad().
  • -
    - -
    -

    -Windows WMME

    - -
      -
    • -sDevicePtrs now allocated using GlobalAlloc(). This prevents a -crash in Pa_Terminate() on Win2000. Thanks Mike Berry for finding this. -Thanks Mike Berry.
    • - -
    • -Pass process instead of thread to SetPriorityClass(). This fixes -a bug that caused the priority to not be increased. Thanks to Alberto di -Bene for spotting this.
    • -
    - -

    -Windows DirectSound

    - -
      -
    • -Casts for compiling with __MWERKS__ CodeWarrior.
    • -
    - -

    -UNIX OSS

    - -
      -
    • -Derived from Linux OSS implementation.
    • - -
    • -Numerous patches from Heiko Purnhagen, Stephen Brandon, etc.
    • - -
    • -Improved query mechanism which often bailed out unnecessarily.
    • - -
    • -Removed sNumDevices and potential related bugs,
    • - -
    • -Use getenv("PA_MIN_LATENCY_MSEC") in code to set desired latency. -User can set by entering:
    • - -
          export PA_MIN_LATENCY_MSEC=40
    - -

    -Macintosh Sound Manager

    - -
      -
    • -Pass unused event to WaitNextEvent instead of NULL to prevent Mac OSX crash. -Thanks Dominic Mazzoni.
    • - -
       
    -
    - -

    -V15 - 5/29/01

    - -
    -
      -
    • -New Linux OSS Beta
    • -
    - -

    -Windows WMME

    - -
      -
    • - sDevicePtrs now allocated based on sizeof(pointer). Was allocating -too much space.
    • - -
    • - Check for excessive numbers of channels. Some drivers reported bogus -numbers.
    • - -
    • -Apply Mike Berry's changes for CodeWarrior on PC including condition including -of memory.h, and explicit typecasting on memory allocation.
    • -
    - -

    -Macintosh Sound Manager

    - -
      -
    • -ScanInputDevices was setting sDefaultOutputDeviceID instead of sDefaultInputDeviceID.
    • - -
    • -Device Scan was crashing for anything other than siBadSoundInDevice, but -some Macs may return other errors! Caused failure to init on some G4s under -OS9.
    • - -
    • -Fix TIMEOUT in record mode.
    • - -
    • -Change CARBON_COMPATIBLE to TARGET_API_MAC_CARBON
    • -
    -
    - -

    -V14 - 2/6/01

    - -
    -
      -
    • -Added implementation for Windows MultiMedia Extensions (WMME) by Ross and -Phil
    • - -
    • -Changed Pa_StopStream() so that it waits for the buffers to drain.
    • - -
    • -Added Pa_AbortStream() that stops immediately without waiting.
    • - -
    • -Added new test: patest_stop.c to test above two mods.
    • - -
    • -Fixed Pa_StreamTime() so that it returns current play position instead -of the write position. Added "patest_sync.c" to demo audio/video sync.
    • - -
    • -Improved stability of Macintosh implementation. Added timeouts to prevent -hangs.
    • - -
    • -Added Pa_GetSampleSize( PaSampleFormat format );
    • - -
    • -Changes some "int"s to "long"s so that PA works properly on Macintosh which -often compiles using 16 bit ints.
    • - -
    • -Added Implementation Guide
    • -
    -
    - -

    -V12 - 1/9/01

    - -
    -
      -
    • -Mac now scans for and queries all devices. But it does not yet support -selecting any other than the default device.
    • - -
    • -Blocking I/O calls renamed to separate them from the PortAudio API.
    • - -
    • -Cleaned up indentation problems with tabs versus spaces.
    • - -
    • -Now attempts to correct bogus sample rate info returned from DirectSound -device queries.
    • -
    -
    - - - + + + + + + + + + PortAudio Implementations for DirectSound + + +  +
    + + + +
    +
    +

    +PortAudio - Release Notes

    +
    + +

    Link to PortAudio Home Page +

    +V17 - 10/15/01

    + +
    Unix OSS +
      +
    • +Set num channels back to two after device query for ALSA. This fixed a +bug in V16 that sometimes caused a failure when querying for the sample +rates. Thanks Stweart Greenhill.
    • +
    +
    + +
    +

    +Macintosh Sound Manager

    + +
      +
    • +Use NewSndCallBackUPP() for CARBON compatibility.
    • +
    +
    + +

    +V16 - 9/27/01

    + +
    Added Alpha implementations for ASIO, SGI, and BeOS! +
      +
  • +CPULoad is now calculated based on the time spent to generate a known number +of frames. This is more accurate than a simple percentage of real-time. +Implemented in pa_unix_oss, pa_win_wmme and pa_win_ds.
  • + +
  • +Fix dither and shift for recording PaUInt8 format data.
  • + +
  • +Added "patest_maxsines.c" which tests Pa_GetCPULoad().
  • +
    + +
    +

    +Windows WMME

    + +
      +
    • +sDevicePtrs now allocated using GlobalAlloc(). This prevents a +crash in Pa_Terminate() on Win2000. Thanks Mike Berry for finding this. +Thanks Mike Berry.
    • + +
    • +Pass process instead of thread to SetPriorityClass(). This fixes +a bug that caused the priority to not be increased. Thanks to Alberto di +Bene for spotting this.
    • +
    + +

    +Windows DirectSound

    + +
      +
    • +Casts for compiling with __MWERKS__ CodeWarrior.
    • +
    + +

    +UNIX OSS

    + +
      +
    • +Derived from Linux OSS implementation.
    • + +
    • +Numerous patches from Heiko Purnhagen, Stephen Brandon, etc.
    • + +
    • +Improved query mechanism which often bailed out unnecessarily.
    • + +
    • +Removed sNumDevices and potential related bugs,
    • + +
    • +Use getenv("PA_MIN_LATENCY_MSEC") in code to set desired latency. +User can set by entering:
    • + +
          export PA_MIN_LATENCY_MSEC=40
    + +

    +Macintosh Sound Manager

    + +
      +
    • +Pass unused event to WaitNextEvent instead of NULL to prevent Mac OSX crash. +Thanks Dominic Mazzoni.
    • + +
       
    +
    + +

    +V15 - 5/29/01

    + +
    +
      +
    • +New Linux OSS Beta
    • +
    + +

    +Windows WMME

    + +
      +
    • + sDevicePtrs now allocated based on sizeof(pointer). Was allocating +too much space.
    • + +
    • + Check for excessive numbers of channels. Some drivers reported bogus +numbers.
    • + +
    • +Apply Mike Berry's changes for CodeWarrior on PC including condition including +of memory.h, and explicit typecasting on memory allocation.
    • +
    + +

    +Macintosh Sound Manager

    + +
      +
    • +ScanInputDevices was setting sDefaultOutputDeviceID instead of sDefaultInputDeviceID.
    • + +
    • +Device Scan was crashing for anything other than siBadSoundInDevice, but +some Macs may return other errors! Caused failure to init on some G4s under +OS9.
    • + +
    • +Fix TIMEOUT in record mode.
    • + +
    • +Change CARBON_COMPATIBLE to TARGET_API_MAC_CARBON
    • +
    +
    + +

    +V14 - 2/6/01

    + +
    +
      +
    • +Added implementation for Windows MultiMedia Extensions (WMME) by Ross and +Phil
    • + +
    • +Changed Pa_StopStream() so that it waits for the buffers to drain.
    • + +
    • +Added Pa_AbortStream() that stops immediately without waiting.
    • + +
    • +Added new test: patest_stop.c to test above two mods.
    • + +
    • +Fixed Pa_StreamTime() so that it returns current play position instead +of the write position. Added "patest_sync.c" to demo audio/video sync.
    • + +
    • +Improved stability of Macintosh implementation. Added timeouts to prevent +hangs.
    • + +
    • +Added Pa_GetSampleSize( PaSampleFormat format );
    • + +
    • +Changes some "int"s to "long"s so that PA works properly on Macintosh which +often compiles using 16 bit ints.
    • + +
    • +Added Implementation Guide
    • +
    +
    + +

    +V12 - 1/9/01

    + +
    +
      +
    • +Mac now scans for and queries all devices. But it does not yet support +selecting any other than the default device.
    • + +
    • +Blocking I/O calls renamed to separate them from the PortAudio API.
    • + +
    • +Cleaned up indentation problems with tabs versus spaces.
    • + +
    • +Now attempts to correct bogus sample rate info returned from DirectSound +device queries.
    • +
    +
    + + + diff --git a/lib-src/portaudio/pa_mac/patest_devinfo.c b/lib-src/portaudio/pa_mac/patest_devinfo.c index 94e26ed08..6bbdf94a0 100644 --- a/lib-src/portaudio/pa_mac/patest_devinfo.c +++ b/lib-src/portaudio/pa_mac/patest_devinfo.c @@ -1 +1,152 @@ -/* * Test calling SPBSetDeviceInfo() * Should small parameters less than 4 bytes long be passed through a pointer, or directly? * * According to an Applet TechNote at: * http://developer.apple.com/technotes/tn/tn1048.html * * ------------- begin quote -------------- * Trouble with Void Pointers * The SetSoundOutputInfo, SndSetInfo, and SPBSetDeviceInfo all take a void* as their last parameter. * Because the last parameter of these calls is a void*, it looks as if you need to pass a pointer * to the value you are setting, but this is not the case if what you are passing is 4 bytes or * less in size. If you are passing a parameter that is larger than four bytes, you must pass a * pointer to it. * * If you are calling GetSoundOutputInfo, SndGetInfo, or SPBGetDeviceInfo and * it is returning a value that is 4 bytes in size or less, it does not return a pointer to * that value, it just returns the value. * ------------ end quote ------------------ * * But my experiments on a PowerComputing Mac clone running Mac OS 8.1 indicate that * the TechNote is wrong and that a pointer should be passed to SPBSetDeviceInfo. * * Author: Phil Burk * Copyright 2000 Phil Burk * This code may be used freely for any purpose. */ #include #include #include #include #include /* Mac specific includes */ #include "OSUtils.h" #include #include #include #include #include #include #include #include #include /* Change this to 0 or 1 to use the direct parameter method, or the indirect pointer method. */ #define USE_POINTER (1) /* Debugging output macros. */ #define PRINT(x) { printf x; fflush(stdout); } #define ERR_RPT(x) PRINT(x) #define DBUG(x) PRINT(x) static int TestSettingDeviceInfo( const unsigned char *deviceName ); int main( void ); int main( void ) { unsigned char noname = 0; int result = TestSettingDeviceInfo( (const unsigned char *) &noname ); PRINT(("Test complete. result = %d\n", result )); return 0; } /************************************************************************* ** TestSettingDeviceInfo() ** Query information about a named input device. */ static int TestSettingDeviceInfo( const unsigned char *deviceName ) { OSErr err; long mRefNum = 0; long tempL; short tempS; Fixed tempF; err = SPBOpenDevice( deviceName, siWritePermission, &mRefNum); if (err) { PRINT(("Cound not open device!\n")); return -1; } /* Define macros for printing out device info. */ #define PrintDeviceInfo(selector,var) \ err = SPBGetDeviceInfo(mRefNum, selector, (Ptr) &var); \ if (err) { \ PRINT(("query %s failed\n", #selector )); \ }\ else { \ PRINT(("query %s = 0x%x\n", #selector, var )); \ } PrintDeviceInfo( siContinuous, tempS ); PrintDeviceInfo( siAsync, tempS ); PrintDeviceInfo( siNumberChannels, tempS ); PrintDeviceInfo( siSampleSize, tempS ); PrintDeviceInfo( siSampleRate, tempF ); PrintDeviceInfo( siChannelAvailable, tempS ); PrintDeviceInfo( siActiveChannels, tempL ); PrintDeviceInfo( siDeviceBufferInfo, tempL ); #if USE_POINTER /* Continuous Mode ---------- */ PRINT(("Attempt to set siContinuous to 1 using pointer method.\n")); tempS = 1; err = SPBSetDeviceInfo(mRefNum, siContinuous, (Ptr) &tempS); if (err) PRINT(("setting siContinuous using pointer failed\n")); PrintDeviceInfo( siContinuous, tempS ); PRINT(("Attempt to set siContinuous to 0 using pointer method.\n")); tempS = 1; err = SPBSetDeviceInfo(mRefNum, siContinuous, (Ptr) &tempS); if (err) PRINT(("setting siContinuous using pointer failed\n")); PrintDeviceInfo( siContinuous, tempS ); #else PRINT(("Attempt to set siContinuous to 1 using direct method.\n")); err = SPBSetDeviceInfo(mRefNum, siContinuous, (Ptr) 1); if (err) PRINT(("setting siContinuous using direct failed\n")); PrintDeviceInfo( siContinuous, tempS ); PRINT(("Attempt to set siContinuous to 0 using direct method.\n")); err = SPBSetDeviceInfo(mRefNum, siContinuous, (Ptr) 0); if (err) PRINT(("setting siContinuous using direct failed\n")); PrintDeviceInfo( siContinuous, tempS ); #endif /* Sample rate ----------- */ #if USE_POINTER PRINT(("Attempt to set siSampleRate to 44100 using pointer method.\n")); tempF = ((unsigned long)44100) << 16; err = SPBSetDeviceInfo(mRefNum, siSampleRate, (Ptr) &tempF); if (err) PRINT(("setting siSampleRate using pointer failed\n")); tempF = 0; PrintDeviceInfo( siSampleRate, tempF ); PRINT(("Attempt to set siSampleRate to 22050 using pointer method.\n")); tempF = ((unsigned long)22050) << 16; err = SPBSetDeviceInfo(mRefNum, siSampleRate, (Ptr) &tempF); if (err) PRINT(("setting siSampleRate using pointer failed\n")); tempF = 0; PrintDeviceInfo( siSampleRate, tempF ); #else PRINT(("Attempt to set siSampleRate to 44100 using direct method.\n")); err = SPBSetDeviceInfo(mRefNum, siSampleRate, (Ptr) (((unsigned long)44100) << 16)); if (err) PRINT(("setting siSampleRate using direct failed\n")); PrintDeviceInfo( siSampleRate, tempF ); PRINT(("Attempt to set siSampleRate to 22050 using direct method.\n")); err = SPBSetDeviceInfo(mRefNum, siSampleRate, (Ptr) (((unsigned long)44100) << 16)); if (err) PRINT(("setting siSampleRate using direct failed\n")); PrintDeviceInfo( siSampleRate, tempF ); #endif /* All done so close up device. */ if( mRefNum ) SPBCloseDevice(mRefNum); return 0; error: if( mRefNum ) SPBCloseDevice(mRefNum); return -1; } \ No newline at end of file +/* + * Test calling SPBSetDeviceInfo() + * Should small parameters less than 4 bytes long be passed through a pointer, or directly? + * + * According to an Applet TechNote at: + * http://developer.apple.com/technotes/tn/tn1048.html + * + * ------------- begin quote -------------- + * Trouble with Void Pointers + * The SetSoundOutputInfo, SndSetInfo, and SPBSetDeviceInfo all take a void* as their last parameter. + * Because the last parameter of these calls is a void*, it looks as if you need to pass a pointer + * to the value you are setting, but this is not the case if what you are passing is 4 bytes or + * less in size. If you are passing a parameter that is larger than four bytes, you must pass a + * pointer to it. + * + * If you are calling GetSoundOutputInfo, SndGetInfo, or SPBGetDeviceInfo and + * it is returning a value that is 4 bytes in size or less, it does not return a pointer to + * that value, it just returns the value. + * ------------ end quote ------------------ + * + * But my experiments on a PowerComputing Mac clone running Mac OS 8.1 indicate that + * the TechNote is wrong and that a pointer should be passed to SPBSetDeviceInfo. + * + * Author: Phil Burk + * Copyright 2000 Phil Burk + * This code may be used freely for any purpose. + */ +#include +#include +#include +#include +#include +/* Mac specific includes */ +#include "OSUtils.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* Change this to 0 or 1 to use the direct parameter method, or the indirect pointer method. */ +#define USE_POINTER (1) +/* Debugging output macros. */ +#define PRINT(x) { printf x; fflush(stdout); } +#define ERR_RPT(x) PRINT(x) +#define DBUG(x) PRINT(x) +static int TestSettingDeviceInfo( const unsigned char *deviceName ); +int main( void ); +int main( void ) +{ + unsigned char noname = 0; + int result = TestSettingDeviceInfo( (const unsigned char *) &noname ); + PRINT(("Test complete. result = %d\n", result )); + return 0; +} +/************************************************************************* +** TestSettingDeviceInfo() +** Query information about a named input device. +*/ +static int TestSettingDeviceInfo( const unsigned char *deviceName ) +{ + OSErr err; + long mRefNum = 0; + long tempL; + short tempS; + Fixed tempF; + + err = SPBOpenDevice( deviceName, siWritePermission, &mRefNum); + if (err) + { + PRINT(("Cound not open device!\n")); + return -1; + } + +/* Define macros for printing out device info. */ +#define PrintDeviceInfo(selector,var) \ + err = SPBGetDeviceInfo(mRefNum, selector, (Ptr) &var); \ + if (err) { \ + PRINT(("query %s failed\n", #selector )); \ + }\ + else { \ + PRINT(("query %s = 0x%x\n", #selector, var )); \ + } + + PrintDeviceInfo( siContinuous, tempS ); + PrintDeviceInfo( siAsync, tempS ); + PrintDeviceInfo( siNumberChannels, tempS ); + PrintDeviceInfo( siSampleSize, tempS ); + PrintDeviceInfo( siSampleRate, tempF ); + PrintDeviceInfo( siChannelAvailable, tempS ); + PrintDeviceInfo( siActiveChannels, tempL ); + PrintDeviceInfo( siDeviceBufferInfo, tempL ); +#if USE_POINTER +/* Continuous Mode ---------- */ + PRINT(("Attempt to set siContinuous to 1 using pointer method.\n")); + tempS = 1; + err = SPBSetDeviceInfo(mRefNum, siContinuous, (Ptr) &tempS); + if (err) PRINT(("setting siContinuous using pointer failed\n")); + PrintDeviceInfo( siContinuous, tempS ); + PRINT(("Attempt to set siContinuous to 0 using pointer method.\n")); + tempS = 1; + err = SPBSetDeviceInfo(mRefNum, siContinuous, (Ptr) &tempS); + if (err) PRINT(("setting siContinuous using pointer failed\n")); + PrintDeviceInfo( siContinuous, tempS ); +#else + PRINT(("Attempt to set siContinuous to 1 using direct method.\n")); + err = SPBSetDeviceInfo(mRefNum, siContinuous, (Ptr) 1); + if (err) PRINT(("setting siContinuous using direct failed\n")); + PrintDeviceInfo( siContinuous, tempS ); + + PRINT(("Attempt to set siContinuous to 0 using direct method.\n")); + err = SPBSetDeviceInfo(mRefNum, siContinuous, (Ptr) 0); + if (err) PRINT(("setting siContinuous using direct failed\n")); + PrintDeviceInfo( siContinuous, tempS ); +#endif +/* Sample rate ----------- */ +#if USE_POINTER + PRINT(("Attempt to set siSampleRate to 44100 using pointer method.\n")); + tempF = ((unsigned long)44100) << 16; + err = SPBSetDeviceInfo(mRefNum, siSampleRate, (Ptr) &tempF); + if (err) PRINT(("setting siSampleRate using pointer failed\n")); + tempF = 0; + PrintDeviceInfo( siSampleRate, tempF ); + + PRINT(("Attempt to set siSampleRate to 22050 using pointer method.\n")); + tempF = ((unsigned long)22050) << 16; + err = SPBSetDeviceInfo(mRefNum, siSampleRate, (Ptr) &tempF); + if (err) PRINT(("setting siSampleRate using pointer failed\n")); + tempF = 0; + PrintDeviceInfo( siSampleRate, tempF ); +#else + PRINT(("Attempt to set siSampleRate to 44100 using direct method.\n")); + err = SPBSetDeviceInfo(mRefNum, siSampleRate, (Ptr) (((unsigned long)44100) << 16)); + if (err) PRINT(("setting siSampleRate using direct failed\n")); + PrintDeviceInfo( siSampleRate, tempF ); + + PRINT(("Attempt to set siSampleRate to 22050 using direct method.\n")); + err = SPBSetDeviceInfo(mRefNum, siSampleRate, (Ptr) (((unsigned long)44100) << 16)); + if (err) PRINT(("setting siSampleRate using direct failed\n")); + PrintDeviceInfo( siSampleRate, tempF ); +#endif +/* All done so close up device. */ + if( mRefNum ) SPBCloseDevice(mRefNum); + return 0; + +error: + if( mRefNum ) SPBCloseDevice(mRefNum); + return -1; +} \ No newline at end of file diff --git a/lib-src/portaudio/winproj/PAStaticDS/PAStaticDS.dsp b/lib-src/portaudio/winproj/PAStaticDS/PAStaticDS.dsp index 99613f9b1..d81e125da 100644 --- a/lib-src/portaudio/winproj/PAStaticDS/PAStaticDS.dsp +++ b/lib-src/portaudio/winproj/PAStaticDS/PAStaticDS.dsp @@ -1,232 +1,232 @@ -# Microsoft Developer Studio Project File - Name="PAStaticDS" - Package Owner=<4> - -# Microsoft Developer Studio Generated Build File, Format Version 6.00 - -# ** DO NOT EDIT ** - - - -# TARGTYPE "Win32 (x86) Static Library" 0x0104 - - - -CFG=PAStaticDS - Win32 Debug - -!MESSAGE This is not a valid makefile. To build this project using NMAKE, - -!MESSAGE use the Export Makefile command and run - -!MESSAGE - -!MESSAGE NMAKE /f "PAStaticDS.mak". - -!MESSAGE - -!MESSAGE You can specify a configuration when running NMAKE - -!MESSAGE by defining the macro CFG on the command line. For example: - -!MESSAGE - -!MESSAGE NMAKE /f "PAStaticDS.mak" CFG="PAStaticDS - Win32 Debug" - -!MESSAGE - -!MESSAGE Possible choices for configuration are: - -!MESSAGE - -!MESSAGE "PAStaticDS - Win32 Release" (based on "Win32 (x86) Static Library") - -!MESSAGE "PAStaticDS - Win32 Debug" (based on "Win32 (x86) Static Library") - -!MESSAGE - - - -# Begin Project - -# PROP AllowPerConfigDependencies 0 - -# PROP Scc_ProjName "" - -# PROP Scc_LocalPath "" - -CPP=cl.exe - -RSC=rc.exe - - - -!IF "$(CFG)" == "PAStaticDS - Win32 Release" - - - -# PROP BASE Use_MFC 0 - -# PROP BASE Use_Debug_Libraries 0 - -# PROP BASE Output_Dir "Release" - -# PROP BASE Intermediate_Dir "Release" - -# PROP BASE Target_Dir "" - -# PROP Use_MFC 0 - -# PROP Use_Debug_Libraries 0 - -# PROP Output_Dir "Release" - -# PROP Intermediate_Dir "Release" - -# PROP Target_Dir "" - -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c - -# ADD CPP /nologo /W3 /GX /O2 /I "../../pa_common" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c - -# ADD BASE RSC /l 0x408 /d "NDEBUG" - -# ADD RSC /l 0x408 /d "NDEBUG" - -BSC32=bscmake.exe - -# ADD BASE BSC32 /nologo - -# ADD BSC32 /nologo - -LIB32=link.exe -lib - -# ADD BASE LIB32 /nologo - -# ADD LIB32 /nologo /out:"../Lib/PAStaticDS.lib" - - - -!ELSEIF "$(CFG)" == "PAStaticDS - Win32 Debug" - - - -# PROP BASE Use_MFC 0 - -# PROP BASE Use_Debug_Libraries 1 - -# PROP BASE Output_Dir "Debug" - -# PROP BASE Intermediate_Dir "Debug" - -# PROP BASE Target_Dir "" - -# PROP Use_MFC 0 - -# PROP Use_Debug_Libraries 1 - -# PROP Output_Dir "Debug" - -# PROP Intermediate_Dir "Debug" - -# PROP Target_Dir "" - -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c - -# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../../pa_common" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c - -# ADD BASE RSC /l 0x408 /d "_DEBUG" - -# ADD RSC /l 0x408 /d "_DEBUG" - -BSC32=bscmake.exe - -# ADD BASE BSC32 /nologo - -# ADD BSC32 /nologo - -LIB32=link.exe -lib - -# ADD BASE LIB32 /nologo - -# ADD LIB32 /nologo /out:"../Lib/PAStaticDSD.lib" - - - -!ENDIF - - - -# Begin Target - - - -# Name "PAStaticDS - Win32 Release" - -# Name "PAStaticDS - Win32 Debug" - -# Begin Group "Source Files" - - - -# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" - -# Begin Source File - - - -SOURCE=..\..\pa_win_ds\dsound_wrapper.c - -# End Source File - -# Begin Source File - - - -SOURCE=..\..\pa_win_ds\pa_dsound.c - -# End Source File - -# Begin Source File - - - -SOURCE=..\..\pa_common\pa_lib.c - -# End Source File - -# End Group - -# Begin Group "Header Files" - - - -# PROP Default_Filter "h;hpp;hxx;hm;inl" - -# Begin Source File - - - -SOURCE=..\..\pa_win_ds\dsound_wrapper.h - -# End Source File - -# Begin Source File - - - -SOURCE=..\..\pa_common\pa_host.h - -# End Source File - -# Begin Source File - - - -SOURCE=..\..\pa_common\portaudio.h - -# End Source File - -# End Group - -# End Target - -# End Project - +# Microsoft Developer Studio Project File - Name="PAStaticDS" - Package Owner=<4> + +# Microsoft Developer Studio Generated Build File, Format Version 6.00 + +# ** DO NOT EDIT ** + + + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + + + +CFG=PAStaticDS - Win32 Debug + +!MESSAGE This is not a valid makefile. To build this project using NMAKE, + +!MESSAGE use the Export Makefile command and run + +!MESSAGE + +!MESSAGE NMAKE /f "PAStaticDS.mak". + +!MESSAGE + +!MESSAGE You can specify a configuration when running NMAKE + +!MESSAGE by defining the macro CFG on the command line. For example: + +!MESSAGE + +!MESSAGE NMAKE /f "PAStaticDS.mak" CFG="PAStaticDS - Win32 Debug" + +!MESSAGE + +!MESSAGE Possible choices for configuration are: + +!MESSAGE + +!MESSAGE "PAStaticDS - Win32 Release" (based on "Win32 (x86) Static Library") + +!MESSAGE "PAStaticDS - Win32 Debug" (based on "Win32 (x86) Static Library") + +!MESSAGE + + + +# Begin Project + +# PROP AllowPerConfigDependencies 0 + +# PROP Scc_ProjName "" + +# PROP Scc_LocalPath "" + +CPP=cl.exe + +RSC=rc.exe + + + +!IF "$(CFG)" == "PAStaticDS - Win32 Release" + + + +# PROP BASE Use_MFC 0 + +# PROP BASE Use_Debug_Libraries 0 + +# PROP BASE Output_Dir "Release" + +# PROP BASE Intermediate_Dir "Release" + +# PROP BASE Target_Dir "" + +# PROP Use_MFC 0 + +# PROP Use_Debug_Libraries 0 + +# PROP Output_Dir "Release" + +# PROP Intermediate_Dir "Release" + +# PROP Target_Dir "" + +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c + +# ADD CPP /nologo /W3 /GX /O2 /I "../../pa_common" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c + +# ADD BASE RSC /l 0x408 /d "NDEBUG" + +# ADD RSC /l 0x408 /d "NDEBUG" + +BSC32=bscmake.exe + +# ADD BASE BSC32 /nologo + +# ADD BSC32 /nologo + +LIB32=link.exe -lib + +# ADD BASE LIB32 /nologo + +# ADD LIB32 /nologo /out:"../Lib/PAStaticDS.lib" + + + +!ELSEIF "$(CFG)" == "PAStaticDS - Win32 Debug" + + + +# PROP BASE Use_MFC 0 + +# PROP BASE Use_Debug_Libraries 1 + +# PROP BASE Output_Dir "Debug" + +# PROP BASE Intermediate_Dir "Debug" + +# PROP BASE Target_Dir "" + +# PROP Use_MFC 0 + +# PROP Use_Debug_Libraries 1 + +# PROP Output_Dir "Debug" + +# PROP Intermediate_Dir "Debug" + +# PROP Target_Dir "" + +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c + +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../../pa_common" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c + +# ADD BASE RSC /l 0x408 /d "_DEBUG" + +# ADD RSC /l 0x408 /d "_DEBUG" + +BSC32=bscmake.exe + +# ADD BASE BSC32 /nologo + +# ADD BSC32 /nologo + +LIB32=link.exe -lib + +# ADD BASE LIB32 /nologo + +# ADD LIB32 /nologo /out:"../Lib/PAStaticDSD.lib" + + + +!ENDIF + + + +# Begin Target + + + +# Name "PAStaticDS - Win32 Release" + +# Name "PAStaticDS - Win32 Debug" + +# Begin Group "Source Files" + + + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" + +# Begin Source File + + + +SOURCE=..\..\pa_win_ds\dsound_wrapper.c + +# End Source File + +# Begin Source File + + + +SOURCE=..\..\pa_win_ds\pa_dsound.c + +# End Source File + +# Begin Source File + + + +SOURCE=..\..\pa_common\pa_lib.c + +# End Source File + +# End Group + +# Begin Group "Header Files" + + + +# PROP Default_Filter "h;hpp;hxx;hm;inl" + +# Begin Source File + + + +SOURCE=..\..\pa_win_ds\dsound_wrapper.h + +# End Source File + +# Begin Source File + + + +SOURCE=..\..\pa_common\pa_host.h + +# End Source File + +# Begin Source File + + + +SOURCE=..\..\pa_common\portaudio.h + +# End Source File + +# End Group + +# End Target + +# End Project + diff --git a/lib-src/portaudio/winproj/PAStaticWMME/PAStaticWMME.vcproj b/lib-src/portaudio/winproj/PAStaticWMME/PAStaticWMME.vcproj index e64d56da7..ca0dd9735 100644 --- a/lib-src/portaudio/winproj/PAStaticWMME/PAStaticWMME.vcproj +++ b/lib-src/portaudio/winproj/PAStaticWMME/PAStaticWMME.vcproj @@ -1,729 +1,729 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib-src/portaudio/winproj/WinVC.dsw b/lib-src/portaudio/winproj/WinVC.dsw index 992a4a955..070aef860 100644 --- a/lib-src/portaudio/winproj/WinVC.dsw +++ b/lib-src/portaudio/winproj/WinVC.dsw @@ -1,82 +1,82 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 - -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - - - -############################################################################### - - - -Project: "PAStaticDS"=.\PAStaticDS\PAStaticDS.dsp - Package Owner=<4> - - - -Package=<5> - -{{{ - -}}} - - - -Package=<4> - -{{{ - -}}} - - - -############################################################################### - - - -Project: "PAStaticWMME"=.\PAStaticWMME\PAStaticWMME.dsp - Package Owner=<4> - - - -Package=<5> - -{{{ - -}}} - - - -Package=<4> - -{{{ - -}}} - - - -############################################################################### - - - -Global: - - - -Package=<5> - -{{{ - -}}} - - - -Package=<3> - -{{{ - -}}} - - - -############################################################################### - - - +Microsoft Developer Studio Workspace File, Format Version 6.00 + +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + + + +############################################################################### + + + +Project: "PAStaticDS"=.\PAStaticDS\PAStaticDS.dsp - Package Owner=<4> + + + +Package=<5> + +{{{ + +}}} + + + +Package=<4> + +{{{ + +}}} + + + +############################################################################### + + + +Project: "PAStaticWMME"=.\PAStaticWMME\PAStaticWMME.dsp - Package Owner=<4> + + + +Package=<5> + +{{{ + +}}} + + + +Package=<4> + +{{{ + +}}} + + + +############################################################################### + + + +Global: + + + +Package=<5> + +{{{ + +}}} + + + +Package=<3> + +{{{ + +}}} + + + +############################################################################### + + + diff --git a/lib-src/portmidi/pm_test/latency-VC9.vcproj b/lib-src/portmidi/pm_test/latency-VC9.vcproj index 28dcfd5cc..b5659431e 100644 --- a/lib-src/portmidi/pm_test/latency-VC9.vcproj +++ b/lib-src/portmidi/pm_test/latency-VC9.vcproj @@ -1,212 +1,212 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib-src/portmidi/pm_test/latency.vcproj b/lib-src/portmidi/pm_test/latency.vcproj index d465df89a..776bc563e 100644 --- a/lib-src/portmidi/pm_test/latency.vcproj +++ b/lib-src/portmidi/pm_test/latency.vcproj @@ -1,443 +1,443 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib-src/portmidi/pm_test/midithread-VC9.vcproj b/lib-src/portmidi/pm_test/midithread-VC9.vcproj index 467797dc1..99ab82310 100644 --- a/lib-src/portmidi/pm_test/midithread-VC9.vcproj +++ b/lib-src/portmidi/pm_test/midithread-VC9.vcproj @@ -1,211 +1,211 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib-src/portmidi/pm_test/midithread.vcproj b/lib-src/portmidi/pm_test/midithread.vcproj index f2412998b..42d8f3e9e 100644 --- a/lib-src/portmidi/pm_test/midithread.vcproj +++ b/lib-src/portmidi/pm_test/midithread.vcproj @@ -1,441 +1,441 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib-src/portmidi/pm_test/midithru-VC9.vcproj b/lib-src/portmidi/pm_test/midithru-VC9.vcproj index c4b8f6ac3..d70912508 100644 --- a/lib-src/portmidi/pm_test/midithru-VC9.vcproj +++ b/lib-src/portmidi/pm_test/midithru-VC9.vcproj @@ -1,212 +1,212 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib-src/portmidi/pm_test/midithru.vcproj b/lib-src/portmidi/pm_test/midithru.vcproj index b6d97a6c1..8ddfc3a0d 100644 --- a/lib-src/portmidi/pm_test/midithru.vcproj +++ b/lib-src/portmidi/pm_test/midithru.vcproj @@ -1,442 +1,442 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib-src/portmidi/pm_test/mm-VC9.vcproj b/lib-src/portmidi/pm_test/mm-VC9.vcproj index a95b6a9af..9a0419131 100644 --- a/lib-src/portmidi/pm_test/mm-VC9.vcproj +++ b/lib-src/portmidi/pm_test/mm-VC9.vcproj @@ -1,213 +1,213 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib-src/portmidi/pm_test/mm.vcproj b/lib-src/portmidi/pm_test/mm.vcproj index 227da901a..279a63450 100644 --- a/lib-src/portmidi/pm_test/mm.vcproj +++ b/lib-src/portmidi/pm_test/mm.vcproj @@ -1,445 +1,445 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib-src/portmidi/pm_test/qtest-VC9.vcproj b/lib-src/portmidi/pm_test/qtest-VC9.vcproj index e2fa5950d..4ccc1a129 100644 --- a/lib-src/portmidi/pm_test/qtest-VC9.vcproj +++ b/lib-src/portmidi/pm_test/qtest-VC9.vcproj @@ -1,186 +1,186 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib-src/portmidi/pm_test/qtest.vcproj b/lib-src/portmidi/pm_test/qtest.vcproj index 713726169..0e9b4648b 100644 --- a/lib-src/portmidi/pm_test/qtest.vcproj +++ b/lib-src/portmidi/pm_test/qtest.vcproj @@ -1,356 +1,356 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib-src/portmidi/pm_test/sysex-VC9.vcproj b/lib-src/portmidi/pm_test/sysex-VC9.vcproj index 332715cfc..b2d90ab4b 100644 --- a/lib-src/portmidi/pm_test/sysex-VC9.vcproj +++ b/lib-src/portmidi/pm_test/sysex-VC9.vcproj @@ -1,212 +1,212 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib-src/portmidi/pm_test/sysex.vcproj b/lib-src/portmidi/pm_test/sysex.vcproj index c437fb4f0..76a74c5d9 100644 --- a/lib-src/portmidi/pm_test/sysex.vcproj +++ b/lib-src/portmidi/pm_test/sysex.vcproj @@ -1,443 +1,443 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib-src/portmidi/pm_test/test-VC9.vcproj b/lib-src/portmidi/pm_test/test-VC9.vcproj index 54e98828b..a341de9b5 100644 --- a/lib-src/portmidi/pm_test/test-VC9.vcproj +++ b/lib-src/portmidi/pm_test/test-VC9.vcproj @@ -1,220 +1,220 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib-src/portmidi/pm_test/test.vcproj b/lib-src/portmidi/pm_test/test.vcproj index b247cd824..791e2a773 100644 --- a/lib-src/portmidi/pm_test/test.vcproj +++ b/lib-src/portmidi/pm_test/test.vcproj @@ -1,448 +1,448 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib-src/portmidi/portmidi-VC9.vcproj b/lib-src/portmidi/portmidi-VC9.vcproj index 66e376cc9..5580ecab8 100644 --- a/lib-src/portmidi/portmidi-VC9.vcproj +++ b/lib-src/portmidi/portmidi-VC9.vcproj @@ -1,206 +1,206 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib-src/portmidi/portmidi.vcproj b/lib-src/portmidi/portmidi.vcproj index d1d05321a..83ddc9272 100644 --- a/lib-src/portmidi/portmidi.vcproj +++ b/lib-src/portmidi/portmidi.vcproj @@ -1,306 +1,306 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib-src/portmidi/porttime/porttime-VC9.vcproj b/lib-src/portmidi/porttime/porttime-VC9.vcproj index 5bf2c5a48..929533a2d 100644 --- a/lib-src/portmidi/porttime/porttime-VC9.vcproj +++ b/lib-src/portmidi/porttime/porttime-VC9.vcproj @@ -1,184 +1,184 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib-src/portmidi/porttime/porttime.dsp b/lib-src/portmidi/porttime/porttime.dsp index 2771842af..364373c97 100644 --- a/lib-src/portmidi/porttime/porttime.dsp +++ b/lib-src/portmidi/porttime/porttime.dsp @@ -1,104 +1,104 @@ -# Microsoft Developer Studio Project File - Name="porttime" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Static Library" 0x0104 - -CFG=porttime - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "porttime.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "porttime.mak" CFG="porttime - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "porttime - Win32 Release" (based on "Win32 (x86) Static Library") -!MESSAGE "porttime - Win32 Debug" (based on "Win32 (x86) Static Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "porttime - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c -# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LIB32=link.exe -lib -# ADD BASE LIB32 /nologo -# ADD LIB32 /nologo - -!ELSEIF "$(CFG)" == "porttime - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c -# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "_LIB" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "USE_DLL_FOR_CLEANUP" /YX /FD /GZ /c -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LIB32=link.exe -lib -# ADD BASE LIB32 /nologo -# ADD LIB32 /nologo - -!ENDIF - -# Begin Target - -# Name "porttime - Win32 Release" -# Name "porttime - Win32 Debug" -# Begin Group "Source Files" - -# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" -# Begin Source File - -SOURCE=.\porttime.c -# End Source File -# Begin Source File - -SOURCE=.\ptwinmm.c -# End Source File -# End Group -# Begin Group "Header Files" - -# PROP Default_Filter "h;hpp;hxx;hm;inl" -# Begin Source File - -SOURCE=.\porttime.h -# End Source File -# End Group -# End Target -# End Project +# Microsoft Developer Studio Project File - Name="porttime" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=porttime - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "porttime.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "porttime.mak" CFG="porttime - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "porttime - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "porttime - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "porttime - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "porttime - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "_LIB" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "USE_DLL_FOR_CLEANUP" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "porttime - Win32 Release" +# Name "porttime - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\porttime.c +# End Source File +# Begin Source File + +SOURCE=.\ptwinmm.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\porttime.h +# End Source File +# End Group +# End Target +# End Project diff --git a/lib-src/portmidi/porttime/porttime.vcproj b/lib-src/portmidi/porttime/porttime.vcproj index cd9a5bd96..c126a8ba8 100644 --- a/lib-src/portmidi/porttime/porttime.vcproj +++ b/lib-src/portmidi/porttime/porttime.vcproj @@ -1,406 +1,406 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib-src/portmixer/LICENSE.txt b/lib-src/portmixer/LICENSE.txt index 99f1a5379..2039f9ed3 100644 --- a/lib-src/portmixer/LICENSE.txt +++ b/lib-src/portmixer/LICENSE.txt @@ -1,75 +1,75 @@ -Portable header file to contain: -/* - * PortMixer - * PortMixer API Header File - * - * Copyright (c) 2002 - * - * Written by Dominic Mazzoni - * - * PortMixer is intended to work side-by-side with PortAudio, - * the Portable Real-Time Audio Library by Ross Bencina and - * Phil Burk. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * Any person wishing to distribute modifications to the Software is - * requested to send the modifications to the original developer so that - * they can be incorporated into the canonical version. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -Implementation files to contain: -/* - * PortMixer - * Implementation - * - * - * - * - * - * PortMixer is intended to work side-by-side with PortAudio, - * the Portable Real-Time Audio Library by Ross Bencina and - * Phil Burk. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * Any person wishing to distribute modifications to the Software is - * requested to send the modifications to the original developer so that - * they can be incorporated into the canonical version. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ +Portable header file to contain: +/* + * PortMixer + * PortMixer API Header File + * + * Copyright (c) 2002 + * + * Written by Dominic Mazzoni + * + * PortMixer is intended to work side-by-side with PortAudio, + * the Portable Real-Time Audio Library by Ross Bencina and + * Phil Burk. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +Implementation files to contain: +/* + * PortMixer + * Implementation + * + * + * + * + * + * PortMixer is intended to work side-by-side with PortAudio, + * the Portable Real-Time Audio Library by Ross Bencina and + * Phil Burk. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ diff --git a/lib-src/portmixer/px_tests/px_test.c b/lib-src/portmixer/px_tests/px_test.c old mode 100755 new mode 100644 diff --git a/lib-src/portmixer/src/px_win_endpoint.c b/lib-src/portmixer/src/px_win_endpoint.c old mode 100755 new mode 100644 diff --git a/lib-src/portmixer/src/px_win_endpoint.h b/lib-src/portmixer/src/px_win_endpoint.h old mode 100755 new mode 100644 diff --git a/lib-src/portsmf/portsmf.vcproj b/lib-src/portsmf/portsmf.vcproj index efb1e3d16..8f6d864e8 100644 --- a/lib-src/portsmf/portsmf.vcproj +++ b/lib-src/portsmf/portsmf.vcproj @@ -1,214 +1,214 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib-src/redland/librdf/win32/librdf.vcproj b/lib-src/redland/librdf/win32/librdf.vcproj index 39b105034..cee713514 100644 --- a/lib-src/redland/librdf/win32/librdf.vcproj +++ b/lib-src/redland/librdf/win32/librdf.vcproj @@ -1,325 +1,325 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib-src/redland/raptor/win32/raptortest.cpp b/lib-src/redland/raptor/win32/raptortest.cpp index 1c6b825cf..f2792dfe4 100644 --- a/lib-src/redland/raptor/win32/raptortest.cpp +++ b/lib-src/redland/raptor/win32/raptortest.cpp @@ -1,82 +1,82 @@ -// raptortest.cpp : Defines the entry point for the console application. -// - -#include -#include -#include "..\raptor.h" - -#define TIMEIT -#define DUMPIT - -int nStmts = 0; - -void dump_statement(void* user_data, const raptor_statement *statement) -{ - nStmts++; -#ifdef DUMPIT - printf("%li, [%s, ", nStmts, statement->subject); - - if(statement->predicate_type == RAPTOR_PREDICATE_TYPE_ORDINAL) - printf("[rdf:_%d]", *((int*)statement->predicate)); - else if(statement->predicate_type == RAPTOR_PREDICATE_TYPE_XML_NAME) - printf("%s", (const char*)statement->predicate); - else - printf("[%s]", (const char*)statement->predicate); - - if(statement->object_type == RAPTOR_OBJECT_TYPE_LITERAL || - statement->object_type == RAPTOR_OBJECT_TYPE_XML_LITERAL) - printf(", \"%s\"]", (const char*)statement->object); - else if(statement->object_type == RAPTOR_OBJECT_TYPE_XML_NAME) - printf(", %s]", (const char*)statement->object); - else - printf(", %s]", statement->object); - - printf("\n"); -#endif -} - -void usage() -{ - printf("Usage: raptortest \nE.g. file:c:\\test.rdf\n"); -} - -int main(int argc, char* argv[]) -{ - if (argc != 2) - { - usage(); - return -1; - } - - - raptor_init(); - - raptor_parser* p = raptor_new(""); - - raptor_set_statement_handler(p, NULL, dump_statement); - -#ifdef TIMEIT - LARGE_INTEGER Start; - QueryPerformanceCounter(&Start); -#endif - raptor_parse_file(p, argv[1], NULL); - -#ifdef TIMEIT - LARGE_INTEGER End; - QueryPerformanceCounter(&End); - LARGE_INTEGER Frec; - QueryPerformanceFrequency(&Frec); - double Total = (End.LowPart-Start.LowPart); - double StmtsPer = Total/nStmts; - - printf("%li statments processed in %g t. %g t/stmts, %li t/s, %g stmts/s", nStmts, Total, StmtsPer, Frec.LowPart, (double)Frec.LowPart/StmtsPer); -#endif - - raptor_free(p); - - raptor_finish(); - - return 0; -} - - +// raptortest.cpp : Defines the entry point for the console application. +// + +#include +#include +#include "..\raptor.h" + +#define TIMEIT +#define DUMPIT + +int nStmts = 0; + +void dump_statement(void* user_data, const raptor_statement *statement) +{ + nStmts++; +#ifdef DUMPIT + printf("%li, [%s, ", nStmts, statement->subject); + + if(statement->predicate_type == RAPTOR_PREDICATE_TYPE_ORDINAL) + printf("[rdf:_%d]", *((int*)statement->predicate)); + else if(statement->predicate_type == RAPTOR_PREDICATE_TYPE_XML_NAME) + printf("%s", (const char*)statement->predicate); + else + printf("[%s]", (const char*)statement->predicate); + + if(statement->object_type == RAPTOR_OBJECT_TYPE_LITERAL || + statement->object_type == RAPTOR_OBJECT_TYPE_XML_LITERAL) + printf(", \"%s\"]", (const char*)statement->object); + else if(statement->object_type == RAPTOR_OBJECT_TYPE_XML_NAME) + printf(", %s]", (const char*)statement->object); + else + printf(", %s]", statement->object); + + printf("\n"); +#endif +} + +void usage() +{ + printf("Usage: raptortest \nE.g. file:c:\\test.rdf\n"); +} + +int main(int argc, char* argv[]) +{ + if (argc != 2) + { + usage(); + return -1; + } + + + raptor_init(); + + raptor_parser* p = raptor_new(""); + + raptor_set_statement_handler(p, NULL, dump_statement); + +#ifdef TIMEIT + LARGE_INTEGER Start; + QueryPerformanceCounter(&Start); +#endif + raptor_parse_file(p, argv[1], NULL); + +#ifdef TIMEIT + LARGE_INTEGER End; + QueryPerformanceCounter(&End); + LARGE_INTEGER Frec; + QueryPerformanceFrequency(&Frec); + double Total = (End.LowPart-Start.LowPart); + double StmtsPer = Total/nStmts; + + printf("%li statments processed in %g t. %g t/stmts, %li t/s, %g stmts/s", nStmts, Total, StmtsPer, Frec.LowPart, (double)Frec.LowPart/StmtsPer); +#endif + + raptor_free(p); + + raptor_finish(); + + return 0; +} + + diff --git a/lib-src/redland/rasqal/tests/rdql/testsuite/README-RDQL-tests.txt b/lib-src/redland/rasqal/tests/rdql/testsuite/README-RDQL-tests.txt index 01643c606..6508f9761 100644 --- a/lib-src/redland/rasqal/tests/rdql/testsuite/README-RDQL-tests.txt +++ b/lib-src/redland/rasqal/tests/rdql/testsuite/README-RDQL-tests.txt @@ -1,23 +1,23 @@ -This is the RDQL/Jena test suite from the Jena distribution. -The URI for RDQL is http://jena.hpl.hp.com/2003/07/query/RDQL. - -It is provided so that other implementations of RDQL can get the test suite -without needing the whole Jena distribution and to provide a bookmarkable -resource that "is" the RDQL/Jena test suite - -Contents: - - Documentation: README-RDQL-tests.txt - Manifest file : rdql-tests.n3 - Tests : test-?-?? - Expected results by test : result-?-??.n3 - Input data : model?.* - Data from Jena tutorial (test data): vc-db-?.rdf - -These are also available in the Jena distribution in the testing/RDQL -directory. - -The tests can be run with Jena by: - - java -cp ... jena.rdfquery --test rdql-tests.n3 - +This is the RDQL/Jena test suite from the Jena distribution. +The URI for RDQL is http://jena.hpl.hp.com/2003/07/query/RDQL. + +It is provided so that other implementations of RDQL can get the test suite +without needing the whole Jena distribution and to provide a bookmarkable +resource that "is" the RDQL/Jena test suite + +Contents: + + Documentation: README-RDQL-tests.txt + Manifest file : rdql-tests.n3 + Tests : test-?-?? + Expected results by test : result-?-??.n3 + Input data : model?.* + Data from Jena tutorial (test data): vc-db-?.rdf + +These are also available in the Jena distribution in the testing/RDQL +directory. + +The tests can be run with Jena by: + + java -cp ... jena.rdfquery --test rdql-tests.n3 + diff --git a/lib-src/redland/rasqal/tests/rdql/testsuite/copyright.txt b/lib-src/redland/rasqal/tests/rdql/testsuite/copyright.txt index efe6ed6d4..a09aa5e42 100644 --- a/lib-src/redland/rasqal/tests/rdql/testsuite/copyright.txt +++ b/lib-src/redland/rasqal/tests/rdql/testsuite/copyright.txt @@ -1,26 +1,26 @@ -/* - * (c) Copyright 2000, 2001, 2002, 2003, 2004 Hewlett-Packard Development Company, LP - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +/* + * (c) Copyright 2000, 2001, 2002, 2003, 2004 Hewlett-Packard Development Company, LP + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ diff --git a/lib-src/redland/redland.sln b/lib-src/redland/redland.sln index b5bc8ec52..1bf6646ca 100644 --- a/lib-src/redland/redland.sln +++ b/lib-src/redland/redland.sln @@ -1,74 +1,74 @@ -Microsoft Visual Studio Solution File, Format Version 8.00 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rasqal", "rasqal\win32\rasqal.vcproj", "{B72BB9A4-C889-4242-8188-34133944DC65}" - ProjectSection(ProjectDependencies) = postProject - {D24FB457-A295-4237-8D5E-92ACBBA10139} = {D24FB457-A295-4237-8D5E-92ACBBA10139} - {F48C108E-B937-4D8C-A308-9C257C5D0D3D} = {F48C108E-B937-4D8C-A308-9C257C5D0D3D} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "librdf", "librdf\win32\librdf.vcproj", "{2EF6F83E-DACB-4958-B0C0-A9F34476127A}" - ProjectSection(ProjectDependencies) = postProject - {B72BB9A4-C889-4242-8188-34133944DC65} = {B72BB9A4-C889-4242-8188-34133944DC65} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rapper", "raptor\win32\rapper.vcproj", "{1FFF7A31-D1A9-4516-AB07-4D415ABAB733}" - ProjectSection(ProjectDependencies) = postProject - {F48C108E-B937-4D8C-A308-9C257C5D0D3D} = {F48C108E-B937-4D8C-A308-9C257C5D0D3D} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "raptor", "raptor\win32\raptor.vcproj", "{F48C108E-B937-4D8C-A308-9C257C5D0D3D}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "curllib", "..\curl-7.13.2\lib\curllib.vcproj", "{59ED01CF-49C8-42C5-846F-AAF0A5F3B437}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "roqet", "rasqal\win32\roqet.vcproj", "{143A879E-BD81-4EF4-88EE-851D978304FE}" - ProjectSection(ProjectDependencies) = postProject - {B72BB9A4-C889-4242-8188-34133944DC65} = {B72BB9A4-C889-4242-8188-34133944DC65} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pcre", "..\pcre\6.4\pcre-6.4-src\pcre\pcre.vcproj", "{D24FB457-A295-4237-8D5E-92ACBBA10139}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfiguration) = preSolution - Debug = Debug - Release = Release - EndGlobalSection - GlobalSection(ProjectConfiguration) = postSolution - {B72BB9A4-C889-4242-8188-34133944DC65}.Debug.ActiveCfg = Debug|Win32 - {B72BB9A4-C889-4242-8188-34133944DC65}.Debug.Build.0 = Debug|Win32 - {B72BB9A4-C889-4242-8188-34133944DC65}.Release.ActiveCfg = Release|Win32 - {B72BB9A4-C889-4242-8188-34133944DC65}.Release.Build.0 = Release|Win32 - {2EF6F83E-DACB-4958-B0C0-A9F34476127A}.Debug.ActiveCfg = Debug|Win32 - {2EF6F83E-DACB-4958-B0C0-A9F34476127A}.Debug.Build.0 = Debug|Win32 - {2EF6F83E-DACB-4958-B0C0-A9F34476127A}.Release.ActiveCfg = Release|Win32 - {2EF6F83E-DACB-4958-B0C0-A9F34476127A}.Release.Build.0 = Release|Win32 - {1FFF7A31-D1A9-4516-AB07-4D415ABAB733}.Debug.ActiveCfg = Debug|Win32 - {1FFF7A31-D1A9-4516-AB07-4D415ABAB733}.Debug.Build.0 = Debug|Win32 - {1FFF7A31-D1A9-4516-AB07-4D415ABAB733}.Release.ActiveCfg = Release|Win32 - {1FFF7A31-D1A9-4516-AB07-4D415ABAB733}.Release.Build.0 = Release|Win32 - {F48C108E-B937-4D8C-A308-9C257C5D0D3D}.Debug.ActiveCfg = Debug|Win32 - {F48C108E-B937-4D8C-A308-9C257C5D0D3D}.Debug.Build.0 = Debug|Win32 - {F48C108E-B937-4D8C-A308-9C257C5D0D3D}.Release.ActiveCfg = Release|Win32 - {F48C108E-B937-4D8C-A308-9C257C5D0D3D}.Release.Build.0 = Release|Win32 - {59ED01CF-49C8-42C5-846F-AAF0A5F3B437}.Debug.ActiveCfg = Debug|Win32 - {59ED01CF-49C8-42C5-846F-AAF0A5F3B437}.Debug.Build.0 = Debug|Win32 - {59ED01CF-49C8-42C5-846F-AAF0A5F3B437}.Release.ActiveCfg = Release|Win32 - {59ED01CF-49C8-42C5-846F-AAF0A5F3B437}.Release.Build.0 = Release|Win32 - {143A879E-BD81-4EF4-88EE-851D978304FE}.Debug.ActiveCfg = Debug|Win32 - {143A879E-BD81-4EF4-88EE-851D978304FE}.Debug.Build.0 = Debug|Win32 - {143A879E-BD81-4EF4-88EE-851D978304FE}.Release.ActiveCfg = Release|Win32 - {143A879E-BD81-4EF4-88EE-851D978304FE}.Release.Build.0 = Release|Win32 - {D24FB457-A295-4237-8D5E-92ACBBA10139}.Debug.ActiveCfg = Debug|Win32 - {D24FB457-A295-4237-8D5E-92ACBBA10139}.Debug.Build.0 = Debug|Win32 - {D24FB457-A295-4237-8D5E-92ACBBA10139}.Release.ActiveCfg = Release|Win32 - {D24FB457-A295-4237-8D5E-92ACBBA10139}.Release.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - EndGlobalSection - GlobalSection(ExtensibilityAddIns) = postSolution - EndGlobalSection -EndGlobal +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rasqal", "rasqal\win32\rasqal.vcproj", "{B72BB9A4-C889-4242-8188-34133944DC65}" + ProjectSection(ProjectDependencies) = postProject + {D24FB457-A295-4237-8D5E-92ACBBA10139} = {D24FB457-A295-4237-8D5E-92ACBBA10139} + {F48C108E-B937-4D8C-A308-9C257C5D0D3D} = {F48C108E-B937-4D8C-A308-9C257C5D0D3D} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "librdf", "librdf\win32\librdf.vcproj", "{2EF6F83E-DACB-4958-B0C0-A9F34476127A}" + ProjectSection(ProjectDependencies) = postProject + {B72BB9A4-C889-4242-8188-34133944DC65} = {B72BB9A4-C889-4242-8188-34133944DC65} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rapper", "raptor\win32\rapper.vcproj", "{1FFF7A31-D1A9-4516-AB07-4D415ABAB733}" + ProjectSection(ProjectDependencies) = postProject + {F48C108E-B937-4D8C-A308-9C257C5D0D3D} = {F48C108E-B937-4D8C-A308-9C257C5D0D3D} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "raptor", "raptor\win32\raptor.vcproj", "{F48C108E-B937-4D8C-A308-9C257C5D0D3D}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "curllib", "..\curl-7.13.2\lib\curllib.vcproj", "{59ED01CF-49C8-42C5-846F-AAF0A5F3B437}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "roqet", "rasqal\win32\roqet.vcproj", "{143A879E-BD81-4EF4-88EE-851D978304FE}" + ProjectSection(ProjectDependencies) = postProject + {B72BB9A4-C889-4242-8188-34133944DC65} = {B72BB9A4-C889-4242-8188-34133944DC65} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pcre", "..\pcre\6.4\pcre-6.4-src\pcre\pcre.vcproj", "{D24FB457-A295-4237-8D5E-92ACBBA10139}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {B72BB9A4-C889-4242-8188-34133944DC65}.Debug.ActiveCfg = Debug|Win32 + {B72BB9A4-C889-4242-8188-34133944DC65}.Debug.Build.0 = Debug|Win32 + {B72BB9A4-C889-4242-8188-34133944DC65}.Release.ActiveCfg = Release|Win32 + {B72BB9A4-C889-4242-8188-34133944DC65}.Release.Build.0 = Release|Win32 + {2EF6F83E-DACB-4958-B0C0-A9F34476127A}.Debug.ActiveCfg = Debug|Win32 + {2EF6F83E-DACB-4958-B0C0-A9F34476127A}.Debug.Build.0 = Debug|Win32 + {2EF6F83E-DACB-4958-B0C0-A9F34476127A}.Release.ActiveCfg = Release|Win32 + {2EF6F83E-DACB-4958-B0C0-A9F34476127A}.Release.Build.0 = Release|Win32 + {1FFF7A31-D1A9-4516-AB07-4D415ABAB733}.Debug.ActiveCfg = Debug|Win32 + {1FFF7A31-D1A9-4516-AB07-4D415ABAB733}.Debug.Build.0 = Debug|Win32 + {1FFF7A31-D1A9-4516-AB07-4D415ABAB733}.Release.ActiveCfg = Release|Win32 + {1FFF7A31-D1A9-4516-AB07-4D415ABAB733}.Release.Build.0 = Release|Win32 + {F48C108E-B937-4D8C-A308-9C257C5D0D3D}.Debug.ActiveCfg = Debug|Win32 + {F48C108E-B937-4D8C-A308-9C257C5D0D3D}.Debug.Build.0 = Debug|Win32 + {F48C108E-B937-4D8C-A308-9C257C5D0D3D}.Release.ActiveCfg = Release|Win32 + {F48C108E-B937-4D8C-A308-9C257C5D0D3D}.Release.Build.0 = Release|Win32 + {59ED01CF-49C8-42C5-846F-AAF0A5F3B437}.Debug.ActiveCfg = Debug|Win32 + {59ED01CF-49C8-42C5-846F-AAF0A5F3B437}.Debug.Build.0 = Debug|Win32 + {59ED01CF-49C8-42C5-846F-AAF0A5F3B437}.Release.ActiveCfg = Release|Win32 + {59ED01CF-49C8-42C5-846F-AAF0A5F3B437}.Release.Build.0 = Release|Win32 + {143A879E-BD81-4EF4-88EE-851D978304FE}.Debug.ActiveCfg = Debug|Win32 + {143A879E-BD81-4EF4-88EE-851D978304FE}.Debug.Build.0 = Debug|Win32 + {143A879E-BD81-4EF4-88EE-851D978304FE}.Release.ActiveCfg = Release|Win32 + {143A879E-BD81-4EF4-88EE-851D978304FE}.Release.Build.0 = Release|Win32 + {D24FB457-A295-4237-8D5E-92ACBBA10139}.Debug.ActiveCfg = Debug|Win32 + {D24FB457-A295-4237-8D5E-92ACBBA10139}.Debug.Build.0 = Debug|Win32 + {D24FB457-A295-4237-8D5E-92ACBBA10139}.Release.ActiveCfg = Release|Win32 + {D24FB457-A295-4237-8D5E-92ACBBA10139}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/lib-src/rtaudio/tests/Windows/asio.cpp b/lib-src/rtaudio/tests/Windows/asio.cpp index b241663b3..747b9e858 100644 --- a/lib-src/rtaudio/tests/Windows/asio.cpp +++ b/lib-src/rtaudio/tests/Windows/asio.cpp @@ -1,257 +1,257 @@ -/* - Steinberg Audio Stream I/O API - (c) 1996, Steinberg Soft- und Hardware GmbH - - asio.cpp - - asio functions entries which translate the - asio interface to the asiodrvr class methods -*/ - -#include -#include "asiosys.h" // platform definition -#include "asio.h" - -#if MAC -#include "asiodrvr.h" - -#pragma export on - -AsioDriver *theAsioDriver = 0; - -extern "C" -{ - -long main() -{ - return 'ASIO'; -} - -#elif WINDOWS - -#include "windows.h" -#include "iasiodrv.h" -#include "asiodrivers.h" - -IASIO *theAsioDriver = 0; -extern AsioDrivers *asioDrivers; - -#elif SGI || SUN || BEOS || LINUX -#include "asiodrvr.h" -static AsioDriver *theAsioDriver = 0; -#endif - -//----------------------------------------------------------------------------------------------------- -ASIOError ASIOInit(ASIODriverInfo *info) -{ -#if MAC || SGI || SUN || BEOS || LINUX - if(theAsioDriver) - { - delete theAsioDriver; - theAsioDriver = 0; - } - info->driverVersion = 0; - strcpy(info->name, "No ASIO Driver"); - theAsioDriver = getDriver(); - if(!theAsioDriver) - { - strcpy(info->errorMessage, "Not enough memory for the ASIO driver!"); - return ASE_NotPresent; - } - if(!theAsioDriver->init(info->sysRef)) - { - theAsioDriver->getErrorMessage(info->errorMessage); - delete theAsioDriver; - theAsioDriver = 0; - return ASE_NotPresent; - } - strcpy(info->errorMessage, "No ASIO Driver Error"); - theAsioDriver->getDriverName(info->name); - info->driverVersion = theAsioDriver->getDriverVersion(); - return ASE_OK; - -#else - - info->driverVersion = 0; - strcpy(info->name, "No ASIO Driver"); - if(theAsioDriver) // must be loaded! - { - if(!theAsioDriver->init(info->sysRef)) - { - theAsioDriver->getErrorMessage(info->errorMessage); - theAsioDriver = 0; - return ASE_NotPresent; - } - - strcpy(info->errorMessage, "No ASIO Driver Error"); - theAsioDriver->getDriverName(info->name); - info->driverVersion = theAsioDriver->getDriverVersion(); - return ASE_OK; - } - return ASE_NotPresent; - -#endif // !MAC -} - -ASIOError ASIOExit(void) -{ - if(theAsioDriver) - { -#if WINDOWS - asioDrivers->removeCurrentDriver(); -#else - delete theAsioDriver; -#endif - } - theAsioDriver = 0; - return ASE_OK; -} - -ASIOError ASIOStart(void) -{ - if(!theAsioDriver) - return ASE_NotPresent; - return theAsioDriver->start(); -} - -ASIOError ASIOStop(void) -{ - if(!theAsioDriver) - return ASE_NotPresent; - return theAsioDriver->stop(); -} - -ASIOError ASIOGetChannels(long *numInputChannels, long *numOutputChannels) -{ - if(!theAsioDriver) - { - *numInputChannels = *numOutputChannels = 0; - return ASE_NotPresent; - } - return theAsioDriver->getChannels(numInputChannels, numOutputChannels); -} - -ASIOError ASIOGetLatencies(long *inputLatency, long *outputLatency) -{ - if(!theAsioDriver) - { - *inputLatency = *outputLatency = 0; - return ASE_NotPresent; - } - return theAsioDriver->getLatencies(inputLatency, outputLatency); -} - -ASIOError ASIOGetBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity) -{ - if(!theAsioDriver) - { - *minSize = *maxSize = *preferredSize = *granularity = 0; - return ASE_NotPresent; - } - return theAsioDriver->getBufferSize(minSize, maxSize, preferredSize, granularity); -} - -ASIOError ASIOCanSampleRate(ASIOSampleRate sampleRate) -{ - if(!theAsioDriver) - return ASE_NotPresent; - return theAsioDriver->canSampleRate(sampleRate); -} - -ASIOError ASIOGetSampleRate(ASIOSampleRate *currentRate) -{ - if(!theAsioDriver) - return ASE_NotPresent; - return theAsioDriver->getSampleRate(currentRate); -} - -ASIOError ASIOSetSampleRate(ASIOSampleRate sampleRate) -{ - if(!theAsioDriver) - return ASE_NotPresent; - return theAsioDriver->setSampleRate(sampleRate); -} - -ASIOError ASIOGetClockSources(ASIOClockSource *clocks, long *numSources) -{ - if(!theAsioDriver) - { - *numSources = 0; - return ASE_NotPresent; - } - return theAsioDriver->getClockSources(clocks, numSources); -} - -ASIOError ASIOSetClockSource(long reference) -{ - if(!theAsioDriver) - return ASE_NotPresent; - return theAsioDriver->setClockSource(reference); -} - -ASIOError ASIOGetSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp) -{ - if(!theAsioDriver) - return ASE_NotPresent; - return theAsioDriver->getSamplePosition(sPos, tStamp); -} - -ASIOError ASIOGetChannelInfo(ASIOChannelInfo *info) -{ - if(!theAsioDriver) - { - info->channelGroup = -1; - info->type = ASIOSTInt16MSB; - strcpy(info->name, "None"); - return ASE_NotPresent; - } - return theAsioDriver->getChannelInfo(info); -} - -ASIOError ASIOCreateBuffers(ASIOBufferInfo *bufferInfos, long numChannels, - long bufferSize, ASIOCallbacks *callbacks) -{ - if(!theAsioDriver) - { - ASIOBufferInfo *info = bufferInfos; - for(long i = 0; i < numChannels; i++, info++) - info->buffers[0] = info->buffers[1] = 0; - return ASE_NotPresent; - } - return theAsioDriver->createBuffers(bufferInfos, numChannels, bufferSize, callbacks); -} - -ASIOError ASIODisposeBuffers(void) -{ - if(!theAsioDriver) - return ASE_NotPresent; - return theAsioDriver->disposeBuffers(); -} - -ASIOError ASIOControlPanel(void) -{ - if(!theAsioDriver) - return ASE_NotPresent; - return theAsioDriver->controlPanel(); -} - -ASIOError ASIOFuture(long selector, void *opt) -{ - if(!theAsioDriver) - return ASE_NotPresent; - return theAsioDriver->future(selector, opt); -} - -ASIOError ASIOOutputReady(void) -{ - if(!theAsioDriver) - return ASE_NotPresent; - return theAsioDriver->outputReady(); -} - -#if MAC -} // extern "C" -#pragma export off -#endif - - +/* + Steinberg Audio Stream I/O API + (c) 1996, Steinberg Soft- und Hardware GmbH + + asio.cpp + + asio functions entries which translate the + asio interface to the asiodrvr class methods +*/ + +#include +#include "asiosys.h" // platform definition +#include "asio.h" + +#if MAC +#include "asiodrvr.h" + +#pragma export on + +AsioDriver *theAsioDriver = 0; + +extern "C" +{ + +long main() +{ + return 'ASIO'; +} + +#elif WINDOWS + +#include "windows.h" +#include "iasiodrv.h" +#include "asiodrivers.h" + +IASIO *theAsioDriver = 0; +extern AsioDrivers *asioDrivers; + +#elif SGI || SUN || BEOS || LINUX +#include "asiodrvr.h" +static AsioDriver *theAsioDriver = 0; +#endif + +//----------------------------------------------------------------------------------------------------- +ASIOError ASIOInit(ASIODriverInfo *info) +{ +#if MAC || SGI || SUN || BEOS || LINUX + if(theAsioDriver) + { + delete theAsioDriver; + theAsioDriver = 0; + } + info->driverVersion = 0; + strcpy(info->name, "No ASIO Driver"); + theAsioDriver = getDriver(); + if(!theAsioDriver) + { + strcpy(info->errorMessage, "Not enough memory for the ASIO driver!"); + return ASE_NotPresent; + } + if(!theAsioDriver->init(info->sysRef)) + { + theAsioDriver->getErrorMessage(info->errorMessage); + delete theAsioDriver; + theAsioDriver = 0; + return ASE_NotPresent; + } + strcpy(info->errorMessage, "No ASIO Driver Error"); + theAsioDriver->getDriverName(info->name); + info->driverVersion = theAsioDriver->getDriverVersion(); + return ASE_OK; + +#else + + info->driverVersion = 0; + strcpy(info->name, "No ASIO Driver"); + if(theAsioDriver) // must be loaded! + { + if(!theAsioDriver->init(info->sysRef)) + { + theAsioDriver->getErrorMessage(info->errorMessage); + theAsioDriver = 0; + return ASE_NotPresent; + } + + strcpy(info->errorMessage, "No ASIO Driver Error"); + theAsioDriver->getDriverName(info->name); + info->driverVersion = theAsioDriver->getDriverVersion(); + return ASE_OK; + } + return ASE_NotPresent; + +#endif // !MAC +} + +ASIOError ASIOExit(void) +{ + if(theAsioDriver) + { +#if WINDOWS + asioDrivers->removeCurrentDriver(); +#else + delete theAsioDriver; +#endif + } + theAsioDriver = 0; + return ASE_OK; +} + +ASIOError ASIOStart(void) +{ + if(!theAsioDriver) + return ASE_NotPresent; + return theAsioDriver->start(); +} + +ASIOError ASIOStop(void) +{ + if(!theAsioDriver) + return ASE_NotPresent; + return theAsioDriver->stop(); +} + +ASIOError ASIOGetChannels(long *numInputChannels, long *numOutputChannels) +{ + if(!theAsioDriver) + { + *numInputChannels = *numOutputChannels = 0; + return ASE_NotPresent; + } + return theAsioDriver->getChannels(numInputChannels, numOutputChannels); +} + +ASIOError ASIOGetLatencies(long *inputLatency, long *outputLatency) +{ + if(!theAsioDriver) + { + *inputLatency = *outputLatency = 0; + return ASE_NotPresent; + } + return theAsioDriver->getLatencies(inputLatency, outputLatency); +} + +ASIOError ASIOGetBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity) +{ + if(!theAsioDriver) + { + *minSize = *maxSize = *preferredSize = *granularity = 0; + return ASE_NotPresent; + } + return theAsioDriver->getBufferSize(minSize, maxSize, preferredSize, granularity); +} + +ASIOError ASIOCanSampleRate(ASIOSampleRate sampleRate) +{ + if(!theAsioDriver) + return ASE_NotPresent; + return theAsioDriver->canSampleRate(sampleRate); +} + +ASIOError ASIOGetSampleRate(ASIOSampleRate *currentRate) +{ + if(!theAsioDriver) + return ASE_NotPresent; + return theAsioDriver->getSampleRate(currentRate); +} + +ASIOError ASIOSetSampleRate(ASIOSampleRate sampleRate) +{ + if(!theAsioDriver) + return ASE_NotPresent; + return theAsioDriver->setSampleRate(sampleRate); +} + +ASIOError ASIOGetClockSources(ASIOClockSource *clocks, long *numSources) +{ + if(!theAsioDriver) + { + *numSources = 0; + return ASE_NotPresent; + } + return theAsioDriver->getClockSources(clocks, numSources); +} + +ASIOError ASIOSetClockSource(long reference) +{ + if(!theAsioDriver) + return ASE_NotPresent; + return theAsioDriver->setClockSource(reference); +} + +ASIOError ASIOGetSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp) +{ + if(!theAsioDriver) + return ASE_NotPresent; + return theAsioDriver->getSamplePosition(sPos, tStamp); +} + +ASIOError ASIOGetChannelInfo(ASIOChannelInfo *info) +{ + if(!theAsioDriver) + { + info->channelGroup = -1; + info->type = ASIOSTInt16MSB; + strcpy(info->name, "None"); + return ASE_NotPresent; + } + return theAsioDriver->getChannelInfo(info); +} + +ASIOError ASIOCreateBuffers(ASIOBufferInfo *bufferInfos, long numChannels, + long bufferSize, ASIOCallbacks *callbacks) +{ + if(!theAsioDriver) + { + ASIOBufferInfo *info = bufferInfos; + for(long i = 0; i < numChannels; i++, info++) + info->buffers[0] = info->buffers[1] = 0; + return ASE_NotPresent; + } + return theAsioDriver->createBuffers(bufferInfos, numChannels, bufferSize, callbacks); +} + +ASIOError ASIODisposeBuffers(void) +{ + if(!theAsioDriver) + return ASE_NotPresent; + return theAsioDriver->disposeBuffers(); +} + +ASIOError ASIOControlPanel(void) +{ + if(!theAsioDriver) + return ASE_NotPresent; + return theAsioDriver->controlPanel(); +} + +ASIOError ASIOFuture(long selector, void *opt) +{ + if(!theAsioDriver) + return ASE_NotPresent; + return theAsioDriver->future(selector, opt); +} + +ASIOError ASIOOutputReady(void) +{ + if(!theAsioDriver) + return ASE_NotPresent; + return theAsioDriver->outputReady(); +} + +#if MAC +} // extern "C" +#pragma export off +#endif + + diff --git a/lib-src/rtaudio/tests/Windows/asio.h b/lib-src/rtaudio/tests/Windows/asio.h index 30031306e..3b9497d2b 100644 --- a/lib-src/rtaudio/tests/Windows/asio.h +++ b/lib-src/rtaudio/tests/Windows/asio.h @@ -1,955 +1,955 @@ -//--------------------------------------------------------------------------------------------------- -//--------------------------------------------------------------------------------------------------- - -/* - Steinberg Audio Stream I/O API - (c) 1997 - 1999, Steinberg Soft- und Hardware GmbH - - ASIO Interface Specification v 2.0 - - basic concept is an i/o synchronous double-buffer scheme: - - on bufferSwitch(index == 0), host will read/write: - - after ASIOStart(), the - read first input buffer A (index 0) - | will be invalid (empty) - * ------------------------ - |------------------------|-----------------------| - | | | - | Input Buffer A (0) | Input Buffer B (1) | - | | | - |------------------------|-----------------------| - | | | - | Output Buffer A (0) | Output Buffer B (1) | - | | | - |------------------------|-----------------------| - * ------------------------- - | before calling ASIOStart(), - write host will have filled output - buffer B (index 1) already - - *please* take special care of proper statement of input - and output latencies (see ASIOGetLatencies()), these - control sequencer sync accuracy - -*/ - -//--------------------------------------------------------------------------------------------------- -//--------------------------------------------------------------------------------------------------- - -/* - -prototypes summary: - -ASIOError ASIOInit(ASIODriverInfo *info); -ASIOError ASIOExit(void); -ASIOError ASIOStart(void); -ASIOError ASIOStop(void); -ASIOError ASIOGetChannels(long *numInputChannels, long *numOutputChannels); -ASIOError ASIOGetLatencies(long *inputLatency, long *outputLatency); -ASIOError ASIOGetBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity); -ASIOError ASIOCanSampleRate(ASIOSampleRate sampleRate); -ASIOError ASIOGetSampleRate(ASIOSampleRate *currentRate); -ASIOError ASIOSetSampleRate(ASIOSampleRate sampleRate); -ASIOError ASIOGetClockSources(ASIOClockSource *clocks, long *numSources); -ASIOError ASIOSetClockSource(long reference); -ASIOError ASIOGetSamplePosition (ASIOSamples *sPos, ASIOTimeStamp *tStamp); -ASIOError ASIOGetChannelInfo(ASIOChannelInfo *info); -ASIOError ASIOCreateBuffers(ASIOBufferInfo *bufferInfos, long numChannels, - long bufferSize, ASIOCallbacks *callbacks); -ASIOError ASIODisposeBuffers(void); -ASIOError ASIOControlPanel(void); -void *ASIOFuture(long selector, void *params); -ASIOError ASIOOutputReady(void); - -*/ - -//--------------------------------------------------------------------------------------------------- -//--------------------------------------------------------------------------------------------------- - -#ifndef __ASIO_H -#define __ASIO_H - -// force 4 byte alignment -#if defined(_MSC_VER) && !defined(__MWERKS__) -#pragma pack(push,4) -#elif PRAGMA_ALIGN_SUPPORTED -#pragma options align = native -#endif - -//- - - - - - - - - - - - - - - - - - - - - - - - - -// Type definitions -//- - - - - - - - - - - - - - - - - - - - - - - - - - -// number of samples data type is 64 bit integer -#if NATIVE_INT64 - typedef long long int ASIOSamples; -#else - typedef struct ASIOSamples { - unsigned long hi; - unsigned long lo; - } ASIOSamples; -#endif - -// Timestamp data type is 64 bit integer, -// Time format is Nanoseconds. -#if NATIVE_INT64 - typedef long long int ASIOTimeStamp ; -#else - typedef struct ASIOTimeStamp { - unsigned long hi; - unsigned long lo; - } ASIOTimeStamp; -#endif - -// Samplerates are expressed in IEEE 754 64 bit double float, -// native format as host computer -#if IEEE754_64FLOAT - typedef double ASIOSampleRate; -#else - typedef struct ASIOSampleRate { - char ieee[8]; - } ASIOSampleRate; -#endif - -// Boolean values are expressed as long -typedef long ASIOBool; -enum { - ASIOFalse = 0, - ASIOTrue = 1 -}; - -// Sample Types are expressed as long -typedef long ASIOSampleType; -enum { - ASIOSTInt16MSB = 0, - ASIOSTInt24MSB = 1, // used for 20 bits as well - ASIOSTInt32MSB = 2, - ASIOSTFloat32MSB = 3, // IEEE 754 32 bit float - ASIOSTFloat64MSB = 4, // IEEE 754 64 bit double float - - // these are used for 32 bit data buffer, with different alignment of the data inside - // 32 bit PCI bus systems can be more easily used with these - ASIOSTInt32MSB16 = 8, // 32 bit data with 18 bit alignment - ASIOSTInt32MSB18 = 9, // 32 bit data with 18 bit alignment - ASIOSTInt32MSB20 = 10, // 32 bit data with 20 bit alignment - ASIOSTInt32MSB24 = 11, // 32 bit data with 24 bit alignment - - ASIOSTInt16LSB = 16, - ASIOSTInt24LSB = 17, // used for 20 bits as well - ASIOSTInt32LSB = 18, - ASIOSTFloat32LSB = 19, // IEEE 754 32 bit float, as found on Intel x86 architecture - ASIOSTFloat64LSB = 20, // IEEE 754 64 bit double float, as found on Intel x86 architecture - - // these are used for 32 bit data buffer, with different alignment of the data inside - // 32 bit PCI bus systems can more easily used with these - ASIOSTInt32LSB16 = 24, // 32 bit data with 18 bit alignment - ASIOSTInt32LSB18 = 25, // 32 bit data with 18 bit alignment - ASIOSTInt32LSB20 = 26, // 32 bit data with 20 bit alignment - ASIOSTInt32LSB24 = 27 // 32 bit data with 24 bit alignment -}; - -//- - - - - - - - - - - - - - - - - - - - - - - - - -// Error codes -//- - - - - - - - - - - - - - - - - - - - - - - - - - -typedef long ASIOError; -enum { - ASE_OK = 0, // This value will be returned whenever the call succeeded - ASE_SUCCESS = 0x3f4847a0, // unique success return value for ASIOFuture calls - ASE_NotPresent = -1000, // hardware input or output is not present or available - ASE_HWMalfunction, // hardware is malfunctioning (can be returned by any ASIO function) - ASE_InvalidParameter, // input parameter invalid - ASE_InvalidMode, // hardware is in a bad mode or used in a bad mode - ASE_SPNotAdvancing, // hardware is not running when sample position is inquired - ASE_NoClock, // sample clock or rate cannot be determined or is not present - ASE_NoMemory // not enough memory for completing the request -}; - -//--------------------------------------------------------------------------------------------------- -//--------------------------------------------------------------------------------------------------- - -//- - - - - - - - - - - - - - - - - - - - - - - - - -// Time Info support -//- - - - - - - - - - - - - - - - - - - - - - - - - - -typedef struct ASIOTimeCode -{ - double speed; // speed relation (fraction of nominal speed) - // optional; set to 0. or 1. if not supported - ASIOSamples timeCodeSamples; // time in samples - unsigned long flags; // some information flags (see below) - char future[64]; -} ASIOTimeCode; - -typedef enum ASIOTimeCodeFlags -{ - kTcValid = 1, - kTcRunning = 1 << 1, - kTcReverse = 1 << 2, - kTcOnspeed = 1 << 3, - kTcStill = 1 << 4, - - kTcSpeedValid = 1 << 8 -} ASIOTimeCodeFlags; - -typedef struct AsioTimeInfo -{ - double speed; // absolute speed (1. = nominal) - ASIOTimeStamp systemTime; // system time related to samplePosition, in nanoseconds - // on mac, must be derived from Microseconds() (not UpTime()!) - // on windows, must be derived from timeGetTime() - ASIOSamples samplePosition; - ASIOSampleRate sampleRate; // current rate - unsigned long flags; // (see below) - char reserved[12]; -} AsioTimeInfo; - -typedef enum AsioTimeInfoFlags -{ - kSystemTimeValid = 1, // must always be valid - kSamplePositionValid = 1 << 1, // must always be valid - kSampleRateValid = 1 << 2, - kSpeedValid = 1 << 3, - - kSampleRateChanged = 1 << 4, - kClockSourceChanged = 1 << 5 -} AsioTimeInfoFlags; - -typedef struct ASIOTime // both input/output -{ - long reserved[4]; // must be 0 - struct AsioTimeInfo timeInfo; // required - struct ASIOTimeCode timeCode; // optional, evaluated if (timeCode.flags & kTcValid) -} ASIOTime; - -/* - -using time info: -it is recommended to use the new method with time info even if the asio -device does not support timecode; continuous calls to ASIOGetSamplePosition -and ASIOGetSampleRate are avoided, and there is a more defined relationship -between callback time and the time info. - -see the example below. -to initiate time info mode, after you have received the callbacks pointer in -ASIOCreateBuffers, you will call the asioMessage callback with kAsioSupportsTimeInfo -as the argument. if this returns 1, host has accepted time info mode. -now host expects the new callback bufferSwitchTimeInfo to be used instead -of the old bufferSwitch method. the ASIOTime structure is assumed to be valid -and accessible until the callback returns. - -using time code: -if the device supports reading time code, it will call host's asioMessage callback -with kAsioSupportsTimeCode as the selector. it may then fill the according -fields and set the kTcValid flag. -host will call the future method with the kAsioEnableTimeCodeRead selector when -it wants to enable or disable tc reading by the device. you should also support -the kAsioCanTimeInfo and kAsioCanTimeCode selectors in ASIOFuture (see example). - -note: -the AsioTimeInfo/ASIOTimeCode pair is supposed to work in both directions. -as a matter of convention, the relationship between the sample -position counter and the time code at buffer switch time is -(ignoring offset between tc and sample pos when tc is running): - -on input: sample 0 -> input buffer sample 0 -> time code 0 -on output: sample 0 -> output buffer sample 0 -> time code 0 - -this means that for 'real' calculations, one has to take into account -the according latencies. - -example: - -ASIOTime asioTime; - -in createBuffers() -{ - memset(&asioTime, 0, sizeof(ASIOTime)); - AsioTimeInfo* ti = &asioTime.timeInfo; - ti->sampleRate = theSampleRate; - ASIOTimeCode* tc = &asioTime.timeCode; - tc->speed = 1.; - timeInfoMode = false; - canTimeCode = false; - if(callbacks->asioMessage(kAsioSupportsTimeInfo, 0, 0, 0) == 1) - { - timeInfoMode = true; -#if kCanTimeCode - if(callbacks->asioMessage(kAsioSupportsTimeCode, 0, 0, 0) == 1) - canTimeCode = true; -#endif - } -} - -void switchBuffers(long doubleBufferIndex, bool processNow) -{ - if(timeInfoMode) - { - AsioTimeInfo* ti = &asioTime.timeInfo; - ti->flags = kSystemTimeValid | kSamplePositionValid | kSampleRateValid; - ti->systemTime = theNanoSeconds; - ti->samplePosition = theSamplePosition; - if(ti->sampleRate != theSampleRate) - ti->flags |= kSampleRateChanged; - ti->sampleRate = theSampleRate; - -#if kCanTimeCode - if(canTimeCode && timeCodeEnabled) - { - ASIOTimeCode* tc = &asioTime.timeCode; - tc->timeCodeSamples = tcSamples; // tc in samples - tc->flags = kTcValid | kTcRunning | kTcOnspeed; // if so... - } - ASIOTime* bb = callbacks->bufferSwitchTimeInfo(&asioTime, doubleBufferIndex, processNow ? ASIOTrue : ASIOFalse); -#else - callbacks->bufferSwitchTimeInfo(&asioTime, doubleBufferIndex, processNow ? ASIOTrue : ASIOFalse); -#endif - } - else - callbacks->bufferSwitch(doubleBufferIndex, ASIOFalse); -} - -ASIOError ASIOFuture(long selector, void *params) -{ - switch(selector) - { - case kAsioEnableTimeCodeRead: - timeCodeEnabled = true; - return ASE_SUCCESS; - case kAsioDisableTimeCodeRead: - timeCodeEnabled = false; - return ASE_SUCCESS; - case kAsioCanTimeInfo: - return ASE_SUCCESS; - #if kCanTimeCode - case kAsioCanTimeCode: - return ASE_SUCCESS; - #endif - } - return ASE_NotPresent; -}; - -*/ - -//- - - - - - - - - - - - - - - - - - - - - - - - - -// application's audio stream handler callbacks -//- - - - - - - - - - - - - - - - - - - - - - - - - - -typedef struct ASIOCallbacks -{ - void (*bufferSwitch) (long doubleBufferIndex, ASIOBool directProcess); - // bufferSwitch indicates that both input and output are to be processed. - // the current buffer half index (0 for A, 1 for B) determines - // - the output buffer that the host should start to fill. the other buffer - // will be passed to output hardware regardless of whether it got filled - // in time or not. - // - the input buffer that is now filled with incoming data. Note that - // because of the synchronicity of i/o, the input always has at - // least one buffer latency in relation to the output. - // directProcess suggests to the host whether it should immedeately - // start processing (directProcess == ASIOTrue), or whether its process - // should be deferred because the call comes from a very low level - // (for instance, a high level priority interrupt), and direct processing - // would cause timing instabilities for the rest of the system. If in doubt, - // directProcess should be set to ASIOFalse. - // Note: bufferSwitch may be called at interrupt time for highest efficiency. - - void (*sampleRateDidChange) (ASIOSampleRate sRate); - // gets called when the AudioStreamIO detects a sample rate change - // If sample rate is unknown, 0 is passed (for instance, clock loss - // when externally synchronized). - - long (*asioMessage) (long selector, long value, void* message, double* opt); - // generic callback for various purposes, see selectors below. - // note this is only present if the asio version is 2 or higher - - ASIOTime* (*bufferSwitchTimeInfo) (ASIOTime* params, long doubleBufferIndex, ASIOBool directProcess); - // new callback with time info. makes ASIOGetSamplePosition() and various - // calls to ASIOGetSampleRate obsolete, - // and allows for timecode sync etc. to be preferred; will be used if - // the driver calls asioMessage with selector kAsioSupportsTimeInfo. -} ASIOCallbacks; - -// asioMessage selectors -enum -{ - kAsioSelectorSupported = 1, // selector in , returns 1L if supported, - // 0 otherwise - kAsioEngineVersion, // returns engine (host) asio implementation version, - // 2 or higher - kAsioResetRequest, // request driver reset. if accepted, this - // will close the driver (ASIO_Exit() ) and - // re-open it again (ASIO_Init() etc). some - // drivers need to reconfigure for instance - // when the sample rate changes, or some basic - // changes have been made in ASIO_ControlPanel(). - // returns 1L; note the request is merely passed - // to the application, there is no way to determine - // if it gets accepted at this time (but it usually - // will be). - kAsioBufferSizeChange, // not yet supported, will currently always return 0L. - // for now, use kAsioResetRequest instead. - // once implemented, the new buffer size is expected - // in , and on success returns 1L - kAsioResyncRequest, // the driver went out of sync, such that - // the timestamp is no longer valid. this - // is a request to re-start the engine and - // slave devices (sequencer). returns 1 for ok, - // 0 if not supported. - kAsioLatenciesChanged, // the drivers latencies have changed. The engine - // will refetch the latencies. - kAsioSupportsTimeInfo, // if host returns true here, it will expect the - // callback bufferSwitchTimeInfo to be called instead - // of bufferSwitch - kAsioSupportsTimeCode, // supports time code reading/writing - - kAsioSupportsInputMonitor, // supports input monitoring - - kAsioNumMessageSelectors -}; - -//--------------------------------------------------------------------------------------------------- -//--------------------------------------------------------------------------------------------------- - -//- - - - - - - - - - - - - - - - - - - - - - - - - -// (De-)Construction -//- - - - - - - - - - - - - - - - - - - - - - - - - - -typedef struct ASIODriverInfo -{ - long asioVersion; // currently, 2 - long driverVersion; // driver specific - char name[32]; - char errorMessage[124]; - void *sysRef; // on input: system reference - // (Windows: application main window handle, Mac & SGI: 0) -} ASIODriverInfo; - -ASIOError ASIOInit(ASIODriverInfo *info); -/* Purpose: - Initialize the AudioStreamIO. - Parameter: - info: pointer to an ASIODriver structure: - - asioVersion: - - on input, the host version. *** Note *** this is 0 for earlier asio - implementations, and the asioMessage callback is implemeted - only if asioVersion is 2 or greater. sorry but due to a design fault - the driver doesn't have access to the host version in ASIOInit :-( - added selector for host (engine) version in the asioMessage callback - so we're ok from now on. - - on return, asio implementation version. - older versions are 1 - if you support this version (namely, ASIO_outputReady() ) - this should be 2 or higher. also see the note in - ASIO_getTimeStamp() ! - - version: on return, the driver version (format is driver specific) - - name: on return, a null-terminated string containing the driver's name - - error message: on return, should contain a user message describing - the type of error that occured during ASIOInit(), if any. - - sysRef: platform specific - Returns: - If neither input nor output is present ASE_NotPresent - will be returned. - ASE_NoMemory, ASE_HWMalfunction are other possible error conditions -*/ - -ASIOError ASIOExit(void); -/* Purpose: - Terminates the AudioStreamIO. - Parameter: - None. - Returns: - If neither input nor output is present ASE_NotPresent - will be returned. - Notes: this implies ASIOStop() and ASIODisposeBuffers(), - meaning that no host callbacks must be accessed after ASIOExit(). -*/ - -//- - - - - - - - - - - - - - - - - - - - - - - - - -// Start/Stop -//- - - - - - - - - - - - - - - - - - - - - - - - - - -ASIOError ASIOStart(void); -/* Purpose: - Start input and output processing synchronously. - This will - - reset the sample counter to zero - - start the hardware (both input and output) - The first call to the hosts' bufferSwitch(index == 0) then tells - the host to read from input buffer A (index 0), and start - processing to output buffer A while output buffer B (which - has been filled by the host prior to calling ASIOStart()) - is possibly sounding (see also ASIOGetLatencies()) - Parameter: - None. - Returns: - If neither input nor output is present, ASE_NotPresent - will be returned. - If the hardware fails to start, ASE_HWMalfunction will be returned. - Notes: - There is no restriction on the time that ASIOStart() takes - to perform (that is, it is not considered a realtime trigger). -*/ - -ASIOError ASIOStop(void); -/* Purpose: - Stops input and output processing altogether. - Parameter: - None. - Returns: - If neither input nor output is present ASE_NotPresent - will be returned. - Notes: - On return from ASIOStop(), the driver must in no - case call the hosts' bufferSwitch() routine. -*/ - -//- - - - - - - - - - - - - - - - - - - - - - - - - -// Inquiry methods and sample rate -//- - - - - - - - - - - - - - - - - - - - - - - - - - -ASIOError ASIOGetChannels(long *numInputChannels, long *numOutputChannels); -/* Purpose: - Returns number of individual input/output channels. - Parameter: - numInputChannels will hold the number of available input channels - numOutputChannels will hold the number of available output channels - Returns: - If no input/output is present ASE_NotPresent will be returned. - If only inputs, or only outputs are available, the according - other parameter will be zero, and ASE_OK is returned. -*/ - -ASIOError ASIOGetLatencies(long *inputLatency, long *outputLatency); -/* Purpose: - Returns the input and output latencies. This includes - device specific delays, like FIFOs etc. - Parameter: - inputLatency will hold the 'age' of the first sample frame - in the input buffer when the hosts reads it in bufferSwitch() - (this is theoretical, meaning it does not include the overhead - and delay between the actual physical switch, and the time - when bufferSitch() enters). - This will usually be the size of one block in sample frames, plus - device specific latencies. - - outputLatency will specify the time between the buffer switch, - and the time when the next play buffer will start to sound. - The next play buffer is defined as the one the host starts - processing after (or at) bufferSwitch(), indicated by the - index parameter (0 for buffer A, 1 for buffer B). - It will usually be either one block, if the host writes directly - to a dma buffer, or two or more blocks if the buffer is 'latched' by - the driver. As an example, on ASIOStart(), the host will have filled - the play buffer at index 1 already; when it gets the callback (with - the parameter index == 0), this tells it to read from the input - buffer 0, and start to fill the play buffer 0 (assuming that now - play buffer 1 is already sounding). In this case, the output - latency is one block. If the driver decides to copy buffer 1 - at that time, and pass it to the hardware at the next slot (which - is most commonly done, but should be avoided), the output latency - becomes two blocks instead, resulting in a total i/o latency of at least - 3 blocks. As memory access is the main bottleneck in native dsp processing, - and to acheive less latency, it is highly recommended to try to avoid - copying (this is also why the driver is the owner of the buffers). To - summarize, the minimum i/o latency can be acheived if the input buffer - is processed by the host into the output buffer which will physically - start to sound on the next time slice. Also note that the host expects - the bufferSwitch() callback to be accessed for each time slice in order - to retain sync, possibly recursively; if it fails to process a block in - time, it will suspend its operation for some time in order to recover. - Returns: - If no input/output is present ASE_NotPresent will be returned. -*/ - -ASIOError ASIOGetBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity); -/* Purpose: - Returns min, max, and preferred buffer sizes for input/output - Parameter: - minSize will hold the minimum buffer size - maxSize will hold the maxium possible buffer size - preferredSize will hold the preferred buffer size (a size which - best fits performance and hardware requirements) - granularity will hold the granularity at which buffer sizes - may differ. Usually, the buffer size will be a power of 2; - in this case, granularity will hold -1 on return, signalling - possible buffer sizes starting from minSize, increased in - powers of 2 up to maxSize. - Returns: - If no input/output is present ASE_NotPresent will be returned. - Notes: - When minimum and maximum buffer size are equal, - the preferred buffer size has to be the same value as well; granularity - should be 0 in this case. -*/ - -ASIOError ASIOCanSampleRate(ASIOSampleRate sampleRate); -/* Purpose: - Inquires the hardware for the available sample rates. - Parameter: - sampleRate is the rate in question. - Returns: - If the inquired sample rate is not supported, ASE_NoClock will be returned. - If no input/output is present ASE_NotPresent will be returned. -*/ -ASIOError ASIOGetSampleRate(ASIOSampleRate *currentRate); -/* Purpose: - Get the current sample Rate. - Parameter: - currentRate will hold the current sample rate on return. - Returns: - If sample rate is unknown, sampleRate will be 0 and ASE_NoClock will be returned. - If no input/output is present ASE_NotPresent will be returned. - Notes: -*/ - -ASIOError ASIOSetSampleRate(ASIOSampleRate sampleRate); -/* Purpose: - Set the hardware to the requested sample Rate. If sampleRate == 0, - enable external sync. - Parameter: - sampleRate: on input, the requested rate - Returns: - If sampleRate is unknown ASE_NoClock will be returned. - If the current clock is external, and sampleRate is != 0, - ASE_InvalidMode will be returned - If no input/output is present ASE_NotPresent will be returned. - Notes: -*/ - -typedef struct ASIOClockSource -{ - long index; // as used for ASIOSetClockSource() - long associatedChannel; // for instance, S/PDIF or AES/EBU - long associatedGroup; // see channel groups (ASIOGetChannelInfo()) - ASIOBool isCurrentSource; // ASIOTrue if this is the current clock source - char name[32]; // for user selection -} ASIOClockSource; - -ASIOError ASIOGetClockSources(ASIOClockSource *clocks, long *numSources); -/* Purpose: - Get the available external audio clock sources - Parameter: - clocks points to an array of ASIOClockSource structures: - - index: this is used to identify the clock source - when ASIOSetClockSource() is accessed, should be - an index counting from zero - - associatedInputChannel: the first channel of an associated - input group, if any. - - associatedGroup: the group index of that channel. - groups of channels are defined to seperate for - instance analog, S/PDIF, AES/EBU, ADAT connectors etc, - when present simultaniously. Note that associated channel - is enumerated according to numInputs/numOutputs, means it - is independant from a group (see also ASIOGetChannelInfo()) - inputs are associated to a clock if the physical connection - transfers both data and clock (like S/PDIF, AES/EBU, or - ADAT inputs). if there is no input channel associated with - the clock source (like Word Clock, or internal oscillator), both - associatedChannel and associatedGroup should be set to -1. - - isCurrentSource: on exit, ASIOTrue if this is the current clock - source, ASIOFalse else - - name: a null-terminated string for user selection of the available sources. - numSources: - on input: the number of allocated array members - on output: the number of available clock sources, at least - 1 (internal clock generator). - Returns: - If no input/output is present ASE_NotPresent will be returned. - Notes: -*/ - -ASIOError ASIOSetClockSource(long index); -/* Purpose: - Set the audio clock source - Parameter: - index as obtained from an inquiry to ASIOGetClockSources() - Returns: - If no input/output is present ASE_NotPresent will be returned. - If the clock can not be selected because an input channel which - carries the current clock source is active, ASE_InvalidMode - *may* be returned (this depends on the properties of the driver - and/or hardware). - Notes: - Should *not* return ASE_NoClock if there is no clock signal present - at the selected source; this will be inquired via ASIOGetSampleRate(). - It should call the host callback procedure sampleRateHasChanged(), - if the switch causes a sample rate change, or if no external clock - is present at the selected source. -*/ - -ASIOError ASIOGetSamplePosition (ASIOSamples *sPos, ASIOTimeStamp *tStamp); -/* Purpose: - Inquires the sample position/time stamp pair. - Parameter: - sPos will hold the sample position on return. The sample - position is reset to zero when ASIOStart() gets called. - tStamp will hold the system time when the sample position - was latched. - Returns: - If no input/output is present, ASE_NotPresent will be returned. - If there is no clock, ASE_SPNotAdvancing will be returned. - Notes: - - in order to be able to synchronise properly, - the sample position / time stamp pair must refer to the current block, - that is, the engine will call ASIOGetSamplePosition() in its bufferSwitch() - callback and expect the time for the current block. thus, when requested - in the very first bufferSwitch after ASIO_Start(), the sample position - should be zero, and the time stamp should refer to the very time where - the stream was started. it also means that the sample position must be - block aligned. the driver must ensure proper interpolation if the system - time can not be determined for the block position. the driver is responsible - for precise time stamps as it usually has most direct access to lower - level resources. proper behaviour of ASIO_GetSamplePosition() and ASIO_GetLatencies() - are essential for precise media synchronization! -*/ - -typedef struct ASIOChannelInfo -{ - long channel; // on input, channel index - ASIOBool isInput; // on input - ASIOBool isActive; // on exit - long channelGroup; // dto - ASIOSampleType type; // dto - char name[32]; // dto -} ASIOChannelInfo; - -ASIOError ASIOGetChannelInfo(ASIOChannelInfo *info); -/* Purpose: - retreive information about the nature of a channel - Parameter: - info: pointer to a ASIOChannelInfo structure with - - channel: on input, the channel index of the channel in question. - - isInput: on input, ASIOTrue if info for an input channel is - requested, else output - - channelGroup: on return, the channel group that the channel - belongs to. For drivers which support different types of - channels, like analog, S/PDIF, AES/EBU, ADAT etc interfaces, - there should be a reasonable grouping of these types. Groups - are always independant form a channel index, that is, a channel - index always counts from 0 to numInputs/numOutputs regardless - of the group it may belong to. - There will always be at least one group (group 0). Please - also note that by default, the host may decide to activate - channels 0 and 1; thus, these should belong to the most - useful type (analog i/o, if present). - - type: on return, contains the sample type of the channel - - isActive: on return, ASIOTrue if channel is active as it was - installed by ASIOCreateBuffers(), ASIOFalse else - - name: describing the type of channel in question. Used to allow - for user selection, and enabling of specific channels. examples: - "Analog In", "SPDIF Out" etc - Returns: - If no input/output is present ASE_NotPresent will be returned. - Notes: - If possible, the string should be organised such that the first - characters are most significantly describing the nature of the - port, to allow for identification even if the view showing the - port name is too small to display more than 8 characters, for - instance. -*/ - -//- - - - - - - - - - - - - - - - - - - - - - - - - -// Buffer preparation -//- - - - - - - - - - - - - - - - - - - - - - - - - - -typedef struct ASIOBufferInfo -{ - ASIOBool isInput; // on input: ASIOTrue: input, else output - long channelNum; // on input: channel index - void *buffers[2]; // on output: double buffer addresses -} ASIOBufferInfo; - -ASIOError ASIOCreateBuffers(ASIOBufferInfo *bufferInfos, long numChannels, - long bufferSize, ASIOCallbacks *callbacks); - -/* Purpose: - Allocates input/output buffers for all input and output channels to be activated. - Parameter: - bufferInfos is a pointer to an array of ASIOBufferInfo structures: - - isInput: on input, ASIOTrue if the buffer is to be allocated - for an input, output buffer else - - channelNum: on input, the index of the channel in question - (counting from 0) - - buffers: on exit, 2 pointers to the halves of the channels' double-buffer. - the size of the buffer(s) of course depend on both the ASIOSampleType - as obtained from ASIOGetChannelInfo(), and bufferSize - numChannels is the sum of all input and output channels to be created; - thus bufferInfos is a pointer to an array of numChannels ASIOBufferInfo - structures. - bufferSize selects one of the possible buffer sizes as obtained from - ASIOGetBufferSizes(). - callbacks is a pointer to an ASIOCallbacks structure. - Returns: - If not enough memory is available ASE_NoMemory will be returned. - If no input/output is present ASE_NotPresent will be returned. - If bufferSize is not supported, or one or more of the bufferInfos elements - contain invalid settings, ASE_InvalidMode will be returned. - Notes: - If individual channel selection is not possible but requested, - the driver has to handle this. namely, bufferSwitch() will only - have filled buffers of enabled outputs. If possible, processing - and buss activities overhead should be avoided for channels which - were not enabled here. -*/ - -ASIOError ASIODisposeBuffers(void); -/* Purpose: - Releases all buffers for the device. - Parameter: - None. - Returns: - If no buffer were ever prepared, ASE_InvalidMode will be returned. - If no input/output is present ASE_NotPresent will be returned. - Notes: - This implies ASIOStop(). -*/ - -ASIOError ASIOControlPanel(void); -/* Purpose: - request the driver to start a control panel component - for device specific user settings. This will not be - accessed on some platforms (where the component is accessed - instead). - Parameter: - None. - Returns: - If no panel is available ASE_NotPresent will be returned. - Actually, the return code is ignored. - Notes: - if the user applied settings which require a re-configuration - of parts or all of the enigine and/or driver (such as a change of - the block size), the asioMessage callback can be used (see - ASIO_Callbacks). -*/ - -ASIOError ASIOFuture(long selector, void *params); -/* Purpose: - various - Parameter: - selector: operation Code as to be defined. zero is reserved for - testing purposes. - params: depends on the selector; usually pointer to a structure - for passing and retreiving any type and amount of parameters. - Returns: - the return value is also selector dependant. if the selector - is unknown, ASE_InvalidParameter should be returned to prevent - further calls with this selector. on success, ASE_SUCCESS - must be returned (note: ASE_OK is *not* sufficient!) - Notes: - see selectors defined below. -*/ - -enum -{ - kAsioEnableTimeCodeRead = 1, // no arguments - kAsioDisableTimeCodeRead, // no arguments - kAsioSetInputMonitor, // ASIOInputMonitor* in params - kAsioTransport, // ASIOTransportParameters* in params - kAsioSetInputGain, // ASIOChannelControls* in params, apply gain - kAsioGetInputMeter, // ASIOChannelControls* in params, fill meter - kAsioSetOutputGain, // ASIOChannelControls* in params, apply gain - kAsioGetOutputMeter, // ASIOChannelControls* in params, fill meter - kAsioCanInputMonitor, // no arguments for kAsioCanXXX selectors - kAsioCanTimeInfo, - kAsioCanTimeCode, - kAsioCanTransport, - kAsioCanInputGain, - kAsioCanInputMeter, - kAsioCanOutputGain, - kAsioCanOutputMeter -}; - -typedef struct ASIOInputMonitor -{ - long input; // this input was set to monitor (or off), -1: all - long output; // suggested output for monitoring the input (if so) - long gain; // suggested gain, ranging 0 - 0x7fffffffL (-inf to +12 dB) - ASIOBool state; // ASIOTrue => on, ASIOFalse => off - long pan; // suggested pan, 0 => all left, 0x7fffffff => right -} ASIOInputMonitor; - -typedef struct ASIOChannelControls -{ - long channel; // on input, channel index - ASIOBool isInput; // on input - long gain; // on input, ranges 0 thru 0x7fffffff - long meter; // on return, ranges 0 thru 0x7fffffff - char future[32]; -} ASIOChannelControls; - -typedef struct ASIOTransportParameters -{ - long command; // see enum below - ASIOSamples samplePosition; - long track; - long trackSwitches[16]; // 512 tracks on/off - char future[64]; -} ASIOTransportParameters; - -enum -{ - kTransStart = 1, - kTransStop, - kTransLocate, // to samplePosition - kTransPunchIn, - kTransPunchOut, - kTransArmOn, // track - kTransArmOff, // track - kTransMonitorOn, // track - kTransMonitorOff, // track - kTransArm, // trackSwitches - kTransMonitor // trackSwitches -}; - -ASIOError ASIOOutputReady(void); -/* Purpose: - this tells the driver that the host has completed processing - the output buffers. if the data format required by the hardware - differs from the supported asio formats, but the hardware - buffers are DMA buffers, the driver will have to convert - the audio stream data; as the bufferSwitch callback is - usually issued at dma block switch time, the driver will - have to convert the *previous* host buffer, which increases - the output latency by one block. - when the host finds out that ASIOOutputReady() returns - true, it will issue this call whenever it completed - output processing. then the driver can convert the - host data directly to the dma buffer to be played next, - reducing output latency by one block. - another way to look at it is, that the buffer switch is called - in order to pass the *input* stream to the host, so that it can - process the input into the output, and the output stream is passed - to the driver when the host has completed its process. - Parameter: - None - Returns: - only if the above mentioned scenario is given, and a reduction - of output latency can be acheived by this mechanism, should - ASE_OK be returned. otherwise (and usually), ASE_NotPresent - should be returned in order to prevent further calls to this - function. note that the host may want to determine if it is - to use this when the system is not yet fully initialized, so - ASE_OK should always be returned if the mechanism makes sense. - Notes: - please remeber to adjust ASIOGetLatencies() according to - whether ASIOOutputReady() was ever called or not, if your - driver supports this scenario. - also note that the engine may fail to call ASIO_OutputReady() - in time in overload cases. as already mentioned, bufferSwitch - should be called for every block regardless of whether a block - could be processed in time. -*/ - -// restore old alignment -#if defined(_MSC_VER) && !defined(__MWERKS__) -#pragma pack(pop) -#elif PRAGMA_ALIGN_SUPPORTED -#pragma options align = reset -#endif - -#endif - +//--------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------- + +/* + Steinberg Audio Stream I/O API + (c) 1997 - 1999, Steinberg Soft- und Hardware GmbH + + ASIO Interface Specification v 2.0 + + basic concept is an i/o synchronous double-buffer scheme: + + on bufferSwitch(index == 0), host will read/write: + + after ASIOStart(), the + read first input buffer A (index 0) + | will be invalid (empty) + * ------------------------ + |------------------------|-----------------------| + | | | + | Input Buffer A (0) | Input Buffer B (1) | + | | | + |------------------------|-----------------------| + | | | + | Output Buffer A (0) | Output Buffer B (1) | + | | | + |------------------------|-----------------------| + * ------------------------- + | before calling ASIOStart(), + write host will have filled output + buffer B (index 1) already + + *please* take special care of proper statement of input + and output latencies (see ASIOGetLatencies()), these + control sequencer sync accuracy + +*/ + +//--------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------- + +/* + +prototypes summary: + +ASIOError ASIOInit(ASIODriverInfo *info); +ASIOError ASIOExit(void); +ASIOError ASIOStart(void); +ASIOError ASIOStop(void); +ASIOError ASIOGetChannels(long *numInputChannels, long *numOutputChannels); +ASIOError ASIOGetLatencies(long *inputLatency, long *outputLatency); +ASIOError ASIOGetBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity); +ASIOError ASIOCanSampleRate(ASIOSampleRate sampleRate); +ASIOError ASIOGetSampleRate(ASIOSampleRate *currentRate); +ASIOError ASIOSetSampleRate(ASIOSampleRate sampleRate); +ASIOError ASIOGetClockSources(ASIOClockSource *clocks, long *numSources); +ASIOError ASIOSetClockSource(long reference); +ASIOError ASIOGetSamplePosition (ASIOSamples *sPos, ASIOTimeStamp *tStamp); +ASIOError ASIOGetChannelInfo(ASIOChannelInfo *info); +ASIOError ASIOCreateBuffers(ASIOBufferInfo *bufferInfos, long numChannels, + long bufferSize, ASIOCallbacks *callbacks); +ASIOError ASIODisposeBuffers(void); +ASIOError ASIOControlPanel(void); +void *ASIOFuture(long selector, void *params); +ASIOError ASIOOutputReady(void); + +*/ + +//--------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------- + +#ifndef __ASIO_H +#define __ASIO_H + +// force 4 byte alignment +#if defined(_MSC_VER) && !defined(__MWERKS__) +#pragma pack(push,4) +#elif PRAGMA_ALIGN_SUPPORTED +#pragma options align = native +#endif + +//- - - - - - - - - - - - - - - - - - - - - - - - - +// Type definitions +//- - - - - - - - - - - - - - - - - - - - - - - - - + +// number of samples data type is 64 bit integer +#if NATIVE_INT64 + typedef long long int ASIOSamples; +#else + typedef struct ASIOSamples { + unsigned long hi; + unsigned long lo; + } ASIOSamples; +#endif + +// Timestamp data type is 64 bit integer, +// Time format is Nanoseconds. +#if NATIVE_INT64 + typedef long long int ASIOTimeStamp ; +#else + typedef struct ASIOTimeStamp { + unsigned long hi; + unsigned long lo; + } ASIOTimeStamp; +#endif + +// Samplerates are expressed in IEEE 754 64 bit double float, +// native format as host computer +#if IEEE754_64FLOAT + typedef double ASIOSampleRate; +#else + typedef struct ASIOSampleRate { + char ieee[8]; + } ASIOSampleRate; +#endif + +// Boolean values are expressed as long +typedef long ASIOBool; +enum { + ASIOFalse = 0, + ASIOTrue = 1 +}; + +// Sample Types are expressed as long +typedef long ASIOSampleType; +enum { + ASIOSTInt16MSB = 0, + ASIOSTInt24MSB = 1, // used for 20 bits as well + ASIOSTInt32MSB = 2, + ASIOSTFloat32MSB = 3, // IEEE 754 32 bit float + ASIOSTFloat64MSB = 4, // IEEE 754 64 bit double float + + // these are used for 32 bit data buffer, with different alignment of the data inside + // 32 bit PCI bus systems can be more easily used with these + ASIOSTInt32MSB16 = 8, // 32 bit data with 18 bit alignment + ASIOSTInt32MSB18 = 9, // 32 bit data with 18 bit alignment + ASIOSTInt32MSB20 = 10, // 32 bit data with 20 bit alignment + ASIOSTInt32MSB24 = 11, // 32 bit data with 24 bit alignment + + ASIOSTInt16LSB = 16, + ASIOSTInt24LSB = 17, // used for 20 bits as well + ASIOSTInt32LSB = 18, + ASIOSTFloat32LSB = 19, // IEEE 754 32 bit float, as found on Intel x86 architecture + ASIOSTFloat64LSB = 20, // IEEE 754 64 bit double float, as found on Intel x86 architecture + + // these are used for 32 bit data buffer, with different alignment of the data inside + // 32 bit PCI bus systems can more easily used with these + ASIOSTInt32LSB16 = 24, // 32 bit data with 18 bit alignment + ASIOSTInt32LSB18 = 25, // 32 bit data with 18 bit alignment + ASIOSTInt32LSB20 = 26, // 32 bit data with 20 bit alignment + ASIOSTInt32LSB24 = 27 // 32 bit data with 24 bit alignment +}; + +//- - - - - - - - - - - - - - - - - - - - - - - - - +// Error codes +//- - - - - - - - - - - - - - - - - - - - - - - - - + +typedef long ASIOError; +enum { + ASE_OK = 0, // This value will be returned whenever the call succeeded + ASE_SUCCESS = 0x3f4847a0, // unique success return value for ASIOFuture calls + ASE_NotPresent = -1000, // hardware input or output is not present or available + ASE_HWMalfunction, // hardware is malfunctioning (can be returned by any ASIO function) + ASE_InvalidParameter, // input parameter invalid + ASE_InvalidMode, // hardware is in a bad mode or used in a bad mode + ASE_SPNotAdvancing, // hardware is not running when sample position is inquired + ASE_NoClock, // sample clock or rate cannot be determined or is not present + ASE_NoMemory // not enough memory for completing the request +}; + +//--------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------- + +//- - - - - - - - - - - - - - - - - - - - - - - - - +// Time Info support +//- - - - - - - - - - - - - - - - - - - - - - - - - + +typedef struct ASIOTimeCode +{ + double speed; // speed relation (fraction of nominal speed) + // optional; set to 0. or 1. if not supported + ASIOSamples timeCodeSamples; // time in samples + unsigned long flags; // some information flags (see below) + char future[64]; +} ASIOTimeCode; + +typedef enum ASIOTimeCodeFlags +{ + kTcValid = 1, + kTcRunning = 1 << 1, + kTcReverse = 1 << 2, + kTcOnspeed = 1 << 3, + kTcStill = 1 << 4, + + kTcSpeedValid = 1 << 8 +} ASIOTimeCodeFlags; + +typedef struct AsioTimeInfo +{ + double speed; // absolute speed (1. = nominal) + ASIOTimeStamp systemTime; // system time related to samplePosition, in nanoseconds + // on mac, must be derived from Microseconds() (not UpTime()!) + // on windows, must be derived from timeGetTime() + ASIOSamples samplePosition; + ASIOSampleRate sampleRate; // current rate + unsigned long flags; // (see below) + char reserved[12]; +} AsioTimeInfo; + +typedef enum AsioTimeInfoFlags +{ + kSystemTimeValid = 1, // must always be valid + kSamplePositionValid = 1 << 1, // must always be valid + kSampleRateValid = 1 << 2, + kSpeedValid = 1 << 3, + + kSampleRateChanged = 1 << 4, + kClockSourceChanged = 1 << 5 +} AsioTimeInfoFlags; + +typedef struct ASIOTime // both input/output +{ + long reserved[4]; // must be 0 + struct AsioTimeInfo timeInfo; // required + struct ASIOTimeCode timeCode; // optional, evaluated if (timeCode.flags & kTcValid) +} ASIOTime; + +/* + +using time info: +it is recommended to use the new method with time info even if the asio +device does not support timecode; continuous calls to ASIOGetSamplePosition +and ASIOGetSampleRate are avoided, and there is a more defined relationship +between callback time and the time info. + +see the example below. +to initiate time info mode, after you have received the callbacks pointer in +ASIOCreateBuffers, you will call the asioMessage callback with kAsioSupportsTimeInfo +as the argument. if this returns 1, host has accepted time info mode. +now host expects the new callback bufferSwitchTimeInfo to be used instead +of the old bufferSwitch method. the ASIOTime structure is assumed to be valid +and accessible until the callback returns. + +using time code: +if the device supports reading time code, it will call host's asioMessage callback +with kAsioSupportsTimeCode as the selector. it may then fill the according +fields and set the kTcValid flag. +host will call the future method with the kAsioEnableTimeCodeRead selector when +it wants to enable or disable tc reading by the device. you should also support +the kAsioCanTimeInfo and kAsioCanTimeCode selectors in ASIOFuture (see example). + +note: +the AsioTimeInfo/ASIOTimeCode pair is supposed to work in both directions. +as a matter of convention, the relationship between the sample +position counter and the time code at buffer switch time is +(ignoring offset between tc and sample pos when tc is running): + +on input: sample 0 -> input buffer sample 0 -> time code 0 +on output: sample 0 -> output buffer sample 0 -> time code 0 + +this means that for 'real' calculations, one has to take into account +the according latencies. + +example: + +ASIOTime asioTime; + +in createBuffers() +{ + memset(&asioTime, 0, sizeof(ASIOTime)); + AsioTimeInfo* ti = &asioTime.timeInfo; + ti->sampleRate = theSampleRate; + ASIOTimeCode* tc = &asioTime.timeCode; + tc->speed = 1.; + timeInfoMode = false; + canTimeCode = false; + if(callbacks->asioMessage(kAsioSupportsTimeInfo, 0, 0, 0) == 1) + { + timeInfoMode = true; +#if kCanTimeCode + if(callbacks->asioMessage(kAsioSupportsTimeCode, 0, 0, 0) == 1) + canTimeCode = true; +#endif + } +} + +void switchBuffers(long doubleBufferIndex, bool processNow) +{ + if(timeInfoMode) + { + AsioTimeInfo* ti = &asioTime.timeInfo; + ti->flags = kSystemTimeValid | kSamplePositionValid | kSampleRateValid; + ti->systemTime = theNanoSeconds; + ti->samplePosition = theSamplePosition; + if(ti->sampleRate != theSampleRate) + ti->flags |= kSampleRateChanged; + ti->sampleRate = theSampleRate; + +#if kCanTimeCode + if(canTimeCode && timeCodeEnabled) + { + ASIOTimeCode* tc = &asioTime.timeCode; + tc->timeCodeSamples = tcSamples; // tc in samples + tc->flags = kTcValid | kTcRunning | kTcOnspeed; // if so... + } + ASIOTime* bb = callbacks->bufferSwitchTimeInfo(&asioTime, doubleBufferIndex, processNow ? ASIOTrue : ASIOFalse); +#else + callbacks->bufferSwitchTimeInfo(&asioTime, doubleBufferIndex, processNow ? ASIOTrue : ASIOFalse); +#endif + } + else + callbacks->bufferSwitch(doubleBufferIndex, ASIOFalse); +} + +ASIOError ASIOFuture(long selector, void *params) +{ + switch(selector) + { + case kAsioEnableTimeCodeRead: + timeCodeEnabled = true; + return ASE_SUCCESS; + case kAsioDisableTimeCodeRead: + timeCodeEnabled = false; + return ASE_SUCCESS; + case kAsioCanTimeInfo: + return ASE_SUCCESS; + #if kCanTimeCode + case kAsioCanTimeCode: + return ASE_SUCCESS; + #endif + } + return ASE_NotPresent; +}; + +*/ + +//- - - - - - - - - - - - - - - - - - - - - - - - - +// application's audio stream handler callbacks +//- - - - - - - - - - - - - - - - - - - - - - - - - + +typedef struct ASIOCallbacks +{ + void (*bufferSwitch) (long doubleBufferIndex, ASIOBool directProcess); + // bufferSwitch indicates that both input and output are to be processed. + // the current buffer half index (0 for A, 1 for B) determines + // - the output buffer that the host should start to fill. the other buffer + // will be passed to output hardware regardless of whether it got filled + // in time or not. + // - the input buffer that is now filled with incoming data. Note that + // because of the synchronicity of i/o, the input always has at + // least one buffer latency in relation to the output. + // directProcess suggests to the host whether it should immedeately + // start processing (directProcess == ASIOTrue), or whether its process + // should be deferred because the call comes from a very low level + // (for instance, a high level priority interrupt), and direct processing + // would cause timing instabilities for the rest of the system. If in doubt, + // directProcess should be set to ASIOFalse. + // Note: bufferSwitch may be called at interrupt time for highest efficiency. + + void (*sampleRateDidChange) (ASIOSampleRate sRate); + // gets called when the AudioStreamIO detects a sample rate change + // If sample rate is unknown, 0 is passed (for instance, clock loss + // when externally synchronized). + + long (*asioMessage) (long selector, long value, void* message, double* opt); + // generic callback for various purposes, see selectors below. + // note this is only present if the asio version is 2 or higher + + ASIOTime* (*bufferSwitchTimeInfo) (ASIOTime* params, long doubleBufferIndex, ASIOBool directProcess); + // new callback with time info. makes ASIOGetSamplePosition() and various + // calls to ASIOGetSampleRate obsolete, + // and allows for timecode sync etc. to be preferred; will be used if + // the driver calls asioMessage with selector kAsioSupportsTimeInfo. +} ASIOCallbacks; + +// asioMessage selectors +enum +{ + kAsioSelectorSupported = 1, // selector in , returns 1L if supported, + // 0 otherwise + kAsioEngineVersion, // returns engine (host) asio implementation version, + // 2 or higher + kAsioResetRequest, // request driver reset. if accepted, this + // will close the driver (ASIO_Exit() ) and + // re-open it again (ASIO_Init() etc). some + // drivers need to reconfigure for instance + // when the sample rate changes, or some basic + // changes have been made in ASIO_ControlPanel(). + // returns 1L; note the request is merely passed + // to the application, there is no way to determine + // if it gets accepted at this time (but it usually + // will be). + kAsioBufferSizeChange, // not yet supported, will currently always return 0L. + // for now, use kAsioResetRequest instead. + // once implemented, the new buffer size is expected + // in , and on success returns 1L + kAsioResyncRequest, // the driver went out of sync, such that + // the timestamp is no longer valid. this + // is a request to re-start the engine and + // slave devices (sequencer). returns 1 for ok, + // 0 if not supported. + kAsioLatenciesChanged, // the drivers latencies have changed. The engine + // will refetch the latencies. + kAsioSupportsTimeInfo, // if host returns true here, it will expect the + // callback bufferSwitchTimeInfo to be called instead + // of bufferSwitch + kAsioSupportsTimeCode, // supports time code reading/writing + + kAsioSupportsInputMonitor, // supports input monitoring + + kAsioNumMessageSelectors +}; + +//--------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------- + +//- - - - - - - - - - - - - - - - - - - - - - - - - +// (De-)Construction +//- - - - - - - - - - - - - - - - - - - - - - - - - + +typedef struct ASIODriverInfo +{ + long asioVersion; // currently, 2 + long driverVersion; // driver specific + char name[32]; + char errorMessage[124]; + void *sysRef; // on input: system reference + // (Windows: application main window handle, Mac & SGI: 0) +} ASIODriverInfo; + +ASIOError ASIOInit(ASIODriverInfo *info); +/* Purpose: + Initialize the AudioStreamIO. + Parameter: + info: pointer to an ASIODriver structure: + - asioVersion: + - on input, the host version. *** Note *** this is 0 for earlier asio + implementations, and the asioMessage callback is implemeted + only if asioVersion is 2 or greater. sorry but due to a design fault + the driver doesn't have access to the host version in ASIOInit :-( + added selector for host (engine) version in the asioMessage callback + so we're ok from now on. + - on return, asio implementation version. + older versions are 1 + if you support this version (namely, ASIO_outputReady() ) + this should be 2 or higher. also see the note in + ASIO_getTimeStamp() ! + - version: on return, the driver version (format is driver specific) + - name: on return, a null-terminated string containing the driver's name + - error message: on return, should contain a user message describing + the type of error that occured during ASIOInit(), if any. + - sysRef: platform specific + Returns: + If neither input nor output is present ASE_NotPresent + will be returned. + ASE_NoMemory, ASE_HWMalfunction are other possible error conditions +*/ + +ASIOError ASIOExit(void); +/* Purpose: + Terminates the AudioStreamIO. + Parameter: + None. + Returns: + If neither input nor output is present ASE_NotPresent + will be returned. + Notes: this implies ASIOStop() and ASIODisposeBuffers(), + meaning that no host callbacks must be accessed after ASIOExit(). +*/ + +//- - - - - - - - - - - - - - - - - - - - - - - - - +// Start/Stop +//- - - - - - - - - - - - - - - - - - - - - - - - - + +ASIOError ASIOStart(void); +/* Purpose: + Start input and output processing synchronously. + This will + - reset the sample counter to zero + - start the hardware (both input and output) + The first call to the hosts' bufferSwitch(index == 0) then tells + the host to read from input buffer A (index 0), and start + processing to output buffer A while output buffer B (which + has been filled by the host prior to calling ASIOStart()) + is possibly sounding (see also ASIOGetLatencies()) + Parameter: + None. + Returns: + If neither input nor output is present, ASE_NotPresent + will be returned. + If the hardware fails to start, ASE_HWMalfunction will be returned. + Notes: + There is no restriction on the time that ASIOStart() takes + to perform (that is, it is not considered a realtime trigger). +*/ + +ASIOError ASIOStop(void); +/* Purpose: + Stops input and output processing altogether. + Parameter: + None. + Returns: + If neither input nor output is present ASE_NotPresent + will be returned. + Notes: + On return from ASIOStop(), the driver must in no + case call the hosts' bufferSwitch() routine. +*/ + +//- - - - - - - - - - - - - - - - - - - - - - - - - +// Inquiry methods and sample rate +//- - - - - - - - - - - - - - - - - - - - - - - - - + +ASIOError ASIOGetChannels(long *numInputChannels, long *numOutputChannels); +/* Purpose: + Returns number of individual input/output channels. + Parameter: + numInputChannels will hold the number of available input channels + numOutputChannels will hold the number of available output channels + Returns: + If no input/output is present ASE_NotPresent will be returned. + If only inputs, or only outputs are available, the according + other parameter will be zero, and ASE_OK is returned. +*/ + +ASIOError ASIOGetLatencies(long *inputLatency, long *outputLatency); +/* Purpose: + Returns the input and output latencies. This includes + device specific delays, like FIFOs etc. + Parameter: + inputLatency will hold the 'age' of the first sample frame + in the input buffer when the hosts reads it in bufferSwitch() + (this is theoretical, meaning it does not include the overhead + and delay between the actual physical switch, and the time + when bufferSitch() enters). + This will usually be the size of one block in sample frames, plus + device specific latencies. + + outputLatency will specify the time between the buffer switch, + and the time when the next play buffer will start to sound. + The next play buffer is defined as the one the host starts + processing after (or at) bufferSwitch(), indicated by the + index parameter (0 for buffer A, 1 for buffer B). + It will usually be either one block, if the host writes directly + to a dma buffer, or two or more blocks if the buffer is 'latched' by + the driver. As an example, on ASIOStart(), the host will have filled + the play buffer at index 1 already; when it gets the callback (with + the parameter index == 0), this tells it to read from the input + buffer 0, and start to fill the play buffer 0 (assuming that now + play buffer 1 is already sounding). In this case, the output + latency is one block. If the driver decides to copy buffer 1 + at that time, and pass it to the hardware at the next slot (which + is most commonly done, but should be avoided), the output latency + becomes two blocks instead, resulting in a total i/o latency of at least + 3 blocks. As memory access is the main bottleneck in native dsp processing, + and to acheive less latency, it is highly recommended to try to avoid + copying (this is also why the driver is the owner of the buffers). To + summarize, the minimum i/o latency can be acheived if the input buffer + is processed by the host into the output buffer which will physically + start to sound on the next time slice. Also note that the host expects + the bufferSwitch() callback to be accessed for each time slice in order + to retain sync, possibly recursively; if it fails to process a block in + time, it will suspend its operation for some time in order to recover. + Returns: + If no input/output is present ASE_NotPresent will be returned. +*/ + +ASIOError ASIOGetBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity); +/* Purpose: + Returns min, max, and preferred buffer sizes for input/output + Parameter: + minSize will hold the minimum buffer size + maxSize will hold the maxium possible buffer size + preferredSize will hold the preferred buffer size (a size which + best fits performance and hardware requirements) + granularity will hold the granularity at which buffer sizes + may differ. Usually, the buffer size will be a power of 2; + in this case, granularity will hold -1 on return, signalling + possible buffer sizes starting from minSize, increased in + powers of 2 up to maxSize. + Returns: + If no input/output is present ASE_NotPresent will be returned. + Notes: + When minimum and maximum buffer size are equal, + the preferred buffer size has to be the same value as well; granularity + should be 0 in this case. +*/ + +ASIOError ASIOCanSampleRate(ASIOSampleRate sampleRate); +/* Purpose: + Inquires the hardware for the available sample rates. + Parameter: + sampleRate is the rate in question. + Returns: + If the inquired sample rate is not supported, ASE_NoClock will be returned. + If no input/output is present ASE_NotPresent will be returned. +*/ +ASIOError ASIOGetSampleRate(ASIOSampleRate *currentRate); +/* Purpose: + Get the current sample Rate. + Parameter: + currentRate will hold the current sample rate on return. + Returns: + If sample rate is unknown, sampleRate will be 0 and ASE_NoClock will be returned. + If no input/output is present ASE_NotPresent will be returned. + Notes: +*/ + +ASIOError ASIOSetSampleRate(ASIOSampleRate sampleRate); +/* Purpose: + Set the hardware to the requested sample Rate. If sampleRate == 0, + enable external sync. + Parameter: + sampleRate: on input, the requested rate + Returns: + If sampleRate is unknown ASE_NoClock will be returned. + If the current clock is external, and sampleRate is != 0, + ASE_InvalidMode will be returned + If no input/output is present ASE_NotPresent will be returned. + Notes: +*/ + +typedef struct ASIOClockSource +{ + long index; // as used for ASIOSetClockSource() + long associatedChannel; // for instance, S/PDIF or AES/EBU + long associatedGroup; // see channel groups (ASIOGetChannelInfo()) + ASIOBool isCurrentSource; // ASIOTrue if this is the current clock source + char name[32]; // for user selection +} ASIOClockSource; + +ASIOError ASIOGetClockSources(ASIOClockSource *clocks, long *numSources); +/* Purpose: + Get the available external audio clock sources + Parameter: + clocks points to an array of ASIOClockSource structures: + - index: this is used to identify the clock source + when ASIOSetClockSource() is accessed, should be + an index counting from zero + - associatedInputChannel: the first channel of an associated + input group, if any. + - associatedGroup: the group index of that channel. + groups of channels are defined to seperate for + instance analog, S/PDIF, AES/EBU, ADAT connectors etc, + when present simultaniously. Note that associated channel + is enumerated according to numInputs/numOutputs, means it + is independant from a group (see also ASIOGetChannelInfo()) + inputs are associated to a clock if the physical connection + transfers both data and clock (like S/PDIF, AES/EBU, or + ADAT inputs). if there is no input channel associated with + the clock source (like Word Clock, or internal oscillator), both + associatedChannel and associatedGroup should be set to -1. + - isCurrentSource: on exit, ASIOTrue if this is the current clock + source, ASIOFalse else + - name: a null-terminated string for user selection of the available sources. + numSources: + on input: the number of allocated array members + on output: the number of available clock sources, at least + 1 (internal clock generator). + Returns: + If no input/output is present ASE_NotPresent will be returned. + Notes: +*/ + +ASIOError ASIOSetClockSource(long index); +/* Purpose: + Set the audio clock source + Parameter: + index as obtained from an inquiry to ASIOGetClockSources() + Returns: + If no input/output is present ASE_NotPresent will be returned. + If the clock can not be selected because an input channel which + carries the current clock source is active, ASE_InvalidMode + *may* be returned (this depends on the properties of the driver + and/or hardware). + Notes: + Should *not* return ASE_NoClock if there is no clock signal present + at the selected source; this will be inquired via ASIOGetSampleRate(). + It should call the host callback procedure sampleRateHasChanged(), + if the switch causes a sample rate change, or if no external clock + is present at the selected source. +*/ + +ASIOError ASIOGetSamplePosition (ASIOSamples *sPos, ASIOTimeStamp *tStamp); +/* Purpose: + Inquires the sample position/time stamp pair. + Parameter: + sPos will hold the sample position on return. The sample + position is reset to zero when ASIOStart() gets called. + tStamp will hold the system time when the sample position + was latched. + Returns: + If no input/output is present, ASE_NotPresent will be returned. + If there is no clock, ASE_SPNotAdvancing will be returned. + Notes: + + in order to be able to synchronise properly, + the sample position / time stamp pair must refer to the current block, + that is, the engine will call ASIOGetSamplePosition() in its bufferSwitch() + callback and expect the time for the current block. thus, when requested + in the very first bufferSwitch after ASIO_Start(), the sample position + should be zero, and the time stamp should refer to the very time where + the stream was started. it also means that the sample position must be + block aligned. the driver must ensure proper interpolation if the system + time can not be determined for the block position. the driver is responsible + for precise time stamps as it usually has most direct access to lower + level resources. proper behaviour of ASIO_GetSamplePosition() and ASIO_GetLatencies() + are essential for precise media synchronization! +*/ + +typedef struct ASIOChannelInfo +{ + long channel; // on input, channel index + ASIOBool isInput; // on input + ASIOBool isActive; // on exit + long channelGroup; // dto + ASIOSampleType type; // dto + char name[32]; // dto +} ASIOChannelInfo; + +ASIOError ASIOGetChannelInfo(ASIOChannelInfo *info); +/* Purpose: + retreive information about the nature of a channel + Parameter: + info: pointer to a ASIOChannelInfo structure with + - channel: on input, the channel index of the channel in question. + - isInput: on input, ASIOTrue if info for an input channel is + requested, else output + - channelGroup: on return, the channel group that the channel + belongs to. For drivers which support different types of + channels, like analog, S/PDIF, AES/EBU, ADAT etc interfaces, + there should be a reasonable grouping of these types. Groups + are always independant form a channel index, that is, a channel + index always counts from 0 to numInputs/numOutputs regardless + of the group it may belong to. + There will always be at least one group (group 0). Please + also note that by default, the host may decide to activate + channels 0 and 1; thus, these should belong to the most + useful type (analog i/o, if present). + - type: on return, contains the sample type of the channel + - isActive: on return, ASIOTrue if channel is active as it was + installed by ASIOCreateBuffers(), ASIOFalse else + - name: describing the type of channel in question. Used to allow + for user selection, and enabling of specific channels. examples: + "Analog In", "SPDIF Out" etc + Returns: + If no input/output is present ASE_NotPresent will be returned. + Notes: + If possible, the string should be organised such that the first + characters are most significantly describing the nature of the + port, to allow for identification even if the view showing the + port name is too small to display more than 8 characters, for + instance. +*/ + +//- - - - - - - - - - - - - - - - - - - - - - - - - +// Buffer preparation +//- - - - - - - - - - - - - - - - - - - - - - - - - + +typedef struct ASIOBufferInfo +{ + ASIOBool isInput; // on input: ASIOTrue: input, else output + long channelNum; // on input: channel index + void *buffers[2]; // on output: double buffer addresses +} ASIOBufferInfo; + +ASIOError ASIOCreateBuffers(ASIOBufferInfo *bufferInfos, long numChannels, + long bufferSize, ASIOCallbacks *callbacks); + +/* Purpose: + Allocates input/output buffers for all input and output channels to be activated. + Parameter: + bufferInfos is a pointer to an array of ASIOBufferInfo structures: + - isInput: on input, ASIOTrue if the buffer is to be allocated + for an input, output buffer else + - channelNum: on input, the index of the channel in question + (counting from 0) + - buffers: on exit, 2 pointers to the halves of the channels' double-buffer. + the size of the buffer(s) of course depend on both the ASIOSampleType + as obtained from ASIOGetChannelInfo(), and bufferSize + numChannels is the sum of all input and output channels to be created; + thus bufferInfos is a pointer to an array of numChannels ASIOBufferInfo + structures. + bufferSize selects one of the possible buffer sizes as obtained from + ASIOGetBufferSizes(). + callbacks is a pointer to an ASIOCallbacks structure. + Returns: + If not enough memory is available ASE_NoMemory will be returned. + If no input/output is present ASE_NotPresent will be returned. + If bufferSize is not supported, or one or more of the bufferInfos elements + contain invalid settings, ASE_InvalidMode will be returned. + Notes: + If individual channel selection is not possible but requested, + the driver has to handle this. namely, bufferSwitch() will only + have filled buffers of enabled outputs. If possible, processing + and buss activities overhead should be avoided for channels which + were not enabled here. +*/ + +ASIOError ASIODisposeBuffers(void); +/* Purpose: + Releases all buffers for the device. + Parameter: + None. + Returns: + If no buffer were ever prepared, ASE_InvalidMode will be returned. + If no input/output is present ASE_NotPresent will be returned. + Notes: + This implies ASIOStop(). +*/ + +ASIOError ASIOControlPanel(void); +/* Purpose: + request the driver to start a control panel component + for device specific user settings. This will not be + accessed on some platforms (where the component is accessed + instead). + Parameter: + None. + Returns: + If no panel is available ASE_NotPresent will be returned. + Actually, the return code is ignored. + Notes: + if the user applied settings which require a re-configuration + of parts or all of the enigine and/or driver (such as a change of + the block size), the asioMessage callback can be used (see + ASIO_Callbacks). +*/ + +ASIOError ASIOFuture(long selector, void *params); +/* Purpose: + various + Parameter: + selector: operation Code as to be defined. zero is reserved for + testing purposes. + params: depends on the selector; usually pointer to a structure + for passing and retreiving any type and amount of parameters. + Returns: + the return value is also selector dependant. if the selector + is unknown, ASE_InvalidParameter should be returned to prevent + further calls with this selector. on success, ASE_SUCCESS + must be returned (note: ASE_OK is *not* sufficient!) + Notes: + see selectors defined below. +*/ + +enum +{ + kAsioEnableTimeCodeRead = 1, // no arguments + kAsioDisableTimeCodeRead, // no arguments + kAsioSetInputMonitor, // ASIOInputMonitor* in params + kAsioTransport, // ASIOTransportParameters* in params + kAsioSetInputGain, // ASIOChannelControls* in params, apply gain + kAsioGetInputMeter, // ASIOChannelControls* in params, fill meter + kAsioSetOutputGain, // ASIOChannelControls* in params, apply gain + kAsioGetOutputMeter, // ASIOChannelControls* in params, fill meter + kAsioCanInputMonitor, // no arguments for kAsioCanXXX selectors + kAsioCanTimeInfo, + kAsioCanTimeCode, + kAsioCanTransport, + kAsioCanInputGain, + kAsioCanInputMeter, + kAsioCanOutputGain, + kAsioCanOutputMeter +}; + +typedef struct ASIOInputMonitor +{ + long input; // this input was set to monitor (or off), -1: all + long output; // suggested output for monitoring the input (if so) + long gain; // suggested gain, ranging 0 - 0x7fffffffL (-inf to +12 dB) + ASIOBool state; // ASIOTrue => on, ASIOFalse => off + long pan; // suggested pan, 0 => all left, 0x7fffffff => right +} ASIOInputMonitor; + +typedef struct ASIOChannelControls +{ + long channel; // on input, channel index + ASIOBool isInput; // on input + long gain; // on input, ranges 0 thru 0x7fffffff + long meter; // on return, ranges 0 thru 0x7fffffff + char future[32]; +} ASIOChannelControls; + +typedef struct ASIOTransportParameters +{ + long command; // see enum below + ASIOSamples samplePosition; + long track; + long trackSwitches[16]; // 512 tracks on/off + char future[64]; +} ASIOTransportParameters; + +enum +{ + kTransStart = 1, + kTransStop, + kTransLocate, // to samplePosition + kTransPunchIn, + kTransPunchOut, + kTransArmOn, // track + kTransArmOff, // track + kTransMonitorOn, // track + kTransMonitorOff, // track + kTransArm, // trackSwitches + kTransMonitor // trackSwitches +}; + +ASIOError ASIOOutputReady(void); +/* Purpose: + this tells the driver that the host has completed processing + the output buffers. if the data format required by the hardware + differs from the supported asio formats, but the hardware + buffers are DMA buffers, the driver will have to convert + the audio stream data; as the bufferSwitch callback is + usually issued at dma block switch time, the driver will + have to convert the *previous* host buffer, which increases + the output latency by one block. + when the host finds out that ASIOOutputReady() returns + true, it will issue this call whenever it completed + output processing. then the driver can convert the + host data directly to the dma buffer to be played next, + reducing output latency by one block. + another way to look at it is, that the buffer switch is called + in order to pass the *input* stream to the host, so that it can + process the input into the output, and the output stream is passed + to the driver when the host has completed its process. + Parameter: + None + Returns: + only if the above mentioned scenario is given, and a reduction + of output latency can be acheived by this mechanism, should + ASE_OK be returned. otherwise (and usually), ASE_NotPresent + should be returned in order to prevent further calls to this + function. note that the host may want to determine if it is + to use this when the system is not yet fully initialized, so + ASE_OK should always be returned if the mechanism makes sense. + Notes: + please remeber to adjust ASIOGetLatencies() according to + whether ASIOOutputReady() was ever called or not, if your + driver supports this scenario. + also note that the engine may fail to call ASIO_OutputReady() + in time in overload cases. as already mentioned, bufferSwitch + should be called for every block regardless of whether a block + could be processed in time. +*/ + +// restore old alignment +#if defined(_MSC_VER) && !defined(__MWERKS__) +#pragma pack(pop) +#elif PRAGMA_ALIGN_SUPPORTED +#pragma options align = reset +#endif + +#endif + diff --git a/lib-src/rtaudio/tests/Windows/asiodrivers.cpp b/lib-src/rtaudio/tests/Windows/asiodrivers.cpp index 5f56454c2..4067bc0b5 100644 --- a/lib-src/rtaudio/tests/Windows/asiodrivers.cpp +++ b/lib-src/rtaudio/tests/Windows/asiodrivers.cpp @@ -1,186 +1,186 @@ -#include -#include "asiodrivers.h" - -AsioDrivers* asioDrivers = 0; - -bool loadAsioDriver(char *name); - -bool loadAsioDriver(char *name) -{ - if(!asioDrivers) - asioDrivers = new AsioDrivers(); - if(asioDrivers) - return asioDrivers->loadDriver(name); - return false; -} - -//------------------------------------------------------------------------------------ - -#if MAC - -bool resolveASIO(unsigned long aconnID); - -AsioDrivers::AsioDrivers() : CodeFragments("ASIO Drivers", 'AsDr', 'Asio') -{ - connID = -1; - curIndex = -1; -} - -AsioDrivers::~AsioDrivers() -{ - removeCurrentDriver(); -} - -bool AsioDrivers::getCurrentDriverName(char *name) -{ - if(curIndex >= 0) - return getName(curIndex, name); - return false; -} - -long AsioDrivers::getDriverNames(char **names, long maxDrivers) -{ - for(long i = 0; i < getNumFragments() && i < maxDrivers; i++) - getName(i, names[i]); - return getNumFragments() < maxDrivers ? getNumFragments() : maxDrivers; -} - -bool AsioDrivers::loadDriver(char *name) -{ - char dname[64]; - unsigned long newID; - - for(long i = 0; i < getNumFragments(); i++) - { - if(getName(i, dname) && !strcmp(name, dname)) - { - if(newInstance(i, &newID)) - { - if(resolveASIO(newID)) - { - if(connID != -1) - removeInstance(curIndex, connID); - curIndex = i; - connID = newID; - return true; - } - } - break; - } - } - return false; -} - -void AsioDrivers::removeCurrentDriver() -{ - if(connID != -1) - removeInstance(curIndex, connID); - connID = -1; - curIndex = -1; -} - -//------------------------------------------------------------------------------------ - -#elif WINDOWS - -#include "iasiodrv.h" - -extern IASIO* theAsioDriver; - -AsioDrivers::AsioDrivers() : AsioDriverList() -{ - curIndex = -1; -} - -AsioDrivers::~AsioDrivers() -{ -} - -bool AsioDrivers::getCurrentDriverName(char *name) -{ - if(curIndex >= 0) - return asioGetDriverName(curIndex, name, 32) == 0 ? true : false; - name[0] = 0; - return false; -} - -long AsioDrivers::getDriverNames(char **names, long maxDrivers) -{ - for(long i = 0; i < asioGetNumDev() && i < maxDrivers; i++) - asioGetDriverName(i, names[i], 32); - return asioGetNumDev() < maxDrivers ? asioGetNumDev() : maxDrivers; -} - -bool AsioDrivers::loadDriver(char *name) -{ - char dname[64]; - char curName[64]; - - for(long i = 0; i < asioGetNumDev(); i++) - { - if(!asioGetDriverName(i, dname, 32) && !strcmp(name, dname)) - { - curName[0] = 0; - getCurrentDriverName(curName); // in case we fail... - removeCurrentDriver(); - - if(!asioOpenDriver(i, (void **)&theAsioDriver)) - { - curIndex = i; - return true; - } - else - { - theAsioDriver = 0; - if(curName[0] && strcmp(dname, curName)) - loadDriver(curName); // try restore - } - break; - } - } - return false; -} - -void AsioDrivers::removeCurrentDriver() -{ - if(curIndex != -1) - asioCloseDriver(curIndex); - curIndex = -1; -} - -#elif SGI || BEOS - -#include "asiolist.h" - -AsioDrivers::AsioDrivers() - : AsioDriverList() -{ - curIndex = -1; -} - -AsioDrivers::~AsioDrivers() -{ -} - -bool AsioDrivers::getCurrentDriverName(char *name) -{ - return false; -} - -long AsioDrivers::getDriverNames(char **names, long maxDrivers) -{ - return 0; -} - -bool AsioDrivers::loadDriver(char *name) -{ - return false; -} - -void AsioDrivers::removeCurrentDriver() -{ -} - -#else -#error implement me -#endif +#include +#include "asiodrivers.h" + +AsioDrivers* asioDrivers = 0; + +bool loadAsioDriver(char *name); + +bool loadAsioDriver(char *name) +{ + if(!asioDrivers) + asioDrivers = new AsioDrivers(); + if(asioDrivers) + return asioDrivers->loadDriver(name); + return false; +} + +//------------------------------------------------------------------------------------ + +#if MAC + +bool resolveASIO(unsigned long aconnID); + +AsioDrivers::AsioDrivers() : CodeFragments("ASIO Drivers", 'AsDr', 'Asio') +{ + connID = -1; + curIndex = -1; +} + +AsioDrivers::~AsioDrivers() +{ + removeCurrentDriver(); +} + +bool AsioDrivers::getCurrentDriverName(char *name) +{ + if(curIndex >= 0) + return getName(curIndex, name); + return false; +} + +long AsioDrivers::getDriverNames(char **names, long maxDrivers) +{ + for(long i = 0; i < getNumFragments() && i < maxDrivers; i++) + getName(i, names[i]); + return getNumFragments() < maxDrivers ? getNumFragments() : maxDrivers; +} + +bool AsioDrivers::loadDriver(char *name) +{ + char dname[64]; + unsigned long newID; + + for(long i = 0; i < getNumFragments(); i++) + { + if(getName(i, dname) && !strcmp(name, dname)) + { + if(newInstance(i, &newID)) + { + if(resolveASIO(newID)) + { + if(connID != -1) + removeInstance(curIndex, connID); + curIndex = i; + connID = newID; + return true; + } + } + break; + } + } + return false; +} + +void AsioDrivers::removeCurrentDriver() +{ + if(connID != -1) + removeInstance(curIndex, connID); + connID = -1; + curIndex = -1; +} + +//------------------------------------------------------------------------------------ + +#elif WINDOWS + +#include "iasiodrv.h" + +extern IASIO* theAsioDriver; + +AsioDrivers::AsioDrivers() : AsioDriverList() +{ + curIndex = -1; +} + +AsioDrivers::~AsioDrivers() +{ +} + +bool AsioDrivers::getCurrentDriverName(char *name) +{ + if(curIndex >= 0) + return asioGetDriverName(curIndex, name, 32) == 0 ? true : false; + name[0] = 0; + return false; +} + +long AsioDrivers::getDriverNames(char **names, long maxDrivers) +{ + for(long i = 0; i < asioGetNumDev() && i < maxDrivers; i++) + asioGetDriverName(i, names[i], 32); + return asioGetNumDev() < maxDrivers ? asioGetNumDev() : maxDrivers; +} + +bool AsioDrivers::loadDriver(char *name) +{ + char dname[64]; + char curName[64]; + + for(long i = 0; i < asioGetNumDev(); i++) + { + if(!asioGetDriverName(i, dname, 32) && !strcmp(name, dname)) + { + curName[0] = 0; + getCurrentDriverName(curName); // in case we fail... + removeCurrentDriver(); + + if(!asioOpenDriver(i, (void **)&theAsioDriver)) + { + curIndex = i; + return true; + } + else + { + theAsioDriver = 0; + if(curName[0] && strcmp(dname, curName)) + loadDriver(curName); // try restore + } + break; + } + } + return false; +} + +void AsioDrivers::removeCurrentDriver() +{ + if(curIndex != -1) + asioCloseDriver(curIndex); + curIndex = -1; +} + +#elif SGI || BEOS + +#include "asiolist.h" + +AsioDrivers::AsioDrivers() + : AsioDriverList() +{ + curIndex = -1; +} + +AsioDrivers::~AsioDrivers() +{ +} + +bool AsioDrivers::getCurrentDriverName(char *name) +{ + return false; +} + +long AsioDrivers::getDriverNames(char **names, long maxDrivers) +{ + return 0; +} + +bool AsioDrivers::loadDriver(char *name) +{ + return false; +} + +void AsioDrivers::removeCurrentDriver() +{ +} + +#else +#error implement me +#endif diff --git a/lib-src/rtaudio/tests/Windows/asiodrivers.h b/lib-src/rtaudio/tests/Windows/asiodrivers.h index 2ddf7ad02..511f2ea45 100644 --- a/lib-src/rtaudio/tests/Windows/asiodrivers.h +++ b/lib-src/rtaudio/tests/Windows/asiodrivers.h @@ -1,41 +1,41 @@ -#ifndef __AsioDrivers__ -#define __AsioDrivers__ - -#include "ginclude.h" - -#if MAC -#include "CodeFragments.hpp" - -class AsioDrivers : public CodeFragments - -#elif WINDOWS -#include -#include "asiolist.h" - -class AsioDrivers : public AsioDriverList - -#elif SGI || BEOS -#include "asiolist.h" - -class AsioDrivers : public AsioDriverList - -#else -#error implement me -#endif - -{ -public: - AsioDrivers(); - ~AsioDrivers(); - - bool getCurrentDriverName(char *name); - long getDriverNames(char **names, long maxDrivers); - bool loadDriver(char *name); - void removeCurrentDriver(); - long getCurrentDriverIndex() {return curIndex;} -protected: - unsigned long connID; - long curIndex; -}; - -#endif +#ifndef __AsioDrivers__ +#define __AsioDrivers__ + +#include "ginclude.h" + +#if MAC +#include "CodeFragments.hpp" + +class AsioDrivers : public CodeFragments + +#elif WINDOWS +#include +#include "asiolist.h" + +class AsioDrivers : public AsioDriverList + +#elif SGI || BEOS +#include "asiolist.h" + +class AsioDrivers : public AsioDriverList + +#else +#error implement me +#endif + +{ +public: + AsioDrivers(); + ~AsioDrivers(); + + bool getCurrentDriverName(char *name); + long getDriverNames(char **names, long maxDrivers); + bool loadDriver(char *name); + void removeCurrentDriver(); + long getCurrentDriverIndex() {return curIndex;} +protected: + unsigned long connID; + long curIndex; +}; + +#endif diff --git a/lib-src/rtaudio/tests/Windows/asiodrvr.h b/lib-src/rtaudio/tests/Windows/asiodrvr.h index 663f75a74..1670dfac6 100644 --- a/lib-src/rtaudio/tests/Windows/asiodrvr.h +++ b/lib-src/rtaudio/tests/Windows/asiodrvr.h @@ -1,76 +1,76 @@ -/* - Steinberg Audio Stream I/O API - (c) 1996, Steinberg Soft- und Hardware GmbH - charlie (May 1996) - - asiodrvr.h - c++ superclass to implement asio functionality. from this, - you can derive whatever required -*/ - -#ifndef _asiodrvr_ -#define _asiodrvr_ - -// cpu and os system we are running on -#include "asiosys.h" -// basic "C" interface -#include "asio.h" - -class AsioDriver; -extern AsioDriver *getDriver(); // for generic constructor - -#if WINDOWS -#include -#include "combase.h" -#include "iasiodrv.h" -class AsioDriver : public IASIO ,public CUnknown -{ -public: - AsioDriver(LPUNKNOWN pUnk, HRESULT *phr); - - DECLARE_IUNKNOWN - // Factory method - static CUnknown *CreateInstance(LPUNKNOWN pUnk, HRESULT *phr); - // IUnknown - virtual HRESULT STDMETHODCALLTYPE NonDelegatingQueryInterface(REFIID riid,void **ppvObject); - -#else - -class AsioDriver -{ -public: - AsioDriver(); -#endif - virtual ~AsioDriver(); - - virtual ASIOBool init(void* sysRef); - virtual void getDriverName(char *name); // max 32 bytes incl. terminating zero - virtual long getDriverVersion(); - virtual void getErrorMessage(char *string); // max 124 bytes incl. - - virtual ASIOError start(); - virtual ASIOError stop(); - - virtual ASIOError getChannels(long *numInputChannels, long *numOutputChannels); - virtual ASIOError getLatencies(long *inputLatency, long *outputLatency); - virtual ASIOError getBufferSize(long *minSize, long *maxSize, - long *preferredSize, long *granularity); - - virtual ASIOError canSampleRate(ASIOSampleRate sampleRate); - virtual ASIOError getSampleRate(ASIOSampleRate *sampleRate); - virtual ASIOError setSampleRate(ASIOSampleRate sampleRate); - virtual ASIOError getClockSources(ASIOClockSource *clocks, long *numSources); - virtual ASIOError setClockSource(long reference); - - virtual ASIOError getSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp); - virtual ASIOError getChannelInfo(ASIOChannelInfo *info); - - virtual ASIOError createBuffers(ASIOBufferInfo *bufferInfos, long numChannels, - long bufferSize, ASIOCallbacks *callbacks); - virtual ASIOError disposeBuffers(); - - virtual ASIOError controlPanel(); - virtual ASIOError future(long selector, void *opt); - virtual ASIOError outputReady(); -}; -#endif +/* + Steinberg Audio Stream I/O API + (c) 1996, Steinberg Soft- und Hardware GmbH + charlie (May 1996) + + asiodrvr.h + c++ superclass to implement asio functionality. from this, + you can derive whatever required +*/ + +#ifndef _asiodrvr_ +#define _asiodrvr_ + +// cpu and os system we are running on +#include "asiosys.h" +// basic "C" interface +#include "asio.h" + +class AsioDriver; +extern AsioDriver *getDriver(); // for generic constructor + +#if WINDOWS +#include +#include "combase.h" +#include "iasiodrv.h" +class AsioDriver : public IASIO ,public CUnknown +{ +public: + AsioDriver(LPUNKNOWN pUnk, HRESULT *phr); + + DECLARE_IUNKNOWN + // Factory method + static CUnknown *CreateInstance(LPUNKNOWN pUnk, HRESULT *phr); + // IUnknown + virtual HRESULT STDMETHODCALLTYPE NonDelegatingQueryInterface(REFIID riid,void **ppvObject); + +#else + +class AsioDriver +{ +public: + AsioDriver(); +#endif + virtual ~AsioDriver(); + + virtual ASIOBool init(void* sysRef); + virtual void getDriverName(char *name); // max 32 bytes incl. terminating zero + virtual long getDriverVersion(); + virtual void getErrorMessage(char *string); // max 124 bytes incl. + + virtual ASIOError start(); + virtual ASIOError stop(); + + virtual ASIOError getChannels(long *numInputChannels, long *numOutputChannels); + virtual ASIOError getLatencies(long *inputLatency, long *outputLatency); + virtual ASIOError getBufferSize(long *minSize, long *maxSize, + long *preferredSize, long *granularity); + + virtual ASIOError canSampleRate(ASIOSampleRate sampleRate); + virtual ASIOError getSampleRate(ASIOSampleRate *sampleRate); + virtual ASIOError setSampleRate(ASIOSampleRate sampleRate); + virtual ASIOError getClockSources(ASIOClockSource *clocks, long *numSources); + virtual ASIOError setClockSource(long reference); + + virtual ASIOError getSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp); + virtual ASIOError getChannelInfo(ASIOChannelInfo *info); + + virtual ASIOError createBuffers(ASIOBufferInfo *bufferInfos, long numChannels, + long bufferSize, ASIOCallbacks *callbacks); + virtual ASIOError disposeBuffers(); + + virtual ASIOError controlPanel(); + virtual ASIOError future(long selector, void *opt); + virtual ASIOError outputReady(); +}; +#endif diff --git a/lib-src/rtaudio/tests/Windows/asiolist.cpp b/lib-src/rtaudio/tests/Windows/asiolist.cpp index 5a62f5bc0..88b1632ba 100644 --- a/lib-src/rtaudio/tests/Windows/asiolist.cpp +++ b/lib-src/rtaudio/tests/Windows/asiolist.cpp @@ -1,268 +1,268 @@ -#include -#include "iasiodrv.h" -#include "asiolist.h" - -#define ASIODRV_DESC "description" -#define INPROC_SERVER "InprocServer32" -#define ASIO_PATH "software\\asio" -#define COM_CLSID "clsid" - -// ****************************************************************** -// Local Functions -// ****************************************************************** -static LONG findDrvPath (char *clsidstr,char *dllpath,int dllpathsize) -{ - HKEY hkEnum,hksub,hkpath; - char databuf[512]; - LONG cr,rc = -1; - DWORD datatype,datasize; - DWORD index; - OFSTRUCT ofs; - HFILE hfile; - BOOL found = FALSE; - - CharLowerBuff(clsidstr,strlen(clsidstr)); - if ((cr = RegOpenKey(HKEY_CLASSES_ROOT,COM_CLSID,&hkEnum)) == ERROR_SUCCESS) { - - index = 0; - while (cr == ERROR_SUCCESS && !found) { - cr = RegEnumKey(hkEnum,index++,(LPTSTR)databuf,512); - if (cr == ERROR_SUCCESS) { - CharLowerBuff(databuf,strlen(databuf)); - if (!(strcmp(databuf,clsidstr))) { - if ((cr = RegOpenKeyEx(hkEnum,(LPCTSTR)databuf,0,KEY_READ,&hksub)) == ERROR_SUCCESS) { - if ((cr = RegOpenKeyEx(hksub,(LPCTSTR)INPROC_SERVER,0,KEY_READ,&hkpath)) == ERROR_SUCCESS) { - datatype = REG_SZ; datasize = (DWORD)dllpathsize; - cr = RegQueryValueEx(hkpath,0,0,&datatype,(LPBYTE)dllpath,&datasize); - if (cr == ERROR_SUCCESS) { - memset(&ofs,0,sizeof(OFSTRUCT)); - ofs.cBytes = sizeof(OFSTRUCT); - hfile = OpenFile(dllpath,&ofs,OF_EXIST); - if (hfile) rc = 0; - } - RegCloseKey(hkpath); - } - RegCloseKey(hksub); - } - found = TRUE; // break out - } - } - } - RegCloseKey(hkEnum); - } - return rc; -} - - -static LPASIODRVSTRUCT newDrvStruct (HKEY hkey,char *keyname,int drvID,LPASIODRVSTRUCT lpdrv) -{ - HKEY hksub; - char databuf[256]; - char dllpath[MAXPATHLEN]; - WORD wData[100]; - CLSID clsid; - DWORD datatype,datasize; - LONG cr,rc; - - if (!lpdrv) { - if ((cr = RegOpenKeyEx(hkey,(LPCTSTR)keyname,0,KEY_READ,&hksub)) == ERROR_SUCCESS) { - - datatype = REG_SZ; datasize = 256; - cr = RegQueryValueEx(hksub,COM_CLSID,0,&datatype,(LPBYTE)databuf,&datasize); - if (cr == ERROR_SUCCESS) { - rc = findDrvPath (databuf,dllpath,MAXPATHLEN); - if (rc == 0) { - lpdrv = new ASIODRVSTRUCT[1]; - if (lpdrv) { - memset(lpdrv,0,sizeof(ASIODRVSTRUCT)); - lpdrv->drvID = drvID; - MultiByteToWideChar(CP_ACP,0,(LPCSTR)databuf,-1,(LPWSTR)wData,100); - if ((cr = CLSIDFromString((LPOLESTR)wData,(LPCLSID)&clsid)) == S_OK) { - memcpy(&lpdrv->clsid,&clsid,sizeof(CLSID)); - } - - datatype = REG_SZ; datasize = 256; - cr = RegQueryValueEx(hksub,ASIODRV_DESC,0,&datatype,(LPBYTE)databuf,&datasize); - if (cr == ERROR_SUCCESS) { - strcpy(lpdrv->drvname,databuf); - } - else strcpy(lpdrv->drvname,keyname); - } - } - } - RegCloseKey(hksub); - } - } - else lpdrv->next = newDrvStruct(hkey,keyname,drvID+1,lpdrv->next); - - return lpdrv; -} - -static void deleteDrvStruct (LPASIODRVSTRUCT lpdrv) -{ - IASIO *iasio; - - if (lpdrv != 0) { - deleteDrvStruct(lpdrv->next); - if (lpdrv->asiodrv) { - iasio = (IASIO *)lpdrv->asiodrv; - iasio->Release(); - } - delete lpdrv; - } -} - - -static LPASIODRVSTRUCT getDrvStruct (int drvID,LPASIODRVSTRUCT lpdrv) -{ - while (lpdrv) { - if (lpdrv->drvID == drvID) return lpdrv; - lpdrv = lpdrv->next; - } - return 0; -} -// ****************************************************************** - - -// ****************************************************************** -// AsioDriverList -// ****************************************************************** -AsioDriverList::AsioDriverList () -{ - HKEY hkEnum = 0; - char keyname[MAXDRVNAMELEN]; - LPASIODRVSTRUCT pdl; - LONG cr; - DWORD index = 0; - BOOL fin = FALSE; - - numdrv = 0; - lpdrvlist = 0; - - cr = RegOpenKey(HKEY_LOCAL_MACHINE,ASIO_PATH,&hkEnum); - while (cr == ERROR_SUCCESS) { - if ((cr = RegEnumKey(hkEnum,index++,(LPTSTR)keyname,MAXDRVNAMELEN))== ERROR_SUCCESS) { - lpdrvlist = newDrvStruct (hkEnum,keyname,0,lpdrvlist); - } - else fin = TRUE; - } - if (hkEnum) RegCloseKey(hkEnum); - - pdl = lpdrvlist; - while (pdl) { - numdrv++; - pdl = pdl->next; - } - - if (numdrv) CoInitialize(0); // initialize COM -} - -AsioDriverList::~AsioDriverList () -{ - if (numdrv) { - deleteDrvStruct(lpdrvlist); - CoUninitialize(); - } -} - - -LONG AsioDriverList::asioGetNumDev (VOID) -{ - return (LONG)numdrv; -} - - -LONG AsioDriverList::asioOpenDriver (int drvID,LPVOID *asiodrv) -{ - LPASIODRVSTRUCT lpdrv = 0; - long rc; - - if (!asiodrv) return DRVERR_INVALID_PARAM; - - if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) { - if (!lpdrv->asiodrv) { - rc = CoCreateInstance(lpdrv->clsid,0,CLSCTX_INPROC_SERVER,lpdrv->clsid,asiodrv); - if (rc == S_OK) { - lpdrv->asiodrv = *asiodrv; - return 0; - } - // else if (rc == REGDB_E_CLASSNOTREG) - // strcpy (info->messageText, "Driver not registered in the Registration Database!"); - } - else rc = DRVERR_DEVICE_ALREADY_OPEN; - } - else rc = DRVERR_DEVICE_NOT_FOUND; - - return rc; -} - - -LONG AsioDriverList::asioCloseDriver (int drvID) -{ - LPASIODRVSTRUCT lpdrv = 0; - IASIO *iasio; - - if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) { - if (lpdrv->asiodrv) { - iasio = (IASIO *)lpdrv->asiodrv; - iasio->Release(); - lpdrv->asiodrv = 0; - } - } - - return 0; -} - -LONG AsioDriverList::asioGetDriverName (int drvID,char *drvname,int drvnamesize) -{ - LPASIODRVSTRUCT lpdrv = 0; - - if (!drvname) return DRVERR_INVALID_PARAM; - - if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) { - if (strlen(lpdrv->drvname) < (unsigned int)drvnamesize) { - strcpy(drvname,lpdrv->drvname); - } - else { - memcpy(drvname,lpdrv->drvname,drvnamesize-4); - drvname[drvnamesize-4] = '.'; - drvname[drvnamesize-3] = '.'; - drvname[drvnamesize-2] = '.'; - drvname[drvnamesize-1] = 0; - } - return 0; - } - return DRVERR_DEVICE_NOT_FOUND; -} - -LONG AsioDriverList::asioGetDriverPath (int drvID,char *dllpath,int dllpathsize) -{ - LPASIODRVSTRUCT lpdrv = 0; - - if (!dllpath) return DRVERR_INVALID_PARAM; - - if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) { - if (strlen(lpdrv->dllpath) < (unsigned int)dllpathsize) { - strcpy(dllpath,lpdrv->dllpath); - return 0; - } - dllpath[0] = 0; - return DRVERR_INVALID_PARAM; - } - return DRVERR_DEVICE_NOT_FOUND; -} - -LONG AsioDriverList::asioGetDriverCLSID (int drvID,CLSID *clsid) -{ - LPASIODRVSTRUCT lpdrv = 0; - - if (!clsid) return DRVERR_INVALID_PARAM; - - if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) { - memcpy(clsid,&lpdrv->clsid,sizeof(CLSID)); - return 0; - } - return DRVERR_DEVICE_NOT_FOUND; -} - - +#include +#include "iasiodrv.h" +#include "asiolist.h" + +#define ASIODRV_DESC "description" +#define INPROC_SERVER "InprocServer32" +#define ASIO_PATH "software\\asio" +#define COM_CLSID "clsid" + +// ****************************************************************** +// Local Functions +// ****************************************************************** +static LONG findDrvPath (char *clsidstr,char *dllpath,int dllpathsize) +{ + HKEY hkEnum,hksub,hkpath; + char databuf[512]; + LONG cr,rc = -1; + DWORD datatype,datasize; + DWORD index; + OFSTRUCT ofs; + HFILE hfile; + BOOL found = FALSE; + + CharLowerBuff(clsidstr,strlen(clsidstr)); + if ((cr = RegOpenKey(HKEY_CLASSES_ROOT,COM_CLSID,&hkEnum)) == ERROR_SUCCESS) { + + index = 0; + while (cr == ERROR_SUCCESS && !found) { + cr = RegEnumKey(hkEnum,index++,(LPTSTR)databuf,512); + if (cr == ERROR_SUCCESS) { + CharLowerBuff(databuf,strlen(databuf)); + if (!(strcmp(databuf,clsidstr))) { + if ((cr = RegOpenKeyEx(hkEnum,(LPCTSTR)databuf,0,KEY_READ,&hksub)) == ERROR_SUCCESS) { + if ((cr = RegOpenKeyEx(hksub,(LPCTSTR)INPROC_SERVER,0,KEY_READ,&hkpath)) == ERROR_SUCCESS) { + datatype = REG_SZ; datasize = (DWORD)dllpathsize; + cr = RegQueryValueEx(hkpath,0,0,&datatype,(LPBYTE)dllpath,&datasize); + if (cr == ERROR_SUCCESS) { + memset(&ofs,0,sizeof(OFSTRUCT)); + ofs.cBytes = sizeof(OFSTRUCT); + hfile = OpenFile(dllpath,&ofs,OF_EXIST); + if (hfile) rc = 0; + } + RegCloseKey(hkpath); + } + RegCloseKey(hksub); + } + found = TRUE; // break out + } + } + } + RegCloseKey(hkEnum); + } + return rc; +} + + +static LPASIODRVSTRUCT newDrvStruct (HKEY hkey,char *keyname,int drvID,LPASIODRVSTRUCT lpdrv) +{ + HKEY hksub; + char databuf[256]; + char dllpath[MAXPATHLEN]; + WORD wData[100]; + CLSID clsid; + DWORD datatype,datasize; + LONG cr,rc; + + if (!lpdrv) { + if ((cr = RegOpenKeyEx(hkey,(LPCTSTR)keyname,0,KEY_READ,&hksub)) == ERROR_SUCCESS) { + + datatype = REG_SZ; datasize = 256; + cr = RegQueryValueEx(hksub,COM_CLSID,0,&datatype,(LPBYTE)databuf,&datasize); + if (cr == ERROR_SUCCESS) { + rc = findDrvPath (databuf,dllpath,MAXPATHLEN); + if (rc == 0) { + lpdrv = new ASIODRVSTRUCT[1]; + if (lpdrv) { + memset(lpdrv,0,sizeof(ASIODRVSTRUCT)); + lpdrv->drvID = drvID; + MultiByteToWideChar(CP_ACP,0,(LPCSTR)databuf,-1,(LPWSTR)wData,100); + if ((cr = CLSIDFromString((LPOLESTR)wData,(LPCLSID)&clsid)) == S_OK) { + memcpy(&lpdrv->clsid,&clsid,sizeof(CLSID)); + } + + datatype = REG_SZ; datasize = 256; + cr = RegQueryValueEx(hksub,ASIODRV_DESC,0,&datatype,(LPBYTE)databuf,&datasize); + if (cr == ERROR_SUCCESS) { + strcpy(lpdrv->drvname,databuf); + } + else strcpy(lpdrv->drvname,keyname); + } + } + } + RegCloseKey(hksub); + } + } + else lpdrv->next = newDrvStruct(hkey,keyname,drvID+1,lpdrv->next); + + return lpdrv; +} + +static void deleteDrvStruct (LPASIODRVSTRUCT lpdrv) +{ + IASIO *iasio; + + if (lpdrv != 0) { + deleteDrvStruct(lpdrv->next); + if (lpdrv->asiodrv) { + iasio = (IASIO *)lpdrv->asiodrv; + iasio->Release(); + } + delete lpdrv; + } +} + + +static LPASIODRVSTRUCT getDrvStruct (int drvID,LPASIODRVSTRUCT lpdrv) +{ + while (lpdrv) { + if (lpdrv->drvID == drvID) return lpdrv; + lpdrv = lpdrv->next; + } + return 0; +} +// ****************************************************************** + + +// ****************************************************************** +// AsioDriverList +// ****************************************************************** +AsioDriverList::AsioDriverList () +{ + HKEY hkEnum = 0; + char keyname[MAXDRVNAMELEN]; + LPASIODRVSTRUCT pdl; + LONG cr; + DWORD index = 0; + BOOL fin = FALSE; + + numdrv = 0; + lpdrvlist = 0; + + cr = RegOpenKey(HKEY_LOCAL_MACHINE,ASIO_PATH,&hkEnum); + while (cr == ERROR_SUCCESS) { + if ((cr = RegEnumKey(hkEnum,index++,(LPTSTR)keyname,MAXDRVNAMELEN))== ERROR_SUCCESS) { + lpdrvlist = newDrvStruct (hkEnum,keyname,0,lpdrvlist); + } + else fin = TRUE; + } + if (hkEnum) RegCloseKey(hkEnum); + + pdl = lpdrvlist; + while (pdl) { + numdrv++; + pdl = pdl->next; + } + + if (numdrv) CoInitialize(0); // initialize COM +} + +AsioDriverList::~AsioDriverList () +{ + if (numdrv) { + deleteDrvStruct(lpdrvlist); + CoUninitialize(); + } +} + + +LONG AsioDriverList::asioGetNumDev (VOID) +{ + return (LONG)numdrv; +} + + +LONG AsioDriverList::asioOpenDriver (int drvID,LPVOID *asiodrv) +{ + LPASIODRVSTRUCT lpdrv = 0; + long rc; + + if (!asiodrv) return DRVERR_INVALID_PARAM; + + if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) { + if (!lpdrv->asiodrv) { + rc = CoCreateInstance(lpdrv->clsid,0,CLSCTX_INPROC_SERVER,lpdrv->clsid,asiodrv); + if (rc == S_OK) { + lpdrv->asiodrv = *asiodrv; + return 0; + } + // else if (rc == REGDB_E_CLASSNOTREG) + // strcpy (info->messageText, "Driver not registered in the Registration Database!"); + } + else rc = DRVERR_DEVICE_ALREADY_OPEN; + } + else rc = DRVERR_DEVICE_NOT_FOUND; + + return rc; +} + + +LONG AsioDriverList::asioCloseDriver (int drvID) +{ + LPASIODRVSTRUCT lpdrv = 0; + IASIO *iasio; + + if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) { + if (lpdrv->asiodrv) { + iasio = (IASIO *)lpdrv->asiodrv; + iasio->Release(); + lpdrv->asiodrv = 0; + } + } + + return 0; +} + +LONG AsioDriverList::asioGetDriverName (int drvID,char *drvname,int drvnamesize) +{ + LPASIODRVSTRUCT lpdrv = 0; + + if (!drvname) return DRVERR_INVALID_PARAM; + + if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) { + if (strlen(lpdrv->drvname) < (unsigned int)drvnamesize) { + strcpy(drvname,lpdrv->drvname); + } + else { + memcpy(drvname,lpdrv->drvname,drvnamesize-4); + drvname[drvnamesize-4] = '.'; + drvname[drvnamesize-3] = '.'; + drvname[drvnamesize-2] = '.'; + drvname[drvnamesize-1] = 0; + } + return 0; + } + return DRVERR_DEVICE_NOT_FOUND; +} + +LONG AsioDriverList::asioGetDriverPath (int drvID,char *dllpath,int dllpathsize) +{ + LPASIODRVSTRUCT lpdrv = 0; + + if (!dllpath) return DRVERR_INVALID_PARAM; + + if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) { + if (strlen(lpdrv->dllpath) < (unsigned int)dllpathsize) { + strcpy(dllpath,lpdrv->dllpath); + return 0; + } + dllpath[0] = 0; + return DRVERR_INVALID_PARAM; + } + return DRVERR_DEVICE_NOT_FOUND; +} + +LONG AsioDriverList::asioGetDriverCLSID (int drvID,CLSID *clsid) +{ + LPASIODRVSTRUCT lpdrv = 0; + + if (!clsid) return DRVERR_INVALID_PARAM; + + if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) { + memcpy(clsid,&lpdrv->clsid,sizeof(CLSID)); + return 0; + } + return DRVERR_DEVICE_NOT_FOUND; +} + + diff --git a/lib-src/rtaudio/tests/Windows/asiolist.h b/lib-src/rtaudio/tests/Windows/asiolist.h index 01c64f0bb..1f504af3c 100644 --- a/lib-src/rtaudio/tests/Windows/asiolist.h +++ b/lib-src/rtaudio/tests/Windows/asiolist.h @@ -1,46 +1,46 @@ -#ifndef __asiolist__ -#define __asiolist__ - -#define DRVERR -5000 -#define DRVERR_INVALID_PARAM DRVERR-1 -#define DRVERR_DEVICE_ALREADY_OPEN DRVERR-2 -#define DRVERR_DEVICE_NOT_FOUND DRVERR-3 - -#define MAXPATHLEN 512 -#define MAXDRVNAMELEN 128 - -struct asiodrvstruct -{ - int drvID; - CLSID clsid; - char dllpath[MAXPATHLEN]; - char drvname[MAXDRVNAMELEN]; - LPVOID asiodrv; - struct asiodrvstruct *next; -}; - -typedef struct asiodrvstruct ASIODRVSTRUCT; -typedef ASIODRVSTRUCT *LPASIODRVSTRUCT; - -class AsioDriverList { -public: - AsioDriverList(); - ~AsioDriverList(); - - LONG asioOpenDriver (int,VOID **); - LONG asioCloseDriver (int); - - // nice to have - LONG asioGetNumDev (VOID); - LONG asioGetDriverName (int,char *,int); - LONG asioGetDriverPath (int,char *,int); - LONG asioGetDriverCLSID (int,CLSID *); - - // or use directly access - LPASIODRVSTRUCT lpdrvlist; - int numdrv; -}; - -typedef class AsioDriverList *LPASIODRIVERLIST; - -#endif +#ifndef __asiolist__ +#define __asiolist__ + +#define DRVERR -5000 +#define DRVERR_INVALID_PARAM DRVERR-1 +#define DRVERR_DEVICE_ALREADY_OPEN DRVERR-2 +#define DRVERR_DEVICE_NOT_FOUND DRVERR-3 + +#define MAXPATHLEN 512 +#define MAXDRVNAMELEN 128 + +struct asiodrvstruct +{ + int drvID; + CLSID clsid; + char dllpath[MAXPATHLEN]; + char drvname[MAXDRVNAMELEN]; + LPVOID asiodrv; + struct asiodrvstruct *next; +}; + +typedef struct asiodrvstruct ASIODRVSTRUCT; +typedef ASIODRVSTRUCT *LPASIODRVSTRUCT; + +class AsioDriverList { +public: + AsioDriverList(); + ~AsioDriverList(); + + LONG asioOpenDriver (int,VOID **); + LONG asioCloseDriver (int); + + // nice to have + LONG asioGetNumDev (VOID); + LONG asioGetDriverName (int,char *,int); + LONG asioGetDriverPath (int,char *,int); + LONG asioGetDriverCLSID (int,CLSID *); + + // or use directly access + LPASIODRVSTRUCT lpdrvlist; + int numdrv; +}; + +typedef class AsioDriverList *LPASIODRIVERLIST; + +#endif diff --git a/lib-src/rtaudio/tests/Windows/asiosys.h b/lib-src/rtaudio/tests/Windows/asiosys.h index 37f7a48a1..a61c23319 100644 --- a/lib-src/rtaudio/tests/Windows/asiosys.h +++ b/lib-src/rtaudio/tests/Windows/asiosys.h @@ -1,82 +1,82 @@ -#ifndef __asiosys__ - #define __asiosys__ - - #ifdef WIN32 - #undef MAC - #define PPC 0 - #define WINDOWS 1 - #define SGI 0 - #define SUN 0 - #define LINUX 0 - #define BEOS 0 - - #define NATIVE_INT64 0 - #define IEEE754_64FLOAT 1 - - #elif BEOS - #define MAC 0 - #define PPC 0 - #define WINDOWS 0 - #define PC 0 - #define SGI 0 - #define SUN 0 - #define LINUX 0 - - #define NATIVE_INT64 0 - #define IEEE754_64FLOAT 1 - - #ifndef DEBUG - #define DEBUG 0 - #if DEBUG - void DEBUGGERMESSAGE(char *string); - #else - #define DEBUGGERMESSAGE(a) - #endif - #endif - - #elif SGI - #define MAC 0 - #define PPC 0 - #define WINDOWS 0 - #define PC 0 - #define SUN 0 - #define LINUX 0 - #define BEOS 0 - - #define NATIVE_INT64 0 - #define IEEE754_64FLOAT 1 - - #ifndef DEBUG - #define DEBUG 0 - #if DEBUG - void DEBUGGERMESSAGE(char *string); - #else - #define DEBUGGERMESSAGE(a) - #endif - #endif - - #else // MAC - - #define MAC 1 - #define PPC 1 - #define WINDOWS 0 - #define PC 0 - #define SGI 0 - #define SUN 0 - #define LINUX 0 - #define BEOS 0 - - #define NATIVE_INT64 0 - #define IEEE754_64FLOAT 1 - - #ifndef DEBUG - #define DEBUG 0 - #if DEBUG - void DEBUGGERMESSAGE(char *string); - #else - #define DEBUGGERMESSAGE(a) - #endif - #endif - #endif - -#endif +#ifndef __asiosys__ + #define __asiosys__ + + #ifdef WIN32 + #undef MAC + #define PPC 0 + #define WINDOWS 1 + #define SGI 0 + #define SUN 0 + #define LINUX 0 + #define BEOS 0 + + #define NATIVE_INT64 0 + #define IEEE754_64FLOAT 1 + + #elif BEOS + #define MAC 0 + #define PPC 0 + #define WINDOWS 0 + #define PC 0 + #define SGI 0 + #define SUN 0 + #define LINUX 0 + + #define NATIVE_INT64 0 + #define IEEE754_64FLOAT 1 + + #ifndef DEBUG + #define DEBUG 0 + #if DEBUG + void DEBUGGERMESSAGE(char *string); + #else + #define DEBUGGERMESSAGE(a) + #endif + #endif + + #elif SGI + #define MAC 0 + #define PPC 0 + #define WINDOWS 0 + #define PC 0 + #define SUN 0 + #define LINUX 0 + #define BEOS 0 + + #define NATIVE_INT64 0 + #define IEEE754_64FLOAT 1 + + #ifndef DEBUG + #define DEBUG 0 + #if DEBUG + void DEBUGGERMESSAGE(char *string); + #else + #define DEBUGGERMESSAGE(a) + #endif + #endif + + #else // MAC + + #define MAC 1 + #define PPC 1 + #define WINDOWS 0 + #define PC 0 + #define SGI 0 + #define SUN 0 + #define LINUX 0 + #define BEOS 0 + + #define NATIVE_INT64 0 + #define IEEE754_64FLOAT 1 + + #ifndef DEBUG + #define DEBUG 0 + #if DEBUG + void DEBUGGERMESSAGE(char *string); + #else + #define DEBUGGERMESSAGE(a) + #endif + #endif + #endif + +#endif diff --git a/lib-src/rtaudio/tests/Windows/ginclude.h b/lib-src/rtaudio/tests/Windows/ginclude.h index b627dc2e7..5603fac86 100644 --- a/lib-src/rtaudio/tests/Windows/ginclude.h +++ b/lib-src/rtaudio/tests/Windows/ginclude.h @@ -1,38 +1,38 @@ -#ifndef __gInclude__ -#define __gInclude__ - -#if SGI - #undef BEOS - #undef MAC - #undef WINDOWS - // - #define ASIO_BIG_ENDIAN 1 - #define ASIO_CPU_MIPS 1 -#elif defined WIN32 - #undef BEOS - #undef MAC - #undef SGI - #define WINDOWS 1 - #define ASIO_LITTLE_ENDIAN 1 - #define ASIO_CPU_X86 1 -#elif BEOS - #undef MAC - #undef SGI - #undef WINDOWS - #define ASIO_LITTLE_ENDIAN 1 - #define ASIO_CPU_X86 1 - // -#else - #define MAC 1 - #undef BEOS - #undef WINDOWS - #undef SGI - #define ASIO_BIG_ENDIAN 1 - #define ASIO_CPU_PPC 1 -#endif - -// always -#define NATIVE_INT64 0 -#define IEEE754_64FLOAT 1 - -#endif // __gInclude__ +#ifndef __gInclude__ +#define __gInclude__ + +#if SGI + #undef BEOS + #undef MAC + #undef WINDOWS + // + #define ASIO_BIG_ENDIAN 1 + #define ASIO_CPU_MIPS 1 +#elif defined WIN32 + #undef BEOS + #undef MAC + #undef SGI + #define WINDOWS 1 + #define ASIO_LITTLE_ENDIAN 1 + #define ASIO_CPU_X86 1 +#elif BEOS + #undef MAC + #undef SGI + #undef WINDOWS + #define ASIO_LITTLE_ENDIAN 1 + #define ASIO_CPU_X86 1 + // +#else + #define MAC 1 + #undef BEOS + #undef WINDOWS + #undef SGI + #define ASIO_BIG_ENDIAN 1 + #define ASIO_CPU_PPC 1 +#endif + +// always +#define NATIVE_INT64 0 +#define IEEE754_64FLOAT 1 + +#endif // __gInclude__ diff --git a/lib-src/rtaudio/tests/Windows/iasiodrv.h b/lib-src/rtaudio/tests/Windows/iasiodrv.h index 64d2dbb66..1496f0fae 100644 --- a/lib-src/rtaudio/tests/Windows/iasiodrv.h +++ b/lib-src/rtaudio/tests/Windows/iasiodrv.h @@ -1,37 +1,37 @@ -#include "asiosys.h" -#include "asio.h" - -/* Forward Declarations */ - -#ifndef __ASIODRIVER_FWD_DEFINED__ -#define __ASIODRIVER_FWD_DEFINED__ -typedef interface IASIO IASIO; -#endif /* __ASIODRIVER_FWD_DEFINED__ */ - -interface IASIO : public IUnknown -{ - - virtual ASIOBool init(void *sysHandle) = 0; - virtual void getDriverName(char *name) = 0; - virtual long getDriverVersion() = 0; - virtual void getErrorMessage(char *string) = 0; - virtual ASIOError start() = 0; - virtual ASIOError stop() = 0; - virtual ASIOError getChannels(long *numInputChannels, long *numOutputChannels) = 0; - virtual ASIOError getLatencies(long *inputLatency, long *outputLatency) = 0; - virtual ASIOError getBufferSize(long *minSize, long *maxSize, - long *preferredSize, long *granularity) = 0; - virtual ASIOError canSampleRate(ASIOSampleRate sampleRate) = 0; - virtual ASIOError getSampleRate(ASIOSampleRate *sampleRate) = 0; - virtual ASIOError setSampleRate(ASIOSampleRate sampleRate) = 0; - virtual ASIOError getClockSources(ASIOClockSource *clocks, long *numSources) = 0; - virtual ASIOError setClockSource(long reference) = 0; - virtual ASIOError getSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp) = 0; - virtual ASIOError getChannelInfo(ASIOChannelInfo *info) = 0; - virtual ASIOError createBuffers(ASIOBufferInfo *bufferInfos, long numChannels, - long bufferSize, ASIOCallbacks *callbacks) = 0; - virtual ASIOError disposeBuffers() = 0; - virtual ASIOError controlPanel() = 0; - virtual ASIOError future(long selector,void *opt) = 0; - virtual ASIOError outputReady() = 0; -}; +#include "asiosys.h" +#include "asio.h" + +/* Forward Declarations */ + +#ifndef __ASIODRIVER_FWD_DEFINED__ +#define __ASIODRIVER_FWD_DEFINED__ +typedef interface IASIO IASIO; +#endif /* __ASIODRIVER_FWD_DEFINED__ */ + +interface IASIO : public IUnknown +{ + + virtual ASIOBool init(void *sysHandle) = 0; + virtual void getDriverName(char *name) = 0; + virtual long getDriverVersion() = 0; + virtual void getErrorMessage(char *string) = 0; + virtual ASIOError start() = 0; + virtual ASIOError stop() = 0; + virtual ASIOError getChannels(long *numInputChannels, long *numOutputChannels) = 0; + virtual ASIOError getLatencies(long *inputLatency, long *outputLatency) = 0; + virtual ASIOError getBufferSize(long *minSize, long *maxSize, + long *preferredSize, long *granularity) = 0; + virtual ASIOError canSampleRate(ASIOSampleRate sampleRate) = 0; + virtual ASIOError getSampleRate(ASIOSampleRate *sampleRate) = 0; + virtual ASIOError setSampleRate(ASIOSampleRate sampleRate) = 0; + virtual ASIOError getClockSources(ASIOClockSource *clocks, long *numSources) = 0; + virtual ASIOError setClockSource(long reference) = 0; + virtual ASIOError getSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp) = 0; + virtual ASIOError getChannelInfo(ASIOChannelInfo *info) = 0; + virtual ASIOError createBuffers(ASIOBufferInfo *bufferInfos, long numChannels, + long bufferSize, ASIOCallbacks *callbacks) = 0; + virtual ASIOError disposeBuffers() = 0; + virtual ASIOError controlPanel() = 0; + virtual ASIOError future(long selector,void *opt) = 0; + virtual ASIOError outputReady() = 0; +}; diff --git a/lib-src/sbsms/src/btndown.h b/lib-src/sbsms/src/btndown.h index 7a7260977..6d4dfcb85 100644 --- a/lib-src/sbsms/src/btndown.h +++ b/lib-src/sbsms/src/btndown.h @@ -1,23 +1,23 @@ -#ifndef MUSIK_BTNDOWN_EVT -#define MUSIK_BTNDOWN_EVT - -#include "wx/wx.h" - -class CBtnDownEvt : public wxEvtHandler -{ - public: - CBtnDownEvt( wxBitmapButton *parent, wxBitmap *down, wxBitmap *up ){ pParent = parent; pBtnDown = down; pBtnUp = up; }; - ~CBtnDownEvt(){}; - - void OnLeftDown ( wxMouseEvent& event ); - void OnLeftUp ( wxMouseEvent& event ); - void OnMouseMove( wxMouseEvent& event ); - void OnEraseBackground(wxEraseEvent& ) {} - DECLARE_EVENT_TABLE() - private: - wxBitmapButton *pParent; - wxBitmap *pBtnDown; - wxBitmap *pBtnUp; -}; - -#endif +#ifndef MUSIK_BTNDOWN_EVT +#define MUSIK_BTNDOWN_EVT + +#include "wx/wx.h" + +class CBtnDownEvt : public wxEvtHandler +{ + public: + CBtnDownEvt( wxBitmapButton *parent, wxBitmap *down, wxBitmap *up ){ pParent = parent; pBtnDown = down; pBtnUp = up; }; + ~CBtnDownEvt(){}; + + void OnLeftDown ( wxMouseEvent& event ); + void OnLeftUp ( wxMouseEvent& event ); + void OnMouseMove( wxMouseEvent& event ); + void OnEraseBackground(wxEraseEvent& ) {} + DECLARE_EVENT_TABLE() + private: + wxBitmapButton *pParent; + wxBitmap *pBtnDown; + wxBitmap *pBtnUp; +}; + +#endif diff --git a/lib-src/sbsms/win/config.h b/lib-src/sbsms/win/config.h old mode 100755 new mode 100644 diff --git a/lib-src/sbsms/win/libmad/libmad.vcproj b/lib-src/sbsms/win/libmad/libmad.vcproj old mode 100755 new mode 100644 diff --git a/lib-src/sbsms/win/libsndfile/libsndfile.vcproj b/lib-src/sbsms/win/libsndfile/libsndfile.vcproj old mode 100755 new mode 100644 diff --git a/lib-src/sbsms/win/portaudio-v19/portaudio-v19.vcproj b/lib-src/sbsms/win/portaudio-v19/portaudio-v19.vcproj old mode 100755 new mode 100644 diff --git a/lib-src/sbsms/win/pthread/pthread.vcproj b/lib-src/sbsms/win/pthread/pthread.vcproj old mode 100755 new mode 100644 diff --git a/lib-src/sbsms/win/sbsms/sbsms.sln b/lib-src/sbsms/win/sbsms/sbsms.sln old mode 100755 new mode 100644 diff --git a/lib-src/sbsms/win/sbsms/sbsms.vcproj b/lib-src/sbsms/win/sbsms/sbsms.vcproj old mode 100755 new mode 100644 diff --git a/lib-src/slv2/slv2/lv2_ui.h b/lib-src/slv2/slv2/lv2_ui.h index 89aa8d2e4..13a613108 100644 --- a/lib-src/slv2/slv2/lv2_ui.h +++ b/lib-src/slv2/slv2/lv2_ui.h @@ -1,372 +1,372 @@ -/************************************************************************ - * - * In-process UI extension for LV2 - * - * Copyright (C) 2006-2008 Lars Luthman - * - * Based on lv2.h, which was - * - * Copyright (C) 2000-2002 Richard W.E. Furse, Paul Barton-Davis, - * Stefan Westerfeld - * Copyright (C) 2006 Steve Harris, Dave Robillard. - * - * This header is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published - * by the Free Software Foundation; either version 2.1 of the License, - * or (at your option) any later version. - * - * This header 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 - * USA. - * - ***********************************************************************/ - -/** @file - This extension defines an interface that can be used in LV2 plugins and - hosts to create UIs for plugins. The UIs are plugins that reside in - shared object files in an LV2 bundle and are referenced in the RDF data - using the triples (Turtle shown) -
        
    -    @@prefix uiext:  .
    -        uiext:ui      .
    -        a            uiext:GtkUI .
    -      uiext:binary  .
    -
    - where is the URI of the plugin, is - the URI of the plugin UI and is the relative URI to the shared - object file. While it is possible to have the plugin UI and the plugin in - the same shared object file it is probably a good idea to keep them - separate so that hosts that don't want UIs don't have to load the UI code. - A UI MUST specify its class in the RDF data, in this case uiext:GtkUI. The - class defines what type the UI is, e.g. what graphics toolkit it uses. - There are no UI classes defined in this extension, those are specified - separately (and anyone can define their own). - - (Note: the prefix above is used throughout this file for the same URI) - - It's entirely possible to have multiple UIs for the same plugin, or to have - the UI for a plugin in a different bundle from the actual plugin - this - way people other than the plugin author can write plugin UIs independently - without editing the original plugin bundle. - - Note that the process that loads the shared object file containing the UI - code and the process that loads the shared object file containing the - actual plugin implementation does not have to be the same. There are many - valid reasons for having the plugin and the UI in different processes, or - even on different machines. This means that you can _not_ use singletons - and global variables and expect them to refer to the same objects in the - UI and the actual plugin. The function callback interface defined in this - header is all you can expect to work. - - Since the LV2 specification itself allows for extensions that may add - new types of data and configuration parameters that plugin authors may - want to control with a UI, this extension allows for meta-extensions that - can extend the interface between the UI and the host. These extensions - mirror the extensions used for plugins - there are required and optional - "features" that you declare in the RDF data for the UI as -
        
    -     uiext:requiredFeature  .
    -     uiext:optionalFeature  .
    -
    - These predicates have the same semantics as lv2:requiredFeature and - lv2:optionalFeature - if a UI is declaring a feature as required, the - host is NOT allowed to load it unless it supports that feature, and if it - does support a feature (required or optional) it MUST pass that feature's - URI and any additional data (specified by the meta-extension that defines - the feature) in a LV2_Feature struct (as defined in lv2.h) to the UI's - instantiate() function. - - These features may be used to specify how to pass data between the UI - and the plugin port buffers - see LV2UI_Write_Function for details. - - There are four features defined in this extension that hosts may want to - implement: - -
    -    uiext:makeResident
    -
    - If this feature is required by a UI the host MUST NEVER unload the shared - library containing the UI implementation during the lifetime of the host - process (e.g. never calling dlclose() on Linux). This feature may be - needed by e.g. a Gtk UI that registers its own Glib types using - g_type_register_static() - if it gets unloaded and then loaded again the - type registration will break, since there is no way to unregister the - types when the library is unloaded. The data pointer in the LV2_Feature - for this feature should always be set to NULL. - -
    -    uiext:makeSONameResident
    -
    - This feature is ELF specific - it should only be used by UIs that - use the ELF file format for the UI shared object files (e.g. on Linux). - If it is required by an UI the UI should also list a number of SO names - (shared object names) for libraries that the UI shared object - depends on and that may not be unloaded during the lifetime of the host - process, using the predicate @c uiext:residentSONames, like this: -
    -     uiext:residentSONames "libgtkmm-2.4.so.1", "libfoo.so.0"
    -
    - The host MUST then make sure that the shared libraries with the given ELF - SO names are not unloaded when the plugin UI is, but stay loaded during - the entire lifetime of the host process. On Linux this can be accomplished - by calling dlopen() on the shared library file with that SO name and never - calling a matching dlclose(). However, if a plugin UI requires the - @c uiext:makeSONameResident feature, it MUST ALWAYS be safe for the host to - just never unload the shared object containing the UI implementation, i.e. - act as if the UI required the @c uiext:makeResident feature instead. Thus - the host only needs to find the shared library files corresponding to the - given SO names if it wants to save RAM by unloading the UI shared object - file when it is no longer needed. The data pointer for the LV2_Feature for - this feature should always be set to NULL. - -
    -    uiext:noUserResize
    -
    - If an UI requires this feature it indicates that it does not make sense - to let the user resize the main widget, and the host should prevent that. - This feature may not make sense for all UI types. The data pointer for the - LV2_Feature for this feature should always be set to NULL. - -
    -    uiext:fixedSize
    -
    - If an UI requires this feature it indicates the same thing as - uiext:noUserResize, and additionally it means that the UI will not resize - the main widget on its own - it will always remain the same size (e.g. a - pixmap based GUI). This feature may not make sense for all UI types. - The data pointer for the LV2_Feature for this feature should always be set - to NULL. - - - UIs written to this specification do not need to be threadsafe - the - functions defined below may only be called in the same thread as the UI - main loop is running in. - - Note that this UI extension is NOT a lv2:Feature. There is no way for a - plugin to know whether the host that loads it supports UIs or not, and - the plugin must ALWAYS work without the UI (although it may be rather - useless unless it has been configured using the UI in a previous session). - - A UI does not have to be a graphical widget, it could just as well be a - server listening for OSC input or an interface to some sort of hardware - device, depending on the RDF class of the UI. -*/ - -#ifndef LV2_UI_H -#define LV2_UI_H - -#include - -#define LV2_UI_URI "http://lv2plug.in/ns/extensions/ui" - - -#ifdef __cplusplus -extern "C" { -#endif - - -/** A pointer to some widget or other type of UI handle. - The actual type is defined by the type URI of the UI. - All the functionality provided by this extension is toolkit - independent, the host only needs to pass the necessary callbacks and - display the widget, if possible. Plugins may have several UIs, in various - toolkits. */ -typedef void* LV2UI_Widget; - - -/** This handle indicates a particular instance of a UI. - It is valid to compare this to NULL (0 for C++) but otherwise the - host MUST not attempt to interpret it. The UI plugin may use it to - reference internal instance data. */ -typedef void* LV2UI_Handle; - - -/** This handle indicates a particular plugin instance, provided by the host. - It is valid to compare this to NULL (0 for C++) but otherwise the - UI plugin MUST not attempt to interpret it. The host may use it to - reference internal plugin instance data. */ -typedef void* LV2UI_Controller; - - -/** This is the type of the host-provided function that the UI can use to - send data to a plugin's input ports. The @c buffer parameter must point - to a block of data, @c buffer_size bytes large. The contents of this buffer - and what the host should do with it depends on the value of the @c format - parameter. - - The @c format parameter should either be 0 or a numeric ID for a "Transfer - mechanism". Transfer mechanisms are Features and may be defined in - meta-extensions. They specify how to translate the data buffers passed - to this function to input data for the plugin ports. If a UI wishes to - write data to an input port, it must list a transfer mechanism Feature - for that port's class as an optional or required feature (depending on - whether the UI will work without being able to write to that port or not). - The only exception is when the UI wants to write single float values to - input ports of the class lv2:ControlPort, in which case @c buffer_size - should always be 4, the buffer should always contain a single IEEE-754 - float, and @c format should be 0. - - The numeric IDs for the transfer mechanisms are provided by a - URI-to-integer mapping function provided by the host, using the URI Map - feature with the map URI - "http://lv2plug.in/ns/extensions/ui". Thus a UI that requires transfer - mechanism features also requires the URI Map feature, but this is - implicit - the UI does not have to list the URI map feature as a required - or optional feature in it's RDF data. - - An UI MUST NOT pass a @c format parameter value (except 0) that has not - been returned by the host-provided URI mapping function for a - host-supported transfer mechanism feature URI. - - The UI MUST NOT try to write to a port for which there is no specified - transfer mechanism, or to an output port. The UI is responsible for - allocating the buffer and deallocating it after the call. -*/ -typedef void (*LV2UI_Write_Function)(LV2UI_Controller controller, - uint32_t port_index, - uint32_t buffer_size, - uint32_t format, - const void* buffer); - - -/** This struct contains the implementation of an UI. A pointer to an - object of this type is returned by the lv2ui_descriptor() function. -*/ -typedef struct _LV2UI_Descriptor { - - /** The URI for this UI (not for the plugin it controls). */ - const char* URI; - - /** Create a new UI object and return a handle to it. This function works - similarly to the instantiate() member in LV2_Descriptor. - - @param descriptor The descriptor for the UI that you want to instantiate. - @param plugin_uri The URI of the plugin that this UI will control. - @param bundle_path The path to the bundle containing the RDF data file - that references this shared object file, including the - trailing '/'. - @param write_function A function provided by the host that the UI can - use to send data to the plugin's input ports. - @param controller A handle for the plugin instance that should be passed - as the first parameter of @c write_function. - @param widget A pointer to an LV2UI_Widget. The UI will write a - widget pointer to this location (what type of widget - depends on the RDF class of the UI) that will be the - main UI widget. - @param features An array of LV2_Feature pointers. The host must pass - all feature URIs that it and the UI supports and any - additional data, just like in the LV2 plugin - instantiate() function. Note that UI features and plugin - features are NOT necessarily the same, they just share - the same data structure - this will probably not be the - same array as the one the plugin host passes to a - plugin. - */ - LV2UI_Handle (*instantiate)(const struct _LV2UI_Descriptor* descriptor, - const char* plugin_uri, - const char* bundle_path, - LV2UI_Write_Function write_function, - LV2UI_Controller controller, - LV2UI_Widget* widget, - const LV2_Feature* const* features); - - - /** Destroy the UI object and the associated widget. The host must not try - to access the widget after calling this function. - */ - void (*cleanup)(LV2UI_Handle ui); - - /** Tell the UI that something interesting has happened at a plugin port. - What is interesting and how it is written to the buffer passed to this - function is defined by the @c format parameter, which has the same - meaning as in LV2UI_Write_Function. The only exception is ports of the - class lv2:ControlPort, for which this function should be called - when the port value changes (it does not have to be called for every - single change if the host's UI thread has problems keeping up with - the thread the plugin is running in), @c buffer_size should be 4 and the - buffer should contain a single IEEE-754 float. In this case the @c format - parameter should be 0. - - By default, the host should only call this function for input ports of - the lv2:ControlPort class. However, the default setting can be modified - by using the following URIs in the UI's RDF data: -
    -      uiext:portNotification
    -      uiext:noPortNotification
    -      uiext:plugin
    -      uiext:portIndex
    -      
    - For example, if you want the UI with uri - for the plugin with URI - to get notified when the value of the - output control port with index 4 changes, you would use the following - in the RDF for your UI: -
    -       uiext:portNotification [ uiext:plugin  ;
    -                                                      uiext:portIndex 4 ] .
    -      
    - and similarly with uiext:noPortNotification if you wanted - to prevent notifications for a port for which it would be on by default - otherwise. The UI is not allowed to request notifications for ports of - types for which no transfer mechanism is specified, if it does it should - be considered broken and the host should not load it. - - The @c buffer is only valid during the time of this function call, so if - the UI wants to keep it for later use it has to copy the contents to an - internal buffer. - - This member may be set to NULL if the UI is not interested in any - port events. - */ - void (*port_event)(LV2UI_Handle ui, - uint32_t port_index, - uint32_t buffer_size, - uint32_t format, - const void* buffer); - - /** Returns a data structure associated with an extension URI, for example - a struct containing additional function pointers. Avoid returning - function pointers directly since standard C++ has no valid way of - casting a void* to a function pointer. This member may be set to NULL - if the UI is not interested in supporting any extensions. This is similar - to the extension_data() member in LV2_Descriptor. - */ - const void* (*extension_data)(const char* uri); - -} LV2UI_Descriptor; - - - -/** A plugin UI programmer must include a function called "lv2ui_descriptor" - with the following function prototype within the shared object - file. This function will have C-style linkage (if you are using - C++ this is taken care of by the 'extern "C"' clause at the top of - the file). This function will be accessed by the UI host using the - @c dlsym() function and called to get a LV2UI_UIDescriptor for the - wanted plugin. - - Just like lv2_descriptor(), this function takes an index parameter. The - index should only be used for enumeration and not as any sort of ID number - - the host should just iterate from 0 and upwards until the function returns - NULL or a descriptor with an URI matching the one the host is looking for. -*/ -const LV2UI_Descriptor* lv2ui_descriptor(uint32_t index); - - -/** This is the type of the lv2ui_descriptor() function. */ -typedef const LV2UI_Descriptor* (*LV2UI_DescriptorFunction)(uint32_t index); - - - -#ifdef __cplusplus -} -#endif - - -#endif +/************************************************************************ + * + * In-process UI extension for LV2 + * + * Copyright (C) 2006-2008 Lars Luthman + * + * Based on lv2.h, which was + * + * Copyright (C) 2000-2002 Richard W.E. Furse, Paul Barton-Davis, + * Stefan Westerfeld + * Copyright (C) 2006 Steve Harris, Dave Robillard. + * + * This header is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, + * or (at your option) any later version. + * + * This header 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + * USA. + * + ***********************************************************************/ + +/** @file + This extension defines an interface that can be used in LV2 plugins and + hosts to create UIs for plugins. The UIs are plugins that reside in + shared object files in an LV2 bundle and are referenced in the RDF data + using the triples (Turtle shown) +
        
    +    @@prefix uiext:  .
    +        uiext:ui      .
    +        a            uiext:GtkUI .
    +      uiext:binary  .
    +
    + where is the URI of the plugin, is + the URI of the plugin UI and is the relative URI to the shared + object file. While it is possible to have the plugin UI and the plugin in + the same shared object file it is probably a good idea to keep them + separate so that hosts that don't want UIs don't have to load the UI code. + A UI MUST specify its class in the RDF data, in this case uiext:GtkUI. The + class defines what type the UI is, e.g. what graphics toolkit it uses. + There are no UI classes defined in this extension, those are specified + separately (and anyone can define their own). + + (Note: the prefix above is used throughout this file for the same URI) + + It's entirely possible to have multiple UIs for the same plugin, or to have + the UI for a plugin in a different bundle from the actual plugin - this + way people other than the plugin author can write plugin UIs independently + without editing the original plugin bundle. + + Note that the process that loads the shared object file containing the UI + code and the process that loads the shared object file containing the + actual plugin implementation does not have to be the same. There are many + valid reasons for having the plugin and the UI in different processes, or + even on different machines. This means that you can _not_ use singletons + and global variables and expect them to refer to the same objects in the + UI and the actual plugin. The function callback interface defined in this + header is all you can expect to work. + + Since the LV2 specification itself allows for extensions that may add + new types of data and configuration parameters that plugin authors may + want to control with a UI, this extension allows for meta-extensions that + can extend the interface between the UI and the host. These extensions + mirror the extensions used for plugins - there are required and optional + "features" that you declare in the RDF data for the UI as +
        
    +     uiext:requiredFeature  .
    +     uiext:optionalFeature  .
    +
    + These predicates have the same semantics as lv2:requiredFeature and + lv2:optionalFeature - if a UI is declaring a feature as required, the + host is NOT allowed to load it unless it supports that feature, and if it + does support a feature (required or optional) it MUST pass that feature's + URI and any additional data (specified by the meta-extension that defines + the feature) in a LV2_Feature struct (as defined in lv2.h) to the UI's + instantiate() function. + + These features may be used to specify how to pass data between the UI + and the plugin port buffers - see LV2UI_Write_Function for details. + + There are four features defined in this extension that hosts may want to + implement: + +
    +    uiext:makeResident
    +
    + If this feature is required by a UI the host MUST NEVER unload the shared + library containing the UI implementation during the lifetime of the host + process (e.g. never calling dlclose() on Linux). This feature may be + needed by e.g. a Gtk UI that registers its own Glib types using + g_type_register_static() - if it gets unloaded and then loaded again the + type registration will break, since there is no way to unregister the + types when the library is unloaded. The data pointer in the LV2_Feature + for this feature should always be set to NULL. + +
    +    uiext:makeSONameResident
    +
    + This feature is ELF specific - it should only be used by UIs that + use the ELF file format for the UI shared object files (e.g. on Linux). + If it is required by an UI the UI should also list a number of SO names + (shared object names) for libraries that the UI shared object + depends on and that may not be unloaded during the lifetime of the host + process, using the predicate @c uiext:residentSONames, like this: +
    +     uiext:residentSONames "libgtkmm-2.4.so.1", "libfoo.so.0"
    +
    + The host MUST then make sure that the shared libraries with the given ELF + SO names are not unloaded when the plugin UI is, but stay loaded during + the entire lifetime of the host process. On Linux this can be accomplished + by calling dlopen() on the shared library file with that SO name and never + calling a matching dlclose(). However, if a plugin UI requires the + @c uiext:makeSONameResident feature, it MUST ALWAYS be safe for the host to + just never unload the shared object containing the UI implementation, i.e. + act as if the UI required the @c uiext:makeResident feature instead. Thus + the host only needs to find the shared library files corresponding to the + given SO names if it wants to save RAM by unloading the UI shared object + file when it is no longer needed. The data pointer for the LV2_Feature for + this feature should always be set to NULL. + +
    +    uiext:noUserResize
    +
    + If an UI requires this feature it indicates that it does not make sense + to let the user resize the main widget, and the host should prevent that. + This feature may not make sense for all UI types. The data pointer for the + LV2_Feature for this feature should always be set to NULL. + +
    +    uiext:fixedSize
    +
    + If an UI requires this feature it indicates the same thing as + uiext:noUserResize, and additionally it means that the UI will not resize + the main widget on its own - it will always remain the same size (e.g. a + pixmap based GUI). This feature may not make sense for all UI types. + The data pointer for the LV2_Feature for this feature should always be set + to NULL. + + + UIs written to this specification do not need to be threadsafe - the + functions defined below may only be called in the same thread as the UI + main loop is running in. + + Note that this UI extension is NOT a lv2:Feature. There is no way for a + plugin to know whether the host that loads it supports UIs or not, and + the plugin must ALWAYS work without the UI (although it may be rather + useless unless it has been configured using the UI in a previous session). + + A UI does not have to be a graphical widget, it could just as well be a + server listening for OSC input or an interface to some sort of hardware + device, depending on the RDF class of the UI. +*/ + +#ifndef LV2_UI_H +#define LV2_UI_H + +#include + +#define LV2_UI_URI "http://lv2plug.in/ns/extensions/ui" + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** A pointer to some widget or other type of UI handle. + The actual type is defined by the type URI of the UI. + All the functionality provided by this extension is toolkit + independent, the host only needs to pass the necessary callbacks and + display the widget, if possible. Plugins may have several UIs, in various + toolkits. */ +typedef void* LV2UI_Widget; + + +/** This handle indicates a particular instance of a UI. + It is valid to compare this to NULL (0 for C++) but otherwise the + host MUST not attempt to interpret it. The UI plugin may use it to + reference internal instance data. */ +typedef void* LV2UI_Handle; + + +/** This handle indicates a particular plugin instance, provided by the host. + It is valid to compare this to NULL (0 for C++) but otherwise the + UI plugin MUST not attempt to interpret it. The host may use it to + reference internal plugin instance data. */ +typedef void* LV2UI_Controller; + + +/** This is the type of the host-provided function that the UI can use to + send data to a plugin's input ports. The @c buffer parameter must point + to a block of data, @c buffer_size bytes large. The contents of this buffer + and what the host should do with it depends on the value of the @c format + parameter. + + The @c format parameter should either be 0 or a numeric ID for a "Transfer + mechanism". Transfer mechanisms are Features and may be defined in + meta-extensions. They specify how to translate the data buffers passed + to this function to input data for the plugin ports. If a UI wishes to + write data to an input port, it must list a transfer mechanism Feature + for that port's class as an optional or required feature (depending on + whether the UI will work without being able to write to that port or not). + The only exception is when the UI wants to write single float values to + input ports of the class lv2:ControlPort, in which case @c buffer_size + should always be 4, the buffer should always contain a single IEEE-754 + float, and @c format should be 0. + + The numeric IDs for the transfer mechanisms are provided by a + URI-to-integer mapping function provided by the host, using the URI Map + feature with the map URI + "http://lv2plug.in/ns/extensions/ui". Thus a UI that requires transfer + mechanism features also requires the URI Map feature, but this is + implicit - the UI does not have to list the URI map feature as a required + or optional feature in it's RDF data. + + An UI MUST NOT pass a @c format parameter value (except 0) that has not + been returned by the host-provided URI mapping function for a + host-supported transfer mechanism feature URI. + + The UI MUST NOT try to write to a port for which there is no specified + transfer mechanism, or to an output port. The UI is responsible for + allocating the buffer and deallocating it after the call. +*/ +typedef void (*LV2UI_Write_Function)(LV2UI_Controller controller, + uint32_t port_index, + uint32_t buffer_size, + uint32_t format, + const void* buffer); + + +/** This struct contains the implementation of an UI. A pointer to an + object of this type is returned by the lv2ui_descriptor() function. +*/ +typedef struct _LV2UI_Descriptor { + + /** The URI for this UI (not for the plugin it controls). */ + const char* URI; + + /** Create a new UI object and return a handle to it. This function works + similarly to the instantiate() member in LV2_Descriptor. + + @param descriptor The descriptor for the UI that you want to instantiate. + @param plugin_uri The URI of the plugin that this UI will control. + @param bundle_path The path to the bundle containing the RDF data file + that references this shared object file, including the + trailing '/'. + @param write_function A function provided by the host that the UI can + use to send data to the plugin's input ports. + @param controller A handle for the plugin instance that should be passed + as the first parameter of @c write_function. + @param widget A pointer to an LV2UI_Widget. The UI will write a + widget pointer to this location (what type of widget + depends on the RDF class of the UI) that will be the + main UI widget. + @param features An array of LV2_Feature pointers. The host must pass + all feature URIs that it and the UI supports and any + additional data, just like in the LV2 plugin + instantiate() function. Note that UI features and plugin + features are NOT necessarily the same, they just share + the same data structure - this will probably not be the + same array as the one the plugin host passes to a + plugin. + */ + LV2UI_Handle (*instantiate)(const struct _LV2UI_Descriptor* descriptor, + const char* plugin_uri, + const char* bundle_path, + LV2UI_Write_Function write_function, + LV2UI_Controller controller, + LV2UI_Widget* widget, + const LV2_Feature* const* features); + + + /** Destroy the UI object and the associated widget. The host must not try + to access the widget after calling this function. + */ + void (*cleanup)(LV2UI_Handle ui); + + /** Tell the UI that something interesting has happened at a plugin port. + What is interesting and how it is written to the buffer passed to this + function is defined by the @c format parameter, which has the same + meaning as in LV2UI_Write_Function. The only exception is ports of the + class lv2:ControlPort, for which this function should be called + when the port value changes (it does not have to be called for every + single change if the host's UI thread has problems keeping up with + the thread the plugin is running in), @c buffer_size should be 4 and the + buffer should contain a single IEEE-754 float. In this case the @c format + parameter should be 0. + + By default, the host should only call this function for input ports of + the lv2:ControlPort class. However, the default setting can be modified + by using the following URIs in the UI's RDF data: +
    +      uiext:portNotification
    +      uiext:noPortNotification
    +      uiext:plugin
    +      uiext:portIndex
    +      
    + For example, if you want the UI with uri + for the plugin with URI + to get notified when the value of the + output control port with index 4 changes, you would use the following + in the RDF for your UI: +
    +       uiext:portNotification [ uiext:plugin  ;
    +                                                      uiext:portIndex 4 ] .
    +      
    + and similarly with uiext:noPortNotification if you wanted + to prevent notifications for a port for which it would be on by default + otherwise. The UI is not allowed to request notifications for ports of + types for which no transfer mechanism is specified, if it does it should + be considered broken and the host should not load it. + + The @c buffer is only valid during the time of this function call, so if + the UI wants to keep it for later use it has to copy the contents to an + internal buffer. + + This member may be set to NULL if the UI is not interested in any + port events. + */ + void (*port_event)(LV2UI_Handle ui, + uint32_t port_index, + uint32_t buffer_size, + uint32_t format, + const void* buffer); + + /** Returns a data structure associated with an extension URI, for example + a struct containing additional function pointers. Avoid returning + function pointers directly since standard C++ has no valid way of + casting a void* to a function pointer. This member may be set to NULL + if the UI is not interested in supporting any extensions. This is similar + to the extension_data() member in LV2_Descriptor. + */ + const void* (*extension_data)(const char* uri); + +} LV2UI_Descriptor; + + + +/** A plugin UI programmer must include a function called "lv2ui_descriptor" + with the following function prototype within the shared object + file. This function will have C-style linkage (if you are using + C++ this is taken care of by the 'extern "C"' clause at the top of + the file). This function will be accessed by the UI host using the + @c dlsym() function and called to get a LV2UI_UIDescriptor for the + wanted plugin. + + Just like lv2_descriptor(), this function takes an index parameter. The + index should only be used for enumeration and not as any sort of ID number - + the host should just iterate from 0 and upwards until the function returns + NULL or a descriptor with an URI matching the one the host is looking for. +*/ +const LV2UI_Descriptor* lv2ui_descriptor(uint32_t index); + + +/** This is the type of the lv2ui_descriptor() function. */ +typedef const LV2UI_Descriptor* (*LV2UI_DescriptorFunction)(uint32_t index); + + + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/lib-src/soundtouch/COPYING.TXT b/lib-src/soundtouch/COPYING.TXT index f95d0f639..3b204400c 100644 --- a/lib-src/soundtouch/COPYING.TXT +++ b/lib-src/soundtouch/COPYING.TXT @@ -1,458 +1,458 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS diff --git a/lib-src/soundtouch/README.html b/lib-src/soundtouch/README.html index 017158c55..242b0f03d 100644 --- a/lib-src/soundtouch/README.html +++ b/lib-src/soundtouch/README.html @@ -1,675 +1,675 @@ - - - - - - - - - - SoundTouch library README - - - -
    -

    SoundTouch audio processing library v1.3.1 -

    -

    SoundTouch library Copyright (c) Olli -Parviainen 2002-2006

    -
    -

    1. Introduction

    -

    SoundTouch is an open-source audio -processing library that allows changing the sound tempo, pitch -and playback rate parameters independently from each other, i.e.:

    -
      -
    • Sound tempo can be increased or decreased while -maintaining the original pitch
    • -
    • Sound pitch can be increased or decreased while -maintaining the original tempo
    • -
    • Change playback rate that affects both tempo -and pitch at the same time
    • -
    • Choose any combination of tempo/pitch/rate
    • -
    -

    1.1 Contact information

    -

    Author email: oparviai 'at' iki.fi

    -

    SoundTouch WWW page: http://www.surina.net/soundtouch

    -
    -

    2. Compiling SoundTouch

    -

    Before compiling, notice that you can choose the sample data format -if it's desirable to use floating point sample -data instead of 16bit integers. See section "sample data format" -for more information.

    -

    2.1. Building in Microsoft Windows

    -

    Project files for Microsoft Visual C++ 6.0 and Visual C++ .NET are -supplied with the source code package. Please notice that SoundTouch -library uses processor-specific optimizations for Pentium III and AMD -processors that require a processor pack upgrade for -the Visual Studio 6.0 to be installed in order to support these -optimizations. The processor pack upgrade can be downloaded from -Microsoft site at this URL:

    -

    -http://msdn.microsoft.com/vstudio/downloads/tools/ppack/default.aspx

    -

    If the above URL is unavailable or removed, go -to http://msdn.microsoft.com -and perform a search with keywords processor pack.

    -

    Visual Studio .NET supports required -instructions by default and thus doesn't require installing the -processor pack.

    -

    To build the binaries with Visual C++ 6.0 -compiler, either run "make-win.bat" script or open the -appropriate project files in source code directories with Visual -Studio. The final executable will appear under the "SoundTouch\bin" -directory. If using the Visual Studio IDE instead of the -make-win.bat script, directories bin and -lib have to be created manually to the SoundTouch -package root for the final executables. The make-win.bat script -creates these directories automatically. -

    -

    Also other C++ compilers than Visual C++ can be -used, but project or makefiles then have to be adapted accordingly. -Performance optimizations are written in Visual C++ compatible -syntax, they may or may not be compatible with other compilers. If -using GCC (Gnu C Compiler) compiler package such as DJGPP or Cygwin, -please see next chapter for instructions.

    -

    2.2. Building in Gnu platforms

    -

    The SoundTouch library can be compiled in -practically any platform supporting GNU compiler (GCC) tools. -SoundTouch have been tested with gcc version 3.3.4., but it -shouldn't be very specific about the gcc version. Assembler-level -performance optimizations for GNU platform are currently available in -x86 platforms only, they are automatically disabled and replaced with -standard C routines in other processor platforms.

    -

    To build and install the binaries, run the -following commands in SoundTouch/ directory:

    - - - - - - - - - - - - - - - -
    -
    ./configure  -
    -
    -

    Configures the SoundTouch package for the local -environment.

    -
    -
    make         -
    -
    -

    Builds the SoundTouch library & -SoundStretch utility.

    -
    -
    make install -
    -
    -

    Installs the SoundTouch & BPM libraries -to /usr/local/lib and SoundStretch utility to /usr/local/bin. -Please notice that 'root' privileges may be required to install the -binaries to the destination locations.

    -
    -

    NOTE: At the time of release the SoundTouch package has been -tested -to compile in GNU/Linux platform. However, in past it's happened that -new -gcc versions aren't necessarily compatible with the assembler setttings -used in the optimized routines. If you have problems getting the -SoundTouch library compiled, try the workaround of disabling the -optimizations by editing the file "include/STTypes.h" and removing -the following definition there:

    -
    -
    #define ALLOW_OPTIMIZATIONS 1
    -
    -
    -

    3. About implementation & Usage tips

    -

    3.1. Supported sample data formats

    -

    The sample data format can be chosen -between 16bit signed integer and 32bit floating point values, the -default is 32bit floating point.

    - -

    -In Windows environment, the sample data format is chosen -in file "STTypes.h" by choosing one of the following -defines:

    -
      -
    • #define INTEGER_SAMPLES -for 16bit signed -integer
    • -
    • #define FLOAT_SAMPLES for -32bit floating point
    • -
    -

    -In GNU environment, the floating sample format is used by default, but -integer sample format can be chosen by giving the -following switch to the configure script: -

    -
    ./configure --enable-integer-samples
    -
    - -

    The sample data can have either single (mono) -or double (stereo) audio channel. Stereo data is interleaved so -that every other data value is for left channel and every second -for right channel. Notice that while it'd be possible in theory -to process stereo sound as two separate mono channels, this isn't -recommended because processing the channels separately would -result in losing the phase coherency between the channels, which -consequently would ruin the stereo effect.

    -

    Sample rates between 8000-48000Hz are -supported.

    -

    3.2. Processing latency

    -

    The processing and latency constraints of -the SoundTouch library are:

    -
      -
    • Input/output processing latency for the -SoundTouch processor is around 100 ms. This is when time-stretching is -used. If the rate transposing effect alone is used, the latency -requirement -is much shorter, see section 'About algorithms'.
    • -
    • Processing CD-quality sound (16bit stereo -sound with 44100Hz sample rate) in real-time or faster is possible -starting from processors equivalent to Intel Pentium 133Mhz or better, -if using the "quick" processing algorithm. If not using the "quick" -mode or -if floating point sample data are being used, several times more CPU -power is typically required.
    • -
    -

    3.3. About algorithms

    -

    SoundTouch provides three seemingly -independent effects: tempo, pitch and playback rate control. -These three controls are implemented as combination of two primary -effects, sample rate transposing and time-stretching.

    -

    Sample rate transposing affects -both the audio stream duration and pitch. It's implemented simply -by converting the original audio sample stream to the  desired -duration by interpolating from the original audio samples. In -SoundTouch, linear interpolation with anti-alias filtering is -used. Theoretically a higher-order interpolation provide better -result than 1st order linear interpolation, but in audio -application linear interpolation together with anti-alias -filtering performs subjectively about as well as higher-order -filtering would.

    -

    Time-stretching means changing -the audio stream duration without affecting it's pitch. SoundTouch -uses WSOLA-like time-stretching routines that operate in the time -domain. Compared to sample rate transposing, time-stretching is a -much heavier operation and also requires a longer processing -"window" of sound samples used by the -processing algorithm, thus increasing the algorithm input/output -latency. Typical i/o latency for the SoundTouch -time-stretch algorithm is around 100 ms.

    -

    Sample rate transposing and time-stretching -are then used together to produce the tempo, pitch and rate -controls:

    -
      -
    • 'Tempo' control is -implemented purely by time-stretching.
    • -
    • 'Rate' control is implemented -purely by sample rate transposing.
    • -
    • 'Pitch' control is -implemented as a combination of time-stretching and sample rate -transposing. For example, to increase pitch the audio stream is first -time-stretched to longer duration (without affecting pitch) and then -transposed back to original duration by sample rate transposing, which -simultaneously reduces duration and increases pitch. The result is -original duration but increased pitch.
    • -
    -

    3.4 Tuning the algorithm parameters

    -

    The time-stretch algorithm has few -parameters that can be tuned to optimize sound quality for -certain application. The current default parameters have been -chosen by iterative if-then analysis (read: "trial and error") -to obtain best subjective sound quality in pop/rock music -processing, but in applications processing different kind of -sound the default parameter set may result into a sub-optimal -result.

    -

    The time-stretch algorithm default -parameter values are set by these #defines in file "TDStretch.h":

    -
    -
    #define DEFAULT_SEQUENCE_MS     82
    -#define DEFAULT_SEEKWINDOW_MS   28
    -#define DEFAULT_OVERLAP_MS      12
    -
    -

    These parameters affect to the time-stretch -algorithm as follows:

    -
      -
    • DEFAULT_SEQUENCE_MS: This is -the default length of a single processing sequence in milliseconds -which determines the how the original sound is chopped in -the time-stretch algorithm. Larger values mean fewer sequences -are used in processing. In principle a larger value sounds better when -slowing down the tempo, but worse when increasing the tempo and vice -versa.
      -
    • -
    • DEFAULT_SEEKWINDOW_MS: The seeking window -default length in milliseconds is for the algorithm that seeks the best -possible overlapping location. This determines from how -wide a sample "window" the algorithm can use to find an optimal mixing -location when the sound sequences are to be linked back together.
      -
      -The bigger this window setting is, the higher the possibility to find a -better mixing position becomes, but at the same time large values may -cause a "drifting" sound artifact because neighboring sequences can be -chosen at more uneven intervals. If there's a disturbing artifact that -sounds as if a constant frequency was drifting around, try reducing -this setting.
      -
    • -
    • DEFAULT_OVERLAP_MS: Overlap -length in milliseconds. When the sound sequences are mixed back -together to form again a continuous sound stream, this parameter -defines how much the ends of the consecutive sequences will overlap with each other.
      -
      - This shouldn't be that critical parameter. If you reduce the -DEFAULT_SEQUENCE_MS setting by a large amount, you might wish to try a -smaller value on this.
    • -
    -

    Notice that these parameters can also be -set during execution time with functions "TDStretch::setParameters()" -and "SoundTouch::setSetting()".

    -

    The table below summarizes how the -parameters can be adjusted for different applications:

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Parameter nameDefault value -magnitudeLarger value -affects...Smaller value -affects...MusicSpeechEffect in CPU burden
    -
    SEQUENCE_MS
    -
    Default value is relatively -large, chosen for slowing down music tempoLarger value is usually -better for slowing down tempo. Growing the value decelerates the -"echoing" artifact when slowing down the tempo.Smaller value might be better -for speeding up tempo. Reducing the value accelerates the "echoing" -artifact when slowing down the tempo Default value usually goodA smaller value than default -might be betterIncreasing the parameter -value reduces computation burden
    -
    SEEKWINDOW_MS
    -
    Default value is relatively -large, chosen for slowing down music tempoLarger value eases finding a -good mixing position, but may cause a "drifting" artifactSmaller reduce possibility to -find a good mixing position, but reduce the "drifting" artifact.Default value usually good, -unless a "drifting" artifact is disturbing.Default value usually goodIncreasing the parameter -value increases computation burden
    -
    OVERLAP_MS
    -
    Default value is relatively -large, chosen to suit with above parameters. If you reduce the "sequence -ms" setting, you might wish to try a smaller value.  Increasing the parameter -value increases computation burden
    -

    3.5 Performance Optimizations

    -

    General optimizations:

    -

    The time-stretch routine has a 'quick' mode -that substantially speeds up the algorithm but may degrade the -sound quality by a small amount. This mode is activated by -calling SoundTouch::setSetting() function with parameter  id -of SETTING_USE_QUICKSEEK and value "1", i.e.

    -
    -

    setSetting(SETTING_USE_QUICKSEEK, 1);

    -
    -

    CPU-specific optimizations:

    -
      -
    • Intel MMX optimized routines are used with -compatible CPUs when 16bit integer sample type is used. MMX -optimizations are available both in Win32 and Gnu/x86 platforms. -Compatible processors are Intel PentiumMMX and later; AMD K6-2, Athlon -and later.
    • -
    • Intel SSE optimized routines are used with -compatible CPUs when floating point sample type is used. SSE -optimizations are currently implemented for Win32 platform only. -Processors compatible with SSE extension are Intel processors starting -from Pentium-III, and AMD processors starting from Athlon XP.
    • -
    • AMD 3DNow! optimized routines are used with -compatible CPUs when floating point sample type is used, but SSE -extension isn't supported . 3DNow! optimizations are currently -implemented for Win32 platform only. These optimizations are used in -AMD K6-2 and Athlon (classic) CPU's; better performing SSE routines are -used with AMD processor starting from Athlon XP.
    • -
    -
    -

    4. SoundStretch audio processing utility -

    -

    SoundStretch audio processing utility
    -Copyright (c) Olli Parviainen 2002-2005

    -

    SoundStretch is a simple command-line -application that can change tempo, pitch and playback rates of -WAV sound files. This program is intended primarily to -demonstrate how the "SoundTouch" library can be used to -process sound in your own program, but it can as well be used for -processing sound files.

    -

    4.1. SoundStretch Usage Instructions

    -

    SoundStretch Usage syntax:

    -
    -
    soundstretch infile.wav outfile.wav [switches]
    -
    -

    Where:

    - - - - - - - - - - - - - - - -
    -
    "infile.wav"
    -
    is the name of the input sound -data file (in .WAV audio file format).
    -
    "outfile.wav"
    -
    is the name of the output sound -file where the resulting sound is saved (in .WAV audio file format). -This parameter may be omitted if you  don't want to save the -output -(e.g. when only calculating BPM rate with '-bpm' switch).
    -
     [switches]
    -
    Are one or more control -switches.
    -

    Available control switches are:

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -
    -tempo=n 
    -
    Change the sound tempo by n -percents (n = -95.0 .. +5000.0 %)
    -
    -pitch=n
    -
    Change the sound pitch by n -semitones (n = -60.0 .. + 60.0 semitones)
    -
    -rate=n
    -
    Change the sound playback rate by -n percents (n = -95.0 .. +5000.0 %)
    -
    -bpm=n
    -
    Detect the Beats-Per-Minute -(BPM) rate of the sound and adjust the tempo to meet 'n' BPMs. If this -switch is defined, the "-tempo=n" switch value is ignored. If "=n" is -omitted, i.e. switch "-bpm" is used alone, the program just calculates -and displays the BPM rate but doesn't adjust tempo according to the BPM -value.
    -
    -quick
    -
    Use quicker tempo change -algorithm. Gains speed but loses sound quality.
    -
    -naa
    -
    Don't use anti-alias -filtering in sample rate transposing. Gains speed but loses sound -quality.
    -
    -license
    -
    Displays the program license -text (LGPL)
    -

    Notes:

    -
      -
    • The numerical switch values can be entered -using either integer (e.g. "-tempo=123") or decimal (e.g. -"-tempo=123.45") numbers.
    • -
    • The "-naa" and/or "-quick" switches can be -used to reduce CPU usage while compromising some sound quality
    • -
    • The BPM detection algorithm works by detecting -repeating low-frequency (<250Hz) sound patterns and thus works -mostly with most rock/pop music with bass or drum beat. The BPM -detection doesn't work on pieces such as classical music without -distinct, repeating bass frequency patterns. Also pieces with varying -tempo, varying bass patterns or very complex bass patterns (jazz, hiphop) may produce odd BPM readings.
      -
      -In cases when the bass pattern drifts a bit around a nominal beat rate -(e.g. drummer is again drunken :), the BPM algorithm may report -incorrect harmonic one-halft to one-thirdth of the correct BPM value; -in such case the system could for example report BPM value of 50 or 100 -instead of correct BPM value of 150.
    • -
    -

    4.2. SoundStretch usage examples

    -

    Example 1

    -

    The following command increases tempo of -the sound file "originalfile.wav" by 12.5% and saves -result to file "destinationfile.wav":

    -
    -
    soundstretch originalfile.wav destinationfile.wav -tempo=12.5
    -
    -

    Example 2

    -

    The following command decreases the sound -pitch (key) of the sound file "orig.wav" by two -semitones and saves the result to file "dest.wav":

    -
    -
    soundstretch orig.wav dest.wav -pitch=-2
    -
    -

    Example 3

    -

    The following command processes the file "orig.wav" by decreasing the sound tempo by 25.3% and -increasing the sound pitch (key) by 1.5 semitones. Result is -saved to file "dest.wav":

    -
    -
    soundstretch orig.wav dest.wav -tempo=-25.3 -pitch=1.5
    -
    -

    Example 4

    -

    The following command detects the BPM rate -of the file "orig.wav" and adjusts the tempo to match -100 beats per minute. Result is saved to file "dest.wav":

    -
    -
    soundstretch orig.wav dest.wav -bpm=100
    -
    -
    -

    5. Change History

    -

    5.1. SoundTouch library Change History

    - -

    v1.3.1: -

    -
      -
    • Changed static class declaration to GCC 4.x compiler compatible syntax.
    • -
    • Enabled MMX/SSE-optimized routines also for GCC compilers. Earlier -the MMX/SSE-optimized routines were written in compiler-specific inline -assembler, now these routines are migrated to use compiler intrinsic -syntax which allows compiling the same MMX/SSE-optimized source code with -both Visual C++ and GCC compilers.
    • -
    • Set floating point as the default sample format and added switch to -the GNU configure script for selecting the other sample format.
    • - -
    - -

    v1.3.0: -

    -
      -
    • Fixed tempo routine output duration inaccuracy due to rounding -error
    • -
    • Implemented separate processing routines for integer and -floating arithmetic to allow improvements to floating point routines -(earlier used algorithms mostly optimized for integer arithmetic also -for floating point samples)
    • -
    • Fixed a bug that distorts sound if sample rate changes during the -sound stream
    • -
    • Fixed a memory leak that appeared in MMX/SSE/3DNow! optimized -routines
    • -
    • Reduced redundant code pieces in MMX/SSE/3DNow! optimized -routines vs. the standard C routines.
    • -
    • MMX routine incompatibility with new gcc compiler versions
    • -
    • Other miscellaneous bug fixes
    • -
    -

    v1.2.1:

    -
      -
    • Added automake/autoconf scripts for GNU -platforms (in courtesy of David Durham)
    • -
    • Fixed SCALE overflow bug in rate transposer -routine.
    • -
    • Fixed 64bit address space bugs.
    • -
    • Created a 'soundtouch' namespace for -SAMPLETYPE definitions.
    • -
    -

    v1.2.0:

    -
      -
    • Added support for 32bit floating point sample -data type with SSE/3DNow! optimizations for Win32 platform (SSE/3DNow! -optimizations currently not supported in GCC environment)
    • -
    • Replaced 'make-gcc' script for GNU environment -by master Makefile
    • -
    • Added time-stretch routine configurability to -SoundTouch main class
    • -
    • Bugfixes
    • -
    -

    v1.1.1:

    -
      -
    • Moved SoundTouch under lesser GPL license (LGPL). This allows using SoundTouch library in programs that aren't -released under GPL license.
    • -
    • Changed MMX routine organization so that MMX -optimized routines are now implemented in classes that are derived from -the basic classes having the standard non-mmx routines.
    • -
    • MMX routines to support gcc version 3.
    • -
    • Replaced windows makefiles by script using the .dsw files
    • -
    -

    v1.01:

    -
      -
    • "mmx_gcc.cpp": Added "using namespace std" and -removed "return 0" from a function with void return value to fix -compiler errors when compiling the library in Solaris environment.
    • -
    • Moved file "FIFOSampleBuffer.h" to "include" -directory to allow accessing the FIFOSampleBuffer class from external -files.
    • -
    -

    v1.0:

    -
      -
    • Initial release
    • -
    -

     

    -

    5.2. SoundStretch application Change -History

    -

    v1.3.0:

    -
      -
    • Simplified accessing WAV files with floating -point sample format.
      -
    • -
    -

    v1.2.1:

    -
      -
    • Fixed 64bit address space bugs.
    • -
    -

    v1.2.0:

    -
      -
    • Added support for 32bit floating point sample -data type
    • -
    • Restructured the BPM routines into separate -library
    • -
    • Fixed big-endian conversion bugs in WAV file -routines (hopefully :)
    • -
    -

    v1.1.1:

    -
      -
    • Fixed bugs in WAV file reading & added -byte-order conversion for big-endian processors.
    • -
    • Moved SoundStretch source code under 'example' -directory to highlight difference from SoundTouch stuff.
    • -
    • Replaced windows makefiles by script using the .dsw files
    • -
    • Output file name isn't required if output -isn't desired (e.g. if using the switch '-bpm' in plain format only)
    • -
    -

    v1.1:

    -
      -
    • Fixed "Release" settings in Microsoft Visual -C++ project file (.dsp)
    • -
    • Added beats-per-minute (BPM) detection routine -and command-line switch "-bpm"
    • -
    -

    v1.01:

    -
      -
    • Initial release
    • -
    -
    -

    6. LICENSE

    -

    SoundTouch audio processing library
    -Copyright (c) Olli Parviainen

    -

    This library is free software; you can -redistribute it and/or modify it under the terms of the GNU -Lesser General Public License as published by the Free Software -Foundation; either version 2.1 of the License, or (at your option) -any later version.

    -

    This library 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 Lesser General Public License for -more details.

    -

    You should have received a copy of the GNU -Lesser General Public License along with this library; if not, -write to the Free Software Foundation, Inc., 59 Temple Place, -Suite 330, Boston, MA 02111-1307 USA

    -
    - - - + + + + + + + + + + SoundTouch library README + + + +
    +

    SoundTouch audio processing library v1.3.1 +

    +

    SoundTouch library Copyright (c) Olli +Parviainen 2002-2006

    +
    +

    1. Introduction

    +

    SoundTouch is an open-source audio +processing library that allows changing the sound tempo, pitch +and playback rate parameters independently from each other, i.e.:

    +
      +
    • Sound tempo can be increased or decreased while +maintaining the original pitch
    • +
    • Sound pitch can be increased or decreased while +maintaining the original tempo
    • +
    • Change playback rate that affects both tempo +and pitch at the same time
    • +
    • Choose any combination of tempo/pitch/rate
    • +
    +

    1.1 Contact information

    +

    Author email: oparviai 'at' iki.fi

    +

    SoundTouch WWW page: http://www.surina.net/soundtouch

    +
    +

    2. Compiling SoundTouch

    +

    Before compiling, notice that you can choose the sample data format +if it's desirable to use floating point sample +data instead of 16bit integers. See section "sample data format" +for more information.

    +

    2.1. Building in Microsoft Windows

    +

    Project files for Microsoft Visual C++ 6.0 and Visual C++ .NET are +supplied with the source code package. Please notice that SoundTouch +library uses processor-specific optimizations for Pentium III and AMD +processors that require a processor pack upgrade for +the Visual Studio 6.0 to be installed in order to support these +optimizations. The processor pack upgrade can be downloaded from +Microsoft site at this URL:

    +

    +http://msdn.microsoft.com/vstudio/downloads/tools/ppack/default.aspx

    +

    If the above URL is unavailable or removed, go +to http://msdn.microsoft.com +and perform a search with keywords processor pack.

    +

    Visual Studio .NET supports required +instructions by default and thus doesn't require installing the +processor pack.

    +

    To build the binaries with Visual C++ 6.0 +compiler, either run "make-win.bat" script or open the +appropriate project files in source code directories with Visual +Studio. The final executable will appear under the "SoundTouch\bin" +directory. If using the Visual Studio IDE instead of the +make-win.bat script, directories bin and +lib have to be created manually to the SoundTouch +package root for the final executables. The make-win.bat script +creates these directories automatically. +

    +

    Also other C++ compilers than Visual C++ can be +used, but project or makefiles then have to be adapted accordingly. +Performance optimizations are written in Visual C++ compatible +syntax, they may or may not be compatible with other compilers. If +using GCC (Gnu C Compiler) compiler package such as DJGPP or Cygwin, +please see next chapter for instructions.

    +

    2.2. Building in Gnu platforms

    +

    The SoundTouch library can be compiled in +practically any platform supporting GNU compiler (GCC) tools. +SoundTouch have been tested with gcc version 3.3.4., but it +shouldn't be very specific about the gcc version. Assembler-level +performance optimizations for GNU platform are currently available in +x86 platforms only, they are automatically disabled and replaced with +standard C routines in other processor platforms.

    +

    To build and install the binaries, run the +following commands in SoundTouch/ directory:

    + + + + + + + + + + + + + + + +
    +
    ./configure  -
    +
    +

    Configures the SoundTouch package for the local +environment.

    +
    +
    make         -
    +
    +

    Builds the SoundTouch library & +SoundStretch utility.

    +
    +
    make install -
    +
    +

    Installs the SoundTouch & BPM libraries +to /usr/local/lib and SoundStretch utility to /usr/local/bin. +Please notice that 'root' privileges may be required to install the +binaries to the destination locations.

    +
    +

    NOTE: At the time of release the SoundTouch package has been +tested +to compile in GNU/Linux platform. However, in past it's happened that +new +gcc versions aren't necessarily compatible with the assembler setttings +used in the optimized routines. If you have problems getting the +SoundTouch library compiled, try the workaround of disabling the +optimizations by editing the file "include/STTypes.h" and removing +the following definition there:

    +
    +
    #define ALLOW_OPTIMIZATIONS 1
    +
    +
    +

    3. About implementation & Usage tips

    +

    3.1. Supported sample data formats

    +

    The sample data format can be chosen +between 16bit signed integer and 32bit floating point values, the +default is 32bit floating point.

    + +

    +In Windows environment, the sample data format is chosen +in file "STTypes.h" by choosing one of the following +defines:

    +
      +
    • #define INTEGER_SAMPLES +for 16bit signed +integer
    • +
    • #define FLOAT_SAMPLES for +32bit floating point
    • +
    +

    +In GNU environment, the floating sample format is used by default, but +integer sample format can be chosen by giving the +following switch to the configure script: +

    +
    ./configure --enable-integer-samples
    +
    + +

    The sample data can have either single (mono) +or double (stereo) audio channel. Stereo data is interleaved so +that every other data value is for left channel and every second +for right channel. Notice that while it'd be possible in theory +to process stereo sound as two separate mono channels, this isn't +recommended because processing the channels separately would +result in losing the phase coherency between the channels, which +consequently would ruin the stereo effect.

    +

    Sample rates between 8000-48000Hz are +supported.

    +

    3.2. Processing latency

    +

    The processing and latency constraints of +the SoundTouch library are:

    +
      +
    • Input/output processing latency for the +SoundTouch processor is around 100 ms. This is when time-stretching is +used. If the rate transposing effect alone is used, the latency +requirement +is much shorter, see section 'About algorithms'.
    • +
    • Processing CD-quality sound (16bit stereo +sound with 44100Hz sample rate) in real-time or faster is possible +starting from processors equivalent to Intel Pentium 133Mhz or better, +if using the "quick" processing algorithm. If not using the "quick" +mode or +if floating point sample data are being used, several times more CPU +power is typically required.
    • +
    +

    3.3. About algorithms

    +

    SoundTouch provides three seemingly +independent effects: tempo, pitch and playback rate control. +These three controls are implemented as combination of two primary +effects, sample rate transposing and time-stretching.

    +

    Sample rate transposing affects +both the audio stream duration and pitch. It's implemented simply +by converting the original audio sample stream to the  desired +duration by interpolating from the original audio samples. In +SoundTouch, linear interpolation with anti-alias filtering is +used. Theoretically a higher-order interpolation provide better +result than 1st order linear interpolation, but in audio +application linear interpolation together with anti-alias +filtering performs subjectively about as well as higher-order +filtering would.

    +

    Time-stretching means changing +the audio stream duration without affecting it's pitch. SoundTouch +uses WSOLA-like time-stretching routines that operate in the time +domain. Compared to sample rate transposing, time-stretching is a +much heavier operation and also requires a longer processing +"window" of sound samples used by the +processing algorithm, thus increasing the algorithm input/output +latency. Typical i/o latency for the SoundTouch +time-stretch algorithm is around 100 ms.

    +

    Sample rate transposing and time-stretching +are then used together to produce the tempo, pitch and rate +controls:

    +
      +
    • 'Tempo' control is +implemented purely by time-stretching.
    • +
    • 'Rate' control is implemented +purely by sample rate transposing.
    • +
    • 'Pitch' control is +implemented as a combination of time-stretching and sample rate +transposing. For example, to increase pitch the audio stream is first +time-stretched to longer duration (without affecting pitch) and then +transposed back to original duration by sample rate transposing, which +simultaneously reduces duration and increases pitch. The result is +original duration but increased pitch.
    • +
    +

    3.4 Tuning the algorithm parameters

    +

    The time-stretch algorithm has few +parameters that can be tuned to optimize sound quality for +certain application. The current default parameters have been +chosen by iterative if-then analysis (read: "trial and error") +to obtain best subjective sound quality in pop/rock music +processing, but in applications processing different kind of +sound the default parameter set may result into a sub-optimal +result.

    +

    The time-stretch algorithm default +parameter values are set by these #defines in file "TDStretch.h":

    +
    +
    #define DEFAULT_SEQUENCE_MS     82
    +#define DEFAULT_SEEKWINDOW_MS   28
    +#define DEFAULT_OVERLAP_MS      12
    +
    +

    These parameters affect to the time-stretch +algorithm as follows:

    +
      +
    • DEFAULT_SEQUENCE_MS: This is +the default length of a single processing sequence in milliseconds +which determines the how the original sound is chopped in +the time-stretch algorithm. Larger values mean fewer sequences +are used in processing. In principle a larger value sounds better when +slowing down the tempo, but worse when increasing the tempo and vice +versa.
      +
    • +
    • DEFAULT_SEEKWINDOW_MS: The seeking window +default length in milliseconds is for the algorithm that seeks the best +possible overlapping location. This determines from how +wide a sample "window" the algorithm can use to find an optimal mixing +location when the sound sequences are to be linked back together.
      +
      +The bigger this window setting is, the higher the possibility to find a +better mixing position becomes, but at the same time large values may +cause a "drifting" sound artifact because neighboring sequences can be +chosen at more uneven intervals. If there's a disturbing artifact that +sounds as if a constant frequency was drifting around, try reducing +this setting.
      +
    • +
    • DEFAULT_OVERLAP_MS: Overlap +length in milliseconds. When the sound sequences are mixed back +together to form again a continuous sound stream, this parameter +defines how much the ends of the consecutive sequences will overlap with each other.
      +
      + This shouldn't be that critical parameter. If you reduce the +DEFAULT_SEQUENCE_MS setting by a large amount, you might wish to try a +smaller value on this.
    • +
    +

    Notice that these parameters can also be +set during execution time with functions "TDStretch::setParameters()" +and "SoundTouch::setSetting()".

    +

    The table below summarizes how the +parameters can be adjusted for different applications:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Parameter nameDefault value +magnitudeLarger value +affects...Smaller value +affects...MusicSpeechEffect in CPU burden
    +
    SEQUENCE_MS
    +
    Default value is relatively +large, chosen for slowing down music tempoLarger value is usually +better for slowing down tempo. Growing the value decelerates the +"echoing" artifact when slowing down the tempo.Smaller value might be better +for speeding up tempo. Reducing the value accelerates the "echoing" +artifact when slowing down the tempo Default value usually goodA smaller value than default +might be betterIncreasing the parameter +value reduces computation burden
    +
    SEEKWINDOW_MS
    +
    Default value is relatively +large, chosen for slowing down music tempoLarger value eases finding a +good mixing position, but may cause a "drifting" artifactSmaller reduce possibility to +find a good mixing position, but reduce the "drifting" artifact.Default value usually good, +unless a "drifting" artifact is disturbing.Default value usually goodIncreasing the parameter +value increases computation burden
    +
    OVERLAP_MS
    +
    Default value is relatively +large, chosen to suit with above parameters. If you reduce the "sequence +ms" setting, you might wish to try a smaller value.  Increasing the parameter +value increases computation burden
    +

    3.5 Performance Optimizations

    +

    General optimizations:

    +

    The time-stretch routine has a 'quick' mode +that substantially speeds up the algorithm but may degrade the +sound quality by a small amount. This mode is activated by +calling SoundTouch::setSetting() function with parameter  id +of SETTING_USE_QUICKSEEK and value "1", i.e.

    +
    +

    setSetting(SETTING_USE_QUICKSEEK, 1);

    +
    +

    CPU-specific optimizations:

    +
      +
    • Intel MMX optimized routines are used with +compatible CPUs when 16bit integer sample type is used. MMX +optimizations are available both in Win32 and Gnu/x86 platforms. +Compatible processors are Intel PentiumMMX and later; AMD K6-2, Athlon +and later.
    • +
    • Intel SSE optimized routines are used with +compatible CPUs when floating point sample type is used. SSE +optimizations are currently implemented for Win32 platform only. +Processors compatible with SSE extension are Intel processors starting +from Pentium-III, and AMD processors starting from Athlon XP.
    • +
    • AMD 3DNow! optimized routines are used with +compatible CPUs when floating point sample type is used, but SSE +extension isn't supported . 3DNow! optimizations are currently +implemented for Win32 platform only. These optimizations are used in +AMD K6-2 and Athlon (classic) CPU's; better performing SSE routines are +used with AMD processor starting from Athlon XP.
    • +
    +
    +

    4. SoundStretch audio processing utility +

    +

    SoundStretch audio processing utility
    +Copyright (c) Olli Parviainen 2002-2005

    +

    SoundStretch is a simple command-line +application that can change tempo, pitch and playback rates of +WAV sound files. This program is intended primarily to +demonstrate how the "SoundTouch" library can be used to +process sound in your own program, but it can as well be used for +processing sound files.

    +

    4.1. SoundStretch Usage Instructions

    +

    SoundStretch Usage syntax:

    +
    +
    soundstretch infile.wav outfile.wav [switches]
    +
    +

    Where:

    + + + + + + + + + + + + + + + +
    +
    "infile.wav"
    +
    is the name of the input sound +data file (in .WAV audio file format).
    +
    "outfile.wav"
    +
    is the name of the output sound +file where the resulting sound is saved (in .WAV audio file format). +This parameter may be omitted if you  don't want to save the +output +(e.g. when only calculating BPM rate with '-bpm' switch).
    +
     [switches]
    +
    Are one or more control +switches.
    +

    Available control switches are:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    -tempo=n 
    +
    Change the sound tempo by n +percents (n = -95.0 .. +5000.0 %)
    +
    -pitch=n
    +
    Change the sound pitch by n +semitones (n = -60.0 .. + 60.0 semitones)
    +
    -rate=n
    +
    Change the sound playback rate by +n percents (n = -95.0 .. +5000.0 %)
    +
    -bpm=n
    +
    Detect the Beats-Per-Minute +(BPM) rate of the sound and adjust the tempo to meet 'n' BPMs. If this +switch is defined, the "-tempo=n" switch value is ignored. If "=n" is +omitted, i.e. switch "-bpm" is used alone, the program just calculates +and displays the BPM rate but doesn't adjust tempo according to the BPM +value.
    +
    -quick
    +
    Use quicker tempo change +algorithm. Gains speed but loses sound quality.
    +
    -naa
    +
    Don't use anti-alias +filtering in sample rate transposing. Gains speed but loses sound +quality.
    +
    -license
    +
    Displays the program license +text (LGPL)
    +

    Notes:

    +
      +
    • The numerical switch values can be entered +using either integer (e.g. "-tempo=123") or decimal (e.g. +"-tempo=123.45") numbers.
    • +
    • The "-naa" and/or "-quick" switches can be +used to reduce CPU usage while compromising some sound quality
    • +
    • The BPM detection algorithm works by detecting +repeating low-frequency (<250Hz) sound patterns and thus works +mostly with most rock/pop music with bass or drum beat. The BPM +detection doesn't work on pieces such as classical music without +distinct, repeating bass frequency patterns. Also pieces with varying +tempo, varying bass patterns or very complex bass patterns (jazz, hiphop) may produce odd BPM readings.
      +
      +In cases when the bass pattern drifts a bit around a nominal beat rate +(e.g. drummer is again drunken :), the BPM algorithm may report +incorrect harmonic one-halft to one-thirdth of the correct BPM value; +in such case the system could for example report BPM value of 50 or 100 +instead of correct BPM value of 150.
    • +
    +

    4.2. SoundStretch usage examples

    +

    Example 1

    +

    The following command increases tempo of +the sound file "originalfile.wav" by 12.5% and saves +result to file "destinationfile.wav":

    +
    +
    soundstretch originalfile.wav destinationfile.wav -tempo=12.5
    +
    +

    Example 2

    +

    The following command decreases the sound +pitch (key) of the sound file "orig.wav" by two +semitones and saves the result to file "dest.wav":

    +
    +
    soundstretch orig.wav dest.wav -pitch=-2
    +
    +

    Example 3

    +

    The following command processes the file "orig.wav" by decreasing the sound tempo by 25.3% and +increasing the sound pitch (key) by 1.5 semitones. Result is +saved to file "dest.wav":

    +
    +
    soundstretch orig.wav dest.wav -tempo=-25.3 -pitch=1.5
    +
    +

    Example 4

    +

    The following command detects the BPM rate +of the file "orig.wav" and adjusts the tempo to match +100 beats per minute. Result is saved to file "dest.wav":

    +
    +
    soundstretch orig.wav dest.wav -bpm=100
    +
    +
    +

    5. Change History

    +

    5.1. SoundTouch library Change History

    + +

    v1.3.1: +

    +
      +
    • Changed static class declaration to GCC 4.x compiler compatible syntax.
    • +
    • Enabled MMX/SSE-optimized routines also for GCC compilers. Earlier +the MMX/SSE-optimized routines were written in compiler-specific inline +assembler, now these routines are migrated to use compiler intrinsic +syntax which allows compiling the same MMX/SSE-optimized source code with +both Visual C++ and GCC compilers.
    • +
    • Set floating point as the default sample format and added switch to +the GNU configure script for selecting the other sample format.
    • + +
    + +

    v1.3.0: +

    +
      +
    • Fixed tempo routine output duration inaccuracy due to rounding +error
    • +
    • Implemented separate processing routines for integer and +floating arithmetic to allow improvements to floating point routines +(earlier used algorithms mostly optimized for integer arithmetic also +for floating point samples)
    • +
    • Fixed a bug that distorts sound if sample rate changes during the +sound stream
    • +
    • Fixed a memory leak that appeared in MMX/SSE/3DNow! optimized +routines
    • +
    • Reduced redundant code pieces in MMX/SSE/3DNow! optimized +routines vs. the standard C routines.
    • +
    • MMX routine incompatibility with new gcc compiler versions
    • +
    • Other miscellaneous bug fixes
    • +
    +

    v1.2.1:

    +
      +
    • Added automake/autoconf scripts for GNU +platforms (in courtesy of David Durham)
    • +
    • Fixed SCALE overflow bug in rate transposer +routine.
    • +
    • Fixed 64bit address space bugs.
    • +
    • Created a 'soundtouch' namespace for +SAMPLETYPE definitions.
    • +
    +

    v1.2.0:

    +
      +
    • Added support for 32bit floating point sample +data type with SSE/3DNow! optimizations for Win32 platform (SSE/3DNow! +optimizations currently not supported in GCC environment)
    • +
    • Replaced 'make-gcc' script for GNU environment +by master Makefile
    • +
    • Added time-stretch routine configurability to +SoundTouch main class
    • +
    • Bugfixes
    • +
    +

    v1.1.1:

    +
      +
    • Moved SoundTouch under lesser GPL license (LGPL). This allows using SoundTouch library in programs that aren't +released under GPL license.
    • +
    • Changed MMX routine organization so that MMX +optimized routines are now implemented in classes that are derived from +the basic classes having the standard non-mmx routines.
    • +
    • MMX routines to support gcc version 3.
    • +
    • Replaced windows makefiles by script using the .dsw files
    • +
    +

    v1.01:

    +
      +
    • "mmx_gcc.cpp": Added "using namespace std" and +removed "return 0" from a function with void return value to fix +compiler errors when compiling the library in Solaris environment.
    • +
    • Moved file "FIFOSampleBuffer.h" to "include" +directory to allow accessing the FIFOSampleBuffer class from external +files.
    • +
    +

    v1.0:

    +
      +
    • Initial release
    • +
    +

     

    +

    5.2. SoundStretch application Change +History

    +

    v1.3.0:

    +
      +
    • Simplified accessing WAV files with floating +point sample format.
      +
    • +
    +

    v1.2.1:

    +
      +
    • Fixed 64bit address space bugs.
    • +
    +

    v1.2.0:

    +
      +
    • Added support for 32bit floating point sample +data type
    • +
    • Restructured the BPM routines into separate +library
    • +
    • Fixed big-endian conversion bugs in WAV file +routines (hopefully :)
    • +
    +

    v1.1.1:

    +
      +
    • Fixed bugs in WAV file reading & added +byte-order conversion for big-endian processors.
    • +
    • Moved SoundStretch source code under 'example' +directory to highlight difference from SoundTouch stuff.
    • +
    • Replaced windows makefiles by script using the .dsw files
    • +
    • Output file name isn't required if output +isn't desired (e.g. if using the switch '-bpm' in plain format only)
    • +
    +

    v1.1:

    +
      +
    • Fixed "Release" settings in Microsoft Visual +C++ project file (.dsp)
    • +
    • Added beats-per-minute (BPM) detection routine +and command-line switch "-bpm"
    • +
    +

    v1.01:

    +
      +
    • Initial release
    • +
    +
    +

    6. LICENSE

    +

    SoundTouch audio processing library
    +Copyright (c) Olli Parviainen

    +

    This library is free software; you can +redistribute it and/or modify it under the terms of the GNU +Lesser General Public License as published by the Free Software +Foundation; either version 2.1 of the License, or (at your option) +any later version.

    +

    This library 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 Lesser General Public License for +more details.

    +

    You should have received a copy of the GNU +Lesser General Public License along with this library; if not, +write to the Free Software Foundation, Inc., 59 Temple Place, +Suite 330, Boston, MA 02111-1307 USA

    +
    + + + diff --git a/lib-src/soundtouch/config/README.TXT b/lib-src/soundtouch/config/README.TXT index 7c4f6e44c..0b29eaeae 100644 --- a/lib-src/soundtouch/config/README.TXT +++ b/lib-src/soundtouch/config/README.TXT @@ -1,3 +1,3 @@ -Files in this directory are used by GNU autoconf/automake system. -These files aren't used/needed in the Windows environment. - +Files in this directory are used by GNU autoconf/automake system. +These files aren't used/needed in the Windows environment. + diff --git a/lib-src/soundtouch/soundtouch/BPMDetect.h b/lib-src/soundtouch/soundtouch/BPMDetect.h index ef4772c99..cc47de103 100644 --- a/lib-src/soundtouch/soundtouch/BPMDetect.h +++ b/lib-src/soundtouch/soundtouch/BPMDetect.h @@ -1,159 +1,159 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Beats-per-minute (BPM) detection routine. -/// -/// The beat detection algorithm works as follows: -/// - Use function 'inputSamples' to input a chunks of samples to the class for -/// analysis. It's a good idea to enter a large sound file or stream in smallish -/// chunks of around few kilosamples in order not to extinguish too much RAM memory. -/// - Input sound data is decimated to approx 500 Hz to reduce calculation burden, -/// which is basically ok as low (bass) frequencies mostly determine the beat rate. -/// Simple averaging is used for anti-alias filtering because the resulting signal -/// quality isn't of that high importance. -/// - Decimated sound data is enveloped, i.e. the amplitude shape is detected by -/// taking absolute value that's smoothed by sliding average. Signal levels that -/// are below a couple of times the general RMS amplitude level are cut away to -/// leave only notable peaks there. -/// - Repeating sound patterns (e.g. beats) are detected by calculating short-term -/// autocorrelation function of the enveloped signal. -/// - After whole sound data file has been analyzed as above, the bpm level is -/// detected by function 'getBpm' that finds the highest peak of the autocorrelation -/// function, calculates it's precise location and converts this reading to bpm's. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006-09-18 07:39:15 $ -// File revision : $Revision: 1.2 $ -// -// $Id: BPMDetect.h,v 1.2 2006-09-18 07:39:15 richardash1981 Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef _BPMDetect_H_ -#define _BPMDetect_H_ - -#include "STTypes.h" -#include "FIFOSampleBuffer.h" - -/// Minimum allowed BPM rate. Used to restrict accepted result above a reasonable limit. -#define MIN_BPM 45 - -/// Maximum allowed BPM rate. Used to restrict accepted result below a reasonable limit. -#define MAX_BPM 230 - - -/// Class for calculating BPM rate for audio data. -class BPMDetect -{ -protected: - /// Auto-correlation accumulator bins. - float *xcorr; - - /// Amplitude envelope sliding average approximation level accumulator - float envelopeAccu; - - /// RMS volume sliding average approximation level accumulator - float RMSVolumeAccu; - - /// Sample average counter. - int decimateCount; - - /// Sample average accumulator for FIFO-like decimation. - soundtouch::LONG_SAMPLETYPE decimateSum; - - /// Decimate sound by this coefficient to reach approx. 500 Hz. - int decimateBy; - - /// Auto-correlation window length - int windowLen; - - /// Number of channels (1 = mono, 2 = stereo) - int channels; - - /// sample rate - int sampleRate; - - /// Beginning of auto-correlation window: Autocorrelation isn't being updated for - /// the first these many correlation bins. - int windowStart; - - /// FIFO-buffer for decimated processing samples. - soundtouch::FIFOSampleBuffer *buffer; - - /// Initialize the class for processing. - void init(int numChannels, int sampleRate); - - /// Updates auto-correlation function for given number of decimated samples that - /// are read from the internal 'buffer' pipe (samples aren't removed from the pipe - /// though). - void updateXCorr(int process_samples /// How many samples are processed. - ); - - /// Decimates samples to approx. 500 Hz. - /// - /// \return Number of output samples. - int decimate(soundtouch::SAMPLETYPE *dest, ///< Destination buffer - const soundtouch::SAMPLETYPE *src, ///< Source sample buffer - int numsamples ///< Number of source samples. - ); - - /// Calculates amplitude envelope for the buffer of samples. - /// Result is output to 'samples'. - void calcEnvelope(soundtouch::SAMPLETYPE *samples, ///< Pointer to input/output data buffer - int numsamples ///< Number of samples in buffer - ); - -public: - /// Constructor. - BPMDetect(int numChannels, ///< Number of channels in sample data. - int sampleRate ///< Sample rate in Hz. - ); - - /// Destructor. - virtual ~BPMDetect(); - - /// Inputs a block of samples for analyzing: Envelopes the samples and then - /// updates the autocorrelation estimation. When whole song data has been input - /// in smaller blocks using this function, read the resulting bpm with 'getBpm' - /// function. - /// - /// Notice that data in 'samples' array can be disrupted in processing. - void inputSamples(soundtouch::SAMPLETYPE *samples, ///< Pointer to input/working data buffer - int numSamples ///< Number of samples in buffer - ); - - - /// Analyzes the results and returns the BPM rate. Use this function to read result - /// after whole song data has been input to the class by consecutive calls of - /// 'inputSamples' function. - /// - /// \return Beats-per-minute rate, or zero if detection failed. - float getBpm(); -}; - -#endif // _BPMDetect_H_ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Beats-per-minute (BPM) detection routine. +/// +/// The beat detection algorithm works as follows: +/// - Use function 'inputSamples' to input a chunks of samples to the class for +/// analysis. It's a good idea to enter a large sound file or stream in smallish +/// chunks of around few kilosamples in order not to extinguish too much RAM memory. +/// - Input sound data is decimated to approx 500 Hz to reduce calculation burden, +/// which is basically ok as low (bass) frequencies mostly determine the beat rate. +/// Simple averaging is used for anti-alias filtering because the resulting signal +/// quality isn't of that high importance. +/// - Decimated sound data is enveloped, i.e. the amplitude shape is detected by +/// taking absolute value that's smoothed by sliding average. Signal levels that +/// are below a couple of times the general RMS amplitude level are cut away to +/// leave only notable peaks there. +/// - Repeating sound patterns (e.g. beats) are detected by calculating short-term +/// autocorrelation function of the enveloped signal. +/// - After whole sound data file has been analyzed as above, the bpm level is +/// detected by function 'getBpm' that finds the highest peak of the autocorrelation +/// function, calculates it's precise location and converts this reading to bpm's. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006-09-18 07:39:15 $ +// File revision : $Revision: 1.2 $ +// +// $Id: BPMDetect.h,v 1.2 2006-09-18 07:39:15 richardash1981 Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef _BPMDetect_H_ +#define _BPMDetect_H_ + +#include "STTypes.h" +#include "FIFOSampleBuffer.h" + +/// Minimum allowed BPM rate. Used to restrict accepted result above a reasonable limit. +#define MIN_BPM 45 + +/// Maximum allowed BPM rate. Used to restrict accepted result below a reasonable limit. +#define MAX_BPM 230 + + +/// Class for calculating BPM rate for audio data. +class BPMDetect +{ +protected: + /// Auto-correlation accumulator bins. + float *xcorr; + + /// Amplitude envelope sliding average approximation level accumulator + float envelopeAccu; + + /// RMS volume sliding average approximation level accumulator + float RMSVolumeAccu; + + /// Sample average counter. + int decimateCount; + + /// Sample average accumulator for FIFO-like decimation. + soundtouch::LONG_SAMPLETYPE decimateSum; + + /// Decimate sound by this coefficient to reach approx. 500 Hz. + int decimateBy; + + /// Auto-correlation window length + int windowLen; + + /// Number of channels (1 = mono, 2 = stereo) + int channels; + + /// sample rate + int sampleRate; + + /// Beginning of auto-correlation window: Autocorrelation isn't being updated for + /// the first these many correlation bins. + int windowStart; + + /// FIFO-buffer for decimated processing samples. + soundtouch::FIFOSampleBuffer *buffer; + + /// Initialize the class for processing. + void init(int numChannels, int sampleRate); + + /// Updates auto-correlation function for given number of decimated samples that + /// are read from the internal 'buffer' pipe (samples aren't removed from the pipe + /// though). + void updateXCorr(int process_samples /// How many samples are processed. + ); + + /// Decimates samples to approx. 500 Hz. + /// + /// \return Number of output samples. + int decimate(soundtouch::SAMPLETYPE *dest, ///< Destination buffer + const soundtouch::SAMPLETYPE *src, ///< Source sample buffer + int numsamples ///< Number of source samples. + ); + + /// Calculates amplitude envelope for the buffer of samples. + /// Result is output to 'samples'. + void calcEnvelope(soundtouch::SAMPLETYPE *samples, ///< Pointer to input/output data buffer + int numsamples ///< Number of samples in buffer + ); + +public: + /// Constructor. + BPMDetect(int numChannels, ///< Number of channels in sample data. + int sampleRate ///< Sample rate in Hz. + ); + + /// Destructor. + virtual ~BPMDetect(); + + /// Inputs a block of samples for analyzing: Envelopes the samples and then + /// updates the autocorrelation estimation. When whole song data has been input + /// in smaller blocks using this function, read the resulting bpm with 'getBpm' + /// function. + /// + /// Notice that data in 'samples' array can be disrupted in processing. + void inputSamples(soundtouch::SAMPLETYPE *samples, ///< Pointer to input/working data buffer + int numSamples ///< Number of samples in buffer + ); + + + /// Analyzes the results and returns the BPM rate. Use this function to read result + /// after whole song data has been input to the class by consecutive calls of + /// 'inputSamples' function. + /// + /// \return Beats-per-minute rate, or zero if detection failed. + float getBpm(); +}; + +#endif // _BPMDetect_H_ diff --git a/lib-src/soundtouch/soundtouch/FIFOSampleBuffer.h b/lib-src/soundtouch/soundtouch/FIFOSampleBuffer.h index 3ec683432..015eeb1dc 100644 --- a/lib-src/soundtouch/soundtouch/FIFOSampleBuffer.h +++ b/lib-src/soundtouch/soundtouch/FIFOSampleBuffer.h @@ -1,174 +1,174 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// A buffer class for temporarily storaging sound samples, operates as a -/// first-in-first-out pipe. -/// -/// Samples are added to the end of the sample buffer with the 'putSamples' -/// function, and are received from the beginning of the buffer by calling -/// the 'receiveSamples' function. The class automatically removes the -/// output samples from the buffer as well as grows the storage size -/// whenever necessary. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006-09-18 07:39:15 $ -// File revision : $Revision: 1.2 $ -// -// $Id: FIFOSampleBuffer.h,v 1.2 2006-09-18 07:39:15 richardash1981 Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef FIFOSampleBuffer_H -#define FIFOSampleBuffer_H - -#include "FIFOSamplePipe.h" - -namespace soundtouch -{ - -/// Sample buffer working in FIFO (first-in-first-out) principle. The class takes -/// care of storage size adjustment and data moving during input/output operations. -/// -/// Notice that in case of stereo audio, one sample is considered to consist of -/// both channel data. -class FIFOSampleBuffer : public FIFOSamplePipe -{ -private: - /// Sample buffer. - SAMPLETYPE *buffer; - - // Raw unaligned buffer memory. 'buffer' is made aligned by pointing it to first - // 16-byte aligned location of this buffer - SAMPLETYPE *bufferUnaligned; - - /// Sample buffer size in bytes - uint sizeInBytes; - - /// How many samples are currently in buffer. - uint samplesInBuffer; - - /// Channels, 1=mono, 2=stereo. - uint channels; - - /// Current position pointer to the buffer. This pointer is increased when samples are - /// removed from the pipe so that it's necessary to actually rewind buffer (move data) - /// only new data when is put to the pipe. - uint bufferPos; - - /// Rewind the buffer by moving data from position pointed by 'bufferPos' to real - /// beginning of the buffer. - void rewind(); - - /// Ensures that the buffer has capacity for at least this many samples. - void ensureCapacity(const uint capacityRequirement); - - /// Returns current capacity. - uint getCapacity() const; - -public: - - /// Constructor - FIFOSampleBuffer(uint numChannels = 2 ///< Number of channels, 1=mono, 2=stereo. - ///< Default is stereo. - ); - - /// destructor - ~FIFOSampleBuffer(); - - /// Returns a pointer to the beginning of the output samples. - /// This function is provided for accessing the output samples directly. - /// Please be careful for not to corrupt the book-keeping! - /// - /// When using this function to output samples, also remember to 'remove' the - /// output samples from the buffer by calling the - /// 'receiveSamples(numSamples)' function - virtual SAMPLETYPE *ptrBegin() const; - - /// Returns a pointer to the end of the used part of the sample buffer (i.e. - /// where the new samples are to be inserted). This function may be used for - /// inserting new samples into the sample buffer directly. Please be careful - /// not corrupt the book-keeping! - /// - /// When using this function as means for inserting new samples, also remember - /// to increase the sample count afterwards, by calling the - /// 'putSamples(numSamples)' function. - SAMPLETYPE *ptrEnd( - uint slackCapacity ///< How much free capacity (in samples) there _at least_ - ///< should be so that the caller can succesfully insert the - ///< desired samples to the buffer. If necessary, the function - ///< grows the buffer size to comply with this requirement. - ); - - /// Adds 'numSamples' pcs of samples from the 'samples' memory position to - /// the sample buffer. - virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples. - uint numSamples ///< Number of samples to insert. - ); - - /// Adjusts the book-keeping to increase number of samples in the buffer without - /// copying any actual samples. - /// - /// This function is used to update the number of samples in the sample buffer - /// when accessing the buffer directly with 'ptrEnd' function. Please be - /// careful though! - virtual void putSamples(uint numSamples ///< Number of samples been inserted. - ); - - /// Output samples from beginning of the sample buffer. Copies requested samples to - /// output buffer and removes them from the sample buffer. If there are less than - /// 'numsample' samples in the buffer, returns all that available. - /// - /// \return Number of samples returned. - virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples. - uint maxSamples ///< How many samples to receive at max. - ); - - /// Adjusts book-keeping so that given number of samples are removed from beginning of the - /// sample buffer without copying them anywhere. - /// - /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly - /// with 'ptrBegin' function. - virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. - ); - - /// Returns number of samples currently available. - virtual uint numSamples() const; - - /// Sets number of channels, 1 = mono, 2 = stereo. - void setChannels(uint numChannels); - - /// Returns nonzero if there aren't any samples available for outputting. - virtual int isEmpty() const; - - /// Clears all the samples. - virtual void clear(); -}; - -} - -#endif +//////////////////////////////////////////////////////////////////////////////// +/// +/// A buffer class for temporarily storaging sound samples, operates as a +/// first-in-first-out pipe. +/// +/// Samples are added to the end of the sample buffer with the 'putSamples' +/// function, and are received from the beginning of the buffer by calling +/// the 'receiveSamples' function. The class automatically removes the +/// output samples from the buffer as well as grows the storage size +/// whenever necessary. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006-09-18 07:39:15 $ +// File revision : $Revision: 1.2 $ +// +// $Id: FIFOSampleBuffer.h,v 1.2 2006-09-18 07:39:15 richardash1981 Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef FIFOSampleBuffer_H +#define FIFOSampleBuffer_H + +#include "FIFOSamplePipe.h" + +namespace soundtouch +{ + +/// Sample buffer working in FIFO (first-in-first-out) principle. The class takes +/// care of storage size adjustment and data moving during input/output operations. +/// +/// Notice that in case of stereo audio, one sample is considered to consist of +/// both channel data. +class FIFOSampleBuffer : public FIFOSamplePipe +{ +private: + /// Sample buffer. + SAMPLETYPE *buffer; + + // Raw unaligned buffer memory. 'buffer' is made aligned by pointing it to first + // 16-byte aligned location of this buffer + SAMPLETYPE *bufferUnaligned; + + /// Sample buffer size in bytes + uint sizeInBytes; + + /// How many samples are currently in buffer. + uint samplesInBuffer; + + /// Channels, 1=mono, 2=stereo. + uint channels; + + /// Current position pointer to the buffer. This pointer is increased when samples are + /// removed from the pipe so that it's necessary to actually rewind buffer (move data) + /// only new data when is put to the pipe. + uint bufferPos; + + /// Rewind the buffer by moving data from position pointed by 'bufferPos' to real + /// beginning of the buffer. + void rewind(); + + /// Ensures that the buffer has capacity for at least this many samples. + void ensureCapacity(const uint capacityRequirement); + + /// Returns current capacity. + uint getCapacity() const; + +public: + + /// Constructor + FIFOSampleBuffer(uint numChannels = 2 ///< Number of channels, 1=mono, 2=stereo. + ///< Default is stereo. + ); + + /// destructor + ~FIFOSampleBuffer(); + + /// Returns a pointer to the beginning of the output samples. + /// This function is provided for accessing the output samples directly. + /// Please be careful for not to corrupt the book-keeping! + /// + /// When using this function to output samples, also remember to 'remove' the + /// output samples from the buffer by calling the + /// 'receiveSamples(numSamples)' function + virtual SAMPLETYPE *ptrBegin() const; + + /// Returns a pointer to the end of the used part of the sample buffer (i.e. + /// where the new samples are to be inserted). This function may be used for + /// inserting new samples into the sample buffer directly. Please be careful + /// not corrupt the book-keeping! + /// + /// When using this function as means for inserting new samples, also remember + /// to increase the sample count afterwards, by calling the + /// 'putSamples(numSamples)' function. + SAMPLETYPE *ptrEnd( + uint slackCapacity ///< How much free capacity (in samples) there _at least_ + ///< should be so that the caller can succesfully insert the + ///< desired samples to the buffer. If necessary, the function + ///< grows the buffer size to comply with this requirement. + ); + + /// Adds 'numSamples' pcs of samples from the 'samples' memory position to + /// the sample buffer. + virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples. + uint numSamples ///< Number of samples to insert. + ); + + /// Adjusts the book-keeping to increase number of samples in the buffer without + /// copying any actual samples. + /// + /// This function is used to update the number of samples in the sample buffer + /// when accessing the buffer directly with 'ptrEnd' function. Please be + /// careful though! + virtual void putSamples(uint numSamples ///< Number of samples been inserted. + ); + + /// Output samples from beginning of the sample buffer. Copies requested samples to + /// output buffer and removes them from the sample buffer. If there are less than + /// 'numsample' samples in the buffer, returns all that available. + /// + /// \return Number of samples returned. + virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples. + uint maxSamples ///< How many samples to receive at max. + ); + + /// Adjusts book-keeping so that given number of samples are removed from beginning of the + /// sample buffer without copying them anywhere. + /// + /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly + /// with 'ptrBegin' function. + virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. + ); + + /// Returns number of samples currently available. + virtual uint numSamples() const; + + /// Sets number of channels, 1 = mono, 2 = stereo. + void setChannels(uint numChannels); + + /// Returns nonzero if there aren't any samples available for outputting. + virtual int isEmpty() const; + + /// Clears all the samples. + virtual void clear(); +}; + +} + +#endif diff --git a/lib-src/soundtouch/soundtouch/FIFOSamplePipe.h b/lib-src/soundtouch/soundtouch/FIFOSamplePipe.h index 51770fdbd..eb317e645 100644 --- a/lib-src/soundtouch/soundtouch/FIFOSamplePipe.h +++ b/lib-src/soundtouch/soundtouch/FIFOSamplePipe.h @@ -1,217 +1,217 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// 'FIFOSamplePipe' : An abstract base class for classes that manipulate sound -/// samples by operating like a first-in-first-out pipe: New samples are fed -/// into one end of the pipe with the 'putSamples' function, and the processed -/// samples are received from the other end with the 'receiveSamples' function. -/// -/// 'FIFOProcessor' : A base class for classes the do signal processing with -/// the samples while operating like a first-in-first-out pipe. When samples -/// are input with the 'putSamples' function, the class processes them -/// and moves the processed samples to the given 'output' pipe object, which -/// may be either another processing stage, or a fifo sample buffer object. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006-09-18 07:39:15 $ -// File revision : $Revision: 1.2 $ -// -// $Id: FIFOSamplePipe.h,v 1.2 2006-09-18 07:39:15 richardash1981 Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef FIFOSamplePipe_H -#define FIFOSamplePipe_H - -#include -#include -#include "STTypes.h" - -namespace soundtouch -{ - -/// Abstract base class for FIFO (first-in-first-out) sample processing classes. -class FIFOSamplePipe -{ -public: - /// Returns a pointer to the beginning of the output samples. - /// This function is provided for accessing the output samples directly. - /// Please be careful for not to corrupt the book-keeping! - /// - /// When using this function to output samples, also remember to 'remove' the - /// output samples from the buffer by calling the - /// 'receiveSamples(numSamples)' function - virtual SAMPLETYPE *ptrBegin() const = 0; - - /// Adds 'numSamples' pcs of samples from the 'samples' memory position to - /// the sample buffer. - virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples. - uint numSamples ///< Number of samples to insert. - ) = 0; - - - // Moves samples from the 'other' pipe instance to this instance. - void moveSamples(FIFOSamplePipe &other ///< Other pipe instance where from the receive the data. - ) - { - int oNumSamples = other.numSamples(); - - putSamples(other.ptrBegin(), oNumSamples); - other.receiveSamples(oNumSamples); - }; - - /// Output samples from beginning of the sample buffer. Copies requested samples to - /// output buffer and removes them from the sample buffer. If there are less than - /// 'numsample' samples in the buffer, returns all that available. - /// - /// \return Number of samples returned. - virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples. - uint maxSamples ///< How many samples to receive at max. - ) = 0; - - /// Adjusts book-keeping so that given number of samples are removed from beginning of the - /// sample buffer without copying them anywhere. - /// - /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly - /// with 'ptrBegin' function. - virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. - ) = 0; - - /// Returns number of samples currently available. - virtual uint numSamples() const = 0; - - // Returns nonzero if there aren't any samples available for outputting. - virtual int isEmpty() const = 0; - - /// Clears all the samples. - virtual void clear() = 0; -}; - - - -/// Base-class for sound processing routines working in FIFO principle. With this base -/// class it's easy to implement sound processing stages that can be chained together, -/// so that samples that are fed into beginning of the pipe automatically go through -/// all the processing stages. -/// -/// When samples are input to this class, they're first processed and then put to -/// the FIFO pipe that's defined as output of this class. This output pipe can be -/// either other processing stage or a FIFO sample buffer. -class FIFOProcessor :public FIFOSamplePipe -{ -protected: - /// Internal pipe where processed samples are put. - FIFOSamplePipe *output; - - /// Sets output pipe. - void setOutPipe(FIFOSamplePipe *pOutput) - { - assert(output == NULL); - assert(pOutput != NULL); - output = pOutput; - } - - - /// Constructor. Doesn't define output pipe; it has to be set be - /// 'setOutPipe' function. - FIFOProcessor() - { - output = NULL; - } - - - /// Constructor. Configures output pipe. - FIFOProcessor(FIFOSamplePipe *pOutput ///< Output pipe. - ) - { - output = pOutput; - } - - - /// Destructor. - virtual ~FIFOProcessor() - { - } - - - /// Returns a pointer to the beginning of the output samples. - /// This function is provided for accessing the output samples directly. - /// Please be careful for not to corrupt the book-keeping! - /// - /// When using this function to output samples, also remember to 'remove' the - /// output samples from the buffer by calling the - /// 'receiveSamples(numSamples)' function - virtual SAMPLETYPE *ptrBegin() const - { - return output->ptrBegin(); - } - -public: - - /// Output samples from beginning of the sample buffer. Copies requested samples to - /// output buffer and removes them from the sample buffer. If there are less than - /// 'numsample' samples in the buffer, returns all that available. - /// - /// \return Number of samples returned. - virtual uint receiveSamples(SAMPLETYPE *outBuffer, ///< Buffer where to copy output samples. - uint maxSamples ///< How many samples to receive at max. - ) - { - return output->receiveSamples(outBuffer, maxSamples); - } - - - /// Adjusts book-keeping so that given number of samples are removed from beginning of the - /// sample buffer without copying them anywhere. - /// - /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly - /// with 'ptrBegin' function. - virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. - ) - { - return output->receiveSamples(maxSamples); - } - - - /// Returns number of samples currently available. - virtual uint numSamples() const - { - return output->numSamples(); - } - - - /// Returns nonzero if there aren't any samples available for outputting. - virtual int isEmpty() const - { - return output->isEmpty(); - } -}; - -} - -#endif +//////////////////////////////////////////////////////////////////////////////// +/// +/// 'FIFOSamplePipe' : An abstract base class for classes that manipulate sound +/// samples by operating like a first-in-first-out pipe: New samples are fed +/// into one end of the pipe with the 'putSamples' function, and the processed +/// samples are received from the other end with the 'receiveSamples' function. +/// +/// 'FIFOProcessor' : A base class for classes the do signal processing with +/// the samples while operating like a first-in-first-out pipe. When samples +/// are input with the 'putSamples' function, the class processes them +/// and moves the processed samples to the given 'output' pipe object, which +/// may be either another processing stage, or a fifo sample buffer object. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006-09-18 07:39:15 $ +// File revision : $Revision: 1.2 $ +// +// $Id: FIFOSamplePipe.h,v 1.2 2006-09-18 07:39:15 richardash1981 Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef FIFOSamplePipe_H +#define FIFOSamplePipe_H + +#include +#include +#include "STTypes.h" + +namespace soundtouch +{ + +/// Abstract base class for FIFO (first-in-first-out) sample processing classes. +class FIFOSamplePipe +{ +public: + /// Returns a pointer to the beginning of the output samples. + /// This function is provided for accessing the output samples directly. + /// Please be careful for not to corrupt the book-keeping! + /// + /// When using this function to output samples, also remember to 'remove' the + /// output samples from the buffer by calling the + /// 'receiveSamples(numSamples)' function + virtual SAMPLETYPE *ptrBegin() const = 0; + + /// Adds 'numSamples' pcs of samples from the 'samples' memory position to + /// the sample buffer. + virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples. + uint numSamples ///< Number of samples to insert. + ) = 0; + + + // Moves samples from the 'other' pipe instance to this instance. + void moveSamples(FIFOSamplePipe &other ///< Other pipe instance where from the receive the data. + ) + { + int oNumSamples = other.numSamples(); + + putSamples(other.ptrBegin(), oNumSamples); + other.receiveSamples(oNumSamples); + }; + + /// Output samples from beginning of the sample buffer. Copies requested samples to + /// output buffer and removes them from the sample buffer. If there are less than + /// 'numsample' samples in the buffer, returns all that available. + /// + /// \return Number of samples returned. + virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples. + uint maxSamples ///< How many samples to receive at max. + ) = 0; + + /// Adjusts book-keeping so that given number of samples are removed from beginning of the + /// sample buffer without copying them anywhere. + /// + /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly + /// with 'ptrBegin' function. + virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. + ) = 0; + + /// Returns number of samples currently available. + virtual uint numSamples() const = 0; + + // Returns nonzero if there aren't any samples available for outputting. + virtual int isEmpty() const = 0; + + /// Clears all the samples. + virtual void clear() = 0; +}; + + + +/// Base-class for sound processing routines working in FIFO principle. With this base +/// class it's easy to implement sound processing stages that can be chained together, +/// so that samples that are fed into beginning of the pipe automatically go through +/// all the processing stages. +/// +/// When samples are input to this class, they're first processed and then put to +/// the FIFO pipe that's defined as output of this class. This output pipe can be +/// either other processing stage or a FIFO sample buffer. +class FIFOProcessor :public FIFOSamplePipe +{ +protected: + /// Internal pipe where processed samples are put. + FIFOSamplePipe *output; + + /// Sets output pipe. + void setOutPipe(FIFOSamplePipe *pOutput) + { + assert(output == NULL); + assert(pOutput != NULL); + output = pOutput; + } + + + /// Constructor. Doesn't define output pipe; it has to be set be + /// 'setOutPipe' function. + FIFOProcessor() + { + output = NULL; + } + + + /// Constructor. Configures output pipe. + FIFOProcessor(FIFOSamplePipe *pOutput ///< Output pipe. + ) + { + output = pOutput; + } + + + /// Destructor. + virtual ~FIFOProcessor() + { + } + + + /// Returns a pointer to the beginning of the output samples. + /// This function is provided for accessing the output samples directly. + /// Please be careful for not to corrupt the book-keeping! + /// + /// When using this function to output samples, also remember to 'remove' the + /// output samples from the buffer by calling the + /// 'receiveSamples(numSamples)' function + virtual SAMPLETYPE *ptrBegin() const + { + return output->ptrBegin(); + } + +public: + + /// Output samples from beginning of the sample buffer. Copies requested samples to + /// output buffer and removes them from the sample buffer. If there are less than + /// 'numsample' samples in the buffer, returns all that available. + /// + /// \return Number of samples returned. + virtual uint receiveSamples(SAMPLETYPE *outBuffer, ///< Buffer where to copy output samples. + uint maxSamples ///< How many samples to receive at max. + ) + { + return output->receiveSamples(outBuffer, maxSamples); + } + + + /// Adjusts book-keeping so that given number of samples are removed from beginning of the + /// sample buffer without copying them anywhere. + /// + /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly + /// with 'ptrBegin' function. + virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. + ) + { + return output->receiveSamples(maxSamples); + } + + + /// Returns number of samples currently available. + virtual uint numSamples() const + { + return output->numSamples(); + } + + + /// Returns nonzero if there aren't any samples available for outputting. + virtual int isEmpty() const + { + return output->isEmpty(); + } +}; + +} + +#endif diff --git a/lib-src/soundtouch/soundtouch/STTypes.h b/lib-src/soundtouch/soundtouch/STTypes.h index cbd88bbcf..83aceb88b 100644 --- a/lib-src/soundtouch/soundtouch/STTypes.h +++ b/lib-src/soundtouch/soundtouch/STTypes.h @@ -1,143 +1,143 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Common type definitions for SoundTouch audio processing library. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006-09-18 07:39:15 $ -// File revision : $Revision: 1.2 $ -// -// $Id: STTypes.h,v 1.2 2006-09-18 07:39:15 richardash1981 Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef STTypes_H -#define STTypes_H - -typedef unsigned int uint; -typedef unsigned long ulong; - -#ifdef __GNUC__ - // In GCC, include soundtouch_config.h made by config scritps - #include "soundtouch_config.h" -#endif - -#ifndef _WINDEF_ - // if these aren't defined already by Windows headers, define now - - typedef int BOOL; - - #define FALSE 0 - #define TRUE 1 - -#endif // _WINDEF_ - - -namespace soundtouch -{ -/// Activate these undef's to overrule the possible sampletype -/// setting inherited from some other header file: -//#undef INTEGER_SAMPLES -//#undef FLOAT_SAMPLES - -#if !(INTEGER_SAMPLES || FLOAT_SAMPLES) - - /// Choose either 32bit floating point or 16bit integer sampletype - /// by choosing one of the following defines, unless this selection - /// has already been done in some other file. - //// - /// Notes: - /// - In Windows environment, choose the sample format with the - /// following defines. - /// - In GNU environment, the floating point samples are used by - /// default, but integer samples can be chosen by giving the - /// following switch to the configure script: - /// ./configure --enable-integer-samples - /// However, if you still prefer to select the sample format here - /// also in GNU environment, then please #undef the INTEGER_SAMPLE - /// and FLOAT_SAMPLE defines first as in comments above. - //#define INTEGER_SAMPLES 1 //< 16bit integer samples - #define FLOAT_SAMPLES 1 //< 32bit float samples - - #endif - - /// Define this to allow CPU-specific assembler optimizations. Notice that - /// having this enabled on non-x86 platforms doesn't matter; the compiler can - /// drop unsupported extensions on different platforms automatically. - /// However, if you're having difficulties getting the optimized routines - /// compiled with your compler (e.g. some gcc compiler versions may be picky), - /// you may wish to disable the optimizations to make the library compile. - #define ALLOW_OPTIMIZATIONS 1 - - - // If defined, allows the SIMD-optimized routines to take minor shortcuts - // for improved performance. Undefine to require faithfully similar SIMD - // calculations as in normal C implementation. - #define ALLOW_NONEXACT_SIMD_OPTIMIZATION 1 - - - #ifdef INTEGER_SAMPLES - // 16bit integer sample type - typedef short SAMPLETYPE; - // data type for sample accumulation: Use 32bit integer to prevent overflows - typedef long LONG_SAMPLETYPE; - - #ifdef FLOAT_SAMPLES - // check that only one sample type is defined - #error "conflicting sample types defined" - #endif // FLOAT_SAMPLES - - #ifdef ALLOW_OPTIMIZATIONS - #if (WIN32 || __i386__ || __x86_64__) - // Allow MMX optimizations - #define ALLOW_MMX 1 - #endif - #endif - - #else - - // floating point samples - typedef float SAMPLETYPE; - // data type for sample accumulation: Use double to utilize full precision. - typedef double LONG_SAMPLETYPE; - - #ifdef ALLOW_OPTIMIZATIONS - // Allow 3DNow! and SSE optimizations - #if WIN32 - #define ALLOW_3DNOW 1 - #endif - - #if (WIN32 || __i386__ || __x86_64__) - #define ALLOW_SSE 1 - #endif - #endif - - #endif // INTEGER_SAMPLES -}; - -#endif +//////////////////////////////////////////////////////////////////////////////// +/// +/// Common type definitions for SoundTouch audio processing library. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006-09-18 07:39:15 $ +// File revision : $Revision: 1.2 $ +// +// $Id: STTypes.h,v 1.2 2006-09-18 07:39:15 richardash1981 Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef STTypes_H +#define STTypes_H + +typedef unsigned int uint; +typedef unsigned long ulong; + +#ifdef __GNUC__ + // In GCC, include soundtouch_config.h made by config scritps + #include "soundtouch_config.h" +#endif + +#ifndef _WINDEF_ + // if these aren't defined already by Windows headers, define now + + typedef int BOOL; + + #define FALSE 0 + #define TRUE 1 + +#endif // _WINDEF_ + + +namespace soundtouch +{ +/// Activate these undef's to overrule the possible sampletype +/// setting inherited from some other header file: +//#undef INTEGER_SAMPLES +//#undef FLOAT_SAMPLES + +#if !(INTEGER_SAMPLES || FLOAT_SAMPLES) + + /// Choose either 32bit floating point or 16bit integer sampletype + /// by choosing one of the following defines, unless this selection + /// has already been done in some other file. + //// + /// Notes: + /// - In Windows environment, choose the sample format with the + /// following defines. + /// - In GNU environment, the floating point samples are used by + /// default, but integer samples can be chosen by giving the + /// following switch to the configure script: + /// ./configure --enable-integer-samples + /// However, if you still prefer to select the sample format here + /// also in GNU environment, then please #undef the INTEGER_SAMPLE + /// and FLOAT_SAMPLE defines first as in comments above. + //#define INTEGER_SAMPLES 1 //< 16bit integer samples + #define FLOAT_SAMPLES 1 //< 32bit float samples + + #endif + + /// Define this to allow CPU-specific assembler optimizations. Notice that + /// having this enabled on non-x86 platforms doesn't matter; the compiler can + /// drop unsupported extensions on different platforms automatically. + /// However, if you're having difficulties getting the optimized routines + /// compiled with your compler (e.g. some gcc compiler versions may be picky), + /// you may wish to disable the optimizations to make the library compile. + #define ALLOW_OPTIMIZATIONS 1 + + + // If defined, allows the SIMD-optimized routines to take minor shortcuts + // for improved performance. Undefine to require faithfully similar SIMD + // calculations as in normal C implementation. + #define ALLOW_NONEXACT_SIMD_OPTIMIZATION 1 + + + #ifdef INTEGER_SAMPLES + // 16bit integer sample type + typedef short SAMPLETYPE; + // data type for sample accumulation: Use 32bit integer to prevent overflows + typedef long LONG_SAMPLETYPE; + + #ifdef FLOAT_SAMPLES + // check that only one sample type is defined + #error "conflicting sample types defined" + #endif // FLOAT_SAMPLES + + #ifdef ALLOW_OPTIMIZATIONS + #if (WIN32 || __i386__ || __x86_64__) + // Allow MMX optimizations + #define ALLOW_MMX 1 + #endif + #endif + + #else + + // floating point samples + typedef float SAMPLETYPE; + // data type for sample accumulation: Use double to utilize full precision. + typedef double LONG_SAMPLETYPE; + + #ifdef ALLOW_OPTIMIZATIONS + // Allow 3DNow! and SSE optimizations + #if WIN32 + #define ALLOW_3DNOW 1 + #endif + + #if (WIN32 || __i386__ || __x86_64__) + #define ALLOW_SSE 1 + #endif + #endif + + #endif // INTEGER_SAMPLES +}; + +#endif diff --git a/lib-src/soundtouch/soundtouch/SoundTouch.h b/lib-src/soundtouch/soundtouch/SoundTouch.h index 283bb2c89..45d8fdda3 100644 --- a/lib-src/soundtouch/soundtouch/SoundTouch.h +++ b/lib-src/soundtouch/soundtouch/SoundTouch.h @@ -1,252 +1,252 @@ -////////////////////////////////////////////////////////////////////////////// -/// -/// SoundTouch - main class for tempo/pitch/rate adjusting routines. -/// -/// Notes: -/// - Initialize the SoundTouch object instance by setting up the sound stream -/// parameters with functions 'setSampleRate' and 'setChannels', then set -/// desired tempo/pitch/rate settings with the corresponding functions. -/// -/// - The SoundTouch class behaves like a first-in-first-out pipeline: The -/// samples that are to be processed are fed into one of the pipe by calling -/// function 'putSamples', while the ready processed samples can be read -/// from the other end of the pipeline with function 'receiveSamples'. -/// -/// - The SoundTouch processing classes require certain sized 'batches' of -/// samples in order to process the sound. For this reason the classes buffer -/// incoming samples until there are enough of samples available for -/// processing, then they carry out the processing step and consequently -/// make the processed samples available for outputting. -/// -/// - For the above reason, the processing routines introduce a certain -/// 'latency' between the input and output, so that the samples input to -/// SoundTouch may not be immediately available in the output, and neither -/// the amount of outputtable samples may not immediately be in direct -/// relationship with the amount of previously input samples. -/// -/// - The tempo/pitch/rate control parameters can be altered during processing. -/// Please notice though that they aren't currently protected by semaphores, -/// so in multi-thread application external semaphore protection may be -/// required. -/// -/// - This class utilizes classes 'TDStretch' for tempo change (without modifying -/// pitch) and 'RateTransposer' for changing the playback rate (that is, both -/// tempo and pitch in the same ratio) of the sound. The third available control -/// 'pitch' (change pitch but maintain tempo) is produced by a combination of -/// combining the two other controls. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006-09-18 07:39:15 $ -// File revision : $Revision: 1.2 $ -// -// $Id: SoundTouch.h,v 1.2 2006-09-18 07:39:15 richardash1981 Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef SoundTouch_H -#define SoundTouch_H - -#include "FIFOSamplePipe.h" -#include "STTypes.h" - -namespace soundtouch -{ - -/// Soundtouch library version string -#define SOUNDTOUCH_VERSION "1.3.1" - -/// SoundTouch library version id -#define SOUNDTOUCH_VERSION_ID 010301 - -// -// Available setting IDs for the 'setSetting' & 'get_setting' functions: - -/// Enable/disable anti-alias filter in pitch transposer (0 = disable) -#define SETTING_USE_AA_FILTER 0 - -/// Pitch transposer anti-alias filter length (8 .. 128 taps, default = 32) -#define SETTING_AA_FILTER_LENGTH 1 - -/// Enable/disable quick seeking algorithm in tempo changer routine -/// (enabling quick seeking lowers CPU utilization but causes a minor sound -/// quality compromising) -#define SETTING_USE_QUICKSEEK 2 - -/// Time-stretch algorithm single processing sequence length in milliseconds. This determines -/// to how long sequences the original sound is chopped in the time-stretch algorithm. -/// See "STTypes.h" or README for more information. -#define SETTING_SEQUENCE_MS 3 - -/// Time-stretch algorithm seeking window length in milliseconds for algorithm that finds the -/// best possible overlapping location. This determines from how wide window the algorithm -/// may look for an optimal joining location when mixing the sound sequences back together. -/// See "STTypes.h" or README for more information. -#define SETTING_SEEKWINDOW_MS 4 - -/// Time-stretch algorithm overlap length in milliseconds. When the chopped sound sequences -/// are mixed back together, to form a continuous sound stream, this parameter defines over -/// how long period the two consecutive sequences are let to overlap each other. -/// See "STTypes.h" or README for more information. -#define SETTING_OVERLAP_MS 5 - - -class SoundTouch : public FIFOProcessor -{ -private: - /// Rate transposer class instance - class RateTransposer *pRateTransposer; - - /// Time-stretch class instance - class TDStretch *pTDStretch; - - /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters. - float virtualRate; - - /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters. - float virtualTempo; - - /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters. - float virtualPitch; - - /// Flag: Has sample rate been set? - BOOL bSrateSet; - - /// Calculates effective rate & tempo valuescfrom 'virtualRate', 'virtualTempo' and - /// 'virtualPitch' parameters. - void calcEffectiveRateAndTempo(); - -protected : - /// Number of channels - uint channels; - - /// Effective 'rate' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch' - float rate; - - /// Effective 'tempo' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch' - float tempo; - -public: - SoundTouch(); - virtual ~SoundTouch(); - - /// Get SoundTouch library version string - static const char *getVersionString(); - - /// Get SoundTouch library version Id - static uint getVersionId(); - - /// Sets new rate control value. Normal rate = 1.0, smaller values - /// represent slower rate, larger faster rates. - void setRate(float newRate); - - /// Sets new tempo control value. Normal tempo = 1.0, smaller values - /// represent slower tempo, larger faster tempo. - void setTempo(float newTempo); - - /// Sets new rate control value as a difference in percents compared - /// to the original rate (-50 .. +100 %) - void setRateChange(float newRate); - - /// Sets new tempo control value as a difference in percents compared - /// to the original tempo (-50 .. +100 %) - void setTempoChange(float newTempo); - - /// Sets new pitch control value. Original pitch = 1.0, smaller values - /// represent lower pitches, larger values higher pitch. - void setPitch(float newPitch); - - /// Sets pitch change in octaves compared to the original pitch - /// (-1.00 .. +1.00) - void setPitchOctaves(float newPitch); - - /// Sets pitch change in semi-tones compared to the original pitch - /// (-12 .. +12) - void setPitchSemiTones(int newPitch); - void setPitchSemiTones(float newPitch); - - /// Sets the number of channels, 1 = mono, 2 = stereo - void setChannels(uint numChannels); - - /// Sets sample rate. - void setSampleRate(uint srate); - - /// Flushes the last samples from the processing pipeline to the output. - /// Clears also the internal processing buffers. - // - /// Note: This function is meant for extracting the last samples of a sound - /// stream. This function may introduce additional blank samples in the end - /// of the sound stream, and thus it's not recommended to call this function - /// in the middle of a sound stream. - void flush(); - - /// Adds 'numSamples' pcs of samples from the 'samples' memory position into - /// the input of the object. Notice that sample rate _has_to_ be set before - /// calling this function, otherwise throws a runtime_error exception. - virtual void putSamples( - const SAMPLETYPE *samples, ///< Pointer to sample buffer. - uint numSamples ///< Number of samples in buffer. Notice - ///< that in case of stereo-sound a single sample - ///< contains data for both channels. - ); - - /// Clears all the samples in the object's output and internal processing - /// buffers. - virtual void clear(); - - /// Changes a setting controlling the processing system behaviour. See the - /// 'SETTING_...' defines for available setting ID's. - /// - /// \return 'TRUE' if the setting was succesfully changed - BOOL setSetting(uint settingId, ///< Setting ID number. see SETTING_... defines. - uint value ///< New setting value. - ); - - /// Reads a setting controlling the processing system behaviour. See the - /// 'SETTING_...' defines for available setting ID's. - /// - /// \return the setting value. - uint getSetting(uint settingId ///< Setting ID number, see SETTING_... defines. - ) const; - - /// Returns number of samples currently unprocessed. - virtual uint numUnprocessedSamples() const; - - - /// Other handy functions that are implemented in the ancestor classes (see - /// classes 'FIFOProcessor' and 'FIFOSamplePipe') - /// - /// - receiveSamples() : Use this function to receive 'ready' processed samples from SoundTouch. - /// - numSamples() : Get number of 'ready' samples that can be received with - /// function 'receiveSamples()' - /// - isEmpty() : Returns nonzero if there aren't any 'ready' samples. - /// - clear() : Clears all samples from ready/processing buffers. -}; - -} -#endif +////////////////////////////////////////////////////////////////////////////// +/// +/// SoundTouch - main class for tempo/pitch/rate adjusting routines. +/// +/// Notes: +/// - Initialize the SoundTouch object instance by setting up the sound stream +/// parameters with functions 'setSampleRate' and 'setChannels', then set +/// desired tempo/pitch/rate settings with the corresponding functions. +/// +/// - The SoundTouch class behaves like a first-in-first-out pipeline: The +/// samples that are to be processed are fed into one of the pipe by calling +/// function 'putSamples', while the ready processed samples can be read +/// from the other end of the pipeline with function 'receiveSamples'. +/// +/// - The SoundTouch processing classes require certain sized 'batches' of +/// samples in order to process the sound. For this reason the classes buffer +/// incoming samples until there are enough of samples available for +/// processing, then they carry out the processing step and consequently +/// make the processed samples available for outputting. +/// +/// - For the above reason, the processing routines introduce a certain +/// 'latency' between the input and output, so that the samples input to +/// SoundTouch may not be immediately available in the output, and neither +/// the amount of outputtable samples may not immediately be in direct +/// relationship with the amount of previously input samples. +/// +/// - The tempo/pitch/rate control parameters can be altered during processing. +/// Please notice though that they aren't currently protected by semaphores, +/// so in multi-thread application external semaphore protection may be +/// required. +/// +/// - This class utilizes classes 'TDStretch' for tempo change (without modifying +/// pitch) and 'RateTransposer' for changing the playback rate (that is, both +/// tempo and pitch in the same ratio) of the sound. The third available control +/// 'pitch' (change pitch but maintain tempo) is produced by a combination of +/// combining the two other controls. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006-09-18 07:39:15 $ +// File revision : $Revision: 1.2 $ +// +// $Id: SoundTouch.h,v 1.2 2006-09-18 07:39:15 richardash1981 Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef SoundTouch_H +#define SoundTouch_H + +#include "FIFOSamplePipe.h" +#include "STTypes.h" + +namespace soundtouch +{ + +/// Soundtouch library version string +#define SOUNDTOUCH_VERSION "1.3.1" + +/// SoundTouch library version id +#define SOUNDTOUCH_VERSION_ID 010301 + +// +// Available setting IDs for the 'setSetting' & 'get_setting' functions: + +/// Enable/disable anti-alias filter in pitch transposer (0 = disable) +#define SETTING_USE_AA_FILTER 0 + +/// Pitch transposer anti-alias filter length (8 .. 128 taps, default = 32) +#define SETTING_AA_FILTER_LENGTH 1 + +/// Enable/disable quick seeking algorithm in tempo changer routine +/// (enabling quick seeking lowers CPU utilization but causes a minor sound +/// quality compromising) +#define SETTING_USE_QUICKSEEK 2 + +/// Time-stretch algorithm single processing sequence length in milliseconds. This determines +/// to how long sequences the original sound is chopped in the time-stretch algorithm. +/// See "STTypes.h" or README for more information. +#define SETTING_SEQUENCE_MS 3 + +/// Time-stretch algorithm seeking window length in milliseconds for algorithm that finds the +/// best possible overlapping location. This determines from how wide window the algorithm +/// may look for an optimal joining location when mixing the sound sequences back together. +/// See "STTypes.h" or README for more information. +#define SETTING_SEEKWINDOW_MS 4 + +/// Time-stretch algorithm overlap length in milliseconds. When the chopped sound sequences +/// are mixed back together, to form a continuous sound stream, this parameter defines over +/// how long period the two consecutive sequences are let to overlap each other. +/// See "STTypes.h" or README for more information. +#define SETTING_OVERLAP_MS 5 + + +class SoundTouch : public FIFOProcessor +{ +private: + /// Rate transposer class instance + class RateTransposer *pRateTransposer; + + /// Time-stretch class instance + class TDStretch *pTDStretch; + + /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters. + float virtualRate; + + /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters. + float virtualTempo; + + /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters. + float virtualPitch; + + /// Flag: Has sample rate been set? + BOOL bSrateSet; + + /// Calculates effective rate & tempo valuescfrom 'virtualRate', 'virtualTempo' and + /// 'virtualPitch' parameters. + void calcEffectiveRateAndTempo(); + +protected : + /// Number of channels + uint channels; + + /// Effective 'rate' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch' + float rate; + + /// Effective 'tempo' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch' + float tempo; + +public: + SoundTouch(); + virtual ~SoundTouch(); + + /// Get SoundTouch library version string + static const char *getVersionString(); + + /// Get SoundTouch library version Id + static uint getVersionId(); + + /// Sets new rate control value. Normal rate = 1.0, smaller values + /// represent slower rate, larger faster rates. + void setRate(float newRate); + + /// Sets new tempo control value. Normal tempo = 1.0, smaller values + /// represent slower tempo, larger faster tempo. + void setTempo(float newTempo); + + /// Sets new rate control value as a difference in percents compared + /// to the original rate (-50 .. +100 %) + void setRateChange(float newRate); + + /// Sets new tempo control value as a difference in percents compared + /// to the original tempo (-50 .. +100 %) + void setTempoChange(float newTempo); + + /// Sets new pitch control value. Original pitch = 1.0, smaller values + /// represent lower pitches, larger values higher pitch. + void setPitch(float newPitch); + + /// Sets pitch change in octaves compared to the original pitch + /// (-1.00 .. +1.00) + void setPitchOctaves(float newPitch); + + /// Sets pitch change in semi-tones compared to the original pitch + /// (-12 .. +12) + void setPitchSemiTones(int newPitch); + void setPitchSemiTones(float newPitch); + + /// Sets the number of channels, 1 = mono, 2 = stereo + void setChannels(uint numChannels); + + /// Sets sample rate. + void setSampleRate(uint srate); + + /// Flushes the last samples from the processing pipeline to the output. + /// Clears also the internal processing buffers. + // + /// Note: This function is meant for extracting the last samples of a sound + /// stream. This function may introduce additional blank samples in the end + /// of the sound stream, and thus it's not recommended to call this function + /// in the middle of a sound stream. + void flush(); + + /// Adds 'numSamples' pcs of samples from the 'samples' memory position into + /// the input of the object. Notice that sample rate _has_to_ be set before + /// calling this function, otherwise throws a runtime_error exception. + virtual void putSamples( + const SAMPLETYPE *samples, ///< Pointer to sample buffer. + uint numSamples ///< Number of samples in buffer. Notice + ///< that in case of stereo-sound a single sample + ///< contains data for both channels. + ); + + /// Clears all the samples in the object's output and internal processing + /// buffers. + virtual void clear(); + + /// Changes a setting controlling the processing system behaviour. See the + /// 'SETTING_...' defines for available setting ID's. + /// + /// \return 'TRUE' if the setting was succesfully changed + BOOL setSetting(uint settingId, ///< Setting ID number. see SETTING_... defines. + uint value ///< New setting value. + ); + + /// Reads a setting controlling the processing system behaviour. See the + /// 'SETTING_...' defines for available setting ID's. + /// + /// \return the setting value. + uint getSetting(uint settingId ///< Setting ID number, see SETTING_... defines. + ) const; + + /// Returns number of samples currently unprocessed. + virtual uint numUnprocessedSamples() const; + + + /// Other handy functions that are implemented in the ancestor classes (see + /// classes 'FIFOProcessor' and 'FIFOSamplePipe') + /// + /// - receiveSamples() : Use this function to receive 'ready' processed samples from SoundTouch. + /// - numSamples() : Get number of 'ready' samples that can be received with + /// function 'receiveSamples()' + /// - isEmpty() : Returns nonzero if there aren't any 'ready' samples. + /// - clear() : Clears all samples from ready/processing buffers. +}; + +} +#endif diff --git a/lib-src/soundtouch/source/SoundTouch/SoundTouch.vcproj b/lib-src/soundtouch/source/SoundTouch/SoundTouch.vcproj index 2829f7e52..c149b93f0 100644 --- a/lib-src/soundtouch/source/SoundTouch/SoundTouch.vcproj +++ b/lib-src/soundtouch/source/SoundTouch/SoundTouch.vcproj @@ -1,1193 +1,1193 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib-src/soundtouch/source/SoundTouch/cpu_detect_x86_gcc.cpp b/lib-src/soundtouch/source/SoundTouch/cpu_detect_x86_gcc.cpp index a05f1046f..b5e70d974 100644 --- a/lib-src/soundtouch/source/SoundTouch/cpu_detect_x86_gcc.cpp +++ b/lib-src/soundtouch/source/SoundTouch/cpu_detect_x86_gcc.cpp @@ -1,138 +1,138 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// gcc version of the x86 CPU detect routine. -/// -/// This file is to be compiled on any platform with the GNU C compiler. -/// Compiler. Please see 'cpu_detect_x86_win.cpp' for the x86 Windows version -/// of this file. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006-09-18 07:31:42 $ -// File revision : $Revision: 1.3 $ -// -// $Id: cpu_detect_x86_gcc.cpp,v 1.3 2006-09-18 07:31:42 richardash1981 Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#include -#include -#include "cpu_detect.h" - -#ifndef __GNUC__ -#error wrong platform - this source code file is for the GNU C compiler. -#endif - -using namespace std; - -#include -////////////////////////////////////////////////////////////////////////////// -// -// processor instructions extension detection routines -// -////////////////////////////////////////////////////////////////////////////// - - -// Flag variable indicating whick ISA extensions are disabled (for debugging) -static uint _dwDisabledISA = 0x00; // 0xffffffff; //<- use this to disable all extensions - -// Disables given set of instruction extensions. See SUPPORT_... defines. -void disableExtensions(uint dwDisableMask) -{ - _dwDisabledISA = dwDisableMask; -} - - - -/// Checks which instruction set extensions are supported by the CPU. -uint detectCPUextensions(void) -{ -#ifndef __i386__ - return 0; // always disable extensions on non-x86 platforms. -#else - uint res = 0; - - if (_dwDisabledISA == 0xffffffff) return 0; - - asm volatile( - "\n\txor %%esi, %%esi" // clear %%esi = result register - // check if 'cpuid' instructions is available by toggling eflags bit 21 - - "\n\tpushf" // save eflags to stack - "\n\tpop %%eax" // load eax from stack (with eflags) - "\n\tmovl %%eax, %%ecx" // save the original eflags values to ecx - "\n\txor $0x00200000, %%eax" // toggle bit 21 - "\n\tpush %%eax" // store toggled eflags to stack - "\n\tpopf" // load eflags from stack - "\n\tpushf" // save updated eflags to stack - "\n\tpop %%eax" // load from stack - "\n\txor %%edx, %%edx" // clear edx for defaulting no mmx - "\n\tcmp %%ecx, %%eax" // compare to original eflags values - "\n\tjz end" // jumps to 'end' if cpuid not present - - // cpuid instruction available, test for presence of mmx instructions - - "\n\tmovl $1, %%eax" - "\n\tcpuid" -// movl $0x00800000, %edx // force enable MMX - "\n\ttest $0x00800000, %%edx" - "\n\tjz end" // branch if MMX not available - - "\n\tor $0x01, %%esi" // otherwise add MMX support bit - - "\n\ttest $0x02000000, %%edx" - "\n\tjz test3DNow" // branch if SSE not available - - "\n\tor $0x08, %%esi" // otherwise add SSE support bit - - "\n\ttest3DNow:" - // test for precense of AMD extensions - "\n\tmov $0x80000000, %%eax" - "\n\tcpuid" - "\n\tcmp $0x80000000, %%eax" - "\n\tjbe end" // branch if no AMD extensions detected - - // test for precense of 3DNow! extension - "\n\tmov $0x80000001, %%eax" - "\n\tcpuid" - "\n\ttest $0x80000000, %%edx" - "\n\tjz end" // branch if 3DNow! not detected - - "\n\tor $0x02, %%esi" // otherwise add 3DNow support bit - - "\n\tend:" - - "\n\tmov %%esi, %0" - - : "=r" (res) - : /* no inputs */ - : "%edx", "%eax", "%ecx", "%esi" ); - - return res & ~_dwDisabledISA; -#endif -} +//////////////////////////////////////////////////////////////////////////////// +/// +/// gcc version of the x86 CPU detect routine. +/// +/// This file is to be compiled on any platform with the GNU C compiler. +/// Compiler. Please see 'cpu_detect_x86_win.cpp' for the x86 Windows version +/// of this file. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006-09-18 07:31:42 $ +// File revision : $Revision: 1.3 $ +// +// $Id: cpu_detect_x86_gcc.cpp,v 1.3 2006-09-18 07:31:42 richardash1981 Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include "cpu_detect.h" + +#ifndef __GNUC__ +#error wrong platform - this source code file is for the GNU C compiler. +#endif + +using namespace std; + +#include +////////////////////////////////////////////////////////////////////////////// +// +// processor instructions extension detection routines +// +////////////////////////////////////////////////////////////////////////////// + + +// Flag variable indicating whick ISA extensions are disabled (for debugging) +static uint _dwDisabledISA = 0x00; // 0xffffffff; //<- use this to disable all extensions + +// Disables given set of instruction extensions. See SUPPORT_... defines. +void disableExtensions(uint dwDisableMask) +{ + _dwDisabledISA = dwDisableMask; +} + + + +/// Checks which instruction set extensions are supported by the CPU. +uint detectCPUextensions(void) +{ +#ifndef __i386__ + return 0; // always disable extensions on non-x86 platforms. +#else + uint res = 0; + + if (_dwDisabledISA == 0xffffffff) return 0; + + asm volatile( + "\n\txor %%esi, %%esi" // clear %%esi = result register + // check if 'cpuid' instructions is available by toggling eflags bit 21 + + "\n\tpushf" // save eflags to stack + "\n\tpop %%eax" // load eax from stack (with eflags) + "\n\tmovl %%eax, %%ecx" // save the original eflags values to ecx + "\n\txor $0x00200000, %%eax" // toggle bit 21 + "\n\tpush %%eax" // store toggled eflags to stack + "\n\tpopf" // load eflags from stack + "\n\tpushf" // save updated eflags to stack + "\n\tpop %%eax" // load from stack + "\n\txor %%edx, %%edx" // clear edx for defaulting no mmx + "\n\tcmp %%ecx, %%eax" // compare to original eflags values + "\n\tjz end" // jumps to 'end' if cpuid not present + + // cpuid instruction available, test for presence of mmx instructions + + "\n\tmovl $1, %%eax" + "\n\tcpuid" +// movl $0x00800000, %edx // force enable MMX + "\n\ttest $0x00800000, %%edx" + "\n\tjz end" // branch if MMX not available + + "\n\tor $0x01, %%esi" // otherwise add MMX support bit + + "\n\ttest $0x02000000, %%edx" + "\n\tjz test3DNow" // branch if SSE not available + + "\n\tor $0x08, %%esi" // otherwise add SSE support bit + + "\n\ttest3DNow:" + // test for precense of AMD extensions + "\n\tmov $0x80000000, %%eax" + "\n\tcpuid" + "\n\tcmp $0x80000000, %%eax" + "\n\tjbe end" // branch if no AMD extensions detected + + // test for precense of 3DNow! extension + "\n\tmov $0x80000001, %%eax" + "\n\tcpuid" + "\n\ttest $0x80000000, %%edx" + "\n\tjz end" // branch if 3DNow! not detected + + "\n\tor $0x02, %%esi" // otherwise add 3DNow support bit + + "\n\tend:" + + "\n\tmov %%esi, %0" + + : "=r" (res) + : /* no inputs */ + : "%edx", "%eax", "%ecx", "%esi" ); + + return res & ~_dwDisabledISA; +#endif +} diff --git a/lib-src/soundtouch/source/example/SoundStretch/RunParameters.cpp b/lib-src/soundtouch/source/example/SoundStretch/RunParameters.cpp index 0ea7e2d83..a99ff801b 100644 --- a/lib-src/soundtouch/source/example/SoundStretch/RunParameters.cpp +++ b/lib-src/soundtouch/source/example/SoundStretch/RunParameters.cpp @@ -1,293 +1,293 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// A class for parsing the 'soundstretch' application command line parameters -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006-09-18 07:31:47 $ -// File revision : $Revision: 1.2 $ -// -// $Id: RunParameters.cpp,v 1.2 2006-09-18 07:31:47 richardash1981 Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#include -#include -#include - -#include "RunParameters.h" - -using namespace std; - -// Program usage instructions - -static const char licenseText[] = - " LICENSE:\n" - " ========\n" - " \n" - " SoundTouch sound processing library\n" - " Copyright (c) Olli Parviainen\n" - " \n" - " This library is free software; you can redistribute it and/or\n" - " modify it under the terms of the GNU Lesser General Public\n" - " License as published by the Free Software Foundation; either\n" - " version 2.1 of the License, or (at your option) any later version.\n" - " \n" - " This library is distributed in the hope that it will be useful,\n" - " but WITHOUT ANY WARRANTY; without even the implied warranty of\n" - " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n" - " Lesser General Public License for more details.\n" - " \n" - " You should have received a copy of the GNU Lesser General Public\n" - " License along with this library; if not, write to the Free Software\n" - " Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n" - " \n" - "This application is distributed with full source codes; however, if you\n" - "didn't receive them, please visit the author's homepage (see the link above)."; - -static const char whatText[] = - "This application processes WAV audio files by modifying the sound tempo,\n" - "pitch and playback rate properties independently from each other.\n" - "\n"; - -static const char usage[] = - "Usage :\n" - " soundstretch infile.wav outfile.wav [switches]\n\n" - "Available switches are:\n" - " -tempo=n : Change sound tempo by n percents (n=-95..+5000 %)\n" - " -pitch=n : Change sound pitch by n semitones (n=-60..+60 semitones)\n" - " -rate=n : Change sound rate by n percents (n=-95..+5000 %)\n" - " -bpm=n : Detect the BPM rate of sound and adjust tempo to meet 'n' BPMs.\n" - " If '=n' is omitted, just detects the BPM rate.\n" - " -quick : Use quicker tempo change algorithm (gain speed, lose quality)\n" - " -naa : Don't use anti-alias filtering (gain speed, lose quality)\n" - " -license : Display the program license text (LGPL)\n"; - - -// Converts a char into lower case -static int _toLowerCase(int c) -{ - if (c >= 'A' && c <= 'Z') - { - c += 'a' - 'A'; - } - return c; -} - - -// Constructor -RunParameters::RunParameters(const int nParams, const char *paramStr[]) -{ - int i; - int nFirstParam; - - if (nParams < 3) - { - // Too few parameters - if (nParams > 1 && paramStr[1][0] == '-' && - _toLowerCase(paramStr[1][1]) == 'l') - { - // '-license' switch - throwLicense(); - } - string msg = whatText; - msg += usage; - throw runtime_error(msg.c_str()); - } - - inFileName = NULL; - outFileName = NULL; - tempoDelta = 0; - pitchDelta = 0; - rateDelta = 0; - quick = 0; - noAntiAlias = 0; - goalBPM = 0; - detectBPM = FALSE; - - // Get input & output file names - inFileName = (char*)paramStr[1]; - outFileName = (char*)paramStr[2]; - - if (outFileName[0] == '-') - { - // no outputfile name was given but parameters - outFileName = NULL; - nFirstParam = 2; - } - else - { - nFirstParam = 3; - } - - // parse switch parameters - for (i = nFirstParam; i < nParams; i ++) - { - parseSwitchParam(paramStr[i]); - } - - checkLimits(); -} - - - -// Checks parameter limits -void RunParameters::checkLimits() -{ - if (tempoDelta < -95.0f) - { - tempoDelta = -95.0f; - } - else if (tempoDelta > 5000.0f) - { - tempoDelta = 5000.0f; - } - - if (pitchDelta < -60.0f) - { - pitchDelta = -60.0f; - } - else if (pitchDelta > 60.0f) - { - pitchDelta = 60.0f; - } - - if (rateDelta < -95.0f) - { - rateDelta = -95.0f; - } - else if (rateDelta > 5000.0f) - { - rateDelta = 5000.0f; - } -} - - - -// Unknown switch parameter -- throws an exception with an error message -void RunParameters::throwIllegalParamExp(const string &str) const -{ - string msg = "ERROR : Illegal parameter \""; - msg += str; - msg += "\".\n\n"; - msg += usage; - throw runtime_error(msg.c_str()); -} - - - -void RunParameters::throwLicense() const -{ - throw runtime_error(licenseText); -} - - -float RunParameters::parseSwitchValue(const string &str) const -{ - int pos; - - pos = str.find_first_of('='); - if (pos < 0) - { - // '=' missing - throwIllegalParamExp(str); - } - - // Read numerical parameter value after '=' - return (float)atof(str.substr(pos + 1).c_str()); -} - - -// Interprets a single switch parameter string of format "-switch=xx" -// Valid switches are "-tempo=xx", "-pitch=xx" and "-rate=xx". Stores -// switch values into 'params' structure. -void RunParameters::parseSwitchParam(const string &str) -{ - int upS; - - if (str[0] != '-') - { - // leading hyphen missing => not a valid parameter - throwIllegalParamExp(str); - } - - // Take the first character of switch name & change to lower case - upS = _toLowerCase(str[1]); - - // interpret the switch name & operate accordingly - switch (upS) - { - case 't' : - // switch '-tempo=xx' - tempoDelta = parseSwitchValue(str); - break; - - case 'p' : - // switch '-pitch=xx' - pitchDelta = parseSwitchValue(str); - break; - - case 'r' : - // switch '-rate=xx' - rateDelta = parseSwitchValue(str); - break; - - case 'b' : - // switch '-bpm=xx' - detectBPM = TRUE; - try - { - goalBPM = parseSwitchValue(str); - } - catch (runtime_error) - { - // illegal or missing bpm value => just calculate bpm - goalBPM = 0; - } - break; - - case 'q' : - // switch '-quick' - quick = 1; - break; - - case 'n' : - // switch '-naa' - noAntiAlias = 1; - break; - - case 'l' : - // switch '-license' - throwLicense(); - break; - - default: - // unknown switch - throwIllegalParamExp(str); - } -} +//////////////////////////////////////////////////////////////////////////////// +/// +/// A class for parsing the 'soundstretch' application command line parameters +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006-09-18 07:31:47 $ +// File revision : $Revision: 1.2 $ +// +// $Id: RunParameters.cpp,v 1.2 2006-09-18 07:31:47 richardash1981 Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include + +#include "RunParameters.h" + +using namespace std; + +// Program usage instructions + +static const char licenseText[] = + " LICENSE:\n" + " ========\n" + " \n" + " SoundTouch sound processing library\n" + " Copyright (c) Olli Parviainen\n" + " \n" + " This library is free software; you can redistribute it and/or\n" + " modify it under the terms of the GNU Lesser General Public\n" + " License as published by the Free Software Foundation; either\n" + " version 2.1 of the License, or (at your option) any later version.\n" + " \n" + " This library is distributed in the hope that it will be useful,\n" + " but WITHOUT ANY WARRANTY; without even the implied warranty of\n" + " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n" + " Lesser General Public License for more details.\n" + " \n" + " You should have received a copy of the GNU Lesser General Public\n" + " License along with this library; if not, write to the Free Software\n" + " Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n" + " \n" + "This application is distributed with full source codes; however, if you\n" + "didn't receive them, please visit the author's homepage (see the link above)."; + +static const char whatText[] = + "This application processes WAV audio files by modifying the sound tempo,\n" + "pitch and playback rate properties independently from each other.\n" + "\n"; + +static const char usage[] = + "Usage :\n" + " soundstretch infile.wav outfile.wav [switches]\n\n" + "Available switches are:\n" + " -tempo=n : Change sound tempo by n percents (n=-95..+5000 %)\n" + " -pitch=n : Change sound pitch by n semitones (n=-60..+60 semitones)\n" + " -rate=n : Change sound rate by n percents (n=-95..+5000 %)\n" + " -bpm=n : Detect the BPM rate of sound and adjust tempo to meet 'n' BPMs.\n" + " If '=n' is omitted, just detects the BPM rate.\n" + " -quick : Use quicker tempo change algorithm (gain speed, lose quality)\n" + " -naa : Don't use anti-alias filtering (gain speed, lose quality)\n" + " -license : Display the program license text (LGPL)\n"; + + +// Converts a char into lower case +static int _toLowerCase(int c) +{ + if (c >= 'A' && c <= 'Z') + { + c += 'a' - 'A'; + } + return c; +} + + +// Constructor +RunParameters::RunParameters(const int nParams, const char *paramStr[]) +{ + int i; + int nFirstParam; + + if (nParams < 3) + { + // Too few parameters + if (nParams > 1 && paramStr[1][0] == '-' && + _toLowerCase(paramStr[1][1]) == 'l') + { + // '-license' switch + throwLicense(); + } + string msg = whatText; + msg += usage; + throw runtime_error(msg.c_str()); + } + + inFileName = NULL; + outFileName = NULL; + tempoDelta = 0; + pitchDelta = 0; + rateDelta = 0; + quick = 0; + noAntiAlias = 0; + goalBPM = 0; + detectBPM = FALSE; + + // Get input & output file names + inFileName = (char*)paramStr[1]; + outFileName = (char*)paramStr[2]; + + if (outFileName[0] == '-') + { + // no outputfile name was given but parameters + outFileName = NULL; + nFirstParam = 2; + } + else + { + nFirstParam = 3; + } + + // parse switch parameters + for (i = nFirstParam; i < nParams; i ++) + { + parseSwitchParam(paramStr[i]); + } + + checkLimits(); +} + + + +// Checks parameter limits +void RunParameters::checkLimits() +{ + if (tempoDelta < -95.0f) + { + tempoDelta = -95.0f; + } + else if (tempoDelta > 5000.0f) + { + tempoDelta = 5000.0f; + } + + if (pitchDelta < -60.0f) + { + pitchDelta = -60.0f; + } + else if (pitchDelta > 60.0f) + { + pitchDelta = 60.0f; + } + + if (rateDelta < -95.0f) + { + rateDelta = -95.0f; + } + else if (rateDelta > 5000.0f) + { + rateDelta = 5000.0f; + } +} + + + +// Unknown switch parameter -- throws an exception with an error message +void RunParameters::throwIllegalParamExp(const string &str) const +{ + string msg = "ERROR : Illegal parameter \""; + msg += str; + msg += "\".\n\n"; + msg += usage; + throw runtime_error(msg.c_str()); +} + + + +void RunParameters::throwLicense() const +{ + throw runtime_error(licenseText); +} + + +float RunParameters::parseSwitchValue(const string &str) const +{ + int pos; + + pos = str.find_first_of('='); + if (pos < 0) + { + // '=' missing + throwIllegalParamExp(str); + } + + // Read numerical parameter value after '=' + return (float)atof(str.substr(pos + 1).c_str()); +} + + +// Interprets a single switch parameter string of format "-switch=xx" +// Valid switches are "-tempo=xx", "-pitch=xx" and "-rate=xx". Stores +// switch values into 'params' structure. +void RunParameters::parseSwitchParam(const string &str) +{ + int upS; + + if (str[0] != '-') + { + // leading hyphen missing => not a valid parameter + throwIllegalParamExp(str); + } + + // Take the first character of switch name & change to lower case + upS = _toLowerCase(str[1]); + + // interpret the switch name & operate accordingly + switch (upS) + { + case 't' : + // switch '-tempo=xx' + tempoDelta = parseSwitchValue(str); + break; + + case 'p' : + // switch '-pitch=xx' + pitchDelta = parseSwitchValue(str); + break; + + case 'r' : + // switch '-rate=xx' + rateDelta = parseSwitchValue(str); + break; + + case 'b' : + // switch '-bpm=xx' + detectBPM = TRUE; + try + { + goalBPM = parseSwitchValue(str); + } + catch (runtime_error) + { + // illegal or missing bpm value => just calculate bpm + goalBPM = 0; + } + break; + + case 'q' : + // switch '-quick' + quick = 1; + break; + + case 'n' : + // switch '-naa' + noAntiAlias = 1; + break; + + case 'l' : + // switch '-license' + throwLicense(); + break; + + default: + // unknown switch + throwIllegalParamExp(str); + } +} diff --git a/lib-src/soundtouch/source/example/SoundStretch/RunParameters.h b/lib-src/soundtouch/source/example/SoundStretch/RunParameters.h index 3226c22b0..884362d30 100644 --- a/lib-src/soundtouch/source/example/SoundStretch/RunParameters.h +++ b/lib-src/soundtouch/source/example/SoundStretch/RunParameters.h @@ -1,71 +1,71 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// A class for parsing the 'soundstretch' application command line parameters -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006-09-18 07:31:47 $ -// File revision : $Revision: 1.2 $ -// -// $Id: RunParameters.h,v 1.2 2006-09-18 07:31:47 richardash1981 Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef RUNPARAMETERS_H -#define RUNPARAMETERS_H - -#include "STTypes.h" -#include - -using namespace std; - -/// Parses command line parameters into program parameters -class RunParameters -{ -private: - void throwIllegalParamExp(const string &str) const; - void throwLicense() const; - void parseSwitchParam(const string &str); - void checkLimits(); - float parseSwitchValue(const string &str) const; - -public: - char *inFileName; - char *outFileName; - float tempoDelta; - float pitchDelta; - float rateDelta; - int quick; - int noAntiAlias; - float goalBPM; - BOOL detectBPM; - - RunParameters(const int nParams, const char *paramStr[]); -}; - -#endif +//////////////////////////////////////////////////////////////////////////////// +/// +/// A class for parsing the 'soundstretch' application command line parameters +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006-09-18 07:31:47 $ +// File revision : $Revision: 1.2 $ +// +// $Id: RunParameters.h,v 1.2 2006-09-18 07:31:47 richardash1981 Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef RUNPARAMETERS_H +#define RUNPARAMETERS_H + +#include "STTypes.h" +#include + +using namespace std; + +/// Parses command line parameters into program parameters +class RunParameters +{ +private: + void throwIllegalParamExp(const string &str) const; + void throwLicense() const; + void parseSwitchParam(const string &str); + void checkLimits(); + float parseSwitchValue(const string &str) const; + +public: + char *inFileName; + char *outFileName; + float tempoDelta; + float pitchDelta; + float rateDelta; + int quick; + int noAntiAlias; + float goalBPM; + BOOL detectBPM; + + RunParameters(const int nParams, const char *paramStr[]); +}; + +#endif diff --git a/lib-src/soundtouch/source/example/SoundStretch/WavFile.cpp b/lib-src/soundtouch/source/example/SoundStretch/WavFile.cpp index d707d6b29..9b73af616 100644 --- a/lib-src/soundtouch/source/example/SoundStretch/WavFile.cpp +++ b/lib-src/soundtouch/source/example/SoundStretch/WavFile.cpp @@ -1,712 +1,712 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Classes for easy reading & writing of WAV sound files. -/// -/// For big-endian CPU, define _BIG_ENDIAN_ during compile-time to correctly -/// parse the WAV files with such processors. -/// -/// Admittingly, more complete WAV reader routines may exist in public domain, -/// but the reason for 'yet another' one is that those generic WAV reader -/// libraries are exhaustingly large and cumbersome! Wanted to have something -/// simpler here, i.e. something that's not already larger than rest of the -/// SoundTouch/SoundStretch program... -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2008-06-25 20:17:07 $ -// File revision : $Revision: 1.4 $ -// -// $Id: WavFile.cpp,v 1.4 2008-06-25 20:17:07 richardash1981 Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include -#include - -#include "WavFile.h" - -using namespace std; - -const static char riffStr[] = "RIFF"; -const static char waveStr[] = "WAVE"; -const static char fmtStr[] = "fmt "; -const static char dataStr[] = "data"; - - -////////////////////////////////////////////////////////////////////////////// -// -// Helper functions for swapping byte order to correctly read/write WAV files -// with big-endian CPU's: Define compile-time definition _BIG_ENDIAN_ to -// turn-on the conversion if it appears necessary. -// -// For example, Intel x86 is little-endian and doesn't require conversion, -// while PowerPC of Mac's and many other RISC cpu's are big-endian. - -#ifdef BYTE_ORDER - // In gcc compiler detect the byte order automatically - #if BYTE_ORDER == BIG_ENDIAN - // big-endian platform. - #define _BIG_ENDIAN_ - #endif -#endif - -#ifdef _BIG_ENDIAN_ - // big-endian CPU, swap bytes in 16 & 32 bit words - - // helper-function to swap byte-order of 32bit integer - static inline void _swap32(unsigned int &dwData) - { - dwData = ((dwData >> 24) & 0x000000FF) | - ((dwData >> 8) & 0x0000FF00) | - ((dwData << 8) & 0x00FF0000) | - ((dwData << 24) & 0xFF000000); - } - - // helper-function to swap byte-order of 16bit integer - static inline void _swap16(unsigned short &wData) - { - wData = ((wData >> 8) & 0x00FF) | - ((wData << 8) & 0xFF00); - } - - // helper-function to swap byte-order of buffer of 16bit integers - static inline void _swap16Buffer(unsigned short *pData, unsigned int dwNumWords) - { - unsigned long i; - - for (i = 0; i < dwNumWords; i ++) - { - _swap16(pData[i]); - } - } - -#else // BIG_ENDIAN - // little-endian CPU, WAV file is ok as such - - // dummy helper-function - static inline void _swap32(unsigned int &dwData) - { - // do nothing - } - - // dummy helper-function - static inline void _swap16(unsigned short &wData) - { - // do nothing - } - - // dummy helper-function - static inline void _swap16Buffer(unsigned short *pData, unsigned int dwNumBytes) - { - // do nothing - } - -#endif // BIG_ENDIAN - - -////////////////////////////////////////////////////////////////////////////// -// -// Class WavInFile -// - -WavInFile::WavInFile(const char *fileName) -{ - int hdrsOk; - - // Try to open the file for reading - fptr = fopen(fileName, "rb"); - if (fptr == NULL) - { - // didn't succeed - string msg = "Error : Unable to open file \""; - msg += fileName; - msg += "\" for reading."; - throw runtime_error(msg); - } - - // Read the file headers - hdrsOk = readWavHeaders(); - if (hdrsOk != 0) - { - // Something didn't match in the wav file headers - string msg = "File \""; - msg += fileName; - msg += "\" is corrupt or not a WAV file"; - throw runtime_error(msg); - } - - if (header.format.fixed != 1) - { - string msg = "File \""; - msg += fileName; - msg += "\" uses unsupported encoding."; - throw runtime_error(msg); - } - - dataRead = 0; -} - - - -WavInFile::~WavInFile() -{ - close(); -} - - - -void WavInFile::rewind() -{ - int hdrsOk; - - fseek(fptr, 0, SEEK_SET); - hdrsOk = readWavHeaders(); - assert(hdrsOk == 0); - dataRead = 0; -} - - -int WavInFile::checkCharTags() -{ - // header.format.fmt should equal to 'fmt ' - if (memcmp(fmtStr, header.format.fmt, 4) != 0) return -1; - // header.data.data_field should equal to 'data' - if (memcmp(dataStr, header.data.data_field, 4) != 0) return -1; - - return 0; -} - - -int WavInFile::read(char *buffer, int maxElems) -{ - int numBytes; - uint afterDataRead; - - // ensure it's 8 bit format - if (header.format.bits_per_sample != 8) - { - throw runtime_error("Error: WavInFile::read(char*, int) works only with 8bit samples."); - } - assert(sizeof(char) == 1); - - numBytes = maxElems; - afterDataRead = dataRead + numBytes; - if (afterDataRead > header.data.data_len) - { - // Don't read more samples than are marked available in header - numBytes = header.data.data_len - dataRead; - assert(numBytes >= 0); - } - - numBytes = fread(buffer, 1, numBytes, fptr); - dataRead += numBytes; - - return numBytes; -} - - -int WavInFile::read(short *buffer, int maxElems) -{ - unsigned int afterDataRead; - int numBytes; - int numElems; - - if (header.format.bits_per_sample == 8) - { - // 8 bit format - char *temp = new char[maxElems]; - int i; - - numElems = read(temp, maxElems); - // convert from 8 to 16 bit - for (i = 0; i < numElems; i ++) - { - buffer[i] = temp[i] << 8; - } - delete[] temp; - } - else - { - // 16 bit format - assert(header.format.bits_per_sample == 16); - assert(sizeof(short) == 2); - - numBytes = maxElems * 2; - afterDataRead = dataRead + numBytes; - if (afterDataRead > header.data.data_len) - { - // Don't read more samples than are marked available in header - numBytes = header.data.data_len - dataRead; - assert(numBytes >= 0); - } - - numBytes = fread(buffer, 1, numBytes, fptr); - dataRead += numBytes; - numElems = numBytes / 2; - - // 16bit samples, swap byte order if necessary - _swap16Buffer((unsigned short *)buffer, numElems); - } - - return numElems; -} - - - -int WavInFile::read(float *buffer, int maxElems) -{ - short *temp = new short[maxElems]; - int num; - int i; - double fscale; - - num = read(temp, maxElems); - - fscale = 1.0 / 32768.0; - // convert to floats, scale to range [-1..+1[ - for (i = 0; i < num; i ++) - { - buffer[i] = (float)(fscale * (double)temp[i]); - } - - delete[] temp; - - return num; -} - - -int WavInFile::eof() const -{ - // return true if all data has been read or file eof has reached - return (dataRead == header.data.data_len || feof(fptr)); -} - - -void WavInFile::close() -{ - fclose(fptr); - fptr = NULL; -} - - - -// test if character code is between a white space ' ' and little 'z' -static int isAlpha(char c) -{ - return (c >= ' ' && c <= 'z') ? 1 : 0; -} - - -// test if all characters are between a white space ' ' and little 'z' -static int isAlphaStr(char *str) -{ - int c; - - c = str[0]; - while (c) - { - if (isAlpha(c) == 0) return 0; - str ++; - c = str[0]; - } - - return 1; -} - - -int WavInFile::readRIFFBlock() -{ - fread(&(header.riff), sizeof(WavRiff), 1, fptr); - - // swap 32bit data byte order if necessary - _swap32((unsigned int &)header.riff.package_len); - - // header.riff.riff_char should equal to 'RIFF'); - if (memcmp(riffStr, header.riff.riff_char, 4) != 0) return -1; - // header.riff.wave should equal to 'WAVE' - if (memcmp(waveStr, header.riff.wave, 4) != 0) return -1; - - return 0; -} - - - - -int WavInFile::readHeaderBlock() -{ - char label[5]; - string sLabel; - - // lead label string - fread(label, 1, 4, fptr); - label[4] = 0; - - if (isAlphaStr(label) == 0) return -1; // not a valid label - - // Decode blocks according to their label - if (strcmp(label, fmtStr) == 0) - { - int nLen, nDump; - - // 'fmt ' block - memcpy(header.format.fmt, fmtStr, 4); - - // read length of the format field - fread(&nLen, sizeof(int), 1, fptr); - // swap byte order if necessary - _swap32((unsigned int &)nLen); // int format_len; - header.format.format_len = nLen; - - // calculate how much length differs from expected - nDump = nLen - (sizeof(header.format) - 8); - - // if format_len is larger than expected, read only as much data as we've space for - if (nDump > 0) - { - nLen = sizeof(header.format) - 8; - } - - // read data - fread(&(header.format.fixed), nLen, 1, fptr); - - // swap byte order if necessary - _swap16((unsigned short &)header.format.fixed); // short int fixed; - _swap16((unsigned short &)header.format.channel_number); // short int channel_number; - _swap32((unsigned int &)header.format.sample_rate); // int sample_rate; - _swap32((unsigned int &)header.format.byte_rate); // int byte_rate; - _swap16((unsigned short &)header.format.byte_per_sample); // short int byte_per_sample; - _swap16((unsigned short &)header.format.bits_per_sample); // short int bits_per_sample; - - // if format_len is larger than expected, skip the extra data - if (nDump > 0) - { - fseek(fptr, nDump, SEEK_CUR); - } - - return 0; - } - else if (strcmp(label, dataStr) == 0) - { - // 'data' block - memcpy(header.data.data_field, dataStr, 4); - fread(&(header.data.data_len), sizeof(uint), 1, fptr); - - // swap byte order if necessary - _swap32((unsigned int &)header.data.data_len); - - return 1; - } - else - { - uint len, i; - uint temp; - // unknown block - - // read length - fread(&len, sizeof(len), 1, fptr); - // scan through the block - for (i = 0; i < len; i ++) - { - fread(&temp, 1, 1, fptr); - if (feof(fptr)) return -1; // unexpected eof - } - } - return 0; -} - - -int WavInFile::readWavHeaders() -{ - int res; - - memset(&header, 0, sizeof(header)); - - res = readRIFFBlock(); - if (res) return 1; - // read header blocks until data block is found - do - { - // read header blocks - res = readHeaderBlock(); - if (res < 0) return 1; // error in file structure - } while (res == 0); - // check that all required tags are legal - return checkCharTags(); -} - - -uint WavInFile::getNumChannels() const -{ - return header.format.channel_number; -} - - -uint WavInFile::getNumBits() const -{ - return header.format.bits_per_sample; -} - - -uint WavInFile::getBytesPerSample() const -{ - return getNumChannels() * getNumBits() / 8; -} - - -uint WavInFile::getSampleRate() const -{ - return header.format.sample_rate; -} - - - -uint WavInFile::getDataSizeInBytes() const -{ - return header.data.data_len; -} - - -uint WavInFile::getNumSamples() const -{ - return header.data.data_len / header.format.byte_per_sample; -} - - -uint WavInFile::getLengthMS() const -{ - uint numSamples; - uint sampleRate; - - numSamples = getNumSamples(); - sampleRate = getSampleRate(); - - assert(numSamples < UINT_MAX / 1000); - return (1000 * numSamples / sampleRate); -} - - -////////////////////////////////////////////////////////////////////////////// -// -// Class WavOutFile -// - -WavOutFile::WavOutFile(const char *fileName, int sampleRate, int bits, int channels) -{ - bytesWritten = 0; - fptr = fopen(fileName, "wb"); - if (fptr == NULL) - { - string msg = "Error : Unable to open file \""; - msg += fileName; - msg += "\" for writing."; - //pmsg = msg.c_str; - throw runtime_error(msg); - } - - fillInHeader(sampleRate, bits, channels); - writeHeader(); -} - - - -WavOutFile::~WavOutFile() -{ - close(); -} - - - -void WavOutFile::fillInHeader(uint sampleRate, uint bits, uint channels) -{ - // fill in the 'riff' part.. - - // copy string 'RIFF' to riff_char - memcpy(&(header.riff.riff_char), riffStr, 4); - // package_len unknown so far - header.riff.package_len = 0; - // copy string 'WAVE' to wave - memcpy(&(header.riff.wave), waveStr, 4); - - - // fill in the 'format' part.. - - // copy string 'fmt ' to fmt - memcpy(&(header.format.fmt), fmtStr, 4); - - header.format.format_len = 0x10; - header.format.fixed = 1; - header.format.channel_number = (short)channels; - header.format.sample_rate = sampleRate; - header.format.bits_per_sample = (short)bits; - header.format.byte_per_sample = (short)(bits * channels / 8); - header.format.byte_rate = header.format.byte_per_sample * sampleRate; - header.format.sample_rate = sampleRate; - - // fill in the 'data' part.. - - // copy string 'data' to data_field - memcpy(&(header.data.data_field), dataStr, 4); - // data_len unknown so far - header.data.data_len = 0; -} - - -void WavOutFile::finishHeader() -{ - // supplement the file length into the header structure - header.riff.package_len = bytesWritten + 36; - header.data.data_len = bytesWritten; - - writeHeader(); -} - - - -void WavOutFile::writeHeader() -{ - WavHeader hdrTemp; - - // swap byte order if necessary - hdrTemp = header; - _swap32((unsigned int &)hdrTemp.riff.package_len); - _swap32((unsigned int &)hdrTemp.format.format_len); - _swap16((unsigned short &)hdrTemp.format.fixed); - _swap16((unsigned short &)hdrTemp.format.channel_number); - _swap32((unsigned int &)hdrTemp.format.sample_rate); - _swap32((unsigned int &)hdrTemp.format.byte_rate); - _swap16((unsigned short &)hdrTemp.format.byte_per_sample); - _swap16((unsigned short &)hdrTemp.format.bits_per_sample); - _swap32((unsigned int &)hdrTemp.data.data_len); - - // write the supplemented header in the beginning of the file - fseek(fptr, 0, SEEK_SET); - fwrite(&hdrTemp, sizeof(hdrTemp), 1, fptr); - // jump back to the end of the file - fseek(fptr, 0, SEEK_END); -} - - - -void WavOutFile::close() -{ - finishHeader(); - fclose(fptr); - fptr = NULL; -} - - -void WavOutFile::write(const char *buffer, int numElems) -{ - int res; - - if (header.format.bits_per_sample != 8) - { - throw runtime_error("Error: WavOutFile::write(const char*, int) accepts only 8bit samples."); - } - assert(sizeof(char) == 1); - - res = fwrite(buffer, 1, numElems, fptr); - if (res != numElems) - { - throw runtime_error("Error while writing to a wav file."); - } - - bytesWritten += numElems; -} - - -void WavOutFile::write(const short *buffer, int numElems) -{ - int res; - - // 16 bit samples - if (numElems < 1) return; // nothing to do - - if (header.format.bits_per_sample == 8) - { - int i; - char *temp = new char[numElems]; - // convert from 16bit format to 8bit format - for (i = 0; i < numElems; i ++) - { - temp[i] = buffer[i] >> 8; - } - // write in 8bit format - write(temp, numElems); - delete[] temp; - } - else - { - // 16bit format - unsigned short *pTemp = new unsigned short[numElems]; - - assert(header.format.bits_per_sample == 16); - - // allocate temp buffer to swap byte order if necessary - memcpy(pTemp, buffer, numElems * 2); - _swap16Buffer(pTemp, numElems); - - res = fwrite(pTemp, 2, numElems, fptr); - - delete[] pTemp; - - if (res != numElems) - { - throw runtime_error("Error while writing to a wav file."); - } - bytesWritten += 2 * numElems; - } -} - - -void WavOutFile::write(const float *buffer, int numElems) -{ - int i; - short *temp = new short[numElems]; - int iTemp; - - // convert to 16 bit integer - for (i = 0; i < numElems; i ++) - { - // convert to integer - iTemp = (int)(32768.0f * buffer[i]); - - // saturate - if (iTemp < -32768) iTemp = -32768; - if (iTemp > 32767) iTemp = 32767; - temp[i] = (short)iTemp; - } - - write(temp, numElems); - - delete[] temp; -} +//////////////////////////////////////////////////////////////////////////////// +/// +/// Classes for easy reading & writing of WAV sound files. +/// +/// For big-endian CPU, define _BIG_ENDIAN_ during compile-time to correctly +/// parse the WAV files with such processors. +/// +/// Admittingly, more complete WAV reader routines may exist in public domain, +/// but the reason for 'yet another' one is that those generic WAV reader +/// libraries are exhaustingly large and cumbersome! Wanted to have something +/// simpler here, i.e. something that's not already larger than rest of the +/// SoundTouch/SoundStretch program... +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2008-06-25 20:17:07 $ +// File revision : $Revision: 1.4 $ +// +// $Id: WavFile.cpp,v 1.4 2008-06-25 20:17:07 richardash1981 Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include + +#include "WavFile.h" + +using namespace std; + +const static char riffStr[] = "RIFF"; +const static char waveStr[] = "WAVE"; +const static char fmtStr[] = "fmt "; +const static char dataStr[] = "data"; + + +////////////////////////////////////////////////////////////////////////////// +// +// Helper functions for swapping byte order to correctly read/write WAV files +// with big-endian CPU's: Define compile-time definition _BIG_ENDIAN_ to +// turn-on the conversion if it appears necessary. +// +// For example, Intel x86 is little-endian and doesn't require conversion, +// while PowerPC of Mac's and many other RISC cpu's are big-endian. + +#ifdef BYTE_ORDER + // In gcc compiler detect the byte order automatically + #if BYTE_ORDER == BIG_ENDIAN + // big-endian platform. + #define _BIG_ENDIAN_ + #endif +#endif + +#ifdef _BIG_ENDIAN_ + // big-endian CPU, swap bytes in 16 & 32 bit words + + // helper-function to swap byte-order of 32bit integer + static inline void _swap32(unsigned int &dwData) + { + dwData = ((dwData >> 24) & 0x000000FF) | + ((dwData >> 8) & 0x0000FF00) | + ((dwData << 8) & 0x00FF0000) | + ((dwData << 24) & 0xFF000000); + } + + // helper-function to swap byte-order of 16bit integer + static inline void _swap16(unsigned short &wData) + { + wData = ((wData >> 8) & 0x00FF) | + ((wData << 8) & 0xFF00); + } + + // helper-function to swap byte-order of buffer of 16bit integers + static inline void _swap16Buffer(unsigned short *pData, unsigned int dwNumWords) + { + unsigned long i; + + for (i = 0; i < dwNumWords; i ++) + { + _swap16(pData[i]); + } + } + +#else // BIG_ENDIAN + // little-endian CPU, WAV file is ok as such + + // dummy helper-function + static inline void _swap32(unsigned int &dwData) + { + // do nothing + } + + // dummy helper-function + static inline void _swap16(unsigned short &wData) + { + // do nothing + } + + // dummy helper-function + static inline void _swap16Buffer(unsigned short *pData, unsigned int dwNumBytes) + { + // do nothing + } + +#endif // BIG_ENDIAN + + +////////////////////////////////////////////////////////////////////////////// +// +// Class WavInFile +// + +WavInFile::WavInFile(const char *fileName) +{ + int hdrsOk; + + // Try to open the file for reading + fptr = fopen(fileName, "rb"); + if (fptr == NULL) + { + // didn't succeed + string msg = "Error : Unable to open file \""; + msg += fileName; + msg += "\" for reading."; + throw runtime_error(msg); + } + + // Read the file headers + hdrsOk = readWavHeaders(); + if (hdrsOk != 0) + { + // Something didn't match in the wav file headers + string msg = "File \""; + msg += fileName; + msg += "\" is corrupt or not a WAV file"; + throw runtime_error(msg); + } + + if (header.format.fixed != 1) + { + string msg = "File \""; + msg += fileName; + msg += "\" uses unsupported encoding."; + throw runtime_error(msg); + } + + dataRead = 0; +} + + + +WavInFile::~WavInFile() +{ + close(); +} + + + +void WavInFile::rewind() +{ + int hdrsOk; + + fseek(fptr, 0, SEEK_SET); + hdrsOk = readWavHeaders(); + assert(hdrsOk == 0); + dataRead = 0; +} + + +int WavInFile::checkCharTags() +{ + // header.format.fmt should equal to 'fmt ' + if (memcmp(fmtStr, header.format.fmt, 4) != 0) return -1; + // header.data.data_field should equal to 'data' + if (memcmp(dataStr, header.data.data_field, 4) != 0) return -1; + + return 0; +} + + +int WavInFile::read(char *buffer, int maxElems) +{ + int numBytes; + uint afterDataRead; + + // ensure it's 8 bit format + if (header.format.bits_per_sample != 8) + { + throw runtime_error("Error: WavInFile::read(char*, int) works only with 8bit samples."); + } + assert(sizeof(char) == 1); + + numBytes = maxElems; + afterDataRead = dataRead + numBytes; + if (afterDataRead > header.data.data_len) + { + // Don't read more samples than are marked available in header + numBytes = header.data.data_len - dataRead; + assert(numBytes >= 0); + } + + numBytes = fread(buffer, 1, numBytes, fptr); + dataRead += numBytes; + + return numBytes; +} + + +int WavInFile::read(short *buffer, int maxElems) +{ + unsigned int afterDataRead; + int numBytes; + int numElems; + + if (header.format.bits_per_sample == 8) + { + // 8 bit format + char *temp = new char[maxElems]; + int i; + + numElems = read(temp, maxElems); + // convert from 8 to 16 bit + for (i = 0; i < numElems; i ++) + { + buffer[i] = temp[i] << 8; + } + delete[] temp; + } + else + { + // 16 bit format + assert(header.format.bits_per_sample == 16); + assert(sizeof(short) == 2); + + numBytes = maxElems * 2; + afterDataRead = dataRead + numBytes; + if (afterDataRead > header.data.data_len) + { + // Don't read more samples than are marked available in header + numBytes = header.data.data_len - dataRead; + assert(numBytes >= 0); + } + + numBytes = fread(buffer, 1, numBytes, fptr); + dataRead += numBytes; + numElems = numBytes / 2; + + // 16bit samples, swap byte order if necessary + _swap16Buffer((unsigned short *)buffer, numElems); + } + + return numElems; +} + + + +int WavInFile::read(float *buffer, int maxElems) +{ + short *temp = new short[maxElems]; + int num; + int i; + double fscale; + + num = read(temp, maxElems); + + fscale = 1.0 / 32768.0; + // convert to floats, scale to range [-1..+1[ + for (i = 0; i < num; i ++) + { + buffer[i] = (float)(fscale * (double)temp[i]); + } + + delete[] temp; + + return num; +} + + +int WavInFile::eof() const +{ + // return true if all data has been read or file eof has reached + return (dataRead == header.data.data_len || feof(fptr)); +} + + +void WavInFile::close() +{ + fclose(fptr); + fptr = NULL; +} + + + +// test if character code is between a white space ' ' and little 'z' +static int isAlpha(char c) +{ + return (c >= ' ' && c <= 'z') ? 1 : 0; +} + + +// test if all characters are between a white space ' ' and little 'z' +static int isAlphaStr(char *str) +{ + int c; + + c = str[0]; + while (c) + { + if (isAlpha(c) == 0) return 0; + str ++; + c = str[0]; + } + + return 1; +} + + +int WavInFile::readRIFFBlock() +{ + fread(&(header.riff), sizeof(WavRiff), 1, fptr); + + // swap 32bit data byte order if necessary + _swap32((unsigned int &)header.riff.package_len); + + // header.riff.riff_char should equal to 'RIFF'); + if (memcmp(riffStr, header.riff.riff_char, 4) != 0) return -1; + // header.riff.wave should equal to 'WAVE' + if (memcmp(waveStr, header.riff.wave, 4) != 0) return -1; + + return 0; +} + + + + +int WavInFile::readHeaderBlock() +{ + char label[5]; + string sLabel; + + // lead label string + fread(label, 1, 4, fptr); + label[4] = 0; + + if (isAlphaStr(label) == 0) return -1; // not a valid label + + // Decode blocks according to their label + if (strcmp(label, fmtStr) == 0) + { + int nLen, nDump; + + // 'fmt ' block + memcpy(header.format.fmt, fmtStr, 4); + + // read length of the format field + fread(&nLen, sizeof(int), 1, fptr); + // swap byte order if necessary + _swap32((unsigned int &)nLen); // int format_len; + header.format.format_len = nLen; + + // calculate how much length differs from expected + nDump = nLen - (sizeof(header.format) - 8); + + // if format_len is larger than expected, read only as much data as we've space for + if (nDump > 0) + { + nLen = sizeof(header.format) - 8; + } + + // read data + fread(&(header.format.fixed), nLen, 1, fptr); + + // swap byte order if necessary + _swap16((unsigned short &)header.format.fixed); // short int fixed; + _swap16((unsigned short &)header.format.channel_number); // short int channel_number; + _swap32((unsigned int &)header.format.sample_rate); // int sample_rate; + _swap32((unsigned int &)header.format.byte_rate); // int byte_rate; + _swap16((unsigned short &)header.format.byte_per_sample); // short int byte_per_sample; + _swap16((unsigned short &)header.format.bits_per_sample); // short int bits_per_sample; + + // if format_len is larger than expected, skip the extra data + if (nDump > 0) + { + fseek(fptr, nDump, SEEK_CUR); + } + + return 0; + } + else if (strcmp(label, dataStr) == 0) + { + // 'data' block + memcpy(header.data.data_field, dataStr, 4); + fread(&(header.data.data_len), sizeof(uint), 1, fptr); + + // swap byte order if necessary + _swap32((unsigned int &)header.data.data_len); + + return 1; + } + else + { + uint len, i; + uint temp; + // unknown block + + // read length + fread(&len, sizeof(len), 1, fptr); + // scan through the block + for (i = 0; i < len; i ++) + { + fread(&temp, 1, 1, fptr); + if (feof(fptr)) return -1; // unexpected eof + } + } + return 0; +} + + +int WavInFile::readWavHeaders() +{ + int res; + + memset(&header, 0, sizeof(header)); + + res = readRIFFBlock(); + if (res) return 1; + // read header blocks until data block is found + do + { + // read header blocks + res = readHeaderBlock(); + if (res < 0) return 1; // error in file structure + } while (res == 0); + // check that all required tags are legal + return checkCharTags(); +} + + +uint WavInFile::getNumChannels() const +{ + return header.format.channel_number; +} + + +uint WavInFile::getNumBits() const +{ + return header.format.bits_per_sample; +} + + +uint WavInFile::getBytesPerSample() const +{ + return getNumChannels() * getNumBits() / 8; +} + + +uint WavInFile::getSampleRate() const +{ + return header.format.sample_rate; +} + + + +uint WavInFile::getDataSizeInBytes() const +{ + return header.data.data_len; +} + + +uint WavInFile::getNumSamples() const +{ + return header.data.data_len / header.format.byte_per_sample; +} + + +uint WavInFile::getLengthMS() const +{ + uint numSamples; + uint sampleRate; + + numSamples = getNumSamples(); + sampleRate = getSampleRate(); + + assert(numSamples < UINT_MAX / 1000); + return (1000 * numSamples / sampleRate); +} + + +////////////////////////////////////////////////////////////////////////////// +// +// Class WavOutFile +// + +WavOutFile::WavOutFile(const char *fileName, int sampleRate, int bits, int channels) +{ + bytesWritten = 0; + fptr = fopen(fileName, "wb"); + if (fptr == NULL) + { + string msg = "Error : Unable to open file \""; + msg += fileName; + msg += "\" for writing."; + //pmsg = msg.c_str; + throw runtime_error(msg); + } + + fillInHeader(sampleRate, bits, channels); + writeHeader(); +} + + + +WavOutFile::~WavOutFile() +{ + close(); +} + + + +void WavOutFile::fillInHeader(uint sampleRate, uint bits, uint channels) +{ + // fill in the 'riff' part.. + + // copy string 'RIFF' to riff_char + memcpy(&(header.riff.riff_char), riffStr, 4); + // package_len unknown so far + header.riff.package_len = 0; + // copy string 'WAVE' to wave + memcpy(&(header.riff.wave), waveStr, 4); + + + // fill in the 'format' part.. + + // copy string 'fmt ' to fmt + memcpy(&(header.format.fmt), fmtStr, 4); + + header.format.format_len = 0x10; + header.format.fixed = 1; + header.format.channel_number = (short)channels; + header.format.sample_rate = sampleRate; + header.format.bits_per_sample = (short)bits; + header.format.byte_per_sample = (short)(bits * channels / 8); + header.format.byte_rate = header.format.byte_per_sample * sampleRate; + header.format.sample_rate = sampleRate; + + // fill in the 'data' part.. + + // copy string 'data' to data_field + memcpy(&(header.data.data_field), dataStr, 4); + // data_len unknown so far + header.data.data_len = 0; +} + + +void WavOutFile::finishHeader() +{ + // supplement the file length into the header structure + header.riff.package_len = bytesWritten + 36; + header.data.data_len = bytesWritten; + + writeHeader(); +} + + + +void WavOutFile::writeHeader() +{ + WavHeader hdrTemp; + + // swap byte order if necessary + hdrTemp = header; + _swap32((unsigned int &)hdrTemp.riff.package_len); + _swap32((unsigned int &)hdrTemp.format.format_len); + _swap16((unsigned short &)hdrTemp.format.fixed); + _swap16((unsigned short &)hdrTemp.format.channel_number); + _swap32((unsigned int &)hdrTemp.format.sample_rate); + _swap32((unsigned int &)hdrTemp.format.byte_rate); + _swap16((unsigned short &)hdrTemp.format.byte_per_sample); + _swap16((unsigned short &)hdrTemp.format.bits_per_sample); + _swap32((unsigned int &)hdrTemp.data.data_len); + + // write the supplemented header in the beginning of the file + fseek(fptr, 0, SEEK_SET); + fwrite(&hdrTemp, sizeof(hdrTemp), 1, fptr); + // jump back to the end of the file + fseek(fptr, 0, SEEK_END); +} + + + +void WavOutFile::close() +{ + finishHeader(); + fclose(fptr); + fptr = NULL; +} + + +void WavOutFile::write(const char *buffer, int numElems) +{ + int res; + + if (header.format.bits_per_sample != 8) + { + throw runtime_error("Error: WavOutFile::write(const char*, int) accepts only 8bit samples."); + } + assert(sizeof(char) == 1); + + res = fwrite(buffer, 1, numElems, fptr); + if (res != numElems) + { + throw runtime_error("Error while writing to a wav file."); + } + + bytesWritten += numElems; +} + + +void WavOutFile::write(const short *buffer, int numElems) +{ + int res; + + // 16 bit samples + if (numElems < 1) return; // nothing to do + + if (header.format.bits_per_sample == 8) + { + int i; + char *temp = new char[numElems]; + // convert from 16bit format to 8bit format + for (i = 0; i < numElems; i ++) + { + temp[i] = buffer[i] >> 8; + } + // write in 8bit format + write(temp, numElems); + delete[] temp; + } + else + { + // 16bit format + unsigned short *pTemp = new unsigned short[numElems]; + + assert(header.format.bits_per_sample == 16); + + // allocate temp buffer to swap byte order if necessary + memcpy(pTemp, buffer, numElems * 2); + _swap16Buffer(pTemp, numElems); + + res = fwrite(pTemp, 2, numElems, fptr); + + delete[] pTemp; + + if (res != numElems) + { + throw runtime_error("Error while writing to a wav file."); + } + bytesWritten += 2 * numElems; + } +} + + +void WavOutFile::write(const float *buffer, int numElems) +{ + int i; + short *temp = new short[numElems]; + int iTemp; + + // convert to 16 bit integer + for (i = 0; i < numElems; i ++) + { + // convert to integer + iTemp = (int)(32768.0f * buffer[i]); + + // saturate + if (iTemp < -32768) iTemp = -32768; + if (iTemp > 32767) iTemp = 32767; + temp[i] = (short)iTemp; + } + + write(temp, numElems); + + delete[] temp; +} diff --git a/lib-src/soundtouch/source/example/SoundStretch/WavFile.h b/lib-src/soundtouch/source/example/SoundStretch/WavFile.h index fb5f07b67..5c5967dae 100644 --- a/lib-src/soundtouch/source/example/SoundStretch/WavFile.h +++ b/lib-src/soundtouch/source/example/SoundStretch/WavFile.h @@ -1,253 +1,253 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Classes for easy reading & writing of WAV sound files. -/// -/// For big-endian CPU, define BIG_ENDIAN during compile-time to correctly -/// parse the WAV files with such processors. -/// -/// Admittingly, more complete WAV reader routines may exist in public domain, but -/// the reason for 'yet another' one is that those generic WAV reader libraries are -/// exhaustingly large and cumbersome! Wanted to have something simpler here, i.e. -/// something that's not already larger than rest of the SoundTouch/SoundStretch program... -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006-09-18 07:31:48 $ -// File revision : $Revision: 1.2 $ -// -// $Id: WavFile.h,v 1.2 2006-09-18 07:31:48 richardash1981 Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef WAVFILE_H -#define WAVFILE_H - -#include - -#ifndef uint -typedef unsigned int uint; -#endif - - -/// WAV audio file 'riff' section header -typedef struct -{ - char riff_char[4]; - int package_len; - char wave[4]; -} WavRiff; - -/// WAV audio file 'format' section header -typedef struct -{ - char fmt[4]; - int format_len; - short fixed; - short channel_number; - int sample_rate; - int byte_rate; - short byte_per_sample; - short bits_per_sample; -} WavFormat; - -/// WAV audio file 'data' section header -typedef struct -{ - char data_field[4]; - uint data_len; -} WavData; - - -/// WAV audio file header -typedef struct -{ - WavRiff riff; - WavFormat format; - WavData data; -} WavHeader; - - -/// Class for reading WAV audio files. -class WavInFile -{ -private: - /// File pointer. - FILE *fptr; - - /// Counter of how many bytes of sample data have been read from the file. - uint dataRead; - - /// WAV header information - WavHeader header; - - /// Read WAV file headers. - /// \return zero if all ok, nonzero if file format is invalid. - int readWavHeaders(); - - /// Checks WAV file header tags. - /// \return zero if all ok, nonzero if file format is invalid. - int checkCharTags(); - - /// Reads a single WAV file header block. - /// \return zero if all ok, nonzero if file format is invalid. - int readHeaderBlock(); - - /// Reads WAV file 'riff' block - int readRIFFBlock(); - -public: - /// Constructor: Opens the given WAV file. If the file can't be opened, - /// throws 'runtime_error' exception. - WavInFile(const char *filename); - - /// Destructor: Closes the file. - ~WavInFile(); - - /// Close the file. Notice that file is automatically closed also when the - /// class instance is deleted. - void close(); - - /// Rewind to beginning of the file - void rewind(); - - /// Get sample rate. - uint getSampleRate() const; - - /// Get number of bits per sample, i.e. 8 or 16. - uint getNumBits() const; - - /// Get sample data size in bytes. Ahem, this should return same information as - /// 'getBytesPerSample'... - uint getDataSizeInBytes() const; - - /// Get total number of samples in file. - uint getNumSamples() const; - - /// Get number of bytes per audio sample (e.g. 16bit stereo = 4 bytes/sample) - uint getBytesPerSample() const; - - /// Get number of audio channels in the file (1=mono, 2=stereo) - uint getNumChannels() const; - - /// Get the audio file length in milliseconds - uint getLengthMS() const; - - /// Reads audio samples from the WAV file. This routine works only for 8 bit samples. - /// Reads given number of elements from the file or if end-of-file reached, as many - /// elements as are left in the file. - /// - /// \return Number of 8-bit integers read from the file. - int read(char *buffer, int maxElems); - - /// Reads audio samples from the WAV file to 16 bit integer format. Reads given number - /// of elements from the file or if end-of-file reached, as many elements as are - /// left in the file. - /// - /// \return Number of 16-bit integers read from the file. - int read(short *buffer, ///< Pointer to buffer where to read data. - int maxElems ///< Size of 'buffer' array (number of array elements). - ); - - /// Reads audio samples from the WAV file to floating point format, converting - /// sample values to range [-1,1[. Reads given number of elements from the file - /// or if end-of-file reached, as many elements as are left in the file. - /// - /// \return Number of elements read from the file. - int read(float *buffer, ///< Pointer to buffer where to read data. - int maxElems ///< Size of 'buffer' array (number of array elements). - ); - - /// Check end-of-file. - /// - /// \return Nonzero if end-of-file reached. - int eof() const; -}; - - - -/// Class for writing WAV audio files. -class WavOutFile -{ -private: - /// Pointer to the WAV file - FILE *fptr; - - /// WAV file header data. - WavHeader header; - - /// Counter of how many bytes have been written to the file so far. - int bytesWritten; - - /// Fills in WAV file header information. - void fillInHeader(const uint sampleRate, const uint bits, const uint channels); - - /// Finishes the WAV file header by supplementing information of amount of - /// data written to file etc - void finishHeader(); - - /// Writes the WAV file header. - void writeHeader(); - -public: - /// Constructor: Creates a new WAV file. Throws a 'runtime_error' exception - /// if file creation fails. - WavOutFile(const char *fileName, ///< Filename - int sampleRate, ///< Sample rate (e.g. 44100 etc) - int bits, ///< Bits per sample (8 or 16 bits) - int channels ///< Number of channels (1=mono, 2=stereo) - ); - - /// Destructor: Finalizes & closes the WAV file. - ~WavOutFile(); - - /// Write data to WAV file. This function works only with 8bit samples. - /// Throws a 'runtime_error' exception if writing to file fails. - void write(const char *buffer, ///< Pointer to sample data buffer. - int numElems ///< How many array items are to be written to file. - ); - - /// Write data to WAV file. Throws a 'runtime_error' exception if writing to - /// file fails. - void write(const short *buffer, ///< Pointer to sample data buffer. - int numElems ///< How many array items are to be written to file. - ); - - /// Write data to WAV file in floating point format, saturating sample values to range - /// [-1..+1[. Throws a 'runtime_error' exception if writing to file fails. - void write(const float *buffer, ///< Pointer to sample data buffer. - int numElems ///< How many array items are to be written to file. - ); - - /// Finalize & close the WAV file. Automatically supplements the WAV file header - /// information according to written data etc. - /// - /// Notice that file is automatically closed also when the class instance is deleted. - void close(); -}; - -#endif +//////////////////////////////////////////////////////////////////////////////// +/// +/// Classes for easy reading & writing of WAV sound files. +/// +/// For big-endian CPU, define BIG_ENDIAN during compile-time to correctly +/// parse the WAV files with such processors. +/// +/// Admittingly, more complete WAV reader routines may exist in public domain, but +/// the reason for 'yet another' one is that those generic WAV reader libraries are +/// exhaustingly large and cumbersome! Wanted to have something simpler here, i.e. +/// something that's not already larger than rest of the SoundTouch/SoundStretch program... +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006-09-18 07:31:48 $ +// File revision : $Revision: 1.2 $ +// +// $Id: WavFile.h,v 1.2 2006-09-18 07:31:48 richardash1981 Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef WAVFILE_H +#define WAVFILE_H + +#include + +#ifndef uint +typedef unsigned int uint; +#endif + + +/// WAV audio file 'riff' section header +typedef struct +{ + char riff_char[4]; + int package_len; + char wave[4]; +} WavRiff; + +/// WAV audio file 'format' section header +typedef struct +{ + char fmt[4]; + int format_len; + short fixed; + short channel_number; + int sample_rate; + int byte_rate; + short byte_per_sample; + short bits_per_sample; +} WavFormat; + +/// WAV audio file 'data' section header +typedef struct +{ + char data_field[4]; + uint data_len; +} WavData; + + +/// WAV audio file header +typedef struct +{ + WavRiff riff; + WavFormat format; + WavData data; +} WavHeader; + + +/// Class for reading WAV audio files. +class WavInFile +{ +private: + /// File pointer. + FILE *fptr; + + /// Counter of how many bytes of sample data have been read from the file. + uint dataRead; + + /// WAV header information + WavHeader header; + + /// Read WAV file headers. + /// \return zero if all ok, nonzero if file format is invalid. + int readWavHeaders(); + + /// Checks WAV file header tags. + /// \return zero if all ok, nonzero if file format is invalid. + int checkCharTags(); + + /// Reads a single WAV file header block. + /// \return zero if all ok, nonzero if file format is invalid. + int readHeaderBlock(); + + /// Reads WAV file 'riff' block + int readRIFFBlock(); + +public: + /// Constructor: Opens the given WAV file. If the file can't be opened, + /// throws 'runtime_error' exception. + WavInFile(const char *filename); + + /// Destructor: Closes the file. + ~WavInFile(); + + /// Close the file. Notice that file is automatically closed also when the + /// class instance is deleted. + void close(); + + /// Rewind to beginning of the file + void rewind(); + + /// Get sample rate. + uint getSampleRate() const; + + /// Get number of bits per sample, i.e. 8 or 16. + uint getNumBits() const; + + /// Get sample data size in bytes. Ahem, this should return same information as + /// 'getBytesPerSample'... + uint getDataSizeInBytes() const; + + /// Get total number of samples in file. + uint getNumSamples() const; + + /// Get number of bytes per audio sample (e.g. 16bit stereo = 4 bytes/sample) + uint getBytesPerSample() const; + + /// Get number of audio channels in the file (1=mono, 2=stereo) + uint getNumChannels() const; + + /// Get the audio file length in milliseconds + uint getLengthMS() const; + + /// Reads audio samples from the WAV file. This routine works only for 8 bit samples. + /// Reads given number of elements from the file or if end-of-file reached, as many + /// elements as are left in the file. + /// + /// \return Number of 8-bit integers read from the file. + int read(char *buffer, int maxElems); + + /// Reads audio samples from the WAV file to 16 bit integer format. Reads given number + /// of elements from the file or if end-of-file reached, as many elements as are + /// left in the file. + /// + /// \return Number of 16-bit integers read from the file. + int read(short *buffer, ///< Pointer to buffer where to read data. + int maxElems ///< Size of 'buffer' array (number of array elements). + ); + + /// Reads audio samples from the WAV file to floating point format, converting + /// sample values to range [-1,1[. Reads given number of elements from the file + /// or if end-of-file reached, as many elements as are left in the file. + /// + /// \return Number of elements read from the file. + int read(float *buffer, ///< Pointer to buffer where to read data. + int maxElems ///< Size of 'buffer' array (number of array elements). + ); + + /// Check end-of-file. + /// + /// \return Nonzero if end-of-file reached. + int eof() const; +}; + + + +/// Class for writing WAV audio files. +class WavOutFile +{ +private: + /// Pointer to the WAV file + FILE *fptr; + + /// WAV file header data. + WavHeader header; + + /// Counter of how many bytes have been written to the file so far. + int bytesWritten; + + /// Fills in WAV file header information. + void fillInHeader(const uint sampleRate, const uint bits, const uint channels); + + /// Finishes the WAV file header by supplementing information of amount of + /// data written to file etc + void finishHeader(); + + /// Writes the WAV file header. + void writeHeader(); + +public: + /// Constructor: Creates a new WAV file. Throws a 'runtime_error' exception + /// if file creation fails. + WavOutFile(const char *fileName, ///< Filename + int sampleRate, ///< Sample rate (e.g. 44100 etc) + int bits, ///< Bits per sample (8 or 16 bits) + int channels ///< Number of channels (1=mono, 2=stereo) + ); + + /// Destructor: Finalizes & closes the WAV file. + ~WavOutFile(); + + /// Write data to WAV file. This function works only with 8bit samples. + /// Throws a 'runtime_error' exception if writing to file fails. + void write(const char *buffer, ///< Pointer to sample data buffer. + int numElems ///< How many array items are to be written to file. + ); + + /// Write data to WAV file. Throws a 'runtime_error' exception if writing to + /// file fails. + void write(const short *buffer, ///< Pointer to sample data buffer. + int numElems ///< How many array items are to be written to file. + ); + + /// Write data to WAV file in floating point format, saturating sample values to range + /// [-1..+1[. Throws a 'runtime_error' exception if writing to file fails. + void write(const float *buffer, ///< Pointer to sample data buffer. + int numElems ///< How many array items are to be written to file. + ); + + /// Finalize & close the WAV file. Automatically supplements the WAV file header + /// information according to written data etc. + /// + /// Notice that file is automatically closed also when the class instance is deleted. + void close(); +}; + +#endif diff --git a/lib-src/soundtouch/source/example/SoundStretch/main.cpp b/lib-src/soundtouch/source/example/SoundStretch/main.cpp index 4ebd46c39..9ad15d7c2 100644 --- a/lib-src/soundtouch/source/example/SoundStretch/main.cpp +++ b/lib-src/soundtouch/source/example/SoundStretch/main.cpp @@ -1,288 +1,288 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// SoundStretch main routine. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006-09-18 07:31:48 $ -// File revision : $Revision: 1.3 $ -// -// $Id: main.cpp,v 1.3 2006-09-18 07:31:48 richardash1981 Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#include -#include -#include "RunParameters.h" -#include "WavFile.h" -#include "SoundTouch.h" -#include "BPMDetect.h" - -using namespace soundtouch; -using namespace std; - -// Processing chunk size -#define BUFF_SIZE 2048 - - -static const char _helloText[] = - "\n" - " SoundStretch v%s - Written by Olli Parviainen 2001 - 2006\n" - "==================================================================\n" - "author e-mail: - WWW: http://www.surina.net/soundtouch\n" - "\n" - "This program is subject to (L)GPL license. Run \"soundstretch -license\" for\n" - "more information.\n" - "\n"; - -static void openFiles(WavInFile **inFile, WavOutFile **outFile, const RunParameters *params) -{ - int bits, samplerate, channels; - - // open input file... - *inFile = new WavInFile(params->inFileName); - - // ... open output file with same sound parameters - bits = (*inFile)->getNumBits(); - samplerate = (*inFile)->getSampleRate(); - channels = (*inFile)->getNumChannels(); - - if (params->outFileName) - { - *outFile = new WavOutFile(params->outFileName, samplerate, bits, channels); - } - else - { - *outFile = NULL; - } -} - - - -// Sets the 'SoundTouch' object up according to input file sound format & -// command line parameters -static void setup(SoundTouch *pSoundTouch, const WavInFile *inFile, const RunParameters *params) -{ - int sampleRate; - int channels; - - sampleRate = inFile->getSampleRate(); - channels = inFile->getNumChannels(); - pSoundTouch->setSampleRate(sampleRate); - pSoundTouch->setChannels(channels); - - pSoundTouch->setTempoChange(params->tempoDelta); - pSoundTouch->setPitchSemiTones(params->pitchDelta); - pSoundTouch->setRateChange(params->rateDelta); - - pSoundTouch->setSetting(SETTING_USE_QUICKSEEK, params->quick); - pSoundTouch->setSetting(SETTING_USE_AA_FILTER, !params->noAntiAlias); - - // print processing information - if (params->outFileName) - { -#ifdef INTEGER_SAMPLES - printf("Uses 16bit integer sample type in processing.\n\n"); -#else - #ifndef FLOAT_SAMPLES - #error "Sampletype not defined" - #endif - printf("Uses 32bit floating point sample type in processing.\n\n"); -#endif - // print processing information only if outFileName given i.e. some processing will happen - printf("Processing the file with the following changes:\n"); - printf(" tempo change = %+g %%\n", params->tempoDelta); - printf(" pitch change = %+g semitones\n", params->pitchDelta); - printf(" rate change = %+g %%\n\n", params->rateDelta); - printf("Working..."); - } - else - { - // outFileName not given - printf("Warning: output file name missing, won't output anything.\n\n"); - } - - fflush(stdout); -} - - - - -// Processes the sound -static void process(SoundTouch *pSoundTouch, WavInFile *inFile, WavOutFile *outFile) -{ - int nSamples; - int nChannels; - int buffSizeSamples; - SAMPLETYPE sampleBuffer[BUFF_SIZE]; - - if ((inFile == NULL) || (outFile == NULL)) return; // nothing to do. - - nChannels = inFile->getNumChannels(); - buffSizeSamples = BUFF_SIZE / nChannels; - - // Process samples read from the input file - while (inFile->eof() == 0) - { - int num; - - // Read a chunk of samples from the input file - num = inFile->read(sampleBuffer, BUFF_SIZE); - nSamples = num / inFile->getNumChannels(); - - // Feed the samples into SoundTouch processor - pSoundTouch->putSamples(sampleBuffer, nSamples); - - // Read ready samples from SoundTouch processor & write them output file. - // NOTES: - // - 'receiveSamples' doesn't necessarily return any samples at all - // during some rounds! - // - On the other hand, during some round 'receiveSamples' may have more - // ready samples than would fit into 'sampleBuffer', and for this reason - // the 'receiveSamples' call is iterated for as many times as it - // outputs samples. - do - { - nSamples = pSoundTouch->receiveSamples(sampleBuffer, buffSizeSamples); - outFile->write(sampleBuffer, nSamples * nChannels); - } while (nSamples != 0); - } - - // Now the input file is processed, yet 'flush' few last samples that are - // hiding in the SoundTouch's internal processing pipeline. - pSoundTouch->flush(); - do - { - nSamples = pSoundTouch->receiveSamples(sampleBuffer, buffSizeSamples); - outFile->write(sampleBuffer, nSamples * nChannels); - } while (nSamples != 0); -} - - - -// Detect BPM rate of inFile and adjust tempo setting accordingly if necessary -static void detectBPM(WavInFile *inFile, RunParameters *params) -{ - float bpmValue; - int nChannels; - BPMDetect bpm(inFile->getNumChannels(), inFile->getSampleRate()); - SAMPLETYPE sampleBuffer[BUFF_SIZE]; - - // detect bpm rate - printf("Detecting BPM rate..."); - fflush(stdout); - - nChannels = inFile->getNumChannels(); - - // Process the 'inFile' in small blocks, repeat until whole file has - // been processed - while (inFile->eof() == 0) - { - int num, samples; - - // Read sample data from input file - num = inFile->read(sampleBuffer, BUFF_SIZE); - - // Enter the new samples to the bpm analyzer class - samples = num / nChannels; - bpm.inputSamples(sampleBuffer, samples); - } - - // Now the whole song data has been analyzed. Read the resulting bpm. - bpmValue = bpm.getBpm(); - printf("Done!\n"); - - // rewind the file after bpm detection - inFile->rewind(); - - if (bpmValue > 0) - { - printf("Detected BPM rate %.1f\n\n", bpmValue); - } - else - { - printf("Couldn't detect BPM rate.\n\n"); - return; - } - - if (params->goalBPM > 0) - { - // adjust tempo to given bpm - params->tempoDelta = (params->goalBPM / bpmValue - 1.0f) * 100.0f; - printf("The file will be converted to %.1f BPM\n\n", params->goalBPM); - } -} - - - -int main(const int nParams, const char *paramStr[]) -{ - WavInFile *inFile; - WavOutFile *outFile; - RunParameters *params; - SoundTouch SoundTouch; - - printf(_helloText, SoundTouch::getVersionString()); - - try - { - // Parse command line parameters - params = new RunParameters(nParams, paramStr); - - // Open input & output files - openFiles(&inFile, &outFile, params); - - if (params->detectBPM == TRUE) - { - // detect sound BPM (and adjust processing parameters - // accordingly if necessary) - detectBPM(inFile, params); - } - - // Setup the 'SoundTouch' object for processing the sound - setup(&SoundTouch, inFile, params); - - // Process the sound - process(&SoundTouch, inFile, outFile); - - // Close WAV file handles & dispose of the objects - delete inFile; - delete outFile; - delete params; - - printf("Done!\n"); - } - catch (runtime_error &e) - { - // An exception occurred during processing, display an error message - printf("%s\n", e.what()); - return -1; - } - - return 0; -} +//////////////////////////////////////////////////////////////////////////////// +/// +/// SoundStretch main routine. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006-09-18 07:31:48 $ +// File revision : $Revision: 1.3 $ +// +// $Id: main.cpp,v 1.3 2006-09-18 07:31:48 richardash1981 Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include "RunParameters.h" +#include "WavFile.h" +#include "SoundTouch.h" +#include "BPMDetect.h" + +using namespace soundtouch; +using namespace std; + +// Processing chunk size +#define BUFF_SIZE 2048 + + +static const char _helloText[] = + "\n" + " SoundStretch v%s - Written by Olli Parviainen 2001 - 2006\n" + "==================================================================\n" + "author e-mail: - WWW: http://www.surina.net/soundtouch\n" + "\n" + "This program is subject to (L)GPL license. Run \"soundstretch -license\" for\n" + "more information.\n" + "\n"; + +static void openFiles(WavInFile **inFile, WavOutFile **outFile, const RunParameters *params) +{ + int bits, samplerate, channels; + + // open input file... + *inFile = new WavInFile(params->inFileName); + + // ... open output file with same sound parameters + bits = (*inFile)->getNumBits(); + samplerate = (*inFile)->getSampleRate(); + channels = (*inFile)->getNumChannels(); + + if (params->outFileName) + { + *outFile = new WavOutFile(params->outFileName, samplerate, bits, channels); + } + else + { + *outFile = NULL; + } +} + + + +// Sets the 'SoundTouch' object up according to input file sound format & +// command line parameters +static void setup(SoundTouch *pSoundTouch, const WavInFile *inFile, const RunParameters *params) +{ + int sampleRate; + int channels; + + sampleRate = inFile->getSampleRate(); + channels = inFile->getNumChannels(); + pSoundTouch->setSampleRate(sampleRate); + pSoundTouch->setChannels(channels); + + pSoundTouch->setTempoChange(params->tempoDelta); + pSoundTouch->setPitchSemiTones(params->pitchDelta); + pSoundTouch->setRateChange(params->rateDelta); + + pSoundTouch->setSetting(SETTING_USE_QUICKSEEK, params->quick); + pSoundTouch->setSetting(SETTING_USE_AA_FILTER, !params->noAntiAlias); + + // print processing information + if (params->outFileName) + { +#ifdef INTEGER_SAMPLES + printf("Uses 16bit integer sample type in processing.\n\n"); +#else + #ifndef FLOAT_SAMPLES + #error "Sampletype not defined" + #endif + printf("Uses 32bit floating point sample type in processing.\n\n"); +#endif + // print processing information only if outFileName given i.e. some processing will happen + printf("Processing the file with the following changes:\n"); + printf(" tempo change = %+g %%\n", params->tempoDelta); + printf(" pitch change = %+g semitones\n", params->pitchDelta); + printf(" rate change = %+g %%\n\n", params->rateDelta); + printf("Working..."); + } + else + { + // outFileName not given + printf("Warning: output file name missing, won't output anything.\n\n"); + } + + fflush(stdout); +} + + + + +// Processes the sound +static void process(SoundTouch *pSoundTouch, WavInFile *inFile, WavOutFile *outFile) +{ + int nSamples; + int nChannels; + int buffSizeSamples; + SAMPLETYPE sampleBuffer[BUFF_SIZE]; + + if ((inFile == NULL) || (outFile == NULL)) return; // nothing to do. + + nChannels = inFile->getNumChannels(); + buffSizeSamples = BUFF_SIZE / nChannels; + + // Process samples read from the input file + while (inFile->eof() == 0) + { + int num; + + // Read a chunk of samples from the input file + num = inFile->read(sampleBuffer, BUFF_SIZE); + nSamples = num / inFile->getNumChannels(); + + // Feed the samples into SoundTouch processor + pSoundTouch->putSamples(sampleBuffer, nSamples); + + // Read ready samples from SoundTouch processor & write them output file. + // NOTES: + // - 'receiveSamples' doesn't necessarily return any samples at all + // during some rounds! + // - On the other hand, during some round 'receiveSamples' may have more + // ready samples than would fit into 'sampleBuffer', and for this reason + // the 'receiveSamples' call is iterated for as many times as it + // outputs samples. + do + { + nSamples = pSoundTouch->receiveSamples(sampleBuffer, buffSizeSamples); + outFile->write(sampleBuffer, nSamples * nChannels); + } while (nSamples != 0); + } + + // Now the input file is processed, yet 'flush' few last samples that are + // hiding in the SoundTouch's internal processing pipeline. + pSoundTouch->flush(); + do + { + nSamples = pSoundTouch->receiveSamples(sampleBuffer, buffSizeSamples); + outFile->write(sampleBuffer, nSamples * nChannels); + } while (nSamples != 0); +} + + + +// Detect BPM rate of inFile and adjust tempo setting accordingly if necessary +static void detectBPM(WavInFile *inFile, RunParameters *params) +{ + float bpmValue; + int nChannels; + BPMDetect bpm(inFile->getNumChannels(), inFile->getSampleRate()); + SAMPLETYPE sampleBuffer[BUFF_SIZE]; + + // detect bpm rate + printf("Detecting BPM rate..."); + fflush(stdout); + + nChannels = inFile->getNumChannels(); + + // Process the 'inFile' in small blocks, repeat until whole file has + // been processed + while (inFile->eof() == 0) + { + int num, samples; + + // Read sample data from input file + num = inFile->read(sampleBuffer, BUFF_SIZE); + + // Enter the new samples to the bpm analyzer class + samples = num / nChannels; + bpm.inputSamples(sampleBuffer, samples); + } + + // Now the whole song data has been analyzed. Read the resulting bpm. + bpmValue = bpm.getBpm(); + printf("Done!\n"); + + // rewind the file after bpm detection + inFile->rewind(); + + if (bpmValue > 0) + { + printf("Detected BPM rate %.1f\n\n", bpmValue); + } + else + { + printf("Couldn't detect BPM rate.\n\n"); + return; + } + + if (params->goalBPM > 0) + { + // adjust tempo to given bpm + params->tempoDelta = (params->goalBPM / bpmValue - 1.0f) * 100.0f; + printf("The file will be converted to %.1f BPM\n\n", params->goalBPM); + } +} + + + +int main(const int nParams, const char *paramStr[]) +{ + WavInFile *inFile; + WavOutFile *outFile; + RunParameters *params; + SoundTouch SoundTouch; + + printf(_helloText, SoundTouch::getVersionString()); + + try + { + // Parse command line parameters + params = new RunParameters(nParams, paramStr); + + // Open input & output files + openFiles(&inFile, &outFile, params); + + if (params->detectBPM == TRUE) + { + // detect sound BPM (and adjust processing parameters + // accordingly if necessary) + detectBPM(inFile, params); + } + + // Setup the 'SoundTouch' object for processing the sound + setup(&SoundTouch, inFile, params); + + // Process the sound + process(&SoundTouch, inFile, outFile); + + // Close WAV file handles & dispose of the objects + delete inFile; + delete outFile; + delete params; + + printf("Done!\n"); + } + catch (runtime_error &e) + { + // An exception occurred during processing, display an error message + printf("%s\n", e.what()); + return -1; + } + + return 0; +} diff --git a/lib-src/soundtouch/source/example/bpm/BPMDetect.cpp b/lib-src/soundtouch/source/example/bpm/BPMDetect.cpp index 381594aa2..09a63d3b5 100644 --- a/lib-src/soundtouch/source/example/bpm/BPMDetect.cpp +++ b/lib-src/soundtouch/source/example/bpm/BPMDetect.cpp @@ -1,311 +1,311 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Beats-per-minute (BPM) detection routine. -/// -/// The beat detection algorithm works as follows: -/// - Use function 'inputSamples' to input a chunks of samples to the class for -/// analysis. It's a good idea to enter a large sound file or stream in smallish -/// chunks of around few kilosamples in order not to extinguish too much RAM memory. -/// - Inputted sound data is decimated to approx 500 Hz to reduce calculation burden, -/// which is basically ok as low (bass) frequencies mostly determine the beat rate. -/// Simple averaging is used for anti-alias filtering because the resulting signal -/// quality isn't of that high importance. -/// - Decimated sound data is enveloped, i.e. the amplitude shape is detected by -/// taking absolute value that's smoothed by sliding average. Signal levels that -/// are below a couple of times the general RMS amplitude level are cut away to -/// leave only notable peaks there. -/// - Repeating sound patterns (e.g. beats) are detected by calculating short-term -/// autocorrelation function of the enveloped signal. -/// - After whole sound data file has been analyzed as above, the bpm level is -/// detected by function 'getBpm' that finds the highest peak of the autocorrelation -/// function, calculates it's precise location and converts this reading to bpm's. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006-09-18 07:31:48 $ -// File revision : $Revision: 1.2 $ -// -// $Id: BPMDetect.cpp,v 1.2 2006-09-18 07:31:48 richardash1981 Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include "FIFOSampleBuffer.h" -#include "PeakFinder.h" -#include "BPMDetect.h" - -using namespace soundtouch; - -#define INPUT_BLOCK_SAMPLES 2048 -#define DECIMATED_BLOCK_SAMPLES 256 - -typedef unsigned short ushort; - -/// decay constant for calculating RMS volume sliding average approximation -/// (time constant is about 10 sec) -const float avgdecay = 0.99986f; - -/// Normalization coefficient for calculating RMS sliding average approximation. -const float avgnorm = (1 - avgdecay); - - - -BPMDetect::BPMDetect(int numChannels, int sampleRate) -{ - xcorr = NULL; - - buffer = new FIFOSampleBuffer(); - - decimateSum = 0; - decimateCount = 0; - decimateBy = 0; - - this->sampleRate = sampleRate; - this->channels = numChannels; - - envelopeAccu = 0; - - // Initialize RMS volume accumulator to RMS level of 3000 (out of 32768) that's - // a typical RMS signal level value for song data. This value is then adapted - // to the actual level during processing. -#ifdef INTEGER_SAMPLES - // integer samples - RMSVolumeAccu = (3000 * 3000) / avgnorm; -#else - // float samples, scaled to range [-1..+1[ - RMSVolumeAccu = (0.092f * 0.092f) / avgnorm; -#endif - - init(numChannels, sampleRate); -} - - - -BPMDetect::~BPMDetect() -{ - delete[] xcorr; - delete buffer; -} - - -/// low-pass filter & decimate to about 500 Hz. return number of outputted samples. -/// -/// Decimation is used to remove the unnecessary frequencies and thus to reduce -/// the amount of data needed to be processed as calculating autocorrelation -/// function is a very-very heavy operation. -/// -/// Anti-alias filtering is done simply by averaging the samples. This is really a -/// poor-man's anti-alias filtering, but it's not so critical in this kind of application -/// (it'd also be difficult to design a high-quality filter with steep cut-off at very -/// narrow band) -int BPMDetect::decimate(SAMPLETYPE *dest, const SAMPLETYPE *src, int numsamples) -{ - int count, outcount; - LONG_SAMPLETYPE out; - - assert(decimateBy != 0); - outcount = 0; - for (count = 0; count < numsamples; count ++) - { - decimateSum += src[count]; - - decimateCount ++; - if (decimateCount >= decimateBy) - { - // Store every Nth sample only - out = (LONG_SAMPLETYPE)(decimateSum / decimateBy); - decimateSum = 0; - decimateCount = 0; -#ifdef INTEGER_SAMPLES - // check ranges for sure (shouldn't actually be necessary) - if (out > 32767) - { - out = 32767; - } - else if (out < -32768) - { - out = -32768; - } -#endif // INTEGER_SAMPLES - dest[outcount] = (SAMPLETYPE)out; - outcount ++; - } - } - return outcount; -} - - - -// Calculates autocorrelation function of the sample history buffer -void BPMDetect::updateXCorr(int process_samples) -{ - int offs; - SAMPLETYPE *pBuffer; - - assert(buffer->numSamples() >= (uint)(process_samples + windowLen)); - - pBuffer = buffer->ptrBegin(); - for (offs = windowStart; offs < windowLen; offs ++) - { - LONG_SAMPLETYPE sum; - int i; - - sum = 0; - for (i = 0; i < process_samples; i ++) - { - sum += pBuffer[i] * pBuffer[i + offs]; // scaling the sub-result shouldn't be necessary - } -// xcorr[offs] *= xcorr_decay; // decay 'xcorr' here with suitable coefficients - // if it's desired that the system adapts automatically to - // various bpms, e.g. in processing continouos music stream. - // The 'xcorr_decay' should be a value that's smaller than but - // close to one, and should also depend on 'process_samples' value. - - xcorr[offs] += (float)sum; - } -} - - - -// Calculates envelope of the sample data -void BPMDetect::calcEnvelope(SAMPLETYPE *samples, int numsamples) -{ - const float decay = 0.7f; // decay constant for smoothing the envelope - const float norm = (1 - decay); - - int i; - LONG_SAMPLETYPE out; - float val; - - for (i = 0; i < numsamples; i ++) - { - // calc average RMS volume - RMSVolumeAccu *= avgdecay; - val = (float)fabs((float)samples[i]); - RMSVolumeAccu += val * val; - - // cut amplitudes that are below 2 times average RMS volume - // (we're interested in peak values, not the silent moments) - val -= 2 * (float)sqrt(RMSVolumeAccu * avgnorm); - val = (val > 0) ? val : 0; - - // smooth amplitude envelope - envelopeAccu *= decay; - envelopeAccu += val; - out = (LONG_SAMPLETYPE)(envelopeAccu * norm); - -#ifdef INTEGER_SAMPLES - // cut peaks (shouldn't be necessary though) - if (out > 32767) out = 32767; -#endif // INTEGER_SAMPLES - samples[i] = (SAMPLETYPE)out; - } -} - - - -void BPMDetect::inputSamples(SAMPLETYPE *samples, int numSamples) -{ - SAMPLETYPE decimated[DECIMATED_BLOCK_SAMPLES]; - - // convert from stereo to mono if necessary - if (channels == 2) - { - int i; - - for (i = 0; i < numSamples; i ++) - { - samples[i] = (samples[i * 2] + samples[i * 2 + 1]) / 2; - } - } - - // decimate - numSamples = decimate(decimated, samples, numSamples); - - // envelope new samples and add them to buffer - calcEnvelope(decimated, numSamples); - buffer->putSamples(decimated, numSamples); - - // when the buffer has enought samples for processing... - if ((int)buffer->numSamples() > windowLen) - { - int processLength; - - // how many samples are processed - processLength = buffer->numSamples() - windowLen; - - // ... calculate autocorrelations for oldest samples... - updateXCorr(processLength); - // ... and remove them from the buffer - buffer->receiveSamples(processLength); - } -} - - -void BPMDetect::init(int numChannels, int sampleRate) -{ - this->sampleRate = sampleRate; - - // choose decimation factor so that result is approx. 500 Hz - decimateBy = sampleRate / 500; - assert(decimateBy > 0); - assert(INPUT_BLOCK_SAMPLES < decimateBy * DECIMATED_BLOCK_SAMPLES); - - // Calculate window length & starting item according to desired min & max bpms - windowLen = (60 * sampleRate) / (decimateBy * MIN_BPM); - windowStart = (60 * sampleRate) / (decimateBy * MAX_BPM); - - assert(windowLen > windowStart); - - // allocate new working objects - xcorr = new float[windowLen]; - memset(xcorr, 0, windowLen * sizeof(float)); - - // we do processing in mono mode - buffer->setChannels(1); - buffer->clear(); -} - - - -float BPMDetect::getBpm() -{ - float peakPos; - PeakFinder peakFinder; - - // find peak position - peakPos = peakFinder.detectPeak(xcorr, windowStart, windowLen); - - assert(decimateBy != 0); - if (peakPos < 1e-6) return 0.0; // detection failed. - - // calculate BPM - return 60.0f * (((float)sampleRate / (float)decimateBy) / peakPos); -} +//////////////////////////////////////////////////////////////////////////////// +/// +/// Beats-per-minute (BPM) detection routine. +/// +/// The beat detection algorithm works as follows: +/// - Use function 'inputSamples' to input a chunks of samples to the class for +/// analysis. It's a good idea to enter a large sound file or stream in smallish +/// chunks of around few kilosamples in order not to extinguish too much RAM memory. +/// - Inputted sound data is decimated to approx 500 Hz to reduce calculation burden, +/// which is basically ok as low (bass) frequencies mostly determine the beat rate. +/// Simple averaging is used for anti-alias filtering because the resulting signal +/// quality isn't of that high importance. +/// - Decimated sound data is enveloped, i.e. the amplitude shape is detected by +/// taking absolute value that's smoothed by sliding average. Signal levels that +/// are below a couple of times the general RMS amplitude level are cut away to +/// leave only notable peaks there. +/// - Repeating sound patterns (e.g. beats) are detected by calculating short-term +/// autocorrelation function of the enveloped signal. +/// - After whole sound data file has been analyzed as above, the bpm level is +/// detected by function 'getBpm' that finds the highest peak of the autocorrelation +/// function, calculates it's precise location and converts this reading to bpm's. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006-09-18 07:31:48 $ +// File revision : $Revision: 1.2 $ +// +// $Id: BPMDetect.cpp,v 1.2 2006-09-18 07:31:48 richardash1981 Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include "FIFOSampleBuffer.h" +#include "PeakFinder.h" +#include "BPMDetect.h" + +using namespace soundtouch; + +#define INPUT_BLOCK_SAMPLES 2048 +#define DECIMATED_BLOCK_SAMPLES 256 + +typedef unsigned short ushort; + +/// decay constant for calculating RMS volume sliding average approximation +/// (time constant is about 10 sec) +const float avgdecay = 0.99986f; + +/// Normalization coefficient for calculating RMS sliding average approximation. +const float avgnorm = (1 - avgdecay); + + + +BPMDetect::BPMDetect(int numChannels, int sampleRate) +{ + xcorr = NULL; + + buffer = new FIFOSampleBuffer(); + + decimateSum = 0; + decimateCount = 0; + decimateBy = 0; + + this->sampleRate = sampleRate; + this->channels = numChannels; + + envelopeAccu = 0; + + // Initialize RMS volume accumulator to RMS level of 3000 (out of 32768) that's + // a typical RMS signal level value for song data. This value is then adapted + // to the actual level during processing. +#ifdef INTEGER_SAMPLES + // integer samples + RMSVolumeAccu = (3000 * 3000) / avgnorm; +#else + // float samples, scaled to range [-1..+1[ + RMSVolumeAccu = (0.092f * 0.092f) / avgnorm; +#endif + + init(numChannels, sampleRate); +} + + + +BPMDetect::~BPMDetect() +{ + delete[] xcorr; + delete buffer; +} + + +/// low-pass filter & decimate to about 500 Hz. return number of outputted samples. +/// +/// Decimation is used to remove the unnecessary frequencies and thus to reduce +/// the amount of data needed to be processed as calculating autocorrelation +/// function is a very-very heavy operation. +/// +/// Anti-alias filtering is done simply by averaging the samples. This is really a +/// poor-man's anti-alias filtering, but it's not so critical in this kind of application +/// (it'd also be difficult to design a high-quality filter with steep cut-off at very +/// narrow band) +int BPMDetect::decimate(SAMPLETYPE *dest, const SAMPLETYPE *src, int numsamples) +{ + int count, outcount; + LONG_SAMPLETYPE out; + + assert(decimateBy != 0); + outcount = 0; + for (count = 0; count < numsamples; count ++) + { + decimateSum += src[count]; + + decimateCount ++; + if (decimateCount >= decimateBy) + { + // Store every Nth sample only + out = (LONG_SAMPLETYPE)(decimateSum / decimateBy); + decimateSum = 0; + decimateCount = 0; +#ifdef INTEGER_SAMPLES + // check ranges for sure (shouldn't actually be necessary) + if (out > 32767) + { + out = 32767; + } + else if (out < -32768) + { + out = -32768; + } +#endif // INTEGER_SAMPLES + dest[outcount] = (SAMPLETYPE)out; + outcount ++; + } + } + return outcount; +} + + + +// Calculates autocorrelation function of the sample history buffer +void BPMDetect::updateXCorr(int process_samples) +{ + int offs; + SAMPLETYPE *pBuffer; + + assert(buffer->numSamples() >= (uint)(process_samples + windowLen)); + + pBuffer = buffer->ptrBegin(); + for (offs = windowStart; offs < windowLen; offs ++) + { + LONG_SAMPLETYPE sum; + int i; + + sum = 0; + for (i = 0; i < process_samples; i ++) + { + sum += pBuffer[i] * pBuffer[i + offs]; // scaling the sub-result shouldn't be necessary + } +// xcorr[offs] *= xcorr_decay; // decay 'xcorr' here with suitable coefficients + // if it's desired that the system adapts automatically to + // various bpms, e.g. in processing continouos music stream. + // The 'xcorr_decay' should be a value that's smaller than but + // close to one, and should also depend on 'process_samples' value. + + xcorr[offs] += (float)sum; + } +} + + + +// Calculates envelope of the sample data +void BPMDetect::calcEnvelope(SAMPLETYPE *samples, int numsamples) +{ + const float decay = 0.7f; // decay constant for smoothing the envelope + const float norm = (1 - decay); + + int i; + LONG_SAMPLETYPE out; + float val; + + for (i = 0; i < numsamples; i ++) + { + // calc average RMS volume + RMSVolumeAccu *= avgdecay; + val = (float)fabs((float)samples[i]); + RMSVolumeAccu += val * val; + + // cut amplitudes that are below 2 times average RMS volume + // (we're interested in peak values, not the silent moments) + val -= 2 * (float)sqrt(RMSVolumeAccu * avgnorm); + val = (val > 0) ? val : 0; + + // smooth amplitude envelope + envelopeAccu *= decay; + envelopeAccu += val; + out = (LONG_SAMPLETYPE)(envelopeAccu * norm); + +#ifdef INTEGER_SAMPLES + // cut peaks (shouldn't be necessary though) + if (out > 32767) out = 32767; +#endif // INTEGER_SAMPLES + samples[i] = (SAMPLETYPE)out; + } +} + + + +void BPMDetect::inputSamples(SAMPLETYPE *samples, int numSamples) +{ + SAMPLETYPE decimated[DECIMATED_BLOCK_SAMPLES]; + + // convert from stereo to mono if necessary + if (channels == 2) + { + int i; + + for (i = 0; i < numSamples; i ++) + { + samples[i] = (samples[i * 2] + samples[i * 2 + 1]) / 2; + } + } + + // decimate + numSamples = decimate(decimated, samples, numSamples); + + // envelope new samples and add them to buffer + calcEnvelope(decimated, numSamples); + buffer->putSamples(decimated, numSamples); + + // when the buffer has enought samples for processing... + if ((int)buffer->numSamples() > windowLen) + { + int processLength; + + // how many samples are processed + processLength = buffer->numSamples() - windowLen; + + // ... calculate autocorrelations for oldest samples... + updateXCorr(processLength); + // ... and remove them from the buffer + buffer->receiveSamples(processLength); + } +} + + +void BPMDetect::init(int numChannels, int sampleRate) +{ + this->sampleRate = sampleRate; + + // choose decimation factor so that result is approx. 500 Hz + decimateBy = sampleRate / 500; + assert(decimateBy > 0); + assert(INPUT_BLOCK_SAMPLES < decimateBy * DECIMATED_BLOCK_SAMPLES); + + // Calculate window length & starting item according to desired min & max bpms + windowLen = (60 * sampleRate) / (decimateBy * MIN_BPM); + windowStart = (60 * sampleRate) / (decimateBy * MAX_BPM); + + assert(windowLen > windowStart); + + // allocate new working objects + xcorr = new float[windowLen]; + memset(xcorr, 0, windowLen * sizeof(float)); + + // we do processing in mono mode + buffer->setChannels(1); + buffer->clear(); +} + + + +float BPMDetect::getBpm() +{ + float peakPos; + PeakFinder peakFinder; + + // find peak position + peakPos = peakFinder.detectPeak(xcorr, windowStart, windowLen); + + assert(decimateBy != 0); + if (peakPos < 1e-6) return 0.0; // detection failed. + + // calculate BPM + return 60.0f * (((float)sampleRate / (float)decimateBy) / peakPos); +} diff --git a/lib-src/soundtouch/source/example/bpm/PeakFinder.cpp b/lib-src/soundtouch/source/example/bpm/PeakFinder.cpp index 3be9a4e3f..2ef6c236d 100644 --- a/lib-src/soundtouch/source/example/bpm/PeakFinder.cpp +++ b/lib-src/soundtouch/source/example/bpm/PeakFinder.cpp @@ -1,191 +1,191 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Peak detection routine. -/// -/// The routine detects highest value on an array of values and calculates the -/// precise peak location as a mass-center of the 'hump' around the peak value. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006-09-18 07:31:48 $ -// File revision : $Revision: 1.2 $ -// -// $Id: PeakFinder.cpp,v 1.2 2006-09-18 07:31:48 richardash1981 Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#include -#include - -#include "PeakFinder.h" - - -PeakFinder::PeakFinder() -{ -} - - -// Finds 'ground level' of a peak hump by starting from 'peakpos' and proceeding -// to direction defined by 'direction' until next 'hump' after minimum value will -// begin -int PeakFinder::findGround(const float *data, int peakpos, int direction) const -{ - float refvalue; - int lowpos; - int pos; - int climb_count; - float delta; - - climb_count = 0; - refvalue = data[peakpos]; - lowpos = peakpos; - - pos = peakpos; - - while ((pos > minPos) && (pos < maxPos)) - { - int prevpos; - - prevpos = pos; - pos += direction; - - // calculate derivate - delta = data[pos] - data[prevpos]; - if (delta <= 0) - { - // going downhill, ok - if (climb_count) - { - climb_count --; // decrease climb count - } - - // check if new minimum found - if (data[pos] < refvalue) - { - // new minimum found - lowpos = pos; - refvalue = data[pos]; - } - } - else - { - // going uphill, increase climbing counter - climb_count ++; - if (climb_count > 5) break; // we've been climbing too long => it's next uphill => quit - } - } - return lowpos; -} - - -// Find offset where the value crosses the given level, when starting from 'peakpos' and -// proceeds to direction defined in 'direction' -int PeakFinder::findCrossingLevel(const float *data, float level, int peakpos, int direction) const -{ - float peaklevel; - int pos; - - peaklevel = data[peakpos]; - assert(peaklevel >= level); - pos = peakpos; - while ((pos >= minPos) && (pos < maxPos)) - { - if (data[pos + direction] < level) return pos; // crossing found - pos += direction; - } - return -1; // not found -} - - -// Calculates the center of mass location of 'data' array items between 'firstPos' and 'lastPos' -float PeakFinder::calcMassCenter(const float *data, int firstPos, int lastPos) const -{ - int i; - float sum; - float wsum; - - sum = 0; - wsum = 0; - for (i = firstPos; i <= lastPos; i ++) - { - sum += (float)i * data[i]; - wsum += data[i]; - } - return sum / wsum; -} - - -float PeakFinder::detectPeak(const float *data, int minPos, int maxPos) -{ - #define max(x, y) (((x) > (y)) ? (x) : (y)) - - int i; - int peakpos; // position of peak level - float peakLevel; // peak level - int crosspos1, crosspos2; // position where the peak 'hump' crosses cutting level - float cutLevel; // cutting value - float groundLevel; // ground level of the peak - int gp1, gp2; // bottom positions of the peak 'hump' - - this->minPos = minPos; - this->maxPos = maxPos; - - // find absolute peak - peakpos = minPos; - peakLevel = data[minPos]; - for (i = minPos + 1; i < maxPos; i ++) - { - if (data[i] > peakLevel) - { - peakLevel = data[i]; - peakpos = i; - } - } - - // find ground positions. - gp1 = findGround(data, peakpos, -1); - gp2 = findGround(data, peakpos, 1); - - groundLevel = max(data[gp1], data[gp2]); - - if (groundLevel < 1e-6) return 0; // ground level too small => detection failed - if ((peakLevel / groundLevel) < 1.3) return 0; // peak less than 30% of the ground level => no good peak detected - - // calculate 70%-level of the peak - cutLevel = 0.70f * peakLevel + 0.30f * groundLevel; - // find mid-level crossings - crosspos1 = findCrossingLevel(data, cutLevel, peakpos, -1); - crosspos2 = findCrossingLevel(data, cutLevel, peakpos, 1); - - if ((crosspos1 < 0) || (crosspos2 < 0)) return 0; // no crossing, no peak.. - - // calculate mass center of the peak surroundings - return calcMassCenter(data, crosspos1, crosspos2); -} - - +//////////////////////////////////////////////////////////////////////////////// +/// +/// Peak detection routine. +/// +/// The routine detects highest value on an array of values and calculates the +/// precise peak location as a mass-center of the 'hump' around the peak value. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006-09-18 07:31:48 $ +// File revision : $Revision: 1.2 $ +// +// $Id: PeakFinder.cpp,v 1.2 2006-09-18 07:31:48 richardash1981 Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include + +#include "PeakFinder.h" + + +PeakFinder::PeakFinder() +{ +} + + +// Finds 'ground level' of a peak hump by starting from 'peakpos' and proceeding +// to direction defined by 'direction' until next 'hump' after minimum value will +// begin +int PeakFinder::findGround(const float *data, int peakpos, int direction) const +{ + float refvalue; + int lowpos; + int pos; + int climb_count; + float delta; + + climb_count = 0; + refvalue = data[peakpos]; + lowpos = peakpos; + + pos = peakpos; + + while ((pos > minPos) && (pos < maxPos)) + { + int prevpos; + + prevpos = pos; + pos += direction; + + // calculate derivate + delta = data[pos] - data[prevpos]; + if (delta <= 0) + { + // going downhill, ok + if (climb_count) + { + climb_count --; // decrease climb count + } + + // check if new minimum found + if (data[pos] < refvalue) + { + // new minimum found + lowpos = pos; + refvalue = data[pos]; + } + } + else + { + // going uphill, increase climbing counter + climb_count ++; + if (climb_count > 5) break; // we've been climbing too long => it's next uphill => quit + } + } + return lowpos; +} + + +// Find offset where the value crosses the given level, when starting from 'peakpos' and +// proceeds to direction defined in 'direction' +int PeakFinder::findCrossingLevel(const float *data, float level, int peakpos, int direction) const +{ + float peaklevel; + int pos; + + peaklevel = data[peakpos]; + assert(peaklevel >= level); + pos = peakpos; + while ((pos >= minPos) && (pos < maxPos)) + { + if (data[pos + direction] < level) return pos; // crossing found + pos += direction; + } + return -1; // not found +} + + +// Calculates the center of mass location of 'data' array items between 'firstPos' and 'lastPos' +float PeakFinder::calcMassCenter(const float *data, int firstPos, int lastPos) const +{ + int i; + float sum; + float wsum; + + sum = 0; + wsum = 0; + for (i = firstPos; i <= lastPos; i ++) + { + sum += (float)i * data[i]; + wsum += data[i]; + } + return sum / wsum; +} + + +float PeakFinder::detectPeak(const float *data, int minPos, int maxPos) +{ + #define max(x, y) (((x) > (y)) ? (x) : (y)) + + int i; + int peakpos; // position of peak level + float peakLevel; // peak level + int crosspos1, crosspos2; // position where the peak 'hump' crosses cutting level + float cutLevel; // cutting value + float groundLevel; // ground level of the peak + int gp1, gp2; // bottom positions of the peak 'hump' + + this->minPos = minPos; + this->maxPos = maxPos; + + // find absolute peak + peakpos = minPos; + peakLevel = data[minPos]; + for (i = minPos + 1; i < maxPos; i ++) + { + if (data[i] > peakLevel) + { + peakLevel = data[i]; + peakpos = i; + } + } + + // find ground positions. + gp1 = findGround(data, peakpos, -1); + gp2 = findGround(data, peakpos, 1); + + groundLevel = max(data[gp1], data[gp2]); + + if (groundLevel < 1e-6) return 0; // ground level too small => detection failed + if ((peakLevel / groundLevel) < 1.3) return 0; // peak less than 30% of the ground level => no good peak detected + + // calculate 70%-level of the peak + cutLevel = 0.70f * peakLevel + 0.30f * groundLevel; + // find mid-level crossings + crosspos1 = findCrossingLevel(data, cutLevel, peakpos, -1); + crosspos2 = findCrossingLevel(data, cutLevel, peakpos, 1); + + if ((crosspos1 < 0) || (crosspos2 < 0)) return 0; // no crossing, no peak.. + + // calculate mass center of the peak surroundings + return calcMassCenter(data, crosspos1, crosspos2); +} + + diff --git a/lib-src/soundtouch/source/example/bpm/PeakFinder.h b/lib-src/soundtouch/source/example/bpm/PeakFinder.h index 3c465d4a4..7ae8edcfe 100644 --- a/lib-src/soundtouch/source/example/bpm/PeakFinder.h +++ b/lib-src/soundtouch/source/example/bpm/PeakFinder.h @@ -1,85 +1,85 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// The routine detects highest value on an array of values and calculates the -/// precise peak location as a mass-center of the 'hump' around the peak value. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// Last changed : $Date: 2006-09-18 07:31:49 $ -// File revision : $Revision: 1.2 $ -// -// $Id: PeakFinder.h,v 1.2 2006-09-18 07:31:49 richardash1981 Exp $ -// -//////////////////////////////////////////////////////////////////////////////// -// -// License : -// -// SoundTouch audio processing library -// Copyright (c) Olli Parviainen -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library 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 -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef _PeakFinder_H_ -#define _PeakFinder_H_ - -class PeakFinder -{ -protected: - /// Min, max allowed peak positions within the data vector - int minPos, maxPos; - - /// Calculates the mass center between given vector items. - float calcMassCenter(const float *data, ///< Data vector. - int firstPos, ///< Index of first vector item beloging to the peak. - int lastPos ///< Index of last vector item beloging to the peak. - ) const; - - /// Finds the data vector index where the monotoniously decreasing signal crosses the - /// given level. - int findCrossingLevel(const float *data, ///< Data vector. - float level, ///< Goal crossing level. - int peakpos, ///< Peak position index within the data vector. - int direction /// Direction where to proceed from the peak: 1 = right, -1 = left. - ) const; - - /// Finds the 'ground' level, i.e. smallest level between two neighbouring peaks, to right- - /// or left-hand side of the given peak position. - int findGround(const float *data, /// Data vector. - int peakpos, /// Peak position index within the data vector. - int direction /// Direction where to proceed from the peak: 1 = right, -1 = left. - ) const; - -public: - /// Constructor. - PeakFinder(); - - /// Detect exact peak position of the data vector by finding the largest peak 'hump' - /// and calculating the mass-center location of the peak hump. - /// - /// \return The exact mass-center location of the largest peak hump. - float detectPeak(const float *data, /// Data vector to be analyzed. The data vector has - /// to be at least 'maxPos' items long. - int minPos, ///< Min allowed peak location within the vector data. - int maxPos ///< Max allowed peak location within the vector data. - ); -}; - -#endif // _PeakFinder_H_ +//////////////////////////////////////////////////////////////////////////////// +/// +/// The routine detects highest value on an array of values and calculates the +/// precise peak location as a mass-center of the 'hump' around the peak value. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006-09-18 07:31:49 $ +// File revision : $Revision: 1.2 $ +// +// $Id: PeakFinder.h,v 1.2 2006-09-18 07:31:49 richardash1981 Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef _PeakFinder_H_ +#define _PeakFinder_H_ + +class PeakFinder +{ +protected: + /// Min, max allowed peak positions within the data vector + int minPos, maxPos; + + /// Calculates the mass center between given vector items. + float calcMassCenter(const float *data, ///< Data vector. + int firstPos, ///< Index of first vector item beloging to the peak. + int lastPos ///< Index of last vector item beloging to the peak. + ) const; + + /// Finds the data vector index where the monotoniously decreasing signal crosses the + /// given level. + int findCrossingLevel(const float *data, ///< Data vector. + float level, ///< Goal crossing level. + int peakpos, ///< Peak position index within the data vector. + int direction /// Direction where to proceed from the peak: 1 = right, -1 = left. + ) const; + + /// Finds the 'ground' level, i.e. smallest level between two neighbouring peaks, to right- + /// or left-hand side of the given peak position. + int findGround(const float *data, /// Data vector. + int peakpos, /// Peak position index within the data vector. + int direction /// Direction where to proceed from the peak: 1 = right, -1 = left. + ) const; + +public: + /// Constructor. + PeakFinder(); + + /// Detect exact peak position of the data vector by finding the largest peak 'hump' + /// and calculating the mass-center location of the peak hump. + /// + /// \return The exact mass-center location of the largest peak hump. + float detectPeak(const float *data, /// Data vector to be analyzed. The data vector has + /// to be at least 'maxPos' items long. + int minPos, ///< Min allowed peak location within the vector data. + int maxPos ///< Max allowed peak location within the vector data. + ); +}; + +#endif // _PeakFinder_H_ diff --git a/lib-src/twolame/doc/html/api.html b/lib-src/twolame/doc/html/api.html index 082edd47a..7d4500629 100644 --- a/lib-src/twolame/doc/html/api.html +++ b/lib-src/twolame/doc/html/api.html @@ -1,151 +1,151 @@ - - - - - - - -The libtwolame API - - - -
    -
    -

    This is the interface for encoding PCM audio to MPEG Audio Layer 2.

    -

    It is very similar to the libmp3lame API.

    -

    See simplefrontend/simplefrontend.c for a very simple application -using the API.

    -
    -
    -

    Steps to encode PCM to MP2

    -
    -
      -
    1. -

      -Grab a set of default options by calling: -

      -
      -
      -
      twolame_options *encodeOptions;
      -encodeOptions = twolame_init();
      -
      -
    2. -
    3. -

      -Adjust those options to suit your requirements. - See twolame.h for a full list of options. eg. -

      -
      -
      -
      twolame_set_out_samplerate(encodeOptions, 32000);
      -twolame_set_bitrate(encodeOptions, 160);
      -
      -
    4. -
    5. -

      -Initialise twolame library with these options by calling: -

      -
      -
      -
      twolame_init_params(encodeOptions);
      -
      -
      -
      -
      NOTE: The return value should be checked to see if the options were valid.
      -Currently only ever returns 0
      -
      -
    6. -
    7. -

      -Encode PCM audio to MP2 by calling: -

      -
      -
      -
      int twolame_encode_buffer(
      - twolame_options *glopts,   // the set of options you're using
      - const short int leftpcm[], // the left and right audio channels
      - const short int rightpcm[],
      - int num_samples,           // the number of samples in each channel
      - unsigned char *mp2buffer,  // a pointer to a buffer for the MP2 audio data
      -                            // NB User must allocate space!
      - int mp2buffer_size);       // The size of the mp2buffer that the user allocated
      - int *mp2fill_size);
      -
      -
      -
      -
      This function returns the number of bytes written into mp2buffer by the library MPEG.
      -One frame of MPEG audio will be returned for every 1152 samples of PCM audio.
      -Multiple calls can be made to this function.
      -It is the users responsibility to:
      -
      -
        -
      • -

        -allocate the mp2buffer -

        -
      • -
      • -

        -read the pcmaudio from somewhere with new samples always staring from - the beginning of the buffer -

        -
      • -
      • -

        -write the mp2buffer contents to somewhere (it is overwritten with each call) -

        -
      • -
      -
    8. -
    9. -

      -Flush the encoder by calling: -

      -
      -
      -
      int twolame_encode_flush(
      -    twolame_options *glopts,
      -    unsigned char *mp2buffer,
      -    int mp2buffer_size);
      -
      -
      -
      -
      When encoding is finished, unless there was exactly a multiple of 1152 samples/channel
      -sent to the encoder, there will be some remaining audio that is not encoded. This function
      -encodes this last bit of audio by padding out with zeros until there is 1152 samples per channel
      -in the PCM audio buffers and then encoding this.
      -
      -
      -
      -
      This function returns the number of bytes written into mp2buffer by the library MPEG.
      -
      -
    10. -
    11. -

      -The user must "de-initialise" the encoder at the end by calling: -

      -
      -
      -
      void twolame_close(twolame_options **glopts);
      -
      -
      -
      -
      This function must be called to free all the memory and structures
      -associated with this set of encoding parameters.
      -POST: glopts = NULL
      -
      -
    12. -
    -
    - - - + + + + + + + +The libtwolame API + + + +
    +
    +

    This is the interface for encoding PCM audio to MPEG Audio Layer 2.

    +

    It is very similar to the libmp3lame API.

    +

    See simplefrontend/simplefrontend.c for a very simple application +using the API.

    +
    +
    +

    Steps to encode PCM to MP2

    +
    +
      +
    1. +

      +Grab a set of default options by calling: +

      +
      +
      +
      twolame_options *encodeOptions;
      +encodeOptions = twolame_init();
      +
      +
    2. +
    3. +

      +Adjust those options to suit your requirements. + See twolame.h for a full list of options. eg. +

      +
      +
      +
      twolame_set_out_samplerate(encodeOptions, 32000);
      +twolame_set_bitrate(encodeOptions, 160);
      +
      +
    4. +
    5. +

      +Initialise twolame library with these options by calling: +

      +
      +
      +
      twolame_init_params(encodeOptions);
      +
      +
      +
      +
      NOTE: The return value should be checked to see if the options were valid.
      +Currently only ever returns 0
      +
      +
    6. +
    7. +

      +Encode PCM audio to MP2 by calling: +

      +
      +
      +
      int twolame_encode_buffer(
      + twolame_options *glopts,   // the set of options you're using
      + const short int leftpcm[], // the left and right audio channels
      + const short int rightpcm[],
      + int num_samples,           // the number of samples in each channel
      + unsigned char *mp2buffer,  // a pointer to a buffer for the MP2 audio data
      +                            // NB User must allocate space!
      + int mp2buffer_size);       // The size of the mp2buffer that the user allocated
      + int *mp2fill_size);
      +
      +
      +
      +
      This function returns the number of bytes written into mp2buffer by the library MPEG.
      +One frame of MPEG audio will be returned for every 1152 samples of PCM audio.
      +Multiple calls can be made to this function.
      +It is the users responsibility to:
      +
      +
        +
      • +

        +allocate the mp2buffer +

        +
      • +
      • +

        +read the pcmaudio from somewhere with new samples always staring from + the beginning of the buffer +

        +
      • +
      • +

        +write the mp2buffer contents to somewhere (it is overwritten with each call) +

        +
      • +
      +
    8. +
    9. +

      +Flush the encoder by calling: +

      +
      +
      +
      int twolame_encode_flush(
      +    twolame_options *glopts,
      +    unsigned char *mp2buffer,
      +    int mp2buffer_size);
      +
      +
      +
      +
      When encoding is finished, unless there was exactly a multiple of 1152 samples/channel
      +sent to the encoder, there will be some remaining audio that is not encoded. This function
      +encodes this last bit of audio by padding out with zeros until there is 1152 samples per channel
      +in the PCM audio buffers and then encoding this.
      +
      +
      +
      +
      This function returns the number of bytes written into mp2buffer by the library MPEG.
      +
      +
    10. +
    11. +

      +The user must "de-initialise" the encoder at the end by calling: +

      +
      +
      +
      void twolame_close(twolame_options **glopts);
      +
      +
      +
      +
      This function must be called to free all the memory and structures
      +associated with this set of encoding parameters.
      +POST: glopts = NULL
      +
      +
    12. +
    +
    + + + diff --git a/lib-src/twolame/doc/html/authors.html b/lib-src/twolame/doc/html/authors.html index bc67f624d..e3ef0e84f 100644 --- a/lib-src/twolame/doc/html/authors.html +++ b/lib-src/twolame/doc/html/authors.html @@ -1,182 +1,182 @@ - - - - - - - -TwoLAME Authors - - - -
    -
    -
    Nicholas Humfrey - <njh at ecs.soton.ac.uk>
      -
    • -

      -Current Maintainer -

      -
    • -
    • -

      -New automake build system -

      -
    • -
    • -

      -Added libsndfile support -

      -
    • -
    • -

      -Reference documentation for API -

      -
    • -
    • -

      -Lots of cleaning and improving ! -

      -
    • -
    • -

      -New frontend -

      -
    • -
    -
    Christophe Massiot - <cmassiot at freebox.fr>
      -
    • -

      -Changes to make libtwolame thread-safe -

      -
    • -
    -
    Mean - <mean@users.sourceforge.net>
      -
    • -

      -Fix for AMD64 processors -

      -
    • -
    • -

      -Fix for CRC protection -

      -
    • -
    -
    Mike Cheng <mikecheng at NOT planckenergy.com> (remove the NOT)
      -
    • -

      -Author of tooLAME, which TwoLAME is based on. -

      -
    • -
    -
    ISO Dist10 code writers
      -
    • -

      -original basis of toolame -

      -
    • -
    -
    LAME specific contributions
      -
    • -

      -fht routines from Ron Mayer <mayer at acuson.com> -

      -
    • -
    • -

      -fht tweaking by Mathew Hendry <math at vissci.com> -

      -
    • -
    • -

      -window_subband & filter subband from LAME circa v3.30 - (multiple LAME authors) - (before Takehiro's window/filter/mdct combination) -

      -
    • -
    -
    Oliver Lietz <lietz at nanocosmos.de>
      -
    • -

      -Tables now included in the exe! (yay! :) -

      -
    • -
    -
    Patrick de Smet <pds at telin.rug.ac.be>
      -
    • -

      -scale_factor calc speedup. -

      -
    • -
    • -

      -subband_quantization speedup -

      -
    • -
    -
    Bill Eldridge <bill at hk.rfa.org> and Federico Grau <grauf at rfa.org>
      -
    • -

      -option for "no padding" -

      -
    • -
    -
    Nick Burch <gagravarr at SoftHome.net>
      -
    • -

      -WAV file reading -

      -
    • -
    • -

      -os/2 Makefile mods. -

      -
    • -
    -
    Phillipe Jouguet <philippe.jouguet at vdldiffusion.com>
      -
    • -

      -DAB extensions -

      -
    • -
    • -

      -spelling, LSF using psyII, WAVE reading -

      -
    • -
    -
    Henrik Herranen - <leopold at vlsi.fi>
      -
    • -

      -WAVE reading -

      -
    • -
    -
    Andreas Neukoetter - <anti at webhome.de>
      -
    • -

      -verbosity patch -t switch for transcode plugin -

      -
    • -
    -
    Sami Sallinen - <sami.sallinen at g-cluster.com>
      -
    • -

      -filter subband loop unroll psychoi fix for "% 1408" calcs -

      -
    • -
    -
    -
    - - - + + + + + + + +TwoLAME Authors + + + +
    +
    +
    Nicholas Humfrey - <njh at ecs.soton.ac.uk>
      +
    • +

      +Current Maintainer +

      +
    • +
    • +

      +New automake build system +

      +
    • +
    • +

      +Added libsndfile support +

      +
    • +
    • +

      +Reference documentation for API +

      +
    • +
    • +

      +Lots of cleaning and improving ! +

      +
    • +
    • +

      +New frontend +

      +
    • +
    +
    Christophe Massiot - <cmassiot at freebox.fr>
      +
    • +

      +Changes to make libtwolame thread-safe +

      +
    • +
    +
    Mean - <mean@users.sourceforge.net>
      +
    • +

      +Fix for AMD64 processors +

      +
    • +
    • +

      +Fix for CRC protection +

      +
    • +
    +
    Mike Cheng <mikecheng at NOT planckenergy.com> (remove the NOT)
      +
    • +

      +Author of tooLAME, which TwoLAME is based on. +

      +
    • +
    +
    ISO Dist10 code writers
      +
    • +

      +original basis of toolame +

      +
    • +
    +
    LAME specific contributions
      +
    • +

      +fht routines from Ron Mayer <mayer at acuson.com> +

      +
    • +
    • +

      +fht tweaking by Mathew Hendry <math at vissci.com> +

      +
    • +
    • +

      +window_subband & filter subband from LAME circa v3.30 + (multiple LAME authors) + (before Takehiro's window/filter/mdct combination) +

      +
    • +
    +
    Oliver Lietz <lietz at nanocosmos.de>
      +
    • +

      +Tables now included in the exe! (yay! :) +

      +
    • +
    +
    Patrick de Smet <pds at telin.rug.ac.be>
      +
    • +

      +scale_factor calc speedup. +

      +
    • +
    • +

      +subband_quantization speedup +

      +
    • +
    +
    Bill Eldridge <bill at hk.rfa.org> and Federico Grau <grauf at rfa.org>
      +
    • +

      +option for "no padding" +

      +
    • +
    +
    Nick Burch <gagravarr at SoftHome.net>
      +
    • +

      +WAV file reading +

      +
    • +
    • +

      +os/2 Makefile mods. +

      +
    • +
    +
    Phillipe Jouguet <philippe.jouguet at vdldiffusion.com>
      +
    • +

      +DAB extensions +

      +
    • +
    • +

      +spelling, LSF using psyII, WAVE reading +

      +
    • +
    +
    Henrik Herranen - <leopold at vlsi.fi>
      +
    • +

      +WAVE reading +

      +
    • +
    +
    Andreas Neukoetter - <anti at webhome.de>
      +
    • +

      +verbosity patch -t switch for transcode plugin +

      +
    • +
    +
    Sami Sallinen - <sami.sallinen at g-cluster.com>
      +
    • +

      +filter subband loop unroll psychoi fix for "% 1408" calcs +

      +
    • +
    +
    +
    + + + diff --git a/lib-src/twolame/doc/html/changelog.html b/lib-src/twolame/doc/html/changelog.html index a0a833902..595653752 100644 --- a/lib-src/twolame/doc/html/changelog.html +++ b/lib-src/twolame/doc/html/changelog.html @@ -1,517 +1,517 @@ - - - - - - - -What is new in TwoLAME - - - -

    Version 0.3.11 (2007-07-02)

    -
    -
      -
    • -

      -Fixed energy levels bug for mono audio -

      -
        -
      • -

        -thanks to Staale Helleberg for patch -

        -
      • -
      -
    • -
    • -

      -Fixed inline for the forthcoming gcc-4.3 -

      -
        -
      • -

        -thanks to Martin Michlmayr for patch -

        -
      • -
      -
    • -
    • -

      -Fixed STDIN support in twolame frontend -

      -
    • -
    -
    -

    Version 0.3.10 (2007-03-20)

    -
    -
      -
    • -

      -Added win32/winutil.h to tarball - fixes bug #1629945 -

      -
    • -
    • -

      -Fixed presentation of —enable-debug in configure script -

      -
    • -
    • -

      -Added twolame_encode_buffer_float32_interleaved() -

      -
    • -
    • -

      -Fixed bug that was loosing stereo in twolame_encode_buffer_float32() -

      -
    • -
    • -

      -Fixed twolame_set_mode() to accept TWOLAME_AUTO_MODE -

      -
    • -
    • -

      -Added source file Ids to the top of every file -

      -
    • -
    • -

      -Added -pedantic to CFLAGS for debug build -

      -
    • -
    -
    -

    Version 0.3.9 (2006-12-31)

    -
    -
      -
    • -

      -Fix for Windows in simple frontend: open files in binary mode -

      -
        -
      • -

        -thanks to Kurien Mathew -

        -
      • -
      -
    • -
    • -

      -(libtwolame) Fixed energy level support -

      -
        -
      • -

        -thanks to Staale Helleberg -

        -
      • -
      -
    • -
    • -

      -Nows displays the version number of libsndfile in frontend -

      -
        -
      • -

        -as suggested by Elio Blanca -

        -
      • -
      -
    • -
    • -

      -Changed documentation build system, so you have to run it manually -

      -
    • -
    • -

      -Buffer overrun fix in new_extension() -

      -
    • -
    • -

      -(libtwolame) Added warning that DAB support is still broken -

      -
    • -
    • -

      -(libtwolame) Added twolame_get_framelength() to return number of bytes per frame -

      -
    • -
    • -

      -Added TWOLAME_SAMPLES_PER_FRAME macro, clarifying that there are - always 1152 samples per frame in Layer 2 -

      -
    • -
    • -

      -Frontend now displays extra information -

      -
        -
      • -

        -Duration of input file (if known) -

        -
      • -
      • -

        -Total number of frames to be encoded and percentage complete -

        -
      • -
      • -

        -The filesize of the output file -

        -
      • -
      -
    • -
    • -

      -Cleaned up source files so that it is consistent and all uses tabs (tab width 4) -

      -
    • -
    -
    -

    Version 0.3.8 (2006-06-19)

    -
    -
      -
    • -

      -(libtwolame) Fixed CRC protection -

      -
    • -
    • -

      -More code tidying -

      -
    • -
    • -

      -pkg-config is no-longer required (but is recommended) -

      -
    • -
    • -

      -frontend now has the exectuable suffix appended to filename -

      -
    • -
    • -

      -added -std=c99 to the compiler options -

      -
    • -
    -
    -

    Version 0.3.7 (2006-05-07)

    -
    -
      -
    • -

      -(libtwolame) Added twolame_encode_buffer_float32() function -

      -
    • -
    • -

      -(libtwolame) Fix NAN bug for AMD64 processors -

      -
    • -
    • -

      -Checks type sizes of short and float -

      -
    • -
    -
    -

    Version 0.3.6 (2006-12-25)

    -
    -
      -
    • -

      -Removed comma which was causing problems with -pedantic -

      -
        -
      • -

        -Thanks to Akos Maroy -

        -
      • -
      -
    • -
    • -

      -(libtwolame) Added libtool library versioning -

      -
    • -
    -
    -

    Version 0.3.5 (2005-11-29)

    -
    -
      -
    • -

      -(libtwolame) Added back twolame_get_VBR_q/twolame_set_VBR_q -

      -
    • -
    • -

      -More documentation is installed -

      -
    • -
    -
    -

    Version 0.3.4 (2005-11-19)

    -
    -
      -
    • -

      -(libtwolame) Checks parameters a bit better -

      -
    • -
    • -

      -(libtwolame) Removed lots of exit() calls -

      -
    • -
    • -

      -(libtwolame) added twolame_print_config() API call -

      -
    • -
    • -

      -(libtwolame) Fixed twolame.h so that it works with C++ code -

      -
    • -
    • -

      -Rewrote frontend and now (only) uses libsndfile -

      -
    • -
    • -

      -Changed behavior in frontend and backend for verbosity setting -

      -
    • -
    • -

      -Rewrote manpage for frontend -

      -
    • -
    • -

      -(libtwolame) Fixed bug with setting MPEG version -

      -
    • -
    • -

      -(libtwolame) Removed default samplerate - must choose one -

      -
    • -
    • -

      -(libtwolame) Original flag is now turned on by default -

      -
    • -
    • -

      -(libtwolame) Default bitrate is automatically chosen based on the samplerate/channels -

      -
    • -
    • -

      -(libtwolame) Default mode is automatically chosen based on the number of channels -

      -
    • -
    • -

      -Documentation improvements and corrections -

      -
    • -
    • -

      -(libtwolame) made some of VBR debugging send to stderr instead of stdout -

      -
    • -
    -
    -

    Version 0.3.3 (2005-04-19)

    -
    -
      -
    • -

      -Added Debian package description -

      -
    • -
    • -

      -Now installs documentation -

      -
    • -
    • -

      -Removed old unused tables.c and tables.h sources -

      -
    • -
    -
    -

    Version 0.3.2 (2005-04-10)

    -
    -
      -
    • -

      -Added scaling of input samples -

      -
    • -
    • -

      -Added downmixing/upmixing of samples -

      -
    • -
    • -

      -Applied patch from Christophe Massiot to make TwoLAME thread-safe -

      -
    • -
    -
    -

    Version 0.3.1 (2004-09-17)

    -
    -
      -
    • -

      -Frontend displays information about the input file format -

      -
    • -
    • -

      -Fixed bug with audio_get_samples reading more than buffer size -

      -
    • -
    • -

      -Added asciidoc documentation -

      -
    • -
    • -

      -Added doxygen documentation -

      -
    • -
    -
    -

    Version 0.3.0 (2004-09-14)

    -
    -
      -
    • -

      -Based on tooLAME 0.2m beta 8 -

      -
    • -
    • -

      -changed build system to use automake/libtool -

      -
    • -
    • -

      -now builds shared library -

      -
    • -
    • -

      -restructured lots of code -

      -
        -
      • -

        -Removed some dead code and unused files -

        -
      • -
      -
    • -
    • -

      -should now be close to being thread safe -

      -
    • -
    • -

      -removed memory leaks / static variables -

      -
    • -
    • -

      -changed library API so that it is almost the same as LAMEs -

      -
        -
      • -

        -hopefully not too many people have been using the old API -

        -
      • -
      • -

        -not too many big differences -

        -
      • -
      • -

        -will hopefully add resampling support to next release -

        -
      • -
      • -

        -API is ready for resampling support to be added -

        -
      • -
      • -

        -ready for downmixing to be added to libtoolame -

        -
      • -
      -
    • -
    • -

      -Added libsndfile support to toolame frontend (if you have it) -

      -
    • -
    • -

      -moved set/get functions into get_set.c -

      -
    • -
    • -

      -I have broken energy levels support (sorry !) - will try and fix -

      -
    • -
    • -

      -Added LGPL header to the top of all the files -

      -
    • -
    • -

      -Added toolame_encode_buffer_interleaved -

      -
    • -
    -
    - - - + + + + + + + +What is new in TwoLAME + + + +

    Version 0.3.11 (2007-07-02)

    +
    +
      +
    • +

      +Fixed energy levels bug for mono audio +

      +
        +
      • +

        +thanks to Staale Helleberg for patch +

        +
      • +
      +
    • +
    • +

      +Fixed inline for the forthcoming gcc-4.3 +

      +
        +
      • +

        +thanks to Martin Michlmayr for patch +

        +
      • +
      +
    • +
    • +

      +Fixed STDIN support in twolame frontend +

      +
    • +
    +
    +

    Version 0.3.10 (2007-03-20)

    +
    +
      +
    • +

      +Added win32/winutil.h to tarball - fixes bug #1629945 +

      +
    • +
    • +

      +Fixed presentation of —enable-debug in configure script +

      +
    • +
    • +

      +Added twolame_encode_buffer_float32_interleaved() +

      +
    • +
    • +

      +Fixed bug that was loosing stereo in twolame_encode_buffer_float32() +

      +
    • +
    • +

      +Fixed twolame_set_mode() to accept TWOLAME_AUTO_MODE +

      +
    • +
    • +

      +Added source file Ids to the top of every file +

      +
    • +
    • +

      +Added -pedantic to CFLAGS for debug build +

      +
    • +
    +
    +

    Version 0.3.9 (2006-12-31)

    +
    +
      +
    • +

      +Fix for Windows in simple frontend: open files in binary mode +

      +
        +
      • +

        +thanks to Kurien Mathew +

        +
      • +
      +
    • +
    • +

      +(libtwolame) Fixed energy level support +

      +
        +
      • +

        +thanks to Staale Helleberg +

        +
      • +
      +
    • +
    • +

      +Nows displays the version number of libsndfile in frontend +

      +
        +
      • +

        +as suggested by Elio Blanca +

        +
      • +
      +
    • +
    • +

      +Changed documentation build system, so you have to run it manually +

      +
    • +
    • +

      +Buffer overrun fix in new_extension() +

      +
    • +
    • +

      +(libtwolame) Added warning that DAB support is still broken +

      +
    • +
    • +

      +(libtwolame) Added twolame_get_framelength() to return number of bytes per frame +

      +
    • +
    • +

      +Added TWOLAME_SAMPLES_PER_FRAME macro, clarifying that there are + always 1152 samples per frame in Layer 2 +

      +
    • +
    • +

      +Frontend now displays extra information +

      +
        +
      • +

        +Duration of input file (if known) +

        +
      • +
      • +

        +Total number of frames to be encoded and percentage complete +

        +
      • +
      • +

        +The filesize of the output file +

        +
      • +
      +
    • +
    • +

      +Cleaned up source files so that it is consistent and all uses tabs (tab width 4) +

      +
    • +
    +
    +

    Version 0.3.8 (2006-06-19)

    +
    +
      +
    • +

      +(libtwolame) Fixed CRC protection +

      +
    • +
    • +

      +More code tidying +

      +
    • +
    • +

      +pkg-config is no-longer required (but is recommended) +

      +
    • +
    • +

      +frontend now has the exectuable suffix appended to filename +

      +
    • +
    • +

      +added -std=c99 to the compiler options +

      +
    • +
    +
    +

    Version 0.3.7 (2006-05-07)

    +
    +
      +
    • +

      +(libtwolame) Added twolame_encode_buffer_float32() function +

      +
    • +
    • +

      +(libtwolame) Fix NAN bug for AMD64 processors +

      +
    • +
    • +

      +Checks type sizes of short and float +

      +
    • +
    +
    +

    Version 0.3.6 (2006-12-25)

    +
    +
      +
    • +

      +Removed comma which was causing problems with -pedantic +

      +
        +
      • +

        +Thanks to Akos Maroy +

        +
      • +
      +
    • +
    • +

      +(libtwolame) Added libtool library versioning +

      +
    • +
    +
    +

    Version 0.3.5 (2005-11-29)

    +
    +
      +
    • +

      +(libtwolame) Added back twolame_get_VBR_q/twolame_set_VBR_q +

      +
    • +
    • +

      +More documentation is installed +

      +
    • +
    +
    +

    Version 0.3.4 (2005-11-19)

    +
    +
      +
    • +

      +(libtwolame) Checks parameters a bit better +

      +
    • +
    • +

      +(libtwolame) Removed lots of exit() calls +

      +
    • +
    • +

      +(libtwolame) added twolame_print_config() API call +

      +
    • +
    • +

      +(libtwolame) Fixed twolame.h so that it works with C++ code +

      +
    • +
    • +

      +Rewrote frontend and now (only) uses libsndfile +

      +
    • +
    • +

      +Changed behavior in frontend and backend for verbosity setting +

      +
    • +
    • +

      +Rewrote manpage for frontend +

      +
    • +
    • +

      +(libtwolame) Fixed bug with setting MPEG version +

      +
    • +
    • +

      +(libtwolame) Removed default samplerate - must choose one +

      +
    • +
    • +

      +(libtwolame) Original flag is now turned on by default +

      +
    • +
    • +

      +(libtwolame) Default bitrate is automatically chosen based on the samplerate/channels +

      +
    • +
    • +

      +(libtwolame) Default mode is automatically chosen based on the number of channels +

      +
    • +
    • +

      +Documentation improvements and corrections +

      +
    • +
    • +

      +(libtwolame) made some of VBR debugging send to stderr instead of stdout +

      +
    • +
    +
    +

    Version 0.3.3 (2005-04-19)

    +
    +
      +
    • +

      +Added Debian package description +

      +
    • +
    • +

      +Now installs documentation +

      +
    • +
    • +

      +Removed old unused tables.c and tables.h sources +

      +
    • +
    +
    +

    Version 0.3.2 (2005-04-10)

    +
    +
      +
    • +

      +Added scaling of input samples +

      +
    • +
    • +

      +Added downmixing/upmixing of samples +

      +
    • +
    • +

      +Applied patch from Christophe Massiot to make TwoLAME thread-safe +

      +
    • +
    +
    +

    Version 0.3.1 (2004-09-17)

    +
    +
      +
    • +

      +Frontend displays information about the input file format +

      +
    • +
    • +

      +Fixed bug with audio_get_samples reading more than buffer size +

      +
    • +
    • +

      +Added asciidoc documentation +

      +
    • +
    • +

      +Added doxygen documentation +

      +
    • +
    +
    +

    Version 0.3.0 (2004-09-14)

    +
    +
      +
    • +

      +Based on tooLAME 0.2m beta 8 +

      +
    • +
    • +

      +changed build system to use automake/libtool +

      +
    • +
    • +

      +now builds shared library +

      +
    • +
    • +

      +restructured lots of code +

      +
        +
      • +

        +Removed some dead code and unused files +

        +
      • +
      +
    • +
    • +

      +should now be close to being thread safe +

      +
    • +
    • +

      +removed memory leaks / static variables +

      +
    • +
    • +

      +changed library API so that it is almost the same as LAMEs +

      +
        +
      • +

        +hopefully not too many people have been using the old API +

        +
      • +
      • +

        +not too many big differences +

        +
      • +
      • +

        +will hopefully add resampling support to next release +

        +
      • +
      • +

        +API is ready for resampling support to be added +

        +
      • +
      • +

        +ready for downmixing to be added to libtoolame +

        +
      • +
      +
    • +
    • +

      +Added libsndfile support to toolame frontend (if you have it) +

      +
    • +
    • +

      +moved set/get functions into get_set.c +

      +
    • +
    • +

      +I have broken energy levels support (sorry !) - will try and fix +

      +
    • +
    • +

      +Added LGPL header to the top of all the files +

      +
    • +
    • +

      +Added toolame_encode_buffer_interleaved +

      +
    • +
    +
    + + + diff --git a/lib-src/twolame/doc/html/index.html b/lib-src/twolame/doc/html/index.html index 45bc2d494..6d0bea683 100644 --- a/lib-src/twolame/doc/html/index.html +++ b/lib-src/twolame/doc/html/index.html @@ -1,77 +1,77 @@ - - - - - - - -TwoLAME Documentation - - - -
    -
    -

    TwoLAME - an optimized MPEG Audio Layer 2 encoder

    - -

    twolame homepage: http://www.twolame.org
    -twolame mailing list: twolame-discuss@lists.sourceforge.net

    -
    -
    - - - + + + + + + + +TwoLAME Documentation + + + +
    +
    +

    TwoLAME - an optimized MPEG Audio Layer 2 encoder

    + +

    twolame homepage: http://www.twolame.org
    +twolame mailing list: twolame-discuss@lists.sourceforge.net

    +
    +
    + + + diff --git a/lib-src/twolame/doc/html/psycho.html b/lib-src/twolame/doc/html/psycho.html index 2c0701f28..1403e4214 100644 --- a/lib-src/twolame/doc/html/psycho.html +++ b/lib-src/twolame/doc/html/psycho.html @@ -1,132 +1,132 @@ - - - - - - - -Psychoacoustic Models in TwoLAME - - - -

    Introduction

    -
    -

    In MPEG audio encoding, a psychoacoustic model (PAM) is used to determine which -are the sonically important parts of the waveform that is being encoded. The PAM -looks for loud sounds which may mask soft sounds, noise which may affect the level -of sounds nearby, sounds which are too soft for us to hear and should be ignored -and so on. The information from the PAM is used to determine which parts of the -spectrum should get more bits and thus be encoded at greater quality - and which -parts are inaudible/unimportant and should thus get fewer bits.

    -

    In MPEG Audio LayerII encoding, 1152 sound samples are read in - this constitutes -a frame. For each frame the PAM outputs just 32 values -(The values are the Signal to Masking Ratio [SMR] in that subband). This is important! -There are only 32 values to determine how to alloctate bits for 1152 samples - this -is a pretty coarse technique.

    -

    The different PAMs listed below use different techniques to decide on these 32 -values. Some models are better than others - meaning that the 32 values chosen -are pretty good at spreading the bits where they should go. Even with a really -bad PAM (e.g. Model -1) you can still get satisfactory results a lot of the time. -All of these models have strengths and weaknesses. The model you end up using -will be the one that produces the best sound for your ears, for your audio.

    -
    -

    Psychoacoustic Model -1

    -
    -

    This PAM doesn't actually look at the samples being encoded to decide upon the -output values. There is simply a set of 32 default values which are used, -regardless of input.

    -

    Pros: Faaaast. Low complexity. Surprisingly good. -"Surprising" in that the other PAMs go to the effort of calculating FFTs -and subbands and masking, and this one does absolutely nothing. -Zip. Nada. Diddly Squat. This model might be the best example of why -it is hard to make a good model - if having no computations sounds OK, -how do you improve on it?

    -

    Cons: Absolutely no attempt to consider any of the masking effects that -would help the audio sound better.

    -
    -

    Psychoacoustic Model 0

    -
    -

    This PAM looks at the sizes of the scalefactors for the audio and combines -it with the Absolute Threshold of Hearing (ATH) to make the 32 SMR values.

    -

    Pros: Faaast. Low complexity.

    -

    Cons: This model has absolutely no mathematical basis and does not use -any perceptual model of hearing. It simply juggles some of the numbers of -the input sound to determine the values. Feel free to hack the daylights out -of this PAM - add multipliers, constants, log-tables anything. Tweak it until -you begin to like the sound.

    -
    -

    Psychoacoustic Model 1 and 2

    -
    -

    These PAMs are from the ISO standard. Just because they are the standard, -doesn't mean that they are any good. Look at LAME which basically threw out -the MP3 standard psycho models and made their own (GPSYCHO).

    -

    Pros: A reference for future PAMs

    -

    Cons: Terrible ISO code, buggy tables, poor documentation.

    -
    -

    Psychoacoustic Model 3

    -
    -

    A re-implementation of psychoacoustic model 1. ISO11172 was used as the guide -for re-writing this PAM from the ground up.

    -

    Pros: No more obscure tables of values from the ISO code. Hopefully a good -base to work upon for tweaking PAMs

    -

    Cons: At the moment, doesn't really sound any better than PAM1

    -
    -

    Psychoacoustic Model 4

    -
    -

    A cleaned up version of PAM2.

    -

    Pros: Faster than PAM2. No more obscure tables of values from the ISO -standard. Hopefully a good base to work from for improving the PAMs

    -

    Cons: Still has the same "warbling"/"Davros" problems as PAM2.

    -
    -

    Future psychoacoustic models

    -
    -

    There's a heap that could be done. Unfortunately, I've got a set of tin -ears, crappy speakers and a noisy computer room. If you've got the -capability to do proper PAM testing then please feel free to do so. -Otherwise, I'll just keep plodding along with new ideas as they -arise, such as:

    -
      -
    • -

      -Temporal masking (there's no pre-echo or anything in TwoLAME) -

      -
    • -
    • -

      -Left Right Masking -

      -
    • -
    • -

      -A PAM that's fully tuneable from the command line? -

      -
    • -
    • -

      -Graphical output of SMR values etc. Would allow better debugging of PAMs -

      -
    • -
    • -

      -Re-sampling routines -

      -
    • -
    • -

      -Low/High pass filtering -

      -
    • -
    -
    - - - + + + + + + + +Psychoacoustic Models in TwoLAME + + + +

    Introduction

    +
    +

    In MPEG audio encoding, a psychoacoustic model (PAM) is used to determine which +are the sonically important parts of the waveform that is being encoded. The PAM +looks for loud sounds which may mask soft sounds, noise which may affect the level +of sounds nearby, sounds which are too soft for us to hear and should be ignored +and so on. The information from the PAM is used to determine which parts of the +spectrum should get more bits and thus be encoded at greater quality - and which +parts are inaudible/unimportant and should thus get fewer bits.

    +

    In MPEG Audio LayerII encoding, 1152 sound samples are read in - this constitutes +a frame. For each frame the PAM outputs just 32 values +(The values are the Signal to Masking Ratio [SMR] in that subband). This is important! +There are only 32 values to determine how to alloctate bits for 1152 samples - this +is a pretty coarse technique.

    +

    The different PAMs listed below use different techniques to decide on these 32 +values. Some models are better than others - meaning that the 32 values chosen +are pretty good at spreading the bits where they should go. Even with a really +bad PAM (e.g. Model -1) you can still get satisfactory results a lot of the time. +All of these models have strengths and weaknesses. The model you end up using +will be the one that produces the best sound for your ears, for your audio.

    +
    +

    Psychoacoustic Model -1

    +
    +

    This PAM doesn't actually look at the samples being encoded to decide upon the +output values. There is simply a set of 32 default values which are used, +regardless of input.

    +

    Pros: Faaaast. Low complexity. Surprisingly good. +"Surprising" in that the other PAMs go to the effort of calculating FFTs +and subbands and masking, and this one does absolutely nothing. +Zip. Nada. Diddly Squat. This model might be the best example of why +it is hard to make a good model - if having no computations sounds OK, +how do you improve on it?

    +

    Cons: Absolutely no attempt to consider any of the masking effects that +would help the audio sound better.

    +
    +

    Psychoacoustic Model 0

    +
    +

    This PAM looks at the sizes of the scalefactors for the audio and combines +it with the Absolute Threshold of Hearing (ATH) to make the 32 SMR values.

    +

    Pros: Faaast. Low complexity.

    +

    Cons: This model has absolutely no mathematical basis and does not use +any perceptual model of hearing. It simply juggles some of the numbers of +the input sound to determine the values. Feel free to hack the daylights out +of this PAM - add multipliers, constants, log-tables anything. Tweak it until +you begin to like the sound.

    +
    +

    Psychoacoustic Model 1 and 2

    +
    +

    These PAMs are from the ISO standard. Just because they are the standard, +doesn't mean that they are any good. Look at LAME which basically threw out +the MP3 standard psycho models and made their own (GPSYCHO).

    +

    Pros: A reference for future PAMs

    +

    Cons: Terrible ISO code, buggy tables, poor documentation.

    +
    +

    Psychoacoustic Model 3

    +
    +

    A re-implementation of psychoacoustic model 1. ISO11172 was used as the guide +for re-writing this PAM from the ground up.

    +

    Pros: No more obscure tables of values from the ISO code. Hopefully a good +base to work upon for tweaking PAMs

    +

    Cons: At the moment, doesn't really sound any better than PAM1

    +
    +

    Psychoacoustic Model 4

    +
    +

    A cleaned up version of PAM2.

    +

    Pros: Faster than PAM2. No more obscure tables of values from the ISO +standard. Hopefully a good base to work from for improving the PAMs

    +

    Cons: Still has the same "warbling"/"Davros" problems as PAM2.

    +
    +

    Future psychoacoustic models

    +
    +

    There's a heap that could be done. Unfortunately, I've got a set of tin +ears, crappy speakers and a noisy computer room. If you've got the +capability to do proper PAM testing then please feel free to do so. +Otherwise, I'll just keep plodding along with new ideas as they +arise, such as:

    +
      +
    • +

      +Temporal masking (there's no pre-echo or anything in TwoLAME) +

      +
    • +
    • +

      +Left Right Masking +

      +
    • +
    • +

      +A PAM that's fully tuneable from the command line? +

      +
    • +
    • +

      +Graphical output of SMR values etc. Would allow better debugging of PAMs +

      +
    • +
    • +

      +Re-sampling routines +

      +
    • +
    • +

      +Low/High pass filtering +

      +
    • +
    +
    + + + diff --git a/lib-src/twolame/doc/html/readme.html b/lib-src/twolame/doc/html/readme.html index a0e2e4c8b..698dea040 100644 --- a/lib-src/twolame/doc/html/readme.html +++ b/lib-src/twolame/doc/html/readme.html @@ -1,123 +1,123 @@ - - - - - - - -TwoLAME - - - -
    -
    -

    Based on tooLAME by Michael Cheng

    -

    All changes to the ISO source are licensed under the LGPL -(see COPYING for details)

    -
    -
    -
    TwoLAME is free software; you can redistribute it and/or
    -modify it under the terms of the GNU Lesser General Public
    -License as published by the Free Software Foundation; either
    -version 2.1 of the License, or (at your option) any later version.
    -
    -
    -
    -
    TwoLAME 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
    -Lesser General Public License for more details.
    -
    -
    -
    -
    You should have received a copy of the GNU Lesser General Public
    -License along with TwoLAME; if not, write to the Free Software
    -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    -
    -
    -
    -

    INTRODUCTION

    -
    -

    TwoLAME is an optimized MPEG Audio Layer 2 (MP2) encoder. -It is based heavily on:

    -
      -
    • -

      -tooLAME by Michael Cheng -

      -
    • -
    • -

      -the ISO dist10 code -

      -
    • -
    • -

      -improvement to algorithms as part of the LAME project (lame.sf.net) -

      -
    • -
    • -

      -other contributors (see AUTHORS) -

      -
    • -
    -

    TwoLAME should be able to be used as a drop-in replacement for -LAME (a MPEG Layer 3 encoder). The frontend takes very similar -command line options to LAME, and the backend library has a very -similar API to LAME.

    -

    For the latest version of TwoLAME, visit the project homepage: -http://www.twolame.org/

    -
    -

    MPEG Audio Layer 2 (MP2)

    -
    -

    (taken from Wikipedia article on MP2)

    -

    MP2 (sometimes incorrectly named Musicam) is a short form of MPEG Audio Layer II, -and it is also used as a file extension for files containing audio data of this -type. While it has largely been superseded by MP3 for PC and Internet applications, -it remains a dominant standard for audio broadcasting as part of the DAB digital -radio and DVB digital television standards. It is also used internally within the -radio industry, for example in NPR's PRSS Content Depot programming distribution -system.

    -
    -

    INSTALLATION

    -
    -

    Standard automake process:

    -
    -
    -
    ./configure
    -make
    -make install
    -
    -
    -

    REFERENCE PAPERS

    -
    -

    (Specifically Layer II Papers)

    -

    Kumar, M & Zubair, M., A high performance software implementation of mpeg audio -encoder, 1996, ICASSP Conf Proceedings (I think)

    -

    Fischer, K.A., Calculation of the psychoacoustic simultaneous masked threshold -based on MPEG/Audio Encoder Model One, ICSI Technical Report, 1997 -ftp://ftp.icsi.berkeley.edu/pub/real/kyrill/PsychoMpegOne.tar.Z

    -

    Hyen-O et al, New Implementation techniques of a real-time mpeg-2 audio encoding -system. p2287, ICASSP 99.

    -

    Imai, T., et al, MPEG-1 Audio real-time encoding system, IEEE Trans on Consumer -Electronics, v44, n3 1998. p888

    -

    Teh, D., et al, Efficient bit allocation algorithm for ISO/MPEG audio encoder, -Electronics Letters, v34, n8, p721

    -

    Murphy, C & Anandakumar, K, Real-time MPEG-1 audio coding and decoding on a DSP -Chip, IEEE Trans on Consumer Electronics, v43, n1, 1997 p40

    -

    Hans, M & Bhaskaran, V., A compliant MPEG-1 layer II audio decoder with 16-B -arithmetic operations, IEEE Signal Proc Letters v4 n5 1997 p121

    -
    - - - + + + + + + + +TwoLAME + + + +
    +
    +

    Based on tooLAME by Michael Cheng

    +

    All changes to the ISO source are licensed under the LGPL +(see COPYING for details)

    +
    +
    +
    TwoLAME is free software; you can redistribute it and/or
    +modify it under the terms of the GNU Lesser General Public
    +License as published by the Free Software Foundation; either
    +version 2.1 of the License, or (at your option) any later version.
    +
    +
    +
    +
    TwoLAME 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
    +Lesser General Public License for more details.
    +
    +
    +
    +
    You should have received a copy of the GNU Lesser General Public
    +License along with TwoLAME; if not, write to the Free Software
    +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    +
    +
    +
    +

    INTRODUCTION

    +
    +

    TwoLAME is an optimized MPEG Audio Layer 2 (MP2) encoder. +It is based heavily on:

    +
      +
    • +

      +tooLAME by Michael Cheng +

      +
    • +
    • +

      +the ISO dist10 code +

      +
    • +
    • +

      +improvement to algorithms as part of the LAME project (lame.sf.net) +

      +
    • +
    • +

      +other contributors (see AUTHORS) +

      +
    • +
    +

    TwoLAME should be able to be used as a drop-in replacement for +LAME (a MPEG Layer 3 encoder). The frontend takes very similar +command line options to LAME, and the backend library has a very +similar API to LAME.

    +

    For the latest version of TwoLAME, visit the project homepage: +http://www.twolame.org/

    +
    +

    MPEG Audio Layer 2 (MP2)

    +
    +

    (taken from Wikipedia article on MP2)

    +

    MP2 (sometimes incorrectly named Musicam) is a short form of MPEG Audio Layer II, +and it is also used as a file extension for files containing audio data of this +type. While it has largely been superseded by MP3 for PC and Internet applications, +it remains a dominant standard for audio broadcasting as part of the DAB digital +radio and DVB digital television standards. It is also used internally within the +radio industry, for example in NPR's PRSS Content Depot programming distribution +system.

    +
    +

    INSTALLATION

    +
    +

    Standard automake process:

    +
    +
    +
    ./configure
    +make
    +make install
    +
    +
    +

    REFERENCE PAPERS

    +
    +

    (Specifically Layer II Papers)

    +

    Kumar, M & Zubair, M., A high performance software implementation of mpeg audio +encoder, 1996, ICASSP Conf Proceedings (I think)

    +

    Fischer, K.A., Calculation of the psychoacoustic simultaneous masked threshold +based on MPEG/Audio Encoder Model One, ICSI Technical Report, 1997 +ftp://ftp.icsi.berkeley.edu/pub/real/kyrill/PsychoMpegOne.tar.Z

    +

    Hyen-O et al, New Implementation techniques of a real-time mpeg-2 audio encoding +system. p2287, ICASSP 99.

    +

    Imai, T., et al, MPEG-1 Audio real-time encoding system, IEEE Trans on Consumer +Electronics, v44, n3 1998. p888

    +

    Teh, D., et al, Efficient bit allocation algorithm for ISO/MPEG audio encoder, +Electronics Letters, v34, n8, p721

    +

    Murphy, C & Anandakumar, K, Real-time MPEG-1 audio coding and decoding on a DSP +Chip, IEEE Trans on Consumer Electronics, v43, n1, 1997 p40

    +

    Hans, M & Bhaskaran, V., A compliant MPEG-1 layer II audio decoder with 16-B +arithmetic operations, IEEE Signal Proc Letters v4 n5 1997 p121

    +
    + + + diff --git a/lib-src/twolame/doc/html/todo.html b/lib-src/twolame/doc/html/todo.html index b9865c90a..7d68937a3 100644 --- a/lib-src/twolame/doc/html/todo.html +++ b/lib-src/twolame/doc/html/todo.html @@ -1,106 +1,106 @@ - - - - - - - -TwoLAME TODO List - - - -
    -
    -
      -
    • -

      -Fix bug with Padding and framesizes with samplerate of 44.1 and 22kHz -

      -
    • -
    • -

      -use Exact-width integer types (eg uint16_t) -

      -
    • -
    • -

      -Add libresample support to libtoolame (toolame_set_in_samplerate etc.) -

      -
    • -
    • -

      -parameter checking in toolame.c using assert -

      -
    • -
    • -

      -Create a new toolame.spec (be sure to include twolame.pc) -

      -
    • -
    • -

      -quite a lot of duplicated code between toolame_encode_buffer_interleaved - and toolame_encode_buffer -

      -
    • -
    • -

      -sort out changing parameter for toolame_set_VBR_q from FLOAT to int (like LAME) -

      -
    • -
    • -

      -better use of verbosity settings -

      -
    • -
    • -

      -full options sanity checking/verification in toolame_init_params -

      -
    • -
    • -

      -don't allow twolame_set_* after twolame_init_params() has been called -

      -
    • -
    • -

      -Fix broken DAB support -

      -
    • -
    • -

      -with this VBR mode, we know the bits aren't going to run out, so we can - just assign them "greedily". -

      -
    • -
    • -

      -VBR_a_bit_allocation() is yet to be written :) -

      -
    • -
    • -

      -Add a layer 2 decoder ? mpglib ? -

      -
    • -
    • -

      -use 32-bit floats internally where possible -

      -
    • -
    -
    -
    - - - + + + + + + + +TwoLAME TODO List + + + +
    +
    +
      +
    • +

      +Fix bug with Padding and framesizes with samplerate of 44.1 and 22kHz +

      +
    • +
    • +

      +use Exact-width integer types (eg uint16_t) +

      +
    • +
    • +

      +Add libresample support to libtoolame (toolame_set_in_samplerate etc.) +

      +
    • +
    • +

      +parameter checking in toolame.c using assert +

      +
    • +
    • +

      +Create a new toolame.spec (be sure to include twolame.pc) +

      +
    • +
    • +

      +quite a lot of duplicated code between toolame_encode_buffer_interleaved + and toolame_encode_buffer +

      +
    • +
    • +

      +sort out changing parameter for toolame_set_VBR_q from FLOAT to int (like LAME) +

      +
    • +
    • +

      +better use of verbosity settings +

      +
    • +
    • +

      +full options sanity checking/verification in toolame_init_params +

      +
    • +
    • +

      +don't allow twolame_set_* after twolame_init_params() has been called +

      +
    • +
    • +

      +Fix broken DAB support +

      +
    • +
    • +

      +with this VBR mode, we know the bits aren't going to run out, so we can + just assign them "greedily". +

      +
    • +
    • +

      +VBR_a_bit_allocation() is yet to be written :) +

      +
    • +
    • +

      +Add a layer 2 decoder ? mpglib ? +

      +
    • +
    • +

      +use 32-bit floats internally where possible +

      +
    • +
    +
    +
    + + + diff --git a/lib-src/twolame/doc/html/twolame.1.html b/lib-src/twolame/doc/html/twolame.1.html index fc0df4930..4fbe0fe0b 100644 --- a/lib-src/twolame/doc/html/twolame.1.html +++ b/lib-src/twolame/doc/html/twolame.1.html @@ -1,476 +1,476 @@ - - - - - - - - -TWOLAME(1) - - - -

    SYNOPSIS

    -
    -

    twolame [options] <infile> [outfile]

    -
    -

    DESCRIPTION

    -
    -

    TwoLAME is an optimised MPEG Audio Layer 2 (MP2) encoder based on tooLAME by -Mike Cheng, which in turn is based upon the ISO dist10 code and portions of -LAME. Encoding is performed by the libtwolame library backend.

    -
    -

    OPTIONS

    -
    -

    Input File

    -

    twolame uses libsndfile for reading the input sound file, so -the input file can be in any format supported by libsndfile. -To read raw PCM audio from STDIN, then use - as the input filename.

    -

    Output File

    -

    If no output filename is specified, then suffix of the input filename -is automatically changed to .mp2. To write the encoded audio to STDOUT -then use - as the output filename.

    -

    Input Options

    -
    -
    --r, --raw-input -
    -
    -

    - Specifies that input is raw signed PCM audio. - If audio is stereo, than audio samples are interleaved - between the two channels. -

    -
    -
    --x, --byte-swap -
    -
    -

    - Force byte-swapping of the input. Endian detection is performed - automatically by libsndfile, so this option shouldn't - normally be needed. -

    -
    -
    --s, --samplerate <int> -
    -
    -

    - If inputting raw PCM sound, you must specify the sample rate of - the audio in Hz. - Valid sample rates: 16000, 22050, 24000, 32000, 44100, 48000Hz. - Default sample rate is 44100Hz. -

    -
    -
    ---samplesize <int> -
    -
    -

    - Specifies the sample size (in bits) of the raw PCM audio. - Valid sample sizes: 8, 16, 24, 32. - Default sample size is 16-bit. -

    -
    -
    --N, --channels <int> -
    -
    -

    - If inputting raw PCM sound, you must specify the number of channels - in the input audio. Default number of channels is 2. -

    -
    -
    --g, --swap-channels -
    -
    -

    - Swap the Left and Right channels of a stereo input file. -

    -
    -
    ---scale <float> -
    -
    -

    - Scale the input audio prior to encoding. - All of the input audio is multiplied by specified value. - Value between 0 and 1 will reduce the audio gain, and a value - above 1 will increase the gain of the audio. -

    -
    -
    ---scale-l <float> -
    -
    -

    - Same as --scale, but only affects the left channel. -

    -
    -
    ---scale-r <float> -
    -
    -

    - Same as --scale, but only affects the right channel. -

    -
    -
    -

    Output Options

    -
    -
    --m, --mode <char> -
    -
    -

    - Choose the mode of the resulting audio. Default is auto. -

    -
      -
    • -

      -"a" auto - choose mode automatically based on the input -

      -
    • -
    • -

      -"s" stereo -

      -
    • -
    • -

      -"d" dual channel -

      -
    • -
    • -

      -"j" joint stereo -

      -
    • -
    • -

      -"m" mono -

      -
    • -
    -
    -
    --a, --downmix -
    -
    -

    - If the input file is stereo then, downmix the left and right - input channels into a single mono channel. -

    -
    -
    --b, --bitrate <int> -
    -
    -

    - Sets the total bitrate (in kbps) for the output file. - The default bitrate depends on the number of - input channels and samplerate. -

    -
    -
    -
    ------------------------------
    -Sample Rate   Mono    Stereo
    -------------------------------
    -48000         96      192
    -44100         96      192
    -32000         80      160
    -24000         48      96
    -22050         48      96
    -16000         32      64
    -------------------------------
    -
    -
    -
    --P, --psyc-mode <int> -
    -
    -

    - Choose the psycho-acoustic model to use (-1 to 4). - Model number -1 is turns off psycho-acoustic modelling and - uses fixed default values instead. - Please see the file psycho for a full description of - each of the models available. - Default model is 3. -

    -
    -
    --v, --vbr -
    -
    -

    - Enable VBR mode. See vbr documentation file for details. - Default VBR level is 5.0. -

    -
    -
    --v, --vbr-level <float> -
    -
    -

    - Enable VBR mode and set quality level. - The higher the number the better the quality. - Maximum range is -50 to 50 but useful range is -10 to 10. - See vbr documentation file for details. -

    -
    -
    --l, --ath <float> -
    -
    -

    - Set the ATH level. Default level is 0.0. -

    -
    -
    --q, --quick <int> -
    -
    -

    - Enable quick mode. Only re-calculate psycho-acoustic - model every specified number of frames. -

    -
    -
    --S, --single-frame -
    -
    -

    - Enables single frame mode: only a single frame of MPEG audio - is output and then the program terminates. -

    -
    -
    -

    Miscellaneous Options

    -
    -
    --c, --copyright -
    -
    -

    - Turn on Copyright flag in output bitstream. -

    -
    -
    --o, --non-original -
    -
    -

    - Turn off Original flag in output bitstream. -

    -
    -
    ---original -
    -
    -

    - Turn on Original flag in output bitstream. -

    -
    -
    --p, --protect -
    -
    -

    - Enable CRC error protection in output bitstream. - An extra 16-bit checksum is added to frames. -

    -
    -
    --d, --padding -
    -
    -

    - Turn on padding in output bitstream. -

    -
    -
    --R, --reserve <int> -
    -
    -

    - Reserve specified number of bits in the each from of the - output bitstream. -

    -
    -
    --e, --deemphasis <char> -
    -
    -

    - Set the de-emphasis type (n/c/5). Default is none. -

    -
    -
    --E, --energy -
    -
    -

    - Turn on energy level extensions. -

    -
    -
    -

    Verbosity Options

    -
    -
    --t, --talkativity <int> -
    -
    -

    - Set the amount of information to be displayed on stderr (0 to 10). - Default is 2. -

    -
    -
    ---quiet -
    -
    -

    - Don't send any messages to stderr, unless there is an error. - (Same as --talkativity=0) -

    -
    -
    ---brief -
    -
    -

    - Only display a minimal number of messages while encoding. - This setting is quieter than the default talkativity setting. - (Same as --talkativity=1) -

    -
    -
    ---verbose -
    -
    -

    - Display an increased number of messages on stderr. - This setting is useful to diagnose problems. - (Same as --talkativity=4) -

    -
    -
    -
    -

    Return Codes

    -
    -

    If encoding completes successfully, then twolame will return 0. -However if encoding is not successful, then it will return one of the following codes.

    -
      -
    • -

      -1 (No encoding performed) -

      -
    • -
    • -

      -2 (Error opening input file) -

      -
    • -
    • -

      -4 (Error opening output file) -

      -
    • -
    • -

      -6 (Error allocating memory) -

      -
    • -
    • -

      -8 (Error in chosen encoding parameters) -

      -
    • -
    • -

      -10 (Error reading input audio) -

      -
    • -
    • -

      -12 (Error occured while encoding) -

      -
    • -
    • -

      -14 (Error writing output audio) -

      -
    • -
    -
    -

    EXAMPLES

    -
    -

    This will encode sound.wav to sound.mp2 using the default constant bitrate of 192 kbps -and using the default psycho-acoustic model (model 3):

    -
    -
    -
    twolame sound.wav
    -
    -

    Constant bitrate of 160kbps and joint stereo encoding, saved to file sound_160.mp2:

    -
    -
    -
    twolame -b 160 -m j sound.aiff sound_160.mp2
    -
    -

    Encode sound.wav to newfile.mp2 using psycho-acoustic model 2 and encoding -with variable bitrate:

    -
    -
    -
    twolame -P 2 -v sound.wav newfile.mp2
    -
    -

    Same as example above, except that the negative value of the "-V" argument -means that the lower bitrates will be favoured over the higher ones:

    -
    -
    -
    twolame -P 2 -V -5 sound.wav newfile.mp2
    -
    -

    Resample audio file using sox and pipe straight through twolame:

    -
    -
    -
    sox sound_11025.aiff -t raw -r 16000 | twolame -r -s 16000 - - > out.mp2
    -
    -
    -

    AUTHORS

    -
    -

    The twolame frontend was (re)written by Nicholas J Humfrey. -The libtwolame library is based on toolame by Mike Cheng. -For a full list of authors, please see the AUTHORS file.

    -
    -

    RESOURCES

    -
    -

    TwoLAME web site: http://www.twolame.org/

    -
    -

    SEE ALSO

    -
    -

    lame(1), mpg123(1), madplay(1), sox(1)

    -
    -

    COPYING

    -
    -

    Copyright © 2004-2006 The TwoLAME Project. Free use of this software is -granted under the terms of the GNU Lesser General Public License (LGPL).

    -
    - - - + + + + + + + + +TWOLAME(1) + + + +

    SYNOPSIS

    +
    +

    twolame [options] <infile> [outfile]

    +
    +

    DESCRIPTION

    +
    +

    TwoLAME is an optimised MPEG Audio Layer 2 (MP2) encoder based on tooLAME by +Mike Cheng, which in turn is based upon the ISO dist10 code and portions of +LAME. Encoding is performed by the libtwolame library backend.

    +
    +

    OPTIONS

    +
    +

    Input File

    +

    twolame uses libsndfile for reading the input sound file, so +the input file can be in any format supported by libsndfile. +To read raw PCM audio from STDIN, then use - as the input filename.

    +

    Output File

    +

    If no output filename is specified, then suffix of the input filename +is automatically changed to .mp2. To write the encoded audio to STDOUT +then use - as the output filename.

    +

    Input Options

    +
    +
    +-r, --raw-input +
    +
    +

    + Specifies that input is raw signed PCM audio. + If audio is stereo, than audio samples are interleaved + between the two channels. +

    +
    +
    +-x, --byte-swap +
    +
    +

    + Force byte-swapping of the input. Endian detection is performed + automatically by libsndfile, so this option shouldn't + normally be needed. +

    +
    +
    +-s, --samplerate <int> +
    +
    +

    + If inputting raw PCM sound, you must specify the sample rate of + the audio in Hz. + Valid sample rates: 16000, 22050, 24000, 32000, 44100, 48000Hz. + Default sample rate is 44100Hz. +

    +
    +
    +--samplesize <int> +
    +
    +

    + Specifies the sample size (in bits) of the raw PCM audio. + Valid sample sizes: 8, 16, 24, 32. + Default sample size is 16-bit. +

    +
    +
    +-N, --channels <int> +
    +
    +

    + If inputting raw PCM sound, you must specify the number of channels + in the input audio. Default number of channels is 2. +

    +
    +
    +-g, --swap-channels +
    +
    +

    + Swap the Left and Right channels of a stereo input file. +

    +
    +
    +--scale <float> +
    +
    +

    + Scale the input audio prior to encoding. + All of the input audio is multiplied by specified value. + Value between 0 and 1 will reduce the audio gain, and a value + above 1 will increase the gain of the audio. +

    +
    +
    +--scale-l <float> +
    +
    +

    + Same as --scale, but only affects the left channel. +

    +
    +
    +--scale-r <float> +
    +
    +

    + Same as --scale, but only affects the right channel. +

    +
    +
    +

    Output Options

    +
    +
    +-m, --mode <char> +
    +
    +

    + Choose the mode of the resulting audio. Default is auto. +

    +
      +
    • +

      +"a" auto - choose mode automatically based on the input +

      +
    • +
    • +

      +"s" stereo +

      +
    • +
    • +

      +"d" dual channel +

      +
    • +
    • +

      +"j" joint stereo +

      +
    • +
    • +

      +"m" mono +

      +
    • +
    +
    +
    +-a, --downmix +
    +
    +

    + If the input file is stereo then, downmix the left and right + input channels into a single mono channel. +

    +
    +
    +-b, --bitrate <int> +
    +
    +

    + Sets the total bitrate (in kbps) for the output file. + The default bitrate depends on the number of + input channels and samplerate. +

    +
    +
    +
    ------------------------------
    +Sample Rate   Mono    Stereo
    +------------------------------
    +48000         96      192
    +44100         96      192
    +32000         80      160
    +24000         48      96
    +22050         48      96
    +16000         32      64
    +------------------------------
    +
    +
    +
    +-P, --psyc-mode <int> +
    +
    +

    + Choose the psycho-acoustic model to use (-1 to 4). + Model number -1 is turns off psycho-acoustic modelling and + uses fixed default values instead. + Please see the file psycho for a full description of + each of the models available. + Default model is 3. +

    +
    +
    +-v, --vbr +
    +
    +

    + Enable VBR mode. See vbr documentation file for details. + Default VBR level is 5.0. +

    +
    +
    +-v, --vbr-level <float> +
    +
    +

    + Enable VBR mode and set quality level. + The higher the number the better the quality. + Maximum range is -50 to 50 but useful range is -10 to 10. + See vbr documentation file for details. +

    +
    +
    +-l, --ath <float> +
    +
    +

    + Set the ATH level. Default level is 0.0. +

    +
    +
    +-q, --quick <int> +
    +
    +

    + Enable quick mode. Only re-calculate psycho-acoustic + model every specified number of frames. +

    +
    +
    +-S, --single-frame +
    +
    +

    + Enables single frame mode: only a single frame of MPEG audio + is output and then the program terminates. +

    +
    +
    +

    Miscellaneous Options

    +
    +
    +-c, --copyright +
    +
    +

    + Turn on Copyright flag in output bitstream. +

    +
    +
    +-o, --non-original +
    +
    +

    + Turn off Original flag in output bitstream. +

    +
    +
    +--original +
    +
    +

    + Turn on Original flag in output bitstream. +

    +
    +
    +-p, --protect +
    +
    +

    + Enable CRC error protection in output bitstream. + An extra 16-bit checksum is added to frames. +

    +
    +
    +-d, --padding +
    +
    +

    + Turn on padding in output bitstream. +

    +
    +
    +-R, --reserve <int> +
    +
    +

    + Reserve specified number of bits in the each from of the + output bitstream. +

    +
    +
    +-e, --deemphasis <char> +
    +
    +

    + Set the de-emphasis type (n/c/5). Default is none. +

    +
    +
    +-E, --energy +
    +
    +

    + Turn on energy level extensions. +

    +
    +
    +

    Verbosity Options

    +
    +
    +-t, --talkativity <int> +
    +
    +

    + Set the amount of information to be displayed on stderr (0 to 10). + Default is 2. +

    +
    +
    +--quiet +
    +
    +

    + Don't send any messages to stderr, unless there is an error. + (Same as --talkativity=0) +

    +
    +
    +--brief +
    +
    +

    + Only display a minimal number of messages while encoding. + This setting is quieter than the default talkativity setting. + (Same as --talkativity=1) +

    +
    +
    +--verbose +
    +
    +

    + Display an increased number of messages on stderr. + This setting is useful to diagnose problems. + (Same as --talkativity=4) +

    +
    +
    +
    +

    Return Codes

    +
    +

    If encoding completes successfully, then twolame will return 0. +However if encoding is not successful, then it will return one of the following codes.

    +
      +
    • +

      +1 (No encoding performed) +

      +
    • +
    • +

      +2 (Error opening input file) +

      +
    • +
    • +

      +4 (Error opening output file) +

      +
    • +
    • +

      +6 (Error allocating memory) +

      +
    • +
    • +

      +8 (Error in chosen encoding parameters) +

      +
    • +
    • +

      +10 (Error reading input audio) +

      +
    • +
    • +

      +12 (Error occured while encoding) +

      +
    • +
    • +

      +14 (Error writing output audio) +

      +
    • +
    +
    +

    EXAMPLES

    +
    +

    This will encode sound.wav to sound.mp2 using the default constant bitrate of 192 kbps +and using the default psycho-acoustic model (model 3):

    +
    +
    +
    twolame sound.wav
    +
    +

    Constant bitrate of 160kbps and joint stereo encoding, saved to file sound_160.mp2:

    +
    +
    +
    twolame -b 160 -m j sound.aiff sound_160.mp2
    +
    +

    Encode sound.wav to newfile.mp2 using psycho-acoustic model 2 and encoding +with variable bitrate:

    +
    +
    +
    twolame -P 2 -v sound.wav newfile.mp2
    +
    +

    Same as example above, except that the negative value of the "-V" argument +means that the lower bitrates will be favoured over the higher ones:

    +
    +
    +
    twolame -P 2 -V -5 sound.wav newfile.mp2
    +
    +

    Resample audio file using sox and pipe straight through twolame:

    +
    +
    +
    sox sound_11025.aiff -t raw -r 16000 | twolame -r -s 16000 - - > out.mp2
    +
    +
    +

    AUTHORS

    +
    +

    The twolame frontend was (re)written by Nicholas J Humfrey. +The libtwolame library is based on toolame by Mike Cheng. +For a full list of authors, please see the AUTHORS file.

    +
    +

    RESOURCES

    +
    +

    TwoLAME web site: http://www.twolame.org/

    +
    +

    SEE ALSO

    +
    +

    lame(1), mpg123(1), madplay(1), sox(1)

    +
    +

    COPYING

    +
    +

    Copyright © 2004-2006 The TwoLAME Project. Free use of this software is +granted under the terms of the GNU Lesser General Public License (LGPL).

    +
    + + + diff --git a/lib-src/twolame/doc/html/vbr.html b/lib-src/twolame/doc/html/vbr.html index 38e3e07ec..231696f0c 100644 --- a/lib-src/twolame/doc/html/vbr.html +++ b/lib-src/twolame/doc/html/vbr.html @@ -1,337 +1,337 @@ - - - - - - - -TwoLAME: MPEG Audio Layer II VBR - - - -

    Contents

    -
    -
      -
    • -

      -Introduction -

      -
    • -
    • -

      -Usage -

      -
    • -
    • -

      -Bitrate Ranges for various Sampling frequencies -

      -
    • -
    • -

      -Why can't the bitrate vary from 32kbps to 384kbps for every file? -

      -
    • -
    • -

      -Short Answer -

      -
    • -
    • -

      -Long Answer -

      -
    • -
    • -

      -Tech Stuff -

      -
    • -
    -
    -

    Introduction

    -
    -

    VBR mode works by selecting a different bitrate for each frame. Frames -which are harder to encode will be allocated more bits i.e. a higher bitrate.

    -

    LayerII VBR is a complete hack - the ISO standard actually says that decoders are not -required to support it. As a hack, its implementation is a pain to try and understand. -If you're mega-keen to get full range VBR working, either (a) send me money (b) grab the -ISO standard and a C compiler and email me.

    -
    -

    Usage

    -
    -
    -
    -
    twolame -v [level] inputfile outputfile.
    -
    -

    A level of 5 works very well for me.

    -

    The level value can is a measurement of quality - the higher -the level the higher the average bitrate of the resultant file. -[See TECH STUFF for a better explanation of what the value does]

    -

    The confusing part of my implementation of LayerII VBR is that it's different from MP3 VBR.

    -
      -
    • -

      -The range of bitrates used is controlled by the input sampling frequency. (See below "Bitrate ranges") -

      -
    • -
    • -

      -The tendency to use higher bitrates is governed by the <level>. -

      -
    • -
    -

    E.g. Say you have a 44.1kHz Stereo file. In VBR mode, the bitrate can range from 192 to 384 kbps.

    -

    Using "-v -5" will force the encoder to favour the lower bitrate.

    -

    Using "-v 5" will force the encoder to favour the upper bitrate.

    -

    The value can actually be any int. -27, 233, 47. The larger the number, the greater -the bitrate bias.

    -
    -

    Bitrate Ranges

    -
    -

    When making a VBR stream, the bitrate is only allowed to vary within -set limits

    -
    -
    -
    48kHz
    -Stereo: 112-384kbps  Mono: 56-192kbps
    -
    -
    -
    -
    44.1kHz & 32kHz
    -Stereo: 192-384kbps  Mono: 96-192kbps
    -
    -
    -
    -
    24kHz, 22.05kHz & 16kHz
    -Stereo/Mono: 8-160kbps
    -
    -
    -

    Why doesn't the VBR mode work the same as MP3VBR? The Short Answer

    -
    -

    Why can't the bitrate vary from 32kbps to 384kbps for every file?

    -

    According to the standard (ISO/IEC 11172-3:1993) Section 2.4.2.3

    -
    -
    -
    "In order to provide the smallest possible delay and complexity, the
    - decoder is not required to support a continuously variable bitrate when
    - in layer I or II.  Layer III supports variable bitrate by switching the
    - bitrate index."
    -
    -
    -
    -
    and
    -
    -
    -
    -
    "For Layer II, not all combinations of total bitrate and mode are allowed."
    -
    -

    Hence, most LayerII coders would not have been written with VBR in mind, and -LayerII VBR is a hack. It works for limited cases. Getting it to work to -the same extent as MP3-style VBR will be a major hack.

    -

    (If you really want better bitrate ranges, read "The Long Answer" and submit your mega-patch.)

    -
    -

    Why doesn't the VBR mode work the same as MP3VBR? The Long Answer

    -
    -

    Why can't the bitrate vary from 32kbps to 384kbps for every file?

    -

    Reason 1: The standard limits the range

    -

    As quoted above from the standard for 48/44.1/32kHz:

    -
    -
    -
    "For Layer II, not all combinations of total bitrate and mode are allowed. See
    - the following table."
    -
    -
    -
    -
    Bitrate         Allowed Modes
    -(kbps)
    -32              mono only
    -48              mono only
    -56              mono only
    -64              all modes
    -80              mono only
    -96              all modes
    -112             all modes
    -128             all modes
    -160             all modes
    -192             all modes
    -224             stereo only
    -256             stereo only
    -320             stereo only
    -384             stereo only
    -
    -

    So based upon this table alone, you could have VBR stereo encoding which varies -smoothly from 96 to 384kbps. Or you could have have VBR mono encoding which varies from -32 to 192kbps. But since the top and bottom bitrates don't apply to all modes, it would -be impossible to have a stereo file encoded from 32 to 384 kbps.

    -

    But this isn't what is really limiting the allowable bitrate range - the bit allocation -tables are the major hurdle.

    -

    Reason 2: The bit allocation tables don't allow it

    -

    From the standard, Section 2.4.3.3.1 "Bit allocation decoding"

    -
    -
    -
    "For different combinations of bitrate and sampling frequency, different bit
    - allocation tables exist.
    -
    -

    These bit allocation tables are pre-determined tables (in Annex B of the standard) which -indicate

    -
      -
    • -

      -how many bits to read for the initial data (2,3 or 4) -

      -
    • -
    • -

      -these bits are then used as an index back into the table to - find the number of quantize levels for the samples in this subband -

      -
    • -
    -

    But the table used (and hence the number of bits and the calculated index) are different -for different combinations of bitrate and sampling frequency.

    -

    I will use TableB.2a as an example.

    -

    Table B.2a Applies for the following combinations.

    -
    -
    -
    Sampling Freq           Bitrates in (kbps/channel) [emphasis: this is a PER CHANNEL bitrate]
    -48                      56, 64, 80, 96, 112, 128, 160, 192
    -44.1                    56, 64, 80
    -32                      56, 64, 80
    -
    -

    If we have a STEREO 48kHz input file, and we use this table, then the bitrates -we could calculate from this would be 112, 128, 160, 192, 224, 256, 320 and 384 kbps.

    -

    This table contains no information on how to encode stuff at bitrates less than 112kbps -(for a stereo file). You would have to load allocation table B.2c to encode stereo at -64kbps and 128kbps.

    -

    Since it would be a MAJOR piece of hacking to get the different tables shifted in and out -during the encoding process, once an allocation table is loaded IT IS NOT CHANGED.

    -

    Hence, the best table is picked at the start of the encoding process, and the encoder -is stuck with it for the rest of the encode.

    -

    For twolame-02j, I have picked the table it loads for different -sampling frequencies in order to optimize the range of bitrates possible.

    -
    -
    -
    48 kHz - Table B.2a
    -         Stereo Bitrate Range: 112 - 384
    -         Mono Bitrate Range : 56 - 192
    -
    -
    -
    -
    44.1/32 kHz - Table B.2b
    -        Stereo Bitrate Range: 192 - 384
    -        Mono Bitrate Range: 96 - 192
    -
    -
    -
    -
    24/22.05/16 kHz - LSF Table (Standard ISO/IEC 13818.3:1995 Annex B, Table B.1)
    -        There is only 1 table for the Lower Sampling Frequencies
    -        All modes (mono and stereo) are allowable at all bitrates
    -        So at the Lower Sampling Frequencies you *can* have a completely variable
    -        bitrate over the entire range.
    -
    -
    -

    Tech Stuff

    -
    -

    The VBR mode is mainly centered around the main_bit_allocation() and -a_bit_allocation() routines in encode.c.

    -

    The limited range of VBR is due to my particular implementation which restricts -ranges to within one alloc table (see tables B.2a, B.2b, B.2c and B.2d in ISO 11172). -The VBR range for 32/44.1khz lies within B.2b, and the 48khz VBR lies within table B.2a.

    -

    I'm not sure whether it is worth extending these ranges down to lower bitrates. -The work required to switch alloc tables during the encoding is major.

    -

    In the case of silence, it might be worth doing a quick check for very low signals -and writing a pre-calculated blank 32kpbs frame. [probably also a lot of work].

    -
    -

    How CBR works

    -
    -
      -
    • -

      -Use the psycho model to determine the MNRs for each subband - [MNR = the ratio of "masking" to "noise"] - (From an encoding perspective, a bigger MNR in a subband means that - it sounds better since the noise is more masked)) -

      -
    • -
    • -

      -calculate the available data bits (adb) for this bitrate. -

      -
    • -
    • -

      -Based upon the MNR (Masking:Noise Ratio) values, allocate bits to each - subband -

      -
    • -
    • -

      -Keep increasing the bits to whichever subband currently has the min MNR - value until we have no bits left. -

      -
    • -
    • -

      -This mode does not guarentee that all the subbands are without noise - ie there may still be subbands with MNR less than 0.0 (noisy!) -

      -
    • -
    -
    -

    How VBR works

    -
    -
      -
    • -

      -pretend we have lots of bits to spare, and work out the bits which would - raise the MNR in each subband to the level given by the argument on the - command line "-v [int]" -

      -
    • -
    • -

      -Pick the bitrate which has more bits than the required_bits we just calculated -

      -
    • -
    • -

      -calculate a_bit_allocation() -

      -
    • -
    • -

      -VBR "guarantees" that all subbands have MNR > VBRLEVEL or that we have - reached the maximum bitrate. -

      -
    • -
    -
    -

    FUTURE

    -
    -
      -
    • -

      -with this VBR mode, we know the bits aren't going to run out, so we can - just assign them "greedily". -

      -
    • -
    • -

      -VBR_a_bit_allocation() is yet to be written :) -

      -
    • -
    -
    - - - + + + + + + + +TwoLAME: MPEG Audio Layer II VBR + + + +

    Contents

    +
    +
      +
    • +

      +Introduction +

      +
    • +
    • +

      +Usage +

      +
    • +
    • +

      +Bitrate Ranges for various Sampling frequencies +

      +
    • +
    • +

      +Why can't the bitrate vary from 32kbps to 384kbps for every file? +

      +
    • +
    • +

      +Short Answer +

      +
    • +
    • +

      +Long Answer +

      +
    • +
    • +

      +Tech Stuff +

      +
    • +
    +
    +

    Introduction

    +
    +

    VBR mode works by selecting a different bitrate for each frame. Frames +which are harder to encode will be allocated more bits i.e. a higher bitrate.

    +

    LayerII VBR is a complete hack - the ISO standard actually says that decoders are not +required to support it. As a hack, its implementation is a pain to try and understand. +If you're mega-keen to get full range VBR working, either (a) send me money (b) grab the +ISO standard and a C compiler and email me.

    +
    +

    Usage

    +
    +
    +
    +
    twolame -v [level] inputfile outputfile.
    +
    +

    A level of 5 works very well for me.

    +

    The level value can is a measurement of quality - the higher +the level the higher the average bitrate of the resultant file. +[See TECH STUFF for a better explanation of what the value does]

    +

    The confusing part of my implementation of LayerII VBR is that it's different from MP3 VBR.

    +
      +
    • +

      +The range of bitrates used is controlled by the input sampling frequency. (See below "Bitrate ranges") +

      +
    • +
    • +

      +The tendency to use higher bitrates is governed by the <level>. +

      +
    • +
    +

    E.g. Say you have a 44.1kHz Stereo file. In VBR mode, the bitrate can range from 192 to 384 kbps.

    +

    Using "-v -5" will force the encoder to favour the lower bitrate.

    +

    Using "-v 5" will force the encoder to favour the upper bitrate.

    +

    The value can actually be any int. -27, 233, 47. The larger the number, the greater +the bitrate bias.

    +
    +

    Bitrate Ranges

    +
    +

    When making a VBR stream, the bitrate is only allowed to vary within +set limits

    +
    +
    +
    48kHz
    +Stereo: 112-384kbps  Mono: 56-192kbps
    +
    +
    +
    +
    44.1kHz & 32kHz
    +Stereo: 192-384kbps  Mono: 96-192kbps
    +
    +
    +
    +
    24kHz, 22.05kHz & 16kHz
    +Stereo/Mono: 8-160kbps
    +
    +
    +

    Why doesn't the VBR mode work the same as MP3VBR? The Short Answer

    +
    +

    Why can't the bitrate vary from 32kbps to 384kbps for every file?

    +

    According to the standard (ISO/IEC 11172-3:1993) Section 2.4.2.3

    +
    +
    +
    "In order to provide the smallest possible delay and complexity, the
    + decoder is not required to support a continuously variable bitrate when
    + in layer I or II.  Layer III supports variable bitrate by switching the
    + bitrate index."
    +
    +
    +
    +
    and
    +
    +
    +
    +
    "For Layer II, not all combinations of total bitrate and mode are allowed."
    +
    +

    Hence, most LayerII coders would not have been written with VBR in mind, and +LayerII VBR is a hack. It works for limited cases. Getting it to work to +the same extent as MP3-style VBR will be a major hack.

    +

    (If you really want better bitrate ranges, read "The Long Answer" and submit your mega-patch.)

    +
    +

    Why doesn't the VBR mode work the same as MP3VBR? The Long Answer

    +
    +

    Why can't the bitrate vary from 32kbps to 384kbps for every file?

    +

    Reason 1: The standard limits the range

    +

    As quoted above from the standard for 48/44.1/32kHz:

    +
    +
    +
    "For Layer II, not all combinations of total bitrate and mode are allowed. See
    + the following table."
    +
    +
    +
    +
    Bitrate         Allowed Modes
    +(kbps)
    +32              mono only
    +48              mono only
    +56              mono only
    +64              all modes
    +80              mono only
    +96              all modes
    +112             all modes
    +128             all modes
    +160             all modes
    +192             all modes
    +224             stereo only
    +256             stereo only
    +320             stereo only
    +384             stereo only
    +
    +

    So based upon this table alone, you could have VBR stereo encoding which varies +smoothly from 96 to 384kbps. Or you could have have VBR mono encoding which varies from +32 to 192kbps. But since the top and bottom bitrates don't apply to all modes, it would +be impossible to have a stereo file encoded from 32 to 384 kbps.

    +

    But this isn't what is really limiting the allowable bitrate range - the bit allocation +tables are the major hurdle.

    +

    Reason 2: The bit allocation tables don't allow it

    +

    From the standard, Section 2.4.3.3.1 "Bit allocation decoding"

    +
    +
    +
    "For different combinations of bitrate and sampling frequency, different bit
    + allocation tables exist.
    +
    +

    These bit allocation tables are pre-determined tables (in Annex B of the standard) which +indicate

    +
      +
    • +

      +how many bits to read for the initial data (2,3 or 4) +

      +
    • +
    • +

      +these bits are then used as an index back into the table to + find the number of quantize levels for the samples in this subband +

      +
    • +
    +

    But the table used (and hence the number of bits and the calculated index) are different +for different combinations of bitrate and sampling frequency.

    +

    I will use TableB.2a as an example.

    +

    Table B.2a Applies for the following combinations.

    +
    +
    +
    Sampling Freq           Bitrates in (kbps/channel) [emphasis: this is a PER CHANNEL bitrate]
    +48                      56, 64, 80, 96, 112, 128, 160, 192
    +44.1                    56, 64, 80
    +32                      56, 64, 80
    +
    +

    If we have a STEREO 48kHz input file, and we use this table, then the bitrates +we could calculate from this would be 112, 128, 160, 192, 224, 256, 320 and 384 kbps.

    +

    This table contains no information on how to encode stuff at bitrates less than 112kbps +(for a stereo file). You would have to load allocation table B.2c to encode stereo at +64kbps and 128kbps.

    +

    Since it would be a MAJOR piece of hacking to get the different tables shifted in and out +during the encoding process, once an allocation table is loaded IT IS NOT CHANGED.

    +

    Hence, the best table is picked at the start of the encoding process, and the encoder +is stuck with it for the rest of the encode.

    +

    For twolame-02j, I have picked the table it loads for different +sampling frequencies in order to optimize the range of bitrates possible.

    +
    +
    +
    48 kHz - Table B.2a
    +         Stereo Bitrate Range: 112 - 384
    +         Mono Bitrate Range : 56 - 192
    +
    +
    +
    +
    44.1/32 kHz - Table B.2b
    +        Stereo Bitrate Range: 192 - 384
    +        Mono Bitrate Range: 96 - 192
    +
    +
    +
    +
    24/22.05/16 kHz - LSF Table (Standard ISO/IEC 13818.3:1995 Annex B, Table B.1)
    +        There is only 1 table for the Lower Sampling Frequencies
    +        All modes (mono and stereo) are allowable at all bitrates
    +        So at the Lower Sampling Frequencies you *can* have a completely variable
    +        bitrate over the entire range.
    +
    +
    +

    Tech Stuff

    +
    +

    The VBR mode is mainly centered around the main_bit_allocation() and +a_bit_allocation() routines in encode.c.

    +

    The limited range of VBR is due to my particular implementation which restricts +ranges to within one alloc table (see tables B.2a, B.2b, B.2c and B.2d in ISO 11172). +The VBR range for 32/44.1khz lies within B.2b, and the 48khz VBR lies within table B.2a.

    +

    I'm not sure whether it is worth extending these ranges down to lower bitrates. +The work required to switch alloc tables during the encoding is major.

    +

    In the case of silence, it might be worth doing a quick check for very low signals +and writing a pre-calculated blank 32kpbs frame. [probably also a lot of work].

    +
    +

    How CBR works

    +
    +
      +
    • +

      +Use the psycho model to determine the MNRs for each subband + [MNR = the ratio of "masking" to "noise"] + (From an encoding perspective, a bigger MNR in a subband means that + it sounds better since the noise is more masked)) +

      +
    • +
    • +

      +calculate the available data bits (adb) for this bitrate. +

      +
    • +
    • +

      +Based upon the MNR (Masking:Noise Ratio) values, allocate bits to each + subband +

      +
    • +
    • +

      +Keep increasing the bits to whichever subband currently has the min MNR + value until we have no bits left. +

      +
    • +
    • +

      +This mode does not guarentee that all the subbands are without noise + ie there may still be subbands with MNR less than 0.0 (noisy!) +

      +
    • +
    +
    +

    How VBR works

    +
    +
      +
    • +

      +pretend we have lots of bits to spare, and work out the bits which would + raise the MNR in each subband to the level given by the argument on the + command line "-v [int]" +

      +
    • +
    • +

      +Pick the bitrate which has more bits than the required_bits we just calculated +

      +
    • +
    • +

      +calculate a_bit_allocation() +

      +
    • +
    • +

      +VBR "guarantees" that all subbands have MNR > VBRLEVEL or that we have + reached the maximum bitrate. +

      +
    • +
    +
    +

    FUTURE

    +
    +
      +
    • +

      +with this VBR mode, we know the bits aren't going to run out, so we can + just assign them "greedily". +

      +
    • +
    • +

      +VBR_a_bit_allocation() is yet to be written :) +

      +
    • +
    +
    + + + diff --git a/lib-src/twolame/win32/libtwolame_dll.sln b/lib-src/twolame/win32/libtwolame_dll.sln index d70501a3a..c0a0b75e5 100644 --- a/lib-src/twolame/win32/libtwolame_dll.sln +++ b/lib-src/twolame/win32/libtwolame_dll.sln @@ -1,20 +1,20 @@ - -Microsoft Visual Studio Solution File, Format Version 9.00 -# Visual C++ Express 2005 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libtwolame_dll", "libtwolame_dll.vcproj", "{DFB06356-061D-4EAD-82F5-4696149B6F01}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {DFB06356-061D-4EAD-82F5-4696149B6F01}.Debug|Win32.ActiveCfg = Debug|Win32 - {DFB06356-061D-4EAD-82F5-4696149B6F01}.Debug|Win32.Build.0 = Debug|Win32 - {DFB06356-061D-4EAD-82F5-4696149B6F01}.Release|Win32.ActiveCfg = Release|Win32 - {DFB06356-061D-4EAD-82F5-4696149B6F01}.Release|Win32.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual C++ Express 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libtwolame_dll", "libtwolame_dll.vcproj", "{DFB06356-061D-4EAD-82F5-4696149B6F01}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DFB06356-061D-4EAD-82F5-4696149B6F01}.Debug|Win32.ActiveCfg = Debug|Win32 + {DFB06356-061D-4EAD-82F5-4696149B6F01}.Debug|Win32.Build.0 = Debug|Win32 + {DFB06356-061D-4EAD-82F5-4696149B6F01}.Release|Win32.ActiveCfg = Release|Win32 + {DFB06356-061D-4EAD-82F5-4696149B6F01}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/lib-src/twolame/win32/libtwolame_dll.vcproj b/lib-src/twolame/win32/libtwolame_dll.vcproj index 2b4d05c5c..5cd3bd71a 100644 --- a/lib-src/twolame/win32/libtwolame_dll.vcproj +++ b/lib-src/twolame/win32/libtwolame_dll.vcproj @@ -1,367 +1,367 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib-src/twolame/win32/libtwolame_static.sln b/lib-src/twolame/win32/libtwolame_static.sln index df6fde58f..3b0326750 100644 --- a/lib-src/twolame/win32/libtwolame_static.sln +++ b/lib-src/twolame/win32/libtwolame_static.sln @@ -1,20 +1,20 @@ - -Microsoft Visual Studio Solution File, Format Version 9.00 -# Visual C++ Express 2005 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libtwolame_static", "libtwolame_static.vcproj", "{8C69F7B6-684F-48D9-9057-8912CA3DAA8B}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {8C69F7B6-684F-48D9-9057-8912CA3DAA8B}.Debug|Win32.ActiveCfg = Debug|Win32 - {8C69F7B6-684F-48D9-9057-8912CA3DAA8B}.Debug|Win32.Build.0 = Debug|Win32 - {8C69F7B6-684F-48D9-9057-8912CA3DAA8B}.Release|Win32.ActiveCfg = Release|Win32 - {8C69F7B6-684F-48D9-9057-8912CA3DAA8B}.Release|Win32.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual C++ Express 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libtwolame_static", "libtwolame_static.vcproj", "{8C69F7B6-684F-48D9-9057-8912CA3DAA8B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {8C69F7B6-684F-48D9-9057-8912CA3DAA8B}.Debug|Win32.ActiveCfg = Debug|Win32 + {8C69F7B6-684F-48D9-9057-8912CA3DAA8B}.Debug|Win32.Build.0 = Debug|Win32 + {8C69F7B6-684F-48D9-9057-8912CA3DAA8B}.Release|Win32.ActiveCfg = Release|Win32 + {8C69F7B6-684F-48D9-9057-8912CA3DAA8B}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/lib-src/twolame/win32/libtwolame_static.vcproj b/lib-src/twolame/win32/libtwolame_static.vcproj index b873e0f9e..87e2db0c1 100644 --- a/lib-src/twolame/win32/libtwolame_static.vcproj +++ b/lib-src/twolame/win32/libtwolame_static.vcproj @@ -1,647 +1,647 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/FileIO.cpp b/src/FileIO.cpp old mode 100755 new mode 100644 diff --git a/src/FileIO.h b/src/FileIO.h old mode 100755 new mode 100644 diff --git a/src/UploadDialog.cpp b/src/UploadDialog.cpp old mode 100755 new mode 100644 diff --git a/src/UploadDialog.h b/src/UploadDialog.h old mode 100755 new mode 100644 diff --git a/src/widgets/HtmlWindow.cpp b/src/widgets/HtmlWindow.cpp old mode 100755 new mode 100644 diff --git a/src/widgets/ProgressDialog.cpp b/src/widgets/ProgressDialog.cpp old mode 100755 new mode 100644 diff --git a/src/widgets/ProgressDialog.h b/src/widgets/ProgressDialog.h old mode 100755 new mode 100644 diff --git a/win/LADSPA_plugins-win/LADSPA_plugins-win.sln b/win/LADSPA_plugins-win/LADSPA_plugins-win.sln index a86c22499..88510c0fe 100644 --- a/win/LADSPA_plugins-win/LADSPA_plugins-win.sln +++ b/win/LADSPA_plugins-win/LADSPA_plugins-win.sln @@ -1,20 +1,20 @@ - -Microsoft Visual Studio Solution File, Format Version 9.00 -# Visual Studio 2005 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LADSPA_plugins-win", "LADSPA_plugins-win.vcproj", "{9ECDF3B4-5266-4F8D-8AB4-53087BBBB2E6}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {9ECDF3B4-5266-4F8D-8AB4-53087BBBB2E6}.Debug|Win32.ActiveCfg = Debug|Win32 - {9ECDF3B4-5266-4F8D-8AB4-53087BBBB2E6}.Debug|Win32.Build.0 = Debug|Win32 - {9ECDF3B4-5266-4F8D-8AB4-53087BBBB2E6}.Release|Win32.ActiveCfg = Release|Win32 - {9ECDF3B4-5266-4F8D-8AB4-53087BBBB2E6}.Release|Win32.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LADSPA_plugins-win", "LADSPA_plugins-win.vcproj", "{9ECDF3B4-5266-4F8D-8AB4-53087BBBB2E6}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9ECDF3B4-5266-4F8D-8AB4-53087BBBB2E6}.Debug|Win32.ActiveCfg = Debug|Win32 + {9ECDF3B4-5266-4F8D-8AB4-53087BBBB2E6}.Debug|Win32.Build.0 = Debug|Win32 + {9ECDF3B4-5266-4F8D-8AB4-53087BBBB2E6}.Release|Win32.ActiveCfg = Release|Win32 + {9ECDF3B4-5266-4F8D-8AB4-53087BBBB2E6}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/win/LADSPA_plugins-win/LADSPA_plugins-win.vcproj b/win/LADSPA_plugins-win/LADSPA_plugins-win.vcproj index a34ede700..bd0eb3427 100644 --- a/win/LADSPA_plugins-win/LADSPA_plugins-win.vcproj +++ b/win/LADSPA_plugins-win/LADSPA_plugins-win.vcproj @@ -1,77 +1,77 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win/Projects/Audacity/Audacity.vcproj b/win/Projects/Audacity/Audacity.vcproj index e16907c7d..2cc5559d6 100644 --- a/win/Projects/Audacity/Audacity.vcproj +++ b/win/Projects/Audacity/Audacity.vcproj @@ -1,3142 +1,3142 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win/Projects/allegro/allegro.vcproj b/win/Projects/allegro/allegro.vcproj index 44814d6ea..89edc6907 100644 --- a/win/Projects/allegro/allegro.vcproj +++ b/win/Projects/allegro/allegro.vcproj @@ -1,358 +1,358 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win/Projects/expat/expat.vcproj b/win/Projects/expat/expat.vcproj index 7aec59555..3ae26ef18 100644 --- a/win/Projects/expat/expat.vcproj +++ b/win/Projects/expat/expat.vcproj @@ -1,317 +1,317 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win/Projects/filedialog/filedialog.vcproj b/win/Projects/filedialog/filedialog.vcproj index cdf3841de..7c1bb55a4 100644 --- a/win/Projects/filedialog/filedialog.vcproj +++ b/win/Projects/filedialog/filedialog.vcproj @@ -1,318 +1,318 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win/Projects/help/help.vcproj b/win/Projects/help/help.vcproj index 8e624eb91..840cbcea3 100644 --- a/win/Projects/help/help.vcproj +++ b/win/Projects/help/help.vcproj @@ -1,105 +1,105 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win/Projects/libflac++/libflac++.vcproj b/win/Projects/libflac++/libflac++.vcproj index c1e68af39..70ea377af 100644 --- a/win/Projects/libflac++/libflac++.vcproj +++ b/win/Projects/libflac++/libflac++.vcproj @@ -1,321 +1,321 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win/Projects/libflac/libflac.vcproj b/win/Projects/libflac/libflac.vcproj index 07c282de3..1d57080c5 100644 --- a/win/Projects/libflac/libflac.vcproj +++ b/win/Projects/libflac/libflac.vcproj @@ -1,397 +1,397 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win/Projects/libid3tag/libid3tag.vcproj b/win/Projects/libid3tag/libid3tag.vcproj index 61449a1f2..ef48e4390 100644 --- a/win/Projects/libid3tag/libid3tag.vcproj +++ b/win/Projects/libid3tag/libid3tag.vcproj @@ -1,441 +1,441 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win/Projects/liblrdf/liblrdf.vcproj b/win/Projects/liblrdf/liblrdf.vcproj index 68e172cf6..e871f930e 100644 --- a/win/Projects/liblrdf/liblrdf.vcproj +++ b/win/Projects/liblrdf/liblrdf.vcproj @@ -1,325 +1,325 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win/Projects/libmad/libmad.vcproj b/win/Projects/libmad/libmad.vcproj index 1580c7799..3aa750d7a 100644 --- a/win/Projects/libmad/libmad.vcproj +++ b/win/Projects/libmad/libmad.vcproj @@ -1,397 +1,397 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win/Projects/libnyquist/libnyquist.vcproj b/win/Projects/libnyquist/libnyquist.vcproj index b2d2beffe..961ce4daa 100644 --- a/win/Projects/libnyquist/libnyquist.vcproj +++ b/win/Projects/libnyquist/libnyquist.vcproj @@ -1,1185 +1,1185 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win/Projects/libogg/libogg.vcproj b/win/Projects/libogg/libogg.vcproj index 36c994913..207606faa 100644 --- a/win/Projects/libogg/libogg.vcproj +++ b/win/Projects/libogg/libogg.vcproj @@ -1,309 +1,309 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win/Projects/librdf/librdf.vcproj b/win/Projects/librdf/librdf.vcproj index 69bfa676f..73060d4ac 100644 --- a/win/Projects/librdf/librdf.vcproj +++ b/win/Projects/librdf/librdf.vcproj @@ -1,597 +1,597 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win/Projects/libresample/libresample.vcproj b/win/Projects/libresample/libresample.vcproj index 3472cb361..8621351de 100644 --- a/win/Projects/libresample/libresample.vcproj +++ b/win/Projects/libresample/libresample.vcproj @@ -1,313 +1,313 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win/Projects/libsamplerate/libsamplerate.vcproj b/win/Projects/libsamplerate/libsamplerate.vcproj index cd4d2a81c..80f1f085a 100644 --- a/win/Projects/libsamplerate/libsamplerate.vcproj +++ b/win/Projects/libsamplerate/libsamplerate.vcproj @@ -1,333 +1,333 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win/Projects/libscorealign/libscorealign.vcproj b/win/Projects/libscorealign/libscorealign.vcproj index d30d8a75f..a404775ea 100644 --- a/win/Projects/libscorealign/libscorealign.vcproj +++ b/win/Projects/libscorealign/libscorealign.vcproj @@ -1,381 +1,381 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win/Projects/libsndfile/libsndfile.vcproj b/win/Projects/libsndfile/libsndfile.vcproj index 8ae6bc19e..2b86ac962 100644 --- a/win/Projects/libsndfile/libsndfile.vcproj +++ b/win/Projects/libsndfile/libsndfile.vcproj @@ -1,673 +1,673 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win/Projects/libvamp/libvamp.vcproj b/win/Projects/libvamp/libvamp.vcproj index 698a9f6b2..85dceef2c 100644 --- a/win/Projects/libvamp/libvamp.vcproj +++ b/win/Projects/libvamp/libvamp.vcproj @@ -1,373 +1,373 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win/Projects/libvorbis/libvorbis.vcproj b/win/Projects/libvorbis/libvorbis.vcproj index 967076299..ee294174a 100644 --- a/win/Projects/libvorbis/libvorbis.vcproj +++ b/win/Projects/libvorbis/libvorbis.vcproj @@ -1,469 +1,469 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win/Projects/locale/locale.vcproj b/win/Projects/locale/locale.vcproj index 6f69308ac..cbf2ea7fd 100644 --- a/win/Projects/locale/locale.vcproj +++ b/win/Projects/locale/locale.vcproj @@ -1,1295 +1,1295 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win/Projects/mod-script-pipe/mod-script-pipe.vcproj b/win/Projects/mod-script-pipe/mod-script-pipe.vcproj index a9cc99327..d49aaf001 100644 --- a/win/Projects/mod-script-pipe/mod-script-pipe.vcproj +++ b/win/Projects/mod-script-pipe/mod-script-pipe.vcproj @@ -1,343 +1,343 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win/Projects/portaudio-v19/portaudio-v19.vcproj b/win/Projects/portaudio-v19/portaudio-v19.vcproj index ad0d2db0d..7ce942556 100644 --- a/win/Projects/portaudio-v19/portaudio-v19.vcproj +++ b/win/Projects/portaudio-v19/portaudio-v19.vcproj @@ -1,737 +1,737 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win/Projects/portmidi/portmidi.vcproj b/win/Projects/portmidi/portmidi.vcproj index 69beff8e8..40a3ae56b 100644 --- a/win/Projects/portmidi/portmidi.vcproj +++ b/win/Projects/portmidi/portmidi.vcproj @@ -1,337 +1,337 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win/Projects/portmixer/portmixer.vcproj b/win/Projects/portmixer/portmixer.vcproj index 17712ff02..1885aee7f 100644 --- a/win/Projects/portmixer/portmixer.vcproj +++ b/win/Projects/portmixer/portmixer.vcproj @@ -1,377 +1,377 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win/Projects/portsmf/portsmf.vcproj b/win/Projects/portsmf/portsmf.vcproj index e9a01384a..32decd9f9 100644 --- a/win/Projects/portsmf/portsmf.vcproj +++ b/win/Projects/portsmf/portsmf.vcproj @@ -1,333 +1,333 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win/Projects/raptor/raptor.vcproj b/win/Projects/raptor/raptor.vcproj index 070ffeb4c..0897a9153 100644 --- a/win/Projects/raptor/raptor.vcproj +++ b/win/Projects/raptor/raptor.vcproj @@ -1,485 +1,485 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win/Projects/rasqal/rasqal.vcproj b/win/Projects/rasqal/rasqal.vcproj index 82572ac22..dd3108d37 100644 --- a/win/Projects/rasqal/rasqal.vcproj +++ b/win/Projects/rasqal/rasqal.vcproj @@ -1,401 +1,401 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win/Projects/sbsms/sbsms.vcproj b/win/Projects/sbsms/sbsms.vcproj index d790c2cd6..fffa28683 100644 --- a/win/Projects/sbsms/sbsms.vcproj +++ b/win/Projects/sbsms/sbsms.vcproj @@ -1,401 +1,401 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win/Projects/slv2/slv2.vcproj b/win/Projects/slv2/slv2.vcproj index 497cfafa6..479d2e16c 100644 --- a/win/Projects/slv2/slv2.vcproj +++ b/win/Projects/slv2/slv2.vcproj @@ -1,441 +1,441 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win/Projects/soundtouch/soundtouch.vcproj b/win/Projects/soundtouch/soundtouch.vcproj index 4dfbaf3ce..aac3c2b37 100644 --- a/win/Projects/soundtouch/soundtouch.vcproj +++ b/win/Projects/soundtouch/soundtouch.vcproj @@ -1,365 +1,365 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win/Projects/taglib/taglib.vcproj b/win/Projects/taglib/taglib.vcproj index 5733d650c..745171943 100644 --- a/win/Projects/taglib/taglib.vcproj +++ b/win/Projects/taglib/taglib.vcproj @@ -1,934 +1,934 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win/Projects/twolame/twolame.vcproj b/win/Projects/twolame/twolame.vcproj index dfd327ed6..51608047e 100644 --- a/win/Projects/twolame/twolame.vcproj +++ b/win/Projects/twolame/twolame.vcproj @@ -1,466 +1,466 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win/audacity.sln b/win/audacity.sln index 456acc051..fcc4a7efc 100644 --- a/win/audacity.sln +++ b/win/audacity.sln @@ -1,340 +1,340 @@ -Microsoft Visual Studio Solution File, Format Version 10.00 -# Visual Studio 2008 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Audacity", "Projects\Audacity\Audacity.vcproj", "{1D64095C-F936-4FCF-B609-56E9DDF941FA}" - ProjectSection(ProjectDependencies) = postProject - {8A1C2514-85DD-4AE2-9CF3-3183B66C537D} = {8A1C2514-85DD-4AE2-9CF3-3183B66C537D} - {A64FFB5D-0CF0-43EE-9DE3-C72260864BFF} = {A64FFB5D-0CF0-43EE-9DE3-C72260864BFF} - {D5AB2D87-51DC-4277-A9AB-2A6018D0E947} = {D5AB2D87-51DC-4277-A9AB-2A6018D0E947} - {C0FE933B-4AF7-4ACD-95E8-ACD3A73F1400} = {C0FE933B-4AF7-4ACD-95E8-ACD3A73F1400} - {7E111491-6A07-4661-90CD-6DEBB83CE755} = {7E111491-6A07-4661-90CD-6DEBB83CE755} - {F1E127C2-58B1-4CBF-B91F-0CF6DB9CC6DD} = {F1E127C2-58B1-4CBF-B91F-0CF6DB9CC6DD} - {7BAFA434-3257-408A-AAC0-A8D352B2CE54} = {7BAFA434-3257-408A-AAC0-A8D352B2CE54} - {EC3F5835-C486-4970-8A6B-A0700F4B3637} = {EC3F5835-C486-4970-8A6B-A0700F4B3637} - {6C7DC635-26FB-419A-B69A-7ECBBB068245} = {6C7DC635-26FB-419A-B69A-7ECBBB068245} - {B28C9F3F-FF0E-4FEC-844C-685390B8AC06} = {B28C9F3F-FF0E-4FEC-844C-685390B8AC06} - {5284D863-3813-479F-BBF0-AC234E216BC6} = {5284D863-3813-479F-BBF0-AC234E216BC6} - {F4B4A272-4ED3-4951-A6EE-B7BAAC1C4952} = {F4B4A272-4ED3-4951-A6EE-B7BAAC1C4952} - {727D6675-67EE-4D0B-9DC1-177A0AF741F0} = {727D6675-67EE-4D0B-9DC1-177A0AF741F0} - {7ABA0F80-94AE-4E82-AB89-2E1258212D59} = {7ABA0F80-94AE-4E82-AB89-2E1258212D59} - {3A76129B-55AB-4D54-BAA7-08F63ED52569} = {3A76129B-55AB-4D54-BAA7-08F63ED52569} - {A52BBEA5-8B02-4147-8734-5D9BBF4D1177} = {A52BBEA5-8B02-4147-8734-5D9BBF4D1177} - {3DDDCAA9-276D-4FC3-A15C-485F7B9B24CC} = {3DDDCAA9-276D-4FC3-A15C-485F7B9B24CC} - {38C2C6B1-FBF8-4C5C-BB90-63F996083F56} = {38C2C6B1-FBF8-4C5C-BB90-63F996083F56} - {8C69F7B6-684F-48D9-9057-8912CA3DAA8B} = {8C69F7B6-684F-48D9-9057-8912CA3DAA8B} - {D96C7BE1-E3F1-4767-BBBB-320E082CE425} = {D96C7BE1-E3F1-4767-BBBB-320E082CE425} - {7AA41BED-41B0-427A-9148-DEA40549D158} = {7AA41BED-41B0-427A-9148-DEA40549D158} - {A61E2BF1-21AA-4118-B0D8-FD3D53DB892E} = {A61E2BF1-21AA-4118-B0D8-FD3D53DB892E} - {F00717F2-67C8-44E1-AF00-541DFA9CB7F2} = {F00717F2-67C8-44E1-AF00-541DFA9CB7F2} - {A939AAF8-44F1-4CE7-9DD0-7A6E99814857} = {A939AAF8-44F1-4CE7-9DD0-7A6E99814857} - {BEF965EB-6330-4D18-858C-3B9F66CA9F18} = {BEF965EB-6330-4D18-858C-3B9F66CA9F18} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "soundtouch", "Projects\soundtouch\soundtouch.vcproj", "{EC3F5835-C486-4970-8A6B-A0700F4B3637}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "expat", "Projects\expat\expat.vcproj", "{38C2C6B1-FBF8-4C5C-BB90-63F996083F56}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libflac", "Projects\libflac\libflac.vcproj", "{6C7DC635-26FB-419A-B69A-7ECBBB068245}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libflac++", "Projects\libflac++\libflac++.vcproj", "{B28C9F3F-FF0E-4FEC-844C-685390B8AC06}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libid3tag", "Projects\libid3tag\libid3tag.vcproj", "{D96C7BE1-E3F1-4767-BBBB-320E082CE425}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmad", "Projects\libmad\libmad.vcproj", "{A52BBEA5-8B02-4147-8734-5D9BBF4D1177}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libnyquist", "Projects\libnyquist\libnyquist.vcproj", "{7AA41BED-41B0-427A-9148-DEA40549D158}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libresample", "Projects\libresample\libresample.vcproj", "{F00717F2-67C8-44E1-AF00-541DFA9CB7F2}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libsamplerate", "Projects\libsamplerate\libsamplerate.vcproj", "{3DDDCAA9-276D-4FC3-A15C-485F7B9B24CC}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libsndfile", "Projects\libsndfile\libsndfile.vcproj", "{F4B4A272-4ED3-4951-A6EE-B7BAAC1C4952}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libogg", "Projects\libogg\libogg.vcproj", "{A939AAF8-44F1-4CE7-9DD0-7A6E99814857}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "portmixer", "Projects\portmixer\portmixer.vcproj", "{3A76129B-55AB-4D54-BAA7-08F63ED52569}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libvorbis", "Projects\libvorbis\libvorbis.vcproj", "{727D6675-67EE-4D0B-9DC1-177A0AF741F0}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "portaudio-v19", "Projects\portaudio-v19\portaudio-v19.vcproj", "{7ABA0F80-94AE-4E82-AB89-2E1258212D59}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "locale", "Projects\locale\locale.vcproj", "{BE9F28C5-058A-45F5-B2C1-D077BC058AAE}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "filedialog", "Projects\filedialog\filedialog.vcproj", "{5284D863-3813-479F-BBF0-AC234E216BC6}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod-script-pipe", "Projects\mod-script-pipe\mod-script-pipe.vcproj", "{85774A29-EA2F-4A40-994F-6BE593D847A5}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libvamp", "Projects\libvamp\libvamp.vcproj", "{A61E2BF1-21AA-4118-B0D8-FD3D53DB892E}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "twolame", "Projects\twolame\twolame.vcproj", "{8C69F7B6-684F-48D9-9057-8912CA3DAA8B}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "liblrdf", "Projects\liblrdf\liblrdf.vcproj", "{7BAFA434-3257-408A-AAC0-A8D352B2CE54}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "librdf", "Projects\librdf\librdf.vcproj", "{F1E127C2-58B1-4CBF-B91F-0CF6DB9CC6DD}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "raptor", "Projects\raptor\raptor.vcproj", "{7E111491-6A07-4661-90CD-6DEBB83CE755}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rasqal", "Projects\rasqal\rasqal.vcproj", "{BEF965EB-6330-4D18-858C-3B9F66CA9F18}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "slv2", "Projects\slv2\slv2.vcproj", "{0FEC8848-E24E-4FA5-9ACD-E4582DC4CBBE}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "portsmf", "Projects\portsmf\portsmf.vcproj", "{8A1C2514-85DD-4AE2-9CF3-3183B66C537D}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sbsms", "Projects\sbsms\sbsms.vcproj", "{A64FFB5D-0CF0-43EE-9DE3-C72260864BFF}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "taglib", "Projects\taglib\taglib.vcproj", "{D912E7BF-61FE-4D17-9D1B-3F1D268429D6}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libscorealign", "Projects\libscorealign\libscorealign.vcproj", "{C0FE933B-4AF7-4ACD-95E8-ACD3A73F1400}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "portmidi", "Projects\portmidi\portmidi.vcproj", "{D5AB2D87-51DC-4277-A9AB-2A6018D0E947}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "help", "Projects\help\help.vcproj", "{02F94A40-586A-4403-8464-13B50801FFEC}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - Unicode Debug|Win32 = Unicode Debug|Win32 - Unicode Release|Win32 = Unicode Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {1D64095C-F936-4FCF-B609-56E9DDF941FA}.Debug|Win32.ActiveCfg = Debug|Win32 - {1D64095C-F936-4FCF-B609-56E9DDF941FA}.Debug|Win32.Build.0 = Debug|Win32 - {1D64095C-F936-4FCF-B609-56E9DDF941FA}.Release|Win32.ActiveCfg = Release|Win32 - {1D64095C-F936-4FCF-B609-56E9DDF941FA}.Release|Win32.Build.0 = Release|Win32 - {1D64095C-F936-4FCF-B609-56E9DDF941FA}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 - {1D64095C-F936-4FCF-B609-56E9DDF941FA}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 - {1D64095C-F936-4FCF-B609-56E9DDF941FA}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 - {1D64095C-F936-4FCF-B609-56E9DDF941FA}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 - {EC3F5835-C486-4970-8A6B-A0700F4B3637}.Debug|Win32.ActiveCfg = Debug|Win32 - {EC3F5835-C486-4970-8A6B-A0700F4B3637}.Debug|Win32.Build.0 = Debug|Win32 - {EC3F5835-C486-4970-8A6B-A0700F4B3637}.Release|Win32.ActiveCfg = Release|Win32 - {EC3F5835-C486-4970-8A6B-A0700F4B3637}.Release|Win32.Build.0 = Release|Win32 - {EC3F5835-C486-4970-8A6B-A0700F4B3637}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 - {EC3F5835-C486-4970-8A6B-A0700F4B3637}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 - {EC3F5835-C486-4970-8A6B-A0700F4B3637}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 - {EC3F5835-C486-4970-8A6B-A0700F4B3637}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 - {38C2C6B1-FBF8-4C5C-BB90-63F996083F56}.Debug|Win32.ActiveCfg = Debug|Win32 - {38C2C6B1-FBF8-4C5C-BB90-63F996083F56}.Release|Win32.ActiveCfg = Release|Win32 - {38C2C6B1-FBF8-4C5C-BB90-63F996083F56}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 - {38C2C6B1-FBF8-4C5C-BB90-63F996083F56}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 - {6C7DC635-26FB-419A-B69A-7ECBBB068245}.Debug|Win32.ActiveCfg = Debug|Win32 - {6C7DC635-26FB-419A-B69A-7ECBBB068245}.Debug|Win32.Build.0 = Debug|Win32 - {6C7DC635-26FB-419A-B69A-7ECBBB068245}.Release|Win32.ActiveCfg = Release|Win32 - {6C7DC635-26FB-419A-B69A-7ECBBB068245}.Release|Win32.Build.0 = Release|Win32 - {6C7DC635-26FB-419A-B69A-7ECBBB068245}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 - {6C7DC635-26FB-419A-B69A-7ECBBB068245}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 - {6C7DC635-26FB-419A-B69A-7ECBBB068245}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 - {6C7DC635-26FB-419A-B69A-7ECBBB068245}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 - {B28C9F3F-FF0E-4FEC-844C-685390B8AC06}.Debug|Win32.ActiveCfg = Debug|Win32 - {B28C9F3F-FF0E-4FEC-844C-685390B8AC06}.Debug|Win32.Build.0 = Debug|Win32 - {B28C9F3F-FF0E-4FEC-844C-685390B8AC06}.Release|Win32.ActiveCfg = Release|Win32 - {B28C9F3F-FF0E-4FEC-844C-685390B8AC06}.Release|Win32.Build.0 = Release|Win32 - {B28C9F3F-FF0E-4FEC-844C-685390B8AC06}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 - {B28C9F3F-FF0E-4FEC-844C-685390B8AC06}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 - {B28C9F3F-FF0E-4FEC-844C-685390B8AC06}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 - {B28C9F3F-FF0E-4FEC-844C-685390B8AC06}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 - {D96C7BE1-E3F1-4767-BBBB-320E082CE425}.Debug|Win32.ActiveCfg = Debug|Win32 - {D96C7BE1-E3F1-4767-BBBB-320E082CE425}.Debug|Win32.Build.0 = Debug|Win32 - {D96C7BE1-E3F1-4767-BBBB-320E082CE425}.Release|Win32.ActiveCfg = Release|Win32 - {D96C7BE1-E3F1-4767-BBBB-320E082CE425}.Release|Win32.Build.0 = Release|Win32 - {D96C7BE1-E3F1-4767-BBBB-320E082CE425}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 - {D96C7BE1-E3F1-4767-BBBB-320E082CE425}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 - {D96C7BE1-E3F1-4767-BBBB-320E082CE425}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 - {D96C7BE1-E3F1-4767-BBBB-320E082CE425}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 - {A52BBEA5-8B02-4147-8734-5D9BBF4D1177}.Debug|Win32.ActiveCfg = Debug|Win32 - {A52BBEA5-8B02-4147-8734-5D9BBF4D1177}.Debug|Win32.Build.0 = Debug|Win32 - {A52BBEA5-8B02-4147-8734-5D9BBF4D1177}.Release|Win32.ActiveCfg = Release|Win32 - {A52BBEA5-8B02-4147-8734-5D9BBF4D1177}.Release|Win32.Build.0 = Release|Win32 - {A52BBEA5-8B02-4147-8734-5D9BBF4D1177}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 - {A52BBEA5-8B02-4147-8734-5D9BBF4D1177}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 - {A52BBEA5-8B02-4147-8734-5D9BBF4D1177}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 - {A52BBEA5-8B02-4147-8734-5D9BBF4D1177}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 - {7AA41BED-41B0-427A-9148-DEA40549D158}.Debug|Win32.ActiveCfg = Debug|Win32 - {7AA41BED-41B0-427A-9148-DEA40549D158}.Debug|Win32.Build.0 = Debug|Win32 - {7AA41BED-41B0-427A-9148-DEA40549D158}.Release|Win32.ActiveCfg = Release|Win32 - {7AA41BED-41B0-427A-9148-DEA40549D158}.Release|Win32.Build.0 = Release|Win32 - {7AA41BED-41B0-427A-9148-DEA40549D158}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 - {7AA41BED-41B0-427A-9148-DEA40549D158}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 - {7AA41BED-41B0-427A-9148-DEA40549D158}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 - {7AA41BED-41B0-427A-9148-DEA40549D158}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 - {F00717F2-67C8-44E1-AF00-541DFA9CB7F2}.Debug|Win32.ActiveCfg = Debug|Win32 - {F00717F2-67C8-44E1-AF00-541DFA9CB7F2}.Debug|Win32.Build.0 = Debug|Win32 - {F00717F2-67C8-44E1-AF00-541DFA9CB7F2}.Release|Win32.ActiveCfg = Release|Win32 - {F00717F2-67C8-44E1-AF00-541DFA9CB7F2}.Release|Win32.Build.0 = Release|Win32 - {F00717F2-67C8-44E1-AF00-541DFA9CB7F2}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 - {F00717F2-67C8-44E1-AF00-541DFA9CB7F2}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 - {F00717F2-67C8-44E1-AF00-541DFA9CB7F2}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 - {F00717F2-67C8-44E1-AF00-541DFA9CB7F2}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 - {3DDDCAA9-276D-4FC3-A15C-485F7B9B24CC}.Debug|Win32.ActiveCfg = Debug|Win32 - {3DDDCAA9-276D-4FC3-A15C-485F7B9B24CC}.Debug|Win32.Build.0 = Debug|Win32 - {3DDDCAA9-276D-4FC3-A15C-485F7B9B24CC}.Release|Win32.ActiveCfg = Release|Win32 - {3DDDCAA9-276D-4FC3-A15C-485F7B9B24CC}.Release|Win32.Build.0 = Release|Win32 - {3DDDCAA9-276D-4FC3-A15C-485F7B9B24CC}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 - {3DDDCAA9-276D-4FC3-A15C-485F7B9B24CC}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 - {3DDDCAA9-276D-4FC3-A15C-485F7B9B24CC}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 - {3DDDCAA9-276D-4FC3-A15C-485F7B9B24CC}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 - {F4B4A272-4ED3-4951-A6EE-B7BAAC1C4952}.Debug|Win32.ActiveCfg = Debug|Win32 - {F4B4A272-4ED3-4951-A6EE-B7BAAC1C4952}.Debug|Win32.Build.0 = Debug|Win32 - {F4B4A272-4ED3-4951-A6EE-B7BAAC1C4952}.Release|Win32.ActiveCfg = Release|Win32 - {F4B4A272-4ED3-4951-A6EE-B7BAAC1C4952}.Release|Win32.Build.0 = Release|Win32 - {F4B4A272-4ED3-4951-A6EE-B7BAAC1C4952}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 - {F4B4A272-4ED3-4951-A6EE-B7BAAC1C4952}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 - {F4B4A272-4ED3-4951-A6EE-B7BAAC1C4952}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 - {F4B4A272-4ED3-4951-A6EE-B7BAAC1C4952}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 - {A939AAF8-44F1-4CE7-9DD0-7A6E99814857}.Debug|Win32.ActiveCfg = Debug|Win32 - {A939AAF8-44F1-4CE7-9DD0-7A6E99814857}.Debug|Win32.Build.0 = Debug|Win32 - {A939AAF8-44F1-4CE7-9DD0-7A6E99814857}.Release|Win32.ActiveCfg = Release|Win32 - {A939AAF8-44F1-4CE7-9DD0-7A6E99814857}.Release|Win32.Build.0 = Release|Win32 - {A939AAF8-44F1-4CE7-9DD0-7A6E99814857}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 - {A939AAF8-44F1-4CE7-9DD0-7A6E99814857}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 - {A939AAF8-44F1-4CE7-9DD0-7A6E99814857}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 - {A939AAF8-44F1-4CE7-9DD0-7A6E99814857}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 - {3A76129B-55AB-4D54-BAA7-08F63ED52569}.Debug|Win32.ActiveCfg = Debug|Win32 - {3A76129B-55AB-4D54-BAA7-08F63ED52569}.Debug|Win32.Build.0 = Debug|Win32 - {3A76129B-55AB-4D54-BAA7-08F63ED52569}.Release|Win32.ActiveCfg = Release|Win32 - {3A76129B-55AB-4D54-BAA7-08F63ED52569}.Release|Win32.Build.0 = Release|Win32 - {3A76129B-55AB-4D54-BAA7-08F63ED52569}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 - {3A76129B-55AB-4D54-BAA7-08F63ED52569}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 - {3A76129B-55AB-4D54-BAA7-08F63ED52569}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 - {3A76129B-55AB-4D54-BAA7-08F63ED52569}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 - {727D6675-67EE-4D0B-9DC1-177A0AF741F0}.Debug|Win32.ActiveCfg = Debug|Win32 - {727D6675-67EE-4D0B-9DC1-177A0AF741F0}.Debug|Win32.Build.0 = Debug|Win32 - {727D6675-67EE-4D0B-9DC1-177A0AF741F0}.Release|Win32.ActiveCfg = Release|Win32 - {727D6675-67EE-4D0B-9DC1-177A0AF741F0}.Release|Win32.Build.0 = Release|Win32 - {727D6675-67EE-4D0B-9DC1-177A0AF741F0}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 - {727D6675-67EE-4D0B-9DC1-177A0AF741F0}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 - {727D6675-67EE-4D0B-9DC1-177A0AF741F0}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 - {727D6675-67EE-4D0B-9DC1-177A0AF741F0}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 - {7ABA0F80-94AE-4E82-AB89-2E1258212D59}.Debug|Win32.ActiveCfg = Debug|Win32 - {7ABA0F80-94AE-4E82-AB89-2E1258212D59}.Debug|Win32.Build.0 = Debug|Win32 - {7ABA0F80-94AE-4E82-AB89-2E1258212D59}.Release|Win32.ActiveCfg = Release|Win32 - {7ABA0F80-94AE-4E82-AB89-2E1258212D59}.Release|Win32.Build.0 = Release|Win32 - {7ABA0F80-94AE-4E82-AB89-2E1258212D59}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 - {7ABA0F80-94AE-4E82-AB89-2E1258212D59}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 - {7ABA0F80-94AE-4E82-AB89-2E1258212D59}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 - {7ABA0F80-94AE-4E82-AB89-2E1258212D59}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 - {BE9F28C5-058A-45F5-B2C1-D077BC058AAE}.Debug|Win32.ActiveCfg = Debug|Win32 - {BE9F28C5-058A-45F5-B2C1-D077BC058AAE}.Release|Win32.ActiveCfg = Release|Win32 - {BE9F28C5-058A-45F5-B2C1-D077BC058AAE}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 - {BE9F28C5-058A-45F5-B2C1-D077BC058AAE}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 - {5284D863-3813-479F-BBF0-AC234E216BC6}.Debug|Win32.ActiveCfg = Debug|Win32 - {5284D863-3813-479F-BBF0-AC234E216BC6}.Debug|Win32.Build.0 = Debug|Win32 - {5284D863-3813-479F-BBF0-AC234E216BC6}.Release|Win32.ActiveCfg = Release|Win32 - {5284D863-3813-479F-BBF0-AC234E216BC6}.Release|Win32.Build.0 = Release|Win32 - {5284D863-3813-479F-BBF0-AC234E216BC6}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 - {5284D863-3813-479F-BBF0-AC234E216BC6}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 - {5284D863-3813-479F-BBF0-AC234E216BC6}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 - {5284D863-3813-479F-BBF0-AC234E216BC6}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 - {85774A29-EA2F-4A40-994F-6BE593D847A5}.Debug|Win32.ActiveCfg = Debug|Win32 - {85774A29-EA2F-4A40-994F-6BE593D847A5}.Debug|Win32.Build.0 = Debug|Win32 - {85774A29-EA2F-4A40-994F-6BE593D847A5}.Release|Win32.ActiveCfg = Release|Win32 - {85774A29-EA2F-4A40-994F-6BE593D847A5}.Release|Win32.Build.0 = Release|Win32 - {85774A29-EA2F-4A40-994F-6BE593D847A5}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 - {85774A29-EA2F-4A40-994F-6BE593D847A5}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 - {85774A29-EA2F-4A40-994F-6BE593D847A5}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 - {85774A29-EA2F-4A40-994F-6BE593D847A5}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 - {A61E2BF1-21AA-4118-B0D8-FD3D53DB892E}.Debug|Win32.ActiveCfg = Debug|Win32 - {A61E2BF1-21AA-4118-B0D8-FD3D53DB892E}.Debug|Win32.Build.0 = Debug|Win32 - {A61E2BF1-21AA-4118-B0D8-FD3D53DB892E}.Release|Win32.ActiveCfg = Release|Win32 - {A61E2BF1-21AA-4118-B0D8-FD3D53DB892E}.Release|Win32.Build.0 = Release|Win32 - {A61E2BF1-21AA-4118-B0D8-FD3D53DB892E}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 - {A61E2BF1-21AA-4118-B0D8-FD3D53DB892E}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 - {A61E2BF1-21AA-4118-B0D8-FD3D53DB892E}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 - {A61E2BF1-21AA-4118-B0D8-FD3D53DB892E}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 - {8C69F7B6-684F-48D9-9057-8912CA3DAA8B}.Debug|Win32.ActiveCfg = Debug|Win32 - {8C69F7B6-684F-48D9-9057-8912CA3DAA8B}.Debug|Win32.Build.0 = Debug|Win32 - {8C69F7B6-684F-48D9-9057-8912CA3DAA8B}.Release|Win32.ActiveCfg = Release|Win32 - {8C69F7B6-684F-48D9-9057-8912CA3DAA8B}.Release|Win32.Build.0 = Release|Win32 - {8C69F7B6-684F-48D9-9057-8912CA3DAA8B}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 - {8C69F7B6-684F-48D9-9057-8912CA3DAA8B}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 - {8C69F7B6-684F-48D9-9057-8912CA3DAA8B}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 - {8C69F7B6-684F-48D9-9057-8912CA3DAA8B}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 - {7BAFA434-3257-408A-AAC0-A8D352B2CE54}.Debug|Win32.ActiveCfg = Debug|Win32 - {7BAFA434-3257-408A-AAC0-A8D352B2CE54}.Debug|Win32.Build.0 = Debug|Win32 - {7BAFA434-3257-408A-AAC0-A8D352B2CE54}.Release|Win32.ActiveCfg = Release|Win32 - {7BAFA434-3257-408A-AAC0-A8D352B2CE54}.Release|Win32.Build.0 = Release|Win32 - {7BAFA434-3257-408A-AAC0-A8D352B2CE54}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 - {7BAFA434-3257-408A-AAC0-A8D352B2CE54}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 - {7BAFA434-3257-408A-AAC0-A8D352B2CE54}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 - {7BAFA434-3257-408A-AAC0-A8D352B2CE54}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 - {F1E127C2-58B1-4CBF-B91F-0CF6DB9CC6DD}.Debug|Win32.ActiveCfg = Debug|Win32 - {F1E127C2-58B1-4CBF-B91F-0CF6DB9CC6DD}.Debug|Win32.Build.0 = Debug|Win32 - {F1E127C2-58B1-4CBF-B91F-0CF6DB9CC6DD}.Release|Win32.ActiveCfg = Release|Win32 - {F1E127C2-58B1-4CBF-B91F-0CF6DB9CC6DD}.Release|Win32.Build.0 = Release|Win32 - {F1E127C2-58B1-4CBF-B91F-0CF6DB9CC6DD}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 - {F1E127C2-58B1-4CBF-B91F-0CF6DB9CC6DD}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 - {F1E127C2-58B1-4CBF-B91F-0CF6DB9CC6DD}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 - {F1E127C2-58B1-4CBF-B91F-0CF6DB9CC6DD}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 - {7E111491-6A07-4661-90CD-6DEBB83CE755}.Debug|Win32.ActiveCfg = Debug|Win32 - {7E111491-6A07-4661-90CD-6DEBB83CE755}.Debug|Win32.Build.0 = Debug|Win32 - {7E111491-6A07-4661-90CD-6DEBB83CE755}.Release|Win32.ActiveCfg = Release|Win32 - {7E111491-6A07-4661-90CD-6DEBB83CE755}.Release|Win32.Build.0 = Release|Win32 - {7E111491-6A07-4661-90CD-6DEBB83CE755}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 - {7E111491-6A07-4661-90CD-6DEBB83CE755}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 - {7E111491-6A07-4661-90CD-6DEBB83CE755}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 - {7E111491-6A07-4661-90CD-6DEBB83CE755}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 - {BEF965EB-6330-4D18-858C-3B9F66CA9F18}.Debug|Win32.ActiveCfg = Debug|Win32 - {BEF965EB-6330-4D18-858C-3B9F66CA9F18}.Debug|Win32.Build.0 = Debug|Win32 - {BEF965EB-6330-4D18-858C-3B9F66CA9F18}.Release|Win32.ActiveCfg = Release|Win32 - {BEF965EB-6330-4D18-858C-3B9F66CA9F18}.Release|Win32.Build.0 = Release|Win32 - {BEF965EB-6330-4D18-858C-3B9F66CA9F18}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 - {BEF965EB-6330-4D18-858C-3B9F66CA9F18}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 - {BEF965EB-6330-4D18-858C-3B9F66CA9F18}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 - {BEF965EB-6330-4D18-858C-3B9F66CA9F18}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 - {0FEC8848-E24E-4FA5-9ACD-E4582DC4CBBE}.Debug|Win32.ActiveCfg = Debug|Win32 - {0FEC8848-E24E-4FA5-9ACD-E4582DC4CBBE}.Release|Win32.ActiveCfg = Release|Win32 - {0FEC8848-E24E-4FA5-9ACD-E4582DC4CBBE}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 - {0FEC8848-E24E-4FA5-9ACD-E4582DC4CBBE}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 - {8A1C2514-85DD-4AE2-9CF3-3183B66C537D}.Debug|Win32.ActiveCfg = Debug|Win32 - {8A1C2514-85DD-4AE2-9CF3-3183B66C537D}.Debug|Win32.Build.0 = Debug|Win32 - {8A1C2514-85DD-4AE2-9CF3-3183B66C537D}.Release|Win32.ActiveCfg = Release|Win32 - {8A1C2514-85DD-4AE2-9CF3-3183B66C537D}.Release|Win32.Build.0 = Release|Win32 - {8A1C2514-85DD-4AE2-9CF3-3183B66C537D}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 - {8A1C2514-85DD-4AE2-9CF3-3183B66C537D}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 - {8A1C2514-85DD-4AE2-9CF3-3183B66C537D}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 - {8A1C2514-85DD-4AE2-9CF3-3183B66C537D}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 - {A64FFB5D-0CF0-43EE-9DE3-C72260864BFF}.Debug|Win32.ActiveCfg = Debug|Win32 - {A64FFB5D-0CF0-43EE-9DE3-C72260864BFF}.Debug|Win32.Build.0 = Debug|Win32 - {A64FFB5D-0CF0-43EE-9DE3-C72260864BFF}.Release|Win32.ActiveCfg = Release|Win32 - {A64FFB5D-0CF0-43EE-9DE3-C72260864BFF}.Release|Win32.Build.0 = Release|Win32 - {A64FFB5D-0CF0-43EE-9DE3-C72260864BFF}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 - {A64FFB5D-0CF0-43EE-9DE3-C72260864BFF}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 - {A64FFB5D-0CF0-43EE-9DE3-C72260864BFF}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 - {A64FFB5D-0CF0-43EE-9DE3-C72260864BFF}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 - {D912E7BF-61FE-4D17-9D1B-3F1D268429D6}.Debug|Win32.ActiveCfg = Debug|Win32 - {D912E7BF-61FE-4D17-9D1B-3F1D268429D6}.Debug|Win32.Build.0 = Debug|Win32 - {D912E7BF-61FE-4D17-9D1B-3F1D268429D6}.Release|Win32.ActiveCfg = Release|Win32 - {D912E7BF-61FE-4D17-9D1B-3F1D268429D6}.Release|Win32.Build.0 = Release|Win32 - {D912E7BF-61FE-4D17-9D1B-3F1D268429D6}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 - {D912E7BF-61FE-4D17-9D1B-3F1D268429D6}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 - {D912E7BF-61FE-4D17-9D1B-3F1D268429D6}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 - {D912E7BF-61FE-4D17-9D1B-3F1D268429D6}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 - {C0FE933B-4AF7-4ACD-95E8-ACD3A73F1400}.Debug|Win32.ActiveCfg = Debug|Win32 - {C0FE933B-4AF7-4ACD-95E8-ACD3A73F1400}.Debug|Win32.Build.0 = Debug|Win32 - {C0FE933B-4AF7-4ACD-95E8-ACD3A73F1400}.Release|Win32.ActiveCfg = Release|Win32 - {C0FE933B-4AF7-4ACD-95E8-ACD3A73F1400}.Release|Win32.Build.0 = Release|Win32 - {C0FE933B-4AF7-4ACD-95E8-ACD3A73F1400}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 - {C0FE933B-4AF7-4ACD-95E8-ACD3A73F1400}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 - {C0FE933B-4AF7-4ACD-95E8-ACD3A73F1400}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 - {C0FE933B-4AF7-4ACD-95E8-ACD3A73F1400}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 - {D5AB2D87-51DC-4277-A9AB-2A6018D0E947}.Debug|Win32.ActiveCfg = Debug|Win32 - {D5AB2D87-51DC-4277-A9AB-2A6018D0E947}.Debug|Win32.Build.0 = Debug|Win32 - {D5AB2D87-51DC-4277-A9AB-2A6018D0E947}.Release|Win32.ActiveCfg = Release|Win32 - {D5AB2D87-51DC-4277-A9AB-2A6018D0E947}.Release|Win32.Build.0 = Release|Win32 - {D5AB2D87-51DC-4277-A9AB-2A6018D0E947}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 - {D5AB2D87-51DC-4277-A9AB-2A6018D0E947}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 - {D5AB2D87-51DC-4277-A9AB-2A6018D0E947}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 - {D5AB2D87-51DC-4277-A9AB-2A6018D0E947}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 - {02F94A40-586A-4403-8464-13B50801FFEC}.Debug|Win32.ActiveCfg = Debug|Win32 - {02F94A40-586A-4403-8464-13B50801FFEC}.Debug|Win32.Build.0 = Debug|Win32 - {02F94A40-586A-4403-8464-13B50801FFEC}.Release|Win32.ActiveCfg = Release|Win32 - {02F94A40-586A-4403-8464-13B50801FFEC}.Release|Win32.Build.0 = Release|Win32 - {02F94A40-586A-4403-8464-13B50801FFEC}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 - {02F94A40-586A-4403-8464-13B50801FFEC}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 - {02F94A40-586A-4403-8464-13B50801FFEC}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 - {02F94A40-586A-4403-8464-13B50801FFEC}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Audacity", "Projects\Audacity\Audacity.vcproj", "{1D64095C-F936-4FCF-B609-56E9DDF941FA}" + ProjectSection(ProjectDependencies) = postProject + {8A1C2514-85DD-4AE2-9CF3-3183B66C537D} = {8A1C2514-85DD-4AE2-9CF3-3183B66C537D} + {A64FFB5D-0CF0-43EE-9DE3-C72260864BFF} = {A64FFB5D-0CF0-43EE-9DE3-C72260864BFF} + {D5AB2D87-51DC-4277-A9AB-2A6018D0E947} = {D5AB2D87-51DC-4277-A9AB-2A6018D0E947} + {C0FE933B-4AF7-4ACD-95E8-ACD3A73F1400} = {C0FE933B-4AF7-4ACD-95E8-ACD3A73F1400} + {7E111491-6A07-4661-90CD-6DEBB83CE755} = {7E111491-6A07-4661-90CD-6DEBB83CE755} + {F1E127C2-58B1-4CBF-B91F-0CF6DB9CC6DD} = {F1E127C2-58B1-4CBF-B91F-0CF6DB9CC6DD} + {7BAFA434-3257-408A-AAC0-A8D352B2CE54} = {7BAFA434-3257-408A-AAC0-A8D352B2CE54} + {EC3F5835-C486-4970-8A6B-A0700F4B3637} = {EC3F5835-C486-4970-8A6B-A0700F4B3637} + {6C7DC635-26FB-419A-B69A-7ECBBB068245} = {6C7DC635-26FB-419A-B69A-7ECBBB068245} + {B28C9F3F-FF0E-4FEC-844C-685390B8AC06} = {B28C9F3F-FF0E-4FEC-844C-685390B8AC06} + {5284D863-3813-479F-BBF0-AC234E216BC6} = {5284D863-3813-479F-BBF0-AC234E216BC6} + {F4B4A272-4ED3-4951-A6EE-B7BAAC1C4952} = {F4B4A272-4ED3-4951-A6EE-B7BAAC1C4952} + {727D6675-67EE-4D0B-9DC1-177A0AF741F0} = {727D6675-67EE-4D0B-9DC1-177A0AF741F0} + {7ABA0F80-94AE-4E82-AB89-2E1258212D59} = {7ABA0F80-94AE-4E82-AB89-2E1258212D59} + {3A76129B-55AB-4D54-BAA7-08F63ED52569} = {3A76129B-55AB-4D54-BAA7-08F63ED52569} + {A52BBEA5-8B02-4147-8734-5D9BBF4D1177} = {A52BBEA5-8B02-4147-8734-5D9BBF4D1177} + {3DDDCAA9-276D-4FC3-A15C-485F7B9B24CC} = {3DDDCAA9-276D-4FC3-A15C-485F7B9B24CC} + {38C2C6B1-FBF8-4C5C-BB90-63F996083F56} = {38C2C6B1-FBF8-4C5C-BB90-63F996083F56} + {8C69F7B6-684F-48D9-9057-8912CA3DAA8B} = {8C69F7B6-684F-48D9-9057-8912CA3DAA8B} + {D96C7BE1-E3F1-4767-BBBB-320E082CE425} = {D96C7BE1-E3F1-4767-BBBB-320E082CE425} + {7AA41BED-41B0-427A-9148-DEA40549D158} = {7AA41BED-41B0-427A-9148-DEA40549D158} + {A61E2BF1-21AA-4118-B0D8-FD3D53DB892E} = {A61E2BF1-21AA-4118-B0D8-FD3D53DB892E} + {F00717F2-67C8-44E1-AF00-541DFA9CB7F2} = {F00717F2-67C8-44E1-AF00-541DFA9CB7F2} + {A939AAF8-44F1-4CE7-9DD0-7A6E99814857} = {A939AAF8-44F1-4CE7-9DD0-7A6E99814857} + {BEF965EB-6330-4D18-858C-3B9F66CA9F18} = {BEF965EB-6330-4D18-858C-3B9F66CA9F18} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "soundtouch", "Projects\soundtouch\soundtouch.vcproj", "{EC3F5835-C486-4970-8A6B-A0700F4B3637}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "expat", "Projects\expat\expat.vcproj", "{38C2C6B1-FBF8-4C5C-BB90-63F996083F56}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libflac", "Projects\libflac\libflac.vcproj", "{6C7DC635-26FB-419A-B69A-7ECBBB068245}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libflac++", "Projects\libflac++\libflac++.vcproj", "{B28C9F3F-FF0E-4FEC-844C-685390B8AC06}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libid3tag", "Projects\libid3tag\libid3tag.vcproj", "{D96C7BE1-E3F1-4767-BBBB-320E082CE425}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmad", "Projects\libmad\libmad.vcproj", "{A52BBEA5-8B02-4147-8734-5D9BBF4D1177}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libnyquist", "Projects\libnyquist\libnyquist.vcproj", "{7AA41BED-41B0-427A-9148-DEA40549D158}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libresample", "Projects\libresample\libresample.vcproj", "{F00717F2-67C8-44E1-AF00-541DFA9CB7F2}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libsamplerate", "Projects\libsamplerate\libsamplerate.vcproj", "{3DDDCAA9-276D-4FC3-A15C-485F7B9B24CC}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libsndfile", "Projects\libsndfile\libsndfile.vcproj", "{F4B4A272-4ED3-4951-A6EE-B7BAAC1C4952}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libogg", "Projects\libogg\libogg.vcproj", "{A939AAF8-44F1-4CE7-9DD0-7A6E99814857}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "portmixer", "Projects\portmixer\portmixer.vcproj", "{3A76129B-55AB-4D54-BAA7-08F63ED52569}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libvorbis", "Projects\libvorbis\libvorbis.vcproj", "{727D6675-67EE-4D0B-9DC1-177A0AF741F0}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "portaudio-v19", "Projects\portaudio-v19\portaudio-v19.vcproj", "{7ABA0F80-94AE-4E82-AB89-2E1258212D59}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "locale", "Projects\locale\locale.vcproj", "{BE9F28C5-058A-45F5-B2C1-D077BC058AAE}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "filedialog", "Projects\filedialog\filedialog.vcproj", "{5284D863-3813-479F-BBF0-AC234E216BC6}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod-script-pipe", "Projects\mod-script-pipe\mod-script-pipe.vcproj", "{85774A29-EA2F-4A40-994F-6BE593D847A5}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libvamp", "Projects\libvamp\libvamp.vcproj", "{A61E2BF1-21AA-4118-B0D8-FD3D53DB892E}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "twolame", "Projects\twolame\twolame.vcproj", "{8C69F7B6-684F-48D9-9057-8912CA3DAA8B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "liblrdf", "Projects\liblrdf\liblrdf.vcproj", "{7BAFA434-3257-408A-AAC0-A8D352B2CE54}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "librdf", "Projects\librdf\librdf.vcproj", "{F1E127C2-58B1-4CBF-B91F-0CF6DB9CC6DD}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "raptor", "Projects\raptor\raptor.vcproj", "{7E111491-6A07-4661-90CD-6DEBB83CE755}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rasqal", "Projects\rasqal\rasqal.vcproj", "{BEF965EB-6330-4D18-858C-3B9F66CA9F18}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "slv2", "Projects\slv2\slv2.vcproj", "{0FEC8848-E24E-4FA5-9ACD-E4582DC4CBBE}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "portsmf", "Projects\portsmf\portsmf.vcproj", "{8A1C2514-85DD-4AE2-9CF3-3183B66C537D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sbsms", "Projects\sbsms\sbsms.vcproj", "{A64FFB5D-0CF0-43EE-9DE3-C72260864BFF}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "taglib", "Projects\taglib\taglib.vcproj", "{D912E7BF-61FE-4D17-9D1B-3F1D268429D6}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libscorealign", "Projects\libscorealign\libscorealign.vcproj", "{C0FE933B-4AF7-4ACD-95E8-ACD3A73F1400}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "portmidi", "Projects\portmidi\portmidi.vcproj", "{D5AB2D87-51DC-4277-A9AB-2A6018D0E947}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "help", "Projects\help\help.vcproj", "{02F94A40-586A-4403-8464-13B50801FFEC}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Unicode Debug|Win32 = Unicode Debug|Win32 + Unicode Release|Win32 = Unicode Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1D64095C-F936-4FCF-B609-56E9DDF941FA}.Debug|Win32.ActiveCfg = Debug|Win32 + {1D64095C-F936-4FCF-B609-56E9DDF941FA}.Debug|Win32.Build.0 = Debug|Win32 + {1D64095C-F936-4FCF-B609-56E9DDF941FA}.Release|Win32.ActiveCfg = Release|Win32 + {1D64095C-F936-4FCF-B609-56E9DDF941FA}.Release|Win32.Build.0 = Release|Win32 + {1D64095C-F936-4FCF-B609-56E9DDF941FA}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 + {1D64095C-F936-4FCF-B609-56E9DDF941FA}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 + {1D64095C-F936-4FCF-B609-56E9DDF941FA}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 + {1D64095C-F936-4FCF-B609-56E9DDF941FA}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 + {EC3F5835-C486-4970-8A6B-A0700F4B3637}.Debug|Win32.ActiveCfg = Debug|Win32 + {EC3F5835-C486-4970-8A6B-A0700F4B3637}.Debug|Win32.Build.0 = Debug|Win32 + {EC3F5835-C486-4970-8A6B-A0700F4B3637}.Release|Win32.ActiveCfg = Release|Win32 + {EC3F5835-C486-4970-8A6B-A0700F4B3637}.Release|Win32.Build.0 = Release|Win32 + {EC3F5835-C486-4970-8A6B-A0700F4B3637}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 + {EC3F5835-C486-4970-8A6B-A0700F4B3637}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 + {EC3F5835-C486-4970-8A6B-A0700F4B3637}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 + {EC3F5835-C486-4970-8A6B-A0700F4B3637}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 + {38C2C6B1-FBF8-4C5C-BB90-63F996083F56}.Debug|Win32.ActiveCfg = Debug|Win32 + {38C2C6B1-FBF8-4C5C-BB90-63F996083F56}.Release|Win32.ActiveCfg = Release|Win32 + {38C2C6B1-FBF8-4C5C-BB90-63F996083F56}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 + {38C2C6B1-FBF8-4C5C-BB90-63F996083F56}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 + {6C7DC635-26FB-419A-B69A-7ECBBB068245}.Debug|Win32.ActiveCfg = Debug|Win32 + {6C7DC635-26FB-419A-B69A-7ECBBB068245}.Debug|Win32.Build.0 = Debug|Win32 + {6C7DC635-26FB-419A-B69A-7ECBBB068245}.Release|Win32.ActiveCfg = Release|Win32 + {6C7DC635-26FB-419A-B69A-7ECBBB068245}.Release|Win32.Build.0 = Release|Win32 + {6C7DC635-26FB-419A-B69A-7ECBBB068245}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 + {6C7DC635-26FB-419A-B69A-7ECBBB068245}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 + {6C7DC635-26FB-419A-B69A-7ECBBB068245}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 + {6C7DC635-26FB-419A-B69A-7ECBBB068245}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 + {B28C9F3F-FF0E-4FEC-844C-685390B8AC06}.Debug|Win32.ActiveCfg = Debug|Win32 + {B28C9F3F-FF0E-4FEC-844C-685390B8AC06}.Debug|Win32.Build.0 = Debug|Win32 + {B28C9F3F-FF0E-4FEC-844C-685390B8AC06}.Release|Win32.ActiveCfg = Release|Win32 + {B28C9F3F-FF0E-4FEC-844C-685390B8AC06}.Release|Win32.Build.0 = Release|Win32 + {B28C9F3F-FF0E-4FEC-844C-685390B8AC06}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 + {B28C9F3F-FF0E-4FEC-844C-685390B8AC06}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 + {B28C9F3F-FF0E-4FEC-844C-685390B8AC06}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 + {B28C9F3F-FF0E-4FEC-844C-685390B8AC06}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 + {D96C7BE1-E3F1-4767-BBBB-320E082CE425}.Debug|Win32.ActiveCfg = Debug|Win32 + {D96C7BE1-E3F1-4767-BBBB-320E082CE425}.Debug|Win32.Build.0 = Debug|Win32 + {D96C7BE1-E3F1-4767-BBBB-320E082CE425}.Release|Win32.ActiveCfg = Release|Win32 + {D96C7BE1-E3F1-4767-BBBB-320E082CE425}.Release|Win32.Build.0 = Release|Win32 + {D96C7BE1-E3F1-4767-BBBB-320E082CE425}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 + {D96C7BE1-E3F1-4767-BBBB-320E082CE425}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 + {D96C7BE1-E3F1-4767-BBBB-320E082CE425}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 + {D96C7BE1-E3F1-4767-BBBB-320E082CE425}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 + {A52BBEA5-8B02-4147-8734-5D9BBF4D1177}.Debug|Win32.ActiveCfg = Debug|Win32 + {A52BBEA5-8B02-4147-8734-5D9BBF4D1177}.Debug|Win32.Build.0 = Debug|Win32 + {A52BBEA5-8B02-4147-8734-5D9BBF4D1177}.Release|Win32.ActiveCfg = Release|Win32 + {A52BBEA5-8B02-4147-8734-5D9BBF4D1177}.Release|Win32.Build.0 = Release|Win32 + {A52BBEA5-8B02-4147-8734-5D9BBF4D1177}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 + {A52BBEA5-8B02-4147-8734-5D9BBF4D1177}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 + {A52BBEA5-8B02-4147-8734-5D9BBF4D1177}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 + {A52BBEA5-8B02-4147-8734-5D9BBF4D1177}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 + {7AA41BED-41B0-427A-9148-DEA40549D158}.Debug|Win32.ActiveCfg = Debug|Win32 + {7AA41BED-41B0-427A-9148-DEA40549D158}.Debug|Win32.Build.0 = Debug|Win32 + {7AA41BED-41B0-427A-9148-DEA40549D158}.Release|Win32.ActiveCfg = Release|Win32 + {7AA41BED-41B0-427A-9148-DEA40549D158}.Release|Win32.Build.0 = Release|Win32 + {7AA41BED-41B0-427A-9148-DEA40549D158}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 + {7AA41BED-41B0-427A-9148-DEA40549D158}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 + {7AA41BED-41B0-427A-9148-DEA40549D158}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 + {7AA41BED-41B0-427A-9148-DEA40549D158}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 + {F00717F2-67C8-44E1-AF00-541DFA9CB7F2}.Debug|Win32.ActiveCfg = Debug|Win32 + {F00717F2-67C8-44E1-AF00-541DFA9CB7F2}.Debug|Win32.Build.0 = Debug|Win32 + {F00717F2-67C8-44E1-AF00-541DFA9CB7F2}.Release|Win32.ActiveCfg = Release|Win32 + {F00717F2-67C8-44E1-AF00-541DFA9CB7F2}.Release|Win32.Build.0 = Release|Win32 + {F00717F2-67C8-44E1-AF00-541DFA9CB7F2}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 + {F00717F2-67C8-44E1-AF00-541DFA9CB7F2}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 + {F00717F2-67C8-44E1-AF00-541DFA9CB7F2}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 + {F00717F2-67C8-44E1-AF00-541DFA9CB7F2}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 + {3DDDCAA9-276D-4FC3-A15C-485F7B9B24CC}.Debug|Win32.ActiveCfg = Debug|Win32 + {3DDDCAA9-276D-4FC3-A15C-485F7B9B24CC}.Debug|Win32.Build.0 = Debug|Win32 + {3DDDCAA9-276D-4FC3-A15C-485F7B9B24CC}.Release|Win32.ActiveCfg = Release|Win32 + {3DDDCAA9-276D-4FC3-A15C-485F7B9B24CC}.Release|Win32.Build.0 = Release|Win32 + {3DDDCAA9-276D-4FC3-A15C-485F7B9B24CC}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 + {3DDDCAA9-276D-4FC3-A15C-485F7B9B24CC}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 + {3DDDCAA9-276D-4FC3-A15C-485F7B9B24CC}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 + {3DDDCAA9-276D-4FC3-A15C-485F7B9B24CC}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 + {F4B4A272-4ED3-4951-A6EE-B7BAAC1C4952}.Debug|Win32.ActiveCfg = Debug|Win32 + {F4B4A272-4ED3-4951-A6EE-B7BAAC1C4952}.Debug|Win32.Build.0 = Debug|Win32 + {F4B4A272-4ED3-4951-A6EE-B7BAAC1C4952}.Release|Win32.ActiveCfg = Release|Win32 + {F4B4A272-4ED3-4951-A6EE-B7BAAC1C4952}.Release|Win32.Build.0 = Release|Win32 + {F4B4A272-4ED3-4951-A6EE-B7BAAC1C4952}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 + {F4B4A272-4ED3-4951-A6EE-B7BAAC1C4952}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 + {F4B4A272-4ED3-4951-A6EE-B7BAAC1C4952}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 + {F4B4A272-4ED3-4951-A6EE-B7BAAC1C4952}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 + {A939AAF8-44F1-4CE7-9DD0-7A6E99814857}.Debug|Win32.ActiveCfg = Debug|Win32 + {A939AAF8-44F1-4CE7-9DD0-7A6E99814857}.Debug|Win32.Build.0 = Debug|Win32 + {A939AAF8-44F1-4CE7-9DD0-7A6E99814857}.Release|Win32.ActiveCfg = Release|Win32 + {A939AAF8-44F1-4CE7-9DD0-7A6E99814857}.Release|Win32.Build.0 = Release|Win32 + {A939AAF8-44F1-4CE7-9DD0-7A6E99814857}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 + {A939AAF8-44F1-4CE7-9DD0-7A6E99814857}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 + {A939AAF8-44F1-4CE7-9DD0-7A6E99814857}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 + {A939AAF8-44F1-4CE7-9DD0-7A6E99814857}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 + {3A76129B-55AB-4D54-BAA7-08F63ED52569}.Debug|Win32.ActiveCfg = Debug|Win32 + {3A76129B-55AB-4D54-BAA7-08F63ED52569}.Debug|Win32.Build.0 = Debug|Win32 + {3A76129B-55AB-4D54-BAA7-08F63ED52569}.Release|Win32.ActiveCfg = Release|Win32 + {3A76129B-55AB-4D54-BAA7-08F63ED52569}.Release|Win32.Build.0 = Release|Win32 + {3A76129B-55AB-4D54-BAA7-08F63ED52569}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 + {3A76129B-55AB-4D54-BAA7-08F63ED52569}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 + {3A76129B-55AB-4D54-BAA7-08F63ED52569}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 + {3A76129B-55AB-4D54-BAA7-08F63ED52569}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 + {727D6675-67EE-4D0B-9DC1-177A0AF741F0}.Debug|Win32.ActiveCfg = Debug|Win32 + {727D6675-67EE-4D0B-9DC1-177A0AF741F0}.Debug|Win32.Build.0 = Debug|Win32 + {727D6675-67EE-4D0B-9DC1-177A0AF741F0}.Release|Win32.ActiveCfg = Release|Win32 + {727D6675-67EE-4D0B-9DC1-177A0AF741F0}.Release|Win32.Build.0 = Release|Win32 + {727D6675-67EE-4D0B-9DC1-177A0AF741F0}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 + {727D6675-67EE-4D0B-9DC1-177A0AF741F0}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 + {727D6675-67EE-4D0B-9DC1-177A0AF741F0}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 + {727D6675-67EE-4D0B-9DC1-177A0AF741F0}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 + {7ABA0F80-94AE-4E82-AB89-2E1258212D59}.Debug|Win32.ActiveCfg = Debug|Win32 + {7ABA0F80-94AE-4E82-AB89-2E1258212D59}.Debug|Win32.Build.0 = Debug|Win32 + {7ABA0F80-94AE-4E82-AB89-2E1258212D59}.Release|Win32.ActiveCfg = Release|Win32 + {7ABA0F80-94AE-4E82-AB89-2E1258212D59}.Release|Win32.Build.0 = Release|Win32 + {7ABA0F80-94AE-4E82-AB89-2E1258212D59}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 + {7ABA0F80-94AE-4E82-AB89-2E1258212D59}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 + {7ABA0F80-94AE-4E82-AB89-2E1258212D59}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 + {7ABA0F80-94AE-4E82-AB89-2E1258212D59}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 + {BE9F28C5-058A-45F5-B2C1-D077BC058AAE}.Debug|Win32.ActiveCfg = Debug|Win32 + {BE9F28C5-058A-45F5-B2C1-D077BC058AAE}.Release|Win32.ActiveCfg = Release|Win32 + {BE9F28C5-058A-45F5-B2C1-D077BC058AAE}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 + {BE9F28C5-058A-45F5-B2C1-D077BC058AAE}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 + {5284D863-3813-479F-BBF0-AC234E216BC6}.Debug|Win32.ActiveCfg = Debug|Win32 + {5284D863-3813-479F-BBF0-AC234E216BC6}.Debug|Win32.Build.0 = Debug|Win32 + {5284D863-3813-479F-BBF0-AC234E216BC6}.Release|Win32.ActiveCfg = Release|Win32 + {5284D863-3813-479F-BBF0-AC234E216BC6}.Release|Win32.Build.0 = Release|Win32 + {5284D863-3813-479F-BBF0-AC234E216BC6}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 + {5284D863-3813-479F-BBF0-AC234E216BC6}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 + {5284D863-3813-479F-BBF0-AC234E216BC6}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 + {5284D863-3813-479F-BBF0-AC234E216BC6}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 + {85774A29-EA2F-4A40-994F-6BE593D847A5}.Debug|Win32.ActiveCfg = Debug|Win32 + {85774A29-EA2F-4A40-994F-6BE593D847A5}.Debug|Win32.Build.0 = Debug|Win32 + {85774A29-EA2F-4A40-994F-6BE593D847A5}.Release|Win32.ActiveCfg = Release|Win32 + {85774A29-EA2F-4A40-994F-6BE593D847A5}.Release|Win32.Build.0 = Release|Win32 + {85774A29-EA2F-4A40-994F-6BE593D847A5}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 + {85774A29-EA2F-4A40-994F-6BE593D847A5}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 + {85774A29-EA2F-4A40-994F-6BE593D847A5}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 + {85774A29-EA2F-4A40-994F-6BE593D847A5}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 + {A61E2BF1-21AA-4118-B0D8-FD3D53DB892E}.Debug|Win32.ActiveCfg = Debug|Win32 + {A61E2BF1-21AA-4118-B0D8-FD3D53DB892E}.Debug|Win32.Build.0 = Debug|Win32 + {A61E2BF1-21AA-4118-B0D8-FD3D53DB892E}.Release|Win32.ActiveCfg = Release|Win32 + {A61E2BF1-21AA-4118-B0D8-FD3D53DB892E}.Release|Win32.Build.0 = Release|Win32 + {A61E2BF1-21AA-4118-B0D8-FD3D53DB892E}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 + {A61E2BF1-21AA-4118-B0D8-FD3D53DB892E}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 + {A61E2BF1-21AA-4118-B0D8-FD3D53DB892E}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 + {A61E2BF1-21AA-4118-B0D8-FD3D53DB892E}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 + {8C69F7B6-684F-48D9-9057-8912CA3DAA8B}.Debug|Win32.ActiveCfg = Debug|Win32 + {8C69F7B6-684F-48D9-9057-8912CA3DAA8B}.Debug|Win32.Build.0 = Debug|Win32 + {8C69F7B6-684F-48D9-9057-8912CA3DAA8B}.Release|Win32.ActiveCfg = Release|Win32 + {8C69F7B6-684F-48D9-9057-8912CA3DAA8B}.Release|Win32.Build.0 = Release|Win32 + {8C69F7B6-684F-48D9-9057-8912CA3DAA8B}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 + {8C69F7B6-684F-48D9-9057-8912CA3DAA8B}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 + {8C69F7B6-684F-48D9-9057-8912CA3DAA8B}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 + {8C69F7B6-684F-48D9-9057-8912CA3DAA8B}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 + {7BAFA434-3257-408A-AAC0-A8D352B2CE54}.Debug|Win32.ActiveCfg = Debug|Win32 + {7BAFA434-3257-408A-AAC0-A8D352B2CE54}.Debug|Win32.Build.0 = Debug|Win32 + {7BAFA434-3257-408A-AAC0-A8D352B2CE54}.Release|Win32.ActiveCfg = Release|Win32 + {7BAFA434-3257-408A-AAC0-A8D352B2CE54}.Release|Win32.Build.0 = Release|Win32 + {7BAFA434-3257-408A-AAC0-A8D352B2CE54}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 + {7BAFA434-3257-408A-AAC0-A8D352B2CE54}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 + {7BAFA434-3257-408A-AAC0-A8D352B2CE54}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 + {7BAFA434-3257-408A-AAC0-A8D352B2CE54}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 + {F1E127C2-58B1-4CBF-B91F-0CF6DB9CC6DD}.Debug|Win32.ActiveCfg = Debug|Win32 + {F1E127C2-58B1-4CBF-B91F-0CF6DB9CC6DD}.Debug|Win32.Build.0 = Debug|Win32 + {F1E127C2-58B1-4CBF-B91F-0CF6DB9CC6DD}.Release|Win32.ActiveCfg = Release|Win32 + {F1E127C2-58B1-4CBF-B91F-0CF6DB9CC6DD}.Release|Win32.Build.0 = Release|Win32 + {F1E127C2-58B1-4CBF-B91F-0CF6DB9CC6DD}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 + {F1E127C2-58B1-4CBF-B91F-0CF6DB9CC6DD}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 + {F1E127C2-58B1-4CBF-B91F-0CF6DB9CC6DD}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 + {F1E127C2-58B1-4CBF-B91F-0CF6DB9CC6DD}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 + {7E111491-6A07-4661-90CD-6DEBB83CE755}.Debug|Win32.ActiveCfg = Debug|Win32 + {7E111491-6A07-4661-90CD-6DEBB83CE755}.Debug|Win32.Build.0 = Debug|Win32 + {7E111491-6A07-4661-90CD-6DEBB83CE755}.Release|Win32.ActiveCfg = Release|Win32 + {7E111491-6A07-4661-90CD-6DEBB83CE755}.Release|Win32.Build.0 = Release|Win32 + {7E111491-6A07-4661-90CD-6DEBB83CE755}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 + {7E111491-6A07-4661-90CD-6DEBB83CE755}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 + {7E111491-6A07-4661-90CD-6DEBB83CE755}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 + {7E111491-6A07-4661-90CD-6DEBB83CE755}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 + {BEF965EB-6330-4D18-858C-3B9F66CA9F18}.Debug|Win32.ActiveCfg = Debug|Win32 + {BEF965EB-6330-4D18-858C-3B9F66CA9F18}.Debug|Win32.Build.0 = Debug|Win32 + {BEF965EB-6330-4D18-858C-3B9F66CA9F18}.Release|Win32.ActiveCfg = Release|Win32 + {BEF965EB-6330-4D18-858C-3B9F66CA9F18}.Release|Win32.Build.0 = Release|Win32 + {BEF965EB-6330-4D18-858C-3B9F66CA9F18}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 + {BEF965EB-6330-4D18-858C-3B9F66CA9F18}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 + {BEF965EB-6330-4D18-858C-3B9F66CA9F18}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 + {BEF965EB-6330-4D18-858C-3B9F66CA9F18}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 + {0FEC8848-E24E-4FA5-9ACD-E4582DC4CBBE}.Debug|Win32.ActiveCfg = Debug|Win32 + {0FEC8848-E24E-4FA5-9ACD-E4582DC4CBBE}.Release|Win32.ActiveCfg = Release|Win32 + {0FEC8848-E24E-4FA5-9ACD-E4582DC4CBBE}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 + {0FEC8848-E24E-4FA5-9ACD-E4582DC4CBBE}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 + {8A1C2514-85DD-4AE2-9CF3-3183B66C537D}.Debug|Win32.ActiveCfg = Debug|Win32 + {8A1C2514-85DD-4AE2-9CF3-3183B66C537D}.Debug|Win32.Build.0 = Debug|Win32 + {8A1C2514-85DD-4AE2-9CF3-3183B66C537D}.Release|Win32.ActiveCfg = Release|Win32 + {8A1C2514-85DD-4AE2-9CF3-3183B66C537D}.Release|Win32.Build.0 = Release|Win32 + {8A1C2514-85DD-4AE2-9CF3-3183B66C537D}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 + {8A1C2514-85DD-4AE2-9CF3-3183B66C537D}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 + {8A1C2514-85DD-4AE2-9CF3-3183B66C537D}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 + {8A1C2514-85DD-4AE2-9CF3-3183B66C537D}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 + {A64FFB5D-0CF0-43EE-9DE3-C72260864BFF}.Debug|Win32.ActiveCfg = Debug|Win32 + {A64FFB5D-0CF0-43EE-9DE3-C72260864BFF}.Debug|Win32.Build.0 = Debug|Win32 + {A64FFB5D-0CF0-43EE-9DE3-C72260864BFF}.Release|Win32.ActiveCfg = Release|Win32 + {A64FFB5D-0CF0-43EE-9DE3-C72260864BFF}.Release|Win32.Build.0 = Release|Win32 + {A64FFB5D-0CF0-43EE-9DE3-C72260864BFF}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 + {A64FFB5D-0CF0-43EE-9DE3-C72260864BFF}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 + {A64FFB5D-0CF0-43EE-9DE3-C72260864BFF}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 + {A64FFB5D-0CF0-43EE-9DE3-C72260864BFF}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 + {D912E7BF-61FE-4D17-9D1B-3F1D268429D6}.Debug|Win32.ActiveCfg = Debug|Win32 + {D912E7BF-61FE-4D17-9D1B-3F1D268429D6}.Debug|Win32.Build.0 = Debug|Win32 + {D912E7BF-61FE-4D17-9D1B-3F1D268429D6}.Release|Win32.ActiveCfg = Release|Win32 + {D912E7BF-61FE-4D17-9D1B-3F1D268429D6}.Release|Win32.Build.0 = Release|Win32 + {D912E7BF-61FE-4D17-9D1B-3F1D268429D6}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 + {D912E7BF-61FE-4D17-9D1B-3F1D268429D6}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 + {D912E7BF-61FE-4D17-9D1B-3F1D268429D6}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 + {D912E7BF-61FE-4D17-9D1B-3F1D268429D6}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 + {C0FE933B-4AF7-4ACD-95E8-ACD3A73F1400}.Debug|Win32.ActiveCfg = Debug|Win32 + {C0FE933B-4AF7-4ACD-95E8-ACD3A73F1400}.Debug|Win32.Build.0 = Debug|Win32 + {C0FE933B-4AF7-4ACD-95E8-ACD3A73F1400}.Release|Win32.ActiveCfg = Release|Win32 + {C0FE933B-4AF7-4ACD-95E8-ACD3A73F1400}.Release|Win32.Build.0 = Release|Win32 + {C0FE933B-4AF7-4ACD-95E8-ACD3A73F1400}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 + {C0FE933B-4AF7-4ACD-95E8-ACD3A73F1400}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 + {C0FE933B-4AF7-4ACD-95E8-ACD3A73F1400}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 + {C0FE933B-4AF7-4ACD-95E8-ACD3A73F1400}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 + {D5AB2D87-51DC-4277-A9AB-2A6018D0E947}.Debug|Win32.ActiveCfg = Debug|Win32 + {D5AB2D87-51DC-4277-A9AB-2A6018D0E947}.Debug|Win32.Build.0 = Debug|Win32 + {D5AB2D87-51DC-4277-A9AB-2A6018D0E947}.Release|Win32.ActiveCfg = Release|Win32 + {D5AB2D87-51DC-4277-A9AB-2A6018D0E947}.Release|Win32.Build.0 = Release|Win32 + {D5AB2D87-51DC-4277-A9AB-2A6018D0E947}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 + {D5AB2D87-51DC-4277-A9AB-2A6018D0E947}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 + {D5AB2D87-51DC-4277-A9AB-2A6018D0E947}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 + {D5AB2D87-51DC-4277-A9AB-2A6018D0E947}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 + {02F94A40-586A-4403-8464-13B50801FFEC}.Debug|Win32.ActiveCfg = Debug|Win32 + {02F94A40-586A-4403-8464-13B50801FFEC}.Debug|Win32.Build.0 = Debug|Win32 + {02F94A40-586A-4403-8464-13B50801FFEC}.Release|Win32.ActiveCfg = Release|Win32 + {02F94A40-586A-4403-8464-13B50801FFEC}.Release|Win32.Build.0 = Release|Win32 + {02F94A40-586A-4403-8464-13B50801FFEC}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 + {02F94A40-586A-4403-8464-13B50801FFEC}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 + {02F94A40-586A-4403-8464-13B50801FFEC}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 + {02F94A40-586A-4403-8464-13B50801FFEC}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal