Kestrel Interface
Loading...
Searching...
No Matches
kest_context.c
Go to the documentation of this file.
1#include "kest_int.h"
2
3#ifndef PRINTLINES_ALLOWED
4#define PRINTLINES_ALLOWED 0
5#endif
6
7#define INITIAL_PROFILE_ARRAY_LENGTH 8
8#define PROFILE_ARRAY_CHUNK_SIZE 8
9
10static const char *FNAME = "kest_context.c";
11
13{
14 if (!cxt)
15 return ERR_NULL_PTR;
16
17 cxt->n_profiles = 0;
18
19 cxt->active_profile = NULL;
20 cxt->working_profile = NULL;
21
22 cxt->profiles = NULL;
23 cxt->sequences = NULL;
24 cxt->sequence = NULL;
25
27
28 cxt->main_sequence.name = "Profiles";
29
30 cxt->saved_profiles_loaded = 0;
32
33 cxt->pages.backstage = NULL;
34 cxt->pages.current_page = NULL;
35
36 cxt->effects = NULL;
37
38 init_parameter(&cxt->input_gain, "Input Gain", -100, -30.0, 30.0);
39 cxt->input_gain.units = " dB";
40 cxt->input_gain.id = (kest_parameter_id){.profile_id = CONTEXT_PROFILE_ID, .effect_id = 0, .parameter_id = INPUT_GAIN_PID};
41 cxt->input_gain.max_velocity = 0.4;
44
45 init_parameter(&cxt->output_gain, "Output Gain", -100, -30.0, 30.0);
46 cxt->output_gain.units = " dB";
47 cxt->output_gain.id = (kest_parameter_id){.profile_id = CONTEXT_PROFILE_ID, .effect_id = 0, .parameter_id = OUTPUT_GAIN_PID};
48 cxt->output_gain.max_velocity = 0.4;
51
52 #ifdef KEST_ENABLE_REPRESENTATIONS
53 cxt->state_rep.representer = NULL;
54 cxt->state_rep.representee = cxt;
55 cxt->state_rep.update = kest_state_representation_update;
56 cxt->state_rep_lstub.data = &cxt->state_rep;
57 cxt->state_rep_lstub.next = NULL;
58 #endif
59
60 #ifdef KEST_USE_FREERTOS
61 cxt->mutex = xSemaphoreCreateMutex();
62 #endif
63
64 return NO_ERROR;
65}
66
68{
69 if (!cxt)
70 return ERR_NULL_PTR;
71
73
74 cxt->main_sequence.name = "Profiles";
75 cxt->main_sequence.view_page = &cxt->pages.main_sequence_view;
76
77 for (int k = 0; k < KEST_FILENAME_LEN; k++)
78 {
79 if (!MAIN_SEQUENCE_FNAME[k])
80 {
81 cxt->main_sequence.fname[k] = 0;
82 break;
83 }
84
86 }
87
88 cxt->main_sequence.has_fname = 1;
90
91 return NO_ERROR;
92}
93
95{
96 KEST_PRINTF("kest_context_init_effect_list\n");
97 if (!cxt)
98 return ERR_NULL_PTR;
99
100 return NO_ERROR;
101}
102
104{
105 if (!cxt)
106 return ERR_NULL_PTR;
107
108 cxt->pages.backstage = NULL;
109 cxt->pages.current_page = NULL;
110
111 return NO_ERROR;
112}
113
115{
116 if (!cxt)
117 return ERR_NULL_PTR;
118
119 kest_profile *profile = kest_alloc(sizeof(kest_profile));
120
121 if (!profile)
122 return ERR_ALLOC_FAIL;
123
124 init_m_profile(profile);
125
126 profile_ll *nl = kest_profile_pll_append(cxt->profiles, profile);
127
128 if (!nl)
129 {
130 free_profile(profile);
131 return ERR_ALLOC_FAIL;
132 }
133
134 cxt->profiles = nl;
135
136 cxt->n_profiles++;
137
138 return NO_ERROR;
139}
140
142{
143 if (!cxt)
144 return NULL;
145
146 KEST_PRINTF("kest_context_add_profile_rp\n");
147
148 kest_profile *profile = kest_alloc(sizeof(kest_profile));
149
150 if (!profile)
151 return NULL;
152
153 KEST_PRINTF("profile = %p\n", profile);
154
155 init_m_profile(profile);
156
157 KEST_PRINTF("profile->name = %p\n", profile->name);
158 KEST_PRINTF("\t\t\t= %s\n", profile->name ? profile->name : "(NULL)");
159
160 profile_ll *nl = kest_profile_pll_append(cxt->profiles, profile);
161
162 if (!nl)
163 {
164 free_profile(profile);
165 return NULL;
166 }
167
168 cxt->profiles = nl;
169
170 cxt->n_profiles++;
171
172 return profile;
173}
174
176{
177 if (!cxt)
178 return NULL;
179
180 kest_sequence *sequence = kest_alloc(sizeof(kest_sequence));
181
182 if (!sequence)
183 return NULL;
184
185 init_m_sequence(sequence);
186
187 sequence_ll *nl = kest_sequence_pll_append(cxt->sequences, sequence);
188
189 if (!nl)
190 {
191 free_sequence(sequence);
192 return NULL;
193 }
194
195 cxt->sequences = nl;
196
197 return sequence;
198}
199
201{
202 if (!cxt)
203 return NULL;
204
205 profile_ll *current = cxt->profiles;
206
207 while (current)
208 {
209 if (current->data && current->data->id == profile_id)
210 {
211 return current->data;
212 }
213
214 current = current->next;
215 }
216
217 return NULL;
218}
219
220kest_effect *cxt_get_effect_by_id(kest_context *cxt, uint16_t profile_id, uint16_t effect_id)
221{
222 if (!cxt)
223 return NULL;
224
225 kest_profile *profile = cxt_get_profile_by_id(cxt, profile_id);
226
227 if (!profile)
228 return NULL;
229
230
231 kest_effect_pll *current = profile->pipeline.effects;
232
233 while (current)
234 {
235 if (current->data && current->data->id == effect_id)
236 {
237 return current->data;
238 }
239
240 current = current->next;
241 }
242
243 return NULL;
244}
245
246kest_parameter *cxt_get_parameter_by_id(kest_context *cxt, uint16_t profile_id, uint16_t effect_id, uint16_t parameter_id)
247{
248 if (!cxt)
249 return NULL;
250
251 kest_effect *effect = cxt_get_effect_by_id(cxt, profile_id, effect_id);
252
253 if (!effect)
254 return NULL;
255
256 return effect_get_parameter(effect, parameter_id);
257}
258
260{
261 if (!cxt || !pp || !tp)
262 return ERR_NULL_PTR;
263
264 *pp = NULL;
265 *tp = NULL;
266
267 if (id.profile_id == CONTEXT_PROFILE_ID)
268 {
269 if (id.effect_id == 0)
270 {
271 switch (id.parameter_id)
272 {
273 case INPUT_GAIN_PID:
274 *pp = &global_cxt.input_gain;
275 return NO_ERROR;
276
277 case OUTPUT_GAIN_PID:
278 *pp = &global_cxt.output_gain;
279 return NO_ERROR;
280
281 default:
282 return ERR_BAD_ARGS;
283 }
284 }
285
286 return ERR_BAD_ARGS;
287 }
288
289 kest_effect *effect = cxt_get_effect_by_id(cxt, id.profile_id, id.effect_id);
290
291
292 if (!effect)
293 {
294 return ERR_BAD_ARGS;
295 }
296
297 kest_parameter *param = effect_get_parameter(effect, id.parameter_id);
298
299 if (!param)
300 {
301 return ERR_BAD_ARGS;
302 }
303
304 *pp = param;
305 *tp = effect;
306
307 return NO_ERROR;
308}
309
310kest_setting *cxt_get_setting_by_id(kest_context *cxt, uint16_t profile_id, uint16_t effect_id, uint16_t parameter_id)
311{
312 if (!cxt)
313 return NULL;
314
315 kest_effect *effect = cxt_get_effect_by_id(cxt, profile_id, effect_id);
316
317 if (!effect)
318 return NULL;
319
320 return effect_get_setting(effect, parameter_id);
321}
322
323int cxt_effect_id_to_position(kest_context *cxt, uint16_t profile_id, uint16_t effect_id)
324{
325 if (!cxt)
326 return -ERR_NULL_PTR;
327
328 kest_profile *profile = cxt_get_profile_by_id(cxt, profile_id);
329
330 if (!profile)
332
333 kest_effect_pll *current = profile->pipeline.effects;
334
335 int i = 0;
336 while (current)
337 {
338 if (current->data && current->data->id == effect_id)
339 return i;
340
341 current = current->next;
342 i++;
343 }
344
346}
347
348int cxt_effect_position_to_id(kest_context *cxt, uint16_t profile_id, uint16_t effect_pos)
349{
350 if (!cxt)
351 return -ERR_NULL_PTR;
352
353 kest_profile *profile = cxt_get_profile_by_id(cxt, profile_id);
354
355 if (!profile)
357
358 kest_effect_pll *current = profile->pipeline.effects;
359
360 int i = 0;
361 while (current)
362 {
363 if (i == effect_pos)
364 {
365 if (!current->data)
366 return ERR_NULL_PTR;
367
368 return current->data->id;
369 }
370
371 current = current->next;
372 i++;
373 }
374
376}
377
379{
380 if (!cxt || !profile)
381 return ERR_NULL_PTR;
382
383 profile_ll *current = cxt->profiles;
384 profile_ll *prev = NULL;
385
386 if (profile && profile->has_fname)
387 remove(profile->fname);
388
389 while (current)
390 {
391 if (current->data == profile)
392 {
393 #ifdef USE_TEENSY
394 queue_msg_to_teensy(create_m_message(KEST_MESSAGE_DELETE_PROFILE, "s", profile->id));
395 #endif
396
397 if (!prev)
398 {
399 cxt->profiles = current->next;
400 }
401 else
402 {
403 prev->next = current->next;
404 }
405
406 free_profile(profile);
407 kest_free(current);
408
409 return NO_ERROR;
410 }
411
412 prev = current;
413 current = current->next;
414 }
415
417}
418
420{
421 if (!cxt || !sequence)
422 return ERR_NULL_PTR;
423
424 sequence_ll *current = cxt->sequences;
425 sequence_ll *prev = NULL;
426
427 if (sequence && sequence->has_fname)
428 remove(sequence->fname);
429
430 while (current)
431 {
432 if (current->data == sequence)
433 {
434 if (!prev)
435 {
436 cxt->sequences = current->next;
437 }
438 else
439 {
440 prev->next = current->next;
441 }
442
443 free_sequence(sequence);
444 kest_free(current);
445
446 return NO_ERROR;
447 }
448
449 prev = current;
450 current = current->next;
451 }
452
454}
455
456int cxt_remove_effect(kest_context *cxt, uint16_t pid, uint16_t tid)
457{
458 if (!cxt)
459 return ERR_NULL_PTR;
460
461 int ret_val = kest_profile_remove_effect(cxt_get_profile_by_id(cxt, pid), tid);
462
463 if (ret_val == NO_ERROR)
464 {
465 #ifdef USE_TEENSY
466 queue_msg_to_teensy(create_m_message(KEST_MESSAGE_REMOVE_TRANSFORMER, "ss", pid, tid));
467 #endif
468 }
469
470 return ret_val;
471}
472
474{
475 if (profile)
477
478 if (profile == global_cxt.active_profile)
479 return NO_ERROR;
480
481 if (profile && profile->sequence)
482 {
483 KEST_PRINTF("profile has a sequence. call kest_sequence_activate_at\n");
484 kest_sequence_activate_at(profile->sequence, profile);
485 }
486
488
489 global_cxt.active_profile = profile;
490
491 uint16_t id = profile ? profile->id : 0;
492
493 #ifdef USE_TEENSY
494 int ret_val = queue_msg_to_teensy(create_m_message(KEST_MESSAGE_SWITCH_PROFILE, "s", id));
495 #endif
496
497 return NO_ERROR;
498}
499
500// This version is called from a sequence-related-cb, so there is no need to
501// tell the sequence about it; it is handled from the caller
503{
504 KEST_PRINTF("set_active_profile_from_sequence, profile = %p\n", profile);
505 if (profile)
507
508 if (profile == global_cxt.active_profile)
509 return NO_ERROR;
510
512
513 global_cxt.active_profile = profile;
514
515 int ret_val = NO_ERROR;
516 #ifdef USE_TEENSY
517 uint16_t id = profile ? profile->id : 0;
518 ret_val = queue_msg_to_teensy(create_m_message(KEST_MESSAGE_SWITCH_PROFILE, "s", id));
519 #endif
520
521 return ret_val;
522}
523
525{
526 if (!profile)
527 return ERR_NULL_PTR;
528
529 if (profile == global_cxt.working_profile)
530 return NO_ERROR;
531
532 global_cxt.working_profile = profile;
533
534 return NO_ERROR;
535}
536
538{
539 if (!cxt)
540 return;
541
542 KEST_PRINTF("Printing profiles...\n");
543
544 profile_ll *current = global_cxt.profiles;
545
546
547 int i = 0;
548 while (current)
549 {
550 KEST_PRINTF("Profile %d, stored at %p, ", i, current->data);
551
552 if (current->data)
553 {
554 int j = 0;
555 kest_effect_pll *ct = current->data->pipeline.effects;
556
557 while (ct)
558 {
559 ct = ct->next;
560 j++;
561 }
562 KEST_PRINTF("has name %s, and has %d effects%s", current->data->name ? current->data->name : "(NULL)", j, (j > 0) ? ", which are\n" : "\n\n");
563
564 ct = current->data->pipeline.effects;
565
566 while (ct)
567 {
568 KEST_PRINTF("\t%s,\n", (ct->data && kest_effect_name(ct->data)) ? kest_effect_name(ct->data) : "UNKNOWN");
569 ct = ct->next;
570 }
571 }
572 current = current->next;
573 i++;
574 }
575
576 if (i == 0)
577 {
578 KEST_PRINTF("There are none!\n");
579 }
580}
581
583{
584 if (!cxt)
585 return ERR_NULL_PTR;
586
587 profile_ll *current = cxt->profiles;
588
589 while (current)
590 {
591 if (current->data && current->data->view_page)
592 {
593 //profile_view_set_left_button_mode(current->data->view_page, LEFT_BUTTON_MENU);
594 }
595
596 current = current->next;
597 }
598
599 return NO_ERROR;
600}
601
603{
604 if (!cxt)
605 return ERR_NULL_PTR;
606
607 KEST_PRINTF("cxt_handle_hw_switch, sw = %d\n", sw);
608
609 if (cxt->sequence)
610 {
611 if (sw == 0)
613 else if (sw == 1)
615 }
616
617 return NO_ERROR;
618}
619
621{
622 if (!cxt)
623 return NULL;
624
625 profile_ll *current = cxt->profiles;
626
627 KEST_PRINTF("Searching for profile with fname %s...\n", fname);
628 while (current)
629 {
630 if (current->data && current->data->has_fname)
631 {
632 KEST_PRINTF("Check %s\n", current->data->fname);
633 if (strncmp(current->data->fname, fname, PROFILE_NAME_MAX_LEN) == 0)
634 {
635 KEST_PRINTF("Match!\n");
636 return current->data;
637 }
638 KEST_PRINTF("No match\n");
639 }
640
641 current = current->next;
642 }
643
644 return NULL;
645}
646
648{
649 if (!cxt)
650 return ERR_NULL_PTR;
651
652 profile_ll *current = cxt->profiles;
653
654 while (current)
655 {
656 if (current->data)
657 {
658 kest_profile_save(current->data);
659 }
660
661 current = current->next;
662 }
663
664 return NO_ERROR;
665}
666
668{
669 if (!cxt)
670 return ERR_NULL_PTR;
671
672 #ifdef KEST_USE_FREERTOS
673 if (xSemaphoreTake(cxt->mutex, 0) != pdTRUE) return ERR_MUTEX_UNAVAILABLE;
674 #else
676 #endif
677
678 return NO_ERROR;
679}
680
682{
683 if (!cxt)
684 return ERR_NULL_PTR;
685
686 #ifdef KEST_USE_FREERTOS
687 if (xSemaphoreTake(cxt->mutex, portMAX_DELAY) != pdTRUE)
689 #else
691 #endif
692
693 return NO_ERROR;
694}
695
696
698{
699 if (!cxt)
700 return ERR_NULL_PTR;
701
702 #ifdef KEST_USE_FREERTOS
703 xSemaphoreGive(cxt->mutex);
704 #else
706 #endif
707
708 return NO_ERROR;
709}
710
712{
713 if (!cxt)
714 return ERR_NULL_PTR;
715
716 queue_representation_list_update(&cxt->state_rep_lstub);
717
718 return NO_ERROR;
719}
720
722{
723 KEST_PRINTF("cxt_get_profile_by_fname(cxt = %p, fname = %s)\n", cxt, fname ? fname : "(NULL)");
724
725 if (!cxt || !fname)
726 return NULL;
727
728 kest_profile_pll *current = cxt->profiles;
729
730 KEST_PRINTF("Searching the list. %s\n", !current ? "... but it is empty!" : "");
731 int i = 0;
732 while (current)
733 {
734 KEST_PRINTF("Profile %d ", i);
735 if (current->data)
736 {
737 KEST_PRINTF("has fname \"%s\".\n", current->data->has_fname ? current->data->fname : "(NULL)");
738 }
739 else
740 {
741 KEST_PRINTF("... doesn't exist???\n");
742 }
743 if (current->data && current->data->has_fname && fnames_agree(current->data->fname, fname))
744 {
745 KEST_PRINTF("That's the one :) returning it\n");
746 return current->data;
747 }
748
749 current = current->next;
750 i++;
751 }
752
753 return NULL;
754}
755
757{
758 if (!cxt || !fname)
759 return NULL;
760
761 kest_sequence_pll *current = cxt->sequences;
762
763 while (current)
764 {
765 if (current->data && current->data->has_fname && fnames_agree(current->data->fname, fname))
766 return current->data;
767
768 current = current->next;
769 }
770
771 return NULL;
772}
773
775{
776 KEST_PRINTF("kest_cxt_set_input_gain\n");
777
778 if (!cxt) return ERR_NULL_PTR;
779
780 int ret_val = kest_parameter_trigger_update(&cxt->input_gain, gain);
781
782 KEST_PRINTF("kest_cxt_set_input_gain done\n");
783 return ret_val;
784}
785
787{
788 KEST_PRINTF("kest_cxt_set_output_gain\n");
789 if (!cxt) return ERR_NULL_PTR;
790
791 int ret_val = kest_parameter_trigger_update(&cxt->output_gain, gain);
792
793 KEST_PRINTF("kest_cxt_set_input_gain done\n");
794 return ret_val;
795}
796
798{
799 if (!cxt || !cname)
800 return NULL;
801
802 kest_effect_desc_pll *current = cxt->effects;
803
804 while (current)
805 {
806 if (current->data && current->data->cname && strcmp(current->data->cname, cname) == 0)
807 return current->data;
808
809 current = current->next;
810 }
811
812 return NULL;
813}
void kest_free(void *ptr)
Definition kest_alloc.c:32
void * kest_alloc(size_t size)
Definition kest_alloc.c:11
int cxt_get_parameter_and_effect_by_id(kest_context *cxt, kest_parameter_id id, kest_parameter **pp, kest_effect **tp)
int kest_context_add_profile(kest_context *cxt)
int kest_cxt_set_output_gain(kest_context *cxt, float gain)
int kest_context_init_ui(kest_context *cxt)
int cxt_save_all_profiles(kest_context *cxt)
int set_working_profile(kest_profile *profile)
void context_print_profiles(kest_context *cxt)
kest_profile * cxt_find_profile(kest_context *cxt, const char *fname)
kest_setting * cxt_get_setting_by_id(kest_context *cxt, uint16_t profile_id, uint16_t effect_id, uint16_t parameter_id)
int set_active_profile(kest_profile *profile)
int cxt_remove_effect(kest_context *cxt, uint16_t pid, uint16_t tid)
int kest_cxt_release_mutex(kest_context *cxt)
kest_parameter * cxt_get_parameter_by_id(kest_context *cxt, uint16_t profile_id, uint16_t effect_id, uint16_t parameter_id)
int kest_cxt_obtain_mutex(kest_context *cxt)
kest_effect * cxt_get_effect_by_id(kest_context *cxt, uint16_t profile_id, uint16_t effect_id)
kest_sequence * cxt_get_sequence_by_fname(kest_context *cxt, const char *fname)
int set_active_profile_from_sequence(kest_profile *profile)
int cxt_effect_id_to_position(kest_context *cxt, uint16_t profile_id, uint16_t effect_id)
int kest_cxt_queue_save_state(kest_context *cxt)
kest_profile * kest_context_add_profile_rp(kest_context *cxt)
kest_effect_desc * kest_cxt_get_effect_desc_from_cname(kest_context *cxt, const char *cname)
int kest_cxt_set_input_gain(kest_context *cxt, float gain)
int cxt_effect_position_to_id(kest_context *cxt, uint16_t profile_id, uint16_t effect_pos)
int cxt_remove_sequence(kest_context *cxt, kest_sequence *sequence)
kest_profile * cxt_get_profile_by_id(kest_context *cxt, uint16_t profile_id)
int kest_init_context(kest_context *cxt)
int cxt_handle_hw_switch(kest_context *cxt, int sw)
kest_profile * cxt_get_profile_by_fname(kest_context *cxt, const char *fname)
int kest_context_init_effect_list(kest_context *cxt)
int cxt_remove_profile(kest_context *cxt, kest_profile *profile)
kest_sequence * kest_context_add_sequence_rp(kest_context *cxt)
int kest_cxt_obtain_mutex_wait_forever(kest_context *cxt)
int cxt_set_all_profiles_left_button_to_main_menu(kest_context *cxt)
int kest_context_init_main_sequence(kest_context *cxt)
#define INPUT_GAIN_PID
Definition kest_context.h:7
kest_profile_pll profile_ll
#define OUTPUT_GAIN_PID
Definition kest_context.h:8
#define CONTEXT_PROFILE_ID
Definition kest_context.h:6
const char * kest_effect_name(kest_effect *effect)
Definition kest_effect.c:17
kest_setting * effect_get_setting(kest_effect *effect, int n)
kest_parameter * effect_get_parameter(kest_effect *effect, int n)
#define ERR_ALLOC_FAIL
#define ERR_BAD_ARGS
#define ERR_INVALID_TRANSFORMER_ID
#define NO_ERROR
#define ERR_MUTEX_UNAVAILABLE
#define ERR_FEATURE_DISABLED
#define ERR_INVALID_PROFILE_ID
#define ERR_NULL_PTR
kest_expression kest_expression_standard_gain_min
kest_expression kest_expression_standard_gain_max
int fnames_agree(char *a, char *b)
#define MAIN_SEQUENCE_FNAME
Definition kest_files.h:23
kest_context global_cxt
Definition kest_int.c:12
#define KEST_FILENAME_LEN
Definition kest_int.h:72
int kest_parameter_trigger_update(kest_parameter *param, float target)
int init_parameter(kest_parameter *param, const char *name, float level, float min, float max)
#define KEST_PRINTF(...)
Definition kest_printf.h:10
int kest_profile_remove_effect(kest_profile *profile, uint16_t id)
int init_m_profile(kest_profile *profile)
int kest_profile_save(kest_profile *profile)
void free_profile(kest_profile *profile)
int kest_profile_set_active(kest_profile *profile)
int kest_profile_set_inactive(kest_profile *profile)
#define PROFILE_NAME_MAX_LEN
Definition kest_profile.h:4
int queue_representation_list_update(kest_representation_pll *reps)
int kest_sequence_regress(kest_sequence *sequence)
int kest_sequence_activate_at(kest_sequence *sequence, kest_profile *profile)
int init_m_sequence(kest_sequence *sequence)
void free_sequence(kest_sequence *sequence)
int kest_sequence_advance(kest_sequence *sequence)
kest_sequence_pll sequence_ll
void kest_state_representation_update(void *representer, void *representee)
Definition kest_state.c:65
kest_sequence * sequence
int saved_sequences_loaded
kest_parameter input_gain
profile_ll * profiles
kest_sequence main_sequence
int saved_profiles_loaded
kest_effect_desc_pll * effects
sequence_ll * sequences
kest_profile * working_profile
kest_parameter output_gain
kest_profile * active_profile
struct kest_expression * min_expr
struct kest_expression * max_expr
const char * units
kest_parameter_id id
kest_effect_pll * effects
kest_pipeline pipeline
char fname[KEST_FILENAME_LEN]
uint16_t id
char fname[KEST_FILENAME_LEN]