mirror of
https://github.com/holub/mame
synced 2025-06-05 20:33:45 +03:00
-vgm_visualizer: Added more spectrogram visualization modes. [Ryan Holtz]
This commit is contained in:
parent
eb2b889654
commit
9c6f0781b0
@ -78,6 +78,7 @@ void vgmviz_device::device_start()
|
|||||||
{
|
{
|
||||||
WDL_fft_init();
|
WDL_fft_init();
|
||||||
fill_window();
|
fill_window();
|
||||||
|
m_bitmap.resize(SCREEN_WIDTH, SCREEN_HEIGHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -166,8 +167,8 @@ void vgmviz_device::apply_waterfall()
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
int permuted = WDL_fft_permute(FFT_LENGTH / 2, bar);
|
int permuted = WDL_fft_permute(FFT_LENGTH / 2, bar);
|
||||||
float val = bins[0][permuted].re + bins[1][permuted].re;
|
float val = std::max<float>(bins[0][permuted].re, bins[1][permuted].re);
|
||||||
int level = int(logf(val * 32768.0f) * 31.0f);
|
int level = int(log10f(val * 32768.0f) * 95.0f);
|
||||||
m_waterfall_buf[m_waterfall_length % SCREEN_WIDTH][total_bars - bar] = (level < 0) ? 0 : (level > 255 ? 255 : level);
|
m_waterfall_buf[m_waterfall_length % SCREEN_WIDTH][total_bars - bar] = (level < 0) ? 0 : (level > 255 ? 255 : level);
|
||||||
}
|
}
|
||||||
m_waterfall_length++;
|
m_waterfall_length++;
|
||||||
@ -253,6 +254,8 @@ void vgmviz_device::device_reset()
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_viz_mode = VIZ_WAVEFORM;
|
m_viz_mode = VIZ_WAVEFORM;
|
||||||
|
m_clear_pending = true;
|
||||||
|
m_bitmap.fill(0);
|
||||||
|
|
||||||
m_history_length = 0;
|
m_history_length = 0;
|
||||||
}
|
}
|
||||||
@ -270,6 +273,8 @@ void vgmviz_device::cycle_viz_mode()
|
|||||||
{
|
{
|
||||||
m_viz_mode = VIZ_WAVEFORM;
|
m_viz_mode = VIZ_WAVEFORM;
|
||||||
}
|
}
|
||||||
|
m_bitmap.fill(0);
|
||||||
|
m_clear_pending = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -309,10 +314,17 @@ void vgmviz_device::sound_stream_update(sound_stream &stream, stream_sample_t **
|
|||||||
update_waveform(outputs);
|
update_waveform(outputs);
|
||||||
break;
|
break;
|
||||||
case VIZ_WATERFALL:
|
case VIZ_WATERFALL:
|
||||||
case VIZ_RAWSPEC:
|
case VIZ_RAW_SPEC:
|
||||||
case VIZ_BARSPEC4:
|
case VIZ_BAR_SPEC4:
|
||||||
case VIZ_BARSPEC8:
|
case VIZ_BAR_SPEC8:
|
||||||
case VIZ_BARSPEC16:
|
case VIZ_BAR_SPEC16:
|
||||||
|
case VIZ_PILLAR_SPEC4:
|
||||||
|
case VIZ_PILLAR_SPEC8:
|
||||||
|
case VIZ_PILLAR_SPEC16:
|
||||||
|
case VIZ_TOP_SPEC:
|
||||||
|
case VIZ_TOP_SPEC4:
|
||||||
|
case VIZ_TOP_SPEC8:
|
||||||
|
case VIZ_TOP_SPEC16:
|
||||||
update_fft(outputs);
|
update_fft(outputs);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -483,98 +495,204 @@ void vgmviz_device::device_add_mconfig(machine_config &config)
|
|||||||
// screen_update - update vu meters
|
// screen_update - update vu meters
|
||||||
//-------------------------------------------------
|
//-------------------------------------------------
|
||||||
|
|
||||||
|
template void vgmviz_device::draw_spectrogram<1, vgmviz_device::SPEC_VIZ_BAR>(bitmap_rgb32 &bitmap);
|
||||||
|
template void vgmviz_device::draw_spectrogram<4, vgmviz_device::SPEC_VIZ_BAR>(bitmap_rgb32 &bitmap);
|
||||||
|
template void vgmviz_device::draw_spectrogram<8, vgmviz_device::SPEC_VIZ_BAR>(bitmap_rgb32 &bitmap);
|
||||||
|
template void vgmviz_device::draw_spectrogram<16, vgmviz_device::SPEC_VIZ_BAR>(bitmap_rgb32 &bitmap);
|
||||||
|
template void vgmviz_device::draw_spectrogram<4, vgmviz_device::SPEC_VIZ_TOP>(bitmap_rgb32 &bitmap);
|
||||||
|
template void vgmviz_device::draw_spectrogram<8, vgmviz_device::SPEC_VIZ_TOP>(bitmap_rgb32 &bitmap);
|
||||||
|
template void vgmviz_device::draw_spectrogram<16, vgmviz_device::SPEC_VIZ_TOP>(bitmap_rgb32 &bitmap);
|
||||||
|
template void vgmviz_device::draw_spectrogram<3, vgmviz_device::SPEC_VIZ_PILLAR>(bitmap_rgb32 &bitmap);
|
||||||
|
template void vgmviz_device::draw_spectrogram<6, vgmviz_device::SPEC_VIZ_PILLAR>(bitmap_rgb32 &bitmap);
|
||||||
|
template void vgmviz_device::draw_spectrogram<12, vgmviz_device::SPEC_VIZ_PILLAR>(bitmap_rgb32 &bitmap);
|
||||||
|
|
||||||
uint32_t vgmviz_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
|
uint32_t vgmviz_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
|
||||||
{
|
{
|
||||||
bitmap.fill(0, cliprect);
|
|
||||||
|
|
||||||
switch (m_viz_mode)
|
switch (m_viz_mode)
|
||||||
{
|
{
|
||||||
default:
|
default:
|
||||||
|
bitmap.fill(0, cliprect);
|
||||||
draw_waveform(bitmap);
|
draw_waveform(bitmap);
|
||||||
break;
|
break;
|
||||||
case VIZ_WATERFALL:
|
case VIZ_WATERFALL:
|
||||||
|
bitmap.fill(0, cliprect);
|
||||||
draw_waterfall(bitmap);
|
draw_waterfall(bitmap);
|
||||||
break;
|
break;
|
||||||
case VIZ_RAWSPEC:
|
case VIZ_RAW_SPEC:
|
||||||
case VIZ_BARSPEC4:
|
draw_spectrogram<1, SPEC_VIZ_BAR>(bitmap);
|
||||||
case VIZ_BARSPEC8:
|
break;
|
||||||
case VIZ_BARSPEC16:
|
case VIZ_TOP_SPEC:
|
||||||
draw_spectrogram(bitmap);
|
draw_spectrogram<1, SPEC_VIZ_TOP>(bitmap);
|
||||||
|
break;
|
||||||
|
case VIZ_BAR_SPEC4:
|
||||||
|
draw_spectrogram<4, SPEC_VIZ_BAR>(bitmap);
|
||||||
|
break;
|
||||||
|
case VIZ_PILLAR_SPEC4:
|
||||||
|
draw_spectrogram<3, SPEC_VIZ_PILLAR>(bitmap);
|
||||||
|
break;
|
||||||
|
case VIZ_TOP_SPEC4:
|
||||||
|
draw_spectrogram<4, SPEC_VIZ_TOP>(bitmap);
|
||||||
|
break;
|
||||||
|
case VIZ_BAR_SPEC8:
|
||||||
|
draw_spectrogram<8, SPEC_VIZ_BAR>(bitmap);
|
||||||
|
break;
|
||||||
|
case VIZ_PILLAR_SPEC8:
|
||||||
|
draw_spectrogram<6, SPEC_VIZ_PILLAR>(bitmap);
|
||||||
|
break;
|
||||||
|
case VIZ_TOP_SPEC8:
|
||||||
|
draw_spectrogram<8, SPEC_VIZ_TOP>(bitmap);
|
||||||
|
break;
|
||||||
|
case VIZ_BAR_SPEC16:
|
||||||
|
draw_spectrogram<16, SPEC_VIZ_BAR>(bitmap);
|
||||||
|
break;
|
||||||
|
case VIZ_PILLAR_SPEC16:
|
||||||
|
draw_spectrogram<12, SPEC_VIZ_PILLAR>(bitmap);
|
||||||
|
break;
|
||||||
|
case VIZ_TOP_SPEC16:
|
||||||
|
draw_spectrogram<16, SPEC_VIZ_TOP>(bitmap);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void vgmviz_device::draw_spectrogram(bitmap_rgb32 &bitmap)
|
template <int BarSize, int SpecMode> void vgmviz_device::draw_spectrogram(bitmap_rgb32 &bitmap)
|
||||||
{
|
{
|
||||||
const pen_t *pal = m_palette->pens();
|
const int black_index = 512 + FFT_LENGTH / 2;
|
||||||
const int black_idx = (512 + FFT_LENGTH / 2);
|
|
||||||
|
|
||||||
/*
|
if (m_clear_pending || SpecMode == SPEC_VIZ_BAR)
|
||||||
find_levels();
|
|
||||||
|
|
||||||
int chan_x = 0;
|
|
||||||
for (int chan = 0; chan < 2; chan++)
|
|
||||||
{
|
{
|
||||||
int level = int(m_curr_levels[chan] * 255.0f);
|
bitmap.fill(0);
|
||||||
int peak = int(m_curr_peaks[chan] * 255.0f);
|
m_clear_pending = false;
|
||||||
for (int y = 0; y < 512; y++)
|
}
|
||||||
|
|
||||||
|
const pen_t *pal = m_palette->pens();
|
||||||
|
|
||||||
|
int width = SCREEN_WIDTH;
|
||||||
|
switch (SpecMode)
|
||||||
|
{
|
||||||
|
case SPEC_VIZ_PILLAR:
|
||||||
|
for (int y = 2; y < SCREEN_HEIGHT; y++)
|
||||||
{
|
{
|
||||||
int bar_y = 255 - (y >> 1);
|
uint32_t *src = &m_bitmap.pix32(y);
|
||||||
for (int x = 0; x < 7; x++)
|
uint32_t *dst = &bitmap.pix32(y - 2);
|
||||||
|
for (int x = SCREEN_WIDTH - 1; x >= 1; x--)
|
||||||
{
|
{
|
||||||
uint32_t *line = &bitmap.pix32(y + 256);
|
dst[x] = src[x - 1];
|
||||||
bool lit = bar_y <= level || bar_y == peak;
|
|
||||||
line[chan_x + x] = pal[lit ? bar_y : black_idx];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
chan_x += 8;
|
width = (int)(SCREEN_WIDTH * 0.75f);
|
||||||
m_curr_peaks[chan] *= 0.99f;
|
break;
|
||||||
}
|
case SPEC_VIZ_TOP:
|
||||||
*/
|
for (int y = 1; y < SCREEN_HEIGHT; y++)
|
||||||
|
{
|
||||||
int bar_size = 1;
|
uint32_t *src = &m_bitmap.pix32(y);
|
||||||
switch (m_viz_mode)
|
uint32_t *dst = &bitmap.pix32(y - 1);
|
||||||
{
|
for (int x = 0; x < SCREEN_WIDTH; x++)
|
||||||
|
{
|
||||||
|
dst[x] = src[x];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
bar_size = 1;
|
|
||||||
break;
|
|
||||||
case VIZ_BARSPEC4:
|
|
||||||
bar_size = 4;
|
|
||||||
break;
|
|
||||||
case VIZ_BARSPEC8:
|
|
||||||
bar_size = 8;
|
|
||||||
break;
|
|
||||||
case VIZ_BARSPEC16:
|
|
||||||
bar_size = 16;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
int total_bars = FFT_LENGTH / 2;
|
int total_bars = FFT_LENGTH / 2;
|
||||||
WDL_FFT_COMPLEX *bins[2] = { (WDL_FFT_COMPLEX *)m_fft_buf[0], (WDL_FFT_COMPLEX *)m_fft_buf[1] };
|
WDL_FFT_COMPLEX *bins[2] = { (WDL_FFT_COMPLEX *)m_fft_buf[0], (WDL_FFT_COMPLEX *)m_fft_buf[1] };
|
||||||
for (int bar = 0; bar < total_bars && bar < SCREEN_WIDTH; bar += bar_size)
|
|
||||||
|
for (int bar = 2; bar < total_bars && bar < width; bar += BarSize)
|
||||||
{
|
{
|
||||||
if (bar < 2)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
float max_val = 0.0f;
|
float max_val = 0.0f;
|
||||||
for (int sub_bar = 0; sub_bar < bar_size && (bar + sub_bar) < total_bars; sub_bar++)
|
for (int sub_bar = 0; sub_bar < BarSize && (bar + sub_bar) < total_bars; sub_bar++)
|
||||||
{
|
{
|
||||||
int permuted = WDL_fft_permute(FFT_LENGTH/2, bar + sub_bar);
|
int permuted = WDL_fft_permute(FFT_LENGTH/2, bar + sub_bar);
|
||||||
max_val = std::max<float>((bins[0][permuted].re + bins[1][permuted].re) * 0.5f, max_val);
|
const float max_channel = std::max<float>(bins[0][permuted].re, bins[1][permuted].re);
|
||||||
|
max_val = std::max<float>(max_channel, max_val);
|
||||||
}
|
}
|
||||||
int level = int(logf(max_val * 32768.0f) * 96.0f);
|
|
||||||
for (int y = 0; y < SCREEN_HEIGHT; y++)
|
float raw_level = logf(max_val * 32768.0f);
|
||||||
|
|
||||||
|
int level = 0;
|
||||||
|
int pal_index = 0;
|
||||||
|
switch (SpecMode)
|
||||||
{
|
{
|
||||||
int bar_y = SCREEN_HEIGHT - y;
|
case SPEC_VIZ_BAR:
|
||||||
uint32_t *line = &bitmap.pix32(y);
|
level = int(raw_level * 95.0f);
|
||||||
bool lit = bar_y <= level;
|
if (level <= 767)
|
||||||
const int x_limit = bar_size == 1 ? 1 : bar_size - 1;
|
|
||||||
for (int x = 0; x < x_limit; x++)
|
|
||||||
{
|
{
|
||||||
line[(bar - 2) + x] = pal[lit ? (256 + bar) : black_idx];
|
pal_index = 255 - level / 3;
|
||||||
}
|
}
|
||||||
|
for (int y = 0; y < SCREEN_HEIGHT; y++)
|
||||||
|
{
|
||||||
|
int bar_y = SCREEN_HEIGHT - y;
|
||||||
|
uint32_t *line = &bitmap.pix32(y);
|
||||||
|
for (int x = 0; x < BarSize; x++)
|
||||||
|
{
|
||||||
|
line[(bar - 2) + x] = bar_y <= level ? pal[256 + pal_index] : pal[black_index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SPEC_VIZ_PILLAR:
|
||||||
|
level = int(raw_level * 59.0f);
|
||||||
|
if (level < 383)
|
||||||
|
{
|
||||||
|
pal_index = 255 - (int)(level * 0.75f);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int y = 0; y < SCREEN_HEIGHT; y++)
|
||||||
|
{
|
||||||
|
int bar_y = SCREEN_HEIGHT - y;
|
||||||
|
uint32_t *line = &bitmap.pix32(y);
|
||||||
|
line[0] = 0;
|
||||||
|
if (bar_y > level)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const uint32_t entry = pal[256 + pal_index];
|
||||||
|
for (int x = (bar_y < level) ? 0 : 1; x < (BarSize - 1); x++)
|
||||||
|
{
|
||||||
|
if (bar_y < (level - 1))
|
||||||
|
{
|
||||||
|
const uint8_t r = (uint8_t)(((entry >> 16) & 0xff) * 0.75f);
|
||||||
|
const uint8_t g = (uint8_t)(((entry >> 8) & 0xff) * 0.75f);
|
||||||
|
const uint8_t b = (uint8_t)(((entry >> 0) & 0xff) * 0.75f);
|
||||||
|
line[(bar - 2) + x] = 0xff000000 | (r << 16) | (g << 8) | b;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
line[(bar - 2) + x] = pal[256 + pal_index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const uint8_t r = (uint8_t)(((entry >> 16) & 0xff) * 0.5f);
|
||||||
|
const uint8_t g = (uint8_t)(((entry >> 8) & 0xff) * 0.5f);
|
||||||
|
const uint8_t b = (uint8_t)(((entry >> 0) & 0xff) * 0.5f);
|
||||||
|
line[(bar - 2) + (BarSize - 1)] = 0xff000000 | (r << 16) | (g << 8) | b;
|
||||||
|
if (bar_y < level)
|
||||||
|
{
|
||||||
|
line[(bar - 2) + (BarSize - 2)] = 0xff000000 | (r << 16) | (g << 8) | b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int x = 0; x < SCREEN_WIDTH; x++)
|
||||||
|
{
|
||||||
|
bitmap.pix32(SCREEN_HEIGHT - 1, x) = 0;
|
||||||
|
bitmap.pix32(SCREEN_HEIGHT - 2, x) = 0;
|
||||||
|
}
|
||||||
|
memcpy(&m_bitmap.pix32(0), &bitmap.pix32(0), sizeof(uint32_t) * SCREEN_WIDTH * SCREEN_HEIGHT);
|
||||||
|
break;
|
||||||
|
case SPEC_VIZ_TOP:
|
||||||
|
level = int(raw_level * 63.0f);
|
||||||
|
if (level < 255)
|
||||||
|
{
|
||||||
|
pal_index = 255 - level;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int x = 0; x < BarSize; x++)
|
||||||
|
{
|
||||||
|
bitmap.pix32(SCREEN_HEIGHT - 1, (bar - 2) + x) = level > 0 ? pal[256 + pal_index] : pal[black_index];
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(&m_bitmap.pix32(0), &bitmap.pix32(0), sizeof(uint32_t) * SCREEN_WIDTH * SCREEN_HEIGHT);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,16 +50,31 @@ public:
|
|||||||
void toggle_normalize();
|
void toggle_normalize();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
enum spec_viz_mode : int
|
||||||
|
{
|
||||||
|
SPEC_VIZ_BAR,
|
||||||
|
SPEC_VIZ_PILLAR,
|
||||||
|
SPEC_VIZ_TOP
|
||||||
|
};
|
||||||
|
|
||||||
enum viz_mode : int
|
enum viz_mode : int
|
||||||
{
|
{
|
||||||
VIZ_WAVEFORM,
|
VIZ_WAVEFORM,
|
||||||
VIZ_WATERFALL,
|
VIZ_WATERFALL,
|
||||||
|
|
||||||
VIZ_SPEC_START,
|
VIZ_SPEC_START,
|
||||||
VIZ_RAWSPEC = VIZ_SPEC_START,
|
VIZ_RAW_SPEC = VIZ_SPEC_START,
|
||||||
VIZ_BARSPEC4,
|
VIZ_TOP_SPEC,
|
||||||
VIZ_BARSPEC8,
|
VIZ_BAR_SPEC4,
|
||||||
VIZ_BARSPEC16,
|
VIZ_PILLAR_SPEC4,
|
||||||
VIZ_SPEC_END = VIZ_BARSPEC16,
|
VIZ_TOP_SPEC4,
|
||||||
|
VIZ_BAR_SPEC8,
|
||||||
|
VIZ_PILLAR_SPEC8,
|
||||||
|
VIZ_TOP_SPEC8,
|
||||||
|
VIZ_BAR_SPEC16,
|
||||||
|
VIZ_PILLAR_SPEC16,
|
||||||
|
VIZ_TOP_SPEC16,
|
||||||
|
VIZ_SPEC_END = VIZ_TOP_SPEC16,
|
||||||
|
|
||||||
VIZ_COUNT
|
VIZ_COUNT
|
||||||
};
|
};
|
||||||
@ -86,7 +101,7 @@ protected:
|
|||||||
uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
|
uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
|
||||||
void draw_waveform(bitmap_rgb32 &bitmap);
|
void draw_waveform(bitmap_rgb32 &bitmap);
|
||||||
void draw_waterfall(bitmap_rgb32 &bitmap);
|
void draw_waterfall(bitmap_rgb32 &bitmap);
|
||||||
void draw_spectrogram(bitmap_rgb32 &bitmap);
|
template <int BarSize, int SpecMode> void draw_spectrogram(bitmap_rgb32 &bitmap);
|
||||||
|
|
||||||
void fill_window();
|
void fill_window();
|
||||||
void apply_window(uint32_t buf_index);
|
void apply_window(uint32_t buf_index);
|
||||||
@ -114,6 +129,9 @@ protected:
|
|||||||
|
|
||||||
float m_window[FFT_LENGTH];
|
float m_window[FFT_LENGTH];
|
||||||
|
|
||||||
|
bitmap_rgb32 m_bitmap;
|
||||||
|
bool m_clear_pending;
|
||||||
|
|
||||||
viz_mode m_viz_mode;
|
viz_mode m_viz_mode;
|
||||||
|
|
||||||
static const bool NEEDS_FFT[VIZ_COUNT];
|
static const bool NEEDS_FFT[VIZ_COUNT];
|
||||||
|
Loading…
Reference in New Issue
Block a user