Subversion Repositories spk

Rev

Rev 304 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 304 Rev 325
Line 14... Line 14...
14
#ifdef _WIN32
14
#ifdef _WIN32
15
#include <windows.h>
15
#include <windows.h>
16
#include <direct.h>
16
#include <direct.h>
17
#include <shlobj.h>
17
#include <shlobj.h>
18
#endif
18
#endif
-
 
19
 
-
 
20
#include <set>
19
 
21
 
20
#include "sndfile.hh"
22
#include "sndfile.hh"
21
#include "Utils/CommandLine.h"
23
#include "Utils/CommandLine.h"
22
 
24
 
23
 
25
 
24
void PrintSyntax (const Utils::WString &cmd)
26
void PrintSyntax(const Utils::WString& cmd)
25
{	
27
{
26
	wprintf ( L"Syntax: %s </command> [options]\n", cmd.c_str());
28
	wprintf(L"Syntax: %s <command> [options] [arguments]\n", cmd.c_str());
27
	wprintf ( L"\nCommands:\n" );
29
	wprintf(L"Commands:\n");
28
	/*
-
 
29
	printf ( "   /list\n\t- Lists installed packages\n" );
30
	wprintf(L"\toffset [options] <offset> <file> [--out:<file>]\n");
30
	printf ( "   /install <file>\n\t- Installs a package file\n" );
31
	wprintf(L"\t\tEdits the stream xml file to offset the times for a voice page\n");
31
	printf ( &quot;   /uninstall &lt;package#>\n\t- Uninstalls a package, use id number from list\n" );
32
	wprintf(L&quot;\tmerge [--out:<file>][--outxml:<file>] <file.xml> <file.wav> <mergefile.xml> &lt;mergefile.wav>\n");
32
	printf ( "   /enable <package#>\n\t- Enables an installed package\n" );
33
	wprintf(L"\t\tMerges a voice page with xml into another\n");
33
	printf ( "   /disable <package#>\n\t- Disables an installed package\n" );
-
 
34
	printf ( "   /removeuninstall\n\t- Removes uninstall scripts\n" );
34
	wprintf(L"\textract [--stream:<#>] <page> <file.xml> <file.wav> <output>\n");
35
	printf ( "   /removeshared\n\t- Removes unused sharded files\n" );
35
	wprintf(L"\t\tExtracts a voice page from a large file using the XML for timings\n");
36
	printf ( "\nSwitchs:\n" );
-
 
37
	printf ( "   -d (--directory) [directory]\n\tChange destination directory, otherwise uses current\n\n" );
-
 
38
	printf ( "   -v (--verbose)\n\tTurns on verbose mode\n\n" );
36
	wprintf(L"\tcompile [--stream:<#>] <file.xml> <file.wav> <dir>\n");
39
	printf ( "   -o (--override)\n\tOverride install warnings\n\tIE. allows you to install older scripts\n\n" );
-
 
40
	printf ( "   -t (--textrename)\n\tForces text file renaming for installed packages\n\n" );
-
 
41
	printf ( "   -l (--language) <language>\n\tSets the language id for text file renaming\n\totheriwse reads game lang.dat\n\n" );
-
 
42
	printf ( "   -c (--enablechild)\n\tAuto Enabled all children when parent is enabled\n\n" );
-
 
43
	printf ( ";   -m (--forcemod\n\tForces a mod enabled even if theres one already enabled\n\n" );	
37
	wprintf(L";\t\tCompiles a collection of voice files into a larger one and generates the xml file\n");
44
	*/
-
 
45
}
38
}
46
 
39
 
47
void Pause()
40
void Pause()
48
{
41
{
49
#ifdef _DEBUG
42
#ifdef _DEBUG
50
	char pause;
43
	char pause;
51
	scanf ( "%s", &pause );
44
	scanf ( "%s", &pause );
52
#endif
45
#endif
53
}
46
}
54
 
47
 
55
#define BUFFER_LEN 4096
48
#define BUFFER_LEN 4096
56
 
-
 
57
 
49
 
58
void DoOffset(const Utils::CommandLine &cmd)
50
void DoOffset(const Utils::CommandLine &cmd)
59
{
51
{
60
	if (cmd.argCount() < 3)
52
	if (cmd.argCount() < 3)
61
	{
53
	{
Line 105... Line 97...
105
							Utils::WString s = line.substr(pos + 3);
97
							Utils::WString s = line.substr(pos + 3);
106
							s = s.token(L"\"", 1);
98
							s = s.token(L"\"", 1);
107
							long long time = s.toLong64();
99
							long long time = s.toLong64();
108
							long long toTime = time + offset;
100
							long long toTime = time + offset;
109
							line = line.findReplace(time, toTime);
101
							line = line.findReplace(time, toTime);
110
						}
102
						}
111
					}
103
					}
112
 
104
 
113
					if(!ignore || !doIgnore)
105
					if(!ignore || !doIgnore)
114
						outList.pushBack(line);
106
						outList.pushBack(line);
115
 
107
 
116
					if (line.contains(L"</page>"))
108
					if (line.contains(L"</page>"))
117
						ignore = false;
109
						ignore = false;
118
				}
110
				}
119
				CFileIO outFile(outFileStr);
111
				CFileIO outFile(outFileStr);
