Files
projectm/src/libprojectM/ProjectMCWrapper.cpp
Kai Blaschke 69d2134fa2 Rewrite of audio data processing/beat detection.
Consolidated audio processing code into the PCM class, removing the BeatDetect class in the process. Beat detection now uses the same algorithm as Milkdrop, passing the proper relative bass/mid/treb values to presets. Makes many presets look less jumpy/flickering, as the values are now (smoothly) alternating around 1.0.

Updating frame audio is now done in a function that must specifically be called. Any subsequent calls to GetFrameAudioData() will then return the exact same copy of the audio data. As of now with the exception that new waveform data may be passed in via a separate thread, which will then be returned and might not match the spectrum data. Will fix that in a later commit.
2023-11-24 21:00:39 +01:00

378 lines
11 KiB
C++

#include "ProjectMCWrapper.hpp"
#include "projectM-4/projectM.h"
#include "Audio/AudioConstants.hpp"
#include <cstring>
#include <sstream>
void projectMWrapper::PresetSwitchRequestedEvent(bool isHardCut) const
{
if (m_presetSwitchRequestedEventCallback)
{
m_presetSwitchRequestedEventCallback(isHardCut, m_presetSwitchRequestedEventUserData);
}
}
void projectMWrapper::PresetSwitchFailedEvent(const std::string& presetFilename,
const std::string& failureMessage) const
{
if (m_presetSwitchFailedEventCallback)
{
m_presetSwitchFailedEventCallback(presetFilename.c_str(),
failureMessage.c_str(), m_presetSwitchFailedEventUserData);
}
}
projectMWrapper* handle_to_instance(projectm_handle instance)
{
return reinterpret_cast<projectMWrapper*>(instance);
}
char* projectm_alloc_string(unsigned int length)
{
try
{
return new char[length]{};
}
catch (...)
{
return nullptr;
}
}
char* projectm_alloc_string_from_std_string(const std::string& str)
{
auto pointer = projectm_alloc_string(str.length() + 1);
if (pointer)
{
memcpy(pointer, str.c_str(), str.length());
}
return pointer;
}
void projectm_free_string(const char* str)
{
delete[] str;
}
projectm_handle projectm_create()
{
try
{
auto projectMInstance = new projectMWrapper();
return reinterpret_cast<projectm_handle>(projectMInstance);
}
catch (...)
{
return nullptr;
}
}
void projectm_destroy(projectm_handle instance)
{
auto projectMInstance = handle_to_instance(instance);
delete projectMInstance;
}
void projectm_load_preset_file(projectm_handle instance, const char* filename,
bool smooth_transition)
{
auto projectMInstance = handle_to_instance(instance);
projectMInstance->LoadPresetFile(filename, smooth_transition);
}
void projectm_load_preset_data(projectm_handle instance, const char* data,
bool smooth_transition)
{
std::stringstream presetDataStream(data);
auto projectMInstance = handle_to_instance(instance);
projectMInstance->LoadPresetData(presetDataStream, smooth_transition);
}
void projectm_set_preset_switch_requested_event_callback(projectm_handle instance,
projectm_preset_switch_requested_event callback, void* user_data)
{
auto projectMInstance = handle_to_instance(instance);
projectMInstance->m_presetSwitchRequestedEventCallback = callback;
projectMInstance->m_presetSwitchRequestedEventUserData = user_data;
}
void projectm_set_preset_switch_failed_event_callback(projectm_handle instance,
projectm_preset_switch_failed_event callback, void* user_data)
{
auto projectMInstance = handle_to_instance(instance);
projectMInstance->m_presetSwitchFailedEventCallback = callback;
projectMInstance->m_presetSwitchFailedEventUserData = user_data;
}
void projectm_set_texture_search_paths(projectm_handle instance,
const char** texture_search_paths,
size_t count)
{
auto projectMInstance = handle_to_instance(instance);
std::vector<std::string> texturePaths;
for (size_t index = 0; index < count; index++)
{
texturePaths.emplace_back(texture_search_paths[index]);
}
projectMInstance->SetTexturePaths(texturePaths);
}
void projectm_reset_textures(projectm_handle instance)
{
auto projectMInstance = handle_to_instance(instance);
projectMInstance->ResetTextures();
}
void projectm_get_version_components(int* major, int* minor, int* patch)
{
if (major != nullptr)
{
*major = PROJECTM_VERSION_MAJOR;
}
if (minor != nullptr)
{
*minor = PROJECTM_VERSION_MINOR;
}
if (patch != nullptr)
{
*patch = PROJECTM_VERSION_PATCH;
}
}
char* projectm_get_version_string()
{
auto versionLength = strlen(PROJECTM_VERSION_STRING);
auto buffer = projectm_alloc_string(versionLength + 1);
strncpy(buffer, PROJECTM_VERSION_STRING, versionLength + 1);
return buffer;
}
char* projectm_get_vcs_version_string()
{
auto versionLength = strlen(PROJECTM_VERSION_VCS);
auto buffer = projectm_alloc_string(versionLength + 1);
strncpy(buffer, PROJECTM_VERSION_VCS, versionLength + 1);
return buffer;
}
void projectm_opengl_render_frame(projectm_handle instance)
{
auto projectMInstance = handle_to_instance(instance);
projectMInstance->RenderFrame();
}
void projectm_set_beat_sensitivity(projectm_handle instance, float sensitivity)
{
auto projectMInstance = handle_to_instance(instance);
projectMInstance->SetBeatSensitivity(sensitivity);
}
float projectm_get_beat_sensitivity(projectm_handle instance)
{
auto projectMInstance = handle_to_instance(instance);
return projectMInstance->GetBeatSensitivity();
}
double projectm_get_hard_cut_duration(projectm_handle instance)
{
auto projectMInstance = handle_to_instance(instance);
return projectMInstance->HardCutDuration();
}
void projectm_set_hard_cut_duration(projectm_handle instance, double seconds)
{
auto projectMInstance = handle_to_instance(instance);
projectMInstance->SetHardCutDuration(seconds);
}
bool projectm_get_hard_cut_enabled(projectm_handle instance)
{
auto projectMInstance = handle_to_instance(instance);
return projectMInstance->HardCutEnabled();
}
void projectm_set_hard_cut_enabled(projectm_handle instance, bool enabled)
{
auto projectMInstance = handle_to_instance(instance);
projectMInstance->SetHardCutEnabled(enabled);
}
float projectm_get_hard_cut_sensitivity(projectm_handle instance)
{
auto projectMInstance = handle_to_instance(instance);
return projectMInstance->HardCutSensitivity();
}
void projectm_set_hard_cut_sensitivity(projectm_handle instance, float sensitivity)
{
auto projectMInstance = handle_to_instance(instance);
projectMInstance->SetHardCutSensitivity(sensitivity);
}
double projectm_get_soft_cut_duration(projectm_handle instance)
{
auto projectMInstance = handle_to_instance(instance);
return projectMInstance->SoftCutDuration();
}
void projectm_set_soft_cut_duration(projectm_handle instance, double seconds)
{
auto projectMInstance = handle_to_instance(instance);
projectMInstance->SetSoftCutDuration(seconds);
}
double projectm_get_preset_duration(projectm_handle instance)
{
auto projectMInstance = handle_to_instance(instance);
return projectMInstance->PresetDuration();
}
void projectm_set_preset_duration(projectm_handle instance, double seconds)
{
auto projectMInstance = handle_to_instance(instance);
projectMInstance->SetPresetDuration(seconds);
}
void projectm_get_mesh_size(projectm_handle instance, size_t* width, size_t* height)
{
auto projectMInstance = handle_to_instance(instance);
projectMInstance->MeshSize(*width, *height);
}
void projectm_set_mesh_size(projectm_handle instance, size_t width, size_t height)
{
auto projectMInstance = handle_to_instance(instance);
projectMInstance->SetMeshSize(width, height);
}
int32_t projectm_get_fps(projectm_handle instance)
{
auto projectMInstance = handle_to_instance(instance);
return projectMInstance->TargetFramesPerSecond();
}
void projectm_set_fps(projectm_handle instance, int32_t fps)
{
auto projectMInstance = handle_to_instance(instance);
projectMInstance->SetTargetFramesPerSecond(fps);
}
void projectm_set_aspect_correction(projectm_handle instance, bool enabled)
{
auto projectMInstance = handle_to_instance(instance);
projectMInstance->SetAspectCorrection(enabled);
}
bool projectm_get_aspect_correction(projectm_handle instance)
{
auto projectMInstance = handle_to_instance(instance);
return projectMInstance->AspectCorrection();
}
void projectm_set_easter_egg(projectm_handle instance, float value)
{
auto projectMInstance = handle_to_instance(instance);
projectMInstance->SetEasterEgg(value);
}
float projectm_get_easter_egg(projectm_handle instance)
{
auto projectMInstance = handle_to_instance(instance);
return projectMInstance->EasterEgg();
}
void projectm_touch(projectm_handle instance, float x, float y, int pressure, projectm_touch_type touch_type)
{
auto projectMInstance = handle_to_instance(instance);
projectMInstance->Touch(x, y, pressure, touch_type);
}
void projectm_touch_drag(projectm_handle instance, float x, float y, int pressure)
{
auto projectMInstance = handle_to_instance(instance);
projectMInstance->TouchDrag(x, y, pressure);
}
void projectm_touch_destroy(projectm_handle instance, float x, float y)
{
auto projectMInstance = handle_to_instance(instance);
projectMInstance->TouchDestroy(x, y);
}
void projectm_touch_destroy_all(projectm_handle instance)
{
auto projectMInstance = handle_to_instance(instance);
projectMInstance->TouchDestroyAll();
}
bool projectm_get_preset_locked(projectm_handle instance)
{
auto projectMInstance = handle_to_instance(instance);
return projectMInstance->PresetLocked();
}
void projectm_set_preset_locked(projectm_handle instance, bool lock)
{
auto projectMInstance = handle_to_instance(instance);
projectMInstance->SetPresetLocked(lock);
}
void projectm_get_window_size(projectm_handle instance, size_t* width, size_t* height)
{
auto projectMInstance = handle_to_instance(instance);
*width = projectMInstance->WindowWidth();
*height = projectMInstance->WindowHeight();
}
void projectm_set_window_size(projectm_handle instance, size_t width, size_t height)
{
auto projectMInstance = handle_to_instance(instance);
projectMInstance->ResetOpenGL(width, height);
}
unsigned int projectm_pcm_get_max_samples()
{
return libprojectM::Audio::WaveformSamples;
}
template<class BufferType>
static auto PcmAdd(projectm_handle instance, const BufferType* samples, unsigned int count, projectm_channels channels) -> void
{
auto* projectMInstance = handle_to_instance(instance);
projectMInstance->PCM().Add(samples, channels, count);
}
auto projectm_pcm_add_float(projectm_handle instance, const float* samples, unsigned int count, projectm_channels channels) -> void
{
PcmAdd(instance, samples, count, channels);
}
auto projectm_pcm_add_int16(projectm_handle instance, const int16_t* samples, unsigned int count, projectm_channels channels) -> void
{
PcmAdd(instance, samples, count, channels);
}
auto projectm_pcm_add_uint8(projectm_handle instance, const uint8_t* samples, unsigned int count, projectm_channels channels) -> void
{
PcmAdd(instance, samples, count, channels);
}
auto projectm_write_debug_image_on_next_frame(projectm_handle instance, const char* output_file) -> void
{
auto* projectMInstance = handle_to_instance(instance);
std::string outputFile;
if (output_file)
{
outputFile = output_file;
}
projectMInstance->DumpDebugImageOnNextFrame(outputFile);
}