mirror of
https://github.com/DarkFlippers/unleashed-firmware
synced 2024-11-23 21:13:16 +00:00
Fixed and improved WAV Player by LTVA1
https://github.com/LTVA1/wav_player
This commit is contained in:
parent
6aad6840f6
commit
0650178946
8 changed files with 229 additions and 102 deletions
|
@ -106,7 +106,7 @@ You can support us by using links or addresses below:
|
|||
- WiFi Scanner plugin [(by SequoiaSan)](https://github.com/SequoiaSan/FlipperZero-WiFi-Scanner_Module)
|
||||
- MultiConverter plugin [(by theisolinearchip)](https://github.com/theisolinearchip/flipperzero_stuff)
|
||||
- USB Keyboard plugin [(by huuck)](https://github.com/huuck/FlipperZeroUSBKeyboard)
|
||||
- WAV player plugin (fixed) [(OFW: DrZlo13)](https://github.com/flipperdevices/flipperzero-firmware/tree/zlo/wav-player)
|
||||
- WAV Player [(OFW: DrZlo13)](https://github.com/flipperdevices/flipperzero-firmware/tree/zlo/wav-player) - Fixed and improved by [LTVA1](https://github.com/LTVA1/wav_player)
|
||||
- Barcode generator plugin [(original by McAzzaMan)](https://github.com/McAzzaMan/flipperzero-firmware/tree/UPC-A_Barcode_Generator/applications/barcode_generator) - [EAN-8 and refactoring](https://github.com/DarkFlippers/unleashed-firmware/pull/154) by @msvsergey
|
||||
- GPIO: Sentry Safe plugin [(by H4ckd4ddy)](https://github.com/H4ckd4ddy/flipperzero-sentry-safe-plugin)
|
||||
- ESP32: WiFi Marauder companion plugin [(by 0xchocolate)](https://github.com/0xchocolate/flipperzero-firmware-with-wifi-marauder-companion)
|
||||
|
|
4
applications/plugins/wav_player/README.md
Normal file
4
applications/plugins/wav_player/README.md
Normal file
|
@ -0,0 +1,4 @@
|
|||
# WAV player
|
||||
A Flipper Zero application for playing wav files. My fork adds support for correct playback speed (for files with different sample rates) and for mono files (original wav player only plays stereo). You still need to convert your file to unsigned 8-bit PCM format for it to played correctly on flipper.
|
||||
|
||||
Original app by https://github.com/DrZlo13.
|
|
@ -29,7 +29,7 @@ void wav_parser_free(WavParser* parser) {
|
|||
free(parser);
|
||||
}
|
||||
|
||||
bool wav_parser_parse(WavParser* parser, Stream* stream) {
|
||||
bool wav_parser_parse(WavParser* parser, Stream* stream, WavPlayerApp* app) {
|
||||
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));
|
||||
|
@ -63,6 +63,10 @@ bool wav_parser_parse(WavParser* parser, Stream* stream) {
|
|||
parser->format.byte_per_sec,
|
||||
parser->format.bits_per_sample);
|
||||
|
||||
app->sample_rate = parser->format.sample_rate;
|
||||
app->num_channels = parser->format.channels;
|
||||
app->bits_per_sample = parser->format.bits_per_sample;
|
||||
|
||||
parser->wav_data_start = stream_tell(stream);
|
||||
parser->wav_data_end = parser->wav_data_start + parser->data.size;
|
||||
|
||||
|
|
|
@ -1,6 +1,18 @@
|
|||
#pragma once
|
||||
#include <toolbox/stream/stream.h>
|
||||
|
||||
#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_view.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
@ -34,11 +46,37 @@ typedef struct {
|
|||
|
||||
typedef struct WavParser WavParser;
|
||||
|
||||
typedef struct {
|
||||
Storage* storage;
|
||||
Stream* stream;
|
||||
WavParser* parser;
|
||||
uint16_t* sample_buffer;
|
||||
uint8_t* tmp_buffer;
|
||||
|
||||
uint32_t sample_rate;
|
||||
|
||||
uint16_t num_channels;
|
||||
uint16_t bits_per_sample;
|
||||
|
||||
size_t samples_count_half;
|
||||
size_t samples_count;
|
||||
|
||||
FuriMessageQueue* queue;
|
||||
|
||||
float volume;
|
||||
bool play;
|
||||
|
||||
WavPlayerView* view;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
Gui* gui;
|
||||
NotificationApp* notification;
|
||||
} WavPlayerApp;
|
||||
|
||||
WavParser* wav_parser_alloc();
|
||||
|
||||
void wav_parser_free(WavParser* parser);
|
||||
|
||||
bool wav_parser_parse(WavParser* parser, Stream* stream);
|
||||
bool wav_parser_parse(WavParser* parser, Stream* stream, WavPlayerApp* app);
|
||||
|
||||
size_t wav_parser_get_data_start(WavParser* parser);
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#define WAVPLAYER_FOLDER "/ext/wav_player"
|
||||
|
||||
static bool open_wav_stream(Stream* stream) {
|
||||
DialogsApp* dialogs = furi_record_open("dialogs");
|
||||
DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS);
|
||||
bool result = false;
|
||||
FuriString* path;
|
||||
path = furi_string_alloc();
|
||||
|
@ -32,7 +32,7 @@ static bool open_wav_stream(Stream* stream) {
|
|||
|
||||
bool ret = dialog_file_browser_show(dialogs, path, path, &browser_options);
|
||||
|
||||
furi_record_close("dialogs");
|
||||
furi_record_close(RECORD_DIALOGS);
|
||||
if(ret) {
|
||||
if(!file_stream_open(stream, furi_string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) {
|
||||
FURI_LOG_E(TAG, "Cannot open file \"%s\"", furi_string_get_cstr(path));
|
||||
|
@ -79,27 +79,6 @@ static void wav_player_dma_isr(void* ctx) {
|
|||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
FuriMessageQueue* 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;
|
||||
|
@ -122,7 +101,7 @@ static WavPlayerApp* app_alloc() {
|
|||
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");
|
||||
app->notification = furi_record_open(RECORD_NOTIFICATION);
|
||||
notification_message(app->notification, &sequence_display_backlight_enforce_on);
|
||||
|
||||
return app;
|
||||
|
@ -142,44 +121,89 @@ static void app_free(WavPlayerApp* app) {
|
|||
furi_record_close(RECORD_STORAGE);
|
||||
|
||||
notification_message(app->notification, &sequence_display_backlight_enforce_auto);
|
||||
furi_record_close("notification");
|
||||
furi_record_close(RECORD_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);
|
||||
if(app->num_channels == 1) {
|
||||
uint16_t* sample_buffer_start = &app->sample_buffer[index];
|
||||
size_t count = stream_read(app->stream, app->tmp_buffer, app->samples_count_half);
|
||||
|
||||
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;
|
||||
for(size_t i = count; i < app->samples_count_half; i++) {
|
||||
app->tmp_buffer[i] = 0;
|
||||
}
|
||||
|
||||
if(data > 255) {
|
||||
data = 255;
|
||||
//for(size_t i = 0; i < app->samples_count; i += 2)
|
||||
for(size_t i = 0; i < app->samples_count_half; i++) //now works with mono!
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
//uint8_t data = app->tmp_buffer[i];
|
||||
|
||||
sample_buffer_start[i] = data;
|
||||
}
|
||||
|
||||
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_half;
|
||||
}
|
||||
|
||||
wav_player_view_set_data(app->view, sample_buffer_start, app->samples_count_half);
|
||||
if(app->num_channels == 2) {
|
||||
uint16_t* sample_buffer_start = &app->sample_buffer[index];
|
||||
size_t count = stream_read(app->stream, app->tmp_buffer, app->samples_count);
|
||||
|
||||
return count != 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] + app->tmp_buffer[i + 1]) / 2; // (L + R) / 2
|
||||
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;
|
||||
}
|
||||
|
||||
//uint8_t data = app->tmp_buffer[i];
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ctrl_callback(WavPlayerCtrl ctrl, void* ctx) {
|
||||
|
@ -218,7 +242,7 @@ static void ctrl_callback(WavPlayerCtrl ctrl, void* ctx) {
|
|||
|
||||
static void app_run(WavPlayerApp* app) {
|
||||
if(!open_wav_stream(app->stream)) return;
|
||||
if(!wav_parser_parse(app->parser, app->stream)) return;
|
||||
if(!wav_parser_parse(app->parser, app->stream, app)) return;
|
||||
|
||||
wav_player_view_set_volume(app->view, app->volume);
|
||||
wav_player_view_set_start(app->view, wav_parser_get_data_start(app->parser));
|
||||
|
@ -232,7 +256,7 @@ static void app_run(WavPlayerApp* app) {
|
|||
bool eof = fill_data(app, 0);
|
||||
eof = fill_data(app, app->samples_count_half);
|
||||
|
||||
wav_player_speaker_init();
|
||||
wav_player_speaker_init(app->sample_rate);
|
||||
wav_player_dma_init((uint32_t)app->sample_buffer, app->samples_count);
|
||||
|
||||
furi_hal_interrupt_set_isr(FuriHalInterruptIdDma1Ch1, wav_player_dma_isr, app->queue);
|
||||
|
|
|
@ -2,57 +2,100 @@
|
|||
#include <stm32wbxx_ll_tim.h>
|
||||
#include <stm32wbxx_ll_dma.h>
|
||||
|
||||
#include <stm32wbxx_ll_gpio.h>
|
||||
#include <furi_hal.h>
|
||||
#include <furi_hal_gpio.h>
|
||||
#include <furi_hal_resources.h>
|
||||
|
||||
//#define FURI_HAL_SPEAKER_TIMER TIM16
|
||||
|
||||
#define FURI_HAL_SPEAKER_TIMER TIM16
|
||||
|
||||
#define SAMPLE_RATE_TIMER TIM2
|
||||
|
||||
#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);
|
||||
void wav_player_speaker_init(uint32_t sample_rate)
|
||||
{
|
||||
LL_TIM_InitTypeDef TIM_InitStruct = {0};
|
||||
//TIM_InitStruct.Prescaler = 4;
|
||||
TIM_InitStruct.Prescaler = 1;
|
||||
TIM_InitStruct.Autoreload =
|
||||
255; //in this fork used purely as PWM timer, the DMA now is triggered by SAMPLE_RATE_TIMER
|
||||
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);
|
||||
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);
|
||||
|
||||
//======================================================
|
||||
|
||||
TIM_InitStruct.Prescaler = 0;
|
||||
//TIM_InitStruct.Autoreload = 1451; //64 000 000 / 1451 ~= 44100 Hz
|
||||
|
||||
TIM_InitStruct.Autoreload = 64000000 / sample_rate; //to support various sample rates
|
||||
|
||||
LL_TIM_Init(SAMPLE_RATE_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(SAMPLE_RATE_TIMER, FURI_HAL_SPEAKER_CHANNEL, &TIM_OC_InitStruct);
|
||||
|
||||
//=========================================================
|
||||
//configuring PA6 pin as TIM16 output
|
||||
|
||||
//furi_hal_gpio_init_ex(&gpio_ext_pa6, (GpioMode)GpioPullNo, (GpioPull)GpioModeAltFunctionPushPull, GpioSpeedVeryHigh, GpioAltFn14TIM16);
|
||||
//furi_hal_gpio_init_ex(&gpio_ext_pa6, (GpioMode)GpioPullNo, (GpioPull)GpioModeAltFunctionPushPull, GpioSpeedLow, GpioAltFn14TIM16);
|
||||
furi_hal_gpio_init_ex(&gpio_ext_pa6, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedVeryHigh, GpioAltFn14TIM16);
|
||||
//furi_hal_gpio_init_simple(&gpio_ext_pa6, GpioModeOutputPushPull);
|
||||
//furi_hal_gpio_write(&gpio_ext_pa6, false);
|
||||
}
|
||||
|
||||
void wav_player_speaker_start() {
|
||||
LL_TIM_EnableAllOutputs(FURI_HAL_SPEAKER_TIMER);
|
||||
LL_TIM_EnableCounter(FURI_HAL_SPEAKER_TIMER);
|
||||
LL_TIM_EnableAllOutputs(FURI_HAL_SPEAKER_TIMER);
|
||||
LL_TIM_EnableCounter(FURI_HAL_SPEAKER_TIMER);
|
||||
|
||||
LL_TIM_EnableAllOutputs(SAMPLE_RATE_TIMER);
|
||||
LL_TIM_EnableCounter(SAMPLE_RATE_TIMER);
|
||||
}
|
||||
|
||||
void wav_player_speaker_stop() {
|
||||
LL_TIM_DisableAllOutputs(FURI_HAL_SPEAKER_TIMER);
|
||||
LL_TIM_DisableCounter(FURI_HAL_SPEAKER_TIMER);
|
||||
LL_TIM_DisableAllOutputs(FURI_HAL_SPEAKER_TIMER);
|
||||
LL_TIM_DisableCounter(FURI_HAL_SPEAKER_TIMER);
|
||||
|
||||
LL_TIM_DisableAllOutputs(SAMPLE_RATE_TIMER);
|
||||
LL_TIM_DisableCounter(SAMPLE_RATE_TIMER);
|
||||
}
|
||||
|
||||
void wav_player_dma_init(uint32_t address, size_t size) {
|
||||
uint32_t dma_dst = (uint32_t) & (FURI_HAL_SPEAKER_TIMER->CCR1);
|
||||
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_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_SetPeriphRequest(DMA_INSTANCE, LL_DMAMUX_REQ_TIM2_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);
|
||||
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);
|
||||
LL_DMA_EnableChannel(DMA_INSTANCE);
|
||||
LL_TIM_EnableDMAReq_UPDATE(SAMPLE_RATE_TIMER);
|
||||
}
|
||||
|
||||
void wav_player_dma_stop() {
|
||||
LL_DMA_DisableChannel(DMA_INSTANCE);
|
||||
LL_DMA_DisableChannel(DMA_INSTANCE);
|
||||
}
|
|
@ -1,22 +1,5 @@
|
|||
#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;
|
||||
}
|
||||
|
@ -30,7 +13,7 @@ static void wav_player_view_draw_callback(Canvas* canvas, void* _model) {
|
|||
uint8_t y_pos = 0;
|
||||
|
||||
// volume
|
||||
x_pos = 124;
|
||||
x_pos = 123;
|
||||
y_pos = 0;
|
||||
const float volume = (64 / 10.0f) * model->volume;
|
||||
canvas_draw_frame(canvas, x_pos, y_pos, 4, 64);
|
||||
|
|
|
@ -1,6 +1,16 @@
|
|||
#pragma once
|
||||
#include <gui/view.h>
|
||||
|
||||
#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>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
@ -18,6 +28,27 @@ typedef enum {
|
|||
|
||||
typedef void (*WavPlayerCtrlCallback)(WavPlayerCtrl ctrl, void* context);
|
||||
|
||||
#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;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
WavPlayerView* wav_player_view_alloc();
|
||||
|
||||
void wav_player_view_free(WavPlayerView* wav_view);
|
||||
|
|
Loading…
Reference in a new issue