120
				outFile.writeFile(&outList);
112
				outFile.writeFile(&outList);
121
				outFile.close();
113
				outFile.close();
122
			}
114
			}
123
		}
115
		}
124
		else
116
		else
125
			wprintf(L"Error: Unable to open file, %s\n", fileStr.c_str());
117
			wprintf(L"Error: Unable to open file, %s\n", fileStr.c_str());
126
	}
118
	}
127
 
119
 
128
}
120
}
-
 
121
 
-
 
122
void ExtractPage(int page, int stream, const Utils::WStringList& lines, Utils::WStringList& outLines)
-
 
123
{
-
 
124
	int inPage = 0;
-
 
125
	size_t lowestPos = 0;
-
 
126
	for (auto itr = lines.begin(); itr != lines.end(); itr++)
-
 
127
	{
-
 
128
		Utils::WString line = (*itr)->str;
-
 
129
		if (inPage)
-
 
130
		{
-
 
131
			if (line.contains(L"</page>"))
-
 
132
			{
-
 
133
				inPage = 0;// close the page
-
 
134
				return;
-
 
135
			}
-
 
136
			else if (line.contains(L"<t id="))
-
 
137
				outLines.pushBack(line);
-
 
138
		}
-
 
139
		else if (line.contains(L"<page id=\""))
-
 
140
		{
-
 
141
			long strm = line.between(L" stream=\"", L"\"").toLong();
-
 
142
			if (!stream || strm == stream)
-
 
143
			{
-
 
144
				long id = line.between(L"<page id=\"", L"\"").toLong();
-
 
145
				if (page == id)
-
 
146
					inPage = id;
-
 
147
			}
-
 
148
		}
-
 
149
	}
-
 
150
}
-
 
151
bool ExtractPageTimes(int page, int stream, std::map<int, size_t>& pageIDs, const Utils::WStringList& lines)
-
 
152
{
-
 
153
	int inPage = 0;
-
 
154
	size_t lowestPos = 0;
-
 
155
	for (auto itr = lines.begin(); itr != lines.end(); itr++)
-
 
156
	{
-
 
157
		Utils::WString line = (*itr)->str;
-
 
158
		if (inPage)
-
 
159
		{
-
 
160
			if (line.contains(L"</page>"))
-
 
161
			{
-
 
162
				if (lowestPos)
-
 
163
					pageIDs[inPage] = lowestPos;
-
 
164
				inPage = 0;// close the page
-
 
165
			}
-
 
166
			else if (line.contains(L"<t id="))
-
 
167
			{
-
 
168
				size_t s = static_cast<size_t>(line.between(L" s=\"", L"\"").toLong64());
-
 
169
				if (!lowestPos || s < lowestPos)
-
 
170
					lowestPos = s;
-
 
171
			}
-
 
172
		}
-
 
173
		else if (line.contains(L"<page id=\""))
-
 
174
		{
-
 
175
			long strm = line.between(L" stream=\"", L"\"").toLong();
-
 
176
			if (!stream || strm == stream)
-
 
177
			{
-
 
178
				long id = line.between(L"<page id=\"", L"\"").toLong();
-
 
179
				if (page == 0 || page == id)
-
 
180
					inPage = id;
-
 
181
			}
-
 
182
		}
-
 
183
	}
-
 
184
 
-
 
185
	return true;
-
 
186
}
-
 
187
 
-
 
188
void MergeXML(int id, int stream, long long offset, const Utils::WStringList &in, Utils::WStringList &out)
-
 
189
{
-
 
190
	Utils::WStringList lines;
-
 
191
	ExtractPage(id, 0, in, lines);
-
 
192
	for (auto itr2 = lines.begin(); itr2 != lines.end(); itr2++)
-
 
193
	{
-
 
194
		Utils::WString line2 = (*itr2)->str;
-
 
195
		long long i = line2.between(L" id=\"", L"\"").toLong64();
-
 
196
		long long s = line2.between(L" s=\"", L"\"").toLong64() + offset;
-
 
197
		long long l = line2.between(L" l=\"", L"\"").toLong64();
-
 
198
		out.pushBack(Utils::WString(L"\t<t id=\"") + Utils::WString(i) + L"\" s=\"" + Utils::WString(s) + L"\" l=\"" + Utils::WString(l) + "\"/>");
-
 
199
	}
-
 
200
}
-
 
201
 
-
 
202
void Merge(const Utils::CommandLine& cmd)
-
 
