Deleted all playlist-related code from libprojectM.

Note: SDL test UI won't compile after this commit. Will be fixed in a later commit, when the playlist library is done.
This commit is contained in:
Kai Blaschke
2022-11-06 14:35:45 +01:00
parent 7363afecc2
commit b23b5ce25c
17 changed files with 341 additions and 2109 deletions

View File

@ -32,7 +32,7 @@
extern "C" {
#endif
struct projectm; //!< Opaque projectM instance type.
struct projectm; //!< Opaque projectM instance type.
typedef struct projectm* projectm_handle; //!< A pointer to the opaque projectM instance.
/**
@ -48,42 +48,30 @@ typedef struct projectm* projectm_handle; //!< A pointer to the opaque projectM
* projectm_free_settings() will automatically call projectm_free_string() on it. If you free it on your own, remember
* to reset the pointer to NULL after doing so!</p>
*/
typedef struct PROJECTM_EXPORT projectm_settings_s
{
int mesh_x; //!< Per-pixel mesh X resolution.
int mesh_y; //!< Per-pixel mesh Y resolution.
int fps; //!< Target rendering frames per second.
int texture_size; //!< Size of the render texture. Must be a power of 2.
int window_width; //!< Width of the rendering viewport.
int window_height; //!< Height of the rendering viewport.
char* preset_path; //!< Path with preset files to be loaded into the playlist. Use FLAG_DISABLE_PLAYLIST_LOAD to skip automatic loading of presets.
char* texture_path; //!< Additional path with texture files for use in presets.
char* data_path; //!< Path to data files like default textures and presets.
double preset_duration; //!< Display duration for each preset in seconds.
double soft_cut_duration; //!< Blend-over duration between two presets in seconds.
double hard_cut_duration; //!< Minimum time in seconds a preset is displayed before a hard cut can happen.
bool hard_cut_enabled; //!< Set to true to enable fast beat-driven preset switches.
float hard_cut_sensitivity; //!< Beat sensitivity value that must be surpassed for a hard cut.
float beat_sensitivity; //!< Beat sensitivity. Standard sensitivity is 1.0.
bool aspect_correction; //!< Use aspect ration correction in presets that support it.
float easter_egg; //!< Used as the "sigma" value for a gaussian RNG to randomize preset duration. Unused on Windows.
bool shuffle_enabled; //!< Enable playlist shuffle, selecting a random preset on each switch instead of the next in list.
bool soft_cut_ratings_enabled; //!< If true, use soft cut ratings on soft cuts and hard cut ratings on hard cuts. If false, the hard cut rating is always used.
typedef struct PROJECTM_EXPORT projectm_settings_s {
int mesh_x; //!< Per-pixel mesh X resolution.
int mesh_y; //!< Per-pixel mesh Y resolution.
int fps; //!< Target rendering frames per second.
int texture_size; //!< Size of the render texture. Must be a power of 2.
int window_width; //!< Width of the rendering viewport.
int window_height; //!< Height of the rendering viewport.
char* texture_path; //!< Additional path with texture files for use in presets.
char* data_path; //!< Path to data files like default textures and presets.
double preset_duration; //!< Display duration for each preset in seconds.
double soft_cut_duration; //!< Blend-over duration between two presets in seconds.
double hard_cut_duration; //!< Minimum time in seconds a preset is displayed before a hard cut can happen.
bool hard_cut_enabled; //!< Set to true to enable fast beat-driven preset switches.
float hard_cut_sensitivity; //!< Beat sensitivity value that must be surpassed for a hard cut.
float beat_sensitivity; //!< Beat sensitivity. Standard sensitivity is 1.0.
bool aspect_correction; //!< Use aspect ration correction in presets that support it.
float easter_egg; //!< Used as the "sigma" value for a gaussian RNG to randomize preset duration. Unused on Windows.
} projectm_settings;
/**
* Flags that influence projectM instance creation.
*/
typedef enum
{
PROJECTM_FLAG_NONE = 0, //!< No flags.
PROJECTM_FLAG_DISABLE_PLAYLIST_LOAD = 1 << 0 //!< Set this flag to disable loading a preset playlist on startup.
} projectm_flags;
/**
* For specifying audio data format.
*/
typedef enum {
typedef enum
{
PROJECTM_MONO = 1,
PROJECTM_STEREO = 2
} projectm_channels;
@ -95,7 +83,7 @@ typedef enum {
typedef enum
{
PROJECTM_HARD_CUT_RATING_TYPE, //!< Rating for hard cuts.
PROJECTM_SOFT_CUT_RATING_TYPE //!< Rating for soft cuts.
PROJECTM_SOFT_CUT_RATING_TYPE //!< Rating for soft cuts.
} projectm_preset_rating_type;
/**
@ -106,7 +94,7 @@ typedef enum
PROJECTM_CHANNEL_L = 0, //!< Left audio channel.
PROJECTM_CHANNEL_0 = 0, //!< Left audio channel.
PROJECTM_CHANNEL_R = 1, //!< Right audio channel.
PROJECTM_CHANNEL_1 = 1 //!< Right audio channel.
PROJECTM_CHANNEL_1 = 1 //!< Right audio channel.
} projectm_pcm_channel;
/**
@ -114,15 +102,15 @@ typedef enum
*/
typedef enum
{
PROJECTM_TOUCH_TYPE_RANDOM, //!< Random waveform type.
PROJECTM_TOUCH_TYPE_CIRCLE, //!< Draws a circular waveform.
PROJECTM_TOUCH_TYPE_RADIAL_BLOB, //!< Draws a radial blob waveform.
PROJECTM_TOUCH_TYPE_BLOB2,//!< Draws a blob-style waveform.
PROJECTM_TOUCH_TYPE_BLOB3, //!< Draws another blob-style waveform.
PROJECTM_TOUCH_TYPE_RANDOM, //!< Random waveform type.
PROJECTM_TOUCH_TYPE_CIRCLE, //!< Draws a circular waveform.
PROJECTM_TOUCH_TYPE_RADIAL_BLOB, //!< Draws a radial blob waveform.
PROJECTM_TOUCH_TYPE_BLOB2, //!< Draws a blob-style waveform.
PROJECTM_TOUCH_TYPE_BLOB3, //!< Draws another blob-style waveform.
PROJECTM_TOUCH_TYPE_DERIVATIVE_LINE, //!< Draws a derivative-line waveform.
PROJECTM_TOUCH_TYPE_BLOB5, //!< Draws a five-blob waveform.
PROJECTM_TOUCH_TYPE_LINE, //!< Draws a single-line waveform.
PROJECTM_TOUCH_TYPE_DOUBLE_LINE //!< Draws a double-line waveform.
PROJECTM_TOUCH_TYPE_BLOB5, //!< Draws a five-blob waveform.
PROJECTM_TOUCH_TYPE_LINE, //!< Draws a single-line waveform.
PROJECTM_TOUCH_TYPE_DOUBLE_LINE //!< Draws a double-line waveform.
} projectm_touch_type;
/**
@ -183,7 +171,7 @@ PROJECTM_EXPORT void projectm_free_settings(const projectm_settings* settings);
* @param user_data A user-defined data pointer that was provided when registering the callback,
* e.g. context information.
*/
typedef void(* projectm_preset_switched_event)(bool is_hard_cut, unsigned int index, void* user_data);
typedef void (*projectm_preset_switched_event)(bool is_hard_cut, unsigned int index, void* user_data);
/**
* @brief Callback function that is executed is the shuffle setting has changed.
@ -191,22 +179,22 @@ typedef void(* projectm_preset_switched_event)(bool is_hard_cut, unsigned int in
* @param user_data A user-defined data pointer that was provided when registering the callback,
* e.g. context information.
*/
typedef void(* projectm_shuffle_enable_changed_event)(bool shuffle_enabled, void* user_data);
typedef void (*projectm_shuffle_enable_changed_event)(bool shuffle_enabled, void* user_data);
/**
* @brief Callback function that is executed if a preset change failed.
*
* The message pointer is only valid inside the callback. Make a copy if it must be kept
* for later use.
* The message and filename pointers are only valid inside the callback. Make a copy if these values
* need to be retained for later use.
*
* @param is_hard_cut True if the preset was switched using a hard cut via beat detection.
* @param index The playlist index of the new preset.
* @param preset_filename The filename of the failed preset.
* @param message The error message.
* @param user_data A user-defined data pointer that was provided when registering the callback,
* e.g. context information.
*/
typedef void(* projectm_preset_switch_failed_event)(bool is_hard_cut, unsigned int index, const char* message,
void* user_data);
typedef void (*projectm_preset_switch_failed_event)(bool is_hard_cut, const char* preset_filename,
const char* message, void* user_data);
/**
* @brief Callback function that is executed if a preset rating has been changed.
@ -219,30 +207,27 @@ typedef void(* projectm_preset_switch_failed_event)(bool is_hard_cut, unsigned i
* @param user_data A user-defined data pointer that was provided when registering the callback,
* e.g. context information.
*/
typedef void(* projectm_preset_rating_changed_event)(unsigned int index, int rating,
typedef void (*projectm_preset_rating_changed_event)(unsigned int index, int rating,
projectm_preset_rating_type rating_type, void* user_data);
/**
* @brief Creates a new projectM instance, reading settings from the given file.
* @param setting_file_path A path to the settings file to read the configuration from.
* If NULL or an empty path are provided, default settings will be used.
* @param flags Any combination of values from the projectm_flags enumeration.
* @return A projectM handle for the newly created instance that must be used in subsequent API calls.
* NULL if the instance could not be created successfully.
*/
PROJECTM_EXPORT projectm_handle projectm_create(const char* setting_file_path, int flags);
PROJECTM_EXPORT projectm_handle projectm_create(const char* setting_file_path);
/**
* @brief Creates a new projectM instance with given settings.
* @param settings A pointer to a projectm_settings_t with the settings to be used by the new instance.
* If this pointer is NULL, default settings will be used.
* @param flags Any combination of values from the projectm_flags enumeration.
* @return A projectM handle for the newly created instance that must be used in subsequent API calls.
* NULL if the instance could not be created successfully.
*/
PROJECTM_EXPORT projectm_handle projectm_create_settings(const projectm_settings* settings, int flags);
PROJECTM_EXPORT projectm_handle projectm_create_settings(const projectm_settings* settings);
/**
* @brief Destroys the given instance and frees the resources.
@ -534,13 +519,6 @@ PROJECTM_EXPORT int32_t projectm_get_fps(projectm_handle instance);
*/
PROJECTM_EXPORT void projectm_set_fps(projectm_handle instance, int32_t fps);
/**
* @brief Returns the search path for presets and textures.
* @param instance The projectM instance handle.
* @return The path used to search for presets and textures.
*/
PROJECTM_EXPORT const char* projectm_get_preset_path(projectm_handle instance);
/**
* @brief Returns the search path for additional textures.
* @param instance The projectM instance handle.
@ -654,34 +632,6 @@ PROJECTM_EXPORT projectm_settings* projectm_get_settings(projectm_handle instanc
*/
PROJECTM_EXPORT void projectm_write_config(const char* config_file, const projectm_settings* settings);
/**
* @brief Selects a preset, but does not display it.
* @param instance The projectM instance handle.
* @param index The preset index to select.
*/
PROJECTM_EXPORT void projectm_select_preset_position(projectm_handle instance, unsigned int index);
/**
* @brief Selects and displays the preset.
* @param instance The projectM instance handle.
* @param index the preset to display.
* @param hard_cut If true, a hard cut is made, otherwise it will be blended smoothly.
*/
PROJECTM_EXPORT void projectm_select_preset(projectm_handle instance, unsigned int index, bool hard_cut);
/**
* @brief Removes a preset from the playlist.
* @param instance The projectM instance handle.
* @param index The preset index to remove from the playlist.
*/
PROJECTM_EXPORT void projectm_remove_preset(projectm_handle instance, unsigned int index);
/**
* @brief Clears the preset playlist.
* @param instance The projectM instance handle.
*/
PROJECTM_EXPORT void projectm_clear_playlist(projectm_handle instance);
/**
* @brief Locks or unlocks the current preset.
*
@ -700,183 +650,6 @@ PROJECTM_EXPORT void projectm_lock_preset(projectm_handle instance, bool lock);
*/
PROJECTM_EXPORT bool projectm_is_preset_locked(projectm_handle instance);
/**
* @brief Returns the playlist index for the given preset name.
*
* If the preset name is found multiple times, the first matching index will be returned.
*
* @param instance The projectM instance handle.
* @param preset_name The preset name to search for.
* @return The first found playlist index of the requested preset, or 0 if the preset wasn't found.
*/
PROJECTM_EXPORT unsigned int projectm_get_preset_index(projectm_handle instance, const char* preset_name);
/**
* @brief Displays the preset with the given name.
* @param instance The projectM instance handle.
* @param preset_name The preset name to search for.
* @param hard_cut If true, the preset will be shown immediately, if false a soft transition will be rendered.
*/
PROJECTM_EXPORT void projectm_select_preset_by_name(projectm_handle instance, const char* preset_name, bool hard_cut);
/**
* @brief Returns the currently selected preset index.
* @param instance The projectM instance handle.
* @param index A valid pointer to an unsigned int that will receive the preset index.
* @return True if a preset idnex was returned, false if no preset was selected, e.g. the playlist is empty.
*/
PROJECTM_EXPORT bool projectm_get_selected_preset_index(projectm_handle instance, unsigned int* index);
/**
* @brief Adds a new preset at the end of the playlist.
*
* The rating list is one rating per value of the projectm_preset_rating_type enumeration, with each actual enum
* value used as the index. If the rating list has the wrong length, the preset will not be added.
*
* @param instance The projectM instance handle.
* @param preset_url The full path and filename of the preset.
* @param preset_name The display name of the preset.
* @param rating_list A list with ratings for the preset, one rating per rating type.
* @param rating_list_length Length of the preset rating list.
*/
PROJECTM_EXPORT void projectm_add_preset_url(projectm_handle instance, const char* preset_url,
const char* preset_name, int* rating_list,
unsigned int rating_list_length);
/**
* @brief Adds a new preset at the given position in the playlist.
*
* The rating list is one rating per value of the projectm_preset_rating_type enumeration, with each actual enum
* value used as the index. If the rating list has the wrong length, the preset will not be added.
*
* @param instance The projectM instance handle.
* @param index The playlist index to insert the preset at. Must be less than or equal to the length of
* the playlist.
* @param preset_url The full path and filename of the preset.
* @param preset_name The display name of the preset.
* @param rating_list A list with ratings for the preset, one rating per rating type.
* @param rating_list_length Length of the preset rating list.
*/
PROJECTM_EXPORT void projectm_insert_preset_url(projectm_handle instance, unsigned int index, const char* preset_url,
const char* preset_name, int* rating_list,
unsigned int rating_list_length);
/**
* @brief Returns whether the currently selected preset has a valid position in the playlist.
*
* This function is useful to check if the currently displayed preset is still inside the bounds of
* the current playlist, for example after the playlist was changed.
*
* @param instance The projectM instance handle.
* @return True if the position is valid, false if outside bounds.
*/
PROJECTM_EXPORT bool projectm_preset_position_valid(projectm_handle instance);
/**
* @brief Returns the path and filename of the preset at the requested playlist index.
* @note Make sure the index is inside the playlist bounds!
* @param instance The projectM instance handle.
* @param index The playlist index to return the filename for.
* @return The full path and filename of the preset at the given index.
*/
PROJECTM_EXPORT const char* projectm_get_preset_filename(projectm_handle instance, unsigned int index);
/**
* @brief Returns the display name of the preset at the requested playlist index.
* @note Make sure the index is inside the playlist bounds!
* @param instance The projectM instance handle.
* @param index The playlist index to return the display name for.
* @return The display name of the preset at the given index.
*/
PROJECTM_EXPORT const char* projectm_get_preset_name(projectm_handle instance, unsigned int index);
/**
* @brief Changes the display name of the given preset in the playlist.
* @param instance The projectM instance handle.
* @param index the playlist item index to change.
* @param name The new display name.
*/
PROJECTM_EXPORT void projectm_set_preset_name(projectm_handle instance, unsigned int index, const char* name);
/**
* @brief Returns the rating for the given index and transition type.
* @param instance The projectM instance handle.
* @param index The playlist item to retrieve the rating from.
* @param rating_type The rating type to retrieve, either hard or soft cut.
* @return The rating value of the requested item and type.
*/
PROJECTM_EXPORT int projectm_get_preset_rating(projectm_handle instance, unsigned int index,
projectm_preset_rating_type rating_type);
/**
* @brief Changes the rating or a playlist item and type.
* @param instance The projectM instance handle.
* @param index the playlist item to change the rating of.
* @param rating The new rating value.
* @param rating_type The type of the rating, either hard or soft cut.
*/
PROJECTM_EXPORT void projectm_set_preset_rating(projectm_handle instance, unsigned int index, int rating,
projectm_preset_rating_type rating_type);
/**
* @brief Returns the number of presets in the current playlist.
* @param instance The projectM instance handle.
* @return The number of presets in the currently loaded playlist.
*/
PROJECTM_EXPORT unsigned int projectm_get_playlist_size(projectm_handle instance);
/**
* @brief Returns whether playlist shuffling is currently enabled or not.
* @param instance The projectM instance handle.
* @return True if shuffle is enabled, false if not.
*/
PROJECTM_EXPORT bool projectm_get_shuffle_enabled(projectm_handle instance);
/**
* @brief Enables or disables preset playlist shuffling.
* @param instance The projectM instance handle.
* @param shuffle_enabled True to randomly select the next preset, false to skip to the next item in line.
*/
PROJECTM_EXPORT void projectm_set_shuffle_enabled(projectm_handle instance, bool shuffle_enabled);
/**
* @brief Gets the index of the provided preset name in the current search result list.
* @param instance The projectM instance handle.
* @param name The name of the preset to return the index for.
* @return The search result list index of the given preset name.
*/
PROJECTM_EXPORT unsigned int projectm_get_search_index(projectm_handle instance, const char* name);
/**
* @brief Switches to the previous preset in the current playlist.
*
* This is unaffected by the shuffle mode and will always switch to the previous item.
*
* @param instance The projectM instance handle.
* @param hard_cut True to immediately perform to the previous preset, false to do a soft transition.
*/
PROJECTM_EXPORT void projectm_select_previous_preset(projectm_handle instance, bool hard_cut);
/**
* @brief Switches to the next preset in the current playlist.
*
* This is unaffected by the shuffle mode and will always switch to the next item.
*
* @param instance The projectM instance handle.
* @param hard_cut True to immediately perform to the next preset, false to do a soft transition.
*/
PROJECTM_EXPORT void projectm_select_next_preset(projectm_handle instance, bool hard_cut);
/**
* @brief Switches to a random preset in the current playlist.
*
* This is unaffected by the shuffle mode and will always switch to a random item.
*
* @param instance The projectM instance handle.
* @param hard_cut True to immediately perform to a random preset, false to do a soft transition.
*/
PROJECTM_EXPORT void projectm_select_random_preset(projectm_handle instance, bool hard_cut);
/**
* @brief Returns the current viewport size in pixels.
* @param instance The projectM instance handle.
@ -930,7 +703,7 @@ PROJECTM_EXPORT unsigned int projectm_pcm_get_max_samples();
* Can be PROJECTM_MONO or PROJECTM_STEREO.
*/
PROJECTM_EXPORT void projectm_pcm_add_float(projectm_handle instance, const float* samples,
unsigned int count, projectm_channels channels);
unsigned int count, projectm_channels channels);
/**
* @brief Adds 16-bit integer audio samples.
@ -947,7 +720,7 @@ PROJECTM_EXPORT void projectm_pcm_add_float(projectm_handle instance, const floa
* Can be PROJECTM_MONO or PROJECTM_STEREO.
*/
PROJECTM_EXPORT void projectm_pcm_add_int16(projectm_handle instance, const int16_t* samples,
unsigned int count, projectm_channels channels);
unsigned int count, projectm_channels channels);
/**
* @brief Adds 8-bit unsigned integer audio samples.
@ -964,7 +737,7 @@ PROJECTM_EXPORT void projectm_pcm_add_int16(projectm_handle instance, const int1
* Can be PROJECTM_MONO or PROJECTM_STEREO.
*/
PROJECTM_EXPORT void projectm_pcm_add_uint8(projectm_handle instance, const uint8_t* samples,
unsigned int count, projectm_channels channels);
unsigned int count, projectm_channels channels);
/**
* @brief Writes a .bmp framedump after rendering the next main texture, before shaders are applied.

View File

@ -42,8 +42,6 @@ add_library(projectM_main OBJECT
fatal.h
fftsg.cpp
fftsg.h
FileScanner.cpp
FileScanner.hpp
glError.h
gltext.h
HungarianMethod.hpp
@ -56,14 +54,10 @@ add_library(projectM_main OBJECT
PipelineMerger.hpp
Preset.cpp
Preset.hpp
PresetChooser.cpp
PresetChooser.hpp
PresetFactory.cpp
PresetFactory.hpp
PresetFactoryManager.cpp
PresetFactoryManager.hpp
PresetLoader.cpp
PresetLoader.hpp
ProjectM.cpp
ProjectM.hpp
projectM-opengl.h

View File

@ -19,7 +19,6 @@
*
*/
#include "PresetChooser.hpp"
#include "ProjectM.hpp"
#include "Renderer.hpp"
#include "TimeKeeper.hpp"
@ -78,68 +77,14 @@ void ProjectM::DefaultKeyHandler(projectMEvent event, projectMKeycode keycode) {
m_beatDetect->beatSensitivity = 0;
}
break;
case PROJECTM_K_y:
this->SetShuffleEnabled(!this->ShuffleEnabled());
break;
case PROJECTM_K_a:
m_renderer->correction = !m_renderer->correction;
break;
case PROJECTM_K_n:
SelectNext(true);
break;
case PROJECTM_K_N:
SelectNext(false);
break;
case PROJECTM_K_r:
SelectRandom(true);
break;
case PROJECTM_K_R:
SelectRandom(false);
break;
case PROJECTM_K_p:
SelectPrevious(true);
break;
case PROJECTM_K_P:
case PROJECTM_K_BACKSPACE:
SelectPrevious(false);
break;
case PROJECTM_K_l:
SetPresetLocked(!PresetLocked());
break;
case PROJECTM_K_i:
break;
case PROJECTM_K_EQUALS:
case PROJECTM_K_PLUS:
unsigned int index;
if (SelectedPresetIndex(index)) {
const int oldRating = PresetRating(index, HARD_CUT_RATING_TYPE);
if (oldRating >= 6)
break;
const int rating = oldRating + 1;
ChangePresetRating(index, rating, HARD_CUT_RATING_TYPE);
}
break;
case PROJECTM_K_MINUS:
if (SelectedPresetIndex(index)) {
const int oldRating = PresetRating(index, HARD_CUT_RATING_TYPE);
if (oldRating <= 1)
break;
const int rating = oldRating - 1;
ChangePresetRating(index, rating, HARD_CUT_RATING_TYPE);
}
break;
default:
break;

View File

@ -2692,152 +2692,3 @@ else
return false;
}
// TESTS
#include <TestRunner.hpp>
#ifndef NDEBUG
#include <PresetLoader.hpp>
#define TEST(cond) if (!verify(#cond,cond)) return false
#define TEST2(str,cond) if (!verify(str,cond)) return false
struct ParserTest : public Test
{
ParserTest() : Test("ParserTest")
{}
MilkdropPreset *preset;
std::istringstream is;
std::istringstream &ss(const char *s) { return is = std::istringstream(s); }
bool eq(float a, float b)
{
return std::abs(a-b) < (std::abs(a)+std::abs(b) + 1)/1000.0f;
}
public:
bool test_float()
{
float f=-1.0f;
TEST(PROJECTM_SUCCESS == Parser::parse_float(ss("1.1"),&f));
TEST(1.1f == f);
TEST(PROJECTM_SUCCESS == Parser::parse_float(ss("+1.2"),&f));
TEST(PROJECTM_SUCCESS == Parser::parse_float(ss("-1.3"),&f));
TEST(PROJECTM_PARSE_ERROR == Parser::parse_float(ss(""),&f));
TEST(PROJECTM_PARSE_ERROR == Parser::parse_float(ss("\n"),&f));
TEST(PROJECTM_PARSE_ERROR == Parser::parse_float(ss("+"),&f));
return true;
}
bool test_int()
{
int i=-1;
TEST(PROJECTM_SUCCESS == Parser::parse_int(ss("1"),&i));
TEST(1 == i);
TEST(PROJECTM_SUCCESS == Parser::parse_int(ss("+2"),&i));
TEST(PROJECTM_SUCCESS == Parser::parse_int(ss("-3"),&i));
TEST(PROJECTM_PARSE_ERROR == Parser::parse_int(ss(""),&i));
TEST(PROJECTM_PARSE_ERROR == Parser::parse_int(ss("\n"),&i));
TEST(PROJECTM_PARSE_ERROR == Parser::parse_int(ss("+"),&i));
return true;
}
bool eval_expr(float expected, const char *s)
{
float result;
Expr *expr_parse = Parser::parse_gen_expr(ss(s),nullptr,preset);
TEST(expr_parse != nullptr);
// Expr doesn't really expect to run 'non-optimized' expressions any longer
Expr *expr = Expr::optimize(expr_parse);
expr_parse = nullptr;
if (!ParserTest::eq(expected, result=expr->eval(-1,-1)))
{
std::cout << "failed: expected " << expected << " found " << result << std::endl;
return false;
}
Expr::delete_expr(expr);
return true;
}
bool test_eqn()
{
TEST(eval_expr(1.0f, "1.0"));
TEST(eval_expr(-1.0f, "-(1.0)")); // unary`
TEST(eval_expr(0.5f, "5/10.000")); // binary
TEST(eval_expr(1.0f, "sin(3.14159/2)"));
// emtpy expression evals to 0, NULL usually means error in this parser
TEST(eval_expr(0.0f, ""));
TEST(eval_expr(0.0f, " "));
TEST(eval_expr(0.0f, "\n"));
TEST(eval_expr(0.0f, " \n"));
preset->presetOutputs().rot = 0.99f;
TEST(eval_expr(0.99f, "rot"));
// random other stuff to parse
Parser::parse_gen_expr(ss("0.5 + 0.5*sin(q8*0.613 + 1);"),nullptr,preset);
return true;
}
// test multi-line expression, and multi-expression line
bool test_lines()
{
// TODO
return true;
}
bool test_params()
{
// TODO
return true;
}
bool _test()
{
bool success = true;
success &= test_float();
success &= test_int();
success &= test_eqn();
success &= test_lines();
success &= test_params();
return success;
}
bool test() override
{
// load IdlePreset
PresetLoader *presetLoader = new PresetLoader ( 400, 400, "" );
std::unique_ptr<Preset> preset_ptr = presetLoader->loadPreset("idle://Geiss & Sperl - Feedback (projectM idle HDR mix).milk");
preset = (MilkdropPreset *)preset_ptr.get();
bool success = _test();
delete presetLoader;
return success;
}
};
Test* Parser::test()
{
return new ParserTest();
}
#else
Test* Parser::test()
{
return nullptr;
}
#endif

View File

@ -1,14 +0,0 @@
//
// C++ Implementation: PresetChooser
//
// Description:
//
//
// Author: Carmelo Piccione <carmelo.piccione@gmail.com>, (C) 2007
//
// Copyright: See COPYING file that comes with this distribution
//
//
#include "PresetChooser.hpp"

View File

@ -1,257 +0,0 @@
#ifndef PRESET_CHOOSER_HPP
#define PRESET_CHOOSER_HPP
#include "Preset.hpp"
#include "PresetLoader.hpp"
#include "RandomNumberGenerators.hpp"
#include <cassert>
#include <memory>
#include <iostream>
class PresetChooser;
/// A simple iterator class to traverse back and forth a preset directory
class PresetIterator {
public:
PresetIterator() {}
/// Instantiate a preset iterator at the given starting position
PresetIterator(std::size_t start);
/// Move iterator forward
void operator++();
/// Move iterator backword
void operator--() ;
/// Not equal comparator
bool operator !=(const PresetIterator & presetPos) const ;
/// Equality comparator
bool operator ==(const PresetIterator & presetPos) const ;
/// Returns an integer value representing the iterator position
/// @bug might become internal
/// \brief Returns the indexing value used by the current iterator.
std::size_t operator*() const;
// Return previous index.
std::size_t lastIndex() const;
/// Allocate a new preset given this iterator's associated preset name
/// \param presetInputs the preset inputs to associate with the preset upon construction
/// \param presetOutputs the preset outputs to associate with the preset upon construction
/// \returns an autopointer of the newly allocated preset
std::unique_ptr<Preset> allocate();
/// Set the chooser asocciated with this iterator
void setChooser(const PresetChooser & chooser);
private:
std::size_t _currentIndex;
const PresetChooser * _presetChooser;
};
/// Provides functions and iterators to select presets. Requires a preset loader upon construction
class PresetChooser {
public:
typedef PresetIterator iterator;
/// Initializes a chooser with an established preset loader.
/// \param presetLoader an initialized preset loader to choose presets from
/// \note The preset loader is refreshed via events or otherwise outside this class's scope
PresetChooser(const PresetLoader & presetLoader, bool softCutRatingsEnabled);
inline void setSoftCutRatingsEnabled(bool enabled) {
_softCutRatingsEnabled = enabled;
}
/// Choose a preset via the passed in index. Must be between 0 and num valid presets in directory
/// \param index An index lying in the interval [0, this->getNumPresets())
/// \param presetInputs the preset inputs to associate with the preset upon construction
/// \param presetOutputs the preset outputs to associate with the preset upon construction
/// \returns an auto pointer of the newly allocated preset
std::unique_ptr<Preset> directoryIndex(std::size_t index) const;
/// Gets the number of presets last believed to exist in the preset loader's filename collection
/// \returns the number of presets in the collection
std::size_t size() const;
/// An STL-esque iterator to begin traversing presets from a directory
/// \param index the index to begin iterating at. Assumed valid between [0, num presets)
/// \returns the position of the first preset in the collection
PresetIterator begin(unsigned int index) const;
/// An STL-esque iterator to begin traversing presets from a directory
/// \returns the position of the first preset in the collection
PresetIterator begin();
/// An STL-esque iterator to retrieve an end position from a directory
/// \returns the end position of the collection
PresetIterator end() const;
/// Perform a weighted sample to select a preset (uses preset rating values)
/// \returns an iterator to the randomly selected preset
iterator weightedRandom(bool hardCut) const;
/// True if no presets in directory
bool empty() const;
inline void nextPreset(PresetIterator & presetPos);
inline void previousPreset(PresetIterator & presetPos);
private:
std::vector<float> sampleWeights;
const PresetLoader * _presetLoader;
bool _softCutRatingsEnabled;
};
inline PresetChooser::PresetChooser(const PresetLoader & presetLoader, bool softCutRatingsEnabled):_presetLoader(&presetLoader), _softCutRatingsEnabled(softCutRatingsEnabled) {
}
inline std::size_t PresetChooser::size() const {
return _presetLoader->size();
}
inline void PresetIterator::setChooser(const PresetChooser & chooser) {
_presetChooser = &chooser;
}
inline std::size_t PresetIterator::operator*() const {
return _currentIndex;
}
inline std::size_t PresetIterator::lastIndex() const {
return _currentIndex;
}
inline PresetIterator::PresetIterator(std::size_t start):_currentIndex(start) {}
inline void PresetIterator::operator++() {
assert(_currentIndex < _presetChooser->size());
_currentIndex++;
}
inline void PresetIterator::operator--() {
assert(_currentIndex > 0);
_currentIndex--;
}
inline bool PresetIterator::operator !=(const PresetIterator & presetPos) const {
return (*presetPos != **this);
}
inline bool PresetIterator::operator ==(const PresetIterator & presetPos) const {
return (*presetPos == **this);
}
inline std::unique_ptr<Preset> PresetIterator::allocate() {
return _presetChooser->directoryIndex(_currentIndex);
}
inline void PresetChooser::nextPreset(PresetIterator & presetPos) {
if (this->empty()) {
return;
}
// Case: idle preset currently running, selected first preset of chooser
else if (presetPos == this->end())
presetPos = this->begin();
else
++(presetPos);
// Case: already at last preset, loop to beginning
if (((presetPos) == this->end())) {
presetPos = this->begin();
}
}
inline void PresetChooser::previousPreset(PresetIterator & presetPos) {
if (this->empty())
return;
// Case: idle preset currently running, selected last preset of chooser
else if (presetPos == this->end()) {
--(presetPos);
}
else if (presetPos != this->begin()) {
--(presetPos);
}
else {
presetPos = this->end();
--(presetPos);
}
}
inline PresetIterator PresetChooser::begin() {
PresetIterator pos(0);
pos.setChooser(*this);
return pos;
}
inline PresetIterator PresetChooser::begin(unsigned int index) const{
PresetIterator pos(index);
pos.setChooser(*this);
return pos;
}
inline PresetIterator PresetChooser::end() const {
PresetIterator pos(_presetLoader->size());
pos.setChooser(*this);
return pos;
}
inline bool PresetChooser::empty() const {
return _presetLoader->size() == 0;
}
inline std::unique_ptr<Preset> PresetChooser::directoryIndex(std::size_t index) const {
return _presetLoader->loadPreset(index);
}
inline PresetChooser::iterator PresetChooser::weightedRandom(bool hardCut) const {
// TODO make a sophisticated function object interface to determine why a certain rating
// category is chosen, or weighted distribution thereover.
const PresetRatingType ratingType = hardCut || (!_softCutRatingsEnabled) ?
HARD_CUT_RATING_TYPE : SOFT_CUT_RATING_TYPE;
const std::size_t ratingsTypeIndex = static_cast<std::size_t>(ratingType);
const std::vector<int> & weights = _presetLoader->getPresetRatings()[ratingsTypeIndex];
const auto weightsSum = _presetLoader->getPresetRatingsSums()[ratingsTypeIndex];
std::size_t index;
if (weightsSum > 0)
{
index = RandomNumberGenerators::weightedRandom(weights,
_presetLoader->getPresetRatingsSums()[ratingsTypeIndex]);
}
else
{
// No ratings (all zero), so just select a random preset with a uniform distribution.
index = RandomNumberGenerators::uniformInteger(_presetLoader->size());
}
return begin(index);
}
#endif

View File

@ -1,193 +0,0 @@
//
// C++ Implementation: PresetLoader
//
// Description:
//
//
// Author: Carmelo Piccione <carmelo.piccione@gmail.com>, (C) 2007
//
// Copyright: See COPYING file that comes with this distribution
//
//
#include "PresetLoader.hpp"
#include "Preset.hpp"
#include "PresetFactory.hpp"
#include <iostream>
#include <sstream>
#include <set>
#include <sys/types.h>
#include <cassert>
#include "fatal.h"
PresetLoader::PresetLoader (int gx, int gy, std::string dirname = std::string()) :_dirname ( dirname )
{
_presetFactoryManager.initialize(gx,gy);
std::vector<std::string> dirs{_dirname};
std::vector<std::string> extensions = _presetFactoryManager.extensionsHandled();
fileScanner = FileScanner(dirs, extensions);
// Do one scan
if ( _dirname != std::string() )
rescan();
else
clear();
}
PresetLoader::~PresetLoader() {}
void PresetLoader::setScanDirectory ( std::string dirname )
{
_dirname = dirname;
}
void PresetLoader::addScannedPresetFile(const std::string &path, const std::string &name) {
auto ext = ParseExtension(path);
if (ext.empty())
return;
ext = "." + ext;
// Verify extension is projectm or milkdrop
if (!_presetFactoryManager.extensionHandled(ext))
return;
// std::cout << "Loading preset file " << path << std::endl;
_entries.push_back(path);
_presetNames.push_back(name + ext);
}
void PresetLoader::rescan()
{
// std::cerr << "Rescanning..." << std::endl;
// Clear the directory entry collection
clear();
// scan for presets
using namespace std::placeholders;
fileScanner.scan(std::bind(&PresetLoader::addScannedPresetFile, this, _1, _2));
// Give all presets equal rating of 3 - why 3? I don't know
_ratings = std::vector<RatingList>(TOTAL_RATING_TYPES, RatingList( _presetNames.size(), 3 ));
_ratingsSums = std::vector<int>(TOTAL_RATING_TYPES, 3 *_presetNames.size());
assert ( _entries.size() == _presetNames.size() );
}
std::unique_ptr<Preset> PresetLoader::loadPreset ( PresetIndex index ) const
{
// Check that index isn't insane
assert ( index < _entries.size() );
return _presetFactoryManager.allocate
( _entries[index], _presetNames[index] );
}
std::unique_ptr<Preset> PresetLoader::loadPreset ( const std::string & url ) const
{
// std::cout << "Loading preset " << url << std::endl;
try {
/// @bug probably should not use url for preset name
return _presetFactoryManager.allocate
(url, url);
} catch (const std::exception & e) {
throw PresetFactoryException(e.what());
} catch (...) {
throw PresetFactoryException("preset factory exception of unknown cause");
}
return std::unique_ptr<Preset>();
}
void PresetLoader::setRating(PresetIndex index, int rating, const PresetRatingType ratingType)
{
const unsigned int ratingTypeIndex = static_cast<unsigned int>(ratingType);
assert (index < _ratings[ratingTypeIndex].size());
_ratingsSums[ratingTypeIndex] -= _ratings[ratingTypeIndex][index];
_ratings[ratingTypeIndex][index] = rating;
_ratingsSums[ratingType] += rating;
}
unsigned long PresetLoader::addPresetURL ( const std::string & url, const std::string & presetName, const std::vector<int> & ratings)
{
_entries.push_back(url);
_presetNames.push_back ( presetName );
assert(ratings.size() == TOTAL_RATING_TYPES);
assert(ratings.size() == _ratings.size());
for (unsigned int i = 0; i < _ratings.size(); i++)
_ratings[i].push_back(ratings[i]);
for (unsigned int i = 0; i < ratings.size(); i++)
_ratingsSums[i] += ratings[i];
return _entries.size()-1;
}
void PresetLoader::removePreset ( PresetIndex index )
{
_entries.erase ( _entries.begin() + index );
_presetNames.erase ( _presetNames.begin() + index );
for (unsigned int i = 0; i < _ratingsSums.size(); i++) {
_ratingsSums[i] -= _ratings[i][index];
_ratings[i].erase ( _ratings[i].begin() + index );
}
}
const std::string & PresetLoader::getPresetURL ( PresetIndex index ) const
{
return _entries[index];
}
const std::string & PresetLoader::getPresetName ( PresetIndex index ) const
{
return _presetNames[index];
}
// Get vector of preset names
const std::vector<std::string> &PresetLoader::getPresetNames() const
{
return _presetNames;
}
// Get the preset index given a name
unsigned int PresetLoader::getPresetIndex(const std::string& name) const
{
return find(_presetNames.begin(), _presetNames.end(), name) - _presetNames.begin();
}
int PresetLoader::getPresetRating ( PresetIndex index, const PresetRatingType ratingType ) const
{
return _ratings[ratingType][index];
}
const std::vector<RatingList> & PresetLoader::getPresetRatings () const
{
return _ratings;
}
const std::vector<int> & PresetLoader::getPresetRatingsSums() const {
return _ratingsSums;
}
void PresetLoader::setPresetName(PresetIndex index, std::string name) {
_presetNames[index] = name;
}
void PresetLoader::insertPresetURL ( PresetIndex index, const std::string & url, const std::string & presetName, const RatingList & ratings)
{
_entries.insert ( _entries.begin() + index, url );
_presetNames.insert ( _presetNames.begin() + index, presetName );
for (unsigned int i = 0; i < _ratingsSums.size();i++) {
_ratingsSums[i] += _ratings[i][index];
_ratings[i].insert ( _ratings[i].begin() + index, ratings[i] );
}
assert ( _entries.size() == _presetNames.size() );
}

View File

@ -1,113 +0,0 @@
#ifndef __PRESET_LOADER_HPP
#define __PRESET_LOADER_HPP
#include <string> // used for path / filename stuff
#include <memory> // for auto pointers
#include <sys/types.h>
#include <vector>
#include <map>
#include "PresetFactoryManager.hpp"
#include "FileScanner.hpp"
class Preset;
class PresetFactory;
typedef std::size_t PresetIndex;
class PresetLoader {
public:
/// Initializes the preset loader with the target directory specified
PresetLoader(int gx, int gy, std::string dirname);
~PresetLoader();
/// Load a preset by specifying its unique identifier given when the preset url
/// was added to this loader
std::unique_ptr<Preset> loadPreset(PresetIndex index) const;
std::unique_ptr<Preset> loadPreset ( const std::string & url ) const;
/// Add a preset to the loader's collection.
/// \param url an url referencing the preset
/// \param presetName a name for the preset
/// \param ratings an list representing the goodness ratings
/// \returns The unique index assigned to the preset in the collection. Used with loadPreset
unsigned long addPresetURL(const std::string & url, const std::string & presetName, const RatingList & ratings);
/// Add a preset to the loader's collection.
/// \param index insertion index
/// \param url an url referencing the preset
/// \param presetName a name for the preset
/// \param ratings an list representing the goodness ratings
void insertPresetURL (PresetIndex index, const std::string & url, const std::string & presetName, const RatingList & ratings);
/// Clears all presets from the collection
inline void clear() {
_entries.clear(); _presetNames.clear();
_ratings = std::vector<RatingList>(TOTAL_RATING_TYPES, RatingList());
clearRatingsSum();
}
inline void clearRatingsSum() {
_ratingsSums = std::vector<int>(TOTAL_RATING_TYPES, 0);
}
const std::vector<RatingList> & getPresetRatings() const;
const std::vector<int> & getPresetRatingsSums() const;
/// Removes a preset from the loader
/// \param index the unique identifier of the preset url to be removed
void removePreset(PresetIndex index);
/// Sets the rating of a preset to a new value
void setRating(PresetIndex index, int rating, const PresetRatingType ratingType);
/// Get a preset rating given an index
int getPresetRating ( PresetIndex index, const PresetRatingType ratingType) const;
/// Get a preset url given an index
const std::string & getPresetURL ( PresetIndex index) const;
/// Get a preset name given an index
const std::string & getPresetName ( PresetIndex index) const;
/// Get vector of preset names
const std::vector<std::string> & getPresetNames() const;
/// Get the preset index given a name
unsigned int getPresetIndex(const std::string& name) const;
/// Returns the number of presets in the active directory
inline std::size_t size() const {
return _entries.size();
}
/// Sets the directory where the loader will search for files
void setScanDirectory(std::string pathname);
/// Returns the directory path associated with this preset chooser
inline const std::string & directoryName() const {
return _dirname;
}
/// Rescans the active preset directory
void rescan();
void setPresetName(PresetIndex index, std::string name);
protected:
void addScannedPresetFile(const std::string &path, const std::string &name);
std::string _dirname;
std::vector<int> _ratingsSums;
mutable PresetFactoryManager _presetFactoryManager;
// vector chosen for speed, but not great for reverse index lookups
std::vector<std::string> _entries;
std::vector<std::string> _presetNames;
// Indexed by ratingType, preset position.
std::vector<RatingList> _ratings;
FileScanner fileScanner;
};
#endif

View File

@ -26,7 +26,6 @@
#include "PCM.hpp" //Sound data handler (buffering, FFT, etc.)
#include "PipelineMerger.hpp"
#include "Preset.hpp"
#include "PresetChooser.hpp"
#include "Renderer.hpp"
#include "TimeKeeper.hpp"
@ -55,16 +54,14 @@ void ProjectM::ResetTextures()
}
ProjectM::ProjectM(const std::string& configurationFilename, Flags flags)
: m_flags(flags)
ProjectM::ProjectM(const std::string& configurationFilename)
{
ReadConfig(configurationFilename);
Reset();
ResetOpenGL(m_settings.windowWidth, m_settings.windowHeight);
}
ProjectM::ProjectM(const class Settings& settings, Flags flags)
: m_flags(flags)
ProjectM::ProjectM(const class Settings& settings)
{
ReadSettings(settings);
Reset();
@ -85,12 +82,9 @@ auto ProjectM::WriteConfig(const std::string& configurationFilename, const class
config.add("Window Height", settings.windowHeight);
config.add("Smooth Preset Duration", settings.softCutDuration);
config.add("Preset Duration", settings.presetDuration);
config.add("Preset Path", settings.presetPath);
config.add("Hard Cut Sensitivity", settings.beatSensitivity);
config.add("Aspect Correction", settings.aspectCorrection);
config.add("Easter Egg Parameter", settings.easterEgg);
config.add("Shuffle Enabled", settings.shuffleEnabled);
config.add("Soft Cut Ratings Enabled", settings.softCutRatingsEnabled);
std::fstream file(configurationFilename.c_str(), std::ios_base::trunc | std::ios_base::out);
if (file)
{
@ -117,25 +111,7 @@ void ProjectM::ReadConfig(const std::string& configurationFilename)
m_settings.windowHeight = config.read<int>("Window Height", 512);
m_settings.softCutDuration = config.read<double>("Smooth Preset Duration", config.read<int>("Smooth Transition Duration", 10));
m_settings.presetDuration = config.read<double>("Preset Duration", 15);
#ifdef __unix__
m_settings.presetPath = config.read<string>("Preset Path", "/usr/local/share/projectM/presets");
#endif
#ifdef __APPLE__
/// @bug awful hardcoded hack- need to add intelligence to cmake wrt bundling - carm
m_settings.presetPath = config.read<string>("Preset Path", "../Resources/presets");
#endif
#ifdef _WIN32
m_settings.presetPath = config.read<string>("Preset Path", "/usr/local/share/projectM/presets");
#endif
m_settings.shuffleEnabled = config.read<bool>("Shuffle Enabled", true);
m_settings.easterEgg = config.read<float>("Easter Egg Parameter", 0.0);
m_settings.softCutRatingsEnabled =
config.read<bool>("Soft Cut Ratings Enabled", false);
// Hard Cuts are preset transitions that occur when your music becomes louder. They only occur after a hard cut duration threshold has passed.
m_settings.hardCutEnabled = config.read<bool>("Hard Cuts Enabled", false);
@ -164,11 +140,8 @@ void ProjectM::ReadSettings(const class Settings& settings)
m_settings.windowHeight = settings.windowHeight;
m_settings.softCutDuration = settings.softCutDuration;
m_settings.presetDuration = settings.presetDuration;
m_settings.softCutRatingsEnabled = settings.softCutRatingsEnabled;
m_settings.presetPath = settings.presetPath;
m_settings.texturePath = settings.texturePath;
m_settings.shuffleEnabled = settings.shuffleEnabled;
m_settings.dataPath = settings.dataPath;
m_settings.easterEgg = settings.easterEgg;
@ -248,41 +221,24 @@ auto ProjectM::RenderFrameOnlyPass1(Pipeline* pipeline) -> Pipeline*
m_beatDetect->CalculateBeatStatistics();
//if the preset isn't locked and there are more presets
if (!m_renderer->noSwitch && !m_presetChooser->empty())
if (!m_renderer->noSwitch)
{
//if preset is done and we're not already switching
if (m_timeKeeper->PresetProgressA() >= 1.0 && !m_timeKeeper->IsSmoothing())
{
if (Settings().shuffleEnabled)
{
SelectRandom(false);
}
else
{
SelectNext(false);
}
// Call preset change callback
}
else if (Settings().hardCutEnabled &&
(m_beatDetect->vol - m_beatDetect->volOld > Settings().hardCutSensitivity) &&
m_timeKeeper->CanHardCut())
{
// Hard Cuts must be enabled, must have passed the hardcut duration, and the volume must be a greater difference than the hardcut sensitivity.
if (Settings().shuffleEnabled)
{
SelectRandom(true);
}
else
{
SelectNext(true);
}
// Call preset change callback
}
}
if (m_timeKeeper->IsSmoothing() && m_timeKeeper->SmoothRatio() <= 1.0 && !m_presetChooser->empty())
if (m_timeKeeper->IsSmoothing() && m_timeKeeper->SmoothRatio() <= 1.0 && m_activePreset2 != nullptr)
{
assert(m_activePreset2.get());
#if USE_THREADS
m_workerSync.WakeUpBackgroundTask();
#endif
@ -384,10 +340,6 @@ void ProjectM::Initialize()
m_beatDetect = std::make_unique<BeatDetect>(m_pcm);
// Create texture search path list
if (!m_settings.presetPath.empty())
{
m_textureSearchPaths.emplace_back(m_settings.presetPath);
}
if (!m_settings.texturePath.empty())
{
m_textureSearchPaths.emplace_back(m_settings.texturePath);
@ -412,8 +364,6 @@ void ProjectM::Initialize()
m_workerThread = std::thread(&ProjectM::ThreadWorker, this);
#endif
/// @bug order of operatoins here is busted
//renderer->setPresetName ( m_activePreset->name() );
m_timeKeeper->StartPreset();
// ToDo: Calculate the real FPS instead
@ -446,96 +396,18 @@ auto ProjectM::InitializePresetTools() -> void
/* Set the seed to the current time in seconds */
srand(time(nullptr));
std::string url;
if ((m_flags & Flags::DisablePlaylistLoad) != Flags::DisablePlaylistLoad)
{
url = Settings().presetPath;
}
m_presetLoader = std::make_unique<PresetLoader>(m_settings.meshX, m_settings.meshY, url);
m_presetChooser = std::make_unique<PresetChooser>(*m_presetLoader, Settings().softCutRatingsEnabled);
m_presetPos = std::make_unique<PresetIterator>();
// Start at end ptr- this allows next/previous to easily be done from this position.
*m_presetPos = m_presetChooser->end();
// Load idle preset
m_activePreset = m_presetLoader->loadPreset("idle://Geiss & Sperl - Feedback (projectM idle HDR mix).milk");
m_renderer->setPresetName("Geiss & Sperl - Feedback (projectM idle HDR mix)");
m_renderer->SetPipeline(m_activePreset->pipeline());
ResetEngine();
}
/// @bug queuePreset case isn't handled
void ProjectM::RemovePreset(unsigned int index)
{
size_t chooserIndex = **m_presetPos;
m_presetLoader->removePreset(index);
// Case: no more presets, set iterator to end
if (m_presetChooser->empty())
{
*m_presetPos = m_presetChooser->end();
// Case: chooser index has become one less due to removal of an index below it
}
else if (chooserIndex > index)
{
chooserIndex--;
*m_presetPos = m_presetChooser->begin(chooserIndex);
}
// Case: we have deleted the active preset position
// Set iterator to end of chooser
else if (chooserIndex == index)
{
*m_presetPos = m_presetChooser->end();
}
}
auto ProjectM::AddPresetURL(const std::string& presetFilename, const std::string& presetName, const RatingList& ratingList) -> unsigned int
{
bool restorePosition = false;
if (*m_presetPos == m_presetChooser->end())
{
restorePosition = true;
}
int index = m_presetLoader->addPresetURL(presetFilename, presetName, ratingList);
if (restorePosition)
{
*m_presetPos = m_presetChooser->end();
}
return index;
}
void ProjectM::SelectPreset(unsigned int index, bool hardCut)
{
if (m_presetChooser->empty())
{
return;
}
*m_presetPos = m_presetChooser->begin(index);
if (!StartPresetTransition(hardCut))
{
SelectRandom(hardCut);
}
}
bool ProjectM::StartPresetTransition(bool hardCut)
{
std::unique_ptr<Preset> new_preset = SwitchToCurrentPreset();
if (new_preset == nullptr)
{
PresetSwitchFailedEvent(hardCut, **m_presetPos, "fake error");
PresetSwitchFailedEvent(hardCut, "", "No preset available to switch to");
m_errorLoadingCurrentPreset = true;
return false;
@ -553,36 +425,11 @@ bool ProjectM::StartPresetTransition(bool hardCut)
m_timeKeeper->StartSmoothing();
}
PresetSwitchedEvent(hardCut, **m_presetPos);
m_errorLoadingCurrentPreset = false;
return true;
}
void ProjectM::SelectRandom(const bool hardCut)
{
if (m_presetChooser->empty())
{
return;
}
m_presetHistory.push_back(m_presetPos->lastIndex());
for (int i = 0; i < kMaxSwitchRetries; ++i)
{
*m_presetPos = m_presetChooser->weightedRandom(hardCut);
if (StartPresetTransition(hardCut))
{
break;
}
}
// If presetHistory is tracking more than 10, then delete the oldest entry so we cap to a history of 10.
if (m_presetHistory.size() >= 10)
{
m_presetHistory.erase(m_presetHistory.begin());
}
m_presetFuture.clear();
}
auto ProjectM::WindowWidth() -> int
{
return m_settings.windowWidth;
@ -598,60 +445,6 @@ auto ProjectM::ErrorLoadingCurrentPreset() const -> bool
return m_errorLoadingCurrentPreset;
}
void ProjectM::SelectPrevious(const bool hardCut)
{
if (m_presetChooser->empty())
{
return;
}
if (Settings().shuffleEnabled && m_presetHistory.size() >= 1 &&
static_cast<std::size_t>(m_presetHistory.back()) != m_presetLoader->size())
{ // if randomly browsing presets, "previous" should return to last random preset not the index--. Avoid returning to size() because that's the idle:// preset.
m_presetFuture.push_back(m_presetPos->lastIndex());
SelectPreset(m_presetHistory.back());
m_presetHistory.pop_back();
}
else
{
// if we are not shuffling or there is no random future history, then let's not track a random vector and move backwards in the preset index.
m_presetHistory.clear();
m_presetFuture.clear();
m_presetChooser->previousPreset(*m_presetPos);
if (!StartPresetTransition(hardCut))
{
SelectRandom(hardCut);
}
}
}
void ProjectM::SelectNext(const bool hardCut)
{
if (m_presetChooser->empty())
{
return;
}
if (Settings().shuffleEnabled && m_presetFuture.size() >= 1 &&
static_cast<std::size_t>(m_presetFuture.front()) != m_presetLoader->size())
{ // if shuffling and we have future presets already stashed then let's go forward rather than truely move randomly.
m_presetHistory.push_back(m_presetPos->lastIndex());
SelectPreset(m_presetFuture.back());
m_presetFuture.pop_back();
}
else
{
// if we are not shuffling or there is no random history, then let's not track a random vector and move forwards in the preset index.
m_presetFuture.clear();
m_presetHistory.clear();
m_presetChooser->nextPreset(*m_presetPos);
if (!StartPresetTransition(hardCut))
{
SelectRandom(hardCut);
}
}
}
/**
* Switches the pipeline and renderer to the current preset.
* @return the resulting Preset object, or nullptr on failure.
@ -663,23 +456,14 @@ auto ProjectM::SwitchToCurrentPreset() -> std::unique_ptr<Preset>
std::lock_guard<std::recursive_mutex> guard(m_presetSwitchMutex);
#endif
try
{
new_preset = m_presetPos->allocate();
}
catch (const PresetFactoryException& e)
{
std::cerr << "problem allocating target preset: " << e.message()
<< std::endl;
}
// ToDo: Load preset by filename here
if (new_preset == nullptr)
{
std::cerr << "Could not switch to current preset" << std::endl;
return nullptr;
}
// Set preset name here- event is not done because at the moment this function
// Set preset name here - event is not done because at the moment this function
// is oblivious to smooth/hard switches
m_renderer->setPresetName(new_preset->name());
std::string result = m_renderer->SetPipeline(new_preset->pipeline());
@ -693,6 +477,8 @@ auto ProjectM::SwitchToCurrentPreset() -> std::unique_ptr<Preset>
void ProjectM::SetPresetLocked(bool locked)
{
// ToDo: Add a preset switch timer separate from the display timer and reset to 0 when
// disabling the preset switch lock.
m_renderer->noSwitch = locked;
}
@ -701,123 +487,7 @@ auto ProjectM::PresetLocked() const -> bool
return m_renderer->noSwitch;
}
auto ProjectM::PresetURL(unsigned int index) const -> std::string
{
return m_presetLoader->getPresetURL(index);
}
auto ProjectM::PresetRating(unsigned int index, const PresetRatingType ratingType) const -> int
{
return m_presetLoader->getPresetRating(index, ratingType);
}
auto ProjectM::PresetName(unsigned int index) const -> std::string
{
return m_presetLoader->getPresetName(index);
}
void ProjectM::ClearPlaylist()
{
m_presetLoader->clear();
*m_presetPos = m_presetChooser->end();
}
void ProjectM::SelectPresetPosition(unsigned int index)
{
*m_presetPos = m_presetChooser->begin(index);
}
auto ProjectM::SelectedPresetIndex(unsigned int& index) const -> bool
{
if (*m_presetPos == m_presetChooser->end())
{
return false;
}
index = **m_presetPos;
return true;
}
auto ProjectM::PresetPositionValid() const -> bool
{
return (*m_presetPos != m_presetChooser->end());
}
auto ProjectM::PlaylistSize() const -> unsigned int
{
return m_presetLoader->size();
}
void ProjectM::SetShuffleEnabled(bool value)
{
m_settings.shuffleEnabled = value;
}
auto ProjectM::ShuffleEnabled() const -> bool
{
return m_settings.shuffleEnabled;
}
void ProjectM::PresetSwitchedEvent(bool, size_t) const {}
void ProjectM::ShuffleEnabledValueChanged(bool) const {}
void ProjectM::PresetSwitchFailedEvent(bool, unsigned int, const std::string&) const {}
void ProjectM::PresetRatingChanged(unsigned int, int, PresetRatingType) const {}
void ProjectM::ChangePresetRating(unsigned int index, int rating, const PresetRatingType ratingType)
{
m_presetLoader->setRating(index, rating, ratingType);
PresetRatingChanged(index, rating, ratingType);
}
void ProjectM::InsertPresetURL(unsigned int index, const std::string& presetFilename, const std::string& presetName,
const RatingList& ratingList)
{
bool atEndPosition = false;
int newSelectedIndex = 0;
if (*m_presetPos == m_presetChooser->end()) // Case: preset not selected
{
atEndPosition = true;
}
else if (**m_presetPos < index) // Case: inserting before selected preset
{
newSelectedIndex = **m_presetPos;
}
else if (**m_presetPos > index) // Case: inserting after selected preset
{
newSelectedIndex++;
}
else // Case: inserting at selected preset
{
newSelectedIndex++;
}
m_presetLoader->insertPresetURL(index, presetFilename, presetName, ratingList);
if (atEndPosition)
{
*m_presetPos = m_presetChooser->end();
}
else
{
*m_presetPos = m_presetChooser->begin(newSelectedIndex);
}
}
void ProjectM::ChangePresetName(unsigned int index, std::string presetName)
{
m_presetLoader->setPresetName(index, presetName);
}
void ProjectM::PresetSwitchFailedEvent(bool, const std::string&, const std::string&) const {}
void ProjectM::SetTextureSize(size_t size)
{
@ -846,12 +516,6 @@ auto ProjectM::SoftCutDuration() const -> double
return m_settings.softCutDuration;
}
void ProjectM::SetSoftCutDuration(int seconds)
{
m_settings.softCutDuration = static_cast<double>(seconds);
m_timeKeeper->ChangeSoftCutDuration(seconds);
}
void ProjectM::SetSoftCutDuration(double seconds)
{
m_settings.softCutDuration = seconds;
@ -863,12 +527,6 @@ auto ProjectM::HardCutDuration() const -> double
return m_settings.hardCutDuration;
}
void ProjectM::SetHardCutDuration(int seconds)
{
m_settings.hardCutDuration = seconds;
m_timeKeeper->ChangeHardCutDuration(seconds);
}
void ProjectM::SetHardCutDuration(double seconds)
{
m_settings.hardCutDuration = static_cast<int>(seconds);
@ -895,7 +553,7 @@ void ProjectM::SetHardCutSensitivity(float sensitivity)
m_settings.hardCutSensitivity = sensitivity;
}
void ProjectM::SetPresetDuration(int seconds)
void ProjectM::SetPresetDuration(double seconds)
{
m_timeKeeper->ChangePresetDuration(seconds);
}
@ -905,11 +563,6 @@ auto ProjectM::PresetDuration() const -> double
return m_timeKeeper->PresetDuration();
}
void ProjectM::SetPresetDuration(double seconds)
{
m_timeKeeper->ChangePresetDuration(seconds);
}
auto ProjectM::FramesPerSecond() const -> int32_t
{
return m_settings.fps;
@ -964,40 +617,6 @@ auto ProjectM::Pcm() -> class Pcm&
return m_pcm;
}
// get index from search results based on preset name
auto ProjectM::SearchIndex(const std::string& presetName) const -> unsigned int
{
for (auto& it : m_renderer->m_presetList)
{
if (it.name == presetName)
{
return it.id;
}
}
return 0;
}
// get preset index based on preset name
auto ProjectM::PresetIndex(const std::string& presetFilename) const -> unsigned int
{
return m_presetLoader->getPresetIndex(presetFilename);
}
// load preset based on name
void ProjectM::SelectPresetByName(std::string presetName, bool hardCut)
{
if (presetName == "")
{
return;
}
unsigned int index = PresetIndex(presetName);
if (m_presetChooser->empty())
{
return;
}
SelectPreset(index);
}
auto ProjectM::Settings() const -> const class ProjectM::Settings&
{
return m_settings;

View File

@ -59,12 +59,6 @@ class Renderer;
class Preset;
class PresetIterator;
class PresetChooser;
class PresetLoader;
class TimeKeeper;
class Pipeline;
@ -72,16 +66,6 @@ class Pipeline;
class ProjectM
{
public:
/*
* Behaviour flags for the projectM instance. Currently, it's only used to prevent automatically filling
* the preset playlist by traversing the preset path for files.
*/
enum Flags
{
None = 0, //!< No special flags.
DisablePlaylistLoad = 1 << 0 //!< Prevent automatic playlist loading on startup.
};
class Settings
{
public:
@ -91,7 +75,6 @@ public:
size_t textureSize{512};
size_t windowWidth{512};
size_t windowHeight{512};
std::string presetPath;
std::string texturePath;
std::string dataPath;
double presetDuration{15.0};
@ -102,13 +85,11 @@ public:
float beatSensitivity{1.0};
bool aspectCorrection{true};
float easterEgg{0.0};
bool shuffleEnabled{true};
bool softCutRatingsEnabled{false};
};
explicit ProjectM(const std::string& configurationFilename, Flags flags = Flags::None);
explicit ProjectM(const std::string& configurationFilename);
explicit ProjectM(const class Settings& configurationFilename, Flags flags = Flags::None);
explicit ProjectM(const class Settings& configurationFilename);
virtual ~ProjectM();
@ -134,14 +115,10 @@ public:
auto SoftCutDuration() const -> double;
void SetSoftCutDuration(int seconds);
void SetSoftCutDuration(double seconds);
auto HardCutDuration() const -> double;
void SetHardCutDuration(int seconds);
void SetHardCutDuration(double seconds);
auto HardCutEnabled() const -> bool;
@ -158,8 +135,6 @@ public:
*/
auto PresetDuration() const -> double;
void SetPresetDuration(int seconds);
void SetPresetDuration(double seconds);
/**
@ -200,91 +175,16 @@ public:
static auto WriteConfig(const std::string& configurationFilename,
const class Settings& settings) -> bool;
/// Sets preset iterator position to the passed in index
void SelectPresetPosition(unsigned int index);
/// Plays a preset immediately
void SelectPreset(unsigned int index, bool hardCut = true);
/// Removes a preset from the play list. If it is playing then it will continue as normal until next switch
void RemovePreset(unsigned int index);
/// Removes entire playlist, The currently loaded preset will end up sticking until new presets are added
void ClearPlaylist();
/// Turn on or off a lock that prevents projectM from switching to another preset
void SetPresetLocked(bool locked);
/// Returns true if the active preset is locked
auto PresetLocked() const -> bool;
auto PresetIndex(const std::string& presetFilename) const -> unsigned int;
/// Plays a preset immediately when given preset name
void SelectPresetByName(std::string presetName, bool hardCut = true);
/// Returns index of currently active preset. In the case where the active
/// preset was removed from the playlist, this function will return the element
/// before active preset (thus the next in order preset is invariant with respect
/// to the removal)
auto SelectedPresetIndex(unsigned int& index) const -> bool;
/// Add a preset url to the play list. Appended to bottom. Returns index of preset
auto AddPresetURL(const std::string& presetFilename,
const std::string& presetName,
const RatingList& ratingList) -> unsigned int;
/// Insert a preset url to the play list at the suggested index.
void InsertPresetURL(unsigned int index,
const std::string& presetFilename,
const std::string& presetName,
const RatingList& ratingList);
/// Returns true if the selected preset position points to an actual preset in the
/// currently loaded playlist
auto PresetPositionValid() const -> bool;
/// Returns the url associated with a preset index
auto PresetURL(unsigned int index) const -> std::string;
/// Returns the preset name associated with a preset index
auto PresetName(unsigned int index) const -> std::string;
void ChangePresetName(unsigned int index, std::string presetName);
/// Returns the rating associated with a preset index
auto PresetRating(unsigned int index, PresetRatingType ratingType) const -> int;
void ChangePresetRating(unsigned int index, int rating, PresetRatingType ratingType);
/// Returns the size of the play list
auto PlaylistSize() const -> unsigned int;
void SetShuffleEnabled(bool value);
auto ShuffleEnabled() const -> bool;
/// Occurs when active preset has switched. Switched to index is returned
virtual void PresetSwitchedEvent(bool hardCut, size_t index) const;
virtual void ShuffleEnabledValueChanged(bool enabled) const;
virtual void PresetSwitchFailedEvent(bool hardCut, unsigned int index, const std::string& message) const;
/// Occurs whenever preset rating has changed via ChangePresetRating() method
virtual void PresetRatingChanged(unsigned int index, int rating, PresetRatingType ratingType) const;
virtual void PresetSwitchFailedEvent(bool hardCut, const std::string& presetFilename, const std::string& message) const;
auto Pcm() -> class Pcm&;
/// Get the preset index given a name
auto SearchIndex(const std::string& presetName) const -> unsigned int;
void SelectPrevious(bool hardCut);
void SelectNext(bool hardCut);
void SelectRandom(bool hardCut);
auto WindowWidth() -> int;
auto WindowHeight() -> int;
@ -347,11 +247,6 @@ private:
class Settings m_settings; //!< The projectM Settings.
Flags m_flags{Flags::None}; //!< Behaviour flags.
std::vector<int> m_presetHistory; //!< List of previously played preset indices.
std::vector<int> m_presetFuture; //!< List of preset indices queued for playing.
std::vector<std::string> m_textureSearchPaths; ///!< List of paths to search for texture files
/** Timing information */
@ -364,9 +259,6 @@ private:
std::unique_ptr<Renderer> m_renderer; //!< The Preset renderer.
std::unique_ptr<BeatDetect> m_beatDetect; //!< The beat detection class.
std::unique_ptr<PresetIterator> m_presetPos; //!< The current position of the directory iterator.
std::unique_ptr<PresetLoader> m_presetLoader; //!< Required by the preset chooser. Manages a loaded preset directory.
std::unique_ptr<PresetChooser> m_presetChooser; //!< Provides accessor functions to choose presets.
std::unique_ptr<Preset> m_activePreset; //!< Currently loaded preset.
std::unique_ptr<Preset> m_activePreset2; //!< Destination preset when smooth preset switching.
std::unique_ptr<TimeKeeper> m_timeKeeper; //!< Keeps the different timers used to render and switch presets.

View File

@ -5,51 +5,26 @@
#include <cstring>
#include <utility>
projectMWrapper::projectMWrapper(std::string configFile, int flags)
: ProjectM(std::move(configFile), static_cast<ProjectM::Flags>(flags))
projectMWrapper::projectMWrapper(std::string configFile)
: ProjectM(std::move(configFile))
{
}
projectMWrapper::projectMWrapper(class ProjectM::Settings settings, int flags)
: ProjectM(std::move(settings), static_cast<ProjectM::Flags>(flags))
projectMWrapper::projectMWrapper(class ProjectM::Settings settings)
: ProjectM(std::move(settings))
{
}
void projectMWrapper::PresetSwitchedEvent(bool isHardCut, size_t presetIndex) const
{
if (_presetSwitchedEventCallback)
{
_presetSwitchedEventCallback(isHardCut, presetIndex, _presetSwitchedEventUserData);
}
}
void projectMWrapper::ShuffleEnabledValueChanged(bool shuffle_enabled) const
{
if (_shuffleEnableChangedEventCallback)
{
_shuffleEnableChangedEventCallback(shuffle_enabled, _shuffleEnableChangedEventUserData);
}
}
void projectMWrapper::PresetSwitchFailedEvent(bool isHardCut, unsigned int presetIndex,
void projectMWrapper::PresetSwitchFailedEvent(bool isHardCut, const std::string& presetFilename,
const std::string& failureMessage) const
{
if (_presetSwitchFailedEventCallback)
{
_presetSwitchFailedEventCallback(isHardCut, presetIndex,
_presetSwitchFailedEventCallback(isHardCut, presetFilename.c_str(),
failureMessage.c_str(), _presetSwitchFailedEventUserData);
}
}
void projectMWrapper::PresetRatingChanged(unsigned int presetIndex, int rating, PresetRatingType ratingType) const
{
if (_presetRatingChangedEventCallback)
{
_presetRatingChangedEventCallback(presetIndex, rating, static_cast<projectm_preset_rating_type>(ratingType),
_presetRatingChangedEventUserData);
}
}
projectMWrapper* handle_to_instance(projectm_handle instance)
{
return reinterpret_cast<projectMWrapper*>(instance);
@ -98,7 +73,6 @@ void projectm_free_settings(const projectm_settings* settings)
{
if (settings)
{
projectm_free_string(settings->preset_path);
projectm_free_string(settings->texture_path);
projectm_free_string(settings->data_path);
}
@ -106,11 +80,11 @@ void projectm_free_settings(const projectm_settings* settings)
delete settings;
}
projectm_handle projectm_create(const char* setting_file_path, int flags)
projectm_handle projectm_create(const char* setting_file_path)
{
try
{
auto projectMInstance = new projectMWrapper(std::string(setting_file_path), flags);
auto projectMInstance = new projectMWrapper(std::string(setting_file_path));
return reinterpret_cast<projectm_handle>(projectMInstance);
}
catch (...)
@ -119,7 +93,7 @@ projectm_handle projectm_create(const char* setting_file_path, int flags)
}
}
projectm_handle projectm_create_settings(const projectm_settings* settings, int flags)
projectm_handle projectm_create_settings(const projectm_settings* settings)
{
try
{
@ -130,7 +104,6 @@ projectm_handle projectm_create_settings(const projectm_settings* settings, int
cppSettings.textureSize = settings->texture_size;
cppSettings.windowWidth = settings->window_width;
cppSettings.windowHeight = settings->window_height;
cppSettings.presetPath = settings->preset_path ? settings->preset_path : "";
cppSettings.texturePath = settings->texture_path ? settings->texture_path : "";
cppSettings.dataPath = settings->data_path ? settings->data_path : "";
cppSettings.softCutDuration = settings->soft_cut_duration;
@ -141,10 +114,8 @@ projectm_handle projectm_create_settings(const projectm_settings* settings, int
cppSettings.beatSensitivity = settings->beat_sensitivity;
cppSettings.aspectCorrection = settings->aspect_correction;
cppSettings.easterEgg = settings->easter_egg;
cppSettings.shuffleEnabled = settings->shuffle_enabled;
cppSettings.softCutRatingsEnabled = settings->soft_cut_ratings_enabled;
auto projectMInstance = new projectMWrapper(cppSettings, flags);
auto projectMInstance = new projectMWrapper(cppSettings);
return reinterpret_cast<projectm_handle>(projectMInstance);
}
catch (...)
@ -159,22 +130,6 @@ void projectm_destroy(projectm_handle instance)
delete projectMInstance;
}
void projectm_set_preset_switched_event_callback(projectm_handle instance, projectm_preset_switched_event callback,
void* user_data)
{
auto projectMInstance = handle_to_instance(instance);
projectMInstance->_presetSwitchedEventCallback = callback;
projectMInstance->_presetSwitchedEventUserData = user_data;
}
void projectm_set_shuffle_enable_changed_event_callback(projectm_handle instance,
projectm_shuffle_enable_changed_event callback, void* user_data)
{
auto projectMInstance = handle_to_instance(instance);
projectMInstance->_shuffleEnableChangedEventCallback = callback;
projectMInstance->_shuffleEnableChangedEventUserData = user_data;
}
void projectm_set_preset_switch_failed_event_callback(projectm_handle instance,
projectm_preset_switch_failed_event callback, void* user_data)
{
@ -183,14 +138,6 @@ void projectm_set_preset_switch_failed_event_callback(projectm_handle instance,
projectMInstance->_presetSwitchFailedEventUserData = user_data;
}
void projectm_set_preset_rating_changed_event_callback(projectm_handle instance,
projectm_preset_rating_changed_event callback, void* user_data)
{
auto projectMInstance = handle_to_instance(instance);
projectMInstance->_presetRatingChangedEventCallback = callback;
projectMInstance->_presetRatingChangedEventUserData = user_data;
}
void projectm_reset_gl(projectm_handle instance, int width, int height)
{
auto projectMInstance = handle_to_instance(instance);
@ -336,12 +283,6 @@ void projectm_set_fps(projectm_handle instance, int32_t fps)
projectMInstance->SetFramesPerSecond(fps);
}
const char* projectm_get_preset_path(projectm_handle instance)
{
auto projectMInstance = handle_to_instance(instance);
return projectm_alloc_string_from_std_string(projectMInstance->Settings().presetPath);
}
const char* projectm_get_texture_path(projectm_handle instance)
{
auto projectMInstance = handle_to_instance(instance);
@ -414,7 +355,6 @@ projectm_settings* projectm_get_settings(projectm_handle instance)
settingsStruct->texture_size = settings.textureSize;
settingsStruct->window_width = settings.windowWidth;
settingsStruct->window_height = settings.windowHeight;
settingsStruct->preset_path = projectm_alloc_string_from_std_string(settings.presetPath);
settingsStruct->texture_path = projectm_alloc_string_from_std_string(settings.texturePath);
settingsStruct->data_path = projectm_alloc_string_from_std_string(settings.dataPath);
settingsStruct->soft_cut_duration = settings.softCutDuration;
@ -425,8 +365,6 @@ projectm_settings* projectm_get_settings(projectm_handle instance)
settingsStruct->beat_sensitivity = settings.beatSensitivity;
settingsStruct->aspect_correction = settings.aspectCorrection;
settingsStruct->easter_egg = settings.easterEgg;
settingsStruct->shuffle_enabled = settings.shuffleEnabled;
settingsStruct->soft_cut_ratings_enabled = settings.softCutRatingsEnabled;
return settingsStruct;
}
@ -440,7 +378,6 @@ void projectm_write_config(const char* config_file, const projectm_settings* set
cppSettings.textureSize = settings->texture_size;
cppSettings.windowWidth = settings->window_width;
cppSettings.windowHeight = settings->window_height;
cppSettings.presetPath = settings->preset_path ? settings->preset_path : "";
cppSettings.texturePath = settings->texture_path ? settings->texture_path : "";
cppSettings.dataPath = settings->data_path ? settings->data_path : "";
cppSettings.softCutDuration = settings->soft_cut_duration;
@ -451,36 +388,10 @@ void projectm_write_config(const char* config_file, const projectm_settings* set
cppSettings.beatSensitivity = settings->beat_sensitivity;
cppSettings.aspectCorrection = settings->aspect_correction;
cppSettings.easterEgg = settings->easter_egg;
cppSettings.shuffleEnabled = settings->shuffle_enabled;
cppSettings.softCutRatingsEnabled = settings->soft_cut_ratings_enabled;
ProjectM::WriteConfig(config_file, cppSettings);
}
void projectm_select_preset_position(projectm_handle instance, unsigned int index)
{
auto projectMInstance = handle_to_instance(instance);
projectMInstance->SelectPresetPosition(index);
}
void projectm_select_preset(projectm_handle instance, unsigned int index, bool hard_cut)
{
auto projectMInstance = handle_to_instance(instance);
projectMInstance->SelectPreset(index, hard_cut);
}
void projectm_remove_preset(projectm_handle instance, unsigned int index)
{
auto projectMInstance = handle_to_instance(instance);
projectMInstance->RemovePreset(index);
}
void projectm_clear_playlist(projectm_handle instance)
{
auto projectMInstance = handle_to_instance(instance);
projectMInstance->ClearPlaylist();
}
void projectm_lock_preset(projectm_handle instance, bool lock)
{
auto projectMInstance = handle_to_instance(instance);
@ -493,160 +404,6 @@ bool projectm_is_preset_locked(projectm_handle instance)
return projectMInstance->PresetLocked();
}
unsigned int projectm_get_preset_index(projectm_handle instance, const char* preset_name)
{
if (!preset_name)
{
return 0;
}
auto projectMInstance = handle_to_instance(instance);
return projectMInstance->PresetIndex(preset_name);
}
void projectm_select_preset_by_name(projectm_handle instance, const char* preset_name, bool hard_cut)
{
if (!preset_name)
{
return;
}
auto projectMInstance = handle_to_instance(instance);
return projectMInstance->SelectPresetByName(preset_name, hard_cut);
}
bool projectm_get_selected_preset_index(projectm_handle instance, unsigned int* index)
{
if (!index)
{
return false;
}
auto projectMInstance = handle_to_instance(instance);
return projectMInstance->SelectedPresetIndex(*index);
}
void projectm_add_preset_url(projectm_handle instance, const char* preset_url, const char* preset_name,
int* rating_list, unsigned int rating_list_length)
{
if (!preset_url
|| !preset_name
|| (!rating_list && rating_list_length > 0)
|| rating_list_length != TOTAL_RATING_TYPES)
{
return;
}
RatingList ratingList;
for (unsigned int ratingIndex = 0; ratingIndex < rating_list_length; ratingIndex++)
{
ratingList.push_back(rating_list[ratingIndex]);
}
auto projectMInstance = handle_to_instance(instance);
projectMInstance->AddPresetURL(preset_url, preset_name, ratingList);
}
void projectm_insert_preset_url(projectm_handle instance, unsigned int index, const char* preset_url,
const char* preset_name, int* rating_list, unsigned int rating_list_length)
{
if (!preset_url
|| !preset_name
|| (!rating_list && rating_list_length > 0)
|| rating_list_length != TOTAL_RATING_TYPES)
{
return;
}
RatingList ratingList;
for (unsigned int ratingIndex = 0; ratingIndex < rating_list_length; ratingIndex++)
{
ratingList.push_back(rating_list[ratingIndex]);
}
auto projectMInstance = handle_to_instance(instance);
projectMInstance->InsertPresetURL(index, preset_url, preset_name, ratingList);
}
bool projectm_preset_position_valid(projectm_handle instance)
{
auto projectMInstance = handle_to_instance(instance);
return projectMInstance->PresetPositionValid();
}
const char* projectm_get_preset_filename(projectm_handle instance, unsigned int index)
{
auto projectMInstance = handle_to_instance(instance);
return projectm_alloc_string_from_std_string(projectMInstance->PresetURL(index));
}
const char* projectm_get_preset_name(projectm_handle instance, unsigned int index)
{
auto projectMInstance = handle_to_instance(instance);
return projectm_alloc_string_from_std_string(projectMInstance->PresetName(index));
}
void projectm_set_preset_name(projectm_handle instance, unsigned int index, const char* name)
{
auto projectMInstance = handle_to_instance(instance);
projectMInstance->ChangePresetName(index, name);
}
int projectm_get_preset_rating(projectm_handle instance, unsigned int index, projectm_preset_rating_type rating_type)
{
auto projectMInstance = handle_to_instance(instance);
return projectMInstance->PresetRating(index, static_cast<PresetRatingType>(rating_type));
}
void projectm_set_preset_rating(projectm_handle instance, unsigned int index, int rating,
projectm_preset_rating_type rating_type)
{
auto projectMInstance = handle_to_instance(instance);
projectMInstance->ChangePresetRating(index, rating, static_cast<PresetRatingType>(rating_type));
}
unsigned int projectm_get_playlist_size(projectm_handle instance)
{
auto projectMInstance = handle_to_instance(instance);
return projectMInstance->PlaylistSize();
}
bool projectm_get_shuffle_enabled(projectm_handle instance)
{
auto projectMInstance = handle_to_instance(instance);
return projectMInstance->ShuffleEnabled();
}
void projectm_set_shuffle_enabled(projectm_handle instance, bool shuffle_enabled)
{
auto projectMInstance = handle_to_instance(instance);
projectMInstance->SetShuffleEnabled(shuffle_enabled);
}
unsigned int projectm_get_search_index(projectm_handle instance, const char* name)
{
auto projectMInstance = handle_to_instance(instance);
return projectMInstance->SearchIndex(name);
}
void projectm_select_previous_preset(projectm_handle instance, bool hard_cut)
{
auto projectMInstance = handle_to_instance(instance);
projectMInstance->SelectPrevious(hard_cut);
}
void projectm_select_next_preset(projectm_handle instance, bool hard_cut)
{
auto projectMInstance = handle_to_instance(instance);
projectMInstance->SelectNext(hard_cut);
}
void projectm_select_random_preset(projectm_handle instance, bool hard_cut)
{
auto projectMInstance = handle_to_instance(instance);
projectMInstance->SelectRandom(hard_cut);
}
void projectm_get_window_size(projectm_handle instance, size_t* width, size_t* height)
{
auto projectMInstance = handle_to_instance(instance);

View File

@ -28,26 +28,14 @@
class projectMWrapper : public ProjectM
{
public:
projectMWrapper(std::string configFile, int flags);
projectMWrapper(std::string configFile);
projectMWrapper(class Settings settings, int flags);
projectMWrapper(class Settings settings);
void PresetSwitchedEvent(bool isHardCut, size_t presetIndex) const override;
void ShuffleEnabledValueChanged(bool shuffle_enabled) const override;
void PresetSwitchFailedEvent(bool isHardCut, unsigned int presetIndex,
void PresetSwitchFailedEvent(bool isHardCut, const std::string& presetFilename,
const std::string& failureMessage) const override;
void PresetRatingChanged(unsigned int presetIndex, int rating, PresetRatingType ratingType) const override;
projectm_preset_switched_event _presetSwitchedEventCallback{ nullptr };
projectm_shuffle_enable_changed_event _shuffleEnableChangedEventCallback{ nullptr };
projectm_preset_switch_failed_event _presetSwitchFailedEventCallback{ nullptr };
projectm_preset_rating_changed_event _presetRatingChangedEventCallback{ nullptr };
void* _presetSwitchedEventUserData{ nullptr };
void* _shuffleEnableChangedEventUserData{ nullptr };
void* _presetSwitchFailedEventUserData{ nullptr };
void* _presetRatingChangedEventUserData{ nullptr };
};

View File

@ -8,6 +8,8 @@ add_library(Renderer OBJECT
Border.hpp
DarkenCenter.cpp
DarkenCenter.hpp
FileScanner.cpp
FileScanner.hpp
Filters.cpp
Filters.hpp
MilkdropNoise.cpp

View File

@ -1,217 +1,217 @@
//
// FileScanner.cpp
// libprojectM
//
//
#include "FileScanner.hpp"
#include "Common.hpp"
#ifndef _WIN32
#include <sys/stat.h>
#include <sys/types.h>
#endif
FileScanner::FileScanner() {}
FileScanner::FileScanner(const std::vector<std::string> &rootDirs, std::vector<std::string> &extensions) : _rootDirs(rootDirs), _extensions(extensions) {}
void FileScanner::scan(ScanCallback cb) {
#if HAVE_FTS_H
scanPosix(cb);
#else
for (const auto& dir : _rootDirs)
scanGeneric(cb, dir.c_str());
#endif
}
void FileScanner::handleDirectoryError(std::string dir) {
#ifndef HAVE_FTS_H
std::cerr << "[PresetLoader] warning: errno unsupported on win32, etc platforms. fix me" << std::endl;
#else
std::cerr << dir << " scan error: ";
switch ( errno )
{
case ENOENT:
std::cerr << "ENOENT error. The path \"" << dir << "\" probably does not exist. \"man open\" for more info." << std::endl;
break;
case ENOMEM:
std::cerr << "out of memory!" << std::endl;
abort();
case ENOTDIR:
std::cerr << "directory specified is not a directory! Trying to continue..." << std::endl;
break;
case ENFILE:
std::cerr << "Your system has reached its open file limit. Trying to continue..." << std::endl;
break;
case EMFILE:
std::cerr << "too many files in use by projectM! Bailing!" << std::endl;
break;
case EACCES:
std::cerr << "permissions issue reading the specified preset directory." << std::endl;
break;
default:
break;
}
#endif
}
std::string FileScanner::extensionMatches(std::string &filename) {
// returns file name without extension
// TODO: optimize me
std::string lowerCaseFileName(filename);
std::transform(lowerCaseFileName.begin(), lowerCaseFileName.end(), lowerCaseFileName.begin(), tolower);
// Remove extension
for (auto ext : _extensions)
{
size_t found = lowerCaseFileName.find(ext);
if (found != std::string::npos)
{
std::string name = filename;
name.replace(int(found), ext.size(), "");
return name;
}
}
return {};
}
bool FileScanner::isValidFilename(std::string &filename) {
if (filename.find("__MACOSX") != std::string::npos) return false;
return true;
}
// generic implementation using dirent
void FileScanner::scanGeneric(ScanCallback cb, const char *currentDir) {
DIR * m_dir;
// Allocate a new a stream given the current directory name
if ((m_dir = opendir(currentDir)) == NULL)
{
return; // no files found in here
}
struct dirent * dir_entry;
while ((dir_entry = readdir(m_dir)) != NULL)
{
// Convert char * to friendly string
std::string filename(dir_entry->d_name);
// Some sanity checks
if (! isValidFilename(filename)) continue;
if (filename.length() == 0 || filename[0] == '.')
continue;
std::string fullPath = std::string(currentDir) + pathSeparator + filename;
#ifndef _WIN32
// filesystems are free to return DT_UNKNOWN
if (dir_entry->d_type == DT_UNKNOWN)
{
struct stat stat_path;
if (stat(fullPath.c_str(), &stat_path) == 0)
{
/**/ if (S_ISDIR(stat_path.st_mode))
dir_entry->d_type = DT_DIR;
else if (S_ISLNK(stat_path.st_mode))
dir_entry->d_type = DT_LNK;
else if (S_ISREG(stat_path.st_mode))
dir_entry->d_type = DT_REG;
}
}
#endif
if (dir_entry->d_type == DT_DIR) {
// recurse into dir
scanGeneric(cb, fullPath.c_str());
continue;
} else if (dir_entry->d_type != DT_REG && dir_entry->d_type != DT_LNK) {
// not regular file/link
continue;
}
auto nameMatched = extensionMatches(filename);
if (! nameMatched.empty())
cb(fullPath, nameMatched);
}
if (m_dir)
{
closedir(m_dir);
m_dir = 0;
}
}
#if HAVE_FTS_H
// more optimized posix "fts" directory traversal
int fts_compare(const FTSENT** one, const FTSENT** two) {
return (strcmp((*one)->fts_name, (*two)->fts_name));
}
#endif
void FileScanner::scanPosix(ScanCallback cb) {
#if HAVE_FTS_H
// efficient directory traversal
FTS* fileSystem = NULL;
FTSENT *node = NULL;
if (_rootDirs.empty())
{
return ;
}
// list of directories to scan
auto rootDirCount = _rootDirs.size();
char **dirList = (char **)malloc(sizeof(char*) * (rootDirCount + 1));
for (unsigned long i = 0; i < rootDirCount; i++) {
dirList[i] = (char *) _rootDirs[i].c_str();
}
dirList[rootDirCount] = NULL;
// initialize file hierarchy traversal
fileSystem = fts_open(dirList, FTS_LOGICAL|FTS_NOCHDIR|FTS_NOSTAT, &fts_compare);
if (fileSystem == NULL) {
std::string s;
for (std::size_t i = 0; i < _rootDirs.size(); i++)
s += _rootDirs[i] + ' ';
handleDirectoryError(s);
free(dirList);
return;
}
std::string path, name, nameMatched;
// traverse dirList
while( (node = fts_read(fileSystem)) != NULL) {
switch (node->fts_info) {
case FTS_F:
case FTS_SL:
case FTS_NSOK:
// found a file
path = std::string(node->fts_path);
name = std::string(node->fts_name);
if (!isValidFilename(path) || !isValidFilename(name)) break;
// check extension
nameMatched = extensionMatches(name);
if (! nameMatched.empty())
cb(path, nameMatched);
break;
default:
break;
}
}
fts_close(fileSystem);
free(dirList);
#endif
}
//
// FileScanner.cpp
// libprojectM
//
//
#include "FileScanner.hpp"
#include "Common.hpp"
#ifndef _WIN32
#include <sys/stat.h>
#include <sys/types.h>
#endif
FileScanner::FileScanner() {}
FileScanner::FileScanner(const std::vector<std::string> &rootDirs, std::vector<std::string> &extensions) : _rootDirs(rootDirs), _extensions(extensions) {}
void FileScanner::scan(ScanCallback cb) {
#if HAVE_FTS_H
scanPosix(cb);
#else
for (const auto& dir : _rootDirs)
scanGeneric(cb, dir.c_str());
#endif
}
void FileScanner::handleDirectoryError(std::string dir) {
#ifndef HAVE_FTS_H
std::cerr << "[PresetLoader] warning: errno unsupported on win32, etc platforms. fix me" << std::endl;
#else
std::cerr << dir << " scan error: ";
switch ( errno )
{
case ENOENT:
std::cerr << "ENOENT error. The path \"" << dir << "\" probably does not exist. \"man open\" for more info." << std::endl;
break;
case ENOMEM:
std::cerr << "out of memory!" << std::endl;
abort();
case ENOTDIR:
std::cerr << "directory specified is not a directory! Trying to continue..." << std::endl;
break;
case ENFILE:
std::cerr << "Your system has reached its open file limit. Trying to continue..." << std::endl;
break;
case EMFILE:
std::cerr << "too many files in use by projectM! Bailing!" << std::endl;
break;
case EACCES:
std::cerr << "permissions issue reading the specified preset directory." << std::endl;
break;
default:
break;
}
#endif
}
std::string FileScanner::extensionMatches(std::string &filename) {
// returns file name without extension
// TODO: optimize me
std::string lowerCaseFileName(filename);
std::transform(lowerCaseFileName.begin(), lowerCaseFileName.end(), lowerCaseFileName.begin(), tolower);
// Remove extension
for (auto ext : _extensions)
{
size_t found = lowerCaseFileName.find(ext);
if (found != std::string::npos)
{
std::string name = filename;
name.replace(int(found), ext.size(), "");
return name;
}
}
return {};
}
bool FileScanner::isValidFilename(std::string &filename) {
if (filename.find("__MACOSX") != std::string::npos) return false;
return true;
}
// generic implementation using dirent
void FileScanner::scanGeneric(ScanCallback cb, const char *currentDir) {
DIR * m_dir;
// Allocate a new a stream given the current directory name
if ((m_dir = opendir(currentDir)) == NULL)
{
return; // no files found in here
}
struct dirent * dir_entry;
while ((dir_entry = readdir(m_dir)) != NULL)
{
// Convert char * to friendly string
std::string filename(dir_entry->d_name);
// Some sanity checks
if (! isValidFilename(filename)) continue;
if (filename.length() == 0 || filename[0] == '.')
continue;
std::string fullPath = std::string(currentDir) + pathSeparator + filename;
#ifndef _WIN32
// filesystems are free to return DT_UNKNOWN
if (dir_entry->d_type == DT_UNKNOWN)
{
struct stat stat_path;
if (stat(fullPath.c_str(), &stat_path) == 0)
{
/**/ if (S_ISDIR(stat_path.st_mode))
dir_entry->d_type = DT_DIR;
else if (S_ISLNK(stat_path.st_mode))
dir_entry->d_type = DT_LNK;
else if (S_ISREG(stat_path.st_mode))
dir_entry->d_type = DT_REG;
}
}
#endif
if (dir_entry->d_type == DT_DIR) {
// recurse into dir
scanGeneric(cb, fullPath.c_str());
continue;
} else if (dir_entry->d_type != DT_REG && dir_entry->d_type != DT_LNK) {
// not regular file/link
continue;
}
auto nameMatched = extensionMatches(filename);
if (! nameMatched.empty())
cb(fullPath, nameMatched);
}
if (m_dir)
{
closedir(m_dir);
m_dir = 0;
}
}
#if HAVE_FTS_H
// more optimized posix "fts" directory traversal
int fts_compare(const FTSENT** one, const FTSENT** two) {
return (strcmp((*one)->fts_name, (*two)->fts_name));
}
#endif
void FileScanner::scanPosix(ScanCallback cb) {
#if HAVE_FTS_H
// efficient directory traversal
FTS* fileSystem = NULL;
FTSENT *node = NULL;
if (_rootDirs.empty())
{
return ;
}
// list of directories to scan
auto rootDirCount = _rootDirs.size();
char **dirList = (char **)malloc(sizeof(char*) * (rootDirCount + 1));
for (unsigned long i = 0; i < rootDirCount; i++) {
dirList[i] = (char *) _rootDirs[i].c_str();
}
dirList[rootDirCount] = NULL;
// initialize file hierarchy traversal
fileSystem = fts_open(dirList, FTS_LOGICAL|FTS_NOCHDIR|FTS_NOSTAT, &fts_compare);
if (fileSystem == NULL) {
std::string s;
for (std::size_t i = 0; i < _rootDirs.size(); i++)
s += _rootDirs[i] + ' ';
handleDirectoryError(s);
free(dirList);
return;
}
std::string path, name, nameMatched;
// traverse dirList
while( (node = fts_read(fileSystem)) != NULL) {
switch (node->fts_info) {
case FTS_F:
case FTS_SL:
case FTS_NSOK:
// found a file
path = std::string(node->fts_path);
name = std::string(node->fts_name);
if (!isValidFilename(path) || !isValidFilename(name)) break;
// check extension
nameMatched = extensionMatches(name);
if (! nameMatched.empty())
cb(path, nameMatched);
break;
default:
break;
}
}
fts_close(fileSystem);
free(dirList);
#endif
}

View File

@ -1,48 +1,48 @@
//
// FileScanner.hpp
// libprojectM
//
// Cross-platform directory traversal with filtering by extension
#ifndef FileScanner_hpp
#define FileScanner_hpp
#include <string>
#include <vector>
#include <iostream>
#include <functional>
#include <string.h>
#if HAVE_FTS_H
#include <fts.h>
extern "C"
{
#include <errno.h>
#include <dirent.h>
}
#else
#include "dirent.h"
#endif
typedef std::function<void(std::string &path, std::string &name)> ScanCallback;
class FileScanner
{
public:
FileScanner();
FileScanner(const std::vector<std::string> &rootDirs, std::vector<std::string> &extensions);
void scan(ScanCallback cb);
std::string extensionMatches(std::string &filename);
private:
std::vector<std::string> _rootDirs;
std::vector<std::string> _extensions;
void scanGeneric(ScanCallback cb, const char *dir);
void scanPosix(ScanCallback cb);
void handleDirectoryError(std::string dir);
bool isValidFilename(std::string &filename);
};
#endif /* FileScanner_hpp */
//
// FileScanner.hpp
// libprojectM
//
// Cross-platform directory traversal with filtering by extension
#ifndef FileScanner_hpp
#define FileScanner_hpp
#include <string>
#include <vector>
#include <iostream>
#include <functional>
#include <string.h>
#if HAVE_FTS_H
#include <fts.h>
extern "C"
{
#include <errno.h>
#include <dirent.h>
}
#else
#include "dirent.h"
#endif
typedef std::function<void(std::string &path, std::string &name)> ScanCallback;
class FileScanner
{
public:
FileScanner();
FileScanner(const std::vector<std::string> &rootDirs, std::vector<std::string> &extensions);
void scan(ScanCallback cb);
std::string extensionMatches(std::string &filename);
private:
std::vector<std::string> _rootDirs;
std::vector<std::string> _extensions;
void scanGeneric(ScanCallback cb, const char *dir);
void scanPosix(ScanCallback cb);
void handleDirectoryError(std::string dir);
bool isValidFilename(std::string &filename);
};
#endif /* FileScanner_hpp */

View File

@ -43,12 +43,6 @@ class Renderer
{
public:
struct preset {
int id;
std::string name;
std::string presetPack;
};
Renderer() = delete;
Renderer(int width, int height, int gx, int gy, BeatDetect* beatDetect, std::vector<std::string>& textureSearchPaths);
~Renderer();
@ -97,8 +91,6 @@ public:
void UpdateContext(PipelineContext& context);
bool shuffletrack{ false };
bool correction{ true };
bool noSwitch{ false };
@ -111,8 +103,6 @@ public:
float realfps{ 0.0 };
std::string title;
int m_activePresetID{ 0 };
std::vector<preset> m_presetList;
private:
void SetupPass1(const Pipeline& pipeline, const PipelineContext& pipelineContext);

View File

@ -3,7 +3,6 @@
//
#include <iostream>
#include <MilkdropPresetFactory/Parser.hpp>
#include <TestRunner.hpp>
#include <MilkdropPresetFactory/Param.hpp>
@ -25,7 +24,6 @@ bool TestRunner::run()
// We still call register/run tests in NDEBUG (useful for performance testing)
// but tests may choose to comment out body to save space
tests.push_back(Param::test());
tests.push_back(Parser::test());
tests.push_back(Expr::test());
}