| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,237 @@ | ||
| #ifndef AL_ALC_H | ||
| #define AL_ALC_H | ||
|
|
||
| #if defined(__cplusplus) | ||
| extern "C" { | ||
| #endif | ||
|
|
||
| #ifndef ALC_API | ||
| #if defined(AL_LIBTYPE_STATIC) | ||
| #define ALC_API | ||
| #elif defined(_WIN32) | ||
| #define ALC_API __declspec(dllimport) | ||
| #else | ||
| #define ALC_API extern | ||
| #endif | ||
| #endif | ||
|
|
||
| #if defined(_WIN32) | ||
| #define ALC_APIENTRY __cdecl | ||
| #else | ||
| #define ALC_APIENTRY | ||
| #endif | ||
|
|
||
|
|
||
| /** Deprecated macro. */ | ||
| #define ALCAPI ALC_API | ||
| #define ALCAPIENTRY ALC_APIENTRY | ||
| #define ALC_INVALID 0 | ||
|
|
||
| /** Supported ALC version? */ | ||
| #define ALC_VERSION_0_1 1 | ||
|
|
||
| /** Opaque device handle */ | ||
| typedef struct ALCdevice_struct ALCdevice; | ||
| /** Opaque context handle */ | ||
| typedef struct ALCcontext_struct ALCcontext; | ||
|
|
||
| /** 8-bit boolean */ | ||
| typedef char ALCboolean; | ||
|
|
||
| /** character */ | ||
| typedef char ALCchar; | ||
|
|
||
| /** signed 8-bit 2's complement integer */ | ||
| typedef signed char ALCbyte; | ||
|
|
||
| /** unsigned 8-bit integer */ | ||
| typedef unsigned char ALCubyte; | ||
|
|
||
| /** signed 16-bit 2's complement integer */ | ||
| typedef short ALCshort; | ||
|
|
||
| /** unsigned 16-bit integer */ | ||
| typedef unsigned short ALCushort; | ||
|
|
||
| /** signed 32-bit 2's complement integer */ | ||
| typedef int ALCint; | ||
|
|
||
| /** unsigned 32-bit integer */ | ||
| typedef unsigned int ALCuint; | ||
|
|
||
| /** non-negative 32-bit binary integer size */ | ||
| typedef int ALCsizei; | ||
|
|
||
| /** enumerated 32-bit value */ | ||
| typedef int ALCenum; | ||
|
|
||
| /** 32-bit IEEE754 floating-point */ | ||
| typedef float ALCfloat; | ||
|
|
||
| /** 64-bit IEEE754 floating-point */ | ||
| typedef double ALCdouble; | ||
|
|
||
| /** void type (for opaque pointers only) */ | ||
| typedef void ALCvoid; | ||
|
|
||
|
|
||
| /* Enumerant values begin at column 50. No tabs. */ | ||
|
|
||
| /** Boolean False. */ | ||
| #define ALC_FALSE 0 | ||
|
|
||
| /** Boolean True. */ | ||
| #define ALC_TRUE 1 | ||
|
|
||
| /** Context attribute: <int> Hz. */ | ||
| #define ALC_FREQUENCY 0x1007 | ||
|
|
||
| /** Context attribute: <int> Hz. */ | ||
| #define ALC_REFRESH 0x1008 | ||
|
|
||
| /** Context attribute: AL_TRUE or AL_FALSE. */ | ||
| #define ALC_SYNC 0x1009 | ||
|
|
||
| /** Context attribute: <int> requested Mono (3D) Sources. */ | ||
| #define ALC_MONO_SOURCES 0x1010 | ||
|
|
||
| /** Context attribute: <int> requested Stereo Sources. */ | ||
| #define ALC_STEREO_SOURCES 0x1011 | ||
|
|
||
| /** No error. */ | ||
| #define ALC_NO_ERROR 0 | ||
|
|
||
| /** Invalid device handle. */ | ||
| #define ALC_INVALID_DEVICE 0xA001 | ||
|
|
||
| /** Invalid context handle. */ | ||
| #define ALC_INVALID_CONTEXT 0xA002 | ||
|
|
||
| /** Invalid enum parameter passed to an ALC call. */ | ||
| #define ALC_INVALID_ENUM 0xA003 | ||
|
|
||
| /** Invalid value parameter passed to an ALC call. */ | ||
| #define ALC_INVALID_VALUE 0xA004 | ||
|
|
||
| /** Out of memory. */ | ||
| #define ALC_OUT_OF_MEMORY 0xA005 | ||
|
|
||
|
|
||
| /** Runtime ALC version. */ | ||
| #define ALC_MAJOR_VERSION 0x1000 | ||
| #define ALC_MINOR_VERSION 0x1001 | ||
|
|
||
| /** Context attribute list properties. */ | ||
| #define ALC_ATTRIBUTES_SIZE 0x1002 | ||
| #define ALC_ALL_ATTRIBUTES 0x1003 | ||
|
|
||
| /** String for the default device specifier. */ | ||
| #define ALC_DEFAULT_DEVICE_SPECIFIER 0x1004 | ||
| /** | ||
| * String for the given device's specifier. | ||
| * | ||
| * If device handle is NULL, it is instead a null-char separated list of | ||
| * strings of known device specifiers (list ends with an empty string). | ||
| */ | ||
| #define ALC_DEVICE_SPECIFIER 0x1005 | ||
| /** String for space-separated list of ALC extensions. */ | ||
| #define ALC_EXTENSIONS 0x1006 | ||
|
|
||
|
|
||
| /** Capture extension */ | ||
| #define ALC_EXT_CAPTURE 1 | ||
| /** | ||
| * String for the given capture device's specifier. | ||
| * | ||
| * If device handle is NULL, it is instead a null-char separated list of | ||
| * strings of known capture device specifiers (list ends with an empty string). | ||
| */ | ||
| #define ALC_CAPTURE_DEVICE_SPECIFIER 0x310 | ||
| /** String for the default capture device specifier. */ | ||
| #define ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER 0x311 | ||
| /** Number of sample frames available for capture. */ | ||
| #define ALC_CAPTURE_SAMPLES 0x312 | ||
|
|
||
|
|
||
| /** Enumerate All extension */ | ||
| #define ALC_ENUMERATE_ALL_EXT 1 | ||
| /** String for the default extended device specifier. */ | ||
| #define ALC_DEFAULT_ALL_DEVICES_SPECIFIER 0x1012 | ||
| /** | ||
| * String for the given extended device's specifier. | ||
| * | ||
| * If device handle is NULL, it is instead a null-char separated list of | ||
| * strings of known extended device specifiers (list ends with an empty string). | ||
| */ | ||
| #define ALC_ALL_DEVICES_SPECIFIER 0x1013 | ||
|
|
||
|
|
||
| /** Context management. */ | ||
| ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCint* attrlist); | ||
| ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context); | ||
| ALC_API void ALC_APIENTRY alcProcessContext(ALCcontext *context); | ||
| ALC_API void ALC_APIENTRY alcSuspendContext(ALCcontext *context); | ||
| ALC_API void ALC_APIENTRY alcDestroyContext(ALCcontext *context); | ||
| ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void); | ||
| ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice(ALCcontext *context); | ||
|
|
||
| /** Device management. */ | ||
| ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *devicename); | ||
| ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device); | ||
|
|
||
|
|
||
| /** | ||
| * Error support. | ||
| * | ||
| * Obtain the most recent Device error. | ||
| */ | ||
| ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device); | ||
|
|
||
| /** | ||
| * Extension support. | ||
| * | ||
| * Query for the presence of an extension, and obtain any appropriate | ||
| * function pointers and enum values. | ||
| */ | ||
| ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const ALCchar *extname); | ||
| ALC_API void* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *funcname); | ||
| ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *enumname); | ||
|
|
||
| /** Query function. */ | ||
| ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum param); | ||
| ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values); | ||
|
|
||
| /** Capture function. */ | ||
| ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize); | ||
| ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device); | ||
| ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device); | ||
| ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device); | ||
| ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCsizei samples); | ||
|
|
||
| /** Pointer-to-function type, useful for dynamically getting ALC entry points. */ | ||
| typedef ALCcontext* (ALC_APIENTRY *LPALCCREATECONTEXT)(ALCdevice *device, const ALCint *attrlist); | ||
| typedef ALCboolean (ALC_APIENTRY *LPALCMAKECONTEXTCURRENT)(ALCcontext *context); | ||
| typedef void (ALC_APIENTRY *LPALCPROCESSCONTEXT)(ALCcontext *context); | ||
| typedef void (ALC_APIENTRY *LPALCSUSPENDCONTEXT)(ALCcontext *context); | ||
| typedef void (ALC_APIENTRY *LPALCDESTROYCONTEXT)(ALCcontext *context); | ||
| typedef ALCcontext* (ALC_APIENTRY *LPALCGETCURRENTCONTEXT)(void); | ||
| typedef ALCdevice* (ALC_APIENTRY *LPALCGETCONTEXTSDEVICE)(ALCcontext *context); | ||
| typedef ALCdevice* (ALC_APIENTRY *LPALCOPENDEVICE)(const ALCchar *devicename); | ||
| typedef ALCboolean (ALC_APIENTRY *LPALCCLOSEDEVICE)(ALCdevice *device); | ||
| typedef ALCenum (ALC_APIENTRY *LPALCGETERROR)(ALCdevice *device); | ||
| typedef ALCboolean (ALC_APIENTRY *LPALCISEXTENSIONPRESENT)(ALCdevice *device, const ALCchar *extname); | ||
| typedef void* (ALC_APIENTRY *LPALCGETPROCADDRESS)(ALCdevice *device, const ALCchar *funcname); | ||
| typedef ALCenum (ALC_APIENTRY *LPALCGETENUMVALUE)(ALCdevice *device, const ALCchar *enumname); | ||
| typedef const ALCchar* (ALC_APIENTRY *LPALCGETSTRING)(ALCdevice *device, ALCenum param); | ||
| typedef void (ALC_APIENTRY *LPALCGETINTEGERV)(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values); | ||
| typedef ALCdevice* (ALC_APIENTRY *LPALCCAPTUREOPENDEVICE)(const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize); | ||
| typedef ALCboolean (ALC_APIENTRY *LPALCCAPTURECLOSEDEVICE)(ALCdevice *device); | ||
| typedef void (ALC_APIENTRY *LPALCCAPTURESTART)(ALCdevice *device); | ||
| typedef void (ALC_APIENTRY *LPALCCAPTURESTOP)(ALCdevice *device); | ||
| typedef void (ALC_APIENTRY *LPALCCAPTURESAMPLES)(ALCdevice *device, ALCvoid *buffer, ALCsizei samples); | ||
|
|
||
| #if defined(__cplusplus) | ||
| } | ||
| #endif | ||
|
|
||
| #endif /* AL_ALC_H */ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,355 @@ | ||
| /** | ||
| * OpenAL cross platform audio library | ||
| * Copyright (C) 2008 by authors. | ||
| * This library is free software; you can redistribute it and/or | ||
| * modify it under the terms of the GNU Library General Public | ||
| * License as published by the Free Software Foundation; either | ||
| * version 2 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 | ||
| * Library General Public License for more details. | ||
| * | ||
| * You should have received a copy of the GNU Library 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. | ||
| * Or go to http://www.gnu.org/copyleft/lgpl.html | ||
| */ | ||
|
|
||
| #ifndef AL_ALEXT_H | ||
| #define AL_ALEXT_H | ||
|
|
||
| #include <stddef.h> | ||
| /* Define int64_t and uint64_t types */ | ||
| #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L | ||
| #include <inttypes.h> | ||
| #elif defined(_WIN32) && defined(__GNUC__) | ||
| #include <stdint.h> | ||
| #elif defined(_WIN32) | ||
| typedef __int64 int64_t; | ||
| typedef unsigned __int64 uint64_t; | ||
| #else | ||
| /* Fallback if nothing above works */ | ||
| #include <inttypes.h> | ||
| #endif | ||
|
|
||
| #include "alc.h" | ||
| #include "al.h" | ||
|
|
||
| #ifdef __cplusplus | ||
| extern "C" { | ||
| #endif | ||
|
|
||
| #ifndef AL_LOKI_IMA_ADPCM_format | ||
| #define AL_LOKI_IMA_ADPCM_format 1 | ||
| #define AL_FORMAT_IMA_ADPCM_MONO16_EXT 0x10000 | ||
| #define AL_FORMAT_IMA_ADPCM_STEREO16_EXT 0x10001 | ||
| #endif | ||
|
|
||
| #ifndef AL_LOKI_WAVE_format | ||
| #define AL_LOKI_WAVE_format 1 | ||
| #define AL_FORMAT_WAVE_EXT 0x10002 | ||
| #endif | ||
|
|
||
| #ifndef AL_EXT_vorbis | ||
| #define AL_EXT_vorbis 1 | ||
| #define AL_FORMAT_VORBIS_EXT 0x10003 | ||
| #endif | ||
|
|
||
| #ifndef AL_LOKI_quadriphonic | ||
| #define AL_LOKI_quadriphonic 1 | ||
| #define AL_FORMAT_QUAD8_LOKI 0x10004 | ||
| #define AL_FORMAT_QUAD16_LOKI 0x10005 | ||
| #endif | ||
|
|
||
| #ifndef AL_EXT_float32 | ||
| #define AL_EXT_float32 1 | ||
| #define AL_FORMAT_MONO_FLOAT32 0x10010 | ||
| #define AL_FORMAT_STEREO_FLOAT32 0x10011 | ||
| #endif | ||
|
|
||
| #ifndef AL_EXT_double | ||
| #define AL_EXT_double 1 | ||
| #define AL_FORMAT_MONO_DOUBLE_EXT 0x10012 | ||
| #define AL_FORMAT_STEREO_DOUBLE_EXT 0x10013 | ||
| #endif | ||
|
|
||
| #ifndef AL_EXT_MULAW | ||
| #define AL_EXT_MULAW 1 | ||
| #define AL_FORMAT_MONO_MULAW_EXT 0x10014 | ||
| #define AL_FORMAT_STEREO_MULAW_EXT 0x10015 | ||
| #endif | ||
|
|
||
| #ifndef AL_EXT_ALAW | ||
| #define AL_EXT_ALAW 1 | ||
| #define AL_FORMAT_MONO_ALAW_EXT 0x10016 | ||
| #define AL_FORMAT_STEREO_ALAW_EXT 0x10017 | ||
| #endif | ||
|
|
||
| #ifndef ALC_LOKI_audio_channel | ||
| #define ALC_LOKI_audio_channel 1 | ||
| #define ALC_CHAN_MAIN_LOKI 0x500001 | ||
| #define ALC_CHAN_PCM_LOKI 0x500002 | ||
| #define ALC_CHAN_CD_LOKI 0x500003 | ||
| #endif | ||
|
|
||
| #ifndef AL_EXT_MCFORMATS | ||
| #define AL_EXT_MCFORMATS 1 | ||
| #define AL_FORMAT_QUAD8 0x1204 | ||
| #define AL_FORMAT_QUAD16 0x1205 | ||
| #define AL_FORMAT_QUAD32 0x1206 | ||
| #define AL_FORMAT_REAR8 0x1207 | ||
| #define AL_FORMAT_REAR16 0x1208 | ||
| #define AL_FORMAT_REAR32 0x1209 | ||
| #define AL_FORMAT_51CHN8 0x120A | ||
| #define AL_FORMAT_51CHN16 0x120B | ||
| #define AL_FORMAT_51CHN32 0x120C | ||
| #define AL_FORMAT_61CHN8 0x120D | ||
| #define AL_FORMAT_61CHN16 0x120E | ||
| #define AL_FORMAT_61CHN32 0x120F | ||
| #define AL_FORMAT_71CHN8 0x1210 | ||
| #define AL_FORMAT_71CHN16 0x1211 | ||
| #define AL_FORMAT_71CHN32 0x1212 | ||
| #endif | ||
|
|
||
| #ifndef AL_EXT_MULAW_MCFORMATS | ||
| #define AL_EXT_MULAW_MCFORMATS 1 | ||
| #define AL_FORMAT_MONO_MULAW 0x10014 | ||
| #define AL_FORMAT_STEREO_MULAW 0x10015 | ||
| #define AL_FORMAT_QUAD_MULAW 0x10021 | ||
| #define AL_FORMAT_REAR_MULAW 0x10022 | ||
| #define AL_FORMAT_51CHN_MULAW 0x10023 | ||
| #define AL_FORMAT_61CHN_MULAW 0x10024 | ||
| #define AL_FORMAT_71CHN_MULAW 0x10025 | ||
| #endif | ||
|
|
||
| #ifndef AL_EXT_IMA4 | ||
| #define AL_EXT_IMA4 1 | ||
| #define AL_FORMAT_MONO_IMA4 0x1300 | ||
| #define AL_FORMAT_STEREO_IMA4 0x1301 | ||
| #endif | ||
|
|
||
| #ifndef AL_EXT_STATIC_BUFFER | ||
| #define AL_EXT_STATIC_BUFFER 1 | ||
| typedef ALvoid (AL_APIENTRY*PFNALBUFFERDATASTATICPROC)(const ALint,ALenum,ALvoid*,ALsizei,ALsizei); | ||
| #ifdef AL_ALEXT_PROTOTYPES | ||
| AL_API ALvoid AL_APIENTRY alBufferDataStatic(const ALint buffer, ALenum format, ALvoid *data, ALsizei len, ALsizei freq); | ||
| #endif | ||
| #endif | ||
|
|
||
| #ifndef ALC_EXT_EFX | ||
| #define ALC_EXT_EFX 1 | ||
| #include "efx.h" | ||
| #endif | ||
|
|
||
| #ifndef ALC_EXT_disconnect | ||
| #define ALC_EXT_disconnect 1 | ||
| #define ALC_CONNECTED 0x313 | ||
| #endif | ||
|
|
||
| #ifndef ALC_EXT_thread_local_context | ||
| #define ALC_EXT_thread_local_context 1 | ||
| typedef ALCboolean (ALC_APIENTRY*PFNALCSETTHREADCONTEXTPROC)(ALCcontext *context); | ||
| typedef ALCcontext* (ALC_APIENTRY*PFNALCGETTHREADCONTEXTPROC)(void); | ||
| #ifdef AL_ALEXT_PROTOTYPES | ||
| ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context); | ||
| ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void); | ||
| #endif | ||
| #endif | ||
|
|
||
| #ifndef AL_EXT_source_distance_model | ||
| #define AL_EXT_source_distance_model 1 | ||
| #define AL_SOURCE_DISTANCE_MODEL 0x200 | ||
| #endif | ||
|
|
||
| #ifndef AL_SOFT_buffer_sub_data | ||
| #define AL_SOFT_buffer_sub_data 1 | ||
| #define AL_BYTE_RW_OFFSETS_SOFT 0x1031 | ||
| #define AL_SAMPLE_RW_OFFSETS_SOFT 0x1032 | ||
| typedef ALvoid (AL_APIENTRY*PFNALBUFFERSUBDATASOFTPROC)(ALuint,ALenum,const ALvoid*,ALsizei,ALsizei); | ||
| #ifdef AL_ALEXT_PROTOTYPES | ||
| AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer,ALenum format,const ALvoid *data,ALsizei offset,ALsizei length); | ||
| #endif | ||
| #endif | ||
|
|
||
| #ifndef AL_SOFT_loop_points | ||
| #define AL_SOFT_loop_points 1 | ||
| #define AL_LOOP_POINTS_SOFT 0x2015 | ||
| #endif | ||
|
|
||
| #ifndef AL_EXT_FOLDBACK | ||
| #define AL_EXT_FOLDBACK 1 | ||
| #define AL_EXT_FOLDBACK_NAME "AL_EXT_FOLDBACK" | ||
| #define AL_FOLDBACK_EVENT_BLOCK 0x4112 | ||
| #define AL_FOLDBACK_EVENT_START 0x4111 | ||
| #define AL_FOLDBACK_EVENT_STOP 0x4113 | ||
| #define AL_FOLDBACK_MODE_MONO 0x4101 | ||
| #define AL_FOLDBACK_MODE_STEREO 0x4102 | ||
| typedef void (AL_APIENTRY*LPALFOLDBACKCALLBACK)(ALenum,ALsizei); | ||
| typedef void (AL_APIENTRY*LPALREQUESTFOLDBACKSTART)(ALenum,ALsizei,ALsizei,ALfloat*,LPALFOLDBACKCALLBACK); | ||
| typedef void (AL_APIENTRY*LPALREQUESTFOLDBACKSTOP)(void); | ||
| #ifdef AL_ALEXT_PROTOTYPES | ||
| AL_API void AL_APIENTRY alRequestFoldbackStart(ALenum mode,ALsizei count,ALsizei length,ALfloat *mem,LPALFOLDBACKCALLBACK callback); | ||
| AL_API void AL_APIENTRY alRequestFoldbackStop(void); | ||
| #endif | ||
| #endif | ||
|
|
||
| #ifndef ALC_EXT_DEDICATED | ||
| #define ALC_EXT_DEDICATED 1 | ||
| #define AL_DEDICATED_GAIN 0x0001 | ||
| #define AL_EFFECT_DEDICATED_DIALOGUE 0x9001 | ||
| #define AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT 0x9000 | ||
| #endif | ||
|
|
||
| #ifndef AL_SOFT_buffer_samples | ||
| #define AL_SOFT_buffer_samples 1 | ||
| /* Channel configurations */ | ||
| #define AL_MONO_SOFT 0x1500 | ||
| #define AL_STEREO_SOFT 0x1501 | ||
| #define AL_REAR_SOFT 0x1502 | ||
| #define AL_QUAD_SOFT 0x1503 | ||
| #define AL_5POINT1_SOFT 0x1504 | ||
| #define AL_6POINT1_SOFT 0x1505 | ||
| #define AL_7POINT1_SOFT 0x1506 | ||
|
|
||
| /* Sample types */ | ||
| #define AL_BYTE_SOFT 0x1400 | ||
| #define AL_UNSIGNED_BYTE_SOFT 0x1401 | ||
| #define AL_SHORT_SOFT 0x1402 | ||
| #define AL_UNSIGNED_SHORT_SOFT 0x1403 | ||
| #define AL_INT_SOFT 0x1404 | ||
| #define AL_UNSIGNED_INT_SOFT 0x1405 | ||
| #define AL_FLOAT_SOFT 0x1406 | ||
| #define AL_DOUBLE_SOFT 0x1407 | ||
| #define AL_BYTE3_SOFT 0x1408 | ||
| #define AL_UNSIGNED_BYTE3_SOFT 0x1409 | ||
|
|
||
| /* Storage formats */ | ||
| #define AL_MONO8_SOFT 0x1100 | ||
| #define AL_MONO16_SOFT 0x1101 | ||
| #define AL_MONO32F_SOFT 0x10010 | ||
| #define AL_STEREO8_SOFT 0x1102 | ||
| #define AL_STEREO16_SOFT 0x1103 | ||
| #define AL_STEREO32F_SOFT 0x10011 | ||
| #define AL_QUAD8_SOFT 0x1204 | ||
| #define AL_QUAD16_SOFT 0x1205 | ||
| #define AL_QUAD32F_SOFT 0x1206 | ||
| #define AL_REAR8_SOFT 0x1207 | ||
| #define AL_REAR16_SOFT 0x1208 | ||
| #define AL_REAR32F_SOFT 0x1209 | ||
| #define AL_5POINT1_8_SOFT 0x120A | ||
| #define AL_5POINT1_16_SOFT 0x120B | ||
| #define AL_5POINT1_32F_SOFT 0x120C | ||
| #define AL_6POINT1_8_SOFT 0x120D | ||
| #define AL_6POINT1_16_SOFT 0x120E | ||
| #define AL_6POINT1_32F_SOFT 0x120F | ||
| #define AL_7POINT1_8_SOFT 0x1210 | ||
| #define AL_7POINT1_16_SOFT 0x1211 | ||
| #define AL_7POINT1_32F_SOFT 0x1212 | ||
|
|
||
| /* Buffer attributes */ | ||
| #define AL_INTERNAL_FORMAT_SOFT 0x2008 | ||
| #define AL_BYTE_LENGTH_SOFT 0x2009 | ||
| #define AL_SAMPLE_LENGTH_SOFT 0x200A | ||
| #define AL_SEC_LENGTH_SOFT 0x200B | ||
|
|
||
| typedef void (AL_APIENTRY*LPALBUFFERSAMPLESSOFT)(ALuint,ALuint,ALenum,ALsizei,ALenum,ALenum,const ALvoid*); | ||
| typedef void (AL_APIENTRY*LPALBUFFERSUBSAMPLESSOFT)(ALuint,ALsizei,ALsizei,ALenum,ALenum,const ALvoid*); | ||
| typedef void (AL_APIENTRY*LPALGETBUFFERSAMPLESSOFT)(ALuint,ALsizei,ALsizei,ALenum,ALenum,ALvoid*); | ||
| typedef ALboolean (AL_APIENTRY*LPALISBUFFERFORMATSUPPORTEDSOFT)(ALenum); | ||
| #ifdef AL_ALEXT_PROTOTYPES | ||
| AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint buffer, ALuint samplerate, ALenum internalformat, ALsizei samples, ALenum channels, ALenum type, const ALvoid *data); | ||
| AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint buffer, ALsizei offset, ALsizei samples, ALenum channels, ALenum type, const ALvoid *data); | ||
| AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint buffer, ALsizei offset, ALsizei samples, ALenum channels, ALenum type, ALvoid *data); | ||
| AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum format); | ||
| #endif | ||
| #endif | ||
|
|
||
| #ifndef AL_SOFT_direct_channels | ||
| #define AL_SOFT_direct_channels 1 | ||
| #define AL_DIRECT_CHANNELS_SOFT 0x1033 | ||
| #endif | ||
|
|
||
| #ifndef ALC_SOFT_loopback | ||
| #define ALC_SOFT_loopback 1 | ||
| #define ALC_FORMAT_CHANNELS_SOFT 0x1990 | ||
| #define ALC_FORMAT_TYPE_SOFT 0x1991 | ||
|
|
||
| /* Sample types */ | ||
| #define ALC_BYTE_SOFT 0x1400 | ||
| #define ALC_UNSIGNED_BYTE_SOFT 0x1401 | ||
| #define ALC_SHORT_SOFT 0x1402 | ||
| #define ALC_UNSIGNED_SHORT_SOFT 0x1403 | ||
| #define ALC_INT_SOFT 0x1404 | ||
| #define ALC_UNSIGNED_INT_SOFT 0x1405 | ||
| #define ALC_FLOAT_SOFT 0x1406 | ||
|
|
||
| /* Channel configurations */ | ||
| #define ALC_MONO_SOFT 0x1500 | ||
| #define ALC_STEREO_SOFT 0x1501 | ||
| #define ALC_QUAD_SOFT 0x1503 | ||
| #define ALC_5POINT1_SOFT 0x1504 | ||
| #define ALC_6POINT1_SOFT 0x1505 | ||
| #define ALC_7POINT1_SOFT 0x1506 | ||
|
|
||
| typedef ALCdevice* (ALC_APIENTRY*LPALCLOOPBACKOPENDEVICESOFT)(const ALCchar*); | ||
| typedef ALCboolean (ALC_APIENTRY*LPALCISRENDERFORMATSUPPORTEDSOFT)(ALCdevice*,ALCsizei,ALCenum,ALCenum); | ||
| typedef void (ALC_APIENTRY*LPALCRENDERSAMPLESSOFT)(ALCdevice*,ALCvoid*,ALCsizei); | ||
| #ifdef AL_ALEXT_PROTOTYPES | ||
| ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceName); | ||
| ALC_API ALCboolean ALC_APIENTRY alcIsRenderFormatSupportedSOFT(ALCdevice *device, ALCsizei freq, ALCenum channels, ALCenum type); | ||
| ALC_API void ALC_APIENTRY alcRenderSamplesSOFT(ALCdevice *device, ALCvoid *buffer, ALCsizei samples); | ||
| #endif | ||
| #endif | ||
|
|
||
| #ifndef AL_EXT_STEREO_ANGLES | ||
| #define AL_EXT_STEREO_ANGLES 1 | ||
| #define AL_STEREO_ANGLES 0x1030 | ||
| #endif | ||
|
|
||
| #ifndef AL_EXT_SOURCE_RADIUS | ||
| #define AL_EXT_SOURCE_RADIUS 1 | ||
| #define AL_SOURCE_RADIUS 0x1031 | ||
| #endif | ||
|
|
||
| #ifndef AL_SOFT_source_latency | ||
| #define AL_SOFT_source_latency 1 | ||
| #define AL_SAMPLE_OFFSET_LATENCY_SOFT 0x1200 | ||
| #define AL_SEC_OFFSET_LATENCY_SOFT 0x1201 | ||
| typedef int64_t ALint64SOFT; | ||
| typedef uint64_t ALuint64SOFT; | ||
| typedef void (AL_APIENTRY*LPALSOURCEDSOFT)(ALuint,ALenum,ALdouble); | ||
| typedef void (AL_APIENTRY*LPALSOURCE3DSOFT)(ALuint,ALenum,ALdouble,ALdouble,ALdouble); | ||
| typedef void (AL_APIENTRY*LPALSOURCEDVSOFT)(ALuint,ALenum,const ALdouble*); | ||
| typedef void (AL_APIENTRY*LPALGETSOURCEDSOFT)(ALuint,ALenum,ALdouble*); | ||
| typedef void (AL_APIENTRY*LPALGETSOURCE3DSOFT)(ALuint,ALenum,ALdouble*,ALdouble*,ALdouble*); | ||
| typedef void (AL_APIENTRY*LPALGETSOURCEDVSOFT)(ALuint,ALenum,ALdouble*); | ||
| typedef void (AL_APIENTRY*LPALSOURCEI64SOFT)(ALuint,ALenum,ALint64SOFT); | ||
| typedef void (AL_APIENTRY*LPALSOURCE3I64SOFT)(ALuint,ALenum,ALint64SOFT,ALint64SOFT,ALint64SOFT); | ||
| typedef void (AL_APIENTRY*LPALSOURCEI64VSOFT)(ALuint,ALenum,const ALint64SOFT*); | ||
| typedef void (AL_APIENTRY*LPALGETSOURCEI64SOFT)(ALuint,ALenum,ALint64SOFT*); | ||
| typedef void (AL_APIENTRY*LPALGETSOURCE3I64SOFT)(ALuint,ALenum,ALint64SOFT*,ALint64SOFT*,ALint64SOFT*); | ||
| typedef void (AL_APIENTRY*LPALGETSOURCEI64VSOFT)(ALuint,ALenum,ALint64SOFT*); | ||
| #ifdef AL_ALEXT_PROTOTYPES | ||
| AL_API void AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value); | ||
| AL_API void AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3); | ||
| AL_API void AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values); | ||
| AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value); | ||
| AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3); | ||
| AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values); | ||
| AL_API void AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value); | ||
| AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3); | ||
| AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values); | ||
| AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value); | ||
| AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3); | ||
| AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values); | ||
| #endif | ||
| #endif | ||
|
|
||
| #ifdef __cplusplus | ||
| } | ||
| #endif | ||
|
|
||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| /* The tokens that would be defined here are already defined in efx.h. This | ||
| * empty file is here to provide compatibility with Windows-based projects | ||
| * that would include it. */ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| #include <al.h> | ||
|
|
||
| // X-RAM Function pointer definitions | ||
| typedef ALboolean (__cdecl *EAXSetBufferMode)(ALsizei n, ALuint *buffers, ALint value); | ||
| typedef ALenum (__cdecl *EAXGetBufferMode)(ALuint buffer, ALint *value); | ||
|
|
||
| ////////////////////////////////////////////////////////////////////////////// | ||
| // Query for X-RAM extension | ||
| // | ||
| // if (alIsExtensionPresent("EAX-RAM") == AL_TRUE) | ||
| // X-RAM Extension found | ||
| // | ||
| ////////////////////////////////////////////////////////////////////////////// | ||
|
|
||
|
|
||
| ////////////////////////////////////////////////////////////////////////////// | ||
| // X-RAM enum names | ||
| // | ||
| // "AL_EAX_RAM_SIZE" | ||
| // "AL_EAX_RAM_FREE" | ||
| // "AL_STORAGE_AUTOMATIC" | ||
| // "AL_STORAGE_HARDWARE" | ||
| // "AL_STORAGE_ACCESSIBLE" | ||
| // | ||
| // Query enum values using alGetEnumValue, for example | ||
| // | ||
| // long lRamSizeEnum = alGetEnumValue("AL_EAX_RAM_SIZE") | ||
| // | ||
| ////////////////////////////////////////////////////////////////////////////// | ||
|
|
||
|
|
||
| ////////////////////////////////////////////////////////////////////////////// | ||
| // Query total amount of X-RAM | ||
| // | ||
| // long lTotalSize = alGetInteger(alGetEnumValue("AL_EAX_RAM_SIZE") | ||
| // | ||
| ////////////////////////////////////////////////////////////////////////////// | ||
|
|
||
|
|
||
| ////////////////////////////////////////////////////////////////////////////// | ||
| // Query free X-RAM available | ||
| // | ||
| // long lFreeSize = alGetInteger(alGetEnumValue("AL_EAX_RAM_FREE") | ||
| // | ||
| ////////////////////////////////////////////////////////////////////////////// | ||
|
|
||
|
|
||
| ////////////////////////////////////////////////////////////////////////////// | ||
| // Query X-RAM Function pointers | ||
| // | ||
| // Use typedefs defined above to get the X-RAM function pointers using | ||
| // alGetProcAddress | ||
| // | ||
| // EAXSetBufferMode eaxSetBufferMode; | ||
| // EAXGetBufferMode eaxGetBufferMode; | ||
| // | ||
| // eaxSetBufferMode = (EAXSetBufferMode)alGetProcAddress("EAXSetBufferMode"); | ||
| // eaxGetBufferMode = (EAXGetBufferMode)alGetProcAddress("EAXGetBufferMode"); | ||
| // | ||
| ////////////////////////////////////////////////////////////////////////////// | ||
|
|
||
|
|
||
| ////////////////////////////////////////////////////////////////////////////// | ||
| // Force an Open AL Buffer into X-RAM (good for non-streaming buffers) | ||
| // | ||
| // ALuint uiBuffer; | ||
| // alGenBuffers(1, &uiBuffer); | ||
| // eaxSetBufferMode(1, &uiBuffer, alGetEnumValue("AL_STORAGE_HARDWARE")); | ||
| // alBufferData(...); | ||
| // | ||
| ////////////////////////////////////////////////////////////////////////////// | ||
|
|
||
|
|
||
| ////////////////////////////////////////////////////////////////////////////// | ||
| // Force an Open AL Buffer into 'accessible' (currently host) RAM (good for streaming buffers) | ||
| // | ||
| // ALuint uiBuffer; | ||
| // alGenBuffers(1, &uiBuffer); | ||
| // eaxSetBufferMode(1, &uiBuffer, alGetEnumValue("AL_STORAGE_ACCESSIBLE")); | ||
| // alBufferData(...); | ||
| // | ||
| ////////////////////////////////////////////////////////////////////////////// | ||
|
|
||
|
|
||
| ////////////////////////////////////////////////////////////////////////////// | ||
| // Put an Open AL Buffer into X-RAM if memory is available, otherwise use | ||
| // host RAM. This is the default mode. | ||
| // | ||
| // ALuint uiBuffer; | ||
| // alGenBuffers(1, &uiBuffer); | ||
| // eaxSetBufferMode(1, &uiBuffer, alGetEnumValue("AL_STORAGE_AUTOMATIC")); | ||
| // alBufferData(...); | ||
| // | ||
| ////////////////////////////////////////////////////////////////////////////// |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,184 @@ | ||
| //////////////////////////////////////////////////////////////////////////////// | ||
| /// | ||
| /// FIR low-pass (anti-alias) filter with filter coefficient design routine and | ||
| /// MMX optimization. | ||
| /// | ||
| /// Anti-alias filter is used to prevent folding of high frequencies when | ||
| /// transposing the sample rate with interpolation. | ||
| /// | ||
| /// Author : Copyright (c) Olli Parviainen | ||
| /// Author e-mail : oparviai 'at' iki.fi | ||
| /// SoundTouch WWW: http://www.surina.net/soundtouch | ||
| /// | ||
| //////////////////////////////////////////////////////////////////////////////// | ||
| // | ||
| // Last changed : $Date: 2009-01-11 13:34:24 +0200 (Sun, 11 Jan 2009) $ | ||
| // File revision : $Revision: 4 $ | ||
| // | ||
| // $Id: AAFilter.cpp 45 2009-01-11 11:34:24Z oparviai $ | ||
| // | ||
| //////////////////////////////////////////////////////////////////////////////// | ||
| // | ||
| // 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 <memory.h> | ||
| #include <assert.h> | ||
| #include <math.h> | ||
| #include <stdlib.h> | ||
| #include "AAFilter.h" | ||
| #include "FIRFilter.h" | ||
|
|
||
| using namespace soundtouch; | ||
|
|
||
| #define PI 3.141592655357989 | ||
| #define TWOPI (2 * PI) | ||
|
|
||
| /***************************************************************************** | ||
| * | ||
| * Implementation of the class 'AAFilter' | ||
| * | ||
| *****************************************************************************/ | ||
|
|
||
| AAFilter::AAFilter(uint len) | ||
| { | ||
| pFIR = FIRFilter::newInstance(); | ||
| cutoffFreq = 0.5; | ||
| setLength(len); | ||
| } | ||
|
|
||
|
|
||
|
|
||
| AAFilter::~AAFilter() | ||
| { | ||
| delete pFIR; | ||
| } | ||
|
|
||
|
|
||
|
|
||
| // Sets new anti-alias filter cut-off edge frequency, scaled to | ||
| // sampling frequency (nyquist frequency = 0.5). | ||
| // The filter will cut frequencies higher than the given frequency. | ||
| void AAFilter::setCutoffFreq(double newCutoffFreq) | ||
| { | ||
| cutoffFreq = newCutoffFreq; | ||
| calculateCoeffs(); | ||
| } | ||
|
|
||
|
|
||
|
|
||
| // Sets number of FIR filter taps | ||
| void AAFilter::setLength(uint newLength) | ||
| { | ||
| length = newLength; | ||
| calculateCoeffs(); | ||
| } | ||
|
|
||
|
|
||
|
|
||
| // Calculates coefficients for a low-pass FIR filter using Hamming window | ||
| void AAFilter::calculateCoeffs() | ||
| { | ||
| uint i; | ||
| double cntTemp, temp, tempCoeff,h, w; | ||
| double fc2, wc; | ||
| double scaleCoeff, sum; | ||
| double *work; | ||
| SAMPLETYPE *coeffs; | ||
|
|
||
| assert(length >= 2); | ||
| assert(length % 4 == 0); | ||
| assert(cutoffFreq >= 0); | ||
| assert(cutoffFreq <= 0.5); | ||
|
|
||
| work = new double[length]; | ||
| coeffs = new SAMPLETYPE[length]; | ||
|
|
||
| fc2 = 2.0 * cutoffFreq; | ||
| wc = PI * fc2; | ||
| tempCoeff = TWOPI / (double)length; | ||
|
|
||
| sum = 0; | ||
| for (i = 0; i < length; i ++) | ||
| { | ||
| cntTemp = (double)i - (double)(length / 2); | ||
|
|
||
| temp = cntTemp * wc; | ||
| if (temp != 0) | ||
| { | ||
| h = fc2 * sin(temp) / temp; // sinc function | ||
| } | ||
| else | ||
| { | ||
| h = 1.0; | ||
| } | ||
| w = 0.54 + 0.46 * cos(tempCoeff * cntTemp); // hamming window | ||
|
|
||
| temp = w * h; | ||
| work[i] = temp; | ||
|
|
||
| // calc net sum of coefficients | ||
| sum += temp; | ||
| } | ||
|
|
||
| // ensure the sum of coefficients is larger than zero | ||
| assert(sum > 0); | ||
|
|
||
| // ensure we've really designed a lowpass filter... | ||
| assert(work[length/2] > 0); | ||
| assert(work[length/2 + 1] > -1e-6); | ||
| assert(work[length/2 - 1] > -1e-6); | ||
|
|
||
| // Calculate a scaling coefficient in such a way that the result can be | ||
| // divided by 16384 | ||
| scaleCoeff = 16384.0f / sum; | ||
|
|
||
| for (i = 0; i < length; i ++) | ||
| { | ||
| // scale & round to nearest integer | ||
| temp = work[i] * scaleCoeff; | ||
| temp += (temp >= 0) ? 0.5 : -0.5; | ||
| // ensure no overfloods | ||
| assert(temp >= -32768 && temp <= 32767); | ||
| coeffs[i] = (SAMPLETYPE)temp; | ||
| } | ||
|
|
||
| // Set coefficients. Use divide factor 14 => divide result by 2^14 = 16384 | ||
| pFIR->setCoefficients(coeffs, length, 14); | ||
|
|
||
| delete[] work; | ||
| delete[] coeffs; | ||
| } | ||
|
|
||
|
|
||
| // Applies the filter to the given sequence of samples. | ||
| // Note : The amount of outputted samples is by value of 'filter length' | ||
| // smaller than the amount of input samples. | ||
| uint AAFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) const | ||
| { | ||
| return pFIR->evaluate(dest, src, numSamples, numChannels); | ||
| } | ||
|
|
||
|
|
||
| uint AAFilter::getLength() const | ||
| { | ||
| return pFIR->getLength(); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,91 @@ | ||
| //////////////////////////////////////////////////////////////////////////////// | ||
| /// | ||
| /// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo | ||
| /// while maintaining the original pitch by using a time domain WSOLA-like method | ||
| /// with several performance-increasing tweaks. | ||
| /// | ||
| /// Anti-alias filter is used to prevent folding of high frequencies when | ||
| /// transposing the sample rate with interpolation. | ||
| /// | ||
| /// Author : Copyright (c) Olli Parviainen | ||
| /// Author e-mail : oparviai 'at' iki.fi | ||
| /// SoundTouch WWW: http://www.surina.net/soundtouch | ||
| /// | ||
| //////////////////////////////////////////////////////////////////////////////// | ||
| // | ||
| // Last changed : $Date: 2008-02-10 18:26:55 +0200 (Sun, 10 Feb 2008) $ | ||
| // File revision : $Revision: 4 $ | ||
| // | ||
| // $Id: AAFilter.h 11 2008-02-10 16:26:55Z oparviai $ | ||
| // | ||
| //////////////////////////////////////////////////////////////////////////////// | ||
| // | ||
| // 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 AAFilter_H | ||
| #define AAFilter_H | ||
|
|
||
| #include "STTypes.h" | ||
|
|
||
| namespace soundtouch | ||
| { | ||
|
|
||
| class AAFilter | ||
| { | ||
| protected: | ||
| class FIRFilter *pFIR; | ||
|
|
||
| /// Low-pass filter cut-off frequency, negative = invalid | ||
| double cutoffFreq; | ||
|
|
||
| /// num of filter taps | ||
| uint length; | ||
|
|
||
| /// Calculate the FIR coefficients realizing the given cutoff-frequency | ||
| void calculateCoeffs(); | ||
| public: | ||
| AAFilter(uint length); | ||
|
|
||
| ~AAFilter(); | ||
|
|
||
| /// Sets new anti-alias filter cut-off edge frequency, scaled to sampling | ||
| /// frequency (nyquist frequency = 0.5). The filter will cut off the | ||
| /// frequencies than that. | ||
| void setCutoffFreq(double newCutoffFreq); | ||
|
|
||
| /// Sets number of FIR filter taps, i.e. ~filter complexity | ||
| void setLength(uint newLength); | ||
|
|
||
| uint getLength() const; | ||
|
|
||
| /// Applies the filter to the given sequence of samples. | ||
| /// Note : The amount of outputted samples is by value of 'filter length' | ||
| /// smaller than the amount of input samples. | ||
| uint evaluate(SAMPLETYPE *dest, | ||
| const SAMPLETYPE *src, | ||
| uint numSamples, | ||
| uint numChannels) const; | ||
| }; | ||
|
|
||
| } | ||
|
|
||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,370 @@ | ||
| //////////////////////////////////////////////////////////////////////////////// | ||
| /// | ||
| /// 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: 2012-08-30 22:45:25 +0300 (Thu, 30 Aug 2012) $ | ||
| // File revision : $Revision: 4 $ | ||
| // | ||
| // $Id: BPMDetect.cpp 149 2012-08-30 19:45:25Z oparviai $ | ||
| // | ||
| //////////////////////////////////////////////////////////////////////////////// | ||
| // | ||
| // 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 <math.h> | ||
| #include <assert.h> | ||
| #include <string.h> | ||
| #include <stdio.h> | ||
| #include "FIFOSampleBuffer.h" | ||
| #include "PeakFinder.h" | ||
| #include "BPMDetect.h" | ||
|
|
||
| using namespace soundtouch; | ||
|
|
||
| #define INPUT_BLOCK_SAMPLES 2048 | ||
| #define DECIMATED_BLOCK_SAMPLES 256 | ||
|
|
||
| /// 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); | ||
|
|
||
|
|
||
| //////////////////////////////////////////////////////////////////////////////// | ||
|
|
||
| // Enable following define to create bpm analysis file: | ||
|
|
||
| // #define _CREATE_BPM_DEBUG_FILE | ||
|
|
||
| #ifdef _CREATE_BPM_DEBUG_FILE | ||
|
|
||
| #define DEBUGFILE_NAME "c:\\temp\\soundtouch-bpm-debug.txt" | ||
|
|
||
| static void _SaveDebugData(const float *data, int minpos, int maxpos, double coeff) | ||
| { | ||
| FILE *fptr = fopen(DEBUGFILE_NAME, "wt"); | ||
| int i; | ||
|
|
||
| if (fptr) | ||
| { | ||
| printf("\n\nWriting BPM debug data into file " DEBUGFILE_NAME "\n\n"); | ||
| for (i = minpos; i < maxpos; i ++) | ||
| { | ||
| fprintf(fptr, "%d\t%.1lf\t%f\n", i, coeff / (double)i, data[i]); | ||
| } | ||
| fclose(fptr); | ||
| } | ||
| } | ||
| #else | ||
| #define _SaveDebugData(a,b,c,d) | ||
| #endif | ||
|
|
||
| //////////////////////////////////////////////////////////////////////////////// | ||
|
|
||
|
|
||
| BPMDetect::BPMDetect(int numChannels, int aSampleRate) | ||
| { | ||
| this->sampleRate = aSampleRate; | ||
| this->channels = numChannels; | ||
|
|
||
| decimateSum = 0; | ||
| decimateCount = 0; | ||
|
|
||
| envelopeAccu = 0; | ||
|
|
||
| // Initialize RMS volume accumulator to RMS level of 1500 (out of 32768) that's | ||
| // safe initial RMS signal level value for song data. This value is then adapted | ||
| // to the actual level during processing. | ||
| #ifdef SOUNDTOUCH_INTEGER_SAMPLES | ||
| // integer samples | ||
| RMSVolumeAccu = (1500 * 1500) / avgnorm; | ||
| #else | ||
| // float samples, scaled to range [-1..+1[ | ||
| RMSVolumeAccu = (0.045f * 0.045f) / avgnorm; | ||
| #endif | ||
|
|
||
| // choose decimation factor so that result is approx. 1000 Hz | ||
| decimateBy = sampleRate / 1000; | ||
| 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)); | ||
|
|
||
| // allocate processing buffer | ||
| buffer = new FIFOSampleBuffer(); | ||
| // we do processing in mono mode | ||
| buffer->setChannels(1); | ||
| buffer->clear(); | ||
| } | ||
|
|
||
|
|
||
|
|
||
| BPMDetect::~BPMDetect() | ||
| { | ||
| delete[] xcorr; | ||
| delete buffer; | ||
| } | ||
|
|
||
|
|
||
|
|
||
| /// convert to mono, 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(channels > 0); | ||
| assert(decimateBy > 0); | ||
| outcount = 0; | ||
| for (count = 0; count < numsamples; count ++) | ||
| { | ||
| int j; | ||
|
|
||
| // convert to mono and accumulate | ||
| for (j = 0; j < channels; j ++) | ||
| { | ||
| decimateSum += src[j]; | ||
| } | ||
| src += j; | ||
|
|
||
| decimateCount ++; | ||
| if (decimateCount >= decimateBy) | ||
| { | ||
| // Store every Nth sample only | ||
| out = (LONG_SAMPLETYPE)(decimateSum / (decimateBy * channels)); | ||
| decimateSum = 0; | ||
| decimateCount = 0; | ||
| #ifdef SOUNDTOUCH_INTEGER_SAMPLES | ||
| // check ranges for sure (shouldn't actually be necessary) | ||
| if (out > 32767) | ||
| { | ||
| out = 32767; | ||
| } | ||
| else if (out < -32768) | ||
| { | ||
| out = -32768; | ||
| } | ||
| #endif // SOUNDTOUCH_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 static double decay = 0.7f; // decay constant for smoothing the envelope | ||
| const static double norm = (1 - decay); | ||
|
|
||
| int i; | ||
| LONG_SAMPLETYPE out; | ||
| double 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 cutoff ~2 times RMS volume | ||
| // (we're interested in peak values, not the silent moments) | ||
| if (val < 0.5 * sqrt(RMSVolumeAccu * avgnorm)) | ||
| { | ||
| val = 0; | ||
| } | ||
|
|
||
| // smooth amplitude envelope | ||
| envelopeAccu *= decay; | ||
| envelopeAccu += val; | ||
| out = (LONG_SAMPLETYPE)(envelopeAccu * norm); | ||
|
|
||
| #ifdef SOUNDTOUCH_INTEGER_SAMPLES | ||
| // cut peaks (shouldn't be necessary though) | ||
| if (out > 32767) out = 32767; | ||
| #endif // SOUNDTOUCH_INTEGER_SAMPLES | ||
| samples[i] = (SAMPLETYPE)out; | ||
| } | ||
| } | ||
|
|
||
|
|
||
|
|
||
| void BPMDetect::inputSamples(const SAMPLETYPE *samples, int numSamples) | ||
| { | ||
| SAMPLETYPE decimated[DECIMATED_BLOCK_SAMPLES]; | ||
|
|
||
| // iterate so that max INPUT_BLOCK_SAMPLES processed per iteration | ||
| while (numSamples > 0) | ||
| { | ||
| int block; | ||
| int decSamples; | ||
|
|
||
| block = (numSamples > INPUT_BLOCK_SAMPLES) ? INPUT_BLOCK_SAMPLES : numSamples; | ||
|
|
||
| // decimate. note that converts to mono at the same time | ||
| decSamples = decimate(decimated, samples, block); | ||
| samples += block * channels; | ||
| numSamples -= block; | ||
|
|
||
| // envelope new samples and add them to buffer | ||
| calcEnvelope(decimated, decSamples); | ||
| buffer->putSamples(decimated, decSamples); | ||
| } | ||
|
|
||
| // when the buffer has enought samples for processing... | ||
| if ((int)buffer->numSamples() > windowLen) | ||
| { | ||
| int processLength; | ||
|
|
||
| // how many samples are processed | ||
| processLength = (int)buffer->numSamples() - windowLen; | ||
|
|
||
| // ... calculate autocorrelations for oldest samples... | ||
| updateXCorr(processLength); | ||
| // ... and remove them from the buffer | ||
| buffer->receiveSamples(processLength); | ||
| } | ||
| } | ||
|
|
||
|
|
||
|
|
||
| void BPMDetect::removeBias() | ||
| { | ||
| int i; | ||
| float minval = 1e12f; // arbitrary large number | ||
|
|
||
| for (i = windowStart; i < windowLen; i ++) | ||
| { | ||
| if (xcorr[i] < minval) | ||
| { | ||
| minval = xcorr[i]; | ||
| } | ||
| } | ||
|
|
||
| for (i = windowStart; i < windowLen; i ++) | ||
| { | ||
| xcorr[i] -= minval; | ||
| } | ||
| } | ||
|
|
||
|
|
||
| float BPMDetect::getBpm() | ||
| { | ||
| double peakPos; | ||
| double coeff; | ||
| PeakFinder peakFinder; | ||
|
|
||
| coeff = 60.0 * ((double)sampleRate / (double)decimateBy); | ||
|
|
||
| // save bpm debug analysis data if debug data enabled | ||
| _SaveDebugData(xcorr, windowStart, windowLen, coeff); | ||
|
|
||
| // remove bias from xcorr data | ||
| removeBias(); | ||
|
|
||
| // find peak position | ||
| peakPos = peakFinder.detectPeak(xcorr, windowStart, windowLen); | ||
|
|
||
| assert(decimateBy != 0); | ||
| if (peakPos < 1e-9) return 0.0; // detection failed. | ||
|
|
||
| // calculate BPM | ||
| return (float) (coeff / peakPos); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,164 @@ | ||
| //////////////////////////////////////////////////////////////////////////////// | ||
| /// | ||
| /// 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: 2012-08-30 22:53:44 +0300 (Thu, 30 Aug 2012) $ | ||
| // File revision : $Revision: 4 $ | ||
| // | ||
| // $Id: BPMDetect.h 150 2012-08-30 19:53:44Z oparviai $ | ||
| // | ||
| //////////////////////////////////////////////////////////////////////////////// | ||
| // | ||
| // 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" | ||
|
|
||
| namespace soundtouch | ||
| { | ||
|
|
||
| /// Minimum allowed BPM rate. Used to restrict accepted result above a reasonable limit. | ||
| #define MIN_BPM 29 | ||
|
|
||
| /// Maximum allowed BPM rate. Used to restrict accepted result below a reasonable limit. | ||
| #define MAX_BPM 200 | ||
|
|
||
|
|
||
| /// Class for calculating BPM rate for audio data. | ||
| class BPMDetect | ||
| { | ||
| protected: | ||
| /// Auto-correlation accumulator bins. | ||
| float *xcorr; | ||
|
|
||
| /// Amplitude envelope sliding average approximation level accumulator | ||
| double envelopeAccu; | ||
|
|
||
| /// RMS volume sliding average approximation level accumulator | ||
| double 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; | ||
|
|
||
| /// 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 | ||
| ); | ||
|
|
||
| /// remove constant bias from xcorr data | ||
| void removeBias(); | ||
|
|
||
| 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(const 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_ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| set(SRCS | ||
| AAFilter.cpp | ||
| BPMDetect.cpp | ||
| cpu_detect_x86.cpp | ||
| FIFOSampleBuffer.cpp | ||
| FIRFilter.cpp | ||
| mmx_optimized.cpp | ||
| PeakFinder.cpp | ||
| RateTransposer.cpp | ||
| SoundTouch.cpp | ||
| sse_optimized.cpp | ||
| TDStretch.cpp | ||
| ) | ||
|
|
||
| add_library(SoundTouch STATIC ${SRCS}) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,274 @@ | ||
| //////////////////////////////////////////////////////////////////////////////// | ||
| /// | ||
| /// 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 | ||
| /// outputted samples from the buffer, as well as grows the buffer 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: 2012-11-08 20:53:01 +0200 (Thu, 08 Nov 2012) $ | ||
| // File revision : $Revision: 4 $ | ||
| // | ||
| // $Id: FIFOSampleBuffer.cpp 160 2012-11-08 18:53:01Z oparviai $ | ||
| // | ||
| //////////////////////////////////////////////////////////////////////////////// | ||
| // | ||
| // 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 <stdlib.h> | ||
| #include <memory.h> | ||
| #include <string.h> | ||
| #include <assert.h> | ||
|
|
||
| #include "FIFOSampleBuffer.h" | ||
|
|
||
| using namespace soundtouch; | ||
|
|
||
| // Constructor | ||
| FIFOSampleBuffer::FIFOSampleBuffer(int numChannels) | ||
| { | ||
| assert(numChannels > 0); | ||
| sizeInBytes = 0; // reasonable initial value | ||
| buffer = NULL; | ||
| bufferUnaligned = NULL; | ||
| samplesInBuffer = 0; | ||
| bufferPos = 0; | ||
| channels = (uint)numChannels; | ||
| ensureCapacity(32); // allocate initial capacity | ||
| } | ||
|
|
||
|
|
||
| // destructor | ||
| FIFOSampleBuffer::~FIFOSampleBuffer() | ||
| { | ||
| delete[] bufferUnaligned; | ||
| bufferUnaligned = NULL; | ||
| buffer = NULL; | ||
| } | ||
|
|
||
|
|
||
| // Sets number of channels, 1 = mono, 2 = stereo | ||
| void FIFOSampleBuffer::setChannels(int numChannels) | ||
| { | ||
| uint usedBytes; | ||
|
|
||
| assert(numChannels > 0); | ||
| usedBytes = channels * samplesInBuffer; | ||
| channels = (uint)numChannels; | ||
| samplesInBuffer = usedBytes / channels; | ||
| } | ||
|
|
||
|
|
||
| // if output location pointer 'bufferPos' isn't zero, 'rewinds' the buffer and | ||
| // zeroes this pointer by copying samples from the 'bufferPos' pointer | ||
| // location on to the beginning of the buffer. | ||
| void FIFOSampleBuffer::rewind() | ||
| { | ||
| if (buffer && bufferPos) | ||
| { | ||
| memmove(buffer, ptrBegin(), sizeof(SAMPLETYPE) * channels * samplesInBuffer); | ||
| bufferPos = 0; | ||
| } | ||
| } | ||
|
|
||
|
|
||
| // Adds 'numSamples' pcs of samples from the 'samples' memory position to | ||
| // the sample buffer. | ||
| void FIFOSampleBuffer::putSamples(const SAMPLETYPE *samples, uint nSamples) | ||
| { | ||
| memcpy(ptrEnd(nSamples), samples, sizeof(SAMPLETYPE) * nSamples * channels); | ||
| samplesInBuffer += nSamples; | ||
| } | ||
|
|
||
|
|
||
| // Increases the 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! | ||
| void FIFOSampleBuffer::putSamples(uint nSamples) | ||
| { | ||
| uint req; | ||
|
|
||
| req = samplesInBuffer + nSamples; | ||
| ensureCapacity(req); | ||
| samplesInBuffer += nSamples; | ||
| } | ||
|
|
||
|
|
||
| // 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! | ||
| // | ||
| // Parameter 'slackCapacity' tells the function how much free capacity (in | ||
| // terms of samples) there _at least_ should be, in order to the caller to | ||
| // succesfully insert all the required samples to the buffer. When necessary, | ||
| // the function grows the buffer size to comply with this requirement. | ||
| // | ||
| // 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 *FIFOSampleBuffer::ptrEnd(uint slackCapacity) | ||
| { | ||
| ensureCapacity(samplesInBuffer + slackCapacity); | ||
| return buffer + samplesInBuffer * channels; | ||
| } | ||
|
|
||
|
|
||
| // Returns a pointer to the beginning of the currently non-outputted samples. | ||
| // This function is provided for accessing the output samples directly. | ||
| // Please be careful! | ||
| // | ||
| // When using this function to output samples, also remember to 'remove' the | ||
| // outputted samples from the buffer by calling the | ||
| // 'receiveSamples(numSamples)' function | ||
| SAMPLETYPE *FIFOSampleBuffer::ptrBegin() | ||
| { | ||
| assert(buffer); | ||
| return buffer + bufferPos * channels; | ||
| } | ||
|
|
||
|
|
||
| // Ensures that the buffer has enought capacity, i.e. space for _at least_ | ||
| // 'capacityRequirement' number of samples. The buffer is grown in steps of | ||
| // 4 kilobytes to eliminate the need for frequently growing up the buffer, | ||
| // as well as to round the buffer size up to the virtual memory page size. | ||
| void FIFOSampleBuffer::ensureCapacity(uint capacityRequirement) | ||
| { | ||
| SAMPLETYPE *tempUnaligned, *temp; | ||
|
|
||
| if (capacityRequirement > getCapacity()) | ||
| { | ||
| // enlarge the buffer in 4kbyte steps (round up to next 4k boundary) | ||
| sizeInBytes = (capacityRequirement * channels * sizeof(SAMPLETYPE) + 4095) & (uint)-4096; | ||
| assert(sizeInBytes % 2 == 0); | ||
| tempUnaligned = new SAMPLETYPE[sizeInBytes / sizeof(SAMPLETYPE) + 16 / sizeof(SAMPLETYPE)]; | ||
| if (tempUnaligned == NULL) | ||
| { | ||
| ST_THROW_RT_ERROR("Couldn't allocate memory!\n"); | ||
| } | ||
| // Align the buffer to begin at 16byte cache line boundary for optimal performance | ||
| temp = (SAMPLETYPE *)SOUNDTOUCH_ALIGN_POINTER_16(tempUnaligned); | ||
| if (samplesInBuffer) | ||
| { | ||
| memcpy(temp, ptrBegin(), samplesInBuffer * channels * sizeof(SAMPLETYPE)); | ||
| } | ||
| delete[] bufferUnaligned; | ||
| buffer = temp; | ||
| bufferUnaligned = tempUnaligned; | ||
| bufferPos = 0; | ||
| } | ||
| else | ||
| { | ||
| // simply rewind the buffer (if necessary) | ||
| rewind(); | ||
| } | ||
| } | ||
|
|
||
|
|
||
| // Returns the current buffer capacity in terms of samples | ||
| uint FIFOSampleBuffer::getCapacity() const | ||
| { | ||
| return sizeInBytes / (channels * sizeof(SAMPLETYPE)); | ||
| } | ||
|
|
||
|
|
||
| // Returns the number of samples currently in the buffer | ||
| uint FIFOSampleBuffer::numSamples() const | ||
| { | ||
| return samplesInBuffer; | ||
| } | ||
|
|
||
|
|
||
| // Output samples from beginning of the sample buffer. Copies demanded number | ||
| // of samples to output and removes them from the sample buffer. If there | ||
| // are less than 'numsample' samples in the buffer, returns all available. | ||
| // | ||
| // Returns number of samples copied. | ||
| uint FIFOSampleBuffer::receiveSamples(SAMPLETYPE *output, uint maxSamples) | ||
| { | ||
| uint num; | ||
|
|
||
| num = (maxSamples > samplesInBuffer) ? samplesInBuffer : maxSamples; | ||
|
|
||
| memcpy(output, ptrBegin(), channels * sizeof(SAMPLETYPE) * num); | ||
| return receiveSamples(num); | ||
| } | ||
|
|
||
|
|
||
| // Removes samples from the beginning of the sample buffer without copying them | ||
| // anywhere. Used to reduce the number of samples in the buffer, when accessing | ||
| // the sample buffer with the 'ptrBegin' function. | ||
| uint FIFOSampleBuffer::receiveSamples(uint maxSamples) | ||
| { | ||
| if (maxSamples >= samplesInBuffer) | ||
| { | ||
| uint temp; | ||
|
|
||
| temp = samplesInBuffer; | ||
| samplesInBuffer = 0; | ||
| return temp; | ||
| } | ||
|
|
||
| samplesInBuffer -= maxSamples; | ||
| bufferPos += maxSamples; | ||
|
|
||
| return maxSamples; | ||
| } | ||
|
|
||
|
|
||
| // Returns nonzero if the sample buffer is empty | ||
| int FIFOSampleBuffer::isEmpty() const | ||
| { | ||
| return (samplesInBuffer == 0) ? 1 : 0; | ||
| } | ||
|
|
||
|
|
||
| // Clears the sample buffer | ||
| void FIFOSampleBuffer::clear() | ||
| { | ||
| samplesInBuffer = 0; | ||
| bufferPos = 0; | ||
| } | ||
|
|
||
|
|
||
| /// allow trimming (downwards) amount of samples in pipeline. | ||
| /// Returns adjusted amount of samples | ||
| uint FIFOSampleBuffer::adjustAmountOfSamples(uint numSamples) | ||
| { | ||
| if (numSamples < samplesInBuffer) | ||
| { | ||
| samplesInBuffer = numSamples; | ||
| } | ||
| return samplesInBuffer; | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,178 @@ | ||
| //////////////////////////////////////////////////////////////////////////////// | ||
| /// | ||
| /// 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: 2012-06-13 22:29:53 +0300 (Wed, 13 Jun 2012) $ | ||
| // File revision : $Revision: 4 $ | ||
| // | ||
| // $Id: FIFOSampleBuffer.h 143 2012-06-13 19:29:53Z oparviai $ | ||
| // | ||
| //////////////////////////////////////////////////////////////////////////////// | ||
| // | ||
| // 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(uint capacityRequirement); | ||
|
|
||
| /// Returns current capacity. | ||
| uint getCapacity() const; | ||
|
|
||
| public: | ||
|
|
||
| /// Constructor | ||
| FIFOSampleBuffer(int 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(); | ||
|
|
||
| /// 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(int numChannels); | ||
|
|
||
| /// Returns nonzero if there aren't any samples available for outputting. | ||
| virtual int isEmpty() const; | ||
|
|
||
| /// Clears all the samples. | ||
| virtual void clear(); | ||
|
|
||
| /// allow trimming (downwards) amount of samples in pipeline. | ||
| /// Returns adjusted amount of samples | ||
| uint adjustAmountOfSamples(uint numSamples); | ||
| }; | ||
|
|
||
| } | ||
|
|
||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,234 @@ | ||
| //////////////////////////////////////////////////////////////////////////////// | ||
| /// | ||
| /// '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: 2012-06-13 22:29:53 +0300 (Wed, 13 Jun 2012) $ | ||
| // File revision : $Revision: 4 $ | ||
| // | ||
| // $Id: FIFOSamplePipe.h 143 2012-06-13 19:29:53Z oparviai $ | ||
| // | ||
| //////////////////////////////////////////////////////////////////////////////// | ||
| // | ||
| // 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 <assert.h> | ||
| #include <stdlib.h> | ||
| #include "STTypes.h" | ||
|
|
||
| namespace soundtouch | ||
| { | ||
|
|
||
| /// Abstract base class for FIFO (first-in-first-out) sample processing classes. | ||
| class FIFOSamplePipe | ||
| { | ||
| public: | ||
| // virtual default destructor | ||
| virtual ~FIFOSamplePipe() {} | ||
|
|
||
|
|
||
| /// 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() = 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; | ||
|
|
||
| /// allow trimming (downwards) amount of samples in pipeline. | ||
| /// Returns adjusted amount of samples | ||
| virtual uint adjustAmountOfSamples(uint numSamples) = 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() | ||
| { | ||
| 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(); | ||
| } | ||
|
|
||
| /// allow trimming (downwards) amount of samples in pipeline. | ||
| /// Returns adjusted amount of samples | ||
| virtual uint adjustAmountOfSamples(uint numSamples) | ||
| { | ||
| return output->adjustAmountOfSamples(numSamples); | ||
| } | ||
|
|
||
| }; | ||
|
|
||
| } | ||
|
|
||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,259 @@ | ||
| //////////////////////////////////////////////////////////////////////////////// | ||
| /// | ||
| /// General FIR digital filter routines with MMX optimization. | ||
| /// | ||
| /// Note : MMX optimized functions reside in a separate, platform-specific file, | ||
| /// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' | ||
| /// | ||
| /// Author : Copyright (c) Olli Parviainen | ||
| /// Author e-mail : oparviai 'at' iki.fi | ||
| /// SoundTouch WWW: http://www.surina.net/soundtouch | ||
| /// | ||
| //////////////////////////////////////////////////////////////////////////////// | ||
| // | ||
| // Last changed : $Date: 2011-09-02 21:56:11 +0300 (Fri, 02 Sep 2011) $ | ||
| // File revision : $Revision: 4 $ | ||
| // | ||
| // $Id: FIRFilter.cpp 131 2011-09-02 18:56:11Z oparviai $ | ||
| // | ||
| //////////////////////////////////////////////////////////////////////////////// | ||
| // | ||
| // 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 <memory.h> | ||
| #include <assert.h> | ||
| #include <math.h> | ||
| #include <stdlib.h> | ||
| #include "FIRFilter.h" | ||
| #include "cpu_detect.h" | ||
|
|
||
| using namespace soundtouch; | ||
|
|
||
| /***************************************************************************** | ||
| * | ||
| * Implementation of the class 'FIRFilter' | ||
| * | ||
| *****************************************************************************/ | ||
|
|
||
| FIRFilter::FIRFilter() | ||
| { | ||
| resultDivFactor = 0; | ||
| resultDivider = 0; | ||
| length = 0; | ||
| lengthDiv8 = 0; | ||
| filterCoeffs = NULL; | ||
| } | ||
|
|
||
|
|
||
| FIRFilter::~FIRFilter() | ||
| { | ||
| delete[] filterCoeffs; | ||
| } | ||
|
|
||
| // Usual C-version of the filter routine for stereo sound | ||
| uint FIRFilter::evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const | ||
| { | ||
| uint i, j, end; | ||
| LONG_SAMPLETYPE suml, sumr; | ||
| #ifdef SOUNDTOUCH_FLOAT_SAMPLES | ||
| // when using floating point samples, use a scaler instead of a divider | ||
| // because division is much slower operation than multiplying. | ||
| double dScaler = 1.0 / (double)resultDivider; | ||
| #endif | ||
|
|
||
| assert(length != 0); | ||
| assert(src != NULL); | ||
| assert(dest != NULL); | ||
| assert(filterCoeffs != NULL); | ||
|
|
||
| end = 2 * (numSamples - length); | ||
|
|
||
| for (j = 0; j < end; j += 2) | ||
| { | ||
| const SAMPLETYPE *ptr; | ||
|
|
||
| suml = sumr = 0; | ||
| ptr = src + j; | ||
|
|
||
| for (i = 0; i < length; i += 4) | ||
| { | ||
| // loop is unrolled by factor of 4 here for efficiency | ||
| suml += ptr[2 * i + 0] * filterCoeffs[i + 0] + | ||
| ptr[2 * i + 2] * filterCoeffs[i + 1] + | ||
| ptr[2 * i + 4] * filterCoeffs[i + 2] + | ||
| ptr[2 * i + 6] * filterCoeffs[i + 3]; | ||
| sumr += ptr[2 * i + 1] * filterCoeffs[i + 0] + | ||
| ptr[2 * i + 3] * filterCoeffs[i + 1] + | ||
| ptr[2 * i + 5] * filterCoeffs[i + 2] + | ||
| ptr[2 * i + 7] * filterCoeffs[i + 3]; | ||
| } | ||
|
|
||
| #ifdef SOUNDTOUCH_INTEGER_SAMPLES | ||
| suml >>= resultDivFactor; | ||
| sumr >>= resultDivFactor; | ||
| // saturate to 16 bit integer limits | ||
| suml = (suml < -32768) ? -32768 : (suml > 32767) ? 32767 : suml; | ||
| // saturate to 16 bit integer limits | ||
| sumr = (sumr < -32768) ? -32768 : (sumr > 32767) ? 32767 : sumr; | ||
| #else | ||
| suml *= dScaler; | ||
| sumr *= dScaler; | ||
| #endif // SOUNDTOUCH_INTEGER_SAMPLES | ||
| dest[j] = (SAMPLETYPE)suml; | ||
| dest[j + 1] = (SAMPLETYPE)sumr; | ||
| } | ||
| return numSamples - length; | ||
| } | ||
|
|
||
|
|
||
|
|
||
|
|
||
| // Usual C-version of the filter routine for mono sound | ||
| uint FIRFilter::evaluateFilterMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const | ||
| { | ||
| uint i, j, end; | ||
| LONG_SAMPLETYPE sum; | ||
| #ifdef SOUNDTOUCH_FLOAT_SAMPLES | ||
| // when using floating point samples, use a scaler instead of a divider | ||
| // because division is much slower operation than multiplying. | ||
| double dScaler = 1.0 / (double)resultDivider; | ||
| #endif | ||
|
|
||
|
|
||
| assert(length != 0); | ||
|
|
||
| end = numSamples - length; | ||
| for (j = 0; j < end; j ++) | ||
| { | ||
| sum = 0; | ||
| for (i = 0; i < length; i += 4) | ||
| { | ||
| // loop is unrolled by factor of 4 here for efficiency | ||
| sum += src[i + 0] * filterCoeffs[i + 0] + | ||
| src[i + 1] * filterCoeffs[i + 1] + | ||
| src[i + 2] * filterCoeffs[i + 2] + | ||
| src[i + 3] * filterCoeffs[i + 3]; | ||
| } | ||
| #ifdef SOUNDTOUCH_INTEGER_SAMPLES | ||
| sum >>= resultDivFactor; | ||
| // saturate to 16 bit integer limits | ||
| sum = (sum < -32768) ? -32768 : (sum > 32767) ? 32767 : sum; | ||
| #else | ||
| sum *= dScaler; | ||
| #endif // SOUNDTOUCH_INTEGER_SAMPLES | ||
| dest[j] = (SAMPLETYPE)sum; | ||
| src ++; | ||
| } | ||
| return end; | ||
| } | ||
|
|
||
|
|
||
| // Set filter coeffiecients and length. | ||
| // | ||
| // Throws an exception if filter length isn't divisible by 8 | ||
| void FIRFilter::setCoefficients(const SAMPLETYPE *coeffs, uint newLength, uint uResultDivFactor) | ||
| { | ||
| assert(newLength > 0); | ||
| if (newLength % 8) ST_THROW_RT_ERROR("FIR filter length not divisible by 8"); | ||
|
|
||
| lengthDiv8 = newLength / 8; | ||
| length = lengthDiv8 * 8; | ||
| assert(length == newLength); | ||
|
|
||
| resultDivFactor = uResultDivFactor; | ||
| resultDivider = (SAMPLETYPE)::pow(2.0, (int)resultDivFactor); | ||
|
|
||
| delete[] filterCoeffs; | ||
| filterCoeffs = new SAMPLETYPE[length]; | ||
| memcpy(filterCoeffs, coeffs, length * sizeof(SAMPLETYPE)); | ||
| } | ||
|
|
||
|
|
||
| uint FIRFilter::getLength() const | ||
| { | ||
| return length; | ||
| } | ||
|
|
||
|
|
||
|
|
||
| // Applies the filter to the given sequence of samples. | ||
| // | ||
| // Note : The amount of outputted samples is by value of 'filter_length' | ||
| // smaller than the amount of input samples. | ||
| uint FIRFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) const | ||
| { | ||
| assert(numChannels == 1 || numChannels == 2); | ||
|
|
||
| assert(length > 0); | ||
| assert(lengthDiv8 * 8 == length); | ||
| if (numSamples < length) return 0; | ||
| if (numChannels == 2) | ||
| { | ||
| return evaluateFilterStereo(dest, src, numSamples); | ||
| } else { | ||
| return evaluateFilterMono(dest, src, numSamples); | ||
| } | ||
| } | ||
|
|
||
|
|
||
|
|
||
| // Operator 'new' is overloaded so that it automatically creates a suitable instance | ||
| // depending on if we've a MMX-capable CPU available or not. | ||
| void * FIRFilter::operator new(size_t s) | ||
| { | ||
| // Notice! don't use "new FIRFilter" directly, use "newInstance" to create a new instance instead! | ||
| ST_THROW_RT_ERROR("Error in FIRFilter::new: Don't use 'new FIRFilter', use 'newInstance' member instead!"); | ||
| return newInstance(); | ||
| } | ||
|
|
||
|
|
||
| FIRFilter * FIRFilter::newInstance() | ||
| { | ||
| uint uExtensions; | ||
|
|
||
| uExtensions = detectCPUextensions(); | ||
|
|
||
| // Check if MMX/SSE instruction set extensions supported by CPU | ||
|
|
||
| #ifdef SOUNDTOUCH_ALLOW_MMX | ||
| // MMX routines available only with integer sample types | ||
| if (uExtensions & SUPPORT_MMX) | ||
| { | ||
| return ::new FIRFilterMMX; | ||
| } | ||
| else | ||
| #endif // SOUNDTOUCH_ALLOW_MMX | ||
|
|
||
| #ifdef SOUNDTOUCH_ALLOW_SSE | ||
| if (uExtensions & SUPPORT_SSE) | ||
| { | ||
| // SSE support | ||
| return ::new FIRFilterSSE; | ||
| } | ||
| else | ||
| #endif // SOUNDTOUCH_ALLOW_SSE | ||
|
|
||
| { | ||
| // ISA optimizations not supported, use plain C version | ||
| return ::new FIRFilter; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,145 @@ | ||
| //////////////////////////////////////////////////////////////////////////////// | ||
| /// | ||
| /// General FIR digital filter routines with MMX optimization. | ||
| /// | ||
| /// Note : MMX optimized functions reside in a separate, platform-specific file, | ||
| /// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' | ||
| /// | ||
| /// Author : Copyright (c) Olli Parviainen | ||
| /// Author e-mail : oparviai 'at' iki.fi | ||
| /// SoundTouch WWW: http://www.surina.net/soundtouch | ||
| /// | ||
| //////////////////////////////////////////////////////////////////////////////// | ||
| // | ||
| // Last changed : $Date: 2011-02-13 21:13:57 +0200 (Sun, 13 Feb 2011) $ | ||
| // File revision : $Revision: 4 $ | ||
| // | ||
| // $Id: FIRFilter.h 104 2011-02-13 19:13:57Z oparviai $ | ||
| // | ||
| //////////////////////////////////////////////////////////////////////////////// | ||
| // | ||
| // 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 FIRFilter_H | ||
| #define FIRFilter_H | ||
|
|
||
| #include <stddef.h> | ||
| #include "STTypes.h" | ||
|
|
||
| namespace soundtouch | ||
| { | ||
|
|
||
| class FIRFilter | ||
| { | ||
| protected: | ||
| // Number of FIR filter taps | ||
| uint length; | ||
| // Number of FIR filter taps divided by 8 | ||
| uint lengthDiv8; | ||
|
|
||
| // Result divider factor in 2^k format | ||
| uint resultDivFactor; | ||
|
|
||
| // Result divider value. | ||
| SAMPLETYPE resultDivider; | ||
|
|
||
| // Memory for filter coefficients | ||
| SAMPLETYPE *filterCoeffs; | ||
|
|
||
| virtual uint evaluateFilterStereo(SAMPLETYPE *dest, | ||
| const SAMPLETYPE *src, | ||
| uint numSamples) const; | ||
| virtual uint evaluateFilterMono(SAMPLETYPE *dest, | ||
| const SAMPLETYPE *src, | ||
| uint numSamples) const; | ||
|
|
||
| public: | ||
| FIRFilter(); | ||
| virtual ~FIRFilter(); | ||
|
|
||
| /// Operator 'new' is overloaded so that it automatically creates a suitable instance | ||
| /// depending on if we've a MMX-capable CPU available or not. | ||
| static void * operator new(size_t s); | ||
|
|
||
| static FIRFilter *newInstance(); | ||
|
|
||
| /// Applies the filter to the given sequence of samples. | ||
| /// Note : The amount of outputted samples is by value of 'filter_length' | ||
| /// smaller than the amount of input samples. | ||
| /// | ||
| /// \return Number of samples copied to 'dest'. | ||
| uint evaluate(SAMPLETYPE *dest, | ||
| const SAMPLETYPE *src, | ||
| uint numSamples, | ||
| uint numChannels) const; | ||
|
|
||
| uint getLength() const; | ||
|
|
||
| virtual void setCoefficients(const SAMPLETYPE *coeffs, | ||
| uint newLength, | ||
| uint uResultDivFactor); | ||
| }; | ||
|
|
||
|
|
||
| // Optional subclasses that implement CPU-specific optimizations: | ||
|
|
||
| #ifdef SOUNDTOUCH_ALLOW_MMX | ||
|
|
||
| /// Class that implements MMX optimized functions exclusive for 16bit integer samples type. | ||
| class FIRFilterMMX : public FIRFilter | ||
| { | ||
| protected: | ||
| short *filterCoeffsUnalign; | ||
| short *filterCoeffsAlign; | ||
|
|
||
| virtual uint evaluateFilterStereo(short *dest, const short *src, uint numSamples) const; | ||
| public: | ||
| FIRFilterMMX(); | ||
| ~FIRFilterMMX(); | ||
|
|
||
| virtual void setCoefficients(const short *coeffs, uint newLength, uint uResultDivFactor); | ||
| }; | ||
|
|
||
| #endif // SOUNDTOUCH_ALLOW_MMX | ||
|
|
||
|
|
||
| #ifdef SOUNDTOUCH_ALLOW_SSE | ||
| /// Class that implements SSE optimized functions exclusive for floating point samples type. | ||
| class FIRFilterSSE : public FIRFilter | ||
| { | ||
| protected: | ||
| float *filterCoeffsUnalign; | ||
| float *filterCoeffsAlign; | ||
|
|
||
| virtual uint evaluateFilterStereo(float *dest, const float *src, uint numSamples) const; | ||
| public: | ||
| FIRFilterSSE(); | ||
| ~FIRFilterSSE(); | ||
|
|
||
| virtual void setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor); | ||
| }; | ||
|
|
||
| #endif // SOUNDTOUCH_ALLOW_SSE | ||
|
|
||
| } | ||
|
|
||
| #endif // FIRFilter_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,276 @@ | ||
| //////////////////////////////////////////////////////////////////////////////// | ||
| /// | ||
| /// 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: 2012-12-28 21:52:47 +0200 (Fri, 28 Dec 2012) $ | ||
| // File revision : $Revision: 4 $ | ||
| // | ||
| // $Id: PeakFinder.cpp 164 2012-12-28 19:52:47Z oparviai $ | ||
| // | ||
| //////////////////////////////////////////////////////////////////////////////// | ||
| // | ||
| // 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 <math.h> | ||
| #include <assert.h> | ||
|
|
||
| #include "PeakFinder.h" | ||
|
|
||
| using namespace soundtouch; | ||
|
|
||
| #define max(x, y) (((x) > (y)) ? (x) : (y)) | ||
|
|
||
|
|
||
| PeakFinder::PeakFinder() | ||
| { | ||
| minPos = maxPos = 0; | ||
| } | ||
|
|
||
|
|
||
| // Finds real 'top' of a peak hump from neighnourhood of the given 'peakpos'. | ||
| int PeakFinder::findTop(const float *data, int peakpos) const | ||
| { | ||
| int i; | ||
| int start, end; | ||
| float refvalue; | ||
|
|
||
| refvalue = data[peakpos]; | ||
|
|
||
| // seek within ±10 points | ||
| start = peakpos - 10; | ||
| if (start < minPos) start = minPos; | ||
| end = peakpos + 10; | ||
| if (end > maxPos) end = maxPos; | ||
|
|
||
| for (i = start; i <= end; i ++) | ||
| { | ||
| if (data[i] > refvalue) | ||
| { | ||
| peakpos = i; | ||
| refvalue = data[i]; | ||
| } | ||
| } | ||
|
|
||
| // failure if max value is at edges of seek range => it's not peak, it's at slope. | ||
| if ((peakpos == start) || (peakpos == end)) return 0; | ||
|
|
||
| return peakpos; | ||
| } | ||
|
|
||
|
|
||
| // 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 | ||
| { | ||
| int lowpos; | ||
| int pos; | ||
| int climb_count; | ||
| float refvalue; | ||
| float delta; | ||
|
|
||
| climb_count = 0; | ||
| refvalue = data[peakpos]; | ||
| lowpos = peakpos; | ||
|
|
||
| pos = peakpos; | ||
|
|
||
| while ((pos > minPos+1) && (pos < maxPos-1)) | ||
| { | ||
| 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' | ||
| double 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]; | ||
| } | ||
|
|
||
| if (wsum < 1e-6) return 0; | ||
| return sum / wsum; | ||
| } | ||
|
|
||
|
|
||
|
|
||
| /// get exact center of peak near given position by calculating local mass of center | ||
| double PeakFinder::getPeakCenter(const float *data, int peakpos) const | ||
| { | ||
| 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' | ||
|
|
||
| // find ground positions. | ||
| gp1 = findGround(data, peakpos, -1); | ||
| gp2 = findGround(data, peakpos, 1); | ||
|
|
||
| groundLevel = 0.5f * (data[gp1] + data[gp2]); | ||
| peakLevel = data[peakpos]; | ||
|
|
||
| // 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); | ||
| } | ||
|
|
||
|
|
||
|
|
||
| double PeakFinder::detectPeak(const float *data, int aminPos, int amaxPos) | ||
| { | ||
|
|
||
| int i; | ||
| int peakpos; // position of peak level | ||
| double highPeak, peak; | ||
|
|
||
| this->minPos = aminPos; | ||
| this->maxPos = amaxPos; | ||
|
|
||
| // find absolute peak | ||
| peakpos = minPos; | ||
| peak = data[minPos]; | ||
| for (i = minPos + 1; i < maxPos; i ++) | ||
| { | ||
| if (data[i] > peak) | ||
| { | ||
| peak = data[i]; | ||
| peakpos = i; | ||
| } | ||
| } | ||
|
|
||
| // Calculate exact location of the highest peak mass center | ||
| highPeak = getPeakCenter(data, peakpos); | ||
| peak = highPeak; | ||
|
|
||
| // Now check if the highest peak were in fact harmonic of the true base beat peak | ||
| // - sometimes the highest peak can be Nth harmonic of the true base peak yet | ||
| // just a slightly higher than the true base | ||
|
|
||
| for (i = 3; i < 10; i ++) | ||
| { | ||
| double peaktmp, harmonic; | ||
| int i1,i2; | ||
|
|
||
| harmonic = (double)i * 0.5; | ||
| peakpos = (int)(highPeak / harmonic + 0.5f); | ||
| if (peakpos < minPos) break; | ||
| peakpos = findTop(data, peakpos); // seek true local maximum index | ||
| if (peakpos == 0) continue; // no local max here | ||
|
|
||
| // calculate mass-center of possible harmonic peak | ||
| peaktmp = getPeakCenter(data, peakpos); | ||
|
|
||
| // accept harmonic peak if | ||
| // (a) it is found | ||
| // (b) is within ±4% of the expected harmonic interval | ||
| // (c) has at least half x-corr value of the max. peak | ||
|
|
||
| double diff = harmonic * peaktmp / highPeak; | ||
| if ((diff < 0.96) || (diff > 1.04)) continue; // peak too afar from expected | ||
|
|
||
| // now compare to highest detected peak | ||
| i1 = (int)(highPeak + 0.5); | ||
| i2 = (int)(peaktmp + 0.5); | ||
| if (data[i2] >= 0.4*data[i1]) | ||
| { | ||
| // The harmonic is at least half as high primary peak, | ||
| // thus use the harmonic peak instead | ||
| peak = peaktmp; | ||
| } | ||
| } | ||
|
|
||
| return peak; | ||
| } |