1
0
mirror of synced 2024-11-24 07:30:21 +01:00

Squashed commit of the following:

commit c99443a7d3
Author: Ashiro12138 <ashiro12138@gmail.com>
Date:   Fri Jul 26 01:29:15 2024 +1000

    Chore/add editor config (#656)

    * Create .editorconfig

    * format ENTIRE project

    * Remove unnecessary import or usings

    Sort Imports or usings
    Apply file header preferences

    * Fix build error by adding import
This commit is contained in:
0auBSQ 2024-07-26 01:07:31 +09:00
parent c47c9c9400
commit 88a15defc1
274 changed files with 62002 additions and 76846 deletions

189
.editorconfig Normal file
View File

@ -0,0 +1,189 @@
# editorconfig.org
# top-most EditorConfig file
root = true
# Default settings:
# A newline ending every file
# Use 4 spaces as indentation
[*]
insert_final_newline = true
indent_style = tab
indent_size = 4
trim_trailing_whitespace = true
[project.json]
indent_size = 2
# Generated code
[*{_AssemblyInfo.cs,.notsupported.cs}]
generated_code = true
# C# files
[*.cs]
# New line preferences
csharp_new_line_before_open_brace = none
csharp_new_line_before_else = false
csharp_new_line_before_catch = false
csharp_new_line_before_finally = false
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_members_in_anonymous_types = true
csharp_new_line_between_query_expression_clauses = true
# Indentation preferences
csharp_indent_block_contents = true
csharp_indent_braces = false
csharp_indent_case_contents = true
csharp_indent_case_contents_when_block = true
csharp_indent_switch_labels = true
csharp_indent_labels = one_less_than_current
# Modifier preferences
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion
# avoid this. unless absolutely necessary
dotnet_style_qualification_for_field = false:suggestion
dotnet_style_qualification_for_property = false:suggestion
dotnet_style_qualification_for_method = false:suggestion
dotnet_style_qualification_for_event = false:suggestion
# Types: use keywords instead of BCL types, and permit var only when the type is clear
csharp_style_var_for_built_in_types = false:suggestion
csharp_style_var_when_type_is_apparent = false:none
csharp_style_var_elsewhere = false:suggestion
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
dotnet_style_predefined_type_for_member_access = true:suggestion
# name all constant fields using PascalCase
dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields
dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style
dotnet_naming_symbols.constant_fields.applicable_kinds = field
dotnet_naming_symbols.constant_fields.required_modifiers = const
dotnet_naming_style.pascal_case_style.capitalization = pascal_case
# static fields should have s_ prefix
dotnet_naming_rule.static_fields_should_have_prefix.severity = suggestion
dotnet_naming_rule.static_fields_should_have_prefix.symbols = static_fields
dotnet_naming_rule.static_fields_should_have_prefix.style = static_prefix_style
dotnet_naming_symbols.static_fields.applicable_kinds = field
dotnet_naming_symbols.static_fields.required_modifiers = static
dotnet_naming_symbols.static_fields.applicable_accessibilities = private, internal, private_protected
dotnet_naming_style.static_prefix_style.required_prefix = s_
dotnet_naming_style.static_prefix_style.capitalization = camel_case
# internal and private fields should be _camelCase
dotnet_naming_rule.camel_case_for_private_internal_fields.severity = suggestion
dotnet_naming_rule.camel_case_for_private_internal_fields.symbols = private_internal_fields
dotnet_naming_rule.camel_case_for_private_internal_fields.style = camel_case_underscore_style
dotnet_naming_symbols.private_internal_fields.applicable_kinds = field
dotnet_naming_symbols.private_internal_fields.applicable_accessibilities = private, internal
dotnet_naming_style.camel_case_underscore_style.required_prefix = _
dotnet_naming_style.camel_case_underscore_style.capitalization = camel_case
# Code style defaults
csharp_using_directive_placement = outside_namespace:suggestion
dotnet_sort_system_directives_first = true
csharp_prefer_braces = true:silent
csharp_preserve_single_line_blocks = true:none
csharp_preserve_single_line_statements = false:none
csharp_prefer_static_local_function = true:suggestion
csharp_prefer_simple_using_statement = false:none
csharp_style_prefer_switch_expression = true:suggestion
dotnet_style_readonly_field = true:suggestion
# Expression-level preferences
dotnet_style_object_initializer = true:suggestion
dotnet_style_collection_initializer = true:suggestion
dotnet_style_explicit_tuple_names = true:suggestion
dotnet_style_coalesce_expression = true:suggestion
dotnet_style_null_propagation = true:suggestion
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
dotnet_style_prefer_inferred_tuple_names = true:suggestion
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
dotnet_style_prefer_auto_properties = true:suggestion
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
dotnet_style_prefer_conditional_expression_over_return = true:silent
csharp_prefer_simple_default_expression = true:suggestion
# Expression-bodied members
csharp_style_expression_bodied_methods = true:silent
csharp_style_expression_bodied_constructors = true:silent
csharp_style_expression_bodied_operators = true:silent
csharp_style_expression_bodied_properties = true:silent
csharp_style_expression_bodied_indexers = true:silent
csharp_style_expression_bodied_accessors = true:silent
csharp_style_expression_bodied_lambdas = true:silent
csharp_style_expression_bodied_local_functions = true:silent
# Pattern matching
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
csharp_style_inlined_variable_declaration = true:suggestion
# Null checking preferences
csharp_style_throw_expression = true:suggestion
csharp_style_conditional_delegate_call = true:suggestion
# Other features
csharp_style_prefer_index_operator = false:none
csharp_style_prefer_range_operator = false:none
csharp_style_pattern_local_over_anonymous_function = false:none
# Space preferences
csharp_space_after_cast = false
csharp_space_after_colon_in_inheritance_clause = true
csharp_space_after_comma = true
csharp_space_after_dot = false
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_after_semicolon_in_for_statement = true
csharp_space_around_binary_operators = before_and_after
csharp_space_around_declaration_statements = do_not_ignore
csharp_space_before_colon_in_inheritance_clause = true
csharp_space_before_comma = false
csharp_space_before_dot = false
csharp_space_before_open_square_brackets = false
csharp_space_before_semicolon_in_for_statement = false
csharp_space_between_empty_square_brackets = false
csharp_space_between_method_call_empty_parameter_list_parentheses = false
csharp_space_between_method_call_name_and_opening_parenthesis = false
csharp_space_between_method_call_parameter_list_parentheses = false
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
csharp_space_between_method_declaration_name_and_open_parenthesis = false
csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_between_parentheses = false
csharp_space_between_square_brackets = false
# C++ Files
[*.{cpp,h,in}]
curly_bracket_next_line = true
indent_brace_style = Allman
# Xml project files
[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,nativeproj,locproj}]
indent_size = 2
[*.{csproj,vbproj,proj,nativeproj,locproj}]
charset = utf-8
# Xml build files
[*.builds]
indent_size = 2
# Xml files
[*.{xml,stylecop,resx,ruleset}]
indent_size = 2
# Xml config files
[*.{props,targets,config,nuspec}]
indent_size = 2
# YAML config files
[*.{yml,yaml}]
indent_size = 2
# Shell scripts
[*.sh]
end_of_line = lf
[*.{cmd,bat}]
end_of_line = crlf

View File

@ -1,22 +1,13 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace FDK
{
public class CActivity
{
namespace FDK {
public class CActivity {
// プロパティ
public bool IsActivated { get; private set; }
public bool IsDeActivated
{
get
{
public bool IsDeActivated {
get {
return !this.IsActivated;
}
set
{
set {
this.IsActivated = !value;
}
}
@ -32,8 +23,7 @@ namespace FDK
// コンストラクタ
public CActivity()
{
public CActivity() {
this.IsDeActivated = true;
this.ChildActivities = new List<CActivity>();
}
@ -44,10 +34,9 @@ namespace FDK
#region [ override ]
//-----------------
public virtual void Activate()
{
public virtual void Activate() {
// すでに活性化してるなら何もしない。
if( this.IsActivated )
if (this.IsActivated)
return;
this.IsActivated = true; // このフラグは、以下の処理をする前にセットする。
@ -57,16 +46,15 @@ namespace FDK
//this.CreateUnmanagedResource();
// すべての子 Activity を活性化する。
foreach( CActivity activity in this.ChildActivities )
foreach (CActivity activity in this.ChildActivities)
activity.Activate();
// その他の初期化
this.IsFirstDraw = true;
}
public virtual void DeActivate()
{
public virtual void DeActivate() {
// 活性化してないなら何もしない。
if( this.IsDeActivated )
if (this.IsDeActivated)
return;
// 自身のリソースを解放する。
@ -74,7 +62,7 @@ namespace FDK
//this.ReleaseManagedResource();
// すべての 子Activity を非活性化する。
foreach( CActivity activity in this.ChildActivities )
foreach (CActivity activity in this.ChildActivities)
activity.DeActivate();
this.IsDeActivated = true; // このフラグは、以上のメソッドを呼び出した後にセットする。
@ -87,10 +75,9 @@ namespace FDK
/// <para>いつどのタイミングで呼び出されるかいつDirect3Dが再作成されるか分からないので、
/// いつ何時呼び出されても問題無いようにコーディングしておくこと。</para>
/// </summary>
public virtual void CreateManagedResource()
{
public virtual void CreateManagedResource() {
// すべての 子Activity の Managed リソースを作成する。
foreach( CActivity activity in this.ChildActivities )
foreach (CActivity activity in this.ChildActivities)
activity.CreateManagedResource();
}
@ -101,10 +88,9 @@ namespace FDK
/// <para>いつどのタイミングで呼び出されるかいつDirect3Dが再作成またはリセットされるか分からないので、
/// いつ何時呼び出されても問題無いようにコーディングしておくこと。</para>
/// </summary>
public virtual void CreateUnmanagedResource()
{
public virtual void CreateUnmanagedResource() {
// すべての 子Activity の Unmanaged リソースを作成する。
foreach( CActivity activity in this.ChildActivities )
foreach (CActivity activity in this.ChildActivities)
activity.CreateUnmanagedResource();
}
@ -114,14 +100,13 @@ namespace FDK
/// <para>いつどのタイミングで呼び出されるかいつDirect3Dが解放またはリセットされるか分からないので、
/// いつ何時呼び出されても問題無いようにコーディングしておくこと。</para>
/// </summary>
public virtual void ReleaseUnmanagedResource()
{
public virtual void ReleaseUnmanagedResource() {
// 活性化してないなら何もしない。
if( this.IsDeActivated )
if (this.IsDeActivated)
return;
// すべての 子Activity の Unmanaged リソースを解放する。
foreach( CActivity activity in this.ChildActivities )
foreach (CActivity activity in this.ChildActivities)
activity.ReleaseUnmanagedResource();
}
@ -132,14 +117,13 @@ namespace FDK
/// <para>いつどのタイミングで呼び出されるかいつDirect3Dが解放されるか分からないので、
/// いつ何時呼び出されても問題無いようにコーディングしておくこと。</para>
/// </summary>
public virtual void ReleaseManagedResource()
{
public virtual void ReleaseManagedResource() {
// 活性化してないなら何もしない。
if( this.IsDeActivated )
if (this.IsDeActivated)
return;
// すべての 子Activity の Managed リソースを解放する。
foreach( CActivity activity in this.ChildActivities )
foreach (CActivity activity in this.ChildActivities)
activity.ReleaseManagedResource();
}
@ -148,10 +132,9 @@ namespace FDK
/// <para>このメソッドは BeginScene() の後に呼び出されるので、メソッド内でいきなり描画を行ってかまわない。</para>
/// </summary>
/// <returns>任意の整数。呼び出し元との整合性を合わせておくこと。</returns>
public virtual int Draw()
{
public virtual int Draw() {
// 活性化してないなら何もしない。
if( this.IsDeActivated )
if (this.IsDeActivated)
return 0;

View File

@ -1,11 +1,5 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace FDK
{
public class CConversion
{
namespace FDK {
public class CConversion {
// プロパティ
public static readonly string str16進数文字 = "0123456789ABCDEFabcdef";
@ -14,194 +8,175 @@ namespace FDK
// メソッド
public static bool bONorOFF( char c )
{
return ( c != '0' );
public static bool bONorOFF(char c) {
return (c != '0');
}
public static double DegreeToRadian( double angle )
{
return ( ( Math.PI * angle ) / 180.0 );
public static double DegreeToRadian(double angle) {
return ((Math.PI * angle) / 180.0);
}
public static double RadianToDegree( double angle )
{
return ( angle * 180.0 / Math.PI );
public static double RadianToDegree(double angle) {
return (angle * 180.0 / Math.PI);
}
public static float DegreeToRadian( float angle )
{
return (float) DegreeToRadian( (double) angle );
public static float DegreeToRadian(float angle) {
return (float)DegreeToRadian((double)angle);
}
public static float RadianToDegree( float angle )
{
return (float) RadianToDegree( (double) angle );
public static float RadianToDegree(float angle) {
return (float)RadianToDegree((double)angle);
}
public static int n値を範囲内に丸めて返す( int value, int min, int max )
{
if( value < min )
public static int n値を範囲内に丸めて返す(int value, int min, int max) {
if (value < min)
return min;
if( value > max )
if (value > max)
return max;
return value;
}
public static int n値を文字列から取得して範囲内に丸めて返す( string text, int min, int max, int defaultValue )
{
public static int n値を文字列から取得して範囲内に丸めて返す(string text, int min, int max, int defaultValue) {
int num;
if( ( int.TryParse( text, out num ) && ( num >= min ) ) && ( num <= max ) )
if ((int.TryParse(text, out num) && (num >= min)) && (num <= max))
return num;
return defaultValue;
}
public static double db値を文字列から取得して範囲内に丸めて返す( string text, double min, double max, double defaultValue )
{
public static double db値を文字列から取得して範囲内に丸めて返す(string text, double min, double max, double defaultValue) {
double num;
if( ( double.TryParse( text, out num ) && ( num >= min ) ) && ( num <= max ) )
if ((double.TryParse(text, out num) && (num >= min)) && (num <= max))
return num;
return defaultValue;
}
// #23568 2010.11.04 ikanick add
public static int n値を文字列から取得して範囲内にちゃんと丸めて返す(string text, int min, int max, int defaultValue)
{
public static int n値を文字列から取得して範囲内にちゃんと丸めて返す(string text, int min, int max, int defaultValue) {
// 1 と違って範囲外の場合ちゃんと丸めて返します。
int num;
if (int.TryParse(text, out num)) {
if ((num >= min) && (num <= max))
return num;
if ( num < min )
if (num < min)
return min;
if ( num > max )
if (num > max)
return max;
}
return defaultValue;
}
// --------------------ここまで-------------------------/
public static int StringToInt( string text, int defaultValue )
{
public static int StringToInt(string text, int defaultValue) {
int num;
if( !int.TryParse( text, out num ) )
if (!int.TryParse(text, out num))
num = defaultValue;
return num;
}
public static int n16進数2桁の文字列を数値に変換して返す( string strNum )
{
if( strNum.Length < 2 )
public static int n16進数2桁の文字列を数値に変換して返す(string strNum) {
if (strNum.Length < 2)
return -1;
int digit2 = str16進数文字.IndexOf( strNum[ 0 ] );
if( digit2 < 0 )
int digit2 = str16進数文字.IndexOf(strNum[0]);
if (digit2 < 0)
return -1;
if( digit2 >= 16 )
if (digit2 >= 16)
digit2 -= (16 - 10); // A,B,C... -> 1,2,3...
int digit1 = str16進数文字.IndexOf( strNum[ 1 ] );
if( digit1 < 0 )
int digit1 = str16進数文字.IndexOf(strNum[1]);
if (digit1 < 0)
return -1;
if( digit1 >= 16 )
if (digit1 >= 16)
digit1 -= (16 - 10);
return digit2 * 16 + digit1;
}
public static int n36進数2桁の文字列を数値に変換して返す( string strNum )
{
if( strNum.Length < 2 )
public static int n36進数2桁の文字列を数値に変換して返す(string strNum) {
if (strNum.Length < 2)
return -1;
int digit2 = str36進数文字.IndexOf( strNum[ 0 ] );
if( digit2 < 0 )
int digit2 = str36進数文字.IndexOf(strNum[0]);
if (digit2 < 0)
return -1;
if( digit2 >= 36 )
if (digit2 >= 36)
digit2 -= (36 - 10); // A,B,C... -> 1,2,3...
int digit1 = str36進数文字.IndexOf( strNum[ 1 ] );
if( digit1 < 0 )
int digit1 = str36進数文字.IndexOf(strNum[1]);
if (digit1 < 0)
return -1;
if( digit1 >= 36 )
if (digit1 >= 36)
digit1 -= (36 - 10);
return digit2 * 36 + digit1;
}
public static int n小節番号の文字列3桁を数値に変換して返す( string strNum )
{
if( strNum.Length >= 3 )
{
int digit3 = str36進数文字.IndexOf( strNum[ 0 ] );
if( digit3 < 0 )
public static int n小節番号の文字列3桁を数値に変換して返す(string strNum) {
if (strNum.Length >= 3) {
int digit3 = str36進数文字.IndexOf(strNum[0]);
if (digit3 < 0)
return -1;
if( digit3 >= 36 ) // 3桁目は36進数
if (digit3 >= 36) // 3桁目は36進数
digit3 -= (36 - 10);
int digit2 = str16進数文字.IndexOf( strNum[ 1 ] ); // 2桁目は10進数
if( ( digit2 < 0 ) || ( digit2 > 9 ) )
int digit2 = str16進数文字.IndexOf(strNum[1]); // 2桁目は10進数
if ((digit2 < 0) || (digit2 > 9))
return -1;
int digit1 = str16進数文字.IndexOf( strNum[ 2 ] ); // 1桁目も10進数
if( ( digit1 >= 0 ) && ( digit1 <= 9 ) )
int digit1 = str16進数文字.IndexOf(strNum[2]); // 1桁目も10進数
if ((digit1 >= 0) && (digit1 <= 9))
return digit3 * 100 + digit2 * 10 + digit1;
}
return -1;
}
public static string str小節番号を文字列3桁に変換して返す( int num )
{
if( ( num < 0 ) || ( num >= 3600 ) ) // 3600 == Z99 + 1
public static string str小節番号を文字列3桁に変換して返す(int num) {
if ((num < 0) || (num >= 3600)) // 3600 == Z99 + 1
return "000";
int digit4 = num / 100;
int digit2 = ( num % 100 ) / 10;
int digit1 = ( num % 100 ) % 10;
char ch3 = str36進数文字[ digit4 ];
char ch2 = str16進数文字[ digit2 ];
char ch1 = str16進数文字[ digit1 ];
return ( ch3.ToString() + ch2.ToString() + ch1.ToString() );
int digit2 = (num % 100) / 10;
int digit1 = (num % 100) % 10;
char ch3 = str36進数文字[digit4];
char ch2 = str16進数文字[digit2];
char ch1 = str16進数文字[digit1];
return (ch3.ToString() + ch2.ToString() + ch1.ToString());
}
public static string str数値を16進数2桁に変換して返す( int num )
{
if( ( num < 0 ) || ( num >= 0x100 ) )
public static string str数値を16進数2桁に変換して返す(int num) {
if ((num < 0) || (num >= 0x100))
return "00";
char ch2 = str16進数文字[ num / 0x10 ];
char ch1 = str16進数文字[ num % 0x10 ];
return ( ch2.ToString() + ch1.ToString() );
char ch2 = str16進数文字[num / 0x10];
char ch1 = str16進数文字[num % 0x10];
return (ch2.ToString() + ch1.ToString());
}
public static string str数値を36進数2桁に変換して返す( int num )
{
if( ( num < 0 ) || ( num >= 36 * 36 ) )
public static string str数値を36進数2桁に変換して返す(int num) {
if ((num < 0) || (num >= 36 * 36))
return "00";
char ch2 = str36進数文字[ num / 36 ];
char ch1 = str36進数文字[ num % 36 ];
return ( ch2.ToString() + ch1.ToString() );
char ch2 = str36進数文字[num / 36];
char ch1 = str36進数文字[num % 36];
return (ch2.ToString() + ch1.ToString());
}
public static int[] StringToIntArray( string str )
{
public static int[] StringToIntArray(string str) {
//0,1,2 ...の形式で書かれたstringをint配列に変換する。
//一応実装はしたものの、例外処理などはまだ完成していない。
//str = "0,1,2";
if( String.IsNullOrEmpty( str ) )
if (String.IsNullOrEmpty(str))
return null;
string[] strArray = str.Split( ',' );
string[] strArray = str.Split(',');
List<int> listIntArray;
listIntArray = new List<int>();
for( int n = 0; n < strArray.Length; n++ )
{
int n追加する数値 = Convert.ToInt32( strArray[ n ] );
listIntArray.Add( n追加する数値 );
for (int n = 0; n < strArray.Length; n++) {
int n追加する数値 = Convert.ToInt32(strArray[n]);
listIntArray.Add(n追加する数値);
}
int[] nArray = new int[] { 1 };
nArray = listIntArray.ToArray();
@ -215,8 +190,7 @@ namespace FDK
/// </summary>
/// <param name="num"></param>
/// <returns></returns>
public static int nParsentTo255( double num )
{
public static int nParsentTo255(double num) {
return (int)(255.0 * num);
}
@ -225,30 +199,25 @@ namespace FDK
/// </summary>
/// <param name="num"></param>
/// <returns></returns>
public static int n255ToParsent( int num )
{
public static int n255ToParsent(int num) {
return (int)(100.0 / num);
}
public static Color4 n255ToColor4( int nR, int nG, int nB )
{
float fR = n255ToParsent( nR );
float fG = n255ToParsent( nG );
float fB = n255ToParsent( nB );
public static Color4 n255ToColor4(int nR, int nG, int nB) {
float fR = n255ToParsent(nR);
float fG = n255ToParsent(nG);
float fB = n255ToParsent(nB);
return new Color4( fR, fG, fB, 1f );
return new Color4(fR, fG, fB, 1f);
}
public static Color4 ColorToColor4(System.Drawing.Color col)
{
public static Color4 ColorToColor4(System.Drawing.Color col) {
return new Color4(col.R / 255f, col.G / 255f, col.B / 255f, col.A / 255f);
}
public static int[] SeparateDigits(int num)
{
public static int[] SeparateDigits(int num) {
int[] digits = new int[num.ToString().Length];
for (int i = 0; i < digits.Length; i++)
{
for (int i = 0; i < digits.Length; i++) {
digits[i] = num % 10;
num /= 10;
}
@ -259,8 +228,7 @@ namespace FDK
//-----------------
// private コンストラクタでインスタンス生成を禁止する。
private CConversion()
{
private CConversion() {
}
//-----------------
#endregion

View File

@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace FDK
{
namespace FDK {
/// <summary>
/// 一定間隔で単純増加する整数(カウント値)を扱う。
/// </summary>
@ -18,70 +13,56 @@ namespace FDK
/// double値を使う場合、t進行db、t進行LoopDbを使うこと。
/// また、double版では間隔の値はミリ秒単位ではなく、通常の秒単位になります。
/// </remarks>
public class CCounter
{
public bool IsStarted
{
public class CCounter {
public bool IsStarted {
get;
set;
}
// 値プロパティ
public double BeginValue
{
public double BeginValue {
get;
private set;
}
public double EndValue
{
public double EndValue {
get;
set;
}
public int CurrentValue
{
public int CurrentValue {
get;
set;
}
public double _Interval
{
get
{
public double _Interval {
get {
return this.Interval;
}
set
{
set {
this.Interval = value >= 0 ? value : value * -1;
}
}
public double NowTime
{
public double NowTime {
get;
set;
}
// 状態プロパティ
public bool IsTicked
{
public bool IsTicked {
get { return (this.NowTime != -1); }
}
public bool IsStoped
{
public bool IsStoped {
get { return !this.IsTicked; }
}
public bool IsEnded
{
public bool IsEnded {
get { return (this.CurrentValue >= this.EndValue); }
}
public bool IsUnEnded
{
public bool IsUnEnded {
get { return !this.IsEnded; }
}
// コンストラクタ
public CCounter()
{
public CCounter() {
this.NormalTimer = null;
this.BeginValue = 0;
this.EndValue = 0;
@ -92,15 +73,13 @@ namespace FDK
/// <summary>生成と同時に開始する。</summary>
public CCounter(double begin, double end, double interval, CTimer timer)
: this()
{
: this() {
this.Start(begin, end, interval, timer);
}
/// <summary>生成と同時に開始する。(double版)</summary>
public CCounter(double begin, double end, double interval, CSoundTimer timer)
: this()
{
: this() {
this.Start(begin, end, interval * 1000.0f, timer);
}
@ -114,8 +93,7 @@ namespace FDK
/// <param name="end">最後のカウント値。</param>
/// <param name="interval">カウント値を1増加させるのにかける時間(ミリ秒単位)。</param>
/// <param name="timer">カウントに使用するタイマ。</param>
public void Start(double begin, double end, double interval, CTimer timer)
{
public void Start(double begin, double end, double interval, CTimer timer) {
this.BeginValue = begin;
this.EndValue = end;
this._Interval = interval;
@ -132,8 +110,7 @@ namespace FDK
/// <param name="end">最後のカウント値。</param>
/// <param name="interval">カウント値を1増加させるのにかける時間(秒単位)。</param>
/// <param name="timer">カウントに使用するタイマ。</param>
public void Start(double begin, double end, double interval, CSoundTimer timer)
{
public void Start(double begin, double end, double interval, CSoundTimer timer) {
this.BeginValue = begin;
this.EndValue = end;
this._Interval = interval;
@ -147,16 +124,13 @@ namespace FDK
/// 前回の t進行() の呼び出しからの経過時間をもとに、必要なだけカウント値を増加させる。
/// カウント値が終了値に達している場合は、それ以上増加しない(終了値を維持する)。
/// </summary>
public void Tick()
{
if ((this.NormalTimer != null) && (this.NowTime != CTimer.UnusedNum))
{
public void Tick() {
if ((this.NormalTimer != null) && (this.NowTime != CTimer.UnusedNum)) {
long num = this.NormalTimer.NowTime;
if (num < this.NowTime)
this.NowTime = num;
while ((num - this.NowTime) >= this.Interval)
{
while ((num - this.NowTime) >= this.Interval) {
if (++this.CurrentValue > this.EndValue)
this.CurrentValue = (int)this.EndValue;
@ -169,16 +143,13 @@ namespace FDK
/// 前回の t進行() の呼び出しからの経過時間をもとに、必要なだけカウント値を増加させる。
/// カウント値が終了値に達している場合は、それ以上増加しない(終了値を維持する)。
/// </summary>
public void TickDB()
{
if ((this.TimerDB != null) && (this.NowTime != CSoundTimer.UnusedNum))
{
public void TickDB() {
if ((this.TimerDB != null) && (this.NowTime != CSoundTimer.UnusedNum)) {
double num = this.TimerDB.NowTime;
if (num < this.NowTime)
this.NowTime = num;
while ((num - this.NowTime) >= this.Interval)
{
while ((num - this.NowTime) >= this.Interval) {
if (++this.CurrentValue > this.EndValue)
this.CurrentValue = (int)this.EndValue;
@ -191,16 +162,13 @@ namespace FDK
/// 前回の t進行Loop() の呼び出しからの経過時間をもとに、必要なだけカウント値を増加させる。
/// カウント値が終了値に達している場合は、次の増加タイミングで開始値に戻る(値がループする)。
/// </summary>
public void TickLoop()
{
if ((this.NormalTimer != null) && (this.NowTime != CTimer.UnusedNum))
{
public void TickLoop() {
if ((this.NormalTimer != null) && (this.NowTime != CTimer.UnusedNum)) {
long num = this.NormalTimer.NowTime;
if (num < this.NowTime)
this.NowTime = num;
while ((num - this.NowTime) >= this.Interval)
{
while ((num - this.NowTime) >= this.Interval) {
if (++this.CurrentValue > this.EndValue)
this.CurrentValue = (int)this.BeginValue;
@ -213,16 +181,13 @@ namespace FDK
/// 前回の t進行Loop() の呼び出しからの経過時間をもとに、必要なだけカウント値を増加させる。
/// カウント値が終了値に達している場合は、次の増加タイミングで開始値に戻る(値がループする)。
/// </summary>
public void TickLoopDB()
{
if ((this.TimerDB != null) && (this.NowTime != CSoundTimer.UnusedNum))
{
public void TickLoopDB() {
if ((this.TimerDB != null) && (this.NowTime != CSoundTimer.UnusedNum)) {
double num = this.TimerDB.NowTime;
if (num < this.NowTime)
this.NowTime = num;
while ((num - this.NowTime) >= this.Interval)
{
while ((num - this.NowTime) >= this.Interval) {
if (++this.CurrentValue > this.EndValue)
this.CurrentValue = (int)this.BeginValue;
@ -235,13 +200,11 @@ namespace FDK
/// カウントを停止する。
/// これ以降に t進行() や t進行Loop() を呼び出しても何も処理されない。
/// </summary>
public void Stop()
{
public void Stop() {
this.NowTime = CTimer.UnusedNum;
}
public void ChangeInterval(double Value)
{
public void ChangeInterval(double Value) {
this._Interval = Value;
}
@ -257,16 +220,13 @@ namespace FDK
/// </summary>
/// <param name="pressFlag">キーが押下されている場合は true。</param>
/// <param name="keyProcess">キーが押下されている場合に実行する処理。</param>
public void KeyIntervalFunc(bool pressFlag, KeyProcess keyProcess)
{
public void KeyIntervalFunc(bool pressFlag, KeyProcess keyProcess) {
const int first = 0;
const int second = 1;
const int later = 2;
if (pressFlag)
{
switch (this.CurrentValue)
{
if (pressFlag) {
switch (this.CurrentValue) {
case first:
keyProcess();
@ -276,8 +236,7 @@ namespace FDK
case second:
if ((this.NormalTimer.NowTime - this.NowTime) > 200)
{
if ((this.NormalTimer.NowTime - this.NowTime) > 200) {
keyProcess();
this.NowTime = this.NormalTimer.NowTime;
this.CurrentValue = later;
@ -286,16 +245,13 @@ namespace FDK
case later:
if ((this.NormalTimer.NowTime - this.NowTime) > 30)
{
if ((this.NormalTimer.NowTime - this.NowTime) > 30) {
keyProcess();
this.NowTime = this.NormalTimer.NowTime;
}
return;
}
}
else
{
} else {
this.CurrentValue = first;
}
}

View File

@ -1,25 +1,16 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace FDK
{
public class CFPS
{
namespace FDK {
public class CFPS {
// プロパティ
public int NowFPS
{
public int NowFPS {
get;
private set;
}
public double DeltaTime
{
public double DeltaTime {
get;
private set;
}
public bool ChangedFPS
{
public bool ChangedFPS {
get;
private set;
}
@ -27,11 +18,10 @@ namespace FDK
// コンストラクタ
public CFPS()
{
public CFPS() {
this.NowFPS = 0;
this.DeltaTime = 0;
this.FPSTimer = new CTimer( CTimer.TimerType.MultiMedia );
this.FPSTimer = new CTimer(CTimer.TimerType.MultiMedia);
this.BeginTime = this.FPSTimer.NowTime;
this.CoreFPS = 0;
this.ChangedFPS = false;
@ -40,16 +30,14 @@ namespace FDK
// メソッド
public void Update()
{
public void Update() {
this.FPSTimer.Update();
this.ChangedFPS = false;
const long INTERVAL = 1000;
this.DeltaTime = (this.FPSTimer.NowTime - this.PrevFrameTime) / 1000.0;
PrevFrameTime = this.FPSTimer.NowTime;
while ( ( this.FPSTimer.NowTime - this.BeginTime ) >= INTERVAL )
{
while ((this.FPSTimer.NowTime - this.BeginTime) >= INTERVAL) {
this.NowFPS = this.CoreFPS;
this.CoreFPS = 0;
this.ChangedFPS = true;

View File

@ -1,81 +1,66 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Diagnostics;
using System.Text;
namespace FDK
{
namespace FDK {
/// <summary>
/// 汎用的な .iniファイルを扱う。
/// </summary>
public class CIniFile
{
public class CIniFile {
// プロパティ
public string FileName
{
public string FileName {
get;
private set;
}
public List<CSection> Sections
{
public List<CSection> Sections {
get;
set;
}
public class CSection
{
public class CSection {
public string SectionName = "";
public List<KeyValuePair<string,string>> Parameters = new List<KeyValuePair<string, string>>();
public List<KeyValuePair<string, string>> Parameters = new List<KeyValuePair<string, string>>();
}
// コンストラクタ
public CIniFile()
{
public CIniFile() {
this.FileName = "";
this.Sections = new List<CSection>();
}
public CIniFile( string fileName )
:this()
{
this.tRead( fileName );
public CIniFile(string fileName)
: this() {
this.tRead(fileName);
}
// メソッド
public void tRead( string fileName )
{
public void tRead(string fileName) {
this.FileName = fileName;
StreamReader sr = null;
CSection section = null;
try
{
sr = new StreamReader( this.FileName, Encoding.GetEncoding("Shift_JIS") ); // ファイルが存在しない場合は例外発生。
try {
sr = new StreamReader(this.FileName, Encoding.GetEncoding("Shift_JIS")); // ファイルが存在しない場合は例外発生。
string line;
while( ( line = sr.ReadLine() ) != null )
{
line = line.Replace( '\t', ' ' ).TrimStart( new char[] { '\t', ' ' } );
if( string.IsNullOrEmpty( line ) || line[ 0 ] == ';' ) // ';'以降はコメントとして無視
while ((line = sr.ReadLine()) != null) {
line = line.Replace('\t', ' ').TrimStart(new char[] { '\t', ' ' });
if (string.IsNullOrEmpty(line) || line[0] == ';') // ';'以降はコメントとして無視
continue;
if( line[ 0 ] == '[' )
{
if (line[0] == '[') {
#region [ ]
//-----------------------------
var builder = new StringBuilder( 32 );
var builder = new StringBuilder(32);
int num = 1;
while( ( num < line.Length ) && ( line[ num ] != ']' ) )
builder.Append( line[ num++ ] );
while ((num < line.Length) && (line[num] != ']'))
builder.Append(line[num++]);
// 変数 section が使用中の場合は、List<CSection> に追加して新しい section を作成する。
if( section != null )
this.Sections.Add( section );
if (section != null)
this.Sections.Add(section);
section = new CSection();
section.SectionName = builder.ToString();
@ -85,49 +70,41 @@ namespace FDK
continue;
}
string[] strArray = line.Split( new char[] { '=' } );
if( strArray.Length != 2 )
string[] strArray = line.Split(new char[] { '=' });
if (strArray.Length != 2)
continue;
string key = strArray[ 0 ].Trim();
string value = strArray[ 1 ].Trim();
string key = strArray[0].Trim();
string value = strArray[1].Trim();
if( section != null && !string.IsNullOrEmpty( key ) && !string.IsNullOrEmpty( value ) )
section.Parameters.Add( new KeyValuePair<string, string>( key, value ) );
if (section != null && !string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(value))
section.Parameters.Add(new KeyValuePair<string, string>(key, value));
}
if( section != null )
this.Sections.Add( section );
}
finally
{
if( sr != null )
if (section != null)
this.Sections.Add(section);
} finally {
if (sr != null)
sr.Close();
}
}
public void tWrite( string fileName )
{
public void tWrite(string fileName) {
this.FileName = fileName;
this.tWrite();
}
public void tWrite()
{
public void tWrite() {
StreamWriter sw = null;
try
{
sw = new StreamWriter( this.FileName, false, Encoding.GetEncoding( "Shift_JIS" ) ); // オープン失敗の場合は例外発生。
try {
sw = new StreamWriter(this.FileName, false, Encoding.GetEncoding("Shift_JIS")); // オープン失敗の場合は例外発生。
foreach( CSection section in this.Sections )
{
sw.WriteLine( "[{0}]", section.SectionName );
foreach (CSection section in this.Sections) {
sw.WriteLine("[{0}]", section.SectionName);
foreach( KeyValuePair<string,string> kvp in section.Parameters )
sw.WriteLine( "{0}={1}", kvp.Key, kvp.Value );
foreach (KeyValuePair<string, string> kvp in section.Parameters)
sw.WriteLine("{0}={1}", kvp.Key, kvp.Value);
}
}
finally
{
if( sw != null )
} finally {
if (sw != null)
sw.Close();
}
}

View File

@ -1,41 +1,33 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace FDK
{
namespace FDK {
/// <summary>
/// <para>一定の間隔で処理を行うテンプレートパターンの定義。</para>
/// <para>たとえば、t進行() で 5ms ごとに行う処理を前回のt進行()の呼び出しから 15ms 後に呼び出した場合は、処理が 3回 実行される。</para>
/// </summary>
public class CIntervalProcessing : IDisposable
{
public class CIntervalProcessing : IDisposable {
public delegate void dgProc();
public void Tick( long interval, dgProc proc )
{
public void Tick(long interval, dgProc proc) {
// タイマ更新
if( this.timer == null )
if (this.timer == null)
return;
this.timer.Update();
// 初めての進行処理
if( this.PrevTime == CTimer.UnusedNum )
if (this.PrevTime == CTimer.UnusedNum)
this.PrevTime = this.timer.NowTimeMs;
// タイマが一回りしてしまった時のため……
if( this.timer.NowTimeMs < this.PrevTime )
if (this.timer.NowTimeMs < this.PrevTime)
this.PrevTime = this.timer.NowTimeMs;
// 時間内の処理を実行。
while( ( this.timer.NowTimeMs - this.PrevTime ) >= interval )
{
while ((this.timer.NowTimeMs - this.PrevTime) >= interval) {
proc();
this.PrevTime += interval;
@ -44,8 +36,7 @@ namespace FDK
#region [ IDisposable ]
//-----------------
public void Dispose()
{
public void Dispose() {
timer.Dispose();
}
//-----------------
@ -53,7 +44,7 @@ namespace FDK
#region [ protected ]
//-----------------
protected CTimer timer = new CTimer( CTimer.TimerType.MultiMedia );
protected CTimer timer = new CTimer(CTimer.TimerType.MultiMedia);
protected long PrevTime = CTimer.UnusedNum;
//-----------------
#endregion

View File

@ -1,25 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;
using System.Text;
using System.IO;
using System.Diagnostics;
namespace TJAPlayer3
{
public class CJudgeTextEncoding
{
namespace TJAPlayer3 {
public class CJudgeTextEncoding {
/// <summary>
/// Hnc8様のReadJEncを使用して文字コードの判別をする。
/// </summary>
public static Encoding JudgeFileEncoding(string path)
{
public static Encoding JudgeFileEncoding(string path) {
if (!File.Exists(path)) return null;
Encoding enc;
FileInfo file = new FileInfo(path);
using (Hnx8.ReadJEnc.FileReader reader = new Hnx8.ReadJEnc.FileReader(file))
{
using (Hnx8.ReadJEnc.FileReader reader = new Hnx8.ReadJEnc.FileReader(file)) {
// 判別読み出し実行。判別結果はReadメソッドの戻り値で把握できます
Hnx8.ReadJEnc.CharCode c = reader.Read(file);
// 戻り値のNameプロパティから文字コード名を取得できます
@ -30,8 +22,7 @@ namespace TJAPlayer3
}
Debug.Print(path + " Encoding=" + enc.CodePage);
if (enc == null)
{
if (enc == null) {
enc = Encoding.GetEncoding(932);
}
return enc;
@ -42,14 +33,12 @@ namespace TJAPlayer3
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public static string ReadTextFile(string path)
{
public static string ReadTextFile(string path) {
if (!File.Exists(path)) return null;
string str = null;
FileInfo file = new FileInfo(path);
using (Hnx8.ReadJEnc.FileReader reader = new Hnx8.ReadJEnc.FileReader(file))
{
using (Hnx8.ReadJEnc.FileReader reader = new Hnx8.ReadJEnc.FileReader(file)) {
reader.Read(file);
str = reader.Text;
}
@ -66,8 +55,7 @@ namespace TJAPlayer3
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static string JudgeNewLine(string str)
{
public static string JudgeNewLine(string str) {
if (str.Contains("\r\n"))
return ("\r\n");

View File

@ -1,31 +1,19 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace FDK
{
public class CTimer : CTimerBase
{
public enum TimerType
{
namespace FDK {
public class CTimer : CTimerBase {
public enum TimerType {
Unknown = -1,
PerformanceCounter = 0,
MultiMedia = 1,
GetTickCount = 2,
}
public TimerType CurrentTimerType
{
public TimerType CurrentTimerType {
get;
protected set;
}
public override long SystemTimeMs
{
get
{
public override long SystemTimeMs {
get {
/*
switch( this.eタイマ種別 )
{
@ -52,9 +40,8 @@ namespace FDK
}
}
public CTimer( TimerType timerType )
:base()
{
public CTimer(TimerType timerType)
: base() {
this.CurrentTimerType = timerType;
/*
@ -84,20 +71,18 @@ namespace FDK
base.Reset();
ReferenceCount[ (int) this.CurrentTimerType ]++;
ReferenceCount[(int)this.CurrentTimerType]++;
}
public override void Dispose()
{
if( this.CurrentTimerType == TimerType.Unknown )
public override void Dispose() {
if (this.CurrentTimerType == TimerType.Unknown)
return;
int type = (int) this.CurrentTimerType;
int type = (int)this.CurrentTimerType;
ReferenceCount[ type ] = Math.Max( ReferenceCount[ type ] - 1, 0 );
ReferenceCount[type] = Math.Max(ReferenceCount[type] - 1, 0);
if( ReferenceCount[ type ] == 0 )
{
if (ReferenceCount[type] == 0) {
/*
if( this.eタイマ種別 == E種別.MultiMedia )
timeEndPeriod( this.timeCaps.wPeriodMin );
@ -110,11 +95,10 @@ namespace FDK
#region [ protected ]
//-----------------
protected long CurrentFrequency;
protected static int[] ReferenceCount = new int[ 3 ];
protected static int[] ReferenceCount = new int[3];
//protected TimeCaps timeCaps;
protected bool GetSetTickCount()
{
protected bool GetSetTickCount() {
this.CurrentTimerType = TimerType.GetTickCount;
return true;
}

View File

@ -1,164 +1,129 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace FDK
{
namespace FDK {
/// <summary>
/// <para>タイマの抽象クラス。</para>
/// <para>このクラスを継承し、override したクラスを作成することで、任意のクロックを持つタイマを作成できる。</para>
/// </summary>
public abstract class CTimerBase : IDisposable
{
public abstract class CTimerBase : IDisposable {
public const long UnusedNum = -1;
// この2つを override する。
public abstract long SystemTimeMs
{
public abstract long SystemTimeMs {
get;
}
public double SystemTimeMs_Double
{
public double SystemTimeMs_Double {
get;
set;
}
public abstract void Dispose();
#region [ DTXMania用にmsのつかない宣言を追加 ]
public long SystemTime
{
public long SystemTime {
get { return SystemTimeMs; }
}
public long NowTime
{
public long NowTime {
get { return NowTimeMs; }
set { NowTimeMs = value; }
}
public long PrevResetTime
{
public long PrevResetTime {
get { return PrevResetTimeMs; }
}
//double
public double SystemTime_Double
{
public double SystemTime_Double {
get { return SystemTimeMs_Double; }
}
public double NowTime_Double
{
public double NowTime_Double {
get { return NowTimeMs_Double; }
set { NowTimeMs_Double = value; }
}
public double PrevResetTime_Double
{
public double PrevResetTime_Double {
get { return PrevResetTimeMs_Double; }
}
#endregion
public long NowTimeMs
{
get
{
if( this.StopCount > 0 )
return ( this.PauseSystemTimeMs - this.PrevResetTimeMs );
public long NowTimeMs {
get {
if (this.StopCount > 0)
return (this.PauseSystemTimeMs - this.PrevResetTimeMs);
return ( this.UpdateSystemTime - this.PrevResetTimeMs );
return (this.UpdateSystemTime - this.PrevResetTimeMs);
}
set
{
if( this.StopCount > 0 )
set {
if (this.StopCount > 0)
this.PrevResetTimeMs = this.PauseSystemTimeMs - value;
else
this.PrevResetTimeMs = this.UpdateSystemTime - value;
}
}
public long RealNowTimeMs
{
get
{
if( this.StopCount > 0 )
return ( this.PauseSystemTimeMs - this.PrevResetTimeMs );
public long RealNowTimeMs {
get {
if (this.StopCount > 0)
return (this.PauseSystemTimeMs - this.PrevResetTimeMs);
return ( this.SystemTimeMs - this.PrevResetTimeMs );
return (this.SystemTimeMs - this.PrevResetTimeMs);
}
}
public long PrevResetTimeMs
{
public long PrevResetTimeMs {
get;
protected set;
}
public double NowTimeMs_Double
{
get
{
if( this.StopCount > 0 )
return ( this.PauseSystemTimeMs_Double - this.PrevResetTimeMs_Double );
public double NowTimeMs_Double {
get {
if (this.StopCount > 0)
return (this.PauseSystemTimeMs_Double - this.PrevResetTimeMs_Double);
return ( this.UpdateSystemTime_Double - this.PrevResetTimeMs_Double );
return (this.UpdateSystemTime_Double - this.PrevResetTimeMs_Double);
}
set
{
if( this.StopCount > 0 )
set {
if (this.StopCount > 0)
this.PrevResetTimeMs_Double = this.PauseSystemTimeMs_Double - value;
else
this.PrevResetTimeMs_Double = this.UpdateSystemTime_Double - value;
}
}
public double RealNowTimeMs_Double
{
get
{
if( this.StopCount > 0 )
return ( this.PauseSystemTimeMs_Double - this.PrevResetTimeMs_Double );
public double RealNowTimeMs_Double {
get {
if (this.StopCount > 0)
return (this.PauseSystemTimeMs_Double - this.PrevResetTimeMs_Double);
return ( this.SystemTimeMs_Double - this.PrevResetTimeMs_Double );
return (this.SystemTimeMs_Double - this.PrevResetTimeMs_Double);
}
}
public double PrevResetTimeMs_Double
{
public double PrevResetTimeMs_Double {
get;
protected set;
}
public bool IsUnStoped
{
get
{
return ( this.StopCount == 0 );
public bool IsUnStoped {
get {
return (this.StopCount == 0);
}
}
public void Reset()
{
public void Reset() {
this.Update();
this.PrevResetTimeMs = this.UpdateSystemTime;
this.PauseSystemTimeMs = this.UpdateSystemTime;
this.StopCount = 0;
}
public void Pause()
{
if( this.StopCount == 0 )
{
public void Pause() {
if (this.StopCount == 0) {
this.PauseSystemTimeMs = this.UpdateSystemTime;
this.PauseSystemTimeMs_Double = this.UpdateSystemTime_Double;
}
this.StopCount++;
}
public void Update()
{
public void Update() {
this.UpdateSystemTime = this.SystemTimeMs;
this.UpdateSystemTime_Double = this.SystemTimeMs_Double;
}
public void Resume()
{
if( this.StopCount > 0 )
{
public void Resume() {
if (this.StopCount > 0) {
this.StopCount--;
if( this.StopCount == 0 )
{
if (this.StopCount == 0) {
this.Update();
this.PrevResetTimeMs += this.UpdateSystemTime - this.PauseSystemTimeMs;
this.PrevResetTimeMs_Double += this.UpdateSystemTime_Double - this.PauseSystemTimeMs_Double;

View File

@ -1,127 +1,86 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Diagnostics;
using System.Diagnostics;
namespace FDK
{
public class CTraceLogListener : TraceListener
{
public CTraceLogListener( StreamWriter stream )
{
namespace FDK {
public class CTraceLogListener : TraceListener {
public CTraceLogListener(StreamWriter stream) {
this.LogStreamWriter = stream;
}
public override void Flush()
{
if( this.LogStreamWriter != null )
{
try
{
public override void Flush() {
if (this.LogStreamWriter != null) {
try {
this.LogStreamWriter.Flush();
}
catch( ObjectDisposedException )
{
} catch (ObjectDisposedException) {
}
}
}
public override void TraceEvent( TraceEventCache eventCache, string source, TraceEventType eventType, int id, string message )
{
if( this.LogStreamWriter != null )
{
try
{
this.LogEventType( eventType );
public override void TraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id, string message) {
if (this.LogStreamWriter != null) {
try {
this.LogEventType(eventType);
this.LogIndent();
this.LogStreamWriter.WriteLine( message );
}
catch( ObjectDisposedException )
{
this.LogStreamWriter.WriteLine(message);
} catch (ObjectDisposedException) {
}
}
}
public override void TraceEvent( TraceEventCache eventCache, string source, TraceEventType eventType, int id, string format, params object[] args )
{
if( this.LogStreamWriter != null )
{
try
{
this.LogEventType( eventType );
public override void TraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id, string format, params object[] args) {
if (this.LogStreamWriter != null) {
try {
this.LogEventType(eventType);
this.LogIndent();
this.LogStreamWriter.WriteLine( string.Format( format, args ) );
}
catch( ObjectDisposedException )
{
this.LogStreamWriter.WriteLine(string.Format(format, args));
} catch (ObjectDisposedException) {
}
}
}
public override void Write( string message )
{
if( this.LogStreamWriter != null )
{
try
{
this.LogStreamWriter.Write( message );
}
catch( ObjectDisposedException )
{
public override void Write(string message) {
if (this.LogStreamWriter != null) {
try {
this.LogStreamWriter.Write(message);
} catch (ObjectDisposedException) {
}
}
}
public override void WriteLine( string message )
{
if( this.LogStreamWriter != null )
{
try
{
this.LogStreamWriter.WriteLine( message );
}
catch( ObjectDisposedException )
{
public override void WriteLine(string message) {
if (this.LogStreamWriter != null) {
try {
this.LogStreamWriter.WriteLine(message);
} catch (ObjectDisposedException) {
}
}
}
protected override void Dispose( bool disposing )
{
if( this.LogStreamWriter != null )
{
try
{
protected override void Dispose(bool disposing) {
if (this.LogStreamWriter != null) {
try {
this.LogStreamWriter.Close();
}
catch
{
} catch {
}
this.LogStreamWriter = null;
}
base.Dispose( disposing );
base.Dispose(disposing);
}
#region [ private ]
//-----------------
private StreamWriter LogStreamWriter;
private void LogEventType( TraceEventType eventType )
{
if( this.LogStreamWriter != null )
{
try
{
private void LogEventType(TraceEventType eventType) {
if (this.LogStreamWriter != null) {
try {
var now = DateTime.Now;
this.LogStreamWriter.Write( string.Format( "{0:D4}/{1:D2}/{2:D2} {3:D2}:{4:D2}:{5:D2}.{6:D3} ", new object[] { now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second, now.Millisecond } ) );
switch( eventType )
{
this.LogStreamWriter.Write(string.Format("{0:D4}/{1:D2}/{2:D2} {3:D2}:{4:D2}:{5:D2}.{6:D3} ", new object[] { now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second, now.Millisecond }));
switch (eventType) {
case TraceEventType.Error:
this.LogStreamWriter.Write( "[ERROR] " );
this.LogStreamWriter.Write("[ERROR] ");
return;
case ( TraceEventType.Error | TraceEventType.Critical ):
case (TraceEventType.Error | TraceEventType.Critical):
return;
case TraceEventType.Warning:
this.LogStreamWriter.Write( "[WARNING] " );
this.LogStreamWriter.Write("[WARNING] ");
return;
case TraceEventType.Information:
@ -130,24 +89,17 @@ namespace FDK
default:
return;
}
this.LogStreamWriter.Write( "[INFO] " );
}
catch( ObjectDisposedException )
{
this.LogStreamWriter.Write("[INFO] ");
} catch (ObjectDisposedException) {
}
}
}
private void LogIndent()
{
if( ( this.LogStreamWriter != null ) && ( base.IndentLevel > 0 ) )
{
try
{
for( int i = 0; i < base.IndentLevel; i++ )
this.LogStreamWriter.Write( " " );
}
catch( ObjectDisposedException )
{
private void LogIndent() {
if ((this.LogStreamWriter != null) && (base.IndentLevel > 0)) {
try {
for (int i = 0; i < base.IndentLevel; i++)
this.LogStreamWriter.Write(" ");
} catch (ObjectDisposedException) {
}
}
}

View File

@ -1,17 +1,10 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
namespace FDK
{
public class CUtility
{
namespace FDK {
public class CUtility {
public static void RunCompleteGC()
{
public static void RunCompleteGC() {
GC.Collect(); // アクセス不可能なオブジェクトを除去し、ファイナライぜーション実施。
GC.WaitForPendingFinalizers(); // ファイナライゼーションが終わるまでスレッドを待機。
GC.Collect(); // ファイナライズされたばかりのオブジェクトに関連するメモリを開放。
@ -22,46 +15,38 @@ namespace FDK
// ログ
public static void LogBlock( string name, Action method )
{
Trace.TraceInformation( "--------------------" );
Trace.TraceInformation( "開始 - " + name );
public static void LogBlock(string name, Action method) {
Trace.TraceInformation("--------------------");
Trace.TraceInformation("開始 - " + name);
Trace.Indent();
try
{
try {
method();
}
finally
{
} finally {
Trace.Unindent();
Trace.TraceInformation( "終了 - " + name );
Trace.TraceInformation( "--------------------" );
Trace.TraceInformation("終了 - " + name);
Trace.TraceInformation("--------------------");
}
}
public static void LogException( Exception e )
{
Trace.WriteLine( "---例外ここから----" );
Trace.WriteLine( e.ToString() );
Trace.WriteLine( "---例外ここまで----" );
public static void LogException(Exception e) {
Trace.WriteLine("---例外ここから----");
Trace.WriteLine(e.ToString());
Trace.WriteLine("---例外ここまで----");
}
// IO
public static string t指定した拡張子を持つファイルを検索し最初に見つけたファイルの絶対パスを返す( string strフォルダパス, List<string> extensions )
{
string[] files = Directory.GetFiles( strフォルダパス ); // GetFiles() は完全パスを返す。
public static string t指定した拡張子を持つファイルを検索し最初に見つけたファイルの絶対パスを返す(string strフォルダパス, List<string> extensions) {
string[] files = Directory.GetFiles(strフォルダパス); // GetFiles() は完全パスを返す。
// ファイル順より拡張子順を優先して検索する。→ 拡張子リストの前方の拡張子ほど先に発見されるようにするため。
foreach( string ext in extensions )
{
foreach( string file in files )
{
string fileExt = Path.GetExtension( file );
foreach (string ext in extensions) {
foreach (string file in files) {
string fileExt = Path.GetExtension(file);
if( fileExt.Equals( ext, StringComparison.OrdinalIgnoreCase ) )
if (fileExt.Equals(ext, StringComparison.OrdinalIgnoreCase))
return file; // あった
}
}
@ -69,39 +54,31 @@ namespace FDK
return null; // なかった
}
public static void ReadXML<T>( string fileName, out T xmlObject )
{
xmlObject = default( T );
public static void ReadXML<T>(string fileName, out T xmlObject) {
xmlObject = default(T);
FileStream fs = null;
StreamReader sr = null;
try
{
fs = new FileStream( fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite ); // FileShare を付けとかないと、Close() 後もロックがかかる。
sr = new StreamReader( fs, Encoding.UTF8 );
var xmlsl = new System.Xml.Serialization.XmlSerializer( typeof( T ) );
xmlObject = (T) xmlsl.Deserialize( sr );
}
finally
{
if( sr != null )
try {
fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); // FileShare を付けとかないと、Close() 後もロックがかかる。
sr = new StreamReader(fs, Encoding.UTF8);
var xmlsl = new System.Xml.Serialization.XmlSerializer(typeof(T));
xmlObject = (T)xmlsl.Deserialize(sr);
} finally {
if (sr != null)
sr.Close(); // fr も一緒にClose()される
}
}
public static void WriteXML<T>( string fileName, T xmlObject )
{
public static void WriteXML<T>(string fileName, T xmlObject) {
FileStream fs = null;
StreamWriter sw = null;
try
{
fs = new FileStream( fileName, FileMode.Create, FileAccess.Write, FileShare.ReadWrite ); // FileShare を付けとかないと、Close() 後もロックがかかる。
sw = new StreamWriter( fs, Encoding.UTF8 );
var xmlsl = new System.Xml.Serialization.XmlSerializer( typeof( T ) );
xmlsl.Serialize( sw, xmlObject );
}
finally
{
if( sw != null )
try {
fs = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.ReadWrite); // FileShare を付けとかないと、Close() 後もロックがかかる。
sw = new StreamWriter(fs, Encoding.UTF8);
var xmlsl = new System.Xml.Serialization.XmlSerializer(typeof(T));
xmlsl.Serialize(sw, xmlObject);
} finally {
if (sw != null)
sw.Close(); // fs も一緒にClose()される
}
}
@ -109,27 +86,22 @@ namespace FDK
// 数学
public static double DegreeToRadian( double angle )
{
return ( ( Math.PI * angle ) / 180.0 );
public static double DegreeToRadian(double angle) {
return ((Math.PI * angle) / 180.0);
}
public static double RadianToDegree( double angle )
{
return ( angle * 180.0 / Math.PI );
public static double RadianToDegree(double angle) {
return (angle * 180.0 / Math.PI);
}
public static float DegreeToRadian( float angle )
{
return (float) DegreeToRadian( (double) angle );
public static float DegreeToRadian(float angle) {
return (float)DegreeToRadian((double)angle);
}
public static float RadianToDegree( float angle )
{
return (float) RadianToDegree( (double) angle );
public static float RadianToDegree(float angle) {
return (float)RadianToDegree((double)angle);
}
public static bool ToggleBoolian( ref bool bFlag )
{
if( bFlag == true ) bFlag = false;
else if( bFlag == false ) bFlag = true;
public static bool ToggleBoolian(ref bool bFlag) {
if (bFlag == true) bFlag = false;
else if (bFlag == false) bFlag = true;
return true;
}

View File

@ -1,28 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FDK
{
public class Color4
{
namespace FDK {
public class Color4 {
public float Red;
public float Green;
public float Blue;
public float Alpha;
public Color4(float r, float g, float b, float a)
{
public Color4(float r, float g, float b, float a) {
Red = r;
Green = g;
Blue = b;
Alpha = a;
}
public Color4(int rgba)
{
public Color4(int rgba) {
Alpha = ((rgba >> 24) & 255) / 255.0f;
Blue = ((rgba >> 16) & 255) / 255.0f;
Green = ((rgba >> 8) & 255) / 255.0f;

View File

@ -1,11 +1,6 @@
using System;
namespace FDK.ExtensionMethods
{
public static class DoubleExtensions
{
public static double Clamp(this double value, double min, double max)
{
namespace FDK.ExtensionMethods {
public static class DoubleExtensions {
public static double Clamp(this double value, double min, double max) {
return Math.Min(Math.Max(value, min), max);
}
}

View File

@ -1,11 +1,6 @@
using System;
namespace FDK.ExtensionMethods
{
public static class Int32Extensions
{
public static int Clamp(this int value, int min, int max)
{
namespace FDK.ExtensionMethods {
public static class Int32Extensions {
public static int Clamp(this int value, int min, int max) {
return Math.Min(Math.Max(value, min), max);
}
}

View File

@ -19,26 +19,19 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.ComponentModel;
using System.Threading;
using System.Collections.ObjectModel;
using Silk.NET.Windowing;
using FDK;
using Silk.NET.Core;
using Silk.NET.GLFW;
using Silk.NET.Maths;
using Silk.NET.OpenGLES;
using Silk.NET.Windowing;
using SkiaSharp;
using FDK;
using Silk.NET.GLFW;
using System.Runtime.InteropServices;
using Silk.NET.Core;
namespace SampleFramework
{
namespace SampleFramework {
/// <summary>
/// Presents an easy to use wrapper for making games and samples.
/// </summary>
public abstract class Game : IDisposable
{
public abstract class Game : IDisposable {
public static GL Gl { get; private set; }
public static Silk.NET.Core.Contexts.IGLContext Context { get; private set; }
@ -47,17 +40,13 @@ namespace SampleFramework
private string strIconFileName;
protected string _Text = "";
protected string Text
{
get
{
protected string Text {
get {
return _Text;
}
set
{
set {
_Text = value;
if (Window_ != null)
{
if (Window_ != null) {
Window_.Title = value;
}
}
@ -68,34 +57,26 @@ namespace SampleFramework
public IWindow Window_;
private Vector2D<int> _WindowSize;
public Vector2D<int> WindowSize
{
get
{
public Vector2D<int> WindowSize {
get {
return _WindowSize;
}
set
{
set {
_WindowSize = value;
if (Window_ != null)
{
if (Window_ != null) {
Window_.Size = value;
}
}
}
private Vector2D<int> _WindowPosition;
public Vector2D<int> WindowPosition
{
get
{
public Vector2D<int> WindowPosition {
get {
return _WindowPosition;
}
set
{
set {
_WindowPosition = value;
if (Window_ != null)
{
if (Window_ != null) {
Window_.Position = value;
}
}
@ -103,51 +84,39 @@ namespace SampleFramework
private int _Framerate;
public int Framerate
{
get
{
public int Framerate {
get {
return _Framerate;
}
set
{
set {
_Framerate = value;
if (Window_ != null)
{
if (Window_ != null) {
UpdateWindowFramerate(VSync, value);
}
}
}
private bool _FullScreen;
public bool FullScreen
{
get
{
public bool FullScreen {
get {
return _FullScreen;
}
set
{
set {
_FullScreen = value;
if (Window_ != null)
{
if (Window_ != null) {
Window_.WindowState = value ? WindowState.Fullscreen : WindowState.Normal;
}
}
}
private bool _VSync;
public bool VSync
{
get
{
public bool VSync {
get {
return _VSync;
}
set
{
set {
_VSync = value;
if (Window_ != null)
{
if (Window_ != null) {
UpdateWindowFramerate(value, Framerate);
Window_.VSync = value;
}
@ -159,21 +128,16 @@ namespace SampleFramework
private Vector2D<int> ViewPortSize = new Vector2D<int>();
private Vector2D<int> ViewPortOffset = new Vector2D<int>();
public unsafe SKBitmap GetScreenShot()
{
public unsafe SKBitmap GetScreenShot() {
int ViewportWidth = ViewPortSize.X;
int ViewportHeight = ViewPortSize.Y;
fixed(uint* pixels = new uint[(uint)ViewportWidth * (uint)ViewportHeight])
{
fixed (uint* pixels = new uint[(uint)ViewportWidth * (uint)ViewportHeight]) {
Gl.ReadBuffer(GLEnum.Front);
Gl.ReadPixels(ViewPortOffset.X, ViewPortOffset.Y, (uint)ViewportWidth, (uint)ViewportHeight, PixelFormat.Bgra, GLEnum.UnsignedByte, pixels);
fixed(uint* pixels2 = new uint[(uint)ViewportWidth * (uint)ViewportHeight])
{
for(int x = 0; x < ViewportWidth; x++)
{
for(int y = 1; y < ViewportHeight; y++)
{
fixed (uint* pixels2 = new uint[(uint)ViewportWidth * (uint)ViewportHeight]) {
for (int x = 0; x < ViewportWidth; x++) {
for (int y = 1; y < ViewportHeight; y++) {
int pos = x + ((y - 1) * ViewportWidth);
int pos2 = x + ((ViewportHeight - y) * ViewportWidth);
var p = pixels[pos2];
@ -188,24 +152,19 @@ namespace SampleFramework
}
}
public unsafe void GetScreenShotAsync(Action<SKBitmap> action)
{
public unsafe void GetScreenShotAsync(Action<SKBitmap> action) {
int ViewportWidth = ViewPortSize.X;
int ViewportHeight = ViewPortSize.Y;
byte[] pixels = new byte[(uint)ViewportWidth * (uint)ViewportHeight * 4];
Gl.ReadBuffer(GLEnum.Front);
fixed(byte* pix = pixels)
{
fixed (byte* pix = pixels) {
Gl.ReadPixels(ViewPortOffset.X, ViewPortOffset.Y, (uint)ViewportWidth, (uint)ViewportHeight, PixelFormat.Bgra, GLEnum.UnsignedByte, pix);
}
Task.Run(() =>{
fixed(byte* pixels2 = new byte[(uint)ViewportWidth * (uint)ViewportHeight * 4])
{
for(int x = 0; x < ViewportWidth; x++)
{
for(int y = 1; y < ViewportHeight; y++)
{
Task.Run(() => {
fixed (byte* pixels2 = new byte[(uint)ViewportWidth * (uint)ViewportHeight * 4]) {
for (int x = 0; x < ViewportWidth; x++) {
for (int y = 1; y < ViewportHeight; y++) {
int pos = x + ((y - 1) * ViewportWidth);
int pos2 = x + ((ViewportHeight - y) * ViewportWidth);
pixels2[(pos * 4) + 0] = pixels[(pos2 * 4) + 0];
@ -226,10 +185,8 @@ namespace SampleFramework
public static Matrix4X4<float> Camera;
public static float ScreenAspect
{
get
{
public static float ScreenAspect {
get {
return (float)GameWindowSize.Width / GameWindowSize.Height;
}
}
@ -240,15 +197,13 @@ namespace SampleFramework
/// <summary>
/// Initializes the <see cref="Game"/> class.
/// </summary>
static Game()
{
static Game() {
//GlfwProvider.UninitializedGLFW.Value.InitHint(InitHint.AnglePlatformType, (int)AnglePlatformType.OpenGL);
//GlfwProvider.UninitializedGLFW.Value.Init();
//GetError();
}
private RawImage GetIconData(string fileName)
{
private RawImage GetIconData(string fileName) {
SKCodec codec = SKCodec.Create(fileName);
using SKBitmap bitmap = SKBitmap.Decode(codec, new SKImageInfo(codec.Info.Width, codec.Info.Height, SKColorType.Rgba8888));
return new RawImage(bitmap.Width, bitmap.Height, bitmap.GetPixelSpan().ToArray());
@ -257,8 +212,7 @@ namespace SampleFramework
/// <summary>
/// Initializes a new instance of the <see cref="Game"/> class.
/// </summary>
protected Game(string iconFileName)
{
protected Game(string iconFileName) {
strIconFileName = iconFileName;
MainThreadID = Thread.CurrentThread.ManagedThreadId;
@ -299,16 +253,12 @@ namespace SampleFramework
Window_.FramebufferResize += Window_FramebufferResize;
}
private void UpdateWindowFramerate(bool vsync, int value)
{
if (vsync)
{
private void UpdateWindowFramerate(bool vsync, int value) {
if (vsync) {
Window_.UpdatesPerSecond = 0;
Window_.FramesPerSecond = 0;
Context.SwapInterval(1);
}
else
{
} else {
Window_.UpdatesPerSecond = value;
Window_.FramesPerSecond = value;
Context.SwapInterval(0);
@ -318,18 +268,15 @@ namespace SampleFramework
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose()
{
public void Dispose() {
Window_.Dispose();
}
public void Exit()
{
public void Exit() {
Window_.Close();
}
protected void ToggleWindowMode()
{
protected void ToggleWindowMode() {
/*
DeviceSettings settings = base.GraphicsDeviceManager.CurrentSettings.Clone();
if ( ( ConfigIni != null ) && ( ConfigIni.bウィンドウモード != settings.Windowed ) )
@ -359,44 +306,36 @@ namespace SampleFramework
/// <summary>
/// Runs the game.
/// </summary>
public void Run()
{
public void Run() {
Window_.Run();
}
protected virtual void Configuration()
{
protected virtual void Configuration() {
}
protected virtual void Initialize()
{
protected virtual void Initialize() {
}
protected virtual void LoadContent()
{
protected virtual void LoadContent() {
}
protected virtual void UnloadContent()
{
protected virtual void UnloadContent() {
}
protected virtual void OnExiting()
{
protected virtual void OnExiting() {
}
protected virtual void Update()
{
protected virtual void Update() {
}
protected virtual void Draw()
{
protected virtual void Draw() {
}
@ -404,14 +343,12 @@ namespace SampleFramework
/// Releases unmanaged and - optionally - managed resources
/// </summary>
/// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
protected internal virtual void Dispose(bool disposing)
{
protected internal virtual void Dispose(bool disposing) {
}
public void Window_Load()
{
public void Window_Load() {
Window_.SetWindowIcon(new ReadOnlySpan<RawImage>(GetIconData(strIconFileName)));
Context = new AngleContext(GraphicsDeviceType_, Window_);
@ -432,8 +369,7 @@ namespace SampleFramework
LoadContent();
}
public void Window_Closing()
{
public void Window_Closing() {
CTexture.Terminate();
UnloadContent();
@ -442,20 +378,17 @@ namespace SampleFramework
Context.Dispose();
}
public void Window_Update(double deltaTime)
{
public void Window_Update(double deltaTime) {
double fps = 1.0f / deltaTime;
TimeMs = (long)(Window_.Time * 1000);
Update();
}
public void Window_Render(double deltaTime)
{
public void Window_Render(double deltaTime) {
Camera = Matrix4X4<float>.Identity;
if (AsyncActions.Count > 0)
{
if (AsyncActions.Count > 0) {
AsyncActions[0]?.Invoke();
AsyncActions.Remove(AsyncActions[0]);
}
@ -468,19 +401,14 @@ namespace SampleFramework
Context.SwapBuffers();
}
public void Window_Resize(Vector2D<int> size)
{
if (size.X > 0 && size.Y > 0)
{
public void Window_Resize(Vector2D<int> size) {
if (size.X > 0 && size.Y > 0) {
float resolutionAspect = (float)GameWindowSize.Width / GameWindowSize.Height;
float windowAspect = (float)size.X / size.Y;
if (windowAspect > resolutionAspect)
{
if (windowAspect > resolutionAspect) {
ViewPortSize.X = (int)(size.Y * resolutionAspect);
ViewPortSize.Y = size.Y;
}
else
{
} else {
ViewPortSize.X = size.X;
ViewPortSize.Y = (int)(size.X / resolutionAspect);
}
@ -493,13 +421,11 @@ namespace SampleFramework
Gl.Viewport(ViewPortOffset.X, ViewPortOffset.Y, (uint)ViewPortSize.X, (uint)ViewPortSize.Y);
}
public void Window_Move(Vector2D<int> size)
{
public void Window_Move(Vector2D<int> size) {
WindowPosition = size;
}
public void Window_FramebufferResize(Vector2D<int> size)
{
public void Window_FramebufferResize(Vector2D<int> size) {
}
}
}

View File

@ -1,9 +1,5 @@
using System;
namespace SampleFramework
{
public static class GameWindowSize
{
namespace SampleFramework {
public static class GameWindowSize {
public static int Width = 1280;
public static int Height = 720;
}

View File

@ -1,53 +1,40 @@
using OpenTK.Graphics.Egl; //OpenTKさん ありがとう!
using Silk.NET.Core.Contexts;
using Silk.NET.GLFW;
using OpenTK.Graphics.Egl; //OpenTKさん ありがとう!
using Silk.NET.Windowing;
using Silk.NET.OpenGLES;
namespace SampleFramework;
public class AngleContext : IGLContext
{
public class AngleContext : IGLContext {
private nint Display;
private nint Context;
private nint Surface;
public AngleContext(AnglePlatformType anglePlatformType, IWindow window)
{
public AngleContext(AnglePlatformType anglePlatformType, IWindow window) {
nint windowHandle;
nint display;
if (window.Native.Kind.HasFlag(NativeWindowFlags.Win32))
{
if (window.Native.Kind.HasFlag(NativeWindowFlags.Win32)) {
windowHandle = window.Native.Win32.Value.Hwnd;
display = window.Native.Win32.Value.HDC;
}
else if (window.Native.Kind.HasFlag(NativeWindowFlags.X11))
{
} else if (window.Native.Kind.HasFlag(NativeWindowFlags.X11)) {
windowHandle = (nint)window.Native.X11.Value.Window;
// Temporary fix for the segfaults
// Note than X11 Display number is NOT always 0, it can be 1, 2 and so on for example in cases of user switching
display = 0;// Egl.GetDisplay(window.Native.X11.Value.Display);
}
else if (window.Native.Kind.HasFlag(NativeWindowFlags.Cocoa))
{
} else if (window.Native.Kind.HasFlag(NativeWindowFlags.Cocoa)) {
windowHandle = window.Native.Cocoa.Value;
display = 0;
}
else if (window.Native.Kind.HasFlag(NativeWindowFlags.Wayland))
{
} else if (window.Native.Kind.HasFlag(NativeWindowFlags.Wayland)) {
windowHandle = window.Native.Wayland.Value.Surface;
display = window.Native.Wayland.Value.Display;
}
else
{
} else {
throw new Exception("Window not found");
}
Source = window;
int platform = 0;
switch(anglePlatformType)
{
switch (anglePlatformType) {
case AnglePlatformType.OpenGL:
platform = Egl.PLATFORM_ANGLE_TYPE_OPENGL_ANGLE;
break;
@ -86,8 +73,7 @@ public class AngleContext : IGLContext
Egl.BUFFER_SIZE, 0,
Egl.NONE
};
unsafe
{
unsafe {
Egl.ChooseConfig(Display, configAttributes, configs, configs.Length, out int num_config);
}
@ -117,39 +103,32 @@ public class AngleContext : IGLContext
public bool IsCurrent { get; set; } = true;
public nint GetProcAddress(string proc, int? slot = null)
{
public nint GetProcAddress(string proc, int? slot = null) {
nint addr = Egl.GetProcAddress(proc);
return addr;
}
public bool TryGetProcAddress(string proc, out nint addr, int? slot = null)
{
public bool TryGetProcAddress(string proc, out nint addr, int? slot = null) {
addr = Egl.GetProcAddress(proc);
return addr != 0;
}
public void SwapInterval(int interval)
{
public void SwapInterval(int interval) {
Egl.SwapInterval(Display, interval);
}
public void SwapBuffers()
{
public void SwapBuffers() {
Egl.SwapBuffers(Display, Surface);
}
public void MakeCurrent()
{
public void MakeCurrent() {
Egl.MakeCurrent(Display, Surface, Surface, Context);
}
public void Clear()
{
public void Clear() {
}
public void Dispose()
{
public void Dispose() {
Egl.DestroyContext(Display, Context);
Egl.DestroySurface(Display, Surface);
Egl.Terminate(Display);

View File

@ -23,7 +23,6 @@
// OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Runtime.InteropServices;
// ReSharper disable InconsistentNaming
@ -31,27 +30,24 @@ using System.Runtime.InteropServices;
#pragma warning disable 1591 // Missing XML comments
namespace OpenTK.Graphics.Egl
{
using EGLNativeDisplayType = IntPtr;
using EGLNativeWindowType = IntPtr;
using EGLNativePixmapType = IntPtr;
namespace OpenTK.Graphics.Egl {
using EGLClientBuffer = IntPtr;
using EGLConfig = IntPtr;
using EGLContext = IntPtr;
using EGLDisplay = IntPtr;
using EGLNativeDisplayType = IntPtr;
using EGLNativePixmapType = IntPtr;
using EGLNativeWindowType = IntPtr;
using EGLSurface = IntPtr;
using EGLClientBuffer = IntPtr;
public enum RenderApi
{
public enum RenderApi {
ES = Egl.OPENGL_ES_API,
GL = Egl.OPENGL_API,
VG = Egl.OPENVG_API
}
[Flags]
public enum RenderableFlags
{
public enum RenderableFlags {
ES = Egl.OPENGL_ES_BIT,
ES2 = Egl.OPENGL_ES2_BIT,
ES3 = Egl.OPENGL_ES3_BIT,
@ -59,8 +55,7 @@ namespace OpenTK.Graphics.Egl
VG = Egl.OPENVG_BIT,
}
public enum ErrorCode
{
public enum ErrorCode {
SUCCESS = 12288,
NOT_INITIALIZED = 12289,
BAD_ACCESS = 12290,
@ -78,8 +73,7 @@ namespace OpenTK.Graphics.Egl
CONTEXT_LOST = 12302,
}
public enum SurfaceType
{
public enum SurfaceType {
PBUFFER_BIT = 0x0001,
PIXMAP_BIT = 0x0002,
WINDOW_BIT = 0x0004,
@ -89,17 +83,13 @@ namespace OpenTK.Graphics.Egl
SWAP_BEHAVIOR_PRESERVED_BIT = 0x0400,
}
public class EglException : Exception
{
public EglException() : base()
{ }
public class EglException : Exception {
public EglException() : base() { }
public EglException(string message) : base(message)
{ }
public EglException(string message) : base(message) { }
}
public static partial class Egl
{
public static partial class Egl {
public const int CONTEXT_MAJOR_VERSION = 0x3098;
public const int CONTEXT_MINOR_VERSION = 0x30FB;
@ -343,11 +333,9 @@ namespace OpenTK.Graphics.Egl
[DllImportAttribute("libEGL", EntryPoint = "eglCreateContext")]
private static extern IntPtr eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, int[] attrib_list);
public static EGLContext CreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, int[] attrib_list)
{
public static EGLContext CreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, int[] attrib_list) {
IntPtr ptr = eglCreateContext(dpy, config, share_context, attrib_list);
if (ptr == IntPtr.Zero)
{
if (ptr == IntPtr.Zero) {
throw new EglException(string.Format("Failed to create EGL context, error: {0}.", Egl.GetError()));
}
return ptr;
@ -407,12 +395,9 @@ namespace OpenTK.Graphics.Egl
public static extern EGLSurface CreatePlatformPixmapSurfaceEXT(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType native_pixmap, int[] attrib_list);
// Returns true if Egl drivers exist on the system.
public static bool IsSupported
{
get
{
try { GetCurrentContext(); }
catch (Exception) { return false; }
public static bool IsSupported {
get {
try { GetCurrentContext(); } catch (Exception) { return false; }
return true;
}
}

View File

@ -2,8 +2,7 @@ using Silk.NET.OpenGLES;
namespace SampleFramework;
public enum BlendType
{
public enum BlendType {
Normal,
Add,
Screen,
@ -11,12 +10,9 @@ public enum BlendType
Sub
}
public static class BlendHelper
{
public static void SetBlend(BlendType blendType)
{
switch(blendType)
{
public static class BlendHelper {
public static void SetBlend(BlendType blendType) {
switch (blendType) {
case BlendType.Normal:
Game.Gl.BlendEquation(BlendEquationModeEXT.FuncAdd);
Game.Gl.BlendFunc(GLEnum.SrcAlpha, GLEnum.OneMinusSrcAlpha);

View File

@ -2,12 +2,10 @@ using ImGuiNET;
namespace LWGFW.Graphics;
public class ImGUIManager : IDisposable
{
public class ImGUIManager : IDisposable {
private nint Context;
public ImGUIManager()
{
public ImGUIManager() {
Context = ImGui.CreateContext();
ImGui.SetCurrentContext(Context);
@ -19,8 +17,7 @@ public class ImGUIManager : IDisposable
ImGui.StyleColorsDark();
}
public void Dispose()
{
public void Dispose() {
ImGui.DestroyContext(Context);
}
}

View File

@ -2,10 +2,8 @@ using Silk.NET.OpenGLES;
namespace SampleFramework;
public static class ShaderHelper
{
public static uint CreateShader(string code, ShaderType shaderType)
{
public static class ShaderHelper {
public static uint CreateShader(string code, ShaderType shaderType) {
uint vertexShader = Game.Gl.CreateShader(shaderType);
Game.Gl.ShaderSource(vertexShader, code);
@ -20,8 +18,7 @@ public static class ShaderHelper
return vertexShader;
}
public static uint CreateShaderProgram(uint vertexShader, uint fragmentShader)
{
public static uint CreateShaderProgram(uint vertexShader, uint fragmentShader) {
uint program = Game.Gl.CreateProgram();
Game.Gl.AttachShader(program, vertexShader);
@ -40,8 +37,7 @@ public static class ShaderHelper
return program;
}
public static uint CreateShaderProgramFromSource(string vertexCode, string fragmentCode)
{
public static uint CreateShaderProgramFromSource(string vertexCode, string fragmentCode) {
uint vertexShader = CreateShader(vertexCode, ShaderType.VertexShader);
uint fragmentShader = CreateShader(fragmentCode, ShaderType.FragmentShader);

View File

@ -1,17 +1,10 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using Silk.NET.Input;
namespace FDK
{
public class CInputGamepad : IInputDevice, IDisposable
{
namespace FDK {
public class CInputGamepad : IInputDevice, IDisposable {
// コンストラクタ
public CInputGamepad(IGamepad gamepad)
{
public CInputGamepad(IGamepad gamepad) {
this.CurrentType = InputDeviceType.Gamepad;
this.GUID = gamepad.Index.ToString();
this.ID = gamepad.Index;
@ -25,58 +18,45 @@ namespace FDK
// メソッド
public void SetID( int nID )
{
public void SetID(int nID) {
this.ID = nID;
}
#region [ IInputDevice ]
//-----------------
public InputDeviceType CurrentType
{
public InputDeviceType CurrentType {
get;
private set;
}
public string GUID
{
public string GUID {
get;
private set;
}
public int ID
{
public int ID {
get;
private set;
}
public List<STInputEvent> InputEvents
{
public List<STInputEvent> InputEvents {
get;
private set;
}
public string strDeviceName
{
public string strDeviceName {
get;
set;
}
public void Polling(bool useBufferInput)
{
public void Polling(bool useBufferInput) {
InputEvents.Clear();
for (int i = 0; i < ButtonStates.Length; i++)
{
if (ButtonStates[i].Item1)
{
if (ButtonStates[i].Item2 >= 1)
{
for (int i = 0; i < ButtonStates.Length; i++) {
if (ButtonStates[i].Item1) {
if (ButtonStates[i].Item2 >= 1) {
ButtonStates[i].Item2 = 2;
}
else
{
} else {
ButtonStates[i].Item2 = 1;
InputEvents.Add(
new STInputEvent()
{
new STInputEvent() {
nKey = i,
Pressed = true,
Released = false,
@ -85,20 +65,14 @@ namespace FDK
}
);
}
}
else
{
if (ButtonStates[i].Item2 <= -1)
{
} else {
if (ButtonStates[i].Item2 <= -1) {
ButtonStates[i].Item2 = -2;
}
else
{
} else {
ButtonStates[i].Item2 = -1;
InputEvents.Add(
new STInputEvent()
{
new STInputEvent() {
nKey = i,
Pressed = false,
Released = true,
@ -111,20 +85,16 @@ namespace FDK
}
}
public bool KeyPressed(int nButton)
{
public bool KeyPressed(int nButton) {
return ButtonStates[nButton].Item2 == 1;
}
public bool KeyPressing(int nButton)
{
public bool KeyPressing(int nButton) {
return ButtonStates[nButton].Item2 >= 1;
}
public bool KeyReleased(int nButton)
{
public bool KeyReleased(int nButton) {
return ButtonStates[nButton].Item2 == -1;
}
public bool KeyReleasing(int nButton)
{
public bool KeyReleasing(int nButton) {
return ButtonStates[nButton].Item2 <= -1;
}
//-----------------
@ -132,12 +102,9 @@ namespace FDK
#region [ IDisposable ]
//-----------------
public void Dispose()
{
if(!this.IsDisposed)
{
if (this.InputEvents != null)
{
public void Dispose() {
if (!this.IsDisposed) {
if (this.InputEvents != null) {
this.InputEvents = null;
}
this.IsDisposed = true;
@ -154,18 +121,14 @@ namespace FDK
private (bool, int)[] ButtonStates = new (bool, int)[15];
private bool IsDisposed;
private void Joystick_ButtonDown(IGamepad joystick, Button button)
{
if (button.Name != ButtonName.Unknown)
{
private void Joystick_ButtonDown(IGamepad joystick, Button button) {
if (button.Name != ButtonName.Unknown) {
ButtonStates[(int)button.Name].Item1 = true;
}
}
private void Joystick_ButtonUp(IGamepad joystick, Button button)
{
if (button.Name != ButtonName.Unknown)
{
private void Joystick_ButtonUp(IGamepad joystick, Button button) {
if (button.Name != ButtonName.Unknown) {
ButtonStates[(int)button.Name].Item1 = false;
}
}

View File

@ -1,19 +1,12 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using Silk.NET.Input;
using Silk.NET.Input;
namespace FDK
{
public class CInputJoystick : IInputDevice, IDisposable
{
namespace FDK {
public class CInputJoystick : IInputDevice, IDisposable {
// コンストラクタ
private IJoystick Joystick {get; set;}
private IJoystick Joystick { get; set; }
public CInputJoystick(IJoystick joystick)
{
public CInputJoystick(IJoystick joystick) {
Joystick = joystick;
this.CurrentType = InputDeviceType.Joystick;
this.GUID = joystick.Index.ToString();
@ -30,41 +23,34 @@ namespace FDK
// メソッド
public void SetID( int nID )
{
public void SetID(int nID) {
this.ID = nID;
}
#region [ IInputDevice ]
//-----------------
public InputDeviceType CurrentType
{
public InputDeviceType CurrentType {
get;
private set;
}
public string GUID
{
public string GUID {
get;
private set;
}
public int ID
{
public int ID {
get;
private set;
}
public List<STInputEvent> InputEvents
{
public List<STInputEvent> InputEvents {
get;
private set;
}
public string strDeviceName
{
public string strDeviceName {
get;
set;
}
public void Polling(bool useBufferInput)
{
public void Polling(bool useBufferInput) {
InputEvents.Clear();
// BUG: In Silk.NET, GLFW input does not fire events, so we have to poll
@ -75,21 +61,15 @@ namespace FDK
ButtonStates[button.Index].Item1 = button.Pressed;
}
for (int i = 0; i < ButtonStates.Length; i++)
{
if (ButtonStates[i].Item1)
{
if (ButtonStates[i].Item2 >= 1)
{
for (int i = 0; i < ButtonStates.Length; i++) {
if (ButtonStates[i].Item1) {
if (ButtonStates[i].Item2 >= 1) {
ButtonStates[i].Item2 = 2;
}
else
{
} else {
ButtonStates[i].Item2 = 1;
InputEvents.Add(
new STInputEvent()
{
new STInputEvent() {
nKey = i,
Pressed = true,
Released = false,
@ -98,20 +78,14 @@ namespace FDK
}
);
}
}
else
{
if (ButtonStates[i].Item2 <= -1)
{
} else {
if (ButtonStates[i].Item2 <= -1) {
ButtonStates[i].Item2 = -2;
}
else
{
} else {
ButtonStates[i].Item2 = -1;
InputEvents.Add(
new STInputEvent()
{
new STInputEvent() {
nKey = i,
Pressed = false,
Released = true,
@ -124,20 +98,16 @@ namespace FDK
}
}
public bool KeyPressed(int nButton)
{
public bool KeyPressed(int nButton) {
return ButtonStates[nButton].Item2 == 1;
}
public bool KeyPressing(int nButton)
{
public bool KeyPressing(int nButton) {
return ButtonStates[nButton].Item2 >= 1;
}
public bool KeyReleased(int nButton)
{
public bool KeyReleased(int nButton) {
return ButtonStates[nButton].Item2 == -1;
}
public bool KeyReleasing(int nButton)
{
public bool KeyReleasing(int nButton) {
return ButtonStates[nButton].Item2 <= -1;
}
//-----------------
@ -145,12 +115,9 @@ namespace FDK
#region [ IDisposable ]
//-----------------
public void Dispose()
{
if(!this.IsDisposed)
{
if (this.InputEvents != null)
{
public void Dispose() {
if (!this.IsDisposed) {
if (this.InputEvents != null) {
this.InputEvents = null;
}
this.IsDisposed = true;
@ -167,29 +134,23 @@ namespace FDK
private (bool, int)[] ButtonStates = new (bool, int)[18];
private bool IsDisposed;
private void Joystick_ButtonDown(IJoystick joystick, Button button)
{
if (button.Name != ButtonName.Unknown)
{
private void Joystick_ButtonDown(IJoystick joystick, Button button) {
if (button.Name != ButtonName.Unknown) {
ButtonStates[(int)button.Name].Item1 = true;
}
}
private void Joystick_ButtonUp(IJoystick joystick, Button button)
{
if (button.Name != ButtonName.Unknown)
{
private void Joystick_ButtonUp(IJoystick joystick, Button button) {
if (button.Name != ButtonName.Unknown) {
ButtonStates[(int)button.Name].Item1 = false;
}
}
private void Joystick_AxisMoved(IJoystick joystick, Axis axis)
{
private void Joystick_AxisMoved(IJoystick joystick, Axis axis) {
}
private void Joystick_HatMoved(IJoystick joystick, Hat hat)
{
private void Joystick_HatMoved(IJoystick joystick, Hat hat) {
}
//-----------------

View File

@ -1,23 +1,15 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using Silk.NET.Input;
using Silk.NET.Input;
namespace FDK
{
public class CInputKeyboard : IInputDevice, IDisposable
{
namespace FDK {
public class CInputKeyboard : IInputDevice, IDisposable {
// コンストラクタ
public CInputKeyboard(IReadOnlyList<IKeyboard> keyboards)
{
public CInputKeyboard(IReadOnlyList<IKeyboard> keyboards) {
this.CurrentType = InputDeviceType.Keyboard;
this.GUID = "";
this.ID = 0;
foreach (var keyboard in keyboards)
{
foreach (var keyboard in keyboards) {
keyboard.KeyDown += KeyDown;
keyboard.KeyUp += KeyUp;
keyboard.KeyChar += KeyChar;
@ -39,24 +31,17 @@ namespace FDK
public List<STInputEvent> InputEvents { get; private set; }
public string strDeviceName { get; set; }
public void Polling(bool useBufferInput)
{
public void Polling(bool useBufferInput) {
InputEvents.Clear();
for (int i = 0; i < KeyStates.Length; i++)
{
if (KeyStates[i].Item1)
{
if (KeyStates[i].Item2 >= 1)
{
for (int i = 0; i < KeyStates.Length; i++) {
if (KeyStates[i].Item1) {
if (KeyStates[i].Item2 >= 1) {
KeyStates[i].Item2 = 2;
}
else
{
} else {
KeyStates[i].Item2 = 1;
InputEvents.Add(
new STInputEvent()
{
new STInputEvent() {
nKey = i,
Pressed = true,
Released = false,
@ -65,19 +50,13 @@ namespace FDK
}
);
}
}
else
{
if (KeyStates[i].Item2 <= -1)
{
} else {
if (KeyStates[i].Item2 <= -1) {
KeyStates[i].Item2 = -2;
}
else
{
} else {
KeyStates[i].Item2 = -1;
InputEvents.Add(
new STInputEvent()
{
new STInputEvent() {
nKey = i,
Pressed = false,
Released = true,
@ -92,29 +71,25 @@ namespace FDK
/// <param name="nKey">
/// 調べる SlimDX.DirectInput.Key を int にキャストした値。SharpDX.DirectInput.Key ではないので注意。)
/// </param>
public bool KeyPressed(int nKey)
{
public bool KeyPressed(int nKey) {
return KeyStates[nKey].Item2 == 1;
}
/// <param name="nKey">
/// 調べる SlimDX.DirectInput.Key を int にキャストした値。SharpDX.DirectInput.Key ではないので注意。)
/// </param>
public bool KeyPressing(int nKey)
{
public bool KeyPressing(int nKey) {
return KeyStates[nKey].Item2 >= 1;
}
/// <param name="nKey">
/// 調べる SlimDX.DirectInput.Key を int にキャストした値。SharpDX.DirectInput.Key ではないので注意。)
/// </param>
public bool KeyReleased(int nKey)
{
public bool KeyReleased(int nKey) {
return KeyStates[nKey].Item2 == -1;
}
/// <param name="nKey">
/// 調べる SlimDX.DirectInput.Key を int にキャストした値。SharpDX.DirectInput.Key ではないので注意。)
/// </param>
public bool KeyReleasing(int nKey)
{
public bool KeyReleasing(int nKey) {
return KeyStates[nKey].Item2 <= -1;
}
//-----------------
@ -122,12 +97,9 @@ namespace FDK
#region [ IDisposable ]
//-----------------
public void Dispose()
{
if(!this.IsDisposed)
{
if (this.InputEvents != null)
{
public void Dispose() {
if (!this.IsDisposed) {
if (this.InputEvents != null) {
this.InputEvents = null;
}
this.IsDisposed = true;
@ -147,26 +119,21 @@ namespace FDK
//private CTimer ct;
private void KeyDown(IKeyboard keyboard, Key key, int keyCode)
{
if (key != Key.Unknown)
{
private void KeyDown(IKeyboard keyboard, Key key, int keyCode) {
if (key != Key.Unknown) {
var keyNum = DeviceConstantConverter.DIKtoKey(key);
KeyStates[(int)keyNum].Item1 = true;
}
}
private void KeyUp(IKeyboard keyboard, Key key, int keyCode)
{
if (key != Key.Unknown)
{
private void KeyUp(IKeyboard keyboard, Key key, int keyCode) {
if (key != Key.Unknown) {
var keyNum = DeviceConstantConverter.DIKtoKey(key);
KeyStates[(int)keyNum].Item1 = false;
}
}
private void KeyChar(IKeyboard keyboard, char ch)
{
private void KeyChar(IKeyboard keyboard, char ch) {
}
//-----------------

View File

@ -1,12 +1,5 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
namespace FDK
{
public class CInputMIDI : IInputDevice, IDisposable
{
namespace FDK {
public class CInputMIDI : IInputDevice, IDisposable {
// プロパティ
public IntPtr MidiInPtr;
@ -14,8 +7,7 @@ namespace FDK
// コンストラクタ
public CInputMIDI(uint nID)
{
public CInputMIDI(uint nID) {
this.MidiInPtr = IntPtr.Zero;
this.EventBuffers = new List<STInputEvent>(32);
this.InputEvents = new List<STInputEvent>(32);
@ -28,8 +20,7 @@ namespace FDK
// メソッド
public void tメッセージからMIDI信号のみ受信(uint wMsg, IntPtr dwInstance, IntPtr dwParam1, IntPtr dwParam2, long n受信システム時刻)
{
public void tメッセージからMIDI信号のみ受信(uint wMsg, IntPtr dwInstance, IntPtr dwParam1, IntPtr dwParam2, long n受信システム時刻) {
/*
if (wMsg == CWin32.MIM_DATA)
{
@ -71,8 +62,7 @@ namespace FDK
public List<STInputEvent> InputEvents { get; private set; }
public string strDeviceName { get; set; }
public void Polling(bool bWindowがアクティブ中)
{
public void Polling(bool bWindowがアクティブ中) {
// this.list入力イベント = new List<STInputEvent>( 32 );
this.InputEvents.Clear(); // #xxxxx 2012.6.11 yyagi; To optimize, I removed new();
@ -81,27 +71,21 @@ namespace FDK
this.EventBuffers.Clear();
}
public bool KeyPressed(int nKey)
{
foreach (STInputEvent event2 in this.InputEvents)
{
if ((event2.nKey == nKey) && event2.Pressed)
{
public bool KeyPressed(int nKey) {
foreach (STInputEvent event2 in this.InputEvents) {
if ((event2.nKey == nKey) && event2.Pressed) {
return true;
}
}
return false;
}
public bool KeyPressing(int nKey)
{
public bool KeyPressing(int nKey) {
return false;
}
public bool KeyReleased(int nKey)
{
public bool KeyReleased(int nKey) {
return false;
}
public bool KeyReleasing(int nKey)
{
public bool KeyReleasing(int nKey) {
return false;
}
//-----------------
@ -109,14 +93,11 @@ namespace FDK
#region [ IDisposable ]
//-----------------
public void Dispose()
{
if (this.EventBuffers != null)
{
public void Dispose() {
if (this.EventBuffers != null) {
this.EventBuffers = null;
}
if (this.InputEvents != null)
{
if (this.InputEvents != null) {
this.InputEvents = null;
}
}

View File

@ -1,15 +1,9 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Runtime.InteropServices;
using Silk.NET.Windowing;
using System.Diagnostics;
using Silk.NET.Input;
using Silk.NET.Windowing;
namespace FDK
{
public class CInputManager : IDisposable
{
namespace FDK {
public class CInputManager : IDisposable {
// 定数
public static int DefaultVolume = 110;
@ -17,23 +11,17 @@ namespace FDK
// プロパティ
public List<IInputDevice> InputDevices
{
public List<IInputDevice> InputDevices {
get;
private set;
}
public IInputDevice Keyboard
{
get
{
if (this._Keyboard != null)
{
public IInputDevice Keyboard {
get {
if (this._Keyboard != null) {
return this._Keyboard;
}
foreach (IInputDevice device in this.InputDevices)
{
if (device.CurrentType == InputDeviceType.Keyboard)
{
foreach (IInputDevice device in this.InputDevices) {
if (device.CurrentType == InputDeviceType.Keyboard) {
this._Keyboard = device;
return device;
}
@ -41,18 +29,13 @@ namespace FDK
return null;
}
}
public IInputDevice Mouse
{
get
{
if (this._Mouse != null)
{
public IInputDevice Mouse {
get {
if (this._Mouse != null) {
return this._Mouse;
}
foreach (IInputDevice device in this.InputDevices)
{
if (device.CurrentType == InputDeviceType.Mouse)
{
foreach (IInputDevice device in this.InputDevices) {
if (device.CurrentType == InputDeviceType.Mouse) {
this._Mouse = device;
return device;
}
@ -63,129 +46,97 @@ namespace FDK
// コンストラクタ
public CInputManager(IWindow window, bool bUseMidiIn = true)
{
public CInputManager(IWindow window, bool bUseMidiIn = true) {
Initialize(window, bUseMidiIn);
}
public void Initialize(IWindow window, bool bUseMidiIn)
{
public void Initialize(IWindow window, bool bUseMidiIn) {
Context = window.CreateInput();
this.InputDevices = new List<IInputDevice>(10);
#region [ Enumerate keyboard/mouse: exception is masked if keyboard/mouse is not connected ]
CInputKeyboard cinputkeyboard = null;
CInputMouse cinputmouse = null;
try
{
try {
cinputkeyboard = new CInputKeyboard(Context.Keyboards);
cinputmouse = new CInputMouse(Context.Mice[0]);
} catch {
}
catch
{
}
if (cinputkeyboard != null)
{
if (cinputkeyboard != null) {
this.InputDevices.Add(cinputkeyboard);
}
if (cinputmouse != null)
{
if (cinputmouse != null) {
this.InputDevices.Add(cinputmouse);
}
#endregion
#region [ Enumerate joypad ]
foreach (var joysticks in Context.Joysticks)
{
foreach (var joysticks in Context.Joysticks) {
this.InputDevices.Add(new CInputJoystick(joysticks));
}
foreach (var gamepad in Context.Gamepads)
{
foreach (var gamepad in Context.Gamepads) {
this.InputDevices.Add(new CInputGamepad(gamepad));
}
#endregion
Trace.TraceInformation("Found {0} Input Device{1}", InputDevices.Count, InputDevices.Count != 1 ? "s:" : ":");
for (int i = 0; i < InputDevices.Count; i++)
{
try
{
for (int i = 0; i < InputDevices.Count; i++) {
try {
Trace.TraceInformation("Input Device #" + i + " (" + InputDevices[i].CurrentType.ToString() + ")");
}
catch { }
} catch { }
}
}
// メソッド
public IInputDevice Joystick(int ID)
{
foreach (IInputDevice device in this.InputDevices)
{
if ((device.CurrentType == InputDeviceType.Joystick) && (device.ID == ID))
{
public IInputDevice Joystick(int ID) {
foreach (IInputDevice device in this.InputDevices) {
if ((device.CurrentType == InputDeviceType.Joystick) && (device.ID == ID)) {
return device;
}
}
return null;
}
public IInputDevice Joystick(string GUID)
{
foreach (IInputDevice device in this.InputDevices)
{
if ((device.CurrentType == InputDeviceType.Joystick) && device.GUID.Equals(GUID))
{
public IInputDevice Joystick(string GUID) {
foreach (IInputDevice device in this.InputDevices) {
if ((device.CurrentType == InputDeviceType.Joystick) && device.GUID.Equals(GUID)) {
return device;
}
}
return null;
}
public IInputDevice Gamepad(int ID)
{
foreach (IInputDevice device in this.InputDevices)
{
if ((device.CurrentType == InputDeviceType.Gamepad) && (device.ID == ID))
{
public IInputDevice Gamepad(int ID) {
foreach (IInputDevice device in this.InputDevices) {
if ((device.CurrentType == InputDeviceType.Gamepad) && (device.ID == ID)) {
return device;
}
}
return null;
}
public IInputDevice Gamepad(string GUID)
{
foreach (IInputDevice device in this.InputDevices)
{
if ((device.CurrentType == InputDeviceType.Gamepad) && device.GUID.Equals(GUID))
{
public IInputDevice Gamepad(string GUID) {
foreach (IInputDevice device in this.InputDevices) {
if ((device.CurrentType == InputDeviceType.Gamepad) && device.GUID.Equals(GUID)) {
return device;
}
}
return null;
}
public IInputDevice MidiIn(int ID)
{
foreach (IInputDevice device in this.InputDevices)
{
if ((device.CurrentType == InputDeviceType.MidiIn) && (device.ID == ID))
{
public IInputDevice MidiIn(int ID) {
foreach (IInputDevice device in this.InputDevices) {
if ((device.CurrentType == InputDeviceType.MidiIn) && (device.ID == ID)) {
return device;
}
}
return null;
}
public void Polling(bool useBufferInput)
{
lock (this.objMidiIn排他用)
{
public void Polling(bool useBufferInput) {
lock (this.objMidiIn排他用) {
// foreach( IInputDevice device in this.list入力デバイス )
for (int i = this.InputDevices.Count - 1; i >= 0; i--) // #24016 2011.1.6 yyagi: change not to use "foreach" to avoid InvalidOperation exception by Remove().
{
IInputDevice device = this.InputDevices[i];
try
{
try {
device.Polling(useBufferInput);
}
catch (Exception e) // #24016 2011.1.6 yyagi: catch exception for unplugging USB joystick, and remove the device object from the polling items.
} catch (Exception e) // #24016 2011.1.6 yyagi: catch exception for unplugging USB joystick, and remove the device object from the polling items.
{
this.InputDevices.Remove(device);
device.Dispose();
@ -197,30 +148,22 @@ namespace FDK
#region [ IDisposableα ]
//-----------------
public void Dispose()
{
public void Dispose() {
this.Dispose(true);
}
public void Dispose(bool disposeManagedObjects)
{
if (!this.bDisposed済み)
{
if (disposeManagedObjects)
{
foreach (IInputDevice device in this.InputDevices)
{
public void Dispose(bool disposeManagedObjects) {
if (!this.bDisposed済み) {
if (disposeManagedObjects) {
foreach (IInputDevice device in this.InputDevices) {
CInputMIDI tmidi = device as CInputMIDI;
if (tmidi != null)
{
if (tmidi != null) {
Trace.TraceInformation("MIDI In: [{0}] を停止しました。", new object[] { tmidi.ID });
}
}
foreach (IInputDevice device2 in this.InputDevices)
{
foreach (IInputDevice device2 in this.InputDevices) {
device2.Dispose();
}
lock (this.objMidiIn排他用)
{
lock (this.objMidiIn排他用) {
this.InputDevices.Clear();
}
@ -229,8 +172,7 @@ namespace FDK
this.bDisposed済み = true;
}
}
~CInputManager()
{
~CInputManager() {
this.Dispose(false);
GC.KeepAlive(this);
}

View File

@ -1,14 +1,9 @@
using System;
using System.Diagnostics;
using System.Numerics;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using Silk.NET.Input;
namespace FDK
{
public class CInputMouse : IInputDevice, IDisposable
{
namespace FDK {
public class CInputMouse : IInputDevice, IDisposable {
// 定数
public const int MouseButtonCount = 8;
@ -16,18 +11,14 @@ namespace FDK
// コンストラクタ
public CInputMouse(IMouse mouse)
{
public CInputMouse(IMouse mouse) {
this.CurrentType = InputDeviceType.Mouse;
this.GUID = "";
this.ID = 0;
try
{
try {
Trace.TraceInformation(mouse.Name + " を生成しました。"); // なぜか0x00のゴミが出るので削除
this.strDeviceName = mouse.Name;
}
catch
{
} catch {
Trace.TraceWarning("Mouse デバイスの生成に失敗しました。");
throw;
}
@ -52,24 +43,17 @@ namespace FDK
public List<STInputEvent> InputEvents { get; private set; }
public string strDeviceName { get; set; }
public void Polling(bool useBufferInput)
{
public void Polling(bool useBufferInput) {
InputEvents.Clear();
for (int i = 0; i < MouseStates.Length; i++)
{
if (MouseStates[i].Item1)
{
if (MouseStates[i].Item2 >= 1)
{
for (int i = 0; i < MouseStates.Length; i++) {
if (MouseStates[i].Item1) {
if (MouseStates[i].Item2 >= 1) {
MouseStates[i].Item2 = 2;
}
else
{
} else {
MouseStates[i].Item2 = 1;
InputEvents.Add(
new STInputEvent()
{
new STInputEvent() {
nKey = i,
Pressed = true,
Released = false,
@ -78,19 +62,13 @@ namespace FDK
}
);
}
}
else
{
if (MouseStates[i].Item2 <= -1)
{
} else {
if (MouseStates[i].Item2 <= -1) {
MouseStates[i].Item2 = -2;
}
else
{
} else {
MouseStates[i].Item2 = -1;
InputEvents.Add(
new STInputEvent()
{
new STInputEvent() {
nKey = i,
Pressed = false,
Released = true,
@ -102,20 +80,16 @@ namespace FDK
}
}
}
public bool KeyPressed(int nButton)
{
public bool KeyPressed(int nButton) {
return MouseStates[nButton].Item2 == 1;
}
public bool KeyPressing(int nButton)
{
public bool KeyPressing(int nButton) {
return MouseStates[nButton].Item2 >= 1;
}
public bool KeyReleased(int nButton)
{
public bool KeyReleased(int nButton) {
return MouseStates[nButton].Item2 == -1;
}
public bool KeyReleasing(int nButton)
{
public bool KeyReleasing(int nButton) {
return MouseStates[nButton].Item2 <= -1;
}
//-----------------
@ -123,12 +97,9 @@ namespace FDK
#region [ IDisposable ]
//-----------------
public void Dispose()
{
if(!this.IsDisposed)
{
if (this.InputEvents != null)
{
public void Dispose() {
if (!this.IsDisposed) {
if (this.InputEvents != null) {
this.InputEvents = null;
}
this.IsDisposed = true;
@ -145,34 +116,27 @@ namespace FDK
private (bool, int)[] MouseStates = new (bool, int)[12];
private bool IsDisposed;
private void Mouse_Click(IMouse mouse, MouseButton mouseButton, Vector2 vector2)
{
private void Mouse_Click(IMouse mouse, MouseButton mouseButton, Vector2 vector2) {
}
private void Mouse_DoubleClick(IMouse mouse, MouseButton mouseButton, Vector2 vector2)
{
private void Mouse_DoubleClick(IMouse mouse, MouseButton mouseButton, Vector2 vector2) {
}
private void Mouse_MouseDown(IMouse mouse, MouseButton mouseButton)
{
if (mouseButton != MouseButton.Unknown)
{
private void Mouse_MouseDown(IMouse mouse, MouseButton mouseButton) {
if (mouseButton != MouseButton.Unknown) {
MouseStates[(int)mouseButton].Item1 = true;
}
}
private void Mouse_MouseUp(IMouse mouse, MouseButton mouseButton)
{
if (mouseButton != MouseButton.Unknown)
{
private void Mouse_MouseUp(IMouse mouse, MouseButton mouseButton) {
if (mouseButton != MouseButton.Unknown) {
MouseStates[(int)mouseButton].Item1 = false;
}
}
private void Mouse_MouseMove(IMouse mouse, Vector2 vector2)
{
private void Mouse_MouseMove(IMouse mouse, Vector2 vector2) {
}
//-----------------

View File

@ -1,18 +1,12 @@
using System;
using System.Collections.Generic;
using System.Text;
using SlimDXKeys;
using SlimDXKeys;
using SlimDXKey = SlimDXKeys.Key;
namespace FDK
{
public static class DeviceConstantConverter
{
namespace FDK {
public static class DeviceConstantConverter {
// メソッド
public static Key DIKtoKey( Silk.NET.Input.Key key )
{
public static Key DIKtoKey(Silk.NET.Input.Key key) {
return _DIKtoKey[key];
}

View File

@ -1,41 +1,31 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace FDK
{
public interface IInputDevice : IDisposable
{
namespace FDK {
public interface IInputDevice : IDisposable {
// プロパティ
InputDeviceType CurrentType
{
InputDeviceType CurrentType {
get;
}
string GUID
{
string GUID {
get;
}
int ID
{
int ID {
get;
}
List<STInputEvent> InputEvents
{
List<STInputEvent> InputEvents {
get;
}
// メソッドインターフェース
void Polling( bool bバッファ入力を使用する );
bool KeyPressed( int nKey );
bool KeyPressed( List<int> nKey ) { return nKey.Any(key => KeyPressed(key)); }
bool KeyPressing( int nKey );
bool KeyPressing( List<int> nKey ) { return nKey.Any(key => KeyPressing(key)); }
bool KeyReleased( int nKey );
bool KeyReleased( List<int> nKey ) { return nKey.Any(key => KeyReleased(key)); }
bool KeyReleasing( int nKey );
bool KeyReleasing( List<int> nKey ) { return nKey.Any(key => KeyReleasing(key)); }
void Polling(bool bバッファ入力を使用する);
bool KeyPressed(int nKey);
bool KeyPressed(List<int> nKey) { return nKey.Any(key => KeyPressed(key)); }
bool KeyPressing(int nKey);
bool KeyPressing(List<int> nKey) { return nKey.Any(key => KeyPressing(key)); }
bool KeyReleased(int nKey);
bool KeyReleased(List<int> nKey) { return nKey.Any(key => KeyReleased(key)); }
bool KeyReleasing(int nKey);
bool KeyReleasing(List<int> nKey) { return nKey.Any(key => KeyReleasing(key)); }
}
}

View File

@ -1,13 +1,7 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace FDK
{
namespace FDK {
// 定数
public enum InputDeviceType
{
public enum InputDeviceType {
Keyboard,
Mouse,
Joystick,

View File

@ -1,15 +1,10 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices;
namespace FDK
{
namespace FDK {
// 構造体
[StructLayout( LayoutKind.Sequential )]
public struct STInputEvent
{
[StructLayout(LayoutKind.Sequential)]
public struct STInputEvent {
public int nKey { get; set; }
public bool Pressed { get; set; }
public bool Released { get; set; }

View File

@ -1,13 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SlimDXKeys
{
public enum Key
{
namespace SlimDXKeys {
public enum Key {
D0 = 0,
D1 = 1,
D2 = 2,
@ -154,8 +146,7 @@ namespace SlimDXKeys
Yen = 143,
Unknown = 144
}
public enum MouseObject
{
public enum MouseObject {
Button1 = 0,
Button2 = 1,
Button3 = 2,

View File

@ -1,27 +1,18 @@
using System;
using System.Collections.ObjectModel;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.IO;
using System.Linq;
using System.Threading;
using FDK.BassMixExtension;
using FDK.ExtensionMethods;
using ManagedBass;
using ManagedBass.Asio;
using ManagedBass.Wasapi;
using ManagedBass.Mix;
using ManagedBass.Fx;
using Silk.NET.Windowing;
using FDK.BassMixExtension;
using ManagedBass.Mix;
namespace FDK
{
namespace FDK {
// CSound は、サウンドデバイスが変更されたときも、インスタンスを再作成することなく、新しいデバイスで作り直せる必要がある。
// そのため、デバイスごとに別のクラスに分割するのではなく、1つのクラスに集約するものとする。
public class CSound : IDisposable
{
public class CSound : IDisposable {
public const int MinimumSongVol = 0;
public const int MaximumSongVol = 200; // support an approximate doubling in volume.
public const int DefaultSongVol = 100;
@ -49,8 +40,7 @@ namespace FDK
#region [ DTXMania用拡張 ]
public int TotalPlayTime
{
public int TotalPlayTime {
get;
private set;
}
@ -63,56 +53,41 @@ namespace FDK
{
get { return false; }
}
public double Frequency
{
get
{
public double Frequency {
get {
return _Frequency;
}
set
{
if ( _Frequency != value )
{
set {
if (_Frequency != value) {
_Frequency = value;
if ( IsBassSound )
{
Bass.ChannelSetAttribute( this.hBassStream, ChannelAttribute.Frequency, ( float ) ( _Frequency * _PlaySpeed * nオリジナルの周波数 ) );
if (IsBassSound) {
Bass.ChannelSetAttribute(this.hBassStream, ChannelAttribute.Frequency, (float)(_Frequency * _PlaySpeed * nオリジナルの周波数));
}
}
}
}
public double PlaySpeed
{
get
{
public double PlaySpeed {
get {
return _PlaySpeed;
}
set
{
if ( _PlaySpeed != value )
{
set {
if (_PlaySpeed != value) {
_PlaySpeed = value;
IsNormalSpeed = ( _PlaySpeed == 1.000f );
if ( IsBassSound )
{
if ( _hTempoStream != 0 && !this.IsNormalSpeed ) // 再生速度がx1.000のときは、TempoStreamを用いないようにして高速化する
IsNormalSpeed = (_PlaySpeed == 1.000f);
if (IsBassSound) {
if (_hTempoStream != 0 && !this.IsNormalSpeed) // 再生速度がx1.000のときは、TempoStreamを用いないようにして高速化する
{
this.hBassStream = _hTempoStream;
}
else
{
} else {
this.hBassStream = _hBassStream;
}
if ( SoundManager.bIsTimeStretch )
{
Bass.ChannelSetAttribute( this.hBassStream, ChannelAttribute.Tempo, (float) ( PlaySpeed * 100 - 100 ) );
if (SoundManager.bIsTimeStretch) {
Bass.ChannelSetAttribute(this.hBassStream, ChannelAttribute.Tempo, (float)(PlaySpeed * 100 - 100));
//double seconds = Bass.BASS_ChannelBytes2Seconds( this.hTempoStream, nBytes );
//this.n総演奏時間ms = (int) ( seconds * 1000 );
}
else
{
Bass.ChannelSetAttribute( this.hBassStream, ChannelAttribute.Frequency, ( float ) ( _Frequency * _PlaySpeed * nオリジナルの周波数 ) );
} else {
Bass.ChannelSetAttribute(this.hBassStream, ChannelAttribute.Frequency, (float)(_Frequency * _PlaySpeed * nオリジナルの周波数));
}
}
}
@ -135,13 +110,11 @@ namespace FDK
/// for mixing in the SONGVOL value, when available. It is also used for
/// DTXViewer preview mode.
/// </summary>
public void SetGain(int songVol)
{
public void SetGain(int songVol) {
SetGain(LinearIntegerPercentToLufs(songVol), null);
}
private static Lufs LinearIntegerPercentToLufs(int percent)
{
private static Lufs LinearIntegerPercentToLufs(int percent) {
// 2018-08-27 twopointzero: We'll use the standard conversion until an appropriate curve can be selected
return new Lufs(20.0 * Math.Log10(percent / 100.0));
}
@ -155,18 +128,15 @@ namespace FDK
/// This method, taking a LUFS gain value and a LUFS true audio peak value,
/// is used for mixing in the loudness-metadata-base gain value, when available.
/// </summary>
public void SetGain(Lufs gain, Lufs? truePeak)
{
if (Equals(_gain, gain))
{
public void SetGain(Lufs gain, Lufs? truePeak) {
if (Equals(_gain, gain)) {
return;
}
_gain = gain;
_truePeak = truePeak;
if (SoundGroup == ESoundGroup.SongPlayback)
{
if (SoundGroup == ESoundGroup.SongPlayback) {
Trace.TraceInformation($"{nameof(CSound)}.{nameof(SetGain)}: Gain: {_gain}. True Peak: {_truePeak}");
}
@ -182,20 +152,16 @@ namespace FDK
/// case right now for the song selection screen background music fade
/// in and fade out.
/// </summary>
public int AutomationLevel
{
public int AutomationLevel {
get => _automationLevel;
set
{
if (_automationLevel == value)
{
set {
if (_automationLevel == value) {
return;
}
_automationLevel = value;
if (SoundGroup == ESoundGroup.SongPlayback)
{
if (SoundGroup == ESoundGroup.SongPlayback) {
Trace.TraceInformation($"{nameof(CSound)}.{nameof(AutomationLevel)} set: {AutomationLevel}");
}
@ -216,20 +182,16 @@ namespace FDK
///
/// See the SoundGroupLevelController and related classes for more.
/// </summary>
public int GroupLevel
{
public int GroupLevel {
private get => _groupLevel;
set
{
if (_groupLevel == value)
{
set {
if (_groupLevel == value) {
return;
}
_groupLevel = value;
if (SoundGroup == ESoundGroup.SongPlayback)
{
if (SoundGroup == ESoundGroup.SongPlayback) {
Trace.TraceInformation($"{nameof(CSound)}.{nameof(GroupLevel)} set: {GroupLevel}");
}
@ -237,8 +199,7 @@ namespace FDK
}
}
private void SetVolume()
{
private void SetVolume() {
var automationLevel = LinearIntegerPercentToLufs(AutomationLevel);
var groupLevel = LinearIntegerPercentToLufs(GroupLevel);
@ -250,8 +211,7 @@ namespace FDK
var safeTruePeakGain = _truePeak?.Negate() ?? new Lufs(0);
var finalGain = gain.Min(safeTruePeakGain);
if (SoundGroup == ESoundGroup.SongPlayback)
{
if (SoundGroup == ESoundGroup.SongPlayback) {
Trace.TraceInformation(
$"{nameof(CSound)}.{nameof(SetVolume)}: Gain:{_gain}. Automation Level: {automationLevel}. Group Level: {groupLevel}. Summed Gain: {gain}. Safe True Peak Gain: {safeTruePeakGain}. Final Gain: {finalGain}.");
}
@ -259,15 +219,12 @@ namespace FDK
lufs音量 = finalGain;
}
private Lufs lufs音量
{
set
{
if (this.IsBassSound)
{
private Lufs lufs音量 {
set {
if (this.IsBassSound) {
var db音量 = ((value.ToDouble() / 100.0) + 1.0).Clamp(0, 1);
Bass.ChannelSetAttribute(this._hBassStream, ChannelAttribute.Volume, (float) db音量);
Bass.ChannelSetAttribute(this._hTempoStream, ChannelAttribute.Volume, (float) db音量);
Bass.ChannelSetAttribute(this._hBassStream, ChannelAttribute.Volume, (float)db音量);
Bass.ChannelSetAttribute(this._hTempoStream, ChannelAttribute.Volume, (float)db音量);
}
}
}
@ -275,28 +232,23 @@ namespace FDK
/// <summary>
/// <para>左:-100中央:0100:右。set のみ。</para>
/// </summary>
public int SoundPosition
{
get
{
if( this.IsBassSound )
{
public int SoundPosition {
get {
if (this.IsBassSound) {
float f位置 = 0.0f;
if ( !Bass.ChannelGetAttribute( this.hBassStream, ChannelAttribute.Pan, out f位置 ) )
if (!Bass.ChannelGetAttribute(this.hBassStream, ChannelAttribute.Pan, out f位置))
//if( BassMix.BASS_Mixer_ChannelGetEnvelopePos( this.hBassStream, BASSMIXEnvelope.BASS_MIXER_ENV_PAN, ref f位置 ) == -1 )
return 0;
return (int) ( f位置 * 100 );
return (int)(f位置 * 100);
}
return -9999;
}
set
{
if( this.IsBassSound )
{
float f位置 = Math.Min( Math.Max( value, -100 ), 100 ) / 100.0f; // -100100 → -1.01.0
set {
if (this.IsBassSound) {
float f位置 = Math.Min(Math.Max(value, -100), 100) / 100.0f; // -100100 → -1.01.0
//var nodes = new BASS_MIXER_NODE[ 1 ] { new BASS_MIXER_NODE( 0, f位置 ) };
//BassMix.BASS_Mixer_ChannelSetEnvelope( this.hBassStream, BASSMIXEnvelope.BASS_MIXER_ENV_PAN, nodes );
Bass.ChannelSetAttribute( this.hBassStream, ChannelAttribute.Pan, f位置 );
Bass.ChannelSetAttribute(this.hBassStream, ChannelAttribute.Pan, f位置);
}
}
}
@ -307,112 +259,89 @@ namespace FDK
/// </summary>
public static readonly ObservableCollection<CSound> SoundInstances = new ObservableCollection<CSound>();
public static void ShowAllCSoundFiles()
{
public static void ShowAllCSoundFiles() {
int i = 0;
foreach ( CSound cs in SoundInstances )
{
Debug.WriteLine( i++.ToString( "d3" ) + ": " + Path.GetFileName( cs.FileName ) );
foreach (CSound cs in SoundInstances) {
Debug.WriteLine(i++.ToString("d3") + ": " + Path.GetFileName(cs.FileName));
}
}
public CSound(ESoundGroup soundGroup)
{
public CSound(ESoundGroup soundGroup) {
SoundGroup = soundGroup;
this.SoundPosition = 0;
this._Frequency = 1.0;
this._PlaySpeed = 1.0;
// this._cbRemoveMixerChannel = new WaitCallback( RemoveMixerChannelLater );
// this._cbRemoveMixerChannel = new WaitCallback( RemoveMixerChannelLater );
this._hBassStream = -1;
this._hTempoStream = 0;
}
public void CreateBassSound( string fileName, int hMixer )
{
public void CreateBassSound(string fileName, int hMixer) {
this.CurrentSoundDeviceType = ESoundDeviceType.Bass; // 作成後に設定する。(作成に失敗してると例外発出されてここは実行されない)
this.CreateBassSound( fileName, hMixer, BassFlags.Decode );
this.CreateBassSound(fileName, hMixer, BassFlags.Decode);
}
public void CreateASIOSound( string fileName, int hMixer )
{
public void CreateASIOSound(string fileName, int hMixer) {
this.CurrentSoundDeviceType = ESoundDeviceType.ASIO; // 作成後に設定する。(作成に失敗してると例外発出されてここは実行されない)
this.CreateBassSound( fileName, hMixer, BassFlags.Decode );
this.CreateBassSound(fileName, hMixer, BassFlags.Decode);
}
public void CreateWASAPISound( string fileName, int hMixer, ESoundDeviceType deviceType )
{
public void CreateWASAPISound(string fileName, int hMixer, ESoundDeviceType deviceType) {
this.CurrentSoundDeviceType = deviceType; // 作成後に設定する。(作成に失敗してると例外発出されてここは実行されない)
this.CreateBassSound( fileName, hMixer, BassFlags.Decode | BassFlags.Float );
this.CreateBassSound(fileName, hMixer, BassFlags.Decode | BassFlags.Float);
}
#region [ DTXMania用の変換 ]
public void DisposeSound( CSound cs )
{
public void DisposeSound(CSound cs) {
cs.tDispose();
}
public void PlayStart()
{
public void PlayStart() {
tSetPositonToBegin();
if (!b速度上げすぎ問題)
tPlaySound(false);
}
public void PlayStart( bool looped )
{
if ( IsBassSound )
{
if ( looped )
{
Bass.ChannelFlags( this.hBassStream, BassFlags.Loop, BassFlags.Loop );
}
else
{
Bass.ChannelFlags( this.hBassStream, BassFlags.Default, BassFlags.Default );
public void PlayStart(bool looped) {
if (IsBassSound) {
if (looped) {
Bass.ChannelFlags(this.hBassStream, BassFlags.Loop, BassFlags.Loop);
} else {
Bass.ChannelFlags(this.hBassStream, BassFlags.Default, BassFlags.Default);
}
}
tSetPositonToBegin();
tPlaySound( looped );
tPlaySound(looped);
}
public void Stop()
{
public void Stop() {
tStopSound();
tSetPositonToBegin();
}
public void Pause()
{
public void Pause() {
tStopSound(true);
this.PauseCount++;
}
public void Resume( long t ) // ★★★★★★★★★★★★★★★★★★★★★★★★★★★★
public void Resume(long t) // ★★★★★★★★★★★★★★★★★★★★★★★★★★★★
{
Debug.WriteLine( "t再生を再開する(long " + t + ")" );
tSetPositonToBegin( t );
Debug.WriteLine("t再生を再開する(long " + t + ")");
tSetPositonToBegin(t);
tPlaySound();
this.PauseCount--;
}
public bool IsPaused
{
get
{
if ( this.IsBassSound )
{
bool ret = ( !BassMixExtensions.ChannelIsPlaying( this.hBassStream ) ) &
( BassMix.ChannelGetPosition( this.hBassStream ) > 0 );
public bool IsPaused {
get {
if (this.IsBassSound) {
bool ret = (!BassMixExtensions.ChannelIsPlaying(this.hBassStream)) &
(BassMix.ChannelGetPosition(this.hBassStream) > 0);
return ret;
}
else
{
return ( this.PauseCount > 0 );
} else {
return (this.PauseCount > 0);
}
}
}
public bool IsPlaying
{
get
{
public bool IsPlaying {
get {
// 基本的にはBASS_ACTIVE_PLAYINGなら再生中だが、最後まで再生しきったchannelも
// BASS_ACTIVE_PLAYINGのままになっているので、小細工が必要。
bool ret = (BassMixExtensions.ChannelIsPlaying(this.hBassStream));
if (BassMix.ChannelGetPosition(this.hBassStream) >= nBytes)
{
if (BassMix.ChannelGetPosition(this.hBassStream) >= nBytes) {
ret = false;
}
return ret;
@ -426,118 +355,89 @@ namespace FDK
#endregion
public void tDispose()
{
tDispose( false );
public void tDispose() {
tDispose(false);
}
public void tDispose( bool deleteInstance )
{
if ( this.IsBassSound ) // stream数の削減用
public void tDispose(bool deleteInstance) {
if (this.IsBassSound) // stream数の削減用
{
tRemoveSoundFromMixer();
//_cbStreamXA = null;
SoundManager.nStreams--;
}
bool disposeWithManaged = true;
this.Dispose( disposeWithManaged, deleteInstance );
//Debug.WriteLine( "Disposed: " + _bインスタンス削除 + " : " + Path.GetFileName( this.strファイル名 ) );
this.Dispose(disposeWithManaged, deleteInstance);
//Debug.WriteLine( "Disposed: " + _bインスタンス削除 + " : " + Path.GetFileName( this.strファイル名 ) );
}
public void tPlaySound()
{
tPlaySound( false );
public void tPlaySound() {
tPlaySound(false);
}
private void tPlaySound( bool bループする )
private void tPlaySound(bool bループする) {
if (this.IsBassSound) // BASSサウンド時のループ処理は、t再生を開始する()側に実装。ここでは「bループする」は未使用。
{
if ( this.IsBassSound ) // BASSサウンド時のループ処理は、t再生を開始する()側に実装。ここでは「bループする」は未使用。
{
//Debug.WriteLine( "再生中?: " + System.IO.Path.GetFileName(this.strファイル名) + " status=" + BassMix.BASS_Mixer_ChannelIsActive( this.hBassStream ) + " current=" + BassMix.BASS_Mixer_ChannelGetPosition( this.hBassStream ) + " nBytes=" + nBytes );
bool b = BassMixExtensions.ChannelPlay( this.hBassStream );
if ( !b )
{
//Debug.WriteLine( "再生しようとしたが、Mixerに登録されていなかった: " + Path.GetFileName( this.strファイル名 ) + ", stream#=" + this.hBassStream + ", ErrCode=" + Bass.BASS_ErrorGetCode() );
//Debug.WriteLine( "再生中?: " + System.IO.Path.GetFileName(this.strファイル名) + " status=" + BassMix.BASS_Mixer_ChannelIsActive( this.hBassStream ) + " current=" + BassMix.BASS_Mixer_ChannelGetPosition( this.hBassStream ) + " nBytes=" + nBytes );
bool b = BassMixExtensions.ChannelPlay(this.hBassStream);
if (!b) {
//Debug.WriteLine( "再生しようとしたが、Mixerに登録されていなかった: " + Path.GetFileName( this.strファイル名 ) + ", stream#=" + this.hBassStream + ", ErrCode=" + Bass.BASS_ErrorGetCode() );
bool bb = AddBassSoundFromMixer();
if ( !bb )
{
Debug.WriteLine( "Mixerへの登録に失敗: " + Path.GetFileName( this.FileName ) + ", ErrCode=" + Bass.LastError );
}
else
{
//Debug.WriteLine( "Mixerへの登録に成功: " + Path.GetFileName( this.strファイル名 ) + ": " + Bass.BASS_ErrorGetCode() );
if (!bb) {
Debug.WriteLine("Mixerへの登録に失敗: " + Path.GetFileName(this.FileName) + ", ErrCode=" + Bass.LastError);
} else {
//Debug.WriteLine( "Mixerへの登録に成功: " + Path.GetFileName( this.strファイル名 ) + ": " + Bass.BASS_ErrorGetCode() );
}
//this.t再生位置を先頭に戻す();
bool bbb = BassMixExtensions.ChannelPlay( this.hBassStream );
if (!bbb)
{
Debug.WriteLine("更に再生に失敗: " + Path.GetFileName(this.FileName) + ", ErrCode=" + Bass.LastError );
bool bbb = BassMixExtensions.ChannelPlay(this.hBassStream);
if (!bbb) {
Debug.WriteLine("更に再生に失敗: " + Path.GetFileName(this.FileName) + ", ErrCode=" + Bass.LastError);
} else {
// Debug.WriteLine("再生成功(ミキサー追加後) : " + Path.GetFileName(this.strファイル名));
}
else
{
// Debug.WriteLine("再生成功(ミキサー追加後) : " + Path.GetFileName(this.strファイル名));
}
}
else
{
//Debug.WriteLine( "再生成功: " + Path.GetFileName( this.strファイル名 ) + " (" + hBassStream + ")" );
} else {
//Debug.WriteLine( "再生成功: " + Path.GetFileName( this.strファイル名 ) + " (" + hBassStream + ")" );
}
}
}
public void tStopSoundAndRemoveSoundFromMixer()
{
tStopSound( false );
if ( IsBassSound )
{
public void tStopSoundAndRemoveSoundFromMixer() {
tStopSound(false);
if (IsBassSound) {
tRemoveSoundFromMixer();
}
}
public void tStopSound()
{
tStopSound( false );
public void tStopSound() {
tStopSound(false);
}
public void tStopSound( bool pause )
{
if( this.IsBassSound )
{
//Debug.WriteLine( "停止: " + System.IO.Path.GetFileName( this.strファイル名 ) + " status=" + BassMix.BASS_Mixer_ChannelIsActive( this.hBassStream ) + " current=" + BassMix.BASS_Mixer_ChannelGetPosition( this.hBassStream ) + " nBytes=" + nBytes );
BassMixExtensions.ChannelPause( this.hBassStream );
if ( !pause )
{
public void tStopSound(bool pause) {
if (this.IsBassSound) {
//Debug.WriteLine( "停止: " + System.IO.Path.GetFileName( this.strファイル名 ) + " status=" + BassMix.BASS_Mixer_ChannelIsActive( this.hBassStream ) + " current=" + BassMix.BASS_Mixer_ChannelGetPosition( this.hBassStream ) + " nBytes=" + nBytes );
BassMixExtensions.ChannelPause(this.hBassStream);
if (!pause) {
// tBASSサウンドをミキサーから削除する(); // PAUSEと再生停止を区別できるようにすること!!
}
}
this.PauseCount = 0;
}
public void tSetPositonToBegin()
{
if( this.IsBassSound )
{
BassMix.ChannelSetPosition( this.hBassStream, 0 );
public void tSetPositonToBegin() {
if (this.IsBassSound) {
BassMix.ChannelSetPosition(this.hBassStream, 0);
//pos = 0;
}
}
public void tSetPositonToBegin( long positionMs )
{
if( this.IsBassSound )
{
public void tSetPositonToBegin(long positionMs) {
if (this.IsBassSound) {
bool b = true;
try
{
b = BassMix.ChannelSetPosition( this.hBassStream, Bass.ChannelSeconds2Bytes( this.hBassStream, positionMs * this.Frequency * this.PlaySpeed / 1000.0 ), PositionFlags.Bytes );
}
catch( Exception e )
{
Trace.TraceError( e.ToString() );
Trace.TraceInformation( Path.GetFileName( this.FileName ) + ": Seek error: " + e.ToString() + ": " + positionMs + "ms" );
}
finally
{
if ( !b )
{
try {
b = BassMix.ChannelSetPosition(this.hBassStream, Bass.ChannelSeconds2Bytes(this.hBassStream, positionMs * this.Frequency * this.PlaySpeed / 1000.0), PositionFlags.Bytes);
} catch (Exception e) {
Trace.TraceError(e.ToString());
Trace.TraceInformation(Path.GetFileName(this.FileName) + ": Seek error: " + e.ToString() + ": " + positionMs + "ms");
} finally {
if (!b) {
Errors be = Bass.LastError;
Trace.TraceInformation( Path.GetFileName( this.FileName ) + ": Seek error: " + be.ToString() + ": " + positionMs + "MS" );
Trace.TraceInformation(Path.GetFileName(this.FileName) + ": Seek error: " + be.ToString() + ": " + positionMs + "MS");
}
}
//if ( this.n総演奏時間ms > 5000 )
@ -551,31 +451,24 @@ Debug.WriteLine("更に再生に失敗: " + Path.GetFileName(this.FileName) + ",
/// </summary>
/// <param name="positionByte"></param>
/// <param name="positionMs"></param>
public void tGetPlayPositon( out long positionByte, out double positionMs )
{
if ( this.IsBassSound )
{
positionByte = BassMix.ChannelGetPosition( this.hBassStream );
positionMs = Bass.ChannelBytes2Seconds( this.hBassStream, positionByte );
}
else
{
public void tGetPlayPositon(out long positionByte, out double positionMs) {
if (this.IsBassSound) {
positionByte = BassMix.ChannelGetPosition(this.hBassStream);
positionMs = Bass.ChannelBytes2Seconds(this.hBassStream, positionByte);
} else {
positionByte = 0;
positionMs = 0.0;
}
}
public static void tResetAllSound()
{
foreach ( var sound in CSound.SoundInstances )
{
sound.tDispose( false );
public static void tResetAllSound() {
foreach (var sound in CSound.SoundInstances) {
sound.tDispose(false);
}
}
internal static void tReloadSound( ISoundDevice device )
{
if( CSound.SoundInstances.Count == 0 )
internal static void tReloadSound(ISoundDevice device) {
if (CSound.SoundInstances.Count == 0)
return;
@ -587,15 +480,13 @@ Debug.WriteLine("更に再生に失敗: " + Path.GetFileName(this.FileName) + ",
// 配列に基づいて個々のサウンドを作成する。
for( int i = 0; i < sounds.Length; i++ )
{
switch( sounds[ i ].CurrnetCreateType )
{
for (int i = 0; i < sounds.Length; i++) {
switch (sounds[i].CurrnetCreateType) {
#region [ ]
case CreateType.FromFile:
string strファイル名 = sounds[ i ].FileName;
sounds[ i ].Dispose( true, false );
device.tCreateSound( strファイル名, sounds[ i ] );
string strファイル名 = sounds[i].FileName;
sounds[i].Dispose(true, false);
device.tCreateSound(strファイル名, sounds[i]);
break;
#endregion
}
@ -604,24 +495,20 @@ Debug.WriteLine("更に再生に失敗: " + Path.GetFileName(this.FileName) + ",
#region [ Dispose-Finalizeパターン実装 ]
//-----------------
public void Dispose()
{
this.Dispose( true, true );
GC.SuppressFinalize( this );
public void Dispose() {
this.Dispose(true, true);
GC.SuppressFinalize(this);
}
private void Dispose( bool deleteWithManaged, bool deleteInstance )
{
if( this.IsBassSound )
{
private void Dispose(bool deleteWithManaged, bool deleteInstance) {
if (this.IsBassSound) {
#region [ ASIO, WASAPI ]
//-----------------
if ( _hTempoStream != 0 )
{
BassMix.MixerRemoveChannel( this._hTempoStream );
Bass.StreamFree( this._hTempoStream );
if (_hTempoStream != 0) {
BassMix.MixerRemoveChannel(this._hTempoStream);
Bass.StreamFree(this._hTempoStream);
}
BassMix.MixerRemoveChannel( this._hBassStream );
Bass.StreamFree( this._hBassStream );
BassMix.MixerRemoveChannel(this._hBassStream);
Bass.StreamFree(this._hBassStream);
this.hBassStream = -1;
this._hBassStream = -1;
this._hTempoStream = 0;
@ -629,8 +516,7 @@ Debug.WriteLine("更に再生に失敗: " + Path.GetFileName(this.FileName) + ",
#endregion
}
if( deleteWithManaged )
{
if (deleteWithManaged) {
//int freeIndex = -1;
//if ( CSound.listインスタンス != null )
@ -644,8 +530,7 @@ Debug.WriteLine("更に再生に失敗: " + Path.GetFileName(this.FileName) + ",
this.CurrentSoundDeviceType = ESoundDeviceType.Unknown;
if ( deleteInstance )
{
if (deleteInstance) {
//try
//{
// CSound.listインスタンス.RemoveAt( freeIndex );
@ -654,18 +539,16 @@ Debug.WriteLine("更に再生に失敗: " + Path.GetFileName(this.FileName) + ",
//{
// Debug.WriteLine( "FAILED to remove CSound.listインスタンス: Count=" + CSound.listインスタンス.Count + ", filename=" + Path.GetFileName( this.strファイル名 ) );
//}
bool b = CSound.SoundInstances.Remove( this ); // これだと、Clone()したサウンドのremoveに失敗する
if ( !b )
{
Debug.WriteLine( "FAILED to remove CSound.listインスタンス: Count=" + CSound.SoundInstances.Count + ", filename=" + Path.GetFileName( this.FileName ) );
bool b = CSound.SoundInstances.Remove(this); // これだと、Clone()したサウンドのremoveに失敗する
if (!b) {
Debug.WriteLine("FAILED to remove CSound.listインスタンス: Count=" + CSound.SoundInstances.Count + ", filename=" + Path.GetFileName(this.FileName));
}
}
}
}
~CSound()
{
this.Dispose( false, true );
~CSound() {
this.Dispose(false, true);
}
//-----------------
#endregion
@ -706,15 +589,13 @@ Debug.WriteLine("更に再生に失敗: " + Path.GetFileName(this.FileName) + ",
#region [ private ]
//-----------------
private bool IsBassSound
{
get
{
private bool IsBassSound {
get {
return (
this.CurrentSoundDeviceType == ESoundDeviceType.Bass ||
this.CurrentSoundDeviceType == ESoundDeviceType.ASIO ||
this.CurrentSoundDeviceType == ESoundDeviceType.ExclusiveWASAPI ||
this.CurrentSoundDeviceType == ESoundDeviceType.SharedWASAPI );
this.CurrentSoundDeviceType == ESoundDeviceType.SharedWASAPI);
}
}
private int _n位置 = 0;
@ -730,72 +611,64 @@ Debug.WriteLine("更に再生に失敗: " + Path.GetFileName(this.FileName) + ",
private double _PlaySpeed = 1.0;
private bool IsNormalSpeed = true;
public void CreateBassSound( string strファイル名, int hMixer, BassFlags flags )
{
public void CreateBassSound(string strファイル名, int hMixer, BassFlags flags) {
this.CurrnetCreateType = CreateType.FromFile;
this.FileName = strファイル名;
// BASSファイルストリームを作成。
this._hBassStream = Bass.CreateStream( strファイル名, 0, 0, flags );
if( this._hBassStream == 0 )
throw new Exception( string.Format( "サウンドストリームの生成に失敗しました。(BASS_StreamCreateFile)[{0}]", Bass.LastError.ToString() ) );
this._hBassStream = Bass.CreateStream(strファイル名, 0, 0, flags);
if (this._hBassStream == 0)
throw new Exception(string.Format("サウンドストリームの生成に失敗しました。(BASS_StreamCreateFile)[{0}]", Bass.LastError.ToString()));
nBytes = Bass.ChannelGetLength( this._hBassStream );
nBytes = Bass.ChannelGetLength(this._hBassStream);
tBASSサウンドを作成する_ストリーム生成後の共通処理( hMixer );
tBASSサウンドを作成する_ストリーム生成後の共通処理(hMixer);
}
private void tBASSサウンドを作成する_ストリーム生成後の共通処理( int hMixer )
{
private void tBASSサウンドを作成する_ストリーム生成後の共通処理(int hMixer) {
SoundManager.nStreams++;
// 個々のストリームの出力をテンポ変更のストリームに入力する。テンポ変更ストリームの出力を、Mixerに出力する。
// if ( CSound管理.bIsTimeStretch ) // TimeStretchのON/OFFに関わりなく、テンポ変更のストリームを生成する。後からON/OFF切り替え可能とするため。
{
this._hTempoStream = BassFx.TempoCreate( this._hBassStream, BassFlags.Decode | BassFlags.FxFreeSource );
if ( this._hTempoStream == 0 )
// if ( CSound管理.bIsTimeStretch ) // TimeStretchのON/OFFに関わりなく、テンポ変更のストリームを生成する。後からON/OFF切り替え可能とするため。
{
this._hTempoStream = BassFx.TempoCreate(this._hBassStream, BassFlags.Decode | BassFlags.FxFreeSource);
if (this._hTempoStream == 0) {
hGC.Free();
throw new Exception( string.Format( "サウンドストリームの生成に失敗しました。(BASS_FX_TempoCreate)[{0}]", Bass.LastError.ToString() ) );
}
else
{
Bass.ChannelSetAttribute( this._hTempoStream, ChannelAttribute.TempoUseQuickAlgorithm, 1f ); // 高速化(音の品質は少し落ちる)
throw new Exception(string.Format("サウンドストリームの生成に失敗しました。(BASS_FX_TempoCreate)[{0}]", Bass.LastError.ToString()));
} else {
Bass.ChannelSetAttribute(this._hTempoStream, ChannelAttribute.TempoUseQuickAlgorithm, 1f); // 高速化(音の品質は少し落ちる)
}
}
if ( _hTempoStream != 0 && !this.IsNormalSpeed ) // 再生速度がx1.000のときは、TempoStreamを用いないようにして高速化する
if (_hTempoStream != 0 && !this.IsNormalSpeed) // 再生速度がx1.000のときは、TempoStreamを用いないようにして高速化する
{
this.hBassStream = _hTempoStream;
}
else
{
} else {
this.hBassStream = _hBassStream;
}
// #32248 再生終了時に発火するcallbackを登録する (演奏終了後に再生終了するチップを非同期的にミキサーから削除するため。)
_cbEndofStream = new SyncProcedure( CallbackEndofStream );
Bass.ChannelSetSync( hBassStream, SyncFlags.End | SyncFlags.Mixtime, 0, _cbEndofStream, IntPtr.Zero );
_cbEndofStream = new SyncProcedure(CallbackEndofStream);
Bass.ChannelSetSync(hBassStream, SyncFlags.End | SyncFlags.Mixtime, 0, _cbEndofStream, IntPtr.Zero);
// n総演奏時間の取得; DTXMania用に追加。
double seconds = Bass.ChannelBytes2Seconds( this._hBassStream, nBytes );
this.TotalPlayTime = (int) ( seconds * 1000 );
double seconds = Bass.ChannelBytes2Seconds(this._hBassStream, nBytes);
this.TotalPlayTime = (int)(seconds * 1000);
//this.pos = 0;
this.hMixer = hMixer;
float freq = 0.0f;
if ( !Bass.ChannelGetAttribute( this._hBassStream, ChannelAttribute.Frequency, out freq ) )
{
if (!Bass.ChannelGetAttribute(this._hBassStream, ChannelAttribute.Frequency, out freq)) {
hGC.Free();
throw new Exception( string.Format( "サウンドストリームの周波数取得に失敗しました。(BASS_ChannelGetAttribute)[{0}]", Bass.LastError.ToString() ) );
throw new Exception(string.Format("サウンドストリームの周波数取得に失敗しました。(BASS_ChannelGetAttribute)[{0}]", Bass.LastError.ToString()));
}
this.nオリジナルの周波数 = (int) freq;
this.nオリジナルの周波数 = (int)freq;
// インスタンスリストに登録。
CSound.SoundInstances.Add( this );
CSound.SoundInstances.Add(this);
}
//-----------------
@ -820,50 +693,45 @@ Debug.WriteLine("更に再生に失敗: " + Path.GetFileName(this.FileName) + ",
/// <param name="channel"></param>
/// <param name="data"></param>
/// <param name="user"></param>
private void CallbackEndofStream( int handle, int channel, int data, IntPtr user ) // #32248 2013.10.14 yyagi
private void CallbackEndofStream(int handle, int channel, int data, IntPtr user) // #32248 2013.10.14 yyagi
{
// Trace.TraceInformation( "Callback!(remove): " + Path.GetFileName( this.strファイル名 ) );
if ( b演奏終了後も再生が続くチップである ) // 演奏終了後に再生終了するチップ音のミキサー削除は、再生終了のコールバックに引っ掛けて、自前で行う。
// Trace.TraceInformation( "Callback!(remove): " + Path.GetFileName( this.strファイル名 ) );
if (b演奏終了後も再生が続くチップである) // 演奏終了後に再生終了するチップ音のミキサー削除は、再生終了のコールバックに引っ掛けて、自前で行う。
{ // そうでないものは、ミキサー削除予定時刻に削除する。
RemoveBassSoundFromMixer( channel );
RemoveBassSoundFromMixer(channel);
}
}
// mixerからの削除
// mixerからの削除
public bool tRemoveSoundFromMixer()
{
return RemoveBassSoundFromMixer( this.hBassStream );
public bool tRemoveSoundFromMixer() {
return RemoveBassSoundFromMixer(this.hBassStream);
}
public bool RemoveBassSoundFromMixer( int channel )
{
bool b = BassMix.MixerRemoveChannel( channel );
if ( b )
{
Interlocked.Decrement( ref SoundManager.nMixing );
// Debug.WriteLine( "Removed: " + Path.GetFileName( this.strファイル名 ) + " (" + channel + ")" + " MixedStreams=" + CSound管理.nMixing );
public bool RemoveBassSoundFromMixer(int channel) {
bool b = BassMix.MixerRemoveChannel(channel);
if (b) {
Interlocked.Decrement(ref SoundManager.nMixing);
// Debug.WriteLine( "Removed: " + Path.GetFileName( this.strファイル名 ) + " (" + channel + ")" + " MixedStreams=" + CSound管理.nMixing );
}
return b;
}
// mixer への追加
// mixer への追加
public bool AddBassSoundFromMixer()
{
if ( BassMix.ChannelGetMixer( hBassStream ) == 0 )
{
public bool AddBassSoundFromMixer() {
if (BassMix.ChannelGetMixer(hBassStream) == 0) {
BassFlags bf = BassFlags.SpeakerFront | BassFlags.MixerChanNoRampin | BassFlags.MixerChanPause;
Interlocked.Increment( ref SoundManager.nMixing );
Interlocked.Increment(ref SoundManager.nMixing);
// preloadされることを期待して、敢えてflagからはBASS_MIXER_PAUSEを外してAddChannelした上で、すぐにPAUSEする
// -> ChannelUpdateでprebufferできることが分かったため、BASS_MIXER_PAUSEを使用することにした
bool b1 = BassMix.MixerAddChannel( this.hMixer, this.hBassStream, bf );
bool b1 = BassMix.MixerAddChannel(this.hMixer, this.hBassStream, bf);
//bool b2 = BassMix.BASS_Mixer_ChannelPause( this.hBassStream );
tSetPositonToBegin(); // StreamAddChannelの後で再生位置を戻さないとダメ。逆だと再生位置が変わらない。
//Trace.TraceInformation( "Add Mixer: " + Path.GetFileName( this.strファイル名 ) + " (" + hBassStream + ")" + " MixedStreams=" + CSound管理.nMixing );
Bass.ChannelUpdate( this.hBassStream, 0 ); // pre-buffer
//Trace.TraceInformation( "Add Mixer: " + Path.GetFileName( this.strファイル名 ) + " (" + hBassStream + ")" + " MixedStreams=" + CSound管理.nMixing );
Bass.ChannelUpdate(this.hBassStream, 0); // pre-buffer
return b1; // &b2;
}
return true;

View File

@ -1,33 +1,23 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using FDK.ExtensionMethods;
using System.Diagnostics;
using ManagedBass;
using ManagedBass.Asio;
using ManagedBass.Mix;
namespace FDK
{
namespace FDK {
/// <summary>
/// 全ASIOデバイスを列挙する静的クラス。
/// BASS_Init()やBASS_ASIO_Init()の状態とは無関係に使用可能。
/// </summary>
public static class CEnumerateAllAsioDevices
{
public static string[] GetAllASIODevices()
{
try
{
public static class CEnumerateAllAsioDevices {
public static string[] GetAllASIODevices() {
try {
string[] bassAsioDevName = new string[BassAsio.DeviceCount];
for(int i = 0; i < bassAsioDevName.Length; i++)
for (int i = 0; i < bassAsioDevName.Length; i++)
bassAsioDevName[i] = BassAsio.GetDeviceInfo(i).Name;
if(bassAsioDevName.Length != 0)
if (bassAsioDevName.Length != 0)
return bassAsioDevName;
}
catch(Exception e)
{
} catch (Exception e) {
Trace.TraceWarning($"Exception occured in GetAllASIODevices ({e})");
}
@ -35,79 +25,62 @@ namespace FDK
}
}
internal class CSoundDeviceASIO : ISoundDevice
{
internal class CSoundDeviceASIO : ISoundDevice {
// プロパティ
public ESoundDeviceType SoundDeviceType
{
public ESoundDeviceType SoundDeviceType {
get;
protected set;
}
public long OutputDelay
{
public long OutputDelay {
get;
protected set;
}
public long BufferSize
{
public long BufferSize {
get;
protected set;
}
public int ASIODevice
{
public int ASIODevice {
get;
set;
}
// CSoundTimer 用に公開しているプロパティ
public long ElapsedTimeMs
{
public long ElapsedTimeMs {
get;
protected set;
}
public long UpdateSystemTimeMs
{
public long UpdateSystemTimeMs {
get;
protected set;
}
public CTimer SystemTimer
{
public CTimer SystemTimer {
get;
protected set;
}
// マスターボリュームの制御コードは、WASAPI/ASIOで全く同じ。
public int nMasterVolume
{
get
{
public int nMasterVolume {
get {
float f音量 = 0.0f;
bool b = Bass.ChannelGetAttribute( this.hMixer, ChannelAttribute.Volume, out f音量 );
if ( !b )
{
bool b = Bass.ChannelGetAttribute(this.hMixer, ChannelAttribute.Volume, out f音量);
if (!b) {
Errors be = Bass.LastError;
Trace.TraceInformation( "ASIO Master Volume Get Error: " + be.ToString() );
}
else
{
Trace.TraceInformation("ASIO Master Volume Get Error: " + be.ToString());
} else {
//Trace.TraceInformation( "ASIO Master Volume Get Success: " + (f音量 * 100) );
}
return (int) ( f音量 * 100 );
return (int)(f音量 * 100);
}
set
{
bool b = Bass.ChannelSetAttribute( this.hMixer, ChannelAttribute.Volume, (float) ( value / 100.0 ) );
if ( !b )
{
set {
bool b = Bass.ChannelSetAttribute(this.hMixer, ChannelAttribute.Volume, (float)(value / 100.0));
if (!b) {
Errors be = Bass.LastError;
Trace.TraceInformation( "ASIO Master Volume Set Error: " + be.ToString() );
}
else
{
Trace.TraceInformation("ASIO Master Volume Set Error: " + be.ToString());
} else {
// int n = this.nMasterVolume;
// Trace.TraceInformation( "ASIO Master Volume Set Success: " + value );
}
@ -116,27 +89,26 @@ namespace FDK
// メソッド
public CSoundDeviceASIO( long bufferSize, int deviceIndex )
{
public CSoundDeviceASIO(long bufferSize, int deviceIndex) {
// 初期化。
Trace.TraceInformation( "BASS (ASIO) の初期化を開始します。" );
Trace.TraceInformation("BASS (ASIO) の初期化を開始します。");
this.SoundDeviceType = ESoundDeviceType.Unknown;
this.OutputDelay = 0;
this.ElapsedTimeMs = 0;
this.UpdateSystemTimeMs = CTimer.UnusedNum;
this.SystemTimer = new CTimer( CTimer.TimerType.MultiMedia );
this.SystemTimer = new CTimer(CTimer.TimerType.MultiMedia);
this.ASIODevice = deviceIndex;
// BASS の設定。
this.bIsBASSFree = true;
if (!Bass.Configure( Configuration.UpdatePeriod, 0 )) // 0:BASSストリームの自動更新を行わない。
if (!Bass.Configure(Configuration.UpdatePeriod, 0)) // 0:BASSストリームの自動更新を行わない。
{
Trace.TraceWarning($"BASS_SetConfig({nameof(Configuration.UpdatePeriod)}) に失敗しました。[{Bass.LastError.ToString()}]");
}
if (!Bass.Configure( Configuration.UpdateThreads, 0 )) // 0:BASSストリームの自動更新を行わない。
if (!Bass.Configure(Configuration.UpdateThreads, 0)) // 0:BASSストリームの自動更新を行わない。
{
Trace.TraceWarning($"BASS_SetConfig({nameof(Configuration.UpdateThreads)}) に失敗しました。[{Bass.LastError.ToString()}]");
}
@ -145,27 +117,27 @@ namespace FDK
int nデバイス = 0; // 0:"no device" … BASS からはデバイスへアクセスさせない。アクセスは BASSASIO アドオンから行う。
int n周波数 = 44100; // 仮決め。最終的な周波数はデバイス(≠ドライバ)が決める。
if( !Bass.Init( nデバイス, n周波数, DeviceInitFlags.Default, IntPtr.Zero ) )
throw new Exception( string.Format( "BASS の初期化に失敗しました。(BASS_Init)[{0}]", Bass.LastError.ToString() ) );
if (!Bass.Init(nデバイス, n周波数, DeviceInitFlags.Default, IntPtr.Zero))
throw new Exception(string.Format("BASS の初期化に失敗しました。(BASS_Init)[{0}]", Bass.LastError.ToString()));
Bass.Configure(Configuration.LogarithmicVolumeCurve, true);
//Debug.WriteLine( "BASS_Init()完了。" );
//Debug.WriteLine( "BASS_Init()完了。" );
#region [ : ASIOデバイスのenumerateと ]
// CEnumerateAllAsioDevices.GetAllASIODevices();
//Debug.WriteLine( "BassAsio.BASS_ASIO_GetDeviceInfo():" );
// int a, count = 0;
// BASS_ASIO_DEVICEINFO asioDevInfo;
// for ( a = 0; ( asioDevInfo = BassAsio.BASS_ASIO_GetDeviceInfo( a ) ) != null; a++ )
// {
// Trace.TraceInformation( "ASIO Device {0}: {1}, driver={2}", a, asioDevInfo.name, asioDevInfo.driver );
// count++; // count it
// }
// CEnumerateAllAsioDevices.GetAllASIODevices();
//Debug.WriteLine( "BassAsio.BASS_ASIO_GetDeviceInfo():" );
// int a, count = 0;
// BASS_ASIO_DEVICEINFO asioDevInfo;
// for ( a = 0; ( asioDevInfo = BassAsio.BASS_ASIO_GetDeviceInfo( a ) ) != null; a++ )
// {
// Trace.TraceInformation( "ASIO Device {0}: {1}, driver={2}", a, asioDevInfo.name, asioDevInfo.driver );
// count++; // count it
// }
#endregion
// BASS ASIO の初期化。
AsioInfo asioInfo;
if ( BassAsio.Init( ASIODevice, AsioInitFlags.Thread ) ) // 専用スレッドにて起動
if (BassAsio.Init(ASIODevice, AsioInitFlags.Thread)) // 専用スレッドにて起動
{
#region [ ASIO ]
//-----------------
@ -173,13 +145,13 @@ namespace FDK
BassAsio.GetInfo(out asioInfo);
this.n出力チャンネル数 = asioInfo.Outputs;
this.db周波数 = BassAsio.Rate;
this.fmtASIOデバイスフォーマット = BassAsio.ChannelGetFormat( false, 0 );
this.fmtASIOデバイスフォーマット = BassAsio.ChannelGetFormat(false, 0);
Trace.TraceInformation( "BASS を初期化しました。(ASIO, デバイス:\"{0}\", 入力{1}, 出力{2}, {3}Hz, バッファ{4}{6}sample ({5:0.###}{7:0.###}ms), デバイスフォーマット:{8})",
Trace.TraceInformation("BASS を初期化しました。(ASIO, デバイス:\"{0}\", 入力{1}, 出力{2}, {3}Hz, バッファ{4}{6}sample ({5:0.###}{7:0.###}ms), デバイスフォーマット:{8})",
asioInfo.Name,
asioInfo.Inputs,
asioInfo.Outputs,
this.db周波数.ToString( "0.###" ),
this.db周波数.ToString("0.###"),
asioInfo.MinBufferLength, asioInfo.MinBufferLength * 1000 / this.db周波数,
asioInfo.MaxBufferLength, asioInfo.MaxBufferLength * 1000 / this.db周波数,
this.fmtASIOデバイスフォーマット.ToString()
@ -198,20 +170,17 @@ namespace FDK
#endregion
//-----------------
#endregion
}
else
{
} else {
#region [ ASIO ]
//-----------------
Errors errcode = Bass.LastError;
string errmes = errcode.ToString();
if ( errcode == Errors.OK )
{
if (errcode == Errors.OK) {
errmes = "BASS_OK; The device may be dissconnected";
}
Bass.Free();
this.bIsBASSFree = true;
throw new Exception( string.Format( "BASS (ASIO) の初期化に失敗しました。(BASS_ASIO_Init)[{0}]", errmes ) );
throw new Exception(string.Format("BASS (ASIO) の初期化に失敗しました。(BASS_ASIO_Init)[{0}]", errmes));
//-----------------
#endregion
}
@ -219,40 +188,39 @@ namespace FDK
// ASIO 出力チャンネルの初期化。
this.tAsioProc = new AsioProcedure( this.tAsio処理 ); // アンマネージに渡す delegate は、フィールドとして保持しておかないとGCでアドレスが変わってしまう。
if ( !BassAsio.ChannelEnable( false, 0, this.tAsioProc, IntPtr.Zero ) ) // 出力チャンネル0 の有効化。
this.tAsioProc = new AsioProcedure(this.tAsio処理); // アンマネージに渡す delegate は、フィールドとして保持しておかないとGCでアドレスが変わってしまう。
if (!BassAsio.ChannelEnable(false, 0, this.tAsioProc, IntPtr.Zero)) // 出力チャンネル0 の有効化。
{
#region [ ASIO ]
//-----------------
BassAsio.Free();
Bass.Free();
this.bIsBASSFree = true;
throw new Exception( string.Format( "Failed BASS_ASIO_ChannelEnable() [{0}]", BassAsio.LastError.ToString() ) );
throw new Exception(string.Format("Failed BASS_ASIO_ChannelEnable() [{0}]", BassAsio.LastError.ToString()));
//-----------------
#endregion
}
for ( int i = 1; i < this.n出力チャンネル数; i++ ) // 出力チャネルを全てチャネル0とグループ化する。
for (int i = 1; i < this.n出力チャンネル数; i++) // 出力チャネルを全てチャネル0とグループ化する。
{ // チャネル1だけを0とグループ化すると、3ch以上の出力をサポートしたカードでの動作がおかしくなる
if ( !BassAsio.ChannelJoin( false, i, 0 ) )
{
if (!BassAsio.ChannelJoin(false, i, 0)) {
#region [ ]
//-----------------
BassAsio.Free();
Bass.Free();
this.bIsBASSFree = true;
throw new Exception( string.Format( "Failed BASS_ASIO_ChannelJoin({1}) [{0}]", BassAsio.LastError, i ) );
throw new Exception(string.Format("Failed BASS_ASIO_ChannelJoin({1}) [{0}]", BassAsio.LastError, i));
//-----------------
#endregion
}
}
if ( !BassAsio.ChannelSetFormat( false, 0, this.fmtASIOチャンネルフォーマット ) ) // 出力チャンネル0のフォーマット
if (!BassAsio.ChannelSetFormat(false, 0, this.fmtASIOチャンネルフォーマット)) // 出力チャンネル0のフォーマット
{
#region [ ASIO ]
//-----------------
BassAsio.Free();
Bass.Free();
this.bIsBASSFree = true;
throw new Exception( string.Format( "Failed BASS_ASIO_ChannelSetFormat() [{0}]", BassAsio.LastError.ToString() ) );
throw new Exception(string.Format("Failed BASS_ASIO_ChannelSetFormat() [{0}]", BassAsio.LastError.ToString()));
//-----------------
#endregion
}
@ -260,25 +228,23 @@ namespace FDK
// ASIO 出力と同じフォーマットを持つ BASS ミキサーを作成。
var flag = BassFlags.MixerNonStop | BassFlags.Decode; // デコードのみ発声しない。ASIO に出力されるだけ。
if( this.fmtASIOデバイスフォーマット == AsioSampleFormat.Float )
if (this.fmtASIOデバイスフォーマット == AsioSampleFormat.Float)
flag |= BassFlags.Float;
this.hMixer = BassMix.CreateMixerStream( (int) this.db周波数, this.n出力チャンネル数, flag );
this.hMixer = BassMix.CreateMixerStream((int)this.db周波数, this.n出力チャンネル数, flag);
if ( this.hMixer == 0 )
{
if (this.hMixer == 0) {
Errors err = Bass.LastError;
BassAsio.Free();
Bass.Free();
this.bIsBASSFree = true;
throw new Exception( string.Format( "BASSミキサ(mixing)の作成に失敗しました。[{0}]", err ) );
throw new Exception(string.Format("BASSミキサ(mixing)の作成に失敗しました。[{0}]", err));
}
// BASS ミキサーの1秒あたりのバイト数を算出。
var mixerInfo = Bass.ChannelGetInfo( this.hMixer );
var mixerInfo = Bass.ChannelGetInfo(this.hMixer);
int nサンプルサイズbyte = 0;
switch( this.fmtASIOチャンネルフォーマット )
{
switch (this.fmtASIOチャンネルフォーマット) {
case AsioSampleFormat.Bit16: nサンプルサイズbyte = 2; break;
case AsioSampleFormat.Bit24: nサンプルサイズbyte = 3; break;
case AsioSampleFormat.Bit32: nサンプルサイズbyte = 4; break;
@ -294,93 +260,81 @@ namespace FDK
// そのため、もう一段mixerを噛ませて、一段先のmixerからChannelGetData()することで、
// hMixerの音量制御を反映させる。
this.hMixer_DeviceOut = BassMix.CreateMixerStream(
(int) this.db周波数, this.n出力チャンネル数, flag );
if ( this.hMixer_DeviceOut == 0 )
{
(int)this.db周波数, this.n出力チャンネル数, flag);
if (this.hMixer_DeviceOut == 0) {
Errors errcode = Bass.LastError;
BassAsio.Free();
Bass.Free();
this.bIsBASSFree = true;
throw new Exception( string.Format( "BASSミキサ(最終段)の作成に失敗しました。[{0}]", errcode ) );
throw new Exception(string.Format("BASSミキサ(最終段)の作成に失敗しました。[{0}]", errcode));
}
{
bool b1 = BassMix.MixerAddChannel( this.hMixer_DeviceOut, this.hMixer, BassFlags.Default );
if ( !b1 )
{
bool b1 = BassMix.MixerAddChannel(this.hMixer_DeviceOut, this.hMixer, BassFlags.Default);
if (!b1) {
Errors errcode = Bass.LastError;
BassAsio.Free();
Bass.Free();
this.bIsBASSFree = true;
throw new Exception( string.Format( "BASSミキサ(最終段とmixing)の接続に失敗しました。[{0}]", errcode ) );
throw new Exception(string.Format("BASSミキサ(最終段とmixing)の接続に失敗しました。[{0}]", errcode));
};
}
// 出力を開始。
this.nバッファサイズsample = (int) ( bufferSize * this.db周波数 / 1000.0 );
this.nバッファサイズsample = (int)(bufferSize * this.db周波数 / 1000.0);
//this.nバッファサイズsample = (int) nバッファサイズbyte;
if ( !BassAsio.Start( this.nバッファサイズsample ) ) // 範囲外の値を指定した場合は自動的にデフォルト値に設定される。
if (!BassAsio.Start(this.nバッファサイズsample)) // 範囲外の値を指定した場合は自動的にデフォルト値に設定される。
{
Errors err = BassAsio.LastError;
BassAsio.Free();
Bass.Free();
this.bIsBASSFree = true;
throw new Exception( "ASIO デバイス出力開始に失敗しました。" + err.ToString() );
}
else
{
int n遅延sample = BassAsio.GetLatency( false ); // この関数は BASS_ASIO_Start() 後にしか呼び出せない。
int n希望遅延sample = (int) ( bufferSize * this.db周波数 / 1000.0 );
this.BufferSize = this.OutputDelay = (long) ( n遅延sample * 1000.0f / this.db周波数 );
Trace.TraceInformation( "ASIO デバイス出力開始:バッファ{0}sample(希望{1}) [{2}ms(希望{3}ms)]", n遅延sample, n希望遅延sample, this.OutputDelay, bufferSize );
throw new Exception("ASIO デバイス出力開始に失敗しました。" + err.ToString());
} else {
int n遅延sample = BassAsio.GetLatency(false); // この関数は BASS_ASIO_Start() 後にしか呼び出せない。
int n希望遅延sample = (int)(bufferSize * this.db周波数 / 1000.0);
this.BufferSize = this.OutputDelay = (long)(n遅延sample * 1000.0f / this.db周波数);
Trace.TraceInformation("ASIO デバイス出力開始:バッファ{0}sample(希望{1}) [{2}ms(希望{3}ms)]", n遅延sample, n希望遅延sample, this.OutputDelay, bufferSize);
}
}
#region [ tサウンドを作成する() ]
public CSound tCreateSound( string strファイル名, ESoundGroup soundGroup )
{
public CSound tCreateSound(string strファイル名, ESoundGroup soundGroup) {
var sound = new CSound(soundGroup);
sound.CreateASIOSound( strファイル名, this.hMixer );
sound.CreateASIOSound(strファイル名, this.hMixer);
return sound;
}
public void tCreateSound( string strファイル名, CSound sound )
{
sound.CreateASIOSound( strファイル名, this.hMixer );
public void tCreateSound(string strファイル名, CSound sound) {
sound.CreateASIOSound(strファイル名, this.hMixer);
}
#endregion
#region [ Dispose-Finallizeパターン実装 ]
//-----------------
public void Dispose()
{
this.Dispose( true );
GC.SuppressFinalize( this );
public void Dispose() {
this.Dispose(true);
GC.SuppressFinalize(this);
}
protected void Dispose( bool bManagedDispose )
{
protected void Dispose(bool bManagedDispose) {
SoundDeviceType = ESoundDeviceType.Unknown; // まず出力停止する(Dispose中にクラス内にアクセスされることを防ぐ)
if ( hMixer != -1 )
{
Bass.StreamFree( hMixer );
if (hMixer != -1) {
Bass.StreamFree(hMixer);
}
if ( !bIsBASSFree )
{
if (!bIsBASSFree) {
BassAsio.Free(); // システムタイマより先に呼び出すこと。tAsio処理() の中でシステムタイマを参照してるため)
Bass.Free();
}
if( bManagedDispose )
{
if (bManagedDispose) {
SystemTimer.Dispose();
SystemTimer = null;
}
}
~CSoundDeviceASIO()
{
this.Dispose( false );
~CSoundDeviceASIO() {
this.Dispose(false);
}
//-----------------
#endregion
@ -396,22 +350,21 @@ namespace FDK
//protected BASSASIOFormat fmtASIOチャンネルフォーマット = BASSASIOFormat.BASS_ASIO_FORMAT_32BIT;// 16bit 固定
protected AsioProcedure tAsioProc = null;
protected int tAsio処理( bool input, int channel, IntPtr buffer, int length, IntPtr user )
{
if( input ) return 0;
protected int tAsio処理(bool input, int channel, IntPtr buffer, int length, IntPtr user) {
if (input) return 0;
// BASSミキサからの出力データをそのまま ASIO buffer へ丸投げ。
int num = Bass.ChannelGetData( this.hMixer_DeviceOut, buffer, length ); // num = 実際に転送した長さ
int num = Bass.ChannelGetData(this.hMixer_DeviceOut, buffer, length); // num = 実際に転送した長さ
if ( num == -1 ) num = 0;
if (num == -1) num = 0;
// 経過時間を更新。
// データの転送差分ではなく累積転送バイト数から算出する。
this.ElapsedTimeMs = ( this.n累積転送バイト数 * 1000 / this.nミキサーの1秒あたりのバイト数 ) - this.OutputDelay;
this.ElapsedTimeMs = (this.n累積転送バイト数 * 1000 / this.nミキサーの1秒あたりのバイト数) - this.OutputDelay;
this.UpdateSystemTimeMs = this.SystemTimer.SystemTimeMs;

View File

@ -1,48 +1,35 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Reflection;
using System.IO;
using System.Diagnostics;
using ManagedBass;
using ManagedBass.Mix;
namespace FDK
{
public class CSoundDeviceBASS : ISoundDevice
{
namespace FDK {
public class CSoundDeviceBASS : ISoundDevice {
// プロパティ
public ESoundDeviceType SoundDeviceType
{
public ESoundDeviceType SoundDeviceType {
get;
protected set;
}
public long OutputDelay
{
public long OutputDelay {
get;
protected set;
}
public long BufferSize
{
public long BufferSize {
get;
protected set;
}
// CSoundTimer 用に公開しているプロパティ
public long ElapsedTimeMs
{
public long ElapsedTimeMs {
get;
protected set;
}
public long UpdateSystemTimeMs
{
public long UpdateSystemTimeMs {
get;
protected set;
}
public CTimer SystemTimer
{
public CTimer SystemTimer {
get;
protected set;
}
@ -50,32 +37,26 @@ namespace FDK
public float CPUUsage => (float)Bass.CPUUsage;
// マスターボリュームの制御コードは、WASAPI/ASIOで全く同じ。
public int nMasterVolume
{
get
{
public int nMasterVolume {
get {
float fVolume = 0.0f;
bool b = Bass.ChannelGetAttribute(this.MixerHandle, ChannelAttribute.Volume, out fVolume);
if (!b)
{
if (!b) {
Errors be = Bass.LastError;
Trace.TraceInformation("BASS Master Volume Get Error: " + be.ToString());
}
return (int)(fVolume * 100);
}
set
{
set {
bool b = Bass.ChannelSetAttribute(this.MixerHandle, ChannelAttribute.Volume, (float)(value / 100.0));
if (!b)
{
if (!b) {
Errors be = Bass.LastError;
Trace.TraceInformation("BASS Master Volume Set Error: " + be.ToString());
}
}
}
public CSoundDeviceBASS(int updatePeriod, int bufferSize)
{
public CSoundDeviceBASS(int updatePeriod, int bufferSize) {
Trace.TraceInformation("Start initialization of BASS");
this.SoundDeviceType = ESoundDeviceType.Unknown;
this.OutputDelay = 0;
@ -92,12 +73,10 @@ namespace FDK
if (!Bass.Init(-1, freq, DeviceInitFlags.Default))
throw new Exception(string.Format("BASS の初期化に失敗しました。(BASS_Init)[{0}]", Bass.LastError.ToString()));
if (!Bass.Configure(Configuration.UpdatePeriod, updatePeriod))
{
if (!Bass.Configure(Configuration.UpdatePeriod, updatePeriod)) {
Trace.TraceWarning($"BASS_SetConfig({nameof(Configuration.UpdatePeriod)}) に失敗しました。[{Bass.LastError}]");
}
if (!Bass.Configure(Configuration.UpdateThreads, 1))
{
if (!Bass.Configure(Configuration.UpdateThreads, 1)) {
Trace.TraceWarning($"BASS_SetConfig({nameof(Configuration.UpdateThreads)}) に失敗しました。[{Bass.LastError}]");
}
@ -107,11 +86,10 @@ namespace FDK
this.STREAMPROC = new StreamProcedure(StreamProc);
this.MainStreamHandle = Bass.CreateStream(freq, 2, BassFlags.Default, this.STREAMPROC, IntPtr.Zero);
var flag = BassFlags.MixerNonStop| BassFlags.Decode; // デコードのみ=発声しない。
var flag = BassFlags.MixerNonStop | BassFlags.Decode; // デコードのみ=発声しない。
this.MixerHandle = BassMix.CreateMixerStream(freq, 2, flag);
if (this.MixerHandle == 0)
{
if (this.MixerHandle == 0) {
Errors err = Bass.LastError;
Bass.Free();
this.IsBASSSoundFree = true;
@ -133,8 +111,7 @@ namespace FDK
// hMixerの音量制御を反映させる。
Mixer_DeviceOut = BassMix.CreateMixerStream(
freq, 2, flag);
if (this.Mixer_DeviceOut == 0)
{
if (this.Mixer_DeviceOut == 0) {
Errors errcode = Bass.LastError;
Bass.Free();
this.IsBASSSoundFree = true;
@ -142,8 +119,7 @@ namespace FDK
}
{
bool b1 = BassMix.MixerAddChannel(this.Mixer_DeviceOut, this.MixerHandle, BassFlags.Default);
if (!b1)
{
if (!b1) {
Errors errcode = Bass.LastError;
Bass.Free();
this.IsBASSSoundFree = true;
@ -161,9 +137,7 @@ namespace FDK
Bass.Free();
this.IsBASSSoundFree = true;
throw new Exception("BASS デバイス出力開始に失敗しました。" + err.ToString());
}
else
{
} else {
Bass.GetInfo(out var info);
this.BufferSize = this.OutputDelay = info.Latency + bufferSize;//求め方があっているのだろうか…
@ -176,15 +150,13 @@ namespace FDK
}
#region [ tCreateSound() ]
public CSound tCreateSound(string strFilename, ESoundGroup soundGroup)
{
public CSound tCreateSound(string strFilename, ESoundGroup soundGroup) {
var sound = new CSound(soundGroup);
sound.CreateBassSound(strFilename, this.MixerHandle);
return sound;
}
public void tCreateSound(string strFilename, CSound sound)
{
public void tCreateSound(string strFilename, CSound sound) {
sound.CreateBassSound(strFilename, this.MixerHandle);
}
#endregion
@ -192,43 +164,35 @@ namespace FDK
#region [ Dispose-Finallizeパターン実装 ]
//-----------------
public void Dispose()
{
public void Dispose() {
this.Dispose(true);
GC.SuppressFinalize(this);
}
protected void Dispose(bool bManagedDispose)
{
protected void Dispose(bool bManagedDispose) {
this.SoundDeviceType = ESoundDeviceType.Unknown; // まず出力停止する(Dispose中にクラス内にアクセスされることを防ぐ)
if (MainStreamHandle != -1)
{
if (MainStreamHandle != -1) {
Bass.StreamFree(this.MainStreamHandle);
}
if (MixerHandle != -1)
{
if (MixerHandle != -1) {
Bass.StreamFree(this.MixerHandle);
}
if (!this.IsBASSSoundFree)
{
if (!this.IsBASSSoundFree) {
Bass.Stop();
Bass.Free();// システムタイマより先に呼び出すこと。Stream処理() の中でシステムタイマを参照してるため)
}
if (bManagedDispose)
{
if (bManagedDispose) {
SystemTimer.Dispose();
this.SystemTimer = null;
}
}
~CSoundDeviceBASS()
{
~CSoundDeviceBASS() {
this.Dispose(false);
}
//-----------------
#endregion
public int StreamProc(int handle, IntPtr buffer, int length, IntPtr user)
{
public int StreamProc(int handle, IntPtr buffer, int length, IntPtr user) {
// BASSミキサからの出力データをそのまま ASIO buffer へ丸投げ。
int num = Bass.ChannelGetData(this.Mixer_DeviceOut, buffer, length); // num = 実際に転送した長さ

View File

@ -1,82 +1,65 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Diagnostics;
using ManagedBass;
using ManagedBass.Wasapi;
using ManagedBass.Mix;
using ManagedBass.Wasapi;
namespace FDK
{
internal class CSoundDeviceWASAPI : ISoundDevice
{
namespace FDK {
internal class CSoundDeviceWASAPI : ISoundDevice {
// プロパティ
public ESoundDeviceType SoundDeviceType
{
public ESoundDeviceType SoundDeviceType {
get;
protected set;
}
public long OutputDelay
{
public long OutputDelay {
get;
protected set;
}
public long BufferSize
{
public long BufferSize {
get;
protected set;
}
// CSoundTimer 用に公開しているプロパティ
public long ElapsedTimeMs
{
public long ElapsedTimeMs {
get;
protected set;
}
public long UpdateSystemTimeMs
{
public long UpdateSystemTimeMs {
get;
protected set;
}
public CTimer SystemTimer
{
public CTimer SystemTimer {
get;
protected set;
}
public enum EWASAPIMode { Exclusion, Share }
public int nMasterVolume
{
get
{
public int nMasterVolume {
get {
float volume = 0.0f;
//if ( BassMix.BASS_Mixer_ChannelGetEnvelopePos( this.hMixer, BASSMIXEnvelope.BASS_MIXER_ENV_VOL, ref f音量 ) == -1 )
// return 100;
//bool b = Bass.BASS_ChannelGetAttribute( this.hMixer, BASSAttribute.BASS_ATTRIB_VOL, ref f音量 );
bool b = Bass.ChannelGetAttribute( this.hMixer, ChannelAttribute.Volume, out volume );
if ( !b )
{
bool b = Bass.ChannelGetAttribute(this.hMixer, ChannelAttribute.Volume, out volume);
if (!b) {
Errors be = Bass.LastError;
Trace.TraceInformation( "WASAPI Master Volume Get Error: " + be.ToString() );
}
else
{
Trace.TraceInformation( "WASAPI Master Volume Get Success: " + (volume * 100) );
Trace.TraceInformation("WASAPI Master Volume Get Error: " + be.ToString());
} else {
Trace.TraceInformation("WASAPI Master Volume Get Success: " + (volume * 100));
}
return (int) ( volume * 100 );
return (int)(volume * 100);
}
set
{
set {
// bool b = Bass.BASS_SetVolume( value / 100.0f );
// →Exclusiveモード時は無効
// bool b = BassWasapi.BASS_WASAPI_SetVolume( BASSWASAPIVolume.BASS_WASAPI_VOL_SESSION, (float) ( value / 100 ) );
// bool b = BassWasapi.BASS_WASAPI_SetVolume( BASSWASAPIVolume.BASS_WASAPI_CURVE_WINDOWS, (float) ( value / 100 ) );
bool b = Bass.ChannelSetAttribute( this.hMixer, ChannelAttribute.Volume, (float) ( value / 100.0 ) );
// bool b = BassWasapi.BASS_WASAPI_SetVolume( BASSWASAPIVolume.BASS_WASAPI_VOL_SESSION, (float) ( value / 100 ) );
// bool b = BassWasapi.BASS_WASAPI_SetVolume( BASSWASAPIVolume.BASS_WASAPI_CURVE_WINDOWS, (float) ( value / 100 ) );
bool b = Bass.ChannelSetAttribute(this.hMixer, ChannelAttribute.Volume, (float)(value / 100.0));
// If you would like to have a volume control in exclusive mode too, and you're using the BASSmix add-on,
// you can adjust the source's BASS_ATTRIB_VOL setting via BASS_ChannelSetAttribute.
// しかし、hMixerに対するBASS_ChannelSetAttribute()でBASS_ATTRIB_VOLを変更: なぜか出力音量に反映されず
@ -88,13 +71,10 @@ namespace FDK
//var nodes = new BASS_MIXER_NODE[ 1 ] { new BASS_MIXER_NODE( 0, (float) value ) };
//bool b = BassMix.BASS_Mixer_ChannelSetEnvelope( this.hMixer, BASSMIXEnvelope.BASS_MIXER_ENV_VOL, nodes );
//bool b = Bass.BASS_ChannelSetAttribute( this.hMixer, BASSAttribute.BASS_ATTRIB_VOL, value / 100.0f );
if ( !b )
{
if (!b) {
Errors be = Bass.LastError;
Trace.TraceInformation( "WASAPI Master Volume Set Error: " + be.ToString() );
}
else
{
Trace.TraceInformation("WASAPI Master Volume Set Error: " + be.ToString());
} else {
// int n = this.nMasterVolume;
// Trace.TraceInformation( "WASAPI Master Volume Set Success: " + value );
@ -109,28 +89,27 @@ namespace FDK
/// <param name="mode"></param>
/// <param name="bufferSize">(未使用; 本メソッド内で自動設定する)</param>
/// <param name="interval">(未使用; 本メソッド内で自動設定する)</param>
public CSoundDeviceWASAPI( EWASAPIMode mode, long bufferSize, long interval )
{
public CSoundDeviceWASAPI(EWASAPIMode mode, long bufferSize, long interval) {
// 初期化。
Trace.TraceInformation( "BASS (WASAPI) の初期化を開始します。" );
Trace.TraceInformation("BASS (WASAPI) の初期化を開始します。");
this.SoundDeviceType = ESoundDeviceType.Unknown;
this.OutputDelay = 0;
this.ElapsedTimeMs = 0;
this.UpdateSystemTimeMs = CTimer.UnusedNum;
this.SystemTimer = new CTimer( CTimer.TimerType.MultiMedia );
this.SystemTimer = new CTimer(CTimer.TimerType.MultiMedia);
this.b最初の実出力遅延算出 = true;
// BASS の設定。
this.bIsBASSFree = true;
if (!Bass.Configure( Configuration.UpdatePeriod, 0 )) // 0:BASSストリームの自動更新を行わない。
if (!Bass.Configure(Configuration.UpdatePeriod, 0)) // 0:BASSストリームの自動更新を行わない。
{
Trace.TraceWarning($"Configure({nameof(Configuration.UpdatePeriod)}) に失敗しました。[{Bass.LastError.ToString()}]");
}
if (!Bass.Configure( Configuration.UpdateThreads, 0 )) // 0:BASSストリームの自動更新を行わない。
if (!Bass.Configure(Configuration.UpdateThreads, 0)) // 0:BASSストリームの自動更新を行わない。
{
Trace.TraceWarning($"Configure({nameof(Configuration.UpdateThreads)}) に失敗しました。[{Bass.LastError.ToString()}]");
}
@ -150,12 +129,10 @@ namespace FDK
int a;
string strDefaultSoundDeviceName = null;
DeviceInfo[] bassDevInfos = new DeviceInfo[Bass.DeviceCount];
for(int j = 0; j < bassDevInfos.Length; j++)
{
for (int j = 0; j < bassDevInfos.Length; j++) {
bassDevInfos[j] = Bass.GetDeviceInfo(j);
}
for (a = 0; a < bassDevInfos.GetLength(0); a++)
{
for (a = 0; a < bassDevInfos.GetLength(0); a++) {
{
Trace.TraceInformation("Sound Device #{0}: {1}: IsDefault={2}, isEnabled={3}",
a,
@ -163,8 +140,7 @@ namespace FDK
bassDevInfos[a].IsDefault,
bassDevInfos[a].IsEnabled
);
if (bassDevInfos[a].IsDefault)
{
if (bassDevInfos[a].IsDefault) {
// これはOS標準のdefault device。後でWASAPIのdefault deviceと比較する。
strDefaultSoundDeviceName = bassDevInfos[a].Name;
}
@ -177,7 +153,7 @@ namespace FDK
nデバイス = -1;
n周波数 = 0; // デフォルトデバイスの周波数 (0="mix format" sample rate)
int nチャンネル数 = 0; // デフォルトデバイスのチャンネル数 (0="mix format" channels)
this.tWasapiProc = new WasapiProcedure( this.tWASAPI処理 ); // アンマネージに渡す delegate は、フィールドとして保持しておかないとGCでアドレスが変わってしまう。
this.tWasapiProc = new WasapiProcedure(this.tWASAPI処理); // アンマネージに渡す delegate は、フィールドとして保持しておかないとGCでアドレスが変わってしまう。
// WASAPIの更新間隔(period)は、バッファサイズにも影響を与える。
// 更新間隔を最小にするには、BassWasapi.BASS_WASAPI_GetDeviceInfo( ndevNo ).minperiod の値を使えばよい。
@ -185,8 +161,7 @@ namespace FDK
#region [ WASAPIデバイスを検索しmsを設定できる最小値にする ]
int nDevNo = -1;
WasapiDeviceInfo deviceInfo;
for (int n = 0; BassWasapi.GetDeviceInfo(n, out deviceInfo); n++)
{
for (int n = 0; BassWasapi.GetDeviceInfo(n, out deviceInfo); n++) {
// #37940 2018.2.15: BASS_DEVICEINFOとBASS_WASAPI_DEVICEINFOで、IsDefaultとなっているデバイスが異なる場合がある。
// (WASAPIでIsDefaultとなっているデバイスが正しくない場合がある)
// そのため、BASS_DEVICEでIsDefaultとなっているものを探し、それと同じ名前のWASAPIデバイスを使用する。
@ -195,8 +170,7 @@ namespace FDK
// (具体的には、defperiod, minperiod, mixchans, mixfreqがすべて0のデバイスは使用不可のため
// これらが0でないものを選択する)
//if ( deviceInfo.IsDefault )
if (deviceInfo.Name == strDefaultSoundDeviceName && deviceInfo.MixFrequency > 0)
{
if (deviceInfo.Name == strDefaultSoundDeviceName && deviceInfo.MixFrequency > 0) {
nDevNo = n;
#region [ ]
Trace.TraceInformation("WASAPI Device #{0}: {1}: IsDefault={2}, defPeriod={3}s, minperiod={4}s, mixchans={5}, mixfreq={6}",
@ -207,8 +181,7 @@ namespace FDK
break;
}
}
if (nDevNo != -1)
{
if (nDevNo != -1) {
Trace.TraceInformation("Start Bass_Init(device=0(fixed value: no sound), deviceInfo.mixfreq=" + deviceInfo.MixFrequency + ", BASS_DEVICE_DEFAULT, Zero)");
if (!Bass.Init(0, deviceInfo.MixFrequency, DeviceInitFlags.Default, IntPtr.Zero)) // device = 0:"no device": BASS からはデバイスへアクセスさせない。アクセスは BASSWASAPI アドオンから行う。
throw new Exception(string.Format("BASS (WASAPI{0}) の初期化に失敗しました。(BASS_Init)[{1}]", mode.ToString(), Bass.LastError.ToString()));
@ -224,30 +197,26 @@ namespace FDK
//{
// n希望バッファサイズms = n更新間隔ms + 1; // 2013.4.25 #31237 yyagi; バッファサイズ設定の完全自動化。更新間隔バッファサイズにするとBASS_ERROR_UNKNOWNになるので+1する。
//}
}
else
{
} else {
Trace.TraceError("Error: Default WASAPI Device is not found.");
}
#endregion
//Retry:
var flags = ( mode == EWASAPIMode.Exclusion ) ? WasapiInitFlags.AutoFormat | WasapiInitFlags.Exclusive : WasapiInitFlags.Shared | WasapiInitFlags.AutoFormat;
var flags = (mode == EWASAPIMode.Exclusion) ? WasapiInitFlags.AutoFormat | WasapiInitFlags.Exclusive : WasapiInitFlags.Shared | WasapiInitFlags.AutoFormat;
//var flags = ( mode == Eデバイスモード.排他 ) ? BASSWASAPIInit.BASS_WASAPI_AUTOFORMAT | BASSWASAPIInit.BASS_WASAPI_EVENT | BASSWASAPIInit.BASS_WASAPI_EXCLUSIVE : BASSWASAPIInit.BASS_WASAPI_AUTOFORMAT | BASSWASAPIInit.BASS_WASAPI_EVENT;
if ( BassWasapi.Init( nデバイス, n周波数, nチャンネル数, flags, ( bufferSize / 1000.0f ), ( interval / 1000.0f ), this.tWasapiProc, IntPtr.Zero ) )
{
if( mode == EWASAPIMode.Exclusion )
{
if (BassWasapi.Init(nデバイス, n周波数, nチャンネル数, flags, (bufferSize / 1000.0f), (interval / 1000.0f), this.tWasapiProc, IntPtr.Zero)) {
if (mode == EWASAPIMode.Exclusion) {
#region [ ]
//-----------------
this.SoundDeviceType = ESoundDeviceType.ExclusiveWASAPI;
nDevNo = BassWasapi.CurrentDevice;
deviceInfo = BassWasapi.GetDeviceInfo( nDevNo );
deviceInfo = BassWasapi.GetDeviceInfo(nDevNo);
BassWasapi.GetInfo(out var wasapiInfo);
int n1サンプルのバイト数 = 2 * wasapiInfo.Channels; // default;
switch( wasapiInfo.Format ) // BASS WASAPI で扱うサンプルはすべて 32bit float で固定されているが、デバイスはそうとは限らない。
switch (wasapiInfo.Format) // BASS WASAPI で扱うサンプルはすべて 32bit float で固定されているが、デバイスはそうとは限らない。
{
case WasapiFormat.Bit8: n1サンプルのバイト数 = 1 * wasapiInfo.Channels; break;
case WasapiFormat.Bit16: n1サンプルのバイト数 = 2 * wasapiInfo.Channels; break;
@ -257,24 +226,22 @@ namespace FDK
case WasapiFormat.Unknown: throw new ArgumentOutOfRangeException($"WASAPI format error ({wasapiInfo.ToString()})");
}
int n1秒のバイト数 = n1サンプルのバイト数 * wasapiInfo.Frequency;
this.BufferSize = (long) ( wasapiInfo.BufferLength * 1000.0f / n1秒のバイト数 );
this.BufferSize = (long)(wasapiInfo.BufferLength * 1000.0f / n1秒のバイト数);
this.OutputDelay = 0; // 初期値はゼロ
Trace.TraceInformation( "使用デバイス: #" + nDevNo + " : " + deviceInfo.Name );
Trace.TraceInformation( "BASS を初期化しました。(WASAPI排他モード, {0}Hz, {1}ch, フォーマット:{2}, バッファ{3}bytes [{4}ms(希望{5}ms)], 更新間隔{6}ms)",
Trace.TraceInformation("使用デバイス: #" + nDevNo + " : " + deviceInfo.Name);
Trace.TraceInformation("BASS を初期化しました。(WASAPI排他モード, {0}Hz, {1}ch, フォーマット:{2}, バッファ{3}bytes [{4}ms(希望{5}ms)], 更新間隔{6}ms)",
wasapiInfo.Frequency,
wasapiInfo.Channels,
wasapiInfo.Format.ToString(),
wasapiInfo.BufferLength,
BufferSize.ToString(),
bufferSize.ToString(),
interval.ToString() );
Trace.TraceInformation( "デバイスの最小更新時間={0}ms, 既定の更新時間={1}ms", deviceInfo.MinimumUpdatePeriod * 1000, deviceInfo.DefaultUpdatePeriod * 1000 );
interval.ToString());
Trace.TraceInformation("デバイスの最小更新時間={0}ms, 既定の更新時間={1}ms", deviceInfo.MinimumUpdatePeriod * 1000, deviceInfo.DefaultUpdatePeriod * 1000);
this.bIsBASSFree = false;
//-----------------
#endregion
}
else
{
} else {
#region [ ]
//-----------------
this.SoundDeviceType = ESoundDeviceType.SharedWASAPI;
@ -296,7 +263,7 @@ namespace FDK
this.OutputDelay = 0; // 初期値はゼロ
Trace.TraceInformation( "BASS を初期化しました。(WASAPI共有モード, {0}ms, 更新間隔{1}ms)", bufferSize, devInfo.DefaultUpdatePeriod * 1000.0f );
Trace.TraceInformation("BASS を初期化しました。(WASAPI共有モード, {0}ms, 更新間隔{1}ms)", bufferSize, devInfo.DefaultUpdatePeriod * 1000.0f);
this.bIsBASSFree = false;
//-----------------
#endregion
@ -315,14 +282,13 @@ namespace FDK
// #endregion
//}
#endregion
else
{
else {
#region [ ]
//-----------------
Errors errcode = Bass.LastError;
Bass.Free();
this.bIsBASSFree = true;
throw new Exception( string.Format( "BASS (WASAPI) の初期化に失敗しました。(BASS_WASAPI_Init)[{0}]", errcode ) );
throw new Exception(string.Format("BASS (WASAPI) の初期化に失敗しました。(BASS_WASAPI_Init)[{0}]", errcode));
//-----------------
#endregion
}
@ -335,19 +301,18 @@ namespace FDK
info.Frequency,
info.Channels,
BassFlags.MixerNonStop | BassFlags.Float | BassFlags.Decode); // デコードのみ発声しない。WASAPIに出力されるだけ。
if ( this.hMixer == 0 )
{
if (this.hMixer == 0) {
Errors errcode = Bass.LastError;
BassWasapi.Free();
Bass.Free();
this.bIsBASSFree = true;
throw new Exception( string.Format( "BASSミキサ(mixing)の作成に失敗しました。[{0}]", errcode ) );
throw new Exception(string.Format("BASSミキサ(mixing)の作成に失敗しました。[{0}]", errcode));
}
// BASS ミキサーの1秒あたりのバイト数を算出。
var mixerInfo = Bass.ChannelGetInfo( this.hMixer );
var mixerInfo = Bass.ChannelGetInfo(this.hMixer);
long nミキサーの1サンプルあたりのバイト数 = mixerInfo.Channels * 4; // 4 = sizeof(FLOAT)
this.nミキサーの1秒あたりのバイト数 = nミキサーの1サンプルあたりのバイト数 * mixerInfo.Frequency;
@ -360,25 +325,23 @@ namespace FDK
this.hMixer_DeviceOut = BassMix.CreateMixerStream(
info.Frequency,
info.Channels,
BassFlags.MixerNonStop | BassFlags.Float | BassFlags.Decode ); // デコードのみ発声しない。WASAPIに出力されるだけ。
if ( this.hMixer_DeviceOut == 0 )
{
BassFlags.MixerNonStop | BassFlags.Float | BassFlags.Decode); // デコードのみ発声しない。WASAPIに出力されるだけ。
if (this.hMixer_DeviceOut == 0) {
Errors errcode = Bass.LastError;
BassWasapi.Free();
Bass.Free();
this.bIsBASSFree = true;
throw new Exception( string.Format( "BASSミキサ(最終段)の作成に失敗しました。[{0}]", errcode ) );
throw new Exception(string.Format("BASSミキサ(最終段)の作成に失敗しました。[{0}]", errcode));
}
{
bool b1 = BassMix.MixerAddChannel( this.hMixer_DeviceOut, this.hMixer, BassFlags.Default );
if ( !b1 )
{
bool b1 = BassMix.MixerAddChannel(this.hMixer_DeviceOut, this.hMixer, BassFlags.Default);
if (!b1) {
Errors errcode = Bass.LastError;
BassWasapi.Free();
Bass.Free();
this.bIsBASSFree = true;
throw new Exception( string.Format( "BASSミキサ(最終段とmixing)の接続に失敗しました。[{0}]", errcode ) );
throw new Exception(string.Format("BASSミキサ(最終段とmixing)の接続に失敗しました。[{0}]", errcode));
};
}
@ -388,47 +351,39 @@ namespace FDK
BassWasapi.Start();
}
#region [ tサウンドを作成する() ]
public CSound tCreateSound( string strファイル名, ESoundGroup soundGroup )
{
public CSound tCreateSound(string strファイル名, ESoundGroup soundGroup) {
var sound = new CSound(soundGroup);
sound.CreateWASAPISound( strファイル名, this.hMixer, this.SoundDeviceType );
sound.CreateWASAPISound(strファイル名, this.hMixer, this.SoundDeviceType);
return sound;
}
public void tCreateSound( string strファイル名, CSound sound )
{
sound.CreateWASAPISound( strファイル名, this.hMixer, this.SoundDeviceType );
public void tCreateSound(string strファイル名, CSound sound) {
sound.CreateWASAPISound(strファイル名, this.hMixer, this.SoundDeviceType);
}
#endregion
#region [ Dispose-Finallizeパターン実装 ]
//-----------------
public void Dispose()
{
this.Dispose( true );
GC.SuppressFinalize( this );
public void Dispose() {
this.Dispose(true);
GC.SuppressFinalize(this);
}
protected void Dispose( bool bManagedDispose )
{
protected void Dispose(bool bManagedDispose) {
SoundDeviceType = ESoundDeviceType.Unknown; // まず出力停止する(Dispose中にクラス内にアクセスされることを防ぐ)
if ( hMixer != -1 )
{
Bass.StreamFree( hMixer );
if (hMixer != -1) {
Bass.StreamFree(hMixer);
}
if ( !bIsBASSFree )
{
if (!bIsBASSFree) {
BassWasapi.Free(); // システムタイマより先に呼び出すこと。tWasapi処理() の中でシステムタイマを参照してるため)
Bass.Free();
}
if( bManagedDispose )
{
if (bManagedDispose) {
SystemTimer.Dispose();
SystemTimer = null;
}
}
~CSoundDeviceWASAPI()
{
this.Dispose( false );
~CSoundDeviceWASAPI() {
this.Dispose(false);
}
//-----------------
#endregion
@ -437,26 +392,25 @@ namespace FDK
protected int hMixer_DeviceOut = -1;
protected WasapiProcedure tWasapiProc = null;
protected int tWASAPI処理( IntPtr buffer, int length, IntPtr user )
{
protected int tWASAPI処理(IntPtr buffer, int length, IntPtr user) {
// BASSミキサからの出力データをそのまま WASAPI buffer へ丸投げ。
int num = Bass.ChannelGetData( this.hMixer_DeviceOut, buffer, length ); // num = 実際に転送した長さ
if ( num == -1 ) num = 0;
int num = Bass.ChannelGetData(this.hMixer_DeviceOut, buffer, length); // num = 実際に転送した長さ
if (num == -1) num = 0;
// 経過時間を更新。
// データの転送差分ではなく累積転送バイト数から算出する。
int n未再生バイト数 = BassWasapi.GetData( null, (int) DataFlags.Available ); // 誤差削減のため、必要となるギリギリ直前に取得する。
this.ElapsedTimeMs = ( this.n累積転送バイト数 - n未再生バイト数 ) * 1000 / this.nミキサーの1秒あたりのバイト数;
int n未再生バイト数 = BassWasapi.GetData(null, (int)DataFlags.Available); // 誤差削減のため、必要となるギリギリ直前に取得する。
this.ElapsedTimeMs = (this.n累積転送バイト数 - n未再生バイト数) * 1000 / this.nミキサーの1秒あたりのバイト数;
this.UpdateSystemTimeMs = this.SystemTimer.SystemTimeMs;
// 実出力遅延を更新。
// 未再生バイト数の平均値。
long n今回の遅延ms = n未再生バイト数 * 1000 / this.nミキサーの1秒あたりのバイト数;
this.OutputDelay = ( this.b最初の実出力遅延算出 ) ? n今回の遅延ms : ( this.OutputDelay + n今回の遅延ms ) / 2;
this.OutputDelay = (this.b最初の実出力遅延算出) ? n今回の遅延ms : (this.OutputDelay + n今回の遅延ms) / 2;
this.b最初の実出力遅延算出 = false;

View File

@ -1,23 +1,13 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Diagnostics;
namespace FDK
{
public class CSoundTimer : CTimerBase
{
public override long SystemTimeMs
{
get
{
if( this.Device.SoundDeviceType == ESoundDeviceType.Bass ||
namespace FDK {
public class CSoundTimer : CTimerBase {
public override long SystemTimeMs {
get {
if (this.Device.SoundDeviceType == ESoundDeviceType.Bass ||
this.Device.SoundDeviceType == ESoundDeviceType.ExclusiveWASAPI ||
this.Device.SoundDeviceType == ESoundDeviceType.SharedWASAPI ||
this.Device.SoundDeviceType == ESoundDeviceType.ASIO )
{
this.Device.SoundDeviceType == ESoundDeviceType.ASIO) {
// BASS 系の ISoundDevice.n経過時間ms はオーディオバッファの更新間隔ずつでしか更新されないため、単にこれを返すだけではとびとびの値になる。
// そこで、更新間隔の最中に呼ばれた場合は、システムタイマを使って補間する。
// この場合の経過時間との誤差は更新間隔以内に収まるので問題ないと判断する。
@ -25,7 +15,7 @@ namespace FDK
// 動作がおかしくなる。(具体的には、ここで返すタイマー値の逆行が発生し、スクロールが巻き戻る)
// この場合の対策は、ASIOのバッファ量を増やして、ASIOの音声合成処理の負荷を下げること。
if ( this.Device.UpdateSystemTimeMs == CTimer.UnusedNum ) // #33890 2014.5.27 yyagi
if (this.Device.UpdateSystemTimeMs == CTimer.UnusedNum) // #33890 2014.5.27 yyagi
{
// 環境によっては、ASIOベースの演奏タイマーが動作する前(つまりASIOのサウンド転送が始まる前)に
// DTXデータの演奏が始まる場合がある。
@ -39,18 +29,14 @@ namespace FDK
// 補正部分をゼロにして、n経過時間msだけを返すようにする。
// こうすることで、演奏タイマが動作を始めても、破綻しなくなる。
return this.Device.ElapsedTimeMs;
}
else
{
if ( FDK.SoundManager.bUseOSTimer )
} else {
if (FDK.SoundManager.bUseOSTimer)
//if ( true )
{
return ctDInputTimer.SystemTimeMs; // 仮にCSoundTimerをCTimer相当の動作にしてみた
}
else
{
} else {
return this.Device.ElapsedTimeMs
+ ( this.Device.SystemTimer.SystemTimeMs - this.Device.UpdateSystemTimeMs );
+ (this.Device.SystemTimer.SystemTimeMs - this.Device.UpdateSystemTimeMs);
}
}
}
@ -58,8 +44,7 @@ namespace FDK
}
}
internal CSoundTimer( ISoundDevice device )
{
internal CSoundTimer(ISoundDevice device) {
this.Device = device;
TimerCallback timerDelegate = new TimerCallback(SnapTimers); // CSoundTimerをシステム時刻に変換するために、
@ -69,13 +54,11 @@ namespace FDK
private void SnapTimers(object o) // 1秒に1回呼び出され、2つのタイマー間の現在値をそれぞれ保持する。
{
try
{
try {
this.nDInputTimerCounter = this.ctDInputTimer.SystemTimeMs;
this.nSoundTimerCounter = this.SystemTimeMs;
//Debug.WriteLine( "BaseCounter: " + nDInputTimerCounter + ", " + nSoundTimerCounter );
}
catch (Exception e)
} catch (Exception e)
// サウンド設定変更時に、timer.Dispose()した後、timerが実際に停止する前にここに来てしまう場合があり
// その際にNullReferenceExceptionが発生する
// timerが実際に停止したことを検出してから次の設定をすべきだが、実装が難しいため、
@ -85,26 +68,22 @@ namespace FDK
Trace.TraceInformation("FDK: CSoundTimer.SnapTimers(): 例外発生しましたが、継続します。");
}
}
public long nサウンドタイマーのシステム時刻msへの変換( long nDInputのタイムスタンプ )
{
public long nサウンドタイマーのシステム時刻msへの変換(long nDInputのタイムスタンプ) {
return nDInputのタイムスタンプ - this.nDInputTimerCounter + this.nSoundTimerCounter; // Timer違いによる時差を補正する
}
public override void Dispose()
{
public override void Dispose() {
// 特になし; ISoundDevice の解放は呼び出し元で行うこと。
//sendinputスレッド削除
if ( timer != null )
{
timer.Change( System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite );
if (timer != null) {
timer.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
// ここで、実際にtimerが停止したことを確認するコードを追加すべきだが、やり方わからず。
// 代替策として、SnapTimers()中で、例外発生を破棄している。
timer.Dispose();
timer = null;
}
if ( ct != null )
{
if (ct != null) {
ct.Pause();
ct.Dispose();
ct = null;

View File

@ -1,11 +1,5 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace FDK
{
public enum ESoundDeviceType
{
namespace FDK {
public enum ESoundDeviceType {
Bass,
ExclusiveWASAPI,
SharedWASAPI,

View File

@ -1,7 +1,5 @@
namespace FDK
{
public enum ESoundGroup
{
namespace FDK {
public enum ESoundGroup {
SoundEffect = 1,
Voice = 2,
SongPreview = 3,

View File

@ -1,25 +1,17 @@
using System;
using System.Collections.Generic;
using System.Text;
using ManagedBass;
using ManagedBass;
using ManagedBass.Mix;
namespace FDK.BassMixExtension
{
public static class BassMixExtensions
{
public static bool ChannelPlay(int hHandle)
{
namespace FDK.BassMixExtension {
public static class BassMixExtensions {
public static bool ChannelPlay(int hHandle) {
return BassMix.ChannelRemoveFlag(hHandle, BassFlags.MixerChanPause);
}
public static bool ChannelPause(int hHandle)
{
public static bool ChannelPause(int hHandle) {
return BassMix.ChannelAddFlag(hHandle, BassFlags.MixerChanPause);
}
public static bool ChannelIsPlaying(int hHandle)
{
public static bool ChannelIsPlaying(int hHandle) {
return !BassMix.ChannelHasFlag(hHandle, BassFlags.MixerChanPause);
}
}

View File

@ -1,12 +1,5 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
namespace FDK
{
internal interface ISoundDevice : IDisposable
{
namespace FDK {
internal interface ISoundDevice : IDisposable {
ESoundDeviceType SoundDeviceType { get; }
int nMasterVolume { get; set; }
long OutputDelay { get; }
@ -15,7 +8,7 @@ namespace FDK
long UpdateSystemTimeMs { get; }
CTimer SystemTimer { get; }
CSound tCreateSound( string strファイル名, ESoundGroup soundGroup );
void tCreateSound( string strファイル名, CSound sound );
CSound tCreateSound(string strファイル名, ESoundGroup soundGroup);
void tCreateSound(string strファイル名, CSound sound);
}
}

View File

@ -1,20 +1,15 @@
using System;
namespace FDK
{
namespace FDK {
/// <summary>
/// The LoudnessMetadata structure is used to carry, and assist with
/// calculations related to, integrated loudness and true peak
/// loudness.
/// </summary>
[Serializable]
public struct LoudnessMetadata
{
public struct LoudnessMetadata {
public readonly Lufs Integrated;
public readonly Lufs? TruePeak;
public LoudnessMetadata(Lufs integrated, Lufs? truePeak)
{
public LoudnessMetadata(Lufs integrated, Lufs? truePeak) {
Integrated = integrated;
TruePeak = truePeak;
}

View File

@ -1,14 +1,8 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Xml.XPath;
namespace FDK
{
namespace FDK {
/// <summary>
/// The LoudnessMetadataScanner plays two roles:
/// 1. Scanning of song audio files using BS1770GAIN (http://bs1770gain.sourceforge.net/)
@ -26,8 +20,7 @@ namespace FDK
/// SongGainController for combination with a configured target loudness, resulting in a
/// gain value assigned to the sound object just before playback begins.
/// </summary>
public static class LoudnessMetadataScanner
{
public static class LoudnessMetadataScanner {
private const string Bs1770GainExeFileName = "bs1770gain.exe";
private static readonly Stack<string> Jobs = new Stack<string>();
@ -37,23 +30,19 @@ namespace FDK
private static Thread ScanningThread;
private static Semaphore Semaphore;
public static void StartBackgroundScanning()
{
public static void StartBackgroundScanning() {
var tracePrefix = $"{nameof(LoudnessMetadataScanner)}.{nameof(StartBackgroundScanning)}";
if (!IsBs1770GainAvailable())
{
if (!IsBs1770GainAvailable()) {
Trace.TraceInformation($"{tracePrefix}: BS1770GAIN is not available. A background scanning thread will not be started.");
return;
}
Trace.TraceInformation($"{tracePrefix}: BS1770GAIN is available. Starting background scanning thread...");
lock (LockObject)
{
lock (LockObject) {
Semaphore = new Semaphore(Jobs.Count, int.MaxValue);
ScanningThread = new Thread(Scan)
{
ScanningThread = new Thread(Scan) {
IsBackground = true,
Name = "LoudnessMetadataScanner background scanning thread.",
Priority = ThreadPriority.Lowest
@ -64,12 +53,10 @@ namespace FDK
Trace.TraceInformation($"{tracePrefix}: Background scanning thread started.");
}
public static void StopBackgroundScanning(bool joinImmediately)
{
public static void StopBackgroundScanning(bool joinImmediately) {
var scanningThread = ScanningThread;
if (scanningThread == null)
{
if (scanningThread == null) {
return;
}
@ -77,36 +64,29 @@ namespace FDK
Trace.TraceInformation($"{tracePrefix}: Stopping background scanning thread...");
lock (LockObject)
{
lock (LockObject) {
ScanningThread = null;
Semaphore.Release();
Semaphore = null;
}
if (joinImmediately)
{
if (joinImmediately) {
scanningThread.Join();
}
Trace.TraceInformation($"{tracePrefix}: Background scanning thread stopped.");
}
public static LoudnessMetadata? LoadForAudioPath(string absoluteBgmPath)
{
try
{
public static LoudnessMetadata? LoadForAudioPath(string absoluteBgmPath) {
try {
var loudnessMetadataPath = GetLoudnessMetadataPath(absoluteBgmPath);
if (File.Exists(loudnessMetadataPath))
{
if (File.Exists(loudnessMetadataPath)) {
return LoadFromMetadataPath(loudnessMetadataPath);
}
SubmitForBackgroundScanning(absoluteBgmPath);
}
catch (Exception e)
{
} catch (Exception e) {
var tracePrefix = $"{nameof(LoudnessMetadataScanner)}.{nameof(LoadForAudioPath)}";
Trace.TraceError($"{tracePrefix}: Encountered an exception while attempting to load {absoluteBgmPath}");
Trace.TraceError(e.ToString());
@ -115,22 +95,17 @@ namespace FDK
return null;
}
private static string GetLoudnessMetadataPath(string absoluteBgmPath)
{
private static string GetLoudnessMetadataPath(string absoluteBgmPath) {
return Path.Combine(
Path.GetDirectoryName(absoluteBgmPath),
Path.GetFileNameWithoutExtension(absoluteBgmPath) + ".bs1770gain.xml");
}
private static LoudnessMetadata? LoadFromMetadataPath(string loudnessMetadataPath)
{
private static LoudnessMetadata? LoadFromMetadataPath(string loudnessMetadataPath) {
XPathDocument xPathDocument;
try
{
try {
xPathDocument = new XPathDocument(loudnessMetadataPath);
}
catch (IOException)
{
} catch (IOException) {
var tracePrefix = $"{nameof(LoudnessMetadataScanner)}.{nameof(LoadFromMetadataPath)}";
Trace.TraceWarning($"{tracePrefix}: Encountered IOException while attempting to read {loudnessMetadataPath}. This can occur when attempting to load while scanning the same file. Returning null...");
return null;
@ -142,8 +117,7 @@ namespace FDK
var integratedLufsNode = trackNavigator?.SelectSingleNode(@"integrated/@lufs");
var truePeakTpfsNode = trackNavigator?.SelectSingleNode(@"true-peak/@tpfs");
if (trackNavigator == null || integratedLufsNode == null || truePeakTpfsNode == null)
{
if (trackNavigator == null || integratedLufsNode == null || truePeakTpfsNode == null) {
var tracePrefix = $"{nameof(LoudnessMetadataScanner)}.{nameof(LoadFromMetadataPath)}";
Trace.TraceWarning($"{tracePrefix}: Encountered incorrect xml element structure while parsing {loudnessMetadataPath}. Returning null...");
return null;
@ -152,8 +126,7 @@ namespace FDK
var integrated = integratedLufsNode.ValueAsDouble;
var truePeak = truePeakTpfsNode.ValueAsDouble;
if (integrated <= -70.0 || truePeak >= 12.04)
{
if (integrated <= -70.0 || truePeak >= 12.04) {
var tracePrefix = $"{nameof(LoudnessMetadataScanner)}.{nameof(LoadFromMetadataPath)}";
Trace.TraceWarning($"{tracePrefix}: Encountered evidence of extreme clipping while parsing {loudnessMetadataPath}. Returning null...");
return null;
@ -162,10 +135,8 @@ namespace FDK
return new LoudnessMetadata(new Lufs(integrated), new Lufs(truePeak));
}
private static void SubmitForBackgroundScanning(string absoluteBgmPath)
{
lock (LockObject)
{
private static void SubmitForBackgroundScanning(string absoluteBgmPath) {
lock (LockObject) {
// Quite often, the loading process will cause the same job to be submitted many times.
// As such, we'll do a quick check as when this happens an equivalent job will often
// already be at the top of the stack and we need not add it again.
@ -178,26 +149,21 @@ namespace FDK
// scrolling through songs and previewing them. Their current interests should drive
// scanning priorities, and it is for this reason that a stack is used instead of a queue.
var semaphore = Semaphore;
if (semaphore != null && (Jobs.Count == 0 || Jobs.Peek() != absoluteBgmPath))
{
if (semaphore != null && (Jobs.Count == 0 || Jobs.Peek() != absoluteBgmPath)) {
Jobs.Push(absoluteBgmPath);
semaphore.Release();
}
}
}
private static void Scan()
{
try
{
while (true)
{
private static void Scan() {
try {
while (true) {
RaiseScanningStateChanged(false);
Semaphore?.WaitOne();
if (ScanningThread == null)
{
if (ScanningThread == null) {
return;
}
@ -205,26 +171,22 @@ namespace FDK
int jobCount;
string absoluteBgmPath;
lock (LockObject)
{
lock (LockObject) {
jobCount = Jobs.Count;
absoluteBgmPath = Jobs.Pop();
}
var tracePrefix = $"{nameof(LoudnessMetadataScanner)}.{nameof(Scan)}";
try
{
if (!File.Exists(absoluteBgmPath))
{
try {
if (!File.Exists(absoluteBgmPath)) {
Trace.TraceWarning($"{tracePrefix}: Scanning jobs outstanding: {jobCount - 1}. Missing audio file. Skipping {absoluteBgmPath}...");
continue;
}
var loudnessMetadataPath = GetLoudnessMetadataPath(absoluteBgmPath);
if (File.Exists(loudnessMetadataPath))
{
if (File.Exists(loudnessMetadataPath)) {
Trace.TraceWarning($"{tracePrefix}: Scanning jobs outstanding: {jobCount - 1}. Pre-existing metadata. Skipping {absoluteBgmPath}...");
continue;
}
@ -238,41 +200,30 @@ namespace FDK
var seconds = stopwatch.Elapsed.TotalSeconds;
RecentFileScanDurations.Enqueue(seconds);
while (RecentFileScanDurations.Count > 20)
{
while (RecentFileScanDurations.Count > 20) {
RecentFileScanDurations.Dequeue();
}
var averageSeconds = RecentFileScanDurations.Average();
Trace.TraceInformation($"{tracePrefix}: Scanned in {seconds}s. Estimated remaining: {(int)(averageSeconds * (jobCount - 1))}s.");
}
catch (Exception e)
{
} catch (Exception e) {
Trace.TraceError($"{tracePrefix}: Encountered an exception while attempting to scan {absoluteBgmPath}");
Trace.TraceError(e.ToString());
}
}
}
catch (Exception e)
{
} catch (Exception e) {
var tracePrefix = $"{nameof(LoudnessMetadataScanner)}.{nameof(Scan)}";
Trace.TraceError($"{tracePrefix}: caught an exception at the level of the thread method. The background scanning thread will now terminate.");
Trace.TraceError(e.ToString());
}
}
private static bool IsBs1770GainAvailable()
{
try
{
private static bool IsBs1770GainAvailable() {
try {
Execute(null, Bs1770GainExeFileName, "-h");
return true;
}
catch (Win32Exception)
{
} catch (Win32Exception) {
return false;
}
catch (Exception e)
{
} catch (Exception e) {
var tracePrefix = $"{nameof(LoudnessMetadataScanner)}.{nameof(IsBs1770GainAvailable)}";
Trace.TraceError($"{tracePrefix}: Encountered an exception. Returning false...");
Trace.TraceError(e.ToString());
@ -282,10 +233,8 @@ namespace FDK
}
private static string Execute(
string workingDirectory, string fileName, string arguments, bool shouldFailOnStdErrDataReceived = false)
{
var processStartInfo = new ProcessStartInfo(fileName, arguments)
{
string workingDirectory, string fileName, string arguments, bool shouldFailOnStdErrDataReceived = false) {
var processStartInfo = new ProcessStartInfo(fileName, arguments) {
CreateNoWindow = true,
RedirectStandardError = true,
RedirectStandardOutput = true,
@ -295,22 +244,17 @@ namespace FDK
var stdoutWriter = new StringWriter();
var stderrWriter = new StringWriter();
using (var process = Process.Start(processStartInfo))
{
process.OutputDataReceived += (s, e) =>
{
if (e.Data != null)
{
using (var process = Process.Start(processStartInfo)) {
process.OutputDataReceived += (s, e) => {
if (e.Data != null) {
stdoutWriter.Write(e.Data);
stdoutWriter.Write(Environment.NewLine);
}
};
var errorDataReceived = false;
process.ErrorDataReceived += (s, e) =>
{
if (e.Data != null)
{
process.ErrorDataReceived += (s, e) => {
if (e.Data != null) {
errorDataReceived = true;
stderrWriter.Write(e.Data);
stderrWriter.Write(Environment.NewLine);
@ -321,11 +265,9 @@ namespace FDK
process.BeginErrorReadLine();
process.WaitForExit();
if ((shouldFailOnStdErrDataReceived && errorDataReceived) || process.ExitCode != 0)
{
if ((shouldFailOnStdErrDataReceived && errorDataReceived) || process.ExitCode != 0) {
var stderr = stderrWriter.ToString();
if (string.IsNullOrEmpty(stderr))
{
if (string.IsNullOrEmpty(stderr)) {
stderr = stdoutWriter.ToString();
}
@ -337,15 +279,12 @@ namespace FDK
}
}
private static void RaiseScanningStateChanged(bool isActivelyScanning)
{
private static void RaiseScanningStateChanged(bool isActivelyScanning) {
ScanningStateChanged?.Invoke(null, new ScanningStateChangedEventArgs(isActivelyScanning));
}
public class ScanningStateChangedEventArgs : EventArgs
{
public ScanningStateChangedEventArgs(bool isActivelyScanning)
{
public class ScanningStateChangedEventArgs : EventArgs {
public ScanningStateChangedEventArgs(bool isActivelyScanning) {
IsActivelyScanning = isActivelyScanning;
}

View File

@ -1,46 +1,36 @@
using System;
namespace FDK
{
namespace FDK {
/// <summary>
/// The Lufs structure is used to carry, and assist with calculations related to,
/// Loudness Units relative to Full Scale. LUFS are measured in absolute scale
/// and whole values represent one decibel.
/// </summary>
[Serializable]
public struct Lufs
{
public struct Lufs {
private readonly double _value;
public Lufs(double value)
{
public Lufs(double value) {
_value = value;
}
public double ToDouble() => _value;
public Lufs Min(Lufs lufs)
{
public Lufs Min(Lufs lufs) {
return new Lufs(Math.Min(_value, lufs._value));
}
public Lufs Negate()
{
public Lufs Negate() {
return new Lufs(-_value);
}
public override string ToString()
{
public override string ToString() {
return _value.ToString();
}
public static Lufs operator- (Lufs left, Lufs right)
{
public static Lufs operator -(Lufs left, Lufs right) {
return new Lufs(left._value - right._value);
}
public static Lufs operator+ (Lufs left, Lufs right)
{
public static Lufs operator +(Lufs left, Lufs right) {
return new Lufs(left._value + right._value);
}
}

View File

@ -1,5 +1,4 @@
namespace FDK
{
namespace FDK {
/// <summary>
/// SongGainController provides a central place through which song preview
/// and song playback attempt to apply BS1770GAIN-based loudness metadata
@ -9,22 +8,17 @@
/// song (preview) CSound object, SongGainController can override the Gain
/// value based on configuration or other information.
/// </summary>
public sealed class SongGainController
{
public sealed class SongGainController {
public bool ApplyLoudnessMetadata { private get; set; }
public Lufs TargetLoudness { private get; set; }
public bool ApplySongVol { private get; set; }
public void Set(int songVol, LoudnessMetadata? songLoudnessMetadata, CSound sound)
{
if (ApplyLoudnessMetadata && songLoudnessMetadata.HasValue)
{
public void Set(int songVol, LoudnessMetadata? songLoudnessMetadata, CSound sound) {
if (ApplyLoudnessMetadata && songLoudnessMetadata.HasValue) {
var gain = TargetLoudness - songLoudnessMetadata.Value.Integrated;
sound.SetGain(gain, songLoudnessMetadata.Value.TruePeak);
}
else
{
} else {
sound.SetGain(ApplySongVol ? songVol : CSound.DefaultSongVol);
}
}

View File

@ -1,11 +1,8 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using FDK.ExtensionMethods;
namespace FDK
{
namespace FDK {
/// <summary>
/// SoundGroupLevelController holds the current sound level value for each
/// of the unique sound groups, along with an increment by which they can
@ -33,10 +30,8 @@ namespace FDK
/// all existing sound objects group levels by iterating that same
/// observable collection.
/// </summary>
public sealed class SoundGroupLevelController
{
private readonly Dictionary<ESoundGroup, int> _levelBySoundGroup = new Dictionary<ESoundGroup, int>
{
public sealed class SoundGroupLevelController {
private readonly Dictionary<ESoundGroup, int> _levelBySoundGroup = new Dictionary<ESoundGroup, int> {
[ESoundGroup.SoundEffect] = CSound.MaximumGroupLevel,
[ESoundGroup.Voice] = CSound.MaximumGroupLevel,
[ESoundGroup.SongPreview] = CSound.MaximumGroupLevel,
@ -48,28 +43,23 @@ namespace FDK
private int _keyboardSoundLevelIncrement;
public SoundGroupLevelController(ObservableCollection<CSound> sounds)
{
public SoundGroupLevelController(ObservableCollection<CSound> sounds) {
_sounds = sounds;
_sounds.CollectionChanged += SoundsOnCollectionChanged;
}
public void SetLevel(ESoundGroup soundGroup, int level)
{
public void SetLevel(ESoundGroup soundGroup, int level) {
var clampedLevel = level.Clamp(CSound.MinimumGroupLevel, CSound.MaximumGroupLevel);
if (_levelBySoundGroup[soundGroup] == clampedLevel)
{
if (_levelBySoundGroup[soundGroup] == clampedLevel) {
return;
}
_levelBySoundGroup[soundGroup] = clampedLevel;
foreach (var sound in _sounds)
{
if (sound.SoundGroup == soundGroup)
{
foreach (var sound in _sounds) {
if (sound.SoundGroup == soundGroup) {
SetLevel(sound);
}
}
@ -77,13 +67,11 @@ namespace FDK
RaiseLevelChanged(soundGroup, clampedLevel);
}
public void SetKeyboardSoundLevelIncrement(int keyboardSoundLevelIncrement)
{
public void SetKeyboardSoundLevelIncrement(int keyboardSoundLevelIncrement) {
_keyboardSoundLevelIncrement = keyboardSoundLevelIncrement;
}
public void AdjustLevel(ESoundGroup soundGroup, bool isAdjustmentPositive)
{
public void AdjustLevel(ESoundGroup soundGroup, bool isAdjustmentPositive) {
var adjustmentIncrement = isAdjustmentPositive
? _keyboardSoundLevelIncrement
: -_keyboardSoundLevelIncrement;
@ -91,34 +79,27 @@ namespace FDK
SetLevel(soundGroup, _levelBySoundGroup[soundGroup] + adjustmentIncrement);
}
private void SetLevel(CSound sound)
{
private void SetLevel(CSound sound) {
sound.GroupLevel = _levelBySoundGroup[sound.SoundGroup];
}
private void SoundsOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
private void SoundsOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) {
switch (e.Action) {
case NotifyCollectionChangedAction.Add:
case NotifyCollectionChangedAction.Replace:
foreach (CSound sound in e.NewItems)
{
foreach (CSound sound in e.NewItems) {
SetLevel(sound);
}
break;
}
}
private void RaiseLevelChanged(ESoundGroup soundGroup, int level)
{
private void RaiseLevelChanged(ESoundGroup soundGroup, int level) {
LevelChanged?.Invoke(this, new LevelChangedEventArgs(soundGroup, level));
}
public class LevelChangedEventArgs : EventArgs
{
public LevelChangedEventArgs(ESoundGroup soundGroup, int level)
{
public class LevelChangedEventArgs : EventArgs {
public LevelChangedEventArgs(ESoundGroup soundGroup, int level) {
SoundGroup = soundGroup;
Level = level;
}

View File

@ -1,30 +1,15 @@
using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.IO;
using System.Linq;
using System.Threading;
using FDK.ExtensionMethods;
using ManagedBass;
using ManagedBass.Asio;
using ManagedBass.Wasapi;
using ManagedBass.Mix;
using ManagedBass.Fx;
using Silk.NET.Windowing;
using FDK.BassMixExtension;
namespace FDK
{
namespace FDK {
public class SoundManager // : CSound
{
private static ISoundDevice SoundDevice
{
private static ISoundDevice SoundDevice {
get; set;
}
private static ESoundDeviceType SoundDeviceType
{
private static ESoundDeviceType SoundDeviceType {
get; set;
}
public static CSoundTimer PlayTimer = null;
@ -40,10 +25,8 @@ namespace FDK
private static IWindow Window_;
private static int _nMasterVolume;
public int nMasterVolume
{
get
{
public int nMasterVolume {
get {
return _nMasterVolume;
}
//get
@ -90,8 +73,7 @@ namespace FDK
// BassMix.BASS_Mixer_ChannelSetEnvelope( SoundDevice.hMixer, BASSMIXEnvelope.BASS_MIXER_ENV_VOL, nodes );
// }
//}
set
{
set {
SoundDevice.nMasterVolume = value;
_nMasterVolume = value;
}
@ -105,13 +87,11 @@ namespace FDK
//public static bool bIsMP3DecodeByWindowsCodec = false;
public static int nMixing = 0;
public int GetMixingStreams()
{
public int GetMixingStreams() {
return nMixing;
}
public static int nStreams = 0;
public int GetStreams()
{
public int GetStreams() {
return nStreams;
}
#region [ WASAPI/ASIO/DirectSound設定値 ]
@ -120,12 +100,10 @@ namespace FDK
/// <para>0以下の値を指定すると、この数値はWASAPI初期化時に自動設定する。正数を指定すると、その値を設定しようと試みる。</para>
/// </summary>
public static int SoundDelayExclusiveWASAPI = 0; // SSTでは、50ms
public int GetSoundExclusiveWASAPI()
{
public int GetSoundExclusiveWASAPI() {
return SoundDelayExclusiveWASAPI;
}
public void SetSoundDelayExclusiveWASAPI( int value )
{
public void SetSoundDelayExclusiveWASAPI(int value) {
SoundDelayExclusiveWASAPI = value;
}
/// <summary>
@ -158,21 +136,17 @@ namespace FDK
/// <para>ASIO 出力におけるバッファサイズ。</para>
/// </summary>
public static int SoundDelayASIO = 0; // 0にすると、デバイスの設定値をそのまま使う。
public int GetSoundDelayASIO()
{
public int GetSoundDelayASIO() {
return SoundDelayASIO;
}
public void SetSoundDelayASIO(int value)
{
public void SetSoundDelayASIO(int value) {
SoundDelayASIO = value;
}
public static int ASIODevice = 0;
public int GetASIODevice()
{
public int GetASIODevice() {
return ASIODevice;
}
public void SetASIODevice(int value)
{
public void SetASIODevice(int value) {
ASIODevice = value;
}
/// <summary>
@ -180,14 +154,10 @@ namespace FDK
/// </summary>
public static int SoundDelayDirectSound = 100;
public long GetSoundDelay()
{
if ( SoundDevice != null )
{
public long GetSoundDelay() {
if (SoundDevice != null) {
return SoundDevice.BufferSize;
}
else
{
} else {
return -1;
}
}
@ -203,15 +173,13 @@ namespace FDK
/// <param name="nSoundDelayExclusiveWASAPI"></param>
/// <param name="nSoundDelayASIO"></param>
/// <param name="nASIODevice"></param>
public SoundManager( IWindow window, ESoundDeviceType soundDeviceType, int nSoundDelayBASS, int nSoundDelayExclusiveWASAPI, int nSoundDelayASIO, int nASIODevice, bool _bUseOSTimer )
{
public SoundManager(IWindow window, ESoundDeviceType soundDeviceType, int nSoundDelayBASS, int nSoundDelayExclusiveWASAPI, int nSoundDelayASIO, int nASIODevice, bool _bUseOSTimer) {
Window_ = window;
SoundDevice = null;
//bUseOSTimer = false;
tInitialize( soundDeviceType, nSoundDelayBASS, nSoundDelayExclusiveWASAPI, nSoundDelayASIO, nASIODevice, _bUseOSTimer );
tInitialize(soundDeviceType, nSoundDelayBASS, nSoundDelayExclusiveWASAPI, nSoundDelayASIO, nASIODevice, _bUseOSTimer);
}
public void Dispose()
{
public void Dispose() {
t終了();
}
@ -220,21 +188,18 @@ namespace FDK
// t初期化( ESoundDeviceType.DirectSound, 0, 0, 0 );
//}
public void tInitialize( ESoundDeviceType soundDeviceType, int _nSoundDelayBASS, int _nSoundDelayExclusiveWASAPI, int _nSoundDelayASIO, int _nASIODevice, IntPtr handle )
{
public void tInitialize(ESoundDeviceType soundDeviceType, int _nSoundDelayBASS, int _nSoundDelayExclusiveWASAPI, int _nSoundDelayASIO, int _nASIODevice, IntPtr handle) {
//if ( !bInitialized )
{
tInitialize( soundDeviceType, _nSoundDelayBASS, _nSoundDelayExclusiveWASAPI, _nSoundDelayASIO, _nASIODevice );
tInitialize(soundDeviceType, _nSoundDelayBASS, _nSoundDelayExclusiveWASAPI, _nSoundDelayASIO, _nASIODevice);
//bInitialized = true;
}
}
public void tInitialize( ESoundDeviceType soundDeviceType, int _nSoundDelayBASS, int _nSoundDelayExclusiveWASAPI, int _nSoundDelayASIO, int _nASIODevice )
{
tInitialize( soundDeviceType, _nSoundDelayBASS, _nSoundDelayExclusiveWASAPI, _nSoundDelayASIO, _nASIODevice, false );
public void tInitialize(ESoundDeviceType soundDeviceType, int _nSoundDelayBASS, int _nSoundDelayExclusiveWASAPI, int _nSoundDelayASIO, int _nASIODevice) {
tInitialize(soundDeviceType, _nSoundDelayBASS, _nSoundDelayExclusiveWASAPI, _nSoundDelayASIO, _nASIODevice, false);
}
public void tInitialize( ESoundDeviceType soundDeviceType, int _nSoundDelayBASS, int _nSoundDelayExclusiveWASAPI, int _nSoundDelayASIO, int _nASIODevice, bool _bUseOSTimer )
{
public void tInitialize(ESoundDeviceType soundDeviceType, int _nSoundDelayBASS, int _nSoundDelayExclusiveWASAPI, int _nSoundDelayASIO, int _nASIODevice, bool _bUseOSTimer) {
//SoundDevice = null; // 後で再初期化することがあるので、null初期化はコンストラクタに回す
PlayTimer = null; // Global.Bass 依存(つまりユーザ依存)
nMixing = 0;
@ -256,8 +221,7 @@ namespace FDK
};
int initialDevice;
switch ( soundDeviceType )
{
switch (soundDeviceType) {
case ESoundDeviceType.Bass:
initialDevice = 0;
break;
@ -274,39 +238,32 @@ namespace FDK
initialDevice = 4;
break;
}
for ( SoundDeviceType = ESoundDeviceTypes[ initialDevice ]; ; SoundDeviceType = ESoundDeviceTypes[ ++initialDevice ] )
{
try
{
for (SoundDeviceType = ESoundDeviceTypes[initialDevice]; ; SoundDeviceType = ESoundDeviceTypes[++initialDevice]) {
try {
tReloadSoundDeviceAndSound();
break;
}
catch ( Exception e )
{
Trace.TraceError( e.ToString() );
Trace.TraceError( "例外が発生しましたが処理を継続します。 (2609806d-23e8-45c2-9389-b427e80915bc)" );
if ( ESoundDeviceTypes[ initialDevice ] == ESoundDeviceType.Unknown )
{
Trace.TraceError( string.Format( "サウンドデバイスの初期化に失敗しました。" ) );
} catch (Exception e) {
Trace.TraceError(e.ToString());
Trace.TraceError("例外が発生しましたが処理を継続します。 (2609806d-23e8-45c2-9389-b427e80915bc)");
if (ESoundDeviceTypes[initialDevice] == ESoundDeviceType.Unknown) {
Trace.TraceError(string.Format("サウンドデバイスの初期化に失敗しました。"));
break;
}
}
}
if ( soundDeviceType == ESoundDeviceType.Bass
if (soundDeviceType == ESoundDeviceType.Bass
|| soundDeviceType == ESoundDeviceType.ExclusiveWASAPI
|| soundDeviceType == ESoundDeviceType.SharedWASAPI
|| soundDeviceType == ESoundDeviceType.ASIO )
{
|| soundDeviceType == ESoundDeviceType.ASIO) {
//Bass.BASS_SetConfig( BASSConfig.BASS_CONFIG_UPDATETHREADS, 4 );
//Bass.BASS_SetConfig( BASSConfig.BASS_CONFIG_UPDATEPERIOD, 0 );
Trace.TraceInformation( "BASS_CONFIG_UpdatePeriod=" + Bass.GetConfig( Configuration.UpdatePeriod ) );
Trace.TraceInformation( "BASS_CONFIG_UpdateThreads=" + Bass.GetConfig( Configuration.UpdateThreads ) );
Trace.TraceInformation("BASS_CONFIG_UpdatePeriod=" + Bass.GetConfig(Configuration.UpdatePeriod));
Trace.TraceInformation("BASS_CONFIG_UpdateThreads=" + Bass.GetConfig(Configuration.UpdateThreads));
}
}
public void tDisableUpdateBufferAutomatically()
{
public void tDisableUpdateBufferAutomatically() {
//Bass.BASS_SetConfig( BASSConfig.BASS_CONFIG_UPDATETHREADS, 0 );
//Bass.BASS_SetConfig( BASSConfig.BASS_CONFIG_UPDATEPERIOD, 0 );
@ -315,19 +272,16 @@ namespace FDK
}
public static void t終了()
{
public static void t終了() {
SoundDevice.Dispose();
PlayTimer.Dispose(); // Global.Bass を解放した後に解放すること。Global.Bass で参照されているため)
}
public static void tReloadSoundDeviceAndSound()
{
public static void tReloadSoundDeviceAndSound() {
#region [ ]
//-----------------
if ( SoundDevice != null )
{
if (SoundDevice != null) {
// すでに生成済みのサウンドがあれば初期状態に戻す。
CSound.tResetAllSound(); // リソースは解放するが、CSoundのインスタンスは残す。
@ -343,65 +297,58 @@ namespace FDK
#region [ ]
//-----------------
switch ( SoundDeviceType )
{
switch (SoundDeviceType) {
case ESoundDeviceType.Bass:
SoundDevice = new CSoundDeviceBASS( SoundDelayBASS, SoundUpdatePeriodBASS );
SoundDevice = new CSoundDeviceBASS(SoundDelayBASS, SoundUpdatePeriodBASS);
break;
case ESoundDeviceType.ExclusiveWASAPI:
SoundDevice = new CSoundDeviceWASAPI( CSoundDeviceWASAPI.EWASAPIMode.Exclusion, SoundDelayExclusiveWASAPI, SoundUpdatePeriodExclusiveWASAPI );
SoundDevice = new CSoundDeviceWASAPI(CSoundDeviceWASAPI.EWASAPIMode.Exclusion, SoundDelayExclusiveWASAPI, SoundUpdatePeriodExclusiveWASAPI);
break;
case ESoundDeviceType.SharedWASAPI:
SoundDevice = new CSoundDeviceWASAPI( CSoundDeviceWASAPI.EWASAPIMode.Share, SoundDelaySharedWASAPI, SoundUpdatePeriodSharedWASAPI );
SoundDevice = new CSoundDeviceWASAPI(CSoundDeviceWASAPI.EWASAPIMode.Share, SoundDelaySharedWASAPI, SoundUpdatePeriodSharedWASAPI);
break;
case ESoundDeviceType.ASIO:
SoundDevice = new CSoundDeviceASIO( SoundDelayASIO, ASIODevice );
SoundDevice = new CSoundDeviceASIO(SoundDelayASIO, ASIODevice);
break;
default:
throw new Exception( string.Format( "未対応の SoundDeviceType です。[{0}]", SoundDeviceType.ToString() ) );
throw new Exception(string.Format("未対応の SoundDeviceType です。[{0}]", SoundDeviceType.ToString()));
}
//-----------------
#endregion
#region [ ]
//-----------------
PlayTimer = new CSoundTimer( SoundDevice );
PlayTimer = new CSoundTimer(SoundDevice);
//-----------------
#endregion
SoundDevice.nMasterVolume = _nMasterVolume; // サウンドデバイスに対して、マスターボリュームを再設定する
CSound.tReloadSound( SoundDevice ); // すでに生成済みのサウンドがあれば作り直す。
CSound.tReloadSound(SoundDevice); // すでに生成済みのサウンドがあれば作り直す。
}
public CSound tCreateSound( string filename, ESoundGroup soundGroup )
{
if( !File.Exists( filename ) )
{
public CSound tCreateSound(string filename, ESoundGroup soundGroup) {
if (!File.Exists(filename)) {
Trace.TraceWarning($"[i18n] File does not exist: {filename}");
return null;
}
if ( SoundDeviceType == ESoundDeviceType.Unknown )
{
throw new Exception( string.Format( "未対応の SoundDeviceType です。[{0}]", SoundDeviceType.ToString() ) );
if (SoundDeviceType == ESoundDeviceType.Unknown) {
throw new Exception(string.Format("未対応の SoundDeviceType です。[{0}]", SoundDeviceType.ToString()));
}
return SoundDevice.tCreateSound( filename, soundGroup );
return SoundDevice.tCreateSound(filename, soundGroup);
}
private static DateTime lastUpdateTime = DateTime.MinValue;
public void tDisposeSound( CSound csound )
{
csound?.tDispose( true ); // インスタンスは存続→破棄にする。
public void tDisposeSound(CSound csound) {
csound?.tDispose(true); // インスタンスは存続→破棄にする。
}
public string GetCurrentSoundDeviceType()
{
switch ( SoundDeviceType )
{
public string GetCurrentSoundDeviceType() {
switch (SoundDeviceType) {
case ESoundDeviceType.Bass:
return "Bass";
case ESoundDeviceType.ExclusiveWASAPI:
@ -415,23 +362,19 @@ namespace FDK
}
}
public void AddMixer( CSound cs, double db再生速度, bool _b演奏終了後も再生が続くチップである )
{
public void AddMixer(CSound cs, double db再生速度, bool _b演奏終了後も再生が続くチップである) {
cs.b演奏終了後も再生が続くチップである = _b演奏終了後も再生が続くチップである;
cs.PlaySpeed = db再生速度;
cs.AddBassSoundFromMixer();
}
public void AddMixer( CSound cs, double db再生速度 )
{
public void AddMixer(CSound cs, double db再生速度) {
cs.PlaySpeed = db再生速度;
cs.AddBassSoundFromMixer();
}
public void AddMixer( CSound cs )
{
public void AddMixer(CSound cs) {
cs.AddBassSoundFromMixer();
}
public void RemoveMixer( CSound cs )
{
public void RemoveMixer(CSound cs) {
cs.tRemoveSoundFromMixer();
}
}

View File

@ -1,15 +1,8 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using SkiaSharp;
namespace FDK
{
public static class BitmapUtil
{
namespace FDK {
public static class BitmapUtil {
// 定数
public const uint DIB_PAL_COLORS = 1;
@ -18,9 +11,8 @@ namespace FDK
// 構造体
[StructLayout( LayoutKind.Sequential, Pack = 1 )]
public struct BITMAPFILEHEADER
{
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct BITMAPFILEHEADER {
public ushort bfType;
public uint bfSize;
public ushort bfReserved1;
@ -28,9 +20,8 @@ namespace FDK
public uint bfOffBits;
}
[StructLayout( LayoutKind.Sequential, Pack = 1 )]
public struct BITMAPINFOHEADER
{
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct BITMAPINFOHEADER {
public const int BI_RGB = 0;
public uint biSize構造体のサイズ;
public int biWidthビットマップの幅dot;
@ -48,25 +39,24 @@ namespace FDK
// メソッド
public static unsafe SKBitmap ToBitmap( IntPtr pBITMAPINFOHEADER )
{
public static unsafe SKBitmap ToBitmap(IntPtr pBITMAPINFOHEADER) {
BITMAPFILEHEADER bitmapfileheader;
BITMAPINFOHEADER* bitmapinfoheaderPtr = (BITMAPINFOHEADER*) pBITMAPINFOHEADER;
BITMAPINFOHEADER* bitmapinfoheaderPtr = (BITMAPINFOHEADER*)pBITMAPINFOHEADER;
bitmapfileheader.bfType = 0x4d42;
bitmapfileheader.bfOffBits = (uint) ( sizeof( BITMAPFILEHEADER ) + sizeof( BITMAPINFOHEADER ) );
bitmapfileheader.bfOffBits = (uint)(sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER));
bitmapfileheader.bfSize = bitmapfileheader.bfOffBits + bitmapinfoheaderPtr->biSizeImage画像イメージのサイズ;
MemoryStream output = new MemoryStream();
BinaryWriter writer = new BinaryWriter( output );
byte[] destination = new byte[ sizeof( BITMAPFILEHEADER ) ];
Marshal.Copy( (IntPtr) ( &bitmapfileheader ), destination, 0, destination.Length );
writer.Write( destination );
destination = new byte[ sizeof( BITMAPINFOHEADER ) ];
Marshal.Copy( pBITMAPINFOHEADER, destination, 0, destination.Length );
writer.Write( destination );
destination = new byte[ bitmapinfoheaderPtr->biSizeImage画像イメージのサイズ ];
BinaryWriter writer = new BinaryWriter(output);
byte[] destination = new byte[sizeof(BITMAPFILEHEADER)];
Marshal.Copy((IntPtr)(&bitmapfileheader), destination, 0, destination.Length);
writer.Write(destination);
destination = new byte[sizeof(BITMAPINFOHEADER)];
Marshal.Copy(pBITMAPINFOHEADER, destination, 0, destination.Length);
writer.Write(destination);
destination = new byte[bitmapinfoheaderPtr->biSizeImage画像イメージのサイズ];
bitmapinfoheaderPtr++;
Marshal.Copy( (IntPtr) bitmapinfoheaderPtr, destination, 0, destination.Length );
writer.Write( destination );
Marshal.Copy((IntPtr)bitmapinfoheaderPtr, destination, 0, destination.Length);
writer.Write(destination);
writer.Flush();
writer.BaseStream.Position = 0L;
return null;

View File

@ -1,59 +1,44 @@
using System;
using System.Drawing;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.Runtime.InteropServices;
using FFmpeg.AutoGen;
namespace FDK
{
public class CDecodedFrame : IDisposable
{
public CDecodedFrame(Size texsize)
{
namespace FDK {
public class CDecodedFrame : IDisposable {
public CDecodedFrame(Size texsize) {
this.Using = false;
this.TexSize = texsize;
this.TexPointer = Marshal.AllocHGlobal(texsize.Width * TexSize.Height * 4);
}
public bool Using
{
public bool Using {
get;
private set;
}
public double Time
{
public double Time {
get;
private set;
}
public IntPtr TexPointer
{
public IntPtr TexPointer {
get;
private set;
}
public Size TexSize
{
public Size TexSize {
get;
private set;
}
public unsafe CDecodedFrame UpdateFrame(double time, AVFrame* frame)
{
public unsafe CDecodedFrame UpdateFrame(double time, AVFrame* frame) {
this.Time = time;
Buffer.MemoryCopy(frame->data[0], (void*)this.TexPointer, frame->linesize[0] * frame->height, frame->linesize[0] * frame->height);
this.Using = true;
return this;
}
public void RemoveFrame()
{
public void RemoveFrame() {
this.Using = false;
}
public void Dispose()
{
public void Dispose() {
this.Using = false;
Marshal.FreeHGlobal(this.TexPointer);
}

View File

@ -1,20 +1,13 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
using System.Drawing;
using System.Runtime.InteropServices;
using FFmpeg.AutoGen;
namespace FDK
{
public unsafe class CFrameConverter : IDisposable
{
public CFrameConverter(Size FrameSize, AVPixelFormat pix_fmt)
{
namespace FDK {
public unsafe class CFrameConverter : IDisposable {
public CFrameConverter(Size FrameSize, AVPixelFormat pix_fmt) {
this.FrameSize = FrameSize;
if (pix_fmt != CVPxfmt)
{
if (pix_fmt != CVPxfmt) {
convert_context = ffmpeg.sws_getContext(
FrameSize.Width,
FrameSize.Height,
@ -33,10 +26,8 @@ namespace FDK
ffmpeg.av_image_fill_arrays(ref _dstData, ref _dstLinesize, (byte*)_convertedFrameBufferPtr, CVPxfmt, FrameSize.Width, FrameSize.Height, 1);
}
public AVFrame* Convert(AVFrame* framep)
{
if (this.IsConvert)
{
public AVFrame* Convert(AVFrame* framep) {
if (this.IsConvert) {
ffmpeg.sws_scale(convert_context, framep->data, framep->linesize, 0, framep->height, _dstData, _dstLinesize);
AVFrame* tmp = ffmpeg.av_frame_alloc();
@ -51,15 +42,12 @@ namespace FDK
ffmpeg.av_frame_unref(framep);
return tmp;
}
else
{
} else {
return framep;
}
}
public void Dispose()
{
public void Dispose() {
Marshal.FreeHGlobal(_convertedFrameBufferPtr);
ffmpeg.sws_freeContext(convert_context);
}

View File

@ -1,18 +1,6 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Diagnostics;
using Silk.NET.Maths;
using Rectangle = System.Drawing.Rectangle;
using Rectangle = System.Drawing.Rectangle;
using Point = System.Drawing.Point;
using Color = System.Drawing.Color;
namespace FDK
{
namespace FDK {
/// <summary>
/// 縦長_横長の画像を自動で折りたたんでテクスチャ化するCTexture。
/// 例えば、768x30 のテクスチャファイルが入力されたら、
@ -20,8 +8,7 @@ namespace FDK
/// 必要に応じて、正方形テクスチャにもする。
/// また、t2D描画は、その折り返しを加味して実行する。
/// </summary>
public class CTextureAf : CTexture, IDisposable
{
public class CTextureAf : CTexture, IDisposable {
/// <summary>
/// <para>画像ファイルからテクスチャを生成する。</para>
@ -36,18 +23,16 @@ namespace FDK
/// <param name="b黒を透過する">画像の黒0xFFFFFFFFを透過させるなら true。</param>
/// <param name="pool">テクスチャの管理方法。</param>
/// <exception cref="CTextureCreateFailedException">テクスチャの作成に失敗しました。</exception>
public CTextureAf( string strファイル名, bool b黒を透過する )
{
MakeTexture( strファイル名, b黒を透過する );
public CTextureAf(string strファイル名, bool b黒を透過する) {
MakeTexture(strファイル名, b黒を透過する);
}
public new void MakeTexture( string strファイル名, bool b黒を透過する )
{
if ( !File.Exists( strファイル名 ) ) // #27122 2012.1.13 from: ImageInformation では FileNotFound 例外は返ってこないので、ここで自分でチェックする。わかりやすいログのために。
throw new FileNotFoundException( string.Format( "ファイルが存在しません。\n[{0}]", strファイル名 ) );
public new void MakeTexture(string strファイル名, bool b黒を透過する) {
if (!File.Exists(strファイル名)) // #27122 2012.1.13 from: ImageInformation では FileNotFound 例外は返ってこないので、ここで自分でチェックする。わかりやすいログのために。
throw new FileNotFoundException(string.Format("ファイルが存在しません。\n[{0}]", strファイル名));
base.MakeTexture(strファイル名, b黒を透過する);
}
@ -60,26 +45,23 @@ namespace FDK
/// <param name="height"></param>
/// <param name="foldtimes"></param>
/// <returns></returns>
private bool GetFoldedTextureSize( ref int width, ref int height, out int foldtimes )
{
private bool GetFoldedTextureSize(ref int width, ref int height, out int foldtimes) {
int orgWidth = width, orgHeight = height;
#region [ widthが2 ]
int pow = 1;
while ( orgWidth >= pow )
{
while (orgWidth >= pow) {
pow *= 2;
}
pow /= 2;
#endregion
#region [ 22 ]
foldtimes = ( orgWidth == pow ) ? 0 : 1; // 2のべき乗からの溢れがあれば、まずその溢れ分で1回折り畳む
if ( foldtimes != 0 )
{
//Debug.WriteLine( "powちょうどではないので、溢れあり。まずは1回折りたたむ。" );
foldtimes = (orgWidth == pow) ? 0 : 1; // 2のべき乗からの溢れがあれば、まずその溢れ分で1回折り畳む
if (foldtimes != 0) {
//Debug.WriteLine( "powちょうどではないので、溢れあり。まずは1回折りたたむ。" );
// 試しに、widthをpowに切り詰め、1回折り返してみる。
// width>heightを維持しているなら、テクスチャサイズはより最適な状態になったということになる。
if ( pow <= orgHeight * 2 ) // 新width > 新heightを維持できなくなったなら
if (pow <= orgHeight * 2) // 新width > 新heightを維持できなくなったなら
{ // 最適化不可とみなし、baseの処理に委ねる
return false;
}
@ -88,15 +70,14 @@ namespace FDK
#region [ width > height ]
width = pow;
height = orgHeight * 2; // 初期値1回折りたたんだ状態
do
{
do {
width /= 2;
foldtimes = ( orgWidth / width ) + ( ( orgWidth % width > 0 ) ? 1 : 0 ) - 1;
height = orgHeight * ( foldtimes + 1 );
} while ( width > height );
foldtimes = (orgWidth / width) + ((orgWidth % width > 0) ? 1 : 0) - 1;
height = orgHeight * (foldtimes + 1);
} while (width > height);
width *= 2;
foldtimes = ( orgWidth / width ) + ( ( orgWidth % width > 0 ) ? 1 : 0 ) - 1;
height = orgHeight * ( foldtimes + 1 );
foldtimes = (orgWidth / width) + ((orgWidth % width > 0) ? 1 : 0) - 1;
height = orgHeight * (foldtimes + 1);
#endregion
return true;
@ -110,69 +91,58 @@ namespace FDK
/// <param name="device">Direct3D9 デバイス。</param>
/// <param name="x">描画位置(テクスチャの左上位置の X 座標[dot])。</param>
/// <param name="y">描画位置(テクスチャの左上位置の Y 座標[dot])。</param>
public new void t2D描画( int x, int y )
{
public new void t2D描画(int x, int y) {
#if TEST_FOLDTEXTURE
base.t2D描画( x, y, 1f, rc全画像 );
#else
for ( int n = 0; n <= _foldtimes; n++ )
{
for (int n = 0; n <= _foldtimes; n++) {
Rectangle r;
if ( b横長のテクスチャである )
{
if (b横長のテクスチャである) {
int currentHeight = n * _orgHeight;
r = new Rectangle( 0, currentHeight, this.rc全画像.Width, _orgHeight );
base.t2D描画( x + n * this.rc全画像.Width, y, 1f, r );
}
else
{
r = new Rectangle(0, currentHeight, this.rc全画像.Width, _orgHeight);
base.t2D描画(x + n * this.rc全画像.Width, y, 1f, r);
} else {
int currentWidth = n * _orgWidth;
r = new Rectangle( currentWidth, 0, _orgWidth, this.rc全画像.Height );
base.t2D描画( x, y + n * this.rc全画像.Height, 1f, r );
r = new Rectangle(currentWidth, 0, _orgWidth, this.rc全画像.Height);
base.t2D描画(x, y + n * this.rc全画像.Height, 1f, r);
}
}
#endif
}
public new void t2D描画( int x, int y, Rectangle rc )
{
public new void t2D描画(int x, int y, Rectangle rc) {
Rectangle r;
if ( b横長のテクスチャである )
{
if (b横長のテクスチャである) {
int beginFold = rc.X / this.rc全画像.Width;
int endFold = ( rc.X + rc.Width ) / rc全画像.Width;
for ( int i = beginFold; i <= endFold; i++ )
{
if ( i > _foldtimes ) break;
int endFold = (rc.X + rc.Width) / rc全画像.Width;
for (int i = beginFold; i <= endFold; i++) {
if (i > _foldtimes) break;
int newRcY = i * _orgHeight + rc.Y;
int newRcX = ( i == beginFold ) ? ( rc.X % this.rc全画像.Width ) : 0;
int newRcWidth = ( newRcX + rc.Width > rc全画像.Width ) ? rc全画像.Width - newRcX : rc.Width;
int newRcX = (i == beginFold) ? (rc.X % this.rc全画像.Width) : 0;
int newRcWidth = (newRcX + rc.Width > rc全画像.Width) ? rc全画像.Width - newRcX : rc.Width;
r = new Rectangle( newRcX, newRcY, newRcWidth, rc.Height );
base.t2D描画( x, y, 1f, r );
r = new Rectangle(newRcX, newRcY, newRcWidth, rc.Height);
base.t2D描画(x, y, 1f, r);
int deltaX = ( i == beginFold ) ? ( i + 1 ) * rc全画像.Width - rc.X : rc全画像.Width;
int deltaX = (i == beginFold) ? (i + 1) * rc全画像.Width - rc.X : rc全画像.Width;
int newWidth = rc.Width - deltaX;
x += deltaX;
rc.Width = newWidth;
}
}
else
{
} else {
int beginFold = rc.Y / this.rc全画像.Height;
int endFold = ( rc.Y + rc.Height ) / rc全画像.Height;
for ( int i = beginFold; i <= endFold; i++ )
{
if ( i > _foldtimes ) break;
int endFold = (rc.Y + rc.Height) / rc全画像.Height;
for (int i = beginFold; i <= endFold; i++) {
if (i > _foldtimes) break;
int newRcX = i * _orgWidth + rc.X;
int newRcY = ( i == beginFold ) ? ( rc.Y % this.rc全画像.Height ) : 0;
int newRcHeight = ( newRcY + rc.Height > rc全画像.Height ) ? rc全画像.Height - newRcY : rc.Height;
int newRcY = (i == beginFold) ? (rc.Y % this.rc全画像.Height) : 0;
int newRcHeight = (newRcY + rc.Height > rc全画像.Height) ? rc全画像.Height - newRcY : rc.Height;
r = new Rectangle( newRcX, newRcY, rc.Width, newRcHeight );
base.t2D描画( x, y, 1f, r );
r = new Rectangle(newRcX, newRcY, rc.Width, newRcHeight);
base.t2D描画(x, y, 1f, r);
int deltaY = ( i == beginFold ) ? ( i + 1 ) * rc全画像.Height - rc.Y : rc全画像.Height;
int deltaY = (i == beginFold) ? (i + 1) * rc全画像.Height - rc.Y : rc全画像.Height;
int newHeight = rc.Height - deltaY;
y += deltaY;
rc.Height = newHeight;
@ -180,13 +150,11 @@ namespace FDK
}
}
public new void t2D描画( float x, float y )
{
t2D描画( (int) x, (int) y );
public new void t2D描画(float x, float y) {
t2D描画((int)x, (int)y);
}
public void t2D描画( float x, float y, Rectangle rc )
{
t2D描画( (int) x, (int) y, rc );
public void t2D描画(float x, float y, Rectangle rc) {
t2D描画((int)x, (int)y, rc);
}
#region [ private ]

View File

@ -1,29 +1,20 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Serialization;
using System.Runtime.Serialization;
namespace FDK
{
namespace FDK {
/// <summary>
/// テクスチャの作成に失敗しました。
/// </summary>
public class CTextureCreateFailedException : Exception
{
public CTextureCreateFailedException()
{
public class CTextureCreateFailedException : Exception {
public CTextureCreateFailedException() {
}
public CTextureCreateFailedException( string message )
: base( message )
{
public CTextureCreateFailedException(string message)
: base(message) {
}
public CTextureCreateFailedException( SerializationInfo info, StreamingContext context )
: base( info, context )
{
public CTextureCreateFailedException(SerializationInfo info, StreamingContext context)
: base(info, context) {
}
public CTextureCreateFailedException( string message, Exception innerException )
: base( message, innerException )
{
public CTextureCreateFailedException(string message, Exception innerException)
: base(message, innerException) {
}
}
}

View File

@ -1,35 +1,21 @@
using System;
using System.IO;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Collections.Generic;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Collections.Concurrent;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using FFmpeg.AutoGen;
using System.Threading;
using Size = System.Drawing.Size;
namespace FDK
{
namespace FDK {
/// <summary>
/// ビデオのデコードをするクラス
/// ファイル名・nullのCTextureをもらえれば、勝手に、CTextureに映像を格納して返す。
/// 演奏とは別のタイマーを使用しているので、ずれる可能性がある。
/// </summary>
public unsafe class CVideoDecoder : IDisposable
{
public CVideoDecoder(string filename)
{
public unsafe class CVideoDecoder : IDisposable {
public CVideoDecoder(string filename) {
if (!File.Exists(filename))
throw new FileNotFoundException(filename + " not found...");
format_context = ffmpeg.avformat_alloc_context();
fixed (AVFormatContext** format_contexttmp = &format_context)
{
fixed (AVFormatContext** format_contexttmp = &format_context) {
if (ffmpeg.avformat_open_input(format_contexttmp, filename, null, null) != 0)
throw new FileLoadException("avformat_open_input failed\n");
@ -37,10 +23,8 @@ namespace FDK
throw new FileLoadException("avformat_find_stream_info failed\n");
// find audio stream
for (int i = 0; i < (int)format_context->nb_streams; i++)
{
if (format_context->streams[i]->codecpar->codec_type == AVMediaType.AVMEDIA_TYPE_VIDEO)
{
for (int i = 0; i < (int)format_context->nb_streams; i++) {
if (format_context->streams[i]->codecpar->codec_type == AVMediaType.AVMEDIA_TYPE_VIDEO) {
video_stream = format_context->streams[i];
break;
}
@ -76,8 +60,7 @@ namespace FDK
}
}
public void Dispose()
{
public void Dispose() {
bDrawing = false;
close = true;
cts?.Cancel();
@ -88,8 +71,7 @@ namespace FDK
if (ffmpeg.avcodec_close(codec_context) < 0)
Trace.TraceError("codec context close error.");
video_stream = null;
fixed (AVFormatContext** format_contexttmp = &format_context)
{
fixed (AVFormatContext** format_contexttmp = &format_context) {
ffmpeg.avformat_close_input(format_contexttmp);
}
if (lastTexture != null)
@ -98,8 +80,7 @@ namespace FDK
frame.Dispose();
}
public void Start()
{
public void Start() {
CTimer.Reset();
CTimer.Resume();
this.bPlaying = true;
@ -107,40 +88,31 @@ namespace FDK
}
public void PauseControl()
{
if (this.bPlaying)
{
public void PauseControl() {
if (this.bPlaying) {
CTimer.Pause();
this.bPlaying = false;
}
else
{
} else {
CTimer.Resume();
this.bPlaying = true;
}
}
public void Stop()
{
public void Stop() {
CTimer.Pause();
this.bPlaying = false;
bDrawing = false;
}
public void InitRead()
{
if (!bqueueinitialized)
{
public void InitRead() {
if (!bqueueinitialized) {
this.Seek(0);
bqueueinitialized = true;
}
else
} else
Trace.TraceError("The class has already been initialized.\n");
}
public void Seek(long timestampms)
{
public void Seek(long timestampms) {
cts?.Cancel();
while (DS != DecodingState.Stopped) ;
if (ffmpeg.av_seek_frame(format_context, video_stream->index, timestampms, ffmpeg.AVSEEK_FLAG_BACKWARD) < 0)
@ -156,21 +128,16 @@ namespace FDK
lastTexture = new CTexture(FrameSize.Width, FrameSize.Height);
}
public void GetNowFrame(ref CTexture Texture)
{
if (this.bPlaying && decodedframes.Count != 0)
{
public void GetNowFrame(ref CTexture Texture) {
if (this.bPlaying && decodedframes.Count != 0) {
CTimer.Update();
if (decodedframes.TryPeek(out CDecodedFrame frame))
{
while (frame.Time <= (CTimer.NowTimeMs * _dbPlaySpeed))
{
if (decodedframes.TryPeek(out CDecodedFrame frame)) {
while (frame.Time <= (CTimer.NowTimeMs * _dbPlaySpeed)) {
if (decodedframes.TryDequeue(out CDecodedFrame cdecodedframe)) {
if (decodedframes.Count != 0)
if (decodedframes.TryPeek(out frame))
if (frame.Time <= (CTimer.NowTimeMs * _dbPlaySpeed))
{
if (frame.Time <= (CTimer.NowTimeMs * _dbPlaySpeed)) {
cdecodedframe.RemoveFrame();
continue;
}
@ -197,24 +164,19 @@ namespace FDK
}
private void EnqueueFrames()
{
if (DS != DecodingState.Running && !close)
{
private void EnqueueFrames() {
if (DS != DecodingState.Running && !close) {
cts = new CancellationTokenSource();
Task.Factory.StartNew(() => EnqueueOneFrame());
}
}
private void EnqueueOneFrame()
{
private void EnqueueOneFrame() {
DS = DecodingState.Running;
AVFrame* frame = ffmpeg.av_frame_alloc();
AVPacket* packet = ffmpeg.av_packet_alloc();
try
{
while (true)
{
try {
while (true) {
if (cts.IsCancellationRequested || close)
return;
@ -223,14 +185,10 @@ namespace FDK
{
int error = ffmpeg.av_read_frame(format_context, packet);
if (error >= 0)
{
if (packet->stream_index == video_stream->index)
{
if (ffmpeg.avcodec_send_packet(codec_context, packet) >= 0)
{
if (ffmpeg.avcodec_receive_frame(codec_context, frame) == 0)
{
if (error >= 0) {
if (packet->stream_index == video_stream->index) {
if (ffmpeg.avcodec_send_packet(codec_context, packet) >= 0) {
if (ffmpeg.avcodec_receive_frame(codec_context, frame) == 0) {
AVFrame* outframe = null;
outframe = frameconv.Convert(frame);
@ -246,26 +204,18 @@ namespace FDK
//2020/10/27 Mr-Ojii packetが解放されない周回があった問題を修正。
ffmpeg.av_packet_unref(packet);
}
else if (error == ffmpeg.AVERROR_EOF)
{
} else if (error == ffmpeg.AVERROR_EOF) {
return;
}
}
else
{
} else {
//ポーズ中に無限ループに入り、CPU使用率が異常に高くなってしまうため、1ms待つ。
//ネットを調べると、await Task.Delay()を使えというお話が出てくるが、unsafeなので、使えない
Thread.Sleep(1);
}
}
}
catch (Exception e)
{
} catch (Exception e) {
Trace.TraceError(e.ToString());
}
finally
{
} finally {
ffmpeg.av_packet_free(&packet);
ffmpeg.av_frame_unref(frame);
ffmpeg.av_free(frame);
@ -273,42 +223,32 @@ namespace FDK
}
}
public CDecodedFrame PickUnusedDcodedFrame()
{
public CDecodedFrame PickUnusedDcodedFrame() {
for (int i = 0; i < framelist.Length; i++) {
if (framelist[i].Using == false)
{
if (framelist[i].Using == false) {
return framelist[i];
}
}
return null;
}
public Size FrameSize
{
public Size FrameSize {
get;
private set;
}
public double Duration
{
public double Duration {
get;
private set;
}
public double dbPlaySpeed
{
get
{
public double dbPlaySpeed {
get {
return this._dbPlaySpeed;
}
set
{
if (value > 0)
{
set {
if (value > 0) {
this._dbPlaySpeed = value;
}
else
{
} else {
throw new ArgumentOutOfRangeException();
}
}
@ -325,8 +265,7 @@ namespace FDK
private CancellationTokenSource cts;
private CDecodedFrame[] framelist = new CDecodedFrame[6];
private DecodingState DS = DecodingState.Stopped;
private enum DecodingState
{
private enum DecodingState {
Stopped,
Running
}

View File

@ -1,34 +1,27 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics;
using SkiaSharp;
using Color = System.Drawing.Color;
namespace FDK
{
namespace FDK {
/// <summary>
/// 高速描画版のCFontRendererクラス。
/// といっても、一度レンダリングした結果をキャッシュして使いまわしているだけ。
/// </summary>
public class CCachedFontRenderer : CFontRenderer
{
public class CCachedFontRenderer : CFontRenderer {
#region [ ]
public CCachedFontRenderer( string fontpath, int pt, CFontRenderer.FontStyle style )
{
Initialize( fontpath, pt, style );
public CCachedFontRenderer(string fontpath, int pt, CFontRenderer.FontStyle style) {
Initialize(fontpath, pt, style);
}
public CCachedFontRenderer( string fontpath, int pt )
{
Initialize( fontpath, pt, CFontRenderer.FontStyle.Regular );
public CCachedFontRenderer(string fontpath, int pt) {
Initialize(fontpath, pt, CFontRenderer.FontStyle.Regular);
}
#endregion
#region [ ]
protected new void Initialize( string fontpath, int pt, CFontRenderer.FontStyle style )
{
protected new void Initialize(string fontpath, int pt, CFontRenderer.FontStyle style) {
this.bDisposed_CCachedFontRenderer = false;
this.listFontCache = new List<FontCache>();
base.Initialize( fontpath, pt, style );
base.Initialize(fontpath, pt, style);
}
#endregion
@ -41,9 +34,8 @@ namespace FDK
/// <param name="fontColor">描画色</param>
/// <param name="edgeColor">縁取色</param>
/// <returns>描画済テクスチャ</returns>
public new SKBitmap DrawText( string drawstr, Color fontColor, Color edgeColor, Color? secondEdgeColor, int edge_Ratio, bool keepCenter = false)
{
return DrawText( drawstr, DrawMode.Edge, fontColor, edgeColor, secondEdgeColor, Color.White, Color.White, edge_Ratio, keepCenter );
public new SKBitmap DrawText(string drawstr, Color fontColor, Color edgeColor, Color? secondEdgeColor, int edge_Ratio, bool keepCenter = false) {
return DrawText(drawstr, DrawMode.Edge, fontColor, edgeColor, secondEdgeColor, Color.White, Color.White, edge_Ratio, keepCenter);
}
/// <summary>
@ -53,9 +45,8 @@ namespace FDK
/// <param name="fontColor">描画色</param>
/// <param name="edgeColor">縁取色</param>
/// <returns>描画済テクスチャ</returns>
public SKBitmap DrawText( string drawstr, Color fontColor, Color edgeColor, Color? secondEdgeColor, DrawMode dMode, int edge_Ratio, bool keepCenter = false)
{
return DrawText( drawstr, dMode, fontColor, edgeColor, secondEdgeColor, Color.White, Color.White, edge_Ratio, keepCenter );
public SKBitmap DrawText(string drawstr, Color fontColor, Color edgeColor, Color? secondEdgeColor, DrawMode dMode, int edge_Ratio, bool keepCenter = false) {
return DrawText(drawstr, dMode, fontColor, edgeColor, secondEdgeColor, Color.White, Color.White, edge_Ratio, keepCenter);
}
/// <summary>
@ -67,9 +58,8 @@ namespace FDK
/// <param name="gradationTopColor">グラデーション 上側の色</param>
/// <param name="gradationBottomColor">グラデーション 下側の色</param>
/// <returns>描画済テクスチャ</returns>
public new SKBitmap DrawText( string drawstr, Color fontColor, Color edgeColor, Color? secondEdgeColor, Color gradationTopColor, Color gradataionBottomColor, int edge_Ratio, bool keepCenter = false )
{
return DrawText( drawstr, DrawMode.Edge | DrawMode.Gradation, fontColor, edgeColor, secondEdgeColor, gradationTopColor, gradataionBottomColor, edge_Ratio, keepCenter );
public new SKBitmap DrawText(string drawstr, Color fontColor, Color edgeColor, Color? secondEdgeColor, Color gradationTopColor, Color gradataionBottomColor, int edge_Ratio, bool keepCenter = false) {
return DrawText(drawstr, DrawMode.Edge | DrawMode.Gradation, fontColor, edgeColor, secondEdgeColor, gradationTopColor, gradataionBottomColor, edge_Ratio, keepCenter);
}
/// <summary>
@ -81,19 +71,16 @@ namespace FDK
/// <param name="gradationTopColor">グラデーション 上側の色</param>
/// <param name="gradationBottomColor">グラデーション 下側の色</param>
/// <returns>描画済テクスチャ</returns>
public new SKBitmap DrawText_V( string drawstr, Color fontColor, Color edgeColor, Color? secondEdgeColor, int edge_Ratio, bool keepCenter = false )
{
public new SKBitmap DrawText_V(string drawstr, Color fontColor, Color edgeColor, Color? secondEdgeColor, int edge_Ratio, bool keepCenter = false) {
return DrawText_V(drawstr, DrawMode.Edge, fontColor, edgeColor, secondEdgeColor, Color.Black, Color.Black, edge_Ratio, keepCenter);
}
#endregion
protected new SKBitmap DrawText( string drawstr, DrawMode drawmode, Color fontColor, Color edgeColor, Color? secondEdgeColor, Color gradationTopColor, Color gradationBottomColor, int edge_Ratio, bool keepCenter = false )
{
protected new SKBitmap DrawText(string drawstr, DrawMode drawmode, Color fontColor, Color edgeColor, Color? secondEdgeColor, Color gradationTopColor, Color gradationBottomColor, int edge_Ratio, bool keepCenter = false) {
#region [ /? (?) ]
int index = listFontCache.FindIndex(
delegate( FontCache fontcache )
{
delegate (FontCache fontcache) {
return (
drawstr == fontcache.drawstr &&
drawmode == fontcache.drawmode &&
@ -108,12 +95,11 @@ namespace FDK
}
);
#endregion
if ( index < 0 )
{
if (index < 0) {
// キャッシュにヒットせず。
#region [ ]
FontCache fc = new FontCache();
fc.bmp = base.DrawText( drawstr, drawmode, fontColor, edgeColor, secondEdgeColor, gradationTopColor, gradationBottomColor, edge_Ratio, keepCenter);
fc.bmp = base.DrawText(drawstr, drawmode, fontColor, edgeColor, secondEdgeColor, gradationTopColor, gradationBottomColor, edge_Ratio, keepCenter);
fc.drawstr = drawstr;
fc.drawmode = drawmode;
fc.fontColor = fontColor;
@ -123,40 +109,34 @@ namespace FDK
fc.gradationBottomColor = gradationBottomColor;
fc.Vertical = false;
fc.KeepCenter = keepCenter;
listFontCache.Add( fc );
Debug.WriteLine( drawstr + ": Cacheにヒットせず。(cachesize=" + listFontCache.Count + ")" );
listFontCache.Add(fc);
Debug.WriteLine(drawstr + ": Cacheにヒットせず。(cachesize=" + listFontCache.Count + ")");
#endregion
#region [ ]
if ( listFontCache.Count > MAXCACHESIZE )
{
Debug.WriteLine( "Cache溢れ。" + listFontCache[ 0 ].drawstr + " を解放します。" );
if ( listFontCache[ 0 ].bmp != null )
{
listFontCache[ 0 ].bmp.Dispose();
if (listFontCache.Count > MAXCACHESIZE) {
Debug.WriteLine("Cache溢れ。" + listFontCache[0].drawstr + " を解放します。");
if (listFontCache[0].bmp != null) {
listFontCache[0].bmp.Dispose();
}
listFontCache.RemoveAt( 0 );
listFontCache.RemoveAt(0);
}
#endregion
// 呼び出し元のDispose()でキャッシュもDispose()されないように、Clone()で返す。
return listFontCache[ listFontCache.Count - 1 ].bmp.Copy();
}
else
{
Debug.WriteLine( drawstr + ": Cacheにヒット!! index=" + index );
return listFontCache[listFontCache.Count - 1].bmp.Copy();
} else {
Debug.WriteLine(drawstr + ": Cacheにヒット!! index=" + index);
#region [ ]
// 呼び出し元のDispose()でキャッシュもDispose()されないように、Clone()で返す。
return listFontCache[ index ].bmp.Copy();
return listFontCache[index].bmp.Copy();
#endregion
}
}
protected new SKBitmap DrawText_V(string drawstr, DrawMode drawmode, Color fontColor, Color edgeColor, Color? secondEdgeColor, Color gradationTopColor, Color gradationBottomColor, int edge_Ratio, bool keepCenter = false)
{
protected new SKBitmap DrawText_V(string drawstr, DrawMode drawmode, Color fontColor, Color edgeColor, Color? secondEdgeColor, Color gradationTopColor, Color gradationBottomColor, int edge_Ratio, bool keepCenter = false) {
#region [ /? (?) ]
int index = listFontCache.FindIndex(
delegate (FontCache fontcache)
{
delegate (FontCache fontcache) {
return (
drawstr == fontcache.drawstr &&
drawmode == fontcache.drawmode &&
@ -171,8 +151,7 @@ namespace FDK
}
);
#endregion
if ( index < 0 )
{
if (index < 0) {
// キャッシュにヒットせず。
#region [ ]
FontCache fc = new FontCache();
@ -185,48 +164,39 @@ namespace FDK
fc.gradationBottomColor = gradationBottomColor;
fc.Vertical = true;
fc.KeepCenter = keepCenter;
listFontCache.Add( fc );
Debug.WriteLine( drawstr + ": Cacheにヒットせず。(cachesize=" + listFontCache.Count + ")" );
listFontCache.Add(fc);
Debug.WriteLine(drawstr + ": Cacheにヒットせず。(cachesize=" + listFontCache.Count + ")");
#endregion
#region [ ]
if ( listFontCache.Count > MAXCACHESIZE )
{
Debug.WriteLine( "Cache溢れ。" + listFontCache[ 0 ].drawstr + " を解放します。" );
if ( listFontCache[ 0 ].bmp != null )
{
listFontCache[ 0 ].bmp.Dispose();
if (listFontCache.Count > MAXCACHESIZE) {
Debug.WriteLine("Cache溢れ。" + listFontCache[0].drawstr + " を解放します。");
if (listFontCache[0].bmp != null) {
listFontCache[0].bmp.Dispose();
}
listFontCache.RemoveAt( 0 );
listFontCache.RemoveAt(0);
}
#endregion
// 呼び出し元のDispose()でキャッシュもDispose()されないように、Clone()で返す。
return listFontCache[ listFontCache.Count - 1 ].bmp.Copy();
}
else
{
Debug.WriteLine( drawstr + ": Cacheにヒット!! index=" + index );
return listFontCache[listFontCache.Count - 1].bmp.Copy();
} else {
Debug.WriteLine(drawstr + ": Cacheにヒット!! index=" + index);
#region [ ]
// 呼び出し元のDispose()でキャッシュもDispose()されないように、Clone()で返す。
return listFontCache[ index ].bmp.Copy();
return listFontCache[index].bmp.Copy();
#endregion
}
}
#region [ IDisposable ]
//-----------------
public new void Dispose()
{
if (!this.bDisposed_CCachedFontRenderer)
{
if (listFontCache != null)
{
public new void Dispose() {
if (!this.bDisposed_CCachedFontRenderer) {
if (listFontCache != null) {
//Debug.WriteLine( "Disposing CCachedFontRenderer()" );
#region [ ]
foreach (FontCache bc in listFontCache)
{
if (bc.bmp != null)
{
foreach (FontCache bc in listFontCache) {
if (bc.bmp != null) {
bc.bmp.Dispose();
}
}
@ -248,8 +218,7 @@ namespace FDK
/// </summary>
private const int MAXCACHESIZE = 256;
private struct FontCache
{
private struct FontCache {
// public Font font;
public string drawstr;
public DrawMode drawmode;

View File

@ -1,40 +1,31 @@
using System;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using SkiaSharp;
using Color = System.Drawing.Color;
namespace FDK
{
namespace FDK {
public class CFontRenderer : IDisposable
{
public class CFontRenderer : IDisposable {
#region[static系]
public static void SetTextCorrectionX_Chara_List_Vertical(string[] list)
{
public static void SetTextCorrectionX_Chara_List_Vertical(string[] list) {
if (list != null)
CorrectionX_Chara_List_Vertical = list.Where(c => c != null).ToArray();
}
public static void SetTextCorrectionX_Chara_List_Value_Vertical(int[] list)
{
public static void SetTextCorrectionX_Chara_List_Value_Vertical(int[] list) {
if (list != null)
CorrectionX_Chara_List_Value_Vertical = list;
}
public static void SetTextCorrectionY_Chara_List_Vertical(string[] list)
{
public static void SetTextCorrectionY_Chara_List_Vertical(string[] list) {
if (list != null)
CorrectionY_Chara_List_Vertical = list.Where(c => c != null).ToArray();
}
public static void SetTextCorrectionY_Chara_List_Value_Vertical(int[] list)
{
public static void SetTextCorrectionY_Chara_List_Value_Vertical(int[] list) {
if (list != null)
CorrectionY_Chara_List_Value_Vertical = list;
}
public static void SetRotate_Chara_List_Vertical(string[] list)
{
public static void SetRotate_Chara_List_Vertical(string[] list) {
if (list != null)
Rotate_Chara_List_Vertical = list.Where(c => c != null).ToArray();
}
@ -49,16 +40,14 @@ namespace FDK
[Flags]
public enum DrawMode
{
public enum DrawMode {
Normal = 0,
Edge,
Gradation
}
[Flags]
public enum FontStyle
{
public enum FontStyle {
Regular = 0,
Bold,
Italic,
@ -66,10 +55,8 @@ namespace FDK
Strikeout
}
public static string DefaultFontName
{
get
{
public static string DefaultFontName {
get {
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
return "MS UI Gothic";
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
@ -79,100 +66,78 @@ namespace FDK
}
}
public static bool FontExists(string fontpath)
{
public static bool FontExists(string fontpath) {
return SKFontManager.Default.FontFamilies.Contains(fontpath) || File.Exists(fontpath);
}
#region [ ]
public CFontRenderer(string fontpath, int pt, FontStyle style)
{
public CFontRenderer(string fontpath, int pt, FontStyle style) {
Initialize(fontpath, pt, style);
}
public CFontRenderer(string fontpath, int pt)
{
public CFontRenderer(string fontpath, int pt) {
Initialize(fontpath, pt, FontStyle.Regular);
}
public CFontRenderer()
{
public CFontRenderer() {
//throw new ArgumentException("CFontRenderer: 引数があるコンストラクタを使用してください。");
}
#endregion
protected void Initialize(string fontpath, int pt, FontStyle style)
{
try
{
protected void Initialize(string fontpath, int pt, FontStyle style) {
try {
this.textRenderer = new CSkiaSharpTextRenderer(fontpath, pt, style);
return;
}
catch(Exception e)
{
} catch (Exception e) {
Trace.TraceWarning("SkiaSharpでのフォント生成に失敗しました。" + e.ToString());
this.textRenderer?.Dispose();
}
try
{
try {
this.textRenderer = new CSkiaSharpTextRenderer(Assembly.GetExecutingAssembly().GetManifestResourceStream(@"FDK.mplus-1p-medium.ttf"), pt, style);
}
catch (Exception e)
{
} catch (Exception e) {
Trace.TraceWarning("ビルトインフォントを使用してのフォント生成に失敗しました。" + e.ToString());
this.textRenderer?.Dispose();
throw;
}
}
public SKBitmap DrawText(string drawstr, Color fontColor, bool keepCenter = false)
{
public SKBitmap DrawText(string drawstr, Color fontColor, bool keepCenter = false) {
return DrawText(drawstr, CFontRenderer.DrawMode.Normal, fontColor, Color.White, null, Color.White, Color.White, 0, keepCenter);
}
public SKBitmap DrawText(string drawstr, Color fontColor, Color edgeColor, Color? secondEdgeColor, int edge_Ratio, bool keepCenter = false)
{
public SKBitmap DrawText(string drawstr, Color fontColor, Color edgeColor, Color? secondEdgeColor, int edge_Ratio, bool keepCenter = false) {
return DrawText(drawstr, CFontRenderer.DrawMode.Edge, fontColor, edgeColor, secondEdgeColor, Color.White, Color.White, edge_Ratio, keepCenter);
}
public SKBitmap DrawText(string drawstr, Color fontColor, Color gradationTopColor, Color gradataionBottomColor, int edge_Ratio, bool keepCenter = false)
{
public SKBitmap DrawText(string drawstr, Color fontColor, Color gradationTopColor, Color gradataionBottomColor, int edge_Ratio, bool keepCenter = false) {
return DrawText(drawstr, CFontRenderer.DrawMode.Gradation, fontColor, Color.White, null, gradationTopColor, gradataionBottomColor, edge_Ratio, keepCenter);
}
public SKBitmap DrawText(string drawstr, Color fontColor, Color edgeColor, Color? secondEdgeColor, Color gradationTopColor, Color gradataionBottomColor, int edge_Ratio, bool keepCenter = false)
{
public SKBitmap DrawText(string drawstr, Color fontColor, Color edgeColor, Color? secondEdgeColor, Color gradationTopColor, Color gradataionBottomColor, int edge_Ratio, bool keepCenter = false) {
return DrawText(drawstr, CFontRenderer.DrawMode.Edge | CFontRenderer.DrawMode.Gradation, fontColor, edgeColor, secondEdgeColor, gradationTopColor, gradataionBottomColor, edge_Ratio, keepCenter);
}
protected SKBitmap DrawText(string drawstr, CFontRenderer.DrawMode drawmode, Color fontColor, Color edgeColor, Color? secondEdgeColor, Color gradationTopColor, Color gradationBottomColor, int edge_Ratio, bool keepCenter = false)
{
protected SKBitmap DrawText(string drawstr, CFontRenderer.DrawMode drawmode, Color fontColor, Color edgeColor, Color? secondEdgeColor, Color gradationTopColor, Color gradationBottomColor, int edge_Ratio, bool keepCenter = false) {
//横書きに対してのCorrectionは廃止
return this.textRenderer.DrawText(drawstr, drawmode, fontColor, edgeColor, secondEdgeColor, gradationTopColor, gradationBottomColor, edge_Ratio, keepCenter);
}
public SKBitmap DrawText_V(string drawstr, Color fontColor, bool keepCenter = false)
{
public SKBitmap DrawText_V(string drawstr, Color fontColor, bool keepCenter = false) {
return DrawText_V(drawstr, CFontRenderer.DrawMode.Normal, fontColor, Color.White, null, Color.White, Color.White, 0, keepCenter);
}
public SKBitmap DrawText_V(string drawstr, Color fontColor, Color edgeColor, Color? secondEdgeColor, int edge_Ratio, bool keepCenter = false)
{
public SKBitmap DrawText_V(string drawstr, Color fontColor, Color edgeColor, Color? secondEdgeColor, int edge_Ratio, bool keepCenter = false) {
return DrawText_V(drawstr, CFontRenderer.DrawMode.Edge, fontColor, edgeColor, secondEdgeColor, Color.White, Color.White, edge_Ratio, keepCenter);
}
public SKBitmap DrawText_V(string drawstr, Color fontColor, Color gradationTopColor, Color gradataionBottomColor, int edge_Ratio, bool keepCenter = false)
{
public SKBitmap DrawText_V(string drawstr, Color fontColor, Color gradationTopColor, Color gradataionBottomColor, int edge_Ratio, bool keepCenter = false) {
return DrawText_V(drawstr, CFontRenderer.DrawMode.Gradation, fontColor, Color.White, null, gradationTopColor, gradataionBottomColor, edge_Ratio, keepCenter);
}
public SKBitmap DrawText_V(string drawstr, Color fontColor, Color edgeColor, Color? secondEdgeColor, Color gradationTopColor, Color gradataionBottomColor, int edge_Ratio, bool keepCenter = false)
{
public SKBitmap DrawText_V(string drawstr, Color fontColor, Color edgeColor, Color? secondEdgeColor, Color gradationTopColor, Color gradataionBottomColor, int edge_Ratio, bool keepCenter = false) {
return DrawText_V(drawstr, CFontRenderer.DrawMode.Edge | CFontRenderer.DrawMode.Gradation, fontColor, edgeColor, secondEdgeColor, gradationTopColor, gradataionBottomColor, edge_Ratio, keepCenter);
}
protected SKBitmap DrawText_V(string drawstr, CFontRenderer.DrawMode drawmode, Color fontColor, Color edgeColor, Color? secondEdgeColor, Color gradationTopColor, Color gradationBottomColor, int edge_Ratio, bool keepCenter = false)
{
if (string.IsNullOrEmpty(drawstr))
{
protected SKBitmap DrawText_V(string drawstr, CFontRenderer.DrawMode drawmode, Color fontColor, Color edgeColor, Color? secondEdgeColor, Color gradationTopColor, Color gradationBottomColor, int edge_Ratio, bool keepCenter = false) {
if (string.IsNullOrEmpty(drawstr)) {
//nullか""だったら、1x1を返す
return new SKBitmap(1, 1);
}
@ -187,15 +152,12 @@ namespace FDK
//レンダリング,大きさ計測
int nWidth = 0;
int nHeight = 0;
for (int i = 0; i < strImageList.Length; i++)
{
for (int i = 0; i < strImageList.Length; i++) {
strImageList[i] = this.textRenderer.DrawText(strList[i], drawmode, fontColor, edgeColor, secondEdgeColor, gradationTopColor, gradationBottomColor, edge_Ratio, false);
//回転する文字
if(Rotate_Chara_List_Vertical.Contains(strList[i]))
{
using (var surface = new SKCanvas(strImageList[i]))
{
if (Rotate_Chara_List_Vertical.Contains(strList[i])) {
using (var surface = new SKCanvas(strImageList[i])) {
surface.RotateDegrees(90, strImageList[i].Width / 2, strImageList[i].Height / 2);
surface.DrawBitmap(strImageList[i], 0, 0);
}
@ -212,44 +174,29 @@ namespace FDK
//1文字ずつ描画したやつを全体キャンバスに描画していく
int nowHeightPos = 0;
for (int i = 0; i < strImageList.Length; i++)
{
for (int i = 0; i < strImageList.Length; i++) {
int Correction_X = 0, Correction_Y = 0;
if (CorrectionX_Chara_List_Vertical != null && CorrectionX_Chara_List_Value_Vertical != null)
{
if (CorrectionX_Chara_List_Vertical != null && CorrectionX_Chara_List_Value_Vertical != null) {
int Xindex = Array.IndexOf(CorrectionX_Chara_List_Vertical, strList[i]);
if (-1 < Xindex && Xindex < CorrectionX_Chara_List_Value_Vertical.Length && CorrectionX_Chara_List_Vertical.Contains(strList[i]))
{
if (-1 < Xindex && Xindex < CorrectionX_Chara_List_Value_Vertical.Length && CorrectionX_Chara_List_Vertical.Contains(strList[i])) {
Correction_X = CorrectionX_Chara_List_Value_Vertical[Xindex];
}
else
{
if (-1 < Xindex && CorrectionX_Chara_List_Value_Vertical.Length <= Xindex && CorrectionX_Chara_List_Vertical.Contains(strList[i]))
{
} else {
if (-1 < Xindex && CorrectionX_Chara_List_Value_Vertical.Length <= Xindex && CorrectionX_Chara_List_Vertical.Contains(strList[i])) {
Correction_X = CorrectionX_Chara_List_Value_Vertical[0];
}
else
{
} else {
Correction_X = 0;
}
}
}
if (CorrectionY_Chara_List_Vertical != null && CorrectionY_Chara_List_Value_Vertical != null)
{
if (CorrectionY_Chara_List_Vertical != null && CorrectionY_Chara_List_Value_Vertical != null) {
int Yindex = Array.IndexOf(CorrectionY_Chara_List_Vertical, strList[i]);
if (-1 < Yindex && Yindex < CorrectionY_Chara_List_Value_Vertical.Length && CorrectionY_Chara_List_Vertical.Contains(strList[i]))
{
if (-1 < Yindex && Yindex < CorrectionY_Chara_List_Value_Vertical.Length && CorrectionY_Chara_List_Vertical.Contains(strList[i])) {
Correction_Y = CorrectionY_Chara_List_Value_Vertical[Yindex];
}
else
{
if (-1 < Yindex && CorrectionY_Chara_List_Value_Vertical.Length <= Yindex && CorrectionY_Chara_List_Vertical.Contains(strList[i]))
{
} else {
if (-1 < Yindex && CorrectionY_Chara_List_Value_Vertical.Length <= Yindex && CorrectionY_Chara_List_Vertical.Contains(strList[i])) {
Correction_Y = CorrectionY_Chara_List_Value_Vertical[0];
}
else
{
} else {
Correction_Y = 0;
}
}
@ -259,8 +206,7 @@ namespace FDK
}
//1文字ずつ描画したやつの解放
for (int i = 0; i < strImageList.Length; i++)
{
for (int i = 0; i < strImageList.Length; i++) {
strImageList[i].Dispose();
}
@ -270,8 +216,7 @@ namespace FDK
return SKBitmap.FromImage(image);
}
public void Dispose()
{
public void Dispose() {
this.textRenderer.Dispose();
}

View File

@ -1,40 +1,24 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SkiaSharp;
using System.Text.RegularExpressions;
using Color = System.Drawing.Color;
using Rectangle = System.Drawing.Rectangle;
using System.Drawing;
using static FDK.CSkiaSharpTextRenderer;
using System.Text.RegularExpressions;
using SkiaSharp;
using Color = System.Drawing.Color;
namespace FDK
{
internal class CSkiaSharpTextRenderer : ITextRenderer
{
namespace FDK {
internal class CSkiaSharpTextRenderer : ITextRenderer {
//https://monobook.org/wiki/SkiaSharp%E3%81%A7%E6%97%A5%E6%9C%AC%E8%AA%9E%E6%96%87%E5%AD%97%E5%88%97%E3%82%92%E6%8F%8F%E7%94%BB%E3%81%99%E3%82%8B
public CSkiaSharpTextRenderer(string fontpath, int pt)
{
public CSkiaSharpTextRenderer(string fontpath, int pt) {
Initialize(fontpath, pt, CFontRenderer.FontStyle.Regular);
}
public CSkiaSharpTextRenderer(string fontpath, int pt, CFontRenderer.FontStyle style)
{
public CSkiaSharpTextRenderer(string fontpath, int pt, CFontRenderer.FontStyle style) {
Initialize(fontpath, pt, style);
}
public CSkiaSharpTextRenderer(Stream fontstream, int pt, CFontRenderer.FontStyle style)
{
public CSkiaSharpTextRenderer(Stream fontstream, int pt, CFontRenderer.FontStyle style) {
Initialize(fontstream, pt, style);
}
protected void Initialize(Stream fontstream, int pt, CFontRenderer.FontStyle style)
{
protected void Initialize(Stream fontstream, int pt, CFontRenderer.FontStyle style) {
paint = new SKPaint();
//stream・filepathから生成した場合に、style設定をどうすればいいのかがわからない
@ -44,28 +28,23 @@ namespace FDK
paint.IsAntialias = true;
}
protected void Initialize(string fontpath, int pt, CFontRenderer.FontStyle style)
{
protected void Initialize(string fontpath, int pt, CFontRenderer.FontStyle style) {
paint = new SKPaint();
SKFontStyleWeight weight = SKFontStyleWeight.Normal;
SKFontStyleWidth width = SKFontStyleWidth.Normal;
SKFontStyleSlant slant = SKFontStyleSlant.Upright;
if (style.HasFlag(CFontRenderer.FontStyle.Bold))
{
if (style.HasFlag(CFontRenderer.FontStyle.Bold)) {
weight = SKFontStyleWeight.Bold;
}
if (style.HasFlag(CFontRenderer.FontStyle.Italic))
{
if (style.HasFlag(CFontRenderer.FontStyle.Italic)) {
slant = SKFontStyleSlant.Italic;
}
if (style.HasFlag(CFontRenderer.FontStyle.Strikeout))
{
if (style.HasFlag(CFontRenderer.FontStyle.Strikeout)) {
paint.Style = SKPaintStyle.Stroke;
}
if (style.HasFlag(CFontRenderer.FontStyle.Underline))
{
if (style.HasFlag(CFontRenderer.FontStyle.Underline)) {
//????
//paint.FontMetrics.UnderlinePosition;
}
@ -84,8 +63,7 @@ namespace FDK
paint.IsAntialias = true;
}
internal struct SStringToken
{
internal struct SStringToken {
public string s;
public Color TextColor;
public bool UseGradiant;
@ -99,13 +77,11 @@ namespace FDK
private const string TagRegex = @"<(/?)([gc](?:\.#[0-9a-fA-F]{6})*?)>";
private string Purify(string input)
{
private string Purify(string input) {
return Regex.Replace(input, TagRegex, "");
}
private List<SStringToken> Tokenize(string input, Color fontColor, Color edgeColor, Color? secondEdgeColor, Color gradationTopColor, Color gradationBottomColor)
{
private List<SStringToken> Tokenize(string input, Color fontColor, Color edgeColor, Color? secondEdgeColor, Color gradationTopColor, Color gradationBottomColor) {
List<SStringToken> tokens = new List<SStringToken>();
Stack<string> tags = new Stack<string>();
Stack<SStringToken> tokenStack = new Stack<SStringToken>();
@ -114,16 +90,13 @@ namespace FDK
var tagRegex = new Regex(TagRegex);
var matches = tagRegex.Matches(input);
foreach (Match match in matches)
{
foreach (Match match in matches) {
int pos = match.Index;
string text = input.Substring(lastPos, pos - lastPos);
// First
if (text.Length > 0)
{
SStringToken token = new SStringToken
{
if (text.Length > 0) {
SStringToken token = new SStringToken {
s = text,
UseGradiant = tokenStack.Count > 0 && tokenStack.Peek().UseGradiant,
GradiantTop = (tokenStack.Count == 0) ? gradationTopColor : tokenStack.Peek().GradiantTop,
@ -137,16 +110,12 @@ namespace FDK
lastPos = pos + match.Length;
if (match.Groups[1].Value == "/")
{
if (match.Groups[1].Value == "/") {
if (tags.Count > 0) tags.Pop();
if (tokenStack.Count > 0) tokenStack.Pop();
}
else
{
} else {
tags.Push(match.Groups[2].Value);
SStringToken newToken = new SStringToken
{
SStringToken newToken = new SStringToken {
UseGradiant = tokenStack.Count > 0 ? tokenStack.Peek().UseGradiant : false,
GradiantTop = (tokenStack.Count == 0) ? gradationTopColor : tokenStack.Peek().GradiantTop,
GradiantBottom = (tokenStack.Count == 0) ? gradationBottomColor : tokenStack.Peek().GradiantBottom,
@ -157,28 +126,21 @@ namespace FDK
string[] _varSplit = match.Groups[2].Value.Split(".");
if (_varSplit.Length > 0)
{
switch (_varSplit[0])
{
case "g":
{
if (_varSplit.Length > 2)
{
if (_varSplit.Length > 0) {
switch (_varSplit[0]) {
case "g": {
if (_varSplit.Length > 2) {
newToken.UseGradiant = true;
newToken.GradiantTop = ColorTranslator.FromHtml(_varSplit[1]);
newToken.GradiantBottom = ColorTranslator.FromHtml(_varSplit[2]);
}
break;
}
case "c":
{
if (_varSplit.Length > 1)
{
case "c": {
if (_varSplit.Length > 1) {
newToken.TextColor = ColorTranslator.FromHtml(_varSplit[1]);
}
if (_varSplit.Length > 2)
{
if (_varSplit.Length > 2) {
newToken.UseOutline = true;
newToken.OutlineColor = ColorTranslator.FromHtml(_varSplit[2]);
}
@ -193,10 +155,8 @@ namespace FDK
}
// Last
if (lastPos < input.Length)
{
SStringToken token = new SStringToken
{
if (lastPos < input.Length) {
SStringToken token = new SStringToken {
s = input.Substring(lastPos),
UseGradiant = tokenStack.Count > 0 && tokenStack.Peek().UseGradiant,
GradiantTop = (tokenStack.Count == 0) ? gradationTopColor : tokenStack.Peek().GradiantTop,
@ -211,10 +171,8 @@ namespace FDK
return tokens;
}
public SKBitmap DrawText(string drawstr, CFontRenderer.DrawMode drawMode, Color fontColor, Color edgeColor, Color? secondEdgeColor, Color gradationTopColor, Color gradationBottomColor, int edge_Ratio, bool keepCenter)
{
if (string.IsNullOrEmpty(drawstr))
{
public SKBitmap DrawText(string drawstr, CFontRenderer.DrawMode drawMode, Color fontColor, Color edgeColor, Color? secondEdgeColor, Color gradationTopColor, Color gradationBottomColor, int edge_Ratio, bool keepCenter) {
if (string.IsNullOrEmpty(drawstr)) {
//nullか""だったら、1x1を返す
return new SKBitmap(1, 1);
}
@ -222,8 +180,7 @@ namespace FDK
string[] strs = drawstr.Split("\n");
List<SStringToken>[] tokens = new List<SStringToken>[strs.Length];
for (int i = 0; i < strs.Length; i++)
{
for (int i = 0; i < strs.Length; i++) {
tokens[i] = Tokenize(strs[i], fontColor, edgeColor, secondEdgeColor, gradationTopColor, gradationBottomColor);
}
@ -241,17 +198,14 @@ namespace FDK
int x_offset = 0;
foreach (SStringToken tok in tokens[i])
{
foreach (SStringToken tok in tokens[i]) {
int token_width = (int)Math.Ceiling(paint.MeasureText(tok.s, ref bounds));
if (drawMode.HasFlag(CFontRenderer.DrawMode.Edge) || tok.UseOutline)
{
if (drawMode.HasFlag(CFontRenderer.DrawMode.Edge) || tok.UseOutline) {
SKPath path = paint.GetTextPath(tok.s, 25 + x_offset, -paint.FontMetrics.Ascent + 25);
if (secondEdgeColor != null)
{
if (secondEdgeColor != null) {
SKPaint secondEdgePaint = new SKPaint();
secondEdgePaint.StrokeWidth = paint.TextSize * 8 / edge_Ratio;
secondEdgePaint.StrokeJoin = SKStrokeJoin.Round;
@ -270,8 +224,7 @@ namespace FDK
canvas.DrawPath(path, edgePaint);
}
if (tok.UseGradiant)
{
if (tok.UseGradiant) {
//https://docs.microsoft.com/ja-jp/xamarin/xamarin-forms/user-interface/graphics/skiasharp/effects/shaders/linear-gradient
paint.Shader = SKShader.CreateLinearGradient(
new SKPoint(0, 25),
@ -282,9 +235,7 @@ namespace FDK
new float[] { 0, 1 },
SKShaderTileMode.Clamp);
paint.Color = new SKColor(0xffffffff);
}
else
{
} else {
paint.Shader = null;
paint.Color = new SKColor(tok.TextColor.R, tok.TextColor.G, tok.TextColor.B);
}
@ -304,8 +255,7 @@ namespace FDK
int ret_width = 0;
int ret_height = 0;
for(int i = 0; i < images.Length; i++)
{
for (int i = 0; i < images.Length; i++) {
ret_width = Math.Max(ret_width, images[i].Width);
ret_height += images[i].Height - 25;
}
@ -322,14 +272,10 @@ namespace FDK
int height_i = -25;
for (int i = 0; i < images.Length; i++)
{
if (keepCenter)
{
for (int i = 0; i < images.Length; i++) {
if (keepCenter) {
skCanvas.DrawBitmap(images[i], new SKPoint((ret_width / 2) - (images[i].Width / 2.0f), height_i));
}
else
{
} else {
skCanvas.DrawBitmap(images[i], new SKPoint(0, height_i));
}
height_i += images[i].Height - 50;
@ -343,8 +289,7 @@ namespace FDK
return SKBitmap.FromImage(image);
}
public void Dispose()
{
public void Dispose() {
paint.Dispose();
}

View File

@ -1,11 +1,8 @@
using System;
using SkiaSharp;
using Color = System.Drawing.Color;
namespace FDK
{
internal interface ITextRenderer : IDisposable
{
namespace FDK {
internal interface ITextRenderer : IDisposable {
SKBitmap DrawText(string drawstr, CFontRenderer.DrawMode drawmode, Color fontColor, Color edgeColor, Color? secondEdgeColor, Color gradationTopColor, Color gradationBottomColor, int edge_Ratio, bool keepCenter);
}
}

View File

@ -1,16 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TJAPlayer3;
using FDK;
using FDK;
namespace TJAPlayer3.Animations
{
class Animator : IAnimatable
{
public Animator(int startValue, int endValue, int tickInterval, bool isLoop)
{
namespace TJAPlayer3.Animations {
class Animator : IAnimatable {
public Animator(int startValue, int endValue, int tickInterval, bool isLoop) {
Type = CounterType.Normal;
StartValue = startValue;
EndValue = endValue;
@ -18,8 +10,7 @@ namespace TJAPlayer3.Animations
IsLoop = isLoop;
Counter = new CCounter();
}
public Animator(double startValue, double endValue, double tickInterval, bool isLoop)
{
public Animator(double startValue, double endValue, double tickInterval, bool isLoop) {
Type = CounterType.Double;
StartValue = startValue;
EndValue = endValue;
@ -27,11 +18,9 @@ namespace TJAPlayer3.Animations
IsLoop = isLoop;
Counter = new CCounter();
}
public void Start()
{
public void Start() {
if (Counter == null) throw new NullReferenceException();
switch (Type)
{
switch (Type) {
case CounterType.Normal:
Counter.Start((int)StartValue, (int)EndValue, (int)TickInterval, TJAPlayer3.Timer);
break;
@ -42,22 +31,18 @@ namespace TJAPlayer3.Animations
break;
}
}
public void Stop()
{
public void Stop() {
if (Counter == null) throw new NullReferenceException();
Counter.Stop();
}
public void Reset()
{
public void Reset() {
if (Counter == null) throw new NullReferenceException();
Start();
}
public void Tick()
{
public void Tick() {
if (Counter == null) throw new NullReferenceException();
switch (Type)
{
switch (Type) {
case CounterType.Normal:
if (IsLoop) Counter.TickLoop(); else Counter.Tick();
if (!IsLoop && Counter.IsEnded) Stop();
@ -71,48 +56,40 @@ namespace TJAPlayer3.Animations
}
}
public virtual object GetAnimation()
{
public virtual object GetAnimation() {
throw new NotImplementedException();
}
// プロパティ
public CCounter Counter
{
public CCounter Counter {
get;
private set;
}
public CounterType Type
{
public CounterType Type {
get;
private set;
}
public object StartValue
{
public object StartValue {
get;
private set;
}
public object EndValue
{
public object EndValue {
get;
private set;
}
public object TickInterval
{
public object TickInterval {
get;
private set;
}
public bool IsLoop
{
public bool IsLoop {
get;
private set;
}
}
enum CounterType
{
enum CounterType {
Normal,
Double
}

View File

@ -1,31 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TJAPlayer3.Animations
{
namespace TJAPlayer3.Animations {
/// <summary>
/// イーズインを行うクラス。
/// </summary>
class EaseIn : Animator
{
class EaseIn : Animator {
/// <summary>
/// イーズインを初期化します。
/// </summary>
/// <param name="startPoint">始点。</param>
/// <param name="endPoint">終点。</param>
/// <param name="timeMs">イージングにかける時間。</param>
public EaseIn(int startPoint, int endPoint, int timeMs) : base(0, timeMs, 1, false)
{
public EaseIn(int startPoint, int endPoint, int timeMs) : base(0, timeMs, 1, false) {
StartPoint = startPoint;
EndPoint = endPoint;
Sa = EndPoint - StartPoint;
TimeMs = timeMs;
}
public override object GetAnimation()
{
public override object GetAnimation() {
var persent = Counter.CurrentValue / (double)TimeMs;
return ((double)Sa * persent * persent * persent) + StartPoint;
}

View File

@ -1,38 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TJAPlayer3.Animations
{
namespace TJAPlayer3.Animations {
/// <summary>
/// イーズイン・アウトを行うクラス。
/// </summary>
class EaseInOut : Animator
{
class EaseInOut : Animator {
/// <summary>
/// イーズイン・アウトを初期化します。
/// </summary>
/// <param name="startPoint">始点。</param>
/// <param name="endPoint">終点。</param>
/// <param name="timeMs">イージングにかける時間。</param>
public EaseInOut(int startPoint, int endPoint, int timeMs) : base(0, timeMs, 1, false)
{
public EaseInOut(int startPoint, int endPoint, int timeMs) : base(0, timeMs, 1, false) {
StartPoint = startPoint;
EndPoint = endPoint;
Sa = EndPoint - StartPoint;
TimeMs = timeMs;
}
public override object GetAnimation()
{
public override object GetAnimation() {
var persent = Counter.CurrentValue / (double)TimeMs * 2.0;
if (persent < 1)
{
if (persent < 1) {
return ((double)Sa / 2.0 * persent * persent * persent) + StartPoint;
}
else
{
} else {
persent -= 2;
return ((double)Sa / 2.0 * ((persent * persent * persent) + 2)) + StartPoint;
}

View File

@ -1,31 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TJAPlayer3.Animations
{
namespace TJAPlayer3.Animations {
/// <summary>
/// イーズアウトを行うクラス。
/// </summary>
class EaseOut : Animator
{
class EaseOut : Animator {
/// <summary>
/// イーズアウトを初期化します。
/// </summary>
/// <param name="startPoint">始点。</param>
/// <param name="endPoint">終点。</param>
/// <param name="timeMs">イージングにかける時間。</param>
public EaseOut(int startPoint, int endPoint, int timeMs) : base(0, timeMs, 1, false)
{
public EaseOut(int startPoint, int endPoint, int timeMs) : base(0, timeMs, 1, false) {
StartPoint = startPoint;
EndPoint = endPoint;
Sa = EndPoint - StartPoint;
TimeMs = timeMs;
}
public override object GetAnimation()
{
public override object GetAnimation() {
var persent = Counter.CurrentValue / (double)TimeMs;
persent -= 1;
return (double)Sa * (persent * persent * persent + 1) + StartPoint;

View File

@ -1,21 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TJAPlayer3.Animations
{
namespace TJAPlayer3.Animations {
/// <summary>
/// フェードインを行うクラス。
/// </summary>
internal class FadeIn : Animator
{
internal class FadeIn : Animator {
/// <summary>
/// フェードインを初期化します。
/// </summary>
/// <param name="timems">フェードインに掛ける秒数(ミリ秒)</param>
public FadeIn(int timems) : base(0, timems - 1, 1, false)
{
public FadeIn(int timems) : base(0, timems - 1, 1, false) {
TimeMs = timems;
}
@ -23,8 +15,7 @@ namespace TJAPlayer3.Animations
/// フェードインの不透明度を255段階で返します。
/// </summary>
/// <returns>不透明度。</returns>
public override object GetAnimation()
{
public override object GetAnimation() {
var opacity = base.Counter.CurrentValue * 255 / TimeMs;
return opacity;
}

View File

@ -1,21 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TJAPlayer3.Animations
{
namespace TJAPlayer3.Animations {
/// <summary>
/// フェードアウトを行うクラス。
/// </summary>
internal class FadeOut : Animator
{
internal class FadeOut : Animator {
/// <summary>
/// フェードアウトを初期化します。
/// </summary>
/// <param name="timems">フェードアウトに掛ける秒数(ミリ秒)</param>
public FadeOut(int timems) : base(0, timems - 1, 1, false)
{
public FadeOut(int timems) : base(0, timems - 1, 1, false) {
TimeMs = timems;
}
@ -23,8 +15,7 @@ namespace TJAPlayer3.Animations
/// フェードアウトの不透明度を255段階で返します。
/// </summary>
/// <returns>不透明度。</returns>
public override object GetAnimation()
{
public override object GetAnimation() {
var opacity = (TimeMs - base.Counter.CurrentValue) * 255 / TimeMs;
return opacity;
}

View File

@ -1,15 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TJAPlayer3.Animations
{
namespace TJAPlayer3.Animations {
/// <summary>
/// アニメーション インターフェイス。
/// </summary>
interface IAnimatable
{
interface IAnimatable {
/// <summary>
/// アニメーションを開始します。
/// </summary>

View File

@ -1,31 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TJAPlayer3.Animations
{
namespace TJAPlayer3.Animations {
/// <summary>
/// リニア移動を行うクラス。
/// </summary>
class Linear : Animator
{
class Linear : Animator {
/// <summary>
/// リニア移動を初期化します。
/// </summary>
/// <param name="startPoint">始点。</param>
/// <param name="endPoint">終点。</param>
/// <param name="timeMs">移動にかける時間。</param>
public Linear(int startPoint, int endPoint, int timeMs) : base(0, timeMs, 1, false)
{
public Linear(int startPoint, int endPoint, int timeMs) : base(0, timeMs, 1, false) {
StartPoint = startPoint;
EndPoint = endPoint;
Sa = EndPoint - StartPoint;
TimeMs = timeMs;
}
public override object GetAnimation()
{
public override object GetAnimation() {
var persent = Counter.CurrentValue / (double)TimeMs;
return (Sa * persent) + StartPoint;
}

View File

@ -1,14 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using FDK;
using FDK;
namespace TJAPlayer3
{
class CMenuCharacter
{
namespace TJAPlayer3 {
class CMenuCharacter {
private static CCounter[] ctCharacterNormal = new CCounter[5] { new CCounter(), new CCounter(), new CCounter(), new CCounter(), new CCounter() };
private static CCounter[] ctCharacterSelect = new CCounter[5] { new CCounter(), new CCounter(), new CCounter(), new CCounter(), new CCounter() };
private static CCounter[] ctCharacterStart = new CCounter[5] { new CCounter(), new CCounter(), new CCounter(), new CCounter(), new CCounter() };
@ -16,8 +9,7 @@ namespace TJAPlayer3
private static CCounter[] ctCharacterEntry = new CCounter[5] { new CCounter(), new CCounter(), new CCounter(), new CCounter(), new CCounter() };
private static CCounter[] ctCharacterEntryNormal = new CCounter[5] { new CCounter(), new CCounter(), new CCounter(), new CCounter(), new CCounter() };
public enum ECharacterAnimation
{
public enum ECharacterAnimation {
// Song select
NORMAL,
START,
@ -29,46 +21,37 @@ namespace TJAPlayer3
}
private static bool _usesSubstituteTexture(int player, ECharacterAnimation eca)
{
private static bool _usesSubstituteTexture(int player, ECharacterAnimation eca) {
int _charaId = TJAPlayer3.SaveFileInstances[TJAPlayer3.GetActualPlayer(player)].data.Character;
if (_charaId >= 0 && _charaId < TJAPlayer3.Skin.Characters_Ptn)
{
switch (eca)
{
case (ECharacterAnimation.NORMAL):
{
if (_charaId >= 0 && _charaId < TJAPlayer3.Skin.Characters_Ptn) {
switch (eca) {
case (ECharacterAnimation.NORMAL): {
if (TJAPlayer3.Tx.Characters_Menu_Loop[_charaId].Length > 0)
return false;
break;
}
case (ECharacterAnimation.START):
{
case (ECharacterAnimation.START): {
if (TJAPlayer3.Tx.Characters_Menu_Start[_charaId].Length > 0)
return false;
break;
}
case (ECharacterAnimation.SELECT):
{
case (ECharacterAnimation.SELECT): {
if (TJAPlayer3.Tx.Characters_Menu_Select[_charaId].Length > 0)
return false;
break;
}
case (ECharacterAnimation.WAIT):
{
case (ECharacterAnimation.WAIT): {
if (TJAPlayer3.Tx.Characters_Menu_Wait[_charaId].Length > 0)
return false;
break;
}
case (ECharacterAnimation.ENTRY):
{
case (ECharacterAnimation.ENTRY): {
if (TJAPlayer3.Tx.Characters_Title_Entry[_charaId].Length > 0)
return false;
break;
}
case (ECharacterAnimation.ENTRY_NORMAL):
{
case (ECharacterAnimation.ENTRY_NORMAL): {
if (TJAPlayer3.Tx.Characters_Title_Normal[_charaId].Length > 0)
return false;
break;
@ -79,40 +62,33 @@ namespace TJAPlayer3
return true;
}
public static CTexture[] _getReferenceArray(int player, ECharacterAnimation eca)
{
public static CTexture[] _getReferenceArray(int player, ECharacterAnimation eca) {
int _charaId = TJAPlayer3.SaveFileInstances[TJAPlayer3.GetActualPlayer(player)].data.Character;
if (_charaId >= 0 && _charaId < TJAPlayer3.Skin.Characters_Ptn)
{
switch (eca)
{
case (ECharacterAnimation.NORMAL):
{
if (_charaId >= 0 && _charaId < TJAPlayer3.Skin.Characters_Ptn) {
switch (eca) {
case (ECharacterAnimation.NORMAL): {
if (TJAPlayer3.Tx.Characters_Menu_Loop[_charaId].Length > 0)
return TJAPlayer3.Tx.Characters_Menu_Loop[_charaId];
if (TJAPlayer3.Tx.Characters_Normal[_charaId].Length > 0)
return TJAPlayer3.Tx.Characters_Normal[_charaId];
break;
}
case (ECharacterAnimation.START):
{
case (ECharacterAnimation.START): {
if (TJAPlayer3.Tx.Characters_Menu_Start[_charaId].Length > 0)
return TJAPlayer3.Tx.Characters_Menu_Start[_charaId];
if (TJAPlayer3.Tx.Characters_10Combo[_charaId].Length > 0)
return TJAPlayer3.Tx.Characters_10Combo[_charaId];
break;
}
case (ECharacterAnimation.SELECT):
{
case (ECharacterAnimation.SELECT): {
if (TJAPlayer3.Tx.Characters_Menu_Select[_charaId].Length > 0)
return TJAPlayer3.Tx.Characters_Menu_Select[_charaId];
if (TJAPlayer3.Tx.Characters_10Combo[_charaId].Length > 0)
return TJAPlayer3.Tx.Characters_10Combo[_charaId];
break;
}
case (ECharacterAnimation.WAIT):
{
case (ECharacterAnimation.WAIT): {
if (TJAPlayer3.Tx.Characters_Menu_Wait[_charaId].Length > 0)
return TJAPlayer3.Tx.Characters_Menu_Wait[_charaId];
if (TJAPlayer3.Tx.Characters_Menu_Loop[_charaId].Length > 0)
@ -121,16 +97,14 @@ namespace TJAPlayer3
return TJAPlayer3.Tx.Characters_GoGoTime[_charaId];
break;
}
case (ECharacterAnimation.ENTRY):
{
case (ECharacterAnimation.ENTRY): {
if (TJAPlayer3.Tx.Characters_Title_Entry[_charaId].Length > 0)
return TJAPlayer3.Tx.Characters_Title_Entry[_charaId];
if (TJAPlayer3.Tx.Characters_10Combo[_charaId].Length > 0)
return TJAPlayer3.Tx.Characters_10Combo[_charaId];
break;
}
case (ECharacterAnimation.ENTRY_NORMAL):
{
case (ECharacterAnimation.ENTRY_NORMAL): {
if (TJAPlayer3.Tx.Characters_Title_Normal[_charaId].Length > 0)
return TJAPlayer3.Tx.Characters_Title_Normal[_charaId];
if (TJAPlayer3.Tx.Characters_Normal[_charaId].Length > 0)
@ -144,108 +118,84 @@ namespace TJAPlayer3
return null;
}
public static CCounter[] _getReferenceCounter(ECharacterAnimation eca)
{
switch (eca)
{
case (ECharacterAnimation.NORMAL):
{
public static CCounter[] _getReferenceCounter(ECharacterAnimation eca) {
switch (eca) {
case (ECharacterAnimation.NORMAL): {
return ctCharacterNormal;
}
case (ECharacterAnimation.START):
{
case (ECharacterAnimation.START): {
return ctCharacterStart;
}
case (ECharacterAnimation.SELECT):
{
case (ECharacterAnimation.SELECT): {
return ctCharacterSelect;
}
case (ECharacterAnimation.WAIT):
{
case (ECharacterAnimation.WAIT): {
return ctCharacterWait;
}
case (ECharacterAnimation.ENTRY):
{
case (ECharacterAnimation.ENTRY): {
return ctCharacterEntry;
}
case (ECharacterAnimation.ENTRY_NORMAL):
{
case (ECharacterAnimation.ENTRY_NORMAL): {
return ctCharacterEntryNormal;
}
}
return null;
}
public static int _getReferenceAnimationDuration(int player, ECharacterAnimation eca)
{
public static int _getReferenceAnimationDuration(int player, ECharacterAnimation eca) {
int _charaId = TJAPlayer3.SaveFileInstances[TJAPlayer3.GetActualPlayer(player)].data.Character;
switch (eca)
{
case (ECharacterAnimation.NORMAL):
{
switch (eca) {
case (ECharacterAnimation.NORMAL): {
return TJAPlayer3.Skin.Characters_Menu_Loop_AnimationDuration[_charaId];
}
case (ECharacterAnimation.START):
{
case (ECharacterAnimation.START): {
return TJAPlayer3.Skin.Characters_Menu_Start_AnimationDuration[_charaId];
}
case (ECharacterAnimation.SELECT):
{
case (ECharacterAnimation.SELECT): {
return TJAPlayer3.Skin.Characters_Menu_Select_AnimationDuration[_charaId];
}
case (ECharacterAnimation.WAIT):
{
case (ECharacterAnimation.WAIT): {
return TJAPlayer3.Skin.Characters_Menu_Wait_AnimationDuration[_charaId];
}
case (ECharacterAnimation.ENTRY):
{
case (ECharacterAnimation.ENTRY): {
return TJAPlayer3.Skin.Characters_Title_Entry_AnimationDuration[_charaId];
}
case (ECharacterAnimation.ENTRY_NORMAL):
{
case (ECharacterAnimation.ENTRY_NORMAL): {
return TJAPlayer3.Skin.Characters_Title_Normal_AnimationDuration[_charaId];
}
}
return 1000;
}
public static void tDisableCounter(ECharacterAnimation eca)
{
switch (eca)
{
case (ECharacterAnimation.NORMAL):
{
public static void tDisableCounter(ECharacterAnimation eca) {
switch (eca) {
case (ECharacterAnimation.NORMAL): {
for (int i = 0; i < 5; i++)
ctCharacterNormal[i] = new CCounter();
break;
}
case (ECharacterAnimation.START):
{
case (ECharacterAnimation.START): {
for (int i = 0; i < 5; i++)
ctCharacterStart[i] = new CCounter();
break;
}
case (ECharacterAnimation.SELECT):
{
case (ECharacterAnimation.SELECT): {
for (int i = 0; i < 5; i++)
ctCharacterSelect[i] = new CCounter();
break;
}
case (ECharacterAnimation.WAIT):
{
case (ECharacterAnimation.WAIT): {
for (int i = 0; i < 5; i++)
ctCharacterWait[i] = new CCounter();
break;
}
case (ECharacterAnimation.ENTRY):
{
case (ECharacterAnimation.ENTRY): {
for (int i = 0; i < 5; i++)
ctCharacterEntry[i] = new CCounter();
break;
}
case (ECharacterAnimation.ENTRY_NORMAL):
{
case (ECharacterAnimation.ENTRY_NORMAL): {
for (int i = 0; i < 5; i++)
ctCharacterEntryNormal[i] = new CCounter();
break;
@ -255,35 +205,29 @@ namespace TJAPlayer3
}
public static void tMenuResetTimer(int player, ECharacterAnimation eca)
{
public static void tMenuResetTimer(int player, ECharacterAnimation eca) {
CTexture[] _ref = _getReferenceArray(player, eca);
CCounter[] _ctref = _getReferenceCounter(eca);
int _animeref = _getReferenceAnimationDuration(player, eca);
if (_ref != null && _ref.Length > 0 && _ctref != null)
{
if (_ref != null && _ref.Length > 0 && _ctref != null) {
_ctref[player] = new CCounter(0, _ref.Length - 1, _animeref / (float)_ref.Length, TJAPlayer3.Timer);
}
}
public static void tMenuResetTimer(ECharacterAnimation eca)
{
for (int i = 0; i < 5; i++)
{
public static void tMenuResetTimer(ECharacterAnimation eca) {
for (int i = 0; i < 5; i++) {
tMenuResetTimer(i, eca);
}
}
public static void tMenuDisplayCharacter(int player, int x, int y, ECharacterAnimation eca, int opacity = 255)
{
public static void tMenuDisplayCharacter(int player, int x, int y, ECharacterAnimation eca, int opacity = 255) {
int _charaId = TJAPlayer3.SaveFileInstances[TJAPlayer3.GetActualPlayer(player)].data.Character;
CTexture[] _ref = _getReferenceArray(player, eca);
CCounter[] _ctref = _getReferenceCounter(eca);
bool _substitute = _usesSubstituteTexture(player, eca);
if (_ctref[player] != null && _ref != null && _ctref[player].CurrentValue < _ref.Length)
{
if (_ctref[player] != null && _ref != null && _ctref[player].CurrentValue < _ref.Length) {
if (eca == ECharacterAnimation.NORMAL
|| eca == ECharacterAnimation.WAIT
|| eca == ECharacterAnimation.ENTRY
@ -311,8 +255,7 @@ namespace TJAPlayer3
float _x = x;
float _y = y;
if (player % 2 == 0)
{
if (player % 2 == 0) {
//_ref[_ctref[player].n現在の値].t2D描画(x, y);
//_ref[_ctref[player].n現在の値].t2D中心基準描画(x + 150, y + 156);
@ -323,9 +266,7 @@ namespace TJAPlayer3
}
else
{
} else {
//_ref[_ctref[player].n現在の値].t2D左右反転描画(x, y);
//_ref[_ctref[player].n現在の値].t2D中心基準描画Mirrored(x + 150, y + 156);

View File

@ -1,22 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using FDK;
using FDK;
namespace TJAPlayer3
{
class CResultCharacter
{
namespace TJAPlayer3 {
class CResultCharacter {
private static CCounter[] ctCharacterNormal = new CCounter[5] { new CCounter(), new CCounter(), new CCounter(), new CCounter(), new CCounter() };
private static CCounter[] ctCharacterClear = new CCounter[5] { new CCounter(), new CCounter(), new CCounter(), new CCounter(), new CCounter() };
private static CCounter[] ctCharacterFailed = new CCounter[5] { new CCounter(), new CCounter(), new CCounter(), new CCounter(), new CCounter() };
private static CCounter[] ctCharacterFailedIn = new CCounter[5] { new CCounter(), new CCounter(), new CCounter(), new CCounter(), new CCounter() };
public enum ECharacterResult
{
public enum ECharacterResult {
// Song select
NORMAL,
CLEAR,
@ -24,8 +16,7 @@ namespace TJAPlayer3
FAILED_IN,
}
public static bool tIsCounterProcessing(int player, ECharacterResult eca)
{
public static bool tIsCounterProcessing(int player, ECharacterResult eca) {
CCounter[] _ctref = _getReferenceCounter(eca);
if (_ctref[player] != null)
@ -33,8 +24,7 @@ namespace TJAPlayer3
return false;
}
public static bool tIsCounterEnded(int player, ECharacterResult eca)
{
public static bool tIsCounterEnded(int player, ECharacterResult eca) {
CCounter[] _ctref = _getReferenceCounter(eca);
if (_ctref[player] != null)
@ -42,34 +32,27 @@ namespace TJAPlayer3
return false;
}
private static bool _usesSubstituteTexture(int player, ECharacterResult eca)
{
private static bool _usesSubstituteTexture(int player, ECharacterResult eca) {
int _charaId = TJAPlayer3.SaveFileInstances[TJAPlayer3.GetActualPlayer(player)].data.Character;
if (_charaId >= 0 && _charaId < TJAPlayer3.Skin.Characters_Ptn)
{
switch (eca)
{
case (ECharacterResult.NORMAL):
{
if (_charaId >= 0 && _charaId < TJAPlayer3.Skin.Characters_Ptn) {
switch (eca) {
case (ECharacterResult.NORMAL): {
if (TJAPlayer3.Tx.Characters_Result_Normal[_charaId].Length > 0)
return false;
break;
}
case (ECharacterResult.CLEAR):
{
case (ECharacterResult.CLEAR): {
if (TJAPlayer3.Tx.Characters_Result_Clear[_charaId].Length > 0)
return false;
break;
}
case (ECharacterResult.FAILED):
{
case (ECharacterResult.FAILED): {
if (TJAPlayer3.Tx.Characters_Result_Failed[_charaId].Length > 0)
return false;
break;
}
case (ECharacterResult.FAILED_IN):
{
case (ECharacterResult.FAILED_IN): {
if (TJAPlayer3.Tx.Characters_Result_Failed_In[_charaId].Length > 0)
return false;
break;
@ -80,40 +63,33 @@ namespace TJAPlayer3
return true;
}
public static CTexture[] _getReferenceArray(int player, ECharacterResult eca)
{
public static CTexture[] _getReferenceArray(int player, ECharacterResult eca) {
int _charaId = TJAPlayer3.SaveFileInstances[TJAPlayer3.GetActualPlayer(player)].data.Character;
if (_charaId >= 0 && _charaId < TJAPlayer3.Skin.Characters_Ptn)
{
switch (eca)
{
case (ECharacterResult.NORMAL):
{
if (_charaId >= 0 && _charaId < TJAPlayer3.Skin.Characters_Ptn) {
switch (eca) {
case (ECharacterResult.NORMAL): {
if (TJAPlayer3.Tx.Characters_Result_Normal[_charaId].Length > 0)
return TJAPlayer3.Tx.Characters_Result_Normal[_charaId];
if (TJAPlayer3.Tx.Characters_Normal[_charaId].Length > 0)
return TJAPlayer3.Tx.Characters_Normal[_charaId];
break;
}
case (ECharacterResult.CLEAR):
{
case (ECharacterResult.CLEAR): {
if (TJAPlayer3.Tx.Characters_Result_Clear[_charaId].Length > 0)
return TJAPlayer3.Tx.Characters_Result_Clear[_charaId];
if (TJAPlayer3.Tx.Characters_10Combo[_charaId].Length > 0)
return TJAPlayer3.Tx.Characters_10Combo[_charaId];
break;
}
case (ECharacterResult.FAILED):
{
case (ECharacterResult.FAILED): {
if (TJAPlayer3.Tx.Characters_Result_Failed[_charaId].Length > 0)
return TJAPlayer3.Tx.Characters_Result_Failed[_charaId];
if (TJAPlayer3.Tx.Characters_Normal[_charaId].Length > 0)
return TJAPlayer3.Tx.Characters_Normal[_charaId];
break;
}
case (ECharacterResult.FAILED_IN):
{
case (ECharacterResult.FAILED_IN): {
if (TJAPlayer3.Tx.Characters_Result_Failed_In[_charaId].Length > 0)
return TJAPlayer3.Tx.Characters_Result_Failed_In[_charaId];
if (TJAPlayer3.Tx.Characters_Normal[_charaId].Length > 0)
@ -127,80 +103,62 @@ namespace TJAPlayer3
return null;
}
public static CCounter[] _getReferenceCounter(ECharacterResult eca)
{
switch (eca)
{
case (ECharacterResult.NORMAL):
{
public static CCounter[] _getReferenceCounter(ECharacterResult eca) {
switch (eca) {
case (ECharacterResult.NORMAL): {
return ctCharacterNormal;
}
case (ECharacterResult.CLEAR):
{
case (ECharacterResult.CLEAR): {
return ctCharacterClear;
}
case (ECharacterResult.FAILED):
{
case (ECharacterResult.FAILED): {
return ctCharacterFailed;
}
case (ECharacterResult.FAILED_IN):
{
case (ECharacterResult.FAILED_IN): {
return ctCharacterFailedIn;
}
}
return null;
}
public static int _getReferenceAnimationDuration(int player, ECharacterResult eca)
{
public static int _getReferenceAnimationDuration(int player, ECharacterResult eca) {
int _charaId = TJAPlayer3.SaveFileInstances[TJAPlayer3.GetActualPlayer(player)].data.Character;
switch (eca)
{
case (ECharacterResult.NORMAL):
{
switch (eca) {
case (ECharacterResult.NORMAL): {
return TJAPlayer3.Skin.Characters_Result_Normal_AnimationDuration[_charaId];
}
case (ECharacterResult.CLEAR):
{
case (ECharacterResult.CLEAR): {
return TJAPlayer3.Skin.Characters_Result_Clear_AnimationDuration[_charaId];
}
case (ECharacterResult.FAILED):
{
case (ECharacterResult.FAILED): {
return TJAPlayer3.Skin.Characters_Result_Failed_AnimationDuration[_charaId];
}
case (ECharacterResult.FAILED_IN):
{
case (ECharacterResult.FAILED_IN): {
return TJAPlayer3.Skin.Characters_Result_Failed_In_AnimationDuration[_charaId];
}
}
return 1000;
}
public static void tDisableCounter(ECharacterResult eca)
{
switch (eca)
{
case (ECharacterResult.NORMAL):
{
public static void tDisableCounter(ECharacterResult eca) {
switch (eca) {
case (ECharacterResult.NORMAL): {
for (int i = 0; i < 5; i++)
ctCharacterNormal[i] = new CCounter();
break;
}
case (ECharacterResult.CLEAR):
{
case (ECharacterResult.CLEAR): {
for (int i = 0; i < 5; i++)
ctCharacterClear[i] = new CCounter();
break;
}
case (ECharacterResult.FAILED):
{
case (ECharacterResult.FAILED): {
for (int i = 0; i < 5; i++)
ctCharacterFailed[i] = new CCounter();
break;
}
case (ECharacterResult.FAILED_IN):
{
case (ECharacterResult.FAILED_IN): {
for (int i = 0; i < 5; i++)
ctCharacterFailedIn[i] = new CCounter();
break;
@ -210,35 +168,29 @@ namespace TJAPlayer3
}
public static void tMenuResetTimer(int player, ECharacterResult eca)
{
public static void tMenuResetTimer(int player, ECharacterResult eca) {
CTexture[] _ref = _getReferenceArray(player, eca);
CCounter[] _ctref = _getReferenceCounter(eca);
int _animeref = _getReferenceAnimationDuration(player, eca);
if (_ref != null && _ref.Length > 0 && _ctref != null)
{
if (_ref != null && _ref.Length > 0 && _ctref != null) {
_ctref[player] = new CCounter(0, _ref.Length - 1, _animeref / (float)_ref.Length, TJAPlayer3.Timer);
}
}
public static void tMenuResetTimer(ECharacterResult eca)
{
for (int i = 0; i < 5; i++)
{
public static void tMenuResetTimer(ECharacterResult eca) {
for (int i = 0; i < 5; i++) {
tMenuResetTimer(i, eca);
}
}
public static void tMenuDisplayCharacter(int player, int x, int y, ECharacterResult eca, int pos = 0, int opacity = 255)
{
public static void tMenuDisplayCharacter(int player, int x, int y, ECharacterResult eca, int pos = 0, int opacity = 255) {
int _charaId = TJAPlayer3.SaveFileInstances[TJAPlayer3.GetActualPlayer(player)].data.Character;
CTexture[] _ref = _getReferenceArray(player, eca);
CCounter[] _ctref = _getReferenceCounter(eca);
bool _substitute = _usesSubstituteTexture(player, eca);
if (_ctref[player] != null && _ref != null && _ctref[player].CurrentValue < _ref.Length)
{
if (_ctref[player] != null && _ref != null && _ctref[player].CurrentValue < _ref.Length) {
if (eca == ECharacterResult.NORMAL
|| eca == ECharacterResult.CLEAR
|| eca == ECharacterResult.FAILED)
@ -268,15 +220,12 @@ namespace TJAPlayer3
_tex.vcScaleRatio.X *= resolutionRatioX;
_tex.vcScaleRatio.Y *= resolutionRatioY;
if (pos % 2 == 0 || TJAPlayer3.ConfigIni.nPlayerCount > 2)
{
if (pos % 2 == 0 || TJAPlayer3.ConfigIni.nPlayerCount > 2) {
_tex.t2D拡大率考慮下中心基準描画(
_x,
_y
);
}
else
{
} else {
_tex.t2D拡大率考慮下中心基準描画Mirrored(
_x,
_y

View File

@ -1,41 +1,28 @@
using TJAPlayer3;
using FDK;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using FDK;
using Silk.NET.Maths;
using Rectangle = System.Drawing.Rectangle;
namespace TJAPlayer3
{
class PuchiChara : CActivity
{
public PuchiChara()
{
namespace TJAPlayer3 {
class PuchiChara : CActivity {
public PuchiChara() {
base.IsDeActivated = true;
}
public override void Activate()
{
public override void Activate() {
Counter = new CCounter(0, TJAPlayer3.Skin.Game_PuchiChara[2] - 1, TJAPlayer3.Skin.Game_PuchiChara_Timer * 0.5f, TJAPlayer3.Timer);
SineCounter = new CCounter(0, 360, TJAPlayer3.Skin.Game_PuchiChara_SineTimer, SoundManager.PlayTimer);
SineCounterIdle = new CCounter(1, 360, (float)TJAPlayer3.Skin.Game_PuchiChara_SineTimer * 2f, TJAPlayer3.Timer);
this.inGame = false;
base.Activate();
}
public override void DeActivate()
{
public override void DeActivate() {
Counter = null;
SineCounter = null;
SineCounterIdle = null;
base.DeActivate();
}
public static int tGetPuchiCharaIndexByName(int p)
{
public static int tGetPuchiCharaIndexByName(int p) {
var _pc = TJAPlayer3.SaveFileInstances[p].data.PuchiChara;
var _pcs = TJAPlayer3.Skin.Puchicharas_Name;
int puriChar = 0;
@ -45,15 +32,13 @@ namespace TJAPlayer3
return puriChar;
}
public void ChangeBPM(double bpm)
{
public void ChangeBPM(double bpm) {
Counter = new CCounter(0, TJAPlayer3.Skin.Game_PuchiChara[2] - 1, (int)(TJAPlayer3.Skin.Game_PuchiChara_Timer * bpm / TJAPlayer3.Skin.Game_PuchiChara[2]), TJAPlayer3.Timer);
SineCounter = new CCounter(1, 360, TJAPlayer3.Skin.Game_PuchiChara_SineTimer * bpm / 180, SoundManager.PlayTimer);
this.inGame = true;
}
public void IdleAnimation()
{
public void IdleAnimation() {
this.inGame = false;
}
@ -64,8 +49,7 @@ namespace TJAPlayer3
/// <param name="y">Y座標(中央)</param>
/// <param name="alpha">不透明度</param>
/// <returns></returns>
public int On進行描画(int x, int y, bool isGrowing, int alpha = 255, bool isBalloon = false, int player = 0, float scale = 1.0f)
{
public int On進行描画(int x, int y, bool isGrowing, int alpha = 255, bool isBalloon = false, int player = 0, float scale = 1.0f) {
if (!TJAPlayer3.ConfigIni.ShowPuchiChara) return base.Draw();
if (Counter == null || SineCounter == null || TJAPlayer3.Tx.Puchichara == null) return base.Draw();
Counter.TickLoop();
@ -98,8 +82,7 @@ namespace TJAPlayer3
var chara = TJAPlayer3.Tx.Puchichara[puriChar].tx;
//TJAPlayer3.Tx.PuchiChara[puriChar];
if (chara != null)
{
if (chara != null) {
float puchiScale = TJAPlayer3.Skin.Resolution[1] / 720.0f;
chara.vcScaleRatio = new Vector3D<float>((isBalloon ? TJAPlayer3.Skin.Game_PuchiChara_Scale[1] * puchiScale : TJAPlayer3.Skin.Game_PuchiChara_Scale[0] * puchiScale));

View File

@ -1,17 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace TJAPlayer3 {
internal class BestPlayRecords {
namespace TJAPlayer3
{
internal class BestPlayRecords
{
public enum EClearStatus
{
public enum EClearStatus {
NONE = 0,
ASSISTED_CLEAR = 1,
CLEAR = 2,
@ -20,8 +10,7 @@ namespace TJAPlayer3
TOTAL = 5
}
public enum EDanClearStatus
{
public enum EDanClearStatus {
NONE = 0,
ASSISTED_CLEAR_RED = 1,
ASSISTED_CLEAR_GOLD = 2,
@ -34,8 +23,7 @@ namespace TJAPlayer3
TOTAL = 9
}
public enum ETowerClearStatus
{
public enum ETowerClearStatus {
NONE = 0,
ASSISTED_CLEAR = 1,
PROGRESS_10 = 2,
@ -48,8 +36,7 @@ namespace TJAPlayer3
TOTAL = 9
}
public class CSongSelectTableEntry
{
public class CSongSelectTableEntry {
public int ScoreRankDifficulty = 0;
public int ScoreRank = -1;
public int ClearStatusDifficulty = 0;
@ -60,8 +47,7 @@ namespace TJAPlayer3
public int[] HighScore = new int[(int)Difficulty.Total] { 0, 0, 0, 0, 0, 0, 0 };
}
public class CBestPlayRecord
{
public class CBestPlayRecord {
public string ChartUniqueId = "none";
public string ChartGenre = "none";
public string Charter = "none";
@ -90,8 +76,7 @@ namespace TJAPlayer3
public Int64 HighScoreBoomCount = 0;
}
public class CBestPlayStats
{
public class CBestPlayStats {
public int DistinctPlays = 0;
public int DistinctClears = 0;
public int DistinctFCs = 0;
@ -119,8 +104,7 @@ namespace TJAPlayer3
public Dictionary<string, int> CharterFCs = new Dictionary<string, int>();
public Dictionary<string, int> CharterPerfects = new Dictionary<string, int>();
public CBestPlayStats()
{
public CBestPlayStats() {
// 0 : Not clear, 1 : Assisted clear, 2 : Clear, 3 : FC, 4 : Perfect
ClearStatuses[0] = new int[(int)EClearStatus.TOTAL] { 0, 0, 0, 0, 0 };
ClearStatuses[1] = new int[(int)EClearStatus.TOTAL] { 0, 0, 0, 0, 0 };
@ -139,8 +123,7 @@ namespace TJAPlayer3
}
}
static private void InitOrAddDict<T>(Dictionary<T, int> dict, T entry) where T : notnull
{
static private void InitOrAddDict<T>(Dictionary<T, int> dict, T entry) where T : notnull {
if (!dict.ContainsKey(entry))
dict[entry] = 0;
dict[entry]++;
@ -149,24 +132,20 @@ namespace TJAPlayer3
static public CBestPlayStats tGenerateBestPlayStats(
Dictionary<string, CBestPlayRecord>.ValueCollection uniqueChartBestPlays,
Dictionary<string, CBestPlayRecord>.ValueCollection uniqueSongBestPlays
)
{
) {
CBestPlayStats stats = new CBestPlayStats();
// Individual charts
foreach (CBestPlayRecord record in uniqueChartBestPlays)
{
foreach (CBestPlayRecord record in uniqueChartBestPlays) {
Int64 roundedDifficulty = Math.Max((int)Difficulty.Easy, Math.Min((int)Difficulty.Total - 1, record.ChartDifficulty));
if (roundedDifficulty <= (int)Difficulty.Edit)
{
if (roundedDifficulty <= (int)Difficulty.Edit) {
string[] ChartersArr = record.Charter.SplitByCommas();
Int64 roundedScoreRank = Math.Max(0, Math.Min(7, record.ScoreRank + 1));
Int64 roundedClearStatus = Math.Max((int)EClearStatus.NONE, Math.Min((int)EClearStatus.PERFECT, record.ClearStatus + 1));
stats.ScoreRanks[roundedDifficulty][roundedScoreRank]++;
stats.ClearStatuses[roundedDifficulty][roundedClearStatus]++;
foreach (string Charter in ChartersArr)
{
foreach (string Charter in ChartersArr) {
InitOrAddDict(stats.CharterPlays, Charter);
if (roundedClearStatus >= (int)EClearStatus.CLEAR) InitOrAddDict(stats.CharterClears, Charter);
if (roundedClearStatus >= (int)EClearStatus.FC) InitOrAddDict(stats.CharterFCs, Charter);
@ -184,15 +163,11 @@ namespace TJAPlayer3
if (roundedClearStatus >= (int)EClearStatus.CLEAR) stats.DistinctClears++;
if (roundedClearStatus >= (int)EClearStatus.FC) stats.DistinctFCs++;
if (roundedClearStatus == (int)EClearStatus.PERFECT) stats.DistinctPerfects++;
}
else if (roundedDifficulty == (int)Difficulty.Tower)
{
} else if (roundedDifficulty == (int)Difficulty.Tower) {
Int64 roundedClearStatus = Math.Clamp(record.ClearStatus + 1, (int)ETowerClearStatus.NONE, (int)ETowerClearStatus.TOTAL);
stats.ClearStatuses[roundedDifficulty][roundedClearStatus]++;
}
else if (roundedDifficulty == (int)Difficulty.Dan)
{
} else if (roundedDifficulty == (int)Difficulty.Dan) {
Int64 roundedClearStatus = Math.Clamp(record.ClearStatus + 1, (int)EDanClearStatus.NONE, (int)EDanClearStatus.TOTAL);
stats.ClearStatuses[roundedDifficulty][roundedClearStatus]++;
@ -200,12 +175,10 @@ namespace TJAPlayer3
}
// Individual songs
foreach (CBestPlayRecord record in uniqueSongBestPlays)
{
foreach (CBestPlayRecord record in uniqueSongBestPlays) {
Int64 roundedDifficulty = Math.Max((int)Difficulty.Easy, Math.Min((int)Difficulty.Total - 1, record.ChartDifficulty));
if (roundedDifficulty <= (int)Difficulty.Edit)
{
if (roundedDifficulty <= (int)Difficulty.Edit) {
Int64 roundedClearStatus = Math.Max((int)EClearStatus.NONE, Math.Min((int)EClearStatus.PERFECT, record.ClearStatus + 1));
InitOrAddDict(stats.SongGenrePlays, record.ChartGenre);

File diff suppressed because it is too large Load Diff

View File

@ -1,27 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Security.Cryptography;
namespace TJAPlayer3
{
internal class CCrypto
{
namespace TJAPlayer3 {
internal class CCrypto {
internal static readonly char[] chars =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890".ToCharArray();
public static string GetUniqueKey(int size)
{
public static string GetUniqueKey(int size) {
byte[] data = new byte[4 * size];
using (var crypto = RandomNumberGenerator.Create())
{
using (var crypto = RandomNumberGenerator.Create()) {
crypto.GetBytes(data);
}
StringBuilder result = new StringBuilder(size);
for (int i = 0; i < size; i++)
{
for (int i = 0; i < size; i++) {
var rnd = BitConverter.ToUInt32(data, i * 4);
var idx = rnd % chars.Length;

View File

@ -1,23 +1,18 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Text;
namespace TJAPlayer3
{
namespace TJAPlayer3 {
/// <summary>
/// <para>DTXMania のバージョン。</para>
/// <para>例1"078b" → 整数部=078, 小数部=2000000 ('英字'+'yymmdd') </para>
/// <para>例2"078a(100124)" → 整数部=078, 小数部=1100124 ('英字'+'yymmdd')</para>
/// </summary>
public class CDTXVersion
{
public class CDTXVersion {
// プロパティ
/// <summary>
/// <para>バージョンが未知のときに true になる。</para>
/// </summary>
public bool Unknown
{
public bool Unknown {
get;
private set;
}
@ -40,79 +35,62 @@ namespace TJAPlayer3
// コンストラクタ
public CDTXVersion()
{
public CDTXVersion() {
this.n整数部 = 0;
this.n小数部 = 0;
this.Unknown = true;
}
public CDTXVersion( int n整数部 )
{
public CDTXVersion(int n整数部) {
this.n整数部 = n整数部;
this.n小数部 = 0;
this.Unknown = false;
}
public CDTXVersion( string Version )
{
public CDTXVersion(string Version) {
this.n整数部 = 0;
this.n小数部 = 0;
this.Unknown = true;
if( Version.ToLower().Equals( "unknown" ) )
{
if (Version.ToLower().Equals("unknown")) {
this.Unknown = true;
}
else
{
} else {
int num = 0;
int length = Version.Length;
if( ( num < length ) && char.IsDigit( Version[ num ] ) )
{
if ((num < length) && char.IsDigit(Version[num])) {
// 整数部 取得
while( ( num < length ) && char.IsDigit( Version[ num ] ) )
{
this.n整数部 = ( this.n整数部 * 10 ) + CDTXVersion.DIG10.IndexOf( Version[ num++ ] );
while ((num < length) && char.IsDigit(Version[num])) {
this.n整数部 = (this.n整数部 * 10) + CDTXVersion.DIG10.IndexOf(Version[num++]);
}
// 小数部(1)英字部分 取得
while( ( num < length ) && ( ( Version[ num ] == ' ' ) || ( Version[ num ] == '(' ) ) )
{
while ((num < length) && ((Version[num] == ' ') || (Version[num] == '('))) {
num++;
}
if( ( num < length ) && ( CDTXVersion.DIG36.IndexOf( Version[ num ] ) >= 10 ) )
{
this.n小数部 = CDTXVersion.DIG36.IndexOf( Version[ num++ ] ) - 10;
if( this.n小数部 >= 0x1a )
{
if ((num < length) && (CDTXVersion.DIG36.IndexOf(Version[num]) >= 10)) {
this.n小数部 = CDTXVersion.DIG36.IndexOf(Version[num++]) - 10;
if (this.n小数部 >= 0x1a) {
this.n小数部 -= 0x1a;
}
this.n小数部++;
}
// 小数部(2)日付部分(yymmdd) 取得
while( ( num < length ) && ( ( Version[ num ] == ' ' ) || ( Version[ num ] == '(' ) ) )
{
while ((num < length) && ((Version[num] == ' ') || (Version[num] == '('))) {
num++;
}
for( int i = 0; i < 6; i++ )
{
for (int i = 0; i < 6; i++) {
this.n小数部 *= 10;
if( ( num < length ) && char.IsDigit( Version[ num ] ) )
{
this.n小数部 += CDTXVersion.DIG10.IndexOf( Version[ num ] );
if ((num < length) && char.IsDigit(Version[num])) {
this.n小数部 += CDTXVersion.DIG10.IndexOf(Version[num]);
}
num++;
}
this.Unknown = false;
}
else
{
} else {
this.Unknown = true;
}
}
}
public CDTXVersion( int n整数部, int n小数部 )
{
public CDTXVersion(int n整数部, int n小数部) {
this.n整数部 = n整数部;
this.n小数部 = n小数部;
this.Unknown = false;
@ -121,73 +99,60 @@ namespace TJAPlayer3
// メソッド
public string toString()
{
var result = new StringBuilder( 32 );
public string toString() {
var result = new StringBuilder(32);
// 整数部
result.Append( this.n整数部.ToString( "000" ) );
result.Append(this.n整数部.ToString("000"));
// 英字部分(あれば)
if( this.n小数部 >= 1000000 )
{
int n英字 = Math.Min( this.n小数部 / 1000000, 26 ); // 126
result.Append( CDTXVersion.DIG36[ 10 + ( n英字 - 1 ) ] );
if (this.n小数部 >= 1000000) {
int n英字 = Math.Min(this.n小数部 / 1000000, 26); // 126
result.Append(CDTXVersion.DIG36[10 + (n英字 - 1)]);
}
// 日付部分(あれば)
int n日付 = this.n小数部 % 1000000;
if( n日付 > 0 )
{
result.Append( '(' );
result.Append( n日付.ToString( "000000" ) );
result.Append( ')' );
if (n日付 > 0) {
result.Append('(');
result.Append(n日付.ToString("000000"));
result.Append(')');
}
return result.ToString();
}
public static bool operator ==( CDTXVersion x, CDTXVersion y )
{
return ( ( ( x.n整数部 == y.n整数部 ) && ( x.n小数部 == y.n小数部 ) ) && ( x.Unknown == y.Unknown ) );
public static bool operator ==(CDTXVersion x, CDTXVersion y) {
return (((x.n整数部 == y.n整数部) && (x.n小数部 == y.n小数部)) && (x.Unknown == y.Unknown));
}
public static bool operator >( CDTXVersion x, CDTXVersion y )
{
return ( ( x.n整数部 > y.n整数部 ) || ( ( x.n整数部 == y.n整数部 ) && ( x.n小数部 > y.n小数部 ) ) );
public static bool operator >(CDTXVersion x, CDTXVersion y) {
return ((x.n整数部 > y.n整数部) || ((x.n整数部 == y.n整数部) && (x.n小数部 > y.n小数部)));
}
public static bool operator >=( CDTXVersion x, CDTXVersion y )
{
return ( ( x.n整数部 > y.n整数部 ) || ( ( x.n整数部 == y.n整数部 ) && ( x.n小数部 >= y.n小数部 ) ) );
public static bool operator >=(CDTXVersion x, CDTXVersion y) {
return ((x.n整数部 > y.n整数部) || ((x.n整数部 == y.n整数部) && (x.n小数部 >= y.n小数部)));
}
public static bool operator !=( CDTXVersion x, CDTXVersion y )
{
if( ( x.n整数部 == y.n整数部 ) && ( x.n小数部 == y.n小数部 ) )
{
return ( x.Unknown != y.Unknown );
public static bool operator !=(CDTXVersion x, CDTXVersion y) {
if ((x.n整数部 == y.n整数部) && (x.n小数部 == y.n小数部)) {
return (x.Unknown != y.Unknown);
}
return true;
}
public static bool operator <( CDTXVersion x, CDTXVersion y )
{
return ( ( x.n整数部 < y.n整数部 ) || ( ( x.n整数部 == y.n整数部 ) && ( x.n小数部 < y.n小数部 ) ) );
public static bool operator <(CDTXVersion x, CDTXVersion y) {
return ((x.n整数部 < y.n整数部) || ((x.n整数部 == y.n整数部) && (x.n小数部 < y.n小数部)));
}
public static bool operator <=( CDTXVersion x, CDTXVersion y )
{
return ( ( x.n整数部 < y.n整数部 ) || ( ( x.n整数部 == y.n整数部 ) && ( x.n小数部 <= y.n小数部 ) ) );
public static bool operator <=(CDTXVersion x, CDTXVersion y) {
return ((x.n整数部 < y.n整数部) || ((x.n整数部 == y.n整数部) && (x.n小数部 <= y.n小数部)));
}
public override bool Equals(object obj) // 2011.1.3 yyagi: warningを無くすために追加
{
if (obj == null)
{
if (obj == null) {
return false;
}
if (this.GetType() != obj.GetType())
{
if (this.GetType() != obj.GetType()) {
return false;
}
CDTXVersion objCDTXVersion = (CDTXVersion)obj;
if (!int.Equals(this.n整数部, objCDTXVersion.n整数部) || !int.Equals(this.n小数部, objCDTXVersion.n小数部))
{
if (!int.Equals(this.n整数部, objCDTXVersion.n整数部) || !int.Equals(this.n小数部, objCDTXVersion.n小数部)) {
return false;
}
return true;

View File

@ -1,24 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TJAPlayer3
{
class CHitSounds
{
public CHitSounds(string path)
{
namespace TJAPlayer3 {
class CHitSounds {
public CHitSounds(string path) {
tLoadFile(path);
for (int i = 0; i < 5; i++)
{
for (int i = 0; i < 5; i++) {
tReloadHitSounds(TJAPlayer3.ConfigIni.nHitSounds[i], i);
}
}
public bool tReloadHitSounds(int id, int player)
{
public bool tReloadHitSounds(int id, int player) {
if (id >= names.Length || id >= data.Length)
return false;
@ -46,8 +35,7 @@ namespace TJAPlayer3
#region [private]
private class HitSoundsData
{
private class HitSoundsData {
public string name;
public string path;
public string format;
@ -55,14 +43,12 @@ namespace TJAPlayer3
private HitSoundsData[] data;
private void tLoadFile(string path)
{
private void tLoadFile(string path) {
data = ConfigManager.GetConfig<List<HitSoundsData>>(path).ToArray();
names = new string[data.Length];
for (int i = 0; i < data.Length; i++)
{
for (int i = 0; i < data.Length; i++) {
names[i] = data[i].name;
}
}

View File

@ -1,26 +1,19 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices;
using FDK;
namespace TJAPlayer3
{
public class CPad
{
namespace TJAPlayer3 {
public class CPad {
// プロパティ
internal STHIT st検知したデバイス;
[StructLayout( LayoutKind.Sequential )]
internal struct STHIT
{
[StructLayout(LayoutKind.Sequential)]
internal struct STHIT {
public bool Keyboard;
public bool MIDIIN;
public bool Joypad;
public bool Gamepad;
public bool Mouse;
public void Clear()
{
public void Clear() {
this.Keyboard = false;
this.MIDIIN = false;
this.Joypad = false;
@ -31,8 +24,7 @@ namespace TJAPlayer3
// コンストラクタ
internal CPad( CConfigIni configIni, CInputManager mgrInput )
{
internal CPad(CConfigIni configIni, CInputManager mgrInput) {
this.rConfigIni = configIni;
this.rInput管理 = mgrInput;
this.st検知したデバイス.Clear();
@ -41,58 +33,47 @@ namespace TJAPlayer3
// メソッド
public List<STInputEvent> GetEvents( EInstrumentPad part, EPad pad )
{
CConfigIni.CKeyAssign.STKEYASSIGN[] stkeyassignArray = this.rConfigIni.KeyAssign[ (int) part ][ (int) pad ];
public List<STInputEvent> GetEvents(EInstrumentPad part, EPad pad) {
CConfigIni.CKeyAssign.STKEYASSIGN[] stkeyassignArray = this.rConfigIni.KeyAssign[(int)part][(int)pad];
List<STInputEvent> list = new List<STInputEvent>();
// すべての入力デバイスについて…
foreach( IInputDevice device in this.rInput管理.InputDevices )
{
if( ( device.InputEvents != null ) && ( device.InputEvents.Count != 0 ) )
{
foreach( STInputEvent event2 in device.InputEvents )
{
for( int i = 0; i < stkeyassignArray.Length; i++ )
{
switch( stkeyassignArray[ i ]. )
{
foreach (IInputDevice device in this.rInput管理.InputDevices) {
if ((device.InputEvents != null) && (device.InputEvents.Count != 0)) {
foreach (STInputEvent event2 in device.InputEvents) {
for (int i = 0; i < stkeyassignArray.Length; i++) {
switch (stkeyassignArray[i].) {
case EInputDevice.Keyboard:
if( ( device.CurrentType == InputDeviceType.Keyboard ) && ( event2.nKey == stkeyassignArray[ i ]. ) )
{
list.Add( event2 );
if ((device.CurrentType == InputDeviceType.Keyboard) && (event2.nKey == stkeyassignArray[i].)) {
list.Add(event2);
this.st検知したデバイス.Keyboard = true;
}
break;
case EInputDevice.MIDIInput:
if( ( ( device.CurrentType == InputDeviceType.MidiIn ) && ( device.ID == stkeyassignArray[ i ].ID ) ) && ( event2.nKey == stkeyassignArray[ i ]. ) )
{
list.Add( event2 );
if (((device.CurrentType == InputDeviceType.MidiIn) && (device.ID == stkeyassignArray[i].ID)) && (event2.nKey == stkeyassignArray[i].)) {
list.Add(event2);
this.st検知したデバイス.MIDIIN = true;
}
break;
case EInputDevice.Joypad:
if( ( ( device.CurrentType == InputDeviceType.Joystick ) && ( device.ID == stkeyassignArray[ i ].ID ) ) && ( event2.nKey == stkeyassignArray[ i ]. ) )
{
list.Add( event2 );
if (((device.CurrentType == InputDeviceType.Joystick) && (device.ID == stkeyassignArray[i].ID)) && (event2.nKey == stkeyassignArray[i].)) {
list.Add(event2);
this.st検知したデバイス.Joypad = true;
}
break;
case EInputDevice.Gamepad:
if( ( ( device.CurrentType == InputDeviceType.Gamepad ) && ( device.ID == stkeyassignArray[ i ].ID ) ) && ( event2.nKey == stkeyassignArray[ i ]. ) )
{
list.Add( event2 );
if (((device.CurrentType == InputDeviceType.Gamepad) && (device.ID == stkeyassignArray[i].ID)) && (event2.nKey == stkeyassignArray[i].)) {
list.Add(event2);
this.st検知したデバイス.Gamepad = true;
}
break;
case EInputDevice.Mouse:
if( ( device.CurrentType == InputDeviceType.Mouse ) && ( event2.nKey == stkeyassignArray[ i ]. ) )
{
list.Add( event2 );
if ((device.CurrentType == InputDeviceType.Mouse) && (event2.nKey == stkeyassignArray[i].)) {
list.Add(event2);
this.st検知したデバイス.Mouse = true;
}
break;
@ -104,58 +85,51 @@ namespace TJAPlayer3
}
return list;
}
public bool bPressed( EInstrumentPad part, EPad pad )
{
if( part != EInstrumentPad.UNKNOWN )
{
public bool bPressed(EInstrumentPad part, EPad pad) {
if (part != EInstrumentPad.UNKNOWN) {
CConfigIni.CKeyAssign.STKEYASSIGN[] stkeyassignArray = this.rConfigIni.KeyAssign[ (int) part ][ (int) pad ];
for( int i = 0; i < stkeyassignArray.Length; i++ )
{
switch( stkeyassignArray[ i ]. )
{
CConfigIni.CKeyAssign.STKEYASSIGN[] stkeyassignArray = this.rConfigIni.KeyAssign[(int)part][(int)pad];
for (int i = 0; i < stkeyassignArray.Length; i++) {
switch (stkeyassignArray[i].) {
case EInputDevice.Keyboard:
if( !this.rInput管理.Keyboard.KeyPressed( stkeyassignArray[ i ]. ) )
if (!this.rInput管理.Keyboard.KeyPressed(stkeyassignArray[i].))
break;
this.st検知したデバイス.Keyboard = true;
return true;
case EInputDevice.MIDIInput:
{
IInputDevice device2 = this.rInput管理.MidiIn( stkeyassignArray[ i ].ID );
if( ( device2 == null ) || !device2.KeyPressed( stkeyassignArray[ i ]. ) )
case EInputDevice.MIDIInput: {
IInputDevice device2 = this.rInput管理.MidiIn(stkeyassignArray[i].ID);
if ((device2 == null) || !device2.KeyPressed(stkeyassignArray[i].))
break;
this.st検知したデバイス.MIDIIN = true;
return true;
}
case EInputDevice.Joypad:
{
if( !this.rConfigIni.dicJoystick.ContainsKey( stkeyassignArray[ i ].ID ) )
case EInputDevice.Joypad: {
if (!this.rConfigIni.dicJoystick.ContainsKey(stkeyassignArray[i].ID))
break;
IInputDevice device = this.rInput管理.Joystick( stkeyassignArray[ i ].ID );
if( ( device == null ) || !device.KeyPressed( stkeyassignArray[ i ]. ) )
IInputDevice device = this.rInput管理.Joystick(stkeyassignArray[i].ID);
if ((device == null) || !device.KeyPressed(stkeyassignArray[i].))
break;
this.st検知したデバイス.Joypad = true;
return true;
}
case EInputDevice.Gamepad:
{
if( !this.rConfigIni.dicJoystick.ContainsKey( stkeyassignArray[ i ].ID ) )
case EInputDevice.Gamepad: {
if (!this.rConfigIni.dicJoystick.ContainsKey(stkeyassignArray[i].ID))
break;
IInputDevice device = this.rInput管理.Gamepad( stkeyassignArray[ i ].ID );
if( ( device == null ) || !device.KeyPressed( stkeyassignArray[ i ]. ) )
IInputDevice device = this.rInput管理.Gamepad(stkeyassignArray[i].ID);
if ((device == null) || !device.KeyPressed(stkeyassignArray[i].))
break;
this.st検知したデバイス.Gamepad = true;
return true;
}
case EInputDevice.Mouse:
if( !this.rInput管理.Mouse.KeyPressed( stkeyassignArray[ i ]. ) )
if (!this.rInput管理.Mouse.KeyPressed(stkeyassignArray[i].))
break;
this.st検知したデバイス.Mouse = true;
@ -165,71 +139,55 @@ namespace TJAPlayer3
}
return false;
}
public bool bPressedDGB( EPad pad )
{
if( !this.bPressed( EInstrumentPad.DRUMS, pad ) && !this.bPressed( EInstrumentPad.GUITAR, pad ) )
{
return this.bPressed( EInstrumentPad.BASS, pad );
public bool bPressedDGB(EPad pad) {
if (!this.bPressed(EInstrumentPad.DRUMS, pad) && !this.bPressed(EInstrumentPad.GUITAR, pad)) {
return this.bPressed(EInstrumentPad.BASS, pad);
}
return true;
}
public bool bPressedGB( EPad pad )
{
if( !this.bPressed( EInstrumentPad.GUITAR, pad ) )
{
return this.bPressed( EInstrumentPad.BASS, pad );
public bool bPressedGB(EPad pad) {
if (!this.bPressed(EInstrumentPad.GUITAR, pad)) {
return this.bPressed(EInstrumentPad.BASS, pad);
}
return true;
}
public bool b押されている( EInstrumentPad part, EPad pad )
{
if( part != EInstrumentPad.UNKNOWN )
{
CConfigIni.CKeyAssign.STKEYASSIGN[] stkeyassignArray = this.rConfigIni.KeyAssign[ (int) part ][ (int) pad ];
for( int i = 0; i < stkeyassignArray.Length; i++ )
{
switch( stkeyassignArray[ i ]. )
{
public bool b押されている(EInstrumentPad part, EPad pad) {
if (part != EInstrumentPad.UNKNOWN) {
CConfigIni.CKeyAssign.STKEYASSIGN[] stkeyassignArray = this.rConfigIni.KeyAssign[(int)part][(int)pad];
for (int i = 0; i < stkeyassignArray.Length; i++) {
switch (stkeyassignArray[i].) {
case EInputDevice.Keyboard:
if( !this.rInput管理.Keyboard.KeyPressing( stkeyassignArray[ i ]. ) )
{
if (!this.rInput管理.Keyboard.KeyPressing(stkeyassignArray[i].)) {
break;
}
this.st検知したデバイス.Keyboard = true;
return true;
case EInputDevice.Joypad:
{
if( !this.rConfigIni.dicJoystick.ContainsKey( stkeyassignArray[ i ].ID ) )
{
case EInputDevice.Joypad: {
if (!this.rConfigIni.dicJoystick.ContainsKey(stkeyassignArray[i].ID)) {
break;
}
IInputDevice device = this.rInput管理.Joystick( stkeyassignArray[ i ].ID );
if( ( device == null ) || !device.KeyPressing( stkeyassignArray[ i ]. ) )
{
IInputDevice device = this.rInput管理.Joystick(stkeyassignArray[i].ID);
if ((device == null) || !device.KeyPressing(stkeyassignArray[i].)) {
break;
}
this.st検知したデバイス.Joypad = true;
return true;
}
case EInputDevice.Gamepad:
{
if( !this.rConfigIni.dicJoystick.ContainsKey( stkeyassignArray[ i ].ID ) )
{
case EInputDevice.Gamepad: {
if (!this.rConfigIni.dicJoystick.ContainsKey(stkeyassignArray[i].ID)) {
break;
}
IInputDevice device = this.rInput管理.Gamepad( stkeyassignArray[ i ].ID );
if( ( device == null ) || !device.KeyPressing( stkeyassignArray[ i ]. ) )
{
IInputDevice device = this.rInput管理.Gamepad(stkeyassignArray[i].ID);
if ((device == null) || !device.KeyPressing(stkeyassignArray[i].)) {
break;
}
this.st検知したデバイス.Gamepad = true;
return true;
}
case EInputDevice.Mouse:
if( !this.rInput管理.Mouse.KeyPressing( stkeyassignArray[ i ]. ) )
{
if (!this.rInput管理.Mouse.KeyPressing(stkeyassignArray[i].)) {
break;
}
this.st検知したデバイス.Mouse = true;
@ -239,11 +197,9 @@ namespace TJAPlayer3
}
return false;
}
public bool b押されているGB( EPad pad )
{
if( !this.b押されている( EInstrumentPad.GUITAR, pad ) )
{
return this.b押されている( EInstrumentPad.BASS, pad );
public bool b押されているGB(EPad pad) {
if (!this.b押されている(EInstrumentPad.GUITAR, pad)) {
return this.b押されている(EInstrumentPad.BASS, pad);
}
return true;
}

View File

@ -1,22 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
namespace TJAPlayer3
{
class CSavableT<T> where T : new()
{
public virtual string _fn
{
namespace TJAPlayer3 {
class CSavableT<T> where T : new() {
public virtual string _fn {
get;
protected set;
}
public void tDBInitSavable()
{
public void tDBInitSavable() {
if (!File.Exists(_fn))
tSaveFile();
@ -27,13 +15,11 @@ namespace TJAPlayer3
#region [private]
private void tSaveFile()
{
private void tSaveFile() {
ConfigManager.SaveConfig(data, _fn);
}
private void tLoadFile()
{
private void tLoadFile() {
data = ConfigManager.GetConfig<T>(_fn);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,14 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.Drawing;
namespace TJAPlayer3
{
internal class CSongDict
{
namespace TJAPlayer3 {
internal class CSongDict {
private static Dictionary<string, CSongListNode> nodes = new Dictionary<string, CSongListNode>();
private static HashSet<string> urls = new HashSet<string>();
@ -21,64 +14,54 @@ namespace TJAPlayer3
new CActSelect曲リスト.CScorePad[(int)Difficulty.Edit + 2] { new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad(), new CActSelect曲リスト.CScorePad() }
};
public static int tGetNodesCount()
{
public static int tGetNodesCount() {
return nodes.Count();
}
public static string[] tGetNodesByGenreName(string genreName)
{
public static string[] tGetNodesByGenreName(string genreName) {
return nodes.Where(_nd => _nd.Value.strジャンル == genreName).Select(_nd => _nd.Key).ToArray();
}
#region [General song dict methods]
public static CSongListNode tGetNodeFromID(string id)
{
public static CSongListNode tGetNodeFromID(string id) {
if (nodes.ContainsKey(id))
return nodes[id].Clone();
return null;
}
public static void tAddSongNode(CSongUniqueID sid, CSongListNode node)
{
public static void tAddSongNode(CSongUniqueID sid, CSongListNode node) {
if (sid != null && sid.data.id != null && sid.data.id != "" && !nodes.ContainsKey(sid.data.id))
nodes.Add(sid.data.id, node.Clone());
tAddSongUrl(sid);
}
public static bool tContainsSongUrl(string url)
{
public static bool tContainsSongUrl(string url) {
return urls.Contains(url);
}
public static void tAddSongUrl(CSongUniqueID sid)
{
public static void tAddSongUrl(CSongUniqueID sid) {
var url = sid.data.url;
if (url != null && url != "" && !urls.Contains(url))
urls.Add(url);
}
public static void tRemoveSongUrl(CSongUniqueID sid)
{
public static void tRemoveSongUrl(CSongUniqueID sid) {
var url = sid.data.url;
if (url != null && url != "" && urls.Contains(url))
urls.Remove(url);
}
public static void tRemoveSongNode(CSongUniqueID sid)
{
if (sid != null && nodes.ContainsKey(sid.data.id))
{
public static void tRemoveSongNode(CSongUniqueID sid) {
if (sid != null && nodes.ContainsKey(sid.data.id)) {
tRemoveSongUrl(sid);
nodes.Remove(sid.data.id);
}
}
public static void tClearSongNodes()
{
public static void tClearSongNodes() {
nodes.Clear();
urls.Clear();
}
@ -88,8 +71,7 @@ namespace TJAPlayer3
#region [Extra methods]
// Generate a back button
public static CSongListNode tGenerateBackButton(CSongListNode parent, string path = "/", List<string> listStrBoxDef = null)
{
public static CSongListNode tGenerateBackButton(CSongListNode parent, string path = "/", List<string> listStrBoxDef = null) {
CSongListNode itemBack = new CSongListNode();
itemBack.eード種別 = CSongListNode.ENodeType.BACKBOX;
@ -113,8 +95,7 @@ namespace TJAPlayer3
"" : parent.rParentNode.strSkinPath;
// I guess this is used to count the number of box.def instances and only at startup, which makes using it here pretty weird
if (listStrBoxDef != null && itemBack.strSkinPath != "" && !listStrBoxDef.Contains(itemBack.strSkinPath))
{
if (listStrBoxDef != null && itemBack.strSkinPath != "" && !listStrBoxDef.Contains(itemBack.strSkinPath)) {
listStrBoxDef.Add(itemBack.strSkinPath);
}
@ -129,8 +110,7 @@ namespace TJAPlayer3
return (itemBack);
}
public static CSongListNode tGenerateRandomButton(CSongListNode parent, string path = "/")
{
public static CSongListNode tGenerateRandomButton(CSongListNode parent, string path = "/") {
CSongListNode itemRandom = new CSongListNode();
itemRandom.eード種別 = CSongListNode.ENodeType.RANDOM;
@ -148,15 +128,13 @@ namespace TJAPlayer3
}
// Reset the position of all back buttons, also adds a random button at the end
public static List<CSongListNode> tReinsertBackButtons(CSongListNode parent, List<CSongListNode> songList, string path = "/", List<string> listStrBoxDef = null)
{
public static List<CSongListNode> tReinsertBackButtons(CSongListNode parent, List<CSongListNode> songList, string path = "/", List<string> listStrBoxDef = null) {
// Remove all the existing back boxes currently existing
songList.RemoveAll(e => e.eード種別 == CSongListNode.ENodeType.BACKBOX || e.eード種別 == CSongListNode.ENodeType.RANDOM);
int songCount = songList.Count;
for (int index = 0; index < (songCount / 7) + 1; index++)
{
for (int index = 0; index < (songCount / 7) + 1; index++) {
var backBox = tGenerateBackButton(parent, path, listStrBoxDef);
songList.Insert(Math.Min(index * (7 + 1), songList.Count), backBox);
}
@ -169,10 +147,8 @@ namespace TJAPlayer3
}
private static CSongListNode tReadaptChildNote(CSongListNode parent, CSongListNode node)
{
if (node != null)
{
private static CSongListNode tReadaptChildNote(CSongListNode parent, CSongListNode node) {
if (node != null) {
node.rParentNode = parent;
node.isChangedBgType = parent.isChangedBgType;
node.isChangedBgColor = parent.isChangedBgColor;
@ -192,15 +168,12 @@ namespace TJAPlayer3
}
// Generate the favorite folder content
public static List<CSongListNode> tFetchFavoriteFolder(CSongListNode parent)
{
public static List<CSongListNode> tFetchFavoriteFolder(CSongListNode parent) {
List<CSongListNode> childList = new List<CSongListNode>();
foreach (string id in TJAPlayer3.Favorites.data.favorites[TJAPlayer3.SaveFile])
{
foreach (string id in TJAPlayer3.Favorites.data.favorites[TJAPlayer3.SaveFile]) {
var node = tReadaptChildNote(parent, tGetNodeFromID(id));
if (node != null)
{
if (node != null) {
childList.Add(node);
}
@ -216,15 +189,12 @@ namespace TJAPlayer3
}
// Generate recently played songs folder
public static List<CSongListNode> tFetchRecentlyPlayedSongsFolder(CSongListNode parent)
{
public static List<CSongListNode> tFetchRecentlyPlayedSongsFolder(CSongListNode parent) {
List<CSongListNode> childList = new List<CSongListNode>();
foreach (string id in TJAPlayer3.RecentlyPlayedSongs.data.recentlyplayedsongs[TJAPlayer3.SaveFile].Reverse())
{
foreach (string id in TJAPlayer3.RecentlyPlayedSongs.data.recentlyplayedsongs[TJAPlayer3.SaveFile].Reverse()) {
var node = tReadaptChildNote(parent, tGetNodeFromID(id));
if (node != null)
{
if (node != null) {
childList.Add(node);
}
@ -240,27 +210,23 @@ namespace TJAPlayer3
}
// 13 includes any higher difficulty
private static bool tLevelMatches(int check, int level)
{
private static bool tLevelMatches(int check, int level) {
if (level == 13)
return check >= level;
return check == level;
}
// Generate search by difficulty folder
public static List<CSongListNode> tFetchSongsByDifficulty(CSongListNode parent, int difficulty = (int)Difficulty.Oni, int level = 8)
{
public static List<CSongListNode> tFetchSongsByDifficulty(CSongListNode parent, int difficulty = (int)Difficulty.Oni, int level = 8) {
List<CSongListNode> childList = new List<CSongListNode>();
foreach (CSongListNode nodeT in nodes.Values)
{
foreach (CSongListNode nodeT in nodes.Values) {
var score = nodeT.nLevel;
if (tLevelMatches(score[difficulty], level)
|| (difficulty == (int)Difficulty.Oni && tLevelMatches(score[(int)Difficulty.Edit], level))) // Oni includes Ura
{
var node = tReadaptChildNote(parent, nodeT);
if (node != null)
{
if (node != null) {
childList.Add(node);
}
}
@ -279,24 +245,18 @@ namespace TJAPlayer3
#region [Score tables methods]
public static void tRefreshScoreTables()
{
for (int pl = 0; pl < 5; pl++)
{
public static void tRefreshScoreTables() {
for (int pl = 0; pl < 5; pl++) {
CActSelect曲リスト.CScorePad[] SPArrRef = ScorePads[pl];
var BestPlayStats = TJAPlayer3.SaveFileInstances[TJAPlayer3.GetActualPlayer(pl)].data.bestPlaysStats;
for (int s = 0; s <= (int)Difficulty.Edit + 1; s++)
{
for (int s = 0; s <= (int)Difficulty.Edit + 1; s++) {
CActSelect曲リスト.CScorePad SPRef = SPArrRef[s];
if (s <= (int)Difficulty.Edit)
{
if (s <= (int)Difficulty.Edit) {
SPRef.ScoreRankCount = BestPlayStats.ScoreRanks[s].Skip(1).ToArray(); ;
SPRef.CrownCount= BestPlayStats.ClearStatuses[s].Skip(1).ToArray(); ;
}
else
{
SPRef.CrownCount = BestPlayStats.ClearStatuses[s].Skip(1).ToArray(); ;
} else {
SPRef.ScoreRankCount = BestPlayStats.ScoreRanks[(int)Difficulty.Oni].Skip(1).Zip(BestPlayStats.ScoreRanks[(int)Difficulty.Edit].Skip(1).ToArray(), (x, y) => x + y).ToArray();
SPRef.CrownCount = BestPlayStats.ClearStatuses[(int)Difficulty.Oni].Skip(1).Zip(BestPlayStats.ClearStatuses[(int)Difficulty.Edit].Skip(1).ToArray(), (x, y) => x + y).ToArray();
}

View File

@ -1,17 +1,11 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing;
using FDK;
namespace TJAPlayer3
{
internal class CTextConsole : CActivity
{
namespace TJAPlayer3 {
internal class CTextConsole : CActivity {
// 定数
public enum EFontType
{
public enum EFontType {
White,
Cyan,
Gray,
@ -22,31 +16,21 @@ namespace TJAPlayer3
// メソッド
public void tPrint( int x, int y, EFontType font, string strAlphanumericString )
{
if( !base.IsDeActivated && !string.IsNullOrEmpty( strAlphanumericString ) )
{
public void tPrint(int x, int y, EFontType font, string strAlphanumericString) {
if (!base.IsDeActivated && !string.IsNullOrEmpty(strAlphanumericString)) {
int BOL = x;
for( int i = 0; i < strAlphanumericString.Length; i++ )
{
char ch = strAlphanumericString[ i ];
if( ch == '\n' )
{
for (int i = 0; i < strAlphanumericString.Length; i++) {
char ch = strAlphanumericString[i];
if (ch == '\n') {
x = BOL;
y += nFontHeight;
}
else
{
int index = str表記可能文字.IndexOf( ch );
if( index < 0 )
{
} else {
int index = str表記可能文字.IndexOf(ch);
if (index < 0) {
x += nFontWidth;
}
else
{
if( this.txフォント8x16[ (int) ( (int) font / (int) EFontType.WhiteSlim ) ] != null )
{
this.txフォント8x16[ (int) ( (int) font / (int) EFontType.WhiteSlim ) ].t2D描画( x, y, this.rc文字の矩形領域[ (int) ( (int) font % (int) EFontType.WhiteSlim ), index ] );
} else {
if (this.txフォント8x16[(int)((int)font / (int)EFontType.WhiteSlim)] != null) {
this.txフォント8x16[(int)((int)font / (int)EFontType.WhiteSlim)].t2D描画(x, y, this.rc文字の矩形領域[(int)((int)font % (int)EFontType.WhiteSlim), index]);
}
x += nFontWidth;
}
@ -58,32 +42,26 @@ namespace TJAPlayer3
// CActivity 実装
public override void Activate()
{
public override void Activate() {
base.Activate();
}
public override void DeActivate()
{
if( this.rc文字の矩形領域 != null )
public override void DeActivate() {
if (this.rc文字の矩形領域 != null)
this.rc文字の矩形領域 = null;
base.DeActivate();
}
public override void CreateManagedResource()
{
if( !base.IsDeActivated )
{
this.txフォント8x16[ 0 ] = TJAPlayer3.Tx.TxC(@"Console_Font.png");
this.txフォント8x16[ 1 ] = TJAPlayer3.Tx.TxC(@"Console_Font_Small.png");
public override void CreateManagedResource() {
if (!base.IsDeActivated) {
this.txフォント8x16[0] = TJAPlayer3.Tx.TxC(@"Console_Font.png");
this.txフォント8x16[1] = TJAPlayer3.Tx.TxC(@"Console_Font_Small.png");
nFontWidth = this.txフォント8x16[0].szTextureSize.Width / 32;
nFontHeight = this.txフォント8x16[0].szTextureSize.Height / 16;
this.rc文字の矩形領域 = new Rectangle[3, str表記可能文字.Length];
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < str表記可能文字.Length; j++)
{
for (int i = 0; i < 3; i++) {
for (int j = 0; j < str表記可能文字.Length; j++) {
int regionX = nFontWidth * 16, regionY = nFontHeight * 8;
this.rc文字の矩形領域[i, j].X = ((i / 2) * regionX) + ((j % 16) * nFontWidth);
this.rc文字の矩形領域[i, j].Y = ((i % 2) * regionY) + ((j / 16) * nFontHeight);
@ -95,16 +73,12 @@ namespace TJAPlayer3
base.CreateManagedResource();
}
}
public override void ReleaseManagedResource()
{
if( !base.IsDeActivated )
{
for( int i = 0; i < 2; i++ )
{
if( this.txフォント8x16[ i ] != null )
{
this.txフォント8x16[ i ].Dispose();
this.txフォント8x16[ i ] = null;
public override void ReleaseManagedResource() {
if (!base.IsDeActivated) {
for (int i = 0; i < 2; i++) {
if (this.txフォント8x16[i] != null) {
this.txフォント8x16[i].Dispose();
this.txフォント8x16[i] = null;
}
}
base.ReleaseManagedResource();
@ -119,7 +93,7 @@ namespace TJAPlayer3
private Rectangle[,] rc文字の矩形領域;
private const string str表記可能文字 = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ";
public int nFontWidth = 8, nFontHeight = 16;
private CTexture[] txフォント8x16 = new CTexture[ 2 ];
private CTexture[] txフォント8x16 = new CTexture[2];
//-----------------
#endregion
}

View File

@ -1,13 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TJAPlayer3
{
class CVersionList
{
namespace TJAPlayer3 {
class CVersionList {
public static string[] VersionList = {
"0.1.0",
"0.2.0",

View File

@ -1,7 +1,6 @@
using FDK;
namespace TJAPlayer3
{
namespace TJAPlayer3 {
/// <summary>
/// The ConfigIniToSongGainControllerBinder allows for SONGVOL and/or other
/// properties related to the Gain levels applied to song preview and
@ -10,18 +9,14 @@ namespace TJAPlayer3
/// ConfigIni or SongGainController having awareness of one another.
/// See those classes properties, methods, and events for more details.
/// </summary>
internal static class ConfigIniToSongGainControllerBinder
{
internal static void Bind(CConfigIni configIni, SongGainController songGainController)
{
internal static class ConfigIniToSongGainControllerBinder {
internal static void Bind(CConfigIni configIni, SongGainController songGainController) {
songGainController.ApplyLoudnessMetadata = configIni.ApplyLoudnessMetadata;
songGainController.TargetLoudness = new Lufs(configIni.TargetLoudness);
songGainController.ApplySongVol = configIni.ApplySongVol;
configIni.PropertyChanged += (sender, args) =>
{
switch (args.PropertyName)
{
configIni.PropertyChanged += (sender, args) => {
switch (args.PropertyName) {
case nameof(CConfigIni.ApplyLoudnessMetadata):
songGainController.ApplyLoudnessMetadata = configIni.ApplyLoudnessMetadata;
break;

View File

@ -1,8 +1,6 @@
using System;
using FDK;
using FDK;
namespace TJAPlayer3
{
namespace TJAPlayer3 {
/// <summary>
/// The ConfigIniToSoundGroupLevelControllerBinder allows for updated sound
/// group level values, and keyboard sound level adjustment increment
@ -10,20 +8,16 @@ namespace TJAPlayer3
/// without either of those two classes being aware of one another.
/// See those classes properties, methods, and events for more details.
/// </summary>
internal static class ConfigIniToSoundGroupLevelControllerBinder
{
internal static void Bind(CConfigIni configIni, SoundGroupLevelController soundGroupLevelController)
{
internal static class ConfigIniToSoundGroupLevelControllerBinder {
internal static void Bind(CConfigIni configIni, SoundGroupLevelController soundGroupLevelController) {
soundGroupLevelController.SetLevel(ESoundGroup.SoundEffect, configIni.SoundEffectLevel);
soundGroupLevelController.SetLevel(ESoundGroup.Voice, configIni.VoiceLevel);
soundGroupLevelController.SetLevel(ESoundGroup.SongPreview, configIni.SongPreviewLevel);
soundGroupLevelController.SetLevel(ESoundGroup.SongPlayback, configIni.SongPlaybackLevel);
soundGroupLevelController.SetKeyboardSoundLevelIncrement(configIni.KeyboardSoundLevelIncrement);
configIni.PropertyChanged += (sender, args) =>
{
switch (args.PropertyName)
{
configIni.PropertyChanged += (sender, args) => {
switch (args.PropertyName) {
case nameof(CConfigIni.SoundEffectLevel):
soundGroupLevelController.SetLevel(ESoundGroup.SoundEffect, configIni.SoundEffectLevel);
break;
@ -42,10 +36,8 @@ namespace TJAPlayer3
}
};
soundGroupLevelController.LevelChanged += (sender, args) =>
{
switch (args.SoundGroup)
{
soundGroupLevelController.LevelChanged += (sender, args) => {
switch (args.SoundGroup) {
case ESoundGroup.SoundEffect:
configIni.SoundEffectLevel = args.Level;
break;

View File

@ -1,19 +1,14 @@
using System.IO;
using System.Text;
using System.Text;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
namespace TJAPlayer3
{
namespace TJAPlayer3 {
/// <summary>
/// 設定ファイル入出力クラス。
/// </summary>
public static class ConfigManager
{
public static class ConfigManager {
private static readonly JsonSerializerSettings Settings =
new JsonSerializerSettings()
{
new JsonSerializerSettings() {
ObjectCreationHandling = ObjectCreationHandling.Auto,
DefaultValueHandling = DefaultValueHandling.Include,
// ContractResolver = new CamelCasePropertyNamesContractResolver(),
@ -28,16 +23,13 @@ namespace TJAPlayer3
/// <typeparam name="T">シリアライズしたクラス。</typeparam>
/// <param name="filePath">ファイル名。</param>
/// <returns>デシリアライズ結果。</returns>
public static T GetConfig<T>(string filePath) where T : new()
{
public static T GetConfig<T>(string filePath) where T : new() {
var json = "";
if (!System.IO.File.Exists(filePath))
{
if (!System.IO.File.Exists(filePath)) {
// ファイルが存在しないので
SaveConfig(new T(), filePath);
}
using (var stream = new System.IO.StreamReader(filePath, Encoding.UTF8))
{
using (var stream = new System.IO.StreamReader(filePath, Encoding.UTF8)) {
json = stream.ReadToEnd();
}
return JsonConvert.DeserializeObject<T>(json, Settings);
@ -48,11 +40,9 @@ namespace TJAPlayer3
/// </summary>
/// <param name="obj">シリアライズするインスタンス。</param>
/// <param name="filePath">ファイル名。</param>
public static void SaveConfig(object obj, string filePath)
{
public static void SaveConfig(object obj, string filePath) {
(new FileInfo(filePath)).Directory.Create();
using (var stream = new System.IO.StreamWriter(filePath, false, Encoding.UTF8))
{
using (var stream = new System.IO.StreamWriter(filePath, false, Encoding.UTF8)) {
stream.Write(JsonConvert.SerializeObject(obj, Formatting.None, Settings));
}
}

View File

@ -1,16 +1,11 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices;
namespace TJAPlayer3
{
namespace TJAPlayer3 {
/// <summary>
/// 難易度。
/// </summary>
public enum Difficulty
{
public enum Difficulty {
Easy,
Normal,
Hard,
@ -21,21 +16,18 @@ namespace TJAPlayer3
Total
}
public enum EScrollMode
{
public enum EScrollMode {
Normal,
BMSCROLL,
HBSCROLL
}
public enum EGame
{
public enum EGame {
OFF = 0,
= 1,
= 2
}
public enum E難易度表示タイプ
{
public enum E難易度表示タイプ {
OFF = 0,
n曲目に表示 = 1,
mtaikoに画像で表示 = 2,
@ -226,8 +218,7 @@ namespace TJAPlayer3
RBlue2P = 64,
UNKNOWN = 4096
}
public enum ERandomMode
{
public enum ERandomMode {
OFF,
RANDOM,
MIRROR,
@ -235,16 +226,14 @@ namespace TJAPlayer3
MIRRORRANDOM
}
public enum EFunMods
{
public enum EFunMods {
NONE,
AVALANCHE,
MINESWEEPER,
TOTAL,
}
public enum EGameType
{
public enum EGameType {
TAIKO = 0,
KONGA = 1,
}
@ -267,8 +256,7 @@ namespace TJAPlayer3
UNKNOWN = EInstrumentPad.UNKNOWN
}
internal enum EInputDevice
{
internal enum EInputDevice {
Keyboard = 0,
MIDIInput = 1,
Joypad = 2,
@ -276,8 +264,7 @@ namespace TJAPlayer3
Gamepad = 4,
Unknown = -1
}
public enum ENoteJudge
{
public enum ENoteJudge {
Perfect = 0,
Great = 1,
Good = 2,
@ -288,22 +275,19 @@ namespace TJAPlayer3
ADLIB = 7,
Mine = 8,
}
internal enum E判定文字表示位置
{
internal enum E判定文字表示位置 {
OFF,
,
,
}
internal enum EFIFOモード
{
internal enum EFIFOモード {
,
}
internal enum E演奏画面の戻り値
{
internal enum E演奏画面の戻り値 {
,
,
,
@ -311,15 +295,13 @@ namespace TJAPlayer3
_再演奏,
}
internal enum E曲読込画面の戻り値
{
internal enum E曲読込画面の戻り値 {
= 0,
,
}
public enum ENoteState
{
public enum ENoteState {
none,
wait,
perfect,
@ -327,8 +309,7 @@ namespace TJAPlayer3
bad
}
public enum E連打State
{
public enum E連打State {
none,
roll,
rollB,
@ -336,8 +317,7 @@ namespace TJAPlayer3
potato
}
public enum EStealthMode
{
public enum EStealthMode {
OFF = 0,
DORON = 1,
STEALTH = 2
@ -346,8 +326,7 @@ namespace TJAPlayer3
/// <summary>
/// 透明チップの種類
/// </summary>
public enum EInvisible
{
public enum EInvisible {
OFF, // チップを透明化しない
SEMI, // Poor/Miss時だけ、一時的に透明解除する
FULL // チップを常に透明化する
@ -358,7 +337,7 @@ namespace TJAPlayer3
/// </summary>
/// <typeparam name="T">値の型。</typeparam>
[Serializable]
[StructLayout( LayoutKind.Sequential )]
[StructLayout(LayoutKind.Sequential)]
public struct STDGBVALUE<T> // indexはE楽器パートと一致させること
{
public T Drums;
@ -366,50 +345,45 @@ namespace TJAPlayer3
public T Bass;
public T Taiko;
public T Unknown;
public T this[ int index ]
{
get
{
switch( index )
{
case (int) EInstrumentPad.DRUMS:
public T this[int index] {
get {
switch (index) {
case (int)EInstrumentPad.DRUMS:
return this.Drums;
case (int) EInstrumentPad.GUITAR:
case (int)EInstrumentPad.GUITAR:
return this.Guitar;
case (int) EInstrumentPad.BASS:
case (int)EInstrumentPad.BASS:
return this.Bass;
case (int) EInstrumentPad.TAIKO:
case (int)EInstrumentPad.TAIKO:
return this.Taiko;
case (int) EInstrumentPad.UNKNOWN:
case (int)EInstrumentPad.UNKNOWN:
return this.Unknown;
}
throw new IndexOutOfRangeException();
}
set
{
switch( index )
{
case (int) EInstrumentPad.DRUMS:
set {
switch (index) {
case (int)EInstrumentPad.DRUMS:
this.Drums = value;
return;
case (int) EInstrumentPad.GUITAR:
case (int)EInstrumentPad.GUITAR:
this.Guitar = value;
return;
case (int) EInstrumentPad.BASS:
case (int)EInstrumentPad.BASS:
this.Bass = value;
return;
case (int) EInstrumentPad.TAIKO:
case (int)EInstrumentPad.TAIKO:
this.Taiko = value;
return;
case (int) EInstrumentPad.UNKNOWN:
case (int)EInstrumentPad.UNKNOWN:
this.Unknown = value;
return;
}
@ -418,28 +392,24 @@ namespace TJAPlayer3
}
}
public enum EReturnValue : int
{
public enum EReturnValue : int {
Continuation,
ReturnToTitle,
SongChoosen
}
#region[Ver.K追加]
public enum Eレーンタイプ
{
public enum Eレーンタイプ {
TypeA,
TypeB,
TypeC,
TypeD
}
public enum Eミラー
{
public enum Eミラー {
TypeA,
TypeB
}
public enum EClipDispType
{
public enum EClipDispType {
= 1,
= 2,
= 3,

View File

@ -1,16 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TJAPlayer3;
using FDK;
using FDK;
namespace TJAPlayer3
{
class Easing
{
public int EaseIn(CCounter counter, float startPoint, float endPoint, CalcType type)
{
namespace TJAPlayer3 {
class Easing {
public int EaseIn(CCounter counter, float startPoint, float endPoint, CalcType type) {
StartPoint = startPoint;
EndPoint = endPoint;
Sa = EndPoint - StartPoint;
@ -18,8 +10,7 @@ namespace TJAPlayer3
Type = type;
CounterValue = counter.CurrentValue;
switch (Type)
{
switch (Type) {
case CalcType.Quadratic: //Quadratic
CounterValue /= TimeMs;
Value = Sa * CounterValue * CounterValue + StartPoint;
@ -53,8 +44,7 @@ namespace TJAPlayer3
return (int)Value;
}
public int EaseOut(CCounter counter, float startPoint, float endPoint, CalcType type)
{
public int EaseOut(CCounter counter, float startPoint, float endPoint, CalcType type) {
StartPoint = startPoint;
EndPoint = endPoint;
Sa = EndPoint - StartPoint;
@ -62,8 +52,7 @@ namespace TJAPlayer3
Type = type;
CounterValue = counter.CurrentValue;
switch (Type)
{
switch (Type) {
case CalcType.Quadratic: //Quadratic
CounterValue /= TimeMs;
Value = -Sa * CounterValue * (CounterValue - 2) + StartPoint;
@ -102,8 +91,7 @@ namespace TJAPlayer3
return (int)Value;
}
public float EaseInOut(CCounter counter, float startPoint, float endPoint, CalcType type)
{
public float EaseInOut(CCounter counter, float startPoint, float endPoint, CalcType type) {
StartPoint = startPoint;
EndPoint = endPoint;
Sa = EndPoint - StartPoint;
@ -111,12 +99,10 @@ namespace TJAPlayer3
Type = type;
CounterValue = counter.CurrentValue;
switch (Type)
{
switch (Type) {
case CalcType.Quadratic: //Quadratic
CounterValue /= TimeMs / 2;
if (CounterValue < 1)
{
if (CounterValue < 1) {
Value = Sa / 2 * CounterValue * CounterValue + StartPoint;
break;
}
@ -125,8 +111,7 @@ namespace TJAPlayer3
break;
case CalcType.Cubic: //Cubic
CounterValue /= TimeMs / 2;
if (CounterValue < 1)
{
if (CounterValue < 1) {
Value = Sa / 2 * CounterValue * CounterValue * CounterValue + StartPoint;
break;
}
@ -135,8 +120,7 @@ namespace TJAPlayer3
break;
case CalcType.Quartic: //Quartic
CounterValue /= TimeMs / 2;
if (CounterValue < 1)
{
if (CounterValue < 1) {
Value = Sa / 2 * CounterValue * CounterValue * CounterValue * CounterValue + StartPoint;
break;
}
@ -146,8 +130,7 @@ namespace TJAPlayer3
case CalcType.Quintic: //Quintic
CounterValue /= TimeMs;
CounterValue /= TimeMs / 2;
if (CounterValue < 1)
{
if (CounterValue < 1) {
Value = Sa / 2 * CounterValue * CounterValue * CounterValue * CounterValue * CounterValue + StartPoint;
break;
}
@ -159,8 +142,7 @@ namespace TJAPlayer3
break;
case CalcType.Exponential: //Exponential
CounterValue /= TimeMs / 2;
if (CounterValue < 1)
{
if (CounterValue < 1) {
Value = Sa / 2 * Math.Pow(2, 10 * (CounterValue - 1)) + StartPoint;
break;
}
@ -169,8 +151,7 @@ namespace TJAPlayer3
break;
case CalcType.Circular: //Circular
CounterValue /= TimeMs / 2;
if (CounterValue < 1)
{
if (CounterValue < 1) {
Value = -Sa / 2 * (Math.Sqrt(1 - CounterValue * CounterValue) - 1) + StartPoint;
break;
}
@ -193,8 +174,7 @@ namespace TJAPlayer3
private CalcType Type;
private double CounterValue;
private double Value;
public enum CalcType
{
public enum CalcType {
Quadratic,
Cubic,
Quartic,

View File

@ -1,15 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace TJAPlayer3
{
internal class Favorites
{
namespace TJAPlayer3 {
internal class Favorites {
public void tFavorites() {
if (!File.Exists("Favorite.json"))
tSaveFile();
@ -19,8 +9,7 @@ namespace TJAPlayer3
#region [Auxiliary methods]
public void tToggleFavorite(string chartID)
{
public void tToggleFavorite(string chartID) {
if (tIsFavorite(chartID))
data.favorites[TJAPlayer3.SaveFile].Remove(chartID);
else
@ -29,16 +18,14 @@ namespace TJAPlayer3
tSaveFile();
}
public bool tIsFavorite(string chartID)
{
public bool tIsFavorite(string chartID) {
return (data.favorites[TJAPlayer3.SaveFile].Contains(chartID));
}
#endregion
public class Data
{
public class Data {
public HashSet<string>[] favorites = new HashSet<string>[2] { new HashSet<string>(), new HashSet<string>() };
}
@ -46,13 +33,11 @@ namespace TJAPlayer3
#region [private]
private void tSaveFile()
{
private void tSaveFile() {
ConfigManager.SaveConfig(data, "Favorite.json");
}
private void tLoadFile()
{
private void tLoadFile() {
data = ConfigManager.GetConfig<Data>(@"Favorite.json");
}

View File

@ -1,7 +1,6 @@
using FDK;
namespace TJAPlayer3
{
namespace TJAPlayer3 {
/// <summary>
/// KeyboardSoundGroupLevelControlHandler is called by the song selection
/// and song play stages when handling keyboard input. By delegating to
@ -18,14 +17,12 @@ namespace TJAPlayer3
/// configuration is updated. See ConfigIniToSoundGroupLevelControllerBinder
/// for more details on the latter.
/// </summary>
internal static class KeyboardSoundGroupLevelControlHandler
{
internal static class KeyboardSoundGroupLevelControlHandler {
internal static void Handle(
IInputDevice keyboard,
SoundGroupLevelController soundGroupLevelController,
CSkin skin,
bool isSongPreview)
{
bool isSongPreview) {
bool isAdjustmentPositive = TJAPlayer3.ConfigIni.KeyAssign.KeyIsPressed(TJAPlayer3.ConfigIni.KeyAssign.System.SongVolIncrease);
bool isAdjustmentNegative = TJAPlayer3.ConfigIni.KeyAssign.KeyIsPressed(TJAPlayer3.ConfigIni.KeyAssign.System.SongVolDecrease);
@ -35,19 +32,14 @@ namespace TJAPlayer3
CSkin.CSystemSound = null;
if (keyboard.KeyPressing((int)SlimDXKeys.Key.LeftControl) ||
keyboard.KeyPressing((int)SlimDXKeys.Key.RightControl))
{
keyboard.KeyPressing((int)SlimDXKeys.Key.RightControl)) {
soundGroup = ESoundGroup.SoundEffect;
= skin.soundDecideSFX;
}
else if (keyboard.KeyPressing((int)SlimDXKeys.Key.LeftShift) ||
keyboard.KeyPressing((int)SlimDXKeys.Key.RightShift))
{
} else if (keyboard.KeyPressing((int)SlimDXKeys.Key.LeftShift) ||
keyboard.KeyPressing((int)SlimDXKeys.Key.RightShift)) {
soundGroup = ESoundGroup.Voice;
= skin.soundゲーム開始音;
}
else
{
} else {
soundGroup = ESoundGroup.SongPlayback;
}

View File

@ -1,29 +1,19 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
using FDK;
namespace TJAPlayer3
{
internal class LogNotification
{
namespace TJAPlayer3 {
internal class LogNotification {
private static Queue<CLogNotification> Notifications = new Queue<CLogNotification>();
public enum ENotificationType
{
public enum ENotificationType {
EINFO,
ESUCCESS,
EWARNING,
EERROR,
}
public class CLogNotification
{
public CLogNotification(ENotificationType nt, string msg)
{
public class CLogNotification {
public CLogNotification(ENotificationType nt, string msg) {
NotificationType = nt;
Message = msg;
}
@ -34,32 +24,27 @@ namespace TJAPlayer3
}
public static void PopError(string message)
{
public static void PopError(string message) {
Notifications.Enqueue(new CLogNotification(ENotificationType.EERROR, message));
Trace.TraceError("<Runtime Error>: " + message);
}
public static void PopWarning(string message)
{
public static void PopWarning(string message) {
Notifications.Enqueue(new CLogNotification(ENotificationType.EWARNING, message));
Trace.TraceWarning("<Runtime Warning>: " + message);
}
public static void PopSuccess(string message)
{
public static void PopSuccess(string message) {
Notifications.Enqueue(new CLogNotification(ENotificationType.ESUCCESS, message));
Trace.TraceInformation("<Runtime Success>: " + message);
}
public static void PopInfo(string message)
{
public static void PopInfo(string message) {
Notifications.Enqueue(new CLogNotification(ENotificationType.EINFO, message));
Trace.TraceInformation("<Runtime Info>: " + message);
}
public static void Display()
{
public static void Display() {
while (Notifications.Count > 0 && Notifications.Peek().LifeTime.IsEnded) Notifications.Dequeue();
// Add an optimized method to display the notifications here
}

View File

@ -1,18 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using FDK;
using System.Drawing;
using static TJAPlayer3.CActSelect曲リスト;
namespace TJAPlayer3
{
internal class Modal
{
public Modal(EModalType mt, int ra, params object[] re)
{
namespace TJAPlayer3 {
internal class Modal {
public Modal(EModalType mt, int ra, params object[] re) {
modalType = mt;
rarity = ra;
reference = re;
@ -20,8 +12,7 @@ namespace TJAPlayer3
// TODO: Add an int (?) or string to find the Puchichara/Character/Song asset to display it
}
public void tSetupModal()
{
public void tSetupModal() {
CTexture[] arrRef;
if (modalFormat == EModalFormat.Half)
@ -35,8 +26,7 @@ namespace TJAPlayer3
if (modalType == EModalType.Coin)
_box = arrRef[arrRef.Length - 1];
else
{
else {
int usedTex = Math.Max(0, Math.Min(arrRef.Length - 2, rarity));
_box = arrRef[usedTex];
}
@ -64,10 +54,8 @@ namespace TJAPlayer3
_isSet = true;
}
public void tDisplayModal()
{
if (_isSet == true)
{
public void tDisplayModal() {
if (_isSet == true) {
_box?.t2D描画(_boxRect.Width * (player % 2), _boxRect.Height * (player / 2), _boxRect);
int[] title_x;
@ -77,8 +65,7 @@ namespace TJAPlayer3
int moveX;
int moveY;
if (modalFormat == EModalFormat.Full)
{
if (modalFormat == EModalFormat.Full) {
title_x = new int[] { TJAPlayer3.Skin.Modal_Title_Full[0] };
title_y = new int[] { TJAPlayer3.Skin.Modal_Title_Full[1] };
@ -87,9 +74,7 @@ namespace TJAPlayer3
moveX = TJAPlayer3.Skin.Modal_Text_Full_Move[0];
moveY = TJAPlayer3.Skin.Modal_Text_Full_Move[1];
}
else if (modalFormat == EModalFormat.Half)
{
} else if (modalFormat == EModalFormat.Half) {
title_x = TJAPlayer3.Skin.Modal_Title_Half_X;
title_y = TJAPlayer3.Skin.Modal_Title_Half_Y;
@ -98,9 +83,7 @@ namespace TJAPlayer3
moveX = TJAPlayer3.Skin.Modal_Text_Half_Move[0];
moveY = TJAPlayer3.Skin.Modal_Text_Half_Move[1];
}
else if (modalFormat == EModalFormat.Half_4P)
{
} else if (modalFormat == EModalFormat.Half_4P) {
title_x = TJAPlayer3.Skin.Modal_Title_Half_X_4P;
title_y = TJAPlayer3.Skin.Modal_Title_Half_Y_4P;
@ -109,8 +92,7 @@ namespace TJAPlayer3
moveX = TJAPlayer3.Skin.Modal_Text_Half_Move_4P[0];
moveY = TJAPlayer3.Skin.Modal_Text_Half_Move_4P[1];
}
else// 5P
} else// 5P
{
title_x = TJAPlayer3.Skin.Modal_Title_Half_X_5P;
title_y = TJAPlayer3.Skin.Modal_Title_Half_Y_5P;
@ -149,16 +131,14 @@ namespace TJAPlayer3
}
}
public void tPlayModalSfx()
{
public void tPlayModalSfx() {
if (modalType == EModalType.Coin)
TJAPlayer3.Skin.soundModal[TJAPlayer3.Skin.soundModal.Length - 1].tPlay();
else
TJAPlayer3.Skin.soundModal[Math.Max(0, Math.Min(TJAPlayer3.Skin.soundModal.Length - 2, rarity))].tPlay();
}
public static void tInitModalFonts()
{
public static void tInitModalFonts() {
if (_pfModalContentHalf != null
&& _pfModalTitleHalf != null
&& _pfModalContentFull != null
@ -173,8 +153,7 @@ namespace TJAPlayer3
#region [Enum definitions]
public enum EModalType
{
public enum EModalType {
Coin = 0,
Character = 1,
Puchichara = 2,
@ -184,8 +163,7 @@ namespace TJAPlayer3
}
// Full : 1P standard modal, Half : Splitted screen modal
public enum EModalFormat
{
public enum EModalFormat {
Full,
Half,
Half_4P,
@ -211,19 +189,16 @@ namespace TJAPlayer3
#region [private]
// Check if the text is vertically centered or slightly up (to let enough space for the unlocked unit texture)
private bool tTextCentered()
{
private bool tTextCentered() {
if (modalType == EModalType.Coin)
return true;
return false;
}
// Generate the modal title and content text textures
private void tGenerateTextures()
{
private void tGenerateTextures() {
string modalKey = "MODAL_TITLE_COIN";
switch (modalType)
{
switch (modalType) {
case EModalType.Character:
modalKey = "MODAL_TITLE_CHARA";
break;
@ -248,8 +223,7 @@ namespace TJAPlayer3
string content = "";
if (modalType == EModalType.Coin)
{
if (modalType == EModalType.Coin) {
content = CLangManager.LangInstance.GetString("MODAL_MESSAGE_COIN", reference[0].ToString(), TJAPlayer3.SaveFileInstances[player].data.Medals.ToString());
//content = String.Format("+{0} {1} ({2}: {3})",
// (int)reference[0],
@ -257,21 +231,13 @@ namespace TJAPlayer3
// CLangManager.LangInstance.GetString(307),
// TJAPlayer3.SaveFileInstances[player].data.Medals
// );
}
else if (modalType == EModalType.Title)
{
} else if (modalType == EModalType.Title) {
content = ((string)reference[0]).RemoveTags();
}
else if (modalType == EModalType.Character)
{
} else if (modalType == EModalType.Character) {
content = ((string)reference[0]).RemoveTags();
}
else if (modalType == EModalType.Puchichara)
{
} else if (modalType == EModalType.Puchichara) {
content = ((string)reference[0]).RemoveTags();
}
else if (modalType == EModalType.Song)
{
} else if (modalType == EModalType.Song) {
content = ((string)reference[0]).RemoveTags();
}

View File

@ -1,22 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TJAPlayer3
{
internal class ModalQueue
{
public ModalQueue(Modal.EModalFormat mf)
{
namespace TJAPlayer3 {
internal class ModalQueue {
public ModalQueue(Modal.EModalFormat mf) {
_modalQueues = new Queue<Modal>[] { new Queue<Modal>(), new Queue<Modal>(), new Queue<Modal>(), new Queue<Modal>(), new Queue<Modal>() };
_modalFormat = mf;
}
// Add two modals (one per player) at the same time
public void tAddModal(Modal mp1, Modal mp2, Modal mp3, Modal mp4, Modal mp5)
{
public void tAddModal(Modal mp1, Modal mp2, Modal mp3, Modal mp4, Modal mp5) {
mp1.modalFormat = _modalFormat;
mp2.modalFormat = _modalFormat;
mp3.modalFormat = _modalFormat;
@ -46,8 +36,7 @@ namespace TJAPlayer3
}
// Add a single modal
public void tAddModal(Modal mp, int player)
{
public void tAddModal(Modal mp, int player) {
mp.modalFormat = _modalFormat;
mp.player = player;
mp.tSetupModal();
@ -56,23 +45,20 @@ namespace TJAPlayer3
_modalQueues[player].Enqueue(mp);
}
public Modal tPopModal(int player)
{
public Modal tPopModal(int player) {
if (!tIsQueueEmpty(player))
return _modalQueues[player].Dequeue();
return null;
}
public bool tIsQueueEmpty(int player)
{
public bool tIsQueueEmpty(int player) {
if (player < 0 || player >= TJAPlayer3.ConfigIni.nPlayerCount)
return true;
return _modalQueues[player].Count < 1;
}
public bool tAreBothQueuesEmpty()
{
public bool tAreBothQueuesEmpty() {
return tIsQueueEmpty(0) && tIsQueueEmpty(1) && tIsQueueEmpty(2) && tIsQueueEmpty(3) && tIsQueueEmpty(4);
}

View File

@ -1,17 +1,8 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json;
namespace TJAPlayer3
{
class NamePlateConfig
{
public void tNamePlateConfig()
{
namespace TJAPlayer3 {
class NamePlateConfig {
public void tNamePlateConfig() {
// Deprecated, only converts to new format
/*
if (!File.Exists("NamePlate.json"))
@ -23,13 +14,11 @@ namespace TJAPlayer3
#region [Medals]
public void tEarnCoins(int[] amounts)
{
public void tEarnCoins(int[] amounts) {
if (amounts.Length < 2)
return;
for (int i = 0; i < 5; i++)
{
for (int i = 0; i < 5; i++) {
int p = TJAPlayer3.GetActualPlayer(i);
data.Medals[p] += amounts[i];
@ -38,8 +27,7 @@ namespace TJAPlayer3
}
// Return false if the current amount of coins is to low
public bool tSpendCoins(int amount, int player)
{
public bool tSpendCoins(int amount, int player) {
if (player > 1 || player < 0)
return false;
@ -57,8 +45,7 @@ namespace TJAPlayer3
#region [Dan titles]
public bool tUpdateDanTitle(string title, bool isGold, int clearStatus, int player)
{
public bool tUpdateDanTitle(string title, bool isGold, int clearStatus, int player) {
bool changed = false;
bool iG = isGold;
@ -67,8 +54,7 @@ namespace TJAPlayer3
if (TJAPlayer3.NamePlateConfig.data.DanTitles[player] == null)
TJAPlayer3.NamePlateConfig.data.DanTitles[player] = new Dictionary<string, SaveFile.CDanTitle>();
if (TJAPlayer3.NamePlateConfig.data.DanTitles[player].ContainsKey(title))
{
if (TJAPlayer3.NamePlateConfig.data.DanTitles[player].ContainsKey(title)) {
if (TJAPlayer3.NamePlateConfig.data.DanTitles[player][title].clearStatus > cs)
cs = TJAPlayer3.NamePlateConfig.data.DanTitles[player][title].clearStatus;
if (TJAPlayer3.NamePlateConfig.data.DanTitles[player][title].isGold)
@ -78,8 +64,7 @@ namespace TJAPlayer3
// Automatically set the dan to nameplate if new
// Add a function within the NamePlate.cs file to update the title texture
if (!TJAPlayer3.NamePlateConfig.data.DanTitles[player].ContainsKey(title) || cs != clearStatus || iG != isGold)
{
if (!TJAPlayer3.NamePlateConfig.data.DanTitles[player].ContainsKey(title) || cs != clearStatus || iG != isGold) {
changed = true;
/*
TJAPlayer3.NamePlateConfig.data.Dan[player] = title;
@ -102,10 +87,8 @@ namespace TJAPlayer3
#region [Auxilliary classes]
public class CDanTitle
{
public CDanTitle(bool iG, int cs)
{
public class CDanTitle {
public CDanTitle(bool iG, int cs) {
isGold = iG;
clearStatus = cs;
}
@ -117,10 +100,8 @@ namespace TJAPlayer3
public int clearStatus;
}
public class CNamePlateTitle
{
public CNamePlateTitle(int type)
{
public class CNamePlateTitle {
public CNamePlateTitle(int type) {
iType = type;
}
@ -132,8 +113,7 @@ namespace TJAPlayer3
#region [Heya]
public void tReindexCharacter(int p, string[] characterNamesList)
{
public void tReindexCharacter(int p, string[] characterNamesList) {
string character = this.data.CharacterName[p];
if (characterNamesList.Contains(character))
@ -141,20 +121,17 @@ namespace TJAPlayer3
}
public void tUpdateCharacterName(int p, string newChara)
{
public void tUpdateCharacterName(int p, string newChara) {
this.data.CharacterName[p] = newChara;
}
public void tApplyHeyaChanges()
{
public void tApplyHeyaChanges() {
this.tSaveFile();
}
#endregion
public class Data
{
public class Data {
[JsonProperty("name")]
public string[] Name = { "プレイヤー1", "プレイヤー2", "プレイヤー3", "プレイヤー4", "プレイヤー5" };
@ -207,13 +184,11 @@ namespace TJAPlayer3
#region [private]
private void tSaveFile()
{
private void tSaveFile() {
ConfigManager.SaveConfig(data, "NamePlate.json");
}
private void tLoadFile()
{
private void tLoadFile() {
//data = ConfigManager.GetConfig<Data>(@"NamePlate.json");
if (!File.Exists("NamePlate.json"))
@ -221,8 +196,7 @@ namespace TJAPlayer3
var _data = ConfigManager.GetConfig<Data>(@"NamePlate.json");
for (int i = 0; i < _data.Name.Length; i++)
{
for (int i = 0; i < _data.Name.Length; i++) {
var _sf = new SaveFile();
_sf.tSaveFile((i + 1) + "P");
_sf.data.Name = _data.Name[i];

View File

@ -1,76 +1,60 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Text;
using System.Runtime.InteropServices;
using System.Threading;
using System.Diagnostics;
using System.IO;
using FDK;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
namespace TJAPlayer3
{
internal class Program
{
namespace TJAPlayer3 {
internal class Program {
#region [ DLL存在チェック ]
//-----------------------------
private static Mutex mutex二重起動防止用;
private static bool tDLLの存在チェック( string strDll名, string str存在しないときに表示するエラー文字列jp, string str存在しないときに表示するエラー文字列en, bool bLoadDllCheck )
{
string str存在しないときに表示するエラー文字列 = ( CultureInfo.CurrentUICulture.TwoLetterISOLanguageName == "ja" ) ?
private static bool tDLLの存在チェック(string strDll名, string str存在しないときに表示するエラー文字列jp, string str存在しないときに表示するエラー文字列en, bool bLoadDllCheck) {
string str存在しないときに表示するエラー文字列 = (CultureInfo.CurrentUICulture.TwoLetterISOLanguageName == "ja") ?
str存在しないときに表示するエラー文字列jp : str存在しないときに表示するエラー文字列en;
if ( bLoadDllCheck )
{
IntPtr hModule = LoadLibrary( strDll名 ); // 実際にLoadDll()してチェックする
if ( hModule == IntPtr.Zero )
{
if (bLoadDllCheck) {
IntPtr hModule = LoadLibrary(strDll名); // 実際にLoadDll()してチェックする
if (hModule == IntPtr.Zero) {
//MessageBox.Show( str存在しないときに表示するエラー文字列, "DTXMania runtime error", MessageBoxButtons.OK, MessageBoxIcon.Hand );
return false;
}
FreeLibrary( hModule );
}
else
{ // 単純にファイルの存在有無をチェックするだけ (プロジェクトで「参照」していたり、アンマネージドなDLLが暗黙リンクされるものはこちら)
string path = Path.Combine( System.IO.Directory.GetCurrentDirectory(), strDll名 );
if ( !File.Exists( path ) )
{
FreeLibrary(hModule);
} else { // 単純にファイルの存在有無をチェックするだけ (プロジェクトで「参照」していたり、アンマネージドなDLLが暗黙リンクされるものはこちら)
string path = Path.Combine(System.IO.Directory.GetCurrentDirectory(), strDll名);
if (!File.Exists(path)) {
//MessageBox.Show( str存在しないときに表示するエラー文字列, "DTXMania runtime error", MessageBoxButtons.OK, MessageBoxIcon.Hand );
return false;
}
}
return true;
}
private static bool tDLLの存在チェック( string strDll名, string str存在しないときに表示するエラー文字列jp, string str存在しないときに表示するエラー文字列en )
{
private static bool tDLLの存在チェック(string strDll名, string str存在しないときに表示するエラー文字列jp, string str存在しないときに表示するエラー文字列en) {
return true;
//return tDLLの存在チェック( strDll名, str存在しないときに表示するエラー文字列jp, str存在しないときに表示するエラー文字列en, false );
}
#region [DllImport]
[DllImport( "kernel32", CharSet = CharSet.Unicode, SetLastError = true )]
internal static extern void FreeLibrary( IntPtr hModule );
[DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern void FreeLibrary(IntPtr hModule);
[DllImport( "kernel32", CharSet = CharSet.Unicode, SetLastError = true )]
internal static extern IntPtr LoadLibrary( string lpFileName );
[DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern IntPtr LoadLibrary(string lpFileName);
#endregion
//-----------------------------
#endregion
[STAThread]
static void Main()
{
static void Main() {
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
mutex二重起動防止用 = new Mutex( false, "DTXManiaMutex" );
mutex二重起動防止用 = new Mutex(false, "DTXManiaMutex");
if ( mutex二重起動防止用.WaitOne( 0, false ) )
{
if (mutex二重起動防止用.WaitOne(0, false)) {
string newLine = Environment.NewLine;
bool bDLLnotfound = false;
Trace.WriteLine( "Current Directory: " + Environment.CurrentDirectory );
Trace.WriteLine("Current Directory: " + Environment.CurrentDirectory);
//Trace.WriteLine( "EXEのあるフォルダ: " + Path.GetDirectoryName( Application.ExecutablePath ) );
Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
@ -96,8 +80,7 @@ namespace TJAPlayer3
string platform = "";
switch (RuntimeInformation.ProcessArchitecture)
{
switch (RuntimeInformation.ProcessArchitecture) {
case Architecture.X64:
platform = "x64";
break;
@ -118,16 +101,15 @@ namespace TJAPlayer3
DirectoryInfo info = new DirectoryInfo(AppContext.BaseDirectory + @"Libs/" + osplatform + "-" + platform + "/");
//実行ファイルの階層にライブラリをコピー
foreach (FileInfo fileinfo in info.GetFiles())
{
foreach (FileInfo fileinfo in info.GetFiles()) {
fileinfo.CopyTo(AppContext.BaseDirectory + fileinfo.Name, true);
}
using ( var mania = new TJAPlayer3() )
using (var mania = new TJAPlayer3())
mania.Run();
Trace.WriteLine( "" );
Trace.WriteLine( "遊んでくれてありがとう!" );
Trace.WriteLine("");
Trace.WriteLine("遊んでくれてありがとう!");
}
#if !DEBUG
catch( Exception e )
@ -144,8 +126,8 @@ namespace TJAPlayer3
// END #24606 2011.03.08 from
// END #23670 2010.11.13 from
if ( Trace.Listeners.Count > 1 )
Trace.Listeners.RemoveAt( 1 );
if (Trace.Listeners.Count > 1)
Trace.Listeners.RemoveAt(1);
}
// BEGIN #24615 2011.03.09 from: Mutex.WaitOne() が true を返した場合は、Mutex のリリースが必要である。
@ -154,14 +136,13 @@ namespace TJAPlayer3
mutex二重起動防止用 = null;
// END #24615 2011.03.09 from
}
else // DTXManiaが既に起動中
} else // DTXManiaが既に起動中
{
// → 引数が0個の時はそのまま終了
// 1個( コンパクトモード or DTXV -S) か2個 (DTXV -Nxxx ファイル名)のときは、そのプロセスにコマンドラインを丸々投げて終了する
for ( int i = 0; i < 5; i++ ) // 検索結果のハンドルがZeroになることがあるので、200ms間隔で5回リトライする
for (int i = 0; i < 5; i++) // 検索結果のハンドルがZeroになることがあるので、200ms間隔で5回リトライする
{
#region [ DTXManiaプロセスを検索する]
// このやり方だと、ShowInTaskbar=falseでタスクバーに表示されないパターンの時に検索に失敗するようだが
@ -169,16 +150,14 @@ namespace TJAPlayer3
// FindWindowを使えばこのパターンにも対応できるが、C#でビルドするアプリはウインドウクラス名を自前指定できないので、これは使わない。
Process current = Process.GetCurrentProcess();
Process[] running = Process.GetProcessesByName( current.ProcessName );
Process[] running = Process.GetProcessesByName(current.ProcessName);
Process target = null;
//IntPtr hWnd = FindWindow( null, "DTXMania .NET style release " + CDTXMania.VERSION );
foreach ( Process p in running )
{
if ( p.Id != current.Id ) // プロセス名は同じでかつ、プロセスIDが自分自身とは異なるものを探す
{
if ( p.MainModule.FileName == current.MainModule.FileName && p.MainWindowHandle != IntPtr.Zero )
foreach (Process p in running) {
if (p.Id != current.Id) // プロセス名は同じでかつ、プロセスIDが自分自身とは異なるものを探す
{
if (p.MainModule.FileName == current.MainModule.FileName && p.MainWindowHandle != IntPtr.Zero) {
target = p;
break;
}
@ -187,31 +166,24 @@ namespace TJAPlayer3
#endregion
#region [ DTXManiaがいれば ]
if ( target != null )
{
if (target != null) {
string[] commandLineArgs = Environment.GetCommandLineArgs();
if ( commandLineArgs != null && commandLineArgs.Length > 1 )
{
if (commandLineArgs != null && commandLineArgs.Length > 1) {
string arg = null;
for ( int j = 1; j < commandLineArgs.Length; j++ )
{
if ( j == 1 )
{
arg += commandLineArgs[ j ];
}
else
{
arg += " " + "\"" + commandLineArgs[ j ] + "\"";
for (int j = 1; j < commandLineArgs.Length; j++) {
if (j == 1) {
arg += commandLineArgs[j];
} else {
arg += " " + "\"" + commandLineArgs[j] + "\"";
}
}
}
break;
}
#endregion
else
{
Trace.TraceInformation( "メッセージ送信先のプロセスが見つからず。5回リトライします。" );
Thread.Sleep( 200 );
else {
Trace.TraceInformation("メッセージ送信先のプロセスが見つからず。5回リトライします。");
Thread.Sleep(200);
}
}
}

View File

@ -1,15 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace TJAPlayer3
{
internal class RecentlyPlayedSongs
{
namespace TJAPlayer3 {
internal class RecentlyPlayedSongs {
public void tRecentlyPlayedSongs() {
if (!File.Exists("RecentlyPlayedSongs.json"))
tSaveFile();
@ -19,8 +9,7 @@ namespace TJAPlayer3
#region [Auxiliary methods]
public void tAddChart(string chartID)
{
public void tAddChart(string chartID) {
if (!data.recentlyplayedsongs[TJAPlayer3.SaveFile].Contains(chartID))
data.recentlyplayedsongs[TJAPlayer3.SaveFile].Enqueue(chartID);
@ -32,8 +21,7 @@ namespace TJAPlayer3
#endregion
public class Data
{
public class Data {
public Queue<string>[] recentlyplayedsongs = new Queue<string>[2] { new Queue<string>(), new Queue<string>() };
}
@ -41,13 +29,11 @@ namespace TJAPlayer3
#region [private]
private void tSaveFile()
{
private void tSaveFile() {
ConfigManager.SaveConfig(data, "RecentlyPlayedSongs.json");
}
private void tLoadFile()
{
private void tLoadFile() {
data = ConfigManager.GetConfig<Data>(@"RecentlyPlayedSongs.json");
}

View File

@ -1,24 +1,13 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Policy;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json;
namespace TJAPlayer3
{
internal class SaveFile
{
namespace TJAPlayer3 {
internal class SaveFile {
public void tSaveFile(string filename)
{
public void tSaveFile(string filename) {
path = @$"Saves{Path.DirectorySeparatorChar}" + filename + @".json";
name = filename;
if (!File.Exists(path))
{
if (!File.Exists(path)) {
this.data.Name = filename;
tSaveFile();
}
@ -28,14 +17,12 @@ namespace TJAPlayer3
tInitSaveFile();
}
public void tInitSaveFile()
{
public void tInitSaveFile() {
data.bestPlays = DBSaves.GetBestPlaysAsDict(data.SaveId);
data.tFactorizeBestPlays();
}
public void tLoadUnlockables()
{
public void tLoadUnlockables() {
data.UnlockedCharacters = DBSaves.FetchStringUnlockedAsset(data.SaveId, "unlocked_characters");
data.UnlockedPuchicharas = DBSaves.FetchStringUnlockedAsset(data.SaveId, "unlocked_puchicharas");
data.UnlockedSongs = DBSaves.FetchStringUnlockedAsset(data.SaveId, "unlocked_songs");
@ -46,8 +33,7 @@ namespace TJAPlayer3
#region [Medals and PlayCount]
public void tEarnCoins(int amount)
{
public void tEarnCoins(int amount) {
data.Medals += amount;
data.TotalEarnedMedals += amount;
@ -59,8 +45,7 @@ namespace TJAPlayer3
}
// Return false if the current amount of coins is to low
public bool tSpendCoins(int amount)
{
public bool tSpendCoins(int amount) {
if (data.Medals < amount)
return false;
@ -71,8 +56,7 @@ namespace TJAPlayer3
return true;
}
public void tRegisterAIBattleModePlay(bool IsWon)
{
public void tRegisterAIBattleModePlay(bool IsWon) {
data.AIBattleModePlaycount++;
if (IsWon) data.AIBattleModeWins++;
DBSaves.RegisterAIBattleModePlay(data.SaveId, IsWon);
@ -82,8 +66,7 @@ namespace TJAPlayer3
#region [Dan titles]
public bool tUpdateDanTitle(string title, bool isGold, int clearStatus)
{
public bool tUpdateDanTitle(string title, bool isGold, int clearStatus) {
bool changed = false;
bool iG = isGold;
@ -92,8 +75,7 @@ namespace TJAPlayer3
if (this.data.DanTitles == null)
this.data.DanTitles = new Dictionary<string, CDanTitle>();
if (this.data.DanTitles.ContainsKey(title))
{
if (this.data.DanTitles.ContainsKey(title)) {
if (this.data.DanTitles[title].clearStatus > cs)
cs = this.data.DanTitles[title].clearStatus;
if (this.data.DanTitles[title].isGold)
@ -103,8 +85,7 @@ namespace TJAPlayer3
// Automatically set the dan to nameplate if new
// Add a function within the NamePlate.cs file to update the title texture
if (!this.data.DanTitles.ContainsKey(title) || cs != clearStatus || iG != isGold)
{
if (!this.data.DanTitles.ContainsKey(title) || cs != clearStatus || iG != isGold) {
DBSaves.RegisterDanTitle(data.SaveId, title, clearStatus, isGold);
changed = true;
/*
@ -128,16 +109,13 @@ namespace TJAPlayer3
#region [Auxilliary classes]
public class CDanTitle
{
public CDanTitle(bool iG, int cs)
{
public class CDanTitle {
public CDanTitle(bool iG, int cs) {
isGold = iG;
clearStatus = cs;
}
public CDanTitle()
{
public CDanTitle() {
isGold = false;
clearStatus = 0;
}
@ -149,10 +127,8 @@ namespace TJAPlayer3
public int clearStatus;
}
public class CNamePlateTitle
{
public CNamePlateTitle(int type)
{
public class CNamePlateTitle {
public CNamePlateTitle(int type) {
iType = type;
cld = new CLocalizationData();
}
@ -164,10 +140,8 @@ namespace TJAPlayer3
public CLocalizationData cld;
}
public class CPassStatus
{
public CPassStatus()
{
public class CPassStatus {
public CPassStatus() {
d = new int[5] { -1, -1, -1, -1, -1 };
}
@ -178,8 +152,7 @@ namespace TJAPlayer3
#region [Heya]
public void tReindexCharacter(string[] characterNamesList)
{
public void tReindexCharacter(string[] characterNamesList) {
string character = this.data.CharacterName;
if (characterNamesList.Contains(character))
@ -187,21 +160,18 @@ namespace TJAPlayer3
}
public void tUpdateCharacterName(string newChara)
{
public void tUpdateCharacterName(string newChara) {
this.data.CharacterName = newChara;
}
public void tApplyHeyaChanges()
{
public void tApplyHeyaChanges() {
DBSaves.ApplyChangesFromMyRoom(this);
//this.tSaveFile();
}
#endregion
public class Data
{
public class Data {
[JsonProperty("saveId")]
public Int64 SaveId = 0;
@ -232,6 +202,7 @@ namespace TJAPlayer3
[JsonProperty("puchiChara")]
public string PuchiChara = "0";
[JsonProperty("medals")]
public Int64 Medals = 0;
@ -276,7 +247,7 @@ namespace TJAPlayer3
public HashSet<string> ActiveTriggers = new HashSet<string>();
[JsonIgnore]
public Dictionary<string, BestPlayRecords.CBestPlayRecord> bestPlays = new Dictionary<string, BestPlayRecords.CBestPlayRecord> ();
public Dictionary<string, BestPlayRecords.CBestPlayRecord> bestPlays = new Dictionary<string, BestPlayRecords.CBestPlayRecord>();
[JsonIgnore]
public Dictionary<string, BestPlayRecords.CBestPlayRecord> bestPlaysDistinctCharts = new Dictionary<string, BestPlayRecords.CBestPlayRecord>();
@ -293,29 +264,22 @@ namespace TJAPlayer3
[JsonIgnore]
public BestPlayRecords.CBestPlayStats bestPlaysStats = new BestPlayRecords.CBestPlayStats();
public BestPlayRecords.CSongSelectTableEntry tGetSongSelectTableEntry(string uniqueId)
{
public BestPlayRecords.CSongSelectTableEntry tGetSongSelectTableEntry(string uniqueId) {
if (songSelectTableEntries.ContainsKey(uniqueId)) return songSelectTableEntries[uniqueId];
return new BestPlayRecords.CSongSelectTableEntry();
}
#region [Factorize best plays]
public void tFactorizeBestPlays()
{
public void tFactorizeBestPlays() {
bestPlaysDistinctCharts = new Dictionary<string, BestPlayRecords.CBestPlayRecord>();
foreach (BestPlayRecords.CBestPlayRecord bestPlay in bestPlays.Values)
{
foreach (BestPlayRecords.CBestPlayRecord bestPlay in bestPlays.Values) {
string key = bestPlay.ChartUniqueId + bestPlay.ChartDifficulty.ToString();
if (!bestPlaysDistinctCharts.ContainsKey(key))
{
if (!bestPlaysDistinctCharts.ContainsKey(key)) {
bestPlaysDistinctCharts[key] = bestPlay.Copy();
}
else
{
if (bestPlay.HighScore > bestPlaysDistinctCharts[key].HighScore)
{
} else {
if (bestPlay.HighScore > bestPlaysDistinctCharts[key].HighScore) {
bestPlaysDistinctCharts[key].HighScore = bestPlay.HighScore;
bestPlaysDistinctCharts[key].HighScoreGoodCount = bestPlay.HighScoreGoodCount;
bestPlaysDistinctCharts[key].HighScoreOkCount = bestPlay.HighScoreOkCount;
@ -333,17 +297,12 @@ namespace TJAPlayer3
bestPlaysDistinctSongs = new Dictionary<string, BestPlayRecords.CBestPlayRecord>();
songSelectTableEntries = new Dictionary<string, BestPlayRecords.CSongSelectTableEntry>();
foreach (BestPlayRecords.CBestPlayRecord bestPlay in bestPlaysDistinctCharts.Values)
{
foreach (BestPlayRecords.CBestPlayRecord bestPlay in bestPlaysDistinctCharts.Values) {
string key = bestPlay.ChartUniqueId;
if (!bestPlaysDistinctSongs.ContainsKey(key))
{
if (!bestPlaysDistinctSongs.ContainsKey(key)) {
bestPlaysDistinctSongs[key] = bestPlay.Copy();
}
else
{
if (bestPlay.HighScore > bestPlaysDistinctSongs[key].HighScore)
{
} else {
if (bestPlay.HighScore > bestPlaysDistinctSongs[key].HighScore) {
bestPlaysDistinctSongs[key].HighScore = bestPlay.HighScore;
bestPlaysDistinctSongs[key].HighScoreGoodCount = bestPlay.HighScoreGoodCount;
bestPlaysDistinctSongs[key].HighScoreOkCount = bestPlay.HighScoreOkCount;
@ -358,17 +317,14 @@ namespace TJAPlayer3
}
// Entries to replace score.GPInfo on the song select menus
if (!songSelectTableEntries.ContainsKey(key))
{
if (!songSelectTableEntries.ContainsKey(key)) {
songSelectTableEntries[key] = new BestPlayRecords.CSongSelectTableEntry();
}
if (bestPlay.ChartDifficulty > songSelectTableEntries[key].ScoreRankDifficulty && bestPlay.ScoreRank >= 0)
{
if (bestPlay.ChartDifficulty > songSelectTableEntries[key].ScoreRankDifficulty && bestPlay.ScoreRank >= 0) {
songSelectTableEntries[key].ScoreRankDifficulty = (int)bestPlay.ChartDifficulty;
songSelectTableEntries[key].ScoreRank = (int)bestPlay.ScoreRank;
}
if (bestPlay.ChartDifficulty > songSelectTableEntries[key].ClearStatusDifficulty && bestPlay.ClearStatus >= 0)
{
if (bestPlay.ChartDifficulty > songSelectTableEntries[key].ClearStatusDifficulty && bestPlay.ClearStatus >= 0) {
songSelectTableEntries[key].ClearStatusDifficulty = (int)bestPlay.ChartDifficulty;
songSelectTableEntries[key].ClearStatus = (int)bestPlay.ClearStatus;
}
@ -390,13 +346,11 @@ namespace TJAPlayer3
#region [private]
private void tSaveFile()
{
private void tSaveFile() {
ConfigManager.SaveConfig(data, path);
}
private void tLoadFile()
{
private void tLoadFile() {
data = ConfigManager.GetConfig<Data>(path);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TJAPlayer3
{
internal class CGimmickValue
{
namespace TJAPlayer3 {
internal class CGimmickValue {
}
}

View File

@ -1,25 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json;
namespace TJAPlayer3
{
namespace TJAPlayer3 {
[Serializable]
internal class CLocalizationData
{
internal class CLocalizationData {
[JsonProperty("strings")]
private Dictionary<string, string> Strings = new Dictionary<string, string>();
public CLocalizationData()
{
public CLocalizationData() {
Strings = new Dictionary<string, string>();
}
public string GetString(string defaultsDefault)
{
public string GetString(string defaultsDefault) {
string _lang = CLangManager.fetchLang();
if (Strings.ContainsKey(_lang))
return Strings[_lang];
@ -28,8 +19,7 @@ namespace TJAPlayer3
return defaultsDefault;
}
public void SetString(string langcode, string str)
{
public void SetString(string langcode, string str) {
Strings[langcode] = str;
}
}

View File

@ -1,15 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using static SevenZip.Compression.LZMA.SevenZipHelper;
namespace TJAPlayer3
{
class CSongReplay
{
namespace TJAPlayer3 {
class CSongReplay {
/* Game version used for the replay
* 521 = 0.5.2.1
* 530 = 0.5.3
@ -35,8 +25,7 @@ namespace TJAPlayer3
* - 8 (256) : Safe (Bad => Ok)
*/
[Flags]
public enum EModFlag
{
public enum EModFlag {
None = 0,
Mirror = 1 << 0,
Random = 1 << 1,
@ -49,40 +38,33 @@ namespace TJAPlayer3
Safe = 1 << 8
}
public CSongReplay()
{
public CSongReplay() {
replayFolder = "";
storedPlayer = 0;
}
public CSongReplay(string ChartPath, int player)
{
public CSongReplay(string ChartPath, int player) {
string _chartFolder = Path.GetDirectoryName(ChartPath);
replayFolder = Path.Combine(_chartFolder, REPLAY_FOLDER_NAME);
try
{
try {
Directory.CreateDirectory(replayFolder);
Console.WriteLine("Folder Path: " + replayFolder);
}
catch (Exception ex)
{
} catch (Exception ex) {
Console.WriteLine("An error occurred: " + ex.Message);
}
storedPlayer = player;
}
public void tRegisterInput(double timestamp, byte keypress)
{
public void tRegisterInput(double timestamp, byte keypress) {
allInputs.Add(Tuple.Create(timestamp, keypress));
}
#region [Dan methods]
public void tDanRegisterSongCount(int songCount)
{
public void tDanRegisterSongCount(int songCount) {
DanSongCount = songCount;
IndividualGoodCount = new int[songCount];
IndividualOkCount = new int[songCount];
@ -94,8 +76,7 @@ namespace TJAPlayer3
IndividualScore = new int[songCount];
}
public void tDanInputSongResults(int songNo)
{
public void tDanInputSongResults(int songNo) {
if (songNo >= DanSongCount) return;
if (songNo < 0) return;
IndividualGoodCount[songNo] = TJAPlayer3.stage演奏ドラム画面.n良[songNo];
@ -114,12 +95,10 @@ namespace TJAPlayer3
#region [Load methods]
private List<Tuple<double, byte>> ConvertByteArrayToTupleList(byte[] byteArray)
{
private List<Tuple<double, byte>> ConvertByteArrayToTupleList(byte[] byteArray) {
List<Tuple<double, byte>> tupleList = new List<Tuple<double, byte>>();
for (int i = 0; i < byteArray.Length; i += sizeof(double) + sizeof(byte))
{
for (int i = 0; i < byteArray.Length; i += sizeof(double) + sizeof(byte)) {
double doubleValue = BitConverter.ToDouble(byteArray, i);
byte byteValue = byteArray[i + sizeof(double)];
tupleList.Add(Tuple.Create(doubleValue, byteValue));
@ -128,14 +107,10 @@ namespace TJAPlayer3
return tupleList;
}
public void tLoadReplayFile(string optkrFilePath)
{
try
{
using (FileStream fileStream = new FileStream(optkrFilePath, FileMode.Open))
{
using (BinaryReader reader = new BinaryReader(fileStream))
{
public void tLoadReplayFile(string optkrFilePath) {
try {
using (FileStream fileStream = new FileStream(optkrFilePath, FileMode.Open)) {
using (BinaryReader reader = new BinaryReader(fileStream)) {
GameMode = reader.ReadByte();
GameVersion = reader.ReadInt32();
ChartChecksum = reader.ReadString();
@ -152,8 +127,7 @@ namespace TJAPlayer3
ReachedFloor = reader.ReadInt32();
RemainingLives = reader.ReadInt32();
DanSongCount = reader.ReadInt32();
for (int i = 0; i < DanSongCount; i++)
{
for (int i = 0; i < DanSongCount; i++) {
IndividualGoodCount[i] = reader.ReadInt32();
IndividualOkCount[i] = reader.ReadInt32();
IndividualBadCount[i] = reader.ReadInt32();
@ -182,9 +156,7 @@ namespace TJAPlayer3
OnlineScoreID = reader.ReadInt64();
}
}
}
catch (Exception ex)
{
} catch (Exception ex) {
}
}
@ -193,12 +165,10 @@ namespace TJAPlayer3
#region [Save methods]
private byte[] ConvertTupleListToByteArray(List<Tuple<double, byte>> tupleList)
{
private byte[] ConvertTupleListToByteArray(List<Tuple<double, byte>> tupleList) {
List<byte> byteArray = new List<byte>();
foreach (var tuple in tupleList)
{
foreach (var tuple in tupleList) {
byte[] doubleBytes = BitConverter.GetBytes(tuple.Item1);
byteArray.AddRange(doubleBytes);
byteArray.Add(tuple.Item2);
@ -207,16 +177,12 @@ namespace TJAPlayer3
return byteArray.ToArray();
}
public void tSaveReplayFile()
{
public void tSaveReplayFile() {
string _path = replayFolder + @"/Replay_" + ChartUniqueID + @"_" + PlayerName + @"_" + Timestamp.ToString() + @".optkr";
try
{
using (FileStream fileStream = new FileStream(_path, FileMode.Create))
{
using (BinaryWriter writer = new BinaryWriter(fileStream))
{
try {
using (FileStream fileStream = new FileStream(_path, FileMode.Create)) {
using (BinaryWriter writer = new BinaryWriter(fileStream)) {
writer.Write(GameMode);
writer.Write(GameVersion);
writer.Write(ChartChecksum);
@ -233,8 +199,7 @@ namespace TJAPlayer3
writer.Write(ReachedFloor);
writer.Write(RemainingLives);
writer.Write(DanSongCount);
for (int i = 0; i < DanSongCount; i++)
{
for (int i = 0; i < DanSongCount; i++) {
writer.Write(IndividualGoodCount[i]);
writer.Write(IndividualOkCount[i]);
writer.Write(IndividualBadCount[i]);
@ -261,21 +226,17 @@ namespace TJAPlayer3
writer.Write(OnlineScoreID);
}
}
}
catch (Exception ex)
{
} catch (Exception ex) {
}
}
public void tResultsRegisterReplayInformations(int Coins, int Clear, int SRank)
{
public void tResultsRegisterReplayInformations(int Coins, int Clear, int SRank) {
// Actual player (Used for saved informations)
int actualPlayer = TJAPlayer3.GetActualPlayer(storedPlayer);
// Game mode
switch (TJAPlayer3.stageSongSelect.nChoosenSongDifficulty[0])
{
switch (TJAPlayer3.stageSongSelect.nChoosenSongDifficulty[0]) {
case (int)Difficulty.Dan:
GameMode = 1;
break;
@ -303,8 +264,7 @@ namespace TJAPlayer3
Score = TJAPlayer3.stage演奏ドラム画面.CChartScore[storedPlayer].nScore;
CoinValue = (short)Coins;
// Tower parameters
if (GameMode == 2)
{
if (GameMode == 2) {
ReachedFloor = CFloorManagement.LastRegisteredFloor;
RemainingLives = CFloorManagement.CurrentNumberOfLives;
}

View File

@ -1,32 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using FDK;
using FDK;
namespace TJAPlayer3
{
class CVisualLogManager
{
public enum ELogCardType
{
namespace TJAPlayer3 {
class CVisualLogManager {
public enum ELogCardType {
LogInfo,
LogWarning,
LogError
}
class LogCard
{
public LogCard(ELogCardType type, string message)
{
class LogCard {
public LogCard(ELogCardType type, string message) {
lct = type;
msg = message;
timeSinceCreation = new CCounter(0, 10000, 1, TJAPlayer3.Timer);
}
public void Display(int screenPosition)
{
public void Display(int screenPosition) {
timeSinceCreation.Tick();
// Display stuff here
@ -37,8 +26,7 @@ namespace TJAPlayer3
TJAPlayer3.actTextConsole.tPrint(x, y, CTextConsole.EFontType.Cyan, msg);
}
public bool IsExpired()
{
public bool IsExpired() {
return timeSinceCreation.IsEnded;
}
@ -47,13 +35,11 @@ namespace TJAPlayer3
private string msg;
}
public void PushCard(ELogCardType lct, string msg)
{
public void PushCard(ELogCardType lct, string msg) {
cards.Add(new LogCard(lct, msg));
}
public void Display()
{
public void Display() {
for (int i = 0; i < cards.Count; i++)
cards[i].Display(i);
cards.RemoveAll(card => card.IsExpired());

View File

@ -1,28 +1,20 @@
using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json;
using Newtonsoft.Json;
namespace TJAPlayer3
{
class DBCDN : CSavableT<Dictionary<string, DBCDN.CDNData>>
{
public DBCDN()
{
namespace TJAPlayer3 {
class DBCDN : CSavableT<Dictionary<string, DBCDN.CDNData>> {
public DBCDN() {
_fn = @$"{TJAPlayer3.strEXEのあるフォルダ}Databases{Path.DirectorySeparatorChar}CDN.json";
base.tDBInitSavable();
}
#region [Auxiliary classes]
public class CDNHooks
{
public class CDNHooks {
public string id = "id";
public Dictionary<string, string> title = new Dictionary<string, string>()
{
public Dictionary<string, string> title = new Dictionary<string, string>() {
["default"] = "title",
};
public Dictionary<string, string> subtitle = new Dictionary<string, string>()
{
public Dictionary<string, string> subtitle = new Dictionary<string, string>() {
["default"] = "subtitle",
};
public string[] difficulties = { "easy", "normal", "hard", "extreme", "extra", "tower", "dan" };
@ -30,28 +22,24 @@ namespace TJAPlayer3
public string updateDate = "updateDate";
public string creationDate = "creationDate";
public string uploadDate = "uploadDate";
public Dictionary<string, string> md5 = new Dictionary<string, string>()
{
public Dictionary<string, string> md5 = new Dictionary<string, string>() {
["default"] = "md5",
};
public string genre = "genre";
public Dictionary<string, string> genreSub = new Dictionary<string, string>()
{
public Dictionary<string, string> genreSub = new Dictionary<string, string>() {
["default"] = "name",
};
public string charter = "charter";
}
public class CDNData
{
public class CDNData {
[JsonProperty("baseUrl")]
public string BaseUrl;
[JsonProperty("download")]
public Dictionary<string, string> Download = new Dictionary<string, string>()
{
public Dictionary<string, string> Download = new Dictionary<string, string>() {
["default"] = "download/",
};

Some files were not shown because too many files have changed in this diff Show More