lipsync/Boare.Lib.Vsq/VsqUtil.cs
2024-05-20 00:17:44 +00:00

391 lines
15 KiB
C#

/*
* VsqUtil.cs
* Copyright (c) 2008-2009 kbinani
*
* This file is part of Boare.Lib.Vsq.
*
* Boare.Lib.Vsq is free software; you can redistribute it and/or
* modify it under the terms of the BSD License.
*
* Boare.Lib.Vsq is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
using System;
using System.IO;
using System.Text;
using System.Collections.Generic;
using bocoree;
namespace Boare.Lib.Vsq {
/// <summary>
/// Represents the voice language of singer.
/// </summary>
public enum VsqVoiceLanguage : int {
/// <summary>
/// Default value, equivalent to "Japanese".
/// </summary>
Default = 0,
/// <summary>
/// Japanese
/// </summary>
Japanese = 0,
/// <summary>
/// English
/// </summary>
English = 1,
}
/// <summary>
/// Static library to treat the information of VOCALOID2 system.
/// </summary>
public static class VsqUtil {
/// <summary>
/// Maximum number of singers which can be allowed in VOCALOID2 system.
/// </summary>
public const uint MAX_SINGERS = 0x4000;
private static string s_dll2_path = "";
private static string s_dll1_path = "";
private static string s_exp_db_dir = "";
private static bool s_initialized = false;
private static Dictionary<int, SingerConfig> s_singer_configs = null;
private static List<SingerConfig> s_installed_singers = new List<SingerConfig>();
private static string s_editor_path = "";
public static double getAmplifyCoeffFromPanLeft( int pan ) {
return pan / -64.0 + 1.0;
}
public static double getAmplifyCoeffFromPanRight( int pan ) {
return pan / 64.0 + 1.0;
}
public static double getAmplifyCoeffFromFeder( int feder ) {
return Math.Exp( -1.26697245e-02 + 1.18448420e-01 * feder / 10.0 );
}
/// <summary>
/// Gets the list of installed singers which is installed in the computer.
/// </summary>
/// <returns></returns>
public static SingerConfig[] getInstalledSingers() {
return s_installed_singers.ToArray();
}
/// <summary>
/// Gets the list of singer configs.
/// </summary>
/// <returns></returns>
public static Dictionary<int, SingerConfig> getSingerConfigs() {
Dictionary<int, SingerConfig> ret = new Dictionary<int, SingerConfig>();
foreach ( KeyValuePair<int, SingerConfig> kvp in s_singer_configs ) {
ret.Add( kvp.Key, kvp.Value );
}
return ret;
}
/// <summary>
/// Gets the path of VOCALOID Editor.
/// </summary>
public static string getEditorPath() {
if ( !s_initialized ) {
init();
}
return s_editor_path;
}
/// <summary>
/// Gets the voice language of specified program change
/// </summary>
/// <param name="program_change">program change to get the voice language</param>
/// <returns></returns>
public static VsqVoiceLanguage getLanguage( int program_change ) {
string name = getOriginalSinger( program_change );
switch ( name ) {
case "Miku":
case "Rin":
case "Len":
case "Rin_ACT2":
case "Len_ACT2":
case "Gackpoid":
case "Luka_JPN":
return VsqVoiceLanguage.Japanese;
case "Sweet_Ann":
case "Prima":
case "Luka_ENG":
return VsqVoiceLanguage.English;
}
return VsqVoiceLanguage.Default;
}
/// <summary>
/// Gets the name of original singer of specified program change.
/// </summary>
/// <param name="program_change"></param>
/// <returns></returns>
public static string getOriginalSinger( int program_change ) {
if ( s_singer_configs == null ) {
loadSingerConfigs();
}
if ( s_singer_configs.ContainsKey( program_change ) ) {
SingerConfig sc = getSingerInfo( program_change );
string voiceidstr = sc.VOICEIDSTR;
foreach ( SingerConfig installed in s_installed_singers ) {
if ( installed.VOICEIDSTR == voiceidstr ) {
return installed.VOICENAME;
}
}
}
return "";
}
/// <summary>
/// Gets the VsqID of program change.
/// </summary>
/// <param name="program_change"></param>
/// <returns></returns>
public static VsqID getSingerID( int program_change ) {
VsqID ret = new VsqID( 0 );
ret.type = VsqIDType.Singer;
SingerConfig sc = getSingerInfo( program_change );
int lang = 0;
foreach ( SingerConfig sc2 in s_installed_singers ) {
if ( sc.VOICEIDSTR == sc2.VOICEIDSTR ) {
switch ( sc2.VOICENAME ) {
case "Miku":
lang = 0;
break;
}
}
}
ret.IconHandle = new IconHandle();
ret.IconHandle.IconID = "$0701" + program_change.ToString( "0000" );
ret.IconHandle.IDS = sc.VOICENAME;
ret.IconHandle.Index = 0;
ret.IconHandle.Language = lang;
ret.IconHandle.Length = 1;
ret.IconHandle.Original = sc.Original;
ret.IconHandle.Program = program_change;
ret.IconHandle.Caption = "";
return ret;
}
/// <summary>
/// Gets the singer information of pecified program change.
/// </summary>
/// <param name="program_change"></param>
/// <returns></returns>
public static SingerConfig getSingerInfo( int program_change ) {
if ( s_singer_configs == null ) {
loadSingerConfigs();
}
if ( s_singer_configs.ContainsKey( program_change ) ) {
return s_singer_configs[program_change];
} else {
return null;
}
}
/// <summary>
/// Loads the singer config from ExpDbPath.
/// This method will automatically called when GetSingerInfo method or GetSingerID method is called in first time.
/// </summary>
public static void loadSingerConfigs() {
if ( s_singer_configs == null ) {
loadSingerConfigs( getExpDbPath() );
}
}
/// <summary>
/// Loads the list of singer configuration from the specified path.
/// Keys in the dictionary "s_singer_configs" represents the program change of each singer.
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
private static void loadSingerConfigs( string path ) {
#if DEBUG
bocoree.debug.push_log( "SingerConfig+LoadSingerConfigs(String)" );
#endif
s_singer_configs = new Dictionary<int, SingerConfig>();
string map_file = Path.Combine( path, "voice.map" );
if ( !File.Exists( map_file ) ) {
return;
}
using ( FileStream fs = new FileStream( map_file, FileMode.Open, FileAccess.Read ) ) {
byte[] dat = new byte[8];
fs.Seek( 0x20, SeekOrigin.Begin );
for ( int i = 0; i < MAX_SINGERS; i++ ) {
fs.Read( dat, 0, 8 );
ulong value = makelong_le( dat );
if ( value >= 1 ) {
string file = Path.Combine( path, "vvoice" + value + ".vvd" );
if ( File.Exists( file ) ) {
s_singer_configs.Add( i, new SingerConfig( file, (int)(value - 1) ) );
}
}
}
}
List<string> voiceidstrs = new List<string>();
foreach ( SingerConfig sc in s_singer_configs.Values ) {
if ( !voiceidstrs.Contains( sc.VOICEIDSTR ) ) {
voiceidstrs.Add( sc.VOICEIDSTR );
}
}
foreach ( string s in voiceidstrs ) {
string dir = Path.Combine( path, s );
string[] files = Directory.GetFiles( dir, "*.vvd" );
foreach ( string s2 in files ) {
string file = Path.Combine( dir, s2 );
if ( File.Exists( file ) ) {
s_installed_singers.Add( new SingerConfig( file, -1 ) );
}
}
}
#if DEBUG
bocoree.debug.push_log( " s_singer_configs" );
foreach ( SingerConfig sc in s_singer_configs.Values ) {
bocoree.debug.push_log( " VOICENAME=" + sc.VOICENAME );
}
bocoree.debug.push_log( " s_installed_singers" );
foreach( SingerConfig sc in s_installed_singers ){
bocoree.debug.push_log( " VOICENAME=" + sc.VOICENAME );
}
#endif
}
/// <summary>
/// Transform the byte array(length=8) to unsigned long, assuming that the byte array is little endian.
/// </summary>
/// <param name="oct"></param>
/// <returns></returns>
private static ulong makelong_le( byte[] oct ) {
return (ulong)oct[7] << 56 | (ulong)oct[6] << 48 | (ulong)oct[5] << 40 | (ulong)oct[4] << 32 | (ulong)oct[3] << 24 | (ulong)oct[2] << 16 | (ulong)oct[1] << 8 | (ulong)oct[0];
}
/// <summary>
/// Gets the path of VOCALOID2 Playback VSTi dll.
/// </summary>
/// <returns></returns>
public static string getDllPathVsti2() {
if ( !s_initialized ) {
init();
}
return s_dll2_path;
}
/// <summary>
/// Gets the path of VOCALOID1 Playback VSTi dll.
/// </summary>
/// <returns></returns>
public static string getDllPathVsti1() {
if ( !s_initialized ) {
init();
}
return s_dll1_path;
}
/// <summary>
/// Initializes the library.
/// </summary>
private static void init() {
try {
#if DEBUG
bocoree.debug.push_log( "VsqUtil+Init()" );
#endif
// vocaloid2 dll path
Microsoft.Win32.RegistryKey regkey_dll = null;
regkey_dll = Microsoft.Win32.Registry.LocalMachine.OpenSubKey( "SOFTWARE\\VOCALOID2\\APPLICATION", false );
if ( regkey_dll == null ) {
regkey_dll = Microsoft.Win32.Registry.LocalMachine.OpenSubKey( "SOFTWARE\\VOCALOID2_DEMO\\APPLICATION", false );
}
if ( regkey_dll != null ) {
string[] keys = regkey_dll.GetSubKeyNames();
for ( int i = 0; i < keys.Length; i++ ) {
Microsoft.Win32.RegistryKey key = regkey_dll.OpenSubKey( keys[i], false );
if ( key != null ) {
string name = (string)key.GetValue( "PATH" );
if ( name.ToLower().EndsWith( "\\vocaloid2.dll" ) ) {
s_dll2_path = name;
} else if ( name.ToLower().EndsWith( "\\vocaloid2_demo.dll" ) ) {
s_dll2_path = name;
} else if ( name.ToLower().EndsWith( "\\vocaloid2.exe" ) ) {
s_editor_path = name;
}
key.Close();
}
}
regkey_dll.Close();
}
// vocaloid1 dll path
Microsoft.Win32.RegistryKey regkey_dll1 = null;
regkey_dll1 = Microsoft.Win32.Registry.LocalMachine.OpenSubKey( "SOFTWARE\\VOCALOID\\APPLICATION", false );
if ( regkey_dll1 != null ){
string[] keys = regkey_dll1.GetSubKeyNames();
for ( int i = 0; i < keys.Length; i++ ) {
Microsoft.Win32.RegistryKey key = regkey_dll1.OpenSubKey( keys[i], false );
if ( key != null ) {
string name = (string)key.GetValue( "PATH" );
if ( name.ToLower().EndsWith( "\\vocaloid.dll" ) ) {
s_dll1_path = name;
key.Close();
break;
}
key.Close();
}
}
regkey_dll1.Close();
}
// voicedbdir
Microsoft.Win32.RegistryKey regkey_voicedb = Microsoft.Win32.Registry.LocalMachine.OpenSubKey( "SOFTWARE\\VOCALOID2\\DATABASE\\VOICE", false );
if ( regkey_voicedb == null ) {
regkey_voicedb = Microsoft.Win32.Registry.LocalMachine.OpenSubKey( "SOFTWARE\\VOCALOID2_DEMO\\DATABASE\\VOICE", false );
}
if ( regkey_voicedb != null ) {
string[] keys = regkey_voicedb.GetSubKeyNames();
for ( int i = 0; i < keys.Length; i++ ) {
Microsoft.Win32.RegistryKey key = regkey_voicedb.OpenSubKey( keys[i], false );
if ( key != null ) {
string name = (string)key.GetValue( "INSTALLDIR" );
if ( name.ToLower().EndsWith( "\\voicedbdir" ) ) {
s_exp_db_dir = name;
break;
}
key.Close();
}
}
regkey_voicedb.Close();
}
} catch ( Exception ex ) {
bocoree.debug.push_log( "VsqUtil.Init" );
bocoree.debug.push_log( " ex=" + ex );
} finally {
s_initialized = true;
#if DEBUG
bocoree.debug.push_log( " s_dll2_path=" + s_dll2_path );
bocoree.debug.push_log( " s_exp_db_dir=" + s_exp_db_dir );
#endif
}
}
/// <summary>
/// Gets the path of directories in which singer expression database is installed.
/// </summary>
/// <returns></returns>
public static string getExpDbPath() {
if ( !s_initialized ) {
init();
}
return s_exp_db_dir;
}
}
}