203
{
-
 
204
	if (cmd.argCount() < 5)
-
 
205
	{
-
 
206
		wprintf(L"Syntax: %s merge [--out:<file>][--outxml:<file>] <file.xml> <file.wav> <mergefile.xml> <mergefile.wav>\n", cmd.cmdName().c_str());
-
 
207
		wprintf(L"	<file.wav>\t\tThe main wav file to merge into\n");
-
 
208
		wprintf(L"	<file.xml>\t\tThe main xml file to merge into\n");
-
 
209
		wprintf(L"	<mergefile.wav>\t\tThe wav file to merge\n");
-
 
210
		wprintf(L"	<mergefile.xml>\t\tThe xml file to merge\n");
-
 
211
		wprintf(L"\nOptions:\n");
-
 
212
		wprintf(L"	--out:<file>\t\tOptional output wav file, otherwise will write over the input\n");
-
 
213
		wprintf(L"	--outxml:<file>\t\tOptional output xml file, otherwise will write over the input\n");
-
 
214
		wprintf(L"	--stream:<#>\t\tThe stream id to write too\n");
-
 
215
		wprintf(L"	--page:<#>\t\tThe page id to merge\n");
-
 
216
	}
-
 
217
	else
-
 
218
	{
-
 
219
		Utils::WString xmlfile = cmd.fullFilename(cmd.arg(1));
-
 
220
		Utils::WString wavfile = cmd.fullFilename(cmd.arg(2));
-
 
221
		Utils::WString mergexmlfile = cmd.fullFilename(cmd.arg(3));
-
 
222
		Utils::WString mergewavfile = cmd.fullFilename(cmd.arg(4));
-
 
223
		Utils::WString outwavefile = cmd.hasSwitch(L"out") ? cmd.fullFilename(cmd.switchData(L"out")) : wavfile;
-
 
224
		int stream = cmd.hasSwitch(L"stream") ? cmd.switchData(L"stream").toInt() : 3;
-
 
225
		int page = cmd.hasSwitch(L"page") ? cmd.switchData(L"page").toInt() : 0;
-
 
226
 
-
 
227
		if (!CFileIO(wavfile).exists())
-
 
228
		{
-
 
229
			wprintf(L"Error: Unable to open wav file, %s\n", wavfile.c_str());
-
 
230
			return;
-
 
231
		}
-
 
232
		if (!CFileIO(mergewavfile).exists())
-
 
233
		{
-
 
234
			wprintf(L"Error: Unable to open wav file, %s\n", mergewavfile.c_str());
-
 
235
			return;
-
 
236
		}
-
 
237
		CFileIO xml(xmlfile);
-
 
238
		if (!xml.exists())
-
 
239
		{
-
 
240
			wprintf(L"Error: Unable to open xml file, %s\n", xmlfile.c_str());
-
 
241
			return;
-
 
242
		}
-
 
243
 
-
 
244
		Utils::WStringList xmlLines;
-
 
245
		if (!xml.readLines(xmlLines))
-
 
246
		{
-
 
247
			wprintf(L"Error: Unable to read xml file, %s\n", xmlfile.c_str());
-
 
248
			return;
-
 
249
		}
-
 
250
 
-
 
251
		CFileIO mergexml(mergexmlfile);
-
 
252
		if (!mergexml.exists())
-
 
253
		{
-
 
254
			wprintf(L"Error: Unable to open xml file, %s\n", mergexmlfile.c_str());
-
 
255
			return;
-
 
256
		}
-
 
257
 
-
 
258
		Utils::WStringList mergeXmlLines;
-
 
259
		if (!mergexml.readLines(mergeXmlLines))
-
 
260
		{
-
 
261
			wprintf(L"Error: Unable to read xml file, %s\n", mergexmlfile.c_str());
-
 
262
			return;
-
 
263
		}
-
 
264
 
-
 
265
		bool overwrite = (wavfile.Compare(outwavefile));
-
 
266
 
-
 
267
		int sampleRate = 44100;
-
 
268
		{
-
 
269
			SF_INFO inInfo;
-
 
270
			SNDFILE* inputFile = sf_open(wavfile.toFileUTF8().c_str(), SFM_READ, &inInfo);
-
 
271
			if (inputFile)
-
 
272
			{
-
 
273
				sampleRate = inInfo.samplerate;
-
 
274
				sf_close(inputFile);
-
 
275
			}
-
 
276
		}
-
 
277
 
-
 
278
		SF_INFO outInfo;
-
 
279
		outInfo.channels = 1;
-
 
280
		outInfo.samplerate = sampleRate;
-
 
281
		outInfo.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
-
 
282
		SNDFILE* outputFile = sf_open(outwavefile.toStdString().c_str(), overwrite ? SFM_RDWR : SFM_WRITE, &outInfo);
-
 
283
		if (outputFile)
-
 
284
		{
-
 
285
			double buffer[BUFFER_LEN];
-
 
286
			size_t currentPos = 0;
-
 
287
 
-
 
288
			// seek to end of file
-
 
289
			int check = sf_format_check(&outInfo);
-
 
290
			sf_count_t seek = sf_seek(outputFile, 0, SEEK_END);
-
 
291
 
-
 
292
			// if output file is different, then we need to copy the data
-
 
293
			if (!overwrite)
-
 
294
			{
-
 
295
				SF_INFO inInfo;
-
 
296
				SNDFILE* inputFile = sf_open(wavfile.toFileUTF8().c_str(), SFM_READ, &inInfo);
-
 
297
				if (inputFile)
-
 
298
				{
-
 
299
					double duration = static_cast<double>(inInfo.frames) / static_cast<double>(inInfo.samplerate);
-
 
300
					size_t len = static_cast<size_t>((duration * 1000.0) + 0.5);
-
 
301
					sf_count_t readcount;
-
 
302
					while ((readcount = sf_read_double(inputFile, buffer, BUFFER_LEN)) > 0)
-
 
303
						sf_write_double(outputFile, buffer, readcount);
-
 
304
					sf_close(inputFile);
-
 
305
					currentPos += len;
-
 
306
				}
-
 
307
			}
-
 
308
			else
-
 
309
				currentPos += static_cast<size_t>((static_cast<double>(outInfo.frames) / static_cast<double>(outInfo.samplerate) * 1000.0) + 0.5);
-
 
310
 
-
 
311
			size_t startPos = currentPos;
-
 
312
 
-
 
313
			// now we need to merge the wav file
-
 
314
			{
-
 
315
				SF_INFO inInfo;
-
 
316
				SNDFILE* inputFile = sf_open(mergewavfile.toFileUTF8().c_str(), SFM_READ, &inInfo);
-
 
317
				if (inputFile)
-
 
318
				{
-
 
319
					double duration = static_cast<double>(inInfo.frames) / static_cast<double>(inInfo.samplerate);
-
 
320
					size_t len = static_cast<size_t>((duration * 1000.0) + 0.5);
-
 
321
					sf_count_t readcount;
-
 
322
					while ((readcount = sf_read_double(inputFile, buffer, BUFFER_LEN)) > 0)
-
 
323
						sf_write_double(outputFile, buffer, readcount);
-
 
324
					sf_close(inputFile);
-
 
325
					currentPos += len;
-
 
326
				}
-
 
327
			}
-
 
328
			sf_close(outputFile);
-
 
329
 
-
 
330
			// finally, we need to generate the new xml file
-
 
331
			Utils::WString outxmlfile = cmd.hasSwitch(L"outxml") ? cmd.fullFilename(cmd.switchData(L"outxml")) : xmlfile;
-
 
332
			Utils::WStringList outXmlLines;
-
 
333
 
-
 
334
			// extract the pages we need to merge
-
 
335
			std::map<int, size_t> pageIDs;
-
 
336
			ExtractPageTimes(page, 0, pageIDs, mergeXmlLines);
-
 
337
 
-
 
338
			// write the new xml file
-
 
339
			for (auto itr = xmlLines.begin(); itr != xmlLines.end(); itr++)
-
 
340
			{
-
 
341
				Utils::WString line = (*itr)->str;
-
 
342
				if (line.contains(L"<page id=\""))
-
 
343
				{
-
 
344
					long id = line.between(L"<page id=\"", L"\"").toLong();
-
 
345
					auto findItr = pageIDs.find(id);
-
 
346
					if (findItr != pageIDs.end())
-
 
347
					{
-
 
348
						long strm = line.between(L"stream=\"", L"\"").toLong();
-
 
349
						if (strm == stream)
-
 
350
						{
-
 
351
							// add the page line
-
 
352
							outXmlLines.pushBack(line);
-
 
353
 
-
 
354
							// add all the new lines
-
 
355
							MergeXML(id, stream, static_cast<long long>(startPos) - static_cast<long long>(findItr->second), mergeXmlLines, outXmlLines);
-
 
356
							pageIDs.erase(findItr);
-
 
357
							continue;
-
 
358
						}
-
 
359
					}
-
 
360
				}
-
 
361
				else if (line.contains(L"</language>"))
-
 
362
				{
-
 
363
					// now we need to add the new lines
-
 
364
					for (auto itr = pageIDs.begin(); itr != pageIDs.end(); itr++)
-
 
365
					{
-
 
366
						// add the page line
-
 
367
						Utils::WString line = Utils::WString(L"<page id=\"") + (long)itr->first + L"\" stream=\"" + (long)stream + L"\">";
-
 
368
						outXmlLines.pushBack(line);
-
 
369
						// add all the new lines
-
 
370
						MergeXML(itr->first, stream, static_cast<long long>(startPos) - static_cast<long long>(itr->second), mergeXmlLines, outXmlLines);
-
 
371
						outXmlLines.pushBack(L"</page>");
-
 
372
					}
-
 
373
				}
-
 
374
 
-
 
375
				// add the line
-
 
376
				outXmlLines.pushBack(line);
-
 
377
			}
-
 
378
 
-
 
379
			CFileIO outFile(outxmlfile);
-
 
380
			bool write = outFile.writeFile(&outXmlLines);
-
 
381
 
-
 
382
			if (!cmd.hasSwitch(L"quiet"))
-
 
383
			{
-
 
384
				if(write)
-
 
385
					wprintf(L"Output XML file, %s, created\n", outxmlfile.c_str());
-
 
386
				else
-
 
387
					wprintf(L"Error: Unable to write XML file, %s\n", outxmlfile.c_str());
-
 
388
			}
-
 
389
			if (write && cmd.hasSwitch(L"showresult"))
-
 
390
				wprintf(L"Merged %s into %s at %lldms for page %d\n", CFileIO(mergewavfile).filename().c_str(), CFileIO(outwavefile).filename().c_str(), startPos, page);
-
 
391
		}
-
 
392
	}
-
 
393
}
-
 
