Skip to content

Commit

Permalink
add tuner app (#2429)
Browse files Browse the repository at this point in the history
* _

* icon
  • Loading branch information
zxkmm authored Dec 18, 2024
1 parent fff63e0 commit ead9449
Show file tree
Hide file tree
Showing 6 changed files with 499 additions and 4 deletions.
8 changes: 6 additions & 2 deletions firmware/application/external/external.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -134,11 +134,14 @@ set(EXTCPPSRC
#mcu_temperature
external/mcu_temperature/main.cpp
external/mcu_temperature/mcu_temperature.cpp


#fmradio
external/fmradio/main.cpp
external/fmradio/ui_fmradio.cpp

#tuner
external/tuner/main.cpp
external/tuner/ui_tuner.cpp
)

set(EXTAPPLIST
Expand Down Expand Up @@ -172,7 +175,8 @@ set(EXTAPPLIST
ook_editor
shoppingcart_lock
flippertx
remote
remote
mcu_temperature
fmradio
tuner
)
11 changes: 9 additions & 2 deletions firmware/application/external/external.ld
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ MEMORY
ram_external_app_ook_editor(rwx) : org = 0xADCE0000, len = 32k
ram_external_app_remote(rwx) : org = 0xADCF0000, len = 32k
ram_external_app_mcu_temperature(rwx) : org = 0xADD00000, len = 32k
ram_external_app_fmradio(rwx) : org = 0xADE00000, len = 32k
ram_external_app_fmradio(rwx) : org = 0xADD10000, len = 32k
ram_external_app_tuner(rwx) : org = 0xADD20000, len = 32k

}

SECTIONS
Expand Down Expand Up @@ -252,11 +254,16 @@ SECTIONS
KEEP(*(.external_app.app_mcu_temperature.application_information));
*(*ui*external_app*mcu_temperature*);
} > ram_external_app_mcu_temperature


.external_app_fmradio : ALIGN(4) SUBALIGN(4)
{
KEEP(*(.external_app.app_fmradio.application_information));
*(*ui*external_app*fmradio*);
} > ram_external_app_fmradio

.external_app_tuner : ALIGN(4) SUBALIGN(4)
{
KEEP(*(.external_app.app_tuner.application_information));
*(*ui*external_app*tuner*);
} > ram_external_app_tuner
}
83 changes: 83 additions & 0 deletions firmware/application/external/tuner/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* Copyright (C) 2024 Bernd
*
* 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_tuner.hpp"
#include "ui_navigation.hpp"
#include "external_app.hpp"

namespace ui::external_app::tuner {
void initialize_app(ui::NavigationView& nav) {
nav.push<TunerView>();
}
} // namespace ui::external_app::tuner

