Исходник ImGui(C++) - Music / SoundBars / exp 3.1 + Розыгрыш

get good, get zeus, for ever
Участник
Участник
Статус
Оффлайн
Регистрация
1 Июн 2018
Сообщения
706
Реакции
152
Выкладываю исходник саундбара для ImGui на C++.
В качестве примера — видео, где видно, как работает саундбар на музыке но без музыки.


Розыгрыш:
Если угадаете, что за песня играет на видео, скину победителю скины для CS2 в Steam на 500 рублей.


Условия:
— Два варианта в одном сообщении. Писать можете сколько угодно раз.
— Ответы отправляйте мне под хайдом в этой теме.
— Кто первый угадает — тому скромный приз скинами в Steam(около 500+ рублей).
Видео:

AudioProcessor.h:
Expand Collapse Copy
#pragma once
#include <vector>

#define MINIAUDIO_IMPLEMENTATION
#include <miniaudio.h>

class AudioProcessor {
public:
    AudioProcessor();
    ~AudioProcessor();

    void Update();

    const std::vector<float>& GetBands() const;

private:
    std::vector<float> bands;
    void ProcessFFT(const float* samples, size_t count);
};

AudioProcessor.cpp:
Expand Collapse Copy
#include "AudioProcessor.h"
#include <miniaudio.h>
#include <kissfft/kiss_fft.h>
#include <cmath>
#include <cstring>
#include <stdexcept>

static const int FFT_SIZE = 1024;

static ma_context context;
static ma_device device;
static std::vector<float> audioBuffer;
static std::vector<float> windowedSamples;
static kiss_fft_cfg fft_cfg = nullptr;

AudioProcessor::AudioProcessor() : bands(6, 0.0f) {
    ma_context_init(NULL, 0, NULL, &context);

    ma_device_config config = ma_device_config_init(ma_device_type_loopback);
    config.capture.format = ma_format_f32;
    config.capture.channels = 1;
    config.sampleRate = 48000;
    config.dataCallback = [](ma_device* d, void* out, const void* in, ma_uint32 frameCount) {
        const float* fIn = (const float*)in;
        for (ma_uint32 i = 0; i < frameCount; ++i)
            audioBuffer.push_back(fIn[i]);

        if (audioBuffer.size() > FFT_SIZE * 4)
            audioBuffer.erase(audioBuffer.begin(), audioBuffer.end() - FFT_SIZE * 4);
        };
    config.pUserData = nullptr;

    if (ma_device_init(&context, &config, &device) != MA_SUCCESS) {
        throw std::runtime_error("Failed to initialize loopback device");
    }

    fft_cfg = kiss_fft_alloc(FFT_SIZE, 0, NULL, NULL);
    audioBuffer.reserve(FFT_SIZE * 4);
    windowedSamples.resize(FFT_SIZE);

    ma_device_start(&device);
}

AudioProcessor::~AudioProcessor() {
    ma_device_uninit(&device);
    ma_context_uninit(&context);
    if (fft_cfg) free(fft_cfg);
}

void AudioProcessor::Update() {
    if (audioBuffer.size() < FFT_SIZE) return;

    std::copy(audioBuffer.end() - FFT_SIZE, audioBuffer.end(), windowedSamples.begin());

    for (int i = 0; i < FFT_SIZE; ++i) {
        windowedSamples[i] *= 0.5f * (1.0f - cosf(2.0f * 3.14159f * i / (FFT_SIZE - 1)));
    }

    ProcessFFT(windowedSamples.data(), FFT_SIZE);
}

void AudioProcessor::ProcessFFT(const float* samples, size_t count) {
    std::vector<kiss_fft_cpx> in(count), out(count);
    for (size_t i = 0; i < count; ++i) {
        in[i].r = samples[i];
        in[i].i = 0.0f;
    }

    kiss_fft(fft_cfg, in.data(), out.data());

    std::vector<float> magnitudes(count / 2);
    for (size_t i = 0; i < count / 2; ++i) {
        magnitudes[i] = sqrtf(out[i].r * out[i].r + out[i].i * out[i].i);
    }

    // 6 полос: низ → верх
    int bandsMap[6][2] = {
        { 1, 4 },    // суббас
        { 5, 15 },   // бас
        { 16, 40 },  // нижняя середина
        { 41, 100 }, // середина
        { 101, 200 },// верхняя середина
        { 201, 400 } // высокие
    };

    for (int b = 0; b < 6; ++b) {
        float sum = 0.0f;
        int from = bandsMap[b][0], to = bandsMap[b][1];
        for (int i = from; i <= to && i < magnitudes.size(); ++i)
            sum += magnitudes[i];
        bands[b] = sum / (to - from + 1);
    }
}

const std::vector<float>& AudioProcessor::GetBands() const {
    return bands;
}


soundbar begin:
Expand Collapse Copy
should be called outside of cycle
AudioProcessor audio;

