├── Automation
└── CI
│ ├── JenkinsBuildCILinux.sh
│ ├── JenkinsBuildCIOSX.sh
│ └── JenkinsBuildCIWindows.bat
├── Documentation
├── HowThePhaseVocoderWorks.md
├── Images
│ ├── BassDrumEntireWaveform.png
│ ├── BassDrumExpansionExample.png
│ ├── BassDrumSpectrogram.png
│ ├── BassDrumWaveform.png
│ ├── C1PianoNoteWaveform.png
│ ├── C2PianoNoteWaveform.png
│ ├── C3PianoNoteWaveform.png
│ ├── TransientAudioExample.png
│ ├── TransientAudioExampleMax256Annotated.png
│ ├── TransientAudioExampleMax32Annotated.png
│ ├── TransientAudioExampleMax512.png
│ ├── TransientAudioExampleMax512Annotated.png
│ ├── TransientAudioExampleTransientFound.png
│ └── TransientQualification.png
└── TransientDetection.md
├── Doxygen
└── Doxyfile
├── README.md
└── Source
├── AudioData
├── AudioData.h
├── CMakeLists.txt
├── Source
│ └── AudioData.cpp
└── UT
│ ├── AudioData-UT.cpp
│ └── CMakeLists.txt
├── CMakeLists.txt
├── CMakeSupport
├── CMakeLists.CompilerSettings.txt
├── CMakeLists.Externals.txt
└── CMakeLists.GoogleTest.txt
├── Signal
├── CMakeLists.txt
├── Fourier.h
├── FrequencyDomain.h
├── LowPassFilter.h
├── PeakFrequencyDetection.h
├── PeakProfile.h
├── PhaseVocoder.h
├── Resampler.h
├── SignalConversion.h
├── Source
│ ├── Fourier.cpp
│ ├── FrequencyDomain.cpp
│ ├── LowPassFilter.cpp
│ ├── PeakFrequencyDetection.cpp
│ ├── PeakProfile.cpp
│ ├── PhaseVocoder.cpp
│ ├── Resampler.cpp
│ ├── SignalConversion.cpp
│ ├── TransientDetector.cpp
│ ├── TransientPeakAndValley.cpp
│ ├── WindowedSincValues.cpp
│ ├── WindowedSincValues.h
│ └── Windowing.cpp
├── TransientDetector.h
├── TransientPeakAndValley.h
├── UT
│ ├── CMakeLists.txt
│ ├── Fourier-UT.cpp
│ ├── LowPassFilter-UT.cpp
│ ├── PeakFrequencyDetection-UT.cpp
│ ├── PeakProfile-UT.cpp
│ ├── PhaseVocoder-UT.cpp
│ ├── Resampler-UT.cpp
│ ├── SignalConversion-UT.cpp
│ ├── TestAudio
│ │ ├── 100HzSineWaveAt32768Hz.wav
│ │ ├── 222HzSineAnd19000HzSine.wav
│ │ ├── 400HzSineAnd2121HzSine.wav
│ │ ├── 5000HzSineAnd9797HzSine.wav
│ │ ├── 808BassDrum.wav
│ │ ├── 808RimShot616SamplesLong.wav
│ │ ├── 808Snare1024SamplesLong.wav
│ │ ├── 808Snare2615SamplesLong.wav
│ │ ├── 808Snare4096SamplesLong.wav
│ │ ├── 808Snare4097SamplesLong.wav
│ │ ├── 808Snare4100SamplesLong.wav
│ │ ├── AcousticGuitarDualStringPluck.wav
│ │ ├── AcousticGuitarStringPluck.wav
│ │ ├── BuiltToSpillBeat32123HzSampleRate.wav
│ │ ├── BuiltToSpillBeatBeginningWithSilence.wav
│ │ ├── PeakAt6000And10000.wav
│ │ ├── SinglePianoKey.wav
│ │ ├── SweetEmotion.wav
│ │ └── TenSamples.wav
│ ├── TestAudioResults
│ │ ├── 100HzSineWaveAt32768HzCompressed.wav
│ │ ├── 100HzSineWaveAt32768HzResampled.wav
│ │ ├── 100HzSineWaveAt32768HzStretched.wav
│ │ ├── 222HzSineAnd19000HzSineLowPassFilteredAt8000Hz.wav
│ │ ├── 222HzSineAnd19000HzSineResampled.wav
│ │ ├── 400HzSineAnd2121HzSineLowPassFilteredAt1000Hz.wav
│ │ ├── 400HzSineAnd2121HzSineResampled.wav
│ │ ├── 5000HzSineAnd9797HzSineLowPassFilteredAt6000Hz.wav
│ │ ├── 5000HzSineAnd9797HzSineResampled.wav
│ │ ├── 808BassDrumCompressed.wav
│ │ ├── 808BassDrumStretched.wav
│ │ ├── 808RimShot616SamplesLongCompressed.wav
│ │ ├── 808RimShot616SamplesLongStretched.wav
│ │ ├── 808Snare1024SamplesLongCompressed.wav
│ │ ├── 808Snare1024SamplesLongOutputStretched.wav
│ │ ├── 808Snare2615SamplesLongCompressed.wav
│ │ ├── 808Snare2615SamplesLongStretched.wav
│ │ ├── 808Snare4096SamplesLongCompressed.wav
│ │ ├── 808Snare4096SamplesLongStretched.wav
│ │ ├── 808Snare4097SamplesLongCompressed.wav
│ │ ├── 808Snare4097SamplesLongStretched.wav
│ │ ├── 808Snare4100SamplesLongCompressed.wav
│ │ ├── 808Snare4100SamplesLongStretched.wav
│ │ ├── AcousticGuitarStringPluckCompressed.wav
│ │ ├── AcousticGuitarStringPluckStretched.wav
│ │ ├── SinglePianoKeyCompressed.wav
│ │ ├── SinglePianoKeyResampled.wav
│ │ ├── SinglePianoKeyStretched.wav
│ │ ├── TenSamplesOutputCompressed.wav
│ │ └── TenSamplesOutputStretched.wav
│ ├── TransientDetector-UT.cpp
│ ├── TransientPeakAndValley-UT.cpp
│ ├── Windowing-UT.cpp
│ └── main.cpp
└── Windowing.h
├── ThreadSafeAudioFile
├── CMakeLists.txt
├── Reader.h
├── Source
│ ├── Reader.cpp
│ └── Writer.cpp
├── UT
│ ├── AudioFileDataHelper.cpp
│ ├── AudioFileDataHelper.h
│ ├── CMakeLists.txt
│ ├── Reader-UT.cpp
│ └── Writer-UT.cpp
└── Writer.h
├── Utilities
├── CMakeLists.txt
├── Exception.h
├── File.h
├── Source
│ ├── Exception.cpp
│ ├── File.cpp
│ ├── Stringify.cpp
│ └── Timer.cpp
├── Stringify.h
├── Timer.h
└── UT
│ ├── CMakeLists.txt
│ ├── Exception-UT.cpp
│ ├── File-UT.cpp
│ ├── Stringify-UT.cpp
│ ├── TestFiles
│ ├── TestFileA.txt
│ └── TestFileB.txt
│ └── Timer-UT.cpp
└── WaveFile
├── CMakeLists.txt
├── Source
├── WaveFileReader.cpp
└── WaveFileWriter.cpp
├── UT
├── CMakeLists.txt
├── TestWaveFile.wav
├── TestWaveFileMono.wav
├── TestWaveFileStereo.wav
├── WaveFileReader-UT.cpp
└── WaveFileWriter-UT.cpp
├── WaveFileDefines.h
├── WaveFileHeader.h
├── WaveFileReader.h
└── WaveFileWriter.h
/Automation/CI/JenkinsBuildCILinux.sh:
--------------------------------------------------------------------------------
1 | # Do a debug build
2 | mkdir DebugBuild
3 | cd DebugBuild
4 | cmake -DCMAKE_BUILD_TYPE=Debug -G "Unix Makefiles" ../Source
5 | cmake --build .
6 |
7 | cd ..
8 |
9 | # Do a release build
10 | mkdir ReleaseBuild
11 | cd ReleaseBuild
12 | cmake -DCMAKE_BUILD_TYPE=Release -G "Unix Makefiles" ../Source
13 | cmake --build .
14 |
--------------------------------------------------------------------------------
/Automation/CI/JenkinsBuildCIOSX.sh:
--------------------------------------------------------------------------------
1 | # Do a debug build
2 | mkdir DebugBuild
3 | cd DebugBuild
4 | /usr/local/bin/cmake -G "Xcode" -DCMAKE_BUILD_TYPE=Debug ../Source
5 | xcodebuild -project AudioLib.xcodeproj -configuration Debug
6 |
7 | cd ..
8 |
9 | # Do a releaase build
10 | mkdir ReleaseBuild
11 | cd ReleaseBuild
12 | /usr/local/bin/cmake -G "Xcode" -DCMAKE_BUILD_TYPE=Release ../Source
13 | xcodebuild -project AudioLib.xcodeproj -configuration Release
14 |
--------------------------------------------------------------------------------
/Automation/CI/JenkinsBuildCIWindows.bat:
--------------------------------------------------------------------------------
1 | call "%VisualStudioPath%\vcvarsall.bat" amd64
2 | cd %WORKSPACE%
3 | mkdir AudioLibBuilt
4 | cd AudioLibBuilt
5 | cmake -G "%CMakeGeneratorString%" ../Source
6 | devenv AudioLib.sln /Build Debug
7 | devenv AudioLib.sln /Build Release
8 |
--------------------------------------------------------------------------------
/Documentation/HowThePhaseVocoderWorks.md:
--------------------------------------------------------------------------------
1 | How the PhaseVocoder Works
2 | ==========================
3 |
4 | The PhaseVocoder allows for time expansion/compression and pitch shifting of audio. The general process involves analyzing input audio and placing it into two different categories: transient components and sinusoidal components. An audio transient is usually a higher amplitude, short-duration percusive sound occurring at the onset of audio such as a drum hit or musical note (more info on transient detection [here](TransientDetection.md)). Frequently, audio with more sinusoidal components follows the transient. The PhaseVocoder works by preserving the transient and stretching or compressing the phase of the sinusoidal components of the input audio.
5 |
6 |
7 |
8 |
9 | **Time Expansion Example**
10 |
11 | The waveform and spectrogram below is that of the first 70 milliseconds of a bass drum. A wave file of this audio can be found [here](https://github.com/tmdarwen/PhaseVocoder/blob/master/Source/Signal/UT/TestAudio/808BassDrum.wav). In the waveform, note how the first few milliseconds of audio has an irregular shape and then the waveform follows a sinusoidal shape.
12 |
13 |
14 |
15 | Similarly, in the spectrogram below, note how the first few milliseconds of audio has strong amounts of energy across nearly the entire spectrum of 0 to 8,000 Hz before concentrating at specific lower frequencies.
16 |
17 |
18 |
19 | The entire waveform of the bass drum can be seen below. After the initial transient, the audio continues uninterrupted for the entire 1.66 seconds. In other words, no other transients occur aside from the initial transient.
20 |
21 |
22 |
23 | In order to apply time expansion or compression to the input audio, without degrading audio quality, the PhaseVocoder first preserves the transient section. The PhaseVocoder then takes small windows of the audio following the transient, adjusts the phase of the window in the frequency domain, before taking the inverse Fourier transform and writing the window to the output audio. The following is an oversimplification but should give you a general idea of how the process works:
24 |
25 |
26 |
27 |
28 |
29 | **Pitch Shifting**
30 |
31 | Shifting the pitch of audio without changing its length is done using a resampler in conjunction with the phase vocoding technique described above.
32 |
33 | The key to understanding pitch shifting is to understand that playing audio back at different sample rates adjusts the pitch of the audio. For example, if you have audio of a C2 piano note (65.41 Hz) recorded at 44.1 KHz, playing back the audio at twice the sample rate (88.2 KHz) will result in a C3 piano note (130.81 Hz), effectively adjusting the pitch up by an octave.
34 |
35 | Similarly, playing back the audio at half the sample rate (22.05 KHz) will result in a C1 piano note (32.70 Hz). These examples are shown below. Take note of the values above the waveform on the x-axis. These are in units of seconds.
36 |
37 | A C2 piano note recorded at 44.1 KHz two seconds in durations:
38 |
39 |
40 |
41 | The C2 piano note recorded at 44.1 KHz but played back at 88.2 KHz results in a pitch shift up by one octave to C3. Note the duration of the audio is cut in half to one second:
42 |
43 |
44 |
45 | The C2 piano note recorded at 44.1 KHz but played back at 22.05 KHz results in a pitch shift down one octave to C1. Note the duration of the audio is doubled to four seconds:
46 |
47 |
48 |
49 | As shown above, pitch shifting can be accomplished by adjusting sample rates. However, this results in the length of the input audio being extended or reduced. This is where the PhaseVocoder's phase vocoding abilities come in. Often in audio editing and production you'll want the note to remain a constant time length as the pitch is adjusted. The same phase vocoding technique explained earlier in this document is applied to the resampled audio to accomplish this.
50 |
--------------------------------------------------------------------------------
/Documentation/Images/BassDrumEntireWaveform.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tmdarwen/AudioLib/a13efa0ce077e0d1f76e32126588a07aa815a1c8/Documentation/Images/BassDrumEntireWaveform.png
--------------------------------------------------------------------------------
/Documentation/Images/BassDrumExpansionExample.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tmdarwen/AudioLib/a13efa0ce077e0d1f76e32126588a07aa815a1c8/Documentation/Images/BassDrumExpansionExample.png
--------------------------------------------------------------------------------
/Documentation/Images/BassDrumSpectrogram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tmdarwen/AudioLib/a13efa0ce077e0d1f76e32126588a07aa815a1c8/Documentation/Images/BassDrumSpectrogram.png
--------------------------------------------------------------------------------
/Documentation/Images/BassDrumWaveform.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tmdarwen/AudioLib/a13efa0ce077e0d1f76e32126588a07aa815a1c8/Documentation/Images/BassDrumWaveform.png
--------------------------------------------------------------------------------
/Documentation/Images/C1PianoNoteWaveform.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tmdarwen/AudioLib/a13efa0ce077e0d1f76e32126588a07aa815a1c8/Documentation/Images/C1PianoNoteWaveform.png
--------------------------------------------------------------------------------
/Documentation/Images/C2PianoNoteWaveform.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tmdarwen/AudioLib/a13efa0ce077e0d1f76e32126588a07aa815a1c8/Documentation/Images/C2PianoNoteWaveform.png
--------------------------------------------------------------------------------
/Documentation/Images/C3PianoNoteWaveform.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tmdarwen/AudioLib/a13efa0ce077e0d1f76e32126588a07aa815a1c8/Documentation/Images/C3PianoNoteWaveform.png
--------------------------------------------------------------------------------
/Documentation/Images/TransientAudioExample.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tmdarwen/AudioLib/a13efa0ce077e0d1f76e32126588a07aa815a1c8/Documentation/Images/TransientAudioExample.png
--------------------------------------------------------------------------------
/Documentation/Images/TransientAudioExampleMax256Annotated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tmdarwen/AudioLib/a13efa0ce077e0d1f76e32126588a07aa815a1c8/Documentation/Images/TransientAudioExampleMax256Annotated.png
--------------------------------------------------------------------------------
/Documentation/Images/TransientAudioExampleMax32Annotated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tmdarwen/AudioLib/a13efa0ce077e0d1f76e32126588a07aa815a1c8/Documentation/Images/TransientAudioExampleMax32Annotated.png
--------------------------------------------------------------------------------
/Documentation/Images/TransientAudioExampleMax512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tmdarwen/AudioLib/a13efa0ce077e0d1f76e32126588a07aa815a1c8/Documentation/Images/TransientAudioExampleMax512.png
--------------------------------------------------------------------------------
/Documentation/Images/TransientAudioExampleMax512Annotated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tmdarwen/AudioLib/a13efa0ce077e0d1f76e32126588a07aa815a1c8/Documentation/Images/TransientAudioExampleMax512Annotated.png
--------------------------------------------------------------------------------
/Documentation/Images/TransientAudioExampleTransientFound.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tmdarwen/AudioLib/a13efa0ce077e0d1f76e32126588a07aa815a1c8/Documentation/Images/TransientAudioExampleTransientFound.png
--------------------------------------------------------------------------------
/Documentation/Images/TransientQualification.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tmdarwen/AudioLib/a13efa0ce077e0d1f76e32126588a07aa815a1c8/Documentation/Images/TransientQualification.png
--------------------------------------------------------------------------------
/Documentation/TransientDetection.md:
--------------------------------------------------------------------------------
1 | Transient Detection
2 | ===================
3 |
4 | A transient is usually a higher amplitude, short-duration percusive sound occurring at the onset of audio such as a drum hit or musical note. For the sake of sound quality, it's key to preserve transients when performing the phase vocoding process.
5 |
6 | What qualifies audio as being a transient is debatable, and therefore can be difficult to auto-detect. What I explain below is a transient detection algorithm I've developed. One important item to note about this algorithm is that it's imperative to make the transient detection point occur _immediately before_ the transient begins. If the PhaseVocoder does not preserve the entire transient the audio quality will suffer.
7 |
8 |
9 |
10 |
11 | **Transient Detection By Example**
12 |
13 | In the audio snippet pictured, it's clear we have three transients: One at the very beginning of the audio, one between 0.20 and 0.30 and another one between 0.40 and 0.50.
14 |
15 |
16 |
17 | When first analyzing audio input, detecting the first transient is a special case. We simply consider the first audio that occurs above a nominal audio output threshold to be the transient. Because of this, it's more useful here to explain how the second transient (between 0.20 and 0.30) is detected.
18 |
19 | The first step we perform in transient detection is to reduce the input signal down to roughly twelve millisecond sections, plotting a point that is the max sample value in this twelve millisecond section as shown below.
20 |
21 |
22 |
23 | We then take note of the "peak" and "valley" points in this graph as shown below.
24 |
25 |
26 |
27 | We then perform the exact same process between the valley and peak sample positions but at a resolution of about six milliseconds, resulting in the following:
28 |
29 |
30 |
31 | And then one additional time at a resolution of about one millisecond:
32 |
33 |
34 |
35 | We use this final valley point to calculate the beginning of the transient. For this example, this results in finding the transient position _immediately before_ the transient occurs as shown below.
36 |
37 |
38 |
39 | Another way of considering this process is that we're recursively "zooming in" on the point where the audio transitions from low intensity to high intensity to pinpoint the start of the audio transient.
40 |
41 |
42 |
43 |
44 | **Transient Qualification**
45 |
46 | Of course, not every peak/valley combination is a transient. In order for a peak/valley combination to be considered a transient the peak value must be at least 1.5 times greater than the valley. Note the image below. The circled peak and valley combination is not considered a transient since the growth from the valley point to the peak point is less than a ratio of 1.5.
47 |
48 |
49 |
50 | When using the PhaseVocoder, this ratio can be configured by the user through the `--valleypeakratio`. This option allows the user to set a specific ratio. The default ratio is 1.5. Setting a lower ratio will result in the software more liberally detecting audio transients, setting a higher ratio will cause the software to be more strict when considering if a peak/value combination is a transient.
51 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | AudioLib
2 | ========
3 |
4 | This is a library I've made to support some of my audio related projects. It's currently used in my [PhaseVocoder](https://github.com/tmdarwen/PhaseVocoder) project and my [AudioAnalysisTool](https://github.com/tmdarwen/AudioAnalysisTool) project. Feel free to use this library in your own projects. It's licensed under the permissable [MIT license](https://en.wikipedia.org/wiki/MIT_License).
5 |
6 |
7 |
8 | **Main Components**
9 |
10 | - AudioData - A class allowing for easy transportation and access of digital audio data.
11 |
12 | - Signal - Various digital signal processing utilities, such as the [PhaseVocder](Documentation/HowThePhaseVocoderWorks.md) and [TransientDetector](Documentation/TransientDetection.md).
13 |
14 | - ThreadSafeAudioFile - Provides threadsafe reading and writing of wave audio files.
15 |
16 | - Utilities - Basic utilities supporting application development.
17 |
18 | - WaveFile - Simple classes for reading and writing wave audio files.
19 |
20 |
21 |
22 | **Doxygen Documentation**
23 |
24 | Doxygen documentation can easily be generated by simply running Doxygen using the config file located in the [Doxygen](Doxygen) directory.
25 |
26 |
27 |
28 | **Unit Test Coverage**
29 |
30 | Unit test coverage is extensive. You'll notice every component within the source directory has a UT directory which contains unit tests. These automatically build and run as part of the build process.
31 |
32 |
33 |
34 | **Build Dependencies**
35 |
36 | - Building this project requires [CMake](https://cmake.org) version 3.0 or later.
37 |
38 | - Building this project requires a C++14 compliant compiler. This project is routinely built in my continous integration system which uses MS Visual Studio 2017, GCC 5.3.1 and Apple LLVM version 7.3.0 (clang 703.0.31).
39 |
40 | - [GoogleTest](https://github.com/google/googletest) is currently the only external dependency. You do *not* need to clone or install this manually. The GoogleTest GitHub repo will be cloned automatically when CMake runs.
41 |
42 |
43 |
44 | **Steps for Building**
45 |
46 | 1. Clone this repo.
47 |
48 | 2. Create a new directory at the parallel level as the cloned repo. This directory will hold the project files CMake creates.
49 |
50 | 3. cd into this new directory.
51 |
52 | 4. From the command line, run _cmake -G YourDesiredGeneratorType ../AudioLib/Source_
53 |
54 | 5. Run make or open the project file in an IDE and build.
55 |
56 |
57 |
58 |
59 | **Continuous Integration**
60 |
61 | The [Automation/CI directory](/Automation/CI) contains scripts that can be used with [Jenkins](https://jenkins.io/) to setup continuous integration in Linux, MacOS and Windows. For more information on how to setup Jenkins to use these scripts please see [this document](https://github.com/tmdarwen/PhaseVocoder/tree/master/Documentation/JenkinsSetup.md).
62 |
63 |
64 |
65 |
66 | **Licensing**
67 |
68 | The MIT License applies to this software and its supporting documentation:
69 |
70 | *Copyright (c) 2017-2018 - Terence M. Darwen - tmdarwen.com*
71 |
72 | *Permission is hereby granted, free of charge, to any person obtaining a copy of
73 | this software and associated documentation files (the "Software"), to deal in
74 | the Software without restriction, including without limitation the rights to
75 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
76 | the Software, and to permit persons to whom the Software is furnished to do so,
77 | subject to the following conditions:*
78 |
79 | *The above copyright notice and this permission notice shall be included in all
80 | copies or substantial portions of the Software.*
81 |
82 | *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
83 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
84 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
85 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
86 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
87 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.*
88 |
--------------------------------------------------------------------------------
/Source/AudioData/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | include_directories("${PROJECT_SOURCE_DIR}")
2 | file(GLOB source_files [^.]*.h [^.]*.cpp "Source/[^.]*.h" "Source/[^.]*.cpp")
3 | add_library(AudioData ${source_files})
4 |
5 | include(${PROJECT_SOURCE_DIR}/CMakeSupport/CMakeLists.CompilerSettings.txt)
6 |
7 | add_subdirectory(UT)
8 |
9 | set_target_properties(AudioData PROPERTIES FOLDER Libs)
10 |
11 |
--------------------------------------------------------------------------------
/Source/AudioData/UT/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | #set(project_name AudioData-UT)
2 | include_directories("${PROJECT_SOURCE_DIR}/External/googletest/googletest/include")
3 | file(GLOB source_files [^.]*.h [^.]*.cpp "../Source/[^.]*.h" "../Source/[^.]*.cpp")
4 | add_executable(AudioData-UT ${source_files})
5 | include(${PROJECT_SOURCE_DIR}/CMakeSupport/CMakeLists.CompilerSettings.txt)
6 | target_link_libraries(AudioData-UT Utilities gtest)
7 | add_custom_command(TARGET AudioData-UT POST_BUILD COMMAND AudioData-UT --output-on-failure)
8 |
9 | set_target_properties(AudioData-UT PROPERTIES FOLDER Libs)
10 |
11 |
--------------------------------------------------------------------------------
/Source/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.0)
2 |
3 | set_property(GLOBAL PROPERTY USE_FOLDERS ON)
4 |
5 | project(AudioLib)
6 |
7 | if(DEBUG_BUILD)
8 | add_definitions(-DDEBUG_BUILD)
9 | endif(DEBUG_BUILD)
10 |
11 | if(DEBUG_TO_LOG_FILE)
12 | add_definitions(-DDEBUG_BUILD)
13 | add_definitions(-DDEBUG_TO_LOG_FILE)
14 | endif(DEBUG_TO_LOG_FILE)
15 |
16 | option(INCLUDE_GOOGLE_TEST "Pulldown GoogleTest and include it in the project" ON)
17 |
18 | option(MSVC_MULTI_THREADED_DLL_RUNTIME_LIB "Allows for setting the runtime lib for MSVC compiler to multi-threaded DLL" OFF)
19 |
20 | # "Externals" consists of GoogleTest
21 | if(INCLUDE_GOOGLE_TEST)
22 | include(${CMAKE_CURRENT_SOURCE_DIR}/CMakeSupport/CMakeLists.Externals.txt)
23 | include_externals()
24 | endif()
25 |
26 | add_subdirectory(AudioData)
27 | add_subdirectory(Signal)
28 | add_subdirectory(ThreadSafeAudioFile)
29 | add_subdirectory(Utilities)
30 | add_subdirectory(WaveFile)
31 |
--------------------------------------------------------------------------------
/Source/CMakeSupport/CMakeLists.CompilerSettings.txt:
--------------------------------------------------------------------------------
1 | # Specific compiler settings we want to set in various projects
2 |
3 | option(MSVCMT "Pulldown GoogleTest and include it in the project" ON)
4 |
5 | if(MSVC)
6 | set(CMAKE_CXX_FLAGS "/Zi /EHsc")
7 | if(MSVC_MULTI_THREADED_DLL_RUNTIME_LIB)
8 | set(CMAKE_CXX_FLAGS_DEBUG "/Od /MDd")
9 | set(CMAKE_CXX_FLAGS_RELEASE "/Ox /MD")
10 | else()
11 | set(CMAKE_CXX_FLAGS_DEBUG "/Od /MTd")
12 | set(CMAKE_CXX_FLAGS_RELEASE "/Ox /MT")
13 | endif(MSVC_MULTI_THREADED_DLL_RUNTIME_LIB)
14 | set(CMAKE_EXE_LINKER_FLAGS_RELEASE "/DEBUG /INCREMENTAL:NO /OPT:REF /OPT:ICF") #Generate PDBs for release build
15 | elseif(APPLE)
16 | add_definitions(-DTARGET_MAC)
17 | set(CMAKE_CXX_FLAGS "-std=c++14")
18 | elseif(UNIX)
19 | add_definitions(-DTARGET_LINUX)
20 | set(CMAKE_CXX_FLAGS "-std=c++14 -g")
21 | endif(MSVC)
22 |
23 |
--------------------------------------------------------------------------------
/Source/CMakeSupport/CMakeLists.Externals.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.0)
2 |
3 | function(include_external cmake_file project_name)
4 | configure_file(${cmake_file} ${project_name}-download/CMakeLists.txt)
5 | execute_process(COMMAND "${CMAKE_COMMAND}" -G "${CMAKE_GENERATOR}" . WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/${project_name}-download")
6 | execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/${project_name}-download" )
7 | add_subdirectory("${CMAKE_BINARY_DIR}/${project_name}-src" "${CMAKE_BINARY_DIR}/${project_name}-build")
8 | endfunction()
9 |
10 | function(include_externals)
11 | # Pulldown GoogleTest
12 | if(MSVC)
13 | # The following is needed for compiling with MSVC C++ compiler v15.5 b/c of deprecation of std::tr1 namespace
14 | add_definitions(-D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING)
15 | if(MSVC_MULTI_THREADED_DLL_RUNTIME_LIB)
16 | set(CMAKE_CXX_FLAGS_RELEASE "/MD")
17 | set(CMAKE_CXX_FLAGS_DEBUG "/MDd")
18 | else()
19 | set(CMAKE_CXX_FLAGS_DEBUG "/Od /MTd")
20 | set(CMAKE_CXX_FLAGS_RELEASE "/Ox /MT")
21 | endif(MSVC_MULTI_THREADED_DLL_RUNTIME_LIB)
22 | set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) # Prevent GoogleTest from overriding options when building with MSVC
23 | endif(MSVC)
24 | include_external(CMakeSupport/CMakeLists.GoogleTest.txt googletest)
25 | endfunction()
26 |
--------------------------------------------------------------------------------
/Source/CMakeSupport/CMakeLists.GoogleTest.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.0)
2 |
3 | project(googletest-download NONE)
4 |
5 | include(ExternalProject)
6 | ExternalProject_Add(googletest
7 | GIT_REPOSITORY https://github.com/google/googletest.git
8 | GIT_TAG release-1.8.0
9 | SOURCE_DIR "${CMAKE_BINARY_DIR}/googletest-src"
10 | BINARY_DIR "${CMAKE_BINARY_DIR}/googletest-build"
11 | CONFIGURE_COMMAND ""
12 | BUILD_COMMAND ""
13 | INSTALL_COMMAND ""
14 | TEST_COMMAND ""
15 | )
16 |
--------------------------------------------------------------------------------
/Source/Signal/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | include_directories("${PROJECT_SOURCE_DIR}")
2 | file(GLOB source_files [^.]*.h [^.]*.cpp "Source/[^.]*.h" "Source/[^.]*.cpp")
3 | add_library(Signal ${source_files})
4 |
5 | include(${PROJECT_SOURCE_DIR}/CMakeSupport/CMakeLists.CompilerSettings.txt)
6 |
7 | add_subdirectory(UT)
8 |
9 | set_target_properties(Signal PROPERTIES FOLDER Libs)
10 |
11 |
--------------------------------------------------------------------------------
/Source/Signal/Fourier.h:
--------------------------------------------------------------------------------
1 | /*
2 | * AudioLib
3 | *
4 | * Copyright (c) 2017 - Terence M. Darwen - tmdarwen.com
5 | *
6 | * The MIT License
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in
16 | * all copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | * THE SOFTWARE.
25 | */
26 |
27 | //! @file Fourier.h
28 | //! @brief Functions allowing for Fourier transformations.
29 |
30 | #pragma once
31 |
32 | #include
33 | #include
34 | #include
35 |
36 | namespace Signal {
37 |
38 |
39 | namespace Fourier
40 | {
41 | //! Returns true if the given number is a power of two; false otherwise.
42 | bool IsPowerOfTwo(std::size_t number);
43 |
44 | //! Applies the Discrete Fourier Transform to the given audio data.
45 | Signal::FrequencyDomain ApplyDFT(const AudioData& timeDomainSignal);
46 |
47 | //! Applies the Inverse Discrete Fourier Transform to the given frequency data.
48 | AudioData ApplyInverseDFT(const Signal::FrequencyDomain& frequencyDomainData);
49 |
50 | //! Applies the Fast Fourier Transform to the given audio data.
51 | //
52 | //! Note that the length of the given audio must be a power of two.
53 | Signal::FrequencyDomain ApplyFFT(const AudioData& timeDomainSignal);
54 |
55 | //! Applies the Inverse Fast Fourier Transform to the given audio data.
56 | //
57 | //! Note that the length of the given frequency domain data must be a power of two.
58 | AudioData ApplyInverseFFT(const Signal::FrequencyDomain& frequencyDomainData);
59 | }
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/Source/Signal/FrequencyDomain.h:
--------------------------------------------------------------------------------
1 | /*
2 | * AudioLib
3 | *
4 | * Copyright (c) 2017 - Terence M. Darwen - tmdarwen.com
5 | *
6 | * The MIT License
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in
16 | * all copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | * THE SOFTWARE.
25 | */
26 |
27 | //! @file FrequencyDomain.h
28 | //! @brief Class to hold frequency domain information for a signal.
29 |
30 | #pragma once
31 |
32 | #include
33 | #include
34 |
35 | namespace Signal {
36 |
37 | //! Simple structure to hold a single frequency bin's frequency domain data.
38 |
39 | struct FrequencyBin
40 | {
41 | //! Instantiates frequency bin data with zeroes for real and imaginary values.
42 | FrequencyBin() : reX_(0.0), imX_(0.0) { }
43 |
44 | //! Instantiates frequency bin data with the given values.
45 | FrequencyBin(double reX, double imX) : reX_(reX), imX_(imX) { }
46 |
47 | //! The real component of the frequency.
48 | double reX_;
49 |
50 | //! The imaginary component of the frequency.
51 | double imX_;
52 | };
53 |
54 |
55 | //! Class to hold frequency domain information for a signal.
56 |
57 | class FrequencyDomain
58 | {
59 | public:
60 |
61 | //! Constructs object with no frequency data.
62 | FrequencyDomain();
63 |
64 | //! Constructs object with the given frequency domain data.
65 | FrequencyDomain(std::vector FrequencyBin);
66 |
67 | //! Add the given frequency bin data.
68 | void PushFrequencyBin(Signal::FrequencyBin FrequencyBin);
69 |
70 | //! Get the number of frequency bins in this frequency domain data.
71 | std::size_t GetSize() const;
72 |
73 | //! Get frequency bin data for the given frequency bin.
74 | const FrequencyBin& GetBin(std::size_t binNumber) const;
75 |
76 | //! Get the magnitudes for all frequency bins.
77 | const std::vector& GetMagnitudes();
78 |
79 | //! Get the wrapped phase values for all frequency bins.
80 | const std::vector& GetWrappedPhases();
81 |
82 | //! Get the real components of all frequency bins.
83 | const std::vector& GetRealComponent();
84 |
85 | //! Get the imaginary components of all frequency bins.
86 | const std::vector& GetImaginaryComponent();
87 |
88 | //! Get the data for all frequency bins.
89 | std::vector GetRectangularFrequencyData() const;
90 |
91 | private:
92 | double CalculateArcTangent(double imaginary, double real);
93 | enum Quadrant
94 | {
95 | QUADRANT1,
96 | QUADRANT2,
97 | QUADRANT3,
98 | QUADRANT4,
99 | BETWEEN_QUADRANT1_AND_QUADRANT2,
100 | BETWEEN_QUADRANT2_AND_QUADRANT3,
101 | BETWEEN_QUADRANT3_AND_QUADRANT4,
102 | BETWEEN_QUADRANT4_AND_QUADRANT1
103 | };
104 |
105 | Quadrant GetQuadrant(double reX, double imX);
106 | double GetWrappedPhase(double reX, double imX);
107 |
108 | std::vector data_;
109 |
110 | // Cached data, lazy initialized
111 | std::vector magnitudes_;
112 | std::vector wrappedPhases_;
113 | std::vector realComponent_;
114 | std::vector imaginaryComponent_;
115 | };
116 |
117 | }
118 |
--------------------------------------------------------------------------------
/Source/Signal/LowPassFilter.h:
--------------------------------------------------------------------------------
1 | /*
2 | * AudioLib
3 | *
4 | * Copyright (c) 2017 - Terence M. Darwen - tmdarwen.com
5 | *
6 | * The MIT License
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in
16 | * all copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | * THE SOFTWARE.
25 | */
26 |
27 | //! @file LowPassFilter.h
28 | //! @brief Implementation of a low pass filter.
29 |
30 | #pragma once
31 |
32 | #include
33 | #include
34 |
35 | namespace Signal {
36 |
37 | //! An implementation of a low pass filter.
38 | //
39 | //! This is an implementation of equation 16-4 (Windowed Sinc Filter) from the
40 | //! book "The Scientist and Engineer's Guide to Digital Signal Processing" 2nd
41 | //! edition by Steven W. Smith.
42 |
43 | class LowPassFilter
44 | {
45 | public:
46 |
47 | //! Instatiate the LowPassFilter.
48 | //
49 | //! The cutoffRatio should be calculated as follows:
50 | //! cutoffRatio = OutputSampleRate/InputSampleRate * 0.5
51 | //! signal sample rate. For example, if you're input is a 44100Hz signal and
52 | //! you want to filter out everything above 32000Hz you would use a ratio of
53 | //! 0.3628.
54 | LowPassFilter(double cutoffRatio, std::size_t filterLength=100);
55 |
56 | //! Clears internal buffers and counters to restart processing fresh.
57 | void Reset();
58 |
59 | //! Submit audio data for the filter to process.
60 | void SubmitAudioData(const AudioData& audioData);
61 |
62 | //! Method to retrieve output after processed by the low pass filter.
63 | AudioData GetAudioData(uint64_t samples);
64 |
65 | //! Returns the number of output samples currently available.
66 | std::size_t OutputSamplesAvailable();
67 |
68 | //! At the end of processing, this can be called to get any and all remaining output samples.
69 | AudioData FlushAudioData();
70 |
71 | //! Returns the minimum input samples needed for processing. This is the same as the filter length.
72 | std::size_t MinimumSamplesNeededForProcessing();
73 |
74 |
75 | private:
76 | void CalculateFilterKernel();
77 | void Process();
78 |
79 | double cutoffRatio_;
80 | std::size_t filterLength_;
81 | std::vector filterKernel_;
82 |
83 | AudioData audioInput_;
84 | AudioData audioOutput_;
85 |
86 | std::mutex mutex_;
87 |
88 | const double minCutoffRatioRange_{0.0001};
89 | const double maxCutoffRatioRange_{0.5000};
90 | };
91 |
92 | }
93 |
--------------------------------------------------------------------------------
/Source/Signal/PeakFrequencyDetection.h:
--------------------------------------------------------------------------------
1 | /*
2 | * AudioLib
3 | *
4 | * Copyright (c) 2017 - Terence M. Darwen - tmdarwen.com
5 | *
6 | * The MIT License
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in
16 | * all copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | * THE SOFTWARE.
25 | */
26 |
27 | //! @file PeakFrequencyDetection.h
28 | //! @brief Pinpoint signal frequency from Fourier information.
29 |
30 | #pragma once
31 |
32 | #include
33 |
34 | namespace Signal {
35 |
36 | //! Allows for generating audio data of the given sine wave at the given sample rate, frequency, etc.
37 | std::vector GenerateSineWave(double sampleRate, std::size_t lengthInSamples, double signalFrequency, double phase=0.0);
38 |
39 | // *******************************************************************************************************
40 | // ******************* USE THE "QUINN" ALGORITHM AND AVOID THE CORRELATION ONE BELOW *********************
41 | // *******************************************************************************************************
42 | // I got this algorithm from: http://dspguru.com/dsp/howtos/how-to-interpolate-fft-peak it's called "Quinn's Second Estimator".
43 | // If there's any question about how well it performs compared to correlation, see the UT titled "TestPeakBinFrequencyAccuracy"
44 |
45 | //! Given a time domain signal, and the frequency bin, this will ascertain what the frequency of the signal is.
46 | double GetPeakFrequencyByQuinn(std::size_t peakBin, const std::vector& timeDomainSignal, double inputSignalSampleRate);
47 |
48 | //! Given a frequency domain information of a signal, this will ascertain what the frequency of the signal is.
49 | double GetPeakFrequencyByQuinn(std::size_t peakBin, std::size_t fourierSize, const std::vector& real, const std::vector& imaginary, double inputSignalSampleRate);
50 |
51 | //! Attempts to use correlation to pinpoint the frequency of the signal for the given frequency bin.
52 | double GetPeakFrequencyByCorrelation(std::size_t peakBin, const std::vector& timeDomainSignal, double inputSignalSampleRate);
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/Source/Signal/PeakProfile.h:
--------------------------------------------------------------------------------
1 | /*
2 | * AudioLib
3 | *
4 | * Copyright (c) 2017 - Terence M. Darwen - tmdarwen.com
5 | *
6 | * The MIT License
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in
16 | * all copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | * THE SOFTWARE.
25 | */
26 |
27 | //! @file PeakProfile.h
28 | //! @brief Identifies peak frequency bins in an audio signal.
29 |
30 | #pragma once
31 |
32 | #include
33 | #include
34 | #include
35 |
36 | namespace Signal {
37 |
38 | //! Given a frequency domain signal, this will find all the "peak" bins.
39 |
40 | class PeakProfile
41 | {
42 | public:
43 | //! Instantiate the object with frequency domain information.
44 | PeakProfile(const FrequencyDomain& frequencyDomain);
45 |
46 | //! This will return the closest peak for the given frequency bin.
47 | std::size_t GetLocalPeakForBin(std::size_t bin);
48 |
49 | //! Returns a list of all peak bins.
50 | const std::vector& GetAllPeakBins();
51 |
52 | //! Returns a list of all valley bins.
53 | std::pair GetValleyBins(std::size_t peakBin);
54 |
55 | private:
56 | void CalculatePeaksAndValleys();
57 |
58 | // The following hold the bin numbers of peaks (high point of magnitude) and
59 | // the low points (or "valleys") on both sides of the peaks.
60 | std::vector peakBins_;
61 | std::vector valleyBins_;
62 |
63 | // The frequency domain given by the user at construction
64 | FrequencyDomain frequencyDomain_;
65 | };
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/Source/Signal/PhaseVocoder.h:
--------------------------------------------------------------------------------
1 | /*
2 | * AudioLib
3 | *
4 | * Copyright (c) 2017 - Terence M. Darwen - tmdarwen.com
5 | *
6 | * The MIT License
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in
16 | * all copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | * THE SOFTWARE.
25 | */
26 |
27 | //! @file PhaseVocoder.h
28 | //! @brief Implementation of a phase vocoder.
29 |
30 | #pragma once
31 |
32 | #include
33 | #include
34 | #include