Skip to content

Commit

Permalink
WIP - new geWaveform
Browse files Browse the repository at this point in the history
  • Loading branch information
gvnnz committed Dec 13, 2024
1 parent 7d8ad49 commit da99c53
Show file tree
Hide file tree
Showing 4 changed files with 234 additions and 2 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,8 @@ list(APPEND SOURCES
src/gui/elems/plugin/pluginElement.h
src/gui/elems/sampleEditor/waveform_DEPR_.cpp
src/gui/elems/sampleEditor/waveform_DEPR_.h
src/gui/elems/sampleEditor/waveform.cpp
src/gui/elems/sampleEditor/waveform.h
src/gui/elems/sampleEditor/waveTools.cpp
src/gui/elems/sampleEditor/waveTools.h
src/gui/elems/volumeTool.cpp
Expand Down
155 changes: 155 additions & 0 deletions src/gui/elems/sampleEditor/waveform.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
/* -----------------------------------------------------------------------------
*
* Giada - Your Hardcore Loopmachine
*
* -----------------------------------------------------------------------------
*
* Copyright (C) 2010-2024 Giovanni A. Zuliani | Monocasual Laboratories
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
* Giada - Your Hardcore Loopmachine is free software: you can
* redistribute it and/or modify it under the terms of the GNU General
* Public License as published by the Free Software Foundation, either
* version 3 of the License, or (at your option) any later version.
*
* Giada - Your Hardcore Loopmachine is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Giada - Your Hardcore Loopmachine. If not, see
* <http://www.gnu.org/licenses/>.
*
* -------------------------------------------------------------------------- */

#include "gui/elems/sampleEditor/waveform.h"
#include "core/const.h"
#include "core/wave.h"
#include "gui/drawing.h"
#include "utils/log.h"
#include "utils/math.h"

namespace giada::v
{
geWaveform::Data::Data(const m::Wave& wave, geompp::Range<Frame> widthAudio, int widthScreen)
{
const mcl::AudioBuffer& audioBuffer = wave.getBuffer();

/* ratio
Defines the ratio between the audio content and the screen width. If < 1.0,
we are digging into samples. If >= 1.0, it also tells how many audio frames
we should consider as a 'chunk' to use for a single column in screen space. */

const double ratio = widthAudio.getLength() / static_cast<double>(widthScreen);

if (ratio < 1.0)
{
G_DEBUG("Ratio < 1.0 not supported yet!");
return;
}

for (int channel = 0; channel < audioBuffer.countChannels(); channel++)
{
m_peaks.push_back({});

double frame = 0;
for (int column = 0; column < widthScreen; column++)
{
/* Compute up/down peaks in the [frame, frame+ratio) range. */
float peakUp = 0.0;
float peakDown = 0.0;
for (int i = frame; i < std::floor(frame + ratio); i++)
{
const float value = audioBuffer[i][channel];
peakUp = std::max(value, peakUp);
peakDown = std::min(value, peakDown);
}

m_peaks[channel].push_back({peakUp, peakDown});

frame += ratio;
}
}
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

const geWaveform::Data::Peaks& geWaveform::Data::get() const
{
return m_peaks;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

geWaveform::geWaveform()
: Fl_Widget(0, 0, 0, 0)
, m_wave(nullptr)
{
}

/* -------------------------------------------------------------------------- */

void geWaveform::draw()
{
v::drawRect({x(), y(), w(), h()}, G_COLOR_GREY_2);

if (m_wave == nullptr)
return;

fl_color(G_COLOR_BLACK);

const int channelHeight = h() / m_data.get().size();

for (int numChannel = 0; const auto& channel : m_data.get())
{
const int channelY = (channelHeight * numChannel) + y();
const int zero = channelY + (channelHeight / 2);

for (int column = x(); const auto& peaks : channel)
{
const float peakUpAudio = peaks.first;
const float peakDownAudio = peaks.second;
const int peakUpScreen = u::math::map(peakUpAudio, 0.0f, 1.0f, zero, channelY);
const int peakDownScreen = u::math::map(peakDownAudio, 0.0f, -1.0f, zero, channelY + channelHeight);

fl_line(column, zero, column, peakUpScreen);
fl_line(column, zero, column, peakDownScreen);

column++;
}

numChannel++;
}
}

/* -------------------------------------------------------------------------- */

void geWaveform::setWave(const m::Wave* w)
{
m_wave = w;
if (m_wave == nullptr)
m_range = {};
else
m_range = {0, m_wave->getBuffer().countFrames()};

invalidate();
}

/* -------------------------------------------------------------------------- */

void geWaveform::invalidate()
{
assert(m_wave != nullptr);

G_DEBUG("Invalidate waveform data");

m_data = {*m_wave, m_range, w()};
}

} // namespace giada::v
75 changes: 75 additions & 0 deletions src/gui/elems/sampleEditor/waveform.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/* -----------------------------------------------------------------------------
*
* Giada - Your Hardcore Loopmachine
*
* -----------------------------------------------------------------------------
*
* Copyright (C) 2010-2024 Giovanni A. Zuliani | Monocasual Laboratories
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
* Giada - Your Hardcore Loopmachine is free software: you can
* redistribute it and/or modify it under the terms of the GNU General
* Public License as published by the Free Software Foundation, either
* version 3 of the License, or (at your option) any later version.
*
* Giada - Your Hardcore Loopmachine is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Giada - Your Hardcore Loopmachine. If not, see
* <http://www.gnu.org/licenses/>.
*
* -------------------------------------------------------------------------- */

#ifndef GE_WAVEFORM_H
#define GE_WAVEFORM_H

#include "core/types.h"
#include "deps/geompp/src/range.hpp"
#include <FL/Fl_Widget.H>
#include <utility>
#include <vector>

namespace giada::m
{
class Wave;
}

namespace giada::v
{
class geWaveform : public Fl_Widget
{
public:
geWaveform();

void draw() override;

void setWave(const m::Wave*);

private:
class Data
{
public:
using Peaks = std::vector<std::vector<std::pair<float, float>>>;

Data() = default;
Data(const m::Wave&, geompp::Range<Frame>, int width);

const Peaks& get() const;

private:
Peaks m_peaks;
};

void invalidate();

const m::Wave* m_wave;
geompp::Range<Frame> m_range;
Data m_data;
};
} // namespace giada::v

#endif
4 changes: 2 additions & 2 deletions src/gui/elems/sampleEditor/waveform_DEPR_.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
*
* -------------------------------------------------------------------------- */

#ifndef GE_WAVEFORM_H
#define GE_WAVEFORM_H
#ifndef GE_WAVEFORM_DEPR_H
#define GE_WAVEFORM_DEPR_H

#include "core/const.h"
#include "core/types.h"
Expand Down

0 comments on commit da99c53

Please sign in to comment.