everything

This commit is contained in:
Robert 2021-04-27 13:19:52 +02:00
parent 608722bc0d
commit c607b8ec02
7 changed files with 26889 additions and 0 deletions

7
.gitignore vendored Normal file
View file

@ -0,0 +1,7 @@
out
bin
.vs
__pycache__
*.json
res

0
.gitmodules vendored
View file

14
CMakeLists.txt Normal file
View file

@ -0,0 +1,14 @@
cmake_minimum_required(VERSION 3.14)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
project(spectralyze)
add_executable(spectralyze
"src/main.cpp"
"src/FFT.hpp")
target_include_directories(spectralyze PRIVATE
"lib/AudioFile"
"lib/json"
)

1293
lib/AudioFile/AudioFile.h Normal file

File diff suppressed because it is too large Load diff

25447
lib/json/json.hpp Normal file

File diff suppressed because it is too large Load diff

75
src/FFT.hpp Normal file
View file

@ -0,0 +1,75 @@
#pragma once
#define _USE_MATH_DEFINES
#include <math.h>
#include <vector>
#include <complex>
#define TWO_PI (double)6.28318530718f
#define POW_OF_TWO(x) (x && !(x & (x - 1)))
using namespace std::complex_literals;
std::vector<std::complex<double>> radix2dit(const std::vector<double>::const_iterator& begin, size_t N, size_t s)
{
std::vector<std::complex<double>> output(N);
if (N == 1)
{
output[0] = *begin;
}
else
{
size_t halfN = N >> 1;
std::vector<std::complex<double>> first = radix2dit(begin, halfN, s << 1);
std::vector<std::complex<double>> second = radix2dit(begin + s, halfN, s << 1);
/*if (s == 1) {
std::future<std::vector<std::complex<double>>> firstFuture = std::async(&radix2dit, begin, halfN, s << 1);
std::future<std::vector<std::complex<double>>> secondFuture = std::async(&radix2dit, begin + s, halfN, s << 1);
first = firstFuture.get();
second = secondFuture.get();
}
else {
first = radix2dit(begin, halfN, s << 1);
second = radix2dit(begin + 1, halfN, s << 1);
}*/
std::complex<double> coeff = -M_PI * 1.0i / (double)halfN;
for (int k = 0; k < N >> 1; k++)
{
std::complex<double> p = first[k];
std::complex<double> q = std::exp(coeff * (double)k) * second[k];
output[k] = p + q;
output[halfN + k] = p - q;
}
}
return output;
}
std::vector<std::pair<double, double>> FFT(std::vector<double> signal, size_t sampleRate)
{
size_t N = signal.size();
while (!POW_OF_TWO(N))
{
// Pad with zeros
signal.push_back(0.0f);
N++;
}
std::vector<std::complex<double>> spectrum = radix2dit(signal.cbegin(), N, 1);
double freqRes = (double)sampleRate / (double)N;
double nyquistLimit = (double)sampleRate / 2.0f;
std::vector<std::pair<double, double>> output;
double freq = 0.0f;
for (int k = 0; freq < nyquistLimit; k++)
{
output.push_back(std::make_pair(freq, 2.0f * std::abs(spectrum[k]) / (double)N));
freq += freqRes;
}
return output;
}

53
src/main.cpp Normal file
View file

@ -0,0 +1,53 @@
#include <iostream>
#include <fstream>
#include <iomanip>
#include <filesystem>
#include "AudioFile.h"
#include "json.hpp"
#include "FFT.hpp"
void PrintUsage();
int main(int argc, char** argv)
{
if (argc < 2) {
PrintUsage();
return 1;
}
int numFiles = argc - 1;
for (int i = 1; i < argc; i++) {
AudioFile<double> audioFile;
audioFile.load(argv[i]);
std::string filename = std::filesystem::path(argv[i]).filename().string();
int sampleRate = audioFile.getSampleRate();
int numChannels = audioFile.getNumChannels();
nlohmann::json output;
for (int c = 1; c <= numChannels; c++) {
std::cout << "\rAnalyzing " << filename << "... Channel " << c << "/" << numChannels << " ";
std::vector<std::pair<double, double>> spectrum = FFT(audioFile.samples[c-1], sampleRate);
std::string chName = "channel_" + std::to_string(c);
output[chName] = nlohmann::json::array();
for (const std::pair<double, double>& pair : spectrum) {
output[chName].push_back({ {"freq", pair.first}, {"mag", pair.second } });
}
}
std::ofstream ofs(std::filesystem::path(argv[i]).replace_extension("json"));
ofs << std::setw(4) << output << std::endl;
ofs.close();
std::cout << "\rAnalyzing " << filename << "... Done! " << std::endl;
}
return 0;
}
void PrintUsage()
{
std::cerr << "Usage: spectralyze file1 [file2...]" << std::endl;
}