trunk/src/emu/sound/ymf271.c
r23978 | r23979 | |
17 | 17 | - Src B and Src NOTE bits |
18 | 18 | - statusreg Busy and End bits |
19 | 19 | - timer register 0x11 |
| 20 | - ch2/ch3 (4 speakers) |
| 21 | - PFM (FM using external PCM waveform) |
| 22 | - detune |
| 23 | - Acc On bit |
20 | 24 | - Is memory handling 100% correct? At the moment, seibuspi.c is the only |
21 | 25 | hardware currently emulated that uses external handlers. |
22 | | - oh, and a lot more... |
23 | 26 | */ |
24 | 27 | |
25 | 28 | #include "emu.h" |
26 | 29 | #include "ymf271.h" |
27 | 30 | |
28 | | #define VERBOSE (1) |
| 31 | #define MAXOUT (+32767) |
| 32 | #define MINOUT (-32768) |
29 | 33 | |
30 | | #define MAXOUT (+32767) |
31 | | #define MINOUT (-32768) |
32 | | |
33 | 34 | #define SIN_BITS 10 |
34 | 35 | #define SIN_LEN (1<<SIN_BITS) |
35 | 36 | #define SIN_MASK (SIN_LEN-1) |
r23978 | r23979 | |
41 | 42 | #define ALFO_MAX (+65536) |
42 | 43 | #define ALFO_MIN (0) |
43 | 44 | |
44 | | //#define log2(n) (log((float) n)/log((float) 2)) |
45 | | |
46 | 45 | // slot mapping assists |
47 | | static const int fm_tab[] = { 0, 1, 2, -1, 3, 4, 5, -1, 6, 7, 8, -1, 9, 10, 11, -1 }; |
48 | | static const int pcm_tab[] = { 0, 4, 8, -1, 12, 16, 20, -1, 24, 28, 32, -1, 36, 40, 44, -1 }; |
| 46 | static const int fm_tab[16] = { 0, 1, 2, -1, 3, 4, 5, -1, 6, 7, 8, -1, 9, 10, 11, -1 }; |
| 47 | static const int pcm_tab[16] = { 0, 4, 8, -1, 12, 16, 20, -1, 24, 28, 32, -1, 36, 40, 44, -1 }; |
49 | 48 | |
50 | 49 | static INT16 *wavetable[8]; |
51 | 50 | static double plfo_table[4][8][LFO_LENGTH]; |
r23978 | r23979 | |
241 | 240 | |
242 | 241 | INLINE int GET_EXTERNAL_KEYCODE(int block, int fns) |
243 | 242 | { |
244 | | /* TODO: SrcB and SrcNote !? */ |
245 | 243 | int n43; |
246 | 244 | if (fns < 0x100) |
247 | 245 | { |
r23978 | r23979 | |
320 | 318 | int decay_level = 255 - (slot->decay1lvl << 4); |
321 | 319 | slot->volume -= slot->env_decay1_step; |
322 | 320 | |
323 | | if ((slot->volume >> (ENV_VOLUME_SHIFT)) <= decay_level) |
| 321 | if ((slot->volume >> ENV_VOLUME_SHIFT) <= decay_level) |
324 | 322 | { |
325 | 323 | slot->env_state = ENV_DECAY2; |
326 | 324 | } |
r23978 | r23979 | |
331 | 329 | { |
332 | 330 | slot->volume -= slot->env_decay2_step; |
333 | 331 | |
334 | | if (slot->volume < 0) |
| 332 | if (slot->volume <= 0) |
335 | 333 | { |
| 334 | slot->active = 0; |
336 | 335 | slot->volume = 0; |
337 | 336 | } |
338 | 337 | break; |
r23978 | r23979 | |
342 | 341 | { |
343 | 342 | slot->volume -= slot->env_release_step; |
344 | 343 | |
345 | | if (slot->volume <= (0 << ENV_VOLUME_SHIFT)) |
| 344 | if (slot->volume <= 0) |
346 | 345 | { |
347 | 346 | slot->active = 0; |
348 | 347 | slot->volume = 0; |
r23978 | r23979 | |
366 | 365 | } |
367 | 366 | else |
368 | 367 | { |
369 | | keycode = GET_EXTERNAL_KEYCODE(slot->block, slot->fns); |
| 368 | keycode = GET_EXTERNAL_KEYCODE(slot->block, slot->fns & 0x7ff); |
| 369 | /* keycode = (keycode + slot->srcb * 4 + slot->srcnote) / 2; */ // not sure |
370 | 370 | } |
371 | 371 | |
372 | 372 | // init attack state |
r23978 | r23979 | |
994 | 994 | update_pcm(j + (3*12), mixp, samples); |
995 | 995 | break; |
996 | 996 | } |
997 | | |
998 | | default: break; |
999 | 997 | } |
1000 | 998 | } |
1001 | 999 | |
r23978 | r23979 | |
1014 | 1012 | switch (reg) |
1015 | 1013 | { |
1016 | 1014 | case 0: |
1017 | | { |
1018 | 1015 | slot->ext_en = (data & 0x80) ? 1 : 0; |
1019 | 1016 | slot->ext_out = (data>>3)&0xf; |
1020 | 1017 | |
r23978 | r23979 | |
1040 | 1037 | } |
1041 | 1038 | } |
1042 | 1039 | break; |
1043 | | } |
1044 | 1040 | |
1045 | 1041 | case 1: |
1046 | | { |
1047 | 1042 | slot->lfoFreq = data; |
1048 | 1043 | break; |
1049 | | } |
1050 | 1044 | |
1051 | 1045 | case 2: |
1052 | | { |
1053 | 1046 | slot->lfowave = data & 3; |
1054 | 1047 | slot->pms = (data >> 3) & 0x7; |
1055 | 1048 | slot->ams = (data >> 6) & 0x3; |
1056 | 1049 | break; |
1057 | | } |
1058 | 1050 | |
1059 | 1051 | case 3: |
1060 | | { |
1061 | 1052 | slot->multiple = data & 0xf; |
1062 | 1053 | slot->detune = (data >> 4) & 0x7; |
1063 | 1054 | break; |
1064 | | } |
1065 | 1055 | |
1066 | 1056 | case 4: |
1067 | | { |
1068 | 1057 | slot->tl = data & 0x7f; |
1069 | 1058 | break; |
1070 | | } |
1071 | 1059 | |
1072 | 1060 | case 5: |
1073 | | { |
1074 | 1061 | slot->ar = data & 0x1f; |
1075 | 1062 | slot->keyscale = (data>>5)&0x7; |
1076 | 1063 | break; |
1077 | | } |
1078 | 1064 | |
1079 | 1065 | case 6: |
1080 | | { |
1081 | 1066 | slot->decay1rate = data & 0x1f; |
1082 | 1067 | break; |
1083 | | } |
1084 | 1068 | |
1085 | 1069 | case 7: |
1086 | | { |
1087 | 1070 | slot->decay2rate = data & 0x1f; |
1088 | 1071 | break; |
1089 | | } |
1090 | 1072 | |
1091 | 1073 | case 8: |
1092 | | { |
1093 | 1074 | slot->relrate = data & 0xf; |
1094 | 1075 | slot->decay1lvl = (data >> 4) & 0xf; |
1095 | 1076 | break; |
1096 | | } |
1097 | 1077 | |
1098 | 1078 | case 9: |
1099 | | { |
1100 | 1079 | slot->fns &= ~0xff; |
1101 | 1080 | slot->fns |= data; |
1102 | 1081 | break; |
1103 | | } |
1104 | 1082 | |
1105 | 1083 | case 10: |
1106 | | { |
1107 | 1084 | slot->fns &= ~0xff00; |
1108 | 1085 | slot->fns |= (data & 0xf)<<8; |
1109 | 1086 | slot->block = (data>>4)&0xf; |
1110 | 1087 | break; |
1111 | | } |
1112 | 1088 | |
1113 | 1089 | case 11: |
1114 | | { |
1115 | 1090 | slot->waveform = data & 0x7; |
1116 | 1091 | slot->feedback = (data >> 4) & 0x7; |
1117 | 1092 | slot->accon = (data & 0x80) ? 1 : 0; |
1118 | 1093 | break; |
1119 | | } |
1120 | 1094 | |
1121 | 1095 | case 12: |
1122 | | { |
1123 | 1096 | slot->algorithm = data & 0xf; |
1124 | 1097 | break; |
1125 | | } |
1126 | 1098 | |
1127 | 1099 | case 13: |
1128 | | { |
1129 | 1100 | slot->ch0_level = data >> 4; |
1130 | 1101 | slot->ch1_level = data & 0xf; |
1131 | 1102 | break; |
1132 | | } |
1133 | 1103 | |
1134 | 1104 | case 14: |
1135 | | { |
1136 | 1105 | slot->ch2_level = data >> 4; |
1137 | 1106 | slot->ch3_level = data & 0xf; |
1138 | 1107 | break; |
1139 | | } |
1140 | 1108 | |
1141 | 1109 | default: |
1142 | 1110 | break; |
1143 | 1111 | } |
1144 | 1112 | } |
1145 | 1113 | |
1146 | | void ymf271_device::ymf271_write_fm(int grp, int adr, int data) |
| 1114 | void ymf271_device::ymf271_write_fm(int bank, int address, int data) |
1147 | 1115 | { |
1148 | | int reg; |
1149 | | //int slotnum; |
1150 | | int slot_group; |
1151 | | int sync_mode, sync_reg; |
1152 | | //YMF271Slot *slot; |
| 1116 | int groupnum = fm_tab[address & 0xf]; |
| 1117 | if (groupnum == -1) |
| 1118 | { |
| 1119 | logerror("ymf271_write_fm invalid group %02X\n", data); |
| 1120 | return; |
| 1121 | } |
1153 | 1122 | |
1154 | | //slotnum = 12*grp; |
1155 | | //slotnum += fm_tab[adr & 0xf]; |
1156 | | //slot = &m_slots[slotnum]; |
1157 | | slot_group = fm_tab[adr & 0xf]; |
| 1123 | int reg = (address >> 4) & 0xf; |
1158 | 1124 | |
1159 | | reg = (adr >> 4) & 0xf; |
1160 | | |
1161 | 1125 | // check if the register is a synchronized register |
1162 | | sync_reg = 0; |
| 1126 | int sync_reg = 0; |
1163 | 1127 | switch (reg) |
1164 | 1128 | { |
1165 | 1129 | case 0: |
r23978 | r23979 | |
1176 | 1140 | } |
1177 | 1141 | |
1178 | 1142 | // check if the slot is key on slot for synchronizing |
1179 | | sync_mode = 0; |
1180 | | switch (m_groups[slot_group].sync) |
| 1143 | int sync_mode = 0; |
| 1144 | switch (m_groups[groupnum].sync) |
1181 | 1145 | { |
1182 | 1146 | case 0: // 4 slot mode |
1183 | 1147 | { |
1184 | | if (grp == 0) |
| 1148 | if (bank == 0) |
1185 | 1149 | sync_mode = 1; |
1186 | 1150 | break; |
1187 | 1151 | } |
1188 | 1152 | case 1: // 2x 2 slot mode |
1189 | 1153 | { |
1190 | | if (grp == 0 || grp == 1) |
| 1154 | if (bank == 0 || bank == 1) |
1191 | 1155 | sync_mode = 1; |
1192 | 1156 | break; |
1193 | 1157 | } |
1194 | 1158 | case 2: // 3 slot + 1 slot mode |
1195 | 1159 | { |
1196 | | if (grp == 0) |
| 1160 | if (bank == 0) |
1197 | 1161 | sync_mode = 1; |
1198 | 1162 | break; |
1199 | 1163 | } |
r23978 | r23979 | |
1204 | 1168 | |
1205 | 1169 | if (sync_mode && sync_reg) // key-on slot & synced register |
1206 | 1170 | { |
1207 | | switch (m_groups[slot_group].sync) |
| 1171 | switch (m_groups[groupnum].sync) |
1208 | 1172 | { |
1209 | 1173 | case 0: // 4 slot mode |
1210 | 1174 | { |
1211 | | write_register((12 * 0) + slot_group, reg, data); |
1212 | | write_register((12 * 1) + slot_group, reg, data); |
1213 | | write_register((12 * 2) + slot_group, reg, data); |
1214 | | write_register((12 * 3) + slot_group, reg, data); |
| 1175 | write_register((12 * 0) + groupnum, reg, data); |
| 1176 | write_register((12 * 1) + groupnum, reg, data); |
| 1177 | write_register((12 * 2) + groupnum, reg, data); |
| 1178 | write_register((12 * 3) + groupnum, reg, data); |
1215 | 1179 | break; |
1216 | 1180 | } |
1217 | 1181 | case 1: // 2x 2 slot mode |
1218 | 1182 | { |
1219 | | if (grp == 0) // Slot 1 - Slot 3 |
| 1183 | if (bank == 0) // Slot 1 - Slot 3 |
1220 | 1184 | { |
1221 | | write_register((12 * 0) + slot_group, reg, data); |
1222 | | write_register((12 * 2) + slot_group, reg, data); |
| 1185 | write_register((12 * 0) + groupnum, reg, data); |
| 1186 | write_register((12 * 2) + groupnum, reg, data); |
1223 | 1187 | } |
1224 | 1188 | else // Slot 2 - Slot 4 |
1225 | 1189 | { |
1226 | | write_register((12 * 1) + slot_group, reg, data); |
1227 | | write_register((12 * 3) + slot_group, reg, data); |
| 1190 | write_register((12 * 1) + groupnum, reg, data); |
| 1191 | write_register((12 * 3) + groupnum, reg, data); |
1228 | 1192 | } |
1229 | 1193 | break; |
1230 | 1194 | } |
1231 | 1195 | case 2: // 3 slot + 1 slot mode |
1232 | 1196 | { |
1233 | 1197 | // 1 slot is handled normally |
1234 | | write_register((12 * 0) + slot_group, reg, data); |
1235 | | write_register((12 * 1) + slot_group, reg, data); |
1236 | | write_register((12 * 2) + slot_group, reg, data); |
| 1198 | write_register((12 * 0) + groupnum, reg, data); |
| 1199 | write_register((12 * 1) + groupnum, reg, data); |
| 1200 | write_register((12 * 2) + groupnum, reg, data); |
1237 | 1201 | break; |
1238 | 1202 | } |
1239 | | default: |
1240 | | break; |
1241 | 1203 | } |
1242 | 1204 | } |
1243 | 1205 | else // write register normally |
1244 | 1206 | { |
1245 | | write_register((12 * grp) + slot_group, reg, data); |
| 1207 | write_register((12 * bank) + groupnum, reg, data); |
1246 | 1208 | } |
1247 | 1209 | } |
1248 | 1210 | |
1249 | 1211 | void ymf271_device::ymf271_write_pcm(int data) |
1250 | 1212 | { |
1251 | | int slotnum; |
1252 | | YMF271Slot *slot; |
| 1213 | int slotnum = pcm_tab[m_pcmreg & 0xf]; |
| 1214 | if (slotnum == -1) |
| 1215 | { |
| 1216 | logerror("ymf271_write_pcm invalid slot %02X\n", data); |
| 1217 | return; |
| 1218 | } |
| 1219 | YMF271Slot *slot = &m_slots[slotnum]; |
1253 | 1220 | |
1254 | | slotnum = pcm_tab[m_pcmreg&0xf]; |
1255 | | slot = &m_slots[slotnum]; |
1256 | | |
1257 | | switch ((m_pcmreg>>4)&0xf) |
| 1221 | switch (m_pcmreg >> 4 & 0xf) |
1258 | 1222 | { |
1259 | 1223 | case 0: |
1260 | 1224 | slot->startaddr &= ~0xff; |
1261 | 1225 | slot->startaddr |= data; |
1262 | 1226 | break; |
| 1227 | |
1263 | 1228 | case 1: |
1264 | 1229 | slot->startaddr &= ~0xff00; |
1265 | 1230 | slot->startaddr |= data<<8; |
1266 | 1231 | break; |
| 1232 | |
1267 | 1233 | case 2: |
1268 | 1234 | slot->startaddr &= ~0xff0000; |
1269 | 1235 | slot->startaddr |= (data & 0x7f)<<16; |
1270 | 1236 | slot->altloop = (data & 0x80) ? 1 : 0; |
1271 | 1237 | break; |
| 1238 | |
1272 | 1239 | case 3: |
1273 | 1240 | slot->endaddr &= ~0xff; |
1274 | 1241 | slot->endaddr |= data; |
1275 | 1242 | break; |
| 1243 | |
1276 | 1244 | case 4: |
1277 | 1245 | slot->endaddr &= ~0xff00; |
1278 | 1246 | slot->endaddr |= data<<8; |
1279 | 1247 | break; |
| 1248 | |
1280 | 1249 | case 5: |
1281 | 1250 | slot->endaddr &= ~0xff0000; |
1282 | 1251 | slot->endaddr |= (data & 0x7f)<<16; |
1283 | 1252 | break; |
| 1253 | |
1284 | 1254 | case 6: |
1285 | 1255 | slot->loopaddr &= ~0xff; |
1286 | 1256 | slot->loopaddr |= data; |
1287 | 1257 | break; |
| 1258 | |
1288 | 1259 | case 7: |
1289 | 1260 | slot->loopaddr &= ~0xff00; |
1290 | 1261 | slot->loopaddr |= data<<8; |
1291 | 1262 | break; |
| 1263 | |
1292 | 1264 | case 8: |
1293 | 1265 | slot->loopaddr &= ~0xff0000; |
1294 | 1266 | slot->loopaddr |= (data & 0x7f)<<16; |
1295 | 1267 | break; |
| 1268 | |
1296 | 1269 | case 9: |
1297 | 1270 | slot->fs = data & 0x3; |
1298 | 1271 | slot->bits = (data & 0x4) ? 12 : 8; |
1299 | 1272 | slot->srcnote = (data >> 3) & 0x3; |
1300 | 1273 | slot->srcb = (data >> 5) & 0x7; |
1301 | 1274 | break; |
| 1275 | |
1302 | 1276 | default: |
1303 | 1277 | break; |
1304 | 1278 | } |
r23978 | r23979 | |
1308 | 1282 | { |
1309 | 1283 | switch(id) |
1310 | 1284 | { |
1311 | | case 0: |
1312 | | m_status |= 1; |
| 1285 | case 0: |
| 1286 | m_status |= 1; |
1313 | 1287 | |
1314 | | // assert IRQ |
1315 | | if (m_enable & 4) |
1316 | | { |
1317 | | m_irqstate |= 1; |
| 1288 | // assert IRQ |
| 1289 | if (m_enable & 4) |
| 1290 | { |
| 1291 | m_irqstate |= 1; |
1318 | 1292 | |
1319 | | if (!m_irq_handler.isnull()) |
1320 | | m_irq_handler(1); |
1321 | | } |
| 1293 | if (!m_irq_handler.isnull()) |
| 1294 | m_irq_handler(1); |
| 1295 | } |
1322 | 1296 | |
1323 | | // reload timer |
1324 | | m_timA->adjust(attotime::from_hz(m_clock) * (384 * 4 * (256 - m_timerA)), 0); |
1325 | | break; |
| 1297 | // reload timer |
| 1298 | m_timA->adjust(attotime::from_hz(m_clock) * (384 * 4 * (256 - m_timerA)), 0); |
| 1299 | break; |
1326 | 1300 | |
1327 | | case 1: |
1328 | | m_status |= 2; |
| 1301 | case 1: |
| 1302 | m_status |= 2; |
1329 | 1303 | |
1330 | | // assert IRQ |
1331 | | if (m_enable & 8) |
1332 | | { |
1333 | | m_irqstate |= 2; |
| 1304 | // assert IRQ |
| 1305 | if (m_enable & 8) |
| 1306 | { |
| 1307 | m_irqstate |= 2; |
1334 | 1308 | |
1335 | | if (!m_irq_handler.isnull()) |
1336 | | m_irq_handler(1); |
1337 | | } |
| 1309 | if (!m_irq_handler.isnull()) |
| 1310 | m_irq_handler(1); |
| 1311 | } |
1338 | 1312 | |
1339 | | // reload timer |
1340 | | m_timB->adjust(attotime::from_hz(m_clock) * (384 * 16 * (256 - m_timerB)), 0); |
1341 | | break; |
| 1313 | // reload timer |
| 1314 | m_timB->adjust(attotime::from_hz(m_clock) * (384 * 16 * (256 - m_timerB)), 0); |
| 1315 | break; |
| 1316 | |
| 1317 | default: |
| 1318 | assert_always(FALSE, "Unknown id in ymf271_device::device_timer"); |
| 1319 | break; |
1342 | 1320 | } |
1343 | 1321 | } |
1344 | 1322 | |
r23978 | r23979 | |
1362 | 1340 | |
1363 | 1341 | void ymf271_device::ymf271_write_timer(int data) |
1364 | 1342 | { |
1365 | | int slotnum; |
1366 | | YMF271Group *group; |
1367 | | |
1368 | | slotnum = fm_tab[m_timerreg & 0xf]; |
1369 | | group = &m_groups[slotnum]; |
1370 | | |
1371 | 1343 | if ((m_timerreg & 0xf0) == 0) |
1372 | 1344 | { |
| 1345 | int groupnum = fm_tab[m_timerreg & 0xf]; |
| 1346 | if (groupnum == -1) |
| 1347 | { |
| 1348 | logerror("ymf271_write_timer invalid group %02X\n", data); |
| 1349 | return; |
| 1350 | } |
| 1351 | YMF271Group *group = &m_groups[groupnum]; |
| 1352 | |
1373 | 1353 | group->sync = data & 0x3; |
1374 | 1354 | group->pfm = data >> 7; |
1375 | 1355 | } |
r23978 | r23979 | |
1434 | 1414 | m_ext_address &= ~0xff; |
1435 | 1415 | m_ext_address |= data; |
1436 | 1416 | break; |
| 1417 | |
1437 | 1418 | case 0x15: |
1438 | 1419 | m_ext_address &= ~0xff00; |
1439 | 1420 | m_ext_address |= data << 8; |
1440 | 1421 | break; |
| 1422 | |
1441 | 1423 | case 0x16: |
1442 | 1424 | m_ext_address &= ~0xff0000; |
1443 | 1425 | m_ext_address |= (data & 0x7f) << 16; |
1444 | 1426 | m_ext_rw = (data & 0x80) ? 1 : 0; |
1445 | 1427 | break; |
| 1428 | |
1446 | 1429 | case 0x17: |
1447 | 1430 | m_ext_address = (m_ext_address + 1) & 0x7fffff; |
1448 | 1431 | if (!m_ext_rw && !m_ext_write_handler.isnull()) |
1449 | 1432 | m_ext_write_handler(m_ext_address, data); |
1450 | 1433 | break; |
| 1434 | |
| 1435 | case 0x20: |
| 1436 | case 0x21: |
| 1437 | case 0x22: |
| 1438 | // test |
| 1439 | break; |
1451 | 1440 | |
1452 | 1441 | default: |
1453 | 1442 | break; |
r23978 | r23979 | |
1464 | 1453 | case 0: |
1465 | 1454 | m_reg0 = data; |
1466 | 1455 | break; |
| 1456 | |
1467 | 1457 | case 1: |
1468 | 1458 | ymf271_write_fm(0, m_reg0, data); |
1469 | 1459 | break; |
| 1460 | |
1470 | 1461 | case 2: |
1471 | 1462 | m_reg1 = data; |
1472 | 1463 | break; |
| 1464 | |
1473 | 1465 | case 3: |
1474 | 1466 | ymf271_write_fm(1, m_reg1, data); |
1475 | 1467 | break; |
| 1468 | |
1476 | 1469 | case 4: |
1477 | 1470 | m_reg2 = data; |
1478 | 1471 | break; |
| 1472 | |
1479 | 1473 | case 5: |
1480 | 1474 | ymf271_write_fm(2, m_reg2, data); |
1481 | 1475 | break; |
| 1476 | |
1482 | 1477 | case 6: |
1483 | 1478 | m_reg3 = data; |
1484 | 1479 | break; |
| 1480 | |
1485 | 1481 | case 7: |
1486 | 1482 | ymf271_write_fm(3, m_reg3, data); |
1487 | 1483 | break; |
| 1484 | |
1488 | 1485 | case 8: |
1489 | 1486 | m_pcmreg = data; |
1490 | 1487 | break; |
| 1488 | |
1491 | 1489 | case 9: |
1492 | 1490 | ymf271_write_pcm(data); |
1493 | 1491 | break; |
| 1492 | |
1494 | 1493 | case 0xc: |
1495 | 1494 | m_timerreg = data; |
1496 | 1495 | break; |
| 1496 | |
1497 | 1497 | case 0xd: |
1498 | 1498 | ymf271_write_timer(data); |
1499 | 1499 | break; |
| 1500 | |
1500 | 1501 | default: |
1501 | 1502 | break; |
1502 | 1503 | } |
r23978 | r23979 | |
1664 | 1665 | save_item(NAME(m_slots[i].lfo_amplitude), i); |
1665 | 1666 | } |
1666 | 1667 | |
1667 | | for (i = 0; i < sizeof(m_groups) / sizeof(m_groups[0]); i++) |
| 1668 | for (i = 0; i < ARRAY_LENGTH(m_groups); i++) |
1668 | 1669 | { |
1669 | 1670 | save_item(NAME(m_groups[i].sync), i); |
1670 | 1671 | save_item(NAME(m_groups[i].pfm), i); |