-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcodegen.cpp
More file actions
130 lines (116 loc) · 3.8 KB
/
Copy pathcodegen.cpp
File metadata and controls
130 lines (116 loc) · 3.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#include "codegen.h"
#include <cstdio>
#include <cstring>
namespace {
void write(FILE* fp, int c)
{
fputc(c, fp);
}
void write16(FILE* fp, int w)
{
fputc(w & 0xFF, fp);
fputc((w >> 8) & 0xFF, fp);
}
void write_n(FILE* fp, void* ptr, size_t size)
{
fwrite(ptr, 1, size, fp);
}
}
uint16_t codegen::write_meta(FILE* fp, const std::string& tag)
{
uint16_t offset = 0;
if(auto it = meta.find(tag); it != meta.end()) {
offset = static_cast<uint16_t>(ftell(fp));
for(const char* p = it->second.c_str(); *p != '\0'; p++) {
if(tag == "Title2" && *p == ';') write(fp, '\n');
else write(fp, *p);
}
write(fp, '\0');
}
return offset;
}
void codegen::register_meta(const std::string& tag, const std::string& value)
{
if(auto [iter, success] = meta.insert_or_assign(tag, value); !success) {
printf("Warning: meta tag redefined! [%s]\n", tag.c_str());
}
}
int codegen::write_pmd(FILE *out_fp)
{
std::vector<uint16_t> drum_pattern_offsets;
uint16_t title_offset = 0, title2_offset = 0, part_offsets[MAXPART] = {0}, drum_offset = 0;
int actual_parts = count_actual_parts();
int min_parts = std::max(actual_parts, 6);
end_parts();
memset(part_offsets, 0, sizeof part_offsets);
// write part definitions
write(out_fp, 0);
write(out_fp, min_parts);
// write header
for(int i = 0; i < min_parts; i++) {
write16(out_fp, 0); // placeholder for part offset
}
write16(out_fp, 0); // placeholder for drum pattern offset
write16(out_fp, 0); // placeholder for title offset
write16(out_fp, 0); // placeholder for title2 offset
// write title, title2
title_offset = write_meta(out_fp, "Title");
title2_offset = write_meta(out_fp, "Title2");
// write drums
for(auto& pb: drum_patterns) {
if(pb.pos > 0) {
drum_pattern_offsets.push_back(static_cast<uint16_t>(ftell(out_fp)));
write_n(out_fp, pb.buffer.data(), pb.size);
} else {
drum_pattern_offsets.push_back(0);
}
}
// write parts
for(int part = 0; part < MAXPART; part++) {
if(part_buffer& pb = parts[part]; pb.pos > 0 && pb.length_written > 0) {
size_t fp = ftell(out_fp);
if (fp > 0xffff) {
printf("Warning: part %c is too large to fit in PMD file\n", 'A' + part);
}
part_offsets[part] = static_cast<uint16_t>(fp & 0xffff);
pb.update_part_offset(part_offsets[part]);
write_n(out_fp, pb.buffer.data(), pb.size);
} else {
if(pb.pos > 0 && pb.length_written == 0) {
printf("Warning: part %c has some data but no ticks, skipping part (avoiding infinite loop in muslib)\n", 'A' + part);
}
part_offsets[part] = 0;
}
}
// write drum pattern offsets
drum_offset = static_cast<uint16_t>(ftell(out_fp));
if(drum_pattern_offsets.empty()) {
drum_offset = 0;
} else {
for(auto& i: drum_pattern_offsets) {
write16(out_fp, i);
}
}
// update header
fseek(out_fp, 2, SEEK_SET);
for(int i = 0, p = 0; i < MAXPART && p < actual_parts; i++) {
if(part_offsets[i] > 0) {
write16(out_fp, part_offsets[i]);
p++;
}
}
for (int i = actual_parts; i < min_parts; i++)
write16(out_fp, 0);
write16(out_fp, drum_offset);
write16(out_fp, title_offset); // title offset
write16(out_fp, title2_offset); // title2 offset
fseek(out_fp, 0, SEEK_END);
return ftell(out_fp);
}
void codegen::report_meta(FILE *fp)
{
fprintf(fp, "META definitions:\n");
for(auto& [key, value]: meta) {
fprintf(fp, "\t#%s = [%s]\n", key.c_str(), value.c_str());
}
}