should be called in while
        audio.Update();
        const auto& bands = audio.GetBands();
   
   
{
    {
        ImGui::Begin("Audio Visualizer");
        {
            ImVec2 window_origin = ImGui::GetCursorScreenPos();
            ImVec2 visualizer_size = ImVec2(752, 752);
            ImRect visualizer_bb(window_origin, window_origin + visualizer_size);

            const float visualizer_padding = 6.0f;
            ImRect visualizer_inner_bb(visualizer_bb.Min + ImVec2(visualizer_padding, visualizer_padding), visualizer_bb.Max - ImVec2(visualizer_padding, visualizer_padding));

            ImDrawList* draw_list = ImGui::GetWindowDrawList();

            draw_list->AddRectFilled(visualizer_bb.Min, visualizer_bb.Max, IM_COL32(20, 20, 30, 0), 4.0f);
            draw_list->AddRect(visualizer_inner_bb.Min, visualizer_inner_bb.Max, IM_COL32(100, 100, 150, 0), 4.0f);

            float visualizer_center_y = (visualizer_inner_bb.Min.y + visualizer_inner_bb.Max.y) * 0.5f;
            const float bar_max_height = (visualizer_inner_bb.GetHeight() * 0.5f) - 2.0f;

            const int bars_count = 6;
            const float bar_width = 22.0f;
            float visualizer_inner_width = visualizer_inner_bb.GetWidth();
            float bar_spacing = (visualizer_inner_width - bars_count * bar_width) / (bars_count + 1);

            static std::unordered_map<ImGuiID, float> current_bar_heights;
            static std::unordered_map<ImGuiID, float> bar_peak_heights;
            static std::unordered_map<ImGuiID, float> bar_fall_speeds;

            static float global_signal_max = 0.1f;
            float current_signal_max = 0.0f;
            for (int bar_index = 0; bar_index < bars_count; ++bar_index) {
                current_signal_max = ImMax(current_signal_max, bands[bar_index]);
            }
            global_signal_max = ImMax(global_signal_max * 0.997f, current_signal_max * 1.05f);

            const float band_sensitivity_correction[bars_count] = { 0.6f, 0.8f, 1.0f, 1.2f, 1.5f, 2.0f };

            for (int bar_index = 0; bar_index < bars_count; ++bar_index) {
                ImGuiID bar_id = ImGui::GetID(bar_index);

                float band_raw_amplitude = bands[bar_index];
                float band_scaled_amplitude = (logf(1.0f + band_raw_amplitude * 20.0f) * band_sensitivity_correction[bar_index]) / (logf(1.0f + global_signal_max * 20.0f) + 0.001f);

                float bar_target_height = ImClamp(band_scaled_amplitude * bar_max_height, 2.0f, bar_max_height);

                if (!current_bar_heights.count(bar_id)) {
                    current_bar_heights[bar_id] = bar_target_height;
                    bar_peak_heights[bar_id] = bar_target_height;
                    bar_fall_speeds[bar_id] = 0.3f;
                }

                float& bar_current_height = current_bar_heights[bar_id];
                float& bar_peak_height = bar_peak_heights[bar_id];
                float& bar_fall_speed = bar_fall_speeds[bar_id];

                if (bar_target_height > bar_current_height) {
                    bar_current_height = ImLerp(bar_current_height, bar_target_height, 0.7f);
                    bar_peak_height = bar_target_height;
                    bar_fall_speed = 0.01f;
                }
                else {
                    bar_fall_speed = ImMin(bar_fall_speed + 0.02f, 0.95f);
                    bar_current_height = ImLerp(bar_current_height, bar_target_height, bar_fall_speed);
                }

                float bar_center_x = visualizer_inner_bb.Min.x + bar_spacing * (bar_index + 1) + bar_width * bar_index + bar_width * 0.5f;

                ImVec2 bar_top_left(bar_center_x, visualizer_center_y - bar_current_height);
                ImVec2 bar_bottom_right(bar_center_x, visualizer_center_y + bar_current_height);

                float amplitude_ratio = bar_current_height / bar_max_height;
                ImU32 bar_color = IM_COL32(100 + (int)(155 * amplitude_ratio), 150, 255 - (int)(155 * amplitude_ratio), 220);

                draw_list->AddRectFilled(bar_top_left, bar_bottom_right + ImVec2(bar_width, 0), bar_color, bar_width);
            }

            ImGui::Dummy(visualizer_size);
        }

        ImGui::End();
    }
}
Если что музыка обрывается в конце, она до играла не до конца но с самого начала играла.
Так же на видео отчётливо видно биты и тд тп.
 
Последнее редактирование:
я глухой или на видосе нет музыки?)
достаточно бесполезная вещь, но приколько
 
Обратите внимание, пользователь заблокирован на форуме. Не рекомендуется проводить сделки.
на видосе играет песня "..."
 
Назад
Сверху Снизу