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