extern "C" {

__attribute__((section(".external_app.app_tuner.application_information"), used)) application_information_t _application_information_tuner = {
/*.memory_location = */ (uint8_t*)0x00000000,
/*.externalAppEntry = */ ui::external_app::tuner::initialize_app,
/*.header_version = */ CURRENT_HEADER_VERSION,
/*.app_version = */ VERSION_MD5,

/*.app_name = */ "Tuner",
/*.bitmap_data = */ {
0x00,
0x00,
0x00,
0x00,
0x22,
0x44,
0x21,
0x84,
0x2D,
0xB4,
0x25,
0xA4,
0x25,
0xA4,
0x2D,
0xB4,
0x61,
0x86,
0xC2,
0x43,
0x80,
0x01,
0x80,
0x01,
0x80,
0x01,
0x80,
0x01,
0x00,
0x00,
0x00,
0x00,
},
/*.icon_color = */ ui::Color::cyan().v,
/*.menu_location = */ app_location_t::UTILITIES,
/*.desired_menu_position = */ -1,

/*.m4_app_tag = portapack::spi_flash::image_tag_none */ {'P', 'A', 'B', 'P'},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
};
}
256 changes: 256 additions & 0 deletions firmware/application/external/tuner/ui_tuner.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
/*
* copyleft 2024 sommermorgentraum
*
* 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_tuner.hpp"
#include "baseband_api.hpp"
#include "audio.hpp"
#include "portapack.hpp"

using namespace portapack;

namespace ui::external_app::tuner {

TunerView::TunerView(NavigationView& nav)
: nav_{nav} {
baseband::run_prepared_image(portapack::memory::map::m4_code.base()); // proc_audio_beep baseband is external too

add_children({
&labels,
&field_volume,
&options_instrument,
&options_note,
&button_play_stop,
&text_note_frequency,
&text_note_octave_shift,
});

audio::set_rate(audio::Rate::Hz_24000);

options_instrument.on_change = [this](size_t, int32_t value) {
const Instrument* selected_instrument = nullptr;

switch (value) {
case 0:
selected_instrument = &guitar;
break;
case 1:
selected_instrument = &violin;
break;
case 2:
selected_instrument = &pitch_fork;
break;
}

if (selected_instrument) {
update_notes_for_instrument(*selected_instrument);
}

update_current_note();
};

options_note.on_change = [this](size_t, int32_t index) {
const Instrument* current_instrument = nullptr;
switch (options_instrument.selected_index_value()) {
case 0:
current_instrument = &guitar;
break;
case 1:
current_instrument = &violin;
break;
case 2:
current_instrument = &pitch_fork;
break;
}

if (current_instrument) {
auto it = current_instrument->notes.begin();
std::advance(it, index);
if (it != current_instrument->notes.end()) {
current_note_frequency = it->second.frequency;
current_note_sample_rate = it->second.sample_rate;
current_note_octave_shift = it->second.octave_shift;
}
}

update_current_note();
};

button_play_stop.on_select = [this]() {
if (current_note_playing) {
stop_play();
} else {
play_change_note();
}
};

options_instrument.set_selected_index(0);
update_notes_for_instrument(guitar);
update_current_note();

field_volume.set_value(0); // seems that a change is required to force update, so setting to 0 first
field_volume.set_value(99);

audio::set_rate(audio::Rate::Hz_24000);
audio::output::start();
}

TunerView::~TunerView() {
receiver_model.disable();
baseband::shutdown();
audio::output::stop();
}

void TunerView::focus() {
options_instrument.focus();
}

void TunerView::update_notes_for_instrument(const Instrument& instrument) {
std::vector<OptionsField::option_t> note_options;
size_t index = 0;

for (const auto& note_pair : instrument.notes) {
note_options.emplace_back(OptionsField::option_t{
note_pair.first,
index++});
}

options_note.set_options(note_options);
if (!note_options.empty()) {
options_note.set_selected_index(0);
}
}

void TunerView::update_current_note() {
const Instrument* current_instrument = nullptr;

switch (options_instrument.selected_index_value()) {
case 0:
current_instrument = &guitar;
break;
case 1:
current_instrument = &violin;
break;
case 2:
current_instrument = &pitch_fork;
break;
}

if (current_instrument) {
std::string note_name = options_note.selected_index_name();

// map
auto note_it = current_instrument->notes.find(note_name);
if (note_it != current_instrument->notes.end()) {
current_note_frequency = note_it->second.frequency;
current_note_sample_rate = note_it->second.sample_rate;
current_note_octave_shift = note_it->second.octave_shift;

text_note_frequency.set(std::to_string(current_note_frequency));
text_note_octave_shift.set(std::to_string(current_note_octave_shift));

set_dirty();

if (current_note_playing) {
play_change_note();
}
}
}
}

void TunerView::stop_play() {
baseband::request_beep_stop();
current_note_playing = false;
button_play_stop.set_bitmap(&bitmap_icon_replay);
}

void TunerView::play_change_note() {
if (current_note_playing) {
baseband::request_beep_stop();
audio::set_rate(current_note_sample_rate);
baseband::request_audio_beep(current_note_frequency, protected_sample_rate(current_note_sample_rate), 0);
} else {
audio::set_rate(current_note_sample_rate);
baseband::request_audio_beep(current_note_frequency, protected_sample_rate(current_note_sample_rate), 0);
}
current_note_playing = true;
button_play_stop.set_bitmap(&bitmap_icon_sleep);
set_dirty();
}

uint32_t TunerView::protected_sample_rate(audio::Rate r) {
switch (r) {
case audio::Rate::Hz_12000:
return 12000;
case audio::Rate::Hz_24000:
return 24000;
case audio::Rate::Hz_48000:
return 48000;
default:
return 24000;
}
}

void TunerView::paint(Painter& painter) {
View::paint(painter);

painter.fill_rectangle(
{screen_width / 4, 8 * 16, screen_width / 2, 6 * 16},
Theme::getInstance()->bg_darkest->background);

if (!current_note_playing) return;

painter.fill_rectangle(
{screen_width / 4, 10 * 16, 2, 2 * 16},
Theme::getInstance()->fg_light->foreground);

painter.fill_rectangle(
{screen_width / 4, 12 * 16, screen_width / 4 * 2 + 2, 2},
Theme::getInstance()->fg_light->foreground);

painter.fill_rectangle(
{(screen_width / 4) * 3, 10 * 16, 2, 2 * 16},
Theme::getInstance()->fg_light->foreground);

painter.draw_string(
{screen_width / 4 - 2 * 8, 8 * 16},
(current_note_octave_shift == 0) ? *Theme::getInstance()->bg_darkest : *Theme::getInstance()->fg_red,
std::to_string(current_note_frequency));

int16_t real_frequency = current_note_frequency;
if (current_note_octave_shift > 0) {
for (int i = 0; i < current_note_octave_shift; i++) {
real_frequency *= 2;
}
} else if (current_note_octave_shift < 0) {
for (int i = 0; i > current_note_octave_shift; i--) {
real_frequency /= 2;
}
}
painter.draw_string({(screen_width / 4) * 3 - 2 * 8, 8 * 16},
(current_note_octave_shift == 0) ? *Theme::getInstance()->bg_darkest : *Theme::getInstance()->fg_red,
std::to_string(real_frequency));

painter.draw_string({screen_width / 2 - 3 * 16, 13 * 16},
(current_note_octave_shift == 0) ? *Theme::getInstance()->bg_darkest : *Theme::getInstance()->fg_red,
std::to_string(current_note_octave_shift) + " * 8ev");
}

} // namespace ui::external_app::tuner
Loading

0 comments on commit ead9449

Please sign in to comment.