Adjust sound volume with select+up/down & add DMG color palette
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
build
|
||||
uf2
|
||||
src/rom.c
|
||||
+64
-9
@@ -24,6 +24,9 @@
|
||||
|
||||
#include "i2s.h"
|
||||
|
||||
/**
|
||||
* return the default i2s context used to store information about the setup
|
||||
*/
|
||||
i2s_config_t i2s_get_default_config(void) {
|
||||
i2s_config_t i2s_config = {
|
||||
.sample_freq = 44100,
|
||||
@@ -35,11 +38,16 @@ i2s_config_t i2s_get_default_config(void) {
|
||||
.dma_channel = 0,
|
||||
.dma_buf = NULL,
|
||||
.dma_trans_count = 0,
|
||||
.volume = 0,
|
||||
};
|
||||
|
||||
return i2s_config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the I2S driver. Must be called before calling i2s_write or i2s_dma_write
|
||||
* i2s_config: I2S context obtained by i2s_get_default_config()
|
||||
*/
|
||||
void i2s_init(i2s_config_t *i2s_config) {
|
||||
uint8_t func=GPIO_FUNC_PIO0; // TODO: GPIO_FUNC_PIO0 for pio0 or GPIO_FUNC_PIO1 for pio1
|
||||
gpio_set_function(i2s_config->data_pin, GPIO_FUNC_PIO0);
|
||||
@@ -52,17 +60,17 @@ void i2s_init(i2s_config_t *i2s_config) {
|
||||
|
||||
audio_i2s_program_init(i2s_config->pio, i2s_config->sm , offset, i2s_config->data_pin , i2s_config->clock_pin_base);
|
||||
|
||||
// Set PIO clock
|
||||
/* Set PIO clock */
|
||||
uint32_t system_clock_frequency = clock_get_hz(clk_sys);
|
||||
uint32_t divider = system_clock_frequency * 4 / i2s_config->sample_freq; // avoid arithmetic overflow
|
||||
pio_sm_set_clkdiv_int_frac(i2s_config->pio, i2s_config->sm , divider >> 8u, divider & 0xffu);
|
||||
|
||||
pio_sm_set_enabled(i2s_config->pio, i2s_config->sm, false);
|
||||
|
||||
// Allocate memory for the DMA buffer
|
||||
/* Allocate memory for the DMA buffer */
|
||||
i2s_config->dma_buf=malloc(i2s_config->dma_trans_count*sizeof(uint32_t));
|
||||
|
||||
// Direct Memory Access setup
|
||||
/* Direct Memory Access setup */
|
||||
i2s_config->dma_channel = dma_claim_unused_channel(true);
|
||||
|
||||
dma_channel_config dma_config = dma_channel_get_default_config(i2s_config->dma_channel);
|
||||
@@ -81,20 +89,67 @@ void i2s_init(i2s_config_t *i2s_config) {
|
||||
pio_sm_set_enabled(i2s_config->pio, i2s_config->sm , true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write samples to I2S directly and wait for completion (blocking)
|
||||
* i2s_config: I2S context obtained by i2s_get_default_config()
|
||||
* sample: pointer to an array of len x 32 bits samples
|
||||
* Each 32 bits sample contains 2x16 bits samples,
|
||||
* one for the left channel and one for the right channel
|
||||
* len: length of sample in 32 bits words
|
||||
*/
|
||||
void i2s_write(const i2s_config_t *i2s_config,const int16_t *samples,const size_t len) {
|
||||
for(size_t i=0;i<len;i++) {
|
||||
for(size_t i=0;i<len;i+=2) {
|
||||
pio_sm_put_blocking(i2s_config->pio, i2s_config->sm, (uint32_t)samples[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Write samples to DMA buffer and initiate DMA transfer (non blocking)
|
||||
/**
|
||||
* Write samples to DMA buffer and initiate DMA transfer (non blocking)
|
||||
* i2s_config: I2S context obtained by i2s_get_default_config()
|
||||
* sample: pointer to an array of dma_trans_count x 32 bits samples
|
||||
*/
|
||||
void i2s_dma_write(i2s_config_t *i2s_config,const int16_t *samples) {
|
||||
// Wait the completion of the previous DMA transfer
|
||||
/* Wait the completion of the previous DMA transfer */
|
||||
dma_channel_wait_for_finish_blocking(i2s_config->dma_channel);
|
||||
// Copy samples into the DMA buffer
|
||||
memcpy(i2s_config->dma_buf,samples,i2s_config->dma_trans_count*sizeof(int32_t));
|
||||
// Initiate the DMA transfer
|
||||
/* Copy samples into the DMA buffer */
|
||||
if(i2s_config->volume==0) {
|
||||
memcpy(i2s_config->dma_buf,samples,i2s_config->dma_trans_count*sizeof(int32_t));
|
||||
} else {
|
||||
for(uint16_t i=0;i<i2s_config->dma_trans_count*2;i++) {
|
||||
i2s_config->dma_buf[i] = samples[i]>>i2s_config->volume;
|
||||
}
|
||||
}
|
||||
|
||||
/* Initiate the DMA transfer */
|
||||
dma_channel_transfer_from_buffer_now(i2s_config->dma_channel,
|
||||
i2s_config->dma_buf,
|
||||
i2s_config->dma_trans_count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust the output volume
|
||||
* i2s_config: I2S context obtained by i2s_get_default_config()
|
||||
* volume: desired volume between 0 (highest. volume) and 16 (lowest volume)
|
||||
*/
|
||||
void i2s_volume(i2s_config_t *i2s_config,uint8_t volume) {
|
||||
if(volume>16) volume=16;
|
||||
i2s_config->volume=volume;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increases the output volume
|
||||
*/
|
||||
void i2s_increase_volume(i2s_config_t *i2s_config) {
|
||||
if(i2s_config->volume>0) {
|
||||
i2s_config->volume--;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decreases the output volume
|
||||
*/
|
||||
void i2s_decrease_volume(i2s_config_t *i2s_config) {
|
||||
if(i2s_config->volume<16) {
|
||||
i2s_config->volume++;
|
||||
}
|
||||
}
|
||||
|
||||
+5
-2
@@ -42,11 +42,14 @@ typedef struct i2s_config
|
||||
uint8_t dma_channel;
|
||||
uint16_t dma_trans_count;
|
||||
uint16_t *dma_buf;
|
||||
|
||||
uint8_t volume;
|
||||
} i2s_config_t;
|
||||
|
||||
|
||||
i2s_config_t i2s_get_default_config(void);
|
||||
void i2s_init(i2s_config_t *i2s_config);
|
||||
void i2s_write(const i2s_config_t *i2s_config,const int16_t *samples,const size_t len);
|
||||
void i2s_dma_write(i2s_config_t *i2s_config,const int16_t *samples);
|
||||
void i2s_dma_write(i2s_config_t *i2s_config,const int16_t *samples);
|
||||
void i2s_volume(i2s_config_t *i2s_config,uint8_t volume);
|
||||
void i2s_increase_volume(i2s_config_t *i2s_config);
|
||||
void i2s_decrease_volume(i2s_config_t *i2s_config);
|
||||
|
||||
@@ -559,6 +559,17 @@ void get_colour_palette(palette_t selected_palette,uint8_t table_entry,uint8_t s
|
||||
memcpy(selected_palette, palette, PALETTE_SIZE_IN_BYTES);
|
||||
return;
|
||||
}
|
||||
if(table_entry==0xFF && shuffling_flags==0xFF)
|
||||
{
|
||||
/* Game Boy DMG palette (4 shades of green) */
|
||||
const palette_t palette = {
|
||||
{ 0x7C02, 0x5BC8, 0x3AC9, 0x2A07 }, /* OBJ0 */
|
||||
{ 0x7C02, 0x5BC8, 0x3AC9, 0x2A07 }, /* OBJ1 */
|
||||
{ 0x7C02, 0x5BC8, 0x3AC9, 0x2A07 } /* BG */
|
||||
};
|
||||
memcpy(selected_palette, palette, PALETTE_SIZE_IN_BYTES);
|
||||
return;
|
||||
}
|
||||
/* default palette */
|
||||
printf("get_colour_palette: No palette found for table_entry=0x%02X shuffling_flags=0x%02X\n",
|
||||
table_entry,
|
||||
|
||||
+83
-51
@@ -71,7 +71,6 @@
|
||||
#define GPIO_B 7
|
||||
#define GPIO_SELECT 8
|
||||
#define GPIO_START 9
|
||||
#define GPIO_BUZZER 15
|
||||
#define GPIO_CS 17
|
||||
#define GPIO_CLK 18
|
||||
#define GPIO_SDA 19
|
||||
@@ -102,6 +101,18 @@ static uint8_t ram[32768];
|
||||
static int lcd_line_busy = 0;
|
||||
static palette_t palette; // Colour palette
|
||||
|
||||
static struct
|
||||
{
|
||||
unsigned a : 1;
|
||||
unsigned b : 1;
|
||||
unsigned select : 1;
|
||||
unsigned start : 1;
|
||||
unsigned right : 1;
|
||||
unsigned left : 1;
|
||||
unsigned up : 1;
|
||||
unsigned down : 1;
|
||||
} prev_joypad_bits;
|
||||
|
||||
/* Multicore command structure. */
|
||||
union core_cmd {
|
||||
struct {
|
||||
@@ -249,7 +260,7 @@ _Noreturn
|
||||
void main_core1(void)
|
||||
{
|
||||
static dma_channel_config c2;
|
||||
static const uint16_t clear_screen_colour = 0x0000;
|
||||
uint16_t clear_screen_colour = palette[2][3];
|
||||
union core_cmd cmd;
|
||||
|
||||
/* Initialise and control LCD on core 1. */
|
||||
@@ -387,7 +398,6 @@ int main(void)
|
||||
gpio_set_function(GPIO_B, GPIO_FUNC_SIO);
|
||||
gpio_set_function(GPIO_SELECT, GPIO_FUNC_SIO);
|
||||
gpio_set_function(GPIO_START, GPIO_FUNC_SIO);
|
||||
gpio_set_function(GPIO_BUZZER, GPIO_FUNC_PWM);
|
||||
gpio_set_function(GPIO_CS, GPIO_FUNC_SIO);
|
||||
gpio_set_function(GPIO_CLK, GPIO_FUNC_SPI);
|
||||
gpio_set_function(GPIO_SDA, GPIO_FUNC_SPI);
|
||||
@@ -403,7 +413,6 @@ int main(void)
|
||||
gpio_set_dir(GPIO_B, false);
|
||||
gpio_set_dir(GPIO_SELECT, false);
|
||||
gpio_set_dir(GPIO_START, false);
|
||||
gpio_set_dir(GPIO_BUZZER, true);
|
||||
gpio_set_dir(GPIO_CS, true);
|
||||
gpio_set_dir(GPIO_RS, true);
|
||||
gpio_set_dir(GPIO_RST, true);
|
||||
@@ -427,12 +436,6 @@ int main(void)
|
||||
spi_init(spi0, 30*1000*1000);
|
||||
spi_set_format(spi0, 16, SPI_CPOL_0, SPI_CPHA_0, SPI_MSB_FIRST);
|
||||
|
||||
/* Start Core1, which processes requests to the LCD. */
|
||||
#if ENABLE_LCD
|
||||
putstdio("CORE1 ");
|
||||
multicore_launch_core1(main_core1);
|
||||
#endif
|
||||
|
||||
/* Initialise GB context. */
|
||||
memcpy(rom_bank0, rom, sizeof(rom_bank0));
|
||||
ret = gb_init(&gb, &gb_rom_read, &gb_cart_ram_read,
|
||||
@@ -445,9 +448,56 @@ int main(void)
|
||||
goto sleep;
|
||||
}
|
||||
|
||||
/* Update buttons state */
|
||||
gb.direct.joypad_bits.up=gpio_get(GPIO_UP);
|
||||
gb.direct.joypad_bits.down=gpio_get(GPIO_DOWN);
|
||||
gb.direct.joypad_bits.left=gpio_get(GPIO_LEFT);
|
||||
gb.direct.joypad_bits.right=gpio_get(GPIO_RIGHT);
|
||||
gb.direct.joypad_bits.a=gpio_get(GPIO_A);
|
||||
gb.direct.joypad_bits.b=gpio_get(GPIO_B);
|
||||
gb.direct.joypad_bits.select=gpio_get(GPIO_SELECT);
|
||||
gb.direct.joypad_bits.start=gpio_get(GPIO_START);
|
||||
|
||||
/* manually assign a palette with button combo */
|
||||
if(!gb.direct.joypad_bits.right) {
|
||||
get_colour_palette(palette,0x05,0x00); /* Right */
|
||||
} else if(!gb.direct.joypad_bits.a && !gb.direct.joypad_bits.down) {
|
||||
get_colour_palette(palette,0x07,0x00); /* A + Down */
|
||||
} else if(!gb.direct.joypad_bits.up) {
|
||||
get_colour_palette(palette,0x12,0x00); /* Up */
|
||||
} else if(!gb.direct.joypad_bits.b && !gb.direct.joypad_bits.right) {
|
||||
get_colour_palette(palette,0x13,0x00); /* B + Right */
|
||||
} else if(!gb.direct.joypad_bits.b && !gb.direct.joypad_bits.left) {
|
||||
get_colour_palette(palette,0x16,0x00); /* B + Left (Game Boy Pocket Palette, shades of gray) */
|
||||
} else if(!gb.direct.joypad_bits.down) {
|
||||
get_colour_palette(palette,0x17,0x00); /* Down */
|
||||
} else if(!gb.direct.joypad_bits.b && !gb.direct.joypad_bits.up) {
|
||||
get_colour_palette(palette,0x19,0x03); /* B + Up */
|
||||
} else if(!gb.direct.joypad_bits.a && !gb.direct.joypad_bits.right) {
|
||||
get_colour_palette(palette,0x1C,0x03); /* A + Right */
|
||||
} else if(!gb.direct.joypad_bits.a && !gb.direct.joypad_bits.left) {
|
||||
get_colour_palette(palette,0x0D,0x05); /* A + Left */
|
||||
} else if(!gb.direct.joypad_bits.a && !gb.direct.joypad_bits.up) {
|
||||
get_colour_palette(palette,0x10,0x05); /* A + Up */
|
||||
} else if(!gb.direct.joypad_bits.left) {
|
||||
get_colour_palette(palette,0x18,0x05); /* Left */
|
||||
} else if(!gb.direct.joypad_bits.b && !gb.direct.joypad_bits.down) {
|
||||
get_colour_palette(palette,0x1A,0x05); /* B + Down */
|
||||
} else if(!gb.direct.joypad_bits.a && !gb.direct.joypad_bits.b) {
|
||||
get_colour_palette(palette,0xFF,0xFF); /* A + B */
|
||||
} else {
|
||||
/* Automatically assign a colour palette to the game */
|
||||
char rom_title[16];
|
||||
auto_assign_palette(palette, gb_colour_hash(&gb),gb_get_rom_name(&gb,rom_title));
|
||||
}
|
||||
|
||||
#if ENABLE_LCD
|
||||
gb_init_lcd(&gb, &lcd_draw_line);
|
||||
{
|
||||
/* Start Core1, which processes requests to the LCD. */
|
||||
putstdio("CORE1 ");
|
||||
multicore_launch_core1(main_core1);
|
||||
|
||||
/* initialise pixel buffer copy DMA. */
|
||||
static dma_channel_config dma_config;
|
||||
gb_priv.dma_pixel_buffer_chan = dma_claim_unused_channel(true);
|
||||
@@ -486,6 +536,7 @@ int main(void)
|
||||
i2s_config_t i2s_config = i2s_get_default_config();
|
||||
i2s_config.sample_freq=AUDIO_SAMPLE_RATE;
|
||||
i2s_config.dma_trans_count =AUDIO_SAMPLES;
|
||||
i2s_volume(&i2s_config,2);
|
||||
i2s_init(&i2s_config);
|
||||
|
||||
// Initialize audio emulation
|
||||
@@ -494,47 +545,6 @@ int main(void)
|
||||
putstdio("AUDIO ");
|
||||
#endif
|
||||
|
||||
/* Update buttons state */
|
||||
gb.direct.joypad_bits.up=gpio_get(GPIO_UP);
|
||||
gb.direct.joypad_bits.down=gpio_get(GPIO_DOWN);
|
||||
gb.direct.joypad_bits.left=gpio_get(GPIO_LEFT);
|
||||
gb.direct.joypad_bits.right=gpio_get(GPIO_RIGHT);
|
||||
gb.direct.joypad_bits.a=gpio_get(GPIO_A);
|
||||
gb.direct.joypad_bits.b=gpio_get(GPIO_B);
|
||||
gb.direct.joypad_bits.select=gpio_get(GPIO_SELECT);
|
||||
gb.direct.joypad_bits.start=gpio_get(GPIO_START);
|
||||
|
||||
/* manually assign a palette with button combo */
|
||||
if(!gb.direct.joypad_bits.right) {
|
||||
get_colour_palette(palette,0x05,0x00); /* Right */
|
||||
} else if(!gb.direct.joypad_bits.a && !gb.direct.joypad_bits.down) {
|
||||
get_colour_palette(palette,0x07,0x00); /* A + Down */
|
||||
} else if(!gb.direct.joypad_bits.up) {
|
||||
get_colour_palette(palette,0x12,0x00); /* Up */
|
||||
} else if(!gb.direct.joypad_bits.b && !gb.direct.joypad_bits.right) {
|
||||
get_colour_palette(palette,0x13,0x00); /* B + Right */
|
||||
} else if(!gb.direct.joypad_bits.b && !gb.direct.joypad_bits.left) {
|
||||
get_colour_palette(palette,0x16,0x00); /* B + Left (Game Boy Pocket Palette, shades of gray) */
|
||||
} else if(!gb.direct.joypad_bits.down) {
|
||||
get_colour_palette(palette,0x17,0x00); /* Down */
|
||||
} else if(!gb.direct.joypad_bits.b && !gb.direct.joypad_bits.up) {
|
||||
get_colour_palette(palette,0x19,0x03); /* B + Up */
|
||||
} else if(!gb.direct.joypad_bits.a && !gb.direct.joypad_bits.right) {
|
||||
get_colour_palette(palette,0x1C,0x03); /* A + Right */
|
||||
} else if(!gb.direct.joypad_bits.a && !gb.direct.joypad_bits.left) {
|
||||
get_colour_palette(palette,0x0D,0x05); /* A + Left */
|
||||
} else if(!gb.direct.joypad_bits.a && !gb.direct.joypad_bits.up) {
|
||||
get_colour_palette(palette,0x10,0x05); /* A + Up */
|
||||
} else if(!gb.direct.joypad_bits.left) {
|
||||
get_colour_palette(palette,0x18,0x05); /* Left */
|
||||
} else if(!gb.direct.joypad_bits.b && !gb.direct.joypad_bits.down) {
|
||||
get_colour_palette(palette,0x1A,0x05); /* B + Down */
|
||||
} else {
|
||||
/* Automatically assign a colour palette to the game */
|
||||
char rom_title[16];
|
||||
auto_assign_palette(palette, gb_colour_hash(&gb),gb_get_rom_name(&gb,rom_title));
|
||||
}
|
||||
|
||||
putstdio("\n> ");
|
||||
uint_fast32_t frames = 0;
|
||||
uint64_t start_time = time_us_64();
|
||||
@@ -556,6 +566,14 @@ int main(void)
|
||||
#endif
|
||||
|
||||
/* Update buttons state */
|
||||
prev_joypad_bits.up=gb.direct.joypad_bits.up;
|
||||
prev_joypad_bits.down=gb.direct.joypad_bits.down;
|
||||
prev_joypad_bits.left=gb.direct.joypad_bits.left;
|
||||
prev_joypad_bits.right=gb.direct.joypad_bits.right;
|
||||
prev_joypad_bits.a=gb.direct.joypad_bits.a;
|
||||
prev_joypad_bits.b=gb.direct.joypad_bits.b;
|
||||
prev_joypad_bits.select=gb.direct.joypad_bits.select;
|
||||
prev_joypad_bits.start=gb.direct.joypad_bits.start;
|
||||
gb.direct.joypad_bits.up=gpio_get(GPIO_UP);
|
||||
gb.direct.joypad_bits.down=gpio_get(GPIO_DOWN);
|
||||
gb.direct.joypad_bits.left=gpio_get(GPIO_LEFT);
|
||||
@@ -565,6 +583,20 @@ int main(void)
|
||||
gb.direct.joypad_bits.select=gpio_get(GPIO_SELECT);
|
||||
gb.direct.joypad_bits.start=gpio_get(GPIO_START);
|
||||
|
||||
/* hotkeys (select + * combo)*/
|
||||
if(!gb.direct.joypad_bits.select) {
|
||||
#if ENABLE_SOUND
|
||||
if(!gb.direct.joypad_bits.up && prev_joypad_bits.up) {
|
||||
/* select + up */
|
||||
i2s_increase_volume(&i2s_config);
|
||||
}
|
||||
if(!gb.direct.joypad_bits.down && prev_joypad_bits.down) {
|
||||
/* select + down */
|
||||
i2s_decrease_volume(&i2s_config);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Serial monitor commands */
|
||||
input = getchar_timeout_us(0);
|
||||
if(input == PICO_ERROR_TIMEOUT)
|
||||
|
||||
Reference in New Issue
Block a user