Skip to main content

SmFile

Struct SmFile 

Source
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

Source

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
Hide additional 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}
Source

pub fn from_string(content: &str) -> Result<SmFile, String>

Source§

impl SmFile

Source

pub fn new() -> SmFile

Trait Implementations§

Source§

impl Clone for SmFile

Source§

fn clone(&self) -> SmFile

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for SmFile

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.