394
 
-
 
395
void Extract(const Utils::CommandLine& cmd)
-
 
396
{
-
 
397
	if (cmd.argCount() < 5)
-
 
398
	{
-
 
399
		wprintf(L"Syntax: %s extract [--stream:<#>] <page> <file.xml> <file.wav> <output>\n", cmd.cmdName().c_str());
-
 
400
		wprintf(L"	<page>\t\tThe page id to extract\n");
-
 
401
		wprintf(L"	<file.wav>\t\tThe main wav file to extract from\n");
-
 
402
		wprintf(L"	<file.xml>\t\tThe main xml file to read timings from\n");
-
 
403
		wprintf(L"	<output>\t\tThe output wav file to create\n");
-
 
404
		wprintf(L"\nOptions:\n");
-
 
405
		wprintf(L"	--stream:<#>\t\tThe stream id to write too\n");
-
 
406
		return;
-
 
407
	}
-
 
408
 
-
 
409
	bool quiet = cmd.hasSwitch(L"quiet");
-
 
410
	bool verbose = cmd.hasSwitch(L"verbose");
-
 
411
 
-
 
412
	Utils::WString xmlfile = cmd.fullFilename(cmd.arg(2));
-
 
413
	Utils::WString wavfile = cmd.fullFilename(cmd.arg(3));
-
 
414
	Utils::WString outputfile = cmd.fullFilename(cmd.arg(4));
-
 
415
	int stream = cmd.hasSwitch(L"stream") ? cmd.switchData(L"stream").toInt() : 0;
-
 
416
	int page = cmd.arg(1).toInt();
-
 
417
 
-
 
418
	if (page <= 0)
-
 
419
	{
-
 
420
		wprintf(L"Error: Invalid page id, %s\n", cmd.arg(1).c_str());
-
 
421
		return;
-
 
422
	}
-
 
423
	if (!CFileIO(wavfile).exists())
-
 
424
	{
-
 
425
		wprintf(L"Error: Unable to open wav file, %s\n", wavfile.c_str());
-
 
426
		return;
-
 
427
	}
-
 
428
	CFileIO xml(xmlfile);
-
 
429
	if (!xml.exists())
-
 
430
	{
-
 
431
		wprintf(L"Error: Unable to open xml file, %s\n", xmlfile.c_str());
-
 
432
		return;
-
 
433
	}
-
 
434
 
-
 
435
	Utils::WStringList xmlLines;
-
 
436
	if (!xml.readLines(xmlLines))
-
 
437
	{
-
 
438
		wprintf(L"Error: Unable to read xml file, %s\n", xmlfile.c_str());
-
 
439
		return;
-
 
440
	}
-
 
441
 
-
 
442
	// find the timings for the page
-
 
443
	Utils::WStringList outLines;
-
 
444
	ExtractPage(page, stream, xmlLines, outLines);
-
 
445
 
-
 
446
	if (outLines.size() == 0)
-
 
447
	{
-
 
448
		wprintf(L"Error: Unable to find page id, %d\n", page);
-
 
449
		return;
-
 
450
	}
-
 
451
 
-
 
452
	long long startPos = outLines.front().between(L" s=\"", L"\"").toLong64();
-
 
453
	long long endPos = outLines.back().between(L" s=\"", L"\"").toLong64() + outLines.back().between(L" l=\"", L"\"").toLong64();
-
 
454
	long long length = endPos - startPos;
-
 
455
 
-
 
456
	SF_INFO inInfo;
-
 
457
	SNDFILE* inputFile = sf_open(wavfile.toFileUTF8().c_str(), SFM_READ, &inInfo);
-
 
458
	if (!inputFile)
-
 
459
	{
-
 
460
		wprintf(L"Error: Unable to open wav file, %s\n", wavfile.c_str());
-
 
461
		return;
-
 
462
	}
-
 
463
	int sampleRate = inInfo.samplerate;
-
 
464
 
-
 
465
	if (verbose)
-
 
466
	{
-
 
467
		wprintf(L"Extracting page %d from %s to %s\n", page, CFileIO(wavfile).filename().c_str(), CFileIO(outputfile).filename().c_str());
-
 
468
		wprintf(L"\tStart Time: \t%lld\n", startPos);
-
 
469
		wprintf(L"\tEnd Time: \t%lld\n", endPos);
-
 
470
		wprintf(L"\tLength: \t%lld\n", length);
-
 
471
	}
-
 
472
 
-
 
473
	long long startFrame = static_cast<long long>((static_cast<double>(startPos) / 1000.0) * sampleRate);
-
 
474
	sf_count_t seek = sf_seek(inputFile, startFrame, SEEK_SET);
-
 
475
 
-
 
476
	SF_INFO outInfo;
-
 
477
	outInfo.channels = 1;
-
 
478
	outInfo.samplerate = sampleRate;
-
 
479
	outInfo.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
-
 
480
	SNDFILE* outputFile = sf_open(outputfile.toFileUTF8().c_str(), SFM_WRITE, &outInfo);
-
 
481
	if (outputFile)
-
 
482
	{
-
 
483
		double buffer[BUFFER_LEN];
-
 
484
		long long endFrame = static_cast<long long>((static_cast<double>(endPos) / 1000.0) * sampleRate);
-
 
485
 
-
 
486
		long long readRemaining = endFrame - startFrame;
-
 
487
		while (readRemaining > 0)
-
 
488
		{
-
 
489
			long long readAmount = readRemaining > BUFFER_LEN ? BUFFER_LEN : readRemaining;
-
 
490
			sf_count_t readcount = sf_read_double(inputFile, buffer, readAmount);
-
 
491
			sf_write_double(outputFile, buffer, readcount);
-
 
492
 
-
 
493
			readRemaining -= readcount;
-
 
494
		}
-
 
495
 
-
 
496
		sf_close(outputFile);
-
 
497
	}
-
 
498
 
-
 
499
	sf_close(inputFile);
-
 
500
 
-
 
501
	if (!quiet || cmd.hasSwitch(L"showresult"))
-
 
502
		wprintf(L"Extracted %lldms from page %d to %s\n", length, page, CFileIO(outputfile).filename().c_str());
-
 
503
}
-
 
504
 
-
 
505
void Split(const Utils::CommandLine& cmd)
-
 
506
{
-
 
507
 
-
 
508
}
-
 
509
 
-
 
510
 
-
 
511
void Compile(const Utils::CommandLine& cmd)
-
 
512
{
-
 
513
	if (cmd.argCount() < 4)
-
 
514
	{
-
 
515
		wprintf(L"Syntax: %s compile [--stream:<#>] <file.xml> <file.wav> <dir>\n", cmd.cmdName().c_str());
-
 
516
		wprintf(L"\t<file.wav>\tThe main wav file to merge into\n");
-
 
517
		wprintf(L"\t<file.xml>\tThe main xml file to merge into\n");
-
 
518
		wprintf(L"\t<dir>\t\tThe directory containing voice files\n");
-
 
519
		wprintf(L"\nOptions:\n");
-
 
520
		wprintf(L"	--stream:<#>\tThe stream id to write too\n");
-
 
521
		return;
-
 
522
	}
-
 
523
 
-
 
524
	bool quiet = cmd.hasSwitch(L"quiet");
-
 
525
	bool verbose = cmd.hasSwitch(L"verbose");
-
 
526
	bool verboseresult = cmd.hasSwitch(L"verboseresult");
-
 
527
 
-
 
528
	Utils::WString xmlfile = cmd.fullFilename(cmd.arg(1));
-
 
529
	Utils::WString wavfile = cmd.fullFilename(cmd.arg(2));
-
 
530
	Utils::WString dir = cmd.fullFilename(cmd.arg(3));
-
 
531
	int stream = cmd.hasSwitch(L"stream") ? cmd.switchData(L"stream").toInt() : 3;
-
 
532
 
-
 
533
	if (!CFileIO(wavfile).exists())
-
 
534
	{
-
 
535
		wprintf(L"Error: Unable to open wav file, %s\n", wavfile.c_str());
-
 
536
		return;
-
 
537
	}
-
 
538
	CFileIO xml(xmlfile);
-
 
539
	if (!xml.exists())
-
 
540
	{
-
 
541
		wprintf(L"Error: Unable to open xml file, %s\n", xmlfile.c_str());
-
 
542
		return;
-
 
543
	}
-
 
544
 
-
 
545
	Utils::WStringList xmlLines;
-
 
546
	if (!xml.readLines(xmlLines))
-
 
547
	{
-
 
548
		wprintf(L"Error: Unable to read xml file, %s\n", xmlfile.c_str());
-
 
549
		return;
-
 
550
	}
-
 
551
 
-
 
552
 
-
 
553
	SF_INFO info;
-
 
554
	SNDFILE* mainFile = sf_open(wavfile.toFileUTF8().c_str(), SFM_RDWR, &info);
-
 
555
	if (mainFile)
-
 
556
	{
-
 
557
		Utils::WStringList addLines;
-
 
558
 
-
 
559
		// compute the current position
-
 
560
		double duration = static_cast<double>(info.frames) / static_cast<double>(info.samplerate);
-
 
561
		size_t currentPos = static_cast<size_t>((duration * 1000.0) + 0.5);
-
 
562
 
-
 
563
		// seek to end of file
-
 
564
		int check = sf_format_check(&info);
-
 
565
		sf_count_t seek = sf_seek(mainFile, 0, SEEK_END);
-
 
566
 
-
 
567
		double buffer[BUFFER_LEN];
-
 
568
 
-
 
569
		// get all files from directory
-
 
570
		CDirIO D(dir);
-
 
571
		Utils::WStringList list;
-
 
572
		if (D.dirList(list))
-
 
573
		{
-
 
574
			for (auto itr = list.begin(); itr != list.end(); itr++)
-
 
575
			{
-
 
576
				if (D.isDir((*itr)->str))
-
 
577
				{
-
 
578
					CDirIO curDir(D.dir((*itr)->str));
-
 
579
					long pageID = (*itr)->str.toInt();
-
 
580
 
-
 
581
					addLines.pushBack(Utils::WString(L"<page id=\"") + pageID + L"\" stream=\"" + (long)stream + L"\">");
-
 
582
 
-
 
583
					Utils::WStringList idList;
-
 
584
					if (curDir.dirList(idList))
-
 
585
					{
-
 
586
						for (auto itr2 = idList.begin(); itr2 != idList.end(); itr2++)
-
 
587
						{
-
 
588
							if (curDir.isFile((*itr2)->str))
-
 
589
							{
-
 
590
								CFileIO F(curDir.file((*itr2)->str));
-
 
591
								long id = F.baseName().toInt();
-
 
592
								size_t len = 0;
-
 
593
 
-
 
594
								SF_INFO inInfo;
-
 
595
								SNDFILE* inputFile = sf_open(F.fullFilename().toFileUTF8().c_str(), SFM_READ, &inInfo);
-
 
596
								if (inputFile)
-
 
597
								{
-
 
598
									if (inInfo.samplerate != info.samplerate)
-
 
599
										wprintf(L"Error: Sample rate mismatch, %d:%s (%d) != (%d)\n", pageID, F.filename().c_str(), info.samplerate, inInfo.samplerate);
-
 
600
									else
-
 
601
									{
-
 
602
										double duration = static_cast<double>(inInfo.frames) / static_cast<double>(inInfo.samplerate);
-
 
603
										size_t len = static_cast<size_t>((duration * 1000.0) + 0.5);
-
 
604
 
-
 
605
										sf_count_t readcount;
-
 
606
										while ((readcount = sf_read_double(inputFile, buffer, BUFFER_LEN)) > 0)
-
 
607
											sf_write_double(mainFile, buffer, readcount);
-
 
608
										//int* data = new int[inInfo.frames * inInfo.channels];
-
 
609
										//sf_count_t readCount = sf_readf_int(inputFile, data, inInfo.frames);
-
 
610
										//sf_count_t writeCount = sf_writef_int(outputFile, data, inInfo.frames);
-
 
611
 
-
 
612
										addLines.pushBack(Utils::WString(L"\t<t id=\"") + id + L"\" s=\"" + (long)currentPos + L"\" l=\"" + (long)len + "\"/>");
-
 
613
 
-
 
614
										if(verbose || verboseresult)
-
 
615
											wprintf(L"Writing %d:%s to %s at %lldms\n", pageID, F.filename().c_str(), CFileIO(wavfile).filename().c_str(), currentPos);
-
 
616
 
-
 
617
										currentPos += len;
-
 
618
									}
-
 
619
									sf_close(inputFile);
-
 
620
								}
-
 
621
							}
-
 
622
						}
-
 
623
					}
-
 
624
 
-
 
625
					addLines.pushBack(L"</page>");
-
 
626
				}
-
 
627
			}
-
 
628
 
-
 
629
			// merge the xml file
-
 
630
			Utils::WStringList outLines;
-
 
631
			for (auto itr = xmlLines.begin(); itr != xmlLines.end(); itr++)
-
 
632
			{
-
 
633
				Utils::WString line = (*itr)->str;
-
 
634
				if (line.contains(L"</language>"))
-
 
635
				{
-
 
636
					// now we need to add the new lines
-
 
637
					for (auto itr2 = addLines.begin(); itr2 != addLines.end(); itr2++)
-
 
638
						outLines.pushBack((*itr2)->str);
-
 
639
				}
-
 
640
 
-
 
641
				outLines.pushBack(line);
-
 
642
			}
-
 
643
 
-
 
644
			CFileIO xml(xmlfile);
-
 
645
			xml.writeFile(&outLines);
-
 
646
		}
-
 
647
 
-
 
648
		sf_close(mainFile);
-
 
649
 
-
 
650
		if (!quiet || cmd.hasSwitch(L"showresult"))
-
 
651
		{
-
 
652
			wprintf(L"\nCompiled %s into %s\n", CFileIO(dir).filename().c_str(), CFileIO(wavfile).filename().c_str());
-
 
653
			if (verbose)
-
 
654
			{
-
 
655
				wprintf(L"\tLength: \t%lldms\n", currentPos);
-
 
656
				wprintf(L"\tStream file: \t%s\n", CFileIO(xmlfile).filename().c_str());
-
 
657
			}
-
 
658
		}
-
 
659
	}
-
 
660
 
-
 
661
}
-
 
