|
From: Lasse Kärkkäi. <tr...@us...> - 2011-01-08 10:56:37
|
Module: editor
Branch: master
Commit: 4c669efde4c7c92ae42206feedf22221c64932cf
Author: Lasse Karkkainen <tro...@tr...>
Date: Sat Jan 8 11:55:36 2011 +0100
Add pitch visualizer (reads music.raw and renders into RAM, not yet displayed on GUI)
---
pitchvis.cc | 43 +++++++++++++++++++++++++++++++++++++++++++
pitchvis.hh | 30 ++++++++++++++++++++++++++++++
2 files changed, 73 insertions(+), 0 deletions(-)
diff --git a/pitchvis.cc b/pitchvis.cc
new file mode 100644
index 0000000..f1e746f
--- /dev/null
+++ b/pitchvis.cc
@@ -0,0 +1,43 @@
+#include "pitchvis.hh"
+
+#include "notes.hh"
+#include "pitch.hh"
+#include <fstream>
+#include <iostream>
+#include <stdexcept>
+
+/** Read the entire file into a vector of some type.
+The file needs to be in the machine-native endianess. **/
+template <typename T> void readVec(std::string const& filename, std::vector<T>& c) {
+ std::ifstream f(filename.c_str(), std::ios::binary);
+ if (!f) throw std::runtime_error("Cannot open " + filename);
+ f.seekg(0, std::ios::end);
+ unsigned size = f.tellg();
+ if (size > 1e+8) throw std::runtime_error("File too large: " + filename);
+ f.seekg(0);
+ c.resize(size / sizeof(T));
+ f.read(reinterpret_cast<char*>(&c[0]), c.size() * sizeof(T));
+ if (!f) throw std::runtime_error("Error reading " + filename);
+}
+
+PitchVis::PitchVis(std::string const& filename): height(512) {
+ std::vector<float> data;
+ try { readVec(filename, data); } catch(std::exception& e) { std::cerr << e.what() << std::endl; return; }
+ unsigned step = 1024;
+ unsigned width = data.size() / step / height;
+ img.resize(width * height);
+ Analyzer analyzer(44100, "");
+ MusicalScale scale;
+ for (unsigned x = 0; x < width; ++x) {
+ analyzer.input(data.begin() + x * step, data.begin() + (x + 1) * step);
+ analyzer.process();
+ Analyzer::Peaks peaks = analyzer.getPeaks();
+ for (unsigned i = 0; i < peaks.size(); ++i) {
+ unsigned y = static_cast<unsigned>(8.0 * (scale.getNote(peaks[i].freq)));
+ if (y >= height) continue;
+ float value = magn2dB(peaks[i].magnitude) + 80.0;
+ if (value > 0.0) (*this)(x, y).r += 0.01 * value;
+ }
+ }
+}
+
diff --git a/pitchvis.hh b/pitchvis.hh
new file mode 100644
index 0000000..05a5c58
--- /dev/null
+++ b/pitchvis.hh
@@ -0,0 +1,30 @@
+#pragma once
+
+#include <string>
+#include <vector>
+
+struct Pixel {
+ float r,g,b,a;
+ Pixel(float r, float g, float b, float a = 1.0f): r(r), g(g), b(b), a(a) {}
+ Pixel(): r(), g(), b(), a(1.0f) {}
+ unsigned rgba() {
+ unsigned ret = 0;
+ for (unsigned i = 0; i < 4; ++i) {
+ float c = (*this)[i];
+ unsigned char byte = static_cast<unsigned char>(0.5 + 255.0 * c * c); // c² is gamma correction
+ ret |= byte << (i * 8);
+ }
+ return ret;
+ }
+ float& operator[](unsigned idx) { return (&r)[idx]; }
+};
+
+class PitchVis {
+ std::size_t height;
+ std::vector<Pixel> img;
+public:
+ Pixel& operator()(std::size_t x, std::size_t y) { return img[x * height + y]; }
+ std::size_t width() const { return img.size() / height; }
+ PitchVis(std::string const& filename);
+};
+
|