diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c6cbe56 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b608edd --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Music Synthesizer \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..96cc43e --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..e7bedf3 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..97626ba --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..508b3d9 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,23 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..5d19981 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..37a85bd --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..7f68460 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/android/.classpath b/android/.classpath deleted file mode 100644 index bea3b48..0000000 --- a/android/.classpath +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - diff --git a/android/.externalToolBuilders/NDK Builder.launch b/android/.externalToolBuilders/NDK Builder.launch deleted file mode 100644 index 18993b1..0000000 --- a/android/.externalToolBuilders/NDK Builder.launch +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/android/.externalToolBuilders/Proto Builder.launch b/android/.externalToolBuilders/Proto Builder.launch deleted file mode 100644 index 18b99a6..0000000 --- a/android/.externalToolBuilders/Proto Builder.launch +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/android/.gitignore b/android/.gitignore deleted file mode 100644 index 67a5cb9..0000000 --- a/android/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Android NDK output files -obj/** -libs/** \ No newline at end of file diff --git a/android/.project b/android/.project deleted file mode 100644 index 6c6f44d..0000000 --- a/android/.project +++ /dev/null @@ -1,75 +0,0 @@ - - - MusicSynthesizer - - - - - - org.eclipse.ui.externaltools.ExternalToolBuilder - auto,full,incremental, - - - LaunchConfigHandle - <project>/.externalToolBuilders/Proto Builder.launch - - - - - org.eclipse.ui.externaltools.ExternalToolBuilder - auto,full,incremental, - - - LaunchConfigHandle - <project>/.externalToolBuilders/NDK Builder.launch - - - - - com.android.ide.eclipse.adt.ResourceManagerBuilder - - - - - com.android.ide.eclipse.adt.PreCompilerBuilder - - - - - org.eclipse.jdt.core.javabuilder - - - - - com.android.ide.eclipse.adt.ApkBuilder - - - - - - com.android.ide.eclipse.adt.AndroidNature - org.eclipse.jdt.core.javanature - - - - core - 2 - PARENT-1-PROJECT_LOC/core/src - - - core-gen - 2 - PARENT-1-PROJECT_LOC/core/gen - - - core-lib - 2 - PARENT-1-PROJECT_LOC/core/lib - - - test - 2 - PARENT-1-PROJECT_LOC/test/src - - - diff --git a/android/.settings/org.eclipse.jdt.core.prefs b/android/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index 5c9506e..0000000 --- a/android/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,280 +0,0 @@ -#Thu Jan 27 01:33:26 PST 2011 -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 -org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.5 -org.eclipse.jdt.core.compiler.debug.lineNumber=generate -org.eclipse.jdt.core.compiler.debug.localVariable=generate -org.eclipse.jdt.core.compiler.debug.sourceFile=generate -org.eclipse.jdt.core.compiler.problem.assertIdentifier=error -org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.5 -org.eclipse.jdt.core.formatter.align_type_members_on_columns=false -org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 -org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0 -org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 -org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16 -org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16 -org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16 -org.eclipse.jdt.core.formatter.alignment_for_assignment=0 -org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16 -org.eclipse.jdt.core.formatter.alignment_for_compact_if=16 -org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80 -org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0 -org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16 -org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0 -org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 -org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16 -org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16 -org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16 -org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16 -org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16 -org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16 -org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16 -org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16 -org.eclipse.jdt.core.formatter.blank_lines_after_imports=1 -org.eclipse.jdt.core.formatter.blank_lines_after_package=1 -org.eclipse.jdt.core.formatter.blank_lines_before_field=0 -org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0 -org.eclipse.jdt.core.formatter.blank_lines_before_imports=1 -org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1 -org.eclipse.jdt.core.formatter.blank_lines_before_method=1 -org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1 -org.eclipse.jdt.core.formatter.blank_lines_before_package=0 -org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1 -org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1 -org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line -org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false -org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false -org.eclipse.jdt.core.formatter.comment.format_block_comments=true -org.eclipse.jdt.core.formatter.comment.format_header=false -org.eclipse.jdt.core.formatter.comment.format_html=true -org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true -org.eclipse.jdt.core.formatter.comment.format_line_comments=true -org.eclipse.jdt.core.formatter.comment.format_source_code=true -org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true -org.eclipse.jdt.core.formatter.comment.indent_root_tags=true -org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert -org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert -org.eclipse.jdt.core.formatter.comment.line_length=100 -org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true -org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true -org.eclipse.jdt.core.formatter.compact_else_if=true -org.eclipse.jdt.core.formatter.continuation_indentation=4 -org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=4 -org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off -org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on -org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false -org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true -org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true -org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true -org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true -org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true -org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true -org.eclipse.jdt.core.formatter.indent_empty_lines=false -org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true -org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true -org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true -org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true -org.eclipse.jdt.core.formatter.indentation.size=2 -org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert -org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_member=insert -org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert -org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert -org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert -org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert -org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert -org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert -org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert -org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert -org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert -org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert -org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert -org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert -org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert -org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert -org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert -org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert -org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert -org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert -org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert -org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert -org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert -org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert -org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert -org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert -org.eclipse.jdt.core.formatter.join_lines_in_comments=true -org.eclipse.jdt.core.formatter.join_wrapped_lines=true -org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=true -org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false -org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false -org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=true -org.eclipse.jdt.core.formatter.lineSplit=100 -org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false -org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false -org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0 -org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1 -org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true -org.eclipse.jdt.core.formatter.tabulation.char=space -org.eclipse.jdt.core.formatter.tabulation.size=2 -org.eclipse.jdt.core.formatter.use_on_off_tags=false -org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=true -org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true -org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true diff --git a/android/.settings/org.eclipse.jdt.ui.prefs b/android/.settings/org.eclipse.jdt.ui.prefs deleted file mode 100644 index a26edcc..0000000 --- a/android/.settings/org.eclipse.jdt.ui.prefs +++ /dev/null @@ -1,8 +0,0 @@ -#Thu Jan 27 01:35:20 PST 2011 -eclipse.preferences.version=1 -formatter_profile=_MusicSynthesizer -formatter_settings_version=11 -org.eclipse.jdt.ui.ignorelowercasenames=true -org.eclipse.jdt.ui.importorder=java;javax;org;com; -org.eclipse.jdt.ui.ondemandthreshold=99 -org.eclipse.jdt.ui.staticondemandthreshold=99 diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml deleted file mode 100644 index 82fc6fb..0000000 --- a/android/AndroidManifest.xml +++ /dev/null @@ -1,84 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/android/default.properties b/android/default.properties deleted file mode 100644 index 4686f7f..0000000 --- a/android/default.properties +++ /dev/null @@ -1,11 +0,0 @@ -# This file is automatically generated by Android Tools. -# Do not modify this file -- YOUR CHANGES WILL BE ERASED! -# -# This file must be checked in Version Control Systems. -# -# To customize properties used by the Ant build system use, -# "build.properties", and override values to adapt the script to your -# project structure. - -# Project target. -target=android-9 diff --git a/android/jni/Android.mk b/android/jni/Android.mk deleted file mode 100644 index 1c3e7ea..0000000 --- a/android/jni/Android.mk +++ /dev/null @@ -1,88 +0,0 @@ -LOCAL_PATH := $(call my-dir)/../../cpp/src - -include $(CLEAR_VARS) -LOCAL_MODULE := synth -LOCAL_CPP_EXTENSION := .cc -LOCAL_SRC_FILES := android_glue.cc \ - dx7note.cc \ - env.cc \ - exp2.cc \ - fir.cc \ - fm_core.cc \ - fm_op_kernel.cc \ - freqlut.cc \ - lfo.cc \ - patch.cc \ - pitchenv.cc \ - resofilter.cc \ - ringbuffer.cc \ - sawtooth.cc \ - sin.cc \ - synth_unit.cc - -ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) - LOCAL_ARM_NEON := true - LOCAL_CFLAGS := -DHAVE_NEON=1 - LOCAL_SRC_FILES += neon_fm_kernel.s \ - neon_ladder.s \ - neon_fir.s -endif - -# for native audio -LOCAL_LDLIBS += -lOpenSLES -# for logging -LOCAL_LDLIBS += -llog - -LOCAL_STATIC_LIBRARIES += cpufeatures - -LOCAL_CFLAGS += -O3 - -include $(BUILD_SHARED_LIBRARY) - -include $(CLEAR_VARS) -LOCAL_SRC_FILES := test_neon.cc \ - resofilter.cc - -ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) - LOCAL_ARM_NEON := true - LOCAL_CFLAGS := -DHAVE_NEON=1 - LOCAL_SRC_FILES += neon_fm_kernel.s \ - neon_ladder.s \ - neon_fir.s -endif - -LOCAL_CFLAGS += -O3 - -LOCAL_STATIC_LIBRARIES += cpufeatures - -LOCAL_MODULE := test_neon - -include $(BUILD_EXECUTABLE) - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := test_filter.cc \ - fir.cc \ - sawtooth.cc \ - exp2.cc \ - sin.cc \ - fm_op_kernel.cc \ - resofilter.cc \ - freqlut.cc - -ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) - LOCAL_ARM_NEON := true - LOCAL_CFLAGS := -DHAVE_NEON=1 - LOCAL_SRC_FILES += neon_fir.s \ - neon_iir.s \ - neon_fm_kernel.s \ - neon_ladder.s -endif - -LOCAL_CFLAGS += -O3 -LOCAL_STATIC_LIBRARIES += cpufeatures -LOCAL_MODULE := test_filter -include $(BUILD_EXECUTABLE) - - -$(call import-module,android/cpufeatures) diff --git a/android/jni/Application.mk b/android/jni/Application.mk deleted file mode 100644 index 3d53443..0000000 --- a/android/jni/Application.mk +++ /dev/null @@ -1,2 +0,0 @@ -APP_ABI := all - diff --git a/android/project.properties b/android/project.properties deleted file mode 100644 index a3ee5ab..0000000 --- a/android/project.properties +++ /dev/null @@ -1,14 +0,0 @@ -# This file is automatically generated by Android Tools. -# Do not modify this file -- YOUR CHANGES WILL BE ERASED! -# -# This file must be checked in Version Control Systems. -# -# To customize properties used by the Ant build system edit -# "ant.properties", and override values to adapt the script to your -# project structure. -# -# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): -#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt - -# Project target. -target=android-17 diff --git a/android/src/com/levien/synthesizer/android/Storage.java b/android/src/com/levien/synthesizer/android/Storage.java deleted file mode 100644 index de4cf81..0000000 --- a/android/src/com/levien/synthesizer/android/Storage.java +++ /dev/null @@ -1,279 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.logging.Level; -import java.util.logging.Logger; - -import android.app.AlertDialog; -import android.content.Context; -import android.content.DialogInterface; -import android.os.Environment; -import android.widget.EditText; -import android.widget.Toast; - -import com.levien.synthesizer.core.music.Music.Score; - -/** - * A collection of functions for storing and retrieving scores. - */ -public class Storage { - /** - * Opens the score stored with the name "_default", which should always be the current score - * being edited. This may be called at any time to restore saved state, since Android Activities - * can come and go. - * - * @param score - The mutable score to populate with the stored data. - * @param context - Android application context. - */ - public static void openDefaultScore(Score.Builder score, Context context) throws IOException { - openScore(score, "_default", context); - } - - /** - * Saves a score with the name "_default", which should always be the current score being edited. - * This may be called at any time to save state, since Android Activities can come and go. - * - * @param score - The score data to save. - * @param context - Android application context. - */ - public static void saveDefaultScore(Score score, Context context) throws IOException { - saveScore(score, "_default", true, context); - } - - /** - * Opens the score with the given name. The name should be name of a valid score file in storage. - * The file must be in the root external files directory for the app. - * - * @param score - The mutable score to update with the data from storage. - * @param name - The name of the file, minus the ".pb" extension. - * @param context - The Android application context. - */ - public static void openScore(Score.Builder score, String name, Context context) throws IOException { - if (!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) && - !Environment.MEDIA_MOUNTED_READ_ONLY.equals(Environment.getExternalStorageState())) { - throw new IOException("External storage is not readable."); - } - File path = context.getExternalFilesDir(null); - File file = new File(path, name + ".pb"); - FileInputStream in = new FileInputStream(file); - score.clear(); - score.mergeFrom(in); - in.close(); - } - - /** - * Saves the score with the given name. Files are stored in the root external files directory for - * the app. - * - * @param score - The score to save. - * @param name - The name of the file, without any extension. - * @param overwrite - If true, replace the existing file, if one already exists. - * @param context - The Android application context. - * @throws IOException - On any kind of IO error, or if name is "", or the file already exists. - */ - public static void saveScore(Score score, - String name, - boolean overwrite, - Context context) throws IOException { - if (!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) { - throw new IOException("External storage is not writeable."); - } - File path = context.getExternalFilesDir(null); - name = cleanupName(name); - if (name.length() == 0) { - throw new IOException("Can't save score without a name."); - } - File file = new File(path, name + ".pb"); - if (!overwrite && file.exists()) { - throw new IOException("File already exists."); - } - FileOutputStream out = new FileOutputStream(file); - score.writeTo(out); - out.close(); - } - - /** - * Returns the list of all valid names of scores that are currently in storage. - */ - public static String[] getScoreNames(Context context) throws IOException { - if (!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) && - !Environment.MEDIA_MOUNTED_READ_ONLY.equals(Environment.getExternalStorageState())) { - throw new IOException("External storage is not readable."); - } - File path = context.getExternalFilesDir(null); - File[] files = path.listFiles(); - ArrayList names = new ArrayList(); - for (File file : files) { - names.add(file.getName().replaceAll("\\.pb", "")); - } - return names.toArray(new String[0]); - } - - /** - * Returns true iff there is a score in storage with the given name. - */ - public static boolean scoreExists(String name, Context context) throws IOException { - String[] names = getScoreNames(context); - for (String existingName : names) { - if (name.equals(existingName)) { - return true; - } - } - return false; - } - - /** - * Interface used to notify callers of openScoreWithDialog() when the opening has completed. - */ - public interface OpenScoreListener { - void onOpenScore(Score.Builder score); - } - - /** - * Shows UI to allow the user to pick one of the current scores in storage, and then populates - * score with the data from that file. - * - * @param score - The mutable score to update. - * @param listener - A listener that is notified after the score is updated. Can be null. - * @param context - An Android application context. - */ - public static void openScoreWithDialog(final Score.Builder score, - final OpenScoreListener listener, - final Context context) { - AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setTitle("Open score..."); - try { - final String[] scoreNames = getScoreNames(context); - builder.setItems(scoreNames, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - try { - openScore(score, scoreNames[which], context); - if (listener != null) { - listener.onOpenScore(score); - } - dialog.dismiss(); - } catch (IOException e) { - Logger logger = Logger.getLogger(Storage.class.getName()); - logger.log(Level.SEVERE, - "Error opening score \"" + scoreNames[which] + "\" with dialog.", e); - Toast.makeText(context, - "Unable to open \"" + scoreNames[which] + "\".", - Toast.LENGTH_SHORT).show(); - } - } - }); - } catch (IOException e) { - Logger logger = Logger.getLogger(Storage.class.getName()); - logger.log(Level.SEVERE, - "Error getting score names.", e); - Toast.makeText(context, - "Unable to get existing score names.", - Toast.LENGTH_SHORT).show(); - } - AlertDialog dialog = builder.create(); - dialog.show(); - } - - /** - * Shows UI to allow the user to pick a name and save the given score in storage. - * - * @param score - The score to save. - * @param context - An Android application context. - */ - public static void saveScoreWithDialog(final Score score, - final Context context) { - AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setTitle("Save score as..."); - builder.setMessage("Name: "); - final EditText input = new EditText(context); - builder.setView(input); - builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { - public void onClick(final DialogInterface nameDialog, int which) { - final String name = cleanupName(input.getText().toString()); - if (name.length() == 0) { - Toast.makeText(context, - "Name must not be empty.", - Toast.LENGTH_SHORT).show(); - } else { - try { - if (scoreExists(name, context)) { - AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setTitle("Overwrite?"); - builder.setMessage( - "A score named " + name + " already exists. Would you like to overwrite it?"); - builder.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface confirmDialog, int which) { - try { - saveScore(score, name, true, context); - confirmDialog.dismiss(); - nameDialog.dismiss(); - } catch (IOException e) { - Logger logger = Logger.getLogger(Storage.class.getName()); - logger.log(Level.SEVERE, - "Error saving score \"" + name + "\" with dialog.", e); - Toast.makeText(context, - "Unable to save \"" + name + "\".", - Toast.LENGTH_SHORT).show(); - } - } - }); - builder.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); - } - }); - AlertDialog confirmDialog = builder.create(); - confirmDialog.show(); - } else { - saveScore(score, name, false, context); - nameDialog.dismiss(); - } - } catch (IOException e) { - Logger logger = Logger.getLogger(Storage.class.getName()); - logger.log(Level.SEVERE, - "Error saving score \"" + name + "\" with dialog.", e); - Toast.makeText(context, - "Unable to save \"" + name + "\".", - Toast.LENGTH_SHORT).show(); - } - } - } - }); - builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); - } - }); - AlertDialog dialog = builder.create(); - dialog.show(); - } - - /** - * Internal method to turn a user input string into a valid file name. - */ - private static String cleanupName(String name) { - name = name.trim(); - name = name.replaceAll("[^A-Za-z0-9_-]", "_"); - return name; - } -} diff --git a/android/src/com/levien/synthesizer/android/ui/AmplificationActivity.java b/android/src/com/levien/synthesizer/android/ui/AmplificationActivity.java deleted file mode 100644 index f7ccd9e..0000000 --- a/android/src/com/levien/synthesizer/android/ui/AmplificationActivity.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.ui; - -import android.os.Bundle; -import com.levien.synthesizer.R; -import com.levien.synthesizer.core.model.composite.MultiChannelSynthesizer; -import com.levien.synthesizer.core.model.composite.Presets.Setting; -import com.levien.synthesizer.android.widgets.knob.KnobView; -import com.levien.synthesizer.android.widgets.piano.PianoView; - -/** - * Activity for modifying amplification/adsr envelope. - * TODO(klimt): Add the ability to switch channels. - */ -public class AmplificationActivity extends SynthesizerActivity { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.amplification); - - attackKnob_ = (KnobView)findViewById(R.id.attackKnob); - decayKnob_ = (KnobView)findViewById(R.id.decayKnob); - sustainKnob_ = (KnobView)findViewById(R.id.sustainKnob); - releaseKnob_ = (KnobView)findViewById(R.id.releaseKnob); - volumeKnob_ = (KnobView)findViewById(R.id.volumeKnob); - piano_ = (PianoView)findViewById(R.id.piano); - } - - @Override - protected void onSynthesizerUpdate(MultiChannelSynthesizer synth) { - int channel = getIntentChannel(this); - attackKnob_.bindTo(synthesizer_, channel, Setting.ATTACK); - decayKnob_.bindTo(synthesizer_, channel, Setting.DECAY); - sustainKnob_.bindTo(synthesizer_, channel, Setting.SUSTAIN); - releaseKnob_.bindTo(synthesizer_, channel, Setting.RELEASE); - volumeKnob_.bindTo(synthesizer_, channel, Setting.VOLUME); - piano_.bindTo(synthesizer_, channel); - } - - private KnobView attackKnob_; - private KnobView decayKnob_; - private KnobView sustainKnob_; - private KnobView releaseKnob_; - private KnobView volumeKnob_; - private PianoView piano_; -} diff --git a/android/src/com/levien/synthesizer/android/ui/ChordGridActivity.java b/android/src/com/levien/synthesizer/android/ui/ChordGridActivity.java deleted file mode 100644 index d9195c6..0000000 --- a/android/src/com/levien/synthesizer/android/ui/ChordGridActivity.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.ui; - -import java.util.ArrayList; - -import android.os.Bundle; -import android.view.View; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemSelectedListener; -import android.widget.ArrayAdapter; -import android.widget.Spinner; - -import com.levien.synthesizer.R; -import com.levien.synthesizer.core.model.composite.MultiChannelSynthesizer; -import com.levien.synthesizer.android.widgets.ChordGridView; - -/** - * Activity for playing whole chords at a time, arranged in a circle of fifths. - */ -public class ChordGridActivity extends SynthesizerActivity { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.chord_grid); - - chordGrid_ = (ChordGridView)findViewById(R.id.chord_grid); - presetSpinner_ = (Spinner)findViewById(R.id.presetSpinner); - - presetSpinner_.setOnItemSelectedListener(new OnItemSelectedListener() { - public void onItemSelected(AdapterView parent, View view, int position, long id) { - if (synthesizer_ == null) { - return; - } - if (position > 0) { - chordGrid_.bindTo(synthesizer_, position - 1); - } - } - public void onNothingSelected(AdapterView parent) { - } - }); - } - - @Override - protected void onSynthesizerUpdate(MultiChannelSynthesizer synth) { - chordGrid_.bindTo(synthesizer_, 0); - - ArrayList presetNames = new ArrayList(); - presetNames.add(""); - synthesizer_.getPresetNames(presetNames); - ArrayAdapter adapter = new ArrayAdapter( - this, android.R.layout.simple_spinner_item, presetNames); - adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - presetSpinner_.setAdapter(adapter); - } - - private ChordGridView chordGrid_; - private Spinner presetSpinner_; -} diff --git a/android/src/com/levien/synthesizer/android/ui/EditInstrumentActivity.java b/android/src/com/levien/synthesizer/android/ui/EditInstrumentActivity.java deleted file mode 100644 index cc4a8e2..0000000 --- a/android/src/com/levien/synthesizer/android/ui/EditInstrumentActivity.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright 2012 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.ui; - -import android.app.ListActivity; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.ServiceConnection; -import android.os.Bundle; -import android.os.IBinder; -import android.view.View; -import android.widget.ArrayAdapter; -import android.widget.ListView; - -import com.levien.synthesizer.R; -import com.levien.synthesizer.core.model.composite.Presets.Setting; -import com.levien.synthesizer.android.service.SynthesizerService; - -/** - * An Activity to let the user choose a subset of a presets settings in order to edit them. - */ -public class EditInstrumentActivity extends ListActivity { - @Override - protected void onCreate(Bundle savedInstanceState){ - super.onCreate(savedInstanceState); - String[] sections = getResources().getStringArray(R.array.sections); - ArrayAdapter adapter = new ArrayAdapter( - this, android.R.layout.simple_list_item_1, sections); - setListAdapter(adapter); - } - - @Override - protected void onStart() { - super.onStart(); - bindService(new Intent(this, SynthesizerService.class), - synthesizerConnection_, Context.BIND_AUTO_CREATE); - } - - @Override - protected void onStop() { - super.onStop(); - unbindService(synthesizerConnection_); - } - - @Override - protected void onListItemClick(ListView list, View view, int position, long id) { - int channel = SynthesizerActivity.getIntentChannel(this); - switch (position) { - case 0: - this.startActivity(new Intent(null, - SynthesizerActivity.makeUri(channel), - this, - VibratoActivity.class)); - break; - case 1: - this.startActivity(new Intent(null, SynthesizerActivity.makeUri( - channel, - Setting.OSCILLATOR_1_WAVEFORM, - Setting.OSCILLATOR_1_GLIDE, - Setting.OSCILLATOR_1_COARSE, - Setting.OSCILLATOR_1_FINE, - Setting.OSCILLATOR_1_VIBRATO, - Setting.BALANCE), - this, OscillatorActivity.class)); - break; - case 2: - this.startActivity(new Intent(null, SynthesizerActivity.makeUri( - channel, - Setting.OSCILLATOR_2_WAVEFORM, - Setting.OSCILLATOR_2_GLIDE, - Setting.OSCILLATOR_2_COARSE, - Setting.OSCILLATOR_2_FINE, - Setting.OSCILLATOR_2_VIBRATO, - Setting.BALANCE), - this, OscillatorActivity.class)); - break; - case 3: - this.startActivity(new Intent(null, SynthesizerActivity.makeUri( - channel, - Setting.OSCILLATOR_1_BLEND, - Setting.OSCILLATOR_1_STRETCH, - Setting.OSCILLATOR_1_EXCITEMENT), - this, KarplusStrongActivity.class)); - break; - case 4: - this.startActivity(new Intent(null, SynthesizerActivity.makeUri( - channel, - Setting.OSCILLATOR_2_BLEND, - Setting.OSCILLATOR_2_STRETCH, - Setting.OSCILLATOR_2_EXCITEMENT), - this, KarplusStrongActivity.class)); - break; - case 5: - this.startActivity(new Intent(null, - SynthesizerActivity.makeUri(channel), - this, - TremoloActivity.class)); - break; - case 6: - this.startActivity(new Intent(null, - SynthesizerActivity.makeUri(channel), - this, - LowPassFilterActivity.class)); - break; - case 7: - this.startActivity(new Intent(null, - SynthesizerActivity.makeUri(channel), - this, - AmplificationActivity.class)); - break; - case 8: - this.startActivity(new Intent(null, - SynthesizerActivity.makeUri(channel), - this, - EffectsActivity.class)); - break; - } - } - - private ServiceConnection synthesizerConnection_ = new ServiceConnection() { - public void onServiceConnected(ComponentName className, IBinder service) { - } - public void onServiceDisconnected(ComponentName className) { - } - }; -} diff --git a/android/src/com/levien/synthesizer/android/ui/EffectsActivity.java b/android/src/com/levien/synthesizer/android/ui/EffectsActivity.java deleted file mode 100644 index 6d0c17f..0000000 --- a/android/src/com/levien/synthesizer/android/ui/EffectsActivity.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.ui; - -import android.os.Bundle; -import com.levien.synthesizer.R; -import com.levien.synthesizer.core.model.composite.MultiChannelSynthesizer; -import com.levien.synthesizer.core.model.composite.Presets.Setting; -import com.levien.synthesizer.android.widgets.knob.KnobView; -import com.levien.synthesizer.android.widgets.piano.PianoView; - -/** - * Activity for modifying effects like echo. - * TODO(klimt): Add the ability to switch channels. - */ -public class EffectsActivity extends SynthesizerActivity { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.effects); - - piano_ = (PianoView)findViewById(R.id.piano); - echoMixKnob_ = (KnobView)findViewById(R.id.echoMixKnob); - echoDelayKnob_ = (KnobView)findViewById(R.id.echoDelayKnob); - } - - @Override - protected void onSynthesizerUpdate(MultiChannelSynthesizer synth) { - int channel = getIntentChannel(this); - piano_.bindTo(synthesizer_, channel); - echoMixKnob_.bindTo(synthesizer_, channel, Setting.ECHO_MIX); - echoDelayKnob_.bindTo(synthesizer_, channel, Setting.ECHO_DELAY); - } - - private PianoView piano_; - private KnobView echoMixKnob_; - private KnobView echoDelayKnob_; -} diff --git a/android/src/com/levien/synthesizer/android/ui/InstrumentListActivity.java b/android/src/com/levien/synthesizer/android/ui/InstrumentListActivity.java deleted file mode 100644 index 1941c95..0000000 --- a/android/src/com/levien/synthesizer/android/ui/InstrumentListActivity.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2012 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.ui; - -import java.util.ArrayList; - -import com.levien.synthesizer.core.model.composite.MultiChannelSynthesizer; -import com.levien.synthesizer.android.service.SynthesizerService; - -import android.app.ListActivity; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.ServiceConnection; -import android.os.IBinder; -import android.view.View; -import android.widget.ArrayAdapter; -import android.widget.ListView; - -/** - * An activity that shows the list of available presets (aka instruments), and let's the user click - * on one of them to begin editing it. - */ -public class InstrumentListActivity extends ListActivity { - @Override - protected void onStart() { - super.onStart(); - bindService(new Intent(this, SynthesizerService.class), - synthesizerConnection_, Context.BIND_AUTO_CREATE); - } - - @Override - protected void onStop() { - super.onStop(); - unbindService(synthesizerConnection_); - } - - @Override - protected void onListItemClick(ListView list, View view, int position, long id) { - this.startActivity(new Intent(null, - SynthesizerActivity.makeUri(position), - this, - EditInstrumentActivity.class)); - } - - private ServiceConnection synthesizerConnection_ = new ServiceConnection() { - public void onServiceConnected(ComponentName className, IBinder service) { - MultiChannelSynthesizer synthesizer = - ((SynthesizerService.LocalBinder)service).getSynthesizer(); - ArrayList presets = new ArrayList(); - synthesizer.getPresetNames(presets); - final ArrayAdapter adapter = new ArrayAdapter( - InstrumentListActivity.this, - android.R.layout.simple_list_item_1, - presets.toArray(new String[0])); - InstrumentListActivity.this.runOnUiThread(new Runnable() { - public void run() { - InstrumentListActivity.this.setListAdapter(adapter); - InstrumentListActivity.this.getListView().invalidate(); - } - }); - - } - public void onServiceDisconnected(ComponentName className) { - } - }; -} diff --git a/android/src/com/levien/synthesizer/android/ui/KarplusStrongActivity.java b/android/src/com/levien/synthesizer/android/ui/KarplusStrongActivity.java deleted file mode 100644 index 0ba5ee8..0000000 --- a/android/src/com/levien/synthesizer/android/ui/KarplusStrongActivity.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.ui; - -import android.os.Bundle; -import com.levien.synthesizer.R; -import com.levien.synthesizer.core.model.composite.MultiChannelSynthesizer; -import com.levien.synthesizer.core.model.composite.Presets.Setting; -import com.levien.synthesizer.android.widgets.knob.KnobView; -import com.levien.synthesizer.android.widgets.piano.PianoView; - -/** - * Activity for modifying Karplus-Strong parameters. - * TODO(klimt): Add the ability to switch channels. - */ -public class KarplusStrongActivity extends SynthesizerActivity { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.karplus_strong); - - piano_ = (PianoView)findViewById(R.id.piano); - blendKnob_ = (KnobView)findViewById(R.id.blendKnob); - stretchKnob_ = (KnobView)findViewById(R.id.stretchKnob); - excitementKnob_ = (KnobView)findViewById(R.id.excitementKnob); - - PianoView piano = (PianoView)findViewById(R.id.piano); - piano.bindTo(synthesizer_, 0); - } - - @Override - protected void onSynthesizerUpdate(MultiChannelSynthesizer synth) { - int channel = getIntentChannel(this); - Setting[] settings = getIntentSettings(this); - piano_.bindTo(synthesizer_, channel); - blendKnob_.bindTo(synthesizer_, channel, settings[0]); - stretchKnob_.bindTo(synthesizer_, channel, settings[1]); - excitementKnob_.bindTo(synthesizer_, channel, settings[2]); - } - - private PianoView piano_; - private KnobView blendKnob_; - private KnobView stretchKnob_; - private KnobView excitementKnob_; -} diff --git a/android/src/com/levien/synthesizer/android/ui/LowPassFilterActivity.java b/android/src/com/levien/synthesizer/android/ui/LowPassFilterActivity.java deleted file mode 100644 index d517c0b..0000000 --- a/android/src/com/levien/synthesizer/android/ui/LowPassFilterActivity.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.ui; - -import android.os.Bundle; -import com.levien.synthesizer.R; -import com.levien.synthesizer.core.model.composite.MultiChannelSynthesizer; -import com.levien.synthesizer.core.model.composite.Presets.Setting; -import com.levien.synthesizer.android.widgets.knob.KnobView; -import com.levien.synthesizer.android.widgets.piano.PianoView; - -/** - * Activity for modifying low-pass filter settings. - * TODO(klimt): Add the ability to switch channels. - */ -public class LowPassFilterActivity extends SynthesizerActivity { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.low_pass_filter); - - piano_ = (PianoView)findViewById(R.id.piano); - cutoffKnob_ = (KnobView)findViewById(R.id.cutoffKnob); - depthKnob_ = (KnobView)findViewById(R.id.depthKnob); - attackKnob_ = (KnobView)findViewById(R.id.attackKnob); - decayKnob_ = (KnobView)findViewById(R.id.decayKnob); - sustainKnob_ = (KnobView)findViewById(R.id.sustainKnob); - releaseKnob_ = (KnobView)findViewById(R.id.releaseKnob); - - PianoView piano = (PianoView)findViewById(R.id.piano); - piano.bindTo(synthesizer_, 0); - } - - @Override - protected void onSynthesizerUpdate(MultiChannelSynthesizer synth) { - int channel = getIntentChannel(this); - piano_.bindTo(synthesizer_, channel); - cutoffKnob_.bindTo(synthesizer_, channel, Setting.FILTER_CUTOFF); - depthKnob_.bindTo(synthesizer_, channel, Setting.FILTER_DEPTH); - attackKnob_.bindTo(synthesizer_, channel, Setting.FILTER_ATTACK); - decayKnob_.bindTo(synthesizer_, channel, Setting.FILTER_DECAY); - sustainKnob_.bindTo(synthesizer_, channel, Setting.FILTER_SUSTAIN); - releaseKnob_.bindTo(synthesizer_, channel, Setting.FILTER_RELEASE); - } - - private PianoView piano_; - private KnobView cutoffKnob_; - private KnobView depthKnob_; - private KnobView attackKnob_; - private KnobView decayKnob_; - private KnobView sustainKnob_; - private KnobView releaseKnob_; -} diff --git a/android/src/com/levien/synthesizer/android/ui/MainActivity.java b/android/src/com/levien/synthesizer/android/ui/MainActivity.java deleted file mode 100644 index caf802f..0000000 --- a/android/src/com/levien/synthesizer/android/ui/MainActivity.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.ui; - -import java.util.ArrayList; - -import android.os.Bundle; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemSelectedListener; -import android.widget.ArrayAdapter; -import android.widget.Button; -import android.widget.Spinner; - -import com.levien.synthesizer.R; -import com.levien.synthesizer.core.model.composite.MultiChannelSynthesizer; -import com.levien.synthesizer.android.widgets.piano.PianoView; - -// TODO(klimt): Add the ability to switch channels. - -public class MainActivity extends SynthesizerActivity { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.main); - - piano_ = (PianoView)findViewById(R.id.piano); - presetSpinner_ = (Spinner)findViewById(R.id.presetSpinner); - - final Button playButton = (Button)findViewById(R.id.playButton); - final Button recordButton = (Button)findViewById(R.id.recordButton); - - playButton.setOnClickListener(new OnClickListener() { - public void onClick(View view) { - if (synthesizer_.getChannel(0).isPlaying()) { - synthesizer_.getChannel(0).stopPlaying(); - playButton.setText(R.string.play); - recordButton.setText(R.string.record); - } else { - synthesizer_.getChannel(0).startPlaying(); - playButton.setText(R.string.stop); - recordButton.setText(R.string.record); - } - } - }); - - recordButton.setOnClickListener(new OnClickListener() { - public void onClick(View view) { - if (synthesizer_.getChannel(0).isRecording()) { - synthesizer_.getChannel(0).stopRecording(); - playButton.setText(R.string.play); - recordButton.setText(R.string.record); - } else { - synthesizer_.getChannel(0).startRecording(); - playButton.setEnabled(true); - playButton.setText(R.string.play); - recordButton.setText(R.string.stop); - } - } - }); - - presetSpinner_.setOnItemSelectedListener(new OnItemSelectedListener() { - public void onItemSelected(AdapterView parent, View view, int position, long id) { - if (synthesizer_ == null) { - return; - } - String preset = presetSpinner_.getItemAtPosition(position).toString(); - if (!preset.equals("")) { - synthesizer_.getChannel(0).setPreset(preset); - } - } - public void onNothingSelected(AdapterView parent) { - } - }); - } - - @Override - protected void onSynthesizerUpdate(MultiChannelSynthesizer synth) { - piano_.bindTo(synthesizer_, 0); - - ArrayList presetNames = new ArrayList(); - presetNames.add(""); - synthesizer_.getPresetNames(presetNames); - ArrayAdapter adapter = new ArrayAdapter( - this, android.R.layout.simple_spinner_item, presetNames); - adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - presetSpinner_.setAdapter(adapter); - } - - private PianoView piano_; - private Spinner presetSpinner_; -} diff --git a/android/src/com/levien/synthesizer/android/ui/OscillatorActivity.java b/android/src/com/levien/synthesizer/android/ui/OscillatorActivity.java deleted file mode 100644 index 57eb91f..0000000 --- a/android/src/com/levien/synthesizer/android/ui/OscillatorActivity.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.ui; - -import android.os.Bundle; -import com.levien.synthesizer.R; -import com.levien.synthesizer.core.model.composite.MultiChannelSynthesizer; -import com.levien.synthesizer.core.model.composite.Presets.Setting; -import com.levien.synthesizer.android.widgets.knob.KnobView; -import com.levien.synthesizer.android.widgets.piano.PianoView; -import com.levien.synthesizer.android.widgets.waveform.WaveformRowView; - -/** - * Activity for modifying oscillator parameters. - * TODO(klimt): Add the ability to switch channels. - */ -public class OscillatorActivity extends SynthesizerActivity { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.oscillator); - - piano_ = (PianoView)findViewById(R.id.piano); - waveformView_ = (WaveformRowView)findViewById(R.id.waveform); - glideKnob_ = (KnobView)findViewById(R.id.glideKnob); - coarseKnob_ = (KnobView)findViewById(R.id.coarseKnob); - fineKnob_ = (KnobView)findViewById(R.id.fineKnob); - vibratoDepthKnob_ = (KnobView)findViewById(R.id.vibratoDepthKnob); - balanceKnob_ = (KnobView)findViewById(R.id.balanceKnob); - } - - @Override - protected void onSynthesizerUpdate(MultiChannelSynthesizer synth) { - int channel = getIntentChannel(this); - Setting[] settings = getIntentSettings(this); - piano_.bindTo(synthesizer_, channel); - waveformView_.bindTo(synthesizer_, channel, settings[0]); - glideKnob_.bindTo(synthesizer_, channel, settings[1]); - coarseKnob_.bindTo(synthesizer_, channel, settings[2]); - fineKnob_.bindTo(synthesizer_, channel, settings[3]); - vibratoDepthKnob_.bindTo(synthesizer_, channel, settings[4]); - balanceKnob_.bindTo(synthesizer_, channel, settings[5]); - } - - private PianoView piano_; - private WaveformRowView waveformView_; - private KnobView glideKnob_; - private KnobView coarseKnob_; - private KnobView fineKnob_; - private KnobView vibratoDepthKnob_; - private KnobView balanceKnob_; -} diff --git a/android/src/com/levien/synthesizer/android/ui/PianoActivity.java b/android/src/com/levien/synthesizer/android/ui/PianoActivity.java deleted file mode 100644 index 2bc6bef..0000000 --- a/android/src/com/levien/synthesizer/android/ui/PianoActivity.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2012 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.ui; - -import java.util.ArrayList; - -import android.os.Bundle; -import android.view.View; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; -import android.widget.Spinner; -import android.widget.AdapterView.OnItemSelectedListener; - -import com.levien.synthesizer.R; -import com.levien.synthesizer.core.model.composite.MultiChannelSynthesizer; -import com.levien.synthesizer.core.model.composite.Presets.Setting; -import com.levien.synthesizer.android.widgets.knob.KnobView; -import com.levien.synthesizer.android.widgets.piano.PianoView; - -/** - * Activity for simply playing the piano. - */ -public class PianoActivity extends SynthesizerActivity { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.piano); - - piano_ = (PianoView)findViewById(R.id.piano); - volumeKnob_ = (KnobView)findViewById(R.id.volumeKnob); - presetSpinner_ = (Spinner)findViewById(R.id.presetSpinner); - - presetSpinner_.setOnItemSelectedListener(new OnItemSelectedListener() { - public void onItemSelected(AdapterView parent, View view, int position, long id) { - if (synthesizer_ == null) { - return; - } - if (position > 0) { - piano_.bindTo(synthesizer_, position - 1); - volumeKnob_.bindTo(synthesizer_, position - 1, Setting.VOLUME); - } - } - public void onNothingSelected(AdapterView parent) { - } - }); - } - - @Override - protected void onSynthesizerUpdate(MultiChannelSynthesizer synth) { - piano_.bindTo(synthesizer_, 0); - volumeKnob_.bindTo(synthesizer_, 0, Setting.VOLUME); - - ArrayList presetNames = new ArrayList(); - presetNames.add(""); - synthesizer_.getPresetNames(presetNames); - ArrayAdapter adapter = new ArrayAdapter( - this, android.R.layout.simple_spinner_item, presetNames); - adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - presetSpinner_.setAdapter(adapter); - } - - private PianoView piano_; - private KnobView volumeKnob_; - private Spinner presetSpinner_; -} diff --git a/android/src/com/levien/synthesizer/android/ui/ScoreActivity.java b/android/src/com/levien/synthesizer/android/ui/ScoreActivity.java deleted file mode 100644 index a39f130..0000000 --- a/android/src/com/levien/synthesizer/android/ui/ScoreActivity.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.ui; - -import java.io.IOException; -import java.util.logging.Level; -import java.util.logging.Logger; - -import android.app.AlertDialog; -import android.content.DialogInterface; -import android.content.Intent; -import android.os.Bundle; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; - -import com.levien.synthesizer.R; -import com.levien.synthesizer.android.Storage; -import com.levien.synthesizer.android.widgets.score.ScoreView; -import com.levien.synthesizer.android.widgets.score.ScoreViewToolbar; -import com.levien.synthesizer.core.midi.MidiListener; -import com.levien.synthesizer.core.music.Music.Score.Builder; - -/** - * An Activity for editing or playing a score. - */ -public class ScoreActivity extends SynthActivity { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.score); - - logger_ = Logger.getLogger(getClass().getName()); - - scoreView_ = (ScoreView)findViewById(R.id.score); - scoreViewToolbar_ = (ScoreViewToolbar)findViewById(R.id.toolbar); - - scoreViewToolbar_.setScoreView(scoreView_); - } - - @Override - protected void onStart() { - super.onStart(); - try { - Storage.openDefaultScore(scoreView_.getScore(), this.getApplicationContext()); - scoreView_.invalidate(); - scoreViewToolbar_.invalidate(); - } catch (IOException e) { - logger_.log(Level.SEVERE, "Unable to open score.", e); - } - } - - @Override - protected void onStop() { - try { - Storage.saveDefaultScore(scoreView_.getScore().build(), this.getApplicationContext()); - } catch (IOException e) { - logger_.log(Level.SEVERE, "Unable to save score.", e); - } - super.onStop(); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.score_menu, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.new_score: - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle("New score..."); - builder.setMessage("This will erase any unsaved work. Are you sure?"); - builder.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - scoreView_.getScore().clear(); - scoreView_.invalidate(); - scoreViewToolbar_.invalidate(); - dialog.dismiss(); - } - }); - builder.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); - } - }); - AlertDialog dialog = builder.create(); - dialog.show(); - return true; - case R.id.open_score: - Storage.openScoreWithDialog(scoreView_.getScore(), new Storage.OpenScoreListener() { - public void onOpenScore(Builder score) { - scoreView_.invalidate(); - scoreViewToolbar_.invalidate(); - } - }, this); - return true; - case R.id.save_score: - Storage.saveScoreWithDialog(scoreView_.getScore().build(), this); - return true; - case R.id.piano: - this.startActivity(new Intent(this, PianoActivity.class)); - return true; - case R.id.chord_grid: - this.startActivity(new Intent(this, ChordGridActivity.class)); - return true; - case R.id.edit_instrument: - this.startActivity(new Intent(this, InstrumentListActivity.class)); - return true; - default: - return super.onOptionsItemSelected(item); - } - } - - protected void onSynthConnected() { - final MidiListener synthMidi = synthesizerService_.getMidiListener(); - scoreView_.bindTo(synthMidi); - } - - private ScoreView scoreView_; - private ScoreViewToolbar scoreViewToolbar_; - - private Logger logger_; -} diff --git a/android/src/com/levien/synthesizer/android/ui/SynthesizerActivity.java b/android/src/com/levien/synthesizer/android/ui/SynthesizerActivity.java deleted file mode 100644 index 06d96eb..0000000 --- a/android/src/com/levien/synthesizer/android/ui/SynthesizerActivity.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.ui; - -import android.app.Activity; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.ServiceConnection; -import android.net.Uri; -import android.os.IBinder; -import android.util.Log; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import com.levien.synthesizer.R; -import com.levien.synthesizer.core.model.composite.MultiChannelSynthesizer; -import com.levien.synthesizer.core.model.composite.Presets.Setting; -import com.levien.synthesizer.android.service.SynthesizerService; - -/** - * A base class for any Android Activity that wants to interact with the SynthesizerService. - */ -public abstract class SynthesizerActivity extends Activity { - /** - * Called when the synthesizer model changes. - */ - protected abstract void onSynthesizerUpdate(MultiChannelSynthesizer synth); - - /** - * Creates a URI for a specific synthesizer path. - * @param path - The absolute path of the component. - */ - public static Uri makeUri(int channel, Setting... settings) { - StringBuilder uri = new StringBuilder("content://com.levien.synthesizer/" + channel + "/"); - boolean first = true; - for (Setting setting : settings) { - if (!first) { - uri.append(','); - } - uri.append(setting.getNumber()); - first = false; - } - return Uri.parse(uri.toString()); - } - - /** - * Returns the path part of the URI that invoked an activity. - */ - private static String getPath(Activity activity) { - Intent intent = activity.getIntent(); - if (intent == null) { - Log.e(SynthesizerActivity.class.getName(), - "Attempted to get Intent module for SynthesizerActivity with no Intent."); - return null; - } - Uri uri = intent.getData(); - if (uri == null) { - Log.e(SynthesizerActivity.class.getName(), - "Attempted to get Intent module for Intent with no URI: " + intent); - return null; - } - String path = uri.getPath(); - if (path == null) { - Log.e(SynthesizerActivity.class.getName(), - "Attempted to get Intent module for URI with no path: " + uri); - return null; - } - if (path.startsWith("/")) { - path = path.substring(1); - } - return path; - } - - /** - * Gets the modules specified by the URI for the intent given to this Activity. - * @return - The list of settings found, if any. Otherwise, null. - */ - public static Setting[] getIntentSettings(Activity activity) { - Setting[] settings = null; - String path = getPath(activity); - // Clip off the channel, if it's there... - if (path.indexOf('/') >= 0) { - path = path.substring(path.indexOf('/') + 1); - } - String[] parts = path.split(", *"); - settings = new Setting[parts.length]; - for (int i = 0; i < parts.length; ++i) { - try { - int id = Integer.parseInt(parts[i]); - settings[i] = Setting.valueOf(id); - } catch (NumberFormatException e) { - Log.e(SynthesizerActivity.class.getName(), - "Unable to convert number \"" + parts[i] + "\" in path: " + path); - } - } - return settings; - } - - /** - * Gets the channel specified by the URI for the intent given to this Activity. - * @return - The channel in the intent, or 0 if none was found. - */ - public static int getIntentChannel(Activity activity) { - String path = getPath(activity); - int firstSlash = path.indexOf('/'); - if (firstSlash < 0) { - Log.e(SynthesizerActivity.class.getName(), - "Unable to find channel number in path: " + path); - return 0; - } - String channelString = path.substring(0, firstSlash); - try { - return Integer.parseInt(channelString); - } catch (NumberFormatException e) { - Log.e(SynthesizerActivity.class.getName(), - "Unable to convert channel number \"" + channelString + "\" in path: " + path); - return 0; - } - } - - @Override - protected void onStart() { - super.onStart(); - bindService(new Intent(this, SynthesizerService.class), - synthesizerConnection_, Context.BIND_AUTO_CREATE); - } - - @Override - protected void onStop() { - super.onStop(); - unbindService(synthesizerConnection_); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.options_menu, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.piano: - this.startActivity(new Intent(this, PianoActivity.class)); - return true; - case R.id.chord_grid: - this.startActivity(new Intent(this, ChordGridActivity.class)); - return true; - case R.id.edit_instrument: - this.startActivity(new Intent(this, InstrumentListActivity.class)); - return true; - case R.id.compose: - this.startActivity(new Intent(this, ScoreActivity.class)); - return true; - default: - return super.onOptionsItemSelected(item); - } - } - - private ServiceConnection synthesizerConnection_ = new ServiceConnection() { - public void onServiceConnected(ComponentName className, IBinder service) { - // synthesizer_ = ISynthesizerService.Stub.asInterface(service); - synthesizer_ = ((SynthesizerService.LocalBinder)service).getSynthesizer(); - SynthesizerActivity.this.onSynthesizerUpdate(synthesizer_); - } - public void onServiceDisconnected(ComponentName className) { - synthesizer_ = null; - SynthesizerActivity.this.onSynthesizerUpdate(synthesizer_); - } - }; - - protected MultiChannelSynthesizer synthesizer_ = null; -} diff --git a/android/src/com/levien/synthesizer/android/ui/TremoloActivity.java b/android/src/com/levien/synthesizer/android/ui/TremoloActivity.java deleted file mode 100644 index d5a0060..0000000 --- a/android/src/com/levien/synthesizer/android/ui/TremoloActivity.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.ui; - -import android.os.Bundle; -import com.levien.synthesizer.R; -import com.levien.synthesizer.core.model.composite.MultiChannelSynthesizer; -import com.levien.synthesizer.core.model.composite.Presets.Setting; -import com.levien.synthesizer.android.widgets.knob.KnobView; -import com.levien.synthesizer.android.widgets.piano.PianoView; -import com.levien.synthesizer.android.widgets.waveform.WaveformRowView; - -/** - * Activity for modifying tremolo. - * TODO(klimt): Add the ability to switch channels. - */ -public class TremoloActivity extends SynthesizerActivity { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.tremolo); - - piano_ = (PianoView)findViewById(R.id.piano); - waveformView_ = (WaveformRowView)findViewById(R.id.waveform); - rateKnob_ = (KnobView)findViewById(R.id.rateKnob); - depthKnob_ = (KnobView)findViewById(R.id.depthKnob); - attackKnob_ = (KnobView)findViewById(R.id.attackKnob); - decayKnob_ = (KnobView)findViewById(R.id.decayKnob); - sustainKnob_ = (KnobView)findViewById(R.id.sustainKnob); - releaseKnob_ = (KnobView)findViewById(R.id.releaseKnob); - } - - @Override - protected void onSynthesizerUpdate(MultiChannelSynthesizer synth) { - int channel = getIntentChannel(this); - piano_.bindTo(synthesizer_, channel); - waveformView_.bindTo(synthesizer_, channel, Setting.TREMOLO_WAVEFORM); - rateKnob_.bindTo(synthesizer_, channel, Setting.TREMOLO_RATE); - depthKnob_.bindTo(synthesizer_, channel, Setting.TREMOLO_DEPTH); - attackKnob_.bindTo(synthesizer_, channel, Setting.TREMOLO_ATTACK); - decayKnob_.bindTo(synthesizer_, channel, Setting.TREMOLO_DECAY); - sustainKnob_.bindTo(synthesizer_, channel, Setting.TREMOLO_SUSTAIN); - releaseKnob_.bindTo(synthesizer_, channel, Setting.TREMOLO_RELEASE); - } - - private PianoView piano_; - private WaveformRowView waveformView_; - private KnobView rateKnob_; - private KnobView depthKnob_; - private KnobView attackKnob_; - private KnobView decayKnob_; - private KnobView sustainKnob_; - private KnobView releaseKnob_; -} diff --git a/android/src/com/levien/synthesizer/android/ui/VibratoActivity.java b/android/src/com/levien/synthesizer/android/ui/VibratoActivity.java deleted file mode 100644 index 6c48e50..0000000 --- a/android/src/com/levien/synthesizer/android/ui/VibratoActivity.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.ui; - -import android.os.Bundle; -import com.levien.synthesizer.R; -import com.levien.synthesizer.core.model.composite.MultiChannelSynthesizer; -import com.levien.synthesizer.core.model.composite.Presets.Setting; -import com.levien.synthesizer.android.widgets.knob.KnobView; -import com.levien.synthesizer.android.widgets.piano.PianoView; -import com.levien.synthesizer.android.widgets.waveform.WaveformRowView; - -/** - * Activity for modifying vibrato. - * TODO(klimt): Add the ability to switch channels. - */ -public class VibratoActivity extends SynthesizerActivity { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.vibrato); - - piano_ = (PianoView)findViewById(R.id.piano); - waveformView_ = (WaveformRowView)findViewById(R.id.waveform); - rateKnob_ = (KnobView)findViewById(R.id.rateKnob); - attackKnob_ = (KnobView)findViewById(R.id.attackKnob); - decayKnob_ = (KnobView)findViewById(R.id.decayKnob); - sustainKnob_ = (KnobView)findViewById(R.id.sustainKnob); - releaseKnob_ = (KnobView)findViewById(R.id.releaseKnob); - } - - @Override - protected void onSynthesizerUpdate(MultiChannelSynthesizer synth) { - int channel = getIntentChannel(this); - piano_.bindTo(synthesizer_, channel); - waveformView_.bindTo(synthesizer_, channel, Setting.VIBRATO_WAVEFORM); - rateKnob_.bindTo(synthesizer_, channel, Setting.VIBRATO_RATE); - attackKnob_.bindTo(synthesizer_, channel, Setting.VIBRATO_ATTACK); - decayKnob_.bindTo(synthesizer_, channel, Setting.VIBRATO_DECAY); - sustainKnob_.bindTo(synthesizer_, channel, Setting.VIBRATO_SUSTAIN); - releaseKnob_.bindTo(synthesizer_, channel, Setting.VIBRATO_RELEASE); - } - - private PianoView piano_; - private WaveformRowView waveformView_; - private KnobView rateKnob_; - private KnobView attackKnob_; - private KnobView decayKnob_; - private KnobView sustainKnob_; - private KnobView releaseKnob_; -} diff --git a/android/src/com/levien/synthesizer/android/widgets/ChordGridView.java b/android/src/com/levien/synthesizer/android/widgets/ChordGridView.java deleted file mode 100644 index 067893d..0000000 --- a/android/src/com/levien/synthesizer/android/widgets/ChordGridView.java +++ /dev/null @@ -1,329 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.widgets; - -import com.levien.synthesizer.R; -import com.levien.synthesizer.core.model.composite.MultiChannelSynthesizer; -import com.levien.synthesizer.core.music.Note; -import com.levien.synthesizer.android.widgets.piano.PianoViewListener; - -import android.content.Context; -import android.content.res.TypedArray; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Path; -import android.graphics.Rect; -import android.graphics.Paint.Style; -import android.util.AttributeSet; -import android.view.MotionEvent; -import android.view.View; - -/** - * ChordGridView is an alternative interface for performing that has keys for chords amongst - * fundamentals arranged in a circle of fifths. - */ -public class ChordGridView extends View { - /** - * Basic android widget constructor. - */ - public ChordGridView(Context context, AttributeSet attrs) { - super(context, attrs); - - // Get the xml attributes for this instance. - TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ChordGridView); - firstOctave_ = a.getInteger(R.styleable.ChordGridView_octave, 4); - - pressedRow_ = -1; - pressedColumn_ = -1; - - drawingRect_ = new Rect(); - path_ = new Path(); - strokePaint_ = new Paint(); - fillPaint_ = new Paint(); - strokePaint_.setStyle(Style.STROKE); - fillPaint_.setStyle(Style.FILL); - } - - /** - * Sets the listener that will receive events from this widget. - */ - public void setPianoViewListener(PianoViewListener pianoViewListener) { - pianoViewListener_ = pianoViewListener; - } - - /** - * Signals the listener that a new note was pressed. - * @param logFrequency - the log frequency of the new note. - * @param retriggerIfOn - true if this is a new touch, rather than just moving. - */ - private void notifyNoteDown(double logFrequency, int finger, boolean retriggerIfOn) { - if (pianoViewListener_ != null) { - pianoViewListener_.noteDown(logFrequency, finger, retriggerIfOn, 1.0f); - } - } - - /** - * Signals the listener that a note was released. - */ - private void notifyNoteUp(int finger) { - if (pianoViewListener_ != null) { - pianoViewListener_.noteUp(finger); - } - } - - /** - * Handler for all touch events. - */ - @Override - public boolean onTouchEvent(MotionEvent event) { - int action = event.getAction(); - int actionCode = action & MotionEvent.ACTION_MASK; - boolean redraw = false; - if (actionCode == MotionEvent.ACTION_DOWN) { - int tileWidth = drawingRect_.width() / COLUMNS; - int tileHeight = drawingRect_.height() / ROWS; - pressedColumn_ = (int)(event.getX() - drawingRect_.left) / tileWidth; - pressedRow_ = (int)(event.getY() - drawingRect_.top) / tileHeight; - redraw = true; - - getTileInfo(pressedRow_, pressedColumn_); - notifyNoteDown(Note.computeLog12TET(tileNote1_, tileOctave1_), 0, true); - notifyNoteDown(Note.computeLog12TET(tileNote2_, tileOctave2_), 1, true); - notifyNoteDown(Note.computeLog12TET(tileNote3_, tileOctave3_), 2, true); - } else if (actionCode == MotionEvent.ACTION_MOVE) { - int tileWidth = drawingRect_.width() / COLUMNS; - int tileHeight = drawingRect_.height() / ROWS; - int newPressedColumn_ = (int)(event.getX() - drawingRect_.left) / tileWidth; - int newPressedRow_ = (int)(event.getY() - drawingRect_.top) / tileHeight; - if (pressedColumn_ != newPressedColumn_ || pressedRow_ != newPressedRow_) { - pressedColumn_ = newPressedColumn_; - pressedRow_ = newPressedRow_; - redraw = true; - - getTileInfo(pressedRow_, pressedColumn_); - notifyNoteDown(Note.computeLog12TET(tileNote1_, tileOctave1_), 0, false); - notifyNoteDown(Note.computeLog12TET(tileNote2_, tileOctave2_), 1, false); - notifyNoteDown(Note.computeLog12TET(tileNote3_, tileOctave3_), 2, false); - } - } else if (actionCode == MotionEvent.ACTION_UP) { - pressedColumn_ = -1; - pressedRow_ = -1; - - notifyNoteUp(0); - notifyNoteUp(1); - notifyNoteUp(2); - redraw = true; - } else { - return super.onTouchEvent(event); - } - if (redraw) { - invalidate(); - } - return true; - } - - /** - * Draws the widget. - */ - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - getDrawingRect(drawingRect_); - int tileWidth = drawingRect_.width() / COLUMNS; - int tileHeight = drawingRect_.height() / ROWS; - for (int row = 0; row < ROWS; ++row) { - for (int column = 0; column < COLUMNS; ++column) { - getTileInfo(row, column); - int foreground; - int background; - if (Note.isNatural(tileNote1_)) { - if (row == pressedRow_ && column == pressedColumn_) { - foreground = Color.GREEN; - } else { - foreground = Color.WHITE; - } - background = Color.BLACK; - } else { - foreground = Color.BLACK; - if (row == pressedRow_ && column == pressedColumn_) { - background = Color.GREEN; - } else { - background = Color.WHITE; - } - } - int textColor = background; - fillPaint_.setColor(foreground); - strokePaint_.setColor(background); - canvas.drawRect(tileWidth * column, - tileHeight * row, - tileWidth * (column + 1), - tileHeight * (row + 1), - fillPaint_); - canvas.drawRect(tileWidth * column + 1, - tileHeight * row + 1, - tileWidth * (column + 1) - 2, - tileHeight * (row + 1) - 2, - strokePaint_); - if (tileIsMajor_) { - textColor = foreground; - strokePaint_.setColor(foreground); - fillPaint_.setColor(background); - path_.reset(); - path_.moveTo(tileWidth * column + 15, tileHeight * (row + 1) - 15); - path_.lineTo(tileWidth * (column + 1) - 15, tileHeight * (row + 1) - 15); - path_.lineTo(tileWidth * column + tileWidth / 2, tileHeight * row + 15); - path_.close(); - canvas.drawPath(path_, fillPaint_); - } - if (tileIsMinor_) { - textColor = foreground; - strokePaint_.setColor(foreground); - fillPaint_.setColor(background); - path_.reset(); - path_.moveTo(tileWidth * column + 15, tileHeight * row + tileHeight / 2); - path_.lineTo(tileWidth * (column + 1) - 15, tileHeight * (row + 1) - 15); - path_.lineTo(tileWidth * (column + 1) - 15, tileHeight * row + 15); - path_.close(); - canvas.drawPath(path_, fillPaint_); - } - if (tileNote1_ == Note.C && !tileIsMinor_ && !tileIsMajor_) { - fillPaint_.setColor(background); - canvas.drawCircle(tileWidth * column + tileWidth / 2, - tileHeight * row + tileHeight / 2, - 10, - fillPaint_); - } - strokePaint_.setColor(textColor); - canvas.drawText(Note.getName(tileNote1_), - tileWidth * column + tileWidth / 2, - tileHeight * row + tileHeight / 2, - strokePaint_); - } - } - } - - /** - * Populates the tile* fields for the tile at the given row and column. - */ - private void getTileInfo(int row, int column) { - int startIndex = 5 + firstOctave_ * 36; - int absoluteIndex = startIndex + row + column * 14; - if (absoluteIndex % 3 == 0) { - // Fundamental key. - tileOctave1_ = absoluteIndex / 36; - tileNote1_ = (absoluteIndex % 36) / 3; - tileOctave2_ = tileOctave1_; - tileNote2_ = tileNote1_; - tileOctave3_ = tileOctave1_; - tileNote3_ = tileNote1_; - tileIsMajor_ = false; - tileIsMinor_ = false; - } else if (absoluteIndex % 3 == 1) { - // Minor chord key. - tileOctave3_ = (int)((absoluteIndex - 1) / 36) + 1; - tileNote3_ = ((absoluteIndex - 1) % 36) / 3; - if (tileNote3_ >= 4) { - tileOctave2_ = tileOctave3_; - tileNote2_ = tileNote3_ - 4; - } else { - tileOctave2_ = tileOctave3_ - 1; - tileNote2_ = tileNote3_ + 8; - } - if (tileNote3_ >= 7) { - tileOctave1_ = tileOctave3_; - tileNote1_ = tileNote3_ - 7; - } else { - tileOctave1_ = tileOctave3_ - 1; - tileNote1_ = tileNote3_ + 5; - } - tileIsMajor_ = false; - tileIsMinor_ = true; - } else if (absoluteIndex % 3 == 2) { - // Major chord key. - tileOctave1_ = (int)((absoluteIndex + 1) / 36); - tileNote1_ = ((absoluteIndex + 1) % 36) / 3; - if (tileNote1_ < 8) { - tileOctave2_ = tileOctave1_; - tileNote2_ = tileNote1_ + 4; - } else { - tileOctave2_ = tileOctave1_ + 1; - tileNote2_ = tileNote1_ - 8; - } - if (tileNote1_ >= 7) { - tileOctave3_ = tileOctave1_; - tileNote3_ = tileNote1_ + 7; - } else { - tileOctave3_ = tileOctave1_ + 1; - tileNote3_ = tileNote1_ - 5; - } - tileIsMajor_ = true; - tileIsMinor_ = false; - } - } - - /** - * Connects the ChordGridView to a Synthesizer. - * @synth - The synthesizer to connect to. - */ - public void bindTo(final MultiChannelSynthesizer synth, final int channel) { - this.setPianoViewListener(new PianoViewListener() { - public void noteDown(double logFrequency, int finger, boolean retriggerIfOn, - float pressure) { - synth.getChannel(channel).setPitch(logFrequency, finger); - synth.getChannel(channel).turnOn(retriggerIfOn, finger); - } - public void noteUp(int finger) { - synth.getChannel(channel).turnOff(finger); - } - }); - } - - /** - * Populated by getTileInfo, these fields will contain the info for a particular key. - */ - private int tileOctave1_; - private int tileOctave2_; - private int tileOctave3_; - private int tileNote1_; - private int tileNote2_; - private int tileNote3_; - private boolean tileIsMajor_; - private boolean tileIsMinor_; - - // The coordinates of the key currently being pressed. - private int pressedColumn_; - private int pressedRow_; - - // The current octave the keyboard is on. - private int firstOctave_; - - // The listener to receive key events. - private PianoViewListener pianoViewListener_; - - // These are basically stack variables for onDraw. They're member variables only so that we can - // avoid reallocating them every time the keyboard is redrawn. - // - // The most recent screen rect that this keyboard was drawn into. - private Rect drawingRect_; - private Path path_; - private Paint strokePaint_; - private Paint fillPaint_; - - private static final int ROWS = 8; - private static final int COLUMNS = 5; -} diff --git a/android/src/com/levien/synthesizer/android/widgets/piano/BlackPianoKey.java b/android/src/com/levien/synthesizer/android/widgets/piano/BlackPianoKey.java deleted file mode 100644 index d88da27..0000000 --- a/android/src/com/levien/synthesizer/android/widgets/piano/BlackPianoKey.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.widgets.piano; - -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Rect; - -import com.levien.synthesizer.core.music.Note; - -/** - * One of the black (non-natural) keys on the piano. - */ -public class BlackPianoKey extends NotePianoKey { - /** - * Creates a new key. - * @param piano - the piano this key is on. - * @param octaveOffset - octave of the key, relative to the leftmost octave of the piano. - * @param key - offset of the key from the start of the octave. - */ - public BlackPianoKey(PianoView piano, int octave, int key) { - super(piano, octave, key); - } - - /** - * Sets rect_ to the position of this key, based on the drawing rect of the piano it's on. - * @param drawingRect - the position of the piano itself. - * @param octaves - the number of octaves visible on the piano keyboard. - */ - public void layout(Rect drawingRect, int octaves) { - int whiteKeyWidth = getWhiteKeyWidth(drawingRect, octaves); - int blackKeyWidth = getBlackKeyWidth(drawingRect, octaves); - rect_.top = 0; - rect_.bottom = rect_.top + getBlackKeyHeight(drawingRect); - rect_.left = ((octaveOffset_ * WHITE_KEYS.length + key_ + 2) * whiteKeyWidth) - - (blackKeyWidth/2); - rect_.right = rect_.left + blackKeyWidth; - } - - /** - * Returns the log frequency of the note of the key. - */ - public double getLogFrequency() { - return Note.computeLog12TET(BLACK_KEYS[key_], octaveOffset_ + piano_.getFirstOctave()); - } - - /** - * Draws the key in the current rect_. - */ - public void draw(Canvas canvas) { - strokePaint_.setColor(Color.BLACK); - if (isPressed()) { - fillPaint_.setColor(Color.GREEN); - } else { - fillPaint_.setColor(Color.BLACK); - } - canvas.drawRect(rect_, fillPaint_); - canvas.drawRect(rect_, strokePaint_); - } - - /** - * Returns true if this is one of the black key positions that should actually have a key. - */ - public static boolean isValid(int note) { - return BLACK_KEYS[note] != Note.NONE; - } - - /** - * Utility function to calculate the width that a standard black key on this keyboard should be. - */ - protected static int getBlackKeyWidth(Rect drawingRect, int octaves) { - return (getWhiteKeyWidth(drawingRect, octaves) * 2) / 3; - } - - /** - * Utility function to calculate the height that a standard black key on this keyboard should be. - */ - protected static int getBlackKeyHeight(Rect drawingRect) { - return getWhiteKeyHeight(drawingRect) / 2; - } -} diff --git a/android/src/com/levien/synthesizer/android/widgets/piano/NotePianoKey.java b/android/src/com/levien/synthesizer/android/widgets/piano/NotePianoKey.java deleted file mode 100644 index 4980458..0000000 --- a/android/src/com/levien/synthesizer/android/widgets/piano/NotePianoKey.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.widgets.piano; - - -/** - * Abstract base class for keys on the piano that play a note when pressed. - */ -public abstract class NotePianoKey extends PianoKey { - /** - * Creates a new key. - * @param piano - the piano this key is on. - * @param octaveOffset - octave of the key, relative to the leftmost octave of the piano. - * @param key - offset of the key from the start of the octave. - */ - public NotePianoKey(PianoView piano, int octaveOffset, int key) { - super(piano); - octaveOffset_ = octaveOffset; - key_ = key; - } - - /** - * Called when the pressed_ state has changed. - */ - protected void onPressedChanged(boolean move) { - } - - /** - * Returns the log frequency of the note of the key. - */ - abstract protected double getLogFrequency(); - - // Octave of the key, relative to the leftmost octave of the piano. - protected int octaveOffset_; - - // Offset of the key from the start of the octave. - protected int key_; -} diff --git a/android/src/com/levien/synthesizer/android/widgets/piano/OctavePianoKey.java b/android/src/com/levien/synthesizer/android/widgets/piano/OctavePianoKey.java deleted file mode 100644 index fe8c31c..0000000 --- a/android/src/com/levien/synthesizer/android/widgets/piano/OctavePianoKey.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.widgets.piano; - - -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Path; -import android.graphics.Rect; - -/** - * A key on the piano for changing the octave up or down. - */ -public class OctavePianoKey extends PianoKey { - /** - * Creates the key. - * @param piano - the piano this key is on. - * @param delta - how the octave should change when this key is pressed. - */ - public OctavePianoKey(PianoView piano, int delta) { - super(piano); - arrow_ = new Path(); - delta_ = delta; - } - - /** - * Sets rect_ to the position of this key, based on the drawing rect of the piano it's on. - * @param drawingRect - the position of the piano itself. - * @param octaves - the number of octaves visible on the piano keyboard. - */ - public void layout(Rect drawingRect, int octaves) { - int whiteKeyWidth = getWhiteKeyWidth(drawingRect, octaves); - rect_.top = 0; - rect_.bottom = getWhiteKeyHeight(drawingRect); - if (delta_ <= 0) { - rect_.left = 0; - rect_.right = rect_.left + whiteKeyWidth; - } else { - rect_.right = drawingRect.right; - rect_.left = rect_.right - whiteKeyWidth; - } - } - - /** - * Returns true if the current octave of the piano could be changed by delta and still be valid. - */ - private boolean isValid() { - return (piano_.getFirstOctave() + delta_ >= 0 && - piano_.getFirstOctave() + piano_.getOctaves() + delta_ <= 8); - } - - /** - * Draws the key in the current rect_. - */ - public void draw(Canvas canvas) { - strokePaint_.setColor(Color.BLACK); - fillPaint_.setColor(Color.BLACK); - if (isPressed() && isValid()) { - fillPaint_.setColor(Color.GREEN); - } - canvas.drawRect(rect_, fillPaint_); - canvas.drawRect(rect_, strokePaint_); - - // Draw an arrow in the direction of the delta. - if (isValid()) { - arrow_.reset(); - if (delta_ <= 0) { - arrow_.moveTo(rect_.left + 2, rect_.height() / 2); - arrow_.lineTo(rect_.right - 2, rect_.height() / 2 - 20); - arrow_.lineTo(rect_.right - 2, rect_.height() / 2 + 20); - } else { - arrow_.moveTo(rect_.right - 2, rect_.height() / 2); - arrow_.lineTo(rect_.left + 2, rect_.height() / 2 - 20); - arrow_.lineTo(rect_.left + 2, rect_.height() / 2 + 20); - } - arrow_.close(); - fillPaint_.setColor(Color.WHITE); - canvas.drawPath(arrow_, fillPaint_); - } - } - - /** - * Called when the pressed_ state has changed. - */ - @Override - protected void onPressedChanged(boolean move) { - if (isPressed() && isValid()) { - piano_.changeOctave(delta_); - } - } - - // This is just used for drawing, but we don't want to pay to reallocate it every time. - private Path arrow_; - - // How the octave should change when this key is pressed. - private int delta_; -} diff --git a/android/src/com/levien/synthesizer/android/widgets/piano/PianoKey.java b/android/src/com/levien/synthesizer/android/widgets/piano/PianoKey.java deleted file mode 100644 index 44e987b..0000000 --- a/android/src/com/levien/synthesizer/android/widgets/piano/PianoKey.java +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.widgets.piano; - -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Rect; -import android.util.Log; - -import com.levien.synthesizer.core.music.Note; - -/** - * PianoKey is the abstract base class for any key on the piano. - * It keeps track of whether the key is currently being pressed. - */ -public abstract class PianoKey { - public PianoKey(PianoView piano) { - piano_ = piano; - pressed_ = new boolean[PianoView.FINGERS]; - rect_ = new Rect(); - - for (int i = 0; i < pressed_.length; ++i) { - pressed_[i] = false; - } - - // Set up some default objects for the key to draw itself with. - fillPaint_ = new Paint(); - strokePaint_ = new Paint(); - fillPaint_.setStyle(Paint.Style.FILL); - strokePaint_.setStyle(Paint.Style.STROKE); - strokePaint_.setColor(Color.BLACK); - float strokeWidth = 1.0f * piano.getResources().getDisplayMetrics().density; - strokePaint_.setStrokeWidth(strokeWidth); - } - - /** - * Sets rect_ to the position of this key, based on the drawing rect of the piano it's on. - * @param drawingRect - the position of the piano itself. - * @param octaves - the number of octaves visible on the piano keyboard. - */ - abstract public void layout(Rect drawingRect, int octaves); - - /** - * Draws the key in the current rect_. - */ - abstract public void draw(Canvas canvas); - - /** - * Called when the key's pressed_ state has changed. - * @param move - true if the key became pressed because the touch moved onto it. - */ - abstract protected void onPressedChanged(boolean move); - - /** - * Returns true if the given co-ordinate is inside the key's current rect_. - */ - public boolean contains(int x_, int y_) { - return rect_.contains(x_, y_); - } - - /** - * Returns true if any finger is pressing this key. - */ - public boolean isPressed() { - for (int i = 0; i < pressed_.length; ++i) { - if (pressed_[i]) { - return true; - } - } - return false; - } - - /** - * Called when a finger has touched down onto this key. - * Returns true iff whether the pressed state changed. - */ - final public boolean onTouchDown(int finger) { - if (finger >= pressed_.length) { - Log.e(getClass().getName(), - "Finger " + finger + " was pressed down, but PianoKey only supports " + - pressed_.length + " fingers."); - } - boolean wasPressed = isPressed(); - pressed_[finger] = true; - if (!wasPressed) { - onPressedChanged(false); - return true; - } - return false; - } - - /** - * Called on a touch event where this key is not being touched. It may already be up. - * Returns true iff whether the pressed state changed. - */ - final public boolean onTouchUp(int finger) { - if (finger >= pressed_.length) { - Log.e(getClass().getName(), - "Finger " + finger + " was released, but PianoKey only supports " + - pressed_.length + " fingers."); - } - boolean wasPressed = isPressed(); - pressed_[finger] = false; - boolean isPressed = isPressed(); - if (wasPressed && !isPressed) { - onPressedChanged(false); - return true; - } - return false; - } - - /** - * Called when there's a touch event where the finger was moved onto this key. - * Returns true iff whether the pressed state changed. - */ - final public boolean onTouchMoved(int finger) { - if (finger >= pressed_.length) { - Log.e(getClass().getName(), - "Finger " + finger + " was pressed down, but PianoKey only supports " + - pressed_.length + " fingers."); - } - boolean wasPressed = isPressed(); - pressed_[finger] = true; - if (!wasPressed) { - onPressedChanged(true); - return true; - } - return false; - } - - /** - * Utility function to calculate the width that a standard white key on this keyboard should be. - */ - protected static int getWhiteKeyWidth(Rect drawingRect, int octaves) { - // It's +2 to reserve space for the octave-up/down buttons. - return drawingRect.width() / ((WHITE_KEYS.length * octaves) + 2); - } - - /** - * Utility function to calculate the height that a standard white key on this keyboard should be. - */ - protected static int getWhiteKeyHeight(Rect drawingRect) { - return drawingRect.height(); - } - - // The piano this key is on. - protected PianoView piano_; - - // Is each keys currently being pressed? - protected boolean[] pressed_; - - // The area this key occupies. - protected Rect rect_; - - // Objects for subclasses to use for painting, just so they don't have to reallocate every time. - protected Paint fillPaint_; - protected Paint strokePaint_; - - // Constants to map notes onto the keys. - protected static final int WHITE_KEYS[] = { - Note.C, Note.D, Note.E, Note.F, Note.G, Note.A, Note.B }; - protected static final int BLACK_KEYS[] = { - Note.C_SHARP, Note.E_FLAT, Note.NONE, Note.F_SHARP, Note.A_FLAT, Note.B_FLAT, Note.NONE }; -} diff --git a/android/src/com/levien/synthesizer/android/widgets/piano/PianoView.java b/android/src/com/levien/synthesizer/android/widgets/piano/PianoView.java deleted file mode 100644 index d1b9d62..0000000 --- a/android/src/com/levien/synthesizer/android/widgets/piano/PianoView.java +++ /dev/null @@ -1,458 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.widgets.piano; - -import java.util.HashMap; -import java.util.Map; - -import android.content.Context; -import android.content.res.TypedArray; -import android.graphics.Canvas; -import android.graphics.Rect; -import android.util.AttributeSet; -import android.util.Log; -import android.view.MotionEvent; -import android.view.View; - -import com.levien.synthesizer.R; -import com.levien.synthesizer.core.midi.MidiListener; -import com.levien.synthesizer.core.model.composite.MultiChannelSynthesizer; -import com.levien.synthesizer.core.music.Note; - -/** - * PianoView is a UI widget that simulates a music keyboard. - */ -public class PianoView extends View { - /** - * Basic android widget constructor. - */ - public PianoView(Context context, AttributeSet attrs) { - super(context, attrs); - - // Get the xml attributes for this instance. - TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PianoView); - octaves_ = a.getInteger(R.styleable.PianoView_octaves, 1); - firstOctave_ = a.getInteger(R.styleable.PianoView_first_octave, 4); - a.recycle(); - - // Set up basic drawing structs, just so we don't have to allocate this later when we draw. - drawingRect_ = new Rect(); - - // Generate the set of keys. There are 12 music keys per octave, plus the octave change button - // on either end. - keys_ = new PianoKey[12 * octaves_ + 2]; - int key = 0; - - // Create the white keys. - for (int octave = 0; octave < octaves_; ++octave) { - for (int note = 0; note < 7; ++note) { - keys_[key++] = new WhitePianoKey(this, octave, note); - } - } - - // Create the black keys. - for (int octave = 0; octave < octaves_; ++octave) { - for (int note = 0; note < 7; ++note) { - if (BlackPianoKey.isValid(note)) { - keys_[key++] = new BlackPianoKey(this, octave, note); - } - } - } - - // Create the octave changing keys. - keys_[key++] = new OctavePianoKey(this, -1); - keys_[key++] = new OctavePianoKey(this, 1); - - // The listener will have to be set later. - pianoViewListener_ = null; - } - - /** - * Returns the absolute octave of the left-most key. - */ - public int getFirstOctave() { - return firstOctave_; - } - - /** - * Returns the number of octaves covered by all of the keys. - */ - public int getOctaves() { - return octaves_; - } - - /** - * Shifts the octave of all of the keys. - * @param delta - The number (and direction) of octaves to shift by. - */ - public void changeOctave(int delta) { - firstOctave_ += delta; - } - - /** - * Sets the listener that will receive events from this widget. - */ - public void setPianoViewListener(PianoViewListener pianoViewListener) { - pianoViewListener_ = pianoViewListener; - } - - /** - * Signals the listener that a new note was pressed. - * @param logFrequency - the log frequency of the new note. - * @param retriggerIfOn - true if this is a new touch, rather than just moving. - */ - private void notifyNoteDown(double logFrequency, int finger, boolean retriggerIfOn, - float pressure) { - if (pianoViewListener_ != null) { - pianoViewListener_.noteDown(logFrequency, finger, retriggerIfOn, pressure); - } - } - - /** - * Signals the listener that a note was released. - */ - private void notifyNoteUp(int finger) { - if (pianoViewListener_ != null) { - pianoViewListener_.noteUp(finger); - } - } - - /** - * Draws the widget. - */ - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - getDrawingRect(drawingRect_); - for (int i = 0; i < keys_.length; ++i) { - keys_[i].layout(drawingRect_, octaves_); - } - for (int i = 0; i < keys_.length; ++i) { - keys_[i].draw(canvas); - } - } - - /** - * Called to handle touch down events. - * Returns true iff we need to redraw. - */ - protected boolean onTouchDown(int finger, int x, int y, float pressure) { - // Look through keys from top to bottom, and set the first one found as down, the rest as up. - PianoKey keyDown = null; - boolean redraw = false; - for (int i = keys_.length - 1; i >= 0; --i) { - if (keyDown != null) { - // If we already found a key that's being touched, then none of the rest can be. - redraw |= keys_[i].onTouchUp(finger); - } else if (keys_[i].contains(x, y)) { - // This key is being touched. - redraw |= keys_[i].onTouchDown(finger); - keyDown = keys_[i]; - } else { - // This key is not being touched. - redraw |= keys_[i].onTouchUp(finger); - } - } - if (!usePressure_) { - pressure = 0.5f; - } - if (keyDown instanceof NotePianoKey) { - notifyNoteDown(((NotePianoKey)keyDown).getLogFrequency(), finger, true, pressure); - } - return redraw; - } - - /** - * Called to handle touch move events. - */ - protected boolean onTouchMove(int finger, int x, int y, float pressure) { - // Look through keys from top to bottom, and set the first one found as moved, the rest as up. - PianoKey keyDown = null; - boolean redraw = false; - boolean wasPressed = false; - for (int i = keys_.length - 1; i >= 0; --i) { - if (keyDown != null) { - // If we already found a key that's being touched, then none of the rest can be. - redraw |= keys_[i].onTouchUp(finger); - } else if (keys_[i].contains(x, y)) { - // This key is being pressed. - wasPressed = keys_[i].isPressed(); - redraw |= keys_[i].onTouchMoved(finger); - keyDown = keys_[i]; - } else { - // This key is not being pressed. - redraw |= keys_[i].onTouchUp(finger); - } - } - if (keyDown instanceof NotePianoKey) { - if (!usePressure_) { - pressure = 0.5f; - } - if (!wasPressed) { - notifyNoteDown(((NotePianoKey)keyDown).getLogFrequency(), finger, false, pressure); - } - } else { - notifyNoteUp(finger); - } - return redraw; - } - - /** - * Called to handle touch up events. - */ - protected boolean onTouchUp(int finger) { - // Set all keys as up. - boolean redraw = false; - for (int i = 0; i < keys_.length; ++i) { - redraw |= keys_[i].onTouchUp(finger); - } - notifyNoteUp(finger); - return redraw; - } - - - /** - * Handler for all touch events. - */ - @Override - public boolean onTouchEvent(MotionEvent event) { - int action = event.getAction(); - int actionCode = action & MotionEvent.ACTION_MASK; - //Log.i("synth", "actionCode = " + actionCode); - boolean redraw = false; - if (actionCode == MotionEvent.ACTION_DOWN) { - int pointerId = event.getPointerId(0); - if (pointerId < FINGERS) { - int x = (int)event.getX(); - int y = (int)event.getY(); - float pressure = event.getPressure(); - redraw |= onTouchDown(pointerId, x, y, pressure); - } else { - Log.i("synth", "Discarded ACTION_DOWN pointerId=" + pointerId); - } - } else if (actionCode == MotionEvent.ACTION_POINTER_DOWN) { - int pointerIndex = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) - >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; - int pointerId = event.getPointerId(pointerIndex); - if (pointerId < FINGERS && pointerId >= 0) { - int x = (int)event.getX(pointerIndex); - int y = (int)event.getY(pointerIndex); - float pressure = event.getPressure(pointerIndex); - redraw |= onTouchDown(pointerId, x, y, pressure); - } else { - Log.i("synth", "Discarded ACTION_POINTER_DOWN pointerId=" + pointerId); - } - } else if (actionCode == MotionEvent.ACTION_MOVE) { - for (int pointerIndex = 0; pointerIndex < event.getPointerCount(); ++pointerIndex) { - int pointerId = event.getPointerId(pointerIndex); - if (pointerId >= FINGERS) { - continue; - } - if (pointerIndex >= 0) { - int x = (int)event.getX(pointerIndex); - int y = (int)event.getY(pointerIndex); - float pressure = event.getPressure(pointerIndex); - redraw |= onTouchMove(pointerId, x, y, pressure); - } - } - } else if (actionCode == MotionEvent.ACTION_UP) { - int pointerId = event.getPointerId(0); - if (pointerId < FINGERS) { - redraw |= onTouchUp(pointerId); - } - // Clean up any other pointers that have disappeared. - for (pointerId = 0; pointerId < FINGERS; ++pointerId) { - boolean found = false; - for (int pointerIndex = 0; pointerIndex < event.getPointerCount(); ++pointerIndex) { - if (pointerId == event.getPointerId(pointerIndex)) { - found = true; - break; - } - } - if (!found) { - boolean thisRedraw = onTouchUp(pointerId); - if (thisRedraw) { - Log.i("synth", "ACTION_UP cleaned up pointerId=" + pointerId); - } - redraw |= thisRedraw; - } - } - } else if (actionCode == MotionEvent.ACTION_POINTER_UP) { - int pointerIndex = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; - int pointerId = event.getPointerId(pointerIndex); - if (pointerId < FINGERS) { - redraw |= onTouchUp(pointerId); - } - // Clean up any other pointers that have disappeared. Note: this is probably not necessary. - for (pointerId = 0; pointerId < FINGERS; ++pointerId) { - boolean found = false; - for (pointerIndex = 0; pointerIndex < event.getPointerCount(); ++pointerIndex) { - if (pointerId == event.getPointerId(pointerIndex)) { - found = true; - break; - } - } - if (!found) { - boolean thisRedraw = onTouchUp(pointerId); - if (thisRedraw) { - Log.i("synth", "ACTION_POINTER_UP cleaned up pointerId=" + pointerId); - } - redraw |= thisRedraw; - } - } - } else { - return super.onTouchEvent(event); - } - if (redraw) { - invalidate(); - } - return true; - } - - /** - * Layout measurement for this widget. - * This method just sets a basic minimum size and makes the widget maximized otherwise. - */ - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int widthMode = MeasureSpec.getMode(widthMeasureSpec); - int widthSize = MeasureSpec.getSize(widthMeasureSpec); - int heightMode = MeasureSpec.getMode(heightMeasureSpec); - int heightSize = MeasureSpec.getSize(heightMeasureSpec); - - int width = 0; - int height = 0; - - switch (widthMode) { - case MeasureSpec.EXACTLY: - width = widthSize; - break; - case MeasureSpec.AT_MOST: - width = widthSize; - break; - case MeasureSpec.UNSPECIFIED: - width = 10; - break; - } - - switch (heightMode) { - case MeasureSpec.EXACTLY: - height = heightSize; - break; - case MeasureSpec.AT_MOST: - height = heightSize; - break; - case MeasureSpec.UNSPECIFIED: - height = 10; - break; - } - - setMeasuredDimension(width, height); - } - - /** - * Connects the PianoView to a Synthesizer. - * @synth - The synthesizer to connect to. - * @channel - Which of the synthesizer's channels to bind to. - */ - public void bindTo(final MultiChannelSynthesizer synth, final int channel) { - this.setPianoViewListener(new PianoViewListener() { - public void noteDown(double logFrequency, int finger, boolean retriggerIfOn, - float pressure) { - synth.getChannel(channel).setPitch(logFrequency, finger); - synth.getChannel(channel).turnOn(retriggerIfOn, finger); - } - public void noteUp(int finger) { - synth.getChannel(channel).turnOff(finger); - } - }); - } - - /** - * Connects the PianoView to an MidiListener. - */ - public void bindTo(final MidiListener midiListener) { - this.setPianoViewListener(new PianoViewListener() { - { - fingerMap_ = new HashMap(); - } - public void noteDown(double logFrequency, int finger, boolean retriggerIfOn, - float pressure) { - noteUp(finger); - int midiNote = Note.getKeyforLog12TET(logFrequency); - fingerMap_.put(finger, midiNote); - int midiPressure = Math.max(1, Math.min(127, (int)(127 * pressure))); - midiListener.onNoteOn(0, midiNote, midiPressure); - } - public void noteUp(int finger) { - if (fingerMap_.containsKey(finger)) { - int midiNote = fingerMap_.get(finger); - fingerMap_.remove(finger); - midiListener.onNoteOff(0, midiNote, 64); - } - } - private Map fingerMap_; - }); - } - - public void setNoteOn(int note, boolean on) { - // This is somewhat painful, hopefully can be done better. - for (int i = 0; i < keys_.length; i++) { - PianoKey key = keys_[i]; - if (key instanceof NotePianoKey) { - int midiNote = Note.getKeyforLog12TET(((NotePianoKey) key).getLogFrequency()); - if (midiNote == note) { - boolean redraw; - if (on) { - // using the last finger is something of a hack - redraw = key.onTouchDown(FINGERS - 1); - } else { - redraw = key.onTouchUp(FINGERS - 1); - } - if (redraw) { - invalidate(); - } - break; - } - } - } - } - - // The most recent screen rect that this keyboard was drawn into. - // - // This is basically a stack variable for onDraw. It's a member variable only so that we can - // avoid reallocating them every time the keyboard is redrawn. - private Rect drawingRect_; - - // The set of keys on the keyboard. - private PianoKey[] keys_; - - // The current octave the keyboard is on. - private int firstOctave_; - - // The total number of octaves the keyboard displays at any one time. - private final int octaves_; - - // The listener to receive key events. - private PianoViewListener pianoViewListener_; - - // The number of simultaneous fingers supported by this control. - protected static final int FINGERS = 10; - - // Whether to use pressure (doesn't work well on all hardware) - private boolean usePressure_ = false; -} diff --git a/android/src/com/levien/synthesizer/android/widgets/piano/PianoViewListener.java b/android/src/com/levien/synthesizer/android/widgets/piano/PianoViewListener.java deleted file mode 100644 index 258f422..0000000 --- a/android/src/com/levien/synthesizer/android/widgets/piano/PianoViewListener.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.widgets.piano; - -// Simple interface for listening to piano widget events. -public interface PianoViewListener { - /** - * A note was pressed. - * @param logFrequency - the log frequency of the note pressed. - * @param retriggerIfOn - true if this is a new touch, rather than just moving. - */ - void noteDown(double logFrequency, int finger, boolean retriggerIfOn, float pressure); - - /** - * The note was released. - */ - void noteUp(int finger); -} diff --git a/android/src/com/levien/synthesizer/android/widgets/piano/WhitePianoKey.java b/android/src/com/levien/synthesizer/android/widgets/piano/WhitePianoKey.java deleted file mode 100644 index 4ab7909..0000000 --- a/android/src/com/levien/synthesizer/android/widgets/piano/WhitePianoKey.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.widgets.piano; - -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Rect; - -import com.levien.synthesizer.core.music.Note; - -/** - * A white key on the piano. - */ -public class WhitePianoKey extends NotePianoKey { - /** - * Creates a new key. - * @param piano - the piano this key is on. - * @param octaveOffset - octave of the key, relative to the leftmost octave of the piano. - * @param key - offset of the key from the start of the octave. - */ - public WhitePianoKey(PianoView piano, int octave, int key) { - super(piano, octave, key); - } - - /** - * Sets rect_ to the position of this key, based on the drawing rect of the piano it's on. - * @param drawingRect - the position of the piano itself. - * @param octaves - the number of octaves visible on the piano keyboard. - */ - public void layout(Rect drawingRect, int octaves) { - int whiteKeyWidth = getWhiteKeyWidth(drawingRect, octaves); - rect_.top = 0; - rect_.bottom = getWhiteKeyHeight(drawingRect); - rect_.left = ((octaveOffset_ * WHITE_KEYS.length + key_ + 1) * whiteKeyWidth); - rect_.right = rect_.left + whiteKeyWidth; - } - - /** - * Returns the log frequency of the note of the key. - */ - public double getLogFrequency() { - return Note.computeLog12TET(WHITE_KEYS[key_], octaveOffset_ + piano_.getFirstOctave()); - } - - /** - * Draws the key in the current rect_. - */ - public void draw(Canvas canvas) { - strokePaint_.setColor(Color.BLACK); - if (isPressed()) { - fillPaint_.setColor(Color.GREEN); - } else { - fillPaint_.setColor(Color.WHITE); - } - canvas.drawRect(rect_, fillPaint_); - canvas.drawRect(rect_, strokePaint_); - } -} diff --git a/android/src/com/levien/synthesizer/android/widgets/score/EditEventTool.java b/android/src/com/levien/synthesizer/android/widgets/score/EditEventTool.java deleted file mode 100644 index b3ea9e4..0000000 --- a/android/src/com/levien/synthesizer/android/widgets/score/EditEventTool.java +++ /dev/null @@ -1,490 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.widgets.score; - -import java.util.logging.Logger; - -import com.levien.synthesizer.R; -import com.levien.synthesizer.core.music.Music.Event; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Path; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; -import android.view.MotionEvent; - -/** - * A tool for editing the events in a score. If the user touches an event, they can move it or - * resize it. If the event is already selected, all selected events will be moved or resized in the - * same way. If the user touches outside any events, a selection rectangle allows them to select - * one or more events. - */ -public class EditEventTool extends ScoreViewTool { - /** - * Creates a new EditEventTool with the given context for loading resources. - */ - EditEventTool(Context context) { - logger_ = Logger.getLogger(getClass().getName()); - - // Set up basic drawing structs, just so we don't have to allocate this later when we draw. - paint_ = new Paint(); - path_ = new Path(); - - selection_ = new Rect(); - - trashVisible_ = false; - trashRect_ = new Rect(); - trashIcon_ = context.getResources().getDrawable(R.drawable.trash); - - icon_ = context.getResources().getDrawable(R.drawable.arrow); - } - - /** - * Starts this tool editing a particular event, and sets it to invoke another tool when done. - * Called by NewEventTool to handle sizing the tool as it's being created. - * @param view - The ScoreView for this tool. - * @param event - The event to start editing. - * @param physicalX - The current x of the user's finger, in screen coordinates. - * @param physicalY -The current y of the user's finger, in screen coordinates. - * @param nextTool - The tool to select when the user is done editing this event. (on touch up) - */ - public void pickupEvent(ScoreView view, - Event.Builder event, - int physicalX, - int physicalY, - ScoreViewTool nextTool) { - // Save the tool to bring up after this operation is complete. - nextTool_ = nextTool; - - // De-select everything. - for (int j = 0; j < view.getScore().getEventCount(); ++j) { - view.getScore().getEventBuilder(j).setSelected(false); - } - // Select just the one that was picked up. - event.setSelected(true); - mode_ = RESIZING_RIGHT; - - // Make sure to snap the event. - if (!event.hasUnsnappedStart()) { - event.setUnsnappedStart(event.getStart()); - } - if (!event.hasUnsnappedEnd()) { - event.setUnsnappedEnd(event.getEnd()); - } - if (view.getSnapTo() != 0) { - event.setStart(((int)(event.getUnsnappedStart() / view.getSnapTo())) * view.getSnapTo()); - event.setEnd(((int)(event.getUnsnappedEnd() / view.getSnapTo())) * view.getSnapTo()); - } else { - event.setStart(event.getUnsnappedStart()); - event.setEnd(event.getUnsnappedEnd()); - } - - // Store the coordinates where it was picked up. - double time = view.getTimeAt(physicalX); - double note = view.getNoteAt(physicalY); - previousTime_ = time; - previousNote_ = note; - } - - /** - * Draws the button on the toolbar. - * @param canvas - The canvas to draw the button on. - * @param score - The ScoreView that this toolbar is for. - * @param rect - The area of the button to be drawn, including any margin. - * @param margin - The preferred margin around the button, in screen coordinates. - */ - @Override - public void drawButton(Canvas canvas, ScoreView score, Rect rect, float margin) { - if (score.getTool() == this) { - paint_.setColor(Color.WHITE); - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(rect.left - margin / 2, - rect.top - margin / 2, - rect.right + margin / 2, - rect.bottom + margin / 2, - paint_); - } - - paint_.setColor(Color.BLACK); - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(rect, paint_); - icon_.setBounds(rect); - icon_.draw(canvas); - } - - /** - * Called on finger down. - */ - private void onTouchDown(ScoreView view, int physicalX, int physicalY) { - double time = view.getTimeAt(physicalX); - double note = view.getNoteAt(physicalY); - - // When we're done editing this item, this tool stays selected. - nextTool_ = this; - - // See if there's an event being touched. - Event.Builder event = view.getEventAt(physicalX, physicalY); - if (event != null) { - if (!event.getSelected()) { - // De-select everything. - for (int j = 0; j < view.getScore().getEventCount(); ++j) { - view.getScore().getEventBuilder(j).setSelected(false); - } - // Select just the one that was pressed. - event.setSelected(true); - } - - // Compute the handle size. - int physicalHandleSize = view.getNoteY(0) - view.getNoteY(1); - double handleWidth = view.getTimeAt(physicalHandleSize) - view.getTimeAt(0); - boolean largeEnough = event.getEnd() - event.getStart() > handleWidth * 2; - - // See if any handle was touched. - if (largeEnough && time <= event.getStart() + handleWidth) { - mode_ = RESIZING_LEFT; - } else if (largeEnough && time >= event.getEnd() - handleWidth) { - mode_ = RESIZING_RIGHT; - } else { - mode_ = MOVING; - } - } else { - // De-select everything. - for (int j = 0; j < view.getScore().getEventCount(); ++j) { - view.getScore().getEventBuilder(j).setSelected(false); - } - - selection_.left = physicalX; - selection_.right = physicalX; - selection_.top = physicalY; - selection_.bottom = physicalY; - - mode_ = SELECTING; - } - view.invalidate(); - previousTime_ = time; - previousNote_ = note; - } - - /** - * Called on finger movements. - */ - private void onTouchMove(ScoreView view, int physicalX, int physicalY) { - double time = view.getTimeAt(physicalX); - double note = view.getNoteAt(physicalY); - double deltaTime = time - previousTime_; - double deltaNote = note - previousNote_; - switch (mode_) { - case RESIZING_RIGHT: { - for (int i = 0; i < view.getScore().getEventCount(); ++i) { - Event.Builder event = view.getScore().getEventBuilder(i); - if (!event.getSelected()) { - continue; - } - - if (!event.hasUnsnappedEnd()) { - event.setUnsnappedEnd(event.getEnd()); - } - event.setUnsnappedEnd(event.getUnsnappedEnd() + deltaTime); - if (view.getSnapTo() != 0) { - event.setEnd(((int)(event.getUnsnappedEnd() / view.getSnapTo())) * view.getSnapTo()); - } else { - event.setEnd(event.getUnsnappedEnd()); - } - - if (event.getEnd() <= event.getStart()) { - event.setEnd(event.getStart() + 1/32.0f); - } - } - break; - } - case RESIZING_LEFT: { - for (int i = 0; i < view.getScore().getEventCount(); ++i) { - Event.Builder event = view.getScore().getEventBuilder(i); - if (!event.getSelected()) { - continue; - } - - if (!event.hasUnsnappedStart()) { - event.setUnsnappedStart(event.getStart()); - } - event.setUnsnappedStart(event.getUnsnappedStart() + deltaTime); - if (view.getSnapTo() != 0) { - event.setStart(((int)(event.getUnsnappedStart() / view.getSnapTo())) * view.getSnapTo()); - } else { - event.setStart(event.getUnsnappedStart()); - } - - if (event.getStart() >= event.getEnd()) { - event.setEnd(event.getEnd() - 1/32.0f); - } - } - break; - } - case MOVING: { - for (int i = 0; i < view.getScore().getEventCount(); ++i) { - Event.Builder event = view.getScore().getEventBuilder(i); - if (!event.getSelected()) { - continue; - } - - if (!event.hasUnsnappedStart()) { - event.setUnsnappedStart(event.getStart()); - } - event.setUnsnappedStart(event.getUnsnappedStart() + deltaTime); - if (view.getSnapTo() != 0) { - event.setStart(((int)(event.getUnsnappedStart() / view.getSnapTo())) * - view.getSnapTo()); - } else { - event.setStart(event.getUnsnappedStart()); - } - - if (!event.hasUnsnappedEnd()) { - event.setUnsnappedEnd(event.getEnd()); - } - event.setUnsnappedEnd(event.getUnsnappedEnd() + deltaTime); - if (view.getSnapTo() != 0) { - event.setEnd(((int)(event.getUnsnappedEnd() / view.getSnapTo())) * view.getSnapTo()); - } else { - event.setEnd(event.getUnsnappedEnd()); - } - - if (event.getEnd() <= event.getStart()) { - event.setEnd(event.getStart() + 1/32.0f); - } - - if (!event.hasUnsnappedKey()) { - event.setUnsnappedKey(event.getKey()); - } - event.setUnsnappedKey(event.getUnsnappedKey() + deltaNote); - event.setKey((int)event.getUnsnappedKey()); - - trashVisible_ = true; - trashRect_.top = view.getDrawingRect().top; - trashRect_.bottom = view.getDrawingRect().top + - Math.max(200, trashIcon_.getIntrinsicHeight()); - trashRect_.left = view.getDrawingRect().right - - Math.max(200, trashIcon_.getIntrinsicWidth()); - trashRect_.right = view.getDrawingRect().right; - trashIcon_.setBounds(trashRect_); - } - break; - } - case SELECTING: { - // Update the selection rectangle. - selection_.right = physicalX; - selection_.bottom = physicalY; - - // Update event selections. - for (int i = 0; i < view.getScore().getEventCount(); ++i) { - Event.Builder event = view.getScore().getEventBuilder(i); - if (selection_.intersects(view.getTimeX(event.getStart()), - view.getNoteY(event.getKey() + 1), - view.getTimeX(event.getEnd()), - view.getNoteY(event.getKey()))) { - view.getScore().getEventBuilder(i).setSelected(true); - } else { - view.getScore().getEventBuilder(i).setSelected(false); - } - } - - break; - } - } - view.invalidate(); - previousTime_ = time; - previousNote_ = note; - } - - /** - * Called on finger up. - */ - private void onTouchUp(ScoreView view, int physicalX, int physicalY) { - trashVisible_ = false; - - if (trashRect_.contains(physicalX, physicalY)) { - for (int i = view.getScore().getEventCount() - 1; i >= 0; --i) { - if (view.getScore().getEventBuilder(i).getSelected()) { - view.getScore().removeEvent(i); - } - } - } - - // Make all snapping permanent. - for (int i = 0; i < view.getScore().getEventCount(); ++i) { - Event.Builder event = view.getScore().getEventBuilder(i); - event.clearUnsnappedStart(); - event.clearUnsnappedEnd(); - event.clearUnsnappedKey(); - } - - mode_ = NONE; - view.setTool(nextTool_); - - view.invalidate(); - } - - /** - * Called when the user touches the ScoreView while this tool is selected. - * @param view - The ScoreView that this tool is for. - * @param event - The touch event that triggered this handler. - * @return true iff this tool handled the touch event. - */ - @Override - public boolean onTouch(ScoreView view, MotionEvent event) { - int action = event.getAction(); - int actionCode = action & MotionEvent.ACTION_MASK; - if (actionCode == MotionEvent.ACTION_DOWN) { - pointerId_ = event.getPointerId(0); - onTouchDown(view, (int)event.getX(), (int)event.getY()); - return true; - } else if (actionCode == MotionEvent.ACTION_POINTER_DOWN) { - return false; - } else if (actionCode == MotionEvent.ACTION_MOVE) { - // Find the current positions of the fingers. - for (int pointerIndex = 0; pointerIndex < event.getPointerCount(); ++pointerIndex) { - int pointerId = event.getPointerId(pointerIndex); - if (pointerId >= 0 && pointerId == pointerId_) { - int physicalX = (int)event.getX(pointerIndex); - int physicalY = (int)event.getY(pointerIndex); - onTouchMove(view, physicalX, physicalY); - return true; - } - } - return false; - } else if (actionCode == MotionEvent.ACTION_UP) { - onTouchUp(view, (int)event.getX(), (int)event.getY()); - return true; - } else if (actionCode == MotionEvent.ACTION_POINTER_UP) { - return false; - } else { - return false; - } - } - - /** - * Called after each event is drawn, to give this tool a chance to draw over it. - * See ScoreView.onDraw() for more information on how ScoreView is drawn. - * @param event - The event that was drawn. - * @param canvas - The canvas the key is drawn into. - * @param rect - The area of the key on the canvas. - */ - @Override - public void afterDrawEvent(Event event, - Canvas canvas, - Rect rect) { - if (rect.right >= rect.left + rect.height() * 2) { - // Draw left arrow. - float margin = 1.0f; - paint_.setStrokeWidth(1.0f); - paint_.setStyle(Paint.Style.STROKE); - if (event.hasKeyEvent()) { - paint_.setColor(Color.BLACK); - } else { - paint_.setColor(Color.WHITE); - } - canvas.drawRect(rect.left, rect.top, - rect.left + rect.height(), rect.top + rect.height(), - paint_); - paint_.setStyle(Paint.Style.FILL); - path_.reset(); - path_.moveTo(rect.left + rect.height() - margin, rect.top + margin); - path_.lineTo(rect.left + rect.height() - margin, rect.bottom - margin); - path_.lineTo(rect.left + margin, (rect.top + rect.bottom) / 2.0f); - path_.close(); - canvas.drawPath(path_, paint_); - - // Draw right arrow. - paint_.setStyle(Paint.Style.STROKE); - if (event.hasKeyEvent()) { - paint_.setColor(Color.BLACK); - } else { - paint_.setColor(Color.WHITE); - } - canvas.drawRect(rect.right - rect.height(), rect.top, rect.right, rect.bottom, paint_); - paint_.setStyle(Paint.Style.FILL); - path_.reset(); - path_.moveTo(rect.right - (rect.height() - (margin + 1)), rect.top + margin); - path_.lineTo(rect.right - (rect.height() - (margin + 1)), rect.bottom - margin); - path_.lineTo(rect.right - margin, (rect.top + rect.bottom) / 2.0f); - path_.close(); - canvas.drawPath(path_, paint_); - } - } - - /** - * Called after the entire score is drawn, to give this tool a chance to draw over it. - * Draws the selection box, and possibly the trash icon. - * See ScoreView.onDraw() for more information on how ScoreView is drawn. - * @param view - The ScoreView being drawn. - * @param canvas - The canvas the key is drawn into. - * @param rect - The area of the key on the canvas. - */ - @Override - public void afterDrawScore(ScoreView view, Canvas canvas, Rect rect) { - if (mode_ == SELECTING) { - paint_.setStyle(Paint.Style.FILL); - paint_.setColor(Color.CYAN); - paint_.setAlpha(127); - canvas.drawRect(selection_, paint_); - paint_.setAlpha(255); - } - - // Draw the trash can. - if (trashVisible_) { - trashIcon_.draw(canvas); - } - } - - // The id of the finger doing the editing. - private int pointerId_; - - // The most recent previous position of the finger. - private double previousTime_; - private double previousNote_; - - // A tool to select the next time the user finishes editing an event. - // Can be "this", but not null. - private ScoreViewTool nextTool_; - - // While the user is drawing a selection rectangle, this is it, in screen (physical) coordinates. - private Rect selection_; - - // Some objects used in drawing. They are owned here so that they don't have to be reallocated - // and garbage collected for every pass of drawing. - protected Paint paint_; - protected Path path_; - private Drawable icon_; - - // The mode of the tool, depending mostly on where the user's finger was when they first touched. - private int mode_; - private static final int NONE = 0; - private static final int RESIZING_LEFT = 1; - private static final int RESIZING_RIGHT = 2; - private static final int MOVING = 3; - private static final int SELECTING = 4; - - // Members for controlling how the trash can icon gets drawn while moving events. - private boolean trashVisible_; - private Rect trashRect_; // in screen (physical) coordinates. - private Drawable trashIcon_; - - @SuppressWarnings("unused") - private Logger logger_; -} diff --git a/android/src/com/levien/synthesizer/android/widgets/score/HideChannelButton.java b/android/src/com/levien/synthesizer/android/widgets/score/HideChannelButton.java deleted file mode 100644 index b8bd815..0000000 --- a/android/src/com/levien/synthesizer/android/widgets/score/HideChannelButton.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.widgets.score; - -import java.util.logging.Logger; - -import com.levien.synthesizer.R; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; - -/** - * A button that toggles between showing the events for all of the synthesizer channels or showing - * just the currently selected channel. - */ -public class HideChannelButton extends ScoreViewTool { - /** - * Creates a new HideChannelButton, using the given context for loading resources. - */ - HideChannelButton(Context context) { - logger_ = Logger.getLogger(getClass().getName()); - - visibleIcon_ = context.getResources().getDrawable(R.drawable.open_eye); - hiddenIcon_ = context.getResources().getDrawable(R.drawable.closed_eye); - paint_ = new Paint(); - } - - /** - * Called when this tool is selected. - * Changes the channel visibility and then reselects the previous tool. - * @param view - The ScoreView that this toolbar is for. - * @param previousTool - The tool that was selected when this one was chosen. - */ - @Override - public void onSelect(ScoreView view, ScoreViewTool previousTool) { - view.setOtherChannelsVisible(!view.getOtherChannelsVisible()); - view.setTool(previousTool); - } - - /** - * Draws the button on the toolbar. - * @param canvas - The canvas to draw the button on. - * @param score - The ScoreView that this toolbar is for. - * @param rect - The area of the button to be drawn, including any margin. - * @param margin - The preferred margin around the button, in screen coordinates. - */ - @Override - public void drawButton(Canvas canvas, ScoreView score, Rect rect, float margin) { - if (score.getTool() == this) { - paint_.setColor(Color.WHITE); - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(rect.left - margin / 2, - rect.top - margin / 2, - rect.right + margin / 2, - rect.bottom + margin / 2, - paint_); - } - - paint_.setColor(Color.BLACK); - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(rect, paint_); - if (score.getOtherChannelsVisible()) { - visibleIcon_.setBounds(rect); - visibleIcon_.draw(canvas); - } else { - hiddenIcon_.setBounds(rect); - hiddenIcon_.draw(canvas); - } - } - - // Some objects used in drawing. They are owned here so that they don't have to be reallocated - // and garbage collected for every pass of drawing. - private Paint paint_; - private Drawable visibleIcon_; - private Drawable hiddenIcon_; - - @SuppressWarnings("unused") - private Logger logger_; -} diff --git a/android/src/com/levien/synthesizer/android/widgets/score/NewEventTool.java b/android/src/com/levien/synthesizer/android/widgets/score/NewEventTool.java deleted file mode 100644 index 3179a23..0000000 --- a/android/src/com/levien/synthesizer/android/widgets/score/NewEventTool.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.widgets.score; - -import java.util.logging.Logger; - -import com.levien.synthesizer.R; -import com.levien.synthesizer.core.music.Music.Event; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; -import android.view.MotionEvent; - -/** - * A tool for creating new events in the score. - */ -public class NewEventTool extends ScoreViewTool { - /** - * Creates a new NewEventTool. - * @param context - The context to use for loading resources. - * @param eventTool - The tool to use for editing the event as it's created. - */ - NewEventTool(Context context, EditEventTool eventTool) { - logger_ = Logger.getLogger(getClass().getName()); - eventTool_ = eventTool; - - icon_ = context.getResources().getDrawable(R.drawable.add); - paint_ = new Paint(); - } - - /** - * Draws the button on the toolbar. - * @param canvas - The canvas to draw the button on. - * @param score - The ScoreView that this toolbar is for. - * @param rect - The area of the button to be drawn, including any margin. - * @param margin - The preferred margin around the button, in screen coordinates. - */ - @Override - public void drawButton(Canvas canvas, ScoreView score, Rect rect, float margin) { - if (score.getTool() == this) { - paint_.setColor(Color.WHITE); - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(rect.left - margin / 2, - rect.top - margin / 2, - rect.right + margin / 2, - rect.bottom + margin / 2, - paint_); - } - - paint_.setColor(Color.BLACK); - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(rect, paint_); - icon_.setBounds(rect); - icon_.draw(canvas); - } - - /** - * Called when the user touches the ScoreView while this tool is selected. - * @param view - The ScoreView that this tool is for. - * @param event - The touch event that triggered this handler. - * @return true iff this tool handled the touch event. - */ - @Override - public boolean onTouch(ScoreView view, MotionEvent event) { - int action = event.getAction(); - int actionCode = action & MotionEvent.ACTION_MASK; - if (actionCode == MotionEvent.ACTION_DOWN) { - double time = view.getTimeAt((int)event.getX()); - double note = view.getNoteAt((int)event.getY()); - - if (view.getSnapTo() != 0) { - time = ((int)(time / view.getSnapTo())) * view.getSnapTo(); - } - - Event.Builder e = view.getScore().addEventBuilder(); - e.setStart(time); - e.setEnd(time + view.getSnapTo()); - e.setKey((int)note); - e.getKeyEventBuilder().setChannel(view.getCurrentChannel()); - - eventTool_.pickupEvent(view, e, (int)event.getX(), (int)event.getY(), this); - view.setTool(eventTool_); - return true; - } else { - return false; - } - } - - // The tool that's used to edit the event after it's created, but only until the finger is up. - // Then control returns back to this control. - private EditEventTool eventTool_; - - // Some objects used in drawing. They are owned here so that they don't have to be reallocated - // and garbage collected for every pass of drawing. - private Paint paint_; - private Drawable icon_; - - @SuppressWarnings("unused") - private Logger logger_; -} diff --git a/android/src/com/levien/synthesizer/android/widgets/score/NewLoopTool.java b/android/src/com/levien/synthesizer/android/widgets/score/NewLoopTool.java deleted file mode 100644 index 9df4e91..0000000 --- a/android/src/com/levien/synthesizer/android/widgets/score/NewLoopTool.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.widgets.score; - -import java.util.logging.Logger; - -import com.levien.synthesizer.R; -import com.levien.synthesizer.core.music.Music.Event; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; -import android.view.MotionEvent; - -/** - * A tool for creating new events in the score. - */ -public class NewLoopTool extends ScoreViewTool { - /** - * Creates a new NewEventTool. - * @param context - The context to use for loading resources. - * @param eventTool - The tool to use for editing the event as it's created. - */ - NewLoopTool(Context context, EditEventTool eventTool) { - logger_ = Logger.getLogger(getClass().getName()); - eventTool_ = eventTool; - - icon_ = context.getResources().getDrawable(R.drawable.loop); - paint_ = new Paint(); - } - - /** - * Draws the button on the toolbar. - * @param canvas - The canvas to draw the button on. - * @param score - The ScoreView that this toolbar is for. - * @param rect - The area of the button to be drawn, including any margin. - * @param margin - The preferred margin around the button, in screen coordinates. - */ - @Override - public void drawButton(Canvas canvas, ScoreView score, Rect rect, float margin) { - if (score.getTool() == this) { - paint_.setColor(Color.WHITE); - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(rect.left - margin / 2, - rect.top - margin / 2, - rect.right + margin / 2, - rect.bottom + margin / 2, - paint_); - } - - paint_.setColor(Color.BLACK); - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(rect, paint_); - icon_.setBounds(rect); - icon_.draw(canvas); - } - - /** - * Called when the user touches the ScoreView while this tool is selected. - * @param view - The ScoreView that this tool is for. - * @param event - The touch event that triggered this handler. - * @return true iff this tool handled the touch event. - */ - @Override - public boolean onTouch(ScoreView view, MotionEvent event) { - int action = event.getAction(); - int actionCode = action & MotionEvent.ACTION_MASK; - if (actionCode == MotionEvent.ACTION_DOWN) { - double time = view.getTimeAt((int)event.getX()); - double note = view.getNoteAt((int)event.getY()); - - if (view.getSnapTo() != 0) { - time = ((int)(time / view.getSnapTo())) * view.getSnapTo(); - } - - Event.Builder e = view.getScore().addEventBuilder(); - e.setStart(time); - e.setEnd(time + view.getSnapTo()); - e.setKey((int)note); - e.getLoopEventBuilder().setCount(1); - - eventTool_.pickupEvent(view, e, (int)event.getX(), (int)event.getY(), this); - view.setTool(eventTool_); - return true; - } else { - return false; - } - } - - // The tool that's used to edit the event after it's created, but only until the finger is up. - // Then control returns back to this control. - private EditEventTool eventTool_; - - // Some objects used in drawing. They are owned here so that they don't have to be reallocated - // and garbage collected for every pass of drawing. - private Paint paint_; - private Drawable icon_; - - @SuppressWarnings("unused") - private Logger logger_; -} diff --git a/android/src/com/levien/synthesizer/android/widgets/score/PlayButton.java b/android/src/com/levien/synthesizer/android/widgets/score/PlayButton.java deleted file mode 100644 index 594aa3c..0000000 --- a/android/src/com/levien/synthesizer/android/widgets/score/PlayButton.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.widgets.score; - -import java.util.logging.Logger; - -import com.levien.synthesizer.R; -import com.levien.synthesizer.core.music.ScorePlayer; -import com.levien.synthesizer.core.music.ScorePlayerListener; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; - -/** - * A button to start the current score playing. - */ -public class PlayButton extends ScoreViewTool implements ScorePlayerListener { - /** - * Creates a new play button, loading resources from the given context. - */ - PlayButton(ScoreViewToolbar toolbar, Context context) { - toolbar_ = toolbar; - logger_ = Logger.getLogger(getClass().getName()); - player_ = new ScorePlayer(); - - playing_ = false; - - playingIcon_ = context.getResources().getDrawable(R.drawable.stop); - stoppedIcon_ = context.getResources().getDrawable(R.drawable.play); - paint_ = new Paint(); - } - - /** - * Called when this tool is selected. Starts the score playing. - * @param view - The ScoreView that this toolbar is for. - * @param previousTool - The tool that was selected when this one was chosen. - */ - @Override - public void onSelect(ScoreView view, ScoreViewTool previousTool) { - view_ = view; - if (playing_) { - player_.stopPlaying(); - } else { - player_.startPlaying(view.getSynthesizer(), view.getScore().build(), 120.0, 4, this); - } - view.setTool(previousTool); - } - - /** - * Draws the button on the toolbar. - * @param canvas - The canvas to draw the button on. - * @param score - The ScoreView that this toolbar is for. - * @param rect - The area of the button to be drawn, including any margin. - * @param margin - The preferred margin around the button, in screen coordinates. - */ - @Override - public void drawButton(Canvas canvas, ScoreView score, Rect rect, float margin) { - if (score.getTool() == this) { - paint_.setColor(Color.WHITE); - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(rect.left - margin / 2, - rect.top - margin / 2, - rect.right + margin / 2, - rect.bottom + margin / 2, - paint_); - } - - paint_.setColor(Color.BLACK); - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(rect, paint_); - - if (playing_) { - playingIcon_.setBounds(rect); - playingIcon_.draw(canvas); - } else { - stoppedIcon_.setBounds(rect); - stoppedIcon_.draw(canvas); - } - } - - /** - * Called when the score starts playing. - */ - public void onStart() { - view_.post(new Thread("PlayButton.onStart()") { - public void run() { - playing_ = true; - view_.invalidate(); - toolbar_.invalidate(); - } - }); - } - - /** - * Called every so often during playback. - * @param time - the time in measures from the start of the song. - */ - public void onTimeUpdate(final double time) { - view_.post(new Thread("PlayButton.onTimeUpdate()") { - public void run() { - view_.setCursor(time); - view_.invalidate(); - toolbar_.invalidate(); - } - }); - } - - /** - * Called when the score stops playing. - */ - public void onStop() { - view_.post(new Thread("PlayButton.onStop()") { - public void run() { - playing_ = false; - view_.invalidate(); - } - }); - } - - // The ScoreView that this button controls. - private ScoreView view_; - private ScoreViewToolbar toolbar_; - - // ScorePlayer to play the score. - private ScorePlayer player_; - - // Is the score playing? - private boolean playing_; - - // Some objects used in drawing. They are owned here so that they don't have to be reallocated - // and garbage collected for every pass of drawing. - private Paint paint_; - private Drawable playingIcon_; - private Drawable stoppedIcon_; - - @SuppressWarnings("unused") - private Logger logger_; -} diff --git a/android/src/com/levien/synthesizer/android/widgets/score/PlayTool.java b/android/src/com/levien/synthesizer/android/widgets/score/PlayTool.java deleted file mode 100644 index 7ff5dc8..0000000 --- a/android/src/com/levien/synthesizer/android/widgets/score/PlayTool.java +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.widgets.score; - -import java.util.logging.Logger; - -import com.levien.synthesizer.R; -import com.levien.synthesizer.core.music.Note; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; -import android.view.MotionEvent; - -/** - * A button to enable "play" mode of the ScoreView. In play mode, pressing anywhere plays the note - * for the key that's being pressed. @see ScoreView. - */ -public class PlayTool extends ScoreViewTool { - /** - * Creates a new PlayTool, loading resources from the given context. - */ - PlayTool(Context context) { - logger_ = Logger.getLogger(getClass().getName()); - - keysDown_ = new int[FINGERS]; - for (int i = 0; i < keysDown_.length; ++i) { - keysDown_[i] = -1; - } - - icon_ = context.getResources().getDrawable(R.drawable.play_piano); - paint_ = new Paint(); - } - - /** - * Draws the button on the toolbar. - * @param canvas - The canvas to draw the button on. - * @param score - The ScoreView that this toolbar is for. - * @param rect - The area of the button to be drawn, including any margin. - * @param margin - The preferred margin around the button, in screen coordinates. - */ - @Override - public void drawButton(Canvas canvas, ScoreView score, Rect rect, float margin) { - if (score.getTool() == this) { - paint_.setColor(Color.WHITE); - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(rect.left - margin / 2, - rect.top - margin / 2, - rect.right + margin / 2, - rect.bottom + margin / 2, - paint_); - } - - paint_.setColor(Color.BLACK); - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(rect, paint_); - icon_.setBounds(rect); - icon_.draw(canvas); - } - - /** - * Called after each key is drawn, to give this tool a chance to draw over it. - * See ScoreView.onDraw() for more information on how ScoreView is drawn. - * @param key - The key that was drawn. - * @param canvas - The canvas the key is drawn into. - * @param rect - The area of the key on the canvas. - */ - @Override - public void afterDrawKey(int key, - Canvas canvas, - Rect rect) { - for (int keyDown : keysDown_) { - if (key == keyDown) { - paint_.setColor(Color.GREEN); - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(rect, paint_); - } - } - } - - /** - * Called to handle touch down events. - * Returns true iff we need to redraw. - */ - private boolean onTouchDown(ScoreView view, int finger, int physicalX, int physicalY) { - int note = (int)Math.floor(view.getNoteAt(physicalY)); - view.getSynthesizer().onNoteOn(view.getCurrentChannel(), note, 64); - keysDown_[finger] = note; - return true; - } - - /** - * Called to handle touch move events. - */ - private boolean onTouchMove(ScoreView view, int finger, int physicalX, int physicalY) { - int note = (int)Math.floor(view.getNoteAt(physicalY)); - int oldNote = keysDown_[finger]; - if (oldNote >= 0) { - view.getSynthesizer().onNoteOff(view.getCurrentChannel(), oldNote, 64); - } - view.getSynthesizer().onNoteOn(view.getCurrentChannel(), note, 64); - keysDown_[finger] = (int)note; - return true; - } - - /** - * Called to handle touch up events. - */ - protected boolean onTouchUp(ScoreView view, int finger) { - int note = keysDown_[finger]; - view.getSynthesizer().onNoteOff(view.getCurrentChannel(), note, 64); - keysDown_[finger] = -1; - return true; - } - - /** - * Called when the user touches the ScoreView while this tool is selected. - * @param view - The ScoreView that this tool is for. - * @param event - The touch event that triggered this handler. - * @return true iff this tool handled the touch event. - */ - @Override - public boolean onTouch(ScoreView view, MotionEvent event) { - int action = event.getAction(); - int actionCode = action & MotionEvent.ACTION_MASK; - boolean redraw = false; - if (actionCode == MotionEvent.ACTION_DOWN) { - int pointerId = event.getPointerId(0); - if (pointerId < FINGERS) { - int x = (int)event.getX(); - int y = (int)event.getY(); - redraw |= onTouchDown(view, pointerId, x, y); - } - } else if (actionCode == MotionEvent.ACTION_POINTER_DOWN) { - int pointerId = action >> MotionEvent.ACTION_POINTER_ID_SHIFT; - if (pointerId < FINGERS) { - int pointerIndex = event.findPointerIndex(pointerId); - if (pointerIndex >= 0) { - int x = (int)event.getX(pointerIndex); - int y = (int)event.getY(pointerIndex); - redraw |= onTouchDown(view, pointerId, x, y); - } - } - } else if (actionCode == MotionEvent.ACTION_MOVE) { - for (int pointerIndex = 0; pointerIndex < event.getPointerCount(); ++pointerIndex) { - int pointerId = event.getPointerId(pointerIndex); - if (pointerId >= FINGERS) { - continue; - } - if (pointerIndex >= 0) { - int x = (int)event.getX(pointerIndex); - int y = (int)event.getY(pointerIndex); - redraw |= onTouchMove(view, pointerId, x, y); - } - } - } else if (actionCode == MotionEvent.ACTION_UP) { - int pointerId = event.getPointerId(0); - if (pointerId < FINGERS) { - redraw |= onTouchUp(view, pointerId); - } - // Clean up any other pointers that have disappeared. - for (pointerId = 0; pointerId < FINGERS; ++pointerId) { - boolean found = false; - for (int pointerIndex = 0; pointerIndex < event.getPointerCount(); ++pointerIndex) { - if (pointerId == event.getPointerId(pointerIndex)) { - found = true; - break; - } - } - if (!found) { - redraw |= onTouchUp(view, pointerId); - } - } - } else if (actionCode == MotionEvent.ACTION_POINTER_UP) { - int pointerId = action >> MotionEvent.ACTION_POINTER_ID_SHIFT; - if (pointerId < FINGERS) { - redraw |= onTouchUp(view, pointerId); - } - // Clean up any other pointers that have disappeared. - for (pointerId = 0; pointerId < FINGERS; ++pointerId) { - boolean found = false; - for (int pointerIndex = 0; pointerIndex < event.getPointerCount(); ++pointerIndex) { - if (pointerId == event.getPointerId(pointerIndex)) { - found = true; - break; - } - } - if (!found) { - redraw |= onTouchUp(view, pointerId); - } - } - } else { - return false; - } - if (redraw) { - view.invalidate(); - } - return true; - } - - // The piano key each finger is holding down, or -1 if a finger is not pressing any key. - private int[] keysDown_; - - // Some objects used in drawing. They are owned here so that they don't have to be reallocated - // and garbage collected for every pass of drawing. - private Paint paint_; - private Drawable icon_; - - // The number of simultaneous fingers supported by this control. - protected static final int FINGERS = 5; - - @SuppressWarnings("unused") - private Logger logger_; -} diff --git a/android/src/com/levien/synthesizer/android/widgets/score/ScoreView.java b/android/src/com/levien/synthesizer/android/widgets/score/ScoreView.java deleted file mode 100644 index 1d8ea5a..0000000 --- a/android/src/com/levien/synthesizer/android/widgets/score/ScoreView.java +++ /dev/null @@ -1,767 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.widgets.score; - -import java.util.logging.Logger; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; -import android.util.AttributeSet; -import android.view.MotionEvent; -import android.view.View; - -import com.levien.synthesizer.R; -import com.levien.synthesizer.core.midi.MidiListener; -import com.levien.synthesizer.core.music.Music.Event; -import com.levien.synthesizer.core.music.Music.Score; -import com.levien.synthesizer.core.music.Note; - -/** - * ScoreView is a UI widget that allows editing a musical score, as well as live playing. The - * majority of the ScoreView area shows a subsequence of the current musical score. Along the - * y-axis are the keys of a piano. Time is along the x-axis. Along the bottom, there is a toolbar, - * which allows selecting various "tools" to use on the score. - * - * A score is composed of various "events", such as playing a note for a certain duration at a - * certain time, using a certain channel. A ScoreView lets the user create or edit these events. - * - * PlayTool - When selected, pressing plays the note at that x using the selected channel. - * ViewportTool - Sets the currently visible part of the score by touching or dragging. - * NewEventTool - Creates new events. - * EditEventTool - Edits an existing event. - * PlayButton - Starts the score playing audibly. - * SelectChannelButton - Selects a particular channel (instrument) for editing or playing. - * HideChannelButton - Toggles whether to show/hide the channels not currently being edited. - * SnapTool - Changes the "snap to" setting for this ScoreView. - */ -public class ScoreView extends View { - /** - * Basic android widget constructor. - */ - public ScoreView(Context context, AttributeSet attrs) { - super(context, attrs); - - logger_ = Logger.getLogger(getClass().getName()); - - // Set the default time to be 20 measures, and show 5 measures to start. - minTime_ = 0.0; - maxTime_ = 20.0; - timeZoom_ = 0.25; - timeOffset_ = 0.0; - - // Set the piano keys to the range of a normal piano, showing one octave to start. - minNote_ = Note.A; - maxNote_ = Note.A + 88.0; - noteZoom_ = 8.0 / 88.0; - noteOffset_ = 44.0; - - // Snap to eighth notes to start. - snapTo_ = 1.0 / 8.0; - - // Create the score to edit. - score_ = Score.newBuilder(); - - // Setup the channels. - currentChannel_ = 0; - showOtherChannels_ = true; - - // Load the icon to use for each channel. - iconForChannel_ = new Drawable[CHANNELS]; - iconForChannel_[0] = context.getResources().getDrawable(R.drawable.guitar); - iconForChannel_[1] = context.getResources().getDrawable(R.drawable.bass); - iconForChannel_[2] = context.getResources().getDrawable(R.drawable.voice); - iconForChannel_[3] = context.getResources().getDrawable(R.drawable.flute); - iconForChannel_[4] = context.getResources().getDrawable(R.drawable.drums); - - arrowsVisible_ = true; - upSelected_ = false; - downSelected_ = false; - upIcon_ = context.getResources().getDrawable(R.drawable.up); - downIcon_ = context.getResources().getDrawable(R.drawable.down); - - // Set up basic drawing structs, just so we don't have to allocate them later when we draw. - drawingRect_ = new Rect(); - keyRect_ = new Rect(); - eventRect_ = new Rect(); - fillPaint_ = new Paint(); - strokePaint_ = new Paint(); - marginPaint_ = new Paint(); - - fillPaint_.setStyle(Paint.Style.FILL); - strokePaint_.setStyle(Paint.Style.STROKE); - marginPaint_.setStyle(Paint.Style.FILL); - marginPaint_.setColor(Color.GRAY); - } - - /** - * Returns a mutable copy of the score being edited. - */ - public Score.Builder getScore() { - return score_; - } - - /** - * Returns the currently selected channel (instrument). - */ - public int getCurrentChannel() { - return currentChannel_; - } - - /** - * Selects the given channel. - * @param channel - The channel to select. - */ - public void setCurrentChannel(int channel) { - currentChannel_ = channel; - } - - /** - * Returns true iff the given channel is visible in the score. - */ - public boolean isChannelVisible(int channel) { - if (showOtherChannels_) { - return true; - } else { - return channel == currentChannel_; - } - } - - /** - * Returns true iff channels that aren't the current one are visible in the score. - */ - public boolean getOtherChannelsVisible() { - return showOtherChannels_; - } - - /** - * Sets whether channels that aren't the current one are visible in the score. - */ - public void setOtherChannelsVisible(boolean visible) { - showOtherChannels_ = visible; - } - - /** - * Returns the currently selected tool for this ScoreView. - */ - public ScoreViewTool getTool() { - return currentTool_; - } - - /** - * Sets a tool to be the current tool for this ScoreView. Informs listeners of the change. - */ - public void setTool(ScoreViewTool tool) { - ScoreViewTool previousTool = currentTool_; - currentTool_ = tool; - tool.onSelect(this, previousTool); - if (listener_ != null) { - listener_.onSetTool(tool); - } - invalidate(); - } - - /** - * Returns the "snap to" setting for this ScoreView. @see setSnapTo(). - * @return the note that should be snapped to. For example, if editing should snap to the nearest - * quarter note, then returns 0.25. For a whole note, 1.0. For no snapping, returns 0.0. - */ - public double getSnapTo() { - return snapTo_; - } - - /** - * Sets the "snap to" setting for this ScoreView. @see getSnapTo(). - * @param snapTo - the note that should be snapped to. For example, if editing should snap to the - * nearest quarter note, then 0.25. For a whole note, 1.0. For no snapping, 0.0. - */ - public void setSnapTo(double snapTo) { - snapTo_ = snapTo; - } - - /** - * Returns the zoom setting for this control on the x-axis. @see setTimeZoom(). - * @return the multiplier for the x-axis on the viewport. 1.0 means the entire time of the score - * is visible. 0.5 means only half of the score (time-wise) is visible. 2.0 means that the - * entire score is shown, but only takes up half the screen. Any excess space is just "margin". - */ - public double getTimeZoom() { - return timeZoom_; - } - - /** - * Sets the zoom level for this control on the x-axis. @see getTimeZoom(). - * @param zoom - the multiplier for the x-axis on the viewport. 1.0 means the entire time of the - * score is visible. 0.5 means only half of the score (time-wise) is visible. 2.0 means that the - * entire score is shown, but only takes up half the screen. Any excess space is just "margin". - */ - public void setTimeZoom(double zoom) { - timeZoom_ = zoom; - } - - /** - * Returns the zoom setting for this control on the y-axis. @see setNoteZoom(). - * @return the multiplier for the y-axis on the viewport, which controls how many note keys are - * visible. 1.0 means show the entire 88 keys of the piano are visible. N/88 means exactly N - * keys are visible. Values larger than 1.0 means extra "margin" is shown at the top and bottom. - */ - public double getNoteZoom() { - return noteZoom_; - } - - /** - * Sets the zoom setting for this control on the y-axis. @see getNoteZoom(). - * @param zoom - the multiplier for the y-axis on the viewport, which controls how many note keys - * are visible. 1.0 means show the entire 88 keys of the piano are visible. N/88 means exactly N - * keys are visible. Values larger than 1.0 means extra "margin" is shown at the top and bottom. - */ - public void setNoteZoom(double zoom) { - noteZoom_ = zoom; - } - - /** - * Returns the left-most time currently visible in this control. @see setTimeOffset(). - * @return the time, in measures, from the beginning of the score to the first visible time - * in the ScoreView. For example, 5.25 in 4/4 time would mean one quarter note past the end of - * the 5th measure. Negative values mean margin is shown on the left side. - */ - public double getTimeOffset() { - return timeOffset_; - } - - /** - * Sets the left-most time currently visible in this control. @see getTimeOffset(). - * @param offset - The time, in measures, from the beginning of the score to the first visible - * time in the ScoreView. For example, 5.25 in 4/4 time would mean one quarter note past the end - * of the 5th measure. Negative values mean margin is shown on the left side. - */ - public void setTimeOffset(double offset) { - timeOffset_ = offset; - } - - /** - * Returns the bottom-most note key currently visible in this control. @see setNoteOffset(). - * @return the note number of the bottom key visible on the screen. 0.0 means the lowest note is - * fully visible, with its bottom along the bottom edge of the screen. 1.0 means the lowest note - * is not visible, but its top edge is along the bottom of the screen. 88.0 means no keys are - * visible, but the top edge of the highest key is along the bottom of the screen. - */ - public double getNoteOffset() { - return noteOffset_; - } - - /** - * Sets the bottom-most note key currently visible in this control. @see getNoteOffset(). - * @param offset - the note number of the bottom key visible on the screen. 0.0 means the lowest - * note is fully visible, with its bottom along the bottom edge of the screen. 1.0 means the - * lowest note is not visible, but its top edge is along the bottom of the screen. 88.0 means no - * keys are visible, but the top edge of the highest key is along the bottom of the screen. - */ - public void setNoteOffset(double offset) { - noteOffset_ = offset; - } - - /** - * Returns the max time viewable or editable by this ScoreView. @see setMaxTime(). - * @return the time, where 0.0 means no time, 1.0 means one measure, and 10 means ten measures. - */ - public double getMaxTime() { - return maxTime_; - } - - /** - * Sets the max time viewable or editable by this ScoreView. @see getMaxTime(). - * @param max - the time, where 0.0 means no time, 1.0 means one measure, and 10 for ten measures. - */ - public void setMaxTime(double max) { - maxTime_ = max; - } - - /** - * Returns the max possible note viewable or editable by this ScoreView. @see setMaxNote(). - * @return the note number. For a normal piano layout, this method should always return 88.0. - */ - public double getMaxNote() { - return maxNote_; - } - - /** - * Sets the max possible note viewable or editable by this ScoreView. @see getMaxNote(). - * @param max - the note number. For a normal piano layout, this should always be 88.0. - */ - public void setMaxNote(double max) { - maxNote_ = max; - } - - /** - * Returns the rectangle, in screen coordinates, where this ScoreView was most recently drawn. - * @return a reference to the Rect. - */ - public Rect getDrawingRect() { - return drawingRect_; - } - - /** - * Returns the time (logical x) that corresponds to the given pixel (physical x). - * @param pixelX - the x in screen coordinates. - * @return the x in logical coordinates (the time, in measures, from the score start). - */ - public double getTimeAt(int pixelX) { - return timeOffset_ + ((double)(pixelX - drawingRect_.left) / drawingRect_.width()) / timeZoom_; - } - - /** - * Returns the pixel (physical x) that corresponds to the given time (logical x). - * @param time - the time, in measures, from the score start. - * @return the x offset of the given time, in screen coordinates. - */ - public int getTimeX(double time) { - return (int)(((time - timeOffset_) * timeZoom_) * drawingRect_.width() + - drawingRect_.left + 0.5); - } - - /** - * Returns the note (logical y) that corresponds to the given pixel (physical y). - * @param pixelY - the y in screen coordinates. - * @return the y in logical coordinates (the note key, typically from 0 to 88.0). - */ - public double getNoteAt(int pixelY) { - return ((double)(drawingRect_.bottom - pixelY) / drawingRect_.height()) / noteZoom_ + noteOffset_; - } - - /** - * Returns the pixel (physical y) that corresponds to the given note (logical y). - * @param note - the note key. - * @return the y offset of the given note, in screen coordinates. - */ - public int getNoteY(double note) { - return (int)(drawingRect_.bottom - (note - noteOffset_) * drawingRect_.height() * noteZoom_); - } - - /** - * Returns the top-most event at the given coordinates. - * @param physicalX - the x in screen coordinates. - * @param physicalY - the y in screen coordinates. - * @return the mutable event. - */ - public Event.Builder getEventAt(int physicalX, int physicalY) { - double time = getTimeAt(physicalX); - double note = getNoteAt(physicalY); - for (int i = score_.getEventCount() - 1; i >= 0; --i) { - double eventStartTime = score_.getEvent(i).getStart(); - double eventEndTime = score_.getEvent(i).getEnd(); - double eventMinNote = score_.getEvent(i).getKey(); - double eventMaxNote = score_.getEvent(i).getKey() + 1; - if (time >= eventStartTime && - time < eventEndTime && - note >= eventMinNote && - note < eventMaxNote) { - return score_.getEventBuilder(i); - } - } - return null; - } - - /** - * Sets the cursor position that shows where playback is in the score. - * This should only be called from the Android UI thread. - */ - public void setCursor(double cursor) { - cursor_ = cursor; - invalidate(); - } - - /** - * Returns the color to use for representing the given channel in this ScoreView. - * @param channel - the channel. - * @return the color to use, Android style. - */ - public int getColorForChannel(int channel) { - switch (channel % CHANNELS) { - case 0: return Color.rgb(0, 255, 255); - case 1: return Color.rgb(255, 0, 255); - case 2: return Color.rgb(255, 255, 0); - case 3: return Color.rgb(255, 0, 0); - case 4: return Color.rgb(0, 255, 0); - case 5: return Color.rgb(0, 0, 255); - } - return Color.BLACK; - } - - /** - * Returns the icon to use for representing the given channel in this ScoreView. - * @param channel - the channel. - * @return the icon to use, as a Drawable. - */ - public Drawable getIconForChannel(int channel) { - return iconForChannel_[channel % iconForChannel_.length]; - } - - /** - * Called to draw the ScoreView widget. - * @param canvas - the canvas to draw the widget on. - */ - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - getDrawingRect(drawingRect_); - - // Clear the rectangle. - fillPaint_.setColor(Color.WHITE); - canvas.drawRect(drawingRect_, fillPaint_); - strokePaint_.setStrokeWidth(1.0f); - - // Draw piano keys to mark the frequencies. - for (int note = (int)minNote_; note < (int)maxNote_; ++note) { - // Draw a single key that fills up a row. - keyRect_.bottom = getNoteY(note); - keyRect_.top = getNoteY(note + 1); - keyRect_.left = getTimeX(0.0); - keyRect_.right = getTimeX(maxTime_); - strokePaint_.setStrokeWidth(2.0f); - strokePaint_.setColor(Color.LTGRAY); - if (Note.isNatural(note)) { - fillPaint_.setColor(Color.WHITE); - } else { - fillPaint_.setColor(Color.LTGRAY); - } - canvas.drawRect(keyRect_, fillPaint_); - canvas.drawRect(keyRect_, strokePaint_); - - if (currentTool_ != null) { - currentTool_.afterDrawKey(note, canvas, keyRect_); - } - } - - // Draw lines to mark the measures. - for (double i = minTime_ + 1; i < maxTime_; ++i) { - strokePaint_.setColor(Color.LTGRAY); - int x = getTimeX(i - 0.75); - canvas.drawLine(x, drawingRect_.top, x, drawingRect_.bottom, strokePaint_); - - strokePaint_.setColor(Color.GRAY); - x = getTimeX(i - 0.5); - canvas.drawLine(x, drawingRect_.top, x, drawingRect_.bottom, strokePaint_); - - strokePaint_.setColor(Color.LTGRAY); - x = getTimeX(i - 0.25); - canvas.drawLine(x, drawingRect_.top, x, drawingRect_.bottom, strokePaint_); - - strokePaint_.setColor(Color.BLACK); - x = getTimeX(i); - canvas.drawLine(x, drawingRect_.top, x, drawingRect_.bottom, strokePaint_); - } - - // Draw the margins. - double leftMargin = getTimeX(minTime_); - if (leftMargin > drawingRect_.left) { - canvas.drawRect(drawingRect_.left, - drawingRect_.top, - (float)leftMargin, - drawingRect_.bottom, - marginPaint_); - } - double rightMargin = getTimeX(maxTime_); - if (rightMargin < drawingRect_.right) { - canvas.drawRect((float)rightMargin, - drawingRect_.top, - drawingRect_.right, - drawingRect_.bottom, - marginPaint_); - } - double topMargin = getNoteY(maxNote_); - if (topMargin > drawingRect_.top) { - canvas.drawRect(drawingRect_.left, - drawingRect_.top, - drawingRect_.right, - (float)topMargin, - marginPaint_); - } - double bottomMargin = getNoteY(minNote_); - if (bottomMargin < drawingRect_.bottom) { - canvas.drawRect(drawingRect_.left, - (float)bottomMargin, - drawingRect_.right, - drawingRect_.bottom, - marginPaint_); - } - - // Draw the sequence. - for (int i = 0; i < score_.getEventCount(); ++i) { - Event event = score_.getEvent(i); - eventRect_.left = getTimeX(event.getStart()); - eventRect_.top = getNoteY(event.getKey() + 1); - eventRect_.right = getTimeX(event.getEnd()); - eventRect_.bottom = getNoteY(event.getKey()); - - if (!event.hasKeyEvent() || isChannelVisible(event.getKeyEvent().getChannel())) { - if (event.getSelected()) { - if (event.hasKeyEvent()) { - fillPaint_.setColor(getColorForChannel(event.getKeyEvent().getChannel())); - strokePaint_.setColor(Color.BLACK); - } else { - fillPaint_.setColor(Color.BLACK); - strokePaint_.setColor(Color.WHITE); - } - fillPaint_.setAlpha(255); - strokePaint_.setStrokeWidth(5.0f); - } else { - if (event.hasKeyEvent()) { - fillPaint_.setColor(getColorForChannel(event.getKeyEvent().getChannel())); - strokePaint_.setColor(Color.BLACK); - } else { - fillPaint_.setColor(Color.BLACK); - strokePaint_.setColor(Color.WHITE); - } - fillPaint_.setAlpha(127); - strokePaint_.setStrokeWidth(1.0f); - } - canvas.drawRect(eventRect_, fillPaint_); - canvas.drawRect(eventRect_, strokePaint_); - - if (currentTool_ != null) { - currentTool_.afterDrawEvent(event, canvas, eventRect_); - } - } - } - - // Draw the cursor. - strokePaint_.setColor(Color.rgb(0, 175, 0)); - strokePaint_.setStrokeWidth(8.0f); - canvas.drawLine(getTimeX(cursor_), drawingRect_.top, - getTimeX(cursor_), drawingRect_.bottom, strokePaint_); - - // Draw the scroll arrows, if visible. - if (arrowsVisible_) { - upIcon_.setBounds(getDrawingRect().left + 50, - getDrawingRect().top + 50, - getDrawingRect().left + 50 + upIcon_.getIntrinsicWidth(), - getDrawingRect().top + 50 + downIcon_.getIntrinsicHeight()); - downIcon_.setBounds(getDrawingRect().left + 50, - (getDrawingRect().bottom - 50) - downIcon_.getIntrinsicHeight(), - getDrawingRect().left + 50 + upIcon_.getIntrinsicWidth(), - getDrawingRect().bottom - 50); - - if (upSelected_) { - fillPaint_.setColor(Color.WHITE); - } else { - fillPaint_.setColor(Color.BLACK); - } - canvas.drawCircle(upIcon_.getBounds().centerX(), - upIcon_.getBounds().centerY(), - upIcon_.getBounds().width(), - fillPaint_); - upIcon_.draw(canvas); - - if (downSelected_) { - fillPaint_.setColor(Color.WHITE); - } else { - fillPaint_.setColor(Color.BLACK); - } - canvas.drawCircle(downIcon_.getBounds().centerX(), - downIcon_.getBounds().centerY(), - downIcon_.getBounds().width(), - fillPaint_); - downIcon_.draw(canvas); - - // Make the bounds for the icons a little larger so they're easier to hit. - downIcon_.getBounds().inset(-50, -50); - upIcon_.getBounds().inset(-50, -50); - } - - if (currentTool_ != null) { - currentTool_.afterDrawScore(this, canvas, drawingRect_); - } - } - - /** - * Handler for all touch events. - */ - @Override - public boolean onTouchEvent(MotionEvent event) { - // Check if they touched the arrows. - int action = event.getAction(); - int actionCode = action & MotionEvent.ACTION_MASK; - if (actionCode == MotionEvent.ACTION_DOWN) { - if (upIcon_.getBounds().contains((int)event.getX(), (int)event.getY())) { - upSelected_ = true; - invalidate(); - return true; - } else if (downIcon_.getBounds().contains((int)event.getX(), (int)event.getY())) { - downSelected_ = true; - invalidate(); - return true; - } else { - arrowsVisible_ = false; - invalidate(); - } - } else if (actionCode == MotionEvent.ACTION_UP) { - arrowsVisible_ = true; - if (upSelected_) { - // Scroll up. - if (getNoteOffset() < maxNote_) { - setNoteOffset(getNoteOffset() + 1); - } - upSelected_ = false; - } - if (downSelected_) { - // Scroll down. - if (getNoteOffset() > minNote_) { - setNoteOffset(getNoteOffset() - 1); - } - downSelected_ = false; - } - invalidate(); - } - - // Delegate the touch to the current tool. - if (!upSelected_ && !downSelected_ && currentTool_ != null) { - return currentTool_.onTouch(this, event); - } else { - return false; - } - } - - /** - * Layout measurement for this widget. - * This method just sets a basic minimum size and makes the widget maximized otherwise. - */ - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int widthMode = MeasureSpec.getMode(widthMeasureSpec); - int widthSize = MeasureSpec.getSize(widthMeasureSpec); - int heightMode = MeasureSpec.getMode(heightMeasureSpec); - int heightSize = MeasureSpec.getSize(heightMeasureSpec); - - int width = 0; - int height = 0; - - switch (widthMode) { - case MeasureSpec.EXACTLY: - width = widthSize; - break; - case MeasureSpec.AT_MOST: - width = widthSize; - break; - case MeasureSpec.UNSPECIFIED: - width = 10; - break; - } - - switch (heightMode) { - case MeasureSpec.EXACTLY: - height = heightSize; - break; - case MeasureSpec.AT_MOST: - height = heightSize; - break; - case MeasureSpec.UNSPECIFIED: - height = 10; - break; - } - - setMeasuredDimension(width, height); - } - - /** - * Connects the ScoreView to a Synthesizer for playback. - * @synth - The synthesizer to connect to. - */ - public void bindTo(final MidiListener synth) { - synthesizer_ = synth; - } - - /** - * Returns the synthesizer connected to this ScoreView. - * @return the connected synthesizer. - */ - public MidiListener getSynthesizer() { - return synthesizer_; - } - - /** - * Sets the listener to notify of events in this control. - * @param listener - the listener to notify. - */ - public void setListener(ScoreViewListener listener) { - listener_ = listener; - } - - // The score being edited, played, etc by this control. - private Score.Builder score_; - - // The current tool being used. - private ScoreViewTool currentTool_; - - // The currently selected channel (instrument). - private int currentChannel_; - - // Whether to show channels other than the currently selected one. - private boolean showOtherChannels_; - - // The set of icons to use for each channel. - private Drawable[] iconForChannel_; - - // What granularity of note to snap to when editing. See getSnapTo and setSnapTo(). - private double snapTo_; - - // The min, max and current viewport for the x and y axes. - private double timeZoom_; - private double timeOffset_; - private double minTime_; - private double maxTime_; - private double noteZoom_; - private double noteOffset_; - private double minNote_; - private double maxNote_; - - // A cursor that indicates where playback is in the score, in logical coordinates. - private double cursor_; - - // The synthesizer this control is bound to. - private MidiListener synthesizer_; - - // The listener to notify of events in this control. - private ScoreViewListener listener_; - - // Buttons to let the user move up and down without switching to the viewport tool. - private boolean arrowsVisible_; - private boolean upSelected_; - private boolean downSelected_; - private Drawable upIcon_; - private Drawable downIcon_; - - // These are basically stack variables for onDraw. They're member variables only so that we can - // avoid reallocating them every time the keyboard is redrawn. - // - // The most recent screen rect that this keyboard was drawn into. - private Rect drawingRect_; - private Rect keyRect_; - private Rect eventRect_; - private Paint fillPaint_; - private Paint strokePaint_; - private Paint marginPaint_; - - // The number of channels (instruments) edittable by this control. - private static final int CHANNELS = 5; - - @SuppressWarnings("unused") - private Logger logger_; -} diff --git a/android/src/com/levien/synthesizer/android/widgets/score/ScoreViewListener.java b/android/src/com/levien/synthesizer/android/widgets/score/ScoreViewListener.java deleted file mode 100644 index 2dd5349..0000000 --- a/android/src/com/levien/synthesizer/android/widgets/score/ScoreViewListener.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.widgets.score; - -/** - * A listener for events happening in a ScoreView. - */ -public interface ScoreViewListener { - /** - * Called when a new tool is selected for the ScoreView. - */ - void onSetTool(ScoreViewTool tool); -} diff --git a/android/src/com/levien/synthesizer/android/widgets/score/ScoreViewTool.java b/android/src/com/levien/synthesizer/android/widgets/score/ScoreViewTool.java deleted file mode 100644 index 5f5efb0..0000000 --- a/android/src/com/levien/synthesizer/android/widgets/score/ScoreViewTool.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.widgets.score; - -import com.levien.synthesizer.core.music.Music.Event; - -import android.graphics.Canvas; -import android.graphics.Rect; -import android.view.MotionEvent; - -/** - * A base class for tools on the ScoreView's toolbar. - */ -public abstract class ScoreViewTool { - /** - * Draws the button on the toolbar. - * @param canvas - The canvas to draw the button on. - * @param score - The ScoreView that this tool is for. - * @param rect - The area of the button to be drawn, including any margin. - * @param margin - The preferred margin around the button, in screen coordinates. - */ - public abstract void drawButton(Canvas canvas, ScoreView score, Rect rect, float margin); - - /** - * Called when this tool is selected. - * @param view - The ScoreView that this tool is for. - * @param previousTool - The tool that was selected when this one was chosen. - */ - public void onSelect(ScoreView view, ScoreViewTool previousTool) {} - - /** - * Called when the user touches the ScoreView while this tool is selected. - * @param view - The ScoreView that this tool is for. - * @param event - The touch event that triggered this handler. - * @return true iff this tool handled the touch event. - */ - public boolean onTouch(ScoreView view, MotionEvent event) { - return false; - } - - /** - * Called after each key is drawn, to give this tool a chance to draw over it. - * See ScoreView.onDraw() for more information on how ScoreView is drawn. - * @param key - The key that was drawn. - * @param canvas - The canvas the key is drawn into. - * @param rect - The area of the key on the canvas. - */ - public void afterDrawKey(int key, Canvas canvas, Rect rect) {} - - /** - * Called after each event is drawn, to give this tool a chance to draw over it. - * See ScoreView.onDraw() for more information on how ScoreView is drawn. - * @param event - The event that was drawn. - * @param canvas - The canvas the key is drawn into. - * @param rect - The area of the key on the canvas. - */ - public void afterDrawEvent(Event event, Canvas canvas, Rect rect) {} - - /** - * Called after the entire score is drawn, to give this tool a chance to draw over it. - * See ScoreView.onDraw() for more information on how ScoreView is drawn. - * @param view - The ScoreView being drawn. - * @param canvas - The canvas the key is drawn into. - * @param rect - The area of the key on the canvas. - */ - public void afterDrawScore(ScoreView view, Canvas canvas, Rect rect) {} -} diff --git a/android/src/com/levien/synthesizer/android/widgets/score/ScoreViewToolbar.java b/android/src/com/levien/synthesizer/android/widgets/score/ScoreViewToolbar.java deleted file mode 100644 index 2d97e51..0000000 --- a/android/src/com/levien/synthesizer/android/widgets/score/ScoreViewToolbar.java +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.widgets.score; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Rect; -import android.util.AttributeSet; -import android.view.MotionEvent; -import android.view.View; - -/** - * A toolbar that goes in a ScoreView and lets the user choose which tool to use on it. - */ -public class ScoreViewToolbar extends View implements ScoreViewListener { - /** Basic constructor for an Android widget. */ - public ScoreViewToolbar(Context context, AttributeSet attrs) { - super(context, attrs); - - paint_ = new Paint(); - rect_ = new Rect(); - textRect_ = new Rect(); - - // Just hard-code the list of tools. - tool_ = new ScoreViewTool[13]; - tool_[0] = new PlayButton(this, context); - tool_[1] = new ViewportTool(context); - tool_[2] = new EditEventTool(context); - tool_[3] = new NewEventTool(context, (EditEventTool)tool_[2]); - tool_[4] = new NewLoopTool(context, (EditEventTool)tool_[2]); - tool_[5] = new HideChannelButton(context); - tool_[6] = new PlayTool(context); - tool_[7] = new SelectChannelButton(context, 0); - tool_[8] = new SelectChannelButton(context, 1); - tool_[9] = new SelectChannelButton(context, 2); - tool_[10] = new SelectChannelButton(context, 3); - tool_[11] = new SelectChannelButton(context, 4); - tool_[12] = new SnapTool(context); - - toolRect_ = new Rect[tool_.length]; - for (int i = 0; i < tool_.length; ++i) { - toolRect_[i] = new Rect(); - } - } - - /** - * Sets the ScoreView that this toolbar controls. - * @param score - the ScoreView. - */ - public void setScoreView(ScoreView score) { - score_ = score; - score_.setListener(this); - score_.setTool(tool_[1]); - invalidate(); - } - - /** - * Sets the current tool. - * @param tool - the tool to use. - */ - public void onSetTool(ScoreViewTool tool) { - invalidate(); - } - - /** - * Touch event handler. - */ - @Override - public boolean onTouchEvent(MotionEvent event) { - int action = event.getAction(); - switch (action) { - case MotionEvent.ACTION_DOWN: { - getDrawingRect(rect_); - for (int i = 0; i < tool_.length; ++i) { - if (toolRect_[i].contains((int)event.getX(), (int)event.getY())) { - score_.setTool(tool_[i]); - invalidate(); - break; - } - } - break; - } - - case MotionEvent.ACTION_MOVE: { - break; - } - - case MotionEvent.ACTION_UP: { - break; - } - } - return true; - } - - /** - * Drawing handler. - */ - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - - getDrawingRect(rect_); - //rect_.set(rect_); - - paint_.setColor(Color.BLACK); - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(rect_, paint_); - - // Draw the buttons. - float margin = 15.0f; - float waveHeight = (rect_.height() - 2.0f * margin); - float waveWidth = waveHeight; - - float xOffset = margin; - float yOffset = margin; - for (int i = 0; i < tool_.length; ++i) { - paint_.setTextSize(24.0f); - paint_.setColor(Color.WHITE); - if (i == 1) { - xOffset += 2 * margin; - paint_.getTextBounds("Tools ", 0, 6, textRect_); - canvas.drawText("Tools ", xOffset, yOffset + (waveHeight + textRect_.height()) / 2, paint_); - xOffset += textRect_.width(); - xOffset += margin; - } else if (i == 7) { - xOffset += 2 * margin; - paint_.getTextBounds("Instruments ", 0, 12, textRect_); - canvas.drawText("Instruments ", xOffset, yOffset + (waveHeight + textRect_.height()) / 2, paint_); - xOffset += textRect_.width(); - xOffset += margin; - } else if (i == 12) { - xOffset += 2 * margin; - paint_.getTextBounds("Snap to ", 0, 8, textRect_); - canvas.drawText("Snap to ", xOffset, yOffset + (waveHeight + textRect_.height()) / 2, paint_); - xOffset += textRect_.width(); - xOffset += margin; - } - paint_.setColor(Color.BLACK); - - toolRect_[i].left = (int)xOffset; - toolRect_[i].top = (int)yOffset; - toolRect_[i].right = (int)(xOffset + waveWidth); - toolRect_[i].bottom = (int)(yOffset + waveHeight); - - tool_[i].drawButton(canvas, score_, toolRect_[i], margin); - - xOffset += waveWidth; - xOffset += margin; - } - } - - /** - * Layout measurement for this widget. - * This method just sets a basic minimum size and makes the width maximized otherwise. - */ - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int widthMode = MeasureSpec.getMode(widthMeasureSpec); - int widthSize = MeasureSpec.getSize(widthMeasureSpec); - int heightMode = MeasureSpec.getMode(heightMeasureSpec); - int heightSize = MeasureSpec.getSize(heightMeasureSpec); - - int width = 0; - int height = 0; - - switch (widthMode) { - case MeasureSpec.EXACTLY: - width = widthSize; - break; - case MeasureSpec.AT_MOST: - width = widthSize; - break; - case MeasureSpec.UNSPECIFIED: - width = 10; - break; - } - - switch (heightMode) { - case MeasureSpec.EXACTLY: - height = heightSize; - break; - case MeasureSpec.AT_MOST: - height = 150; - break; - case MeasureSpec.UNSPECIFIED: - height = 10; - break; - } - - setMeasuredDimension(width, height); - } - - // The score being edited. - private ScoreView score_; - - // Structures used in drawing that we don't want to reallocate every time we draw. - private Paint paint_; - private Rect rect_; - private Rect textRect_; - - // The set of available tools. - private ScoreViewTool[] tool_; - - // The rect that each tool occupied the last time it was drawn. - private Rect[] toolRect_; -} diff --git a/android/src/com/levien/synthesizer/android/widgets/score/SelectChannelButton.java b/android/src/com/levien/synthesizer/android/widgets/score/SelectChannelButton.java deleted file mode 100644 index 4e653f2..0000000 --- a/android/src/com/levien/synthesizer/android/widgets/score/SelectChannelButton.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.widgets.score; - -import java.util.logging.Logger; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; - -/** - * A tool for selecting a particular channel in a ScoreView. - */ -public class SelectChannelButton extends ScoreViewTool { - /** - * Creates a tool for selecting the given channel, loading resources using the given context. - */ - SelectChannelButton(Context context, int channel) { - logger_ = Logger.getLogger(getClass().getName()); - channel_ = channel; - paint_ = new Paint(); - } - - /** - * Returns the channel that this control selects. - */ - public int getChannel() { - return channel_; - } - - /** - * Draws the button on the toolbar. - * @param canvas - The canvas to draw the button on. - * @param score - The ScoreView that this toolbar is for. - * @param rect - The area of the button to be drawn, including any margin. - * @param margin - The preferred margin around the button, in screen coordinates. - */ - @Override - public void drawButton(Canvas canvas, ScoreView score, Rect rect, float margin) { - if (score.getTool() == this) { - paint_.setColor(Color.WHITE); - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(rect.left - margin / 2, - rect.top - margin / 2, - rect.right + margin / 2, - rect.bottom + margin / 2, - paint_); - } - - if (getChannel() == score.getCurrentChannel()) { - paint_.setColor(score.getColorForChannel(getChannel())); - } else { - paint_.setColor(Color.BLACK); - } - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(rect, paint_); - Drawable icon = score.getIconForChannel(getChannel()); - icon.setBounds(rect); - icon.draw(canvas); - } - - /** - * Called when this tool is selected. - * Changes the selected channel for the view and then reselects the previously selected tool. - * @param view - The ScoreView that this toolbar is for. - * @param previousTool - The tool that was selected when this one was chosen. - */ - @Override - public void onSelect(ScoreView view, ScoreViewTool previousTool) { - view.setCurrentChannel(channel_); - view.setTool(previousTool); - } - - // The channel this control selects. - private int channel_; - - // Some objects used in drawing. They are owned here so that they don't have to be reallocated - // and garbage collected for every pass of drawing. - private Paint paint_; - - @SuppressWarnings("unused") - private Logger logger_; -} diff --git a/android/src/com/levien/synthesizer/android/widgets/score/SnapTool.java b/android/src/com/levien/synthesizer/android/widgets/score/SnapTool.java deleted file mode 100644 index 3805df6..0000000 --- a/android/src/com/levien/synthesizer/android/widgets/score/SnapTool.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.widgets.score; - -import com.levien.synthesizer.R; - -import java.util.logging.Logger; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; - -/** - * A control for selecting the "snap to" setting of a ScoreView. - * @see ScoreView - */ -public class SnapTool extends ScoreViewTool { - /** - * Creates a new SnapTool, loading resources from the given context. - */ - SnapTool(Context context) { - logger_ = Logger.getLogger(getClass().getName()); - - customIcon_ = context.getResources().getDrawable(R.drawable.unknown_note); - noneIcon_ = context.getResources().getDrawable(R.drawable.no_note); - thirtySecondIcon_ = context.getResources().getDrawable(R.drawable.thirtysecond_note); - sixteenthIcon_ = context.getResources().getDrawable(R.drawable.sixteenth_note); - eighthIcon_ = context.getResources().getDrawable(R.drawable.eighth_note); - quarterIcon_ = context.getResources().getDrawable(R.drawable.quarter_note); - halfIcon_ = context.getResources().getDrawable(R.drawable.half_note); - wholeIcon_ = context.getResources().getDrawable(R.drawable.whole_note); - - paint_ = new Paint(); - } - - /** - * Called when this tool is selected. Changes the "snap to" setting for the score view and then - * reselects the previously selected tool. - * @param view - The ScoreView that this toolbar is for. - * @param previousTool - The tool that was selected when this one was chosen. - */ - @Override - public void onSelect(ScoreView view, ScoreViewTool previousTool) { - if (view.getSnapTo() == 0.0) { - view.setSnapTo(1.0); - } else if (view.getSnapTo() <= 0.03125) { - view.setSnapTo(0.0); - } else { - view.setSnapTo(view.getSnapTo() / 2.0); - } - view.setTool(previousTool); - } - - /** - * Draws the button on the toolbar. - * @param canvas - The canvas to draw the button on. - * @param score - The ScoreView that this toolbar is for. - * @param rect - The area of the button to be drawn, including any margin. - * @param margin - The preferred margin around the button, in screen coordinates. - */ - @Override - public void drawButton(Canvas canvas, ScoreView score, Rect rect, float margin) { - if (score.getTool() == this) { - paint_.setColor(Color.WHITE); - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(rect.left - margin / 2, - rect.top - margin / 2, - rect.right + margin / 2, - rect.bottom + margin / 2, - paint_); - } - - paint_.setColor(Color.BLACK); - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(rect, paint_); - if (score.getSnapTo() == 1.0) { - wholeIcon_.setBounds(rect); - wholeIcon_.draw(canvas); - } else if (score.getSnapTo() == 0.5) { - halfIcon_.setBounds(rect); - halfIcon_.draw(canvas); - } else if (score.getSnapTo() == 0.25) { - quarterIcon_.setBounds(rect); - quarterIcon_.draw(canvas); - } else if (score.getSnapTo() == 0.125) { - eighthIcon_.setBounds(rect); - eighthIcon_.draw(canvas); - } else if (score.getSnapTo() == 0.0625) { - sixteenthIcon_.setBounds(rect); - sixteenthIcon_.draw(canvas); - } else if (score.getSnapTo() == 0.03125) { - thirtySecondIcon_.setBounds(rect); - thirtySecondIcon_.draw(canvas); - } else if (score.getSnapTo() == 0.0) { - noneIcon_.setBounds(rect); - noneIcon_.draw(canvas); - } else { - customIcon_.setBounds(rect); - customIcon_.draw(canvas); - } - } - - // Some objects used in drawing. They are owned here so that they don't have to be reallocated - // and garbage collected for every pass of drawing. - private Paint paint_; - private Drawable customIcon_; - private Drawable noneIcon_; - private Drawable thirtySecondIcon_; - private Drawable sixteenthIcon_; - private Drawable eighthIcon_; - private Drawable quarterIcon_; - private Drawable halfIcon_; - private Drawable wholeIcon_; - - @SuppressWarnings("unused") - private Logger logger_; -} diff --git a/android/src/com/levien/synthesizer/android/widgets/score/ViewportTool.java b/android/src/com/levien/synthesizer/android/widgets/score/ViewportTool.java deleted file mode 100644 index 19b16f4..0000000 --- a/android/src/com/levien/synthesizer/android/widgets/score/ViewportTool.java +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.widgets.score; - -import java.util.logging.Logger; - -import com.levien.synthesizer.R; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; -import android.view.MotionEvent; - -/** - * A tool for adjusting the visible logical area of a ScoreView. - * When this tool is selected, touching moves around the viewport, and pinching zooms in/out. - */ -public class ViewportTool extends ScoreViewTool { - /** - * Creates a new ViewportTool, loading resources from the given context. - */ - ViewportTool(Context context) { - logger_ = Logger.getLogger(getClass().getName()); - - startX1_ = 0; - startX2_ = 0; - startY1_ = 0; - startY2_ = 0; - - icon_ = context.getResources().getDrawable(R.drawable.zoom); - paint_ = new Paint(); - } - - /** - * Draws the button on the toolbar. - * @param canvas - The canvas to draw the button on. - * @param score - The ScoreView that this toolbar is for. - * @param rect - The area of the button to be drawn, including any margin. - * @param margin - The preferred margin around the button, in screen coordinates. - */ - @Override - public void drawButton(Canvas canvas, ScoreView score, Rect rect, float margin) { - if (score.getTool() == this) { - paint_.setColor(Color.WHITE); - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(rect.left - margin / 2, - rect.top - margin / 2, - rect.right + margin / 2, - rect.bottom + margin / 2, - paint_); - } - - paint_.setColor(Color.BLACK); - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(rect, paint_); - icon_.setBounds(rect); - icon_.draw(canvas); - } - - /** - * Called when the user touches the ScoreView while this tool is selected. - * @param view - The ScoreView that this tool is for. - * @param event - The touch event that triggered this handler. - * @return true iff this tool handled the touch event. - */ - @Override - public boolean onTouch(ScoreView view, MotionEvent event) { - int action = event.getAction(); - int actionCode = action & MotionEvent.ACTION_MASK; - boolean redraw = false; - double timeZoom = view.getTimeZoom(); - double timeOffset = view.getTimeOffset(); - double noteZoom = view.getNoteZoom(); - double noteOffset = view.getNoteOffset(); - - if (actionCode == MotionEvent.ACTION_DOWN) { - int pointerId = event.getPointerId(0); - startX1_ = (int)event.getX(); - startY1_ = (int)event.getY(); - if (pointerId != 0) { - logger_.severe("Initial pointer has id " + pointerId); - } - } else if (actionCode == MotionEvent.ACTION_POINTER_DOWN) { - int pointerId = action >> MotionEvent.ACTION_POINTER_ID_SHIFT; - int pointerIndex = event.findPointerIndex(pointerId); - if (pointerId == 1 && pointerIndex >= 0) { - startX2_ = (int)event.getX(pointerIndex); - startY2_ = (int)event.getY(pointerIndex); - } - } else if (actionCode == MotionEvent.ACTION_MOVE) { - double currentX1 = 0; - double currentX2 = 0; - double currentY1 = 0; - double currentY2 = 0; - boolean has1 = false; - boolean has2 = false; - - // Find the current positions of the fingers. - for (int pointerIndex = 0; pointerIndex < event.getPointerCount(); ++pointerIndex) { - int pointerId = event.getPointerId(pointerIndex); - if (pointerId >= 0) { - int x = (int)event.getX(pointerIndex); - int y = (int)event.getY(pointerIndex); - if (pointerId == 0) { - currentX1 = x; - currentY1 = y; - has1 = true; - } else if (pointerId == 1) { - currentX2 = x; - currentY2 = y; - has2 = true; - } - } - } - - if (has1 && has2) { - // Enforce that finger 1 is to the left of and above finger 2. - if (currentX2 < currentX1) { - double temp = currentX1; - currentX1 = currentX2; - currentX2 = temp; - } - if (currentY2 < currentY1) { - double temp = currentY1; - currentY1 = currentY2; - currentY2 = temp; - } - if (startX2_ < startX1_) { - double temp = startX1_; - startX1_ = startX2_; - startX2_ = temp; - } - if (startY2_ < startY1_) { - double temp = startY1_; - startY1_ = startY2_; - startY2_ = temp; - } - - // Make sure the fingers aren't too close together. - if (startX2_ - startX1_ < 50.0) { - startX2_ = startX1_ + 50.0; - } - if (currentX2 - currentX1 < 50.0) { - currentX2 = currentX1 + 50.0; - } - if (startY2_ - startY1_ < 50.0) { - startY2_ = startY1_ + 50.0; - } - if (currentY2 - currentY1 < 50.0) { - currentY2 = currentY1 + 50.0; - } - - // Figure out the parameters of the new viewport. - double scaleXFactor = Math.abs((currentX1 - currentX2) / (startX1_ - startX2_)); - timeOffset += (startX1_ - currentX1 / scaleXFactor) / - (timeZoom * view.getDrawingRect().width()); - timeZoom *= scaleXFactor; - - double scaleYFactor = Math.abs((currentY1 - currentY2) / (startY1_ - startY2_)); - noteOffset -= (startY1_ - currentY1/scaleYFactor - - view.getDrawingRect().bottom * (1 - 1/scaleYFactor)) / - (noteZoom * view.getDrawingRect().height()); - - noteZoom *= scaleYFactor; - - // Update the tracking. - startX1_ = currentX1; - startX2_ = currentX2; - startY1_ = currentY1; - startY2_ = currentY2; - redraw = true; - } else if (has1) { - // Move the viewport. - timeOffset += (startX1_ - currentX1) / (timeZoom * view.getDrawingRect().width()); - startX1_ = currentX1; - noteOffset -= (startY1_ - currentY1) / (noteZoom * view.getDrawingRect().height()); - startY1_ = currentY1; - redraw = true; - } - } else if (actionCode == MotionEvent.ACTION_UP) { - // Snap back so we aren't showing much margin. - // This code is commented out because it's actually much more intuitive if it doesn't snap - // back but just shows some margin. - /* - if (scaleX < 1.0 / maxX) { - offsetX = 0.0; - scaleX = 1.0 / maxX; - redraw = true; - } - if (scaleY < 1.0 / maxY) { - offsetY = 0.0; - scaleY = 1.0 / maxY; - redraw = true; - } - if (offsetX < 0.0) { - offsetX = 0.0; - redraw = true; - } - if (offsetY < 0.0) { - offsetY = 0.0; - redraw = true; - } - if (offsetX > maxX - 1.0 / scaleX) { - offsetX = maxX - 1.0 / scaleX; - redraw = true; - } - if (offsetY > maxY - 1.0 / scaleY) { - offsetY = maxY - 1.0 / scaleY; - redraw = true; - } - */ - } else if (actionCode == MotionEvent.ACTION_POINTER_UP) { - } else { - return view.onTouchEvent(event); - } - - view.setTimeZoom(timeZoom); - view.setTimeOffset(timeOffset); - view.setNoteZoom(noteZoom); - view.setNoteOffset(noteOffset); - - if (redraw) { - view.invalidate(); - } - - return true; - } - - // The screen coordinates of the first and second fingers pressed on the ScoreView. - // These are updated every time the viewport is updated. - private double startX1_; - private double startX2_; - private double startY1_; - private double startY2_; - - // Some objects used in drawing. They are owned here so that they don't have to be reallocated - // and garbage collected for every pass of drawing. - private Paint paint_; - private Drawable icon_; - - private Logger logger_; -} diff --git a/android/src/com/levien/synthesizer/android/widgets/waveform/WaveformListener.java b/android/src/com/levien/synthesizer/android/widgets/waveform/WaveformListener.java deleted file mode 100644 index d8b9ebb..0000000 --- a/android/src/com/levien/synthesizer/android/widgets/waveform/WaveformListener.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.widgets.waveform; - -/** - * WaveformListener is an interface for getting events when a WaveformView's value changes. - */ -public interface WaveformListener { - /** - * Called when the value changes. - */ - void onWaveformChanged(String waveform); -} diff --git a/android/src/com/levien/synthesizer/android/widgets/waveform/WaveformRowView.java b/android/src/com/levien/synthesizer/android/widgets/waveform/WaveformRowView.java deleted file mode 100644 index cd3b5a0..0000000 --- a/android/src/com/levien/synthesizer/android/widgets/waveform/WaveformRowView.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.widgets.waveform; - -import com.levien.synthesizer.core.model.WaveformInput; - -import android.app.AlertDialog; -import android.content.Context; -import android.content.DialogInterface; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.util.AttributeSet; -import android.view.MotionEvent; - -/** - * WaveformRowView is like a WaveformView, but it arranges its buttons in a row. - */ -public class WaveformRowView extends WaveformView { - /** Basic constructor for an Android widget. */ - public WaveformRowView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - /** - * Touch event handler. - */ - @Override - public boolean onTouchEvent(MotionEvent event) { - int action = event.getAction(); - switch (action) { - case MotionEvent.ACTION_DOWN: { - getDrawingRect(rect_); - double x = (event.getX() - rect_.left) / rect_.width(); - if (x < 1.0/6.0f) { - setWaveform(WaveformInput.SINE); - } else if (x < 2.0/6.0f) { - setWaveform(WaveformInput.TRIANGLE); - } else if (x < 3.0/6.0f) { - setWaveform(WaveformInput.SQUARE); - } else if (x < 4.0/6.0f) { - setWaveform(WaveformInput.SAWTOOTH); - } else if (x < 5.0/6.0f) { - setWaveform(WaveformInput.NOISE); - } else { - CharSequence[] items = new CharSequence[input_.getWaveformCount()]; - for (int i = 0; i < items.length; ++i) { - items[i] = input_.getWaveform(i); - } - AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); - builder.setItems(items, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - setWaveform(input_.getWaveform(which)); - } - }); - builder.create().show(); - } - invalidate(); - break; - } - - case MotionEvent.ACTION_MOVE: { - break; - } - - case MotionEvent.ACTION_UP: { - break; - } - } - return true; - } - - /** - * Drawing handler. - */ - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - - getDrawingRect(rect_); - rect_.set(rect_); - - paint_.setColor(Color.BLACK); - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(rect_, paint_); - - // Draw waveforms. - float lineWidth = 5.0f; - float margin = 15.0f; - float waveWidth = (rect_.width() - 7.0f * margin) / 6.0f; - float waveHeight = (rect_.height() - 2.0f * margin); - - float xOffset = margin; - float yOffset = margin; - drawSine(canvas, xOffset, yOffset, waveWidth, waveHeight, margin, lineWidth); - xOffset += waveWidth; - xOffset += margin; - drawTriangle(canvas, xOffset, yOffset, waveWidth, waveHeight, margin, lineWidth); - xOffset += waveWidth; - xOffset += margin; - drawSquare(canvas, xOffset, yOffset, waveWidth, waveHeight, margin, lineWidth); - xOffset += waveWidth; - xOffset += margin; - drawSawtooth(canvas, xOffset, yOffset, waveWidth, waveHeight, margin, lineWidth); - xOffset += waveWidth; - xOffset += margin; - drawNoise(canvas, xOffset, yOffset, waveWidth, waveHeight, margin, lineWidth); - xOffset += waveWidth; - xOffset += margin; - drawOther(canvas, xOffset, yOffset, waveWidth, waveHeight, margin, lineWidth); - } - - /** - * Layout measurement for this widget. - * This method just sets a basic minimum size and makes the width maximized otherwise. - */ - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int widthMode = MeasureSpec.getMode(widthMeasureSpec); - int widthSize = MeasureSpec.getSize(widthMeasureSpec); - int heightMode = MeasureSpec.getMode(heightMeasureSpec); - int heightSize = MeasureSpec.getSize(heightMeasureSpec); - - int width = 0; - int height = 0; - - switch (widthMode) { - case MeasureSpec.EXACTLY: - width = widthSize; - break; - case MeasureSpec.AT_MOST: - width = widthSize; - break; - case MeasureSpec.UNSPECIFIED: - width = 10; - break; - } - - switch (heightMode) { - case MeasureSpec.EXACTLY: - height = heightSize; - break; - case MeasureSpec.AT_MOST: - height = 150; - break; - case MeasureSpec.UNSPECIFIED: - height = 10; - break; - } - - setMeasuredDimension(width, height); - } -} diff --git a/android/src/com/levien/synthesizer/android/widgets/waveform/WaveformView.java b/android/src/com/levien/synthesizer/android/widgets/waveform/WaveformView.java deleted file mode 100644 index 430c14c..0000000 --- a/android/src/com/levien/synthesizer/android/widgets/waveform/WaveformView.java +++ /dev/null @@ -1,470 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.widgets.waveform; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Path; -import android.graphics.Rect; -import android.util.AttributeSet; -import android.util.Log; -import android.view.MotionEvent; -import android.view.View; -import com.levien.synthesizer.core.model.WaveformInput; -import com.levien.synthesizer.core.model.composite.MultiChannelSynthesizer; -import com.levien.synthesizer.core.model.composite.Presets.Setting; - -/** - * WaveformView is a control for selecting from among available waveforms. - * It's designed to occupy the same space as a KnobView. - */ -public class WaveformView extends View { - /** Basic constructor for an Android widget. */ - public WaveformView(Context context, AttributeSet attrs) { - super(context, attrs); - - waveform_ = WaveformInput.SINE; - - // Set up the drawing structures. - paint_ = new Paint(); - path_ = new Path(); - rect_ = new Rect(); - - // The listener has to be set later. - listener_ = null; - - setPadding(3, 3, 3, 3); - } - - /** - * Touch event handler. - */ - @Override - public boolean onTouchEvent(MotionEvent event) { - int action = event.getAction(); - switch (action) { - case MotionEvent.ACTION_DOWN: { - getDrawingRect(rect_); - double x = (event.getX() - rect_.left) / rect_.width(); - double y = (event.getY() - rect_.top) / rect_.height(); - if (x < 0.5) { - if (y < 0.34) { - setWaveform(WaveformInput.SINE); - } else if (y < 0.67) { - setWaveform(WaveformInput.TRIANGLE); - } else { - setWaveform(WaveformInput.SQUARE); - } - } else { - if (y < 0.34) { - setWaveform(WaveformInput.SAWTOOTH); - } else if (y < 0.67) { - setWaveform(WaveformInput.NOISE); - } - } - invalidate(); - break; - } - - case MotionEvent.ACTION_MOVE: { - break; - } - - case MotionEvent.ACTION_UP: { - break; - } - } - return true; - } - - /** - * Sets the listener to receive events when the value changes. - */ - public void setWaveformListener(WaveformListener listener) { - listener_ = listener; - } - - /** - * Sets the current value of the knob. - */ - public void setWaveform(String waveform) { - waveform_ = waveform; - if (listener_ != null) { - listener_.onWaveformChanged(waveform); - } - invalidate(); - } - - /** - * Returns the current value of the knob. - */ - public String getWaveform() { - return waveform_; - } - - /** - * Draws a button for selecting a sine waveform. - */ - protected void drawSine(Canvas canvas, - float x, float y, - float width, float height, - float margin, - float lineWidth) { - int steps = 12; - - // Sine wave. - path_.reset(); - path_.moveTo(x, y + (height / 2)); - for (int i = 0; i < steps + 1; i++) { - float x1 = x + (i / (float)steps) * width; - float y1 = y + -1 * (height/2) * (float)Math.sin(2.0f/steps * Math.PI * i) + height/2; - path_.lineTo(x1, y1); - } - paint_.setColor(Color.WHITE); - if (waveform_.equals(WaveformInput.SINE)) { - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(x - margin / 2, - y - margin / 2, - x + width + margin / 2, - y + height + margin / 2, - paint_); - paint_.setColor(Color.BLACK); - } - paint_.setStyle(Paint.Style.STROKE); - paint_.setStrokeWidth(lineWidth); - paint_.setStrokeJoin(Paint.Join.ROUND); - canvas.drawPath(path_, paint_); - } - - /** - * Draws a button for selecting a triangle waveform. - */ - protected void drawTriangle(Canvas canvas, - float x, float y, - float width, float height, - float margin, - float lineWidth) { - // Triangle Wave. - path_.reset(); - path_.moveTo(x, y + (height / 2)); - path_.lineTo(x + width / 4, y); - path_.lineTo(x + width * (3.0f / 4.0f), y + height); - path_.lineTo(x + width, y + (height / 2)); - paint_.setColor(Color.WHITE); - if (waveform_.equals(WaveformInput.TRIANGLE)) { - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(x - margin / 2, - y - margin / 2, - x + width + margin / 2, - y + height + margin / 2, - paint_); - paint_.setColor(Color.BLACK); - } - paint_.setStyle(Paint.Style.STROKE); - paint_.setStrokeWidth(lineWidth); - paint_.setStrokeJoin(Paint.Join.ROUND); - canvas.drawPath(path_, paint_); - } - - /** - * Draws a button for selecting a square waveform. - */ - protected void drawSquare(Canvas canvas, - float x, float y, - float width, float height, - float margin, - float lineWidth) { - // Square Wave. - path_.reset(); - path_.moveTo(x, y + height); - path_.lineTo(x + width / 4, y + height); - path_.lineTo(x + width / 4, y); - path_.lineTo(x + width * (3.0f / 4.0f), y); - path_.lineTo(x + width * (3.0f / 4.0f), y + height); - path_.lineTo(x + width, y + height); - paint_.setColor(Color.WHITE); - if (waveform_.equals(WaveformInput.SQUARE)) { - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(x - margin / 2, - y - margin / 2, - x + width + margin / 2, - y + height + margin / 2, - paint_); - paint_.setColor(Color.BLACK); - } - paint_.setStyle(Paint.Style.STROKE); - paint_.setStrokeWidth(lineWidth); - paint_.setStrokeJoin(Paint.Join.ROUND); - canvas.drawPath(path_, paint_); - } - - /** - * Draws a button for selecting a sawtooth waveform. - */ - protected void drawSawtooth(Canvas canvas, - float x, float y, - float width, float height, - float margin, - float lineWidth) { - // Sawtooth Wave. - path_.reset(); - path_.moveTo(x, y + height); - path_.lineTo(x, y); - path_.lineTo(x + width / 2, y + height); - path_.lineTo(x + width / 2, y); - path_.lineTo(x + width, y + height); - paint_.setColor(Color.WHITE); - if (waveform_.equals(WaveformInput.SAWTOOTH)) { - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(x - margin / 2, - y - margin / 2, - x + width + margin / 2, - y + height + margin / 2, - paint_); - paint_.setColor(Color.BLACK); - } - paint_.setStyle(Paint.Style.STROKE); - paint_.setStrokeWidth(lineWidth); - paint_.setStrokeJoin(Paint.Join.ROUND); - canvas.drawPath(path_, paint_); - } - - /** - * Draws a button for selecting a noise waveform. - */ - protected void drawNoise(Canvas canvas, - float x, float y, - float width, float height, - float margin, - float lineWidth) { - // Noise. - path_.reset(); - path_.moveTo(x, y + height * 0.5f); - path_.lineTo(x + 0.125f * width, y + height * 0.4f); - path_.lineTo(x + 0.25f * width, y + height * 1.0f); - path_.lineTo(x + 0.375f * width, y + height * 0.3f); - path_.lineTo(x + 0.5f * width, y + height * 0.7f); - path_.lineTo(x + 0.625f * width, y + height * 0.0f); - path_.lineTo(x + 0.75f * width, y + height * 0.8f); - path_.lineTo(x + 0.875f * width, y + height * 0.2f); - path_.lineTo(x + 1.0f * width, y + height * 0.5f); - paint_.setColor(Color.WHITE); - if (waveform_.equals(WaveformInput.NOISE)) { - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(x - margin / 2, - y - margin / 2, - x + width + margin / 2, - y + height + margin / 2, - paint_); - paint_.setColor(Color.BLACK); - } - paint_.setStyle(Paint.Style.STROKE); - paint_.setStrokeWidth(lineWidth); - paint_.setStrokeJoin(Paint.Join.ROUND); - canvas.drawPath(path_, paint_); - } - - /** - * Draws a button for selecting a Karplus-Strong waveform. - */ - protected void drawOther(Canvas canvas, - float x, float y, - float width, float height, - float margin, - float lineWidth) { - int steps = 12; - - paint_.setColor(Color.WHITE); - if (!waveform_.equals(WaveformInput.SINE) && - !waveform_.equals(WaveformInput.TRIANGLE) && - !waveform_.equals(WaveformInput.SAWTOOTH) && - !waveform_.equals(WaveformInput.SQUARE) && - !waveform_.equals(WaveformInput.NOISE)) { - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(x - margin / 2, - y - margin / 2, - x + width + margin / 2, - y + height + margin / 2, - paint_); - paint_.setColor(Color.BLACK); - } - paint_.setStyle(Paint.Style.STROKE); - paint_.setStrokeWidth(lineWidth); - paint_.setStrokeJoin(Paint.Join.ROUND); - - path_.reset(); - path_.moveTo(x, y + (height / 2)); - for (int i = 0; i < steps + 1; i++) { - float x1 = x + (i / (float)steps) * width; - float y1 = y + -1 * (height/2) * (float)Math.sin(2.0f/steps * Math.PI * i) + height/2; - path_.lineTo(x1, y1); - } - canvas.drawPath(path_, paint_); - - path_.reset(); - path_.moveTo(x, y + (height / 2)); - for (int i = 0; i < steps + 1; i++) { - float x1 = x + (i / (float)steps) * width; - float y1 = y + -0.6f * (height/2) * (float)Math.sin(2.0f/steps * Math.PI * (steps-i)) + height/2; - path_.lineTo(x1, y1); - } - canvas.drawPath(path_, paint_); - } - - /** - * Drawing handler. - */ - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - - getDrawingRect(rect_); - rect_.set(rect_); - // Make it square. - if (rect_.height() > rect_.width()) { - int center = rect_.centerY(); - rect_.top = center - rect_.width() / 2; - rect_.bottom = center + rect_.width() / 2; - } else { - int center = rect_.centerX(); - rect_.left = center - rect_.height() / 2; - rect_.right = center + rect_.height() / 2; - } - - paint_.setColor(Color.BLACK); - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(rect_, paint_); - - // Draw waveforms. - float lineWidth = 5.0f; - float margin = 15.0f; - float waveWidth = (rect_.width() - 3.0f * margin) / 2.0f; - float waveHeight = (rect_.height() - 4.0f * margin) / 3.0f; - - float xOffset = margin; - float yOffset = margin; - drawSine(canvas, xOffset, yOffset, waveWidth, waveHeight, margin, lineWidth); - yOffset += waveHeight; - yOffset += margin; - drawTriangle(canvas, xOffset, yOffset, waveWidth, waveHeight, margin, lineWidth); - yOffset += waveHeight; - yOffset += margin; - drawSquare(canvas, xOffset, yOffset, waveWidth, waveHeight, margin, lineWidth); - yOffset = margin; - xOffset += waveWidth; - xOffset += margin; - drawSawtooth(canvas, xOffset, yOffset, waveWidth, waveHeight, margin, lineWidth); - yOffset += waveHeight; - yOffset += margin; - drawNoise(canvas, xOffset, yOffset, waveWidth, waveHeight, margin, lineWidth); - yOffset += waveHeight; - yOffset += margin; - drawOther(canvas, xOffset, yOffset, waveWidth, waveHeight, margin, lineWidth); - } - - /** - * Controls how the knob is sized; it is square, and prefers to be 100x100 pixels. - */ - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int widthMode = MeasureSpec.getMode(widthMeasureSpec); - int widthSize = MeasureSpec.getSize(widthMeasureSpec); - int heightMode = MeasureSpec.getMode(heightMeasureSpec); - int heightSize = MeasureSpec.getSize(heightMeasureSpec); - - // Specify that 100 is preferred for both dimensions. - int width = 0; - int height = 0; - switch (widthMode) { - case MeasureSpec.EXACTLY: - width = widthSize; - break; - case MeasureSpec.AT_MOST: - width = widthSize; - break; - case MeasureSpec.UNSPECIFIED: - width = 100; - break; - } - switch (heightMode) { - case MeasureSpec.EXACTLY: - height = heightSize; - break; - case MeasureSpec.AT_MOST: - height = heightSize; - break; - case MeasureSpec.UNSPECIFIED: - height = 100; - break; - } - - // Make it square. - if (width > height && widthMode != MeasureSpec.EXACTLY) { - width = height; - } - if (height > width && heightMode != MeasureSpec.EXACTLY) { - height = width; - } - - setMeasuredDimension(width, height); - } - - /** - * Connects control to a WaveformInput. - * @input - The synthesizer input to connect to. - */ - public void bindTo(WaveformInput waveform) { - input_ = waveform; - setWaveform(waveform.getWaveform(waveform.getSelected())); - setWaveformListener(new WaveformListener() { - public void onWaveformChanged(String newValue) { - input_.select(newValue); - } - }); - } - - /** - * Connects control to a WaveformSelector module. - * @synth - The synthesizer to connect to. - * @setting - The setting to connect to. - * @return - True on success, false on failure. - */ - public boolean bindTo(final MultiChannelSynthesizer synth, int channel, Setting setting) { - WaveformInput input = synth.getChannel(0).getWaveformInput(setting); - if (input != null) { - bindTo(input); - return true; - } else { - Log.e(getClass().getName(), "Unable to bind to setting " + setting.name() + "."); - return false; - } - } - - // Currently selected waveform. - private String waveform_; - protected WaveformInput input_; - - // Structures used in drawing that we don't want to reallocate every time we draw. - protected Paint paint_; - protected Path path_; - protected Rect rect_; - - // Object listening for events when the knob's value changes. - private WaveformListener listener_; -} diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..d158a9e --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,41 @@ +apply plugin: 'com.android.model.application' + +model { + android { + compileSdkVersion 23 + buildToolsVersion "23.0.3" + + defaultConfig { + applicationId "com.levien.synthesizer" + minSdkVersion.apiLevel 16 + targetSdkVersion.apiLevel 23 + versionCode 1 + versionName "1.0" + } + buildTypes { + release { + minifyEnabled false + proguardFiles.add(file('proguard-android.txt')) + } + } + ndk { + moduleName "synth" + ldLibs.addAll(['log', 'OpenSLES']) + } + sources { + main { + jni { + source { + excludes.addAll(["main.cc", "wavout.cc", "test_*.cc", "SynthApp/*"]) + } + } + } + } + } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + testCompile 'junit:junit:4.12' + compile 'com.android.support:appcompat-v7:23.4.0' +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..0b51b5f --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /Users/raph/Library/Android/sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/app/src/androidTest/java/com/levien/synthesizer/ApplicationTest.java b/app/src/androidTest/java/com/levien/synthesizer/ApplicationTest.java new file mode 100644 index 0000000..12634bc --- /dev/null +++ b/app/src/androidTest/java/com/levien/synthesizer/ApplicationTest.java @@ -0,0 +1,13 @@ +package com.levien.synthesizer; + +import android.app.Application; +import android.test.ApplicationTestCase; + +/** + * Testing Fundamentals + */ +public class ApplicationTest extends ApplicationTestCase { + public ApplicationTest() { + super(Application.class); + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..f1b60d7 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/src/com/levien/synthesizer/android/AndroidGlue.java b/app/src/main/java/com/levien/synthesizer/android/AndroidGlue.java similarity index 100% rename from android/src/com/levien/synthesizer/android/AndroidGlue.java rename to app/src/main/java/com/levien/synthesizer/android/AndroidGlue.java diff --git a/android/src/com/levien/synthesizer/android/service/SynthesizerService.java b/app/src/main/java/com/levien/synthesizer/android/service/SynthesizerService.java similarity index 97% rename from android/src/com/levien/synthesizer/android/service/SynthesizerService.java rename to app/src/main/java/com/levien/synthesizer/android/service/SynthesizerService.java index e17c3b6..1aa7e42 100755 --- a/android/src/com/levien/synthesizer/android/service/SynthesizerService.java +++ b/app/src/main/java/com/levien/synthesizer/android/service/SynthesizerService.java @@ -43,7 +43,6 @@ import com.levien.synthesizer.android.AndroidGlue; import com.levien.synthesizer.android.usb.UsbMidiDevice; import com.levien.synthesizer.core.midi.MessageTee; import com.levien.synthesizer.core.midi.MidiListener; -import com.levien.synthesizer.core.model.composite.MultiChannelSynthesizer; /** * An Android Service that plays audio from a synthesizer. @@ -56,15 +55,6 @@ public class SynthesizerService extends Service { public SynthesizerService getService() { return SynthesizerService.this; } - - /** - * Gets the underlying synthesizer powering this service. - * - * Obsolete, to be deleted. - */ - public MultiChannelSynthesizer getSynthesizer() { - return null; - } } /** diff --git a/android/src/com/levien/synthesizer/android/service/SynthesizerThread.java b/app/src/main/java/com/levien/synthesizer/android/service/SynthesizerThread.java similarity index 90% rename from android/src/com/levien/synthesizer/android/service/SynthesizerThread.java rename to app/src/main/java/com/levien/synthesizer/android/service/SynthesizerThread.java index ca1e816..a6765ce 100755 --- a/android/src/com/levien/synthesizer/android/service/SynthesizerThread.java +++ b/app/src/main/java/com/levien/synthesizer/android/service/SynthesizerThread.java @@ -14,14 +14,14 @@ * limitations under the License. */ +// This class is probably obsolete and should be deleted + package com.levien.synthesizer.android.service; import android.media.AudioFormat; import android.media.AudioManager; import android.media.AudioTrack; import android.util.Log; -import com.levien.synthesizer.core.model.SynthesisTime; -import com.levien.synthesizer.core.model.composite.MultiChannelSynthesizer; /** * SynthesizerThread is a thread-safe interface to a thread that constantly plays sampled audio data @@ -30,18 +30,14 @@ import com.levien.synthesizer.core.model.composite.MultiChannelSynthesizer; public class SynthesizerThread { /** * Creates a new SynthesizerThread that will play audio from synthesizer. - * @param synthesizer - the source of the audio data to output. */ - public SynthesizerThread(MultiChannelSynthesizer synthesizer, int sampleRateInHz) { + public SynthesizerThread(int sampleRateInHz) { playingLock_ = new Object(); playing_ = false; shouldDie_ = false; audioTrackLock_ = new Object(); audioTrack_ = null; - synthesizer_ = synthesizer; sampleRateInHz_ = sampleRateInHz; - time_ = new SynthesisTime(); - time_.setSampleRate(sampleRateInHz); } /** @@ -141,7 +137,6 @@ public class SynthesizerThread { bufferSizeInBytes, // int bufferSizeInBytes, AudioTrack.MODE_STREAM); // int mode); buffer_ = new short[bufferSizeInBytes / 8]; - time_.reset(); } } @@ -177,7 +172,7 @@ public class SynthesizerThread { for (int i = 0; i < buffer_.length; ++i) { // Change the output range from [-1, 1] to [-32767, 32767]. // 16-bit signed output is fairly standard, and hard-coded. - double output = synthesizer_.getValue(time_); + double output = 0; // Clamp values out of range. if (output < -1.0) { output = -1.0; @@ -186,7 +181,6 @@ public class SynthesizerThread { output = 1.0; } buffer_[i] = (short)(32767 * output); - time_.advance(); } synchronized (audioTrackLock_) { if (audioTrack_ != null) { @@ -221,10 +215,4 @@ public class SynthesizerThread { // The sample rate of the synthesizer. private int sampleRateInHz_; - - // Tracker for time since synthesis started. - private SynthesisTime time_; - - // Module to provide sampled audio data to be output. - private MultiChannelSynthesizer synthesizer_; } diff --git a/android/src/com/levien/synthesizer/android/stats/JitterStats.java b/app/src/main/java/com/levien/synthesizer/android/stats/JitterStats.java similarity index 100% rename from android/src/com/levien/synthesizer/android/stats/JitterStats.java rename to app/src/main/java/com/levien/synthesizer/android/stats/JitterStats.java diff --git a/android/src/com/levien/synthesizer/android/ui/PianoActivity2.java b/app/src/main/java/com/levien/synthesizer/android/ui/PianoActivity2.java similarity index 99% rename from android/src/com/levien/synthesizer/android/ui/PianoActivity2.java rename to app/src/main/java/com/levien/synthesizer/android/ui/PianoActivity2.java index 26da9c0..0008473 100644 --- a/android/src/com/levien/synthesizer/android/ui/PianoActivity2.java +++ b/app/src/main/java/com/levien/synthesizer/android/ui/PianoActivity2.java @@ -89,9 +89,11 @@ public class PianoActivity2 extends SynthActivity implements OnSharedPreferenceC case R.id.settings: startActivity(new Intent(this, SettingsActivity.class)); return true; + /* case R.id.compose: startActivity(new Intent(this, ScoreActivity.class)); return true; + */ default: return super.onOptionsItemSelected(item); } diff --git a/android/src/com/levien/synthesizer/android/ui/SettingsActivity.java b/app/src/main/java/com/levien/synthesizer/android/ui/SettingsActivity.java similarity index 100% rename from android/src/com/levien/synthesizer/android/ui/SettingsActivity.java rename to app/src/main/java/com/levien/synthesizer/android/ui/SettingsActivity.java diff --git a/android/src/com/levien/synthesizer/android/ui/SynthActivity.java b/app/src/main/java/com/levien/synthesizer/android/ui/SynthActivity.java similarity index 100% rename from android/src/com/levien/synthesizer/android/ui/SynthActivity.java rename to app/src/main/java/com/levien/synthesizer/android/ui/SynthActivity.java diff --git a/android/src/com/levien/synthesizer/android/usb/UsbMidiDevice.java b/app/src/main/java/com/levien/synthesizer/android/usb/UsbMidiDevice.java similarity index 100% rename from android/src/com/levien/synthesizer/android/usb/UsbMidiDevice.java rename to app/src/main/java/com/levien/synthesizer/android/usb/UsbMidiDevice.java diff --git a/android/src/com/levien/synthesizer/android/widgets/keyboard/KeySpec.java b/app/src/main/java/com/levien/synthesizer/android/widgets/keyboard/KeySpec.java similarity index 100% rename from android/src/com/levien/synthesizer/android/widgets/keyboard/KeySpec.java rename to app/src/main/java/com/levien/synthesizer/android/widgets/keyboard/KeySpec.java diff --git a/android/src/com/levien/synthesizer/android/widgets/keyboard/KeyboardSpec.java b/app/src/main/java/com/levien/synthesizer/android/widgets/keyboard/KeyboardSpec.java similarity index 100% rename from android/src/com/levien/synthesizer/android/widgets/keyboard/KeyboardSpec.java rename to app/src/main/java/com/levien/synthesizer/android/widgets/keyboard/KeyboardSpec.java diff --git a/android/src/com/levien/synthesizer/android/widgets/keyboard/KeyboardView.java b/app/src/main/java/com/levien/synthesizer/android/widgets/keyboard/KeyboardView.java similarity index 100% rename from android/src/com/levien/synthesizer/android/widgets/keyboard/KeyboardView.java rename to app/src/main/java/com/levien/synthesizer/android/widgets/keyboard/KeyboardView.java diff --git a/android/src/com/levien/synthesizer/android/widgets/keyboard/ScrollStripView.java b/app/src/main/java/com/levien/synthesizer/android/widgets/keyboard/ScrollStripView.java similarity index 100% rename from android/src/com/levien/synthesizer/android/widgets/keyboard/ScrollStripView.java rename to app/src/main/java/com/levien/synthesizer/android/widgets/keyboard/ScrollStripView.java diff --git a/android/src/com/levien/synthesizer/android/widgets/knob/KnobListener.java b/app/src/main/java/com/levien/synthesizer/android/widgets/knob/KnobListener.java similarity index 100% rename from android/src/com/levien/synthesizer/android/widgets/knob/KnobListener.java rename to app/src/main/java/com/levien/synthesizer/android/widgets/knob/KnobListener.java diff --git a/android/src/com/levien/synthesizer/android/widgets/knob/KnobPlaceholderView.java b/app/src/main/java/com/levien/synthesizer/android/widgets/knob/KnobPlaceholderView.java similarity index 100% rename from android/src/com/levien/synthesizer/android/widgets/knob/KnobPlaceholderView.java rename to app/src/main/java/com/levien/synthesizer/android/widgets/knob/KnobPlaceholderView.java diff --git a/android/src/com/levien/synthesizer/android/widgets/knob/KnobPreference.java b/app/src/main/java/com/levien/synthesizer/android/widgets/knob/KnobPreference.java similarity index 100% rename from android/src/com/levien/synthesizer/android/widgets/knob/KnobPreference.java rename to app/src/main/java/com/levien/synthesizer/android/widgets/knob/KnobPreference.java diff --git a/android/src/com/levien/synthesizer/android/widgets/knob/KnobView.java b/app/src/main/java/com/levien/synthesizer/android/widgets/knob/KnobView.java similarity index 88% rename from android/src/com/levien/synthesizer/android/widgets/knob/KnobView.java rename to app/src/main/java/com/levien/synthesizer/android/widgets/knob/KnobView.java index ece5e14..7f95c16 100644 --- a/android/src/com/levien/synthesizer/android/widgets/knob/KnobView.java +++ b/app/src/main/java/com/levien/synthesizer/android/widgets/knob/KnobView.java @@ -34,9 +34,6 @@ import android.view.MotionEvent; import android.view.View; import com.levien.synthesizer.R; -import com.levien.synthesizer.core.model.SynthesizerInput; -import com.levien.synthesizer.core.model.composite.MultiChannelSynthesizer; -import com.levien.synthesizer.core.model.composite.Presets.Setting; /** * KnobView is a widget for setting a real value by turning a virtual "knob". @@ -262,36 +259,6 @@ public class KnobView extends View { setMeasuredDimension(width, height); } - /** - * Connects knob to a SynthesizerInput. - * @input - The synthesizer input to connect to. - */ - public void bindTo(final SynthesizerInput input) { - setValue(input.getSynthesizerInputValue()); - setKnobListener(new KnobListener() { - public void onKnobChanged(double newValue) { - input.setValue(newValue); - } - }); - } - - /** - * Connects knob to a SynthesizerInput. - * @synth - The synthesizer to connect to. - * @path - The setting to connect to. - * @return - True on success, false on failure. - */ - public boolean bindTo(final MultiChannelSynthesizer synth, int channel, Setting setting) { - SynthesizerInput input = synth.getChannel(channel).getSynthesizerInput(setting); - if (input != null) { - bindTo(input); - return true; - } else { - Log.e(getClass().getName(), "Unable to bind to setting " + setting.name() + "."); - return false; - } - } - // Knob's current value, ranges from 0 - 1.0. private double knobValue_; private double min_; diff --git a/core/src/com/levien/synthesizer/core/midi/MessageFromBytes.java b/app/src/main/java/com/levien/synthesizer/core/midi/MessageFromBytes.java similarity index 100% rename from core/src/com/levien/synthesizer/core/midi/MessageFromBytes.java rename to app/src/main/java/com/levien/synthesizer/core/midi/MessageFromBytes.java diff --git a/core/src/com/levien/synthesizer/core/midi/MessageInputProcessor.java b/app/src/main/java/com/levien/synthesizer/core/midi/MessageInputProcessor.java similarity index 100% rename from core/src/com/levien/synthesizer/core/midi/MessageInputProcessor.java rename to app/src/main/java/com/levien/synthesizer/core/midi/MessageInputProcessor.java diff --git a/core/src/com/levien/synthesizer/core/midi/MessageOutputProcessor.java b/app/src/main/java/com/levien/synthesizer/core/midi/MessageOutputProcessor.java similarity index 100% rename from core/src/com/levien/synthesizer/core/midi/MessageOutputProcessor.java rename to app/src/main/java/com/levien/synthesizer/core/midi/MessageOutputProcessor.java diff --git a/core/src/com/levien/synthesizer/core/midi/MessageTee.java b/app/src/main/java/com/levien/synthesizer/core/midi/MessageTee.java similarity index 100% rename from core/src/com/levien/synthesizer/core/midi/MessageTee.java rename to app/src/main/java/com/levien/synthesizer/core/midi/MessageTee.java diff --git a/core/src/com/levien/synthesizer/core/midi/MidiAdapter.java b/app/src/main/java/com/levien/synthesizer/core/midi/MidiAdapter.java similarity index 100% rename from core/src/com/levien/synthesizer/core/midi/MidiAdapter.java rename to app/src/main/java/com/levien/synthesizer/core/midi/MidiAdapter.java diff --git a/core/src/com/levien/synthesizer/core/midi/MidiChannelFilter.java b/app/src/main/java/com/levien/synthesizer/core/midi/MidiChannelFilter.java similarity index 100% rename from core/src/com/levien/synthesizer/core/midi/MidiChannelFilter.java rename to app/src/main/java/com/levien/synthesizer/core/midi/MidiChannelFilter.java diff --git a/core/src/com/levien/synthesizer/core/midi/MidiEvent.java b/app/src/main/java/com/levien/synthesizer/core/midi/MidiEvent.java similarity index 100% rename from core/src/com/levien/synthesizer/core/midi/MidiEvent.java rename to app/src/main/java/com/levien/synthesizer/core/midi/MidiEvent.java diff --git a/core/src/com/levien/synthesizer/core/midi/MidiFile.java b/app/src/main/java/com/levien/synthesizer/core/midi/MidiFile.java similarity index 100% rename from core/src/com/levien/synthesizer/core/midi/MidiFile.java rename to app/src/main/java/com/levien/synthesizer/core/midi/MidiFile.java diff --git a/core/src/com/levien/synthesizer/core/midi/MidiFilePlayer.java b/app/src/main/java/com/levien/synthesizer/core/midi/MidiFilePlayer.java similarity index 100% rename from core/src/com/levien/synthesizer/core/midi/MidiFilePlayer.java rename to app/src/main/java/com/levien/synthesizer/core/midi/MidiFilePlayer.java diff --git a/core/src/com/levien/synthesizer/core/midi/MidiHeader.java b/app/src/main/java/com/levien/synthesizer/core/midi/MidiHeader.java similarity index 100% rename from core/src/com/levien/synthesizer/core/midi/MidiHeader.java rename to app/src/main/java/com/levien/synthesizer/core/midi/MidiHeader.java diff --git a/core/src/com/levien/synthesizer/core/midi/MidiListener.java b/app/src/main/java/com/levien/synthesizer/core/midi/MidiListener.java similarity index 100% rename from core/src/com/levien/synthesizer/core/midi/MidiListener.java rename to app/src/main/java/com/levien/synthesizer/core/midi/MidiListener.java diff --git a/core/src/com/levien/synthesizer/core/midi/MidiListenerProxy.java b/app/src/main/java/com/levien/synthesizer/core/midi/MidiListenerProxy.java similarity index 100% rename from core/src/com/levien/synthesizer/core/midi/MidiListenerProxy.java rename to app/src/main/java/com/levien/synthesizer/core/midi/MidiListenerProxy.java diff --git a/core/src/com/levien/synthesizer/core/midi/MidiReader.java b/app/src/main/java/com/levien/synthesizer/core/midi/MidiReader.java similarity index 100% rename from core/src/com/levien/synthesizer/core/midi/MidiReader.java rename to app/src/main/java/com/levien/synthesizer/core/midi/MidiReader.java diff --git a/core/src/com/levien/synthesizer/core/midi/MidiTrack.java b/app/src/main/java/com/levien/synthesizer/core/midi/MidiTrack.java similarity index 100% rename from core/src/com/levien/synthesizer/core/midi/MidiTrack.java rename to app/src/main/java/com/levien/synthesizer/core/midi/MidiTrack.java diff --git a/core/src/com/levien/synthesizer/core/midi/MidiUtil.java b/app/src/main/java/com/levien/synthesizer/core/midi/MidiUtil.java similarity index 100% rename from core/src/com/levien/synthesizer/core/midi/MidiUtil.java rename to app/src/main/java/com/levien/synthesizer/core/midi/MidiUtil.java diff --git a/cpp/src/SynthApp.gyp b/app/src/main/jni/SynthApp.gyp similarity index 100% rename from cpp/src/SynthApp.gyp rename to app/src/main/jni/SynthApp.gyp diff --git a/cpp/src/SynthApp.xcodeproj/project.pbxproj b/app/src/main/jni/SynthApp.xcodeproj/project.pbxproj similarity index 100% rename from cpp/src/SynthApp.xcodeproj/project.pbxproj rename to app/src/main/jni/SynthApp.xcodeproj/project.pbxproj diff --git a/cpp/src/SynthApp/English.lproj/InfoPlist.strings b/app/src/main/jni/SynthApp/English.lproj/InfoPlist.strings similarity index 100% rename from cpp/src/SynthApp/English.lproj/InfoPlist.strings rename to app/src/main/jni/SynthApp/English.lproj/InfoPlist.strings diff --git a/cpp/src/SynthApp/English.lproj/MainMenu.xib b/app/src/main/jni/SynthApp/English.lproj/MainMenu.xib similarity index 100% rename from cpp/src/SynthApp/English.lproj/MainMenu.xib rename to app/src/main/jni/SynthApp/English.lproj/MainMenu.xib diff --git a/cpp/src/SynthApp/Synth-Info.plist b/app/src/main/jni/SynthApp/Synth-Info.plist similarity index 100% rename from cpp/src/SynthApp/Synth-Info.plist rename to app/src/main/jni/SynthApp/Synth-Info.plist diff --git a/cpp/src/SynthApp/SynthAppDelegate.h b/app/src/main/jni/SynthApp/SynthAppDelegate.h similarity index 100% rename from cpp/src/SynthApp/SynthAppDelegate.h rename to app/src/main/jni/SynthApp/SynthAppDelegate.h diff --git a/cpp/src/SynthApp/SynthAppDelegate.mm b/app/src/main/jni/SynthApp/SynthAppDelegate.mm similarity index 100% rename from cpp/src/SynthApp/SynthAppDelegate.mm rename to app/src/main/jni/SynthApp/SynthAppDelegate.mm diff --git a/cpp/src/SynthApp/SynthApp_Prefix.pch b/app/src/main/jni/SynthApp/SynthApp_Prefix.pch similarity index 100% rename from cpp/src/SynthApp/SynthApp_Prefix.pch rename to app/src/main/jni/SynthApp/SynthApp_Prefix.pch diff --git a/cpp/src/SynthApp/SynthMain.h b/app/src/main/jni/SynthApp/SynthMain.h similarity index 100% rename from cpp/src/SynthApp/SynthMain.h rename to app/src/main/jni/SynthApp/SynthMain.h diff --git a/cpp/src/SynthApp/SynthMain.mm b/app/src/main/jni/SynthApp/SynthMain.mm similarity index 100% rename from cpp/src/SynthApp/SynthMain.mm rename to app/src/main/jni/SynthApp/SynthMain.mm diff --git a/cpp/src/SynthApp/main.m b/app/src/main/jni/SynthApp/main.m similarity index 100% rename from cpp/src/SynthApp/main.m rename to app/src/main/jni/SynthApp/main.m diff --git a/cpp/src/SynthApp/midi_in_mac.cc b/app/src/main/jni/SynthApp/midi_in_mac.cc similarity index 100% rename from cpp/src/SynthApp/midi_in_mac.cc rename to app/src/main/jni/SynthApp/midi_in_mac.cc diff --git a/cpp/src/SynthApp/midi_in_mac.h b/app/src/main/jni/SynthApp/midi_in_mac.h similarity index 100% rename from cpp/src/SynthApp/midi_in_mac.h rename to app/src/main/jni/SynthApp/midi_in_mac.h diff --git a/cpp/src/aligned_buf.h b/app/src/main/jni/aligned_buf.h similarity index 100% rename from cpp/src/aligned_buf.h rename to app/src/main/jni/aligned_buf.h diff --git a/cpp/src/android_glue.cc b/app/src/main/jni/android_glue.cc similarity index 100% rename from cpp/src/android_glue.cc rename to app/src/main/jni/android_glue.cc diff --git a/cpp/src/controllers.h b/app/src/main/jni/controllers.h similarity index 100% rename from cpp/src/controllers.h rename to app/src/main/jni/controllers.h diff --git a/cpp/src/core.gyp b/app/src/main/jni/core.gyp similarity index 100% rename from cpp/src/core.gyp rename to app/src/main/jni/core.gyp diff --git a/cpp/src/core.xcodeproj/project.pbxproj b/app/src/main/jni/core.xcodeproj/project.pbxproj similarity index 100% rename from cpp/src/core.xcodeproj/project.pbxproj rename to app/src/main/jni/core.xcodeproj/project.pbxproj diff --git a/cpp/src/dx7note.cc b/app/src/main/jni/dx7note.cc similarity index 100% rename from cpp/src/dx7note.cc rename to app/src/main/jni/dx7note.cc diff --git a/cpp/src/dx7note.h b/app/src/main/jni/dx7note.h similarity index 100% rename from cpp/src/dx7note.h rename to app/src/main/jni/dx7note.h diff --git a/cpp/src/env.cc b/app/src/main/jni/env.cc similarity index 100% rename from cpp/src/env.cc rename to app/src/main/jni/env.cc diff --git a/cpp/src/env.h b/app/src/main/jni/env.h similarity index 100% rename from cpp/src/env.h rename to app/src/main/jni/env.h diff --git a/cpp/src/exp2.cc b/app/src/main/jni/exp2.cc similarity index 100% rename from cpp/src/exp2.cc rename to app/src/main/jni/exp2.cc diff --git a/cpp/src/exp2.h b/app/src/main/jni/exp2.h similarity index 100% rename from cpp/src/exp2.h rename to app/src/main/jni/exp2.h diff --git a/cpp/src/fir.cc b/app/src/main/jni/fir.cc similarity index 100% rename from cpp/src/fir.cc rename to app/src/main/jni/fir.cc diff --git a/cpp/src/fir.h b/app/src/main/jni/fir.h similarity index 100% rename from cpp/src/fir.h rename to app/src/main/jni/fir.h diff --git a/cpp/src/fm_core.cc b/app/src/main/jni/fm_core.cc similarity index 100% rename from cpp/src/fm_core.cc rename to app/src/main/jni/fm_core.cc diff --git a/cpp/src/fm_core.h b/app/src/main/jni/fm_core.h similarity index 100% rename from cpp/src/fm_core.h rename to app/src/main/jni/fm_core.h diff --git a/cpp/src/fm_op_kernel.cc b/app/src/main/jni/fm_op_kernel.cc similarity index 100% rename from cpp/src/fm_op_kernel.cc rename to app/src/main/jni/fm_op_kernel.cc diff --git a/cpp/src/fm_op_kernel.h b/app/src/main/jni/fm_op_kernel.h similarity index 100% rename from cpp/src/fm_op_kernel.h rename to app/src/main/jni/fm_op_kernel.h diff --git a/cpp/src/freqlut.cc b/app/src/main/jni/freqlut.cc similarity index 100% rename from cpp/src/freqlut.cc rename to app/src/main/jni/freqlut.cc diff --git a/cpp/src/freqlut.h b/app/src/main/jni/freqlut.h similarity index 100% rename from cpp/src/freqlut.h rename to app/src/main/jni/freqlut.h diff --git a/cpp/src/lfo.cc b/app/src/main/jni/lfo.cc similarity index 100% rename from cpp/src/lfo.cc rename to app/src/main/jni/lfo.cc diff --git a/cpp/src/lfo.h b/app/src/main/jni/lfo.h similarity index 100% rename from cpp/src/lfo.h rename to app/src/main/jni/lfo.h diff --git a/cpp/src/log2.cc b/app/src/main/jni/log2.cc similarity index 100% rename from cpp/src/log2.cc rename to app/src/main/jni/log2.cc diff --git a/cpp/src/log2.h b/app/src/main/jni/log2.h similarity index 100% rename from cpp/src/log2.h rename to app/src/main/jni/log2.h diff --git a/cpp/src/main.cc b/app/src/main/jni/main.cc similarity index 100% rename from cpp/src/main.cc rename to app/src/main/jni/main.cc diff --git a/cpp/src/main.gyp b/app/src/main/jni/main.gyp similarity index 100% rename from cpp/src/main.gyp rename to app/src/main/jni/main.gyp diff --git a/cpp/src/module.h b/app/src/main/jni/module.h similarity index 100% rename from cpp/src/module.h rename to app/src/main/jni/module.h diff --git a/cpp/src/neon_fir.s b/app/src/main/jni/neon_fir.s similarity index 100% rename from cpp/src/neon_fir.s rename to app/src/main/jni/neon_fir.s diff --git a/cpp/src/neon_fm_kernel.s b/app/src/main/jni/neon_fm_kernel.s similarity index 100% rename from cpp/src/neon_fm_kernel.s rename to app/src/main/jni/neon_fm_kernel.s diff --git a/cpp/src/neon_iir.s b/app/src/main/jni/neon_iir.s similarity index 100% rename from cpp/src/neon_iir.s rename to app/src/main/jni/neon_iir.s diff --git a/cpp/src/neon_ladder.s b/app/src/main/jni/neon_ladder.s similarity index 100% rename from cpp/src/neon_ladder.s rename to app/src/main/jni/neon_ladder.s diff --git a/cpp/src/patch.cc b/app/src/main/jni/patch.cc similarity index 100% rename from cpp/src/patch.cc rename to app/src/main/jni/patch.cc diff --git a/cpp/src/patch.h b/app/src/main/jni/patch.h similarity index 100% rename from cpp/src/patch.h rename to app/src/main/jni/patch.h diff --git a/cpp/src/pitchenv.cc b/app/src/main/jni/pitchenv.cc similarity index 100% rename from cpp/src/pitchenv.cc rename to app/src/main/jni/pitchenv.cc diff --git a/cpp/src/pitchenv.h b/app/src/main/jni/pitchenv.h similarity index 100% rename from cpp/src/pitchenv.h rename to app/src/main/jni/pitchenv.h diff --git a/cpp/src/resofilter.cc b/app/src/main/jni/resofilter.cc similarity index 100% rename from cpp/src/resofilter.cc rename to app/src/main/jni/resofilter.cc diff --git a/cpp/src/resofilter.h b/app/src/main/jni/resofilter.h similarity index 100% rename from cpp/src/resofilter.h rename to app/src/main/jni/resofilter.h diff --git a/cpp/src/ringbuffer.cc b/app/src/main/jni/ringbuffer.cc similarity index 100% rename from cpp/src/ringbuffer.cc rename to app/src/main/jni/ringbuffer.cc diff --git a/cpp/src/ringbuffer.h b/app/src/main/jni/ringbuffer.h similarity index 100% rename from cpp/src/ringbuffer.h rename to app/src/main/jni/ringbuffer.h diff --git a/cpp/src/sawtooth.cc b/app/src/main/jni/sawtooth.cc similarity index 100% rename from cpp/src/sawtooth.cc rename to app/src/main/jni/sawtooth.cc diff --git a/cpp/src/sawtooth.h b/app/src/main/jni/sawtooth.h similarity index 100% rename from cpp/src/sawtooth.h rename to app/src/main/jni/sawtooth.h diff --git a/cpp/src/sin.cc b/app/src/main/jni/sin.cc similarity index 100% rename from cpp/src/sin.cc rename to app/src/main/jni/sin.cc diff --git a/cpp/src/sin.h b/app/src/main/jni/sin.h similarity index 100% rename from cpp/src/sin.h rename to app/src/main/jni/sin.h diff --git a/cpp/src/synth.h b/app/src/main/jni/synth.h similarity index 100% rename from cpp/src/synth.h rename to app/src/main/jni/synth.h diff --git a/cpp/src/synth_unit.cc b/app/src/main/jni/synth_unit.cc similarity index 100% rename from cpp/src/synth_unit.cc rename to app/src/main/jni/synth_unit.cc diff --git a/cpp/src/synth_unit.h b/app/src/main/jni/synth_unit.h similarity index 100% rename from cpp/src/synth_unit.h rename to app/src/main/jni/synth_unit.h diff --git a/cpp/src/test_filter.cc b/app/src/main/jni/test_filter.cc similarity index 100% rename from cpp/src/test_filter.cc rename to app/src/main/jni/test_filter.cc diff --git a/cpp/src/test_neon.cc b/app/src/main/jni/test_neon.cc similarity index 100% rename from cpp/src/test_neon.cc rename to app/src/main/jni/test_neon.cc diff --git a/cpp/src/test_ringbuffer.cc b/app/src/main/jni/test_ringbuffer.cc similarity index 100% rename from cpp/src/test_ringbuffer.cc rename to app/src/main/jni/test_ringbuffer.cc diff --git a/cpp/src/wavout.cc b/app/src/main/jni/wavout.cc similarity index 100% rename from cpp/src/wavout.cc rename to app/src/main/jni/wavout.cc diff --git a/cpp/src/wavout.h b/app/src/main/jni/wavout.h similarity index 100% rename from cpp/src/wavout.h rename to app/src/main/jni/wavout.h diff --git a/android/res/drawable-hdpi/add.png b/app/src/main/res/drawable-hdpi/add.png similarity index 100% rename from android/res/drawable-hdpi/add.png rename to app/src/main/res/drawable-hdpi/add.png diff --git a/android/res/drawable-hdpi/arrow.png b/app/src/main/res/drawable-hdpi/arrow.png similarity index 100% rename from android/res/drawable-hdpi/arrow.png rename to app/src/main/res/drawable-hdpi/arrow.png diff --git a/android/res/drawable-hdpi/bass.png b/app/src/main/res/drawable-hdpi/bass.png similarity index 100% rename from android/res/drawable-hdpi/bass.png rename to app/src/main/res/drawable-hdpi/bass.png diff --git a/android/res/drawable-hdpi/closed_eye.png b/app/src/main/res/drawable-hdpi/closed_eye.png similarity index 100% rename from android/res/drawable-hdpi/closed_eye.png rename to app/src/main/res/drawable-hdpi/closed_eye.png diff --git a/android/res/drawable-hdpi/down.png b/app/src/main/res/drawable-hdpi/down.png similarity index 100% rename from android/res/drawable-hdpi/down.png rename to app/src/main/res/drawable-hdpi/down.png diff --git a/android/res/drawable-hdpi/drums.png b/app/src/main/res/drawable-hdpi/drums.png similarity index 100% rename from android/res/drawable-hdpi/drums.png rename to app/src/main/res/drawable-hdpi/drums.png diff --git a/android/res/drawable-hdpi/eighth_note.png b/app/src/main/res/drawable-hdpi/eighth_note.png similarity index 100% rename from android/res/drawable-hdpi/eighth_note.png rename to app/src/main/res/drawable-hdpi/eighth_note.png diff --git a/android/res/drawable-hdpi/flute.png b/app/src/main/res/drawable-hdpi/flute.png similarity index 100% rename from android/res/drawable-hdpi/flute.png rename to app/src/main/res/drawable-hdpi/flute.png diff --git a/android/res/drawable-hdpi/guitar.png b/app/src/main/res/drawable-hdpi/guitar.png similarity index 100% rename from android/res/drawable-hdpi/guitar.png rename to app/src/main/res/drawable-hdpi/guitar.png diff --git a/android/res/drawable-hdpi/half_note.png b/app/src/main/res/drawable-hdpi/half_note.png similarity index 100% rename from android/res/drawable-hdpi/half_note.png rename to app/src/main/res/drawable-hdpi/half_note.png diff --git a/android/res/drawable-hdpi/icon.png b/app/src/main/res/drawable-hdpi/icon.png similarity index 100% rename from android/res/drawable-hdpi/icon.png rename to app/src/main/res/drawable-hdpi/icon.png diff --git a/android/res/drawable-hdpi/loop.png b/app/src/main/res/drawable-hdpi/loop.png similarity index 100% rename from android/res/drawable-hdpi/loop.png rename to app/src/main/res/drawable-hdpi/loop.png diff --git a/android/res/drawable-hdpi/no_note.png b/app/src/main/res/drawable-hdpi/no_note.png similarity index 100% rename from android/res/drawable-hdpi/no_note.png rename to app/src/main/res/drawable-hdpi/no_note.png diff --git a/android/res/drawable-hdpi/open_eye.png b/app/src/main/res/drawable-hdpi/open_eye.png similarity index 100% rename from android/res/drawable-hdpi/open_eye.png rename to app/src/main/res/drawable-hdpi/open_eye.png diff --git a/android/res/drawable-hdpi/play.png b/app/src/main/res/drawable-hdpi/play.png similarity index 100% rename from android/res/drawable-hdpi/play.png rename to app/src/main/res/drawable-hdpi/play.png diff --git a/android/res/drawable-hdpi/play_piano.png b/app/src/main/res/drawable-hdpi/play_piano.png similarity index 100% rename from android/res/drawable-hdpi/play_piano.png rename to app/src/main/res/drawable-hdpi/play_piano.png diff --git a/android/res/drawable-hdpi/quarter_note.png b/app/src/main/res/drawable-hdpi/quarter_note.png similarity index 100% rename from android/res/drawable-hdpi/quarter_note.png rename to app/src/main/res/drawable-hdpi/quarter_note.png diff --git a/android/res/drawable-hdpi/sixteenth_note.png b/app/src/main/res/drawable-hdpi/sixteenth_note.png similarity index 100% rename from android/res/drawable-hdpi/sixteenth_note.png rename to app/src/main/res/drawable-hdpi/sixteenth_note.png diff --git a/android/res/drawable-hdpi/stop.png b/app/src/main/res/drawable-hdpi/stop.png similarity index 100% rename from android/res/drawable-hdpi/stop.png rename to app/src/main/res/drawable-hdpi/stop.png diff --git a/android/res/drawable-hdpi/thirtysecond_note.png b/app/src/main/res/drawable-hdpi/thirtysecond_note.png similarity index 100% rename from android/res/drawable-hdpi/thirtysecond_note.png rename to app/src/main/res/drawable-hdpi/thirtysecond_note.png diff --git a/android/res/drawable-hdpi/trash.png b/app/src/main/res/drawable-hdpi/trash.png similarity index 100% rename from android/res/drawable-hdpi/trash.png rename to app/src/main/res/drawable-hdpi/trash.png diff --git a/android/res/drawable-hdpi/unknown_note.png b/app/src/main/res/drawable-hdpi/unknown_note.png similarity index 100% rename from android/res/drawable-hdpi/unknown_note.png rename to app/src/main/res/drawable-hdpi/unknown_note.png diff --git a/android/res/drawable-hdpi/up.png b/app/src/main/res/drawable-hdpi/up.png similarity index 100% rename from android/res/drawable-hdpi/up.png rename to app/src/main/res/drawable-hdpi/up.png diff --git a/android/res/drawable-hdpi/voice.png b/app/src/main/res/drawable-hdpi/voice.png similarity index 100% rename from android/res/drawable-hdpi/voice.png rename to app/src/main/res/drawable-hdpi/voice.png diff --git a/android/res/drawable-hdpi/whole_note.png b/app/src/main/res/drawable-hdpi/whole_note.png similarity index 100% rename from android/res/drawable-hdpi/whole_note.png rename to app/src/main/res/drawable-hdpi/whole_note.png diff --git a/android/res/drawable-hdpi/zoom.png b/app/src/main/res/drawable-hdpi/zoom.png similarity index 100% rename from android/res/drawable-hdpi/zoom.png rename to app/src/main/res/drawable-hdpi/zoom.png diff --git a/android/res/drawable-ldpi/icon.png b/app/src/main/res/drawable-ldpi/icon.png similarity index 100% rename from android/res/drawable-ldpi/icon.png rename to app/src/main/res/drawable-ldpi/icon.png diff --git a/android/res/drawable-mdpi/icon.png b/app/src/main/res/drawable-mdpi/icon.png similarity index 100% rename from android/res/drawable-mdpi/icon.png rename to app/src/main/res/drawable-mdpi/icon.png diff --git a/android/res/layout-sw600dp/piano2.xml b/app/src/main/res/layout-sw600dp/piano2.xml similarity index 100% rename from android/res/layout-sw600dp/piano2.xml rename to app/src/main/res/layout-sw600dp/piano2.xml diff --git a/android/res/layout/amplification.xml b/app/src/main/res/layout/amplification.xml similarity index 100% rename from android/res/layout/amplification.xml rename to app/src/main/res/layout/amplification.xml diff --git a/android/res/layout/chord_grid.xml b/app/src/main/res/layout/chord_grid.xml similarity index 100% rename from android/res/layout/chord_grid.xml rename to app/src/main/res/layout/chord_grid.xml diff --git a/android/res/layout/effects.xml b/app/src/main/res/layout/effects.xml similarity index 100% rename from android/res/layout/effects.xml rename to app/src/main/res/layout/effects.xml diff --git a/android/res/layout/karplus_strong.xml b/app/src/main/res/layout/karplus_strong.xml similarity index 100% rename from android/res/layout/karplus_strong.xml rename to app/src/main/res/layout/karplus_strong.xml diff --git a/android/res/layout/knobpreflayout_va.xml b/app/src/main/res/layout/knobpreflayout_va.xml similarity index 100% rename from android/res/layout/knobpreflayout_va.xml rename to app/src/main/res/layout/knobpreflayout_va.xml diff --git a/android/res/layout/knobpreflayout_vs.xml b/app/src/main/res/layout/knobpreflayout_vs.xml similarity index 100% rename from android/res/layout/knobpreflayout_vs.xml rename to app/src/main/res/layout/knobpreflayout_vs.xml diff --git a/android/res/layout/low_pass_filter.xml b/app/src/main/res/layout/low_pass_filter.xml similarity index 100% rename from android/res/layout/low_pass_filter.xml rename to app/src/main/res/layout/low_pass_filter.xml diff --git a/android/res/layout/main.xml b/app/src/main/res/layout/main.xml similarity index 100% rename from android/res/layout/main.xml rename to app/src/main/res/layout/main.xml diff --git a/android/res/layout/oscillator.xml b/app/src/main/res/layout/oscillator.xml similarity index 100% rename from android/res/layout/oscillator.xml rename to app/src/main/res/layout/oscillator.xml diff --git a/android/res/layout/piano.xml b/app/src/main/res/layout/piano.xml similarity index 100% rename from android/res/layout/piano.xml rename to app/src/main/res/layout/piano.xml diff --git a/android/res/layout/piano2.xml b/app/src/main/res/layout/piano2.xml similarity index 100% rename from android/res/layout/piano2.xml rename to app/src/main/res/layout/piano2.xml diff --git a/android/res/layout/score.xml b/app/src/main/res/layout/score.xml similarity index 100% rename from android/res/layout/score.xml rename to app/src/main/res/layout/score.xml diff --git a/android/res/layout/tremolo.xml b/app/src/main/res/layout/tremolo.xml similarity index 100% rename from android/res/layout/tremolo.xml rename to app/src/main/res/layout/tremolo.xml diff --git a/android/res/layout/vibrato.xml b/app/src/main/res/layout/vibrato.xml similarity index 100% rename from android/res/layout/vibrato.xml rename to app/src/main/res/layout/vibrato.xml diff --git a/android/res/menu/options_menu.xml b/app/src/main/res/menu/options_menu.xml similarity index 100% rename from android/res/menu/options_menu.xml rename to app/src/main/res/menu/options_menu.xml diff --git a/android/res/menu/score_menu.xml b/app/src/main/res/menu/score_menu.xml similarity index 100% rename from android/res/menu/score_menu.xml rename to app/src/main/res/menu/score_menu.xml diff --git a/android/res/menu/synth_menu.xml b/app/src/main/res/menu/synth_menu.xml similarity index 100% rename from android/res/menu/synth_menu.xml rename to app/src/main/res/menu/synth_menu.xml diff --git a/android/res/raw/presets.txt b/app/src/main/res/raw/presets.txt similarity index 100% rename from android/res/raw/presets.txt rename to app/src/main/res/raw/presets.txt diff --git a/android/res/raw/rom1a.syx b/app/src/main/res/raw/rom1a.syx similarity index 100% rename from android/res/raw/rom1a.syx rename to app/src/main/res/raw/rom1a.syx diff --git a/android/res/values-sw600dp/dimens.xml b/app/src/main/res/values-sw600dp/dimens.xml similarity index 100% rename from android/res/values-sw600dp/dimens.xml rename to app/src/main/res/values-sw600dp/dimens.xml diff --git a/android/res/values-v11/styles.xml b/app/src/main/res/values-v11/styles.xml similarity index 100% rename from android/res/values-v11/styles.xml rename to app/src/main/res/values-v11/styles.xml diff --git a/android/res/values/attrs.xml b/app/src/main/res/values/attrs.xml similarity index 100% rename from android/res/values/attrs.xml rename to app/src/main/res/values/attrs.xml diff --git a/android/res/values/dimens.xml b/app/src/main/res/values/dimens.xml similarity index 100% rename from android/res/values/dimens.xml rename to app/src/main/res/values/dimens.xml diff --git a/android/res/values/strings.xml b/app/src/main/res/values/strings.xml similarity index 100% rename from android/res/values/strings.xml rename to app/src/main/res/values/strings.xml diff --git a/android/res/values/styles.xml b/app/src/main/res/values/styles.xml similarity index 100% rename from android/res/values/styles.xml rename to app/src/main/res/values/styles.xml diff --git a/android/res/xml/device_filter.xml b/app/src/main/res/xml/device_filter.xml similarity index 100% rename from android/res/xml/device_filter.xml rename to app/src/main/res/xml/device_filter.xml diff --git a/android/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml similarity index 100% rename from android/res/xml/preferences.xml rename to app/src/main/res/xml/preferences.xml diff --git a/app/src/test/java/com/levien/synthesizer/ExampleUnitTest.java b/app/src/test/java/com/levien/synthesizer/ExampleUnitTest.java new file mode 100644 index 0000000..a318606 --- /dev/null +++ b/app/src/test/java/com/levien/synthesizer/ExampleUnitTest.java @@ -0,0 +1,15 @@ +package com.levien.synthesizer; + +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * To work on unit tests, switch the Test Artifact in the Build Variants view. + */ +public class ExampleUnitTest { + @Test + public void addition_isCorrect() throws Exception { + assertEquals(4, 2 + 2); + } +} \ No newline at end of file diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..238a7c7 --- /dev/null +++ b/build.gradle @@ -0,0 +1,23 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle-experimental:0.7.2' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + jcenter() + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/build.xml b/build.xml deleted file mode 100644 index c95addd..0000000 --- a/build.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/core/.gitignore b/core/.gitignore deleted file mode 100644 index ff4fd7d..0000000 --- a/core/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -build/** -core.jar -bin/protoc -lib/libprotobuf.jar \ No newline at end of file diff --git a/core/build.xml b/core/build.xml deleted file mode 100644 index 777dd8d..0000000 --- a/core/build.xml +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/core/src/com/levien/synthesizer/core/model/CachedFrequencyProvider.java b/core/src/com/levien/synthesizer/core/model/CachedFrequencyProvider.java deleted file mode 100644 index ec8f4f3..0000000 --- a/core/src/com/levien/synthesizer/core/model/CachedFrequencyProvider.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model; - -/** - * Convenient base class for any module that only wants to compute a new log frequency once at each - * step of time. - */ -public abstract class CachedFrequencyProvider implements FrequencyProvider { - public CachedFrequencyProvider() { - cachedTime_ = -1; - } - - /** - * Caching implementation of the FrequencyProvider interface. - * @param time - current synthesis time. - */ - final public double getLogFrequency(SynthesisTime time) { - if (time.getAbsoluteTime() != cachedTime_) { - cachedTime_ = time.getAbsoluteTime(); - cachedValue_ = computeLogFrequency(time); - } - return cachedValue_; - } - - /** - * Method for subclasses to implement to compute a new value for the given time. - */ - protected abstract double computeLogFrequency(SynthesisTime time); - - private double cachedTime_; - private double cachedValue_; -} diff --git a/core/src/com/levien/synthesizer/core/model/CachedSignalProvider.java b/core/src/com/levien/synthesizer/core/model/CachedSignalProvider.java deleted file mode 100644 index eb212d1..0000000 --- a/core/src/com/levien/synthesizer/core/model/CachedSignalProvider.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model; - -/** - * Convenient base class for any module that only wants to compute a new signal value once at each - * step of time. - */ -public abstract class CachedSignalProvider implements SignalProvider { - public CachedSignalProvider() { - cachedTime_ = -1; - } - - /** - * Caching implementation of the SignalProvider interface. - * @param time - current synthesis time. - */ - final public double getValue(SynthesisTime time) { - double absoluteTime = time.getAbsoluteTime(); - if (absoluteTime != cachedTime_) { - cachedTime_ = absoluteTime; - cachedValue_ = computeValue(time); - } - return cachedValue_; - } - - /** - * Method for subclasses to implement to compute a new value for the given time. - */ - protected abstract double computeValue(SynthesisTime time); - - private double cachedTime_; - private double cachedValue_; -} diff --git a/core/src/com/levien/synthesizer/core/model/Envelope.java b/core/src/com/levien/synthesizer/core/model/Envelope.java deleted file mode 100755 index a92f49a..0000000 --- a/core/src/com/levien/synthesizer/core/model/Envelope.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model; - -/** - * An interface for any module that shapes a sound based on something like keyboard keys being - * pressed and released. - */ -public interface Envelope extends SignalProvider { - /** - * Called to tell the envelope that the key has been pressed. - * @param retriggerIfOn - A (hopefully temporary) hack. Tells whether to treat this as a new - * press if the key is already down. - */ - public abstract void turnOn(boolean retriggerIfOn); - - /** - * Called to tell the envelope the key has been released. - */ - public abstract void turnOff(); -} diff --git a/core/src/com/levien/synthesizer/core/model/FrequencyProvider.java b/core/src/com/levien/synthesizer/core/model/FrequencyProvider.java deleted file mode 100644 index e2e0817..0000000 --- a/core/src/com/levien/synthesizer/core/model/FrequencyProvider.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model; - -/** - * An interface for modules that produce some frequency value. - */ -public interface FrequencyProvider { - double getLogFrequency(SynthesisTime time); -} diff --git a/core/src/com/levien/synthesizer/core/model/SignalProvider.java b/core/src/com/levien/synthesizer/core/model/SignalProvider.java deleted file mode 100644 index 41a3599..0000000 --- a/core/src/com/levien/synthesizer/core/model/SignalProvider.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model; - -/** - * An interface for any module that provides a signal, typically in the range [-1, 1]. - */ -public interface SignalProvider { - /** - * Method for subclasses to return a value for the given time. - */ - double getValue(SynthesisTime time); -} diff --git a/core/src/com/levien/synthesizer/core/model/SynthesisTime.java b/core/src/com/levien/synthesizer/core/model/SynthesisTime.java deleted file mode 100644 index e82e17f..0000000 --- a/core/src/com/levien/synthesizer/core/model/SynthesisTime.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model; - -/** - * A simple counter to keep track of the logical time in synthesis. - */ -public class SynthesisTime { - /** - * Creates a new timer with a 0 time delta. - */ - public SynthesisTime() { - deltaTime_ = 0.0; - absoluteTime_ = 0.0; - } - - /** - * Returns how much time will elapse next time advance() is called. - * @return the time delta in seconds. - */ - public double getDeltaTime() { - return deltaTime_; - } - - /** - * Returns the absolute time that has elapsed since creation or last reset(). - * @return the time in seconds. - */ - public double getAbsoluteTime() { - return absoluteTime_; - } - - /** - * Sets the "sample rate" of the synthesizer, which is the inverse of the time delta. - * @param sampleRate - samples per second (in Hz). - */ - public void setSampleRate(double sampleRate) { - if (sampleRate == 0.0) { - deltaTime_ = 0.0; - } else { - deltaTime_ = 1.0 / sampleRate; - } - } - - /** - * Resets the absolute time to zero. - */ - public void reset() { - absoluteTime_ = 0.0; - } - - /** - * Advances the absolute time by the time delta. - */ - public void advance() { - absoluteTime_ += deltaTime_; - } - - private double deltaTime_; - private double absoluteTime_; -} diff --git a/core/src/com/levien/synthesizer/core/model/SynthesizerInput.java b/core/src/com/levien/synthesizer/core/model/SynthesizerInput.java deleted file mode 100644 index e05a17b..0000000 --- a/core/src/com/levien/synthesizer/core/model/SynthesizerInput.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model; - -/** - * SynthesizerInput provides a frequency or signal that doesn't inherently change over time. - * It can change occasionally as the user turns a knob or whatever, but doesn't change on its own. - */ -public class SynthesizerInput implements FrequencyProvider, SignalProvider { - /** - * Creates a new SynthesizerInput that will return value as both a frequency and a signal. - */ - public SynthesizerInput(double value, double min, double max) { - value_ = value; - min_ = min; - max_ = max; - } - - /** - * Returns the input value as a log of frequency. - * @return the value. - */ - public synchronized double getLogFrequency(SynthesisTime time) { - return value_; - } - - /** - * Returns the input value as a signal. - * @return the value. - */ - public synchronized double getValue(SynthesisTime time) { - return value_; - } - - /** - * Returns the input value. - * @return the value. - */ - public synchronized double getSynthesizerInputValue() { - return value_; - } - - /** - * Sets the input to a new value. - * @param value - the new value. - */ - public synchronized void setValue(double value) { - value_ = value; - } - - /** - * Sets the input based on an unsigned byte value in the range 0 to 127. - */ - public synchronized void setByteValue(byte value) { - value_ = min_ + (value / 127.0) * (max_ - min_); - } - - private double min_; - private double max_; - private double value_; -} diff --git a/core/src/com/levien/synthesizer/core/model/WaveformInput.java b/core/src/com/levien/synthesizer/core/model/WaveformInput.java deleted file mode 100644 index 6065f13..0000000 --- a/core/src/com/levien/synthesizer/core/model/WaveformInput.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model; - -import java.util.ArrayList; - -/** - * WaveformInput provides a waveform type that is selectable. - */ -public class WaveformInput { - /** - * Creates a new WaveformInput with the given initial value. - */ - public WaveformInput(String waveform) { - selected_ = 0; - waveforms_ = new ArrayList(); - waveforms_.add(waveform); - } - - /** - * @return the index of the given waveform. - */ - public synchronized int getWaveformIndex(String waveform) { - for (int i = 0; i < waveforms_.size(); ++i) { - if (waveforms_.get(i).equals(waveform)) { - return i; - } - } - return -1; - } - - /** - * Selects a waveform. - */ - public synchronized void select(String waveform) { - selected_ = getWaveformIndex(waveform); - if (selected_ < 0) { - selected_ = 0; - } - } - - /** - * Select the next available waveform. - */ - public synchronized void next() { - selected_ = (selected_ + 1) % waveforms_.size(); - } - - /** - * Select the previous available waveform. - */ - public synchronized void previous() { - if (selected_ == 0) { - selected_ = waveforms_.size() - 1; - } else { - --selected_; - } - } - - /** - * Returns the currently selected waveform. - */ - public synchronized int getSelected() { - return selected_; - } - - /** - * Adds a new waveform to this input. - * @return The index of the new waveform. - */ - public synchronized int addWaveform(String waveform) { - int id = getWaveformIndex(waveform); - if (id < 0) { - id = waveforms_.size(); - waveforms_.add(waveform); - } - return id; - } - - /** - * @return The number of waveforms that are selectable. - */ - public synchronized int getWaveformCount() { - return waveforms_.size(); - } - - /** - * @return The identifier of the waveform with the given index. - */ - public synchronized String getWaveform(int i) { - return waveforms_.get(i); - } - - // The currently selected waveform. - private int selected_; - - // The set of all available waveforms on this input. - private ArrayList waveforms_; - - // A few default built-in strings. - public static String SINE = "sine"; - public static String TRIANGLE = "triangle"; - public static String SQUARE = "square"; - public static String SAWTOOTH = "sawtooth"; - public static String NOISE = "noise"; - public static String KARPLUS_STRONG = "karplus-strong string"; - public static String DRAWBAR_ORGAN = "drawbar organ"; - public static String DRUMS = "drums"; -} diff --git a/core/src/com/levien/synthesizer/core/model/composite/MidiSynthesizer.java b/core/src/com/levien/synthesizer/core/model/composite/MidiSynthesizer.java deleted file mode 100644 index 3de5eda..0000000 --- a/core/src/com/levien/synthesizer/core/model/composite/MidiSynthesizer.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.composite; - -import com.levien.synthesizer.core.model.SignalProvider; -import com.levien.synthesizer.core.music.Note; -import com.levien.synthesizer.core.soundfont.SoundFontReader; - -/** - * MidiSynthesizer is a wrapper around MultiTouchSynthesizer that allows it to accept Midi input in - * a more natural way. As more notes are played, more simulated fingers are used, until there - * aren't any more available, in which case notes are dropped. - */ -public class MidiSynthesizer extends MultiTouchSynthesizer implements SignalProvider { - /** - * Creates a new MidiSynthesizer that wraps MultiTouchSynthesizer with a given number of fingers. - * @param fingers - How many fingers to simulate. - * @param sampleRateInHz - The sample rate of the wrapped synthesizer. - */ - public MidiSynthesizer(int fingers, double sampleRateInHz, SoundFontReader sampleProvider) { - super(fingers, sampleRateInHz, sampleProvider); - noteDown_ = new int[FINGERS]; - for (int i = 0; i < FINGERS; ++i) { - noteDown_[i] = -1; - } - } - - /** - * Called to handle Midi note-on events. - * @param note - The note to turn on. - * @param velocity - How hard the key was pressed, from 0 to 127. - */ - public void onNoteOn(int note, int velocity) { - if (velocity == 0) { - onNoteOff(note, velocity); - } else { - for (int i = 0; i < FINGERS; ++i) { - if (noteDown_[i] < 0) { - noteDown_[i] = note; - setPitch(Note.computeLog12TET(note % 12, note / 12), i); - turnOn(true, i); - break; - } - } - } - } - - /** - * Called to handle Midi note-off events. - * @param note - The note to turn off. - * @param velocity - How hard the key was (un?)pressed, from 0 to 127. - */ - public void onNoteOff(int note, int velocity) { - for (int i = 0; i < FINGERS; ++i) { - if (noteDown_[i] == note) { - noteDown_[i] = -1; - turnOff(i); - break; - } - } - } - - // The map of which notes are being held down by each finger. - private int[] noteDown_; -} diff --git a/core/src/com/levien/synthesizer/core/model/composite/MultiChannelSynthesizer.java b/core/src/com/levien/synthesizer/core/model/composite/MultiChannelSynthesizer.java deleted file mode 100644 index 9e1e4c6..0000000 --- a/core/src/com/levien/synthesizer/core/model/composite/MultiChannelSynthesizer.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.composite; - -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.logging.Logger; - -import com.google.protobuf.TextFormat; -import com.levien.synthesizer.core.midi.MidiAdapter; -import com.levien.synthesizer.core.model.SignalProvider; -import com.levien.synthesizer.core.model.SynthesisTime; -import com.levien.synthesizer.core.model.SynthesizerInput; -import com.levien.synthesizer.core.model.composite.Presets.PresetLibrary; -import com.levien.synthesizer.core.model.composite.Presets.Setting; -import com.levien.synthesizer.core.soundfont.SoundFontReader; - -/** - * MultiChannelSynthesizer is an array of MidiSynthesizer. - */ -public class MultiChannelSynthesizer extends MidiAdapter implements SignalProvider { - /** - * MultiChannelSynthesizer is an array of BasicSynths. - * @param channels - The number of channels of the synthesizer. - * @param fingers - How many fingers to support. - * @param sampleRateInHz - The sample rate of the underlying BasicSynths. - */ - public MultiChannelSynthesizer(int channels, int fingers, double sampleRateInHz, - SoundFontReader sampleProvider) { - logger_ = Logger.getLogger(getClass().getName()); - synth_ = new MidiSynthesizer[channels]; - for (int i = 0; i < synth_.length; ++i) { - synth_[i] = new MidiSynthesizer(fingers, sampleRateInHz, sampleProvider); - } - } - - /** - * Returns the output of the synthesizer. - */ - public double getValue(SynthesisTime time) { - double value = 0.0; - for (int i = 0; i < synth_.length; ++i) { - value += synth_[i].getValue(time); - } - return value; - } - - /** - * Called to turn on the given note for the given channel. - */ - @Override - public void onNoteOn(int channel, int note, int velocity) { - synth_[channel].onNoteOn(note, velocity); - } - - /** - * Called to turn off the given note for the given channel. - */ - @Override - public void onNoteOff(int channel, int note, int velocity) { - synth_[channel].onNoteOff(note, velocity); - } - - /** - * Called when a control value changes on the given channel. - */ - @Override - public void onController(int channel, int control, int value) { - MidiSynthesizer synth = synth_[channel]; - Setting setting = Setting.valueOf(control); - SynthesizerInput input = synth.getSynthesizerInput(setting); - if (input != null) { - input.setByteValue((byte)value); - logger_.warning( - "Processed control: " + setting.name() + "[" + channel + "] = " + value + "."); - } else { - logger_.warning("Unhandled control: " + control + "[" + channel + "] = " + value + "."); - } - } - - /** - * Called when the program is changed. - */ - @Override - public void onProgramChange(int channel, int program) { - synth_[channel].setPreset(program); - } - - /** - * Populates names with the list of all known presets from the library. - * Does *not* clear the list first. - */ - public void getPresetNames(ArrayList names) { - synth_[0].getPresetNames(names); - } - - /** - * Populates library with the presets from the given input stream, in text protocol buffer format. - */ - public void loadLibraryFromText(InputStream input) throws IOException { - PresetLibrary.Builder builder = PresetLibrary.newBuilder(); - TextFormat.merge(new InputStreamReader(input), builder); - PresetLibrary library = builder.build(); - for (int i = 0; i < synth_.length; ++i) { - synth_[i].setLibrary(library); - // Load each channel with the next available preset. - synth_[i].setPreset(i % synth_[i].getPresetCount()); - } - } - - /** - * Loads a channel with the settings from the preset in the library with the given index. - */ - public void setPreset(int channel, int index) { - synth_[channel].setPreset(index); - } - - /** - * Returns the MidiSynthesizer to use for a particular channel. - */ - public MidiSynthesizer getChannel(int channel) { - return synth_[channel]; - } - - // The actual synthesizers. - private MidiSynthesizer[] synth_; - - Logger logger_; -} diff --git a/core/src/com/levien/synthesizer/core/model/composite/MultiTouchSynthesizer.java b/core/src/com/levien/synthesizer/core/model/composite/MultiTouchSynthesizer.java deleted file mode 100644 index 06a69b7..0000000 --- a/core/src/com/levien/synthesizer/core/model/composite/MultiTouchSynthesizer.java +++ /dev/null @@ -1,638 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.composite; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import com.levien.synthesizer.core.model.CachedSignalProvider; -import com.levien.synthesizer.core.model.Envelope; -import com.levien.synthesizer.core.model.FrequencyProvider; -import com.levien.synthesizer.core.model.SignalProvider; -import com.levien.synthesizer.core.model.SynthesisTime; -import com.levien.synthesizer.core.model.SynthesizerInput; -import com.levien.synthesizer.core.model.WaveformInput; -import com.levien.synthesizer.core.model.composite.Presets.Preset; -import com.levien.synthesizer.core.model.composite.Presets.PresetLibrary; -import com.levien.synthesizer.core.model.composite.Presets.Setting; -import com.levien.synthesizer.core.model.modules.AdsrEnvelope; -import com.levien.synthesizer.core.model.modules.Amplifier; -import com.levien.synthesizer.core.model.modules.Delay; -import com.levien.synthesizer.core.model.modules.Echo; -import com.levien.synthesizer.core.model.modules.Glide; -import com.levien.synthesizer.core.model.modules.LowPassFilter; -import com.levien.synthesizer.core.model.modules.Mixer; -import com.levien.synthesizer.core.model.modules.Tremolo; -import com.levien.synthesizer.core.model.modules.Tuner; -import com.levien.synthesizer.core.model.modules.WaveformSelector; -import com.levien.synthesizer.core.model.oscillator.DrawbarOrgan; -import com.levien.synthesizer.core.model.oscillator.KarplusStrong; -import com.levien.synthesizer.core.soundfont.SoundFontOscillator; -import com.levien.synthesizer.core.soundfont.SoundFontReader; - -/** - * MultiTouchSynthesizer is a collection of synthesizer modules, connected together in a way similar - * to many basic analog synthesizers. - */ -public class MultiTouchSynthesizer implements SignalProvider { - /** - * Creates a new synthesizer with default settings. - * @param sampleRateInHz - Sample rate, used to compute buffer size from delay time. - */ - public MultiTouchSynthesizer(int fingers, double sampleRateInHz, SoundFontReader sampleLibrary) { - FINGERS = fingers; - setup(sampleRateInHz, sampleLibrary); - } - - /** - * Connects all of the modules together. - * @param sampleRateInHz - Sample rate, used to compute buffer size from delay time. - */ - @SuppressWarnings("unchecked") - private void setup(double sampleRateInHz, SoundFontReader sampleLibrary) { - // Data Structures. - library_ = PresetLibrary.newBuilder().build(); - pitch_ = new SynthesizerInput[FINGERS]; - synthesizerInputs_ = new HashMap(); - waveformInputs_ = new HashMap(); - envelopes_ = new ArrayList[FINGERS]; - for (int i = 0; i < FINGERS; ++i) { - pitch_[i] = new SynthesizerInput(0.0, 4.0, 15.0); - envelopes_[i] = new ArrayList(); - } - - // Vibrato - SignalProvider[] vibrato = setupVibrato(); - - // Oscillator 1 - SignalProvider[] oscillator1 = setupOscillator(Setting.OSCILLATOR_1_GLIDE, - Setting.OSCILLATOR_1_COARSE, - Setting.OSCILLATOR_1_FINE, - Setting.OSCILLATOR_1_VIBRATO, - Setting.OSCILLATOR_1_WAVEFORM, - Setting.OSCILLATOR_1_BLEND, - Setting.OSCILLATOR_1_STRETCH, - Setting.OSCILLATOR_1_EXCITEMENT, - pitch_, - vibrato, - true, - sampleLibrary, - sampleRateInHz); - // Oscillator 2 - SignalProvider[] oscillator2 = setupOscillator(Setting.OSCILLATOR_2_GLIDE, - Setting.OSCILLATOR_2_COARSE, - Setting.OSCILLATOR_2_FINE, - Setting.OSCILLATOR_2_VIBRATO, - Setting.OSCILLATOR_2_WAVEFORM, - Setting.OSCILLATOR_2_BLEND, - Setting.OSCILLATOR_2_STRETCH, - Setting.OSCILLATOR_2_EXCITEMENT, - pitch_, - vibrato, - true, - sampleLibrary, - sampleRateInHz); - - // Mixing - SynthesizerInput balance = new SynthesizerInput(0.0, 0.0, 1.0); - synthesizerInputs_.put(Setting.BALANCE, balance); - SignalProvider[] oscillatorOutput = new SignalProvider[FINGERS]; - for (int finger = 0; finger < FINGERS; ++finger) { - oscillatorOutput[finger] = new Mixer(oscillator1[finger], oscillator2[finger], balance); - } - - // Tremolo - SignalProvider[] tremolo = setupTremolo(oscillatorOutput); - - // Low-pass Filter - SignalProvider[] low_pass_filter = setupLowPassFilter(tremolo); - - // Amplifier - SignalProvider[] envelope = setupEnvelope(Setting.ATTACK, - Setting.DECAY, - Setting.SUSTAIN, - Setting.RELEASE); - SynthesizerInput volume = new SynthesizerInput(1.0, 0.0, 25.0); - synthesizerInputs_.put(Setting.VOLUME, volume); - - final SignalProvider[] ampOutput = new SignalProvider[FINGERS]; - for (int finger = 0; finger < FINGERS; ++finger) { - SignalProvider amplification = new Amplifier(envelope[finger], volume); - ampOutput[finger] = new Amplifier(low_pass_filter[finger], amplification); - } - - // Merge the fingers. - SignalProvider mergedOutput = new SignalProvider() { - public double getValue(SynthesisTime time) { - double output = 0.0; - for (int finger = 0; finger < FINGERS; ++finger) { - output += ((1.0 / FINGERS) * ampOutput[finger].getValue(time)); - } - return output; - } - }; - - // Effects - SignalProvider echo = setupEcho(mergedOutput, sampleRateInHz); - output_ = setupDelay(echo); - } - - /** - * Sets up an envelope. - */ - private SignalProvider[] setupEnvelope(Setting attackSetting, - Setting decaySetting, - Setting sustainSetting, - Setting releaseSetting) { - SynthesizerInput attack = new SynthesizerInput(0.01, 0.01, 1.0); - SynthesizerInput decay = new SynthesizerInput(0.01, 0.01, 1.0); - SynthesizerInput sustain = new SynthesizerInput(1.0, 0.0, 1.0); - SynthesizerInput release = new SynthesizerInput(0.01, 0.01, 1.0); - - synthesizerInputs_.put(attackSetting, attack); - synthesizerInputs_.put(decaySetting, decay); - synthesizerInputs_.put(sustainSetting, sustain); - synthesizerInputs_.put(releaseSetting, release); - - SignalProvider[] response = new SignalProvider[FINGERS]; - for (int finger = 0; finger < FINGERS; ++finger) { - Envelope envelope = new AdsrEnvelope(attack, decay, sustain, release); - envelopes_[finger].add(envelope); - response[finger] = envelope; - } - return response; - } - - /** - * Sets up the vibrato section of the synthesizer. - */ - private SignalProvider[] setupVibrato() { - SynthesizerInput rate = new SynthesizerInput(0.0, 0.0, 10.0); - WaveformInput waveform = new WaveformInput(WaveformInput.SINE); - synthesizerInputs_.put(Setting.VIBRATO_RATE, rate); - waveformInputs_.put(Setting.VIBRATO_WAVEFORM, waveform); - SignalProvider[] envelope = setupEnvelope(Setting.VIBRATO_ATTACK, - Setting.VIBRATO_DECAY, - Setting.VIBRATO_SUSTAIN, - Setting.VIBRATO_RELEASE); - SignalProvider[] response = new SignalProvider[FINGERS]; - for (int finger = 0; finger < FINGERS; ++finger) { - WaveformSelector waveformOutput = new WaveformSelector(waveform); - waveformOutput.addDefaultWaveforms(rate); - response[finger] = new Amplifier(waveformOutput, envelope[finger]); - } - return response; - } - - /** - * Sets up a Karplus-Strong string section of the synthesizer. - */ - private SignalProvider[] setupKarplusStrong(Setting blendSetting, - Setting stretchSetting, - Setting excitementSetting, - FrequencyProvider[] pitch, - double sampleRateInHz) { - SynthesizerInput blend = new SynthesizerInput(0.0, 0.0, 1.0); - SynthesizerInput stretch = new SynthesizerInput(0.0, 0.0, 1.0); - SynthesizerInput excitement = new SynthesizerInput(0.0, 0.0, 1.0); - - synthesizerInputs_.put(blendSetting, blend); - synthesizerInputs_.put(stretchSetting, stretch); - synthesizerInputs_.put(excitementSetting, excitement); - - SignalProvider[] response = new SignalProvider[FINGERS]; - for (int finger = 0; finger < FINGERS; ++finger) { - KarplusStrong karplusStrong = - new KarplusStrong(pitch[finger], blend, stretch, excitement, sampleRateInHz); - envelopes_[finger].add(karplusStrong); - response[finger] = karplusStrong; - } - return response; - } - - /** - * Sets up a drawbar organ osciallator for each finger. - */ - private SignalProvider[] setupDrawbarOrgan(FrequencyProvider[] pitch) { - SynthesizerInput drawbar1 = new SynthesizerInput(8.0/8.0, 0.0, 1.0); - SynthesizerInput drawbar2 = new SynthesizerInput(8.0/8.0, 0.0, 1.0); - SynthesizerInput drawbar3 = new SynthesizerInput(8.0/8.0, 0.0, 1.0); - SynthesizerInput drawbar4 = new SynthesizerInput(8.0/8.0, 0.0, 1.0); - SynthesizerInput drawbar5 = new SynthesizerInput(0.0/8.0, 0.0, 1.0); - SynthesizerInput drawbar6 = new SynthesizerInput(0.0/8.0, 0.0, 1.0); - SynthesizerInput drawbar7 = new SynthesizerInput(0.0/8.0, 0.0, 1.0); - SynthesizerInput drawbar8 = new SynthesizerInput(0.0/8.0, 0.0, 1.0); - SynthesizerInput drawbar9 = new SynthesizerInput(0.0/8.0, 0.0, 1.0); - synthesizerInputs_.put(Setting.ORGAN_DRAWBAR_1, drawbar1); - synthesizerInputs_.put(Setting.ORGAN_DRAWBAR_2, drawbar2); - synthesizerInputs_.put(Setting.ORGAN_DRAWBAR_3, drawbar3); - synthesizerInputs_.put(Setting.ORGAN_DRAWBAR_4, drawbar4); - synthesizerInputs_.put(Setting.ORGAN_DRAWBAR_5, drawbar5); - synthesizerInputs_.put(Setting.ORGAN_DRAWBAR_6, drawbar6); - synthesizerInputs_.put(Setting.ORGAN_DRAWBAR_7, drawbar7); - synthesizerInputs_.put(Setting.ORGAN_DRAWBAR_8, drawbar8); - synthesizerInputs_.put(Setting.ORGAN_DRAWBAR_9, drawbar9); - SignalProvider[] response = new SignalProvider[FINGERS]; - for (int finger = 0; finger < FINGERS; ++finger) { - DrawbarOrgan organ = new DrawbarOrgan(pitch[finger], - drawbar1, - drawbar2, - drawbar3, - drawbar4, - drawbar5, - drawbar6, - drawbar7, - drawbar8, - drawbar9); - response[finger] = organ; - } - return response; - } - - /** - * Sets up a sampled drum. - */ - private SignalProvider[] setupDrums(FrequencyProvider[] pitch, - double sampleRateInHz, - SoundFontReader sampleLibrary) { - SignalProvider[] response = new SignalProvider[FINGERS]; - for (int finger = 0; finger < FINGERS; ++finger) { - SoundFontOscillator sample = new SoundFontOscillator( - pitch[finger], - sampleLibrary.getPresets().get(sampleLibrary.getPresets().size() - 1), - sampleRateInHz); - response[finger] = sample; - envelopes_[finger].add(sample); - } - return response; - } - - /** - * Sets up an oscillator section of the synthesizer. - */ - private SignalProvider[] setupOscillator(Setting glideSetting, - Setting coarseSetting, - Setting fineSetting, - Setting vibratoSetting, - Setting waveformSetting, - Setting blendSetting, - Setting stretchSetting, - Setting excitementSetting, - FrequencyProvider[] pitch, - SignalProvider[] vibrato, - boolean includeOrgan, - SoundFontReader sampleLibrary, - double sampleRateInHz) { - SynthesizerInput glide = new SynthesizerInput(0.0, 0.0, 1.0); - SynthesizerInput coarse = new SynthesizerInput(0.0, -1.0, 1.0); - SynthesizerInput fine = new SynthesizerInput(0.0, -0.0833333333, 0.0833333333); - SynthesizerInput vibratoDepth = new SynthesizerInput(0.0, 0.0, 0.1666666667); - WaveformInput waveform = new WaveformInput(WaveformInput.SINE); - - // Register all of the inputs. - synthesizerInputs_.put(glideSetting, glide); - synthesizerInputs_.put(coarseSetting, coarse); - synthesizerInputs_.put(fineSetting, fine); - synthesizerInputs_.put(vibratoSetting, vibratoDepth); - waveformInputs_.put(waveformSetting, waveform); - - // Create a KarplusStrong module. - SignalProvider[] karplusStrong = - setupKarplusStrong(blendSetting, stretchSetting, excitementSetting, pitch, sampleRateInHz); - - // Create an organ module. - SignalProvider[] organ = null; - if (includeOrgan) { - organ = setupDrawbarOrgan(pitch); - } - - // Create a drum module. - SignalProvider[] drums = null; - if (sampleLibrary != null) { - drums = setupDrums(pitch, sampleRateInHz, sampleLibrary); - } - - SignalProvider[] response = new SignalProvider[FINGERS]; - for (int finger = 0; finger < FINGERS; ++finger) { - // Apply all of the layers that can control pitch; - FrequencyProvider adjustedPitch = new Glide(pitch[finger], glide); - adjustedPitch = new Tuner(adjustedPitch, coarse); - adjustedPitch = new Tuner(adjustedPitch, fine); - adjustedPitch = new Tuner(adjustedPitch, new Amplifier(vibrato[finger], vibratoDepth)); - - // Create the waveform. - WaveformSelector selector = new WaveformSelector(waveform); - selector.addDefaultWaveforms(adjustedPitch); - selector.addWaveform(WaveformInput.KARPLUS_STRONG, karplusStrong[finger]); - if (organ != null) { - selector.addWaveform(WaveformInput.DRAWBAR_ORGAN, organ[finger]); - } - if (drums != null) { - selector.addWaveform(WaveformInput.DRUMS, drums[finger]); - } - response[finger] = selector; - } - return response; - } - - /** - * Sets up the tremolo section of the synthesizer. - */ - private SignalProvider[] setupTremolo(SignalProvider[] source) { - SynthesizerInput rate = new SynthesizerInput(0.0, 0.0, 10.0); - SynthesizerInput depth = new SynthesizerInput(0.0, 0.0, 1.0); - WaveformInput waveform = new WaveformInput(WaveformInput.SINE); - - synthesizerInputs_.put(Setting.TREMOLO_RATE, rate); - synthesizerInputs_.put(Setting.TREMOLO_DEPTH, depth); - waveformInputs_.put(Setting.TREMOLO_WAVEFORM, waveform); - - SignalProvider[] envelope = setupEnvelope(Setting.TREMOLO_ATTACK, - Setting.TREMOLO_DECAY, - Setting.TREMOLO_SUSTAIN, - Setting.TREMOLO_RELEASE); - - SignalProvider[] response = new SignalProvider[FINGERS]; - for (int finger = 0; finger < FINGERS; ++finger) { - WaveformSelector waveformOutput = new WaveformSelector(waveform); - waveformOutput.addDefaultWaveforms(rate); - response[finger] = - new Amplifier(source[finger], - new Tremolo(new Amplifier(waveformOutput, envelope[finger]), depth)); - } - return response; - } - - /** - * Sets up the filter section of the synthesizer. - */ - private SignalProvider[] setupLowPassFilter(SignalProvider[] source) { - final SynthesizerInput cutoff = new SynthesizerInput(1.0, 0.0, 1.0); - final SynthesizerInput depth = new SynthesizerInput(0.0, -1.0, 1.0); - - synthesizerInputs_.put(Setting.FILTER_CUTOFF, cutoff); - synthesizerInputs_.put(Setting.FILTER_DEPTH, depth); - - final SignalProvider[] envelope = setupEnvelope(Setting.FILTER_ATTACK, - Setting.FILTER_DECAY, - Setting.FILTER_SUSTAIN, - Setting.FILTER_RELEASE); - - SignalProvider[] response = new SignalProvider[FINGERS]; - for (int finger = 0; finger < FINGERS; ++finger) { - final SignalProvider envelope_finger = envelope[finger]; - - SignalProvider shapedCutoff = new CachedSignalProvider() { - public synchronized double computeValue(SynthesisTime time) { - double c = cutoff.getValue(time); - double d = depth.getValue(time); - // This fancy math makes the envelope behave like we want. - double x = c * Math.abs(d) - 0.5 * (d + Math.abs(d)); - return c + x * (envelope_finger.getValue(time) - 1); - } - }; - response[finger] = new LowPassFilter(source[finger], shapedCutoff); - } - return response; - } - - /** - * Sets up an echo module on the synthesizer. - */ - private SignalProvider setupEcho(SignalProvider source, double sampleRateInHz) { - SynthesizerInput mix = new SynthesizerInput(0.0, 0.0, 1.0); - SynthesizerInput delay = new SynthesizerInput(0.0, 0.1, 2.0); - - synthesizerInputs_.put(Setting.ECHO_MIX, mix); - synthesizerInputs_.put(Setting.ECHO_DELAY, delay); - - return new Echo(source, mix, delay, sampleRateInHz); - } - - /** - * Sets up the delay module for the synthesizer. - */ - private SignalProvider setupDelay(SignalProvider source) { - SynthesizerInput mix = new SynthesizerInput(0.5, 0.0, 1.0); - synthesizerInputs_.put(Setting.DELAY_MIX, mix); - delay_ = new Delay(source, mix); - return delay_; - } - - /** - * Gets a particular input for this synthesizer by its control id. - */ - public SynthesizerInput getSynthesizerInput(Setting setting) { - if (synthesizerInputs_.containsKey(setting)) { - return synthesizerInputs_.get(setting); - } - return null; - } - - /** - * Gets a particular input for this synthesizer by its control id. - */ - public WaveformInput getWaveformInput(Setting setting) { - if (waveformInputs_.containsKey(setting)) { - return waveformInputs_.get(setting); - } - return null; - } - - /** - * Sets the input pitch of the synthesizer. - * @param logFrequency - The log frequency of the pitch. - */ - public void setPitch(double logFrequency, int finger) { - if (finger < FINGERS) { - pitch_[finger].setValue(logFrequency); - } - } - - /** - * Returns the output of the synthesizer, as it should go to the speaker. - */ - public double getValue(SynthesisTime time) { - return output_.getValue(time); - } - - /** - * Turns on all envelopes used by the synth. - * @param retriggerIfOn - A (hopefully temporary) hack. Tells whether to treat this as a new - * press if the key is already down. - */ - public void turnOn(boolean retriggerIfOn, int finger) { - if (finger < FINGERS) { - for (int i = 0; i < envelopes_[finger].size(); ++i) { - envelopes_[finger].get(i).turnOn(retriggerIfOn); - } - } - } - - /** - * Turns off all envelopes used by the synth. - */ - public void turnOff(int finger) { - if (finger < FINGERS) { - for (int i = 0; i < envelopes_[finger].size(); ++i) { - envelopes_[finger].get(i).turnOff(); - } - } - } - - /** - * Starts recording what the user plays. - */ - public void startRecording() { - delay_.startRecording(); - } - - /** - * Stops recording. - */ - public void stopRecording() { - delay_.stopRecording(); - } - - /** - * Starts playing what the user has recorded. - */ - public void startPlaying() { - delay_.startPlaying(); - } - - /** - * Stops playing the recorded audio. - */ - public void stopPlaying() { - delay_.stopPlaying(); - } - - /** - * Returns whether the user's recording is being played. - */ - public boolean isPlaying() { - return delay_.isPlaying(); - } - - /** - * Returns whether the user's playing is being recorded. - */ - public boolean isRecording() { - return delay_.isRecording(); - } - - /** - * Loads this synthesizer with the settings from the given preset. - */ - public void setPreset(Preset preset) { - for (int i = 0; i < preset.getInputSettingCount(); ++i) { - SynthesizerInput input = getSynthesizerInput(preset.getInputSetting(i).getSetting()); - if (input != null) { - input.setValue(preset.getInputSetting(i).getValue()); - } else { - throw new RuntimeException( - "Unable to set synthesizer input " + preset.getInputSetting(i).getSetting()); - } - } - for (int i = 0; i < preset.getWaveformSettingCount(); ++i) { - WaveformInput input = getWaveformInput(preset.getWaveformSetting(i).getSetting()); - if (input != null) { - input.select(preset.getWaveformSetting(i).getWaveform()); - } else { - throw new RuntimeException( - "Unable to set synthesizer input " + preset.getWaveformSetting(i).getSetting() + "."); - } - } - } - - /** - * Loads this synthesizer with the settings from the preset in the library with the given name. - */ - public void setPreset(String name) { - for (int i = 0; i < library_.getPresetCount(); ++i) { - if (library_.getPreset(i).getName().equals(name)) { - setPreset(library_.getPreset(i)); - return; - } - } - throw new RuntimeException("Tried to load an unknown preset: \"" + name + "\"."); - } - - /** - * Loads this synthesizer with the settings from the preset in the library with the given index. - */ - public void setPreset(int index) { - if (index < 0 || index >= library_.getPresetCount()) { - throw new RuntimeException("Tried to load an unknown preset: " + index + "."); - } - setPreset(library_.getPreset(index)); - } - - /** - * Returns the number of presets available in the library. - */ - public int getPresetCount() { - return library_.getPresetCount(); - } - - /** - * Populates names with the list of all known presets from the library. - * Does *not* clear the list first. - */ - public void getPresetNames(ArrayList names) { - for (int i = 0; i < library_.getPresetCount(); ++i) { - names.add(library_.getPreset(i).getName()); - } - } - - public void setLibrary(PresetLibrary library) throws IOException { - library_ = library; - } - - /** - * Return the maximum number of fingers that can be used. - */ - public int getMaxFingerCount() { - return FINGERS; - } - - // Data structures for keeping track of input. - private Map synthesizerInputs_; - private Map waveformInputs_; - - // How many fingers this synthesizer supports. - protected final int FINGERS; - - // Keyboard input. - private SynthesizerInput[] pitch_; - - // List of envelopes that needs to be triggered when a key is pressed. - private List[] envelopes_; - - //The delay module that handles recording and playback. - private Delay delay_; - - //Synthesizer output. - private SignalProvider output_; - - // A collection of setting presets. - private PresetLibrary library_; -} diff --git a/core/src/com/levien/synthesizer/core/model/composite/Presets.proto b/core/src/com/levien/synthesizer/core/model/composite/Presets.proto deleted file mode 100644 index 8eb42c7..0000000 --- a/core/src/com/levien/synthesizer/core/model/composite/Presets.proto +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package synthesizer_core_proto; - -option java_package = "com.levien.synthesizer.core.model.composite"; - -enum WaveformDeprecated { - SINE = 0; - TRIANGLE = 1; - SQUARE = 2; - SAWTOOTH = 3; - NOISE = 4; - KARPLUS_STRONG = 5; - DRAWBAR_ORGAN = 6; - DRUMS = 7; - WAVEFORM_COUNT = 8; -} - -enum Setting { - TREMOLO_ATTACK = 3; - TREMOLO_DECAY = 4; - TREMOLO_SUSTAIN = 5; - TREMOLO_RELEASE = 6; - BALANCE = 9; - ECHO_DELAY = 12; - DELAY_MIX = 13; - VOLUME = 14; - VIBRATO_ATTACK = 15; - VIBRATO_DECAY = 16; - VIBRATO_SUSTAIN = 17; - VIBRATO_RELEASE = 18; - OSCILLATOR_2_COARSE = 19; - OSCILLATOR_2_FINE = 20; - OSCILLATOR_1_WAVEFORM_NEXT = 23; - OSCILLATOR_2_WAVEFORM_NEXT = 24; - TREMOLO_WAVEFORM_NEXT = 25; - VIBRATO_WAVEFORM_NEXT = 26; - OSCILLATOR_1_WAVEFORM = 27; - OSCILLATOR_2_WAVEFORM = 28; - TREMOLO_WAVEFORM = 29; - VIBRATO_WAVEFORM = 30; - OSCILLATOR_1_WAVEFORM_PREVIOUS = 33; - OSCILLATOR_2_WAVEFORM_PREVIOUS = 34; - TREMOLO_WAVEFORM_PREVIOUS = 35; - VIBRATO_WAVEFORM_PREVIOUS = 36; - ORGAN_DRAWBAR_1 = 42; - ORGAN_DRAWBAR_2 = 43; - ORGAN_DRAWBAR_3 = 50; - ORGAN_DRAWBAR_4 = 51; - ORGAN_DRAWBAR_5 = 52; - ORGAN_DRAWBAR_6 = 53; - ORGAN_DRAWBAR_7 = 54; - ORGAN_DRAWBAR_8 = 55; - ORGAN_DRAWBAR_9 = 56; - OSCILLATOR_1_GLIDE = 57; - OSCILLATOR_1_STRETCH = 58; - OSCILLATOR_1_BLEND = 59; - OSCILLATOR_1_EXCITEMENT = 60; - OSCILLATOR_2_GLIDE = 61; - OSCILLATOR_2_STRETCH = 62; - OSCILLATOR_2_BLEND = 63; - OSCILLATOR_2_EXCITEMENT = 65; - FILTER_CUTOFF = 74; - OSCILLATOR_1_COARSE = 78; - OSCILLATOR_1_FINE = 79; - ECHO_MIX = 94; - FILTER_ATTACK = 105; - FILTER_DECAY = 106; - FILTER_SUSTAIN = 107; - FILTER_RELEASE = 108; - FILTER_DEPTH = 109; - ATTACK = 110; - DECAY = 111; - SUSTAIN = 112; - RELEASE = 113; - VIBRATO_RATE = 114; - OSCILLATOR_1_VIBRATO = 115; - OSCILLATOR_2_VIBRATO = 116; - TREMOLO_RATE = 117; - TREMOLO_DEPTH = 118; -} - -message InputSetting { - optional Setting setting = 1; - optional double value = 2; -} - -message WaveformSetting { - optional Setting setting = 1; - optional string waveform = 2; -} - -message Preset { - optional string name = 1; - repeated InputSetting input_setting = 2; - repeated WaveformSetting waveform_setting = 3; -} - -message PresetLibrary { - repeated Preset preset = 1; -} \ No newline at end of file diff --git a/core/src/com/levien/synthesizer/core/model/modules/AdsrEnvelope.java b/core/src/com/levien/synthesizer/core/model/modules/AdsrEnvelope.java deleted file mode 100644 index 0ae03fb..0000000 --- a/core/src/com/levien/synthesizer/core/model/modules/AdsrEnvelope.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.modules; - -import com.levien.synthesizer.core.model.CachedSignalProvider; -import com.levien.synthesizer.core.model.Envelope; -import com.levien.synthesizer.core.model.SignalProvider; -import com.levien.synthesizer.core.model.SynthesisTime; - -/** - * An ADSR is the most common envelope for a synth. - */ -public class AdsrEnvelope extends CachedSignalProvider implements Envelope { - /** - * Creates an ADSR with the given parameters. - * @param attack - attack time in seconds. - * @param decay - decay time in seconds. - * @param sustain - sustain level from 0 to 1. - * @param release - release time in seconds. - */ - public AdsrEnvelope(SignalProvider attack, - SignalProvider decay, - SignalProvider sustain, - SignalProvider release) { - value_ = 0.0; - attacking_ = false; - - trigger_ = false; - gate_ = false; - - attack_ = attack; - decay_ = decay; - sustain_ = sustain; - release_ = release; - } - - public synchronized double computeValue(SynthesisTime time) { - if (trigger_) { - attacking_ = true; - trigger_ = false; - // It doesn't really matter if the attack is on the leading or trailing edge of the trigger. - // By having it start on the trailing edge for 0 and the leading edge otherwise, it makes the - // math a tiny bit simpler and makes this a little easier to unit test. - if (value_ == 0) { - return value_; - } - } - - if (gate_) { - double sustain = sustain_.getValue(time); - if (attacking_) { - // Attacking. - double attack = attack_.getValue(time); - if (attack > 0.0) { - double timeDelta = time.getDeltaTime(); - value_ += timeDelta / attack; - if (value_ >= 1.0) { - // TODO(klimt): This isn't exactly right. We should really figure out what time it - // would've reached zero, and go ahead and apply the decay for that extra time that - // has passed. - value_ = 1.0; - attacking_ = false; - } - } else { - value_ = 1.0; - attacking_ = false; - } - } else if (value_ > sustain) { - // Decaying. - double decay = decay_.getValue(time); - if (decay > 0.0) { - double timeDelta = time.getDeltaTime(); - value_ += timeDelta * ((sustain - 1.0) / decay); - if (value_ < sustain) { - value_ = sustain; - } - } else { - value_ = sustain; - } - } else if (value_ < sustain) { - // Decaying backwards. - // This shouldn't _normally_ happen, but can if you change the parameters over time. - double decay = decay_.getValue(time); - if (decay > 0.0) { - double timeDelta = time.getDeltaTime(); - value_ -= timeDelta * ((sustain - 1.0) / decay); - if (value_ > sustain) { - value_ = sustain; - } - } else { - value_ = sustain; - } - } - } else { - // Releasing. - if (value_ > 0.0) { - double release = release_.getValue(time); - if (release > 0.0) { - double sustain = sustain_.getValue(time); - if (sustain == 0.0) { - double decay = decay_.getValue(time); - if (decay == 0.0) { - value_ = 0.0; - } else { - double timeDelta = time.getDeltaTime(); - value_ -= timeDelta * ((sustain - 1.0) / decay); - } - } else { - double timeDelta = time.getDeltaTime(); - value_ -= timeDelta * (sustain / release); - } - if (value_ < 0.0) { - value_ = 0.0; - } - } else { - value_ = 0.0; - } - } - } - return value_; - } - - public synchronized void turnOn(boolean retriggerIfOn) { - if (gate_ && !retriggerIfOn) { - return; - } - trigger_ = true; - gate_ = true; - } - - public synchronized void turnOff() { - gate_ = false; - } - - /** - * Returns whether the envelope is currently being triggered. - */ - public synchronized boolean getTrigger() { - return trigger_; - } - - /** - * Returns whether the key for this envelope is currently being held down. - */ - public synchronized boolean getGate() { - return gate_; - } - - // The most recently output value from this envelope. - private double value_; - - // Are we in the attack phase? - private boolean attacking_; - - // Whether the envelope is "on". - private boolean trigger_; - private boolean gate_; - - // The envelope shape parameters. - private SignalProvider attack_; - private SignalProvider decay_; - private SignalProvider sustain_; - private SignalProvider release_; -} diff --git a/core/src/com/levien/synthesizer/core/model/modules/Amplifier.java b/core/src/com/levien/synthesizer/core/model/modules/Amplifier.java deleted file mode 100755 index 8dbe4ea..0000000 --- a/core/src/com/levien/synthesizer/core/model/modules/Amplifier.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.modules; - -import com.levien.synthesizer.core.model.SignalProvider; -import com.levien.synthesizer.core.model.SynthesisTime; - -/** - * Amplifier simply multiplies the input signal by the input gain. - */ -public class Amplifier implements SignalProvider { - /** - * Creates a new Amplifier with the given signal and gain. - * @param inputSignal - Any input signal. - * @param gain - The signal it's multiplied times. - */ - public Amplifier(SignalProvider inputSignal, SignalProvider gain) { - inputSignal_ = inputSignal; - gain_ = gain; - } - - /** - * Returns signal * gain. - */ - public double getValue(SynthesisTime time) { - // Most of the time, the gain will be 0.0 because of some envelope. So this is an optimization. - double gain = gain_.getValue(time); - if (gain == 0.0) { - return 0.0; - } - return inputSignal_.getValue(time) * gain; - } - - private SignalProvider inputSignal_; - private SignalProvider gain_; -} diff --git a/core/src/com/levien/synthesizer/core/model/modules/Delay.java b/core/src/com/levien/synthesizer/core/model/modules/Delay.java deleted file mode 100755 index d166b96..0000000 --- a/core/src/com/levien/synthesizer/core/model/modules/Delay.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.modules; - -import java.util.Arrays; - -import com.levien.synthesizer.core.model.CachedSignalProvider; -import com.levien.synthesizer.core.model.SignalProvider; -import com.levien.synthesizer.core.model.SynthesisTime; - -/** - * Delay is a module for recording sampled sound and playing it back later. It has 3 modes. - * In regular mode, it outputs its input, attenuated by half. - * In record mode, it also captures sound until it is stopped or the MAX_BUFFER_SIZE is reached. - * In play mode, it plays back its output mixed with the recorded buffer in a loop. - */ -public class Delay extends CachedSignalProvider { - public Delay(SignalProvider source, SignalProvider mix) { - source_ = source; - mix_ = mix; - buffer_ = new double[MAX_BUFFER_SIZE]; - current_ = 0; - bufferSize_ = MAX_BUFFER_SIZE; - Arrays.fill(buffer_, 0.0); - playing_ = false; - recording_ = false; - } - - @Override - protected synchronized double computeValue(SynthesisTime time) { - double input = source_.getValue(time); - double mix = mix_.getValue(time); - if (playing_) { - double output = mix * buffer_[current_] + (1.0 - mix) * input; - current_ = (current_ + 1) % bufferSize_; - return output; - } else { - if (recording_) { - buffer_[bufferSize_++] = input; - if (bufferSize_ >= MAX_BUFFER_SIZE) { - stopRecording(); - } - } - return (1.0 - mix) * input; - } - } - - /** - * Resets the buffer and changes to record mode. - */ - public synchronized void startRecording() { - playing_ = false; - recording_ = true; - current_ = 0; - bufferSize_ = 0; - } - - /** - * Stops recording, but doesn't start playing. - */ - public synchronized void stopRecording() { - recording_ = false; - current_ = 0; - } - - /** - * Starts playing what's recorded. - */ - public synchronized void startPlaying() { - playing_ = true; - recording_ = false; - current_ = 0; - } - - /** - * Stops playing and recording. - */ - public synchronized void stopPlaying() { - playing_ = false; - recording_ = false; - current_ = 0; - } - - /** - * Returns whether the module is in playing mode. - */ - public synchronized boolean isPlaying() { - return playing_; - } - - /** - * Returns whether the module is in record mode. - */ - public synchronized boolean isRecording() { - return recording_; - } - - private SignalProvider source_; - private SignalProvider mix_; - - private double[] buffer_; - private int bufferSize_; - private int current_; - - private boolean playing_; - private boolean recording_; - - private final static int MAX_BUFFER_SIZE = 10; -} diff --git a/core/src/com/levien/synthesizer/core/model/modules/Echo.java b/core/src/com/levien/synthesizer/core/model/modules/Echo.java deleted file mode 100755 index fa347ae..0000000 --- a/core/src/com/levien/synthesizer/core/model/modules/Echo.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.modules; - -import com.levien.synthesizer.core.model.CachedSignalProvider; -import com.levien.synthesizer.core.model.SignalProvider; -import com.levien.synthesizer.core.model.SynthesisTime; - -/** - * The Echo module produces an echo effect by mixing its current input with its earlier input. - */ -public class Echo extends CachedSignalProvider { - /** - * Creates a new Echo module. - * @param source - The input to the echo module. - * @param mix - How wet/dry the output is, i.e. the depth of the effect. - * @param delay - The length of time in seconds between input and its first repetition. - * @param sampleRateInHz - Sample rate, used to compute buffer size from delay time. - */ - public Echo(SignalProvider source, - SignalProvider mix, - SignalProvider delay, - double sampleRateInHz) { - source_ = source; - mix_ = mix; - delay_ = delay; - sampleRateInHz_ = sampleRateInHz; - buffer_ = new double[MAX_BUFFER_SIZE]; - for (int i = 0; i < MAX_BUFFER_SIZE; ++i) { - buffer_[i] = 0.0; - } - bufferSize_ = 0; - current_ = 0; - previousDelay_ = 0.0; - } - - protected void maybeUpdateDelay(double delay) { - // As an optimization, just bail if the delay value hasn't changed. - if (previousDelay_ == delay) { - return; - } - previousDelay_ = delay; - - int newBufferSize = 0; - if (delay != 0.0) { - newBufferSize = (int)Math.round(delay * sampleRateInHz_); - } - if (bufferSize_ == newBufferSize) { - return; - } - bufferSize_ = newBufferSize; - if (bufferSize_ < 1) { - bufferSize_ = 0; - } - if (bufferSize_ > MAX_BUFFER_SIZE) { - bufferSize_ = MAX_BUFFER_SIZE; - } - } - - @Override - protected double computeValue(SynthesisTime time) { - maybeUpdateDelay(delay_.getValue(time)); - double input = source_.getValue(time); - double mix = mix_.getValue(time); - if (bufferSize_ == 0) { - return (1.0 - mix) * input; - } else { - double value = mix * buffer_[current_] + (1.0 - mix) * input; - buffer_[current_] = value; - current_ = (current_ + 1) % bufferSize_; - return value; - } - } - - private SignalProvider source_; - private SignalProvider mix_; - private SignalProvider delay_; - - private double previousDelay_; - private double[] buffer_; - private int bufferSize_; - private double sampleRateInHz_; - private int current_; - - private final static int MAX_BUFFER_SIZE = 55125; -} diff --git a/core/src/com/levien/synthesizer/core/model/modules/Glide.java b/core/src/com/levien/synthesizer/core/model/modules/Glide.java deleted file mode 100644 index e23e97f..0000000 --- a/core/src/com/levien/synthesizer/core/model/modules/Glide.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.modules; - -import com.levien.synthesizer.core.model.CachedFrequencyProvider; -import com.levien.synthesizer.core.model.FrequencyProvider; -import com.levien.synthesizer.core.model.SignalProvider; -import com.levien.synthesizer.core.model.SynthesisTime; - -/** - * Glide smooths changes in frequency over time. - */ -public class Glide extends CachedFrequencyProvider { - /** - * Creates a Glide module to wrap source. - * @param source - The input frequency to smooth. - * @param rate - The time in seconds in which output should change to a new input. - */ - public Glide(FrequencyProvider source, SignalProvider rate) { - source_ = source; - rate_ = rate; - previousLogFrequency_ = 0.0; - nextLogFrequency_ = 0.0; - } - - public double computeLogFrequency(SynthesisTime time) { - double currentLogFrequency = source_.getLogFrequency(time); - double rate = rate_.getValue(time); - - // If rate is 0 seconds, then don't do anything. - if (rate == 0.0) { - previousLogFrequency_ = currentLogFrequency; - nextLogFrequency_ = currentLogFrequency; - return currentLogFrequency; - } - - // It hasn't changed, so don't do anything. - if (currentLogFrequency == previousLogFrequency_ && - nextLogFrequency_ == previousLogFrequency_) { - return currentLogFrequency; - } - - // See where we are, based on where we were last heading. - double timeSinceChange = time.getAbsoluteTime() - switchTime_; - double output; - if (timeSinceChange > rate) { - output = nextLogFrequency_; - } else { - output = previousLogFrequency_ + - (timeSinceChange / rate) * (nextLogFrequency_ - previousLogFrequency_); - } - - // Adjust if there is a new destination. - if (currentLogFrequency != nextLogFrequency_) { - previousLogFrequency_ = output; - nextLogFrequency_ = currentLogFrequency; - switchTime_ = time.getAbsoluteTime(); - } - - return output; - } - - // The wrapped frequency provider to take as input and output smoothed. - private FrequencyProvider source_; - - // The time in seconds in which output should change to a new input. - private SignalProvider rate_; - - // The log frequency that was being output last time the input switched. - private double previousLogFrequency_; - - // The log frequency of the input that this module is moving toward. - private double nextLogFrequency_; - - // The last time that in the input frequency changed. - private double switchTime_; -} diff --git a/core/src/com/levien/synthesizer/core/model/modules/LowPassFilter.java b/core/src/com/levien/synthesizer/core/model/modules/LowPassFilter.java deleted file mode 100644 index 8d8b31b..0000000 --- a/core/src/com/levien/synthesizer/core/model/modules/LowPassFilter.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.modules; - -import com.levien.synthesizer.core.model.CachedSignalProvider; -import com.levien.synthesizer.core.model.SignalProvider; -import com.levien.synthesizer.core.model.SynthesisTime; - -/** - * A very simple low-pass filter. - */ -public class LowPassFilter extends CachedSignalProvider { - /** - * Creates a LowPassFilter with the given parameters. - * @param source - The input signal to filter. - * @param cutoff - "Alpha" parameter that controls the cutoff frequency. - */ - public LowPassFilter(SignalProvider source, SignalProvider cutoff) { - source_ = source; - alpha_ = cutoff; - previousValue_ = 0.0; - } - - public double computeValue(SynthesisTime time) { - double alpha = alpha_.getValue(time); - double output = 0.0; - if (alpha != 0) { - double signal = source_.getValue(time); - output = previousValue_ + alpha * (signal - previousValue_); - previousValue_ = output; - } else { - output = previousValue_; - } - return output; - } - - // The filter parameters. - private SignalProvider source_; - private SignalProvider alpha_; - - private double previousValue_; -} diff --git a/core/src/com/levien/synthesizer/core/model/modules/Mixer.java b/core/src/com/levien/synthesizer/core/model/modules/Mixer.java deleted file mode 100755 index 950a5be..0000000 --- a/core/src/com/levien/synthesizer/core/model/modules/Mixer.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.modules; - -import com.levien.synthesizer.core.model.SignalProvider; -import com.levien.synthesizer.core.model.SynthesisTime; - -/** - * Mixer outputs a weighted average of two input signals. - * A "balance" of 0.0 outputs signal 1, and a balance of 1.0 outputs signal 2. - * The balance can be changed over time. - */ -public class Mixer implements SignalProvider { - /** - * Creates a new Mixer. - * @param signal1 - Any input signal module. - * @param signal2 - Any input signal module. - * @param balance - A module outputting the weight to use when averaging. - */ - public Mixer(SignalProvider signal1, SignalProvider signal2, SignalProvider balance) { - signal1_ = signal1; - signal2_ = signal2; - balance_ = balance; - } - - /** - * Returns the average of the input signals, weighted by balance. - */ - public double getValue(SynthesisTime time) { - double balance = balance_.getValue(time); - // As an optimization, don't compute any signal that's not needed. - if (balance == 0.0) { - return signal1_.getValue(time); - } else if (balance == 1.0) { - return signal2_.getValue(time); - } else { - return (1.0 - balance) * signal1_.getValue(time) + balance * signal2_.getValue(time); - } - } - - private SignalProvider signal1_; - private SignalProvider signal2_; - private SignalProvider balance_; -} diff --git a/core/src/com/levien/synthesizer/core/model/modules/Tremolo.java b/core/src/com/levien/synthesizer/core/model/modules/Tremolo.java deleted file mode 100644 index 2f3878b..0000000 --- a/core/src/com/levien/synthesizer/core/model/modules/Tremolo.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.modules; - -import com.levien.synthesizer.core.model.SignalProvider; -import com.levien.synthesizer.core.model.SynthesisTime; - -/** - * Module to modulate an amplitude over time based on a modulator signal. Its output is intended to - * be fed into an amplifier. - */ -public class Tremolo implements SignalProvider { - /** - * Creates a Tremolo module. - * @param modulator - Waveform that modulates the amplitude. - * @param depth - Depth of amplitude modulation. - */ - public Tremolo(SignalProvider modulator, SignalProvider depth) { - modulator_ = modulator; - depth_ = depth; - } - - public double getValue(SynthesisTime time) { - double modulator = modulator_.getValue(time); - double depth = depth_.getValue(time); - return (modulator * (depth / 2.0)) + (1.0 - depth / 2.0); - } - - // Waveform that modulates the amplitude. - private SignalProvider modulator_; - - // Depth of amplitude modulation. - private SignalProvider depth_; -} diff --git a/core/src/com/levien/synthesizer/core/model/modules/Tuner.java b/core/src/com/levien/synthesizer/core/model/modules/Tuner.java deleted file mode 100644 index bb7e7ee..0000000 --- a/core/src/com/levien/synthesizer/core/model/modules/Tuner.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.modules; - -import com.levien.synthesizer.core.model.FrequencyProvider; -import com.levien.synthesizer.core.model.SignalProvider; -import com.levien.synthesizer.core.model.SynthesisTime; - -/** - * Module to modify the output of a frequency provider. - */ -public class Tuner implements FrequencyProvider { - /** - * Creates a Tuner module to wrap source. - * @param input - The base log frequency. - * @param shift - The amount to alter it. - */ - public Tuner(FrequencyProvider input, SignalProvider shift) { - input_ = input; - shift_ = shift; - } - - public double getLogFrequency(SynthesisTime time) { - double input = input_.getLogFrequency(time); - double shift = shift_.getValue(time); - return input + shift; - } - - // The wrapped frequency provider to take as input. - private FrequencyProvider input_; - - // The amount to alter the signal. - private SignalProvider shift_; -} diff --git a/core/src/com/levien/synthesizer/core/model/modules/WaveformSelector.java b/core/src/com/levien/synthesizer/core/model/modules/WaveformSelector.java deleted file mode 100644 index 6cff8b9..0000000 --- a/core/src/com/levien/synthesizer/core/model/modules/WaveformSelector.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.modules; - -import java.util.ArrayList; - -import com.levien.synthesizer.core.model.FrequencyProvider; -import com.levien.synthesizer.core.model.SignalProvider; -import com.levien.synthesizer.core.model.SynthesisTime; -import com.levien.synthesizer.core.model.WaveformInput; -import com.levien.synthesizer.core.model.oscillator.Noise; -import com.levien.synthesizer.core.model.oscillator.Sawtooth; -import com.levien.synthesizer.core.model.oscillator.Sine; -import com.levien.synthesizer.core.model.oscillator.Square; -import com.levien.synthesizer.core.model.oscillator.Triangle; - -/** - * Module that outputs a waveform from a selectable set of oscillators. - */ -public class WaveformSelector implements SignalProvider { - /** - * Constructs a waveform selector with no waveforms available. - * @param waveform - The source for which waveform to use at any given time. - */ - public WaveformSelector(WaveformInput waveform) { - waveform_ = waveform; - sources_ = new ArrayList(); - } - - /** - * Adds a source for a new waveform type. - */ - public synchronized void addWaveform(String waveform, SignalProvider source) { - int id = waveform_.addWaveform(waveform); - while (sources_.size() < id + 1) { - sources_.add(null); - } - sources_.set(id, source); - } - - /** - * Returns the output of the source associated with the selected waveform. - */ - public synchronized double getValue(SynthesisTime time) { - int selected = waveform_.getSelected(); - SignalProvider provider = sources_.get(selected); - if (provider != null) { - return provider.getValue(time); - } else { - return 0.0; - } - } - - /** - * Adds the standard waveforms to this selector. - */ - public synchronized void addDefaultWaveforms(FrequencyProvider frequency) { - addWaveform(WaveformInput.SINE, new Sine(frequency)); - addWaveform(WaveformInput.TRIANGLE, new Triangle(frequency)); - addWaveform(WaveformInput.SQUARE, new Square(frequency)); - addWaveform(WaveformInput.SAWTOOTH, new Sawtooth(frequency)); - addWaveform(WaveformInput.NOISE, new Noise(frequency)); - } - - // Instances of each waveform type. - private ArrayList sources_; - - // The currently selected waveform. - private WaveformInput waveform_; -} diff --git a/core/src/com/levien/synthesizer/core/model/oscillator/DrawbarOrgan.java b/core/src/com/levien/synthesizer/core/model/oscillator/DrawbarOrgan.java deleted file mode 100644 index 06ed36a..0000000 --- a/core/src/com/levien/synthesizer/core/model/oscillator/DrawbarOrgan.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.oscillator; - -import com.levien.synthesizer.core.model.FrequencyProvider; -import com.levien.synthesizer.core.model.SignalProvider; -import com.levien.synthesizer.core.model.SynthesisTime; - -/** - * An oscillator module that emulates a set of tone wheels for a drawbar organ. - */ -public class DrawbarOrgan extends Oscillator { - /** - * Creates a new drawbar organ with the given pitch and inputs for the level of each drawbar. - */ - public DrawbarOrgan(FrequencyProvider frequency, - SignalProvider subFundamental, - SignalProvider subThirdHarmonic, - SignalProvider fundamental, - SignalProvider secondHarmonic, - SignalProvider thirdHarmonic, - SignalProvider fourthHarmonic, - SignalProvider fifthHarmonic, - SignalProvider sixthHarmonic, - SignalProvider eighthHarmonic) { - super(frequency); - - depth_ = new SignalProvider[9]; - oscillator_ = new Sine[9]; - - depth_[0] = subFundamental; - oscillator_[0] = new Sine(new FrequencyProvider() { - public double getLogFrequency(SynthesisTime time) { - return frequency_.getLogFrequency(time) - 1.0; - } - }); - - depth_[1] = subThirdHarmonic; - oscillator_[1] = new Sine(new FrequencyProvider() { - public double getLogFrequency(SynthesisTime time) { - return frequency_.getLogFrequency(time) + 0.5849625; // log2(3) =~ 7/12 - } - }); - - depth_[2] = fundamental; - oscillator_[2] = new Sine(frequency); - - depth_[3] = secondHarmonic; - oscillator_[3] = new Sine(new FrequencyProvider() { - public double getLogFrequency(SynthesisTime time) { - return frequency_.getLogFrequency(time) + 1.0; - } - }); - - depth_[4] = thirdHarmonic; - oscillator_[4] = new Sine(new FrequencyProvider() { - public double getLogFrequency(SynthesisTime time) { - return frequency_.getLogFrequency(time) + 1.5849625; // 1 + log2(3) =~ 19/12 - } - }); - - depth_[5] = fourthHarmonic; - oscillator_[5] = new Sine(new FrequencyProvider() { - public double getLogFrequency(SynthesisTime time) { - return frequency_.getLogFrequency(time) + 2.0; - } - }); - - depth_[6] = fifthHarmonic; - oscillator_[6] = new Sine(new FrequencyProvider() { - public double getLogFrequency(SynthesisTime time) { - return frequency_.getLogFrequency(time) + 2.3219281; // 1 + log2(5) =~ 28/12; - } - }); - - depth_[7] = sixthHarmonic; - oscillator_[7] = new Sine(new FrequencyProvider() { - public double getLogFrequency(SynthesisTime time) { - return frequency_.getLogFrequency(time) + 2.5849625; // 1 + log2(6) =~ 31/12; - } - }); - - depth_[8] = eighthHarmonic; - oscillator_[8] = new Sine(new FrequencyProvider() { - public double getLogFrequency(SynthesisTime time) { - return frequency_.getLogFrequency(time) + 3.0; - } - }); - } - - /** - * Makes a weighted average of the value from each tone wheel. - */ - public double computeValue(SynthesisTime time) { - double output = 0.0; - double denominator = 0.0; - for (int i = 0; i < oscillator_.length; ++i) { - double depth = depth_[i].getValue(time); - if (depth != 0.0) { - output += (depth * oscillator_[i].getValue(time)); - denominator += depth; - } - } - if (denominator == 0.0) { - return 0.0; - } - return output / denominator; - } - - // How much each drawbar is pulled out. - private SignalProvider[] depth_; - - // The set of underlying sine oscillators for each tone wheel. - private Sine[] oscillator_; -} diff --git a/core/src/com/levien/synthesizer/core/model/oscillator/KarplusStrong.java b/core/src/com/levien/synthesizer/core/model/oscillator/KarplusStrong.java deleted file mode 100644 index 92683e9..0000000 --- a/core/src/com/levien/synthesizer/core/model/oscillator/KarplusStrong.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.oscillator; - -import com.levien.synthesizer.core.model.Envelope; -import com.levien.synthesizer.core.model.FrequencyProvider; -import com.levien.synthesizer.core.model.SignalProvider; -import com.levien.synthesizer.core.model.SynthesisTime; -import java.util.Arrays; - -/** - * Karplus-Strong string/drum synthesis algorithm. - * - * @param frequency - The frequency of the note produced. - * @param blend - Blend factor. Closer to 0 sounds more like a string, closer to 1 more like a drum. - * @param stretch - How fast the vibration of the string should decay. - * @param excitement - How noisy (i.e. random) the initial pluck should be. - * @param sampleRateInHz - The sample rate, used with pitch to compute KS buffer size. - */ -public class KarplusStrong extends Oscillator implements Envelope { - public KarplusStrong(FrequencyProvider frequency, - SignalProvider blend, - SignalProvider stretch, - SignalProvider excitement, - double sampleRateInHz) { - super(frequency); - sampleRateInHz_ = sampleRateInHz; - buffer_ = new double[kMaxBufferSize]; - Arrays.fill(buffer_, 0.0); - bufferSize_ = 0; - current_ = 0; - - blend_ = blend; - stretch_ = stretch; - excitement_ = excitement; - } - - @Override - protected synchronized double computeValue(SynthesisTime time) { - if (current_ == 0) { - // We've looped around to the beginning of the buffer, so take the opportunity to resize. - bufferSize_ = - (int)Math.round(sampleRateInHz_ / (Math.pow(2.0, frequency_.getLogFrequency(time)))); - if (bufferSize_ > kMaxBufferSize) { - bufferSize_ = kMaxBufferSize; - } - } - - // If the frequency is so high the buffer disappears, then we just can't do anything. - if (bufferSize_ == 0) { - trigger_ = false; - return 0.0; - } - - // The "string" has been "plucked". Fill the buffer with noise. - if (trigger_) { - trigger_ = false; - double excitement = excitement_.getValue(time); - for (int i = 0; i < kMaxBufferSize; ++i) { - if (excitement == 0.0) { - // Just an optimization. - buffer_[i] = 0.5; - } else { - buffer_[i] = excitement * (Math.random() * 2.0 - 1.0); - } - } - } - - // Process the buffer. - double output = buffer_[current_]; - double blend = blend_.getValue(time); - double stretch = 1.0 - stretch_.getValue(time); // Invert stretch so it's more intuitive. - double direction = (blend == 0.0 || (blend != 1.0 && blend <= Math.random())) ? -1.0 : 1.0; - double magnitude = 0.0; - if (stretch == 0.0 || (stretch != 1.0 && stretch <= Math.random())) { - magnitude = buffer_[current_]; - } else { - magnitude = (buffer_[current_] + previousOutput_) / 2.0; - } - buffer_[current_] = direction * magnitude; - previousOutput_ = output; - current_ = (current_ + 1) % bufferSize_; - return output; - } - - /** - * Doesn't really do anything at this time. - */ - public synchronized void turnOff() { - gate_ = false; - } - - /** - * Causes the string to be plucked by setting trigger_ to true. - */ - public synchronized void turnOn(boolean retriggerIfOn) { - if (gate_ && !retriggerIfOn) { - return; - } - trigger_ = true; - gate_ = true; - } - - private double[] buffer_; - private int bufferSize_; - private double sampleRateInHz_; - private int current_; - private double previousOutput_; - - // Blend factor. Closer to 0 sounds more like a string. Closer to 1 sounds more like a drum. - private SignalProvider blend_; - - // How fast the vibration of the string should decay. - private SignalProvider stretch_; - - // How noisy (i.e. random) the initial pluck should be. - private SignalProvider excitement_; - - private boolean trigger_; - private boolean gate_; - - // The max buffer size is the highest sample rate divided by the lowest frequency (20 Hz). - private final static int kMaxBufferSize = 44100/20; -} diff --git a/core/src/com/levien/synthesizer/core/model/oscillator/Noise.java b/core/src/com/levien/synthesizer/core/model/oscillator/Noise.java deleted file mode 100755 index f4589a2..0000000 --- a/core/src/com/levien/synthesizer/core/model/oscillator/Noise.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.oscillator; - -import com.levien.synthesizer.core.model.FrequencyProvider; -import com.levien.synthesizer.core.model.SynthesisTime; - -/** - * An oscillator module that outputs random values in the range [-1, 1]. - */ -public class Noise extends Oscillator { - public Noise(FrequencyProvider frequency) { - super(frequency); - } - - public double computeValue(SynthesisTime time) { - return Math.random() * 2.0 - 1.0; - } -} diff --git a/core/src/com/levien/synthesizer/core/model/oscillator/Oscillator.java b/core/src/com/levien/synthesizer/core/model/oscillator/Oscillator.java deleted file mode 100755 index ddb232a..0000000 --- a/core/src/com/levien/synthesizer/core/model/oscillator/Oscillator.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.oscillator; - -import com.levien.synthesizer.core.model.CachedSignalProvider; -import com.levien.synthesizer.core.model.FrequencyProvider; - -/** - * Subclass for any oscillator -- any module that outputs a waveform based on a given frequency. - * The range of the output is [-1, 1.0]. - */ -public abstract class Oscillator extends CachedSignalProvider { - /** - * Constructor for subclasses to store the frequency. - */ - public Oscillator(FrequencyProvider frequency) { - frequency_ = frequency; - } - - protected FrequencyProvider frequency_; -} diff --git a/core/src/com/levien/synthesizer/core/model/oscillator/Sawtooth.java b/core/src/com/levien/synthesizer/core/model/oscillator/Sawtooth.java deleted file mode 100755 index c32ddba..0000000 --- a/core/src/com/levien/synthesizer/core/model/oscillator/Sawtooth.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.oscillator; - -import com.levien.synthesizer.core.model.FrequencyProvider; -import com.levien.synthesizer.core.model.SynthesisTime; - -/** - * An oscillator module that outputs a sawtooth wave. - */ -public class Sawtooth extends Oscillator { - public Sawtooth(FrequencyProvider frequency) { - super(frequency); - value_ = 0.0; - currentFrequency_ = 1.0; - } - - public double computeValue(SynthesisTime time) { - // The output value drops until it is below -1.0, then shoots up to 1.0. - value_ -= (2.0 * currentFrequency_ * time.getDeltaTime()); - while (value_ <= -1.0) { - // Frequency is only updated at the end of each cycle. - double nextFrequency = Math.pow(2.0, frequency_.getLogFrequency(time)); - currentFrequency_ = nextFrequency; - // We can't just set to 1.0. The signal should have decreased from 1.0 by the amount it - // actually decreased below -1.0. - value_ += 2.0; - } - return value_; - } - - // The most recent output value. - private double value_; - - // The current frequency of the waveform. - private double currentFrequency_; -} diff --git a/core/src/com/levien/synthesizer/core/model/oscillator/Sine.java b/core/src/com/levien/synthesizer/core/model/oscillator/Sine.java deleted file mode 100755 index 865a168..0000000 --- a/core/src/com/levien/synthesizer/core/model/oscillator/Sine.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.oscillator; - -import com.levien.synthesizer.core.model.FrequencyProvider; -import com.levien.synthesizer.core.model.SynthesisTime; - -/** - * An oscillator module that outputs a sine wave. - */ -public class Sine extends Oscillator { - public Sine(FrequencyProvider frequency) { - super(frequency); - value_ = 0.0; - offset_ = 0.0; - currentLogFrequency_ = 0.0; - currentFrequency_ = 1.0; - } - - public double computeValue(SynthesisTime time) { - // Compute the output using the current frequency. - value_ = Math.sin(2 * Math.PI * currentFrequency_ * (time.getAbsoluteTime() + offset_)); - - // If the frequency is supposed to change, change the phase offset to where the new frequency - // would be outputting the same current value. - double nextLogFrequency = frequency_.getLogFrequency(time); - if (currentLogFrequency_ != nextLogFrequency) { - double nextFrequency = Math.pow(2.0, nextLogFrequency); - offset_ = ((time.getAbsoluteTime() + offset_) * currentFrequency_ / nextFrequency) - - time.getAbsoluteTime(); - currentLogFrequency_ = nextLogFrequency; - currentFrequency_ = nextFrequency; - } - - return value_; - } - - // Most recently output value. - private double value_; - - // How far out of phrase the wave is from one starting at time 0. - private double offset_; - - // Amplitude and frequency for the current output value. - private double currentLogFrequency_; - private double currentFrequency_; -} diff --git a/core/src/com/levien/synthesizer/core/model/oscillator/Square.java b/core/src/com/levien/synthesizer/core/model/oscillator/Square.java deleted file mode 100755 index b8b88fa..0000000 --- a/core/src/com/levien/synthesizer/core/model/oscillator/Square.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.oscillator; - -import com.levien.synthesizer.core.model.FrequencyProvider; -import com.levien.synthesizer.core.model.SynthesisTime; - -/** - * An oscillator module that outputs a square wave. - */ -public class Square extends Oscillator { - public Square(FrequencyProvider frequency) { - super(frequency); - sine_ = new Sine(frequency); - } - - public double computeValue(SynthesisTime time) { - // The easiest way to make a square wave is to take a sine wave and round it to -1 or 1. - if (sine_.getValue(time) > 0.0) { - return 1.0; - } else { - return -1.0; - } - } - - private Sine sine_; -} diff --git a/core/src/com/levien/synthesizer/core/model/oscillator/Triangle.java b/core/src/com/levien/synthesizer/core/model/oscillator/Triangle.java deleted file mode 100755 index aaea06b..0000000 --- a/core/src/com/levien/synthesizer/core/model/oscillator/Triangle.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.oscillator; - -import com.levien.synthesizer.core.model.FrequencyProvider; -import com.levien.synthesizer.core.model.SynthesisTime; - -/** - * An oscillator module that outputs a triangle wave. - */ -public class Triangle extends Oscillator { - public Triangle(FrequencyProvider frequency) { - super(frequency); - sawtooth_ = new Sawtooth(frequency); - } - - public double computeValue(SynthesisTime time) { - // It's a simple mathematical transformation to convert a sawtooth to a triangle. - return -2.0 * Math.abs(sawtooth_.getValue(time)) + 1.0; - } - - private Sawtooth sawtooth_; -} diff --git a/core/src/com/levien/synthesizer/core/music/EventComparator.java b/core/src/com/levien/synthesizer/core/music/EventComparator.java deleted file mode 100644 index 651302a..0000000 --- a/core/src/com/levien/synthesizer/core/music/EventComparator.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.music; - -import java.util.Comparator; - -import com.levien.synthesizer.core.music.Music.EventOrBuilder; - -/** - * A few comparators for sorting lists of Events (like in a score). - */ -public class EventComparator { - /** - * Sorts by the start times of the events. - */ - public static Comparator byStart() { - return new Comparator() { - public int compare(EventOrBuilder event, EventOrBuilder other) { - if (other.getStart() == event.getStart()) { - if (other.hasKeyEvent() && !event.hasKeyEvent()) { - return -1; - } else if (!other.hasKeyEvent() && event.hasKeyEvent()) { - return 1; - } else if (other.getEnd() == event.getEnd()) { - return 0; - } else if (other.getEnd() > event.getEnd()) { - return 1; - } else { - return -1; - } - } else if (other.getStart() < event.getStart()) { - return 1; - } else { - return -1; - } - } - }; - } - - /** - * Sorts by the end times of the events. - */ - public static Comparator byEnd() { - return new Comparator() { - public int compare(EventOrBuilder event, EventOrBuilder other) { - if (other.getEnd() == event.getEnd()) { - if (other.hasKeyEvent() && !event.hasKeyEvent()) { - return 1; - } else if (!other.hasKeyEvent() && event.hasKeyEvent()) { - return -1; - } else if (other.getStart() == event.getStart()) { - return 0; - } else if (other.getStart() < event.getStart()) { - return -1; - } else { - return 1; - } - } else if (other.getEnd() < event.getEnd()) { - return 1; - } else { - return -1; - } - } - }; - } -} diff --git a/core/src/com/levien/synthesizer/core/music/Music.proto b/core/src/com/levien/synthesizer/core/music/Music.proto deleted file mode 100644 index 1848c0b..0000000 --- a/core/src/com/levien/synthesizer/core/music/Music.proto +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package synthesizer_core_music; - -option java_package = "com.levien.synthesizer.core.music"; - -// An Event is one item in a score. It has a start and end time, and information about what -// happens at that time, such as what note is played, and on what channel (instrument). -message Event { - // The start time of the event in measures from the beginning of the score. - optional double start = 1; - - // The end time of the event. - optional double end = 2; - - // The start time before "snapping to" the nearest note in the editor. - optional double unsnapped_start = 3; - - // The end time before "snapping to" the nearest note in the editor. - optional double unsnapped_end = 4; - - // For a key event, the key/note being pressed. For other events, this is just where it shows up - // in the score. For example, a loop event shows on a certain key just because that makes them - // easier to edit. - optional int32 key = 5; - - // The key before before "snapping to" the nearest whole key in the editor. - // This can hold a fractional key, which can represent a valid frequency between two notes, - // which might be valid for some synthesizers, but not for midi output. - optional double unsnapped_key = 6; - - // Is this event selected in the UI? - optional bool selected = 7; - - // An event where a key is pressed. - optional KeyEvent key_event = 8; - - // An event where that defines a loop. - optional LoopEvent loop_event = 9; -} - -// An event where a key is pressed at the beginning and released at the end. -message KeyEvent { - // The channel/instrument to play the note on. - optional int32 channel = 1; -} - -// An event where playback jumps from the end to the beginning a certain number of times. -message LoopEvent { - // The total number of times to loop. - optional int32 count = 1; - - // The number of times left to loop in the current playback. - optional int32 count_remaining = 2; -} - -// A score, representing a series of synthesizer events that can be played. -message Score { - // The set of events, in no particular order. - repeated Event event = 1; -} diff --git a/core/src/com/levien/synthesizer/core/music/Note.java b/core/src/com/levien/synthesizer/core/music/Note.java deleted file mode 100755 index 49a8428..0000000 --- a/core/src/com/levien/synthesizer/core/music/Note.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.music; - -/** - * Collection of static methods dealing with musical notes. - */ -public class Note { - /** - * Determines the log frequency of a note in 12 tone equal temperament (12-TET). - * @param note - the note, a value from one of the constants in this class. - * @param octave - the octave of the note. - */ - public static double computeLog12TET(int note, int octave) { - return FACTOR + ((((12 * octave) + (note - 9) + 1) - 49) / 12.0); - } - - /** - * Returns the note, or midi key, that corresponds to the given log frequency. - * @param logFrequency - the log frequency that corresponds to a note. - * @return - the nearest note to that frequency. - */ - public static int getKeyforLog12TET(double logFrequency) { - return (int)(12.0 * (logFrequency - FACTOR) + 57.5); - } - - /** - * Returns true if the note is natural, i.e. not a sharp or flat. - * @param note - the note, a value from one of the constants in this class. - */ - public static boolean isNatural(int note) { - return NATURAL[note % NATURAL.length]; - } - - /** - * Returns a printable name for the given note. - * @param note - the note, a value from one of the constants in this class. - */ - public static String getName(int note) { - return NAMES[note]; - } - - // Note frequencies in 12-TET are defined relative to log2 of A4 (440Hz). - // There's no reason to redo the log conversion every time a frequency is computed. - private static final double FACTOR = Math.log(440.0) / Math.log(2.0); - - // Constants for each of the possible notes. - public static final int NONE = -1; - public static final int C = 0; - public static final int C_SHARP = 1; - public static final int D_FLAT = 1; - public static final int D = 2; - public static final int D_SHARP = 3; - public static final int E_FLAT = 3; - public static final int E = 4; - public static final int F = 5; - public static final int F_SHARP = 6; - public static final int G_FLAT = 6; - public static final int G = 7; - public static final int G_SHARP = 8; - public static final int A_FLAT = 8; - public static final int A = 9; - public static final int A_SHARP = 10; - public static final int B_FLAT = 10; - public static final int B = 11; - - // Constants for intervals between notes. - public static final double HALF_STEP = 1.0f / 12.0f; - public static final double WHOLE_STEP = 1.0f / 6.0f; - public static final double OCTAVE = 1.0f; - - // A simple map of which notes are natural. - private static final boolean[] NATURAL = { - true, false, true, false, true, true, false, true, false, true, false, true }; - - // A displayable name for each note. - private static final String[] NAMES = { - "C", "C#", "D", "Eb", "E", "F", "F#", "G", "Ab", "A", "Bb", "B" - }; -} diff --git a/core/src/com/levien/synthesizer/core/music/ScorePlayer.java b/core/src/com/levien/synthesizer/core/music/ScorePlayer.java deleted file mode 100644 index 85e0fb7..0000000 --- a/core/src/com/levien/synthesizer/core/music/ScorePlayer.java +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.music; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.ListIterator; -import java.util.PriorityQueue; -import java.util.logging.Logger; - -import com.levien.synthesizer.core.midi.MidiListener; -import com.levien.synthesizer.core.model.composite.MultiChannelSynthesizer; -import com.levien.synthesizer.core.music.Music.Event; -import com.levien.synthesizer.core.music.Music.Score; - -/** - * Methods for playing a score using a synthesizer. - * @see ScorePlayerListener - */ -public class ScorePlayer { - /** - * Creates a new ScorePlayer. - */ - public ScorePlayer() { - logger_ = Logger.getLogger(ScorePlayer.class.getName()); - playing_ = false; - } - - /** - * Merges identical loop events in a sorted list of events. Since having two loops over the same - * time period would normally make them multiplicative, and that isn't useful, this changes that - * one situation to make them additive. That way, you can have a segment that play three times - * without having to create any events that have a repeat count other than one. - */ - private void mergeIdenticalLoopEvents(ArrayList startList) { - for (int i = 0; i < startList.size(); ++i) { - if (i+1 < startList.size() && - startList.get(i).hasLoopEvent() && - startList.get(i+1).hasLoopEvent() && - startList.get(i).getStart() == startList.get(i+1).getStart() && - startList.get(i).getEnd() == startList.get(i+1).getEnd()) { - startList.get(i).getLoopEventBuilder().setCount( - startList.get(i).getLoopEventBuilder().getCount() + - startList.get(i+1).getLoopEventBuilder().getCount()); - startList.remove(i+1); - i--; - } - } - } - - /** - * Plays the given score using the given synthesizer. Returns immediately, while the music plays - * in a separate thread. - * - * @param synth - the synthesizer to use for output. - * @param score - the score to play. - * @param beatsPerMinute - the tempo to play. - * @param beatsPerMeasure - the time signature. - * @param listener - the listener to notify of events. - */ - public synchronized void startPlaying(MidiListener synth, - Score score, - double beatsPerMinute, - int beatsPerMeasure, - ScorePlayerListener listener) { - if (playing_) { - logger_.warning("startPlaying called while already playing."); - return; - } - - // Copy the sequence so that it's safe to modify it while it's playing asynchronously. - ArrayList startList = - new ArrayList(Score.newBuilder(score).getEventBuilderList()); - Collections.sort(startList, EventComparator.byStart()); - mergeIdenticalLoopEvents(startList); - starts_ = startList.listIterator(); - - ends_ = new PriorityQueue(startList.size(), EventComparator.byEnd()); - - // Setup the internal state. - synth_ = synth; - listener_ = listener; - beatsPerMinute_ = beatsPerMinute; - beatsPerMeasure_ = beatsPerMeasure; - playing_ = true; - stop_ = false; - currentTime_ = 0.0; - - listener_.onStart(); - - new Thread("ScorePlayer.startPlaying()") { - public void run() { - logger_.info("ScorePlayer.startPlaying() thread running."); - while (true) { - // While we have the lock, we'll need to see how long to sleep until the next iteration of - // the loop. This variable will contain that delay at the end of the loop. - long delay; - - synchronized (ScorePlayer.this) { - onTimeUpdate(); - - // Check if it's time to stop. - if (stop_) { - playing_ = false; - - // Okay, now finish off all of the events that have been started. - while (!ends_.isEmpty()) { - Event.Builder event = ends_.remove(); - if (event.hasKeyEvent()) { - synth_.onNoteOff(event.getKeyEvent().getChannel(), event.getKey(), 0); - } - } - - listener_.onStop(); - logger_.info("Finished playing."); - break; - } - - // See if there are more events to process. - if (!starts_.hasNext() && ends_.isEmpty()) { - // There are no more events to process. - stop_ = true; - continue; - } - - // There are more events. See when the next one should be processed. - boolean isEnd; - double targetTime; - if (!starts_.hasNext()) { - // All of the start events are over. The next event will need to be an end event. - isEnd = true; - targetTime = getSecondsPerMeasure() * ends_.peek().getEnd(); - } else if (ends_.isEmpty()) { - // There are no end events queued up yet. The next event will need to be a start. - isEnd = false; - targetTime = getSecondsPerMeasure() * starts_.next().getStart(); - starts_.previous(); - } else { - // We'll need to process either a start or an end, whichever is first. - if (ends_.peek().getEnd() <= peek(starts_).getStart()) { - // Process the next end. - isEnd = true; - targetTime = getSecondsPerMeasure() * ends_.peek().getEnd(); - } else { - // Process the next start. - isEnd = false; - targetTime = getSecondsPerMeasure() * peek(starts_).getStart(); - } - } - - // See if we need to process an event now. - if (currentTime_ >= targetTime) { - // Yes, we do. - if (isEnd) { - Event.Builder event = ends_.remove(); - if (event.hasKeyEvent()) { - synth_.onNoteOff(event.getKeyEvent().getChannel(), - event.getKey(), 0); - } else if (event.hasLoopEvent()) { - if (!event.getLoopEvent().hasCountRemaining()) { - event.getLoopEventBuilder().setCountRemaining(event.getLoopEvent().getCount()); - } - if (event.getLoopEvent().getCountRemaining() > 0) { - // Okay, it's time to loop. - // TODO(klimt): Ideally, we'd kill all note events currently alive, but we - // don't want to kill any of the loop events, so it's a little tricky. - // while (!ends_.isEmpty()) { - // Event.Builder eventToStop = ends_.remove(); - // if (eventToStop.hasKeyEvent()) { - // synth_.onNoteOff(eventToStop.getKeyEvent().getChannel(), - // eventToStop.getKey(), 0); - // } - // } - // Now, rewind the start list until it's before the start time. - while (starts_.previous() != event) { - // Rewind. - } - // Okay, now update the current time. - currentTime_ = getSecondsPerMeasure() * event.getStart(); - targetTime = currentTime_; - event.getLoopEventBuilder().setCountRemaining( - event.getLoopEvent().getCountRemaining() - 1); - } else { - // We're finished with this loop, so we're moving on. - event.getLoopEventBuilder().clearCountRemaining(); - } - } - } else { - Event.Builder event = starts_.next(); - if (event.hasKeyEvent()) { - synth_.onNoteOn(event.getKeyEvent().getChannel(), event.getKey(), 127); - } - // We started the event, so let's make sure we end it eventually. :) - ends_.add(event); - } - // Okay, move on to the next event. - continue; - } - - // If we got this far, we'll need to sleep until the next event. See how long. - delay = (long)((targetTime - currentTime_) * 1000.0); - } // synchronized (ScorePlayer.this) - - // Sleep for a while. - if (delay > 250) { - delay = 250; - } - try { - Thread.sleep(delay); - } catch (InterruptedException e) { - logger_.warning("Sequence.play() thread interrupted."); - } - - synchronized (ScorePlayer.this) { - currentTime_ += (delay / 1000.0); - } - } // while (true) - } // run() - }.start(); - } - - /** - * This is a stupid hack because ListIterator doesn't have a peek method. - */ - private static Event.Builder peek(ListIterator iterator) { - Event.Builder event = iterator.next(); - iterator.previous(); - return event; - } - - /** - * Stops playback as soon as convenient. Doesn't block. - */ - public synchronized void stopPlaying() { - stop_ = true; - } - - /** - * Returns the number of seconds each measure of the song should take. - */ - private synchronized double getSecondsPerMeasure() { - return (beatsPerMeasure_ / beatsPerMinute_) * 60.0; - } - - /** - * Calls the onTimeUpdate() method of the listener. - */ - private synchronized void onTimeUpdate() { - listener_.onTimeUpdate(currentTime_ / getSecondsPerMeasure()); - } - - // The synthesizer to use for playing. - private MidiListener synth_; - - // The tempo of the song. - private double beatsPerMinute_; - - // The time signature of the score. - private int beatsPerMeasure_; - - // The listener to notify of events. - private ScorePlayerListener listener_; - - // Is the thread playing? - private boolean playing_; - - // Should the thread stop? - private boolean stop_; - - // The time of the current head of the playback, in seconds. - private double currentTime_; - - // The sequence being played. - private ListIterator starts_; - private PriorityQueue ends_; - - private Logger logger_; -} diff --git a/core/src/com/levien/synthesizer/core/music/ScorePlayerListener.java b/core/src/com/levien/synthesizer/core/music/ScorePlayerListener.java deleted file mode 100644 index ea6d61b..0000000 --- a/core/src/com/levien/synthesizer/core/music/ScorePlayerListener.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.music; - -/** - * Listener for events from a ScorePlayer. - * @see ScorePlayer - */ -public interface ScorePlayerListener { - /** - * Called when playback starts. - */ - void onStart(); - - /** - * Called every so often during playback. - * @param time - time in measures from the start of the score. - */ - void onTimeUpdate(double time); - - /** - * Called when playback stops. - */ - void onStop(); -} diff --git a/core/src/com/levien/synthesizer/core/soundfont/Bag.java b/core/src/com/levien/synthesizer/core/soundfont/Bag.java deleted file mode 100644 index c3671fd..0000000 --- a/core/src/com/levien/synthesizer/core/soundfont/Bag.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.soundfont; - -import java.io.IOException; - -import com.levien.synthesizer.core.wave.RiffInputStream; - -/** - * A Bag is a structure particular to the SoundFont format that represents a list of generators and - * modulators. It could be a "preset bag" or an "instrument bag", but it's basically the same. - */ -public class Bag { - /** - * Reads one Bag from the given input stream. - * @param input - An input stream where the next bytes represent a bag. - */ - public Bag(RiffInputStream input) throws IOException { - generatorStart_ = input.readWord(); - modulatorStart_ = input.readWord(); - generatorEnd_ = generatorStart_; - modulatorEnd_ = modulatorStart_; - } - - /** - * @return The index of the first generator in this bag. - */ - public int getGeneratorStart() { - return generatorStart_; - } - - /** - * @return The index of the first modulator in this bag. - */ - public int getModulatorStart() { - return modulatorStart_; - } - - /** - * @return The index of the first generator after getGeneratorStart() *not* in this bag. - */ - public int getGeneratorEnd() { - return generatorEnd_; - } - - /** - * @return The index of the first modulator after getModulatorStart() *not* in this bag. - */ - public int getModulatorEnd() { - return modulatorEnd_; - } - - /** - * Sets the value to be returned by getGeneratorEnd(). - */ - public void setGeneratorEnd(int end) { - generatorEnd_ = end; - } - - /** - * Sets the value to be returned by getModulatorEnd(). - */ - public void setModulatorEnd(int end) { - modulatorEnd_ = end; - } - - /** - * Returns a user-readable string representing this bag. - */ - public String toString() { - return - "Bag {\n" + - " generator: [" + generatorStart_ + ", " + generatorEnd_ + ")\n" + - " modulator: [" + modulatorStart_ + ", " + modulatorEnd_ + ")\n" + - "}"; - } - - private int generatorStart_; - private int modulatorStart_; - private int generatorEnd_; - private int modulatorEnd_; -} diff --git a/core/src/com/levien/synthesizer/core/soundfont/Generator.java b/core/src/com/levien/synthesizer/core/soundfont/Generator.java deleted file mode 100644 index 6cc4793..0000000 --- a/core/src/com/levien/synthesizer/core/soundfont/Generator.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.soundfont; - -import java.io.IOException; - -import com.levien.synthesizer.core.wave.RiffInputStream; - -/** - * A Generator is a SoundFont data structure that represents an "operator" and an "amount". - */ -public class Generator { - /** - * Reads one generator from the given input. - */ - public Generator(RiffInputStream input) throws IOException { - operator_ = Operator.fromType(input.readWord()); - amount_ = input.readShort(); - } - - /** - * @return The operator for this generator. - */ - public Operator getOperator() { - return operator_; - } - - /** - * @return The unprocessed argument associated with this generator. - */ - public short getAmount() { - return amount_; - } - - /** - * Returns a user-readable string representing this generator. - */ - public String toString() { - return - "Generator {\n" + - " operator: " + operator_.toString() + " (" + operator_.getType() + ")\n" + - " amount: " + amount_ + "\n" + - "}"; - } - - private Operator operator_; - private short amount_; -} diff --git a/core/src/com/levien/synthesizer/core/soundfont/Instrument.java b/core/src/com/levien/synthesizer/core/soundfont/Instrument.java deleted file mode 100644 index 57775a4..0000000 --- a/core/src/com/levien/synthesizer/core/soundfont/Instrument.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.soundfont; - -import java.io.IOException; -import java.util.ArrayList; - -import com.levien.synthesizer.core.wave.RiffInputStream; - -/** - * An instrument is a SoundFont data structure that consists of a set of zones. Each "zone" is - * basically a flattened "bag" with a sample and a key range, etc. - */ -public class Instrument { - /** - * Reads one instrument from the given input. - */ - public Instrument(RiffInputStream input) throws IOException { - name_ = input.readString(20); - bagStart_ = input.readWord(); - bagEnd_ = bagStart_; - zoneList_ = new ArrayList(); - } - - public String getName() { - return name_; - } - - public int getBagStart() { - return bagStart_; - } - - public int getBagEnd() { - return bagEnd_; - } - - public void setBagEnd(int end) { - bagEnd_ = end; - } - - public void addZone(Zone zone) { - zoneList_.add(zone); - } - - public ArrayList getZoneList() { - return zoneList_; - } - - /** - * Returns a user-readable string representing this instrument. - */ - public String toString() { - return - "Instrument {\n" + - " name: \"" + name_ + "\"\n" + - " bag index: [" + bagStart_ + ", " + bagEnd_ + ")\n" + - "}"; - } - - private String name_; - private int bagStart_; - private int bagEnd_; - private ArrayList zoneList_; -} diff --git a/core/src/com/levien/synthesizer/core/soundfont/Modulator.java b/core/src/com/levien/synthesizer/core/soundfont/Modulator.java deleted file mode 100644 index 0d5811b..0000000 --- a/core/src/com/levien/synthesizer/core/soundfont/Modulator.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.soundfont; - -import java.io.IOException; - -import com.levien.synthesizer.core.wave.RiffInputStream; - -/** - * A Modulator is a SoundFont data structure. They are read in by this library, but then ignored. - */ -public class Modulator { - public Modulator(RiffInputStream input) throws IOException { - sourceOperator = new ModulatorSource(input.readWord()); - destinationOperator = input.readWord(); - amount = input.readShort(); - amountOperator = new ModulatorSource(input.readWord()); - transform = input.readWord(); - } - - public String toString() { - return - "Modulator {\n" + - " source operator: \n" + - sourceOperator + "\n" + - " destination operator: " + destinationOperator + "\n" + - " amount: " + amount + "\n" + - " amount operator: \n" + - amountOperator + "\n" + - " transform: " + transform + "\n" + - "}"; - } - - public ModulatorSource sourceOperator; - public int destinationOperator; - public short amount; - public ModulatorSource amountOperator; - public int transform; -} diff --git a/core/src/com/levien/synthesizer/core/soundfont/ModulatorSource.java b/core/src/com/levien/synthesizer/core/soundfont/ModulatorSource.java deleted file mode 100644 index 12b694c..0000000 --- a/core/src/com/levien/synthesizer/core/soundfont/ModulatorSource.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.soundfont; - -/** - * A ModulatorSource is a SoundFont data structure. They are read by this library and then ignored. - */ -public class ModulatorSource { - /** - * Initializes the source from the given value. - */ - public ModulatorSource(int value) { - type_ = (byte)((0xFC00 & value) >> 10); - polarity_ = ((value & 0x0200) != 0); - direction_ = ((value & 0x0100) != 0); - continuous_ = ((value & 0x0080) != 0); - index_ = (byte)(0x007F & value); - } - - public String toString() { - return - " ModulatorSource {\n" + - " type: " + type_ + "\n" + - " polarity: " + polarity_ + "\n" + - " direction: " + direction_ + "\n" + - " continuous: " + continuous_ + "\n" + - " index: " + index_ + "\n" + - " }"; - } - - private byte type_; - public boolean polarity_; - public boolean direction_; - public boolean continuous_; - public byte index_; -} diff --git a/core/src/com/levien/synthesizer/core/soundfont/Operator.java b/core/src/com/levien/synthesizer/core/soundfont/Operator.java deleted file mode 100644 index 21d5c0e..0000000 --- a/core/src/com/levien/synthesizer/core/soundfont/Operator.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.soundfont; - -/** - * An enumeration of all possible SoundFont Generator Operators. - * Most of these are ignored. - */ -public enum Operator { - UNSUPPORTED(-1), - START_ADDRS_OFFSET(0, false), - END_ADDRS_OFFSET(1, false), - STARTLOOP_ADDRS_OFFSET(2, false), - ENDLOOP_ADDRS_OFFSET(3, false), - START_ADDRS_COARSE_OFFSET(4, false), - MOD_LFO_TO_PITCH(5), - VIB_LFO_TO_PITCH(6), - MOD_ENV_TO_PITCH(7), - INITIAL_FILTER_FC(8), - INITIAL_FILTER_Q(9), - MOD_LFO_TO_FILTER_FC(10), - MOD_ENV_TO_FILTER_FC(11), - END_ADDRS_COARSE_OFFSET(12, false), - MOD_LFO_TO_VOLUME(13), - CHORUS_EFFECTS_SEND(15), - REVERB_EFFECTS_SEND(16), - PAN(17), - DELAY_MOD_LFO(21), - FREQ_MOD_LFO(22), - DELAY_VIB_LFO(23), - FREQ_VIB_LFO(24), - DELAY_MOD_ENV(25), - ATTACK_MOD_ENV(26), - HOLD_MOD_ENV(27), - DECAY_MOD_ENV(28), - SUSTAIN_MOD_ENV(29), - RELEASE_MOD_ENV(30), - KEYNUM_TO_MOD_ENV_HOLD(31), - KEYNUM_TO_MOD_ENV_DECAY(32), - DELAY_VOL_ENV(33), - ATTACK_VOL_ENV(34), - HOLD_VOL_ENV(35), - DECAY_VOL_ENV(36), - SUSTAIN_VOL_ENV(37), - RELEASE_VOL_END(38), - KEYNUM_TO_VOL_ENV_HOLD(39), - KEYNUM_TO_VOL_ENV_DECAY(40), - INSTRUMENT(41, true, false), - KEY_RANGE(43), - VELOCITY_RANGE(44), - STARTLOOP_ADDRS_COARSE_OFFSET(45, false), - KEYNUM(46, false), - VELOCITY(47, false), - INITIAL_ATTENUATION(48), - ENDLOOP_ADDRS_COARSE_OFFSET(50, false), - COARSE_TUNE(51), - FINE_TUNE(52), - SAMPLE_ID(53, false), - SAMPLE_MODES(54, false), - SCALE_TUNING(56), - EXCLUSIVE_CLASS(57, false), - OVERRIDING_ROOT_KEY(58, false), - END_OPER(60); - - /** - * Creates a new enum value. - * @param type - The enum value in the SoundFont format. - * @param validForPreset - True if this operator would be valid in a preset zone. - * @param validForInstrument - True if this operator would be valid in an instrument zone. - */ - Operator(int type, boolean validForPreset, boolean validForInstrument) { - type_ = type; - validForPreset_ = validForPreset; - validForInstrument_ = validForInstrument; - } - - /** - * Creates a new enum value that is valid for an instrument zone. - * @param type - The enum value in the SoundFont format. - * @param validForPreset - True if this operator would be valid in a preset zone. - */ - Operator(int type, boolean validForPreset) { - this(type, validForPreset, true); - } - - /** - * Creates a new enum value that is valid for a preset or instrument zone. - * @param type - The enum value in the SoundFont format. - */ - Operator(int type) { - this(type, true); - } - - /** - * @return The SoundFont enum value for this operator. - */ - public int getType() { - return type_; - } - - /** - * @return True if this operator is valid in a preset zone. - */ - public boolean isValidForPreset() { - return validForPreset_; - } - - /** - * @return True if this operator is valid in an instrument zone. - */ - public boolean isValidForInstrument() { - return validForInstrument_; - } - - /** - * @return The operator corresponding to the given type. - * @param type - The enum value in the SoundFont format. - */ - public static Operator fromType(int type) { - // TODO(klimt): Keep an index instead of linear search. - for (Operator op : Operator.values()) { - if (op.getType() == type) { - return op; - } - } - return UNSUPPORTED; - } - - private final int type_; - private final boolean validForPreset_; - private final boolean validForInstrument_; -} diff --git a/core/src/com/levien/synthesizer/core/soundfont/Preset.java b/core/src/com/levien/synthesizer/core/soundfont/Preset.java deleted file mode 100644 index 9dcaa7f..0000000 --- a/core/src/com/levien/synthesizer/core/soundfont/Preset.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.soundfont; - -import java.io.IOException; -import java.util.ArrayList; - -import com.levien.synthesizer.core.wave.RiffInputStream; - -/** - * A Preset is a SoundFont data structure that corresponds to a bunch of "preset zones" and a set - * of instruments. - */ -public class Preset { - /** - * Reads one Preset from the given input stream. - */ - public Preset(RiffInputStream input) throws IOException { - name_ = input.readString(20); - preset_ = input.readWord(); - bank_ = input.readWord(); - bagStart_ = input.readWord(); - bagEnd_ = bagStart_; - library_ = input.readDWord(); - genre_ = input.readDWord(); - morphology_ = input.readDWord(); - zoneList_ = new ArrayList(); - } - - public String getName() { - return name_; - } - - public int getBagStart() { - return bagStart_; - } - - public int getBagEnd() { - return bagEnd_; - } - - public void setBagEnd(int end) { - bagEnd_ = end; - } - - public void addZone(Zone zone) { - zoneList_.add(zone); - } - - public ArrayList getZoneList() { - return zoneList_; - } - - public String toString() { - return - "Preset {\n" + - " name: \"" + name_ + "\"\n" + - " preset: " + preset_ + "\n" + - " bank: " + bank_ + "\n" + - " bag index: [" + bagStart_ + ", " + bagEnd_ + ")\n" + - "}"; - } - - private String name_; - private int preset_; - private int bank_; - - private int bagStart_; - private int bagEnd_; - - private ArrayList zoneList_; - - @SuppressWarnings("unused") - private long library_; - @SuppressWarnings("unused") - private long genre_; - @SuppressWarnings("unused") - private long morphology_; -} diff --git a/core/src/com/levien/synthesizer/core/soundfont/Sample.java b/core/src/com/levien/synthesizer/core/soundfont/Sample.java deleted file mode 100644 index 5c9ada6..0000000 --- a/core/src/com/levien/synthesizer/core/soundfont/Sample.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.soundfont; - -import java.io.IOException; - -import com.levien.synthesizer.core.wave.RiffInputStream; - -/** - * A Sample is a subset of sample data from a SoundFont file. - */ -public class Sample { - /** - * Reads one SampleHeader from the given input stream. - * @param input - A SoundFont input stream. - * @param samples - All of the sample data from the SoundFont file. - */ - public Sample(RiffInputStream input, double[] samples) throws IOException { - name_ = input.readString(20); - start_ = (int)input.readDWord(); - end_ = (int)input.readDWord(); - startLoop_ = (int)input.readDWord(); - endLoop_ = (int)input.readDWord(); - sampleRate_ = input.readDWord(); - originalKey_ = input.readByte(); - correction_ = input.readChar(); - sampleLink_ = input.readWord(); - sampleType_ = SampleLink.fromType(input.readWord()); - if (sampleType_.equals(SampleLink.UNKNOWN) && - !name_.equals("EOS")) { - throw new IOException("Unsupported sample type."); - } - sample_ = samples; - } - - /** - * @return The index of the first sample in the sample. - */ - public long getStart() { - return start_; - } - - /** - * @return The index of one past the last sample in the sample. - */ - public long getEnd() { - return end_; - } - - /** - * @return The sample rate of the sample. - */ - public long getRate() { - return sampleRate_; - } - - /** - * @return The number of samples in the sample. - */ - public int getCount() { - return end_ - start_; - } - - /** - * Returns one sample from the, um, sample. - * @param i - The index of the sample. Should be between getStart() and getEnd(). - */ - public double getSample(int i) { - return sample_[i]; - } - - /** - * Returns a human-readable description of the sample. - */ - public String toString() { - return - "SampleHeader {\n" + - " name: " + name_ + "\n" + - " start: " + start_ + "\n" + - " end: " + end_ + "\n" + - " start loop: " + startLoop_ + "\n" + - " end loop: " + endLoop_ + "\n" + - " sample rate: " + sampleRate_ + "\n" + - " original key: " + originalKey_ + "\n" + - " correction: " + correction_ + "\n" + - " sample link: " + sampleLink_ + "\n" + - " sample type: " + sampleType_.toString() + " (" + sampleType_.getType() + ")\n" + - "}"; - } - - // The info from the SampleHeader. - private String name_; - private int start_; - private int end_; - private int startLoop_; - private int endLoop_; - private long sampleRate_; - private short originalKey_; - private byte correction_; - private int sampleLink_; - private SampleLink sampleType_; - - // All of the actual sample data from the SoundFont file. - private double[] sample_; -} diff --git a/core/src/com/levien/synthesizer/core/soundfont/SampleLink.java b/core/src/com/levien/synthesizer/core/soundfont/SampleLink.java deleted file mode 100644 index df3c96a..0000000 --- a/core/src/com/levien/synthesizer/core/soundfont/SampleLink.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.soundfont; - -/** - * SampleLink enum for the SoundFont format. - */ -public enum SampleLink { - UNKNOWN(-1), - MONO_SAMPLE(1), - RIGHT_SAMPLE(2), - LEFT_SAMPLE(4), - LINKED_SAMPLE(8), - ROM_MONO_SAMPLE(0x8001), - ROM_RIGHT_SAMPLE(0x8002), - ROM_LEFT_SAMPLE(0x8004), - ROM_LINKED_SAMPLE(0x8008); - - /** - * Creates a new enum value for the given type. - */ - SampleLink(int type) { - type_ = type; - } - - /** - * @return The enum value from the SoundFont format. - */ - public int getType() { - return type_; - } - - /** - * @return The enum corresponding to the given SoundFont format value. - */ - public static SampleLink fromType(int type) { - for (SampleLink sl : SampleLink.values()) { - if (sl.getType() == type) { - return sl; - } - } - return UNKNOWN; - } - - private final int type_; -} diff --git a/core/src/com/levien/synthesizer/core/soundfont/SoundFontOscillator.java b/core/src/com/levien/synthesizer/core/soundfont/SoundFontOscillator.java deleted file mode 100644 index 7f5165e..0000000 --- a/core/src/com/levien/synthesizer/core/soundfont/SoundFontOscillator.java +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.soundfont; - -import java.util.Arrays; -import java.util.logging.Logger; - -import com.levien.synthesizer.core.model.Envelope; -import com.levien.synthesizer.core.model.FrequencyProvider; -import com.levien.synthesizer.core.model.SynthesisTime; -import com.levien.synthesizer.core.model.oscillator.Oscillator; -import com.levien.synthesizer.core.music.Note; -import com.levien.synthesizer.core.soundfont.Zone.SampleMode; - -/** - * An oscillator module that outputs a sample from a file. - */ -public class SoundFontOscillator extends Oscillator implements Envelope { - /** - * Creates a new oscillator from a preset in a SoundFont file. - * @param frequency - The frequency determines what key was pressed. - * @parma preset - The SoundFont preset to get the sample data from. - * @param sampleRateInHz - The sample rate of the output synthesizer. - */ - public SoundFontOscillator(FrequencyProvider frequency, - Preset preset, - double sampleRateInHz) { - super(frequency); - logger_ = Logger.getLogger(getClass().getName()); - preset_ = preset; - sampleRateInHz_ = sampleRateInHz; - - // Find the max sample length. - maxSampleLength_ = 1; - for (Zone pzone : preset_.getZoneList()) { - Instrument instrument = pzone.getInstrument(); - if (instrument != null) { - for (Zone izone : instrument.getZoneList()) { - Sample sample = izone.getSample(); - int length = (int)Math.ceil((sampleRateInHz_ * izone.getCount()) / sample.getRate()); - if (length > maxSampleLength_) { - maxSampleLength_ = length; - } - } - } - } - - currentSample_ = null; - currentSampleIndex_ = 0; - - buffer_ = new double[maxSampleLength_]; - Arrays.fill(buffer_, 0.0); - bufferIndex_ = 0; - } - - /** - * Gets one value from the synthesizer. - */ - public synchronized double computeValue(SynthesisTime time) { - // How many samples have passed? - double deltaTime = time.getAbsoluteTime() - previousTime_; - previousTime_ = time.getAbsoluteTime(); - - // First, skip over however many samples we've passed in the buffer. - int bufferSamples = (int)(deltaTime * sampleRateInHz_ + 0.5); - // If everything in the buffer would be skipped, don't do extra work. - if (bufferSamples > buffer_.length) { - bufferSamples = buffer_.length; - } - // Clear all of the ones we've passed. - for (int i = 0; i < bufferSamples; ++i) { - buffer_[bufferIndex_++] = 0.0; - if (bufferIndex_ >= buffer_.length) { - bufferIndex_ = 0; - } - } - double output = buffer_[bufferIndex_]; - - // If the instrument has been retriggered, find the right sample. - if (pressed_) { - pressed_ = false; - int key = Note.getKeyforLog12TET(frequency_.getLogFrequency(time)); - int velocity = 255; - initSample(key, velocity); - } else { - if (currentSample_ != null) { - // Advance by deltaTime in the current sample. - currentSampleIndex_ += deltaTime * currentSample_.getSample().getRate(); - if (currentSample_.getSampleMode() == SampleMode.NO_LOOP) { - if (currentSampleIndex_ > currentSample_.getEnd()) { - // We're off the end of the sample. - currentSample_ = null; - } - } else { - if (currentSampleIndex_ >= currentSample_.getEndLoop()) { - double distanceFromLoopStart = currentSampleIndex_ - currentSample_.getStartLoop(); - double loopLength = currentSample_.getEndLoop() - currentSample_.getStartLoop(); - currentSampleIndex_ = - currentSample_.getStartLoop() + (distanceFromLoopStart % loopLength); - } - } - } - } - - // Okay, now get the new data from the current sample. - if (currentSample_ != null) { - int firstSample = (int)currentSampleIndex_; - double weight = 1.0 - (currentSampleIndex_ - firstSample); - if (weight == 1.0) { - output += currentSample_.getSample().getSample(firstSample); - } else { - output += - weight * currentSample_.getSample().getSample(firstSample) + - (1.0 - weight) * currentSample_.getSample().getSample(firstSample + 1); - } - } - - return output; - } - - /** - * Initializes the "current sample" based on the given key and velocity. - */ - private synchronized void initSample(int key, int velocity) { - // Find any sample in this preset that can handle the given key and velocity. - currentSample_ = null; - for (Zone pzone : preset_.getZoneList()) { - Instrument instrument = pzone.getInstrument(); - if (instrument != null) { - for (Zone izone : instrument.getZoneList()) { - if (izone.inKeyRange(key) && - izone.inVelocityRange(velocity) && - izone.getSample() != null) { - currentSample_ = izone; - currentSampleIndex_ = currentSample_.getStart(); - return; - } - } - } - } - } - - /** - * Trigger this oscillator to start outputting from the sample. - */ - public synchronized void turnOn(boolean retriggerIfOn) { - pressed_ = true; - } - - /** - * Turns off this oscillator from getting data from the current sample. - * If this sample supports it, then the rest of the current sample is copied to the output buffer - * before the current sample is cleared. - */ - public synchronized void turnOff() { - if (currentSample_ != null) { - // Copy in the rest of the current sample. - int bufferIndex = bufferIndex_; - while (currentSampleIndex_ <= currentSample_.getEnd()) { - int firstSample = (int)currentSampleIndex_; - double weight = 1.0 - (currentSampleIndex_ - firstSample); - if (weight == 1.0) { - buffer_[bufferIndex] += currentSample_.getSample().getSample(firstSample); - } else { - buffer_[bufferIndex] += - weight * currentSample_.getSample().getSample(firstSample) + - (1.0 - weight) * currentSample_.getSample().getSample(firstSample + 1); - } - bufferIndex = (bufferIndex + 1) % buffer_.length; - currentSampleIndex_ += (currentSample_.getSample().getRate() / sampleRateInHz_); - } - } - currentSample_ = null; - } - - @SuppressWarnings("unused") - private Logger logger_; - - // The preset to get samples from. - private Preset preset_; - - // The current sample being played, and where in the sample we are currently at in the output. - private Zone currentSample_; - private double currentSampleIndex_; - - // A buffer of data that has been queued up and should be played in the future. This handles the - // case of releasing the key and then pressing it again at a different value. - private double[] buffer_; - private int bufferIndex_; - - // True if the oscillator has been triggered, but the sample hasn't been loaded yet. - private boolean pressed_; - - // The previous time the oscillator was polled for its value. - private double previousTime_; - - // The maximum length of any sample in this preset, converted to the output sample rate. - private int maxSampleLength_; - - // The sample rate of the output synthesizer. - private double sampleRateInHz_; -} diff --git a/core/src/com/levien/synthesizer/core/soundfont/SoundFontReader.java b/core/src/com/levien/synthesizer/core/soundfont/SoundFontReader.java deleted file mode 100644 index f482da6..0000000 --- a/core/src/com/levien/synthesizer/core/soundfont/SoundFontReader.java +++ /dev/null @@ -1,337 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.soundfont; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; -import java.util.logging.Logger; - -//import com.levien.synthesizer.core.model.sample.Proto; -import com.levien.synthesizer.core.wave.RiffInputStream; - -/** - * Reads a SoundFont file from a stream and provides access its data. - */ -public class SoundFontReader { - /** - * Reads the .sf2 file from a stream and stores the data in a buffer. - * @param input - the stream to read from. - * @throws IOExpection - on a malformed or unsupported file format. - */ - public SoundFontReader(InputStream in) throws IOException { - Logger logger = Logger.getLogger(getClass().getName()); - logger.info("Loading SoundFont file."); - - RiffInputStream input = new RiffInputStream(in); - - input.checkBytes("RIFF"); - long riffSize = input.readDWord(); - long riffRemaining = riffSize; - - input.checkBytes("sfbk"); - riffRemaining -= 4; - - // All of the sample data, scaled from -1 to 1. - double[] samples = null; - - while (riffRemaining > 0) { - input.checkBytes("LIST"); - long listSize = input.readDWord(); - riffRemaining -= 8; - riffRemaining -= listSize; - String chunk = input.readString(4); - long listRemaining = listSize; - listRemaining -= 4; - if (chunk.equals("INFO")) { - // Mostly worthless info headers. - while (listRemaining > 0) { - String subchunk = input.readString(4); - int subchunkSize = (int)input.readDWord(); - listRemaining -= 8; - listRemaining -= subchunkSize; - if (subchunk.equals("ifil")) { - if (subchunkSize != 4) { - throw new IOException("ifil size != 4."); - } - majorVersion_ = input.readWord(); - minorVersion_ = input.readWord(); - } else if (subchunk.equals("isng")) { - engine_ = input.readString(subchunkSize); - } else if (subchunk.equals("INAM")) { - name_ = input.readString(subchunkSize); - } else if (subchunk.equals("irom")) { - rom_ = input.readString(subchunkSize); - } else if (subchunk.equals("iver")) { - if (subchunkSize != 4) { - throw new IOException("iver size != 4."); - } - romMajorVersion_ = input.readWord(); - romMinorVersion_ = input.readWord(); - } else if (subchunk.equals("ICRD")) { - creationDate_ = input.readString(subchunkSize); - } else if (subchunk.equals("IENG")) { - engineer_ = input.readString(subchunkSize); - } else if (subchunk.equals("IPRD")) { - product_ = input.readString(subchunkSize); - } else if (subchunk.equals("ICOP")) { - copyright_ = input.readString(subchunkSize); - } else if (subchunk.equals("ICMT")) { - comment_ = input.readString(subchunkSize); - } else if (subchunk.equals("ISFT")) { - software_ = input.readString(subchunkSize); - } else { - logger.info("Skipping unknown INFO subchunk type " + subchunk + "."); - input.skipBytes(subchunkSize); - } - } - System.out.println("Read SoundFont INFO: \n" + this.toString()); - } else if (chunk.equals("sdta")) { - // The actual sample data. - while (listRemaining > 0) { - String subchunk = input.readString(4); - long subchunkSize = input.readDWord(); - listRemaining -= 8; - listRemaining -= subchunkSize; - if (subchunk.equals("smpl")) { - int words = (int)(subchunkSize / 2); - logger.info("Reading " + words + " samples."); - samples = new double[words]; - for (int i = 0; i < words; ++i) { - samples[i] = input.readShort() / 32768.0; - } - } else { - logger.info("Skipping unknown sdta subchunk type " + subchunk + "."); - input.skipBytes(subchunkSize); - } - } - } else if (chunk.equals("pdta")) { - // This is the so-called HYDRA data structure, with 9 parts. - - ArrayList presetBagList = new ArrayList(); - ArrayList presetModulatorList = new ArrayList(); - ArrayList presetGeneratorList = new ArrayList(); - ArrayList instrumentList = new ArrayList(); - ArrayList instrumentBagList = new ArrayList(); - ArrayList instrumentModulatorList = new ArrayList(); - ArrayList instrumentGeneratorList = new ArrayList(); - ArrayList sampleHeaderList = new ArrayList(); - - // Preset data is the metadata about the samples. - while (listRemaining > 0) { - String subchunk = input.readString(4); - long subchunkSize = input.readDWord(); - listRemaining -= 8; - listRemaining -= subchunkSize; - byte[] subchunkData = input.readBytes((int)subchunkSize); - ByteArrayInputStream subchunkInput = new ByteArrayInputStream(subchunkData); - if (subchunk.equals("phdr")) { - Preset previous = null; - while (subchunkInput.available() > 0) { - Preset preset = new Preset(new RiffInputStream(subchunkInput)); - logger.info("Found preset: " + preset.getName()); - if (previous != null) { - previous.setBagEnd(preset.getBagStart()); - presets_.add(previous); - } - previous = preset; - } - } else if (subchunk.equals("pbag")) { - Bag previous = null; - while (subchunkInput.available() > 0) { - Bag presetBag = new Bag(new RiffInputStream(subchunkInput)); - if (previous != null) { - previous.setGeneratorEnd(presetBag.getGeneratorStart()); - previous.setModulatorEnd(presetBag.getModulatorStart()); - presetBagList.add(previous); - } - previous = presetBag; - } - } else if (subchunk.equals("pmod")) { - while (subchunkInput.available() > 0) { - Modulator presetModulator = new Modulator(new RiffInputStream(subchunkInput)); - if (subchunkInput.available() > 0) { - presetModulatorList.add(presetModulator); - } - } - } else if (subchunk.equals("pgen")) { - while (subchunkInput.available() > 0) { - Generator generator = new Generator(new RiffInputStream(subchunkInput)); - if (subchunkInput.available() > 0) { - presetGeneratorList.add(generator); - } - } - } else if (subchunk.equals("inst")) { - Instrument previous = null; - while (subchunkInput.available() > 0) { - Instrument instrument = new Instrument(new RiffInputStream(subchunkInput)); - logger.info("Found instrument: " + instrument.getName()); - if (previous != null) { - previous.setBagEnd(instrument.getBagStart()); - instrumentList.add(previous); - } - previous = instrument; - } - } else if (subchunk.equals("ibag")) { - Bag previous = null; - while (subchunkInput.available() > 0) { - Bag instrumentBag = new Bag(new RiffInputStream(subchunkInput)); - if (previous != null) { - previous.setGeneratorEnd(instrumentBag.getGeneratorStart()); - previous.setModulatorEnd(instrumentBag.getModulatorStart()); - instrumentBagList.add(previous); - } - previous = instrumentBag; - } - } else if (subchunk.equals("imod")) { - while (subchunkInput.available() > 0) { - Modulator instrumentModulator = new Modulator(new RiffInputStream(subchunkInput)); - if (subchunkInput.available() > 0) { - instrumentModulatorList.add(instrumentModulator); - } - } - } else if (subchunk.equals("igen")) { - while (subchunkInput.available() > 0) { - Generator generator = new Generator(new RiffInputStream(subchunkInput)); - if (subchunkInput.available() > 0) { - instrumentGeneratorList.add(generator); - } - } - } else if (subchunk.equals("shdr")) { - while (subchunkInput.available() > 0) { - Sample sampleHeader = new Sample(new RiffInputStream(subchunkInput), - samples); - if (subchunkInput.available() > 0) { - sampleHeaderList.add(sampleHeader); - } - } - } else { - logger.info("Skipping unknown pdta subchunk type " + subchunk + "."); - } - } - - // Now that we've read in the HYDRA, we have to backtrack through it to convert the _bags_ - // to _zones_. - - for (Preset preset : presets_) { - // There might be a "global" zone for the preset that applies to all the other zones. - Zone globalZone = null; - for (int bag = preset.getBagStart(); bag < preset.getBagEnd(); ++bag) { - // Start with the global zone, if it exists. - Zone zone = (globalZone != null) ? globalZone.copy() : new Zone(); - for (int gen = presetBagList.get(bag).getGeneratorStart(); - gen < presetBagList.get(bag).getGeneratorEnd(); - ++gen) { - zone.addPresetGenerator(presetGeneratorList.get(gen), instrumentList); - } - for (int mod = presetBagList.get(bag).getModulatorStart(); - mod < presetBagList.get(bag).getModulatorEnd(); - ++mod) { - zone.addModulator(presetModulatorList.get(mod)); - } - // This might be the global zone for the preset. - if (zone.getInstrument() == null) { - if (globalZone == null) { - // It is the global zone, so set it. - globalZone = zone; - } - // Any zone missing an instrument is either the global zone or should be ignored. - continue; - } - // Okay, it's not the global zone. - preset.addZone(zone); - } - } - - for (Instrument instrument : instrumentList) { - // There might be a "global" zone for the preset that applies to all the other zones. - Zone globalZone = null; - for (int bag = instrument.getBagStart(); bag < instrument.getBagEnd(); ++bag) { - // Start with the global zone, if it exists. - Zone zone = (globalZone != null) ? globalZone.copy() : new Zone(); - for (int gen = instrumentBagList.get(bag).getGeneratorStart(); - gen < instrumentBagList.get(bag).getGeneratorEnd(); - ++gen) { - zone.addInstrumentGenerator(instrumentGeneratorList.get(gen), sampleHeaderList); - } - for (int mod = instrumentBagList.get(bag).getModulatorStart(); - mod < instrumentBagList.get(bag).getModulatorEnd(); - ++mod) { - zone.addModulator(instrumentModulatorList.get(mod)); - } - // This might be the global zone for the preset. - if (zone.getSample() == null) { - if (globalZone == null) { - // It is the global zone, so set it. - globalZone = zone; - } - // Any zone missing an instrument is either the global zone or should be ignored. - continue; - } - // Okay, it's not the global zone. - instrument.addZone(zone); - } - } - - // TODO(klimt): So, actually some of the generator values for an instrument should be added - // to the generator values for the preset zone it's in, but an instrument could be in - // multiple different preset zones, so there's no way to store that here. So I need to make - // a function to add two zones, and call it whenever the instrument zone is used. Grrr. - } else { - logger.info("Skipping unknown sfbk LIST type " + chunk + "."); - input.skipBytes(listRemaining); - } - } - input.close(); - } - - public List getPresets() { - return presets_; - } - - public String toString() { - return - "version: " + majorVersion_ + "." + minorVersion_ + "\n" + - "engine: " + engine_ + "\n" + - "name: " + name_ + "\n" + - "rom: " + rom_ + "\n" + - "rom version: " + romMajorVersion_ + "." + romMinorVersion_ + "\n" + - "created: " + creationDate_ + "\n" + - "engineer: " + engineer_ + "\n" + - "product: " + product_ + "\n" + - "copyright: " + copyright_ + "\n" + - "comment: " + comment_ + "\n" + - "software: " + software_ + "\n"; - } - - private int majorVersion_; - private int minorVersion_; - private String engine_; - private String name_; - private String rom_; - private int romMajorVersion_; - private int romMinorVersion_; - private String creationDate_; - private String engineer_; - private String product_; - private String copyright_; - private String comment_; - private String software_; - private ArrayList presets_ = new ArrayList(); -} diff --git a/core/src/com/levien/synthesizer/core/soundfont/Zone.java b/core/src/com/levien/synthesizer/core/soundfont/Zone.java deleted file mode 100644 index db077af..0000000 --- a/core/src/com/levien/synthesizer/core/soundfont/Zone.java +++ /dev/null @@ -1,530 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.soundfont; - -import java.util.ArrayList; -import java.util.List; -import java.util.logging.Logger; - -/** - * A zone is like a flattened bag that contains any of the settings that could be in a bag. - */ -@SuppressWarnings("unused") -public class Zone { - /** - * Creates a new Zone that's empty. - */ - public Zone() { - logger_ = Logger.getLogger(getClass().getName()); - modulatorList_ = new ArrayList(); - } - - /** - * Copies all of the values from another zone into this one. - */ - public void CopyFrom(Zone other) { - instrument_ = other.instrument_; - sample_ = other.sample_; - startAddrsOffset_ = other.startAddrsOffset_; - endAddrsOffset_ = other.endAddrsOffset_; - startloopAddrsOffset_ = other.startloopAddrsOffset_; - endloopAddrsOffset_ = other.endloopAddrsOffset_; - startAddrsCoarseOffset_ = other.startAddrsCoarseOffset_; - endAddrsCoarseOffset_ = other.endAddrsCoarseOffset_; - startloopAddrsCoarseOffset_ = other.startloopAddrsCoarseOffset_; - endloopAddrsCoarseOffset_ = other.endloopAddrsCoarseOffset_; - modLfoToPitch_ = other.modLfoToPitch_; - vibLfoToPitch_ = other.vibLfoToPitch_; - modEnvToPitch_ = other.modEnvToPitch_; - initialFilterFc_ = other.initialFilterFc_; - initialFilterQ_ = other.initialFilterQ_; - modLfoToFilterFc_ = other.modLfoToFilterFc_; - modEnvToFilterFc_ = other.modEnvToFilterFc_; - modLfoToVolume_ = other.modLfoToVolume_; - chorusEffectsSend_ = other.chorusEffectsSend_; - reverbEffectsSend_ = other.reverbEffectsSend_; - pan_ = other.pan_; - delayModLFO_ = other.delayModLFO_; - freqModLFO_ = other.freqModLFO_; - delayVibLFO_ = other.delayVibLFO_; - freqVibLFO_ = other.freqVibLFO_; - delayModEnv_ = other.delayModEnv_; - attackModEnv_ = other.attackModEnv_; - holdModEnv_ = other.holdModEnv_; - decayModEnv_ = other.decayModEnv_; - sustainModEnv_ = other.sustainModEnv_; - releaseModEnv_ = other.releaseModEnv_; - keynumToModEnvHold_ = other.keynumToModEnvHold_; - keynumToModEnvDecay_ = other.keynumToModEnvDecay_; - delayVolEnv_ = other.delayVolEnv_; - attackVolEnv_ = other.attackVolEnv_; - holdVolEnv_ = other.holdVolEnv_; - decayVolEnv_ = other.decayVolEnv_; - sustainVolEnv_ = other.sustainVolEnv_; - releaseVolEnv_ = other.releaseVolEnv_; - keynumToVolEnvHold_ = other.keynumToVolEnvHold_; - keynumToVolEnvDecay_ = other.keynumToVolEnvDecay_; - minKey_ = other.minKey_; - maxKey_ = other.maxKey_; - minVelocity_ = other.minVelocity_; - maxVelocity_ = other.maxVelocity_; - keynum_ = other.keynum_; - velocity_ = other.velocity_; - initialAttenuation_ = other.initialAttenuation_; - coarseTune_ = other.coarseTune_; - fineTune_ = other.fineTune_; - sampleMode_ = other.sampleMode_; - scaleTuning_ = other.scaleTuning_; - exclusiveClass_ = other.exclusiveClass_; - overridingRootKey_ = other.overridingRootKey_; - modulatorList_ = new ArrayList(other.modulatorList_); - } - - /** - * @return A new Zone equivalent to this one. - */ - public Zone copy() { - Zone other = new Zone(); - other.CopyFrom(this); - return other; - } - - /** - * @return The input converted from cents to octaves. - */ - private static double convertCentsToOctaves(double value) { - return value / 1200.0; - } - - /** - * @return The input converted from cents to seconds. - */ - private static double convertCentsToSeconds(double value) { - return Math.pow(2.0, convertCentsToOctaves(value)); - } - - /** - * Adds a preset generator to this Zone. - * @param generator - The generator to add. - * @param instruments - The list of all instruments in this SoundFont file. - */ - public void addPresetGenerator(Generator generator, - List instruments) { - if (!generator.getOperator().isValidForPreset()) { - throw new IllegalArgumentException("Invalid operator for preset: " + - generator.getOperator() + "."); - } - addGenerator(generator, instruments, null); - } - - /** - * Adds an instrument generator to this Zone. - * @param generator - The generator to add. - * @param samples - The list of all samples in this SoundFont file. - */ - public void addInstrumentGenerator(Generator generator, - List samples) { - if (!generator.getOperator().isValidForInstrument()) { - throw new IllegalArgumentException("Invalid operator for instrument: " + - generator.getOperator() + "."); - } - addGenerator(generator, null, samples); - } - - /** - * Internal method to add a generator of either type. - */ - protected void addGenerator(Generator generator, - List instruments, - List samples) { - short amount = generator.getAmount(); - // - // This ridiculous switch statement takes the given operator and decodes its argument into the - // right values in the Zone. - // - switch (generator.getOperator()) { - case UNSUPPORTED: { - break; - } - case START_ADDRS_OFFSET: { - startAddrsOffset_ = amount; break; - } - case END_ADDRS_OFFSET: { - endAddrsOffset_ = amount; break; - } - case STARTLOOP_ADDRS_OFFSET: { - startloopAddrsOffset_ = amount; break; - } - case ENDLOOP_ADDRS_OFFSET: { - endloopAddrsOffset_ = amount; break; - } - case START_ADDRS_COARSE_OFFSET: { - startAddrsCoarseOffset_ = amount * 32768; break; - } - case MOD_LFO_TO_PITCH: { - modLfoToPitch_ = convertCentsToOctaves(amount); break; - } - case VIB_LFO_TO_PITCH: { - vibLfoToPitch_ = convertCentsToOctaves(amount); break; - } - case MOD_ENV_TO_PITCH: { - modEnvToPitch_ = convertCentsToOctaves(amount); break; - } - case INITIAL_FILTER_FC: { - initialFilterFc_ = convertCentsToOctaves(amount); break; - } - case INITIAL_FILTER_Q: { - initialFilterQ_ = amount; break; - } - case MOD_LFO_TO_FILTER_FC: { - modLfoToFilterFc_ = convertCentsToOctaves(amount); break; - } - case MOD_ENV_TO_FILTER_FC: { - modEnvToFilterFc_ = convertCentsToOctaves(amount); break; - } - case END_ADDRS_COARSE_OFFSET: { - endAddrsCoarseOffset_ = amount * 32768; break; - } - case MOD_LFO_TO_VOLUME: { - modLfoToVolume_ = amount; break; - } - case CHORUS_EFFECTS_SEND: { - chorusEffectsSend_ = amount / 1000.0; break; - } - case REVERB_EFFECTS_SEND: { - reverbEffectsSend_ = amount / 1000.0; break; - } - case PAN: { - pan_ = amount / 1000.0; break; - } - case DELAY_MOD_LFO: { - delayModLFO_ = convertCentsToSeconds(amount); break; - } - case FREQ_MOD_LFO: { - freqModLFO_ = convertCentsToOctaves(amount); break; - } - case DELAY_VIB_LFO: { - delayVibLFO_ = convertCentsToSeconds(amount); break; - } - case FREQ_VIB_LFO: { - freqVibLFO_ = convertCentsToOctaves(amount); break; - } - case DELAY_MOD_ENV: { - delayModEnv_ = convertCentsToSeconds(amount); break; - } - case ATTACK_MOD_ENV: { - attackModEnv_ = convertCentsToSeconds(amount); break; - } - case HOLD_MOD_ENV: { - holdModEnv_ = convertCentsToSeconds(amount); break; - } - case DECAY_MOD_ENV: { - decayModEnv_ = convertCentsToSeconds(amount); break; - } - case SUSTAIN_MOD_ENV: { - sustainModEnv_ = 1.0 - (amount / -1000.0); break; - } - case RELEASE_MOD_ENV: { - releaseModEnv_ = convertCentsToSeconds(amount); break; - } - case KEYNUM_TO_MOD_ENV_HOLD: { - keynumToModEnvHold_ = convertCentsToSeconds(amount); break; - } - case KEYNUM_TO_MOD_ENV_DECAY: { - keynumToModEnvDecay_ = convertCentsToSeconds(amount); break; - } - case DELAY_VOL_ENV: { - delayVolEnv_ = convertCentsToSeconds(amount); break; - } - case ATTACK_VOL_ENV: { - attackVolEnv_ = convertCentsToSeconds(amount); break; - } - case HOLD_VOL_ENV: { - holdVolEnv_ = convertCentsToSeconds(amount); break; - } - case DECAY_VOL_ENV: { - decayVolEnv_ = convertCentsToSeconds(amount); break; - } - case SUSTAIN_VOL_ENV: { - sustainVolEnv_ = 1.0 - (amount / -1000.0); break; - } - case RELEASE_VOL_END: { - releaseVolEnv_ = convertCentsToSeconds(amount); break; - } - case KEYNUM_TO_VOL_ENV_HOLD: { - keynumToVolEnvHold_ = convertCentsToSeconds(amount); break; - } - case KEYNUM_TO_VOL_ENV_DECAY: { - keynumToVolEnvDecay_ = convertCentsToSeconds(amount); break; - } - case INSTRUMENT: { - instrument_ = instruments.get(((int)amount) & 0xFFFF); break; - } - case KEY_RANGE: { - minKey_ = amount & 0xFF; - maxKey_ = (amount >> 8) & 0xFF; - break; - } - case VELOCITY_RANGE: { - minVelocity_ = amount & 0xFF; - maxVelocity_ = (amount >> 8) & 0xFF; - break; - } - case STARTLOOP_ADDRS_COARSE_OFFSET: { - startloopAddrsCoarseOffset_ = amount * 32768; break; - } - case KEYNUM: { - keynum_ = amount & 0xFF; break; - } - case VELOCITY: { - velocity_ = amount & 0xFF; break; - } - case INITIAL_ATTENUATION: { - initialAttenuation_ = amount; break; - } - case ENDLOOP_ADDRS_COARSE_OFFSET: { - endloopAddrsCoarseOffset_ = amount * 32768; break; - } - case COARSE_TUNE: { - coarseTune_ = amount / 12.0; break; - } - case FINE_TUNE: { - fineTune_ = convertCentsToOctaves(amount); break; - } - case SAMPLE_ID: { - sample_ = samples.get(((int)amount) & 0xFFFF); break; - } - case SAMPLE_MODES: { - switch (amount & 0x03) { - case 0: sampleMode_ = SampleMode.NO_LOOP; break; - case 1: sampleMode_ = SampleMode.LOOP_CONTINUOUSLY; break; - case 2: sampleMode_ = SampleMode.NO_LOOP; break; - case 3: sampleMode_ = SampleMode.LOOP_CONTINUOUSLY_THEN_FINISH; break; - } - break; - } - case SCALE_TUNING: { - scaleTuning_ = convertCentsToOctaves(amount); break; - } - case EXCLUSIVE_CLASS: { - exclusiveClass_ = amount & 0xFF; break; - } - case OVERRIDING_ROOT_KEY: { - overridingRootKey_ = amount & 0xFF; break; - } - case END_OPER: { - break; - } - } - } - - /** - * Adds a modulator the zone. - */ - public void addModulator(Modulator modulator) { - modulatorList_.add(modulator); - } - - /** - * @return the index of the first sample in this instrument zone. - * Adjusts based on the generator settings. - */ - public long getStart() { - long start = startAddrsOffset_ + startAddrsCoarseOffset_; - if (sample_ != null) { - start += sample_.getStart(); - } - return start; - } - - /** - * @return the index one after the last sample in this instrument zone. - * Adjusts based on the generator settings. - */ - public long getEnd() { - long end = endAddrsOffset_ + endAddrsCoarseOffset_; - if (sample_ != null) { - end += sample_.getEnd(); - } - return end; - } - - /** - * @return the number of samples in this instrument zone. - * Adjusts based on the generator settings. - */ - public long getCount() { - return getEnd() - getStart(); - } - - /** - * @return the index of the first sample in this instrument zone's loop subset. - * Adjusts based on the generator settings. - */ - public long getStartLoop() { - long startloop = startloopAddrsOffset_ + startloopAddrsCoarseOffset_; - if (sample_ != null) { - startloop += sample_.getStart(); - } - return startloop; - } - - /** - * @return the index one after the last sample in this instrument zone's loop subset. - * Adjusts based on the generator settings. - */ - public long getEndLoop() { - long endloop = endloopAddrsOffset_ + endloopAddrsCoarseOffset_; - if (sample_ != null) { - endloop += sample_.getEnd(); - } - return endloop; - } - - /** - * @return The instrument associated with this preset zone. - */ - public Instrument getInstrument() { - return instrument_; - } - - /** - * @return True if this instrument zone can handle the given key. - */ - public boolean inKeyRange(int key) { - return ((minKey_ < 0 || key >= minKey_) && - (maxKey_ < 0 || key <= maxKey_)); - } - - /** - * @return True if this instrument zone can handle the given velocity. - */ - public boolean inVelocityRange(int velocity) { - return ((minVelocity_ < 0 || velocity >= minVelocity_) && - (maxVelocity_ < 0 || velocity <= maxVelocity_)); - } - - /** - * @return The sample associated with this instrument zone. - */ - public Sample getSample() { - return sample_; - } - - /** - * @return The sample mode for this instrument zone. - */ - public SampleMode getSampleMode() { - return sampleMode_; - } - - private Logger logger_; - - // - // The various settings for a zone, according to the SoundFont 2.1 format specification. - // Most of these are ignored in this synthesizer implementation, but some are not. - // - - private Instrument instrument_ = null; // Set for a preset zone. - private Sample sample_ = null; // Set for an instrument zone. - - // All in samples. - private int startAddrsOffset_ = 0; - private int endAddrsOffset_ = 0; - private int startloopAddrsOffset_ = 0; - private int endloopAddrsOffset_ = 0; - private int startAddrsCoarseOffset_ = 0; - private int endAddrsCoarseOffset_ = 0; - private int startloopAddrsCoarseOffset_ = 0; - private int endloopAddrsCoarseOffset_ = 0; - - // All in log Hz. - private double modLfoToPitch_ = 0; - private double vibLfoToPitch_ = 0; - private double modEnvToPitch_ = 0; - - private double initialFilterFc_ = convertCentsToOctaves(13500); // in log Hz. - private int initialFilterQ_ = 0; // in centibels. - private double modLfoToFilterFc_ = 0; // in log Hz. - private double modEnvToFilterFc_ = 0; // in log Hz. - - private int modLfoToVolume_ = 0; // in centibels. - - // All are percentages. - private double chorusEffectsSend_ = 0.0; - private double reverbEffectsSend_ = 0.0; - private double pan_ = 0.0; - - private double delayModLFO_ = convertCentsToSeconds(-12000); // in seconds. - private double freqModLFO_ = 0; // in log Hz. - private double delayVibLFO_ = convertCentsToSeconds(-12000); // in seconds. - private double freqVibLFO_ = 0; // in log Hz. - - // All in seconds, except sustain. - private double delayModEnv_ = convertCentsToSeconds(-12000); - private double attackModEnv_ = convertCentsToSeconds(-12000); - private double holdModEnv_ = convertCentsToSeconds(-12000); - private double decayModEnv_ = convertCentsToSeconds(-12000); - private double sustainModEnv_ = 0; // percentage. - private double releaseModEnv_ = convertCentsToSeconds(-12000); - - // All in seconds per key. - private double keynumToModEnvHold_ = 0; - private double keynumToModEnvDecay_ = 0; - - // All in seconds, except sustain. - private double delayVolEnv_ = convertCentsToSeconds(-12000); - private double attackVolEnv_ = convertCentsToSeconds(-12000); - private double holdVolEnv_ = convertCentsToSeconds(-12000); - private double decayVolEnv_ = convertCentsToSeconds(-12000); - private double sustainVolEnv_ = 0; // percentage. - private double releaseVolEnv_ = convertCentsToSeconds(-12000); - - // All in seconds per key. - private double keynumToVolEnvHold_ = 0; - private double keynumToVolEnvDecay_ = 0; - - // These are midi values in the range [0, 127]. -1 means unset. - private int minKey_ = -1; - private int maxKey_ = -1; - private int minVelocity_ = -1; - private int maxVelocity_ = -1; - - // These values override the input value. - private int keynum_ = -1; - private int velocity_ = -1; - - private int initialAttenuation_ = 0; // in centibels. - - // All in log Hz. - private double coarseTune_ = 0; - private double fineTune_ = 0; - - enum SampleMode { - NO_LOOP, - LOOP_CONTINUOUSLY, - LOOP_CONTINUOUSLY_THEN_FINISH, - } - private SampleMode sampleMode_ = SampleMode.NO_LOOP; - - private double scaleTuning_ = 0; // in log Hz per key. - private int exclusiveClass_ = 0; // An id in range [1, 127], or 0 if not set. - private int overridingRootKey_ = -1; // A key in range [0, 127], or -1 if not set. - - // All of the modulators in this zone. This is ignored. - private ArrayList modulatorList_; -} diff --git a/core/src/com/levien/synthesizer/core/wave/RiffInputStream.java b/core/src/com/levien/synthesizer/core/wave/RiffInputStream.java deleted file mode 100644 index 73c8b37..0000000 --- a/core/src/com/levien/synthesizer/core/wave/RiffInputStream.java +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.levien.synthesizer.core.wave; - -import java.io.FilterInputStream; -import java.io.IOException; -import java.io.InputStream; - -/** - * A wrapper around an InputStream that provides some utility functions for reading RIFF files. - */ -public class RiffInputStream extends FilterInputStream { - /** - * Creates a new RiffInputStream wrapping the given input stream. - */ - public RiffInputStream(InputStream in) { - super(in); - } - - /** - * Skips the specified number of bytes in the input. - */ - public void skipBytes(long bytes) throws IOException { - while (bytes > 0) { - int skipped = (int)skip(bytes); - if (skipped <= 0) { - throw new IOException("Error skipping bytes."); - } - bytes -= skipped; - } - } - - /** - * Reads one signed byte from an input stream. - * @param output - the stream to read from. - * @return the signed byte read. - * @throws IOException - on any kind of read error or EOF. - */ - public byte readChar() throws IOException { - return (byte)readByte(); - } - - /** - * Reads one unsigned byte from an input stream. - * @param output - the stream to read from. - * @return the unsigned byte read. - * @throws IOException - on any kind of read error or EOF. - */ - public short readByte() throws IOException { - int b = read(); - if (b < 0) { - throw new IOException("Unexpected EOF while reading byte."); - } - return (short)(b & 0xFF); - } - - /** - * Checks that the given String matches the next bytes in the input stream. - * @param input - the stream to read from. - * @param data - the String to check for. - * @throws IOException - On any kind of read error or if the exact string wasn't found. - */ - public void checkBytes(String data) throws IOException { - byte[] bytes = data.getBytes(); - for (int i = 0; i < bytes.length; ++i) { - int b = read(); - if (b < 0) { - throw new IOException("Expected " + bytes[i] + ", got EOF, while looking for " + data); - } - if ((byte)b != bytes[i]) { - throw new IOException("Expected " + bytes[i] + ", got " + (byte)b + - ", while looking for " + data); - } - } - } - - /** - * Reads the given number of bytes and returns an array of them. - * @param input - the stream to read from. - * @param size - the number of bytes to read. - * @throws IOException - On any kind of read error or EOF. - */ - public byte[] readBytes(int size) throws IOException { - // TODO(klimt): This could be more efficient. - byte[] bytes = new byte[size]; - int length = 0; - for (length = 0; length < bytes.length; ++length) { - int b = read(); - if (b < 0) { - throw new IOException("Unexpected EOF while reading bytes."); - } - bytes[length] = (byte)b; - } - return bytes; - } - - /** - * Reads a string of the given size from the input stream. - * I'm not sure what happens if it's not ASCII. - * @param input - the stream to read from. - * @param size - the number of bytes to read. - * @throws IOException - On any kind of read error or if the exact string wasn't found. - */ - public String readString(int size) throws IOException { - byte[] bytes = new byte[size]; - int length = 0; - for (length = 0; length < bytes.length; ++length) { - int b = read(); - if (b < 0) { - throw new IOException("Unexpected EOF while reading string."); - } - if (b == 0) { - skipBytes(size - (length + 1)); - break; - } - bytes[length] = (byte)b; - } - String s = new String(bytes, 0, length); - if (s.length() > size) { - throw new IOException("Read string \"" + s + "\" longer than " + size + " bytes."); - } - return s; - } - - /** - * Reads one unsigned dword (32 bits) from an input stream in little-endian format. - * @param input - the stream to read from. - * @return - the unsigned dword read. - * @throws IOException - on any kind of read error or EOF. - */ - public long readDWord() throws IOException { - long byte1 = read(); - long byte2 = read(); - long byte3 = read(); - long byte4 = read(); - if (byte1 < 0 || byte2 < 0 || byte3 < 0 || byte4 < 0) { - throw new IOException("Unexpected EOF while reading int32."); - } - return (byte4 << 24) | (byte3 << 16) | (byte2 << 8) | byte1; - } - - /** - * Reads one signed word (16 bits) from an input stream in little-endian format. - * @param output - the stream to read from. - * @return the signed word read. - * @throws IOException - on any kind of read error or EOF. - */ - public short readShort() throws IOException { - return (short)readWord(); - } - - /** - * Reads one unsigned word (16 bits) from an input stream in little-endian format. - * @param output - the stream to read from. - * @return the unsigned word read. - * @throws IOException - on any kind of read error or EOF. - */ - public int readWord() throws IOException { - int lower = read(); - int upper = read(); - if (lower < 0 || upper < 0) { - throw new IOException("Unexpected EOF while reading int16."); - } - int value = (int)(((upper << 8) | lower) & 0xFFFF); - return value; - } -} diff --git a/core/src/com/levien/synthesizer/core/wave/WaveAdapter.java b/core/src/com/levien/synthesizer/core/wave/WaveAdapter.java deleted file mode 100644 index 71f1ce6..0000000 --- a/core/src/com/levien/synthesizer/core/wave/WaveAdapter.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.wave; - -import java.io.IOException; -import java.io.OutputStream; -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.levien.synthesizer.core.model.CachedSignalProvider; -import com.levien.synthesizer.core.model.SignalProvider; -import com.levien.synthesizer.core.model.SynthesisTime; - -/** - * A WaveAdapter wraps a synthesizer component and allows siphoning off its output and writing it to - * a wave file. - * @see WaveWriter - */ -public class WaveAdapter extends CachedSignalProvider { - /** - * Creates a new WaveAdapter. - * @param sampleRate - The sample rate of the synthesizer in Hz. - * @param bitsPerSample - The bits per sample of the wave file to write. Should be 8 or 16. - * @param source - The synthesizer component to siphon output from. - */ - public WaveAdapter(int sampleRate, int bitsPerSample, SignalProvider source) { - logger_ = Logger.getLogger(getClass().getName()); - sampleRate_ = sampleRate; - bitsPerSample_ = bitsPerSample; - source_ = source; - } - - /** - * Starts the WaveAdapter recording for a specified length of time. - * @param seconds - The length of time to record. - * @parma output - The stream to write the output to. - */ - public synchronized void startRecording(double seconds, OutputStream output) { - if (writer_ != null) { - try { - writer_.close(); - } catch (IOException e) { - logger_.log(Level.SEVERE, "Unable to close wave file.", e); - } - writer_ = null; - } - writer_ = new WaveWriter(sampleRate_, bitsPerSample_); - logger_.info("Recording " + seconds + " seconds to file."); - try { - writer_.startRecording(seconds, output); - } catch (IOException e) { - logger_.log(Level.SEVERE, "Unable to open wave file for writing.", e); - } - } - - /** - * Reads one sample from source, writes it to output, and returns it. - */ - @Override - protected synchronized double computeValue(SynthesisTime time) { - double value = source_.getValue(time); - if (writer_ != null) { - try { - if (!writer_.writeSample(value)) { - // The file is full. - logger_.info("Finished writing wave file."); - close(); - } - } catch (IOException e) { - logger_.log(Level.SEVERE, "Unable to write sample to wave file. Aborting.", e); - close(); - } - } - return value; - } - - /** - * Makes sure the file is closed. You don't need to call this between recordings, but only when - * you are done, to make sure the last wave file was closed. If the file has already finished - * recording, then this method will not do anything. - */ - public synchronized void close() { - if (writer_ != null) { - try { - writer_.close(); - } catch (IOException e) { - logger_.log(Level.SEVERE, "Unable to close the wave file. Aborting.", e); - } - writer_ = null; - } - } - - // The sample rate of the source and output, in Hz. - private int sampleRate_; - - // The number of bits per sample specified when creating the file. Should be 8 or 16. - private int bitsPerSample_; - - // The synthesizer module to siphon output from. - private SignalProvider source_; - - // The underlying writer that does the real work of creating the wave file. - private WaveWriter writer_; - - private Logger logger_; -} diff --git a/core/src/com/levien/synthesizer/core/wave/WaveReader.java b/core/src/com/levien/synthesizer/core/wave/WaveReader.java deleted file mode 100644 index f3b5113..0000000 --- a/core/src/com/levien/synthesizer/core/wave/WaveReader.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.wave; - -import java.io.IOException; -import java.io.InputStream; -import java.util.logging.Logger; - -/** - * Reads a WAVE file from a stream and provides access its data. - */ -public class WaveReader { - /** - * Reads the WAVE file from a stream and stores the data in a buffer. - * @param input - the stream to read from. - * @throws IOExpection - on a malformed or unsupported file format. - */ - public WaveReader(InputStream in) throws IOException { - Logger logger = Logger.getLogger(getClass().getName()); - logger.info("Loading WAVE file."); - - RiffInputStream input = new RiffInputStream(in); - - // Header. - input.checkBytes("RIFF"); - logger.info("Read RIFF"); - @SuppressWarnings("unused") - int chunkSize = (int)input.readDWord(); - input.checkBytes("WAVE"); - - // Sub-chunk 1. - input.checkBytes("fmt "); - int subChunk1Size = (int)input.readDWord(); - if (subChunk1Size != 16) { - throw new IOException("Format is not PCM."); - } - int audioFormat = input.readWord(); - if (audioFormat != 1) { - throw new IOException("Unsupported compression scheme: " + audioFormat); - } - numChannels_ = input.readWord(); - if (numChannels_ != 1 && numChannels_ != 2) { - throw new IOException("Unsupported number of channels: " + numChannels_); - } - sampleRateInHz_ = (int)input.readDWord(); - @SuppressWarnings("unused") - int byteRate = (int)input.readDWord(); - @SuppressWarnings("unused") - int blockAlign = input.readWord(); - int bitsPerSample = input.readWord(); - if (bitsPerSample != 8 && bitsPerSample != 16) { - throw new IOException("Unsupported bits per sample: " + bitsPerSample); - } - int bytesPerSample = bitsPerSample / 8; - - // Sub-chunk 2. - input.checkBytes("data"); - int subChunk2Size = (int)input.readDWord(); - - // Actual data. - int numSamples = subChunk2Size / (numChannels_ * bytesPerSample); - leftChannel_ = new double[numSamples]; - rightChannel_ = new double[numSamples]; - for (int i = 0; i < numSamples; ++i) { - switch (bitsPerSample) { - case 8: - leftChannel_[i] = input.readChar() / 128.0; - break; - case 16: - leftChannel_[i] = input.readShort() / 32768.0; - break; - } - if (numChannels_ == 2) { - switch (bitsPerSample) { - case 8: - rightChannel_[i] = input.readChar() / 128.0; - break; - case 16: - rightChannel_[i] = input.readShort() / 32768.0; - break; - } - } else { - rightChannel_[i] = leftChannel_[i]; - } - } - - input.close(); - } - - /** - * Returns the sample rate of the wave file. - */ - public int getSampleRateInHz() { - return sampleRateInHz_; - } - - /** - * Returns the number of samples in the wave file. - */ - public int getSize() { - return leftChannel_.length; - } - - /** - * Returns the nth sample from the left channel of the wave file. - * If it's a mono file, returns the one sample. - */ - public double getLeftSample(int i) { - return leftChannel_[i]; - } - - /** - * Returns the nth sample from the right channel of the wave file. - * If it's a mono file, returns the one sample. - */ - public double getRightSample(int i) { - return rightChannel_[i]; - } - - /** - * Returns the nth sample from the wave file. - * If it's a mono file, returns the one sample. It it's stereo, returns the average. - */ - public double getMonoSample(int i) { - return (leftChannel_[i] + rightChannel_[i]) / 2; - } - - // The number of channels in the file. - private int numChannels_; - - // The sample rate of the file. - private int sampleRateInHz_; - - // The samples in the file. - private double[] leftChannel_; - private double[] rightChannel_; -} diff --git a/core/src/com/levien/synthesizer/core/wave/WaveWriter.java b/core/src/com/levien/synthesizer/core/wave/WaveWriter.java deleted file mode 100644 index b490889..0000000 --- a/core/src/com/levien/synthesizer/core/wave/WaveWriter.java +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.wave; - -import java.io.IOException; -import java.io.OutputStream; - -/** - * WaveWriter is a class for writing sampled audio data to an output stream as a wave file. - * To use it, call startRecording. Then call writeSample until it returns false. Then call close. - * @see WaveAdapter - */ -public class WaveWriter { - /** - * Creates a new WaveWriter with the given parameters. - * @param sampleRate - The sample rate in Hz. - * @param bitsPerSample - The size of each sample. Should be 8 or 16. - * 8-bit is assumed to be unsigned. 16-bit is assumed to be signed. - */ - public WaveWriter(int sampleRate, int bitsPerSample) { - sampleRate_ = sampleRate; - bitsPerSample_ = bitsPerSample; - if (bitsPerSample_ != 8 && bitsPerSample_ != 16) { - throw new RuntimeException( - "Unacceptable bits per sample: " + bitsPerSample_ + ". Try 8 or 16."); - } - samples_ = 0; - output_ = null; - } - - /** - * Initializes the wave file and writes its header. - * @param seconds - How many seconds of recording to do. - * @param output - The stream to write the wave file to. - * @throws IOException - On any kind of write error. - */ - public void startRecording(double seconds, OutputStream output) throws IOException { - if (output_ != null) { - close(); - } - - samples_ = (int)Math.round(sampleRate_ * seconds); - try { - output_ = output; - - writeBytes("RIFF", output_); - writeLittle32(chunkSize(samples_), output_); - writeBytes("WAVE", output_); - - // Sub-chunk 1 - writeBytes("fmt ", output_); - writeLittle32(16, output_); - writeLittle16(1, output_); - writeLittle16(numChannels(), output_); - writeLittle32(sampleRate_, output_); - writeLittle32(byteRate(), output_); - writeLittle16(blockAlign(), output_); - writeLittle16(bitsPerSample(), output_); - - // Sub-chunk 2 - writeBytes("data", output_); - writeLittle32(subChunk2Size(samples_), output_); - } catch (IOException e) { - if (output_ != null) { - output_.close(); - } - output_ = null; - samples_ = 0; - throw e; - } - } - - /** - * Writes one sample of audio data to the file. Closes the stream when the file is full. - * @param sample - The value to output, expected to be in the range [-1, 1]. - * @return False when the sample can't be written because the file is full. True otherwise. - * @throws IOException - On any kind of write error. - */ - public boolean writeSample(double sample) throws IOException { - if (samples_ == 0) { - return false; - } - // Clamp values out of range. - if (sample < -1.0) { - sample = -1.0; - } - if (sample > 1.0) { - sample = 1.0; - } - try { - if (bitsPerSample() == 16) { - short shortSample = (short)(32767 * sample); - writeLittle16(shortSample, output_); - } else if (bitsPerSample() == 8) { - writeByte((int)(255 * sample + 127.5), output_); - } - --samples_; - if (samples_ == 0) { - output_.close(); - } - } catch (IOException e) { - if (output_ != null) { - output_.close(); - output_ = null; - } - samples_ = 0; - throw e; - } - return true; - } - - /** - * Pads the file until it is the pre-specified length, and then closes the stream. - */ - public void close() throws IOException { - while (samples_ > 0) { - writeSample(0.0); - } - output_.close(); - } - - /** - * Returns the chunk size for the wave header. - */ - private int chunkSize(int samples) { - return 36 + subChunk2Size(samples); - } - - /** - * Returns the second sub-chunk size for the wave header. - */ - private int subChunk2Size(int samples) { - return samples * numChannels() * bitsPerSample() / 8; - } - - /** - * Returns the number of channels for the wave file. - */ - private int numChannels() { - return 1; - } - - /** - * Returns the bytes per second of the wave file. - */ - private int byteRate() { - return sampleRate_ * numChannels() * bitsPerSample() / 8; - } - - /** - * Returns the block-align parameter for the wave header. - */ - private int blockAlign() { - return numChannels() * bitsPerSample() / 8; - } - - /** - * Returns the bits per sample used when creating the WaveWriter. - */ - private int bitsPerSample() { - return bitsPerSample_; - } - - /** - * Writes one byte to an output stream. - * @param data - The unsigned byte to write. - * @param output - The stream to write to. - * @throws IOException - On any kind of write error. - */ - private static void writeByte(int data, OutputStream output) throws IOException { - output.write(data); - } - - /** - * Writes a String to an output stream as bytes. - * @param data - The bytes to write. - * @param output - The stream to write to. - * @throws IOException - On any kind of write error. - */ - private static void writeBytes(String data, OutputStream output) throws IOException { - output.write(data.getBytes()); - } - - /** - * Writes one dword (32 bits) to an output stream in little-endian format. - * @param data - The dword to write. - * @param output - The stream to write to. - * @throws IOException - On any kind of write error. - */ - private static void writeLittle32(int data, OutputStream output) throws IOException { - output.write(data & 0xFF); - output.write((data >> 8) & 0xFF); - output.write((data >> 16) & 0xFF); - output.write((data >> 24) & 0xFF); - } - - /** - * Writes one word (16 bits) to an output stream in little-endian format. - * @param data - The word to write. - * @param output - The stream to write to. - * @throws IOException - On any kind of write error. - */ - private static void writeLittle16(int data, OutputStream output) throws IOException { - output.write(data & 0xFF); - output.write((data >> 8) & 0xFF); - } - - // The number of samples left to write until the file is full. - private int samples_; - // The sample rate in Hz. - private int sampleRate_; - // The number of bits per output sample. Should be 8 or 16. - private int bitsPerSample_; - // The output stream to write the wave file to. - private OutputStream output_; -} diff --git a/cpp/README b/cpp/README deleted file mode 100644 index e715643..0000000 --- a/cpp/README +++ /dev/null @@ -1,24 +0,0 @@ -README for C++ codebase - -The C++ codebase will eventually be the primary sound generation module -for this app. It's still experimental, and not yet wired up to the Android -parts, but can be used to make sound. The best way is to use the simple -test app for the Mac. - -To build, edit src/SynthApp/SynthMain.mm to change the path to ROM1A.SYX -to the actual path. These patches can be downloaded from: - -http://www.abdn.ac.uk/~mth192/dx7/dx7patch.zip - -Also change the "KeyRig 49" string to match the actual USB name of your -MIDI controller. Then "open src/SynthApp.xcodeproj", then do "Build and -Run". - -The File Open menu command is hooked up as well and will load SYX format -DX7 patch files (32 patches per file). Send program change midi events -with the first 32 program numbers. - -The xcodeproj files are checked into the repo, but they are autogenerated -from .gyp files, which are the authoritative masters. To modify the -build, change the .gyp file, then run "gyp" in this dir. For changes -to the core, also change ../../android/jni/Android.mk . \ No newline at end of file diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..1d3591c --- /dev/null +++ b/gradle.properties @@ -0,0 +1,18 @@ +# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +# Default value: -Xmx10248m -XX:MaxPermSize=256m +# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..13372ae Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..122a0dc --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Mon Dec 28 10:00:20 PST 2015 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..9d82f78 --- /dev/null +++ b/gradlew @@ -0,0 +1,160 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..aec9973 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/j2se/.classpath b/j2se/.classpath deleted file mode 100644 index a3d94e2..0000000 --- a/j2se/.classpath +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/j2se/.externalToolBuilders/Proto Builder.launch b/j2se/.externalToolBuilders/Proto Builder.launch deleted file mode 100644 index 68b4dfa..0000000 --- a/j2se/.externalToolBuilders/Proto Builder.launch +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/j2se/.gitignore b/j2se/.gitignore deleted file mode 100644 index 6c3adb3..0000000 --- a/j2se/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -build/** -j2se.jar \ No newline at end of file diff --git a/j2se/.project b/j2se/.project deleted file mode 100644 index 8cc21b9..0000000 --- a/j2se/.project +++ /dev/null @@ -1,49 +0,0 @@ - - - MusicSynthesizerJ2SE - - - - - - org.eclipse.ui.externaltools.ExternalToolBuilder - auto,full,incremental, - - - LaunchConfigHandle - <project>/.externalToolBuilders/Proto Builder.launch - - - - - org.eclipse.jdt.core.javabuilder - - - - - - org.eclipse.jdt.core.javanature - - - - core - 2 - PARENT-1-PROJECT_LOC/core/src - - - core-gen - 2 - PARENT-1-PROJECT_LOC/core/gen - - - core-lib - 2 - PARENT-1-PROJECT_LOC/core/lib - - - test - 2 - PARENT-1-PROJECT_LOC/test/src - - - diff --git a/j2se/build.xml b/j2se/build.xml deleted file mode 100644 index 6615363..0000000 --- a/j2se/build.xml +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/j2se/src/com/levien/synthesizer/j2se/Midi.java b/j2se/src/com/levien/synthesizer/j2se/Midi.java deleted file mode 100755 index ed43988..0000000 --- a/j2se/src/com/levien/synthesizer/j2se/Midi.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.j2se; - -import com.levien.synthesizer.core.model.composite.MultiChannelSynthesizer; - -import java.util.ArrayList; -import java.util.List; -import java.util.logging.Logger; -import javax.sound.midi.MidiDevice; -import javax.sound.midi.MidiMessage; -import javax.sound.midi.MidiSystem; -import javax.sound.midi.MidiUnavailableException; - -/** - * Midi keeps track of the Midi devices connected to the system, and their control bindings. - */ -public class Midi { - /** - * Creates a new Midi system for the given synthesizer. - */ - public Midi(MultiChannelSynthesizer synth) { - synthesizer_ = synth; - binders_ = new ArrayList(); - logger_ = Logger.getLogger(getClass().getName()); - } - - /** - * Prints out a list of all of the Midi devices connected to the system. - */ - public void printDevices() { - StringBuilder debug = new StringBuilder("\n"); - MidiDevice.Info[] devices = MidiSystem.getMidiDeviceInfo(); - for (int i = 0; i < devices.length; ++i) { - debug.append("Device " + i + ": " + - devices[i].getName() + ": " + devices[i].getDescription() + "\n"); - debug.append(" " + devices[i].getVendor()); - debug.append(" " + devices[i].getVersion()); - try { - MidiDevice device = MidiSystem.getMidiDevice(devices[i]); - debug.append(" receivers: " + device.getMaxReceivers() + - " transmitters: " + device.getMaxTransmitters() + "\n"); - } catch (MidiUnavailableException mue) { - debug.append(" Unavailable!"); - } - } - logger_.info(debug.toString()); - } - - /** - * Returns the Midi device at the specified index. - */ - private MidiDevice getDevice(int index) { - MidiDevice.Info[] devices = MidiSystem.getMidiDeviceInfo(); - if (index < 0 || index >= devices.length) { - return null; - } - try { - return MidiSystem.getMidiDevice(devices[index]); - } catch (MidiUnavailableException mue) { - return null; - } - } - - /** - * Connects the synthesizer to the controls of the Midi device at the specified index. - */ - public void bindDevice(int index) { - MidiDevice device = getDevice(index); - if (device != null) { - binders_.add(new MidiDeviceBinder(device, synthesizer_)); - } else { - logger_.severe("Unable to get device with index " + index + "."); - } - } - - /** - * Stops the connection to all Midi devices. - */ - public void stop() { - for (MidiDeviceBinder binder : binders_) { - binder.stop(); - } - } - - /** - * Sends the given message to all Midi devices. - */ - public void send(MidiMessage message) { - for (MidiDeviceBinder binder : binders_) { - binder.send(message); - } - } - - // The synthesizer to bind controls to. - private MultiChannelSynthesizer synthesizer_; - - // The list of Midi device bindings. - private List binders_; - - private Logger logger_; -} diff --git a/j2se/src/com/levien/synthesizer/j2se/MidiDeviceBinder.java b/j2se/src/com/levien/synthesizer/j2se/MidiDeviceBinder.java deleted file mode 100644 index c69fc94..0000000 --- a/j2se/src/com/levien/synthesizer/j2se/MidiDeviceBinder.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.j2se; - -import com.levien.synthesizer.core.midi.MessageInputProcessor; -import com.levien.synthesizer.core.model.composite.MultiChannelSynthesizer; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.util.logging.Level; -import java.util.logging.Logger; -import javax.sound.midi.MidiDevice; -import javax.sound.midi.MidiMessage; -import javax.sound.midi.MidiUnavailableException; -import javax.sound.midi.Receiver; -import javax.sound.midi.Transmitter; - -/** - * MidiDeviceBinder manages the connection between a MidiDevice and its associated BindingSet. - */ -public class MidiDeviceBinder { - /** - * MidiDeviceBinder manages the connection between a MidiDevice and its associated BindingSet. - * @param device - The device to connect the BindingSet to. - * @param synth - The synthesizer to bind to. - */ - public MidiDeviceBinder(MidiDevice device, MultiChannelSynthesizer synth) { - device_ = device; - synth_ = synth; - midiIn_ = null; - logger_ = Logger.getLogger(getClass().getName()); - try { - if (midiIn_ == null && device_.getMaxTransmitters() != 0) { - if (!device_.isOpen()) { - device_.open(); - } - midiIn_ = device_.getTransmitter(); - midiIn_.setReceiver(new Receiver() { - public void send(MidiMessage message, long time) { - ByteArrayInputStream stream = new ByteArrayInputStream( - message.getMessage(), 0, message.getLength()); - try { - MessageInputProcessor.process(stream, 0, synth_); - } catch (IOException e) { - logger_.log(Level.SEVERE, "Error processing Midi message.", e); - } - } - public void close() { - logger_.info("Closing MIDI receiver."); - } - }); - } - if (midiOut_ == null && device_.getMaxReceivers() != 0) { - if (!device_.isOpen()) { - device_.open(); - } - midiOut_ = device_.getReceiver(); - } - } catch (MidiUnavailableException mue) { - logger_.severe("Unable to open MIDI device."); - midiIn_ = null; - midiOut_ = null; - } - } - - /** - * Closes the Midi device. - */ - public void stop() { - logger_.info("Closing MIDI device."); - if (device_ != null) { - device_.close(); - } - if (midiIn_ != null) { - midiIn_.close(); - midiIn_ = null; - } - if (midiOut_ != null) { - midiOut_.close(); - midiOut_ = null; - } - } - - /** - * Sends the given message to the Midi device. - */ - public void send(MidiMessage message) { - if (midiOut_ != null) { - midiOut_.send(message, System.currentTimeMillis()); - } - } - - // The synthesizer to bind to. - private MultiChannelSynthesizer synth_; - - // The Midi device to bind to. - private MidiDevice device_; - private Transmitter midiIn_; - private Receiver midiOut_; - - private Logger logger_; -} diff --git a/j2se/src/com/levien/synthesizer/j2se/Perform.java b/j2se/src/com/levien/synthesizer/j2se/Perform.java deleted file mode 100644 index cf15417..0000000 --- a/j2se/src/com/levien/synthesizer/j2se/Perform.java +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.j2se; - -import java.io.BufferedInputStream; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.sound.midi.MidiMessage; - -import com.levien.synthesizer.core.midi.MessageOutputProcessor; -import com.levien.synthesizer.core.midi.MidiFilePlayer; -import com.levien.synthesizer.core.midi.MidiListener; -import com.levien.synthesizer.core.model.composite.MultiChannelSynthesizer; -import com.levien.synthesizer.core.soundfont.SoundFontReader; -import com.levien.synthesizer.core.wave.WaveAdapter; - -/** - * Perform is a simple little command-line app for debugging the synthesizer. - */ -public class Perform { - /** - * Loads presets from the given file into the synthesizer. - * @param filename - The path to the file. - * @param synth - The synthesizer to load the presets into. - */ - public void loadPresetsFile(String filename, MultiChannelSynthesizer synth) { - InputStream input; - try { - input = new BufferedInputStream(new FileInputStream(new File(filename))); - try { - synth.loadLibraryFromText(input); - } catch (IOException e) { - logger_.log(Level.SEVERE, "Unable to read from input stream.", e); - } - } catch (FileNotFoundException e) { - logger_.severe("Unable to open file " + filename + "."); - } - } - - /** - * This is dumb. - */ - private static class DummyMidiMessage extends MidiMessage { - protected DummyMidiMessage(byte[] data) { - super(data); - } - - @Override - public Object clone() { - return new DummyMidiMessage(getMessage()); - } - } - - /** - * The real main() function for this class. Creates a synthesizer and runs a read-eval-print loop - * to take input from the user and control the synthesizer. - */ - public Perform() { - logger_ = Logger.getLogger(getClass().getName()); - double sampleRateInHz = 11025; - - SoundFontReader samples = null; - try { - samples = new SoundFontReader(new FileInputStream(new File("android/res/raw/drums.sf2"))); - } catch (IOException e) { - samples = null; - e.printStackTrace(); - } - - MultiChannelSynthesizer synth = new MultiChannelSynthesizer(16, 5, sampleRateInHz, samples); - WaveAdapter writer = new WaveAdapter((int)sampleRateInHz, 16, synth); - - // Load some arbitrary presets to make playing midis more interesting. - loadPresetsFile("android/res/raw/presets.txt", synth); - synth.setPreset(0, 0); - synth.setPreset(1, 1); - synth.setPreset(2, 3); - synth.setPreset(3, 0); - synth.setPreset(4, 1); - synth.setPreset(5, 1); - synth.setPreset(6, 0); - synth.setPreset(7, 0); - synth.setPreset(8, 0); - synth.setPreset(9, 5); - synth.setPreset(10, 2); - synth.setPreset(11, 0); - synth.setPreset(12, 0); - synth.setPreset(13, 0); - synth.setPreset(14, 0); - synth.setPreset(15, 0); - - final Midi midi = new Midi(synth); - List listeners = new ArrayList(); - listeners.add(synth); - listeners.add(new MessageOutputProcessor() { - @Override - protected void onMessage(byte[] message) { - midi.send(new DummyMidiMessage(message)); - } - }); - MidiFilePlayer player = new MidiFilePlayer(listeners); - - SynthesizerThread thread = new SynthesizerThread(writer, (int)sampleRateInHz); - thread.play(); - - boolean running = true; - BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); - while (running) { - String line = null; - System.out.print("\n[synth]$ "); - System.out.flush(); - try { - line = stdin.readLine(); - } catch (IOException e) { - logger_.log(Level.SEVERE, "Error reading line.", e); - running = false; - } - if (line == null) { - running = false; - } else if (line.trim().equals("")) { - // Do nothing. - } else if (line.equals("exit") || line.equals("quit")) { - running = false; - } else if (line.equals("ls")) { - midi.printDevices(); - } else if (line.equals("ls midi")) { - midi.printDevices(); - } else if (line.equals("ls presets")) { - ArrayList names = new ArrayList(); - synth.getPresetNames(names); - StringBuilder output = new StringBuilder(""); - for (String name : names) { - output.append("\n" + name); - } - logger_.info(output.toString()); - } else if (line.startsWith("bind ")) { - String bindArgs = line.substring("bind ".length()); - try { - int index = Integer.parseInt(bindArgs); - midi.bindDevice(index); - } catch (NumberFormatException e) { - logger_.severe("Invalid number format \"" + bindArgs + "\"."); - } - } else if (line.startsWith("presets ")) { - String filename = line.substring("presets ".length()); - loadPresetsFile(filename, synth); - } else if (line.startsWith("play ")) { - String filename = line.substring("play ".length()); - try { - player.play(new FileInputStream(filename)); - } catch (FileNotFoundException e) { - logger_.log(Level.SEVERE, "Unable to open midi file.", e); - } catch (IOException e) { - logger_.log(Level.SEVERE, "Unable to read midi file.", e); - } - } else if (line.startsWith("record ")) { - String[] args = line.split(" +", 3); - if (args.length != 3) { - logger_.severe("Usage: record