1 /*************************************************************************/
2 /* cp_pattern.cpp */
3 /*************************************************************************/
4 /* This file is part of: */
5 /* GODOT ENGINE */
6 /* https://godotengine.org */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
9 /* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
10 /* */
11 /* Permission is hereby granted, free of charge, to any person obtaining */
12 /* a copy of this software and associated documentation files (the */
13 /* "Software"), to deal in the Software without restriction, including */
14 /* without limitation the rights to use, copy, modify, merge, publish, */
15 /* distribute, sublicense, and/or sell copies of the Software, and to */
16 /* permit persons to whom the Software is furnished to do so, subject to */
17 /* the following conditions: */
18 /* */
19 /* The above copyright notice and this permission notice shall be */
20 /* included in all copies or substantial portions of the Software. */
21 /* */
22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29 /*************************************************************************/
30 #include "cp_pattern.h"
31
clear()32 void CPPattern::clear() {
33
34 if (event_count > 0) {
35
36 CP_FREE(events);
37 events = NULL;
38 event_count = 0;
39 }
40
41 length = DEFAULT_LEN;
42 }
43
resize_event_list_to(uint32_t p_events)44 bool CPPattern::resize_event_list_to(uint32_t p_events) {
45
46 //Module is slow in some cpus, so this should be fast enough
47 uint32_t new_size = ((p_events - 1) & (~((1 << RESIZE_EVERY_BITS) - 1))) + (1 << RESIZE_EVERY_BITS);
48
49 CP_ERR_COND_V(new_size < p_events, true); //bugARM_INFO
50
51 if (event_count == 0 && new_size == 0)
52 return false; //nothing to do
53
54 if (event_count == 0) {
55
56 events = (Event *)CP_ALLOC(new_size * sizeof(Event));
57
58 } else if (new_size == 0) {
59
60 CP_FREE(events);
61 events = NULL;
62 } else {
63
64 CP_ERR_COND_V(events == NULL, true);
65 events = (Event *)CP_REALLOC(events, new_size * sizeof(Event));
66 }
67
68 event_count = p_events;
69
70 return false;
71 }
72
get_event_pos(uint16_t p_target_pos)73 int32_t CPPattern::get_event_pos(uint16_t p_target_pos) {
74
75 if (event_count == 0)
76 return -1;
77
78 int low = 0;
79 int high = event_count - 1;
80 int middle;
81
82 while (low <= high) {
83 middle = (low + high) / 2;
84
85 if (p_target_pos == events[middle].pos) { //match
86 break;
87 } else if (p_target_pos < events[middle].pos)
88 high = middle - 1; //search low end of array
89 else
90 low = middle + 1; //search high end of array
91 }
92
93 /* adapt so we are behind 2 */
94
95 if (events[middle].pos < p_target_pos)
96 middle++;
97 return middle;
98
99 /* Linear search for now */
100
101 /*
102 int32_t pos_idx=0;
103
104 for (;pos_idx<event_count;pos_idx++) {
105
106 if (event_list[pos_idx].pos>=p_target_pos)
107 break;
108
109 } */
110
111 //return pos_idx;
112 }
113
erase_event_at_pos(uint16_t p_pos)114 bool CPPattern::erase_event_at_pos(uint16_t p_pos) {
115
116 if (event_count == 0)
117 return false;
118
119 Event *event_list = events;
120
121 int32_t pos_idx = get_event_pos(p_pos);
122 if (pos_idx == -1) {
123 CP_ERR_COND_V(pos_idx == -1, true);
124 }
125
126 if (pos_idx == event_count || event_list[pos_idx].pos != p_pos) {
127 /* Nothing to Erase */
128 return false;
129 }
130
131 for (int32_t i = pos_idx; i < (event_count - 1); i++) {
132
133 event_list[i] = event_list[i + 1];
134 }
135
136 resize_event_list_to(event_count - 1);
137
138 return false;
139 }
140
set_note(uint8_t p_column,uint16_t p_row,const CPNote & p_note)141 bool CPPattern::set_note(uint8_t p_column, uint16_t p_row, const CPNote &p_note) {
142
143 CP_ERR_COND_V(p_column >= WIDTH, true);
144 CP_ERR_COND_V(p_row >= length, true);
145
146 int32_t new_pos;
147 uint16_t target_pos = p_row * WIDTH + p_column;
148
149 if (p_note.is_empty()) {
150 bool res = erase_event_at_pos(target_pos);
151
152 return res;
153 ;
154 }
155
156 Event *event_list = 0;
157
158 if (event_count == 0) {
159 /* If no events, create the first */
160
161 if (resize_event_list_to(1)) {
162
163 CP_PRINTERR("Can't resize event list to 1");
164 return true;
165 }
166
167 event_list = events;
168 if (event_list == 0) {
169
170 CP_PRINTERR("Can't get event list");
171 return true;
172 }
173
174 new_pos = 0;
175
176 } else {
177 /* Prepare to add */
178
179 event_list = events;
180 if (event_list == 0) {
181
182 CP_PRINTERR("Can't get event list");
183 return true;
184 }
185
186 int32_t pos_idx = get_event_pos(target_pos);
187
188 if (pos_idx == -1) {
189
190 CP_PRINTERR("Can't find add position");
191 return true;
192 }
193
194 if (pos_idx == event_count || event_list[pos_idx].pos != target_pos) {
195 /* If the note being modified didnt exist, then we add it */
196
197 //resize, and return if out of mem
198 if (resize_event_list_to(event_count + 1)) {
199
200 CP_PRINTERR("Can't resize event list");
201 return true;
202 }
203 event_list = events;
204 if (event_list == 0) {
205
206 CP_PRINTERR("Can't get event list");
207 return true;
208 }
209
210 //make room for new pos, this wont do a thing if pos_idx was ==event_count
211 for (int32_t i = (event_count - 1); i > pos_idx; i--) {
212 event_list[i] = event_list[i - 1];
213 }
214
215 } /* Else it means that position is taken, so we just modify it! */
216
217 new_pos = pos_idx;
218 }
219
220 event_list[new_pos].pos = target_pos;
221 event_list[new_pos].note = p_note.note;
222 event_list[new_pos].instrument = p_note.instrument;
223 event_list[new_pos].volume = p_note.volume;
224 event_list[new_pos].command = p_note.command;
225 event_list[new_pos].parameter = p_note.parameter;
226 event_list[new_pos].script_source_sign = p_note.script_source_sign;
227 event_list[new_pos].cloned = p_note.cloned;
228
229 return false;
230 }
get_note(uint8_t p_column,uint16_t p_row)231 CPNote CPPattern::get_note(uint8_t p_column, uint16_t p_row) {
232
233 if (p_column == CPNote::EMPTY) return CPNote();
234
235 CP_ERR_COND_V(p_column >= WIDTH, CPNote());
236 CP_ERR_COND_V(p_row >= length, CPNote());
237
238 if (event_count == 0)
239 return CPNote();
240
241 Event *event_list = events;
242
243 CP_ERR_COND_V(event_list == 0, CPNote());
244
245 uint16_t target_pos = p_row * WIDTH + p_column;
246 int32_t pos_idx = get_event_pos(target_pos);
247 if (pos_idx == -1) {
248
249 CP_PRINTERR("Can't find event pos");
250 return CPNote();
251 }
252
253 if (pos_idx >= event_count || event_list[pos_idx].pos != target_pos) {
254 /* no note found */
255
256 return CPNote();
257 }
258
259 CPNote n;
260 n.note = event_list[pos_idx].note;
261 n.instrument = event_list[pos_idx].instrument;
262 n.volume = event_list[pos_idx].volume;
263 n.command = event_list[pos_idx].command;
264 n.parameter = event_list[pos_idx].parameter;
265 n.script_source_sign = event_list[pos_idx].script_source_sign;
266 n.cloned = event_list[pos_idx].cloned;
267
268 return n;
269 }
270
get_transformed_script_note(uint8_t p_column,uint16_t p_row)271 CPNote CPPattern::get_transformed_script_note(uint8_t p_column, uint16_t p_row) {
272
273 CPNote n = get_note(p_column, p_row);
274
275 // get source channel and note
276
277 int channel = get_scripted_note_target_channel(p_column, p_row);
278 CPNote src_n = get_note(channel, 0);
279
280 if (src_n.note == CPNote::SCRIPT) return CPNote();
281
282 script_transform_note(src_n, n);
283
284 return src_n;
285 }
286
get_scripted_note_target_channel(uint8_t p_column,uint16_t p_row)287 int CPPattern::get_scripted_note_target_channel(uint8_t p_column, uint16_t p_row) {
288
289 CPNote n = get_note(p_column, p_row);
290
291 if (n.note != CPNote::SCRIPT) return CPNote::EMPTY;
292
293 int channel = n.instrument;
294
295 if (n.script_source_sign == '\0') {
296
297 if (channel < 0 || channel >= CPPattern::WIDTH) return CPNote::EMPTY;
298
299 } else {
300
301 channel = p_column + ((n.script_source_sign == '+') ? 1 : -1) * (channel + 1);
302 if (channel < 0 || channel >= CPPattern::WIDTH) return CPNote::EMPTY;
303 }
304
305 return channel;
306 }
307
scripted_clone(uint8_t p_column,uint16_t p_row)308 void CPPattern::scripted_clone(uint8_t p_column, uint16_t p_row) {
309
310 int channel = get_scripted_note_target_channel(p_column, p_row);
311 int src_row = 1;
312 CPNote script_n = get_note(p_column, p_row);
313
314 for (int row = p_row + 1; row < length; ++row) {
315
316 CPNote src_n = get_note(channel, src_row);
317 CPNote target_n = get_note(p_column, row);
318
319 if (target_n.note != CPNote::SCRIPT) {
320 if (src_n.note == CPNote::SCRIPT) {
321 src_n = CPNote();
322 channel = CPNote::EMPTY;
323 }
324
325 script_transform_note(src_n, script_n);
326
327 src_n.cloned = true;
328 set_note(p_column, row, src_n);
329
330 } else {
331
332 return;
333 }
334
335 src_row++;
336 }
337 }
338
scripted_clone_remove(uint8_t p_column,uint16_t p_row)339 void CPPattern::scripted_clone_remove(uint8_t p_column, uint16_t p_row) {
340
341 if (get_note(p_column, p_row).cloned)
342 set_note(p_column, p_row, CPNote());
343
344 for (int row = p_row + 1; row < length; ++row) {
345
346 CPNote target_n = get_note(p_column, row);
347
348 if (target_n.note != CPNote::SCRIPT) {
349
350 set_note(p_column, row, CPNote());
351
352 } else {
353
354 return;
355 }
356 }
357 }
358
script_transform_note(CPNote & n,const CPNote & p_note)359 void CPPattern::script_transform_note(CPNote &n, const CPNote &p_note) {
360
361 // set instrument
362
363 if (n.note < CPNote::NOTES && p_note.volume != CPNote::EMPTY) {
364
365 n.instrument = p_note.volume;
366 }
367
368 // transpose
369
370 if (n.note < CPNote::NOTES && p_note.command != CPNote::EMPTY) {
371
372 int transpose = (p_note.parameter & 0xF) + (p_note.parameter / 0x10) * 12;
373
374 if (p_note.command == '^') {
375
376 if (n.note >= CPNote::NOTES - transpose)
377 n.note = CPNote::NOTES - 1;
378 else
379 n.note += transpose;
380
381 } else if (p_note.command == 'v') {
382
383 if (n.note <= transpose)
384 n.note = 0;
385 else
386 n.note -= transpose;
387 }
388 }
389 }
390
update_scripted_clones_sourcing_channel(int channel)391 bool CPPattern::update_scripted_clones_sourcing_channel(int channel) {
392
393 bool updated = false;
394
395 for (int x = 0; x < WIDTH; ++x) {
396
397 for (int y = 0; y < length; ++y) {
398
399 if (channel == get_scripted_note_target_channel(x, y)) {
400
401 scripted_clone(x, y);
402 updated = true;
403 }
404 }
405 }
406
407 return updated;
408 }
409
set_length(uint16_t p_rows)410 void CPPattern::set_length(uint16_t p_rows) {
411
412 if (event_count == 0) {
413
414 if (p_rows >= MIN_ROWS)
415 length = p_rows;
416
417 return;
418 }
419
420 if (p_rows < MIN_ROWS) {
421
422 return;
423 }
424
425 if (p_rows < length) {
426
427 Event *event_list = events;
428 if (event_list == 0) {
429
430 CP_PRINTERR("get_event_list() Failed");
431 return;
432 }
433
434 uint16_t target_pos = p_rows * WIDTH;
435 int32_t pos_idx = get_event_pos(target_pos);
436
437 if (pos_idx == -1) {
438
439 CP_ERR_COND(pos_idx == -1);
440 }
441
442 if (resize_event_list_to(pos_idx)) {
443
444 CP_PRINTERR("resize_event_list_to(pos_idx) Failed");
445 return;
446 }
447 }
448
449 length = p_rows;
450 }
451 #if 0
452 void CPPattern::copy_to(CPPattern *p_pattern) const {
453
454
455
456
457 p_pattern->clear();
458 p_pattern->length=length;
459
460
461 if (!event_count)
462 return;
463
464
465
466 int bufsiz=MemPool_Wrapper::get_singleton()->get_mem_size( mem_handle );
467 MemPool_Handle aux_mem_handle=MemPool_Wrapper::get_singleton()->alloc_mem( bufsiz );
468
469 if (aux_mem_handle.is_null()) {
470
471 CP_PRINTERR("own handle is null");
472
473 return;
474 }
475
476
477 if (MemPool_Wrapper::get_singleton()->lock_mem(aux_mem_handle)) {
478 CP_PRINTERR("Unable to lock aux new handle");
479
480 return;
481
482 }
483
484 if (MemPool_Wrapper::get_singleton()->lock_mem(mem_handle)) {
485
486 CP_PRINTERR("Unable to lock own handle");
487
488 return;
489 }
490
491 uint8_t* srcuint8_tt8_t*)MemPool_Wrapper::get_singleton()->get_mem(mem_handle);
492 uint8_t* dstuint8_tt8_t*)MemPool_Wrapper::get_singleton()->get_mem(aux_mem_handle);
493
494 for (int i=0;i<bufsiz;i++)
495 dst[i]=src[i];
496
497 MemPool_Wrapper::get_singleton()->unlock_mem(mem_handle);
498 MemPool_Wrapper::get_singleton()->unlock_mem(aux_mem_handle);
499
500 p_pattern->mem_handle=aux_mem_handle;
501 p_pattern->event_count=event_count;
502
503
504 }
505 #endif
get_length()506 uint16_t CPPattern::get_length() {
507
508 return length;
509 }
CPPattern()510 CPPattern::CPPattern() {
511
512 length = DEFAULT_LEN;
513 event_count = 0;
514 clear();
515 }
is_empty()516 bool CPPattern::is_empty() {
517
518 return events == NULL;
519 }
520
~CPPattern()521 CPPattern::~CPPattern() {
522
523 clear();
524 }
525