Skip to content

Commit 31f4d9d

Browse files
committed
feat: reduce json output size
remove gogo prop if it's falsy
1 parent 5c6a540 commit 31f4d9d

7 files changed

+5965
-11728
lines changed

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "tja"
3-
version = "0.3.1"
3+
version = "0.3.2"
44
edition = "2021"
55
description = "TJA file parser written in Rust, working in Rust, Python, and WebAssembly."
66
license = "MIT"

src/bin/synthesize.rs

+118-50
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,20 @@ struct AudioData {
1818
sample_rate: u32,
1919
}
2020

21+
#[derive(Debug, Clone)]
22+
enum FilteredNoteType {
23+
Don,
24+
Ka,
25+
DrumRoll { duration: f64 },
26+
Balloon { duration: f64 },
27+
}
28+
29+
#[derive(Debug, Clone)]
30+
struct FilteredNote {
31+
note_type: FilteredNoteType,
32+
timestamp: f64,
33+
}
34+
2135
fn main() {
2236
let args: Vec<String> = env::args().collect();
2337
if args.len() < 5 {
@@ -251,11 +265,25 @@ fn merge_audio_files(
251265
ka_data.sample_rate = sample_rate;
252266
}
253267

254-
// Create output buffer with same length as music
255-
let mut output_samples = music_data.samples.clone();
268+
let output_samples = merge_samples(
269+
&music_data.samples,
270+
&don_data.samples,
271+
&ka_data.samples,
272+
sample_rate,
273+
course_data,
274+
branch,
275+
);
276+
277+
// Write output file using the detected sample rate
278+
write_audio_file(output_path, &output_samples, sample_rate)?;
279+
280+
Ok(())
281+
}
282+
283+
fn filter_notes(course_data: &tja::Chart, branch: Option<&str>) -> Vec<FilteredNote> {
284+
let mut filtered_notes = Vec::new();
256285

257-
// Process each segment
258-
for (seg_idx, segment) in course_data.segments.clone().into_iter().enumerate() {
286+
for (seg_idx, segment) in course_data.segments.iter().enumerate() {
259287
// Skip if branch doesn't match
260288
if let Some(branch_name) = branch {
261289
if let Some(segment_branch) = &segment.branch {
@@ -268,11 +296,10 @@ fn merge_audio_files(
268296
let mut i = 0;
269297
while i < segment.notes.len() {
270298
let note = &segment.notes[i];
271-
let sample_pos = (note.timestamp * sample_rate as f64) as usize * 2;
272299

273300
match note.note_type {
274301
NoteType::Roll | NoteType::RollBig | NoteType::Balloon | NoteType::BalloonAlt => {
275-
// Find the corresponding EndOf note by searching through current and subsequent segments
302+
// Find the corresponding EndOf note
276303
let mut end_time: Option<f64> = None;
277304

278305
// Search in current segment first
@@ -286,7 +313,6 @@ fn merge_audio_files(
286313
// If not found in current segment, search in subsequent segments
287314
if end_time.is_none() {
288315
for future_segment in course_data.segments[seg_idx + 1..].iter() {
289-
// Skip segments that don't match the branch if branch is specified
290316
if let Some(branch_name) = branch {
291317
if let Some(segment_branch) = &future_segment.branch {
292318
if segment_branch != branch_name {
@@ -309,25 +335,19 @@ fn merge_audio_files(
309335

310336
if let Some(end_time) = end_time {
311337
let duration = end_time - note.timestamp;
312-
let hits = (duration * 15.0) as usize;
313-
let interval = duration / hits as f64;
314-
315-
for hit in 0..hits {
316-
let hit_time = note.timestamp + (interval * hit as f64);
317-
let hit_pos = (hit_time * sample_rate as f64) as usize * 2;
318-
319-
let volume = if note.gogo { 1.2 } else { 1.0 };
320-
for (j, &sample) in don_data.samples.iter().enumerate() {
321-
if hit_pos + j >= output_samples.len() {
322-
break;
323-
}
324-
output_samples[hit_pos + j] = clamp(
325-
output_samples[hit_pos + j] + (sample * volume),
326-
-1.0,
327-
1.0,
328-
);
338+
let filtered_type = match note.note_type {
339+
NoteType::Roll | NoteType::RollBig => {
340+
FilteredNoteType::DrumRoll { duration }
329341
}
330-
}
342+
NoteType::Balloon | NoteType::BalloonAlt => {
343+
FilteredNoteType::Balloon { duration }
344+
}
345+
_ => unreachable!(),
346+
};
347+
filtered_notes.push(FilteredNote {
348+
note_type: filtered_type,
349+
timestamp: note.timestamp,
350+
});
331351
} else {
332352
eprintln!(
333353
"Warning: No end marker found for roll/balloon starting at {}s",
@@ -336,41 +356,89 @@ fn merge_audio_files(
336356
}
337357
}
338358
NoteType::Don | NoteType::DonBig => {
339-
let volume = if note.gogo { 1.2 } else { 1.0 };
340-
for (j, &sample) in don_data.samples.iter().enumerate() {
341-
if sample_pos + j >= output_samples.len() {
342-
break;
343-
}
344-
output_samples[sample_pos + j] = clamp(
345-
output_samples[sample_pos + j] + (sample * volume),
346-
-1.0,
347-
1.0,
348-
);
349-
}
359+
filtered_notes.push(FilteredNote {
360+
note_type: FilteredNoteType::Don,
361+
timestamp: note.timestamp,
362+
});
350363
}
351364
NoteType::Ka | NoteType::KaBig => {
352-
let volume = if note.gogo { 1.2 } else { 1.0 };
353-
for (j, &sample) in ka_data.samples.iter().enumerate() {
354-
if sample_pos + j >= output_samples.len() {
355-
break;
356-
}
357-
output_samples[sample_pos + j] = clamp(
358-
output_samples[sample_pos + j] + (sample * volume),
359-
-1.0,
360-
1.0,
361-
);
362-
}
365+
filtered_notes.push(FilteredNote {
366+
note_type: FilteredNoteType::Ka,
367+
timestamp: note.timestamp,
368+
});
363369
}
364370
_ => {}
365371
}
366372
i += 1;
367373
}
368374
}
369375

370-
// Write output file using the detected sample rate
371-
write_audio_file(output_path, &output_samples, sample_rate)?;
376+
filtered_notes
377+
}
372378

373-
Ok(())
379+
fn merge_samples(
380+
music_samples: &[f32],
381+
don_samples: &[f32],
382+
ka_samples: &[f32],
383+
sample_rate: u32,
384+
course_data: &tja::Chart,
385+
branch: Option<&str>,
386+
) -> Vec<f32> {
387+
let mut output_samples = music_samples.to_vec();
388+
let filtered_notes = filter_notes(course_data, branch);
389+
390+
for note in filtered_notes {
391+
let sample_pos = (note.timestamp * sample_rate as f64) as usize * 2;
392+
393+
match note.note_type {
394+
FilteredNoteType::DrumRoll { duration } | FilteredNoteType::Balloon { duration } => {
395+
let hits = (duration * 15.0) as usize;
396+
let interval = duration / hits as f64;
397+
398+
for hit in 0..hits {
399+
let hit_time = note.timestamp + (interval * hit as f64);
400+
let hit_pos = (hit_time * sample_rate as f64) as usize * 2;
401+
402+
let volume = 1.0;
403+
for (j, &sample) in don_samples.iter().enumerate() {
404+
if hit_pos + j >= output_samples.len() {
405+
break;
406+
}
407+
output_samples[hit_pos + j] =
408+
clamp(output_samples[hit_pos + j] + (sample * volume), -1.0, 1.0);
409+
}
410+
}
411+
}
412+
FilteredNoteType::Don => {
413+
let volume = 1.0;
414+
for (j, &sample) in don_samples.iter().enumerate() {
415+
if sample_pos + j >= output_samples.len() {
416+
break;
417+
}
418+
output_samples[sample_pos + j] = clamp(
419+
output_samples[sample_pos + j] + (sample * volume),
420+
-1.0,
421+
1.0,
422+
);
423+
}
424+
}
425+
FilteredNoteType::Ka => {
426+
let volume = 1.0;
427+
for (j, &sample) in ka_samples.iter().enumerate() {
428+
if sample_pos + j >= output_samples.len() {
429+
break;
430+
}
431+
output_samples[sample_pos + j] = clamp(
432+
output_samples[sample_pos + j] + (sample * volume),
433+
-1.0,
434+
1.0,
435+
);
436+
}
437+
}
438+
}
439+
}
440+
441+
output_samples
374442
}
375443

376444
fn write_audio_file(

src/python.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ impl From<Chart> for PyChart {
9292
PyChart {
9393
player: chart.player,
9494
course: chart.course.clone().map(|c| format!("{:?}", c)),
95-
level: chart.level(),
95+
level: chart.level.map(|l| l.value()),
9696
balloons: chart.balloons,
9797
headers: chart.headers,
9898
segments: chart.segments.into_iter().map(PySegment::from).collect(),

0 commit comments

Comments
 (0)