guitarpro/
song.rs

1
2use fraction::ToPrimitive;
3
4use crate::enums::*;
5use crate::io::*;
6use crate::headers::*;
7use crate::page::*;
8use crate::track::*;
9use crate::key_signature::*;
10use crate::lyric::*;
11use crate::midi::*;
12use crate::rse::*;
13
14
15// Struct utility to read file: https://stackoverflow.com/questions/55555538/what-is-the-correct-way-to-read-a-binary-file-in-chunks-of-a-fixed-size-and-stor
16#[derive(Debug,Clone)]
17pub struct Song {
18    pub version: Version,
19    pub clipboard: Option<Clipboard>,
20
21    pub name: String,
22    pub subtitle: String, //Guitar Pro
23	pub artist: String,
24	pub album: String,
25    pub words: String, //GP
26	pub author: String, //music by
27	pub date: String,
28	pub copyright: String,
29    /// Tab writer
30	pub writer: String,
31	pub transcriber: String,
32    pub instructions: String,
33	pub comments: String,
34    pub notice: Vec<String>,
35
36	pub tracks: Vec<Track>,
37	pub measure_headers: Vec<MeasureHeader>,
38	pub channels: Vec<MidiChannel>,
39    pub lyrics: Lyrics,
40    pub tempo: i16,
41    pub hide_tempo: bool,
42    pub tempo_name:String,
43    pub key: KeySignature,
44
45    pub triplet_feel: TripletFeel,
46    pub master_effect: RseMasterEffect,
47
48    pub page_setup: PageSetup,
49
50    //Used to read the file
51    pub current_measure_number: Option<usize>,
52    pub current_track: Option<usize>,
53    pub current_voice_number: Option<usize>,
54    pub current_beat_number: Option<usize>,
55}
56
57impl Default for Song {
58	fn default() -> Self { Song {
59        version: Version {data: String::with_capacity(30), clipboard: false, number: (5,1,0)}, clipboard: None,
60		name:String::new(), subtitle: String::new(), artist:String::new(), album: String::new(),
61        words: String::new(), author:String::new(), date:String::new(),
62        copyright:String::new(), writer:String::new(), transcriber:String::new(), comments:String::new(),
63        notice:Vec::new(),
64        instructions: String::new(),
65		tracks:Vec::new(),
66		measure_headers:Vec::new(),
67		channels:Vec::with_capacity(64),
68        lyrics: Lyrics::default(),
69        tempo: 120, hide_tempo: false, tempo_name:String::from("Moderate"),
70        key: KeySignature::default(),
71
72        triplet_feel: TripletFeel::None,
73        current_measure_number: None, current_track: None, current_voice_number: None, current_beat_number: None,
74
75        page_setup: PageSetup::default(),
76
77        master_effect: RseMasterEffect::default(),
78	}}
79}
80impl Song {
81    /// Read the song. A song consists of score information, triplet feel, tempo, song key, MIDI channels, measure and track count, measure headers, tracks, measures.
82    /// - Version: `byte-size-string` of size 30.
83    /// - Score information. See `readInfo`.
84    /// - Triplet feel: `bool`. If value is true, then triplet feel is set to eigth.
85    /// - Tempo: `int`.
86    /// - Key: `int`. Key signature of the song.
87    /// - MIDI channels. See `readMidiChannels`.
88    /// - Number of measures: `int`.
89    /// - Number of tracks: `int`.
90    /// - Measure headers. See `readMeasureHeaders`.
91    /// - Tracks. See `read_tracks()`.
92    /// - Measures. See `read_measures()`.
93    pub fn read_gp3(&mut self, data: &[u8]) {
94        let mut seek: usize = 0;
95        self.version = read_version_string(data, &mut seek);
96        self.read_info(data, &mut seek);
97        self.triplet_feel = if read_bool(data, &mut seek) {TripletFeel::Eighth} else {TripletFeel::None};
98        //println!("Triplet feel: {}", self.triplet_feel);
99        self.tempo = read_int(data, &mut seek).to_i16().unwrap();
100        self.key.key = read_int(data, &mut seek).to_i8().unwrap();
101        //println!("Tempo: {} bpm\t\tKey: {}", self.tempo, self.key.to_string());
102        self.read_midi_channels(data, &mut seek);
103        let measure_count = read_int(data, &mut seek).to_usize().unwrap();
104        let track_count = read_int(data, &mut seek).to_usize().unwrap();
105        //println!("Measures count: {}\tTrack count: {}", measure_count, track_count);
106        // Read measure headers. The *measures* are written one after another, their number have been specified previously.
107        self.read_measure_headers(data, &mut seek, measure_count);
108        self.current_measure_number = Some(0);
109        self.read_tracks(data, &mut seek, track_count);
110        self.read_measures(data, &mut seek);
111    }
112    /// Read the song. A song consists of score information, triplet feel, tempo, song key, MIDI channels, measure and track count, measure headers, tracks, measures.
113    /// - Version: `byte-size-string` of size 30.
114    /// - Score information. See `readInfo`.
115    /// - Triplet feel: `bool`. If value is true, then triplet feel is set to eigth.
116    /// - Lyrics. See `read_lyrics()`.
117    /// - Tempo: `int`.
118    /// - Key: `int`. Key signature of the song.
119    /// - Octave: `signed-byte`. Reserved for future uses.
120    /// - MIDI channels. See `readMidiChannels`.
121    /// - Number of measures: `int`.
122    /// - Number of tracks: `int`.
123    /// - Measure headers. See `readMeasureHeaders`.
124    /// - Tracks. See `read_tracks()`.
125    /// - Measures. See `read_measures()`.
126    pub fn read_gp4(&mut self, data: &[u8]) {
127        let mut seek: usize = 0;
128        self.version = read_version_string(data, &mut seek);
129        self.read_clipboard(data, &mut seek);
130        self.read_info(data, &mut seek);
131        self.triplet_feel = if read_bool(data, &mut seek) {TripletFeel::Eighth} else {TripletFeel::None};
132        //println!("Triplet feel: {}", self.triplet_feel);
133        self.lyrics = self.read_lyrics(data, &mut seek); //read lyrics
134        self.tempo = read_int(data, &mut seek).to_i16().unwrap();
135        self.key.key = read_int(data, &mut seek).to_i8().unwrap();
136        //println!("Tempo: {} bpm\t\tKey: {}", self.tempo, self.key.to_string());
137        read_signed_byte(data, &mut seek); //octave
138        self.read_midi_channels(data, &mut seek);
139        let measure_count = read_int(data, &mut seek).to_usize().unwrap();
140        let track_count = read_int(data, &mut seek).to_usize().unwrap();
141        //println!("Measures count: {}\tTrack count: {}", measure_count, track_count);
142        // Read measure headers. The *measures* are written one after another, their number have been specified previously.
143        self.read_measure_headers(data, &mut seek, measure_count);
144        //self.current_measure_number = Some(0);
145        self.read_tracks(data, &mut seek, track_count);
146        self.read_measures(data, &mut seek);
147    }
148    pub fn read_gp5(&mut self, data: &[u8]) {
149        let mut seek: usize = 0;
150        self.version = read_version_string(data, &mut seek);
151        self.read_clipboard(data, &mut seek);
152        self.read_info(data, &mut seek);
153        self.lyrics = self.read_lyrics(data, &mut seek); //read lyrics
154        self.master_effect = self.read_rse_master_effect(data, &mut seek);
155        self.read_page_setup(data, &mut seek);
156        self.tempo_name = read_int_size_string(data, &mut seek);
157        self.tempo = read_int(data, &mut seek).to_i16().unwrap();
158        self.hide_tempo = if self.version.number > (5,0,0) {read_bool(data, &mut seek)} else {false};
159        self.key.key = read_signed_byte(data, &mut seek);
160        read_int(data, &mut seek); //octave
161        self.read_midi_channels(data, &mut seek);
162        let directions = self.read_directions(data, &mut seek);
163        self.master_effect.reverb = read_int(data, &mut seek).to_f32().unwrap();
164        let measure_count = read_int(data, &mut seek).to_usize().unwrap();
165        let track_count = read_int(data, &mut seek).to_usize().unwrap();
166        //println!("{} {} {} {:?}", self.tempo_name, self.tempo, self.hide_tempo, self.key.key); //OK
167        println!("Track count: {} \t Measure count: {}", track_count, measure_count); //OK
168        self.read_measure_headers_v5(data, &mut seek, measure_count, &directions);
169        self.read_tracks_v5(data, &mut seek, track_count);
170        println!("read_gp5(), after tracks   \t seek: {}", seek);
171        self.read_measures(data, &mut seek);
172        println!("read_gp5(), after measures \t seek: {}", seek);
173    }
174
175    /// Read information (name, artist, ...)
176    fn read_info(&mut self, data: &[u8], seek: &mut usize) {
177        self.name        = read_int_byte_size_string(data, seek);//.replace("\r", " ").replace("\n", " ").trim().to_owned();
178        self.subtitle    = read_int_byte_size_string(data, seek);
179        self.artist      = read_int_byte_size_string(data, seek);
180        self.album       = read_int_byte_size_string(data, seek);
181        self.words       = read_int_byte_size_string(data, seek); //music
182        self.author      = if self.version.number.0 < 5 {self.words.clone()} else {read_int_byte_size_string(data, seek)};
183        self.copyright   = read_int_byte_size_string(data, seek);
184        self.writer      = read_int_byte_size_string(data, seek); //tabbed by
185        self.instructions= read_int_byte_size_string(data, seek); //instructions
186        //notices
187        let nc = read_int(data, seek).to_usize().unwrap(); //notes count
188        if nc > 0 { for i in 0..nc { self.notice.push(read_int_byte_size_string(data, seek)); println!("  {}\t\t{}",i, self.notice[self.notice.len()-1]); }}
189    }
190
191    /*pub const _MAX_STRINGS: i32 = 25;
192    pub const _MIN_STRINGS: i32 = 1;
193    pub const _MAX_OFFSET: i32 = 24;
194    pub const _MIN_OFFSET: i32 = -24;*/
195
196    /// Write data to a Vec<u8>, you are free to use the encoded data to write it in a file or in a database or do something else.
197    pub fn write(&self, version: (u8,u8,u8), clipboard: Option<bool>) ->Vec<u8> {
198        let mut data: Vec<u8> = Vec::with_capacity(8388608); //capacity of 8MB, should be sufficient
199        write_version(&mut data, version);
200        if clipboard.is_some() && clipboard.unwrap() && version.0 >= 4 {self.write_clipboard(&mut data, &version);}
201        self.write_info(&mut data, version);
202        if version.0 < 5 {write_bool(&mut data, self.triplet_feel != TripletFeel::None);}
203        if version.0 >= 4 {self.write_lyrics(&mut data);}
204        if version > (5,0,0) {self.write_rse_master_effect(&mut data);}
205        if version.0 >= 5 {
206            self.write_page_setup(&mut data);
207            write_int_byte_size_string(&mut data, &self.tempo_name);
208        }
209        write_i32(&mut data, self.tempo.to_i32().unwrap());
210        if version > (5,0,0) {write_bool(&mut data, self.hide_tempo);}
211        write_i32(&mut data, self.key.key.to_i32().unwrap());
212
213        if version.0 >= 4 {write_signed_byte(&mut data, 0);} //octave
214        self.write_midi_channels(&mut data); //TODO: fixme for writing
215        //return data;
216
217        if version.0 == 5 {
218            self.write_directions(&mut data);
219            self.write_master_reverb(&mut data);
220        }
221
222        write_i32(&mut data, self.tracks[0].measures.len().to_i32().unwrap());
223        write_i32(&mut data, self.tracks.len().to_i32().unwrap());
224        self.write_measure_headers(&mut data, &version);
225        self.write_tracks(&mut data, &version);
226        self.write_measures(&mut data, &version);
227        write_i32(&mut data, 0);
228        data
229    }
230    fn write_info(&self, data: &mut Vec<u8>, version: (u8,u8,u8)) {
231        write_int_byte_size_string(data, &self.name);
232        write_int_byte_size_string(data, &self.subtitle);
233        write_int_byte_size_string(data, &self.artist);
234        write_int_byte_size_string(data, &self.album);
235        if version.0 < 5 {write_int_byte_size_string(data, &self.pack_author());}
236        else {
237            write_int_byte_size_string(data, &self.words);
238            write_int_byte_size_string(data, &self.author);
239        }
240        write_int_byte_size_string(data, &self.copyright);
241        write_int_byte_size_string(data, &self.writer);
242        write_int_byte_size_string(data, &self.instructions);
243        write_i32(data, self.notice.len().to_i32().unwrap());
244        for i in 0..self.notice.len() {write_int_byte_size_string(data, &self.notice[i]);}
245    }
246    fn pack_author(&self) -> String {
247        if !self.words.is_empty() && !self.author.is_empty() {
248            if self.words != self.author {
249                let mut s = self.words.clone();
250                s.push_str(", ");
251                s.push_str(&self.author);
252                s
253            } else {self.words.clone()}
254        } else {
255            let mut s = self.words.clone();
256            s.push_str(&self.author);
257            s
258        }
259    }
260}