/*************************************************************************/ /* cp_pattern.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ /* "Software"), to deal in the Software without restriction, including */ /* without limitation the rights to use, copy, modify, merge, publish, */ /* distribute, sublicense, and/or sell copies of the Software, and to */ /* permit persons to whom the Software is furnished to do so, subject to */ /* the following conditions: */ /* */ /* The above copyright notice and this permission notice shall be */ /* included in all copies or substantial portions of the Software. */ /* */ /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "cp_pattern.h" void CPPattern::clear() { if (event_count>0) { CP_FREE(events); events=NULL; event_count=0; } length=DEFAULT_LEN; } bool CPPattern::resize_event_list_to(uint32_t p_events) { //Module is slow in some cpus, so this should be fast enough uint32_t new_size=((p_events-1)&(~((1<=p_target_pos) break; } */ //return pos_idx; } bool CPPattern::erase_event_at_pos(uint16_t p_pos) { if (event_count==0) return false; Event *event_list=events; int32_t pos_idx = get_event_pos(p_pos); if (pos_idx==-1) { CP_ERR_COND_V(pos_idx==-1,true); } if (pos_idx==event_count || event_list[pos_idx].pos!=p_pos) { /* Nothing to Erase */ return false; } for (int32_t i=pos_idx;i<(event_count-1);i++) { event_list[i]=event_list[i+1]; } resize_event_list_to(event_count-1); return false; } bool CPPattern::set_note(uint8_t p_column, uint16_t p_row,const CPNote& p_note) { CP_ERR_COND_V(p_column>=WIDTH,true); CP_ERR_COND_V(p_row>=length,true); int32_t new_pos; uint16_t target_pos=p_row*WIDTH+p_column; if (p_note.is_empty()) { bool res=erase_event_at_pos(target_pos); return res;; } Event *event_list=0; if (event_count==0) { /* If no events, create the first */ if (resize_event_list_to(1)) { CP_PRINTERR("Can't resize event list to 1"); return true; } event_list=events; if (event_list==0) { CP_PRINTERR("Can't get event list"); return true; } new_pos=0; } else { /* Prepare to add */ event_list=events; if (event_list==0) { CP_PRINTERR("Can't get event list"); return true; } int32_t pos_idx = get_event_pos(target_pos); if (pos_idx==-1) { CP_PRINTERR("Can't find add position"); return true; } if (pos_idx==event_count || event_list[pos_idx].pos!=target_pos) { /* If the note being modified didnt exist, then we add it */ //resize, and return if out of mem if (resize_event_list_to( event_count+1)) { CP_PRINTERR("Can't resize event list"); return true; } event_list=events; if (event_list==0) { CP_PRINTERR("Can't get event list"); return true; } //make room for new pos, this wont do a thing if pos_idx was ==event_count for(int32_t i=(event_count-1);i>pos_idx;i--) { event_list[i]=event_list[i-1]; } } /* Else it means that position is taken, so we just modify it! */ new_pos=pos_idx; } event_list[new_pos].pos=target_pos; event_list[new_pos].note=p_note.note; event_list[new_pos].instrument=p_note.instrument; event_list[new_pos].volume=p_note.volume; event_list[new_pos].command=p_note.command; event_list[new_pos].parameter=p_note.parameter; event_list[new_pos].script_source_sign=p_note.script_source_sign; event_list[new_pos].cloned=p_note.cloned; return false; } CPNote CPPattern::get_note(uint8_t p_column,uint16_t p_row) { if (p_column==CPNote::EMPTY) return CPNote(); CP_ERR_COND_V(p_column>=WIDTH,CPNote()); CP_ERR_COND_V(p_row>=length,CPNote()); if (event_count==0) return CPNote(); Event *event_list=events; CP_ERR_COND_V(event_list==0,CPNote()); uint16_t target_pos=p_row*WIDTH+p_column; int32_t pos_idx = get_event_pos(target_pos); if (pos_idx==-1) { CP_PRINTERR("Can't find event pos"); return CPNote(); } if (pos_idx>=event_count || event_list[pos_idx].pos!=target_pos) { /* no note found */ return CPNote(); } CPNote n; n.note=event_list[pos_idx].note; n.instrument=event_list[pos_idx].instrument; n.volume=event_list[pos_idx].volume; n.command=event_list[pos_idx].command; n.parameter=event_list[pos_idx].parameter; n.script_source_sign=event_list[pos_idx].script_source_sign; n.cloned=event_list[pos_idx].cloned; return n; } CPNote CPPattern::get_transformed_script_note(uint8_t p_column,uint16_t p_row ) { CPNote n = get_note( p_column, p_row ); // get source channel and note int channel = get_scripted_note_target_channel( p_column, p_row ); CPNote src_n = get_note( channel, 0 ); if ( src_n.note == CPNote::SCRIPT ) return CPNote(); script_transform_note( src_n, n ); return src_n; } int CPPattern::get_scripted_note_target_channel(uint8_t p_column, uint16_t p_row) { CPNote n = get_note( p_column, p_row ); if ( n.note != CPNote::SCRIPT ) return CPNote::EMPTY; int channel = n.instrument; if ( n.script_source_sign == '\0' ) { if ( channel < 0 || channel >= CPPattern::WIDTH ) return CPNote::EMPTY; } else { channel = p_column + ( ( n.script_source_sign=='+') ? 1 : -1 ) * (channel+1); if ( channel < 0 || channel >= CPPattern::WIDTH ) return CPNote::EMPTY; } return channel; } void CPPattern::scripted_clone(uint8_t p_column, uint16_t p_row) { int channel = get_scripted_note_target_channel( p_column, p_row ); int src_row = 1; CPNote script_n = get_note( p_column, p_row ); for ( int row = p_row+1; row < length; ++row ) { CPNote src_n = get_note( channel, src_row ); CPNote target_n = get_note( p_column, row ); if ( target_n.note != CPNote::SCRIPT ) { if ( src_n.note == CPNote::SCRIPT ) { src_n = CPNote(); channel = CPNote::EMPTY; } script_transform_note( src_n, script_n ); src_n.cloned = true; set_note( p_column, row, src_n ); } else { return; } src_row++; } } void CPPattern::scripted_clone_remove(uint8_t p_column, uint16_t p_row) { if ( get_note( p_column, p_row ).cloned ) set_note( p_column, p_row, CPNote() ); for ( int row = p_row+1; row < length; ++row ) { CPNote target_n = get_note( p_column, row ); if ( target_n.note != CPNote::SCRIPT ) { set_note( p_column, row, CPNote() ); } else { return; } } } void CPPattern::script_transform_note(CPNote& n, const CPNote& p_note) { // set instrument if ( n.note < CPNote::NOTES && p_note.volume != CPNote::EMPTY ) { n.instrument = p_note.volume; } // transpose if ( n.note < CPNote::NOTES && p_note.command != CPNote::EMPTY ) { int transpose = ( p_note.parameter & 0xF ) + ( p_note.parameter / 0x10 ) * 12; if ( p_note.command == '^' ) { if ( n.note >= CPNote::NOTES-transpose ) n.note = CPNote::NOTES-1; else n.note += transpose; } else if ( p_note.command == 'v' ) { if ( n.note <= transpose ) n.note = 0; else n.note -= transpose; } } } bool CPPattern::update_scripted_clones_sourcing_channel( int channel ) { bool updated = false; for ( int x = 0; x < WIDTH; ++x ) { for (int y = 0; y < length; ++y ) { if ( channel == get_scripted_note_target_channel( x, y ) ) { scripted_clone( x, y ); updated = true; } } } return updated; } void CPPattern::set_length(uint16_t p_rows) { if (event_count==0) { if (p_rows>=MIN_ROWS) length=p_rows; return; } if (p_rowsclear(); p_pattern->length=length; if (!event_count) return; int bufsiz=MemPool_Wrapper::get_singleton()->get_mem_size( mem_handle ); MemPool_Handle aux_mem_handle=MemPool_Wrapper::get_singleton()->alloc_mem( bufsiz ); if (aux_mem_handle.is_null()) { CP_PRINTERR("own handle is null"); return; } if (MemPool_Wrapper::get_singleton()->lock_mem(aux_mem_handle)) { CP_PRINTERR("Unable to lock aux new handle"); return; } if (MemPool_Wrapper::get_singleton()->lock_mem(mem_handle)) { CP_PRINTERR("Unable to lock own handle"); return; } uint8_t* srcuint8_tt8_t*)MemPool_Wrapper::get_singleton()->get_mem(mem_handle); uint8_t* dstuint8_tt8_t*)MemPool_Wrapper::get_singleton()->get_mem(aux_mem_handle); for (int i=0;iunlock_mem(mem_handle); MemPool_Wrapper::get_singleton()->unlock_mem(aux_mem_handle); p_pattern->mem_handle=aux_mem_handle; p_pattern->event_count=event_count; } #endif uint16_t CPPattern::get_length() { return length; } CPPattern::CPPattern() { length=DEFAULT_LEN; event_count=0; clear(); } bool CPPattern::is_empty() { return events==NULL; } CPPattern::~CPPattern() { clear(); }