pub struct SmFile {
pub metadata: Metadata,
pub offset: f64,
pub bpms: Vec<(f64, f64)>,
pub stops: Vec<(f64, f64)>,
pub charts: Vec<Chart>,
}Fields§
§metadata: Metadata§offset: f64§bpms: Vec<(f64, f64)>§stops: Vec<(f64, f64)>§charts: Vec<Chart>Implementations§
Source§impl SmFile
impl SmFile
Sourcepub fn from_file(path: PathBuf) -> Result<SmFile, String>
pub fn from_file(path: PathBuf) -> Result<SmFile, String>
Examples found in repository?
examples/to_osu.rs (line 12)
6fn main() {
7 // Load MEGALOVANIA.sm file
8 let sm_path = PathBuf::from("assets/MEGALOVANIA.sm");
9
10 println!("Loading SM file: {:?}", sm_path);
11
12 let sm_file = match SmFile::from_file(sm_path) {
13 Ok(file) => file,
14 Err(e) => {
15 eprintln!("Error loading SM file: {}", e);
16 std::process::exit(1);
17 }
18 };
19 println!("Offset: {}", sm_file.offset);
20 println!("Loaded {} chart(s)", sm_file.charts.len());
21
22 // Convert each chart to .osu format
23 for (chart_idx, chart) in sm_file.charts.iter().enumerate() {
24 println!("\nConverting chart {}: {} ({})",
25 chart_idx + 1,
26 chart.difficulty.trim_end_matches(':'),
27 chart.stepstype.trim_end_matches(':')
28 );
29
30 // Create OsuSettings (you can adjust these values)
31 let settings = OsuSettings {
32 hp: 5.0, // HP Drain Rate
33 od: 8.0, // Overall Difficulty
34 };
35
36 // Convert to .osu format
37 match create_basic_osu(&sm_file, chart, &settings) {
38 Ok(osu_content) => {
39 // Generate output filename
40 let difficulty_name = chart.difficulty.trim_end_matches(':');
41 let sanitized_name = difficulty_name
42 .chars()
43 .map(|c| if c.is_alphanumeric() || c == '-' || c == '_' { c } else { '_' })
44 .collect::<String>();
45
46 let output_path = format!("output/MEGALOVANIA_{}.osu", sanitized_name);
47
48 // Create output directory if it doesn't exist
49 if let Some(parent) = PathBuf::from(&output_path).parent() {
50 fs::create_dir_all(parent).expect("Failed to create output directory");
51 }
52
53 // Write .osu file
54 fs::write(&output_path, osu_content)
55 .expect("Failed to write .osu file");
56
57 println!(" ✓ Saved to: {}", output_path);
58 }
59 Err(e) => {
60 eprintln!(" ✗ Error converting chart: {}", e);
61 }
62 }
63 }
64
65 println!("\nConversion complete!");
66}More examples
examples/load_sm.rs (line 10)
4fn main() {
5 // Load a .sm file
6 let path = PathBuf::from("assets/MEGALOVANIA.sm");
7
8 println!("Loading file: {:?}", path);
9
10 match SmFile::from_file(path) {
11 Ok(sm_file) => {
12 println!("\n=== METADATA ===");
13 println!("Title: {}", sm_file.metadata.title);
14 println!("Artist: {}", sm_file.metadata.artist);
15 println!("Subtitle: {}", sm_file.metadata.subtitle);
16 println!("Offset: {}", sm_file.offset);
17
18 println!("\n=== BPMS ===");
19 for (beat, bpm) in &sm_file.bpms {
20 println!(" Beat {}: {} BPM", beat, bpm);
21 }
22
23 println!("\n=== STOPS ===");
24 for (beat, duration) in &sm_file.stops {
25 println!(" Beat {}: {} seconds", beat, duration);
26 }
27
28 println!("\n=== CHARTS ===");
29 println!("Number of charts: {}", sm_file.charts.len());
30
31 for (chart_idx, chart) in sm_file.charts.iter().enumerate() {
32 println!("\n--- Chart {} ---", chart_idx + 1);
33 println!("Stepstype: {}", chart.stepstype);
34 println!("Difficulty: {}", chart.difficulty);
35 println!("Meter: {}", chart.meter);
36 println!("Number of measures: {}", chart.measures.len());
37
38 // Print last measure to check total duration
39 if let Some(last_measure) = chart.measures.last() {
40 if let Some(last_beat) = last_measure.beats.last() {
41 let total_duration_sec = last_beat.time / 1000.0;
42 println!("Last beat time: {:.2} ms ({:.2} seconds / {:.2} minutes)",
43 last_beat.time, total_duration_sec, total_duration_sec / 60.0);
44 } else if !chart.measures.is_empty() {
45 // Empty measure - calculate from start_time
46 let total_duration_sec = last_measure.start_time / 1000.0;
47 println!("Last measure start time: {:.2} ms ({:.2} seconds / {:.2} minutes)",
48 last_measure.start_time, total_duration_sec, total_duration_sec / 60.0);
49 }
50 }
51
52 // Print first few measures
53 for (measure_idx, measure) in chart.measures.iter().take(3).enumerate() {
54 println!("\n Measure {}:", measure_idx + 1);
55 println!(" Start time: {:.3} ms", measure.start_time);
56 println!(" Number of beats: {}", measure.beats.len());
57
58 // Print first few beats
59 for (beat_idx, beat) in measure.beats.iter().take(3).enumerate() {
60 println!(" Beat {}: time={:.3} ms, notes={:?}",
61 beat_idx + 1, beat.time, beat.notes);
62 }
63 if measure.beats.len() > 3 {
64 println!(" ... ({} more beats)", measure.beats.len() - 3);
65 }
66 }
67 if chart.measures.len() > 3 {
68 println!("\n ... ({} more measures)", chart.measures.len() - 3);
69 }
70 }
71 }
72 Err(e) => {
73 eprintln!("Error loading file: {}", e);
74 std::process::exit(1);
75 }
76 }
77}pub fn from_string(content: &str) -> Result<SmFile, String>
Trait Implementations§
Auto Trait Implementations§
impl Freeze for SmFile
impl RefUnwindSafe for SmFile
impl Send for SmFile
impl Sync for SmFile
impl Unpin for SmFile
impl UnsafeUnpin for SmFile
impl UnwindSafe for SmFile
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more