1
mirror of https://github.com/DarkFlippers/unleashed-firmware.git synced 2025-12-13 13:09:49 +04:00

add wav player & music player icon

This commit is contained in:
Eng1n33r
2022-06-01 19:00:39 +03:00
parent e6d17b15ed
commit 141ee92065
11 changed files with 803 additions and 1 deletions

View File

@@ -21,6 +21,7 @@ extern int32_t accessor_app(void* p);
extern int32_t archive_app(void* p); extern int32_t archive_app(void* p);
extern int32_t bad_usb_app(void* p); extern int32_t bad_usb_app(void* p);
extern int32_t u2f_app(void* p); extern int32_t u2f_app(void* p);
extern int32_t wav_player_app(void* p);
extern int32_t uart_echo_app(void* p); extern int32_t uart_echo_app(void* p);
extern int32_t blink_test_app(void* p); extern int32_t blink_test_app(void* p);
extern int32_t bt_debug_app(void* p); extern int32_t bt_debug_app(void* p);
@@ -339,7 +340,7 @@ const FlipperApplication FLIPPER_PLUGINS[] = {
{.app = music_player_app, {.app = music_player_app,
.name = "Music Player", .name = "Music Player",
.stack_size = 2048, .stack_size = 2048,
.icon = &A_Plugins_14, .icon = &A_MusicPlayer_14,
.flags = FlipperApplicationFlagDefault}, .flags = FlipperApplicationFlagDefault},
#endif #endif
@@ -350,6 +351,15 @@ const FlipperApplication FLIPPER_PLUGINS[] = {
.icon = &A_Plugins_14, .icon = &A_Plugins_14,
.flags = FlipperApplicationFlagDefault}, .flags = FlipperApplicationFlagDefault},
#endif #endif
#ifdef APP_WAV_PLAYER
{.app = wav_player_app,
.name = "WAV Player",
.stack_size = 4096,
.icon = &A_MusicPlayer_14,
.flags = FlipperApplicationFlagDefault},
#endif
}; };
const size_t FLIPPER_PLUGINS_COUNT = COUNT_OF(FLIPPER_PLUGINS); const size_t FLIPPER_PLUGINS_COUNT = COUNT_OF(FLIPPER_PLUGINS);

View File

@@ -47,6 +47,7 @@ APP_UPDATER = 1
# Plugins # Plugins
APP_MUSIC_PLAYER = 1 APP_MUSIC_PLAYER = 1
APP_SNAKE_GAME = 1 APP_SNAKE_GAME = 1
APP_WAV_PLAYER = 1
# Debug # Debug
APP_ACCESSOR = 1 APP_ACCESSOR = 1
@@ -240,6 +241,13 @@ CFLAGS += -DAPP_SNAKE_GAME
SRV_GUI = 1 SRV_GUI = 1
endif endif
APP_WAV_PLAYER ?= 0
ifeq ($(APP_WAV_PLAYER), 1)
CFLAGS += -DAPP_WAV_PLAYER
SRV_GUI = 1
endif
APP_IBUTTON ?= 0 APP_IBUTTON ?= 0
ifeq ($(APP_IBUTTON), 1) ifeq ($(APP_IBUTTON), 1)
CFLAGS += -DAPP_IBUTTON CFLAGS += -DAPP_IBUTTON

View File

