mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2025-03-01 00:57:20 +00:00
Added wav file viewer
Fileman open now allows going into subdirectories Updated binary
This commit is contained in:
parent
40a71d32a2
commit
6e7b2c751f
@ -213,6 +213,7 @@ set(CPPSRC
|
|||||||
ui_touch_calibration.cpp
|
ui_touch_calibration.cpp
|
||||||
ui_touchtunes.cpp
|
ui_touchtunes.cpp
|
||||||
ui_transmitter.cpp
|
ui_transmitter.cpp
|
||||||
|
ui_view_wav.cpp
|
||||||
ui_whipcalc.cpp
|
ui_whipcalc.cpp
|
||||||
# ui_loadmodule.cpp
|
# ui_loadmodule.cpp
|
||||||
recent_entries.cpp
|
recent_entries.cpp
|
||||||
|
@ -97,6 +97,10 @@ uint32_t WAVFileReader::ms_duration() {
|
|||||||
return ((data_size_ * 1000) / sample_rate_) / bytes_per_sample;
|
return ((data_size_ * 1000) / sample_rate_) / bytes_per_sample;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WAVFileReader::data_seek(const uint64_t Offset) {
|
||||||
|
file.seek(data_start + (Offset * bytes_per_sample));
|
||||||
|
}
|
||||||
|
|
||||||
/*int WAVFileReader::seek_mss(const uint16_t minutes, const uint8_t seconds, const uint32_t samples) {
|
/*int WAVFileReader::seek_mss(const uint16_t minutes, const uint8_t seconds, const uint32_t samples) {
|
||||||
const auto result = file.seek(data_start + ((((minutes * 60) + seconds) * sample_rate_) + samples) * bytes_per_sample);
|
const auto result = file.seek(data_start + ((((minutes * 60) + seconds) * sample_rate_) + samples) * bytes_per_sample);
|
||||||
|
|
||||||
@ -118,6 +122,10 @@ uint32_t WAVFileReader::data_size() {
|
|||||||
return data_size_;
|
return data_size_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t WAVFileReader::sample_count() {
|
||||||
|
return data_size_ / bytes_per_sample;
|
||||||
|
}
|
||||||
|
|
||||||
uint16_t WAVFileReader::bits_per_sample() {
|
uint16_t WAVFileReader::bits_per_sample() {
|
||||||
return header.fmt.wBitsPerSample;
|
return header.fmt.wBitsPerSample;
|
||||||
}
|
}
|
||||||
|
@ -112,12 +112,14 @@ public:
|
|||||||
virtual ~WAVFileReader() = default;
|
virtual ~WAVFileReader() = default;
|
||||||
|
|
||||||
bool open(const std::filesystem::path& path);
|
bool open(const std::filesystem::path& path);
|
||||||
|
void data_seek(const uint64_t Offset);
|
||||||
void rewind();
|
void rewind();
|
||||||
uint32_t ms_duration();
|
uint32_t ms_duration();
|
||||||
//int seek_mss(const uint16_t minutes, const uint8_t seconds, const uint32_t samples);
|
//int seek_mss(const uint16_t minutes, const uint8_t seconds, const uint32_t samples);
|
||||||
uint16_t channels();
|
uint16_t channels();
|
||||||
uint32_t sample_rate();
|
uint32_t sample_rate();
|
||||||
uint32_t data_size();
|
uint32_t data_size();
|
||||||
|
uint32_t sample_count();
|
||||||
uint16_t bits_per_sample();
|
uint16_t bits_per_sample();
|
||||||
std::string title();
|
std::string title();
|
||||||
|
|
||||||
|
@ -32,11 +32,19 @@
|
|||||||
//BUG: SCANNER Lock on frequency, if frequency jump, still locked on first one
|
//BUG: SCANNER Lock on frequency, if frequency jump, still locked on first one
|
||||||
//BUG: SCANNER Multiple slices
|
//BUG: SCANNER Multiple slices
|
||||||
|
|
||||||
|
//TODO: Cap Wav viewer position
|
||||||
|
//TODO: Adapt wav viewer position step
|
||||||
|
//TODO: Optimize wav viewer refresh
|
||||||
|
//TODO: Remove make_bistream from encoders.cpp, too complex, stinks. bitstream_append should be enough.
|
||||||
|
//TODO: Continue work on proc_afskrx_corr, see python script (it works !)
|
||||||
|
//TODO: Super simple text file viewer
|
||||||
|
//TODO: De bruijn sequence scanner for encoders
|
||||||
|
//TODO: FILEMAN Rename folders
|
||||||
|
//TODO: FILEMAN Move files
|
||||||
//TODO: Frequency and bw settings were removed from modemsetup, put those back in LCR TX
|
//TODO: Frequency and bw settings were removed from modemsetup, put those back in LCR TX
|
||||||
|
//TODO: Use separate thread for scanning in EPAR TX
|
||||||
//TODO: Use separate thread for scanning in LCR TX
|
//TODO: Use separate thread for scanning in LCR TX
|
||||||
//TODO: REPLAY Convert C16 to C8 on M0 core
|
//TODO: REPLAY Convert C16 to C8 on M0 core
|
||||||
//TODO: Use TabView
|
|
||||||
//TODO: De bruijn sequence scanner for encoders
|
|
||||||
//TODO: Make freqman refresh simpler (use previous black rectangle method)
|
//TODO: Make freqman refresh simpler (use previous black rectangle method)
|
||||||
//TODO: Merge AFSK and TONES procs ?
|
//TODO: Merge AFSK and TONES procs ?
|
||||||
//TODO: NFM RX mode: nav.pop on squelch
|
//TODO: NFM RX mode: nav.pop on squelch
|
||||||
|
@ -201,17 +201,17 @@ FileLoadView::FileLoadView(
|
|||||||
// Resize menu view to fill screen
|
// Resize menu view to fill screen
|
||||||
menu_view.set_parent_rect({ 0, 3 * 8, 240, 29 * 8 });
|
menu_view.set_parent_rect({ 0, 3 * 8, 240, 29 * 8 });
|
||||||
|
|
||||||
// Just to allow exit on left
|
|
||||||
menu_view.on_left = [&nav, this]() {
|
|
||||||
nav.pop();
|
|
||||||
};
|
|
||||||
|
|
||||||
refresh_list();
|
refresh_list();
|
||||||
|
|
||||||
on_select_entry = [&nav, this]() {
|
on_select_entry = [&nav, this]() {
|
||||||
|
if (entry_list[menu_view.highlighted()].is_directory) {
|
||||||
|
load_directory_contents(get_selected_path());
|
||||||
|
refresh_list();
|
||||||
|
} else {
|
||||||
nav_.pop();
|
nav_.pop();
|
||||||
if (on_changed)
|
if (on_changed)
|
||||||
on_changed(entry_list[menu_view.highlighted()].entry_path);
|
on_changed(entry_list[menu_view.highlighted()].entry_path);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -288,6 +288,7 @@ FileManagerView::FileManagerView(
|
|||||||
};
|
};
|
||||||
|
|
||||||
button_delete.on_select = [this, &nav](Button&) {
|
button_delete.on_select = [this, &nav](Button&) {
|
||||||
|
// Use display_modal ?
|
||||||
nav.push<ModalMessageView>("Delete", "Delete " + entry_list[menu_view.highlighted()].entry_path.filename().string() + "\nAre you sure ?", YESNO,
|
nav.push<ModalMessageView>("Delete", "Delete " + entry_list[menu_view.highlighted()].entry_path.filename().string() + "\nAre you sure ?", YESNO,
|
||||||
[this](bool choice) {
|
[this](bool choice) {
|
||||||
if (choice)
|
if (choice)
|
||||||
|
@ -59,6 +59,7 @@
|
|||||||
#include "ui_soundboard.hpp"
|
#include "ui_soundboard.hpp"
|
||||||
#include "ui_sstvtx.hpp"
|
#include "ui_sstvtx.hpp"
|
||||||
#include "ui_touchtunes.hpp"
|
#include "ui_touchtunes.hpp"
|
||||||
|
#include "ui_view_wav.hpp"
|
||||||
#include "ui_whipcalc.hpp"
|
#include "ui_whipcalc.hpp"
|
||||||
|
|
||||||
#include "analog_audio_app.hpp"
|
#include "analog_audio_app.hpp"
|
||||||
@ -363,6 +364,7 @@ SystemMenuView::SystemMenuView(NavigationView& nav) {
|
|||||||
{ "Capture", ui::Color::blue(), &bitmap_icon_capture, [&nav](){ nav.push<CaptureAppView>(); } },
|
{ "Capture", ui::Color::blue(), &bitmap_icon_capture, [&nav](){ nav.push<CaptureAppView>(); } },
|
||||||
{ "Replay", ui::Color::grey(), &bitmap_icon_replay, [&nav](){ nav.push<ReplayAppView>(); } },
|
{ "Replay", ui::Color::grey(), &bitmap_icon_replay, [&nav](){ nav.push<ReplayAppView>(); } },
|
||||||
{ "Scanner/search", ui::Color::orange(), &bitmap_icon_closecall, [&nav](){ nav.push<ScannerView>(); } },
|
{ "Scanner/search", ui::Color::orange(), &bitmap_icon_closecall, [&nav](){ nav.push<ScannerView>(); } },
|
||||||
|
{ "Wave file viewer", ui::Color::blue(), nullptr, [&nav](){ nav.push<ViewWavView>(); } },
|
||||||
{ "Utilities", ui::Color::purple(), &bitmap_icon_utilities, [&nav](){ nav.push<UtilitiesMenuView>(); } },
|
{ "Utilities", ui::Color::purple(), &bitmap_icon_utilities, [&nav](){ nav.push<UtilitiesMenuView>(); } },
|
||||||
{ "Setup", ui::Color::white(), &bitmap_icon_setup, [&nav](){ nav.push<SetupMenuView>(); } },
|
{ "Setup", ui::Color::white(), &bitmap_icon_setup, [&nav](){ nav.push<SetupMenuView>(); } },
|
||||||
//{ "Debug", ui::Color::white(), nullptr, [&nav](){ nav.push<DebugMenuView>(); } },
|
//{ "Debug", ui::Color::white(), nullptr, [&nav](){ nav.push<DebugMenuView>(); } },
|
||||||
|
197
firmware/application/ui_view_wav.cpp
Normal file
197
firmware/application/ui_view_wav.cpp
Normal file
@ -0,0 +1,197 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||||
|
* Copyright (C) 2017 Furrtek
|
||||||
|
*
|
||||||
|
* This file is part of PortaPack.
|
||||||
|
*
|
||||||
|
* This program 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 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program 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 this program; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ui_view_wav.hpp"
|
||||||
|
#include "ui_fileman.hpp"
|
||||||
|
|
||||||
|
using namespace portapack;
|
||||||
|
|
||||||
|
#include "string_format.hpp"
|
||||||
|
|
||||||
|
namespace ui {
|
||||||
|
|
||||||
|
void ViewWavView::update_scale(int32_t new_scale) {
|
||||||
|
scale = new_scale;
|
||||||
|
ns_per_pixel = (1000000000UL / wav_reader->sample_rate()) * scale;
|
||||||
|
field_pos_samples.set_step(scale);
|
||||||
|
refresh_waveform();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ViewWavView::refresh_waveform() {
|
||||||
|
int16_t sample;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < 240; i++) {
|
||||||
|
wav_reader->data_seek(position + (i * scale));
|
||||||
|
wav_reader->read(&sample, 2);
|
||||||
|
|
||||||
|
waveform_buffer[i] = sample >> 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t span_ns = ns_per_pixel * abs(field_cursor_b.value() - field_cursor_a.value());
|
||||||
|
if (span_ns)
|
||||||
|
text_delta.set(to_string_dec_uint(span_ns / 1000) + "us (" + to_string_dec_uint(1000000000UL / span_ns) + "Hz)");
|
||||||
|
else
|
||||||
|
text_delta.set("0us ?Hz");
|
||||||
|
|
||||||
|
//waveform.set_dirty();
|
||||||
|
|
||||||
|
set_dirty();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ViewWavView::paint(Painter& painter) {
|
||||||
|
// Waveform limits
|
||||||
|
painter.draw_hline({ 0, 6 * 16 - 1 }, 240, Color::grey());
|
||||||
|
painter.draw_hline({ 0, 10 * 16 }, 240, Color::grey());
|
||||||
|
|
||||||
|
// 0~127 to 0~15 color index
|
||||||
|
for (size_t i = 0; i < 240; i++)
|
||||||
|
painter.draw_vline({ (Coord)i, 11 * 16 }, 8, amplitude_colors[amplitude_buffer[i] >> 3]);
|
||||||
|
|
||||||
|
// Window
|
||||||
|
uint64_t w_start = (position * 240) / wav_reader->sample_count();
|
||||||
|
uint64_t w_width = (scale * 240) / (wav_reader->sample_count() / 240);
|
||||||
|
painter.fill_rectangle({ 0, 10 * 16 + 1, 240, 16 }, Color::black());
|
||||||
|
painter.fill_rectangle({ (Coord)w_start, 21 * 8, (Dim)w_width + 1, 8 }, Color::white());
|
||||||
|
display.draw_line({ 0, 10 * 16 + 1 }, { (Coord)w_start, 21 * 8 }, Color::white());
|
||||||
|
display.draw_line({ 239, 10 * 16 + 1 }, { (Coord)(w_start + w_width), 21 * 8 }, Color::white());
|
||||||
|
|
||||||
|
// Cursors
|
||||||
|
painter.fill_rectangle({ 0, 6 * 16 - 8, 240, 7 }, Color::black());
|
||||||
|
painter.draw_vline({ (Coord)field_cursor_a.value(), 11 * 8 }, 7, Color::cyan());
|
||||||
|
painter.draw_vline({ (Coord)field_cursor_b.value(), 11 * 8 }, 7, Color::magenta());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ViewWavView::on_pos_changed() {
|
||||||
|
position = (field_pos_seconds.value() * wav_reader->sample_rate()) + field_pos_samples.value();
|
||||||
|
refresh_waveform();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ViewWavView::load_wav(std::filesystem::path file_path) {
|
||||||
|
int16_t sample;
|
||||||
|
uint32_t average;
|
||||||
|
|
||||||
|
if (!wav_reader->open(file_path)) {
|
||||||
|
nav_.display_modal("Error", "Couldn't open file.", INFO, nullptr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((wav_reader->channels() != 1) || (wav_reader->bits_per_sample() != 16)) {
|
||||||
|
nav_.display_modal("Error", "Wrong format.\nWav viewer only accepts\n16-bit mono files.", INFO, nullptr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
text_filename.set(file_path.filename().string());
|
||||||
|
auto ms_duration = wav_reader->ms_duration();
|
||||||
|
text_duration.set(to_string_dec_uint(ms_duration / 1000) + "s" + to_string_dec_uint(ms_duration % 1000) + "ms");
|
||||||
|
|
||||||
|
wav_reader->rewind();
|
||||||
|
|
||||||
|
text_samplerate.set(to_string_dec_uint(wav_reader->sample_rate()) + "Hz");
|
||||||
|
text_title.set(wav_reader->title());
|
||||||
|
|
||||||
|
// Fill amplitude buffer, world's worst downsampling
|
||||||
|
uint64_t skip = wav_reader->sample_count() / (240 * subsampling_factor);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < 240; i++) {
|
||||||
|
average = 0;
|
||||||
|
|
||||||
|
for (size_t s = 0; s < subsampling_factor; s++) {
|
||||||
|
wav_reader->data_seek(((i * subsampling_factor) + s) * skip);
|
||||||
|
wav_reader->read(&sample, 2);
|
||||||
|
|
||||||
|
if (sample < 0)
|
||||||
|
sample = -sample;
|
||||||
|
|
||||||
|
sample >>= 8;
|
||||||
|
|
||||||
|
average += sample;
|
||||||
|
}
|
||||||
|
|
||||||
|
amplitude_buffer[i] = average / subsampling_factor;
|
||||||
|
}
|
||||||
|
|
||||||
|
reset_controls();
|
||||||
|
update_scale(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ViewWavView::reset_controls() {
|
||||||
|
field_scale.set_value(1);
|
||||||
|
field_scale.on_change = [this](int32_t value) {
|
||||||
|
update_scale(value);
|
||||||
|
};
|
||||||
|
|
||||||
|
field_pos_seconds.set_value(0);
|
||||||
|
field_pos_seconds.on_change = [this](int32_t) {
|
||||||
|
on_pos_changed();
|
||||||
|
};
|
||||||
|
field_pos_samples.set_value(0);
|
||||||
|
field_pos_samples.on_change = [this](int32_t) {
|
||||||
|
on_pos_changed();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
ViewWavView::ViewWavView(
|
||||||
|
NavigationView& nav
|
||||||
|
) : nav_(nav)
|
||||||
|
{
|
||||||
|
wav_reader = std::make_unique<WAVFileReader>();
|
||||||
|
|
||||||
|
add_children({
|
||||||
|
&labels,
|
||||||
|
&text_filename,
|
||||||
|
&text_samplerate,
|
||||||
|
&text_title,
|
||||||
|
&text_duration,
|
||||||
|
&button_open,
|
||||||
|
&waveform,
|
||||||
|
&field_pos_seconds,
|
||||||
|
&field_pos_samples,
|
||||||
|
&field_scale,
|
||||||
|
&field_cursor_a,
|
||||||
|
&field_cursor_b,
|
||||||
|
&text_delta
|
||||||
|
});
|
||||||
|
|
||||||
|
button_open.on_select = [this, &nav](Button&) {
|
||||||
|
auto open_view = nav.push<FileLoadView>();
|
||||||
|
open_view->on_changed = [this](std::filesystem::path file_path) {
|
||||||
|
load_wav(file_path);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
reset_controls();
|
||||||
|
|
||||||
|
field_cursor_a.set_value(0);
|
||||||
|
field_cursor_a.on_change = [this](int32_t) {
|
||||||
|
refresh_waveform();
|
||||||
|
};
|
||||||
|
field_cursor_b.set_value(0);
|
||||||
|
field_cursor_b.on_change = [this](int32_t) {
|
||||||
|
refresh_waveform();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void ViewWavView::focus() {
|
||||||
|
button_open.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* namespace ui */
|
162
firmware/application/ui_view_wav.hpp
Normal file
162
firmware/application/ui_view_wav.hpp
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||||
|
* Copyright (C) 2017 Furrtek
|
||||||
|
*
|
||||||
|
* This file is part of PortaPack.
|
||||||
|
*
|
||||||
|
* This program 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 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program 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 this program; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ui.hpp"
|
||||||
|
#include "ui_navigation.hpp"
|
||||||
|
#include "io_wave.hpp"
|
||||||
|
|
||||||
|
namespace ui {
|
||||||
|
|
||||||
|
class ViewWavView : public View {
|
||||||
|
public:
|
||||||
|
ViewWavView(NavigationView& nav);
|
||||||
|
|
||||||
|
void focus() override;
|
||||||
|
void paint(Painter&) override;
|
||||||
|
|
||||||
|
std::string title() const override { return "WAV viewer"; };
|
||||||
|
|
||||||
|
private:
|
||||||
|
NavigationView& nav_;
|
||||||
|
static constexpr uint32_t subsampling_factor = 8;
|
||||||
|
|
||||||
|
void update_scale(int32_t new_scale);
|
||||||
|
void refresh_waveform();
|
||||||
|
void on_pos_changed();
|
||||||
|
void load_wav(std::filesystem::path file_path);
|
||||||
|
void reset_controls();
|
||||||
|
|
||||||
|
const Color amplitude_colors[16] = {
|
||||||
|
{ 0x00, 0x3F, 0xB0 },
|
||||||
|
{ 0x00, 0x6D, 0xB5 },
|
||||||
|
{ 0x00, 0x9C, 0xBA },
|
||||||
|
{ 0x00, 0xBF, 0xB0 },
|
||||||
|
{ 0x00, 0xC5, 0x86 },
|
||||||
|
{ 0x00, 0xCA, 0x5A },
|
||||||
|
{ 0x00, 0xCF, 0x2A },
|
||||||
|
{ 0x06, 0xD4, 0x00 },
|
||||||
|
{ 0x3A, 0xDA, 0x00 },
|
||||||
|
{ 0x71, 0xDF, 0x00 },
|
||||||
|
{ 0xAA, 0xE4, 0x00 },
|
||||||
|
{ 0xE6, 0xE9, 0x00 },
|
||||||
|
{ 0xEF, 0xB9, 0x00 },
|
||||||
|
{ 0xF4, 0x83, 0x00 },
|
||||||
|
{ 0xF9, 0x4B, 0x00 },
|
||||||
|
{ 0xFF, 0x0F, 0x00 }
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<WAVFileReader> wav_reader { };
|
||||||
|
|
||||||
|
int8_t waveform_buffer[240] { };
|
||||||
|
uint8_t amplitude_buffer[240] { };
|
||||||
|
int32_t scale { 1 };
|
||||||
|
uint64_t ns_per_pixel { };
|
||||||
|
uint64_t position { };
|
||||||
|
|
||||||
|
Labels labels {
|
||||||
|
{ { 0 * 8, 0 * 16 }, "File:", Color::light_grey() },
|
||||||
|
{ { 0 * 8, 1 * 16 }, "Samplerate:", Color::light_grey() },
|
||||||
|
{ { 0 * 8, 2 * 16 }, "Title:", Color::light_grey() },
|
||||||
|
{ { 0 * 8, 3 * 16 }, "Duration:", Color::light_grey() },
|
||||||
|
{ { 0 * 8, 11 * 16 }, "Position: s Scale:", Color::light_grey() },
|
||||||
|
{ { 0 * 8, 12 * 16 }, "Cursor A:", Color::dark_cyan() },
|
||||||
|
{ { 0 * 8, 13 * 16 }, "Cursor B:", Color::dark_magenta() },
|
||||||
|
{ { 0 * 8, 14 * 16 }, "Delta:", Color::light_grey() }
|
||||||
|
};
|
||||||
|
|
||||||
|
Text text_filename {
|
||||||
|
{ 5 * 8, 0 * 16, 12 * 8, 16 },
|
||||||
|
""
|
||||||
|
};
|
||||||
|
Text text_samplerate {
|
||||||
|
{ 11 * 8, 1 * 16, 8 * 8, 16 },
|
||||||
|
""
|
||||||
|
};
|
||||||
|
Text text_title {
|
||||||
|
{ 6 * 8, 2 * 16, 18 * 8, 16 },
|
||||||
|
""
|
||||||
|
};
|
||||||
|
Text text_duration {
|
||||||
|
{ 9 * 8, 3 * 16, 18 * 8, 16 },
|
||||||
|
""
|
||||||
|
};
|
||||||
|
Button button_open {
|
||||||
|
{ 24 * 8, 8, 6 * 8, 2 * 16 },
|
||||||
|
"Open"
|
||||||
|
};
|
||||||
|
|
||||||
|
Waveform waveform {
|
||||||
|
{ 0, 5 * 16, 240, 64 },
|
||||||
|
waveform_buffer,
|
||||||
|
240,
|
||||||
|
0,
|
||||||
|
false,
|
||||||
|
Color::white()
|
||||||
|
};
|
||||||
|
|
||||||
|
NumberField field_pos_seconds {
|
||||||
|
{ 9 * 8, 11 * 16 },
|
||||||
|
3,
|
||||||
|
{ 0, 999 },
|
||||||
|
1,
|
||||||
|
' '
|
||||||
|
};
|
||||||
|
NumberField field_pos_samples {
|
||||||
|
{ 14 * 8, 11 * 16 },
|
||||||
|
6,
|
||||||
|
{ 0, 999999 },
|
||||||
|
1,
|
||||||
|
'0'
|
||||||
|
};
|
||||||
|
NumberField field_scale {
|
||||||
|
{ 28 * 8, 11 * 16 },
|
||||||
|
2,
|
||||||
|
{ 1, 40 },
|
||||||
|
1,
|
||||||
|
' '
|
||||||
|
};
|
||||||
|
|
||||||
|
NumberField field_cursor_a {
|
||||||
|
{ 9 * 8, 12 * 16 },
|
||||||
|
3,
|
||||||
|
{ 0, 239 },
|
||||||
|
1,
|
||||||
|
' ',
|
||||||
|
true
|
||||||
|
};
|
||||||
|
|
||||||
|
NumberField field_cursor_b {
|
||||||
|
{ 9 * 8, 13 * 16 },
|
||||||
|
3,
|
||||||
|
{ 0, 239 },
|
||||||
|
1,
|
||||||
|
' ',
|
||||||
|
true
|
||||||
|
};
|
||||||
|
|
||||||
|
Text text_delta {
|
||||||
|
{ 6 * 8, 14 * 16, 30 * 8, 16 },
|
||||||
|
"-"
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
} /* namespace ui */
|
@ -1236,6 +1236,10 @@ void NumberField::set_range(const int32_t min, const int32_t max) {
|
|||||||
set_value(value(), false);
|
set_value(value(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NumberField::set_step(const int32_t new_step) {
|
||||||
|
step = new_step;
|
||||||
|
}
|
||||||
|
|
||||||
void NumberField::paint(Painter& painter) {
|
void NumberField::paint(Painter& painter) {
|
||||||
const auto text = to_string_dec_int(value_, length_, fill_char);
|
const auto text = to_string_dec_int(value_, length_, fill_char);
|
||||||
|
|
||||||
|
@ -535,6 +535,7 @@ public:
|
|||||||
int32_t value() const;
|
int32_t value() const;
|
||||||
void set_value(int32_t new_value, bool trigger_change = true);
|
void set_value(int32_t new_value, bool trigger_change = true);
|
||||||
void set_range(const int32_t min, const int32_t max);
|
void set_range(const int32_t min, const int32_t max);
|
||||||
|
void set_step(const int32_t new_step);
|
||||||
|
|
||||||
void paint(Painter& painter) override;
|
void paint(Painter& painter) override;
|
||||||
|
|
||||||
@ -544,7 +545,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
range_t range;
|
range_t range;
|
||||||
const int32_t step;
|
int32_t step;
|
||||||
const int length_;
|
const int length_;
|
||||||
const char fill_char;
|
const char fill_char;
|
||||||
int32_t value_ { 0 };
|
int32_t value_ { 0 };
|
||||||
|
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user