-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
0cf2eb6
commit 77d0ad5
Showing
7 changed files
with
993 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
#include "AudioFunctions.h" | ||
#include <cstdint> | ||
#define SIZEOF_BYTE 16 | ||
|
||
//multiplies the audio by a value, either quieting it (if <1) or making it louder (if >1) | ||
//returns false if the audio clips (ie becomes larger than its container) | ||
|
||
template <class number> | ||
bool AudioFunctions::amplify(std::vector<number>& audio, bool numberissigned, float amplificationFactor) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,211 @@ | ||
#pragma once | ||
#include <vector> | ||
#include <cmath> | ||
#include <string> | ||
#include "WAV.h" | ||
|
||
#define BITS_IN_BYTE 8 | ||
|
||
enum Position { | ||
NONE = 0, | ||
START = 1, | ||
END = 2, | ||
BOTH = 3 | ||
}; | ||
|
||
enum class timeFormat { | ||
SECONDS, | ||
SAMPLES | ||
}; | ||
|
||
struct AudioFunctions { | ||
|
||
//finds and returns the peak value of a vector of audio data, for use in amplification | ||
template <class number> | ||
static double getNormalizeRatio(std::vector <number> & audio) { | ||
number buffer = 0; | ||
for (auto n : audio) { | ||
//check to prevent wraparound | ||
//to-do: make more efficient | ||
if (((n != -(ceil(pow(2, BITS_IN_BYTE * sizeof(number))) / 2)) ? abs(n) : abs(++n)) > buffer) { | ||
buffer = (n != -(ceil(pow(2, BITS_IN_BYTE * sizeof(number))) / 2)) ? abs(n) : abs(++n); | ||
} | ||
} | ||
return (((ceil(pow(2, BITS_IN_BYTE * sizeof(number))) / 2) - 1) / buffer); | ||
} | ||
|
||
//multiplies the audio by a value, either quieting it (if <1) or making it louder (if >1) | ||
//returns false if the audio clips (ie becomes larger than its container) | ||
//use 0 as your amplification factor to normalize the audio | ||
template <class number> | ||
static bool amplify(std::vector <number>& audio, double amplificationFactor) { | ||
std::cout << "Amplifying file with factor " << amplificationFactor << "...\n"; | ||
int64_t buffer; | ||
|
||
int64_t upper_limit = (ceil(pow(2, BITS_IN_BYTE * sizeof(number))) / 2); | ||
int64_t lower_limit = -(ceil(pow(2, BITS_IN_BYTE * sizeof(number))) / 2); | ||
|
||
bool clipped = false; | ||
int64_t counter = 0; | ||
for (auto n : audio) { | ||
//std::cout << n << ' '; | ||
buffer = (double)n * amplificationFactor; | ||
//std::cout << buffer << "\n"; | ||
|
||
//clipping test and handler | ||
if (buffer >= upper_limit || | ||
buffer < lower_limit){ | ||
if (!clipped) { | ||
std::cout << "The audio data is clipping!\n"; | ||
clipped = true; | ||
} | ||
if (buffer >= 0) { | ||
buffer = --upper_limit; | ||
} | ||
else { | ||
buffer = lower_limit; | ||
} | ||
} | ||
//std::cout << buffer << "\n"; | ||
//getchar(); | ||
audio.at(counter) = buffer; | ||
++counter; | ||
} | ||
std::cout << "Amplification complete.\n"; | ||
return clipped; | ||
} | ||
|
||
|
||
//remove silence from track | ||
//position can be specific to be from beginning and/or from end of track | ||
//can also remove clicks from track in a nonspecific and clunky way | ||
//return value gives number of samples removed from front and back | ||
template <class number> | ||
static std::pair<uint32_t, uint32_t> removeSilence(std::vector<number>& audio, Position removePosition = BOTH, bool removeClick = false, Position clickPosition = NONE, int16_t threshold = 0) { | ||
std::cout << "Removing silence...\n"; | ||
|
||
std::pair<uint32_t, uint32_t> samplesRemoved; | ||
samplesRemoved.first = 0; | ||
samplesRemoved.second = 0; | ||
|
||
if ((removePosition & START) == START) { | ||
std::cout << "Removing silence from start..."; | ||
for (auto i = audio.begin(); i != audio.end(); ++i) { | ||
if (*i != threshold || *i != -threshold) { | ||
if (removeClick && ((clickPosition & START) == START)) { | ||
std::cout << "Click found!\n"; | ||
removeClick = false; | ||
for (auto it = i; it != audio.end(); ++it) { | ||
if (*it == threshold || *it == -threshold) { | ||
i = it; | ||
break; | ||
} | ||
} | ||
} | ||
else { | ||
std::cout << "Silence found!\n"; | ||
samplesRemoved.first = std::distance(audio.begin(), i); | ||
audio.erase(audio.begin(), i); | ||
break; | ||
} | ||
} | ||
} | ||
std::cout << "Silence removed from start.\n"; | ||
} | ||
|
||
if (clickPosition != NONE) { | ||
removeClick = true; | ||
} | ||
|
||
if ((removePosition & END) == END) { | ||
std::cout << "Removing silence from end..."; | ||
for (auto i = (audio.end() - 1); i != audio.begin(); --i) { | ||
if (*i != threshold || *i != -threshold) { | ||
if (removeClick && ((clickPosition & END) == END)) { | ||
std::cout << "Click found!\n"; | ||
removeClick = false; | ||
for (auto it = i; it != audio.begin(); --it) { | ||
if (*it == threshold || *it == -threshold) { | ||
i = it; | ||
break; | ||
} | ||
} | ||
} | ||
else { | ||
std::cout << "Silence found!\n"; | ||
samplesRemoved.second = std::distance(i, audio.end()); | ||
audio.erase(i, audio.end()); | ||
break; | ||
} | ||
} | ||
} | ||
std::cout << "Silence removed from end.\n"; | ||
} | ||
std::cout << "Silence removal complete.\n"; | ||
return samplesRemoved; | ||
} | ||
|
||
//similar to removeSilence(), but with a specified range of samples to remove, expressed as a pair | ||
template <class number> | ||
static void removeSamples(std::vector <number>& audio, std::pair<uint32_t, uint32_t> numberofSamples) { | ||
if (numberofSamples.first + numberofSamples.second < audio.size()) { | ||
audio.erase(audio.begin(), audio.begin() + numberofSamples.first); | ||
audio.erase((audio.end() - numberofSamples.second), audio.end()); | ||
} | ||
} | ||
|
||
//add silence to beginning and/or end of track | ||
//can be used in either seconds or samples | ||
template <class number> | ||
static void addSilence(std::vector<number>& audio, timeFormat format, double silenceLength, Position addPosition, uint32_t sampleRate = 1) { | ||
if (format == timeFormat::SAMPLES) { | ||
sampleRate = 1; | ||
} | ||
if ((addPosition & START) == START) { | ||
std::cout << "Adding " << silenceLength << " " << ((format == timeFormat::SAMPLES) ? "samples" : "seconds") << " of silence to the start...\n"; | ||
audio.insert(audio.begin(), (silenceLength * ((format == timeFormat::SAMPLES) ? sampleRate : 1)), 0); | ||
} | ||
if ((addPosition & END) == END) { | ||
std::cout << "Adding " << silenceLength << " " << ((format == timeFormat::SAMPLES) ? "samples" : "seconds") << " of silence to the end...\n"; | ||
audio.insert(audio.end(), (silenceLength * ((format == timeFormat::SAMPLES) ? sampleRate : 1)), 0); | ||
} | ||
std::cout << "Silence adding complete!\n"; | ||
} | ||
|
||
//fade the audio out in a specified timeframe | ||
//if used with samples, do not include the sample rate in the arguments | ||
//future plans: add fadein option | ||
template <class number> | ||
static void fade(std::vector<number>& audio, timeFormat format, double fadeLength, Position fadePosition = END, uint32_t sampleRate = 1) { | ||
if (format == timeFormat::SECONDS) { | ||
fadeLength *= sampleRate; | ||
} | ||
|
||
if (fadeLength > audio.size()) { | ||
fadeLength = audio.size(); | ||
} | ||
|
||
double fadeFactor = 1.0; | ||
double fadeRate = fadeFactor / fadeLength; | ||
|
||
if ((fadePosition & START) == START) { | ||
--fadeLength; | ||
std::cout << "Fading in audio..."; | ||
for (auto i = (audio.begin() + fadeLength); i != audio.begin(); --i) { | ||
*i *= fadeFactor; | ||
fadeFactor -= fadeRate; | ||
} | ||
} | ||
else { | ||
std::cout << "Fading out audio..."; | ||
for (auto i = (audio.end() - fadeLength); i != audio.end(); ++i) { | ||
*i *= fadeFactor; | ||
fadeFactor -= fadeRate; | ||
} | ||
} | ||
|
||
std::cout << "Fade complete.\n"; | ||
} | ||
}; | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
#include "CommandLineArguments.h" | ||
|
||
void handleOptions(int argc, char* argv[], std::vector<Option*> opttable) { | ||
|
||
if (argc <= 1) { | ||
std::cout << "No arguments found!\n"; | ||
} | ||
else { | ||
bool errflag = true; | ||
//stores argument that couldn't be parsed | ||
std::vector <std::string> errtable; | ||
//std::cout << argc << '\n'; | ||
|
||
//check each argument sequentially | ||
for (int i = 1; i < argc; i++) { | ||
//std::cout << i << " in main loop\n"; | ||
errflag = true; | ||
//compare each argument with the list of options | ||
for (auto j : opttable) { | ||
//make sure the option hasn't already been set | ||
if (!j->getOptFlag()) { | ||
if (j->testString(argv[i])) { | ||
errflag = false; | ||
if (j->hasArg()) { | ||
i++; | ||
//std::cout << i << " in secondary loop\n"; | ||
|
||
//checks for arguments if the option has them | ||
if (i < argc) { | ||
//if the argument isn't an option | ||
if (argv[i][0] != '-') { | ||
j->setArgument(argv[i]); | ||
} | ||
else { | ||
i--; | ||
break; | ||
} | ||
} | ||
else { | ||
break; | ||
} | ||
} | ||
break; | ||
} | ||
} | ||
} | ||
if (errflag) { | ||
errtable.push_back(argv[i]); | ||
} | ||
} | ||
if (errtable.size() != 0) { | ||
std::cout << "The following arguments could not be parsed:\n"; | ||
for (auto i : errtable) { | ||
std::cout << i << "\n"; | ||
} | ||
} | ||
} | ||
} | ||
|
||
//loads names for options | ||
//'s' is the short option name | ||
//'l' is the long option name | ||
//the strings will be formatted automatically if no -- is included | ||
//set 'a' to true to include an argument with the option | ||
//pass a value to d to give the argument a default value | ||
Option::Option(char s, std::string l, bool a, std::string odescription, std::string adescription, std::string d) { | ||
std::stringstream ss; | ||
ss << '-' << s; | ||
ss >> shortopt; | ||
|
||
ss.clear(); | ||
if (l.at(1) != '-') { | ||
if (l.at(0) != '-') { | ||
ss << "-"; | ||
} | ||
ss << "-" << l; | ||
ss >> longopt; | ||
} | ||
|
||
|
||
optdescription = odescription; | ||
argdescription = adescription; | ||
|
||
arg = d; | ||
|
||
hasarg = a; | ||
optflag = false; | ||
} | ||
|
||
//gives a short description of what the option does | ||
void Option::describeOption() { | ||
std::cout << shortopt << ", " << longopt << '\n'; | ||
std::cout << optdescription << '\n'; | ||
if (argdescription != "") { | ||
std::cout << argdescription << "\n"; | ||
} | ||
if (argIsDefined()) { | ||
std::cout << "(Default argument: " << arg << ")\n"; | ||
} | ||
std::cout << '\n'; | ||
} | ||
|
||
//checks string for compatibility with command line argument | ||
bool Option::testString(std::string compare) { | ||
for (auto i = compare.begin(); i != compare.end(); i++) { | ||
*i = tolower(*i); | ||
} | ||
|
||
optflag = (shortopt == compare || longopt == compare); | ||
if (optflag) { | ||
std::cout << "Match found!\n"; | ||
} | ||
else { | ||
std::cout << "Match not found!\n"; | ||
} | ||
return optflag; | ||
} | ||
|
||
bool Option::getOptFlag() { | ||
return optflag; | ||
} | ||
|
||
bool Option::hasArg() { | ||
return hasarg; | ||
} | ||
|
||
void Option::setArgument(std::string a) { | ||
arg = a; | ||
argflag = true; | ||
} | ||
|
||
std::string Option::getArgument() { | ||
return arg; | ||
} | ||
|
||
bool Option::argIsDefined() { | ||
return (arg != ""); | ||
} |
Oops, something went wrong.