/** * @file tracker.cc * * @brief Legacy code from Hyrule Magic TrackerLogic.c * * @details Attemtping to extract the song banks and convert them into SPC * format for the snes_spc library. * */ #include "tracker.h" #include #include #include #include #include #include "absl/status/status.h" #include "app/core/constants.h" #include "app/gfx/bitmap.h" #include "app/gfx/snes_tile.h" #include "app/rom.h" #include "snes_spc/snes_spc/spc.h" namespace yaze { namespace app { namespace zelda3 { namespace { void AddSPCReloc(SongSPCBlock *sbl, short addr) { sbl->relocs[sbl->relnum++] = addr; if (sbl->relnum == sbl->relsz) { sbl->relsz += 16; sbl->relocs = (unsigned short *)realloc(sbl->relocs, sbl->relsz << 1); } } } // namespace // ============================================================================= SongSPCBlock *Tracker::AllocSPCBlock(int len, int bank) { SongSPCBlock *sbl; if (!len) { printf("warning zero length block allocated"); } if (ss_num == ss_size) { ss_size += 512; ssblt = (SongSPCBlock **)realloc(ssblt, ss_size << 2); } ssblt[ss_num] = sbl = (SongSPCBlock *)malloc(sizeof(SongSPCBlock)); ss_num++; sbl->start = ss_next; sbl->len = len; sbl->buf = (uchar *)malloc(len); sbl->relocs = (ushort *)malloc(32); sbl->relsz = 16; sbl->relnum = 0; sbl->bank = bank & 7; sbl->flag = bank >> 3; ss_next += len; return sbl; } // ============================================================================= unsigned char *Tracker::GetSPCAddr(ROM &rom, unsigned short addr, short bank) { unsigned char *rom_ptr; unsigned short a; unsigned short b; spcbank = bank + 1; again: rom_ptr = rom.data() + sbank_ofs[spcbank]; for (;;) { a = *(unsigned short *)rom_ptr; if (!a) { if (spcbank) { spcbank = 0; goto again; } else return nullptr; } b = *(unsigned short *)(rom_ptr + 2); rom_ptr += 4; if (addr >= b && addr - b < a) { spclen = a; return rom_ptr + addr - b; } rom_ptr += a; } } // ============================================================================= short Tracker::AllocSPCCommand() { int i = m_free; int j; int k; SPCCommand *spc_command; if (i == -1) { j = m_size; m_size += 1024; spc_command = current_spc_command_ = (SPCCommand *)realloc( current_spc_command_, m_size * sizeof(SPCCommand)); k = 1023; while (k--) spc_command[j].next = j + 1, j++; spc_command[j].next = -1; k = 1023; while (k--) spc_command[j].prev = j - 1, j--; spc_command[j].prev = -1; i = j; } else spc_command = current_spc_command_; m_free = spc_command[m_free].next; if (m_free != -1) spc_command[m_free].prev = -1; return i; } // ============================================================================= short Tracker::GetBlockTime(ROM &rom, short num, short prevtime) { SPCCommand *spc_command = current_spc_command_; SPCCommand *spc_command2; int i = -1; int j = 0; int k = 0; int l; int m = 0; int n = prevtime; l = num; if (l == -1) return 0; for (;;) { if (spc_command[l].flag & 4) { j = spc_command[l].tim; m = spc_command[l].tim2; k = 1; } if (!k) i = l; if (spc_command[l].flag & 1) n = spc_command[l].b1; l = spc_command[l].next; if (l == -1) { if (!k) { m = 0; j = 0; } break; } } if (i != -1) for (;;) { if (i == -1) { printf("Error"); m_modf = 1; return 0; } spc_command2 = spc_command + i; if (spc_command2->cmd == 0xef) { k = *(short *)&(spc_command2->p1); if (k >= m_size) { printf("Invalid music address\n"); m_modf = 1; return 0; } if (spc_command2->flag & 1) { j += GetBlockTime(rom, k, 0) * spc_command2->p3; if (ss_lasttime) { j += ss_lasttime * m; j += spc_command[k].tim2 * spc_command2->b1; j += (spc_command2->p3 - 1) * spc_command[k].tim2 * ss_lasttime; } else { j += spc_command2->b1 * (m + spc_command[k].tim2 * spc_command2->p3); } m = 0; } else { j += GetBlockTime(rom, k, 0) * spc_command2->p3; j += ss_lasttime * m; if (ss_lasttime) j += (spc_command2->p3 - 1) * ss_lasttime * spc_command[k].tim2, m = spc_command[k].tim2; else m += spc_command[k].tim2 * spc_command2->p3; } } else { if (spc_command2->cmd < 0xe0) m++; if (spc_command2->flag & 1) { j += m * spc_command[i].b1; m = 0; } } spc_command2->tim = j; spc_command2->tim2 = m; spc_command2->flag |= 4; if (i == num) break; i = spc_command2->prev; } ss_lasttime = n; return spc_command[num].tim + prevtime * spc_command[num].tim2; } // ============================================================================= short Tracker::LoadSPCCommand(ROM &rom, unsigned short addr, short bank, int t) { int b = 0; int c = 0; int d = 0; int e = 0; int f = 0; int g = 0; int h = 0; int i = 0; int l = 0; int m = 0; int n = 0; int o = 0; unsigned char j = 0; unsigned char k = 0; unsigned char *a = nullptr; SongRange *sr; SPCCommand *spc_command = current_spc_command_; SPCCommand *spc_command2; if (!addr) return -1; a = GetSPCAddr(rom, addr, bank); d = spcbank; if (!a) { printf("Address not found when loading track"); return -1; } sr = song_range_; e = srnum; f = 0x10000; for (c = 0; c < e; c++) { if (sr[c].bank == d) if (sr[c].start > addr) { if (sr[c].start < f) f = sr[c].start; n = c; } else if (sr[c].end > addr) { for (f = sr[c].first; f != -1; f = spc_command[f].next) { if (spc_command[f].flag & 4) m = spc_command[f].tim, o = spc_command[f].tim2; if (spc_command[f].addr == addr) { spc_command[f].tim = m; spc_command[f].tim2 = o; lastsr = c; return f; } if (spc_command[f].flag & 1) k = spc_command[f].b1; if (spc_command[f].cmd < 0xca) if (k) m -= k; else o--; } printf("Misaligned music pointer"); return -1; } } c = n; i = h = m_free; a -= addr; m = 0; k = 0; o = 0; for (g = addr; g < f;) { spc_command2 = spc_command + i; if (spc_command2->next == -1) { l = m_size; spc_command = current_spc_command_ = (SPCCommand *)realloc( spc_command, sizeof(SPCCommand) * (m_size += 1024)); spc_command2 = spc_command + i; n = l + 1023; while (l < n) spc_command[l].next = l + 1, l++; spc_command[l].next = -1; n -= 1023; while (l > n) spc_command[l].prev = l - 1, l--; spc_command[l].prev = i; spc_command2->next = l; } spc_command2->addr = g; b = a[g]; if (!b) break; if (m >= t && b != 0xf9) break; g++; j = 0; if (b < 128) { j = 1; k = spc_command2->b1 = b; b = a[g++]; if (b < 128) j = 3, spc_command2->b2 = b, b = a[g++]; } if (b < 0xe0) if (k) m += k; else o++; spc_command2->cmd = b; spc_command2->flag = j; if (b >= 0xe0) { b -= 0xe0; if (op_len[b]) spc_command2->p1 = a[g++]; if (op_len[b] > 1) spc_command2->p2 = a[g++]; if (op_len[b] > 2) spc_command2->p3 = a[g++]; if (b == 15) { m_free = spc_command2->next; spc_command[spc_command2->next].prev = -1; l = LoadSPCCommand(rom, *(short *)(&(spc_command2->p1)), bank, t - m); spc_command = current_spc_command_; spc_command2 = spc_command + i; *(short *)(&(spc_command2->p1)) = l; spc_command2->next = m_free; spc_command[spc_command2->next].prev = i; GetBlockTime(rom, l, 0); if (spc_command[l].flag & 4) m += (spc_command[l].tim + spc_command[l].tim2 * k) * spc_command2->p3; else { i = spc_command2->next; break; } if (song_range_[lastsr].endtime) k = song_range_[lastsr].endtime; } } i = spc_command2->next; } spc_command[h].tim = m; spc_command[h].tim2 = o; spc_command[h].flag |= 4; if (f == g && m < t) { l = spc_command[i].prev; lastsr = c; spc_command[sr[lastsr].first].prev = l; l = spc_command[l].next = sr[lastsr].first; if (spc_command[l].flag & 4) spc_command[h].tim = spc_command[l].tim + m + spc_command[l].tim2 * k, spc_command[h].flag |= 4; sr[lastsr].first = h; sr[lastsr].start = addr; sr[lastsr].inst++; } else { if (srsize == srnum) song_range_ = (SongRange *)realloc(song_range_, (srsize += 16) * sizeof(SongRange)); lastsr = srnum; sr = song_range_ + (srnum++); sr->start = addr; sr->end = g; sr->first = h; sr->endtime = k; sr->inst = 1; sr->editor = 0; sr->bank = d; spc_command[spc_command[i].prev].next = -1; } spc_command[i].prev = -1; m_free = i; return h; } // ============================================================================= void Tracker::LoadSongs(ROM &rom) { unsigned char *b; unsigned char *c; unsigned char *d; short *e; Song song; Song song2; SongPart *sp; SPCCommand *spc_command; ZeldaWave *zelda_wave; int i; int j; int k; int l = 0; int m; int n; int o; int p; int q; int r; int t; int u; int range; int filter; spc_command = current_spc_command_ = (SPCCommand *)malloc(1024 * sizeof(SPCCommand)); m_free = 0; m_size = 1024; srnum = 0; srsize = 0; song_range_ = 0; sp_mark = 0; b = rom.data(); sbank_ofs[1] = (b[0x91c] << 15) + ((b[0x918] & 127) << 8) + b[0x914]; sbank_ofs[3] = (b[0x93a] << 15) + ((b[0x936] & 127) << 8) + b[0x932]; for (i = 0; i < 1024; i++) { spc_command[i].next = i + 1; spc_command[i].prev = i - 1; } // Init blank songs. for (i = 0; i < 128; i++) { Song new_song; songs.emplace_back(new_song); } spc_command[1023].next = -1; for (i = 0; i < 3; i++) { // Extract the song banks. b = GetSPCAddr(rom, 0xd000, i); for (j = 0;; j++) { if ((r = ((unsigned short *)b)[j]) >= 0xd000) { r = (r - 0xd000) >> 1; break; } } numsong[i] = r; for (j = 0; j < r; j++) { k = ((unsigned short *)b)[j]; if (!k) songs[l].in_use = false; else { c = GetSPCAddr(rom, k, i); // Init the bank index we are current loading. if (!spcbank) m = 0; else m = l - j; for (; m < l; m++) if (songs[m].in_use && songs[m].addr == k) { (songs[l] = songs[m]).inst++; break; } if (m == l) { // create a new song (Song *)malloc(sizeof(Song)); songs[l] = song; song.inst = 1; song.addr = k; song.flag = !spcbank; for (m = 0;; m++) if ((n = ((unsigned short *)c)[m]) < 256) break; if (n > 0) { song.flag |= 2; song.lopst = (((unsigned short *)c)[m + 1] - k) >> 1; } song.numparts = m; song.tbl = (SongPart **)malloc(4 * m); for (m = 0; m < song.numparts; m++) { k = ((unsigned short *)c)[m]; d = GetSPCAddr(rom, k, i); if (!spcbank) n = 0; else n = l - j; for (; n < l; n++) { song2 = songs[n]; if (song2.in_use) for (o = 0; o < song2.numparts; o++) if (song2.tbl[o]->addr == k) { (song.tbl[m] = song2.tbl[o])->inst++; goto foundpart; } } for (o = 0; o < m; o++) if (song.tbl[o]->addr == k) { (song.tbl[m] = song.tbl[o])->inst++; goto foundpart; } sp = song.tbl[m] = (SongPart *)malloc(sizeof(SongPart)); sp->flag = !spcbank; sp->inst = 1; sp->addr = k; p = 50000; for (o = 0; o < 8; o++) { q = sp->tbl[o] = LoadSPCCommand(rom, ((unsigned short *)d)[o], i, p); spc_command = current_spc_command_ + q; if ((spc_command->flag & 4) && spc_command->tim < p) p = spc_command->tim; } foundpart:; } } } l++; } } b = GetSPCAddr(rom, 0x800, 0); snddat1 = (char *)malloc(spclen); sndlen1 = spclen; memcpy(snddat1, b, spclen); b = GetSPCAddr(rom, 0x17c0, 0); snddat2 = (char *)malloc(spclen); sndlen2 = spclen; memcpy(snddat2, b, spclen); b = GetSPCAddr(rom, 0x3d00, 0); insts = (ZeldaInstrument *)malloc(spclen); memcpy(insts, b, spclen); numinst = spclen / 6; b = GetSPCAddr(rom, 0x3e00, 0); m_ofs = b - rom.data() + spclen; sndinsts = (ZeldaSfxInstrument *)malloc(spclen); memcpy(sndinsts, b, spclen); numsndinst = spclen / 9; b = GetSPCAddr(rom, 0x3c00, 0); zelda_wave = waves = (ZeldaWave *)malloc(sizeof(ZeldaWave) * (spclen >> 2)); p = spclen >> 1; for (i = 0; i < p; i += 2) { j = ((unsigned short *)b)[i]; if (j == 65535) break; for (k = 0; k < i; k += 2) { if (((unsigned short *)b)[k] == j) { zelda_wave->copy = (short)(k >> 1); goto foundwave; } } zelda_wave->copy = -1; foundwave: d = GetSPCAddr(rom, j, 0); e = (short *)malloc(2048); k = 0; l = 1024; u = t = 0; for (;;) { m = *(d++); range = (m >> 4) + 8; filter = (m & 12) >> 2; for (n = 0; n < 8; n++) { o = (*d) >> 4; if (o > 7) o -= 16; o <<= range; if (filter) o += (t * fil1[filter] >> fil2[filter]) - ((u & -256) * fil3[filter] >> 4); if (o > 0x7fffff) o = 0x7fffff; if (o < -0x800000) o = -0x800000; u = o; // \code if(t>0x7fffff) t=0x7fffff; // \code if(t < -0x800000) t=-0x800000; e[k++] = o >> 8; o = *(d++) & 15; if (o > 7) o -= 16; o <<= range; if (filter) o += (u * fil1[filter] >> fil2[filter]) - ((t & -256) * fil3[filter] >> 4); if (o > 0x7fffff) o = 0x7fffff; if (o < -0x800000) o = -0x800000; t = o; // \code if(u>0x7fffff) u=0x7fffff; // \code if(u < -0x800000) u= -0x800000; e[k++] = o >> 8; } if (m & 1) { zelda_wave->lflag = (m & 2) >> 1; break; } if (k == l) { l += 1024; e = (short *)realloc(e, l << 1); } } e = zelda_wave->buf = (short *)realloc(e, (k + 1) << 1); zelda_wave->lopst = (((unsigned short *)b)[i + 1] - j) * 16 / 9; if (zelda_wave->lflag) e[k] = e[zelda_wave->lopst]; else e[k] = 0; zelda_wave->end = k; zelda_wave++; } numwave = i >> 1; m_loaded = 1; w_modf = 0; } short Tracker::SaveSPCCommand(ROM &rom, short num, short songtime, short endtr) { SPCCommand *spc_command = current_spc_command_; SPCCommand *spc_command2; SongRange *sr = song_range_; SongSPCBlock *sbl; text_buf_ty buf; unsigned char *b; int i = num; int j = 0; int k = 0; int l = 0; int m = 0; int n = 0; int o = 0; int p = 0; if (i == -1) return 0; if (i >= m_size) { printf("Error.\n"); m_modf = 1; return 0; } if (spc_command[i].flag & 8) return spc_command[i].addr; for (;;) { j = spc_command[i].prev; if (j == -1) break; i = j; } for (j = 0; j < srnum; j++) { if (sr[j].first == i) { l = GetBlockTime(rom, i, 0); m = i; for (;;) { if (m == -1) break; k++; spc_command2 = spc_command + m; if (spc_command2->flag & 1) k++, n = spc_command2->b1; if (spc_command2->flag & 2) k++; if (spc_command2->cmd >= 0xe0) k += op_len[spc_command2->cmd - 0xe0]; m = spc_command2->next; } songtime -= l; if (songtime > 0) { l = (songtime + 126) / 127; if (songtime % l) l += 2; l++; if (n && !songtime % n) { p = songtime / n; if (p < l) l = p; } else p = -1; k += l; } k++; sbl = AllocSPCBlock(k, sr[j].bank | ((!endtr) << 3) | 16); b = sbl->buf; for (;;) { if (i == -1) break; spc_command2 = spc_command + i; spc_command2->addr = b - sbl->buf + sbl->start; spc_command2->flag |= 8; if (spc_command2->flag & 1) *(b++) = spc_command2->b1; if (spc_command2->flag & 2) *(b++) = spc_command2->b2; *(b++) = spc_command2->cmd; if (spc_command2->cmd >= 0xe0) { o = op_len[spc_command2->cmd - 0xe0]; if (spc_command2->cmd == 0xef) { *(short *)b = SaveSPCCommand(rom, *(short *)&(spc_command2->p1), 0, 1); if (b) AddSPCReloc(sbl, b - sbl->buf); b[2] = spc_command2->p3; b += 3; } else { if (o) *(b++) = spc_command2->p1; if (o > 1) *(b++) = spc_command2->p2; if (o > 2) *(b++) = spc_command2->p3; } } i = spc_command2->next; } if (songtime > 0) { if (l != p) { l = (songtime + 126) / 127; if (songtime % l) n = 127; else n = songtime / l; *(b++) = n; } for (; songtime >= n; songtime -= n) *(b++) = 0xc9; if (songtime) { *(b++) = (uint8_t)songtime; *(b++) = 0xc9; } } *(b++) = 0; return spc_command[num].addr; } } printf("Address %04X not found", num); printf("Error"); m_modf = 1; return 0; } // ============================================================================= int Tracker::WriteSPCData(ROM &rom, void *buf, int len, int addr, int spc, int limit) { unsigned char *rom_data = rom.data(); if (!len) return addr; if (((addr + len + 4) & 0x7fff) > 0x7ffb) { if (addr + 5 > limit) goto error; *(int *)(rom_data + addr) = 0x00010140; rom_data[addr + 4] = 0xff; addr += 5; } if (addr + len + 4 > limit) { error: printf("Not enough space for sound data"); m_modf = 1; return 0xc8000; } *(short *)(rom_data + addr) = len; *(short *)(rom_data + addr + 2) = spc; memcpy(rom_data + addr + 4, buf, len); return addr + len + 4; } // ============================================================================= void Tracker::SaveSongs(ROM &rom) { int i; int j; int k; int l = 0; int m; int n; int o; int p; int q; int r; int t; int u; int v; int w; int a; int e; int f; int g; unsigned short bank_next[4]; unsigned short bank_lwr[4]; short *c; short *d; unsigned char *rom_data; unsigned char *b; Song song; SPCCommand *spc_command; SongPart *sp; SongSPCBlock *stbl; SongSPCBlock *sptbl; SongSPCBlock *trtbl; SongSPCBlock *pstbl; ZeldaWave *zelda_wave; ZeldaWave *zelda_wave2; ZeldaInstrument *zi; SampleEdit *sed; short wtbl[128]; short x[16]; short y[18]; unsigned char z[64]; ss_num = 0; ss_size = 512; ss_next = 0; // if the music has not been modified, return. if (!(m_modf)) return; ssblt = (SongSPCBlock **)malloc(512 * sizeof(SongSPCBlock)); // set it so the music has not been modified. (reset the status) m_modf = 0; rom_data = rom.data(); // SetCursor(wait_cursor); for (i = 0; i < 3; i++) { k = numsong[i]; for (j = 0; j < k; j++) { song = songs[l++]; if (!song.in_use) continue; song.flag &= -5; for (m = 0; m < song.numparts; m++) { sp = song.tbl[m]; sp->flag &= -3; } } } j = m_size; spc_command = current_spc_command_; for (i = 0; i < j; i++) { spc_command->flag &= -13; spc_command++; } l = 0; for (i = 0; i < 3; i++) { k = numsong[i]; stbl = AllocSPCBlock(k << 1, i + 1); for (j = 0; j < k; j++) { song = songs[l++]; if (!song.in_use) { ((short *)(stbl->buf))[j] = 0; continue; } if (song.flag & 4) goto alreadysaved; sptbl = AllocSPCBlock(((song.numparts + 1) << 1) + (song.flag & 2), (song.flag & 1) ? 0 : (i + 1)); for (m = 0; m < song.numparts; m++) { sp = song.tbl[m]; if (sp->flag & 2) goto spsaved; trtbl = AllocSPCBlock(16, (sp->flag & 1) ? 0 : (i + 1)); p = 0; for (n = 0; n < 8; n++) { o = GetBlockTime(rom, sp->tbl[n], 0); if (o > p) p = o; } q = 1; for (n = 0; n < 8; n++) { core::stle16b_i(trtbl->buf, n, SaveSPCCommand(rom, sp->tbl[n], p, q)); if (core::ldle16b_i(trtbl->buf, n)) AddSPCReloc(trtbl, n << 1), q = 0; } sp->addr = trtbl->start; sp->flag |= 2; spsaved: ((short *)(sptbl->buf))[m] = sp->addr; AddSPCReloc(sptbl, m << 1); } if (song.flag & 2) { ((short *)(sptbl->buf))[m++] = 255; ((short *)(sptbl->buf))[m] = sptbl->start + (song.lopst << 1); AddSPCReloc(sptbl, m << 1); } else ((short *)(sptbl->buf))[m++] = 0; song.addr = sptbl->start; song.flag |= 4; alreadysaved: ((short *)(stbl->buf))[j] = song.addr; AddSPCReloc(stbl, j << 1); } } if (w_modf) { b = (uint8_t *)malloc(0xc000); j = 0; zelda_wave = waves; // if (mbanks[3]) // sed = (SampleEdit *)GetWindowLongPtr(mbanks[3], GWLP_USERDATA); // else // sed = 0; for (i = 0; i < numwave; i++, zelda_wave++) { if (zelda_wave->copy != -1) continue; wtbl[i << 1] = j + 0x4000; if (zelda_wave->lflag) { l = zelda_wave->end - zelda_wave->lopst; if (l & 15) { k = (l << 15) / ((l + 15) & -16); p = (zelda_wave->end << 15) / k; c = (short *)malloc(p << 1); n = 0; d = zelda_wave->buf; for (m = 0;;) { c[n++] = (d[m >> 15] * ((m & 32767) ^ 32767) + d[(m >> 15) + 1] * (m & 32767)) / 32767; m += k; if (n >= p) break; } zelda_wave->lopst = (zelda_wave->lopst << 15) / k; zelda_wave->end = p; zelda_wave->buf = (short *)realloc(zelda_wave->buf, (zelda_wave->end + 1) << 1); memcpy(zelda_wave->buf, c, zelda_wave->end << 1); free(c); zelda_wave->buf[zelda_wave->end] = zelda_wave->buf[zelda_wave->lopst]; zelda_wave2 = waves; for (m = 0; m < numwave; m++, zelda_wave2++) if (zelda_wave2->copy == i) zelda_wave2->lopst = zelda_wave2->lopst << 15 / k; zi = insts; for (m = 0; m < numinst; m++) { n = zi->samp; if (n >= numwave) continue; if (n == i || waves[n].copy == i) { o = (zi->multhi << 8) + zi->multlo; o = (o << 15) / k; zi->multlo = o; zi->multhi = o >> 8; if (sed && sed->editinst == m) { sed->init = 1; // SetDlgItemInt(sed->dlg, 3014, o, 0); sed->init = 0; } } zi++; } // Modifywaves(rom, i); } } k = (-zelda_wave->end) & 15; d = zelda_wave->buf; n = 0; wtbl[(i << 1) + 1] = ((zelda_wave->lopst + k) >> 4) * 9 + wtbl[i << 1]; y[0] = y[1] = 0; u = 4; for (;;) { for (o = 0; o < 16; o++) { if (k) k--, x[o] = 0; else x[o] = d[n++]; } p = 0x7fffffff; a = 0; for (t = 0; t < 4; t++) { r = 0; for (o = 0; o < 16; o++) { l = x[o]; y[o + 2] = l; l += (y[o] * fil3[t] >> 4) - (y[o + 1] * fil1[t] >> fil2[t]); if (l > r) r = l; else if (-l > r) r = -l; } r <<= 1; if (t) m = 14; else m = 15; for (q = 0; q < 12; q++, m += m) if (m >= r) break; tryagain: if (q && (q < 12 || m == r)) v = (1 << (q - 1)) - 1; else v = 0; m = 0; for (o = 0; o < 16; o++) { l = (y[o + 1] * fil1[t] >> fil2[t]) - (y[o] * fil3[t] >> 4); w = x[o]; r = (w - l + v) >> q; if ((r + 8) & 0xfff0) { q++; a -= o; goto tryagain; } z[a++] = r; l = (r << q) + l; y[o + 2] = l; l -= w; m += l * l; } if (u == 4) { u = 0, e = q, f = y[16], g = y[17]; break; } if (m < p) p = m, u = t, e = q, f = y[16], g = y[17]; } m = (e << 4) | (u << 2); if (n == zelda_wave->end) m |= 1; if (zelda_wave->lflag) m |= 2; b[j++] = m; m = 0; a = u << 4; for (o = 0; o < 16; o++) { m |= z[a++] & 15; if (o & 1) b[j++] = m, m = 0; else m <<= 4; } if (n == zelda_wave->end) break; y[0] = f; y[1] = g; } } // if (sed) { // SetDlgItemInt(sed->dlg, ID_Samp_SampleLengthEdit, sed->zelda_wave->end, // 0); SetDlgItemInt(sed->dlg, ID_Samp_LoopPointEdit, // sed->zelda_wave->lopst, 0); // InvalidateRect(GetDlgItem(sed->dlg, ID_Samp_Display), 0, 1); // } zelda_wave = waves; for (i = 0; i < numwave; i++, zelda_wave++) { if (zelda_wave->copy != -1) { wtbl[i << 1] = wtbl[zelda_wave->copy << 1]; wtbl[(i << 1) + 1] = (zelda_wave->lopst >> 4) * 9 + wtbl[i << 1]; } } m = WriteSPCData(rom, wtbl, numwave << 2, 0xc8000, 0x3c00, 0xd74fc); m = WriteSPCData(rom, b, j, m, 0x4000, 0xd74fc); free(b); m = WriteSPCData(rom, insts, numinst * 6, m, 0x3d00, 0xd74fc); m = WriteSPCData(rom, snddat1, sndlen1, m, 0x800, 0xd74fc); m = WriteSPCData(rom, snddat2, sndlen2, m, 0x17c0, 0xd74fc); m = WriteSPCData(rom, sndinsts, numsndinst * 9, m, 0x3e00, 0xd74fc); m_ofs = m; } else { m = m_ofs; } bank_next[0] = 0x2880; bank_next[1] = 0xd000; bank_next[2] = 0xd000; bank_next[3] = 0xd000; bank_lwr[0] = 0x2880; for (k = 0; k < 4; k++) { pstbl = 0; for (i = 0; i < ss_num; i++) { stbl = ssblt[i]; if (stbl->bank != k) continue; j = bank_next[k]; if (j + stbl->len > 0xffc0) { if (k == 3) j = 0x2880; else j = bank_next[0]; bank_lwr[k] = j; pstbl = 0; } if (j + stbl->len > 0x3c00 && j < 0xd000) { printf("Not enough space for music bank %d", k); m_modf = 1; return; } if (pstbl && (pstbl->flag & 1) && (stbl->flag & 2)) j--, pstbl->len--; stbl->addr = j; pstbl = stbl; bank_next[k] = j + stbl->len; } } for (i = 0; i < ss_num; i++) { stbl = ssblt[i]; for (j = stbl->relnum - 1; j >= 0; j--) { k = *(unsigned short *)(stbl->buf + stbl->relocs[j]); for (l = 0; l < ss_num; l++) { sptbl = ssblt[l]; if (sptbl->start <= k && sptbl->len > k - sptbl->start) goto noerror; } printf("Internal error"); m_modf = 1; return; noerror: if (((!sptbl->bank) && stbl->bank < 3) || (sptbl->bank == stbl->bank)) { *(unsigned short *)(stbl->buf + stbl->relocs[j]) = sptbl->addr + k - sptbl->start; } else { printf("An address outside the bank was referenced.\n"); m_modf = 1; return; } } } l = m; for (k = 0; k < 4; k++) { switch (k) { case 1: rom[0x914] = l; rom[0x918] = (l >> 8) | 128; rom[0x91c] = l >> 15; break; case 2: l = 0xd8000; break; case 3: l = m; rom[0x932] = l; rom[0x936] = (l >> 8) | 128; rom[0x93a] = l >> 15; break; } for (o = 0; o < 2; o++) { n = l + 4; for (i = 0; i < ss_num; i++) { stbl = ssblt[i]; if (!stbl) continue; if ((stbl->addr < 0xd000) ^ o) continue; if (stbl->bank != k) continue; if (n + stbl->len > ((k == 2) ? 0xdb7fc : 0xd74fc)) { printf("Not enough space for music"); m_modf = 1; return; } memcpy(rom.data() + n, stbl->buf, stbl->len); n += stbl->len; free(stbl->relocs); free(stbl->buf); free(stbl); ssblt[i] = 0; } if (n > l + 4) { *(short *)(rom + l) = n - l - 4; *(short *)(rom + l + 2) = o ? bank_lwr[k] : 0xd000; l = n; } } *(short *)(rom + l) = 0; *(short *)(rom + l + 2) = 0x800; if (k == 1) m = l + 4; } free(ssblt); } // ============================================================================= void Tracker::EditTrack(ROM &rom, short i) { int j, k, l; SongRange *sr = song_range_; SPCCommand *spc_command; text_buf_ty buf; // ----------------------------- k = srnum; spc_command = current_spc_command_; if (i == -1) return; if (i >= m_size) { printf("Invalid address: %04X", i); goto error; } for (;;) { if ((j = spc_command[i].prev) != -1) i = j; else break; } for (l = 0; l < k; l++) if (sr->first == i) break; else sr++; if (l == k) { printf("Not found: %04X", i); error: printf("Error"); return; } // if (sr->editor) // HM_MDI_ActivateChild(clientwnd, sr->editor); // else // Editwin(rom, "TRACKEDIT", "Song editor", l + (i << 16), // sizeof(TRACKEDIT)); } // CRITICAL_SECTION cs_song; // ============================================================================= void Tracker::NewSR(ROM &rom, int bank) { SPCCommand *spc_command; SongRange *sr; if (srnum == srsize) { srsize += 16; song_range_ = (SongRange *)realloc(song_range_, srsize * sizeof(SongRange)); } sr = song_range_ + srnum; srnum++; sr->first = AllocSPCCommand(); sr->bank = bank; sr->editor = 0; spc_command = current_spc_command_ + sr->first; spc_command->prev = -1; spc_command->next = -1; spc_command->cmd = 128; spc_command->flag = 0; EditTrack(rom, sr->first); } // ============================================================================= } // namespace zelda3 } // namespace app } // namespace yaze