Skip to main content

vsqx/vsqx4/
mod.rs

1//! VOCALOID4 Editorから出力される.vsqx形式
2
3use crate::Result;
4use serde::Deserialize;
5
6pub mod serializer;
7
8/// VOCALOID 4用のVsqx構造体。
9///
10/// vsqx::Vsqx4とバイナリ互換であることを前提にしている。
11/// 詳しくはvsqx3::Vsqx3の説明を見るように。
12#[derive(Clone, Deserialize, Debug, PartialEq)]
13#[serde(rename_all = "camelCase", rename = "vsq4")]
14pub struct Vsqx4 {
15    /* XML関連タグ */
16    #[serde(rename = "xmlns", default = "_vsqx4_default_xmlns")]
17    xmlns: String,
18    #[serde(rename = "xmlns:xsi", default = "_vsqx4_default_xmlns_xsi")]
19    xmlns_xsi: String,
20    #[serde(
21        rename = "xsi:schemaLocation",
22        default = "_vsqx4_default_xsi_schema_location"
23    )]
24    xsi_schema_location: String,
25    /// バージョン情報
26    #[serde(default = "_vsqx4_default_version")]
27    pub version: String,
28    #[serde(default = "_vsqx4_default_vendor")]
29    pub vender: String,
30    #[serde(default, rename = "vVoiceTable")]
31    pub voice_table: VoiceTable,
32    pub mixer: Mixer,
33    pub master_track: MasterTrack,
34    pub vs_track: Vec<VsTrack>,
35    pub mono_track: MonoTrack,
36    #[serde(default, rename = "stTrack")]
37    pub stereo_track: StereoTrack,
38    #[serde(default)]
39    pub aux: Vec<Aux>,
40}
41
42impl Vsqx4 {
43    pub fn write<P: AsRef<std::path::Path>>(&self, path: P) -> Result<()> {
44        use super::write_xml::WriteXml;
45        use quick_xml::Writer;
46        use std::fs::File;
47        use std::io::BufWriter;
48
49        let writer = File::create(path)?;
50        let writer = BufWriter::new(writer);
51        let mut writer = Writer::new(writer);
52        writer.write(br#"<?xml version="1.0" encoding="UTF-8" standalone="no"?>"#)?;
53        writer.write(b"\n")?;
54        <Self as WriteXml>::tagged(self, &mut writer, b"vsq4")?;
55
56        Ok(())
57    }
58
59    pub fn to_string(&self) -> Result<String> {
60        use super::write_xml::WriteXml;
61        use quick_xml::Writer;
62        use std::io::Cursor;
63
64        let mut writer = Writer::new(Cursor::new(Vec::new()));
65        writer.write(br#"<?xml version="1.0" encoding="UTF-8" standalone="no"?>"#)?;
66        writer.write(b"\n")?;
67        <Self as WriteXml>::tagged(self, &mut writer, b"vsq4")?;
68
69        let res = writer.into_inner().into_inner();
70
71        Ok(String::from_utf8_lossy(&res).into())
72    }
73
74    pub fn open<P: AsRef<std::path::Path>>(path: P) -> Result<Self> {
75        use std::fs::File;
76        use std::io::BufReader;
77
78        let file = File::open(path)?;
79        let file = BufReader::new(file);
80
81        Ok(quick_xml::de::from_reader(file)?)
82    }
83}
84
85impl Default for Vsqx4 {
86    fn default() -> Self {
87        Self {
88            xmlns: _vsqx4_default_xmlns(),
89            xmlns_xsi: _vsqx4_default_xmlns_xsi(),
90            xsi_schema_location: _vsqx4_default_xsi_schema_location(),
91            version: _vsqx4_default_version(),
92            vender: _vsqx4_default_vendor(),
93            voice_table: VoiceTable::default(),
94            mixer: Mixer::default(),
95            master_track: MasterTrack::default(),
96            vs_track: Vec::default(),
97            mono_track: MonoTrack::default(),
98            stereo_track: StereoTrack::default(),
99            aux: vec![],
100        }
101    }
102}
103
104impl From<super::vsqx3::Vsqx3> for Vsqx4 {
105    fn from(v3: super::vsqx3::Vsqx3) -> Self {
106        assert_eq!(
107            std::mem::size_of::<super::vsqx3::Vsqx3>(),
108            std::mem::size_of::<Self>()
109        );
110        let mut this: Self = unsafe { std::mem::transmute(v3) };
111
112        this.xmlns = _vsqx4_default_xmlns();
113        this.xmlns_xsi = _vsqx4_default_xmlns_xsi();
114        this.version = _vsqx4_default_version();
115        this.xsi_schema_location = _vsqx4_default_xsi_schema_location();
116
117        this
118    }
119}
120
121impl From<super::vpr::Vpr> for Vsqx4 {
122    fn from(vpr: super::vpr::Vpr) -> Self {
123        super::v5to4::convert_vpr_to_vsqx4(&vpr)
124    }
125}
126
127use std::str::FromStr;
128
129impl FromStr for Vsqx4 {
130    type Err = crate::Error;
131
132    fn from_str(string: &str) -> Result<Self> {
133        Ok(quick_xml::de::from_str(string)?)
134    }
135}
136
137#[derive(Clone, Deserialize, Debug, PartialEq)]
138#[serde(rename = "vVoiceTable")]
139pub struct VoiceTable {
140    #[serde(rename = "vVoice")]
141    pub voices: Vec<Voice>,
142}
143
144impl Default for VoiceTable {
145    fn default() -> Self {
146        VoiceTable {
147            voices: vec![Voice::default()],
148        }
149    }
150}
151
152#[derive(Clone, Deserialize, Debug, PartialEq)]
153pub struct Voice {
154    pub(crate) bs: i64,
155    pub(crate) pc: i64,
156    pub(crate) id: String,
157    pub(crate) name: String,
158    #[serde(rename = "vPrm")]
159    pub(crate) parameters: VoiceParameters,
160}
161
162impl Default for Voice {
163    fn default() -> Self {
164        Voice {
165            // おそらく言語?
166            bs: 0,
167            pc: 0,
168            id: "BHHN4EF9BRWTNHAB".into(),
169            name: "Miku(V2)".into(),
170            parameters: VoiceParameters::default(),
171        }
172    }
173}
174
175#[derive(Clone, Default, Deserialize, Debug, PartialEq)]
176pub struct VoiceParameters {
177    #[serde(rename = "bre")]
178    pub breathiness: i64,
179    #[serde(rename = "bri")]
180    pub brightness: i64,
181    #[serde(rename = "cle")]
182    pub clearness: i64,
183    #[serde(rename = "gen")]
184    pub gender: i64,
185    #[serde(rename = "ope")]
186    pub openness: i64,
187}
188
189#[derive(Clone, Default, Deserialize, Debug, PartialEq)]
190#[serde(rename_all = "camelCase", rename = "mixer")]
191pub struct Mixer {
192    pub master_unit: MasterUnit,
193    pub vs_unit: Vec<VsUnit>,
194    pub mono_unit: Vec<MonoUnit>,
195    #[serde(rename = "stUnit")]
196    pub stereo_unit: Vec<StereoUnit>,
197}
198
199#[derive(Clone, Default, Deserialize, Debug, PartialEq)]
200#[serde(rename_all = "camelCase", rename = "masterUnit")]
201pub struct MasterUnit {
202    #[serde(rename = "oDev")]
203    output_device: i64,
204    #[serde(rename = "rLvl")]
205    return_level: i64,
206    #[serde(rename = "vol")]
207    volume: i64,
208}
209
210#[derive(Clone, Deserialize, Debug, PartialEq)]
211#[serde(rename_all = "camelCase", rename = "vsUnit")]
212pub struct VsUnit {
213    #[serde(rename = "tNo")]
214    pub track_no: i64,
215    #[serde(rename = "iGin")]
216    pub input_gain: i64,
217    #[serde(rename = "sLvl")]
218    pub send_level: i64,
219    #[serde(rename = "sEnable")]
220    pub is_send_enabled: i64,
221    #[serde(rename = "m")]
222    pub mute: i64,
223    #[serde(rename = "s")]
224    pub solo: i64,
225    #[serde(rename = "pan")]
226    pub pan: i64,
227    #[serde(rename = "vol")]
228    pub volume: i64,
229}
230
231impl Default for VsUnit {
232    fn default() -> Self {
233        Self {
234            track_no: 0,
235            input_gain: 0,
236            send_level: -898,
237            is_send_enabled: 0,
238            mute: 0,
239            solo: 0,
240            pan: 64,
241            volume: 0,
242        }
243    }
244}
245
246#[derive(Clone, Deserialize, Debug, PartialEq)]
247#[serde(rename_all = "camelCase", rename = "monoUnit")]
248pub struct MonoUnit {
249    #[serde(rename = "iGin")]
250    input_gain: i64,
251    #[serde(rename = "sLvl")]
252    send_level: i64,
253    #[serde(rename = "sEnable")]
254    is_send_enabled: i64,
255    #[serde(rename = "m")]
256    mute: i64,
257    #[serde(rename = "s")]
258    solo: i64,
259    #[serde(rename = "pan")]
260    pan: i64,
261    #[serde(rename = "vol")]
262    volume: i64,
263}
264
265impl Default for MonoUnit {
266    fn default() -> Self {
267        Self {
268            input_gain: 0,
269            send_level: -898,
270            is_send_enabled: 0,
271            mute: 0,
272            solo: 0,
273            pan: 64,
274            volume: 0,
275        }
276    }
277}
278
279#[derive(Clone, Deserialize, Debug, PartialEq)]
280#[serde(rename_all = "camelCase", rename = "stUnit")]
281pub struct StereoUnit {
282    #[serde(rename = "iGin")]
283    input_gain: i64,
284    #[serde(rename = "m")]
285    mute: i64,
286    #[serde(rename = "s")]
287    solo: i64,
288    #[serde(rename = "vol")]
289    volume: i64,
290}
291
292impl Default for StereoUnit {
293    fn default() -> StereoUnit {
294        Self {
295            input_gain: 0,
296            mute: 0,
297            solo: 0,
298            volume: 0,
299        }
300    }
301}
302
303#[derive(Clone, Deserialize, Debug, PartialEq)]
304#[serde(rename_all = "camelCase", rename = "masterTrack")]
305pub struct MasterTrack {
306    #[serde(rename = "seqName")]
307    pub name: String,
308    #[serde(rename = "seqName", default, skip_serializing_if = "String::is_empty")]
309    pub comment: String,
310    pub resolution: i64,
311    pub pre_measure: i64,
312    #[serde(rename = "timeSig")]
313    pub time_signatures: Vec<TimeSignature>,
314    #[serde(rename = "tempo")]
315    pub tempos: Vec<Tempo>,
316}
317
318impl Default for MasterTrack {
319    fn default() -> Self {
320        Self {
321            name: "Untitled".into(),
322            comment: "".into(),
323            resolution: 480,
324            pre_measure: 0,
325            time_signatures: vec![TimeSignature::default()],
326            tempos: vec![Tempo::default()],
327        }
328    }
329}
330
331#[derive(Clone, Deserialize, Debug, PartialEq)]
332#[serde(rename_all = "camelCase", rename = "timeSig")]
333pub struct TimeSignature {
334    #[serde(rename = "m")]
335    pub position: i64,
336    #[serde(rename = "nu")]
337    pub numerator: i64,
338    #[serde(rename = "de")]
339    pub denominator: i64,
340}
341
342impl Default for TimeSignature {
343    fn default() -> Self {
344        Self {
345            position: 0,
346            numerator: 4,
347            denominator: 4,
348        }
349    }
350}
351
352#[derive(Clone, Deserialize, Debug, PartialEq)]
353#[serde(rename_all = "camelCase", rename = "tempo")]
354pub struct Tempo {
355    #[serde(rename = "t")]
356    pub position: i64,
357    #[serde(rename = "v")]
358    pub value: i64,
359}
360
361impl Default for Tempo {
362    fn default() -> Self {
363        Self {
364            position: 0,
365            value: 12000,
366        }
367    }
368}
369
370#[derive(Clone, Deserialize, Debug, PartialEq)]
371#[serde(rename_all = "camelCase", rename = "vsTrack")]
372pub struct VsTrack {
373    #[serde(rename = "tNo")]
374    pub track_no: i64,
375    pub name: String,
376    pub comment: String,
377    #[serde(rename = "vsPart", default)]
378    pub parts: Vec<VsPart>,
379}
380
381impl Default for VsTrack {
382    fn default() -> Self {
383        Self {
384            track_no: 0,
385            name: "Track".into(),
386            comment: "".into(),
387            parts: vec![],
388        }
389    }
390}
391
392#[derive(Clone, Deserialize, Debug, PartialEq, Default)]
393#[serde(rename_all = "camelCase", rename = "vsPart")]
394pub struct VsPart {
395    #[serde(rename = "t")]
396    pub position: i64,
397    #[serde(rename = "sPlug")]
398    pub style_plugin: StylePlugin,
399    #[serde(skip_serializing_if = "Option::is_none")]
400    pub play_time: Option<u64>,
401    #[serde(skip_serializing_if = "Option::is_none")]
402    pub name: Option<String>,
403    #[serde(skip_serializing_if = "Option::is_none")]
404    pub comment: Option<String>,
405    #[serde(rename = "pStyle")]
406    pub style: Style,
407    #[serde(rename = "singer")]
408    pub singers: Vec<Singer>,
409    #[serde(rename = "cc", default)]
410    pub control_changes: Vec<ControlChange>,
411    #[serde(rename = "note")]
412    pub notes: Vec<Note>,
413    pub plane: i64,
414}
415
416#[derive(Clone, Deserialize, Debug, PartialEq)]
417pub struct ControlChange<T = i64> {
418    pub id: String,
419    pub pos: i64,
420    pub value: T,
421}
422
423#[derive(Clone, Deserialize, Debug, PartialEq)]
424#[serde(rename_all = "camelCase", rename = "sPlug")]
425pub struct StylePlugin {
426    pub id: String,
427    pub name: String,
428    pub version: String,
429}
430
431impl Default for StylePlugin {
432    fn default() -> Self {
433        Self {
434            id: "ACA9C502-A04B-42b5-B2EB-5CEA36D16FCE".into(),
435            name: "VOCALOID2 Compatible Style".into(),
436            version: "3.0.0.1".into(),
437        }
438    }
439}
440
441#[derive(Clone, Deserialize, Debug, PartialEq)]
442#[serde(rename_all = "camelCase", rename = "singer")]
443pub struct Singer {
444    #[serde(rename = "t")]
445    pub(crate) position: i64,
446    pub(crate) bs: i64,
447    pub(crate) pc: i64,
448}
449
450#[derive(Clone, Deserialize, Debug, PartialEq)]
451#[serde(rename_all = "camelCase", rename = "note")]
452pub struct Note {
453    #[serde(rename = "t")]
454    pub position: i64,
455    #[serde(rename = "dur")]
456    pub duration: i64,
457    #[serde(rename = "n")]
458    pub note_num: i64,
459    #[serde(rename = "v")]
460    pub velocity: i64,
461    #[serde(rename = "y")]
462    pub lyric: String,
463    #[serde(rename = "p")]
464    pub phoneme: String,
465    #[serde(rename = "nStyle")]
466    pub style: Style,
467}
468
469impl Default for Note {
470    fn default() -> Self {
471        Self {
472            position: 0,
473            duration: 0,
474            note_num: 81,
475            velocity: 64,
476            lyric: "あ".into(),
477            phoneme: "a".into(),
478            style: Style::default(),
479        }
480    }
481}
482
483#[derive(Clone, Deserialize, Debug, PartialEq)]
484#[serde(rename_all = "camelCase", rename = "nStyle")]
485pub struct Style {
486    #[serde(rename = "v")]
487    pub styles: Vec<StyleKey>,
488}
489
490macro_rules! style {
491    {} => {
492        Style { styles: vec![] }
493    };
494    { $(<v id=$a: literal>$b: literal</v>)+ } => {
495        Style {
496            styles: vec! [
497                $(StyleKey {
498                    id: ($a).into(),
499                    value: $b
500                }),+
501            ]
502        }
503    }
504}
505
506impl Default for Style {
507    fn default() -> Self {
508        style! {
509            <v id="accent">50</v>
510            <v id="bendDep">8</v>
511            <v id="bendLen">0</v>
512            <v id="decay">50</v>
513            <v id="fallPort">0</v>
514            <v id="opening">127</v>
515            <v id="risePort">0</v>
516            <v id="vibLen">0</v>
517            <v id="vibType">0</v>
518        }
519    }
520}
521
522#[derive(Clone, Deserialize, Debug, PartialEq)]
523#[serde(rename_all = "camelCase", rename = "v")]
524pub struct StyleKey {
525    pub id: String,
526    #[serde(rename = "$value")]
527    pub value: i64,
528}
529
530#[derive(Clone, Deserialize, Debug, PartialEq, Default)]
531#[serde(rename_all = "camelCase", rename = "monoTrack")]
532pub struct MonoTrack {}
533
534#[derive(Clone, Deserialize, Debug, PartialEq, Default)]
535#[serde(rename_all = "camelCase", rename = "stTrack")]
536pub struct StereoTrack {}
537
538#[derive(Clone, Deserialize, Debug, PartialEq)]
539#[serde(rename_all = "camelCase", rename = "aux")]
540pub struct Aux {
541    id: String,
542    content: String,
543}
544
545/* デフォルト値 */
546
547fn _vsqx4_default_xmlns() -> String {
548    "http://www.yamaha.co.jp/vocaloid/schema/vsq4/".into()
549}
550
551fn _vsqx4_default_xmlns_xsi() -> String {
552    "http://www.w3.org/2001/XMLSchema-instance".into()
553}
554
555fn _vsqx4_default_xsi_schema_location() -> String {
556    "http://www.yamaha.co.jp/vocaloid/schema/vsq4/ vsq4.xsd".into()
557}
558
559fn _vsqx4_default_version() -> String {
560    "4.0.0.3".into()
561}
562
563fn _vsqx4_default_vendor() -> String {
564    "Yamaha corporation".into()
565}
566
567#[test]
568#[cfg(test)]
569fn test_vsqx4_parse() {
570    let vsqx4 = include_str!("../test/v4.vsqx");
571    let _v: Vsqx4 = quick_xml::de::from_str(&vsqx4).unwrap();
572}