File: ss_binary.hh

package info (click to toggle)
performous 1.1%2Bgit20181118-4
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 11,736 kB
  • sloc: cpp: 30,008; ansic: 2,751; sh: 801; xml: 464; python: 374; makefile: 36
file content (176 lines) | stat: -rw-r--r-- 6,028 bytes parent folder | download | duplicates (6)
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
#include "adpcm.h"
#include "ipuconv.hh"

unsigned getLE16(char* buf) { unsigned char* b = reinterpret_cast<unsigned char*>(buf); return b[0] | (b[1] << 8); }
unsigned getLE32(char* buf) { unsigned char* b = reinterpret_cast<unsigned char*>(buf); return b[0] | (b[1] << 8) | (b[2] << 16) | (b[3] << 24); }

void writeWavHeader(std::ostream& outfile, unsigned ch, unsigned sr, unsigned samples) {
	unsigned bps = ch * 2; // Bytes per sample
	unsigned datasize = bps * samples;
	unsigned size = datasize + 0x2C;
	outfile.write("RIFF" ,4); // RIFF chunk
	{ unsigned int tmp=size-0x8 ; outfile.write((char*)(&tmp),4); } // RIFF chunk size
	outfile.write("WAVEfmt ",8); // WAVEfmt header
	{ int   tmp=0x00000010 ; outfile.write((char*)(&tmp),4); } // Always 0x10
	{ short tmp=0x0001     ; outfile.write((char*)(&tmp),2); } // Always 1
	{ short tmp = ch; outfile.write((char*)(&tmp),2); } // Number of channels
	{ int   tmp = sr; outfile.write((char*)(&tmp),4); } // Sample rate
	{ int   tmp = bps * sr; outfile.write((char*)(&tmp),4); } // Bytes per second
	{ short tmp = bps; outfile.write((char*)(&tmp),2); } // Bytes per frame
	{ short tmp = 16; outfile.write((char*)(&tmp),2); } // Bits per sample
	outfile.write("data",4); // data chunk
	{ int   tmp = datasize; outfile.write((char*)(&tmp),4); }
}

void writeMusic(fs::path const& filename, std::vector<short> const& buf, unsigned sr) {
	std::ofstream f(filename.string().c_str(), std::ios::binary);
	writeWavHeader(f, 2, sr, buf.size());
	f.write(reinterpret_cast<char const*>(&buf[0]), buf.size() * sizeof(short));
}

void video_us(Song& song, PakFile const& iavFile, PakFile const& indFile, fs::path const& outPath) {
	// Tracks on my example
	// 0 => video (ipu)
	// 1 and 2 => adpcm song (left/right)
	// 3 and 4 => adpcm vocals (left/right)

	std::vector<char> ipudata;
	std::vector<char> data;
	std::vector<char> ind_file;
	indFile.get(ind_file);

	unsigned int iav_offset = 0;
	unsigned int frame = 0;
	for( unsigned int ind_offset = 0x68 ; ind_offset < ind_file.size() ; ind_offset+=2) {
		unsigned int size = getLE16(&ind_file[ind_offset]) << 4;
		switch(frame % 5) {
		case 0:
			// first 4 bytes are packet length
			iavFile.get(data, iav_offset, size);
			{
				unsigned int consumed = 0;
				while(consumed < size) {
					unsigned int opaque_footer_size = 3 * sizeof(int);
					unsigned int chunk = getLE32(&data[consumed]);
					ipudata.insert(ipudata.end(), data.begin() + 4 + consumed, data.begin() + consumed + chunk - opaque_footer_size);
					consumed += chunk;
				}
			}
			iav_offset += size;
			break;
		case 1:
		case 2:
		case 3:
		case 4:
			// audio
			iav_offset += size;
			break;
		}
		frame++;
	}

	IPUConv(ipudata, (outPath / "video.mpg").string(), song.pal);
	song.video = outPath / "video.mpg";
}