@@ -0,0 +1,84 @@
#include "wav_parser.h"
#define TAG "WavParser"
const char* format_text(FormatTag tag) {
switch(tag) {
case FormatTagPCM:
return "PCM";
case FormatTagIEEE_FLOAT:
return "IEEE FLOAT";
default:
return "Unknown";
}
};
struct WavParser {
WavHeaderChunk header;
WavFormatChunk format;
WavDataChunk data;
size_t wav_data_start;
size_t wav_data_end;
};
WavParser* wav_parser_alloc() {
return malloc(sizeof(WavParser));
}
void wav_parser_free(WavParser* parser) {
free(parser);
}
bool wav_parser_parse(WavParser* parser, Stream* stream) {
stream_read(stream, (uint8_t*)&parser->header, sizeof(WavHeaderChunk));
stream_read(stream, (uint8_t*)&parser->format, sizeof(WavFormatChunk));
stream_read(stream, (uint8_t*)&parser->data, sizeof(WavDataChunk));
if(memcmp(parser->header.riff, "RIFF", 4) != 0 ||
memcmp(parser->header.wave, "WAVE", 4) != 0) {
FURI_LOG_E(TAG, "WAV: wrong header");
return false;
}
if(memcmp(parser->format.fmt, "fmt ", 4) != 0) {
FURI_LOG_E(TAG, "WAV: wrong format");
return false;
}
if(parser->format.tag != FormatTagPCM || memcmp(parser->data.data, "data", 4) != 0) {
FURI_LOG_E(
TAG,
"WAV: non-PCM format %u, next '%lu'",
parser->format.tag,
(uint32_t)parser->data.data);
return false;
}
FURI_LOG_I(
TAG,
"Format tag: %s, ch: %u, smplrate: %lu, bps: %lu, bits: %u",
format_text(parser->format.tag),
parser->format.channels,
parser->format.sample_rate,
parser->format.byte_per_sec,
parser->format.bits_per_sample);
parser->wav_data_start = stream_tell(stream);
parser->wav_data_end = parser->wav_data_start + parser->data.size;
FURI_LOG_I(TAG, "data: %u - %u", parser->wav_data_start, parser->wav_data_end);
return true;
}
size_t wav_parser_get_data_start(WavParser* parser) {
return parser->wav_data_start;
}
size_t wav_parser_get_data_end(WavParser* parser) {
return parser->wav_data_end;
}
size_t wav_parser_get_data_len(WavParser* parser) {
return parser->wav_data_end - parser->wav_data_start;
}

View File

