]> git.sesse.net Git - kdenlive/blob - src/audioscopes/audiospectrum.cpp
d4bb715b62dea97f5b116fa1ed7019ef3d464738
[kdenlive] / src / audioscopes / audiospectrum.cpp
1 #include "audiospectrum.h"
2 #include "tools/kiss_fftr.h"
3
4 #include <QMenu>
5
6 //#include <iostream>
7 //#include <fstream>
8
9 bool fileWritten = false;
10
11 AudioSpectrum::AudioSpectrum(Monitor *projMonitor, Monitor *clipMonitor, QWidget *parent) :
12         AbstractAudioScopeWidget(projMonitor, clipMonitor, true, parent)
13 {
14     ui = new Ui::AudioSpectrum_UI;
15     ui->setupUi(this);
16
17     m_cfg = kiss_fftr_alloc(512, 0,0,0);
18
19     m_aAutoRefresh->setChecked(true); // TODO remove
20
21     m_aLin = new QAction(i18n("Linear scale"), this);
22     m_aLin->setCheckable(true);
23     m_aLog = new QAction(i18n("Logarithmic scale"), this);
24     m_aLog->setCheckable(true);
25
26     m_agScale = new QActionGroup(this);
27     m_agScale->addAction(m_aLin);
28     m_agScale->addAction(m_aLog);
29
30     m_menu->addSeparator()->setText(i18n("Scale"));;
31     m_menu->addAction(m_aLin);
32     m_menu->addAction(m_aLog);
33
34     init();
35 }
36 AudioSpectrum::~AudioSpectrum()
37 {
38     free(m_cfg);
39     delete m_agScale;
40     delete m_aLin;
41     delete m_aLog;
42 }
43
44 void AudioSpectrum::readConfig()
45 {
46     AbstractAudioScopeWidget::readConfig();
47
48     KSharedConfigPtr config = KGlobal::config();
49     KConfigGroup scopeConfig(config, configName());
50     QString scale = scopeConfig.readEntry("scale");
51     if (scale == "lin") {
52         m_aLin->setChecked(true);
53     } else {
54         m_aLog->setChecked(true);
55     }
56
57 }
58 void AudioSpectrum::writeConfig()
59 {
60     KSharedConfigPtr config = KGlobal::config();
61     KConfigGroup scopeConfig(config, configName());
62     QString scale;
63     if (m_aLin->isChecked()) {
64         scale = "lin";
65     } else {
66         scale = "log";
67     }
68     scopeConfig.writeEntry("scale", scale);
69     scopeConfig.sync();
70 }
71
72 QString AudioSpectrum::widgetName() const { return QString("audiospectrum"); }
73
74 bool AudioSpectrum::isBackgroundDependingOnInput() const { return false; }
75 bool AudioSpectrum::isScopeDependingOnInput() const { return true; }
76 bool AudioSpectrum::isHUDDependingOnInput() const { return false; }
77
78 QImage AudioSpectrum::renderBackground(uint) { return QImage(); }
79 QImage AudioSpectrum::renderScope(uint accelerationFactor, const QVector<int16_t> audioFrame, const int freq, const int num_channels, const int num_samples)
80 {
81     float data[512];
82
83     // The resulting FFT vector is only half as long
84     kiss_fft_cpx freqData[256];
85
86     // Copy the first channel's audio into a vector for the FFT display
87     for (int i = 0; i < 512; i++) {
88         data[i] = (float) audioFrame.data()[i*num_channels];
89     }
90     kiss_fftr(m_cfg, data, freqData);
91 //    qDebug() << num_samples << " samples at " << freq << " Hz";
92 //    qDebug() << "FFT Freq: " << freqData[0].r << " " << freqData[1].r << ", " << freqData[2].r;
93 //    qDebug() << "FFT imag: " << freqData[0].i << " " << freqData[1].i << ", " << freqData[2].i;
94
95     qDebug() << QMetaObject::normalizedSignature("void audioSamplesSignal(const QVector<int16_t>&, int freq, int num_channels, int num_samples)");
96
97     float max = 0;
98     float min = 1000;
99     float val;
100     for (int i = 0; i < 256; i++) {
101         if (m_aLin->isChecked()) {
102             val = pow(pow(fabs(freqData[i].r),2) + pow(fabs(freqData[i].i),2), .5);
103         } else {
104             val = log(pow(pow(fabs(freqData[i].r),2) + pow(fabs(freqData[i].i),2), .5));
105         }
106         max = (max > val) ? max : val;
107         min = (min < val) ? min : val;
108     }
109     qDebug() << "MAX: " << max << ", MIN: " << min;
110
111     float factor = 100./(max-min);
112
113     QImage spectrum(512, 100, QImage::Format_ARGB32);
114     spectrum.fill(qRgba(0,0,0,0));
115     for (int i = 0; i < 256; i++) {
116         if (m_aLin->isChecked()) {
117             val = pow(pow(fabs(freqData[i].r),2) + pow(fabs(freqData[i].i),2), .5);
118         } else {
119             val = log(pow(pow(fabs(freqData[i].r),2) + pow(fabs(freqData[i].i),2), .5));
120         }
121         //val = val >> 16;
122         val = factor * (val-min);
123 //        qDebug() << val;
124         for (int y = 0; y < val && y < 100; y++) {
125             spectrum.setPixel(2*i, 99-y, qRgba(225, 182, 255, 255));
126             spectrum.setPixel(2*i+1, 99-y, qRgba(225, 182, 255, 255));
127         }
128     }
129
130     emit signalScopeRenderingFinished(0, 1);
131
132     /*
133     if (!fileWritten || true) {
134         std::ofstream mFile;
135         mFile.open("/tmp/freq.m");
136         if (!mFile) {
137             qDebug() << "Opening file failed.";
138         } else {
139             mFile << "val = [ ";
140
141             for (int sample = 0; sample < 256; sample++) {
142                 mFile << data[sample] << " ";
143             }
144             mFile << " ];\n";
145
146             mFile << "freq = [ ";
147             for (int sample = 0; sample < 256; sample++) {
148                 mFile << freqData[sample].r << "+" << freqData[sample].i << "*i ";
149             }
150             mFile << " ];\n";
151
152             mFile.close();
153             fileWritten = true;
154             qDebug() << "File written.";
155         }
156     } else {
157         qDebug() << "File already written.";
158     }
159     */
160
161     return spectrum;
162 }
163 QImage AudioSpectrum::renderHUD(uint) { return QImage(); }
164
165 QRect AudioSpectrum::scopeRect() {
166     return QRect(0,0,40,40);
167 }