void music_us(Song& song, PakFile const& iavFile, PakFile const& indFile, fs::path const& outPath) {
	// Tracks on my example
	// 0 => video (ipu)
	// 1 and 2 => adpcm song (left/right)
	// 3 and 4 => adpcm vocals (left/right)
	// std::cout << "  >>> IAV file size: " << iavFile.size << std::endl;
	// std::cout << "  >>> IND file size: " << indFile.size << std::endl;

	std::vector<char> ind_file;
	indFile.get(ind_file);
	unsigned int sr = getLE32(&ind_file[0x60]);
	// std::cout << "  >>> sample rate: " << sr << std::endl;

	const unsigned decodeChannels = 4; // Do not change!
	Adpcm adpcm(0, decodeChannels);
	std::vector<short> pcm[2];

	bool karaoke = false;
	unsigned int iav_offset = 0;
	unsigned int frame = 0;
	unsigned int video_size, audio_size = 0;
	for( unsigned int ind_offset = 0x68 ; ind_offset < ind_file.size() ; ind_offset+=2) {
		unsigned int size = getLE16(&ind_file[ind_offset]) << 4;
		switch(frame%5) {
			case 0:
				video_size = size;
				iav_offset += video_size;
				break;
			case 1:
				// song left
				audio_size = size;
				break;
			case 2:
				// song right
				audio_size += size;
				break;
			case 3:
				// vocals left
				audio_size += size;
				break;
			case 4:
				// vocals right
				audio_size += size;
				adpcm.interleave(size);
				for (unsigned pos = 0, end; (end = pos + 2 * adpcm.chunkBytes()) <= audio_size; pos = end) {
					std::vector<char> data;
					iavFile.get(data, iav_offset + pos, end - pos);
					std::vector<short> pcmtmp(adpcm.chunkFrames() * decodeChannels);
					adpcm.decodeChunk(&data[0], pcmtmp.begin());
					for (size_t s = 0; s < pcmtmp.size(); s += 4) {
						short l1 = pcmtmp[s];
						short r1 = pcmtmp[s + 1];
						short l2 = pcmtmp[s + 2];
						short r2 = pcmtmp[s + 3];
						pcm[0].push_back(l1);
						pcm[0].push_back(r1);
						pcm[1].push_back(l2);
						pcm[1].push_back(r2);
						if (l2 != 0 || r2 != 0) karaoke = true;
					}
				}
				iav_offset += audio_size;
				break;
		}
		frame++;
	}
	std::string ext;
	writeMusic(song.music = outPath / ("music.wav"), pcm[0], sr);
	if (karaoke) writeMusic(song.vocals = outPath / ("vocals.wav"), pcm[1], sr);
}

void music(Song& song, PakFile const& dataFile, PakFile const& headerFile, fs::path const& outPath) {
	std::vector<char> data;
	headerFile.get(data);
	unsigned sr = getLE16(&data[12]);
	unsigned interleave = getLE16(&data[16]);
	const unsigned decodeChannels = 4; // Do not change!
	Adpcm adpcm(interleave, decodeChannels);
	std::vector<short> pcm[2];
	bool karaoke = false;
	for (unsigned pos = 0, end; (end = pos + 2 * adpcm.chunkBytes()) <= dataFile.size; pos = end) {
		dataFile.get(data, pos, end - pos);
		std::vector<short> pcmtmp(adpcm.chunkFrames() * decodeChannels);
		adpcm.decodeChunk(&data[0], pcmtmp.begin());
		for (size_t s = 0; s < pcmtmp.size(); s += 4) {
			short l1 = pcmtmp[s];
			short r1 = pcmtmp[s + 1];
			short l2 = pcmtmp[s + 2];
			short r2 = pcmtmp[s + 3];
			pcm[0].push_back(l1);
			pcm[0].push_back(r1);
			pcm[1].push_back(l2);
			pcm[1].push_back(r2);
			if (l2 != 0 || r2 != 0) karaoke = true;
		}
	}
	std::string ext;
	writeMusic(song.music = outPath / ("music.wav"), pcm[0], sr);
	if (karaoke) writeMusic(song.vocals = outPath / ("vocals.wav"), pcm[1], sr);
}