@@ -0,0 +1,51 @@
#pragma once
#include <toolbox/stream/stream.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
FormatTagPCM = 0x0001,
FormatTagIEEE_FLOAT = 0x0003,
} FormatTag;
typedef struct {
uint8_t riff[4];
uint32_t size;
uint8_t wave[4];
} WavHeaderChunk;
typedef struct {
uint8_t fmt[4];
uint32_t size;
uint16_t tag;
uint16_t channels;
uint32_t sample_rate;
uint32_t byte_per_sec;
uint16_t block_align;
uint16_t bits_per_sample;
} WavFormatChunk;
typedef struct {
uint8_t data[4];
uint32_t size;
} WavDataChunk;
typedef struct WavParser WavParser;
WavParser* wav_parser_alloc();
void wav_parser_free(WavParser* parser);
bool wav_parser_parse(WavParser* parser, Stream* stream);
size_t wav_parser_get_data_start(WavParser* parser);
size_t wav_parser_get_data_end(WavParser* parser);
size_t wav_parser_get_data_len(WavParser* parser);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,301 @@
#include <furi.h>
#include <furi_hal.h>
#include <cli/cli.h>
#include <gui/gui.h>
#include <stm32wbxx_ll_dma.h>
#include <dialogs/dialogs.h>
#include <notification/notification_messages.h>
#include <gui/view_dispatcher.h>
#include <toolbox/stream/file_stream.h>
#include "wav_player_hal.h"
#include "wav_parser.h"
#include "wav_player_view.h"
#define TAG "WavPlayer"
static bool open_wav_stream(Storage* storage, Stream* stream) {
DialogsApp* dialogs = furi_record_open("dialogs");
bool result = false;
string_t path;
string_init(path);
string_set_str(path, "/ext/wav_player");
bool ret =
dialog_file_browser_show(dialogs, path, path, ".wav",
true,
&I_music_10px,
false);
furi_record_close("dialogs");
if(ret) {
if(!file_stream_open(stream, string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) {
FURI_LOG_E(TAG, "Cannot open file \"%s\"", string_get_cstr(path));
} else {
result = true;
}
}
string_clear(path);
return result;
}
typedef enum {
WavPlayerEventHalfTransfer,
WavPlayerEventFullTransfer,
WavPlayerEventCtrlVolUp,
WavPlayerEventCtrlVolDn,
WavPlayerEventCtrlMoveL,
WavPlayerEventCtrlMoveR,
WavPlayerEventCtrlOk,
WavPlayerEventCtrlBack,
} WavPlayerEventType;
typedef struct {
WavPlayerEventType type;
} WavPlayerEvent;
static void wav_player_dma_isr(void* ctx) {
osMessageQueueId_t event_queue = ctx;
// half of transfer
if(LL_DMA_IsActiveFlag_HT1(DMA1)) {
LL_DMA_ClearFlag_HT1(DMA1);
// fill first half of buffer
WavPlayerEvent event = {.type = WavPlayerEventHalfTransfer};
osMessageQueuePut(event_queue, &event, 0, 0);
}
// transfer complete
if(LL_DMA_IsActiveFlag_TC1(DMA1)) {
LL_DMA_ClearFlag_TC1(DMA1);
// fill second half of buffer
WavPlayerEvent event = {.type = WavPlayerEventFullTransfer};
osMessageQueuePut(event_queue, &event, 0, 0);
}
}
typedef struct {
Storage* storage;
Stream* stream;
WavParser* parser;
uint16_t* sample_buffer;
uint8_t* tmp_buffer;
size_t samples_count_half;
size_t samples_count;
osMessageQueueId_t queue;
float volume;
bool play;
WavPlayerView* view;
ViewDispatcher* view_dispatcher;
Gui* gui;
NotificationApp* notification;
} WavPlayerApp;
static WavPlayerApp* app_alloc() {
WavPlayerApp* app = malloc(sizeof(WavPlayerApp));
app->samples_count_half = 1024 * 4;
app->samples_count = app->samples_count_half * 2;
app->storage = furi_record_open("storage");
app->stream = file_stream_alloc(app->storage);
app->parser = wav_parser_alloc();
app->sample_buffer = malloc(sizeof(uint16_t) * app->samples_count);
app->tmp_buffer = malloc(sizeof(uint8_t) * app->samples_count);
app->queue = osMessageQueueNew(10, sizeof(WavPlayerEvent), NULL);
app->volume = 10.0f;
app->play = true;
app->gui = furi_record_open("gui");
app->view_dispatcher = view_dispatcher_alloc();
app->view = wav_player_view_alloc();
view_dispatcher_add_view(app->view_dispatcher, 0, wav_player_view_get_view(app->view));
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
view_dispatcher_switch_to_view(app->view_dispatcher, 0);
app->notification = furi_record_open("notification");
notification_message(app->notification, &sequence_display_backlight_enforce_on);
return app;
}
static void app_free(WavPlayerApp* app) {
view_dispatcher_remove_view(app->view_dispatcher, 0);
view_dispatcher_free(app->view_dispatcher);
wav_player_view_free(app->view);
furi_record_close("gui");
osMessageQueueDelete(app->queue);
free(app->tmp_buffer);
free(app->sample_buffer);
wav_parser_free(app->parser);
stream_free(app->stream);
furi_record_close("storage");
notification_message(app->notification, &sequence_display_backlight_enforce_auto);
furi_record_close("notification");
free(app);
}
// TODO: that works only with 8-bit 2ch audio
static bool fill_data(WavPlayerApp* app, size_t index) {
uint16_t* sample_buffer_start = &app->sample_buffer[index];
size_t count = stream_read(app->stream, app->tmp_buffer, app->samples_count);
for(size_t i = count; i < app->samples_count; i++) {
app->tmp_buffer[i] = 0;
}
for(size_t i = 0; i < app->samples_count; i += 2) {
float data = app->tmp_buffer[i];
data -= UINT8_MAX / 2; // to signed
data /= UINT8_MAX / 2; // scale -1..1
data *= app->volume; // volume
data = tanhf(data); // hyperbolic tangent limiter
data *= UINT8_MAX / 2; // scale -128..127
data += UINT8_MAX / 2; // to unsigned
if(data < 0) {
data = 0;
}
if(data > 255) {
data = 255;
}
sample_buffer_start[i / 2] = data;
}
wav_player_view_set_data(app->view, sample_buffer_start, app->samples_count_half);
return count != app->samples_count;
}
static void ctrl_callback(WavPlayerCtrl ctrl, void* ctx) {
osMessageQueueId_t event_queue = ctx;
WavPlayerEvent event;
switch(ctrl) {
case WavPlayerCtrlVolUp:
event.type = WavPlayerEventCtrlVolUp;
osMessageQueuePut(event_queue, &event, 0, 0);
break;
case WavPlayerCtrlVolDn:
event.type = WavPlayerEventCtrlVolDn;
osMessageQueuePut(event_queue, &event, 0, 0);
break;
case WavPlayerCtrlMoveL:
event.type = WavPlayerEventCtrlMoveL;
osMessageQueuePut(event_queue, &event, 0, 0);
break;
case WavPlayerCtrlMoveR:
event.type = WavPlayerEventCtrlMoveR;
osMessageQueuePut(event_queue, &event, 0, 0);
break;
case WavPlayerCtrlOk:
event.type = WavPlayerEventCtrlOk;
osMessageQueuePut(event_queue, &event, 0, 0);
break;
case WavPlayerCtrlBack:
event.type = WavPlayerEventCtrlBack;
osMessageQueuePut(event_queue, &event, 0, 0);
break;
default:
break;
}
}
static void app_run(WavPlayerApp* app) {
if(!open_wav_stream(app->storage, app->stream)) return;
if(!wav_parser_parse(app->parser, app->stream)) return;
wav_player_view_set_volume(app->view, app->volume);
wav_player_view_set_start(app->view, wav_parser_get_data_start(app->parser));
wav_player_view_set_current(app->view, stream_tell(app->stream));
wav_player_view_set_end(app->view, wav_parser_get_data_end(app->parser));
wav_player_view_set_play(app->view, app->play);
wav_player_view_set_context(app->view, app->queue);
wav_player_view_set_ctrl_callback(app->view, ctrl_callback);
bool eof = fill_data(app, 0);
eof = fill_data(app, app->samples_count_half);
wav_player_speaker_init();
wav_player_dma_init((uint32_t)app->sample_buffer, app->samples_count);
furi_hal_interrupt_set_isr(FuriHalInterruptIdDma1Ch1, wav_player_dma_isr, app->queue);
wav_player_dma_start();
wav_player_speaker_start();
WavPlayerEvent event;
while(1) {
if(osMessageQueueGet(app->queue, &event, NULL, osWaitForever) == osOK) {
if(event.type == WavPlayerEventHalfTransfer) {
eof = fill_data(app, 0);
wav_player_view_set_current(app->view, stream_tell(app->stream));
if(eof) {
stream_seek(
app->stream,
wav_parser_get_data_start(app->parser),
StreamOffsetFromStart);
}
} else if(event.type == WavPlayerEventFullTransfer) {
eof = fill_data(app, app->samples_count_half);
wav_player_view_set_current(app->view, stream_tell(app->stream));
if(eof) {
stream_seek(
app->stream,
wav_parser_get_data_start(app->parser),
StreamOffsetFromStart);
}
} else if(event.type == WavPlayerEventCtrlVolUp) {
if(app->volume < 9.9) app->volume += 0.2;
wav_player_view_set_volume(app->view, app->volume);
} else if(event.type == WavPlayerEventCtrlVolDn) {
if(app->volume > 0.01) app->volume -= 0.2;
wav_player_view_set_volume(app->view, app->volume);
} else if(event.type == WavPlayerEventCtrlMoveL) {
int32_t seek = stream_tell(app->stream) - wav_parser_get_data_start(app->parser);
seek = MIN(seek, wav_parser_get_data_len(app->parser) / 100);
stream_seek(app->stream, -seek, StreamOffsetFromCurrent);
wav_player_view_set_current(app->view, stream_tell(app->stream));
} else if(event.type == WavPlayerEventCtrlMoveR) {
int32_t seek = wav_parser_get_data_end(app->parser) - stream_tell(app->stream);
seek = MIN(seek, wav_parser_get_data_len(app->parser) / 100);
stream_seek(app->stream, seek, StreamOffsetFromCurrent);
wav_player_view_set_current(app->view, stream_tell(app->stream));
} else if(event.type == WavPlayerEventCtrlOk) {
app->play = !app->play;
wav_player_view_set_play(app->view, app->play);
if(!app->play) {
wav_player_speaker_stop();
} else {
wav_player_speaker_start();
}
} else if(event.type == WavPlayerEventCtrlBack) {
break;
}
}
}
wav_player_speaker_stop();
wav_player_dma_stop();
furi_hal_interrupt_set_isr(FuriHalInterruptIdDma1Ch1, NULL, NULL);
}
int32_t wav_player_app(void* p) {
WavPlayerApp* app = app_alloc();
app_run(app);
app_free(app);
return 0;
}

View File

@@ -0,0 +1,58 @@
#include "wav_player_hal.h"
#include <stm32wbxx_ll_tim.h>
#include <stm32wbxx_ll_dma.h>
#define FURI_HAL_SPEAKER_TIMER TIM16
#define FURI_HAL_SPEAKER_CHANNEL LL_TIM_CHANNEL_CH1
#define DMA_INSTANCE DMA1, LL_DMA_CHANNEL_1
void wav_player_speaker_init() {
LL_TIM_InitTypeDef TIM_InitStruct = {0};
TIM_InitStruct.Prescaler = 4;
TIM_InitStruct.Autoreload = 255;
LL_TIM_Init(FURI_HAL_SPEAKER_TIMER, &TIM_InitStruct);
LL_TIM_OC_InitTypeDef TIM_OC_InitStruct = {0};
TIM_OC_InitStruct.OCMode = LL_TIM_OCMODE_PWM1;
TIM_OC_InitStruct.OCState = LL_TIM_OCSTATE_ENABLE;
TIM_OC_InitStruct.CompareValue = 127;
LL_TIM_OC_Init(FURI_HAL_SPEAKER_TIMER, FURI_HAL_SPEAKER_CHANNEL, &TIM_OC_InitStruct);
}
void wav_player_speaker_start() {
LL_TIM_EnableAllOutputs(FURI_HAL_SPEAKER_TIMER);
LL_TIM_EnableCounter(FURI_HAL_SPEAKER_TIMER);
}
void wav_player_speaker_stop() {
LL_TIM_DisableAllOutputs(FURI_HAL_SPEAKER_TIMER);
LL_TIM_DisableCounter(FURI_HAL_SPEAKER_TIMER);
}
void wav_player_dma_init(uint32_t address, size_t size) {
uint32_t dma_dst = (uint32_t) & (FURI_HAL_SPEAKER_TIMER->CCR1);
LL_DMA_ConfigAddresses(DMA_INSTANCE, address, dma_dst, LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
LL_DMA_SetDataLength(DMA_INSTANCE, size);
LL_DMA_SetPeriphRequest(DMA_INSTANCE, LL_DMAMUX_REQ_TIM16_UP);
LL_DMA_SetDataTransferDirection(DMA_INSTANCE, LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
LL_DMA_SetChannelPriorityLevel(DMA_INSTANCE, LL_DMA_PRIORITY_VERYHIGH);
LL_DMA_SetMode(DMA_INSTANCE, LL_DMA_MODE_CIRCULAR);
LL_DMA_SetPeriphIncMode(DMA_INSTANCE, LL_DMA_PERIPH_NOINCREMENT);
LL_DMA_SetMemoryIncMode(DMA_INSTANCE, LL_DMA_MEMORY_INCREMENT);
LL_DMA_SetPeriphSize(DMA_INSTANCE, LL_DMA_PDATAALIGN_HALFWORD);
LL_DMA_SetMemorySize(DMA_INSTANCE, LL_DMA_MDATAALIGN_HALFWORD);
LL_DMA_EnableIT_TC(DMA_INSTANCE);
LL_DMA_EnableIT_HT(DMA_INSTANCE);
}
void wav_player_dma_start() {
LL_DMA_EnableChannel(DMA_INSTANCE);
LL_TIM_EnableDMAReq_UPDATE(FURI_HAL_SPEAKER_TIMER);
}
void wav_player_dma_stop() {
LL_DMA_DisableChannel(DMA_INSTANCE);
}

View File

@@ -0,0 +1,23 @@
#pragma once
#include <stdint.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
void wav_player_speaker_init();
void wav_player_speaker_start();
void wav_player_speaker_stop();
void wav_player_dma_init(uint32_t address, size_t size);
void wav_player_dma_start();
void wav_player_dma_stop();
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,214 @@
#include "wav_player_view.h"
#define DATA_COUNT 116
struct WavPlayerView {
View* view;
WavPlayerCtrlCallback callback;
void* context;
};
typedef struct {
bool play;
float volume;
size_t start;
size_t end;
size_t current;
uint8_t data[DATA_COUNT];
} WavPlayerViewModel;
float map(float x, float in_min, float in_max, float out_min, float out_max) {
return (x - in_min) * (out_max - out_min + 1) / (in_max - in_min + 1) + out_min;
}
static void wav_player_view_draw_callback(Canvas* canvas, void* _model) {
WavPlayerViewModel* model = _model;
canvas_clear(canvas);
canvas_set_color(canvas, ColorBlack);
uint8_t x_pos = 0;
uint8_t y_pos = 0;
// volume
x_pos = 124;
y_pos = 0;
const float volume = (64 / 10.0f) * model->volume;
canvas_draw_frame(canvas, x_pos, y_pos, 4, 64);
canvas_draw_box(canvas, x_pos, y_pos + (64 - volume), 4, volume);
// play / pause
x_pos = 58;
y_pos = 55;
if(model->play) {
canvas_draw_line(canvas, x_pos, y_pos, x_pos + 8, y_pos + 4);
canvas_draw_line(canvas, x_pos, y_pos + 8, x_pos + 8, y_pos + 4);
canvas_draw_line(canvas, x_pos, y_pos + 8, x_pos, y_pos);
} else {
canvas_draw_box(canvas, x_pos, y_pos, 3, 9);
canvas_draw_box(canvas, x_pos + 4, y_pos, 3, 9);
}
x_pos = 78;
y_pos = 55;
canvas_draw_line(canvas, x_pos, y_pos, x_pos + 4, y_pos + 4);
canvas_draw_line(canvas, x_pos, y_pos + 8, x_pos + 4, y_pos + 4);
canvas_draw_line(canvas, x_pos, y_pos + 8, x_pos, y_pos);
x_pos = 82;
y_pos = 55;
canvas_draw_line(canvas, x_pos, y_pos, x_pos + 4, y_pos + 4);
canvas_draw_line(canvas, x_pos, y_pos + 8, x_pos + 4, y_pos + 4);
canvas_draw_line(canvas, x_pos, y_pos + 8, x_pos, y_pos);
x_pos = 40;
y_pos = 55;
canvas_draw_line(canvas, x_pos, y_pos, x_pos - 4, y_pos + 4);
canvas_draw_line(canvas, x_pos, y_pos + 8, x_pos - 4, y_pos + 4);
canvas_draw_line(canvas, x_pos, y_pos + 8, x_pos, y_pos);
x_pos = 44;
y_pos = 55;
canvas_draw_line(canvas, x_pos, y_pos, x_pos - 4, y_pos + 4);
canvas_draw_line(canvas, x_pos, y_pos + 8, x_pos - 4, y_pos + 4);
canvas_draw_line(canvas, x_pos, y_pos + 8, x_pos, y_pos);
// len
x_pos = 4;
y_pos = 47;
const uint8_t play_len = 116;
uint8_t play_pos = map(model->current, model->start, model->end, 0, play_len - 4);
canvas_draw_frame(canvas, x_pos, y_pos, play_len, 4);
canvas_draw_box(canvas, x_pos + play_pos, y_pos - 2, 4, 8);
canvas_draw_box(canvas, x_pos, y_pos, play_pos, 4);
// osc
x_pos = 4;
y_pos = 0;
for(size_t i = 1; i < DATA_COUNT; i++) {
canvas_draw_line(canvas, x_pos + i - 1, model->data[i - 1], x_pos + i, model->data[i]);
}
}
static bool wav_player_view_input_callback(InputEvent* event, void* context) {
WavPlayerView* wav_player_view = context;
bool consumed = false;
if(wav_player_view->callback) {
if(event->type == InputTypeShort || event->type == InputTypeRepeat) {
if(event->key == InputKeyUp) {
wav_player_view->callback(WavPlayerCtrlVolUp, wav_player_view->context);
consumed = true;
} else if(event->key == InputKeyDown) {
wav_player_view->callback(WavPlayerCtrlVolDn, wav_player_view->context);
consumed = true;
} else if(event->key == InputKeyLeft) {
wav_player_view->callback(WavPlayerCtrlMoveL, wav_player_view->context);
consumed = true;
} else if(event->key == InputKeyRight) {
wav_player_view->callback(WavPlayerCtrlMoveR, wav_player_view->context);
consumed = true;
} else if(event->key == InputKeyOk) {
wav_player_view->callback(WavPlayerCtrlOk, wav_player_view->context);
consumed = true;
} else if(event->key == InputKeyBack) {
wav_player_view->callback(WavPlayerCtrlBack, wav_player_view->context);
consumed = true;
}
}
}
return consumed;
}
WavPlayerView* wav_player_view_alloc() {
WavPlayerView* wav_view = malloc(sizeof(WavPlayerView));
wav_view->view = view_alloc();
view_set_context(wav_view->view, wav_view);
view_allocate_model(wav_view->view, ViewModelTypeLocking, sizeof(WavPlayerViewModel));
view_set_draw_callback(wav_view->view, wav_player_view_draw_callback);
view_set_input_callback(wav_view->view, wav_player_view_input_callback);
return wav_view;
}
void wav_player_view_free(WavPlayerView* wav_view) {
furi_assert(wav_view);
view_free(wav_view->view);
free(wav_view);
}
View* wav_player_view_get_view(WavPlayerView* wav_view) {
furi_assert(wav_view);
return wav_view->view;
}
void wav_player_view_set_volume(WavPlayerView* wav_view, float volume) {
furi_assert(wav_view);
with_view_model(
wav_view->view, (WavPlayerViewModel * model) {
model->volume = volume;
return true;
});
}
void wav_player_view_set_start(WavPlayerView* wav_view, size_t start) {
furi_assert(wav_view);
with_view_model(
wav_view->view, (WavPlayerViewModel * model) {
model->start = start;
return true;
});
}
void wav_player_view_set_end(WavPlayerView* wav_view, size_t end) {
furi_assert(wav_view);
with_view_model(
wav_view->view, (WavPlayerViewModel * model) {
model->end = end;
return true;
});
}
void wav_player_view_set_current(WavPlayerView* wav_view, size_t current) {
furi_assert(wav_view);
with_view_model(
wav_view->view, (WavPlayerViewModel * model) {
model->current = current;
return true;
});
}
void wav_player_view_set_play(WavPlayerView* wav_view, bool play) {
furi_assert(wav_view);
with_view_model(
wav_view->view, (WavPlayerViewModel * model) {
model->play = play;
return true;
});
}
void wav_player_view_set_data(WavPlayerView* wav_view, uint16_t* data, size_t data_count) {
furi_assert(wav_view);
with_view_model(
wav_view->view, (WavPlayerViewModel * model) {
size_t inc = (data_count / DATA_COUNT) - 1;
for(size_t i = 0; i < DATA_COUNT; i++) {
model->data[i] = *data / 6;
if(model->data[i] > 42) model->data[i] = 42;
data += inc;
}
return true;
});
}
void wav_player_view_set_ctrl_callback(WavPlayerView* wav_view, WavPlayerCtrlCallback callback) {
furi_assert(wav_view);
wav_view->callback = callback;
}
void wav_player_view_set_context(WavPlayerView* wav_view, void* context) {
furi_assert(wav_view);
wav_view->context = context;
}

View File

@@ -0,0 +1,45 @@
#pragma once
#include <gui/view.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct WavPlayerView WavPlayerView;
typedef enum {
WavPlayerCtrlVolUp,
WavPlayerCtrlVolDn,
WavPlayerCtrlMoveL,
WavPlayerCtrlMoveR,
WavPlayerCtrlOk,
WavPlayerCtrlBack,
} WavPlayerCtrl;
typedef void (*WavPlayerCtrlCallback)(WavPlayerCtrl ctrl, void* context);
WavPlayerView* wav_player_view_alloc();
void wav_player_view_free(WavPlayerView* wav_view);
View* wav_player_view_get_view(WavPlayerView* wav_view);
void wav_player_view_set_volume(WavPlayerView* wav_view, float volume);
void wav_player_view_set_start(WavPlayerView* wav_view, size_t start);
void wav_player_view_set_end(WavPlayerView* wav_view, size_t end);
void wav_player_view_set_current(WavPlayerView* wav_view, size_t current);
void wav_player_view_set_play(WavPlayerView* wav_view, bool play);
void wav_player_view_set_data(WavPlayerView* wav_view, uint16_t* data, size_t data_count);
void wav_player_view_set_ctrl_callback(WavPlayerView* wav_view, WavPlayerCtrlCallback callback);
void wav_player_view_set_context(WavPlayerView* wav_view, void* context);
#ifdef __cplusplus
}
#endif

View File

@@ -372,6 +372,13 @@ const uint8_t _A_Infrared_14_4[] = {0x01,0x00,0x0e,0x00,0x00,0x5f,0x82,0x02,0x05
const uint8_t _A_Infrared_14_5[] = {0x01,0x00,0x15,0x00,0x00,0x2f,0xc2,0x07,0x08,0x82,0x01,0x47,0xc1,0x01,0x05,0x98,0x14,0x41,0xa3,0xf8,0x83,0x80,0x47,0xff,0x3f,}; const uint8_t _A_Infrared_14_5[] = {0x01,0x00,0x15,0x00,0x00,0x2f,0xc2,0x07,0x08,0x82,0x01,0x47,0xc1,0x01,0x05,0x98,0x14,0x41,0xa3,0xf8,0x83,0x80,0x47,0xff,0x3f,};
const uint8_t* const _A_Infrared_14[] = {_A_Infrared_14_0,_A_Infrared_14_1,_A_Infrared_14_2,_A_Infrared_14_3,_A_Infrared_14_4,_A_Infrared_14_5}; const uint8_t* const _A_Infrared_14[] = {_A_Infrared_14_0,_A_Infrared_14_1,_A_Infrared_14_2,_A_Infrared_14_3,_A_Infrared_14_4,_A_Infrared_14_5};
const uint8_t _A_MusicPlayer_14_0[] = {0x01,0x00,0x17,0x00,0x00,0x1e,0x02,0x01,0xc0,0x80,0xf0,0x20,0x74,0x08,0x15,0x02,0x00,0x01,0x3b,0x84,0x02,0xf0,0x01,0x29,0x80,0x5c,0x80,};
const uint8_t _A_MusicPlayer_14_1[] = {0x01,0x00,0x16,0x00,0x80,0x41,0x20,0x10,0xe8,0x04,0x7a,0x01,0x12,0x80,0x40,0x80,0x27,0x80,0x81,0xf0,0x00,0x25,0x80,0x80,0x86,0x94,};
const uint8_t _A_MusicPlayer_14_2[] = {0x01,0x00,0x13,0x00,0x00,0x34,0x82,0x03,0x30,0x81,0xcc,0x20,0x51,0x08,0x00,0x05,0x63,0x90,0x08,0xf0,0x04,0xa1,0x80,};
const uint8_t _A_MusicPlayer_14_3[] = {0x01,0x00,0x16,0x00,0x82,0x40,0x21,0xd0,0x08,0xf4,0x02,0x25,0x00,0x81,0x00,0x52,0x07,0x20,0x81,0xcc,0x00,0x23,0x01,0x90,0x06,0xd4,};
const uint8_t _A_MusicPlayer_14_4[] = {0x01,0x00,0x15,0x00,0x00,0x2c,0x82,0x01,0x70,0x80,0x7c,0x20,0x19,0x08,0x04,0x40,0x02,0x91,0xc8,0x04,0x78,0x02,0x50,0xc8,0x00,};
const uint8_t* const _A_MusicPlayer_14[] = {_A_MusicPlayer_14_0,_A_MusicPlayer_14_1,_A_MusicPlayer_14_2,_A_MusicPlayer_14_3,_A_MusicPlayer_14_4};
const uint8_t _A_NFC_14_0[] = {0x00,0x00,0x08,0x00,0x10,0x00,0x12,0x00,0x22,0x42,0x24,0x87,0x24,0x8D,0x24,0x99,0x24,0xF1,0x24,0x62,0x24,0x00,0x22,0x00,0x12,0x00,0x10,0x00,0x08,}; const uint8_t _A_NFC_14_0[] = {0x00,0x00,0x08,0x00,0x10,0x00,0x12,0x00,0x22,0x42,0x24,0x87,0x24,0x8D,0x24,0x99,0x24,0xF1,0x24,0x62,0x24,0x00,0x22,0x00,0x12,0x00,0x10,0x00,0x08,};
const uint8_t _A_NFC_14_1[] = {0x01,0x00,0x1a,0x00,0x80,0x42,0x20,0x11,0x00,0x09,0x48,0x28,0x52,0x0c,0x3c,0x83,0x1b,0x20,0xcc,0xc8,0x3e,0x32,0x0b,0x14,0x80,0x1a,0x21,0x34,0x84,0x00,}; const uint8_t _A_NFC_14_1[] = {0x01,0x00,0x1a,0x00,0x80,0x42,0x20,0x11,0x00,0x09,0x48,0x28,0x52,0x0c,0x3c,0x83,0x1b,0x20,0xcc,0xc8,0x3e,0x32,0x0b,0x14,0x80,0x1a,0x21,0x34,0x84,0x00,};
const uint8_t _A_NFC_14_2[] = {0x01,0x00,0x10,0x00,0x00,0x3d,0x0a,0x01,0x87,0x80,0x63,0x60,0x19,0x98,0x07,0xc6,0x01,0x62,0x09,0xc0,}; const uint8_t _A_NFC_14_2[] = {0x01,0x00,0x10,0x00,0x00,0x3d,0x0a,0x01,0x87,0x80,0x63,0x60,0x19,0x98,0x07,0xc6,0x01,0x62,0x09,0xc0,};

View File

@@ -99,6 +99,7 @@ extern const Icon A_FileManager_14;
extern const Icon A_GPIO_14; extern const Icon A_GPIO_14;
extern const Icon A_Games_14; extern const Icon A_Games_14;
extern const Icon A_Infrared_14; extern const Icon A_Infrared_14;
extern const Icon A_MusicPlayer_14;
extern const Icon A_NFC_14; extern const Icon A_NFC_14;
extern const Icon A_Passport_14; extern const Icon A_Passport_14;
extern const Icon A_Plugins_14; extern const Icon A_Plugins_14;