diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..7716accd --- /dev/null +++ b/.editorconfig @@ -0,0 +1,264 @@ +# Remove the line below if you want to inherit .editorconfig settings from higher directories +root = true + +# C# files +[*.cs] + +#### Core EditorConfig Options #### + +# Indentation and spacing +indent_size = 4 +indent_style = space +tab_width = 4 + +# New line preferences +end_of_line = crlf +insert_final_newline = false + +#### .NET Coding Conventions #### + +# Organize usings +dotnet_separate_import_directive_groups = true +dotnet_sort_system_directives_first = false +file_header_template = unset + +# this. and Me. preferences +dotnet_style_qualification_for_event = false +dotnet_style_qualification_for_field = false +dotnet_style_qualification_for_method = false +dotnet_style_qualification_for_property = false + +# Language keywords vs BCL types preferences +dotnet_style_predefined_type_for_locals_parameters_members = true:error +dotnet_style_predefined_type_for_member_access = true:error + +# Parentheses preferences +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity +dotnet_style_parentheses_in_other_operators = never_if_unnecessary +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity + +# Modifier preferences +dotnet_style_require_accessibility_modifiers = for_non_interface_members + +# Expression-level preferences +dotnet_style_coalesce_expression = true +dotnet_style_collection_initializer = true:error +dotnet_style_explicit_tuple_names = true +dotnet_style_namespace_match_folder = true +dotnet_style_null_propagation = true +dotnet_style_object_initializer = true:error +dotnet_style_operator_placement_when_wrapping = beginning_of_line +dotnet_style_prefer_auto_properties = true:error +dotnet_style_prefer_collection_expression = true +dotnet_style_prefer_compound_assignment = true:error +dotnet_style_prefer_conditional_expression_over_assignment = true +dotnet_style_prefer_conditional_expression_over_return = true +dotnet_style_prefer_foreach_explicit_cast_in_source = when_strongly_typed +dotnet_style_prefer_inferred_anonymous_type_member_names = true +dotnet_style_prefer_inferred_tuple_names = true +dotnet_style_prefer_is_null_check_over_reference_equality_method = true +dotnet_style_prefer_simplified_boolean_expressions = true:error +dotnet_style_prefer_simplified_interpolation = true + +# Field preferences +dotnet_style_readonly_field = true:error + +# Parameter preferences +dotnet_code_quality_unused_parameters = all:error + +# Suppression preferences +dotnet_remove_unnecessary_suppression_exclusions = none + +# New line preferences +dotnet_style_allow_multiple_blank_lines_experimental = true +dotnet_style_allow_statement_immediately_after_block_experimental = true + +#### C# Coding Conventions #### + +# var preferences +csharp_style_var_elsewhere = true:warning +csharp_style_var_for_built_in_types = true:warning +csharp_style_var_when_type_is_apparent = true:warning + +# Expression-bodied members +csharp_style_expression_bodied_accessors = true:error +csharp_style_expression_bodied_constructors = false +csharp_style_expression_bodied_indexers = true:error +csharp_style_expression_bodied_lambdas = true:error +csharp_style_expression_bodied_local_functions = true:error +csharp_style_expression_bodied_methods = true:error +csharp_style_expression_bodied_operators = true:error +csharp_style_expression_bodied_properties = true:error + +# Pattern matching preferences +csharp_style_pattern_matching_over_as_with_null_check = true +csharp_style_pattern_matching_over_is_with_cast_check = true +csharp_style_prefer_extended_property_pattern = true +csharp_style_prefer_not_pattern = true +csharp_style_prefer_pattern_matching = true:suggestion +csharp_style_prefer_switch_expression = true + +# Null-checking preferences +csharp_style_conditional_delegate_call = true + +# Modifier preferences +csharp_prefer_static_local_function = true +csharp_preferred_modifier_order = public,private,protected,internal,file,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,required,volatile,async +csharp_style_prefer_readonly_struct = true:error +csharp_style_prefer_readonly_struct_member = true + +# Code-block preferences +csharp_prefer_braces = true:error +csharp_prefer_simple_using_statement = true:error +csharp_style_namespace_declarations = block_scoped +csharp_style_prefer_method_group_conversion = true:error +csharp_style_prefer_primary_constructors = true +csharp_style_prefer_top_level_statements = true + +# Expression-level preferences +csharp_prefer_simple_default_expression = true +csharp_style_deconstructed_variable_declaration = true +csharp_style_implicit_object_creation_when_type_is_apparent = true:error +csharp_style_inlined_variable_declaration = true +csharp_style_prefer_index_operator = true:error +csharp_style_prefer_local_over_anonymous_function = true +csharp_style_prefer_null_check_over_type_check = true +csharp_style_prefer_range_operator = true:error +csharp_style_prefer_tuple_swap = true:error +csharp_style_prefer_utf8_string_literals = true +csharp_style_throw_expression = true +csharp_style_unused_value_assignment_preference = discard_variable:error +csharp_style_unused_value_expression_statement_preference = discard_variable + +# 'using' directive preferences +csharp_using_directive_placement = outside_namespace:error + +# New line preferences +csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true +csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = true +csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = true +csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true +csharp_style_allow_embedded_statements_on_same_line_experimental = true + +#### C# Formatting Rules #### + +# New line preferences +csharp_new_line_before_open_brace = all +csharp_new_line_before_catch = true +csharp_new_line_before_else = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_before_members_in_object_initializers = 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_labels = one_less_than_current +csharp_indent_switch_labels = true + +# 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 = false +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 + +# Wrapping preferences +csharp_preserve_single_line_blocks = true +csharp_preserve_single_line_statements = true + +#### Naming styles #### + +# Naming rules + +dotnet_naming_rule.interface_should_be_ipascalcase.severity = error +dotnet_naming_rule.interface_should_be_ipascalcase.symbols = interface +dotnet_naming_rule.interface_should_be_ipascalcase.style = ipascalcase + +dotnet_naming_rule.types_should_be_pascalcase.severity = error +dotnet_naming_rule.types_should_be_pascalcase.symbols = types +dotnet_naming_rule.types_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.non_field_members_should_be_pascalcase.severity = error +dotnet_naming_rule.non_field_members_should_be_pascalcase.symbols = non_field_members +dotnet_naming_rule.non_field_members_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.public_or_protected_field_should_be_camelcase.severity = error +dotnet_naming_rule.public_or_protected_field_should_be_camelcase.symbols = public_or_protected_field +dotnet_naming_rule.public_or_protected_field_should_be_camelcase.style = camelcase + +# Symbol specifications + +dotnet_naming_symbols.interface.applicable_kinds = interface +dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.interface.required_modifiers = + +dotnet_naming_symbols.public_or_protected_field.applicable_kinds = field +dotnet_naming_symbols.public_or_protected_field.applicable_accessibilities = public, protected +dotnet_naming_symbols.public_or_protected_field.required_modifiers = + +dotnet_naming_symbols.private_or_internal_field.applicable_kinds = field +dotnet_naming_symbols.private_or_internal_field.applicable_accessibilities = internal, private, private_protected +dotnet_naming_symbols.private_or_internal_field.required_modifiers = + +dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum +dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.types.required_modifiers = + +dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method +dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.non_field_members.required_modifiers = + +dotnet_naming_symbols.abstract_class.applicable_kinds = class +dotnet_naming_symbols.abstract_class.applicable_accessibilities = +dotnet_naming_symbols.abstract_class.required_modifiers = abstract + +dotnet_naming_symbols.private_property_or_method.applicable_kinds = property, method +dotnet_naming_symbols.private_property_or_method.applicable_accessibilities = private, private_protected +dotnet_naming_symbols.private_property_or_method.required_modifiers = + +dotnet_naming_symbols.static_const.applicable_kinds = property, field, local, method +dotnet_naming_symbols.static_const.applicable_accessibilities = * +dotnet_naming_symbols.static_const.required_modifiers = const, static + +dotnet_naming_symbols.private_static_const.applicable_kinds = property, field, local, method, local_function +dotnet_naming_symbols.private_static_const.applicable_accessibilities = private, private_protected +dotnet_naming_symbols.private_static_const.required_modifiers = const, static + +# Naming styles + +dotnet_naming_style.pascalcase.required_prefix = +dotnet_naming_style.pascalcase.required_suffix = +dotnet_naming_style.pascalcase.word_separator = +dotnet_naming_style.pascalcase.capitalization = pascal_case + +dotnet_naming_style.ipascalcase.required_prefix = I +dotnet_naming_style.ipascalcase.required_suffix = +dotnet_naming_style.ipascalcase.word_separator = +dotnet_naming_style.ipascalcase.capitalization = pascal_case + +dotnet_naming_style.camelcase.required_prefix = +dotnet_naming_style.camelcase.required_suffix = +dotnet_naming_style.camelcase.word_separator = +dotnet_naming_style.camelcase.capitalization = camel_case \ No newline at end of file diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml new file mode 100644 index 00000000..1a593ccf --- /dev/null +++ b/.github/workflows/dotnet.yml @@ -0,0 +1,42 @@ +name: .NET + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +jobs: + build: + + runs-on: windows-latest + + steps: + - uses: actions/checkout@v3 + - name: Setup .NET + uses: actions/setup-dotnet@v3 + with: + dotnet-version: 8.0.x + include-prerelease: true + - name: Restore dependencies + run: dotnet restore + + - name: Build + run: dotnet build --no-restore + - name: Test + run: dotnet test --no-build --verbosity normal /p:CollectCoverage=true /p:CoverletOutput=TestResults/ /p:CoverletOutputFormat=lcov + + - name: Set Up NPM + uses: actions/setup-node@v2 + with: + node-version: '14' + - name: Install 'lcov-result-merger' + run: npm i -g lcov-result-merger + - name: Merge Test Coverage + run: lcov-result-merger "**/coverage.info" "lcov.info" + + - name: Upload to Coveralls + uses: coverallsapp/github-action@master + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + path-to-lcov: lcov.info \ No newline at end of file diff --git a/README.md b/README.md index 344a7612..cff5d063 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,8 @@ # SAM Software Automatic Mouth +![Unit tests](https://github.com/Monczak/SamSharp/actions/workflows/dotnet.yml/badge.svg) +[![Coverage Status](https://coveralls.io/repos/github/Monczak/SamSharp/badge.svg?service=github)](https://coveralls.io/github/Monczak/SamSharp) + ## What is SAM? This is a C# port of the Text-To-Speech (TTS) software @@ -59,10 +62,10 @@ sam.SpeakAsync("I am speaking asynchronously").ContinueWith(audio => DoSomething ### Command line usage -The `SamSharpTest` project contains a simple testing program, which can be run from the command line to try out SAM. Run it with: +The `SamSharpCli` project contains a simple testing program, which can be run from the command line to try out SAM. Run it with: ``` -./SamSharpTest [-p --pitch pitch] [-s --speed speed] [-m --mouth mouth] [-t --throat throat] [--phonetic] [--sing] [-o --output path/to/file.wav] +./SamSharpCli [-p --pitch pitch] [-s --speed speed] [-m --mouth mouth] [-t --throat throat] [--phonetic] [--sing] [-o --output path/to/file.wav] ``` If the `-o` option is omitted, the program will play the synthesized speech on your default audio device. The `pitch`, `speed`, `mouth` and `throat` parameters should be numbers from 0 to 255. diff --git a/SamSharp Tests/GlobalUsings.cs b/SamSharp Tests/GlobalUsings.cs new file mode 100644 index 00000000..cefced49 --- /dev/null +++ b/SamSharp Tests/GlobalUsings.cs @@ -0,0 +1 @@ +global using NUnit.Framework; \ No newline at end of file diff --git a/SamSharp Tests/GoldenWordsTests.cs b/SamSharp Tests/GoldenWordsTests.cs new file mode 100644 index 00000000..367af59d --- /dev/null +++ b/SamSharp Tests/GoldenWordsTests.cs @@ -0,0 +1,90 @@ +using SamSharp; + +using NAudio.Wave; + +using System.Reflection; +using System.Security.Cryptography; + +namespace SamSharp_Tests; + +public class GoldenWordsTests +{ + private readonly Sam sam = new(); + + private static readonly DirectoryInfo GoldensDirectory; + private static readonly DirectoryInfo GoldenWordsDirectory; + + static GoldenWordsTests() + { + var executingAssembly = Assembly.GetExecutingAssembly(); + var assemblyName = + executingAssembly.ManifestModule.Name.SubstringUpTo(".dll"); + + var executingAssemblyDll = new FileInfo(executingAssembly.Location); + var executingAssemblyDir = executingAssemblyDll.Directory; + + var currentDir = executingAssemblyDir; + while (currentDir?.Name != assemblyName) + { + currentDir = currentDir?.Parent; + } + + Assert.IsNotNull(currentDir); + + var gloTestsDir = currentDir; + GoldensDirectory = gloTestsDir.GetDirectories("goldens").Single(); + GoldenWordsDirectory = + GoldensDirectory.GetDirectories("words").Single(); + } + + private static IEnumerable GetGoldenWords() => + File.ReadAllLines( + GoldensDirectory.GetFiles("words/list.txt").Single().FullName) + .Select(line => line.Trim()) + .Where(line => line.Length > 0); + + [Test] + [TestCaseSource(nameof(GetGoldenWords))] + public async Task TestGoldens(string word) + { + var audio = await sam.SpeakAsync(word); + + var provider = new RawSourceWaveStream(new MemoryStream(audio), + new WaveFormat(22050, 8, 1)); + + var outputPath = + Path.Join(GoldenWordsDirectory.FullName, $"{word}.ogg"); + if (!File.Exists(outputPath)) + { + WaveFileWriter.CreateWaveFile(outputPath, provider); + } + else + { + var expectedStream = new WaveFileReader(outputPath); + var actualStream = provider; + AssertStreamsEqual(expectedStream, actualStream); + } + } + + private static void AssertStreamsEqual(Stream expected, Stream actual) => + Assert.AreEqual(ComputeHash(expected), ComputeHash(actual)); + + private static byte[] ComputeHash(Stream data) + { + using HashAlgorithm algorithm = MD5.Create(); + byte[] bytes = algorithm.ComputeHash(data); + data.Seek(0, + SeekOrigin + .Begin); //I'll use this trick so the caller won't end up with the stream in unexpected position + return bytes; + } +} + +static class StringExtensions +{ + public static string SubstringUpTo(this string str, string substr) + { + var indexTo = str.IndexOf(substr); + return indexTo >= 0 ? str[..indexTo] : str; + } +} \ No newline at end of file diff --git a/SamSharp Tests/SamSharp Tests.csproj b/SamSharp Tests/SamSharp Tests.csproj new file mode 100644 index 00000000..c1a0b47f --- /dev/null +++ b/SamSharp Tests/SamSharp Tests.csproj @@ -0,0 +1,31 @@ + + + + net6.0 + SamSharp_Tests + enable + enable + + false + true + + + + + + + + + + + + + + + + + + + + + diff --git a/SamSharp Tests/goldens/delete_golden_audio.bat b/SamSharp Tests/goldens/delete_golden_audio.bat new file mode 100644 index 00000000..d4a99e9f --- /dev/null +++ b/SamSharp Tests/goldens/delete_golden_audio.bat @@ -0,0 +1,8 @@ +@echo off +echo This will delete all goldens audio files. Are you sure you wish to proceed? +pause + +del /S *.ogg + +echo Done. +pause \ No newline at end of file diff --git a/SamSharp Tests/goldens/words/#.ogg b/SamSharp Tests/goldens/words/#.ogg new file mode 100644 index 00000000..85e6111e Binary files /dev/null and b/SamSharp Tests/goldens/words/#.ogg differ diff --git a/SamSharp Tests/goldens/words/$.ogg b/SamSharp Tests/goldens/words/$.ogg new file mode 100644 index 00000000..7da3ed14 Binary files /dev/null and b/SamSharp Tests/goldens/words/$.ogg differ diff --git a/SamSharp Tests/goldens/words/%.ogg b/SamSharp Tests/goldens/words/%.ogg new file mode 100644 index 00000000..088dacd9 Binary files /dev/null and b/SamSharp Tests/goldens/words/%.ogg differ diff --git a/SamSharp Tests/goldens/words/&.ogg b/SamSharp Tests/goldens/words/&.ogg new file mode 100644 index 00000000..d24c7b15 Binary files /dev/null and b/SamSharp Tests/goldens/words/&.ogg differ diff --git a/SamSharp Tests/goldens/words/+.ogg b/SamSharp Tests/goldens/words/+.ogg new file mode 100644 index 00000000..8aea427b Binary files /dev/null and b/SamSharp Tests/goldens/words/+.ogg differ diff --git a/SamSharp Tests/goldens/words/1.ogg b/SamSharp Tests/goldens/words/1.ogg new file mode 100644 index 00000000..d6bcca2e Binary files /dev/null and b/SamSharp Tests/goldens/words/1.ogg differ diff --git a/SamSharp Tests/goldens/words/10th.ogg b/SamSharp Tests/goldens/words/10th.ogg new file mode 100644 index 00000000..8633b952 Binary files /dev/null and b/SamSharp Tests/goldens/words/10th.ogg differ diff --git a/SamSharp Tests/goldens/words/1st.ogg b/SamSharp Tests/goldens/words/1st.ogg new file mode 100644 index 00000000..8b6003b2 Binary files /dev/null and b/SamSharp Tests/goldens/words/1st.ogg differ diff --git a/SamSharp Tests/goldens/words/2.ogg b/SamSharp Tests/goldens/words/2.ogg new file mode 100644 index 00000000..64210b5a Binary files /dev/null and b/SamSharp Tests/goldens/words/2.ogg differ diff --git a/SamSharp Tests/goldens/words/2nd.ogg b/SamSharp Tests/goldens/words/2nd.ogg new file mode 100644 index 00000000..a42db36d Binary files /dev/null and b/SamSharp Tests/goldens/words/2nd.ogg differ diff --git a/SamSharp Tests/goldens/words/3.ogg b/SamSharp Tests/goldens/words/3.ogg new file mode 100644 index 00000000..ed6a8c02 Binary files /dev/null and b/SamSharp Tests/goldens/words/3.ogg differ diff --git a/SamSharp Tests/goldens/words/3rd.ogg b/SamSharp Tests/goldens/words/3rd.ogg new file mode 100644 index 00000000..dd2e1120 Binary files /dev/null and b/SamSharp Tests/goldens/words/3rd.ogg differ diff --git a/SamSharp Tests/goldens/words/4.ogg b/SamSharp Tests/goldens/words/4.ogg new file mode 100644 index 00000000..1ea9fd27 Binary files /dev/null and b/SamSharp Tests/goldens/words/4.ogg differ diff --git a/SamSharp Tests/goldens/words/4th.ogg b/SamSharp Tests/goldens/words/4th.ogg new file mode 100644 index 00000000..bc9d7a97 Binary files /dev/null and b/SamSharp Tests/goldens/words/4th.ogg differ diff --git a/SamSharp Tests/goldens/words/5.ogg b/SamSharp Tests/goldens/words/5.ogg new file mode 100644 index 00000000..6fe7e7ba Binary files /dev/null and b/SamSharp Tests/goldens/words/5.ogg differ diff --git a/SamSharp Tests/goldens/words/5th.ogg b/SamSharp Tests/goldens/words/5th.ogg new file mode 100644 index 00000000..e8775e5d Binary files /dev/null and b/SamSharp Tests/goldens/words/5th.ogg differ diff --git a/SamSharp Tests/goldens/words/6.ogg b/SamSharp Tests/goldens/words/6.ogg new file mode 100644 index 00000000..a2c33f1a Binary files /dev/null and b/SamSharp Tests/goldens/words/6.ogg differ diff --git a/SamSharp Tests/goldens/words/64.ogg b/SamSharp Tests/goldens/words/64.ogg new file mode 100644 index 00000000..471c16ae Binary files /dev/null and b/SamSharp Tests/goldens/words/64.ogg differ diff --git a/SamSharp Tests/goldens/words/6th.ogg b/SamSharp Tests/goldens/words/6th.ogg new file mode 100644 index 00000000..cded2b0e Binary files /dev/null and b/SamSharp Tests/goldens/words/6th.ogg differ diff --git a/SamSharp Tests/goldens/words/7.ogg b/SamSharp Tests/goldens/words/7.ogg new file mode 100644 index 00000000..124ccc83 Binary files /dev/null and b/SamSharp Tests/goldens/words/7.ogg differ diff --git a/SamSharp Tests/goldens/words/7th.ogg b/SamSharp Tests/goldens/words/7th.ogg new file mode 100644 index 00000000..84b881a8 Binary files /dev/null and b/SamSharp Tests/goldens/words/7th.ogg differ diff --git a/SamSharp Tests/goldens/words/8.ogg b/SamSharp Tests/goldens/words/8.ogg new file mode 100644 index 00000000..f45b80a7 Binary files /dev/null and b/SamSharp Tests/goldens/words/8.ogg differ diff --git a/SamSharp Tests/goldens/words/8th.ogg b/SamSharp Tests/goldens/words/8th.ogg new file mode 100644 index 00000000..241be903 Binary files /dev/null and b/SamSharp Tests/goldens/words/8th.ogg differ diff --git a/SamSharp Tests/goldens/words/9.ogg b/SamSharp Tests/goldens/words/9.ogg new file mode 100644 index 00000000..5a23fa37 Binary files /dev/null and b/SamSharp Tests/goldens/words/9.ogg differ diff --git a/SamSharp Tests/goldens/words/9th.ogg b/SamSharp Tests/goldens/words/9th.ogg new file mode 100644 index 00000000..2bccf956 Binary files /dev/null and b/SamSharp Tests/goldens/words/9th.ogg differ diff --git a/SamSharp Tests/goldens/words/=.ogg b/SamSharp Tests/goldens/words/=.ogg new file mode 100644 index 00000000..f60462a3 Binary files /dev/null and b/SamSharp Tests/goldens/words/=.ogg differ diff --git a/SamSharp Tests/goldens/words/@.ogg b/SamSharp Tests/goldens/words/@.ogg new file mode 100644 index 00000000..047d4ab4 Binary files /dev/null and b/SamSharp Tests/goldens/words/@.ogg differ diff --git a/SamSharp Tests/goldens/words/^.ogg b/SamSharp Tests/goldens/words/^.ogg new file mode 100644 index 00000000..ffa68bed Binary files /dev/null and b/SamSharp Tests/goldens/words/^.ogg differ diff --git a/SamSharp Tests/goldens/words/a.ogg b/SamSharp Tests/goldens/words/a.ogg new file mode 100644 index 00000000..76aed08b Binary files /dev/null and b/SamSharp Tests/goldens/words/a.ogg differ diff --git a/SamSharp Tests/goldens/words/able.ogg b/SamSharp Tests/goldens/words/able.ogg new file mode 100644 index 00000000..f5e5288c Binary files /dev/null and b/SamSharp Tests/goldens/words/able.ogg differ diff --git a/SamSharp Tests/goldens/words/again.ogg b/SamSharp Tests/goldens/words/again.ogg new file mode 100644 index 00000000..3e218bda Binary files /dev/null and b/SamSharp Tests/goldens/words/again.ogg differ diff --git a/SamSharp Tests/goldens/words/air.ogg b/SamSharp Tests/goldens/words/air.ogg new file mode 100644 index 00000000..9d08ebd2 Binary files /dev/null and b/SamSharp Tests/goldens/words/air.ogg differ diff --git a/SamSharp Tests/goldens/words/answer.ogg b/SamSharp Tests/goldens/words/answer.ogg new file mode 100644 index 00000000..8cc06465 Binary files /dev/null and b/SamSharp Tests/goldens/words/answer.ogg differ diff --git a/SamSharp Tests/goldens/words/any.ogg b/SamSharp Tests/goldens/words/any.ogg new file mode 100644 index 00000000..97c24d51 Binary files /dev/null and b/SamSharp Tests/goldens/words/any.ogg differ diff --git a/SamSharp Tests/goldens/words/are.ogg b/SamSharp Tests/goldens/words/are.ogg new file mode 100644 index 00000000..b338fefb Binary files /dev/null and b/SamSharp Tests/goldens/words/are.ogg differ diff --git a/SamSharp Tests/goldens/words/as.ogg b/SamSharp Tests/goldens/words/as.ogg new file mode 100644 index 00000000..da78f688 Binary files /dev/null and b/SamSharp Tests/goldens/words/as.ogg differ diff --git a/SamSharp Tests/goldens/words/at.ogg b/SamSharp Tests/goldens/words/at.ogg new file mode 100644 index 00000000..e2d64f07 Binary files /dev/null and b/SamSharp Tests/goldens/words/at.ogg differ diff --git a/SamSharp Tests/goldens/words/atari.ogg b/SamSharp Tests/goldens/words/atari.ogg new file mode 100644 index 00000000..7309728e Binary files /dev/null and b/SamSharp Tests/goldens/words/atari.ogg differ diff --git a/SamSharp Tests/goldens/words/b.ogg b/SamSharp Tests/goldens/words/b.ogg new file mode 100644 index 00000000..ea75c3e0 Binary files /dev/null and b/SamSharp Tests/goldens/words/b.ogg differ diff --git a/SamSharp Tests/goldens/words/be.ogg b/SamSharp Tests/goldens/words/be.ogg new file mode 100644 index 00000000..c13f0f1b Binary files /dev/null and b/SamSharp Tests/goldens/words/be.ogg differ diff --git a/SamSharp Tests/goldens/words/being.ogg b/SamSharp Tests/goldens/words/being.ogg new file mode 100644 index 00000000..389e3cce Binary files /dev/null and b/SamSharp Tests/goldens/words/being.ogg differ diff --git a/SamSharp Tests/goldens/words/boot.ogg b/SamSharp Tests/goldens/words/boot.ogg new file mode 100644 index 00000000..2a87f540 Binary files /dev/null and b/SamSharp Tests/goldens/words/boot.ogg differ diff --git a/SamSharp Tests/goldens/words/both.ogg b/SamSharp Tests/goldens/words/both.ogg new file mode 100644 index 00000000..e12bb937 Binary files /dev/null and b/SamSharp Tests/goldens/words/both.ogg differ diff --git a/SamSharp Tests/goldens/words/break.ogg b/SamSharp Tests/goldens/words/break.ogg new file mode 100644 index 00000000..1c8e6204 Binary files /dev/null and b/SamSharp Tests/goldens/words/break.ogg differ diff --git a/SamSharp Tests/goldens/words/bus.ogg b/SamSharp Tests/goldens/words/bus.ogg new file mode 100644 index 00000000..5a77caaf Binary files /dev/null and b/SamSharp Tests/goldens/words/bus.ogg differ diff --git a/SamSharp Tests/goldens/words/bye.ogg b/SamSharp Tests/goldens/words/bye.ogg new file mode 100644 index 00000000..36c5f019 Binary files /dev/null and b/SamSharp Tests/goldens/words/bye.ogg differ diff --git a/SamSharp Tests/goldens/words/c.ogg b/SamSharp Tests/goldens/words/c.ogg new file mode 100644 index 00000000..a5151ab2 Binary files /dev/null and b/SamSharp Tests/goldens/words/c.ogg differ diff --git a/SamSharp Tests/goldens/words/castle.ogg b/SamSharp Tests/goldens/words/castle.ogg new file mode 100644 index 00000000..c455e716 Binary files /dev/null and b/SamSharp Tests/goldens/words/castle.ogg differ diff --git a/SamSharp Tests/goldens/words/city.ogg b/SamSharp Tests/goldens/words/city.ogg new file mode 100644 index 00000000..32373d1c Binary files /dev/null and b/SamSharp Tests/goldens/words/city.ogg differ diff --git a/SamSharp Tests/goldens/words/com.ogg b/SamSharp Tests/goldens/words/com.ogg new file mode 100644 index 00000000..028091fb Binary files /dev/null and b/SamSharp Tests/goldens/words/com.ogg differ diff --git a/SamSharp Tests/goldens/words/commodore.ogg b/SamSharp Tests/goldens/words/commodore.ogg new file mode 100644 index 00000000..ade831c0 Binary files /dev/null and b/SamSharp Tests/goldens/words/commodore.ogg differ diff --git a/SamSharp Tests/goldens/words/could.ogg b/SamSharp Tests/goldens/words/could.ogg new file mode 100644 index 00000000..3f413dae Binary files /dev/null and b/SamSharp Tests/goldens/words/could.ogg differ diff --git a/SamSharp Tests/goldens/words/d.ogg b/SamSharp Tests/goldens/words/d.ogg new file mode 100644 index 00000000..7049c0f5 Binary files /dev/null and b/SamSharp Tests/goldens/words/d.ogg differ diff --git a/SamSharp Tests/goldens/words/do.ogg b/SamSharp Tests/goldens/words/do.ogg new file mode 100644 index 00000000..2c12639d Binary files /dev/null and b/SamSharp Tests/goldens/words/do.ogg differ diff --git a/SamSharp Tests/goldens/words/does.ogg b/SamSharp Tests/goldens/words/does.ogg new file mode 100644 index 00000000..0ed970b3 Binary files /dev/null and b/SamSharp Tests/goldens/words/does.ogg differ diff --git a/SamSharp Tests/goldens/words/doing.ogg b/SamSharp Tests/goldens/words/doing.ogg new file mode 100644 index 00000000..f1884496 Binary files /dev/null and b/SamSharp Tests/goldens/words/doing.ogg differ diff --git a/SamSharp Tests/goldens/words/done.ogg b/SamSharp Tests/goldens/words/done.ogg new file mode 100644 index 00000000..3bc7386f Binary files /dev/null and b/SamSharp Tests/goldens/words/done.ogg differ diff --git a/SamSharp Tests/goldens/words/dr..ogg b/SamSharp Tests/goldens/words/dr..ogg new file mode 100644 index 00000000..c99b9d93 Binary files /dev/null and b/SamSharp Tests/goldens/words/dr..ogg differ diff --git a/SamSharp Tests/goldens/words/e.ogg b/SamSharp Tests/goldens/words/e.ogg new file mode 100644 index 00000000..9c5b57c3 Binary files /dev/null and b/SamSharp Tests/goldens/words/e.ogg differ diff --git a/SamSharp Tests/goldens/words/equal.ogg b/SamSharp Tests/goldens/words/equal.ogg new file mode 100644 index 00000000..78ced2a1 Binary files /dev/null and b/SamSharp Tests/goldens/words/equal.ogg differ diff --git a/SamSharp Tests/goldens/words/erase.ogg b/SamSharp Tests/goldens/words/erase.ogg new file mode 100644 index 00000000..2fbade76 Binary files /dev/null and b/SamSharp Tests/goldens/words/erase.ogg differ diff --git a/SamSharp Tests/goldens/words/error.ogg b/SamSharp Tests/goldens/words/error.ogg new file mode 100644 index 00000000..1abc2495 Binary files /dev/null and b/SamSharp Tests/goldens/words/error.ogg differ diff --git a/SamSharp Tests/goldens/words/even.ogg b/SamSharp Tests/goldens/words/even.ogg new file mode 100644 index 00000000..66fc25e5 Binary files /dev/null and b/SamSharp Tests/goldens/words/even.ogg differ diff --git a/SamSharp Tests/goldens/words/ever.ogg b/SamSharp Tests/goldens/words/ever.ogg new file mode 100644 index 00000000..f22c2b77 Binary files /dev/null and b/SamSharp Tests/goldens/words/ever.ogg differ diff --git a/SamSharp Tests/goldens/words/evil.ogg b/SamSharp Tests/goldens/words/evil.ogg new file mode 100644 index 00000000..63d9dd10 Binary files /dev/null and b/SamSharp Tests/goldens/words/evil.ogg differ diff --git a/SamSharp Tests/goldens/words/f.ogg b/SamSharp Tests/goldens/words/f.ogg new file mode 100644 index 00000000..6406d274 Binary files /dev/null and b/SamSharp Tests/goldens/words/f.ogg differ diff --git a/SamSharp Tests/goldens/words/father.ogg b/SamSharp Tests/goldens/words/father.ogg new file mode 100644 index 00000000..4193ecf3 Binary files /dev/null and b/SamSharp Tests/goldens/words/father.ogg differ diff --git a/SamSharp Tests/goldens/words/foot.ogg b/SamSharp Tests/goldens/words/foot.ogg new file mode 100644 index 00000000..91e18779 Binary files /dev/null and b/SamSharp Tests/goldens/words/foot.ogg differ diff --git a/SamSharp Tests/goldens/words/friend.ogg b/SamSharp Tests/goldens/words/friend.ogg new file mode 100644 index 00000000..b57b69a2 Binary files /dev/null and b/SamSharp Tests/goldens/words/friend.ogg differ diff --git a/SamSharp Tests/goldens/words/g.ogg b/SamSharp Tests/goldens/words/g.ogg new file mode 100644 index 00000000..2612d4cb Binary files /dev/null and b/SamSharp Tests/goldens/words/g.ogg differ diff --git a/SamSharp Tests/goldens/words/gone.ogg b/SamSharp Tests/goldens/words/gone.ogg new file mode 100644 index 00000000..7999277e Binary files /dev/null and b/SamSharp Tests/goldens/words/gone.ogg differ diff --git a/SamSharp Tests/goldens/words/great.ogg b/SamSharp Tests/goldens/words/great.ogg new file mode 100644 index 00000000..5911a8d0 Binary files /dev/null and b/SamSharp Tests/goldens/words/great.ogg differ diff --git a/SamSharp Tests/goldens/words/h.ogg b/SamSharp Tests/goldens/words/h.ogg new file mode 100644 index 00000000..0b6b9ef0 Binary files /dev/null and b/SamSharp Tests/goldens/words/h.ogg differ diff --git a/SamSharp Tests/goldens/words/have.ogg b/SamSharp Tests/goldens/words/have.ogg new file mode 100644 index 00000000..81e71d01 Binary files /dev/null and b/SamSharp Tests/goldens/words/have.ogg differ diff --git a/SamSharp Tests/goldens/words/here.ogg b/SamSharp Tests/goldens/words/here.ogg new file mode 100644 index 00000000..48ef701e Binary files /dev/null and b/SamSharp Tests/goldens/words/here.ogg differ diff --git a/SamSharp Tests/goldens/words/hour.ogg b/SamSharp Tests/goldens/words/hour.ogg new file mode 100644 index 00000000..7d6b5754 Binary files /dev/null and b/SamSharp Tests/goldens/words/hour.ogg differ diff --git a/SamSharp Tests/goldens/words/house.ogg b/SamSharp Tests/goldens/words/house.ogg new file mode 100644 index 00000000..f7e4ad1d Binary files /dev/null and b/SamSharp Tests/goldens/words/house.ogg differ diff --git a/SamSharp Tests/goldens/words/how.ogg b/SamSharp Tests/goldens/words/how.ogg new file mode 100644 index 00000000..af2cc90a Binary files /dev/null and b/SamSharp Tests/goldens/words/how.ogg differ diff --git a/SamSharp Tests/goldens/words/i'm.ogg b/SamSharp Tests/goldens/words/i'm.ogg new file mode 100644 index 00000000..af3014cc Binary files /dev/null and b/SamSharp Tests/goldens/words/i'm.ogg differ diff --git a/SamSharp Tests/goldens/words/i.ogg b/SamSharp Tests/goldens/words/i.ogg new file mode 100644 index 00000000..80d74e84 Binary files /dev/null and b/SamSharp Tests/goldens/words/i.ogg differ diff --git a/SamSharp Tests/goldens/words/in.ogg b/SamSharp Tests/goldens/words/in.ogg new file mode 100644 index 00000000..e6754ead Binary files /dev/null and b/SamSharp Tests/goldens/words/in.ogg differ diff --git a/SamSharp Tests/goldens/words/inside.ogg b/SamSharp Tests/goldens/words/inside.ogg new file mode 100644 index 00000000..34162db9 Binary files /dev/null and b/SamSharp Tests/goldens/words/inside.ogg differ diff --git a/SamSharp Tests/goldens/words/j.ogg b/SamSharp Tests/goldens/words/j.ogg new file mode 100644 index 00000000..2808c30b Binary files /dev/null and b/SamSharp Tests/goldens/words/j.ogg differ diff --git a/SamSharp Tests/goldens/words/k.ogg b/SamSharp Tests/goldens/words/k.ogg new file mode 100644 index 00000000..de2c4e21 Binary files /dev/null and b/SamSharp Tests/goldens/words/k.ogg differ diff --git a/SamSharp Tests/goldens/words/l.ogg b/SamSharp Tests/goldens/words/l.ogg new file mode 100644 index 00000000..f6b364b8 Binary files /dev/null and b/SamSharp Tests/goldens/words/l.ogg differ diff --git a/SamSharp Tests/goldens/words/laugh.ogg b/SamSharp Tests/goldens/words/laugh.ogg new file mode 100644 index 00000000..41db4906 Binary files /dev/null and b/SamSharp Tests/goldens/words/laugh.ogg differ diff --git a/SamSharp Tests/goldens/words/lead.ogg b/SamSharp Tests/goldens/words/lead.ogg new file mode 100644 index 00000000..85aa4d33 Binary files /dev/null and b/SamSharp Tests/goldens/words/lead.ogg differ diff --git a/SamSharp Tests/goldens/words/list.txt b/SamSharp Tests/goldens/words/list.txt new file mode 100644 index 00000000..49601dd3 --- /dev/null +++ b/SamSharp Tests/goldens/words/list.txt @@ -0,0 +1,195 @@ +a +able +air +again +answer +any +are +as +at +atari + +b +be +being +boot +both +break +bus +bye + +c +castle +city +com +commodore +could + +d +do +does +doing +done +dr. + +e +equal +erase +error +even +ever +evil + +f +father +foot +friend + +g +gone +great + +h +have +here +hour +house +how + +i +i'm +in +inside + +j + +k + +l +laugh +lead + +m +mood +mr. +mrs. +ms. + +n +none +now + +o +of +old +on +once +one +only +other +over + +p +people +power +prof. +put + +q +quarter +quiz + +r +reward + +s +said +school +some + +t +than +that +the +their +them +there +these +they +this +through +thus +to +today +tomorrow +total +two + +u +university +upon + +v +valve +view + +w +want +war +was +wear +were +what +where +woman +women + +x +xylophone + +y +yes +you +young +your + +z + +1 +1st + +2 +2nd + +3 +3rd + +4 +4th + +5 +5th + +6 +64 +6th + +7 +7th + +8 +8th + +9 +9th + +10th + +# +$ +% +& ++ += +@ +^ \ No newline at end of file diff --git a/SamSharp Tests/goldens/words/m.ogg b/SamSharp Tests/goldens/words/m.ogg new file mode 100644 index 00000000..bd624464 Binary files /dev/null and b/SamSharp Tests/goldens/words/m.ogg differ diff --git a/SamSharp Tests/goldens/words/mood.ogg b/SamSharp Tests/goldens/words/mood.ogg new file mode 100644 index 00000000..ef76b133 Binary files /dev/null and b/SamSharp Tests/goldens/words/mood.ogg differ diff --git a/SamSharp Tests/goldens/words/mr..ogg b/SamSharp Tests/goldens/words/mr..ogg new file mode 100644 index 00000000..520f7618 Binary files /dev/null and b/SamSharp Tests/goldens/words/mr..ogg differ diff --git a/SamSharp Tests/goldens/words/mrs..ogg b/SamSharp Tests/goldens/words/mrs..ogg new file mode 100644 index 00000000..3f61366c Binary files /dev/null and b/SamSharp Tests/goldens/words/mrs..ogg differ diff --git a/SamSharp Tests/goldens/words/ms..ogg b/SamSharp Tests/goldens/words/ms..ogg new file mode 100644 index 00000000..888cb667 Binary files /dev/null and b/SamSharp Tests/goldens/words/ms..ogg differ diff --git a/SamSharp Tests/goldens/words/n.ogg b/SamSharp Tests/goldens/words/n.ogg new file mode 100644 index 00000000..3d914bb8 Binary files /dev/null and b/SamSharp Tests/goldens/words/n.ogg differ diff --git a/SamSharp Tests/goldens/words/none.ogg b/SamSharp Tests/goldens/words/none.ogg new file mode 100644 index 00000000..18fabeee Binary files /dev/null and b/SamSharp Tests/goldens/words/none.ogg differ diff --git a/SamSharp Tests/goldens/words/now.ogg b/SamSharp Tests/goldens/words/now.ogg new file mode 100644 index 00000000..f44c09d1 Binary files /dev/null and b/SamSharp Tests/goldens/words/now.ogg differ diff --git a/SamSharp Tests/goldens/words/o.ogg b/SamSharp Tests/goldens/words/o.ogg new file mode 100644 index 00000000..261e7e5d Binary files /dev/null and b/SamSharp Tests/goldens/words/o.ogg differ diff --git a/SamSharp Tests/goldens/words/of.ogg b/SamSharp Tests/goldens/words/of.ogg new file mode 100644 index 00000000..7c080934 Binary files /dev/null and b/SamSharp Tests/goldens/words/of.ogg differ diff --git a/SamSharp Tests/goldens/words/old.ogg b/SamSharp Tests/goldens/words/old.ogg new file mode 100644 index 00000000..d04adb5b Binary files /dev/null and b/SamSharp Tests/goldens/words/old.ogg differ diff --git a/SamSharp Tests/goldens/words/on.ogg b/SamSharp Tests/goldens/words/on.ogg new file mode 100644 index 00000000..0364ed69 Binary files /dev/null and b/SamSharp Tests/goldens/words/on.ogg differ diff --git a/SamSharp Tests/goldens/words/once.ogg b/SamSharp Tests/goldens/words/once.ogg new file mode 100644 index 00000000..aa7e1666 Binary files /dev/null and b/SamSharp Tests/goldens/words/once.ogg differ diff --git a/SamSharp Tests/goldens/words/one.ogg b/SamSharp Tests/goldens/words/one.ogg new file mode 100644 index 00000000..73c03967 Binary files /dev/null and b/SamSharp Tests/goldens/words/one.ogg differ diff --git a/SamSharp Tests/goldens/words/only.ogg b/SamSharp Tests/goldens/words/only.ogg new file mode 100644 index 00000000..fe785f2d Binary files /dev/null and b/SamSharp Tests/goldens/words/only.ogg differ diff --git a/SamSharp Tests/goldens/words/other.ogg b/SamSharp Tests/goldens/words/other.ogg new file mode 100644 index 00000000..718c9dd0 Binary files /dev/null and b/SamSharp Tests/goldens/words/other.ogg differ diff --git a/SamSharp Tests/goldens/words/over.ogg b/SamSharp Tests/goldens/words/over.ogg new file mode 100644 index 00000000..51d30ff8 Binary files /dev/null and b/SamSharp Tests/goldens/words/over.ogg differ diff --git a/SamSharp Tests/goldens/words/p.ogg b/SamSharp Tests/goldens/words/p.ogg new file mode 100644 index 00000000..f5df61f8 Binary files /dev/null and b/SamSharp Tests/goldens/words/p.ogg differ diff --git a/SamSharp Tests/goldens/words/people.ogg b/SamSharp Tests/goldens/words/people.ogg new file mode 100644 index 00000000..104e266c Binary files /dev/null and b/SamSharp Tests/goldens/words/people.ogg differ diff --git a/SamSharp Tests/goldens/words/power.ogg b/SamSharp Tests/goldens/words/power.ogg new file mode 100644 index 00000000..566a6ac0 Binary files /dev/null and b/SamSharp Tests/goldens/words/power.ogg differ diff --git a/SamSharp Tests/goldens/words/prof..ogg b/SamSharp Tests/goldens/words/prof..ogg new file mode 100644 index 00000000..195d493a Binary files /dev/null and b/SamSharp Tests/goldens/words/prof..ogg differ diff --git a/SamSharp Tests/goldens/words/put.ogg b/SamSharp Tests/goldens/words/put.ogg new file mode 100644 index 00000000..cd30a301 Binary files /dev/null and b/SamSharp Tests/goldens/words/put.ogg differ diff --git a/SamSharp Tests/goldens/words/q.ogg b/SamSharp Tests/goldens/words/q.ogg new file mode 100644 index 00000000..1cb754db Binary files /dev/null and b/SamSharp Tests/goldens/words/q.ogg differ diff --git a/SamSharp Tests/goldens/words/quarter.ogg b/SamSharp Tests/goldens/words/quarter.ogg new file mode 100644 index 00000000..33ff214a Binary files /dev/null and b/SamSharp Tests/goldens/words/quarter.ogg differ diff --git a/SamSharp Tests/goldens/words/quiz.ogg b/SamSharp Tests/goldens/words/quiz.ogg new file mode 100644 index 00000000..0a9b092c Binary files /dev/null and b/SamSharp Tests/goldens/words/quiz.ogg differ diff --git a/SamSharp Tests/goldens/words/r.ogg b/SamSharp Tests/goldens/words/r.ogg new file mode 100644 index 00000000..1f087ddb Binary files /dev/null and b/SamSharp Tests/goldens/words/r.ogg differ diff --git a/SamSharp Tests/goldens/words/reward.ogg b/SamSharp Tests/goldens/words/reward.ogg new file mode 100644 index 00000000..06e5c2ed Binary files /dev/null and b/SamSharp Tests/goldens/words/reward.ogg differ diff --git a/SamSharp Tests/goldens/words/s.ogg b/SamSharp Tests/goldens/words/s.ogg new file mode 100644 index 00000000..dea2bd0d Binary files /dev/null and b/SamSharp Tests/goldens/words/s.ogg differ diff --git a/SamSharp Tests/goldens/words/said.ogg b/SamSharp Tests/goldens/words/said.ogg new file mode 100644 index 00000000..cc058a68 Binary files /dev/null and b/SamSharp Tests/goldens/words/said.ogg differ diff --git a/SamSharp Tests/goldens/words/school.ogg b/SamSharp Tests/goldens/words/school.ogg new file mode 100644 index 00000000..137bf03e Binary files /dev/null and b/SamSharp Tests/goldens/words/school.ogg differ diff --git a/SamSharp Tests/goldens/words/some.ogg b/SamSharp Tests/goldens/words/some.ogg new file mode 100644 index 00000000..29dcb6c0 Binary files /dev/null and b/SamSharp Tests/goldens/words/some.ogg differ diff --git a/SamSharp Tests/goldens/words/t.ogg b/SamSharp Tests/goldens/words/t.ogg new file mode 100644 index 00000000..6fbc5246 Binary files /dev/null and b/SamSharp Tests/goldens/words/t.ogg differ diff --git a/SamSharp Tests/goldens/words/than.ogg b/SamSharp Tests/goldens/words/than.ogg new file mode 100644 index 00000000..1c9deb41 Binary files /dev/null and b/SamSharp Tests/goldens/words/than.ogg differ diff --git a/SamSharp Tests/goldens/words/that.ogg b/SamSharp Tests/goldens/words/that.ogg new file mode 100644 index 00000000..714f88bc Binary files /dev/null and b/SamSharp Tests/goldens/words/that.ogg differ diff --git a/SamSharp Tests/goldens/words/the.ogg b/SamSharp Tests/goldens/words/the.ogg new file mode 100644 index 00000000..49806822 Binary files /dev/null and b/SamSharp Tests/goldens/words/the.ogg differ diff --git a/SamSharp Tests/goldens/words/their.ogg b/SamSharp Tests/goldens/words/their.ogg new file mode 100644 index 00000000..6de60c68 Binary files /dev/null and b/SamSharp Tests/goldens/words/their.ogg differ diff --git a/SamSharp Tests/goldens/words/them.ogg b/SamSharp Tests/goldens/words/them.ogg new file mode 100644 index 00000000..1c9deb41 Binary files /dev/null and b/SamSharp Tests/goldens/words/them.ogg differ diff --git a/SamSharp Tests/goldens/words/there.ogg b/SamSharp Tests/goldens/words/there.ogg new file mode 100644 index 00000000..6de60c68 Binary files /dev/null and b/SamSharp Tests/goldens/words/there.ogg differ diff --git a/SamSharp Tests/goldens/words/these.ogg b/SamSharp Tests/goldens/words/these.ogg new file mode 100644 index 00000000..73b2df47 Binary files /dev/null and b/SamSharp Tests/goldens/words/these.ogg differ diff --git a/SamSharp Tests/goldens/words/they.ogg b/SamSharp Tests/goldens/words/they.ogg new file mode 100644 index 00000000..5afefb94 Binary files /dev/null and b/SamSharp Tests/goldens/words/they.ogg differ diff --git a/SamSharp Tests/goldens/words/this.ogg b/SamSharp Tests/goldens/words/this.ogg new file mode 100644 index 00000000..111a2e13 Binary files /dev/null and b/SamSharp Tests/goldens/words/this.ogg differ diff --git a/SamSharp Tests/goldens/words/through.ogg b/SamSharp Tests/goldens/words/through.ogg new file mode 100644 index 00000000..43f042fd Binary files /dev/null and b/SamSharp Tests/goldens/words/through.ogg differ diff --git a/SamSharp Tests/goldens/words/thus.ogg b/SamSharp Tests/goldens/words/thus.ogg new file mode 100644 index 00000000..ac34f814 Binary files /dev/null and b/SamSharp Tests/goldens/words/thus.ogg differ diff --git a/SamSharp Tests/goldens/words/to.ogg b/SamSharp Tests/goldens/words/to.ogg new file mode 100644 index 00000000..2a7b2900 Binary files /dev/null and b/SamSharp Tests/goldens/words/to.ogg differ diff --git a/SamSharp Tests/goldens/words/today.ogg b/SamSharp Tests/goldens/words/today.ogg new file mode 100644 index 00000000..0e11089b Binary files /dev/null and b/SamSharp Tests/goldens/words/today.ogg differ diff --git a/SamSharp Tests/goldens/words/tomorrow.ogg b/SamSharp Tests/goldens/words/tomorrow.ogg new file mode 100644 index 00000000..3d224cd2 Binary files /dev/null and b/SamSharp Tests/goldens/words/tomorrow.ogg differ diff --git a/SamSharp Tests/goldens/words/total.ogg b/SamSharp Tests/goldens/words/total.ogg new file mode 100644 index 00000000..4b094ec2 Binary files /dev/null and b/SamSharp Tests/goldens/words/total.ogg differ diff --git a/SamSharp Tests/goldens/words/two.ogg b/SamSharp Tests/goldens/words/two.ogg new file mode 100644 index 00000000..da4348ea Binary files /dev/null and b/SamSharp Tests/goldens/words/two.ogg differ diff --git a/SamSharp Tests/goldens/words/u.ogg b/SamSharp Tests/goldens/words/u.ogg new file mode 100644 index 00000000..f4eb4fc4 Binary files /dev/null and b/SamSharp Tests/goldens/words/u.ogg differ diff --git a/SamSharp Tests/goldens/words/university.ogg b/SamSharp Tests/goldens/words/university.ogg new file mode 100644 index 00000000..8c39c551 Binary files /dev/null and b/SamSharp Tests/goldens/words/university.ogg differ diff --git a/SamSharp Tests/goldens/words/upon.ogg b/SamSharp Tests/goldens/words/upon.ogg new file mode 100644 index 00000000..5648959b Binary files /dev/null and b/SamSharp Tests/goldens/words/upon.ogg differ diff --git a/SamSharp Tests/goldens/words/v.ogg b/SamSharp Tests/goldens/words/v.ogg new file mode 100644 index 00000000..8ef233f2 Binary files /dev/null and b/SamSharp Tests/goldens/words/v.ogg differ diff --git a/SamSharp Tests/goldens/words/valve.ogg b/SamSharp Tests/goldens/words/valve.ogg new file mode 100644 index 00000000..3e427973 Binary files /dev/null and b/SamSharp Tests/goldens/words/valve.ogg differ diff --git a/SamSharp Tests/goldens/words/view.ogg b/SamSharp Tests/goldens/words/view.ogg new file mode 100644 index 00000000..936f9318 Binary files /dev/null and b/SamSharp Tests/goldens/words/view.ogg differ diff --git a/SamSharp Tests/goldens/words/w.ogg b/SamSharp Tests/goldens/words/w.ogg new file mode 100644 index 00000000..ac65a33b Binary files /dev/null and b/SamSharp Tests/goldens/words/w.ogg differ diff --git a/SamSharp Tests/goldens/words/want.ogg b/SamSharp Tests/goldens/words/want.ogg new file mode 100644 index 00000000..332f9923 Binary files /dev/null and b/SamSharp Tests/goldens/words/want.ogg differ diff --git a/SamSharp Tests/goldens/words/war.ogg b/SamSharp Tests/goldens/words/war.ogg new file mode 100644 index 00000000..441a80c2 Binary files /dev/null and b/SamSharp Tests/goldens/words/war.ogg differ diff --git a/SamSharp Tests/goldens/words/was.ogg b/SamSharp Tests/goldens/words/was.ogg new file mode 100644 index 00000000..5bf37842 Binary files /dev/null and b/SamSharp Tests/goldens/words/was.ogg differ diff --git a/SamSharp Tests/goldens/words/wear.ogg b/SamSharp Tests/goldens/words/wear.ogg new file mode 100644 index 00000000..76625673 Binary files /dev/null and b/SamSharp Tests/goldens/words/wear.ogg differ diff --git a/SamSharp Tests/goldens/words/were.ogg b/SamSharp Tests/goldens/words/were.ogg new file mode 100644 index 00000000..f720664e Binary files /dev/null and b/SamSharp Tests/goldens/words/were.ogg differ diff --git a/SamSharp Tests/goldens/words/what.ogg b/SamSharp Tests/goldens/words/what.ogg new file mode 100644 index 00000000..e7132272 Binary files /dev/null and b/SamSharp Tests/goldens/words/what.ogg differ diff --git a/SamSharp Tests/goldens/words/where.ogg b/SamSharp Tests/goldens/words/where.ogg new file mode 100644 index 00000000..1869ed48 Binary files /dev/null and b/SamSharp Tests/goldens/words/where.ogg differ diff --git a/SamSharp Tests/goldens/words/woman.ogg b/SamSharp Tests/goldens/words/woman.ogg new file mode 100644 index 00000000..1abac0eb Binary files /dev/null and b/SamSharp Tests/goldens/words/woman.ogg differ diff --git a/SamSharp Tests/goldens/words/women.ogg b/SamSharp Tests/goldens/words/women.ogg new file mode 100644 index 00000000..6c51a621 Binary files /dev/null and b/SamSharp Tests/goldens/words/women.ogg differ diff --git a/SamSharp Tests/goldens/words/x.ogg b/SamSharp Tests/goldens/words/x.ogg new file mode 100644 index 00000000..faf09998 Binary files /dev/null and b/SamSharp Tests/goldens/words/x.ogg differ diff --git a/SamSharp Tests/goldens/words/xylophone.ogg b/SamSharp Tests/goldens/words/xylophone.ogg new file mode 100644 index 00000000..631f30ac Binary files /dev/null and b/SamSharp Tests/goldens/words/xylophone.ogg differ diff --git a/SamSharp Tests/goldens/words/y.ogg b/SamSharp Tests/goldens/words/y.ogg new file mode 100644 index 00000000..f6e2a5f4 Binary files /dev/null and b/SamSharp Tests/goldens/words/y.ogg differ diff --git a/SamSharp Tests/goldens/words/yes.ogg b/SamSharp Tests/goldens/words/yes.ogg new file mode 100644 index 00000000..df911857 Binary files /dev/null and b/SamSharp Tests/goldens/words/yes.ogg differ diff --git a/SamSharp Tests/goldens/words/you.ogg b/SamSharp Tests/goldens/words/you.ogg new file mode 100644 index 00000000..1b6d39bc Binary files /dev/null and b/SamSharp Tests/goldens/words/you.ogg differ diff --git a/SamSharp Tests/goldens/words/young.ogg b/SamSharp Tests/goldens/words/young.ogg new file mode 100644 index 00000000..7c32d30e Binary files /dev/null and b/SamSharp Tests/goldens/words/young.ogg differ diff --git a/SamSharp Tests/goldens/words/your.ogg b/SamSharp Tests/goldens/words/your.ogg new file mode 100644 index 00000000..a67d60fa Binary files /dev/null and b/SamSharp Tests/goldens/words/your.ogg differ diff --git a/SamSharp Tests/goldens/words/z.ogg b/SamSharp Tests/goldens/words/z.ogg new file mode 100644 index 00000000..ad49dfc3 Binary files /dev/null and b/SamSharp Tests/goldens/words/z.ogg differ diff --git a/SamSharp.sln b/SamSharp.sln index b8449d19..52afd3ba 100644 --- a/SamSharp.sln +++ b/SamSharp.sln @@ -1,8 +1,13 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SamSharp", "SamSharp\SamSharp.csproj", "{26A545A7-D52C-4EA4-A754-1494035CB760}" +# Visual Studio Version 17 +VisualStudioVersion = 17.8.34112.27 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SamSharp", "SamSharp\SamSharp.csproj", "{26A545A7-D52C-4EA4-A754-1494035CB760}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SamSharpTest", "SamSharpTest\SamSharpTest.csproj", "{47982F03-B33A-4492-B607-1E3C199C9AA6}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SamSharpCli", "SamSharpCli\SamSharpCli.csproj", "{47982F03-B33A-4492-B607-1E3C199C9AA6}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SamSharp Tests", "SamSharp Tests\SamSharp Tests.csproj", "{5B17B8F3-7483-489B-AFA2-516F43428CD7}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -18,5 +23,15 @@ Global {47982F03-B33A-4492-B607-1E3C199C9AA6}.Debug|Any CPU.Build.0 = Debug|Any CPU {47982F03-B33A-4492-B607-1E3C199C9AA6}.Release|Any CPU.ActiveCfg = Release|Any CPU {47982F03-B33A-4492-B607-1E3C199C9AA6}.Release|Any CPU.Build.0 = Release|Any CPU + {5B17B8F3-7483-489B-AFA2-516F43428CD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5B17B8F3-7483-489B-AFA2-516F43428CD7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5B17B8F3-7483-489B-AFA2-516F43428CD7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5B17B8F3-7483-489B-AFA2-516F43428CD7}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {00931D7B-43DB-46DD-A7B2-407C60C0FED8} EndGlobalSection EndGlobal diff --git a/SamSharp/Parser/Parser.AdjustLengths.cs b/SamSharp/Parser/Parser.AdjustLengths.cs index 201e8f8c..7cf38d1c 100644 --- a/SamSharp/Parser/Parser.AdjustLengths.cs +++ b/SamSharp/Parser/Parser.AdjustLengths.cs @@ -38,14 +38,18 @@ private void AdjustLengths(GetPhonemeDelegate getPhoneme, SetLengthDelegate setL { // Not punctuation? if (!PhonemeHasFlag(getPhoneme(position), PhonemeFlags.Punctuation)) + { continue; + } int loopIndex = position; while (--position > 1 && !PhonemeHasFlag(getPhoneme(position), PhonemeFlags.Vowel)) { } // Back up while not a vowel // If beginning of phonemes, exit loop if (position == 0) + { break; - + } + // Now handle everything between position and loopIndex int vowel = position; for (; position < loopIndex; position++) diff --git a/SamSharp/Parser/Parser.Flags.cs b/SamSharp/Parser/Parser.Flags.cs index 6a6096f0..88361af8 100644 --- a/SamSharp/Parser/Parser.Flags.cs +++ b/SamSharp/Parser/Parser.Flags.cs @@ -25,8 +25,8 @@ private enum PhonemeFlags UnvoicedStopConsonant = 0x0001 } - private const int pR = 23; - private const int pD = 57; - private const int pT = 69; + private const int Pr = 23; + private const int Pd = 57; + private const int Pt = 69; } } \ No newline at end of file diff --git a/SamSharp/Parser/Parser.Parser1.cs b/SamSharp/Parser/Parser.Parser1.cs index 79a850a8..3bcb01ce 100644 --- a/SamSharp/Parser/Parser.Parser1.cs +++ b/SamSharp/Parser/Parser.Parser1.cs @@ -13,14 +13,30 @@ public partial class Parser /// Whether the characters form a valid phoneme but not with wildcards. private int? FullMatch(char char1, char char2) { - int index = Array.FindIndex(phonemeNameTable, value => value == $"{char1}{char2}" && value[1] != '*'); - return index != -1 ? index : (int?)null; + for (int i = 0; i < phonemeNameTable.Length; ++i) + { + var phonemeName = phonemeNameTable[i]; + // Checks these chars individually to avoid allocating strings. + if (phonemeName[0] == char1 && phonemeName[1] == char2) + { + return i; + } + } + return null; } private int? WildMatch(char char1) { - int index = Array.FindIndex(phonemeNameTable, value => value == char1 + "*"); - return index != -1 ? index : (int?)null; + for (int i = 0; i < phonemeNameTable.Length; ++i) + { + var phonemeName = phonemeNameTable[i]; + // Checks these chars individually to avoid allocating strings. + if (phonemeName[0] == char1 && phonemeName[1] == '*') + { + return i; + } + } + return null; } /** @@ -103,9 +119,16 @@ private void Parser1(string input, Action addPhoneme, Action addStress // Should be a stress character. Search through the stress table backwards int i = stressTable.Length - 1; - while (char1 != stressTable[i] && i > 0) i--; + while (char1 != stressTable[i] && i > 0) + { + i--; + } + if (i == 0) + { throw new Exception($"Could not parse char {char1}"); + } + addStress(i); } } diff --git a/SamSharp/Parser/Parser.Parser2.cs b/SamSharp/Parser/Parser.Parser2.cs index 7a7542fd..1369f968 100644 --- a/SamSharp/Parser/Parser.Parser2.cs +++ b/SamSharp/Parser/Parser.Parser2.cs @@ -1,5 +1,4 @@ -using System; -using System.Diagnostics; +using System.Diagnostics; namespace SamSharp.Parser { @@ -91,7 +90,9 @@ void ChangeAx(int position, int suffix) { // Is phoneme pause? if (phoneme == 0) + { continue; + } if (PhonemeHasFlag(phoneme, PhonemeFlags.Diphthong)) { @@ -152,19 +153,19 @@ void ChangeAx(int position, int suffix) } var priorPhoneme = (pos == 0) ? null : getPhoneme(pos - 1); - if (phoneme == pR) + if (phoneme == Pr) { // Rules for phonemes before R switch (priorPhoneme) { - case pT: + case Pt: { // Example: TRACK Debug.WriteLine($"{pos} RULE: T* R* -> CH R*"); setPhoneme(pos - 1, 42); break; } - case pD: + case Pd: { // Example: DRY Debug.WriteLine($"{pos} RULE: D* R* -> J* R*"); diff --git a/SamSharp/Parser/Parser.ProlongPlosiveStopConsonantsCode41240.cs b/SamSharp/Parser/Parser.ProlongPlosiveStopConsonantsCode41240.cs index b97a8ab1..f597f88d 100644 --- a/SamSharp/Parser/Parser.ProlongPlosiveStopConsonantsCode41240.cs +++ b/SamSharp/Parser/Parser.ProlongPlosiveStopConsonantsCode41240.cs @@ -1,6 +1,4 @@ -using System; - -namespace SamSharp.Parser +namespace SamSharp.Parser { public partial class Parser { @@ -21,8 +19,10 @@ private void ProlongPlosiveStopConsonantsCode41240(GetPhonemeDelegate getPhoneme { // Not a stop consonant, move to the next one if (!PhonemeHasFlag(phoneme, PhonemeFlags.StopConsonant)) + { continue; - + } + // If plosive, move to the next non-empty phoneme and validate the flags if (PhonemeHasFlag(phoneme, PhonemeFlags.UnvoicedStopConsonant)) { @@ -37,7 +37,9 @@ private void ProlongPlosiveStopConsonantsCode41240(GetPhonemeDelegate getPhoneme // If not END and either flag 0x0008 or "/H" or "/X" if (nextNonEmpty != null && (PhonemeHasFlag(nextNonEmpty, PhonemeFlags._0x0008) || nextNonEmpty == 36 || nextNonEmpty == 37)) + { continue; + } } insertPhoneme(pos + 1, phoneme.Value + 1, getStress(pos), diff --git a/SamSharp/Parser/Parser.SetPhonemeLength.cs b/SamSharp/Parser/Parser.SetPhonemeLength.cs index 39869b5c..067a4646 100644 --- a/SamSharp/Parser/Parser.SetPhonemeLength.cs +++ b/SamSharp/Parser/Parser.SetPhonemeLength.cs @@ -18,9 +18,14 @@ private void SetPhonemeLength(GetPhonemeDelegate getPhoneme, GetStressDelegate g { var stress = getStress(position); if (stress == 0 || stress > 0x7F) + { setLength(position, combinedPhonemeLengthTable[phoneme.Value] & 0xFF); + } else + { setLength(position, combinedPhonemeLengthTable[phoneme.Value] >> 8); + } + position++; } } diff --git a/SamSharp/Parser/Parser.cs b/SamSharp/Parser/Parser.cs index 9c6a4e2b..5f0663d9 100644 --- a/SamSharp/Parser/Parser.cs +++ b/SamSharp/Parser/Parser.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using System.Linq; namespace SamSharp.Parser { @@ -18,11 +17,15 @@ public partial class Parser private int? GetPhoneme(int pos) { if (pos == phonemeIndexes.Count) + { return null; - + } + if (pos < 0 || pos > phonemeIndexes.Count) + { throw new Exception($"Out of bounds: {pos}"); - + } + return pos == phonemeIndexes.Count ? null : phonemeIndexes[pos]; } @@ -109,8 +112,10 @@ public PhonemeData(int? phoneme, int? length, int? stress) public PhonemeData[] Parse(string? input) { if (input is null) + { return null; - + } + stresses = new Dictionary(); phonemeLengths = new Dictionary(); phonemeIndexes = new Dictionary(); @@ -126,7 +131,10 @@ public PhonemeData[] Parse(string? input) value => { if ((value & 128) != 0) + { throw new Exception("Got the flag 0x80, see CopyStress() and SetPhonemeLengths() comments!"); + } + stresses[pos - 1] = value; // Set stress for prior phoneme }); @@ -144,7 +152,9 @@ public PhonemeData[] Parse(string? input) for (int i = 0; i < phonemeIndexes.Count; i++) { if (phonemeIndexes[i] != null && phonemeIndexes[i] != 0) + { result.Add(new PhonemeData(phonemeIndexes[i], phonemeLengths[i], stresses[i])); + } } return result.ToArray(); diff --git a/SamSharp/Reciter/Reciter.cs b/SamSharp/Reciter/Reciter.cs index 596ca12b..b374ff02 100644 --- a/SamSharp/Reciter/Reciter.cs +++ b/SamSharp/Reciter/Reciter.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Collections.Specialized; using System.Diagnostics; using System.Linq; @@ -27,7 +26,10 @@ public Reciter() { (RuleMatcher matcher, char c) = GenerateReciterRule(rule); if (!rules.ContainsKey(c)) + { rules[c] = new List(); + } + rules[c].Add(matcher); } @@ -109,17 +111,23 @@ bool CheckPrefix(string text, int pos) '@' => () => { if (FlagsAt(text, --pos, CharFlags.Voiced)) + { return true; + } var inputChar = CharAt(text, pos); // 'H' if (inputChar != 'H') + { return false; + } // FIXME: This is always true apparently // Check for 'T', 'C', 'S' if (!IsOneOf(inputChar, 'T', 'C', 'S')) + { return false; + } throw new Exception("TCS didn't match, always false but happened?"); }, @@ -133,7 +141,10 @@ bool CheckPrefix(string text, int pos) while (pos >= 0) { if (!FlagsAt(text, pos - 1, CharFlags.Consonant)) + { break; + } + pos--; } @@ -148,7 +159,9 @@ bool CheckPrefix(string text, int pos) // Rule char does not match else if (text[--pos] != ruleByte) + { return false; + } } return true; @@ -178,17 +191,23 @@ bool CheckSuffix(string text, int pos) '@' => () => { if (FlagsAt(text, ++pos, CharFlags.Voiced)) + { return true; + } var inputChar = CharAt(text, pos); // 'H' if (inputChar != 'H') + { return false; + } // FIXME: This is always true apparently // Check for 'T', 'C', 'S' if (!IsOneOf(inputChar, 'T', 'C', 'S')) + { return false; + } throw new Exception("TCS didn't match, always false but happened?"); }, @@ -200,7 +219,10 @@ bool CheckSuffix(string text, int pos) ':' => () => { while (FlagsAt(text, pos + 1, CharFlags.Consonant)) + { pos++; + } + return true; }, /* '%' - check if we have: @@ -253,7 +275,10 @@ bool CheckSuffix(string text, int pos) // Not "ELY" if (CharAt(text, pos + 3) != 'Y') + { return false; + } + pos += 3; return true; } @@ -269,7 +294,9 @@ bool CheckSuffix(string text, int pos) } // Rule char does not match else if (CharAt(text, ++pos) != ruleByte) + { return false; + } } return true; } @@ -278,15 +305,21 @@ bool Matches(string text, int pos) { // Check if content in brackets matches if (!text[pos..].StartsWith(match)) + { return false; - + } + // Check left if (!CheckPrefix(text, pos)) + { return false; - + } + // Check right if (!CheckSuffix(text, pos + match.Length - 1)) + { return false; + } return true; } @@ -339,7 +372,9 @@ void SuccessCallback(string append, int inputSkip) foreach (RuleMatcher rule in rules2) { if (rule(text, inputPos, SuccessCallback)) + { break; + } } continue; } @@ -357,7 +392,9 @@ void SuccessCallback(string append, int inputSkip) foreach (RuleMatcher rule in rules[currentChar]) { if (rule(text, inputPos, SuccessCallback)) + { break; + } } continue; } diff --git a/SamSharp/Renderer/OutputBuffer.cs b/SamSharp/Renderer/OutputBuffer.cs index b8cca0e0..9baeef98 100644 --- a/SamSharp/Renderer/OutputBuffer.cs +++ b/SamSharp/Renderer/OutputBuffer.cs @@ -21,35 +21,42 @@ public void Write(int index, int a) Ary(index, new[] { scaled, scaled, scaled, scaled, scaled }); } - public void Ary(int index, int[] array) + // Timetable for more accurate C64 simulation + private readonly byte[] timetable = { - // Timetable for more accurate C64 simulation - var timetable = new[] - { - new[] { 162, 167, 167, 127, 128 }, // Formants synth - new[] { 226, 60, 60, 0, 0 }, // Unvoiced sample 0 - new[] { 225, 60, 59, 0, 0 }, // Unvoiced sample 1 - new[] { 200, 0, 0, 54, 55 }, // Voiced sample 0 - new[] { 199, 0, 0, 54, 54 }, // Voiced sample 1 - }; - - bufferPos += timetable[oldTimeTableIndex][index]; + 162, 167, 167, 127, 128, // Formants synth + 226, 60, 60, 0, 0, // Unvoiced sample 0 + 225, 60, 59, 0, 0, // Unvoiced sample 1 + 200, 0, 0, 54, 55, // Voiced sample 0 + 199, 0, 0, 54, 54, // Voiced sample 1 + }; + + public void Ary(int index, Span array) + { + bufferPos += timetable[5 * oldTimeTableIndex + index]; if (bufferPos / 50 > buffer.Length) + { throw new Exception($"Buffer overflow, want {bufferPos / 50} but buffer size is {buffer.Length}"); + } oldTimeTableIndex = index; // Write a little bit in advance for (int k = 0; k < 5; k++) + { buffer[bufferPos / 50 + k] = (byte)array[k]; + } } public byte[] Get() { byte[] bytes = new byte[bufferPos / 50]; for (int i = 0; i < bufferPos / 50; i++) + { bytes[i] = (byte)(buffer[i]); + } + return bytes; } } diff --git a/SamSharp/Renderer/Renderer.CreateFrames.cs b/SamSharp/Renderer/Renderer.CreateFrames.cs index 082cafc2..a226ebd9 100644 --- a/SamSharp/Renderer/Renderer.CreateFrames.cs +++ b/SamSharp/Renderer/Renderer.CreateFrames.cs @@ -36,16 +36,22 @@ void AddInflection(int inflection, int pos, Dictionary pitches) // Store the location of the punctuation int end = pos; if (pos < 30) + { pos = 0; + } else + { pos -= 30; + } int a; // FIXME: Explain this fix better, it's not obvious // ML : A =, fixes a problem with invalid pitch with '.' while ((a = pitches[pos]) == 127) + { pos++; + } while (pos != end) { @@ -68,12 +74,16 @@ void AddInflection(int inflection, int pos, Dictionary pitches) var phoneme = data.Phoneme; if (phoneme == PhonemePeriod) + { AddInflection(FallingInflection, x, framesData.Pitches); + } else if (phoneme == PhonemeQuestion) + { AddInflection(RisingInflection, x, framesData.Pitches); + } // Get the stress amount (more stress = higher pitch) - var phase1 = stressPitch_tab47492[data.Stress!.Value]; + var phase1 = stressPitchTab47492[data.Stress!.Value]; // Get number of frames to write // Copy from the source to the frames list diff --git a/SamSharp/Renderer/Renderer.CreateTransitions.cs b/SamSharp/Renderer/Renderer.CreateTransitions.cs index 333d055b..cc9177cc 100644 --- a/SamSharp/Renderer/Renderer.CreateTransitions.cs +++ b/SamSharp/Renderer/Renderer.CreateTransitions.cs @@ -84,16 +84,26 @@ void Interpolate(int width, int table, int frame, int change) // Accumulated a whole integer error, so adjust output error -= width; if (sign) + { val--; + } else if (val != 0) + { val++; // If input is 0, we always leave it alone + } } // Write updated value back to next frame if (table < 0 || table >= tables.Length) + { throw new Exception($"(Interpolate) Invalid table in Read: {table}"); + } + if (frame + 1 < tables[table].Count) + { tables[table][++frame] = val; + } + val += div; // WTF: This is in the JS code, but this does nothing useful? } } @@ -169,7 +179,7 @@ void Interpolate(int width, int table, int frame, int change) } // Add the length of the last phoneme - return boundary + phonemes[^1].Length!.Value; + return boundary + (phonemes.Length > 0 ? phonemes[^1].Length!.Value : 0); } } } \ No newline at end of file diff --git a/SamSharp/Renderer/Renderer.PrepareFrames.cs b/SamSharp/Renderer/Renderer.PrepareFrames.cs index dcf2a2e5..e079bf93 100644 --- a/SamSharp/Renderer/Renderer.PrepareFrames.cs +++ b/SamSharp/Renderer/Renderer.PrepareFrames.cs @@ -1,6 +1,4 @@ -using System.IO.IsolatedStorage; - -namespace SamSharp.Renderer +namespace SamSharp.Renderer { public partial class Renderer { diff --git a/SamSharp/Renderer/Renderer.ProcessFrames.cs b/SamSharp/Renderer/Renderer.ProcessFrames.cs index be4d5984..ddda8f40 100644 --- a/SamSharp/Renderer/Renderer.ProcessFrames.cs +++ b/SamSharp/Renderer/Renderer.ProcessFrames.cs @@ -1,7 +1,5 @@ using System; -using System.Collections.Generic; using System.Diagnostics; -using System.Threading; namespace SamSharp.Renderer { @@ -36,9 +34,14 @@ void RenderTheSample(int index1, int value1, int index0, int value0) do { if ((sample & 128) != 0) + { output.Write(index1, value1); + } else + { output.Write(index0, value0); + } + sample <<= 1; } while (--bit > 0); } @@ -90,6 +93,11 @@ void RenderTheSample(int index1, int value1, int index0, int value0) */ private void ProcessFrames(OutputBuffer output, int frameCount, int speed, FramesData framesData) { + if (framesData.Pitches.Count == 0) + { + return; + } + int speedCounter = speed; int phase1 = 0, phase2 = 0, phase3 = 0; int lastSampleOffset = 0; @@ -97,6 +105,7 @@ private void ProcessFrames(OutputBuffer output, int frameCount, int speed, Frame int glottalPulse = framesData.Pitches[0]; int mem38 = (int)(glottalPulse * .75f); + Span ary = stackalloc int[5]; while (frameCount > 0) { var flags = framesData.SampledConsonantFlags[pos]; @@ -117,7 +126,6 @@ private void ProcessFrames(OutputBuffer output, int frameCount, int speed, Frame // 128-255 = 0x70 // Simulate the glottal pulse and formants - int[] ary = new int[5]; int p1 = phase1 * 256; int p2 = phase2 * 256; int p3 = phase3 * 256; @@ -149,7 +157,10 @@ private void ProcessFrames(OutputBuffer output, int frameCount, int speed, Frame { pos++; // Go to next amplitude frameCount--; - if (frameCount == 0) return; + if (frameCount == 0) + { + return; + } speedCounter = speed; } diff --git a/SamSharp/Renderer/Renderer.SetMouthThroat.cs b/SamSharp/Renderer/Renderer.SetMouthThroat.cs index c7ac67f6..35d84f08 100644 --- a/SamSharp/Renderer/Renderer.SetMouthThroat.cs +++ b/SamSharp/Renderer/Renderer.SetMouthThroat.cs @@ -1,6 +1,4 @@ -using System.Runtime.CompilerServices; - -namespace SamSharp.Renderer +namespace SamSharp.Renderer { public partial class Renderer { diff --git a/SamSharp/Renderer/Renderer.Tables.cs b/SamSharp/Renderer/Renderer.Tables.cs index 9920e6e9..07013fa6 100644 --- a/SamSharp/Renderer/Renderer.Tables.cs +++ b/SamSharp/Renderer/Renderer.Tables.cs @@ -10,7 +10,7 @@ public partial class Renderer private readonly int[] sampledConsonantValues0 = { 0x18, 0x1A, 0x17, 0x17, 0x17 }; // Stress pitch table - private readonly int[] stressPitch_tab47492 = { 0x00, 0xE0, 0xE6, 0xEC, 0xF3, 0xF9, 0x00, 0x06, 0xC, 0x06 }; + private readonly int[] stressPitchTab47492 = { 0x00, 0xE0, 0xE6, 0xEC, 0xF3, 0xF9, 0x00, 0x06, 0xC, 0x06 }; // Used to decide which phoneme's blend lengths to pick. The candidate with the lower score is selected // tab45856 diff --git a/SamSharp/Sam.cs b/SamSharp/Sam.cs index 2d250fd3..71577611 100644 --- a/SamSharp/Sam.cs +++ b/SamSharp/Sam.cs @@ -1,5 +1,4 @@ using System.Threading.Tasks; -using SamSharp.Renderer; namespace SamSharp { @@ -19,7 +18,7 @@ public Sam() : this(new Options()) public byte[] Speak(string input) { Reciter.Reciter reciter = new Reciter.Reciter(); - return SpeakPhonetic(reciter.TextToPhonemes(input)); + return SpeakPhonetic(reciter.TextToPhonemes(input.Trim())); } public byte[] SpeakPhonetic(string phoneticInput) @@ -27,18 +26,12 @@ public byte[] SpeakPhonetic(string phoneticInput) Parser.Parser parser = new Parser.Parser(); Renderer.Renderer renderer = new Renderer.Renderer(); - var data = parser.Parse(phoneticInput); + var data = parser.Parse(phoneticInput.Trim()); return renderer.Render(data, Options); } - public Task SpeakAsync(string input) - { - return Task.Factory.StartNew(() => Speak(input)); - } + public Task SpeakAsync(string input) => Task.Factory.StartNew(() => Speak(input.Trim())); - public Task SpeakPhoneticAsync(string phoneticInput) - { - return Task.Factory.StartNew(() => SpeakPhonetic(phoneticInput)); - } + public Task SpeakPhoneticAsync(string phoneticInput) => Task.Factory.StartNew(() => SpeakPhonetic(phoneticInput.Trim())); } } \ No newline at end of file diff --git a/SamSharp/Utils.cs b/SamSharp/Utils.cs index d07d2223..563ceffe 100644 --- a/SamSharp/Utils.cs +++ b/SamSharp/Utils.cs @@ -1,6 +1,4 @@ -using System; - -namespace SamSharp +namespace SamSharp { internal class Utils { diff --git a/SamSharpTest/CommandLineOptions.cs b/SamSharpCli/CommandLineOptions.cs similarity index 95% rename from SamSharpTest/CommandLineOptions.cs rename to SamSharpCli/CommandLineOptions.cs index d1d75778..0f278ba7 100644 --- a/SamSharpTest/CommandLineOptions.cs +++ b/SamSharpCli/CommandLineOptions.cs @@ -1,31 +1,31 @@ -using CommandLine; - -namespace SamSharpTest; - -public class CommandLineOptions -{ - [Value(0, Required = true, HelpText = "The text to speak")] - public string Text { get; set; } = ""; - - [Option('p', "pitch", Required = false, Default = 64, HelpText = "Pitch parameter (0 - 255)")] - public int Pitch { get; set; } - - [Option('s', "speed", Required = false, Default = 72, HelpText = "Speed parameter (0 - 255)")] - public int Speed { get; set; } - - [Option('m', "mouth", Required = false, Default = 128, HelpText = "Mouth parameter (0 - 255)")] - public int Mouth { get; set; } - - [Option('t', "throat", Required = false, Default = 128, HelpText = "Throat parameter (0 - 255)")] - public int Throat { get; set; } - - [Option("phonetic", Required = false, Default = false, HelpText = "Use phonetic mode")] - public bool Phonetic { get; set; } - - [Option("sing", Required = false, Default = false, HelpText = "Use sing mode")] - public bool SingMode { get; set; } - - [Option('o', "output", Required = false, Default = null, - HelpText = "Path to output .wav file. If not present, will play the audio directly.")] - public string? OutputFile { get; set; } +using CommandLine; + +namespace SamSharpCli; + +public class CommandLineOptions +{ + [Value(0, Required = true, HelpText = "The text to speak")] + public string Text { get; set; } = ""; + + [Option('p', "pitch", Required = false, Default = 64, HelpText = "Pitch parameter (0 - 255)")] + public int Pitch { get; set; } + + [Option('s', "speed", Required = false, Default = 72, HelpText = "Speed parameter (0 - 255)")] + public int Speed { get; set; } + + [Option('m', "mouth", Required = false, Default = 128, HelpText = "Mouth parameter (0 - 255)")] + public int Mouth { get; set; } + + [Option('t', "throat", Required = false, Default = 128, HelpText = "Throat parameter (0 - 255)")] + public int Throat { get; set; } + + [Option("phonetic", Required = false, Default = false, HelpText = "Use phonetic mode")] + public bool Phonetic { get; set; } + + [Option("sing", Required = false, Default = false, HelpText = "Use sing mode")] + public bool SingMode { get; set; } + + [Option('o', "output", Required = false, Default = null, + HelpText = "Path to output .wav file. If not present, will play the audio directly.")] + public string? OutputFile { get; set; } } \ No newline at end of file diff --git a/SamSharpTest/Program.cs b/SamSharpCli/Program.cs similarity index 91% rename from SamSharpTest/Program.cs rename to SamSharpCli/Program.cs index cbca7e88..81de1aa5 100644 --- a/SamSharpTest/Program.cs +++ b/SamSharpCli/Program.cs @@ -1,18 +1,14 @@ -using System.Text; -using SamSharp; +using SamSharp; using CommandLine; using NAudio.Wave; -using SamSharp.Renderer; -namespace SamSharpTest; +namespace SamSharpCli; public static class Program { - public static void Main(string[] args) - { + public static void Main(string[] args) => Parser.Default.ParseArguments(args) .WithParsed(RunOptions); - } private static void RunOptions(CommandLineOptions options) { diff --git a/SamSharpTest/SamSharpTest.csproj b/SamSharpCli/SamSharpCli.csproj similarity index 92% rename from SamSharpTest/SamSharpTest.csproj rename to SamSharpCli/SamSharpCli.csproj index f8872778..2e19e64d 100644 --- a/SamSharpTest/SamSharpTest.csproj +++ b/SamSharpCli/SamSharpCli.csproj @@ -1,4 +1,4 @@ - + Exe diff --git a/global.json b/global.json new file mode 100644 index 00000000..9e5e1fd1 --- /dev/null +++ b/global.json @@ -0,0 +1,7 @@ +{ + "sdk": { + "version": "6.0.0", + "rollForward": "latestMajor", + "allowPrerelease": true + } +} \ No newline at end of file