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