mirror of
https://github.com/G2-Games/minidisc-cli.git
synced 2025-04-20 04:02:53 -05:00
Cleaned up old code, added new functions to commands.rs
This commit is contained in:
parent
4151a4f5c0
commit
bf66c59799
6 changed files with 1125 additions and 652 deletions
|
@ -27,7 +27,6 @@ nofmt = "1.0.0"
|
||||||
once_cell = "1.18.0"
|
once_cell = "1.18.0"
|
||||||
unicode-normalization = "0.1.22"
|
unicode-normalization = "0.1.22"
|
||||||
regex = "1.10.2"
|
regex = "1.10.2"
|
||||||
lazy_static = "1.4.0"
|
|
||||||
cross_usb = "0.3"
|
cross_usb = "0.3"
|
||||||
num-derive = "0.3.3"
|
num-derive = "0.3.3"
|
||||||
num-traits = "0.2.14"
|
num-traits = "0.2.14"
|
||||||
|
@ -39,6 +38,7 @@ ecb = "0.1"
|
||||||
tokio = { version = "1.36", features = ["sync"] }
|
tokio = { version = "1.36", features = ["sync"] }
|
||||||
g2-unicode-jp = "0.4.1"
|
g2-unicode-jp = "0.4.1"
|
||||||
thiserror = "1.0.57"
|
thiserror = "1.0.57"
|
||||||
|
phf = { version = "0.11.2", features = ["phf_macros", "macros"] }
|
||||||
|
|
||||||
[target.'cfg(target_family = "wasm")'.dependencies]
|
[target.'cfg(target_family = "wasm")'.dependencies]
|
||||||
gloo = { version = "0.11.0", features = ["futures"] }
|
gloo = { version = "0.11.0", features = ["futures"] }
|
||||||
|
|
|
@ -5,7 +5,10 @@ use std::error::Error;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use cross_usb::Descriptor;
|
use cross_usb::Descriptor;
|
||||||
|
|
||||||
use super::interface::{MDSession, MDTrack, NetMDInterface, Direction, InterfaceError};
|
use crate::netmd::interface::DiscFlag;
|
||||||
|
use crate::netmd::utils::RawTime;
|
||||||
|
|
||||||
|
use super::interface::{Channels, Encoding, InterfaceError, MDSession, MDTrack, NetMDInterface, TrackFlag};
|
||||||
use super::utils::cross_sleep;
|
use super::utils::cross_sleep;
|
||||||
|
|
||||||
#[derive(FromPrimitive, PartialEq, Eq)]
|
#[derive(FromPrimitive, PartialEq, Eq)]
|
||||||
|
@ -34,6 +37,66 @@ pub struct DeviceStatus {
|
||||||
pub time: Time,
|
pub time: Time,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Track {
|
||||||
|
index: u16,
|
||||||
|
title: String,
|
||||||
|
full_width_title: String,
|
||||||
|
duration: RawTime,
|
||||||
|
channel: Channels,
|
||||||
|
encoding: Encoding,
|
||||||
|
protected: TrackFlag,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Track {
|
||||||
|
pub fn chars_to_cells(len: usize) -> usize {
|
||||||
|
f32::ceil(len as f32 / 7.0) as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn cells_for_title(&mut self) {
|
||||||
|
let encoding_name_correction = match self.encoding {
|
||||||
|
Encoding::SP => 0,
|
||||||
|
_ => 1
|
||||||
|
};
|
||||||
|
|
||||||
|
let full_width_length = Self::chars_to_cells(self.full_width_title.len() * 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Group {
|
||||||
|
index: u16,
|
||||||
|
title: Option<String>,
|
||||||
|
full_width_title: Option<String>,
|
||||||
|
tracks: Vec<Track>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Disc {
|
||||||
|
title: String,
|
||||||
|
full_width_title: String,
|
||||||
|
writeable: bool,
|
||||||
|
write_protected: bool,
|
||||||
|
used: u64,
|
||||||
|
left: u64,
|
||||||
|
total: u64,
|
||||||
|
track_count: u16,
|
||||||
|
groups: Vec<Group>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Disc {
|
||||||
|
pub async fn track_count(&self) -> u16 {
|
||||||
|
self.groups.iter()
|
||||||
|
.map(|g| g.tracks.len())
|
||||||
|
.reduce(|acc, s| acc + s)
|
||||||
|
.unwrap() as u16
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn tracks(&self) -> Vec<Track> {
|
||||||
|
self.groups.iter()
|
||||||
|
.flat_map(|g| g.tracks.clone())
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct NetMDContext {
|
pub struct NetMDContext {
|
||||||
interface: NetMDInterface,
|
interface: NetMDInterface,
|
||||||
}
|
}
|
||||||
|
@ -48,6 +111,7 @@ impl NetMDContext {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
/// Change to the next track (skip forward)
|
/// Change to the next track (skip forward)
|
||||||
pub async fn next_track(&mut self) -> Result<(), InterfaceError> {
|
pub async fn next_track(&mut self) -> Result<(), InterfaceError> {
|
||||||
self.interface.track_change(Direction::Next).await
|
self.interface.track_change(Direction::Next).await
|
||||||
|
@ -62,6 +126,7 @@ impl NetMDContext {
|
||||||
pub async fn restart_track(&mut self) -> Result<(), InterfaceError> {
|
pub async fn restart_track(&mut self) -> Result<(), InterfaceError> {
|
||||||
self.interface.track_change(Direction::Restart).await
|
self.interface.track_change(Direction::Restart).await
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
pub async fn device_status(&mut self) -> Result<DeviceStatus, Box<dyn Error>> {
|
pub async fn device_status(&mut self) -> Result<DeviceStatus, Box<dyn Error>> {
|
||||||
let status = self.interface.status().await?;
|
let status = self.interface.status().await?;
|
||||||
|
@ -132,4 +197,72 @@ impl NetMDContext {
|
||||||
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn list_content(&mut self) -> Result<Disc, Box<dyn Error>> {
|
||||||
|
let flags = self.interface.disc_flags().await?;
|
||||||
|
let title = self.interface.disc_title(false).await?;
|
||||||
|
let full_width_title = self.interface.disc_title(true).await?;
|
||||||
|
let disc_capacity: [RawTime; 3] = self.interface.disc_capacity().await?;
|
||||||
|
let track_count = self.interface.track_count().await?;
|
||||||
|
|
||||||
|
let mut frames_used = disc_capacity[0].as_frames();
|
||||||
|
let mut frames_total = disc_capacity[1].as_frames();
|
||||||
|
let mut frames_left = disc_capacity[2].as_frames();
|
||||||
|
|
||||||
|
// Some devices report the time remaining of the currently selected recording mode. (Sharps)
|
||||||
|
while frames_total > 512 * 60 * 82 {
|
||||||
|
frames_used /= 2;
|
||||||
|
frames_total /= 2;
|
||||||
|
frames_left /= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
let track_group_list = self.interface.track_group_list().await?;
|
||||||
|
|
||||||
|
let mut groups = vec![];
|
||||||
|
for (index, group) in track_group_list.iter().enumerate() {
|
||||||
|
let mut tracks = vec![];
|
||||||
|
for track in &group.2 {
|
||||||
|
let (encoding, channel) = self.interface.track_encoding(*track).await?;
|
||||||
|
let duration = self.interface.track_length(*track).await?;
|
||||||
|
let flags = self.interface.track_flags(*track).await?;
|
||||||
|
let title = self.interface.track_title(*track, false).await?;
|
||||||
|
let full_width_title = self.interface.track_title(*track, true).await?;
|
||||||
|
|
||||||
|
tracks.push(
|
||||||
|
Track {
|
||||||
|
index: *track,
|
||||||
|
title,
|
||||||
|
full_width_title,
|
||||||
|
duration,
|
||||||
|
channel,
|
||||||
|
encoding,
|
||||||
|
protected: TrackFlag::from_u8(flags).unwrap(),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
groups.push(
|
||||||
|
Group {
|
||||||
|
index: index as u16,
|
||||||
|
title: group.0.clone(),
|
||||||
|
full_width_title: group.1.clone(),
|
||||||
|
tracks
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
let disc = Disc {
|
||||||
|
title,
|
||||||
|
full_width_title,
|
||||||
|
writeable: (flags & DiscFlag::Writable as u8) != 0,
|
||||||
|
write_protected: (flags & DiscFlag::WriteProtected as u8) != 0,
|
||||||
|
used: frames_used,
|
||||||
|
left: frames_left,
|
||||||
|
total: frames_total,
|
||||||
|
track_count,
|
||||||
|
groups
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(disc)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,9 @@
|
||||||
use crate::netmd::base;
|
use crate::netmd::base;
|
||||||
use crate::netmd::query_utils::{format_query, scan_query, QueryValue};
|
use crate::netmd::query_utils::{format_query, scan_query, QueryValue};
|
||||||
use crate::netmd::utils::{
|
use crate::netmd::utils::{
|
||||||
half_width_to_full_width_range, length_after_encoding_to_jis, sanitize_full_width_title,
|
half_width_to_full_width_range, length_after_encoding_to_sjis, sanitize_full_width_title,
|
||||||
sanitize_half_width_title, time_to_duration,
|
sanitize_half_width_title,
|
||||||
|
RawTime,
|
||||||
};
|
};
|
||||||
use cbc::cipher::block_padding::NoPadding;
|
use cbc::cipher::block_padding::NoPadding;
|
||||||
use cbc::cipher::{BlockDecryptMut, BlockEncryptMut, KeyInit, KeyIvInit};
|
use cbc::cipher::{BlockDecryptMut, BlockEncryptMut, KeyInit, KeyIvInit};
|
||||||
|
@ -16,8 +17,6 @@ use thiserror::Error;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use tokio::sync::mpsc::UnboundedReceiver;
|
use tokio::sync::mpsc::UnboundedReceiver;
|
||||||
|
|
||||||
use lazy_static::lazy_static;
|
|
||||||
|
|
||||||
use super::base::NetMD;
|
use super::base::NetMD;
|
||||||
use super::utils::cross_sleep;
|
use super::utils::cross_sleep;
|
||||||
|
|
||||||
|
@ -52,7 +51,7 @@ pub enum WireFormat {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WireFormat {
|
impl WireFormat {
|
||||||
fn frame_size(&self) -> u16 {
|
const fn frame_size(&self) -> u16 {
|
||||||
match self {
|
match self {
|
||||||
WireFormat::Pcm => 2048,
|
WireFormat::Pcm => 2048,
|
||||||
WireFormat::L105kbps => 192,
|
WireFormat::L105kbps => 192,
|
||||||
|
@ -60,31 +59,70 @@ impl WireFormat {
|
||||||
WireFormat::LP4 => 96,
|
WireFormat::LP4 => 96,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const fn disc_for_wire(&self) -> DiscFormat {
|
||||||
|
match self {
|
||||||
|
WireFormat::Pcm => DiscFormat::SPStereo,
|
||||||
|
WireFormat::L105kbps => DiscFormat::LP2,
|
||||||
|
WireFormat::LP2 => DiscFormat::LP2,
|
||||||
|
WireFormat::LP4 => DiscFormat::LP4,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum Encoding {
|
pub enum Encoding {
|
||||||
SP = 0x90,
|
SP = 0x90,
|
||||||
LP2 = 0x92,
|
LP2 = 0x92,
|
||||||
LP4 = 0x93,
|
LP4 = 0x93,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Channels {
|
impl ToString for Encoding {
|
||||||
|
fn to_string(&self) -> String {
|
||||||
|
match self {
|
||||||
|
Encoding::SP => String::from("sp"),
|
||||||
|
Encoding::LP2 => String::from("lp2"),
|
||||||
|
Encoding::LP4 => String::from("lp4"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum Channels {
|
||||||
Mono = 0x01,
|
Mono = 0x01,
|
||||||
Stereo = 0x00,
|
Stereo = 0x00,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ToString for Channels {
|
||||||
|
fn to_string(&self) -> String {
|
||||||
|
match self {
|
||||||
|
Channels::Mono => String::from("mono"),
|
||||||
|
Channels::Stereo => String::from("stereo"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
enum ChannelCount {
|
enum ChannelCount {
|
||||||
Mono = 1,
|
Mono = 1,
|
||||||
Stereo = 2,
|
Stereo = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum TrackFlag {
|
#[derive(Debug, Clone, Copy, FromPrimitive)]
|
||||||
|
pub enum TrackFlag {
|
||||||
Protected = 0x03,
|
Protected = 0x03,
|
||||||
Unprotected = 0x00,
|
Unprotected = 0x00,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum DiscFlag {
|
impl ToString for TrackFlag {
|
||||||
|
fn to_string(&self) -> String {
|
||||||
|
match self {
|
||||||
|
TrackFlag::Protected => String::from("protected"),
|
||||||
|
TrackFlag::Unprotected => String::from("unprotected"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum DiscFlag {
|
||||||
Writable = 0x10,
|
Writable = 0x10,
|
||||||
WriteProtected = 0x40,
|
WriteProtected = 0x40,
|
||||||
}
|
}
|
||||||
|
@ -161,15 +199,6 @@ enum NetmdStatus {
|
||||||
Interim = 0x0f,
|
Interim = 0x0f,
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_static! {
|
|
||||||
static ref FRAME_SIZE: HashMap<WireFormat, usize> = HashMap::from([
|
|
||||||
(WireFormat::Pcm, 2048),
|
|
||||||
(WireFormat::LP2, 192),
|
|
||||||
(WireFormat::L105kbps, 152),
|
|
||||||
(WireFormat::LP4, 96),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Error, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Error, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
#[error("invalid status code")]
|
#[error("invalid status code")]
|
||||||
pub struct StatusError;
|
pub struct StatusError;
|
||||||
|
@ -1065,7 +1094,7 @@ impl NetMDInterface {
|
||||||
}
|
}
|
||||||
|
|
||||||
let new_title: Vec<u8>;
|
let new_title: Vec<u8>;
|
||||||
let old_len = length_after_encoding_to_jis(¤t_title);
|
let old_len = length_after_encoding_to_sjis(¤t_title);
|
||||||
|
|
||||||
let wchar_value = match wchar {
|
let wchar_value = match wchar {
|
||||||
true => {
|
true => {
|
||||||
|
@ -1143,7 +1172,7 @@ impl NetMDInterface {
|
||||||
if title == current_title {
|
if title == current_title {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
length_after_encoding_to_jis(¤t_title) as u16
|
length_after_encoding_to_sjis(¤t_title) as u16
|
||||||
}
|
}
|
||||||
Err(error) if error.to_string() == "Rejected" => 0,
|
Err(error) if error.to_string() == "Rejected" => 0,
|
||||||
Err(error) => return Err(error),
|
Err(error) => return Err(error),
|
||||||
|
@ -1232,12 +1261,12 @@ impl NetMDInterface {
|
||||||
Ok(res[0].to_vec().unwrap())
|
Ok(res[0].to_vec().unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the length of tracks as a [std::time::Duration] from a set
|
/// Gets the length of tracks as a raw duration from a set
|
||||||
pub async fn track_lengths(
|
pub async fn track_lengths(
|
||||||
&mut self,
|
&mut self,
|
||||||
tracks: Vec<u16>,
|
tracks: Vec<u16>,
|
||||||
) -> Result<Vec<std::time::Duration>, InterfaceError> {
|
) -> Result<Vec<RawTime>, InterfaceError> {
|
||||||
let mut times: Vec<std::time::Duration> = vec![];
|
let mut times = vec![];
|
||||||
|
|
||||||
self.change_descriptor_state(&Descriptor::AudioContentsTD, &DescriptorAction::OpenRead)
|
self.change_descriptor_state(&Descriptor::AudioContentsTD, &DescriptorAction::OpenRead)
|
||||||
.await?;
|
.await?;
|
||||||
|
@ -1269,8 +1298,12 @@ impl NetMDInterface {
|
||||||
.map(|v| v.to_i64().unwrap() as u64)
|
.map(|v| v.to_i64().unwrap() as u64)
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let length = time_to_duration(×_num);
|
times.push(RawTime {
|
||||||
times.push(length);
|
hours: times_num[0],
|
||||||
|
minutes: times_num[1],
|
||||||
|
seconds: times_num[2],
|
||||||
|
frames: times_num[3],
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
self.change_descriptor_state(&Descriptor::AudioContentsTD, &DescriptorAction::Close)
|
self.change_descriptor_state(&Descriptor::AudioContentsTD, &DescriptorAction::Close)
|
||||||
|
@ -1279,20 +1312,20 @@ impl NetMDInterface {
|
||||||
Ok(times)
|
Ok(times)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the length of a track as a [std::time::Duration]
|
/// Gets the length of a track as a raw duration
|
||||||
pub async fn track_length(
|
pub async fn track_length(
|
||||||
&mut self,
|
&mut self,
|
||||||
track: u16,
|
track: u16,
|
||||||
) -> Result<std::time::Duration, InterfaceError> {
|
) -> Result<RawTime, InterfaceError> {
|
||||||
Ok(self.track_lengths([track].into()).await?[0])
|
Ok(self.track_lengths([track].into()).await?[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the encoding of a track (SP, LP2, LP4)
|
/// Gets the encoding of a track (SP, LP2, LP4)
|
||||||
pub async fn track_encoding(&mut self, track_number: u16) -> Result<Encoding, InterfaceError> {
|
pub async fn track_encoding(&mut self, track_number: u16) -> Result<(Encoding, Channels), InterfaceError> {
|
||||||
let raw_value = self.raw_track_info(track_number, 0x3080, 0x0700).await?;
|
let raw_value = self.raw_track_info(track_number, 0x3080, 0x0700).await?;
|
||||||
let result = scan_query(raw_value, "07 0004 0110 %b %b".to_string())?;
|
let result = scan_query(raw_value, "07 0004 0110 %b %b".to_string())?;
|
||||||
|
|
||||||
let final_encoding = match result[0].to_i64() {
|
let encoding = match result[0].to_i64() {
|
||||||
Ok(0x90) => Encoding::SP,
|
Ok(0x90) => Encoding::SP,
|
||||||
Ok(0x92) => Encoding::LP2,
|
Ok(0x92) => Encoding::LP2,
|
||||||
Ok(0x93) => Encoding::LP4,
|
Ok(0x93) => Encoding::LP4,
|
||||||
|
@ -1300,7 +1333,14 @@ impl NetMDInterface {
|
||||||
Err(_) => unreachable!(),
|
Err(_) => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(final_encoding)
|
let channels = match result[0].to_i64() {
|
||||||
|
Ok(0x01) => Channels::Stereo,
|
||||||
|
Ok(0x00) => Channels::Mono,
|
||||||
|
Ok(e) => return Err(InterfaceError::InvalidEncoding(e as u8)),
|
||||||
|
Err(_) => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok((encoding, channels))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets a track's flags
|
/// Gets a track's flags
|
||||||
|
@ -1323,36 +1363,34 @@ impl NetMDInterface {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the disc capacity as a [std::time::Duration]
|
/// Gets the disc capacity as a [std::time::Duration]
|
||||||
pub async fn disc_capacity(&mut self) -> Result<[std::time::Duration; 3], InterfaceError> {
|
pub async fn disc_capacity(&mut self) -> Result<[RawTime; 3], InterfaceError> {
|
||||||
self.change_descriptor_state(&Descriptor::RootTD, &DescriptorAction::OpenRead)
|
self.change_descriptor_state(&Descriptor::RootTD, &DescriptorAction::OpenRead)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let mut query = format_query("1806 02101000 3080 0300 ff00 00000000".to_string(), vec![])?;
|
let mut query = format_query("1806 02101000 3080 0300 ff00 00000000".to_string(), vec![])?;
|
||||||
let reply = self.send_query(&mut query, false, false).await?;
|
let reply = self.send_query(&mut query, false, false).await?;
|
||||||
let mut result: [std::time::Duration; 3] = [std::time::Duration::from_secs(0); 3];
|
|
||||||
|
|
||||||
// 8003 changed to %?03 - Panasonic returns 0803 instead. This byte's meaning is unknown
|
// 8003 changed to %?03 - Panasonic returns 0803 instead. This byte's meaning is unknown
|
||||||
let res = scan_query(
|
let res = scan_query(
|
||||||
reply,
|
reply,
|
||||||
"1806 02101000 3080 0300 1000 001d0000 001b %?03 0017 8000 0005 %W %B %B %B 0005 %W %B %B %B 0005 %W %B %B %B".to_string()
|
"1806 02101000 3080 0300 1000 001d0000 001b %?03 0017 8000 0005 %W %B %B %B 0005 %W %B %B %B 0005 %W %B %B %B".to_string()
|
||||||
)?; //25^
|
)?;
|
||||||
let res_num: Vec<u64> = res
|
|
||||||
.into_iter()
|
|
||||||
.map(|v| v.to_i64().unwrap() as u64)
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
// Create 3 values, `Frames Used`, `Frames Total`, and `Frames Left`
|
let res_num: Vec<RawTime> = res
|
||||||
for i in 0..3 {
|
.windows(4)
|
||||||
let tmp = &res_num[(4 * i)..=(4 * i) + 3];
|
.step_by(4)
|
||||||
let time_micros =
|
.map(|t| RawTime {
|
||||||
(tmp[0] * 3600000000) + (tmp[1] * 60000000) + (tmp[2] * 1000000) + (tmp[3] * 11600);
|
hours: t[0].to_i64().unwrap() as u64,
|
||||||
result[i] = std::time::Duration::from_micros(time_micros);
|
minutes: t[1].to_i64().unwrap() as u64,
|
||||||
}
|
seconds: t[2].to_i64().unwrap() as u64,
|
||||||
|
frames: t[3].to_i64().unwrap() as u64,
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
self.change_descriptor_state(&Descriptor::RootTD, &DescriptorAction::Close)
|
self.change_descriptor_state(&Descriptor::RootTD, &DescriptorAction::Close)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(result)
|
Ok(res_num.try_into().unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn recording_parameters(&mut self) -> Result<Vec<u8>, InterfaceError> {
|
pub async fn recording_parameters(&mut self) -> Result<Vec<u8>, InterfaceError> {
|
||||||
|
@ -1724,15 +1762,6 @@ pub fn retailmac(key: &[u8], value: &[u8], iv: &[u8; 8]) -> Vec<u8> {
|
||||||
end[..8].to_vec()
|
end[..8].to_vec()
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_static! {
|
|
||||||
static ref DISC_FOR_WIRE: HashMap<WireFormat, DiscFormat> = HashMap::from([
|
|
||||||
(WireFormat::Pcm, DiscFormat::SPStereo),
|
|
||||||
(WireFormat::LP2, DiscFormat::LP2),
|
|
||||||
(WireFormat::L105kbps, DiscFormat::LP2),
|
|
||||||
(WireFormat::LP4, DiscFormat::LP4),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct EKBData {
|
pub struct EKBData {
|
||||||
chains: [[u8; 16]; 2],
|
chains: [[u8; 16]; 2],
|
||||||
depth: i32,
|
depth: i32,
|
||||||
|
@ -1811,7 +1840,7 @@ impl MDTrack {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn frame_size(&self) -> usize {
|
pub fn frame_size(&self) -> usize {
|
||||||
*FRAME_SIZE.get(&self.format).unwrap()
|
self.format.frame_size() as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn chunk_size(&self) -> usize {
|
pub fn chunk_size(&self) -> usize {
|
||||||
|
@ -1907,7 +1936,7 @@ impl<'a> MDSession<'a> {
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
let data_format = track.data_format();
|
let data_format = track.data_format();
|
||||||
let final_disc_format = disc_format.unwrap_or(*DISC_FOR_WIRE.get(&data_format).unwrap());
|
let final_disc_format = disc_format.unwrap_or(data_format.disc_for_wire());
|
||||||
|
|
||||||
let (track_index, uuid, ccid) = self
|
let (track_index, uuid, ccid) = self
|
||||||
.md
|
.md
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,23 +1,19 @@
|
||||||
use crate::netmd::utils;
|
use crate::netmd::utils;
|
||||||
use lazy_static::lazy_static;
|
|
||||||
use std::collections::hash_map::HashMap;
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
lazy_static! {
|
/// %b, w, d, q - explained above (can have endiannes overriden by '>' and '<' operators, f. ex. %>d %<q)
|
||||||
/// %b, w, d, q - explained above (can have endiannes overriden by '>' and '<' operators, f. ex. %>d %<q)
|
/// %s - Uint8Array preceded by 2 bytes of length
|
||||||
/// %s - Uint8Array preceded by 2 bytes of length
|
/// %x - Uint8Array preceded by 2 bytes of length
|
||||||
/// %x - Uint8Array preceded by 2 bytes of length
|
/// %z - Uint8Array preceded by 1 byte of length
|
||||||
/// %z - Uint8Array preceded by 1 byte of length
|
/// %* - raw Uint8Array
|
||||||
/// %* - raw Uint8Array
|
/// %B - BCD-encoded 1-byte number
|
||||||
/// %B - BCD-encoded 1-byte number
|
/// %W - BCD-encoded 2-byte number
|
||||||
/// %W - BCD-encoded 2-byte number
|
static FORMAT_TYPE_LEN_DICT: phf::Map<char, i32> = phf::phf_map!{
|
||||||
static ref FORMAT_TYPE_LEN_DICT: HashMap<char, i32> = HashMap::from([
|
'b' => 1, // byte
|
||||||
('b', 1), // byte
|
'w' => 2, // word
|
||||||
('w', 2), // word
|
'd' => 4, // doubleword
|
||||||
('d', 4), // doubleword
|
'q' => 8, // quadword
|
||||||
('q', 8), // quadword
|
};
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
const DEBUG: bool = false;
|
const DEBUG: bool = false;
|
||||||
|
|
||||||
|
@ -37,11 +33,11 @@ pub enum ValueError {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl QueryValue {
|
impl QueryValue {
|
||||||
pub fn from_array<const S: usize>(value: [u8; S]) -> Self {
|
pub fn _from_array<const S: usize>(value: [u8; S]) -> Self {
|
||||||
Self::Array(value.to_vec())
|
Self::Array(value.to_vec())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_array<const S: usize>(&self) -> Result<[u8; S], ValueError> {
|
pub fn _to_array<const S: usize>(&self) -> Result<[u8; S], ValueError> {
|
||||||
let mut array = [0u8; S];
|
let mut array = [0u8; S];
|
||||||
match self {
|
match self {
|
||||||
QueryValue::Array(a) => {
|
QueryValue::Array(a) => {
|
||||||
|
@ -78,6 +74,20 @@ impl QueryValue {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TryInto<i64> for QueryValue {
|
||||||
|
type Error = ValueError;
|
||||||
|
|
||||||
|
fn try_into(self) -> Result<i64, Self::Error> {
|
||||||
|
match self {
|
||||||
|
QueryValue::Number(a) => Ok(a),
|
||||||
|
_ => Err(ValueError::TypeMismatch {
|
||||||
|
expected: String::from("i64"),
|
||||||
|
actual: format!("{:?}", self)
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Error, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Error, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub enum QueryError {
|
pub enum QueryError {
|
||||||
#[error("unrecognized format character: `{0}`")]
|
#[error("unrecognized format character: `{0}`")]
|
||||||
|
|
|
@ -8,7 +8,7 @@ use unicode_normalization::UnicodeNormalization;
|
||||||
extern crate kana;
|
extern crate kana;
|
||||||
use kana::*;
|
use kana::*;
|
||||||
|
|
||||||
/// Sleep for a specified number of milliseconds on any platform
|
/// Sleep for a specified [Duration] on any platform
|
||||||
pub async fn cross_sleep(duration: Duration) {
|
pub async fn cross_sleep(duration: Duration) {
|
||||||
#[cfg(not(target_family = "wasm"))]
|
#[cfg(not(target_family = "wasm"))]
|
||||||
std::thread::sleep(duration);
|
std::thread::sleep(duration);
|
||||||
|
@ -75,29 +75,34 @@ pub fn get_bytes<const S: usize>(iterator: &mut IntoIter<u8>) -> Result<[u8; S],
|
||||||
Ok(bytes)
|
Ok(bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn length_after_encoding_to_jis(string: &str) -> usize {
|
pub fn length_after_encoding_to_sjis(string: &str) -> usize {
|
||||||
let new_string = SHIFT_JIS.encode(string);
|
let new_string = SHIFT_JIS.encode(string);
|
||||||
|
|
||||||
new_string.0.len()
|
new_string.0.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn validate_shift_jis(sjis_string: Vec<u8>) -> bool {
|
pub fn validate_sjis(sjis_string: Vec<u8>) -> bool {
|
||||||
let (_, _, had_errors) = SHIFT_JIS.decode(&sjis_string);
|
let (_, _, had_errors) = SHIFT_JIS.decode(&sjis_string);
|
||||||
|
|
||||||
had_errors
|
had_errors
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Ensure string contains only hardware allowed characters
|
||||||
fn check(string: String) -> Option<String> {
|
fn check(string: String) -> Option<String> {
|
||||||
if MAPPINGS_HW.contains_key(&string) {
|
if MAPPINGS_HW.contains_key(string.as_str()) {
|
||||||
return Some(MAPPINGS_HW.get(&string).unwrap().to_string());
|
return Some(MAPPINGS_HW.get(string.as_str()).unwrap().to_string());
|
||||||
}
|
}
|
||||||
let mut ch = string.chars();
|
let mut ch = string.chars();
|
||||||
if (ch.next().unwrap() as u32) < 0x7f || ALLOWED_HW_KANA.contains(&string) {
|
if (ch.next().unwrap() as u32) < 0x7f || ALLOWED_HW_KANA.contains(&string.as_str()) {
|
||||||
return Some(string);
|
return Some(string);
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn half_width_title_length(title: &str) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
pub fn sanitize_half_width_title(title: &str) -> Vec<u8> {
|
pub fn sanitize_half_width_title(title: &str) -> Vec<u8> {
|
||||||
let mut string_title = wide2ascii(title);
|
let mut string_title = wide2ascii(title);
|
||||||
string_title = nowidespace(&string_title);
|
string_title = nowidespace(&string_title);
|
||||||
|
@ -115,7 +120,7 @@ pub fn sanitize_half_width_title(title: &str) -> Vec<u8> {
|
||||||
|
|
||||||
let sjis_string = SHIFT_JIS.encode(&new_title).0;
|
let sjis_string = SHIFT_JIS.encode(&new_title).0;
|
||||||
|
|
||||||
if validate_shift_jis(sjis_string.clone().into()) {
|
if validate_sjis(sjis_string.clone().into()) {
|
||||||
return agressive_sanitize_title(title).into();
|
return agressive_sanitize_title(title).into();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,24 +131,25 @@ pub fn sanitize_half_width_title(title: &str) -> Vec<u8> {
|
||||||
pub fn sanitize_full_width_title(title: &str, just_remap: bool) -> Vec<u8> {
|
pub fn sanitize_full_width_title(title: &str, just_remap: bool) -> Vec<u8> {
|
||||||
let new_title: String = title
|
let new_title: String = title
|
||||||
.chars()
|
.chars()
|
||||||
|
.map(|c| c.to_string())
|
||||||
.map(|character| {
|
.map(|character| {
|
||||||
match MAPPINGS_JP.get(&character.to_string()) {
|
match MAPPINGS_JP.get(character.to_string().as_str()) {
|
||||||
Some(string) => string.clone(),
|
Some(string) => string,
|
||||||
None => character.to_string().clone(),
|
None => character.as_str(),
|
||||||
}
|
}
|
||||||
.to_string()
|
.to_string()
|
||||||
})
|
})
|
||||||
.map(|character| {
|
.map(|character| {
|
||||||
match MAPPINGS_RU.get(&character.to_string()) {
|
match MAPPINGS_RU.get(character.as_str()) {
|
||||||
Some(string) => string.clone(),
|
Some(string) => string,
|
||||||
None => character.to_string().clone(),
|
None => character.as_str(),
|
||||||
}
|
}
|
||||||
.to_string()
|
.to_string()
|
||||||
})
|
})
|
||||||
.map(|character| {
|
.map(|character| {
|
||||||
match MAPPINGS_DE.get(&character.to_string()) {
|
match MAPPINGS_DE.get(character.as_str()) {
|
||||||
Some(string) => string.clone(),
|
Some(string) => string,
|
||||||
None => character.to_string().clone(),
|
None => character.as_str(),
|
||||||
}
|
}
|
||||||
.to_string()
|
.to_string()
|
||||||
})
|
})
|
||||||
|
@ -155,7 +161,7 @@ pub fn sanitize_full_width_title(title: &str, just_remap: bool) -> Vec<u8> {
|
||||||
|
|
||||||
let sjis_string = SHIFT_JIS.encode(&new_title).0;
|
let sjis_string = SHIFT_JIS.encode(&new_title).0;
|
||||||
|
|
||||||
if validate_shift_jis(sjis_string.clone().into()) {
|
if validate_sjis(sjis_string.clone().into()) {
|
||||||
return agressive_sanitize_title(title).into();
|
return agressive_sanitize_title(title).into();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,9 +179,28 @@ pub fn agressive_sanitize_title(title: &str) -> String {
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn time_to_duration(time: &[u64]) -> std::time::Duration {
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
assert_eq!(time.len(), 4);
|
pub struct RawTime {
|
||||||
std::time::Duration::from_micros(
|
pub hours: u64,
|
||||||
(time[0] * 3600000000) + (time[1] * 60000000) + (time[2] * 1000000) + (time[3] * 11600),
|
pub minutes: u64,
|
||||||
)
|
pub seconds: u64,
|
||||||
|
pub frames: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<Duration> for RawTime {
|
||||||
|
fn into(self) -> std::time::Duration {
|
||||||
|
self.as_duration()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RawTime {
|
||||||
|
pub fn as_duration(&self) -> Duration {
|
||||||
|
std::time::Duration::from_micros(
|
||||||
|
(self.hours * 3600000000) + (self.minutes * 60000000) + (self.seconds * 1000000) + (self.frames * 11600),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_frames(&self) -> u64 {
|
||||||
|
((self.hours * 60 + self.minutes) * 60 + self.seconds) * 512 + self.frames
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue