1 /*
2  * Copyright (C) 2020 Rerrah
3  *
4  * Permission is hereby granted, free of charge, to any person
5  * obtaining a copy of this software and associated documentation
6  * files (the "Software"), to deal in the Software without
7  * restriction, including without limitation the rights to use,
8  * copy, modify, merge, publish, distribute, sublicense, and/or sell
9  * copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following
11  * conditions:
12  *
13  * The above copyright notice and this permission notice shall be
14  * included in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23  * OTHER DEALINGS IN THE SOFTWARE.
24  */
25 
26 #include "change_values_in_pattern_command.hpp"
27 #include "misc.hpp"
28 
ChangeValuesInPatternCommand(std::weak_ptr<Module> mod,int songNum,int beginTrack,int beginColumn,int beginOrder,int beginStep,int endTrack,int endColumn,int endStep,int value,bool isFMReversed)29 ChangeValuesInPatternCommand::ChangeValuesInPatternCommand(std::weak_ptr<Module> mod, int songNum, int beginTrack,
30 														   int beginColumn, int beginOrder, int beginStep,
31 														   int endTrack, int endColumn, int endStep, int value, bool isFMReversed)
32 	: mod_(mod),
33 	  song_(songNum),
34 	  bTrack_(beginTrack),
35 	  bCol_(beginColumn),
36 	  order_(beginOrder),
37 	  bStep_(beginStep),
38 	  eTrack_(endTrack),
39 	  eCol_(endColumn),
40 	  eStep_(endStep),
41 	  diff_(value),
42 	  fmReverse_(isFMReversed)
43 {
44 	auto& sng = mod.lock()->getSong(songNum);
45 
46 	for (int step = beginStep; step <= endStep; ++step) {
47 		int track = beginTrack;
48 		int col = beginColumn;
49 		std::vector<int> vals;
50 		while (true) {
51 			int val;
52 			Step& st = sng.getTrack(track).getPatternFromOrderNumber(beginOrder).getStep(step);
53 			switch (col) {
54 			case 1:		val = st.getInstrumentNumber();	break;
55 			case 2:		val = st.getVolume();			break;
56 			case 4:		val = st.getEffectValue(0);		break;
57 			case 6:		val = st.getEffectValue(1);		break;
58 			case 8:		val = st.getEffectValue(2);		break;
59 			case 10:	val = st.getEffectValue(3);		break;
60 			default:	val = -1;						break;
61 			}
62 			if (val > -1) vals.push_back(val);
63 			if (track == endTrack && col == endColumn) break;
64 			track += (++col / 11);
65 			col %= 11;
66 		}
67 		prevVals_.push_back(vals);
68 	}
69 }
70 
redo()71 void ChangeValuesInPatternCommand::redo()
72 {
73 	auto& sng = mod_.lock()->getSong(song_);
74 	auto it = prevVals_.begin();
75 	for (int step = bStep_; step <= eStep_; ++step, ++it) {
76 		int track = bTrack_;
77 		int col = bCol_;
78 		auto valit = it->begin();
79 		while (true) {
80 			Track& tr = sng.getTrack(track);
81 			Step& st = tr.getPatternFromOrderNumber(order_).getStep(step);
82 			switch (col) {
83 			case 1:
84 				if (st.getInstrumentNumber() > -1) st.setInstrumentNumber(clamp(diff_ + *valit++, 0, 127));
85 				break;
86 			case 2:
87 				if (st.getVolume() > -1) {
88 					int d = (tr.getAttribute().source == SoundSource::FM && fmReverse_) ? -diff_ : diff_;
89 					st.setVolume(clamp(d + *valit++, 0, 255));
90 				}
91 				break;
92 			case 4:
93 				if (st.getEffectValue(0) > -1) st.setEffectValue(0, clamp(diff_ + *valit++, 0, 255));
94 				break;
95 			case 6:
96 				if (st.getEffectValue(1) > -1) st.setEffectValue(1, clamp(diff_ + *valit++, 0, 255));
97 				break;
98 			case 8:
99 				if (st.getEffectValue(2) > -1) st.setEffectValue(2, clamp(diff_ + *valit++, 0, 255));
100 				break;
101 			case 10:
102 				if (st.getEffectValue(3) > -1) st.setEffectValue(3, clamp(diff_ + *valit++, 0, 255));
103 				break;
104 			default:
105 				break;
106 			}
107 			if (track == eTrack_ && col == eCol_) break;
108 			track += (++col / 11);
109 			col %= 11;
110 		}
111 	}
112 }
113 
undo()114 void ChangeValuesInPatternCommand::undo()
115 {
116 	auto& sng = mod_.lock()->getSong(song_);
117 	auto it = prevVals_.begin();
118 	for (int step = bStep_; step <= eStep_; ++step, ++it) {
119 		int track = bTrack_;
120 		int col = bCol_;
121 		auto valit = it->begin();
122 		while (true) {
123 			Step& st = sng.getTrack(track).getPatternFromOrderNumber(order_).getStep(step);
124 			switch (col) {
125 			case 1:
126 				if (st.getInstrumentNumber() > -1) st.setInstrumentNumber(*valit++);
127 				break;
128 			case 2:
129 				if (st.getVolume() > -1) st.setVolume(*valit++);
130 				break;
131 			case 4:
132 				if (st.getEffectValue(0) > -1) st.setEffectValue(0, *valit++);
133 				break;
134 			case 6:
135 				if (st.getEffectValue(1) > -1) st.setEffectValue(1, *valit++);
136 				break;
137 			case 8:
138 				if (st.getEffectValue(2) > -1) st.setEffectValue(2, *valit++);
139 				break;
140 			case 10:
141 				if (st.getEffectValue(3) > -1) st.setEffectValue(3, *valit++);
142 				break;
143 			default:
144 				break;
145 			}
146 			if (track == eTrack_ && col == eCol_) break;
147 			track += (++col / 11);
148 			col %= 11;
149 		}
150 	}
151 }
152 
getID() const153 CommandId ChangeValuesInPatternCommand::getID() const
154 {
155 	return CommandId::ChangeValuesInPattern;
156 }
157