662
 
129
 
663
 
130
/*
664
/*
131
	Main entry point to program
665
	Main entry point to program
132
*/
666
*/
133
int main ( int argc, char **argv )
667
int main ( int argc, char **argv )
134
{
668
{
135
 	// display program header to command prompt
-
 
136
	printf ( "\nX3 Voice Create V1.00 (SPK Library Version %.2f) 15/12/2023 Created by Cycrow\n\n", GetLibraryVersion() );
-
 
137
 
669
 
138
	Utils::CommandLine cmd(argc, argv);
670
	Utils::CommandLine cmd(argc, argv);
139
	Utils::WString command = cmd.argCount() >= 1 ? cmd.arg(0) : L"";
671
	Utils::WString command = cmd.argCount() >= 1 ? cmd.arg(0) : L"";
-
 
672
	command.toLower();
-
 
673
 
-
 
674
	// display program header to command prompt
-
 
675
	if(!cmd.hasSwitch(L"quiet"))
-
 
676
		printf("\nX3 Voice Create V1.10 (SPK Library Version %.2f) 18/05/2025 Created by Cycrow\n\n", GetLibraryVersion());
140
 
677
 
141
	if (command == L"offset")
678
	if (command == L"offset")
142
		DoOffset(cmd);
679
		DoOffset(cmd);
143
	else if (command == L"help")
680
	else if (command == L"help")
144
		PrintSyntax(cmd.cmdName());
681
		PrintSyntax(cmd.cmdName());
-
 
682
	else if (command == L"merge")
-
 
683
		Merge(cmd);
-
 
684
	else if (command == L"extract")
-
 
685
		Extract(cmd);
-
 
686
	else if (command == L"split")
-
 
687
		Split(cmd);
-
 
688
	else if (command == L"compile")
-
 
689
		Compile(cmd);
145
	else
690
	else
146
	{
-
 
147
 
-
 
148
		Utils::String mainFileStr = "d:/x/X3 Terran Conflict - Guilds/addon2/mov/00344.wav";
-
 
149
		Utils::WString dir = L"d:/x/X3 Terran Conflict - Guilds/addon2/mov/working";
-
 
150
		Utils::String output = "d:/x/X3 Terran Conflict - Guilds/addon2/mov/working/00344.wav";
-
 
151
		Utils::WString outputXML = L"d:/x/X3 Terran Conflict - Guilds/addon2/mov/working/00044.xml";
-
 
152
 
-
 
153
		SF_INFO info;
-
 
154
		SNDFILE* mainFile = sf_open(mainFileStr.c_str(), SFM_READ, &info);
-
 
155
		if (mainFile)
-
 
156
		{
-
 
157
			double duration = static_cast<double>(info.frames) / static_cast<double>(info.samplerate);
-
 
158
			size_t currentPos = static_cast<size_t>((duration * 1000.0) + 0.5);
-
 
159
 
-
 
160
			CFileIO(mainFileStr).copy(output);
-
 
161
 
-
 
162
 
-
 
163
			SF_INFO outInfo;
-
 
164
			SNDFILE* outputFile = sf_open(output.c_str(), SFM_RDWR, &outInfo);
-
 
165
			if (outputFile)
-
 
166
			{
-
 
167
				double buffer[BUFFER_LEN];
-
 
168
 
-
 
169
				int check = sf_format_check(&outInfo);
-
 
170
				sf_count_t seek = sf_seek(outputFile, 0, SEEK_END);
-
 
171
 
-
 
172
				Utils::WStringList xmlOut;
-
 
173
				xmlOut.pushBack(L"<?xml version=\"1.0\" ?>");
-
 
174
				xmlOut.pushBack(L"<language id=\"44\">");
-
 
175
 
-
 
176
				CDirIO D(dir);
-
 
177
				Utils::WStringList list;
-
 
178
				if (D.dirList(list))
-
 
179
				{
-
 
180
					for (auto itr = list.begin(); itr != list.end(); itr++)
-
 
181
					{
-
 
182
						if (D.isDir((*itr)->str))
-
 
183
						{
-
 
184
							CDirIO curDir(D.dir((*itr)->str));
-
 
185
							long pageID = (*itr)->str.toInt();
-
 
186
 
-
 
187
							xmlOut.pushBack(Utils::WString(L"<page id=\"") + pageID + L"\" stream=\"3\">");
-
 
188
 
-
 
189
							Utils::WStringList idList;
-
 
190
							if (curDir.dirList(idList))
-
 
191
							{
-
 
192
								for (auto itr2 = idList.begin(); itr2 != idList.end(); itr2++)
-
 
193
								{
-
 
194
									if (curDir.isFile((*itr2)->str))
-
 
195
									{
-
 
196
										CFileIO F(curDir.file((*itr2)->str));
-
 
197
										long id = F.baseName().toInt();
-
 
198
										size_t len = 0;
-
 
199
 
-
 
200
										SF_INFO inInfo;
-
 
201
										SNDFILE* inputFile = sf_open(F.fullFilename().toString().c_str(), SFM_READ, &inInfo);
-
 
202
										if (inputFile)
-
 
203
										{
-
 
204
											double duration = static_cast<double>(inInfo.frames) / static_cast<double>(inInfo.samplerate);
-
 
205
											size_t len = static_cast<size_t>((duration * 1000.0) + 0.5);
-
 
206
 
-
 
207
 
-
 
208
											sf_count_t readcount;
-
 
209
											while ((readcount = sf_read_double(inputFile, buffer, BUFFER_LEN)) > 0)
-
 
210
												sf_write_double(outputFile, buffer, readcount);
-
 
211
											//int* data = new int[inInfo.frames * inInfo.channels];
-
 
212
											//sf_count_t readCount = sf_readf_int(inputFile, data, inInfo.frames);
-
 
213
											//sf_count_t writeCount = sf_writef_int(outputFile, data, inInfo.frames);
-
 
214
 
-
 
215
											xmlOut.pushBack(Utils::WString(L"\t<t id=\"") + id + L"\" s=\"" + (long)currentPos + L"\" l=\"" + (long)len + "\"/>");
-
 
216
											currentPos += len;
-
 
217
											sf_close(inputFile);
-
 
218
										}
-
 
219
									}
-
 
220
								}
-
 
221
							}
-
 
222
 
-
 
223
							xmlOut.pushBack(L"</page>");
-
 
224
						}
-
 
225
					}
-
 
226
				}
-
 
227
 
-
 
228
				xmlOut.pushBack("</language>");
691
		PrintSyntax(cmd.cmdName());
229
 
-
 
230
				sf_close(outputFile);
-
 
231
 
-
 
232
				CFileIO xml(outputXML);
-
 
233
				xml.writeFile(&xmlOut);
-
 
234
			}
-
 
235
 
-
 
236
			sf_close(mainFile);
-
 
237
		}
-
 
238
	}
-
 
239
	//Pause();
-
 
240
 
692
 
241
	return 0;
693
	return 0;
242
}
694
}