A simple and dumb lv2 plugin to test host state support
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

301 lines
8.2KB

  1. /*
  2. Copyright (C) 2020 falkTX
  3. This work is free. You can redistribute it and/or modify it under the
  4. terms of the Do What The Fuck You Want To Public License, Version 2,
  5. as published by Sam Hocevar. See the COPYING file for more details.
  6. */
  7. #include <lv2.h>
  8. #include <lv2/atom/atom.h>
  9. #include <lv2/log/logger.h>
  10. #include <lv2/state/state.h>
  11. #include <stdlib.h>
  12. #include <stdio.h>
  13. #include <string.h>
  14. #include <unistd.h>
  15. #ifdef DO_NOT_HAVE_LV2_STATE_FREE_PATH
  16. // forwards compatibility with old lv2 headers
  17. #define LV2_STATE__freePath LV2_STATE_PREFIX "freePath"
  18. typedef void* LV2_State_Free_Path_Handle;
  19. typedef struct {
  20. LV2_State_Free_Path_Handle handle;
  21. void (*free_path)(LV2_State_Free_Path_Handle handle, char* path);
  22. } LV2_State_Free_Path;
  23. #endif
  24. typedef struct {
  25. bool activated, deactivated, saved, restored;
  26. LV2_Log_Logger logger;
  27. const LV2_Atom_Sequence* seqIn;
  28. LV2_Atom_Sequence* seqOut;
  29. const LV2_State_Free_Path* freePath;
  30. const LV2_State_Make_Path* makePath;
  31. const LV2_State_Map_Path* mapPath;
  32. } StateTest;
  33. static void lv2_free_path(const LV2_State_Free_Path* freePath, char* path)
  34. {
  35. if (freePath != NULL)
  36. freePath->free_path(freePath->handle, path);
  37. else
  38. free(path);
  39. }
  40. static LV2_Handle instantiate(const LV2_Descriptor* const descriptor,
  41. const double sample_rate,
  42. const char* const bundle_path,
  43. const LV2_Feature* const* const features)
  44. {
  45. const LV2_State_Free_Path* freePath = NULL;
  46. const LV2_State_Make_Path* makePath = NULL;
  47. const LV2_State_Map_Path* mapPath = NULL;
  48. const LV2_Log_Log* log = NULL;
  49. const LV2_URID_Map* uridMap = NULL;
  50. for (int i=0; features[i] != NULL; ++i)
  51. {
  52. /**/ if (strcmp(features[i]->URI, LV2_STATE__freePath) == 0)
  53. freePath = features[i]->data;
  54. else if (strcmp(features[i]->URI, LV2_STATE__makePath) == 0)
  55. makePath = features[i]->data;
  56. else if (strcmp(features[i]->URI, LV2_STATE__mapPath) == 0)
  57. mapPath = features[i]->data;
  58. else if (strcmp(features[i]->URI, LV2_LOG__log) == 0)
  59. log = features[i]->data;
  60. else if (strcmp(features[i]->URI, LV2_URID__map) == 0)
  61. uridMap = features[i]->data;
  62. }
  63. StateTest* instance = calloc(1, sizeof(StateTest));
  64. instance->freePath = freePath;
  65. instance->makePath = makePath;
  66. instance->mapPath = mapPath;
  67. lv2_log_logger_init(&instance->logger, uridMap, log);
  68. if (makePath == NULL)
  69. {
  70. lv2_log_note(&instance->logger, "state-test init, host does not have makePath\n");
  71. return instance;
  72. }
  73. char* projectPath;
  74. // test getting initial dir
  75. projectPath = makePath->path(makePath->handle, ".");
  76. if (projectPath != NULL)
  77. {
  78. const int status = access(projectPath, F_OK);
  79. lv2_log_note(&instance->logger, "state-test init, host has makePath and initial dir is: '%s' (access = %i)\n",
  80. projectPath, status);
  81. lv2_free_path(freePath, projectPath);
  82. }
  83. else
  84. {
  85. lv2_log_note(&instance->logger, "state-test init, host has makePath but failed to get initial path\n");
  86. }
  87. // test creating single subdirs
  88. projectPath = makePath->path(makePath->handle, "single-subdir/");
  89. if (projectPath != NULL)
  90. {
  91. const int status = access(projectPath, F_OK);
  92. lv2_log_note(&instance->logger, "state-test init, single-subdir creation resulted in '%s' (access = %i)\n",
  93. projectPath, status);
  94. lv2_free_path(freePath, projectPath);
  95. }
  96. else
  97. {
  98. lv2_log_note(&instance->logger, "state-test init, single-subdir creation failed\n");
  99. }
  100. // test creating multiple subdirs
  101. projectPath = makePath->path(makePath->handle, "subdir1/subdir2/subdir3/");
  102. if (projectPath != NULL)
  103. {
  104. const int status = access(projectPath, F_OK);
  105. lv2_log_note(&instance->logger, "state-test init, multi-subdir creation resulted in '%s' (access = %i)\n",
  106. projectPath, status);
  107. lv2_free_path(freePath, projectPath);
  108. }
  109. else
  110. {
  111. lv2_log_note(&instance->logger, "state-test init, multi-subdir creation failed\n");
  112. }
  113. return instance;
  114. // unused
  115. (void)descriptor;
  116. (void)sample_rate;
  117. (void)bundle_path;
  118. }
  119. #define instancePtr ((StateTest*)instance)
  120. static void connect_port(LV2_Handle instance, uint32_t port, void* data_location)
  121. {
  122. switch (port)
  123. {
  124. case 0:
  125. instancePtr->seqIn = data_location;
  126. break;
  127. case 1:
  128. instancePtr->seqOut = data_location;
  129. break;
  130. }
  131. }
  132. static void activate(LV2_Handle instance)
  133. {
  134. instancePtr->activated = true;
  135. }
  136. static void run(LV2_Handle instance, uint32_t sample_count)
  137. {
  138. if (instancePtr->deactivated)
  139. {
  140. instancePtr->deactivated = false;
  141. lv2_log_note(&instancePtr->logger, "plugin was deactivated\n");
  142. }
  143. if (instancePtr->activated)
  144. {
  145. instancePtr->activated = false;
  146. lv2_log_note(&instancePtr->logger, "plugin was activated\n");
  147. }
  148. if (instancePtr->restored)
  149. {
  150. instancePtr->restored = false;
  151. lv2_log_note(&instancePtr->logger, "plugin state was restored\n");
  152. }
  153. if (instancePtr->saved)
  154. {
  155. instancePtr->saved = false;
  156. lv2_log_note(&instancePtr->logger, "plugin state was saved\n");
  157. }
  158. return;
  159. // unused
  160. (void)sample_count;
  161. }
  162. static void deactivate(LV2_Handle instance)
  163. {
  164. instancePtr->deactivated = true;
  165. }
  166. static void cleanup(LV2_Handle instance)
  167. {
  168. free(instance);
  169. }
  170. static LV2_State_Status save(LV2_Handle instance,
  171. LV2_State_Store_Function store,
  172. LV2_State_Handle handle,
  173. uint32_t flags,
  174. const LV2_Feature* const* features)
  175. {
  176. const LV2_State_Free_Path* freePath = instancePtr->freePath;
  177. const LV2_State_Make_Path* makePath = instancePtr->makePath;
  178. char* const projectPath = makePath->path(makePath->handle, ".");
  179. if (projectPath != NULL)
  180. {
  181. lv2_log_note(&instancePtr->logger, "state-test save ok, path is: '%s'\n", projectPath);
  182. lv2_free_path(freePath, projectPath);
  183. }
  184. else
  185. {
  186. lv2_log_note(&instancePtr->logger, "state-test save ok, but failed to get initial path\n");
  187. }
  188. instancePtr->saved = true;
  189. return LV2_STATE_SUCCESS;
  190. // TODO
  191. (void)store;
  192. (void)handle;
  193. (void)flags;
  194. (void)features;
  195. }
  196. static LV2_State_Status restore(LV2_Handle instance,
  197. LV2_State_Retrieve_Function retrieve,
  198. LV2_State_Handle handle,
  199. uint32_t flags,
  200. const LV2_Feature* const* features)
  201. {
  202. const LV2_State_Free_Path* freePath = instancePtr->freePath;
  203. const LV2_State_Make_Path* makePath = instancePtr->makePath;
  204. char* const projectPath = makePath->path(makePath->handle, ".");
  205. if (projectPath != NULL)
  206. {
  207. lv2_log_note(&instancePtr->logger, "state-test restore ok, path is: '%s'\n", projectPath);
  208. if (freePath != NULL)
  209. freePath->free_path(freePath->handle, projectPath);
  210. else
  211. free(projectPath);
  212. }
  213. else
  214. {
  215. lv2_log_note(&instancePtr->logger, "state-test restore ok, but failed to get initial path\n");
  216. }
  217. instancePtr->restored = true;
  218. return LV2_STATE_SUCCESS;
  219. // TODO
  220. (void)retrieve;
  221. (void)handle;
  222. (void)flags;
  223. (void)features;
  224. }
  225. static const void* extension_data(const char* const uri)
  226. {
  227. static const LV2_State_Interface iface = {
  228. .save = save,
  229. .restore = restore
  230. };
  231. if (strcmp(uri, LV2_STATE__interface) == 0)
  232. return &iface;
  233. return NULL;
  234. }
  235. LV2_SYMBOL_EXPORT
  236. const LV2_Descriptor* lv2_descriptor(const uint32_t index)
  237. {
  238. static const LV2_Descriptor desc = {
  239. .URI = "https://git.kx.studio/falkTX/lv2-state-test",
  240. .instantiate = instantiate,
  241. .connect_port = connect_port,
  242. .activate = activate,
  243. .run = run,
  244. .deactivate = deactivate,
  245. .cleanup = cleanup,
  246. .extension_data = extension_data
  247. };
  248. return index == 0 ? &desc : NULL;
  249. }