1use crate::Result;
4use serde::Deserialize;
5
6pub mod serializer;
7
8#[derive(Clone, Deserialize, Debug, PartialEq)]
13#[serde(rename_all = "camelCase", rename = "vsq4")]
14pub struct Vsqx4 {
15 #[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 #[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 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
545fn _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}