Ver código fonte

first commit

hwh97 6 anos atrás
commit
7d9cc8e289
100 arquivos alterados com 9269 adições e 0 exclusões
  1. 7 0
      .gitignore
  2. 116 0
      .idea/codeStyles/Project.xml
  3. 19 0
      .idea/libraries/Dart_SDK.xml
  4. 9 0
      .idea/libraries/Flutter_Plugins.xml
  5. 9 0
      .idea/libraries/Flutter_for_Android.xml
  6. 7 0
      .idea/misc.xml
  7. 10 0
      .idea/modules.xml
  8. 6 0
      .idea/runConfigurations/example_lib_main_dart.xml
  9. 156 0
      .idea/workspace.xml
  10. 10 0
      .metadata
  11. 3 0
      CHANGELOG.md
  12. 1 0
      LICENSE
  13. 14 0
      README.md
  14. 8 0
      android/.gitignore
  15. 1 0
      android/.idea/.name
  16. BIN
      android/.idea/caches/build_file_checksums.ser
  17. 116 0
      android/.idea/codeStyles/Project.xml
  18. 18 0
      android/.idea/gradle.xml
  19. 9 0
      android/.idea/misc.xml
  20. 8 0
      android/.idea/modules.xml
  21. 12 0
      android/.idea/runConfigurations.xml
  22. 51 0
      android/build.gradle
  23. 2 0
      android/gradle.properties
  24. 5 0
      android/gradle/wrapper/gradle-wrapper.properties
  25. BIN
      android/libs/Msc.jar
  26. BIN
      android/libs/arm64-v8a/libmsc.so
  27. BIN
      android/libs/armeabi-v7a/libmsc.so
  28. BIN
      android/libs/flutter.jar
  29. 1 0
      android/settings.gradle
  30. 3 0
      android/src/main/AndroidManifest.xml
  31. 153 0
      android/src/main/kotlin/cn/i2edu/speech_plugin/SpeechPlugin.kt
  32. 19 0
      android/src/main/kotlin/cn/i2edu/speech_plugin/audioUtils/audioEvaluator/resultParse/FinalResult.java
  33. 36 0
      android/src/main/kotlin/cn/i2edu/speech_plugin/audioUtils/audioEvaluator/resultParse/ReadSentenceResult.java
  34. 27 0
      android/src/main/kotlin/cn/i2edu/speech_plugin/audioUtils/audioEvaluator/resultParse/ReadSyllableResult.java
  35. 45 0
      android/src/main/kotlin/cn/i2edu/speech_plugin/audioUtils/audioEvaluator/resultParse/ReadWordResult.java
  36. 55 0
      android/src/main/kotlin/cn/i2edu/speech_plugin/audioUtils/audioEvaluator/resultParse/Result.java
  37. 273 0
      android/src/main/kotlin/cn/i2edu/speech_plugin/audioUtils/audioEvaluator/resultParse/XmlResultParser.java
  38. 101 0
      android/src/main/kotlin/cn/i2edu/speech_plugin/audioUtils/audioEvaluator/resultParse/entity/Phone.java
  39. 44 0
      android/src/main/kotlin/cn/i2edu/speech_plugin/audioUtils/audioEvaluator/resultParse/entity/Sentence.java
  40. 56 0
      android/src/main/kotlin/cn/i2edu/speech_plugin/audioUtils/audioEvaluator/resultParse/entity/Syll.java
  41. 57 0
      android/src/main/kotlin/cn/i2edu/speech_plugin/audioUtils/audioEvaluator/resultParse/entity/Word.java
  42. 119 0
      android/src/main/kotlin/cn/i2edu/speech_plugin/audioUtils/audioEvaluator/resultParse/util/ResultFormatUtil.java
  43. 38 0
      android/src/main/kotlin/cn/i2edu/speech_plugin/audioUtils/audioEvaluator/resultParse/util/ResultTranslateUtil.java
  44. 172 0
      android/src/main/kotlin/cn/i2edu/speech_plugin/audioUtils/audiotransfer/CommonFunction.java
  45. 48 0
      android/src/main/kotlin/cn/i2edu/speech_plugin/audioUtils/audiotransfer/Constant.java
  46. 531 0
      android/src/main/kotlin/cn/i2edu/speech_plugin/audioUtils/audiotransfer/DecodeEngine.java
  47. 12 0
      android/src/main/kotlin/cn/i2edu/speech_plugin/audioUtils/audiotransfer/DecodeOperateInterface.java
  48. 202 0
      android/src/main/kotlin/cn/i2edu/speech_plugin/audioUtils/audiotransfer/FileFunction.java
  49. 127 0
      android/src/main/kotlin/cn/i2edu/speech_plugin/audioUtils/audiotransfer/LogFunction.java
  50. 8 0
      android/src/main/kotlin/cn/i2edu/speech_plugin/audioUtils/audiotransfer/Variable.java
  51. 2562 0
      android/src/main/kotlin/cn/i2edu/speech_plugin/audioUtils/audiotransfer/vavi/sound/pcm/resampling/ssrc/SSRC.java
  52. 155 0
      android/src/main/kotlin/cn/i2edu/speech_plugin/audioUtils/audiotransfer/vavi/util/I0Bessel.java
  53. 2604 0
      android/src/main/kotlin/cn/i2edu/speech_plugin/audioUtils/audiotransfer/vavi/util/SplitRadixFft.java
  54. 3 0
      android/src/main/kotlin/cn/i2edu/speech_plugin/audioUtils/bean/SimpleWord.kt
  55. 111 0
      android/src/main/kotlin/cn/i2edu/speech_plugin/util/AudioEvaluatorUtil.kt
  56. 73 0
      example/.gitignore
  57. 10 0
      example/.metadata
  58. 16 0
      example/README.md
  59. 67 0
      example/android/app/build.gradle
  60. 7 0
      example/android/app/src/debug/AndroidManifest.xml
  61. 33 0
      example/android/app/src/main/AndroidManifest.xml
  62. 13 0
      example/android/app/src/main/kotlin/cn/i2edu/speech_plugin_example/MainActivity.kt
  63. 12 0
      example/android/app/src/main/res/drawable/launch_background.xml
  64. BIN
      example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
  65. BIN
      example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
  66. BIN
      example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
  67. BIN
      example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
  68. BIN
      example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
  69. 8 0
      example/android/app/src/main/res/values/styles.xml
  70. 7 0
      example/android/app/src/profile/AndroidManifest.xml
  71. 31 0
      example/android/build.gradle
  72. 2 0
      example/android/gradle.properties
  73. 6 0
      example/android/gradle/wrapper/gradle-wrapper.properties
  74. 15 0
      example/android/settings.gradle
  75. 26 0
      example/ios/Flutter/AppFrameworkInfo.plist
  76. 1 0
      example/ios/Flutter/Debug.xcconfig
  77. 1 0
      example/ios/Flutter/Release.xcconfig
  78. 519 0
      example/ios/Runner.xcodeproj/project.pbxproj
  79. 7 0
      example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
  80. 91 0
      example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
  81. 7 0
      example/ios/Runner.xcworkspace/contents.xcworkspacedata
  82. 13 0
      example/ios/Runner/AppDelegate.swift
  83. 122 0
      example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
  84. BIN
      example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
  85. BIN
      example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
  86. BIN
      example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
  87. BIN
      example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
  88. BIN
      example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
  89. BIN
      example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
  90. BIN
      example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
  91. BIN
      example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
  92. BIN
      example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
  93. BIN
      example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
  94. BIN
      example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
  95. BIN
      example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
  96. BIN
      example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
  97. BIN
      example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
  98. BIN
      example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
  99. 23 0
      example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json
  100. BIN
      example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png

+ 7 - 0
.gitignore

@@ -0,0 +1,7 @@
+.DS_Store
+.dart_tool/
+
+.packages
+.pub/
+
+build/

+ 116 - 0
.idea/codeStyles/Project.xml

@@ -0,0 +1,116 @@
+<component name="ProjectCodeStyleConfiguration">
+  <code_scheme name="Project" version="173">
+    <codeStyleSettings language="XML">
+      <indentOptions>
+        <option name="CONTINUATION_INDENT_SIZE" value="4" />
+      </indentOptions>
+      <arrangement>
+        <rules>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>xmlns:android</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>^$</XML_NAMESPACE>
+                </AND>
+              </match>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>xmlns:.*</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>^$</XML_NAMESPACE>
+                </AND>
+              </match>
+              <order>BY_NAME</order>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>.*:id</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
+                </AND>
+              </match>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>.*:name</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
+                </AND>
+              </match>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>name</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>^$</XML_NAMESPACE>
+                </AND>
+              </match>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>style</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>^$</XML_NAMESPACE>
+                </AND>
+              </match>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>.*</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>^$</XML_NAMESPACE>
+                </AND>
+              </match>
+              <order>BY_NAME</order>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>.*</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
+                </AND>
+              </match>
+              <order>ANDROID_ATTRIBUTE_ORDER</order>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>.*</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>.*</XML_NAMESPACE>
+                </AND>
+              </match>
+              <order>BY_NAME</order>
+            </rule>
+          </section>
+        </rules>
+      </arrangement>
+    </codeStyleSettings>
+  </code_scheme>
+</component>

+ 19 - 0
.idea/libraries/Dart_SDK.xml

@@ -0,0 +1,19 @@
+<component name="libraryTable">
+  <library name="Dart SDK">
+    <CLASSES>
+      <root url="file://C:/flutter/flutter/bin/cache/dart-sdk/lib/async" />
+      <root url="file://C:/flutter/flutter/bin/cache/dart-sdk/lib/collection" />
+      <root url="file://C:/flutter/flutter/bin/cache/dart-sdk/lib/convert" />
+      <root url="file://C:/flutter/flutter/bin/cache/dart-sdk/lib/core" />
+      <root url="file://C:/flutter/flutter/bin/cache/dart-sdk/lib/developer" />
+      <root url="file://C:/flutter/flutter/bin/cache/dart-sdk/lib/html" />
+      <root url="file://C:/flutter/flutter/bin/cache/dart-sdk/lib/io" />
+      <root url="file://C:/flutter/flutter/bin/cache/dart-sdk/lib/isolate" />
+      <root url="file://C:/flutter/flutter/bin/cache/dart-sdk/lib/math" />
+      <root url="file://C:/flutter/flutter/bin/cache/dart-sdk/lib/mirrors" />
+      <root url="file://C:/flutter/flutter/bin/cache/dart-sdk/lib/typed_data" />
+    </CLASSES>
+    <JAVADOC />
+    <SOURCES />
+  </library>
+</component>

+ 9 - 0
.idea/libraries/Flutter_Plugins.xml

@@ -0,0 +1,9 @@
+<component name="libraryTable">
+  <library name="Flutter Plugins" type="FlutterPluginsLibraryType">
+    <CLASSES>
+      <root url="file://$PROJECT_DIR$" />
+    </CLASSES>
+    <JAVADOC />
+    <SOURCES />
+  </library>
+</component>

+ 9 - 0
.idea/libraries/Flutter_for_Android.xml

@@ -0,0 +1,9 @@
+<component name="libraryTable">
+  <library name="Flutter for Android">
+    <CLASSES>
+      <root url="jar://C:/flutter/flutter/bin/cache/artifacts/engine/android-arm/flutter.jar!/" />
+    </CLASSES>
+    <JAVADOC />
+    <SOURCES />
+  </library>
+</component>

+ 7 - 0
.idea/misc.xml

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectRootManager" version="2" project-jdk-name="Android API 22 Platform" project-jdk-type="Android SDK" />
+  <component name="ProjectType">
+    <option name="id" value="io.flutter" />
+  </component>
+</project>

+ 10 - 0
.idea/modules.xml

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/speech_plugin.iml" filepath="$PROJECT_DIR$/speech_plugin.iml" />
+      <module fileurl="file://$PROJECT_DIR$/android/speech_plugin_android.iml" filepath="$PROJECT_DIR$/android/speech_plugin_android.iml" />
+      <module fileurl="file://$PROJECT_DIR$/example/android/speech_plugin_example_android.iml" filepath="$PROJECT_DIR$/example/android/speech_plugin_example_android.iml" />
+    </modules>
+  </component>
+</project>

+ 6 - 0
.idea/runConfigurations/example_lib_main_dart.xml

@@ -0,0 +1,6 @@
+<component name="ProjectRunConfigurationManager">
+  <configuration default="false" name="example/lib/main.dart" type="FlutterRunConfigurationType" factoryName="Flutter">
+    <option name="filePath" value="$PROJECT_DIR$/example/lib/main.dart" />
+    <method />
+  </configuration>
+</component>

+ 156 - 0
.idea/workspace.xml

@@ -0,0 +1,156 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ChangeListManager">
+    <list default="true" id="91fb8cbe-3946-4eca-a4cf-05dab52b73c6" name="Default Changelist" comment="" />
+    <ignored path="$PROJECT_DIR$/.dart_tool/" />
+    <ignored path="$PROJECT_DIR$/.idea/" />
+    <ignored path="$PROJECT_DIR$/.pub/" />
+    <ignored path="$PROJECT_DIR$/build/" />
+    <ignored path="$PROJECT_DIR$/example/.pub/" />
+    <ignored path="$PROJECT_DIR$/example/build/" />
+    <option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
+    <option name="SHOW_DIALOG" value="false" />
+    <option name="HIGHLIGHT_CONFLICTS" value="true" />
+    <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
+    <option name="LAST_RESOLUTION" value="IGNORE" />
+  </component>
+  <component name="ExecutionTargetManager" SELECTED_TARGET="792QAESFTC6MD" />
+  <component name="FileEditorManager">
+    <leaf SIDE_TABS_SIZE_LIMIT_KEY="300">
+      <file pinned="false" current-in-tab="true">
+        <entry file="file://$PROJECT_DIR$/lib/speech_plugin.dart">
+          <provider selected="true" editor-type-id="text-editor">
+            <state relative-caret-position="513">
+              <caret line="29" column="2" lean-forward="true" selection-start-line="29" selection-start-column="2" selection-end-line="29" selection-end-column="2" />
+            </state>
+          </provider>
+        </entry>
+      </file>
+    </leaf>
+  </component>
+  <component name="IdeDocumentHistory">
+    <option name="CHANGED_PATHS">
+      <list>
+        <option value="$PROJECT_DIR$/lib/speech_plugin.dart" />
+      </list>
+    </option>
+  </component>
+  <component name="ProjectFrameBounds" extendedState="6">
+    <option name="width" value="1440" />
+    <option name="height" value="900" />
+  </component>
+  <component name="ProjectView">
+    <navigator currentView="ProjectPane" proportions="" version="1">
+      <foldersAlwaysOnTop value="true" />
+    </navigator>
+    <panes>
+      <pane id="AndroidView" />
+      <pane id="ProjectPane">
+        <subPane>
+          <expand>
+            <path>
+              <item name="speech_plugin" type="b2602c69:ProjectViewProjectNode" />
+              <item name="speech_plugin" type="462c0819:PsiDirectoryNode" />
+            </path>
+            <path>
+              <item name="speech_plugin" type="b2602c69:ProjectViewProjectNode" />
+              <item name="speech_plugin" type="462c0819:PsiDirectoryNode" />
+              <item name="lib" type="462c0819:PsiDirectoryNode" />
+            </path>
+            <path>
+              <item name="speech_plugin" type="b2602c69:ProjectViewProjectNode" />
+              <item name="External Libraries" type="cb654da1:ExternalLibrariesNode" />
+            </path>
+          </expand>
+          <select />
+        </subPane>
+      </pane>
+      <pane id="Scope" />
+      <pane id="PackagesPane" />
+    </panes>
+  </component>
+  <component name="PropertiesComponent">
+    <property name="dart.analysis.tool.window.force.activate" value="false" />
+    <property name="last_opened_file_path" value="$PROJECT_DIR$/android" />
+    <property name="show.migrate.to.gradle.popup" value="false" />
+  </component>
+  <component name="RunDashboard">
+    <option name="ruleStates">
+      <list>
+        <RuleState>
+          <option name="name" value="ConfigurationTypeDashboardGroupingRule" />
+        </RuleState>
+        <RuleState>
+          <option name="name" value="StatusDashboardGroupingRule" />
+        </RuleState>
+      </list>
+    </option>
+  </component>
+  <component name="SvnConfiguration">
+    <configuration />
+  </component>
+  <component name="TaskManager">
+    <task active="true" id="Default" summary="Default task">
+      <changelist id="91fb8cbe-3946-4eca-a4cf-05dab52b73c6" name="Default Changelist" comment="" />
+      <created>1572489275976</created>
+      <option name="number" value="Default" />
+      <option name="presentableId" value="Default" />
+      <updated>1572489275976</updated>
+    </task>
+    <servers />
+  </component>
+  <component name="ToolWindowManager">
+    <frame x="-8" y="-8" width="1936" height="1056" extended-state="6" />
+    <editor active="true" />
+    <layout>
+      <window_info id="Capture Tool" />
+      <window_info id="Structure" side_tool="true" />
+      <window_info id="Favorites" side_tool="true" />
+      <window_info id="Build Variants" side_tool="true" />
+      <window_info id="Image Layers" />
+      <window_info id="Designer" />
+      <window_info id="Captures" side_tool="true" />
+      <window_info id="Resources Explorer" />
+      <window_info active="true" content_ui="combo" id="Project" order="0" visible="true" weight="0.19989339" />
+      <window_info anchor="bottom" id="Run" />
+      <window_info anchor="bottom" id="Dart Analysis" weight="0.32936078" />
+      <window_info anchor="bottom" id="Logcat" />
+      <window_info anchor="bottom" id="TODO" />
+      <window_info anchor="bottom" id="Debug" />
+      <window_info anchor="bottom" id="Terminal" />
+      <window_info anchor="bottom" id="Event Log" side_tool="true" />
+      <window_info anchor="bottom" id="Flutter Performance" side_tool="true" />
+      <window_info anchor="bottom" id="Version Control" />
+      <window_info anchor="bottom" id="Android Profiler" show_stripe_button="false" />
+      <window_info anchor="right" id="Device File Explorer" side_tool="true" />
+      <window_info anchor="right" id="Capture Analysis" />
+      <window_info anchor="right" id="Theme Preview" />
+      <window_info anchor="right" id="Flutter Inspector" />
+      <window_info anchor="right" id="Flutter Outline" />
+      <window_info anchor="right" id="Palette&#9;" />
+    </layout>
+  </component>
+  <component name="editorHistoryManager">
+    <entry file="file://$PROJECT_DIR$/pubspec.yaml">
+      <provider selected="true" editor-type-id="text-editor">
+        <state relative-caret-position="475">
+          <caret line="25" column="47" selection-start-line="25" selection-start-column="47" selection-end-line="25" selection-end-column="47" />
+        </state>
+      </provider>
+    </entry>
+    <entry file="file://$PROJECT_DIR$/example/lib/main.dart">
+      <provider selected="true" editor-type-id="text-editor">
+        <state relative-caret-position="23">
+          <caret line="16" column="11" lean-forward="true" selection-start-line="16" selection-start-column="11" selection-end-line="16" selection-end-column="11" />
+        </state>
+      </provider>
+    </entry>
+    <entry file="file://$PROJECT_DIR$/lib/speech_plugin.dart">
+      <provider selected="true" editor-type-id="text-editor">
+        <state relative-caret-position="513">
+          <caret line="29" column="2" lean-forward="true" selection-start-line="29" selection-start-column="2" selection-end-line="29" selection-end-column="2" />
+        </state>
+      </provider>
+    </entry>
+  </component>
+</project>

+ 10 - 0
.metadata

@@ -0,0 +1,10 @@
+# This file tracks properties of this Flutter project.
+# Used by Flutter tool to assess capabilities and perform upgrades etc.
+#
+# This file should be version controlled and should not be manually edited.
+
+version:
+  revision: 68587a0916366e9512a78df22c44163d041dd5f3
+  channel: stable
+
+project_type: plugin

+ 3 - 0
CHANGELOG.md

@@ -0,0 +1,3 @@
+## 0.0.1
+
+* TODO: Describe initial release.

+ 1 - 0
LICENSE

@@ -0,0 +1 @@
+TODO: Add your license here.

+ 14 - 0
README.md

@@ -0,0 +1,14 @@
+# speech_plugin
+
+A new Flutter plugin for speech lib.
+
+## Getting Started
+
+This project is a starting point for a Flutter
+[plug-in package](https://flutter.dev/developing-packages/),
+a specialized package that includes platform-specific implementation code for
+Android and/or iOS.
+
+For help getting started with Flutter, view our 
+[online documentation](https://flutter.dev/docs), which offers tutorials, 
+samples, guidance on mobile development, and a full API reference.

+ 8 - 0
android/.gitignore

@@ -0,0 +1,8 @@
+*.iml
+.gradle
+/local.properties
+/.idea/workspace.xml
+/.idea/libraries
+.DS_Store
+/build
+/captures

+ 1 - 0
android/.idea/.name

@@ -0,0 +1 @@
+speech_plugin

BIN
android/.idea/caches/build_file_checksums.ser


+ 116 - 0
android/.idea/codeStyles/Project.xml

@@ -0,0 +1,116 @@
+<component name="ProjectCodeStyleConfiguration">
+  <code_scheme name="Project" version="173">
+    <codeStyleSettings language="XML">
+      <indentOptions>
+        <option name="CONTINUATION_INDENT_SIZE" value="4" />
+      </indentOptions>
+      <arrangement>
+        <rules>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>xmlns:android</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>^$</XML_NAMESPACE>
+                </AND>
+              </match>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>xmlns:.*</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>^$</XML_NAMESPACE>
+                </AND>
+              </match>
+              <order>BY_NAME</order>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>.*:id</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
+                </AND>
+              </match>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>.*:name</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
+                </AND>
+              </match>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>name</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>^$</XML_NAMESPACE>
+                </AND>
+              </match>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>style</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>^$</XML_NAMESPACE>
+                </AND>
+              </match>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>.*</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>^$</XML_NAMESPACE>
+                </AND>
+              </match>
+              <order>BY_NAME</order>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>.*</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
+                </AND>
+              </match>
+              <order>ANDROID_ATTRIBUTE_ORDER</order>
+            </rule>
+          </section>
+          <section>
+            <rule>
+              <match>
+                <AND>
+                  <NAME>.*</NAME>
+                  <XML_ATTRIBUTE />
+                  <XML_NAMESPACE>.*</XML_NAMESPACE>
+                </AND>
+              </match>
+              <order>BY_NAME</order>
+            </rule>
+          </section>
+        </rules>
+      </arrangement>
+    </codeStyleSettings>
+  </code_scheme>
+</component>

+ 18 - 0
android/.idea/gradle.xml

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="GradleSettings">
+    <option name="linkedExternalProjectsSettings">
+      <GradleProjectSettings>
+        <option name="distributionType" value="DEFAULT_WRAPPED" />
+        <option name="externalProjectPath" value="$PROJECT_DIR$" />
+        <option name="modules">
+          <set>
+            <option value="$PROJECT_DIR$" />
+          </set>
+        </option>
+        <option name="resolveModulePerSourceSet" value="false" />
+        <option name="testRunner" value="PLATFORM" />
+      </GradleProjectSettings>
+    </option>
+  </component>
+</project>

+ 9 - 0
android/.idea/misc.xml

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="JDK" project-jdk-type="JavaSDK">
+    <output url="file://$PROJECT_DIR$/build/classes" />
+  </component>
+  <component name="ProjectType">
+    <option name="id" value="Android" />
+  </component>
+</project>

+ 8 - 0
android/.idea/modules.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/speech_plugin.iml" filepath="$PROJECT_DIR$/speech_plugin.iml" />
+    </modules>
+  </component>
+</project>

+ 12 - 0
android/.idea/runConfigurations.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="RunConfigurationProducerService">
+    <option name="ignoredProducers">
+      <set>
+        <option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
+        <option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
+        <option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
+      </set>
+    </option>
+  </component>
+</project>

+ 51 - 0
android/build.gradle

@@ -0,0 +1,51 @@
+group 'cn.i2edu.speech_plugin'
+version '1.0-SNAPSHOT'
+
+buildscript {
+    ext.kotlin_version = '1.3.20'
+    repositories {
+        google()
+        jcenter()
+    }
+
+    dependencies {
+        classpath 'com.android.tools.build:gradle:3.2.1'
+        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+    }
+}
+
+rootProject.allprojects {
+    repositories {
+        google()
+        jcenter()
+    }
+}
+
+apply plugin: 'com.android.library'
+apply plugin: 'kotlin-android'
+
+android {
+    compileSdkVersion 28
+    
+    sourceSets {
+        main {
+            java.srcDirs += 'src/main/kotlin'
+            jniLibs.srcDirs = ['libs']
+        }
+    }
+    defaultConfig {
+        minSdkVersion 16
+        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+    }
+    lintOptions {
+        disable 'InvalidPackage'
+    }
+}
+
+dependencies {
+    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+    compileOnly  files('libs/flutter.jar')
+    implementation 'com.googlecode.mp4parser:isoparser:1.0-RC-37'
+    implementation files('libs/Msc.jar')
+    implementation 'com.alibaba:fastjson:1.1.71.android'
+}

+ 2 - 0
android/gradle.properties

@@ -0,0 +1,2 @@
+org.gradle.jvmargs=-Xmx1536M
+

+ 5 - 0
android/gradle/wrapper/gradle-wrapper.properties

@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip

BIN
android/libs/Msc.jar


BIN
android/libs/arm64-v8a/libmsc.so


BIN
android/libs/armeabi-v7a/libmsc.so


BIN
android/libs/flutter.jar


+ 1 - 0
android/settings.gradle

@@ -0,0 +1 @@
+rootProject.name = 'speech_plugin'

+ 3 - 0
android/src/main/AndroidManifest.xml

@@ -0,0 +1,3 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+  package="cn.i2edu.speech_plugin">
+</manifest>

+ 153 - 0
android/src/main/kotlin/cn/i2edu/speech_plugin/SpeechPlugin.kt

@@ -0,0 +1,153 @@
+package cn.i2edu.speech_plugin
+
+import android.app.Activity
+import android.content.Context
+import android.text.TextUtils
+import android.widget.Toast
+import cn.i2edu.dubbing_lib.bean.SimpleWord
+import cn.i2edu.dubbing_lib.util.AudioEvaluatorUtil
+import cn.i2edu.dubbing_lib.util.EvaluatorCallBack
+import cn.i2edu.speech_plugin.audioUtils.audioEvaluator.resultParse.ReadSentenceResult
+import cn.i2edu.speech_plugin.audioUtils.audioEvaluator.resultParse.XmlResultParser
+import com.alibaba.fastjson.JSON
+import com.googlecode.mp4parser.authoring.Movie
+import com.googlecode.mp4parser.authoring.Track
+import com.googlecode.mp4parser.authoring.builder.DefaultMp4Builder
+import com.googlecode.mp4parser.authoring.container.mp4.MovieCreator
+import com.googlecode.mp4parser.authoring.tracks.AppendTrack
+import com.iflytek.cloud.EvaluatorResult
+import com.iflytek.cloud.SpeechConstant
+import com.iflytek.cloud.SpeechError
+import com.iflytek.cloud.SpeechUtility
+import io.flutter.plugin.common.MethodCall
+import io.flutter.plugin.common.MethodChannel
+import io.flutter.plugin.common.MethodChannel.MethodCallHandler
+import io.flutter.plugin.common.MethodChannel.Result
+import io.flutter.plugin.common.PluginRegistry.Registrar
+import java.io.File
+import java.io.RandomAccessFile
+import java.util.*
+
+class SpeechPlugin: MethodCallHandler {
+  
+  companion object {
+    private lateinit var context: Context
+    @JvmStatic
+    fun registerWith(registrar: Registrar) {
+      if (registrar.activity() == null) return
+      val channel = MethodChannel(registrar.messenger(), "speech_plugin")
+      context = registrar.activeContext()
+      channel.setMethodCallHandler(SpeechPlugin())
+    }
+  }
+
+  override fun onMethodCall(call: MethodCall, result: Result) {
+    if (call.method == "getPlatformVersion") {
+      result.success("Android ${android.os.Build.VERSION.RELEASE}")
+    } else if (call.method == "initSpeechSdk") {
+      SpeechUtility.createUtility(context, SpeechConstant.APPID +"=589c15f3")
+      result.success(true)
+    } else if (call.method == "evaluatorByAudio") {
+      val pathEvaluatorDecode = call.argument<String>("pathEvaluatorDecode")!!
+      val index = call.argument<Int>("index")!!
+      val videoId = call.argument<String>("videoId")!!
+      val recordPath = call.argument<String>("recordPath")!!
+      val en = call.argument<String>("en")!!
+
+      evaluatorRecord(pathEvaluatorDecode, index, recordPath, en, false, result)
+    } else if (call.method == "evaluatorByMp4") {
+      val pathEvaluatorDecode = call.argument<String>("pathEvaluatorDecode")!!
+      val index = call.argument<Int>("index")!!
+      val videoId = call.argument<String>("videoId")!!
+      val recordPath = call.argument<String>("recordPath")!!
+      val en = call.argument<String>("en")!!
+
+      evaluatorVideoRecord(pathEvaluatorDecode, index, videoId, recordPath, en, result)
+    } else {
+      result.notImplemented()
+    }
+  }
+
+  private fun evaluatorVideoRecord(pathEvaluatorDecode: String, index: Int, videoId: String, recordPath: String, en: String, channelResult: Result) {
+    try {
+      val movie = MovieCreator.build (recordPath)
+      val audioTracks = arrayListOf<Track>()
+      for (t in movie.tracks){
+        if (t.handler == "soun") {
+          audioTracks.add(t)
+        }
+      }
+      val result =  Movie()
+      if (audioTracks.size > 0) {
+        val array = arrayOfNulls<Track>(audioTracks.size)
+        audioTracks.toArray(array)
+        result.addTrack(AppendTrack(*array))
+      }
+      val out = DefaultMp4Builder().build(result)
+      try {
+        val fc = RandomAccessFile("$pathEvaluatorDecode/${videoId}_$index.aac", "rw").channel
+        out.writeContainer(fc)
+        fc.close()
+        evaluatorRecord(pathEvaluatorDecode, index, "$pathEvaluatorDecode/${videoId}_$index.aac", en, true, channelResult)
+      } catch ( e: Exception) {
+        e.printStackTrace()
+      }
+    }catch (e: Exception) {
+      e.printStackTrace()
+    }
+  }
+
+  private fun evaluatorRecord(pathEvaluatorDecode: String, index: Int, recordPath: String, en: String, isVideo: Boolean, chanelResult: MethodChannel.Result) {
+    val dir = File(pathEvaluatorDecode)
+    if (!dir.exists()) dir.mkdirs()
+    val decodePath = pathEvaluatorDecode + UUID.randomUUID().toString() + ".pcm"
+    AudioEvaluatorUtil.getInstance(context = context)
+            .setEvaluatorCallBack(object : EvaluatorCallBack {
+              override fun onResult(result: EvaluatorResult) {
+                (context as Activity).runOnUiThread {
+                  if (isVideo) {
+                    try {
+                      File(recordPath).delete()
+                    } catch (e: java.lang.Exception) {
+                      e.printStackTrace()
+                    }
+                  }
+                  val builder = StringBuilder()
+                  builder.append(result.resultString)
+                  if (!TextUtils.isEmpty(builder)) {
+                    val resultParser = XmlResultParser()
+                    val parseResult = resultParser.parse(builder.toString()) as ReadSentenceResult
+//                    Toast.makeText(context,
+//                            "识别成功,结果:${if (parseResult.is_rejected) "您在乱读哦" else "您没乱读结果为:${parseResult.total_score}"}", Toast.LENGTH_SHORT).show()
+                    val formatWords = arrayListOf<SimpleWord>()
+                    for (sentence in parseResult.sentences) {
+                      val words = sentence.words
+                      for (word in words) {
+                        // 过滤掉sil、 silv 表示静音, fil 表示噪音
+                        if (word.content == "sil" || word.content == "silv" || word.content == "fil")
+                          continue
+                        formatWords.add(SimpleWord(word.content, word.total_score))
+                      }
+                    }
+
+                    chanelResult.success(
+                            mapOf("index" to index,"score" to (if(parseResult.is_rejected) null else parseResult.total_score), "words" to JSON.toJSONString(formatWords)))
+                  } else {
+//                    Toast.makeText(context, "识别失败,结果为空", Toast.LENGTH_SHORT).show()
+                    chanelResult.success(mapOf("index" to index,"score" to null))
+                  }
+                }
+              }
+
+              override fun onError(error: SpeechError) {
+                (context as Activity).runOnUiThread {
+                  //                  Toast.makeText(activity.applicationContext, "识别失败,错误描述:${error.errorDescription},错误码:${error.errorCode}",
+//                          Toast.LENGTH_SHORT).show()
+                  chanelResult.success(mapOf("index" to index,"score" to null))
+                }
+              }
+            })
+            ?.startEvaluator(en, recordPath, decodePath)
+  }
+
+}

+ 19 - 0
android/src/main/kotlin/cn/i2edu/speech_plugin/audioUtils/audioEvaluator/resultParse/FinalResult.java

@@ -0,0 +1,19 @@
+package cn.i2edu.speech_plugin.audioUtils.audioEvaluator.resultParse;
+
+/**
+ * <p>Title: FinalResult</p>
+ * <p>Description: </p>
+ * <p>Company: www.iflytek.com</p>
+ * @author iflytek
+ */
+public class FinalResult extends Result {
+	
+	public int ret;
+	
+	public float total_score;
+	
+	@Override
+	public String toString() {
+		return "返回值:" + ret + ",总分:" + total_score;
+	}
+}

+ 36 - 0
android/src/main/kotlin/cn/i2edu/speech_plugin/audioUtils/audioEvaluator/resultParse/ReadSentenceResult.java

@@ -0,0 +1,36 @@
+package cn.i2edu.speech_plugin.audioUtils.audioEvaluator.resultParse;
+
+
+import cn.i2edu.speech_plugin.audioUtils.audioEvaluator.resultParse.util.ResultFormatUtil;
+
+/**
+ * <p>Title: ReadSentenceResult</p>
+ * <p>Description: </p>
+ * <p>Company: www.iflytek.com</p>
+ * @author iflytek
+ */
+public class ReadSentenceResult extends Result {
+	
+	public ReadSentenceResult() {
+		category = "read_sentence";
+	}
+	
+	@Override
+	public String toString() {
+		StringBuilder buffer = new StringBuilder();
+		
+		if ("cn".equals(language)) {
+			buffer.append("[总体结果]\n").append("评测内容:").append(content).append("\n").append("朗读时长:").append(time_len).append("\n").append("总分:").append(total_score).append("\n\n")
+				.append("[朗读详情]").append(ResultFormatUtil.formatDetails_CN(sentences));
+		} else {
+			if (is_rejected) {
+				buffer.append("检测到乱读,").append("except_info:").append(except_info).append("\n\n");	// except_info代码说明详见《语音评测参数、结果说明文档》
+			}
+			
+			buffer.append("[总体结果]\n").append("评测内容:").append(content).append("\n").append("总分:").append(total_score).append("\n\n")
+				.append("[朗读详情]").append(ResultFormatUtil.formatDetails_EN(sentences));
+		}
+		
+		return buffer.toString();
+	}
+}

+ 27 - 0
android/src/main/kotlin/cn/i2edu/speech_plugin/audioUtils/audioEvaluator/resultParse/ReadSyllableResult.java

@@ -0,0 +1,27 @@
+package cn.i2edu.speech_plugin.audioUtils.audioEvaluator.resultParse;
+
+
+import cn.i2edu.speech_plugin.audioUtils.audioEvaluator.resultParse.util.ResultFormatUtil;
+
+/**
+ * <p>Title: ReadSyllableResult</p>
+ * <p>Description: 中文单字评测结果</p>
+ * <p>Company: www.iflytek.com</p>
+ * @author iflytek
+ */
+public class ReadSyllableResult extends Result {
+	
+	public ReadSyllableResult() {
+		language = "cn";
+		category = "read_syllable";
+	}
+	
+	@Override
+	public String toString() {
+
+		return "[总体结果]\n" + "评测内容:" + content + "\n" +
+				"朗读时长:" + time_len + "\n" +
+				"总分:" + total_score + "\n\n" +
+				"[朗读详情]" + ResultFormatUtil.formatDetails_CN(sentences);
+	}
+}

+ 45 - 0
android/src/main/kotlin/cn/i2edu/speech_plugin/audioUtils/audioEvaluator/resultParse/ReadWordResult.java

@@ -0,0 +1,45 @@
+package cn.i2edu.speech_plugin.audioUtils.audioEvaluator.resultParse;
+
+
+import cn.i2edu.speech_plugin.audioUtils.audioEvaluator.resultParse.util.ResultFormatUtil;
+
+/**
+ * <p>Title: ReadWordResult</p>
+ * <p>Description: </p>
+ * <p>Company: www.iflytek.com</p>
+ *
+ * @author iflytek
+ */
+public class ReadWordResult extends Result {
+
+    public ReadWordResult() {
+        category = "read_word";
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder buffer = new StringBuilder();
+
+        if ("cn".equals(language)) {
+            buffer.append("[总体结果]\n")
+                    .append("评测内容:").append(content).append("\n")
+                    .append("朗读时长:").append(time_len).append("\n")
+                    .append("总分:").append(total_score).append("\n\n")
+                    .append("[朗读详情]")
+                    .append(ResultFormatUtil.formatDetails_CN(sentences));
+        } else {
+            if (is_rejected) {
+                buffer.append("检测到乱读,")
+                        .append("except_info:").append(except_info).append("\n\n");    // except_info代码说明详见《语音评测参数、结果说明文档》
+            }
+
+            buffer.append("[总体结果]\n")
+                    .append("评测内容:").append(content).append("\n")
+                    .append("总分:").append(total_score).append("\n\n")
+                    .append("[朗读详情]")
+                    .append(ResultFormatUtil.formatDetails_EN(sentences));
+        }
+
+        return buffer.toString();
+    }
+}

+ 55 - 0
android/src/main/kotlin/cn/i2edu/speech_plugin/audioUtils/audioEvaluator/resultParse/Result.java

@@ -0,0 +1,55 @@
+package cn.i2edu.speech_plugin.audioUtils.audioEvaluator.resultParse;
+
+import java.util.ArrayList;
+
+import cn.i2edu.speech_plugin.audioUtils.audioEvaluator.resultParse.entity.Sentence;
+
+
+/**
+ * <p>Title: Result</p>
+ * <p>Description: 评测结果</p>
+ * <p>Company: www.iflytek.com</p>
+ * @author iflytek
+ */
+public class Result {
+	/**
+	 * 评测语种:en(英文)、cn(中文)
+	 */
+	public String language;
+	/**
+	 * 评测种类:read_syllable(cn单字)、read_word(词语)、read_sentence(句子) 
+	 */
+	public String category;
+	/**
+	 * 开始帧位置,每帧相当于10ms
+	 */
+	public int beg_pos;
+	/**
+	 * 结束帧位置
+	 */
+	public int end_pos;
+	/**
+	 * 评测内容
+	 */
+	public String content;
+	/**
+	 * 总得分
+	 */
+	public float total_score;
+	/**
+	 * 时长(cn)
+	 */
+	public int time_len;
+	/**
+	 * 异常信息(en)
+	 */
+	public String except_info;
+	/**
+	 * 是否乱读(cn)
+	 */
+	public boolean is_rejected;
+	/**
+	 * xml结果中的sentence标签
+	 */
+	public ArrayList<Sentence> sentences;
+}

+ 273 - 0
android/src/main/kotlin/cn/i2edu/speech_plugin/audioUtils/audioEvaluator/resultParse/XmlResultParser.java

@@ -0,0 +1,273 @@
+package cn.i2edu.speech_plugin.audioUtils.audioEvaluator.resultParse;
+
+import android.text.TextUtils;
+import android.util.Xml;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+
+import cn.i2edu.speech_plugin.audioUtils.audioEvaluator.resultParse.entity.Phone;
+import cn.i2edu.speech_plugin.audioUtils.audioEvaluator.resultParse.entity.Sentence;
+import cn.i2edu.speech_plugin.audioUtils.audioEvaluator.resultParse.entity.Syll;
+import cn.i2edu.speech_plugin.audioUtils.audioEvaluator.resultParse.entity.Word;
+
+
+/**
+ * <p>Title: XmlResultParser</p>
+ * <p>Description: </p>
+ * <p>Company: www.iflytek.com</p>
+ * @author iflytek
+ */
+public class XmlResultParser {
+	
+	@SuppressWarnings("TryWithIdenticalCatches")
+	public Result parse(String xml) {
+		if (TextUtils.isEmpty(xml)) {
+			return null;
+		}
+		
+		XmlPullParser pullParser = Xml.newPullParser();
+		
+		try {
+			InputStream ins = new ByteArrayInputStream(xml.getBytes());
+			pullParser.setInput(ins, "utf-8");
+			FinalResult finalResult = null;
+			
+			int eventType = pullParser.getEventType();
+			while (XmlPullParser.END_DOCUMENT != eventType) {
+				switch (eventType) {
+				case XmlPullParser.START_TAG:
+					if ("FinalResult".equals(pullParser.getName())) {
+						// 只有一个总分的结果
+						finalResult = new FinalResult();
+					} else if ("ret".equals(pullParser.getName())) {
+						finalResult.ret = getInt(pullParser, "value");
+					} else if ("total_score".equals(pullParser.getName())) {
+						finalResult.total_score = getFloat(pullParser, "value");
+					} else if ("xml_result".equals(pullParser.getName())) {
+						// 详细结果
+						return parseResult(pullParser);
+					}
+					
+					break;
+				case XmlPullParser.END_TAG:
+					if ("FinalResult".equals(pullParser.getName())) {
+						return finalResult;
+					}
+					break;
+				
+				default:
+					break;
+				}
+				eventType = pullParser.next();
+			}
+		} catch (XmlPullParserException e) {
+			e.printStackTrace();
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+		
+		return null;
+	}
+	
+	@SuppressWarnings("TryWithIdenticalCatches")
+	private Result parseResult(XmlPullParser pullParser) {
+		Result result = null;
+		// <rec_paper>标签是否已扫描到
+		boolean rec_paperPassed = false;
+		Sentence sentence = null;
+		Word word = null;
+		Syll syll = null;
+		Phone phone = null;
+		
+		int eventType;
+		try {
+			eventType = pullParser.getEventType();
+			while (XmlPullParser.END_DOCUMENT != eventType) {
+				switch (eventType) {
+				case XmlPullParser.START_TAG:
+					if ("rec_paper".equals(pullParser.getName())) {
+						rec_paperPassed = true;
+					} else if ("read_syllable".equals(pullParser.getName())) {
+						if (!rec_paperPassed) {
+							result = new ReadSyllableResult();
+						} else {
+							readTotalResult(result, pullParser);
+						}
+					} else if ("read_word".equals(pullParser.getName())) {
+						if (!rec_paperPassed) {
+							result = new ReadWordResult();
+							String lan = getLanguage(pullParser);
+							result.language = (null == lan)? "cn": lan;
+						} else {
+							readTotalResult(result, pullParser);
+						}
+					} else if ("read_sentence".equals(pullParser.getName()) || 
+							"read_chapter".equals(pullParser.getName())) {
+						if (!rec_paperPassed) {
+							result = new ReadSentenceResult();
+							String lan = getLanguage(pullParser);
+							result.language = (null == lan)? "cn": lan;
+						} else {
+							readTotalResult(result, pullParser);
+						}
+					} else if ("sentence".equals(pullParser.getName())) {
+						if (null == result.sentences) {
+							result.sentences = new ArrayList<>();
+						}
+						sentence = createSentence(pullParser);
+					} else if ("word".equals(pullParser.getName())) {
+						if (null != sentence && null == sentence.words) {
+							sentence.words = new ArrayList<>();
+						}
+						word = createWord(pullParser);
+					} else if ("syll".equals(pullParser.getName())) {
+						if (null != word && null == word.sylls) {
+							word.sylls = new ArrayList<>();
+						}
+						syll = createSyll(pullParser);
+					} else if ("phone".equals(pullParser.getName())) {
+						if (null != syll && null == syll.phones) {
+							syll.phones = new ArrayList<>();
+						}
+						phone = createPhone(pullParser);
+					}
+					
+					break;
+				case XmlPullParser.END_TAG:
+					if ("phone".equals(pullParser.getName())) {
+						syll.phones.add(phone);
+					} else if ("syll".equals(pullParser.getName())) {
+						word.sylls.add(syll);
+					} else if ("word".equals(pullParser.getName())) {
+						sentence.words.add(word);
+					} else if ("sentence".equals(pullParser.getName())) {
+						result.sentences.add(sentence);
+					} else if ("read_syllable".equals(pullParser.getName()) 
+							|| "read_word".equals(pullParser.getName()) 
+							|| "read_sentence".equals(pullParser.getName())) {
+						return result;
+					} 
+					break;
+
+				default:
+					break;
+				}
+				
+				eventType = pullParser.next();
+			}
+		} catch (XmlPullParserException e) {
+			e.printStackTrace();
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+		
+		return result;
+	}
+	
+	private void readTotalResult(Result result, XmlPullParser pullParser) {
+		result.beg_pos = getInt(pullParser, "beg_pos");
+		result.end_pos = getInt(pullParser, "end_pos");
+		result.content = getContent(pullParser);
+		result.total_score = getFloat(pullParser, "total_score");
+		result.time_len = getInt(pullParser, "time_len");
+		result.except_info = getExceptInfo(pullParser);
+		result.is_rejected = getIsRejected(pullParser);
+	}
+	
+	private Phone createPhone(XmlPullParser pullParser) {
+		Phone phone;
+		phone = new Phone();
+		phone.beg_pos = getInt(pullParser, "beg_pos");
+		phone.end_pos = getInt(pullParser, "end_pos");
+		phone.content = getContent(pullParser);
+		phone.dp_message = getInt(pullParser, "dp_message");
+		phone.time_len = getInt(pullParser, "time_len");
+		return phone;
+	}
+
+	private Syll createSyll(XmlPullParser pullParser) {
+		Syll syll;
+		syll = new Syll();
+		syll.beg_pos = getInt(pullParser, "beg_pos");
+		syll.end_pos = getInt(pullParser, "end_pos");
+		syll.content = getContent(pullParser);
+		syll.symbol = getSymbol(pullParser);
+		syll.dp_message = getInt(pullParser, "dp_message");
+		syll.time_len = getInt(pullParser, "time_len");
+		return syll;
+	}
+
+	private Word createWord(XmlPullParser pullParser) {
+		Word word;
+		word = new Word();
+		word.beg_pos = getInt(pullParser, "beg_pos");
+		word.end_pos = getInt(pullParser, "end_pos");
+		word.content = getContent(pullParser);
+		word.symbol = getSymbol(pullParser);
+		word.time_len = getInt(pullParser, "time_len");
+		word.dp_message = getInt(pullParser, "dp_message");
+		word.total_score = getFloat(pullParser, "total_score");
+		word.global_index = getInt(pullParser, "global_index");
+		word.index = getInt(pullParser, "index");
+		return word;
+	}
+
+	private Sentence createSentence(XmlPullParser pullParser) {
+		Sentence sentence;
+		sentence = new Sentence();
+		sentence.beg_pos = getInt(pullParser, "beg_pos");
+		sentence.end_pos = getInt(pullParser, "end_pos");
+		sentence.content = getContent(pullParser);
+		sentence.time_len = getInt(pullParser, "time_len");
+		sentence.index = getInt(pullParser, "index");
+		sentence.word_count = getInt(pullParser, "word_count");
+		return sentence;
+	}
+
+	private String getLanguage(XmlPullParser pullParser) {
+		return pullParser.getAttributeValue(null, "lan");
+	}
+	
+	private String getExceptInfo(XmlPullParser pullParser) {
+		return pullParser.getAttributeValue(null, "except_info");
+	}
+	
+	private boolean getIsRejected(XmlPullParser pullParser) {
+		String isRejected = pullParser.getAttributeValue(null, "is_rejected");
+		if (null == isRejected) {
+			return false;
+		}
+		
+		return Boolean.parseBoolean(isRejected);
+	}
+
+	private String getSymbol(XmlPullParser pullParser) {
+		return pullParser.getAttributeValue(null, "symbol");
+	}
+
+	private float getFloat(XmlPullParser pullParser, String attrName) {
+		String val = pullParser.getAttributeValue(null, attrName);
+		if (null == val) {
+			return 0f;
+		}
+		return Float.parseFloat(val);
+	}
+
+	private String getContent(XmlPullParser pullParser) {
+		return pullParser.getAttributeValue(null, "content");
+	}
+	
+	private int getInt(XmlPullParser pullParser, String attrName) {
+		String val = pullParser.getAttributeValue(null, attrName);
+		if (null == val) {
+			return 0;
+		}
+		return Integer.parseInt(val);
+	}
+}

+ 101 - 0
android/src/main/kotlin/cn/i2edu/speech_plugin/audioUtils/audioEvaluator/resultParse/entity/Phone.java

@@ -0,0 +1,101 @@
+package cn.i2edu.speech_plugin.audioUtils.audioEvaluator.resultParse.entity;
+
+import java.util.HashMap;
+
+/**
+ * <p>Title: Phone</p>
+ * <p>Description: 音素,对应于xml结果中的Phone标签</p>
+ * <p>Company: www.iflytek.com</p>
+ * @author iflytek
+ */
+public class Phone {
+	/**
+	 * 讯飞音标-标准音标映射表(en)
+	 */
+	public static final HashMap<String, String> phone_map = new HashMap<>();
+	
+	static {
+		phone_map.put("aa", "ɑ:");
+		phone_map.put("oo", "ɔ");
+		phone_map.put("ae", "æ");
+		phone_map.put("ah", "ʌ");
+		phone_map.put("ao", "ɔ:");
+		phone_map.put("aw", "aʊ");
+		phone_map.put("ax", "ə");
+		phone_map.put("ay", "aɪ");
+		phone_map.put("eh", "e");
+		phone_map.put("er", "ə:");
+		phone_map.put("ey", "eɪ");
+		phone_map.put("ih", "ɪ");
+		phone_map.put("iy", "i:");
+		phone_map.put("ow", "əʊ");
+		phone_map.put("oy", "ɔɪ");
+		phone_map.put("uh", "ʊ");
+		phone_map.put("uw", "ʊ:");
+		phone_map.put("ch", "tʃ");
+		phone_map.put("dh", "ð");
+		phone_map.put("hh", "h");
+		phone_map.put("jh", "dʒ");
+		phone_map.put("ng", "ŋ");
+		phone_map.put("sh", "ʃ");
+		phone_map.put("th", "θ");
+		phone_map.put("zh", "ʒ");
+		phone_map.put("y", "j");
+		phone_map.put("d", "d");
+		phone_map.put("k", "k");
+		phone_map.put("l", "l");
+		phone_map.put("m", "m");
+		phone_map.put("n", "n");
+		phone_map.put("b", "b");
+		phone_map.put("f", "f");
+		phone_map.put("g", "g");
+		phone_map.put("p", "p");
+		phone_map.put("r", "r");
+		phone_map.put("s", "s");
+		phone_map.put("t", "t");
+		phone_map.put("v", "v");
+		phone_map.put("w", "w");
+		phone_map.put("z", "z");
+		phone_map.put("ar", "eə");
+		phone_map.put("ir", "iə");
+		phone_map.put("ur", "ʊə");
+		phone_map.put("tr", "tr");
+		phone_map.put("dr", "dr");
+		phone_map.put("ts", "ts");
+		phone_map.put("dz", "dz");
+	}
+	
+	/**
+	 * 开始帧位置,每帧相当于10ms
+	 */
+	public int beg_pos;
+	/**
+	 * 结束帧位置
+	 */
+	public int end_pos;
+	/**
+	 * 音素内容
+	 */
+	public String content;
+	/**
+	 * 增漏读信息:0(正确),16(漏读),32(增读),64(回读),128(替换)
+	 */
+	public int dp_message;
+	/**
+	 * 时长(单位:帧,每帧相当于10ms)(cn)
+	 */
+	public int time_len;
+	
+	/**
+	 * 得到content对应的标准音标(en)
+	 */
+	public String getStdSymbol() {
+		return getStdSymbol(content);
+	}
+	
+	public static String getStdSymbol(String content) {
+		String std = phone_map.get(content);
+		return (null == std)? content: std;
+	}
+	
+}

+ 44 - 0
android/src/main/kotlin/cn/i2edu/speech_plugin/audioUtils/audioEvaluator/resultParse/entity/Sentence.java

@@ -0,0 +1,44 @@
+package cn.i2edu.speech_plugin.audioUtils.audioEvaluator.resultParse.entity;
+
+import java.util.ArrayList;
+
+/**
+ * <p>Title: Sentence</p>
+ * <p>Description: 句子,对应于xml结果中的sentence标签</p>
+ * <p>Company: www.iflytek.com</p>
+ * @author iflytek
+ */
+public class Sentence {
+	/**
+	 * 开始帧位置,每帧相当于10ms
+	 */
+	public int beg_pos;
+	/**
+	 * 结束帧位置
+	 */
+	public int end_pos;
+	/**
+	 * 句子内容
+	 */
+	public String content;
+	/**
+	 * 总得分
+	 */
+	public float total_score;
+	/**
+	 * 时长(单位:帧,每帧相当于10ms)(cn)
+	 */
+	public int time_len;
+	/**
+	 * 句子的索引(en)
+	 */
+	public int index;
+	/**
+	 * 单词数(en)
+	 */
+	public int word_count;
+	/**
+	 * sentence包括的word
+	 */
+	public ArrayList<Word> words;
+}

+ 56 - 0
android/src/main/kotlin/cn/i2edu/speech_plugin/audioUtils/audioEvaluator/resultParse/entity/Syll.java

@@ -0,0 +1,56 @@
+package cn.i2edu.speech_plugin.audioUtils.audioEvaluator.resultParse.entity;
+
+import java.util.ArrayList;
+
+/**
+ * <p>Title: Syll</p>
+ * <p>Description: 音节,对应于结果xml中的Syll标签</p>
+ * <p>Company: www.iflytek.com</p>
+ * @author iflytek
+ */
+public class Syll {
+	/**
+	 * 开始帧位置,每帧相当于10ms
+	 */
+	public int beg_pos;
+	/**
+	 * 结束帧位置
+	 */
+	public int end_pos;
+	/**
+	 * 音节内容
+	 */
+	public String content;
+	/**
+	 * 拼音(cn),数字代表声调,5表示轻声,如fen1
+	 */
+	public String symbol;
+	/**
+	 * 增漏读信息:0(正确),16(漏读),32(增读),64(回读),128(替换)
+	 */
+	public int dp_message;
+	/**
+	 * 时长(单位:帧,每帧相当于10ms)(cn)
+	 */
+	public int time_len;
+	/**
+	 * Syll包含的音节
+	 */
+	public ArrayList<Phone> phones;
+	
+	/**
+	 * 获取音节的标准音标(en)
+	 * 
+	 * @return 标准音标
+	 */
+	public String getStdSymbol() {
+		StringBuilder stdSymbol = new StringBuilder();
+		String[] symbols = content.split(" ");
+
+		for (String symbol1 : symbols) {
+			stdSymbol.append(Phone.getStdSymbol(symbol1));
+		}
+		
+		return stdSymbol.toString();
+	}
+}

+ 57 - 0
android/src/main/kotlin/cn/i2edu/speech_plugin/audioUtils/audioEvaluator/resultParse/entity/Word.java

@@ -0,0 +1,57 @@
+package cn.i2edu.speech_plugin.audioUtils.audioEvaluator.resultParse.entity;
+
+import java.util.ArrayList;
+
+/**
+ * <p>Title: Word</p>
+ * <p>Description: 单词,对应于结果xml中的word标签</p>
+ * <p>Company: www.iflytek.com</p>
+ * @author iflytek
+ */
+public class Word {
+	/**
+	 * 开始帧位置,每帧相当于10ms
+	 */
+	@SuppressWarnings("unused")
+	public int beg_pos;
+	/**
+	 * 结束帧位置
+	 */
+	@SuppressWarnings("unused")
+	public int end_pos;
+	/**
+	 * 单词内容
+	 */
+	public String content;
+	/**
+	 * 增漏读信息:0(正确),16(漏读),32(增读),64(回读),128(替换)
+	 */
+	public int dp_message;
+	/**
+	 * 单词在全篇索引(en)
+	 */
+	@SuppressWarnings("unused")
+	public int global_index;
+	/**
+	 * 单词在句子中的索引(en)
+	 */
+	@SuppressWarnings("unused")
+	public int index;
+	/**
+	 * 拼音(cn),数字代表声调,5表示轻声,如fen1
+	 */
+	public String symbol;
+	/**
+	 * 时长(单位:帧,每帧相当于10ms)(cn)
+	 */
+	public int time_len;
+	/**
+	 * 单词得分(en)
+	 */
+	public float total_score;
+	/**
+	 * Word包含的Syll
+	 */
+	public ArrayList<Syll> sylls;
+	
+}

+ 119 - 0
android/src/main/kotlin/cn/i2edu/speech_plugin/audioUtils/audioEvaluator/resultParse/util/ResultFormatUtil.java

@@ -0,0 +1,119 @@
+package cn.i2edu.speech_plugin.audioUtils.audioEvaluator.resultParse.util;
+
+
+import java.util.ArrayList;
+
+import cn.i2edu.speech_plugin.audioUtils.audioEvaluator.resultParse.entity.Phone;
+import cn.i2edu.speech_plugin.audioUtils.audioEvaluator.resultParse.entity.Sentence;
+import cn.i2edu.speech_plugin.audioUtils.audioEvaluator.resultParse.entity.Syll;
+import cn.i2edu.speech_plugin.audioUtils.audioEvaluator.resultParse.entity.Word;
+
+/**
+ * <p>Title: ResultFormatUtl</p>
+ * <p>Description: </p>
+ * <p>Company: www.iflytek.com</p>
+ * @author iflytek
+ */
+public class ResultFormatUtil {
+	
+	/**
+	 * 将英语评测详情按格式输出
+	 * 
+	 * @param sentences 评测结果
+	 * @return 英语评测详情
+	 */
+	public static String formatDetails_EN(ArrayList<Sentence> sentences) {
+		StringBuilder buffer = new StringBuilder();
+		if (null == sentences) {
+			return buffer.toString();
+		}
+		
+		for (Sentence sentence: sentences ) {
+			if ("噪音".equals(ResultTranslateUtil.getContent(sentence.content)) 
+					|| "静音".equals(ResultTranslateUtil.getContent(sentence.content))) {
+				continue;
+			}
+			
+			if (null == sentence.words) {
+				continue;
+			}
+			for (Word word: sentence.words) {
+				if ("噪音".equals(ResultTranslateUtil.getContent(word.content)) 
+						|| "静音".equals(ResultTranslateUtil.getContent(word.content))) {
+					continue;
+				}
+				
+				buffer.append("\n单词[")
+						.append(ResultTranslateUtil.getContent(word.content))
+						.append("] ")
+						.append("朗读:")
+						.append(ResultTranslateUtil.getDpMessageInfo(word.dp_message)).append(" 得分:").append(word.total_score);
+				if (null == word.sylls) {
+					buffer.append("\n");
+					continue;
+				}
+				
+				for (Syll syll: word.sylls) {
+					buffer.append("\n└音节[").append(ResultTranslateUtil.getContent(syll.getStdSymbol())).append("] ");
+					if (null == syll.phones) {
+						continue;
+					}
+					
+					for (Phone phone: syll.phones) {
+						buffer.append("\n\t└音素[").append(ResultTranslateUtil.getContent(phone.getStdSymbol())).append("] ").append(" 朗读:").append(ResultTranslateUtil.getDpMessageInfo(phone.dp_message));
+					}
+					
+				}
+				buffer.append("\n");
+			}
+		}
+		
+		return buffer.toString();
+	}
+
+	/**
+	 * 将汉语评测详情按格式输出
+	 * 
+	 * @param sentences 评测结果
+	 * @return 汉语评测详情
+	 */
+	public static String formatDetails_CN(ArrayList<Sentence> sentences) {
+		StringBuilder buffer = new StringBuilder();
+		if (null == sentences) {
+			return buffer.toString();
+		}
+		
+		for (Sentence sentence: sentences ) {
+			if (null == sentence.words) {
+				continue;
+			}
+			
+			for (Word word: sentence.words) {
+				buffer.append("\n词语[").append(ResultTranslateUtil.getContent(word.content)).append("] ").append(word.symbol).append(" 时长:").append(word.time_len);
+				if (null == word.sylls) {
+					continue;
+				}
+				
+				for (Syll syll: word.sylls) {
+					if ("噪音".equals(ResultTranslateUtil.getContent(syll.content)) 
+							|| "静音".equals(ResultTranslateUtil.getContent(syll.content))) {
+						continue;
+					}
+					
+					buffer.append("\n└音节[").append(ResultTranslateUtil.getContent(syll.content)).append("] ").append(syll.symbol).append(" 时长:").append(syll.time_len);
+					if (null == syll.phones) {
+						continue;
+					}
+					
+					for (Phone phone: syll.phones) {
+						buffer.append("\n\t└音素[").append(ResultTranslateUtil.getContent(phone.content)).append("] ").append("时长:").append(phone.time_len).append(" 朗读:").append(ResultTranslateUtil.getDpMessageInfo(phone.dp_message));
+					}
+					
+				}
+				buffer.append("\n");
+			}
+		}
+		
+		return buffer.toString();
+	}
+}

+ 38 - 0
android/src/main/kotlin/cn/i2edu/speech_plugin/audioUtils/audioEvaluator/resultParse/util/ResultTranslateUtil.java

@@ -0,0 +1,38 @@
+package cn.i2edu.speech_plugin.audioUtils.audioEvaluator.resultParse.util;
+
+import android.util.SparseArray;
+
+import java.util.HashMap;
+
+/**
+ * <p>Title: ResultTranslateUtl</p>
+ * <p>Description: </p>
+ * <p>Company: www.iflytek.com</p>
+ * @author iflytek
+ */
+public class ResultTranslateUtil {
+	
+	private static final SparseArray<String> dp_message_map = new SparseArray<>();
+	private static final HashMap<String, String> special_content_map = new HashMap<>();
+	
+	static {
+		dp_message_map.put(0, "正常");
+		dp_message_map.put(16, "漏读");
+		dp_message_map.put(32, "增读");
+		dp_message_map.put(64, "回读");
+		dp_message_map.put(128, "替换");
+		
+		special_content_map.put("sil", "静音");
+		special_content_map.put("silv", "静音");
+		special_content_map.put("fil", "噪音");
+	}
+	
+	public static String getDpMessageInfo(int dp_message) {
+		return dp_message_map.get(dp_message);
+	}
+	
+	public static String getContent(String content) {
+		String val = special_content_map.get(content);
+		return (null == val)? content: val;
+	}
+}

+ 172 - 0
android/src/main/kotlin/cn/i2edu/speech_plugin/audioUtils/audiotransfer/CommonFunction.java

@@ -0,0 +1,172 @@
+package cn.i2edu.speech_plugin.audioUtils.audiotransfer;
+
+import android.os.Looper;
+
+import java.text.SimpleDateFormat;
+import java.util.Locale;
+
+/**
+ * Created by zhengtongyu on 16/5/23.
+ */
+public class CommonFunction {
+    public static String FormatRecordTime(int recordTime) {
+        int minute = recordTime / 60;
+        int second = recordTime % 60;
+
+        String formatRecordTime = "";
+
+        if (minute != 0) {
+            formatRecordTime += String.valueOf(minute) + "′";
+        }
+
+        formatRecordTime += String.valueOf(second) + "″";
+
+        return formatRecordTime;
+    }
+
+    public static String GetDate() {
+        long time = System.currentTimeMillis();
+        SimpleDateFormat simpleDateFormat =
+                new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);
+        return simpleDateFormat.format(time);
+    }
+
+    public static String GetDate(long time) {
+        SimpleDateFormat simpleDateFormat =
+                new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);
+        return simpleDateFormat.format(time);
+    }
+
+    public static boolean notEmpty(CharSequence text) {
+        return !isEmpty(text);
+    }
+
+    public static boolean isEmpty(CharSequence text) {
+        return text == null || text.length() == 0;
+
+    }
+
+//    public static String GetPackageName() {
+//        String processName = "";
+//        ActivityManager activityManager = (ActivityManager) MyApplication.getInstance()
+//                .getSystemService(Context.ACTIVITY_SERVICE);
+//        Iterator<ActivityManager.RunningAppProcessInfo> infoIterator =
+//                activityManager.getRunningAppProcesses().iterator();
+//        ActivityManager.RunningAppProcessInfo runningAppProcessInfo;
+//
+//        while (infoIterator.hasNext()) {
+//            runningAppProcessInfo = infoIterator.next();
+//
+//            try {
+//                if (runningAppProcessInfo.pid == android.os.Process.myPid()) {
+//                    processName = runningAppProcessInfo.processName;
+//                    return processName;
+//                }
+//            } catch (Exception e) {
+//                Log.e("查询进程出错", e.toString());
+//            }
+//        }
+//
+//        return processName;
+//    }
+
+
+    public static byte[] GetBytes(short shortValue, boolean bigEnding) {
+        byte[] byteArray = new byte[2];
+
+        if (bigEnding) {
+            byteArray[1] = (byte) (shortValue & 0x00ff);
+            shortValue >>= 8;
+            byteArray[0] = (byte) (shortValue & 0x00ff);
+        } else {
+            byteArray[0] = (byte) (shortValue & 0x00ff);
+            shortValue >>= 8;
+            byteArray[1] = (byte) (shortValue & 0x00ff);
+        }
+
+        return byteArray;
+    }
+
+    public static short GetShort(byte firstByte, byte secondByte, boolean bigEnding) {
+        short shortValue = 0;
+
+        if (bigEnding) {
+            shortValue |= (firstByte & 0x00ff);
+            shortValue <<= 8;
+            shortValue |= (secondByte & 0x00ff);
+        } else {
+            shortValue |= (secondByte & 0x00ff);
+            shortValue <<= 8;
+            shortValue |= (firstByte & 0x00ff);
+        }
+
+        return shortValue;
+    }
+
+    public static byte[] AverageShortByteArray(byte firstShortHighByte, byte firstShortLowByte,
+                                               byte secondShortHighByte, byte secondShortLowByte,
+                                               boolean bigEnding) {
+        short firstShort =
+                CommonFunction.GetShort(firstShortHighByte, firstShortLowByte, bigEnding);
+        short secondShort =
+                CommonFunction.GetShort(secondShortHighByte, secondShortLowByte, bigEnding);
+        return CommonFunction.GetBytes((short) (firstShort / 2 + secondShort / 2), bigEnding);
+    }
+
+    public static short AverageShort(byte firstShortHighByte, byte firstShortLowByte,
+                                     byte secondShortHighByte, byte secondShortLowByte,
+                                     boolean bigEnding) {
+        short firstShort =
+                CommonFunction.GetShort(firstShortHighByte, firstShortLowByte, bigEnding);
+        short secondShort =
+                CommonFunction.GetShort(secondShortHighByte, secondShortLowByte, bigEnding);
+        return (short) (firstShort / 2 + secondShort / 2);
+    }
+
+    public static short WeightShort(byte firstShortHighByte, byte firstShortLowByte,
+                                    byte secondShortHighByte, byte secondShortLowByte,
+                                    float firstWeight, float secondWeight, boolean bigEnding) {
+        short firstShort =
+                CommonFunction.GetShort(firstShortHighByte, firstShortLowByte, bigEnding);
+        short secondShort =
+                CommonFunction.GetShort(secondShortHighByte, secondShortLowByte, bigEnding);
+        return (short) (firstShort * firstWeight + secondShort * secondWeight);
+    }
+
+    public static boolean IsInMainThread() {
+        return Looper.myLooper() == Looper.getMainLooper();
+    }
+
+    public static byte[] GetByteBuffer(short[] shortArray, boolean bigEnding) {
+        return GetByteBuffer(shortArray, shortArray.length, bigEnding);
+    }
+
+    public static byte[] GetByteBuffer(short[] shortArray, int shortArrayLength,
+                                       boolean bigEnding) {
+        int actualShortArrayLength = shortArray.length;
+
+        if (shortArrayLength > actualShortArrayLength) {
+            shortArrayLength = actualShortArrayLength;
+        }
+
+        short shortValue;
+        byte[] byteArray = new byte[2 * shortArrayLength];
+
+        for (int i = 0; i < shortArrayLength; i++) {
+            shortValue = shortArray[i];
+
+            if (bigEnding) {
+                byteArray[i * 2 + 1] = (byte) (shortValue & 0x00ff);
+                shortValue >>= 8;
+                byteArray[i * 2] = (byte) (shortValue & 0x00ff);
+            } else {
+                byteArray[i * 2] = (byte) (shortValue & 0x00ff);
+                shortValue >>= 8;
+                byteArray[i * 2 + 1] = (byte) (shortValue & 0x00ff);
+            }
+        }
+
+        return byteArray;
+    }
+
+}

+ 48 - 0
android/src/main/kotlin/cn/i2edu/speech_plugin/audioUtils/audiotransfer/Constant.java

@@ -0,0 +1,48 @@
+package cn.i2edu.speech_plugin.audioUtils.audiotransfer;
+
+
+//import zty.composeaudio.BuildConfig;
+
+public class Constant {
+//    public static final boolean Debug = BuildConfig.DEBUG;
+
+    public static final int NoExistIndex = -1;
+
+    public static final int OneSecond = 1000;
+
+//    public static final int RecordSampleRate = 44100; // 采样率
+    public static final int RecordSampleRate = 8000; // 采样率
+    public static final int RecrrdSampleRate_16k = 16000;
+    public static final int RecordByteNumber = 2; // 采样率
+    public static final int RecordChannelNumber = 1;  // 与DEFAULT_CHANNEL_CONFIG相关,因为是mono单声,所以是1
+    public static final int RecordDataNumberInOneSecond =
+            RecordSampleRate * RecordByteNumber * RecordChannelNumber;
+    // 与DEFAULT_CHANNEL_CONFIG相关,因为是mono单声,所以是1
+    public static final int BehaviorSampleRate = 44100; // 采样率
+    public static final int LameMp3Quality = 7; // Lame Default Settings
+    public static final int LameBehaviorChannelNumber = RecordChannelNumber;
+    // 与DEFAULT_CHANNEL_CONFIG相关,因为是mono单声,所以是1
+    public static final int lameRecordBitRate = 64;
+    // Encoded bit rate. MP3 file will be encoded with bit rate 64kbps
+    public static final int LameBehaviorBitRate = 128;
+
+    public static final int MusicCutEndOffset = 2;
+
+    public static final int MaxDecodeProgress = 50;
+    public static final int NormalMaxProgress = 100;
+
+    public static final int RecordVolumeMaxRank = 9;
+
+    public static final int ThreadPoolCount = 5;
+
+    public static final float VoiceWeight = 1.8f;
+    public static final float VoiceBackgroundWeight = 0.2f;
+
+    public static final String IGeneImageSuffix = ".ipg";
+    public static final String JPGSuffix = ".jpg";
+    public static final String PngSuffix = ".png";
+    public static final String MusicSuffix = ".mp3";
+    public static final String LyricSuffix = ".lrc";
+    public static final String RecordSuffix = ".mp3";
+    public static final String PcmSuffix = ".pcm";
+}

+ 531 - 0
android/src/main/kotlin/cn/i2edu/speech_plugin/audioUtils/audiotransfer/DecodeEngine.java

@@ -0,0 +1,531 @@
+package cn.i2edu.speech_plugin.audioUtils.audiotransfer;
+
+import android.content.Context;
+import android.media.MediaCodec;
+import android.media.MediaExtractor;
+import android.media.MediaFormat;
+import android.util.Log;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+import cn.i2edu.speech_plugin.audioUtils.audiotransfer.vavi.sound.pcm.resampling.ssrc.SSRC;
+
+
+/**
+ * Created by 郑童宇 on 2016/03/04.
+ */
+public class DecodeEngine {
+    private static final String TAG = DecodeEngine.class.getName();
+    private static DecodeEngine instance;
+    private DecodeEngine() {
+    }
+
+    public static DecodeEngine getInstance(Context context) {
+        if (instance == null) {
+            synchronized (DecodeEngine.class) {
+                if (instance == null) {
+                    instance = new DecodeEngine();
+                }
+            }
+        }
+
+        return instance;
+    }
+
+    public void beginDecodeMusicFile(String musicFileUrl, String decodeFileUrl, int startSecond,
+                                     int desireSampleRate,
+                                     int desireChannel,
+                                     int desireBitwidth,
+                                     final DecodeOperateInterface decodeOperateInterface) {
+
+        final boolean decodeResult =
+                decodeMusicFile(musicFileUrl, decodeFileUrl, startSecond, desireSampleRate, desireChannel, desireBitwidth,
+                        decodeOperateInterface);
+
+//        Handler handler = new Handler(Looper.getMainLooper());
+//        handler.post(new Runnable() {
+//            @Override
+//            public void run() {
+                if (decodeResult) {
+                    decodeOperateInterface.decodeSuccess();
+                } else {
+                    decodeOperateInterface.decodeFail();
+                }
+                // 手动gc一下
+                System.gc();
+//            }
+//        });
+    }
+
+    private boolean decodeMusicFile(String musicFileUrl, String decodeFileUrl, int startSecond,
+                                    int desireSampleRate,
+                                    int desireChannel,
+                                    int desireBitwidth,
+//                                    Handler handler,
+                                    DecodeOperateInterface decodeOperateInterface) {
+        int sampleRate;
+        int channelCount;
+
+        long duration;
+
+        String mime;
+
+        MediaExtractor mediaExtractor = new MediaExtractor();
+        MediaFormat mediaFormat;
+        MediaCodec mediaCodec;
+
+        try {
+            mediaExtractor.setDataSource(musicFileUrl);
+        } catch (IOException e) {
+            LogFunction.error("设置解码音频文件路径错误", e);
+//            CustomBugReporter.reportError(DecodeEngine.class.getName(), "set decode audio file path error", e);
+            return false;
+        }
+
+        mediaFormat = mediaExtractor.getTrackFormat(0);
+        sampleRate = mediaFormat.containsKey(MediaFormat.KEY_SAMPLE_RATE) ?
+                mediaFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE) : 44100;
+        channelCount = mediaFormat.containsKey(MediaFormat.KEY_CHANNEL_COUNT) ?
+                mediaFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT) : 1;
+        duration = mediaFormat.containsKey(MediaFormat.KEY_DURATION) ? mediaFormat.getLong
+                (MediaFormat.KEY_DURATION)
+                : 0;
+        mime = mediaFormat.containsKey(MediaFormat.KEY_MIME) ? mediaFormat.getString(MediaFormat
+                .KEY_MIME) : "";
+
+        LogFunction.log("歌曲信息",
+                "Track info: mime:" + mime + " 采样率sampleRate:" + sampleRate + " channels:" +
+                        channelCount + " duration:" + duration);
+        Log.d("audio_info", "Track info: mime:" + mime + " 采样率sampleRate:" + sampleRate + " channels:" +
+                channelCount + " duration:" + duration);
+        if (CommonFunction.isEmpty(mime) || !mime.startsWith("audio/")) {
+            LogFunction.error("解码文件不是音频文件", "mime:" + mime);
+            return false;
+        }
+
+        if (mime.equals("audio/ffmpeg")) {
+            mime = "audio/mpeg";
+            mediaFormat.setString(MediaFormat.KEY_MIME, mime);
+        }
+
+        try {
+            mediaCodec = MediaCodec.createDecoderByType(mime);
+
+            mediaCodec.configure(mediaFormat, null, null, 0);
+            mediaCodec.start();
+        } catch (Exception e) {
+            LogFunction.error("解码器configure出错", e);
+//            CustomBugReporter.reportError(DecodeEngine.class.getName(), "configure decoder error", e);
+            return false;
+        }
+
+        getDecodeData(mediaExtractor,
+                mediaCodec,
+                decodeFileUrl,
+                sampleRate,
+                channelCount,
+                startSecond,
+                desireSampleRate,
+                desireChannel,
+                desireBitwidth,
+//                handler,
+                decodeOperateInterface);
+        return true;
+    }
+
+    private void getDecodeData(MediaExtractor mediaExtractor,
+                               MediaCodec mediaCodec,
+                               String decodeFileUrl,
+                               int sampleRate,
+                               int channelCount,
+                               int startSecond,
+                               int desireSampleRate,
+                               int desireChannel,
+                               int desireBitwidth,
+//                               Handler handler,
+                               final DecodeOperateInterface decodeOperateInterface) {
+        boolean decodeInputEnd = false;
+        boolean decodeOutputEnd = false;
+
+        int sampleDataSize;
+        int inputBufferIndex;
+        int outputBufferIndex;
+        int byteNumber;
+
+        long decodeNoticeTime = System.currentTimeMillis();
+        long decodeTime;
+        long presentationTimeUs = 0;
+
+        final long timeOutUs = 100;
+//        final long startMicroseconds = startSecond * 1000 * 1000;
+//        final long endMicroseconds = endSecond * 1000 * 1000;
+        final long startMicroseconds = startSecond * 1000;
+//        final long endMicroseconds = endSecond * 1000;
+
+        ByteBuffer[] inputBuffers;
+        ByteBuffer[] outputBuffers;
+
+        ByteBuffer sourceBuffer;
+        ByteBuffer targetBuffer;
+
+//        MediaFormat outputFormat = mediaCodec.getOutputFormat();
+        MediaFormat outputFormat;
+
+        MediaCodec.BufferInfo bufferInfo;
+
+//        byteNumber =
+//                (outputFormat.containsKey("bit-width") ? outputFormat.getInteger("bit-width") :
+//                        0) / 8;
+        byteNumber = 2;
+
+
+
+        inputBuffers = mediaCodec.getInputBuffers();
+        outputBuffers = mediaCodec.getOutputBuffers();
+
+        mediaExtractor.selectTrack(0);
+
+        bufferInfo = new MediaCodec.BufferInfo();
+
+        BufferedOutputStream bufferedOutputStream = FileFunction
+                .GetBufferedOutputStreamFromFile(decodeFileUrl);
+
+        while (!decodeOutputEnd) {
+            if (decodeInputEnd) {
+                break;
+            }
+
+//            decodeTime = System.currentTimeMillis();
+
+//            if (decodeTime - decodeNoticeTime > Constant.OneSecond) {
+//                final int decodeProgress =
+//                        (int) ((presentationTimeUs - startMicroseconds) * Constant
+//                                .NormalMaxProgress /
+//                                endMicroseconds);
+//
+//                if (decodeProgress > 0) {
+//                    handler.post(new Runnable() {
+//                        @Override
+//                        public void run() {
+//                            decodeOperateInterface.updateDecodeProgress(decodeProgress);
+//                        }
+//                    });
+//                }
+//
+//                decodeNoticeTime = decodeTime;
+//            }
+
+            try {
+                inputBufferIndex = mediaCodec.dequeueInputBuffer(timeOutUs);
+
+                if (inputBufferIndex >= 0) {
+                    sourceBuffer = inputBuffers[inputBufferIndex];
+
+                    sampleDataSize = mediaExtractor.readSampleData(sourceBuffer, 0);
+
+                    if (sampleDataSize < 0) {
+                        decodeInputEnd = true;
+                        sampleDataSize = 0;
+                    } else {
+                        presentationTimeUs = mediaExtractor.getSampleTime();
+                    }
+
+                    mediaCodec.queueInputBuffer(inputBufferIndex, 0, sampleDataSize,
+                            presentationTimeUs,
+                            decodeInputEnd ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0);
+
+                    if (!decodeInputEnd) {
+                        mediaExtractor.advance();
+                    }
+                } else {
+                    LogFunction.error("inputBufferIndex", "" + inputBufferIndex);
+                }
+
+                // decode to PCM and push it to the AudioTrack player
+                outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, timeOutUs);
+
+                if (outputBufferIndex < 0) {
+                    switch (outputBufferIndex) {
+                        case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
+                            outputBuffers = mediaCodec.getOutputBuffers();
+                            LogFunction.error("MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED",
+                                    "[AudioDecoder]output buffers have changed.");
+                            break;
+                        case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
+                            outputFormat = mediaCodec.getOutputFormat();
+
+                            sampleRate = outputFormat.containsKey(MediaFormat.KEY_SAMPLE_RATE) ?
+                                    outputFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE) :
+                                    sampleRate;
+                            channelCount = outputFormat.containsKey(MediaFormat.KEY_CHANNEL_COUNT) ?
+                                    outputFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT) :
+                                    channelCount;
+                            byteNumber = (outputFormat.containsKey("bit-width") ? outputFormat
+                                    .getInteger
+                                            ("bit-width") : 16) / 8;
+
+                            LogFunction.error("MediaCodec.INFO_OUTPUT_FORMAT_CHANGED",
+                                    "[AudioDecoder]output format has changed to " +
+                                            mediaCodec.getOutputFormat());
+                            break;
+                        default:
+                            LogFunction.error("error",
+                                    "[AudioDecoder] dequeueOutputBuffer returned " +
+                                            outputBufferIndex);
+                            break;
+                    }
+                    continue;
+                }
+
+                targetBuffer = outputBuffers[outputBufferIndex];
+
+                byte[] sourceByteArray = new byte[bufferInfo.size];
+
+                targetBuffer.get(sourceByteArray);
+                targetBuffer.clear();
+
+                mediaCodec.releaseOutputBuffer(outputBufferIndex, false);
+
+                if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
+                    decodeOutputEnd = true;
+                }
+
+                if (sourceByteArray.length > 0 && bufferedOutputStream != null) {
+                    if (presentationTimeUs < startMicroseconds) {
+                        continue;
+                    }
+
+//                    byte[] convertByteNumberByteArray = ConvertByteNumber(byteNumber, Constant
+//                                    .RecordByteNumber,
+//                            sourceByteArray);
+                        byte[] convertByteNumberByteArray = ConvertByteNumber(byteNumber, desireBitwidth,
+                            sourceByteArray);
+
+//                    byte[] resultByteArray =
+//                            ConvertChannelNumber(channelCount, Constant.RecordChannelNumber,
+//                                    Constant.RecordByteNumber,
+//                                    convertByteNumberByteArray);
+                    byte[] resultByteArray =
+                            ConvertChannelNumber(channelCount, desireChannel,
+                                    desireBitwidth,
+                                    convertByteNumberByteArray);
+                    Log.d("tetetetet","finished");
+                    try {
+                        bufferedOutputStream.write(resultByteArray);
+                    } catch (Exception e) {
+                        LogFunction.error("输出解压音频数据异常", e);
+//                        CustomBugReporter.reportError(DecodeEngine.class.getName(), "output decoded audio data exception", e);
+                    }
+                }
+
+//                if (presentationTimeUs > endMicroseconds) {
+//                    break;
+//                }
+            } catch (Exception e) {
+                LogFunction.error("getDecodeData异常", e);
+//                CustomBugReporter.reportError(TAG, "getDecodedData exception", e);
+            }
+        }
+
+        if (bufferedOutputStream != null) {
+            try {
+                bufferedOutputStream.close();
+            } catch (IOException e) {
+                LogFunction.error("关闭bufferedOutputStream异常", e);
+//                CustomBugReporter.reportError(TAG, "close bufferedOutputStream exception 1",e);
+            }
+        }
+
+        if (sampleRate != desireSampleRate) {
+            Log.d("tetetetet1","finished");
+            Resample(sampleRate, desireSampleRate, byteNumber, desireBitwidth,decodeFileUrl);
+//            Resample(sampleRate, desireSampleRate, desireChannel, decodeFileUrl);
+            Log.d("tetetetet2","finished");
+        }
+
+        if (mediaCodec != null) {
+            mediaCodec.stop();
+            mediaCodec.release();
+        }
+
+        if (mediaExtractor != null) {
+            mediaExtractor.release();
+        }
+    }
+
+    private static void Resample(int srcSampleRate, int desSampleRate,int srcByteNumber, int desByteNumber,String decodeFileUrl) {
+        String newDecodeFileUrl = decodeFileUrl + "new";
+
+        try {
+            FileInputStream fileInputStream =
+                    new FileInputStream(new File(decodeFileUrl));
+            FileOutputStream fileOutputStream =
+                    new FileOutputStream(new File(newDecodeFileUrl));
+
+            new SSRC(fileInputStream, fileOutputStream, srcSampleRate, desSampleRate,
+                    srcByteNumber, desByteNumber, 1, Integer.MAX_VALUE,
+                    0, 0, true);
+            fileInputStream.close();
+            fileOutputStream.close();
+
+            FileFunction.RenameFile(newDecodeFileUrl, decodeFileUrl);
+        } catch (IOException e) {
+            LogFunction.error("关闭bufferedOutputStream异常", e);
+//            CustomBugReporter.reportError(TAG, "close bufferedOoutputStream exception 2", e);
+        }
+    }
+
+
+
+    private static byte[] ConvertByteNumber(int sourceByteNumber, int outputByteNumber, byte[]
+            sourceByteArray) {
+        Log.d("audio_info","sourceByteNumber:" + sourceByteNumber + "   outputByteNumber:" + outputByteNumber);
+        if (sourceByteNumber == outputByteNumber) {
+            return sourceByteArray;
+        }
+
+        int sourceByteArrayLength = sourceByteArray.length;
+
+        byte[] byteArray;
+
+        switch (sourceByteNumber) {
+            case 1:
+                switch (outputByteNumber) {
+                    case 2:
+                        byteArray = new byte[sourceByteArrayLength * 2];
+
+                        byte resultByte[];
+
+                        for (int index = 0; index < sourceByteArrayLength; index += 1) {
+                            resultByte = CommonFunction.GetBytes((short) (sourceByteArray[index]
+                                    * 256), Variable
+                                    .isBigEnding);
+
+                            byteArray[2 * index] = resultByte[0];
+                            byteArray[2 * index + 1] = resultByte[1];
+                        }
+
+                        return byteArray;
+                }
+                break;
+            case 2:
+                switch (outputByteNumber) {
+                    case 1:
+                        int outputByteArrayLength = sourceByteArrayLength / 2;
+
+                        byteArray = new byte[outputByteArrayLength];
+
+                        for (int index = 0; index < outputByteArrayLength; index += 1) {
+                            byteArray[index] = (byte) (CommonFunction.GetShort(sourceByteArray[2
+                                            * index],
+                                    sourceByteArray[2 * index + 1], Variable.isBigEnding) / 256);
+                        }
+
+                        return byteArray;
+                }
+                break;
+        }
+
+        return sourceByteArray;
+    }
+
+    public static byte[] ConvertChannelNumber(int sourceChannelCount, int outputChannelCount,
+                                               int byteNumber,
+                                               byte[] sourceByteArray) {
+        Log.d("audio_info","srcChannel:" + sourceChannelCount + "   desChannel:" + outputChannelCount);
+        if (sourceChannelCount == outputChannelCount) {
+            return sourceByteArray;
+        }
+
+        switch (byteNumber) {
+            case 1:
+            case 2:
+                break;
+            default:
+                return sourceByteArray;
+        }
+
+        int sourceByteArrayLength = sourceByteArray.length;
+
+        byte[] byteArray;
+
+        switch (sourceChannelCount) {
+            case 1:
+                switch (outputChannelCount) {
+                    case 2:
+                        byteArray = new byte[sourceByteArrayLength * 2];
+
+                        byte firstByte;
+                        byte secondByte;
+
+                        switch (byteNumber) {
+                            case 1:
+                                for (int index = 0; index < sourceByteArrayLength; index += 1) {
+                                    firstByte = sourceByteArray[index];
+
+                                    byteArray[2 * index] = firstByte;
+                                    byteArray[2 * index + 1] = firstByte;
+                                }
+                                break;
+                            case 2:
+                                for (int index = 0; index < sourceByteArrayLength; index += 2) {
+                                    firstByte = sourceByteArray[index];
+                                    secondByte = sourceByteArray[index + 1];
+
+                                    byteArray[2 * index] = firstByte;
+                                    byteArray[2 * index + 1] = secondByte;
+                                    byteArray[2 * index + 2] = firstByte;
+                                    byteArray[2 * index + 3] = secondByte;
+                                }
+                                break;
+                        }
+
+                        return byteArray;
+                }
+                break;
+            case 2:
+                switch (outputChannelCount) {
+                    case 1:
+                        int outputByteArrayLength = sourceByteArrayLength / 2;
+
+                        byteArray = new byte[outputByteArrayLength];
+
+                        switch (byteNumber) {
+                            case 1:
+                                for (int index = 0; index < outputByteArrayLength; index += 2) {
+                                    short averageNumber =
+                                            (short) ((short) sourceByteArray[2 * index] + (short)
+                                                    sourceByteArray[2 *
+                                                            index + 1]);
+                                    byteArray[index] = (byte) (averageNumber >> 1);
+                                }
+                                break;
+                            case 2:
+                                for (int index = 0; index < outputByteArrayLength; index += 2) {
+                                    byte resultByte[] = CommonFunction.AverageShortByteArray
+                                            (sourceByteArray[2 * index],
+                                                    sourceByteArray[2 * index + 1],
+                                                    sourceByteArray[2 *
+                                                            index + 2],
+                                                    sourceByteArray[2 * index + 3], Variable
+                                                            .isBigEnding);
+
+                                    byteArray[index] = resultByte[0];
+                                    byteArray[index + 1] = resultByte[1];
+                                }
+                                break;
+                        }
+
+                        return byteArray;
+                }
+                break;
+        }
+
+        return sourceByteArray;
+    }
+}

+ 12 - 0
android/src/main/kotlin/cn/i2edu/speech_plugin/audioUtils/audiotransfer/DecodeOperateInterface.java

@@ -0,0 +1,12 @@
+package cn.i2edu.speech_plugin.audioUtils.audiotransfer;
+
+/**
+ * Created by 郑童宇 on 2016/05/10.
+ */
+public interface DecodeOperateInterface {
+    void updateDecodeProgress(int decodeProgress);
+
+    void decodeSuccess();
+
+    void decodeFail();
+}

+ 202 - 0
android/src/main/kotlin/cn/i2edu/speech_plugin/audioUtils/audiotransfer/FileFunction.java

@@ -0,0 +1,202 @@
+package cn.i2edu.speech_plugin.audioUtils.audiotransfer;
+
+import android.app.Application;
+import android.os.Environment;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+/**
+ * Created by zhengtongyu on 16/5/23.
+ */
+@SuppressWarnings("ResultOfMethodCallIgnored")
+public class FileFunction {
+    public static boolean IsExitsSdcard() {
+        return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
+    }
+
+    @SuppressWarnings("BooleanMethodIsAlwaysInverted")
+    public static boolean IsFileExists(String path) {
+        if (CommonFunction.isEmpty(path)) {
+            return false;
+        }
+
+        return new File(path).exists();
+    }
+
+    private static void CreateDirectory(String path) {
+        File dir = new File(path);
+
+        if (!dir.exists()) {
+            dir.mkdirs();
+        }
+    }
+
+    public static void InitStorage(Application application) {
+        if (!FileFunction.IsExitsSdcard()) {
+            Variable.StorageDirectoryPath = application.getFilesDir().getAbsolutePath();
+        } else {
+            Variable.StorageDirectoryPath =
+                    Environment.getExternalStorageDirectory().getAbsolutePath() + "/ComposeAudio/";
+        }
+
+        Variable.ErrorFilePath = Variable.StorageDirectoryPath + "error.txt";
+
+        CreateDirectory(Variable.StorageDirectoryPath);
+    }
+
+    public static void SaveFile(String url, String content) {
+        SaveFile(url, content, true, false);
+    }
+
+    public static void SaveFile(String url, String content, boolean cover, boolean append) {
+        FileOutputStream out = null;
+        File file = new File(url);
+
+        try {
+            if (file.exists()) {
+                if (cover) {
+                    file.delete();
+                    file.createNewFile();
+                }
+            } else {
+                file.createNewFile();
+            }
+
+            out = new FileOutputStream(file, append);
+            out.write(content.getBytes());
+            out.close();
+            LogFunction.log("保存文件" + url, "保存文件成功");
+        } catch (Exception e) {
+            LogFunction.error("保存文件" + url, e);
+
+            if (out != null) {
+                try {
+                    out.close();
+                } catch (IOException e1) {
+                    e1.printStackTrace();
+                }
+            }
+        }
+    }
+
+    public static void DeleteFile(String path) {
+        if (CommonFunction.notEmpty(path)) {
+            File file = new File(path);
+
+            if (file.exists()) {
+                try {
+                    file.delete();
+                } catch (Exception e) {
+                    LogFunction.error("删除本地文件失败", e);
+                }
+            }
+        }
+    }
+
+    public static void CopyFile(String oldPath, String newPath) {
+        try {
+            int byteRead;
+
+            File oldFile = new File(oldPath);
+            File newFile = new File(newPath);
+
+            if (oldFile.exists()) { //文件存在时
+                if (newFile.exists()) {
+                    newFile.delete();
+                }
+
+                newFile.createNewFile();
+
+                FileInputStream inputStream = new FileInputStream(oldPath); //读入原文件
+                FileOutputStream outputStream = new FileOutputStream(newPath);
+                byte[] buffer = new byte[1024];
+
+                while ((byteRead = inputStream.read(buffer)) != -1) {
+                    outputStream.write(buffer, 0, byteRead);
+                }
+
+                inputStream.close();
+            }
+        } catch (Exception e) {
+            LogFunction.error("复制单个文件操作出错", e);
+        }
+    }
+
+    public static FileInputStream GetFileInputStreamFromFile(String fileUrl) {
+        FileInputStream fileInputStream = null;
+
+        try {
+            File file = new File(fileUrl);
+
+            fileInputStream = new FileInputStream(file);
+        } catch (Exception e) {
+            LogFunction.error("GetBufferedInputStreamFromFile异常", e);
+        }
+
+        return fileInputStream;
+    }
+
+    public static FileOutputStream GetFileOutputStreamFromFile(String fileUrl) {
+        FileOutputStream bufferedOutputStream = null;
+
+        try {
+            File file = new File(fileUrl);
+
+            if (file.exists()) {
+                file.delete();
+            }
+
+            file.createNewFile();
+
+            bufferedOutputStream = new FileOutputStream(file);
+        } catch (Exception e) {
+            LogFunction.error("GetFileOutputStreamFromFile异常", e);
+        }
+
+        return bufferedOutputStream;
+    }
+
+    public static BufferedOutputStream GetBufferedOutputStreamFromFile(String fileUrl) {
+        BufferedOutputStream bufferedOutputStream = null;
+
+        try {
+            File file = new File(fileUrl);
+
+            if (file.exists()) {
+                file.delete();
+            }
+
+            file.createNewFile();
+
+            bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(file));
+        } catch (Exception e) {
+            LogFunction.error("GetBufferedOutputStreamFromFile异常", e);
+        }
+
+        return bufferedOutputStream;
+    }
+
+    public static void RenameFile(String oldPath, String newPath) {
+        if (CommonFunction.notEmpty(oldPath) && CommonFunction.notEmpty(newPath)) {
+            File newFile = new File(newPath);
+
+            if (newFile.exists()) {
+                newFile.delete();
+            }
+
+            File oldFile = new File(oldPath);
+
+            if (oldFile.exists()) {
+                try {
+                    oldFile.renameTo(new File(newPath));
+                } catch (Exception e) {
+                    LogFunction.error("删除本地文件失败", e);
+                }
+            }
+        }
+    }
+}

+ 127 - 0
android/src/main/kotlin/cn/i2edu/speech_plugin/audioUtils/audiotransfer/LogFunction.java

@@ -0,0 +1,127 @@
+package cn.i2edu.speech_plugin.audioUtils.audiotransfer;
+
+import android.util.Log;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+
+/**
+ * Created by zhengtongyu on 16/5/23.
+ */
+@SuppressWarnings("ResultOfMethodCallIgnored")
+public class LogFunction {
+    private static final String tag = "AppLog";
+
+    private static BufferedWriter errorOutputStream;
+
+    public static synchronized void UpdateErrorOutputStream() {
+        try {
+            Log.d("刷新error文件输出流", "刷新开始");
+
+            File file = new File(Variable.ErrorFilePath);
+
+            if (!file.exists()) {
+                file.createNewFile();
+            }
+
+            errorOutputStream = new BufferedWriter(
+                    new OutputStreamWriter(new FileOutputStream(Variable.ErrorFilePath, true)));
+        } catch (Exception e) {
+            Log.e("刷新error日志文件输出流出错", e.toString());
+        }
+    }
+
+    public static synchronized void FinishErrorOutputStream() {
+        try {
+            errorOutputStream.close();
+        } catch (Exception e) {
+            Log.e("关闭error文件出错", e.toString());
+        }
+    }
+
+    public static String getStackTrace(Exception e) {
+        StringWriter writer = new StringWriter();
+        e.printStackTrace(new PrintWriter(writer));
+        return writer.toString();
+    }
+
+    private static String getStackInformation(String content) {
+        StringBuilder buffer = new StringBuilder(content == null ? "" : content);
+        String className;
+        String methodName;
+        int lineNumber;
+
+        try {
+            final int beginStackIndex = 2;
+            final int outputStackLength = 2;
+            int endStackIndex = beginStackIndex + outputStackLength;
+            StackTraceElement[] element = new Throwable().getStackTrace();
+
+            int totalStackLength = element.length;
+
+            if (endStackIndex > totalStackLength) {
+                endStackIndex = totalStackLength;
+            }
+
+            for (int index = beginStackIndex; index < endStackIndex; index++) {
+                className = element[index].getFileName();
+                methodName = element[index].getMethodName();
+                lineNumber = element[index].getLineNumber();
+                buffer.append("\n").append(" ").append(methodName).append("(").append(className)
+                        .append(":").append(lineNumber).append(")");
+            }
+        } catch (Exception e) {
+            Log.e(tag + ":获取stack调用信息异常", e.toString());
+        }
+
+        return buffer.toString();
+    }
+
+    /*
+     * 打印日志数据
+	 */
+    public static void log(String title, String content) {
+    }
+
+    /*
+     * 打印错误日志数据,同时将数据写到外文件
+     */
+    public static void error(String title, String content) {
+
+        try {
+            if (errorOutputStream == null || !FileFunction.IsFileExists(Variable.ErrorFilePath)) {
+                UpdateErrorOutputStream();
+            }
+
+            errorOutputStream
+                    .write(CommonFunction.GetDate() + "   " + title + ":" + content + "\r\n");
+            errorOutputStream.flush();
+        } catch (Exception e) {
+            Log.e(tag + ":打印error数据异常", e.toString());
+        }
+    }
+
+    /*
+     * 为不使getStackInformation少输出一层,故而放弃使用error(title,e.toString()));
+     */
+    public static void error(String title, Exception exception) {
+
+        try {
+            if (errorOutputStream == null || !FileFunction.IsFileExists(Variable.ErrorFilePath)) {
+                UpdateErrorOutputStream();
+            }
+
+            errorOutputStream
+                    .write(CommonFunction.GetDate() + "   " + title + ":" + exception.toString() +
+                            "\r\n");
+            errorOutputStream.flush();
+        } catch (Exception e) {
+            Log.e(tag + ":打印error数据异常", e.toString());
+        }
+    }
+}

+ 8 - 0
android/src/main/kotlin/cn/i2edu/speech_plugin/audioUtils/audiotransfer/Variable.java

@@ -0,0 +1,8 @@
+package cn.i2edu.speech_plugin.audioUtils.audiotransfer;
+
+class Variable {
+    public static final boolean isBigEnding = false;
+
+    public static String StorageDirectoryPath;
+    public static String ErrorFilePath;
+}

+ 2562 - 0
android/src/main/kotlin/cn/i2edu/speech_plugin/audioUtils/audiotransfer/vavi/sound/pcm/resampling/ssrc/SSRC.java

@@ -0,0 +1,2562 @@
+/*
+ * This program(except FFT and Bessel function part) is distributed under
+ * LGPL. See LGPL.txt for details. But, if you make a new program with derived
+ * code from this program,I strongly wish that my name and derived code are
+ * indicated explicitly.
+ */
+
+package cn.i2edu.speech_plugin.audioUtils.audiotransfer.vavi.sound.pcm.resampling.ssrc;
+
+
+import android.annotation.SuppressLint;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.channels.FileChannel;
+import java.util.Random;
+
+import cn.i2edu.speech_plugin.audioUtils.audiotransfer.LogFunction;
+import cn.i2edu.speech_plugin.audioUtils.audiotransfer.vavi.util.I0Bessel;
+import cn.i2edu.speech_plugin.audioUtils.audiotransfer.vavi.util.SplitRadixFft;
+
+
+/**
+ * Shibatch Sampling Rate Converter.
+ *
+ * @author <a href="shibatch@users.sourceforge.net">Naoki Shibata</a>
+ * @author <a href="mailto:vavivavi@yahoo.co.jp">Naohide Sano</a> (nsano)
+ * @author Maksim Khadkevich (a couple of minor changes)
+ * @version 0.00 060127 nsano port to java version <br>
+ */
+@SuppressWarnings({"SuspiciousNameCombination", "ConstantConditions", "UnnecessaryLocalVariable", "RedundantStringFormatCall", "UnusedAssignment", "StatementWithEmptyBody", "PointlessArithmeticExpression", "DanglingJavadoc", "JavaDoc", "ResultOfMethodCallIgnored", "PointlessBitwiseExpression"})
+public class SSRC {
+
+    /** */
+    private final ByteOrder byteOrder = ByteOrder.LITTLE_ENDIAN;
+
+    /** */
+    private final SplitRadixFft fft = new SplitRadixFft();
+
+    /** */
+    private static final String VERSION = "1.30";
+
+    /** */
+    private double AA = 170;
+
+    /** */
+    private double DF = 100;
+
+    /** */
+    private int FFTFIRLEN = 65536;
+
+    /** */
+    //  private static final int M = 15;
+
+    /** */
+    private static final int RANDBUFLEN = 65536;
+
+    /** */
+    private int RINT(double x) {
+        return ((x) >= 0 ? ((int) ((x) + 0.5)) : ((int) ((x) - 0.5)));
+    }
+
+    /** */
+    private static final int scoeffreq[] = {0, 48000, 44100, 37800, 32000, 22050, 48000, 44100};
+
+    /** */
+    private static final int scoeflen[] = {1, 16, 20, 16, 16, 15, 16, 15};
+
+    /** */
+    private static final int samp[] = {8, 18, 27, 8, 8, 8, 10, 9};
+
+    /** */
+    private static final double[][] shapercoefs = {{-1}, // triangular dither
+
+            {-2.8720729351043701172, 5.0413231849670410156, -6.2442994117736816406,
+                    5.8483986854553222656, -3.7067542076110839844, 1.0495119094848632812,
+                    1.1830236911773681641, -2.1126792430877685547, 1.9094531536102294922,
+                    -0.99913084506988525391, 0.17090806365013122559, 0.32615602016448974609,
+                    -0.39127644896507263184, 0.26876461505889892578, -0.097676105797290802002,
+                    0.023473845794796943665,}, // 48k, N=16, amp=18
+
+            {-2.6773197650909423828, 4.8308925628662109375, -6.570110321044921875,
+                    7.4572014808654785156, -6.7263274192810058594, 4.8481650352478027344,
+                    -2.0412089824676513672, -0.7006359100341796875, 2.9537565708160400391,
+                    -4.0800385475158691406, 4.1845216751098632812, -3.3311812877655029297,
+                    2.1179926395416259766, -0.879302978515625, 0.031759146600961685181,
+                    0.42382788658142089844, -0.47882103919982910156, 0.35490813851356506348,
+                    -0.17496839165687561035, 0.060908168554306030273,}, // 44.1k, N=20, amp=27
+
+            {-1.6335992813110351562, 2.2615492343902587891, -2.4077029228210449219,
+                    2.6341717243194580078, -2.1440362930297851562, 1.8153258562088012695,
+                    -1.0816224813461303711, 0.70302653312683105469, -0.15991993248462677002,
+                    -0.041549518704414367676, 0.29416576027870178223, -0.2518316805362701416,
+                    0.27766478061676025391, -0.15785403549671173096, 0.10165894031524658203,
+                    -0.016833892092108726501,}, // 37.8k, N=16
+
+            {-0.82901298999786376953, 0.98922657966613769531, -0.59825712442398071289,
+                    1.0028809309005737305, -0.59938216209411621094, 0.79502451419830322266,
+                    -0.42723315954208374023, 0.54492527246475219727, -0.30792605876922607422,
+                    0.36871799826622009277, -0.18792048096656799316, 0.2261127084493637085,
+                    -0.10573341697454452515, 0.11435490846633911133, -0.038800679147243499756,
+                    0.040842197835445404053,}, // 32k, N=16
+
+            {-0.065229974687099456787, 0.54981261491775512695, 0.40278548002243041992,
+                    0.31783768534660339355, 0.28201797604560852051, 0.16985194385051727295,
+                    0.15433363616466522217, 0.12507140636444091797, 0.08903945237398147583,
+                    0.064410120248794555664, 0.047146003693342208862, 0.032805237919092178345,
+                    0.028495194390416145325, 0.011695005930960178375, 0.011831838637590408325,},
+            // 22.05k, N=15
+
+            {-2.3925774097442626953, 3.4350297451019287109, -3.1853709220886230469,
+                    1.8117271661758422852, 0.20124770700931549072, -1.4759907722473144531,
+                    1.7210904359817504883, -0.97746700048446655273, 0.13790138065814971924,
+                    0.38185903429985046387, -0.27421241998672485352, -0.066584214568138122559,
+                    0.35223302245140075684, -0.37672343850135803223, 0.23964276909828186035,
+                    -0.068674825131893157959,}, // 48k, N=16, amp=10
+
+            {-2.0833916664123535156, 3.0418450832366943359, -3.2047898769378662109,
+                    2.7571926116943359375, -1.4978630542755126953, 0.3427594602108001709,
+                    0.71733748912811279297, -1.0737057924270629883, 1.0225815773010253906,
+                    -0.56649994850158691406, 0.20968692004680633545, 0.065378531813621520996,
+                    -0.10322438180446624756, 0.067442022264003753662, 0.00495197344571352005,},
+            // 44.1k, N=15, amp=9
+    };
+
+    /** */
+    private double[][] shapebuf;
+
+    /** */
+    private int shaper_type, shaper_len, shaper_clipmin, shaper_clipmax;
+
+    /** */
+    private double[] randbuf;
+
+    /** */
+    private int randptr;
+
+    /** */
+    private boolean quiet = false;
+
+    /** */
+    private int lastshowed2;
+
+    /** */
+    private long starttime, lastshowed;
+
+    /** */
+    private static final int POOLSIZE = 97;
+
+    /** */
+    public int init_shaper(int freq, int nch, int min, int max, int dtype, int pdf,
+                           double noiseamp) {
+        int i;
+        int[] pool = new int[POOLSIZE];
+
+        for (i = 1; i < 6; i++) {
+            if (freq == scoeffreq[i]) {
+                break;
+            }
+        }
+        if ((dtype == 3 || dtype == 4) && i == 6) {
+            System.err
+                    .printf("Warning: ATH based noise shaping for destination frequency %dHz is not available, using triangular dither\n",
+                            freq);
+        }
+        if (dtype == 2 || i == 6) {
+            i = 0;
+        }
+        if (dtype == 4 && (i == 1 || i == 2)) {
+            i += 5;
+        }
+
+        shaper_type = i;
+
+        shapebuf = new double[nch][];
+        shaper_len = scoeflen[shaper_type];
+
+        for (i = 0; i < nch; i++) {
+            shapebuf[i] = new double[shaper_len];
+        }
+
+        shaper_clipmin = min;
+        shaper_clipmax = max;
+
+        randbuf = new double[RANDBUFLEN];
+
+        Random random = new Random(System.currentTimeMillis());
+        for (i = 0; i < POOLSIZE; i++) {
+            pool[i] = random.nextInt();
+        }
+
+        switch (pdf) {
+            case 0: // rectangular
+                for (i = 0; i < RANDBUFLEN; i++) {
+                    int r, p;
+
+                    p = random.nextInt() % POOLSIZE;
+                    r = pool[p];
+                    pool[p] = random.nextInt();
+                    randbuf[i] = noiseamp * (((double) r) / Integer.MAX_VALUE - 0.5);
+                }
+                break;
+
+            case 1: // triangular
+                for (i = 0; i < RANDBUFLEN; i++) {
+                    int r1, r2, p;
+
+                    p = random.nextInt() % POOLSIZE;
+                    r1 = pool[p];
+                    pool[p] = random.nextInt();
+                    p = random.nextInt() % POOLSIZE;
+                    r2 = pool[p];
+                    pool[p] = random.nextInt();
+                    randbuf[i] = noiseamp * ((((double) r1) / Integer.MAX_VALUE) -
+                            (((double) r2) / Integer.MAX_VALUE));
+                }
+                break;
+
+            case 2: // gaussian
+            {
+                int sw = 0;
+                double t = 0, u = 0;
+
+                for (i = 0; i < RANDBUFLEN; i++) {
+                    double r;
+                    int p;
+
+                    if (sw == 0) {
+                        sw = 1;
+
+                        p = random.nextInt() % POOLSIZE;
+                        r = ((double) pool[p]) / Integer.MAX_VALUE;
+                        pool[p] = random.nextInt();
+                        if (r == 1.0) {
+                            r = 0.0;
+                        }
+
+                        t = Math.sqrt(-2 * Math.log(1 - r));
+
+                        p = random.nextInt() % POOLSIZE;
+                        r = ((double) pool[p]) / Integer.MAX_VALUE;
+                        pool[p] = random.nextInt();
+
+                        u = 2 * Math.PI * r;
+
+                        randbuf[i] = noiseamp * t * Math.cos(u);
+                    } else {
+                        sw = 0;
+
+                        randbuf[i] = noiseamp * t * Math.sin(u);
+                    }
+                }
+            }
+            break;
+        }
+
+        randptr = 0;
+
+        if (dtype == 0 || dtype == 1) {
+            return 1;
+        }
+        return samp[shaper_type];
+    }
+
+    /** */
+    public int do_shaping(double s, double[] peak, int dtype, int ch) {
+        double u, h;
+        int i;
+
+        if (dtype == 1) {
+            s += randbuf[randptr++ & (RANDBUFLEN - 1)];
+
+            if (s < shaper_clipmin) {
+                double d = s / shaper_clipmin;
+                peak[0] = peak[0] < d ? d : peak[0];
+                s = shaper_clipmin;
+            }
+            if (s > shaper_clipmax) {
+                double d = s / shaper_clipmax;
+                peak[0] = peak[0] < d ? d : peak[0];
+                s = shaper_clipmax;
+            }
+
+            return RINT(s);
+        }
+
+        h = 0;
+        for (i = 0; i < shaper_len; i++) {
+            h += shapercoefs[shaper_type][i] * shapebuf[ch][i];
+        }
+        s += h;
+        u = s;
+        s += randbuf[randptr++ & (RANDBUFLEN - 1)];
+
+        for (i = shaper_len - 2; i >= 0; i--) {
+            shapebuf[ch][i + 1] = shapebuf[ch][i];
+        }
+
+        if (s < shaper_clipmin) {
+            double d = s / shaper_clipmin;
+            peak[0] = peak[0] < d ? d : peak[0];
+            s = shaper_clipmin;
+            shapebuf[ch][0] = s - u;
+
+            if (shapebuf[ch][0] > 1) {
+                shapebuf[ch][0] = 1;
+            }
+            if (shapebuf[ch][0] < -1) {
+                shapebuf[ch][0] = -1;
+            }
+        } else if (s > shaper_clipmax) {
+            double d = s / shaper_clipmax;
+            peak[0] = peak[0] < d ? d : peak[0];
+            s = shaper_clipmax;
+            shapebuf[ch][0] = s - u;
+
+            if (shapebuf[ch][0] > 1) {
+                shapebuf[ch][0] = 1;
+            }
+            if (shapebuf[ch][0] < -1) {
+                shapebuf[ch][0] = -1;
+            }
+        } else {
+            s = RINT(s);
+            shapebuf[ch][0] = s - u;
+        }
+
+        return (int) s;
+    }
+
+    /** */
+    private void quit_shaper(int nch) {
+    }
+
+    /** */
+    private double alpha(double a) {
+        if (a <= 21) {
+            return 0;
+        }
+        if (a <= 50) {
+            return 0.5842 * Math.pow(a - 21, 0.4) + 0.07886 * (a - 21);
+        }
+        return 0.1102 * (a - 8.7);
+    }
+
+    /** */
+    private double win(double n, int len, double alp, double iza) {
+        return I0Bessel
+                .value(alp * Math.sqrt(1 - 4 * n * n / (((double) len - 1) * ((double) len - 1)))) /
+                iza;
+    }
+
+    /** */
+    private double sinc(double x) {
+        return x == 0 ? 1 : Math.sin(x) / x;
+    }
+
+    /** */
+    private double hn_lpf(int n, double lpf, double fs) {
+        double t = 1 / fs;
+        double omega = 2 * Math.PI * lpf;
+        return 2 * lpf * t * sinc(n * omega * t);
+    }
+
+    /** */
+    private void usage() {
+        System.err.printf("http://shibatch.sourceforge.net/\n\n");
+        System.err.printf("usage: ssrc [<options>] <source wav file> <destination wav file>\n");
+        System.err.printf("options : --rate <sampling rate>     output sample rate\n");
+        System.err.printf("          --att <attenuation(dB)>    attenuate signal\n");
+        System.err.printf("          --bits <number of bits>    output quantization bit length\n");
+        System.err.printf("          --tmpfile <file name>      specify temporal file\n");
+        System.err
+                .printf("          --twopass                  two pass processing to avoid clipping\n");
+        System.err.printf("          --normalize                normalize the wave file\n");
+        System.err.printf("          --quiet                    nothing displayed except error\n");
+        System.err.printf("          --dither [<type>]          dithering\n");
+        System.err.printf("                                       0 : no dither\n");
+        System.err.printf("                                       1 : no noise shaping\n");
+        System.err.printf("                                       2 : triangular spectral shape\n");
+        System.err.printf("                                       3 : ATH based noise shaping\n");
+        System.err
+                .printf("                                       4 : less dither amplitude than type 3\n");
+        System.err.printf("          --pdf <type> [<amp>]       select p.d.f. of noise\n");
+        System.err.printf("                                       0 : rectangular\n");
+        System.err.printf("                                       1 : triangular\n");
+        System.err.printf("                                       2 : Gaussian\n");
+        System.err.printf("          --profile <type>           specify profile\n");
+        System.err
+                .printf("                                       standard : the default quality\n");
+        System.err
+                .printf("                                       fast     : fast, not so bad quality\n");
+    }
+
+    /** */
+    private void fmterr(int x) {
+        throw new IllegalStateException("unknown error " + x);
+    }
+
+    /** */
+    private void setstarttime() {
+        starttime = System.currentTimeMillis();
+        lastshowed = 0;
+        lastshowed2 = -1;
+    }
+
+    /** */
+    private void showprogress(double p) {
+        int eta, pc;
+        long t;
+        if (quiet) {
+            return;
+        }
+
+        t = System.currentTimeMillis() - starttime;
+        if (p == 0) {
+            eta = 0;
+        } else {
+            eta = (int) (t * (1 - p) / p);
+        }
+
+        pc = (int) (p * 100);
+
+        if (pc != lastshowed2 || t != lastshowed) {
+            System.err.printf(" %3d%% processed", pc);
+            lastshowed2 = pc;
+        }
+        if (t != lastshowed) {
+            System.err.printf(", ETA =%4dmsec", eta);
+            lastshowed = t;
+        }
+        System.err.printf("\r");
+        System.err.flush();
+    }
+
+    /** */
+    private int gcd(int x, int y) {
+        int t;
+
+        while (y != 0) {
+            t = x % y;
+            x = y;
+            y = t;
+        }
+        return x;
+    }
+
+    /**
+     * @param fpi
+     * @param fpo
+     * @param nch
+     * @param bps
+     * @param dbps     sizeof(double)?
+     * @param sfrq
+     * @param dfrq
+     * @param gain
+     * @param chanklen
+     * @param twopass
+     * @param dither
+     * @return
+     * @throws IOException
+     */
+    @SuppressLint("Assert")
+    public double upsample(InputStream fpi, OutputStream fpo, int nch, int bps, int dbps, int sfrq,
+                           int dfrq, double gain, int chanklen, boolean twopass, int dither)
+            throws IOException {
+        int frqgcd, osf = 0, fs1, fs2;
+        double[][] stage1;
+        double[] stage2;
+        int n1, n1x, n1y, n2, n2b;
+        int filter2len;
+        int[] f1order, f1inc;
+        int[] fft_ip = null;
+        double[] fft_w = null;
+        ByteBuffer rawinbuf, rawoutbuf;
+        double[] inbuf, outbuf;
+        double[][] buf1, buf2;
+        double[] peak = new double[]{0};
+        int spcount = 0;
+        int i, j;
+
+        //        System.err.println("upsample");
+
+        filter2len = FFTFIRLEN; // stage 2 filter length
+
+        // Make stage 1 filter
+
+        {
+            double aa = AA; // stop band attenuation(dB)
+            double lpf, d, df, alp, iza;
+            //          double delta;
+            double guard = 2;
+
+            frqgcd = gcd(sfrq, dfrq);
+
+            fs1 = sfrq / frqgcd * dfrq;
+
+            if (fs1 / dfrq == 1) {
+                osf = 1;
+            } else if (fs1 / dfrq % 2 == 0) {
+                osf = 2;
+            } else if (fs1 / dfrq % 3 == 0) {
+                osf = 3;
+            } else {
+                throw new IllegalArgumentException(String.format(
+                        "Resampling from %dHz to %dHz is not supported.\n" +
+                                "%d/gcd(%d,%d)=%d must be divided by 2 or 3.\n", sfrq, dfrq, sfrq,
+                        sfrq, dfrq, fs1 / dfrq));
+            }
+
+            df = (dfrq * osf / 2 - sfrq / 2) * 2 / guard;
+            lpf = sfrq / 2 + (dfrq * osf / 2 - sfrq / 2) / guard;
+
+            //          delta = Math.pow(10, -aa / 20);
+            if (aa <= 21) {
+                d = 0.9222;
+            } else {
+                d = (aa - 7.95) / 14.36;
+            }
+
+            n1 = (int) (fs1 / df * d + 1);
+            if (n1 % 2 == 0) {
+                n1++;
+            }
+
+            alp = alpha(aa);
+            iza = I0Bessel.value(alp);
+            // System.err.printf("iza = %g\n",iza);
+
+            n1y = fs1 / sfrq;
+            n1x = n1 / n1y + 1;
+
+            f1order = new int[n1y * osf];
+            for (i = 0; i < n1y * osf; i++) {
+                f1order[i] = fs1 / sfrq - (i * (fs1 / (dfrq * osf))) % (fs1 / sfrq);
+                if (f1order[i] == fs1 / sfrq) {
+                    f1order[i] = 0;
+                }
+            }
+
+            f1inc = new int[n1y * osf];
+            for (i = 0; i < n1y * osf; i++) {
+                f1inc[i] = f1order[i] < fs1 / (dfrq * osf) ? nch : 0;
+                if (f1order[i] == fs1 / sfrq) {
+                    f1order[i] = 0;
+                }
+            }
+
+            stage1 = new double[n1y][n1x];
+
+            for (i = -(n1 / 2); i <= n1 / 2; i++) {
+                stage1[(i + n1 / 2) % n1y][(i + n1 / 2) / n1y] =
+                        win(i, n1, alp, iza) * hn_lpf(i, lpf, fs1) * fs1 / sfrq;
+            }
+        }
+
+        // Make stage 2 filter
+
+        {
+            double aa = AA; // stop band attenuation(dB)
+            double lpf, d, df, alp, iza;
+            //          double delta;
+            int ipsize, wsize;
+
+            //          delta = Math.pow(10, -aa / 20);
+            if (aa <= 21) {
+                d = 0.9222;
+            } else {
+                d = (aa - 7.95) / 14.36;
+            }
+
+            fs2 = dfrq * osf;
+
+            for (i = 1; ; i = i * 2) {
+                n2 = filter2len * i;
+                if (n2 % 2 == 0) {
+                    n2--;
+                }
+                df = (fs2 * d) / (n2 - 1);
+                lpf = sfrq / 2;
+                if (df < DF) {
+                    break;
+                }
+            }
+
+            alp = alpha(aa);
+
+            iza = I0Bessel.value(alp);
+
+            for (n2b = 1; n2b < n2; n2b *= 2) {
+            }
+            n2b *= 2;
+
+            stage2 = new double[n2b];
+
+            for (i = -(n2 / 2); i <= n2 / 2; i++) {
+                stage2[i + n2 / 2] = win(i, n2, alp, iza) * hn_lpf(i, lpf, fs2) / n2b * 2;
+            }
+
+            ipsize = (int) (2 + Math.sqrt(n2b));
+            fft_ip = new int[ipsize];
+            fft_ip[0] = 0;
+            wsize = n2b / 2;
+            fft_w = new double[wsize];
+
+            fft.rdft(n2b, 1, stage2, fft_ip, fft_w);
+        }
+
+        // Apply filters
+
+        setstarttime();
+
+        {
+            int n2b2 = n2b / 2;
+            // inbuffs1Tv???
+            int rp;
+            // disposesfrqTv?
+            int ds;
+            // ?t@Cinbuf?lvZ stage2 filternTv?
+            int nsmplwrt1;
+            // ?t@Cinbuf?lvZ stage2 filternTv?
+            int nsmplwrt2 = 0;
+            // stage1 filter?oTv?n1y*osf]
+            int s1p;
+            boolean init;
+            boolean ending;
+            int sumread, sumwrite;
+            int osc;
+            int ip, ip_backup;
+            int s1p_backup, osc_backup;
+            int ch, p;
+            int inbuflen;
+            int delay = 0;
+
+            buf1 = new double[nch][n2b2 / osf + 1];
+
+            buf2 = new double[nch][n2b];
+
+            rawinbuf = ByteBuffer.allocate(nch * (n2b2 + n1x) * bps); // ,bps
+            rawoutbuf = ByteBuffer.allocate(nch * (n2b2 / osf + 1) * dbps); // ,dbps
+
+            inbuf = new double[nch * (n2b2 + n1x)];
+            outbuf = new double[nch * (n2b2 / osf + 1)];
+
+            s1p = 0;
+            rp = 0;
+            ds = 0;
+            osc = 0;
+
+            init = true;
+            ending = false;
+            inbuflen = n1 / 2 / (fs1 / sfrq) + 1;
+            delay = (int) ((double) n2 / 2 / (fs2 / dfrq));
+
+            sumread = sumwrite = 0;
+
+            while (true) {
+                int nsmplread, toberead, toberead2;
+
+                toberead2 = toberead =
+                        (int) (Math.floor((double) n2b2 * sfrq / (dfrq * osf)) + 1 + n1x -
+                                inbuflen);
+                if (toberead + sumread > chanklen) {
+                    toberead = chanklen - sumread;
+                }
+
+                rawinbuf.position(0);
+                rawinbuf.limit(Math.min(rawinbuf.limit(), bps * nch * toberead));
+                //                rawinbuf.limit(bps * nch * toberead);
+
+                byte[] tempData = new byte[rawinbuf.limit()];
+                nsmplread = fpi.read(tempData);
+                if (nsmplread < 0) {
+                    nsmplread = 0;
+                }
+
+                if (nsmplread < rawinbuf.limit()) {
+                    chanklen = sumread + nsmplread / bps * nch;
+                }
+
+                rawinbuf.limit(nsmplread);
+                rawinbuf = ByteBuffer.wrap(tempData);
+                rawinbuf.position(nsmplread);
+
+                rawinbuf.flip();
+                nsmplread /= bps * nch;
+
+                switch (bps) {
+                    case 1:
+                        for (i = 0; i < nsmplread * nch; i++)
+                            inbuf[nch * inbuflen + i] =
+                                    (1 / (double) 0x7f) * ((double) rawinbuf.get(i) - 128);
+                        break;
+
+                    case 2:
+                        for (i = 0; i < nsmplread * nch; i++) {
+                            int v = rawinbuf.order(byteOrder).asShortBuffer().get(i);
+                            inbuf[nch * inbuflen + i] = (1 / (double) 0x7fff) * v;
+                        }
+                        break;
+
+                    case 3:
+                        for (i = 0; i < nsmplread * nch; i++) {
+                            inbuf[nch * inbuflen + i] =
+                                    (1 / (double) 0x7fffff) * ((rawinbuf.get(i * 3) << 0) |
+                                            (rawinbuf.get(i * 3 + 1) << 8) |
+                                            (rawinbuf.get(i * 3 + 2) << 16));
+                        }
+                        break;
+
+                    case 4:
+                        for (i = 0; i < nsmplread * nch; i++) {
+                            int v = rawinbuf.order(byteOrder).asIntBuffer().get(i);
+                            inbuf[nch * inbuflen + i] = (1 / (double) 0x7fffffff) * v;
+                        }
+                        break;
+                }
+
+                for (; i < nch * toberead2; i++) {
+                    inbuf[nch * inbuflen + i] = 0;
+                }
+
+                inbuflen += toberead2;
+
+                sumread += nsmplread;
+
+                ending = sumread >= chanklen;
+                //                ending = fpi.available() == 0 || sumread >= chanklen;
+
+                //              nsmplwrt1 = ((rp - 1) * sfrq / fs1 + inbuflen - n1x) * dfrq * osf / sfrq;
+                //              if (nsmplwrt1 > n2b2) { nsmplwrt1 = n2b2; }
+                nsmplwrt1 = n2b2;
+
+                // apply stage 1 filter
+
+                ip = ((sfrq * (rp - 1) + fs1) / fs1) * nch; // inbuf
+
+                s1p_backup = s1p;
+                ip_backup = ip;
+                osc_backup = osc;
+
+                for (ch = 0; ch < nch; ch++) {
+                    int op = ch; // outbuf
+                    //                  int fdo = fs1 / (dfrq * osf);
+                    int no = n1y * osf;
+
+                    s1p = s1p_backup;
+                    ip = ip_backup + ch;
+
+                    switch (n1x) {
+                        case 7:
+                            for (p = 0; p < nsmplwrt1; p++) {
+                                int s1o = f1order[s1p];
+
+                                buf2[ch][p] = stage1[s1o][0] * inbuf[ip + 0 * nch] +
+                                        stage1[s1o][1] * inbuf[ip + 1 * nch] +
+                                        stage1[s1o][2] * inbuf[ip + 2 * nch] +
+                                        stage1[s1o][3] * inbuf[ip + 3 * nch] +
+                                        stage1[s1o][4] * inbuf[ip + 4 * nch] +
+                                        stage1[s1o][5] * inbuf[ip + 5 * nch] +
+                                        stage1[s1o][6] * inbuf[ip + 6 * nch];
+
+                                ip += f1inc[s1p];
+
+                                s1p++;
+                                if (s1p == no) {
+                                    s1p = 0;
+                                }
+                            }
+                            break;
+
+                        case 9:
+                            for (p = 0; p < nsmplwrt1; p++) {
+                                int s1o = f1order[s1p];
+
+                                buf2[ch][p] = stage1[s1o][0] * inbuf[ip + 0 * nch] +
+                                        stage1[s1o][1] * inbuf[ip + 1 * nch] +
+                                        stage1[s1o][2] * inbuf[ip + 2 * nch] +
+                                        stage1[s1o][3] * inbuf[ip + 3 * nch] +
+                                        stage1[s1o][4] * inbuf[ip + 4 * nch] +
+                                        stage1[s1o][5] * inbuf[ip + 5 * nch] +
+                                        stage1[s1o][6] * inbuf[ip + 6 * nch] +
+                                        stage1[s1o][7] * inbuf[ip + 7 * nch] +
+                                        stage1[s1o][8] * inbuf[ip + 8 * nch];
+
+                                ip += f1inc[s1p];
+
+                                s1p++;
+                                if (s1p == no) {
+                                    s1p = 0;
+                                }
+                            }
+                            break;
+
+                        default:
+                            for (p = 0; p < nsmplwrt1; p++) {
+                                double tmp = 0;
+                                int ip2 = ip;
+
+                                int s1o = f1order[s1p];
+
+                                for (i = 0; i < n1x; i++) {
+                                    tmp += stage1[s1o][i] * inbuf[ip2];
+                                    ip2 += nch;
+                                }
+                                buf2[ch][p] = tmp;
+
+                                ip += f1inc[s1p];
+
+                                s1p++;
+                                if (s1p == no) {
+                                    s1p = 0;
+                                }
+                            }
+                            break;
+                    }
+
+                    osc = osc_backup;
+
+                    // apply stage 2 filter
+
+                    for (p = nsmplwrt1; p < n2b; p++) {
+                        buf2[ch][p] = 0;
+                    }
+
+                    //for(i=0;i<n2b2;i++) { System.err.printf("%d:%g",i,buf2[ch][i]); }
+
+                    fft.rdft(n2b, 1, buf2[ch], fft_ip, fft_w);
+
+                    buf2[ch][0] = stage2[0] * buf2[ch][0];
+                    buf2[ch][1] = stage2[1] * buf2[ch][1];
+
+                    for (i = 1; i < n2b / 2; i++) {
+                        double re, im;
+
+                        re = stage2[i * 2] * buf2[ch][i * 2] -
+                                stage2[i * 2 + 1] * buf2[ch][i * 2 + 1];
+                        im = stage2[i * 2 + 1] * buf2[ch][i * 2] +
+                                stage2[i * 2] * buf2[ch][i * 2 + 1];
+
+                        //System.err.printf("%d : %g %g %g %g %g %g\n",i,stage2[i*2],stage2[i*2+1],buf2[ch][i*2],buf2[ch][i*2+1],re,im);
+
+                        buf2[ch][i * 2] = re;
+                        buf2[ch][i * 2 + 1] = im;
+                    }
+
+                    fft.rdft(n2b, -1, buf2[ch], fft_ip, fft_w);
+
+                    for (i = osc, j = 0; i < n2b2; i += osf, j++) {
+                        double f = (buf1[ch][j] + buf2[ch][i]);
+                        outbuf[op + j * nch] = f;
+                    }
+
+                    nsmplwrt2 = j;
+
+                    osc = i - n2b2;
+
+                    for (j = 0; i < n2b; i += osf, j++) {
+                        buf1[ch][j] = buf2[ch][i];
+                    }
+                }
+
+                rp += nsmplwrt1 * (sfrq / frqgcd) / osf;
+
+                rawoutbuf.clear();
+                if (twopass) {
+                    for (i = 0; i < nsmplwrt2 * nch; i++) {
+                        double f = outbuf[i] > 0 ? outbuf[i] : -outbuf[i];
+                        peak[0] = peak[0] < f ? f : peak[0];
+                        rawoutbuf.asDoubleBuffer().put(i, outbuf[i]);
+                    }
+                } else {
+                    switch (dbps) {
+                        case 1: {
+                            double gain2 = gain * 0x7f;
+                            ch = 0;
+
+                            for (i = 0; i < nsmplwrt2 * nch; i++) {
+                                int s;
+
+                                if (dither != 0) {
+                                    s = do_shaping(outbuf[i] * gain2, peak, dither, ch);
+                                } else {
+                                    s = RINT(outbuf[i] * gain2);
+
+                                    if (s < -0x80) {
+                                        double d = (double) s / -0x80;
+                                        peak[0] = peak[0] < d ? d : peak[0];
+                                        s = -0x80;
+                                    }
+                                    if (0x7f < s) {
+                                        double d = (double) s / 0x7f;
+                                        peak[0] = peak[0] < d ? d : peak[0];
+                                        s = 0x7f;
+                                    }
+                                }
+
+                                rawoutbuf.put(i, (byte) (s + 0x80));
+
+                                ch++;
+                                if (ch == nch) {
+                                    ch = 0;
+                                }
+                            }
+                        }
+                        break;
+
+                        case 2: {
+                            double gain2 = gain * 0x7fff;
+                            ch = 0;
+
+                            for (i = 0; i < nsmplwrt2 * nch; i++) {
+                                int s;
+
+                                if (dither != 0) {
+                                    s = do_shaping(outbuf[i] * gain2, peak, dither, ch);
+                                } else {
+                                    s = RINT(outbuf[i] * gain2);
+
+                                    if (s < -0x8000) {
+                                        double d = (double) s / -0x8000;
+                                        peak[0] = peak[0] < d ? d : peak[0];
+                                        s = -0x8000;
+                                    }
+                                    if (0x7fff < s) {
+                                        double d = (double) s / 0x7fff;
+                                        peak[0] = peak[0] < d ? d : peak[0];
+                                        s = 0x7fff;
+                                    }
+                                }
+
+                                rawoutbuf.order(byteOrder).asShortBuffer().put(i, (short) s);
+
+                                ch++;
+                                if (ch == nch) {
+                                    ch = 0;
+                                }
+                            }
+                        }
+                        break;
+
+                        case 3: {
+                            double gain2 = gain * 0x7fffff;
+                            ch = 0;
+
+                            for (i = 0; i < nsmplwrt2 * nch; i++) {
+                                int s;
+
+                                if (dither != 0) {
+                                    s = do_shaping(outbuf[i] * gain2, peak, dither, ch);
+                                } else {
+                                    s = RINT(outbuf[i] * gain2);
+
+                                    if (s < -0x800000) {
+                                        double d = (double) s / -0x800000;
+                                        peak[0] = peak[0] < d ? d : peak[0];
+                                        s = -0x800000;
+                                    }
+                                    if (0x7fffff < s) {
+                                        double d = (double) s / 0x7fffff;
+                                        peak[0] = peak[0] < d ? d : peak[0];
+                                        s = 0x7fffff;
+                                    }
+                                }
+
+                                rawoutbuf.put(i * 3, (byte) (s & 255));
+                                s >>= 8;
+                                rawoutbuf.put(i * 3 + 1, (byte) (s & 255));
+                                s >>= 8;
+                                rawoutbuf.put(i * 3 + 2, (byte) (s & 255));
+
+                                ch++;
+                                if (ch == nch) {
+                                    ch = 0;
+                                }
+                            }
+                        }
+                        break;
+
+                    }
+                }
+
+                if (!init) {
+                    if (ending) {
+                        if ((double) sumread * dfrq / sfrq + 2 > sumwrite + nsmplwrt2) {
+                            rawoutbuf.position(0);
+                            rawoutbuf.limit(dbps * nch * nsmplwrt2);
+                            writeBuffers(fpo, rawoutbuf);
+                            sumwrite += nsmplwrt2;
+                        } else {
+                            rawoutbuf.position(0);
+                            int limitData = (int) (dbps * nch *
+                                    (Math.floor((double) sumread * dfrq / sfrq) + 2 - sumwrite));
+                            if (limitData > 0) {
+                                rawoutbuf.limit(limitData);
+                                writeBuffers(fpo, rawoutbuf);
+                            }
+                            break;
+                        }
+                    } else {
+                        rawoutbuf.position(0);
+                        rawoutbuf.limit(dbps * nch * nsmplwrt2);
+                        writeBuffers(fpo, rawoutbuf);
+                        sumwrite += nsmplwrt2;
+                    }
+                } else {
+
+                    if (nsmplwrt2 < delay) {
+                        delay -= nsmplwrt2;
+                    } else {
+                        if (ending) {
+                            if ((double) sumread * dfrq / sfrq + 2 > sumwrite + nsmplwrt2 - delay) {
+                                rawoutbuf.position(dbps * nch * delay);
+                                rawoutbuf.limit(dbps * nch * (nsmplwrt2 - delay));
+                                writeBuffers(fpo, rawoutbuf);
+                                sumwrite += nsmplwrt2 - delay;
+                            } else {
+                                rawoutbuf.position(dbps * nch * delay);
+                                rawoutbuf.limit((int) (dbps * nch *
+                                        (Math.floor((double) sumread * dfrq / sfrq) + 2 + sumwrite +
+                                                nsmplwrt2 - delay)));
+                                writeBuffers(fpo, rawoutbuf);
+                                break;
+                            }
+                        } else {
+                            rawoutbuf.position(dbps * nch * delay);
+                            rawoutbuf.limit(dbps * nch * (nsmplwrt2));
+                            writeBuffers(fpo, rawoutbuf);
+                            sumwrite += nsmplwrt2 - delay;
+                            init = false;
+                        }
+                    }
+                }
+
+                {
+                    ds = (rp - 1) / (fs1 / sfrq);
+
+                    assert (inbuflen >= ds);
+
+                    System.arraycopy(inbuf, nch * ds, inbuf, 0,
+                            nch * (inbuflen - ds)); // memmove TODO overlap
+                    inbuflen -= ds;
+                    rp -= ds * (fs1 / sfrq);
+                }
+
+                if ((spcount++ & 7) == 7) {
+                    showprogress((double) sumread / chanklen);
+                }
+            }
+        }
+
+        showprogress(1);
+
+        return peak[0];
+    }
+
+    /** */
+    @SuppressLint("Assert")
+    public double downsample(InputStream fpi, OutputStream fpo, int nch, int bps, int dbps,
+                             int sfrq, int dfrq, double gain, int chanklen, boolean twopass,
+                             int dither) throws IOException {
+        int frqgcd, osf = 0, fs1, fs2;
+        double[] stage1;
+        double[][] stage2;
+        int n2, n2x, n2y, n1, n1b;
+        int filter1len;
+        int[] f2order, f2inc;
+        int[] fft_ip = null;
+        double[] fft_w = null;
+        ByteBuffer rawinbuf, rawoutbuf;
+        double[] inbuf, outbuf;
+        double[][] buf1, buf2;
+        int i, j;
+        int spcount = 0;
+        double[] peak = new double[]{0};
+
+        //        System.err.println("downsample");
+
+        filter1len = FFTFIRLEN; // stage 1 filter length
+
+        // Make stage 1 filter
+
+        {
+            double aa = AA; // stop band attenuation(dB)
+            double lpf, d, df, alp, iza;
+            //          double delta;
+            int ipsize, wsize;
+
+            frqgcd = gcd(sfrq, dfrq);
+
+            if (dfrq / frqgcd == 1) {
+                osf = 1;
+            } else if (dfrq / frqgcd % 2 == 0) {
+                osf = 2;
+            } else if (dfrq / frqgcd % 3 == 0) {
+                osf = 3;
+            } else {
+                throw new IllegalArgumentException(String.format(
+                        "Resampling from %dHz to %dHz is not supported.\n" +
+                                "%d/gcd(%d,%d)=%d must be divided by 2 or 3.", sfrq, dfrq, dfrq,
+                        sfrq, dfrq, dfrq / frqgcd));
+            }
+
+            fs1 = sfrq * osf;
+
+            //          delta = Math.pow(10, -aa / 20);
+            if (aa <= 21) {
+                d = 0.9222;
+            } else {
+                d = (aa - 7.95) / 14.36;
+            }
+
+            n1 = filter1len;
+            for (i = 1; ; i = i * 2) {
+                n1 = filter1len * i;
+                if (n1 % 2 == 0) {
+                    n1--;
+                }
+                df = (fs1 * d) / (n1 - 1);
+                lpf = (dfrq - df) / 2;
+                if (df < DF) {
+                    break;
+                }
+            }
+
+            alp = alpha(aa);
+
+            iza = I0Bessel.value(alp);
+            LogFunction.log("须打log", "不打的话在某些机型上会卡住");
+            //System.err.printf("iza %f, alp: %f\n", iza, alp); // OK
+
+            for (n1b = 1; n1b < n1; n1b *= 2) {
+            }
+            n1b *= 2;
+
+            stage1 = new double[n1b];
+
+            for (i = -(n1 / 2); i <= n1 / 2; i++) {
+                stage1[i + n1 / 2] =
+                        win(i, n1, alp, iza) * hn_lpf(i, lpf, fs1) * fs1 / sfrq / n1b * 2;
+                //System.err.printf("1: %06d: %e\n", i + n1 / 2, stage1[i + n1 / 2]); // OK
+            }
+
+            ipsize = (int) (2 + Math.sqrt(n1b));
+            fft_ip = new int[ipsize];
+            fft_ip[0] = 0;
+            wsize = n1b / 2;
+            fft_w = new double[wsize];
+
+            fft.rdft(n1b, 1, stage1, fft_ip, fft_w);
+            //for (i = -(n1 / 2); i <= n1 / 2; i++) {
+            // System.err.printf("1': %06d: %e\n", i + n1 / 2, stage1[i + n1 / 2]);
+            //}
+            //for (i = 0; i < ipsize; i++) {
+            // System.err.printf("ip: %06d: %d\n", i, fft_ip[i]); // OK
+            //}
+            //for (i = 0; i < wsize; i++) {
+            // System.err.printf("w: %06d: %e\n", i, fft_w[i]); // OK
+            //}
+        }
+
+        // Make stage 2 filter
+
+        if (osf == 1) {
+            fs2 = sfrq / frqgcd * dfrq;
+            n2 = 1;
+            n2y = n2x = 1;
+            f2order = new int[n2y];
+            f2order[0] = 0;
+            f2inc = new int[n2y];
+            f2inc[0] = sfrq / dfrq;
+            stage2 = new double[n2y][n2x];
+            stage2[0][0] = 1;
+        } else {
+            double aa = AA; // stop band attenuation(dB)
+            double lpf, d, df, alp, iza;
+            //          double delta;
+            double guard = 2;
+
+            fs2 = sfrq / frqgcd * dfrq;
+
+            df = (fs1 / 2 - sfrq / 2) * 2 / guard;
+            lpf = sfrq / 2 + (fs1 / 2 - sfrq / 2) / guard;
+
+            //          delta = Math.pow(10, -aa / 20);
+            if (aa <= 21) {
+                d = 0.9222;
+            } else {
+                d = (aa - 7.95) / 14.36;
+            }
+
+            n2 = (int) (fs2 / df * d + 1);
+            if (n2 % 2 == 0) {
+                n2++;
+            }
+
+            alp = alpha(aa);
+            iza = I0Bessel.value(alp);
+            //System.err.printf("iza %f, alp: %f\n", iza, alp); // OK
+
+            n2y = fs2 / fs1; // 0Tvfs2Tv?H
+            n2x = n2 / n2y + 1;
+
+            f2order = new int[n2y];
+            for (i = 0; i < n2y; i++) {
+                f2order[i] = fs2 / fs1 - (i * (fs2 / dfrq)) % (fs2 / fs1);
+                if (f2order[i] == fs2 / fs1) {
+                    f2order[i] = 0;
+                }
+            }
+
+            f2inc = new int[n2y];
+            for (i = 0; i < n2y; i++) {
+                f2inc[i] = (fs2 / dfrq - f2order[i]) / (fs2 / fs1) + 1;
+                if (f2order[i + 1 == n2y ? 0 : i + 1] == 0) {
+                    f2inc[i]--;
+                }
+            }
+
+            stage2 = new double[n2y][n2x];
+
+            //System.err.printf("n2y: %d, n2: %d\n", n2y, n2);
+            for (i = -(n2 / 2); i <= n2 / 2; i++) {
+                stage2[(i + n2 / 2) % n2y][(i + n2 / 2) / n2y] =
+                        win(i, n2, alp, iza) * hn_lpf(i, lpf, fs2) * fs2 / fs1;
+                //System.err.printf(" stage2[%02d][%02d]: %f\n", (i + n2 / 2) % n2y, (i + n2 / 2) / n2y, win(i, n2, alp, iza) * hn_lpf(i, lpf, fs2) * fs2 / fs1); // OK
+            }
+        }
+
+        // Apply filters
+
+        setstarttime();
+
+        {
+            int n1b2 = n1b / 2;
+            int rp; // inbuffs1Tv???
+            int rps; // rp(fs1/sfrq=osf)]
+            int rp2; // buf2fs2Tv???
+            int ds; // disposesfrqTv?
+            // ?t@Cinbuf?lvZ stage2 filternTv?
+            //          int nsmplwrt1;
+            // ?t@Cinbuf?lvZ stage2 filternTv?
+            int nsmplwrt2 = 0;
+            int s2p; // stage1 filter?oTv?n1y*osf]
+            boolean init, ending;
+            //          int osc;
+            int bp; // rp2vZ?Dbuf2Tvu
+            int rps_backup, s2p_backup;
+            int k, ch, p;
+            int inbuflen = 0;
+            int sumread, sumwrite;
+            int delay = 0;
+            int op;
+
+            // |....B....|....C....| buf1 n1b2+n1b2
+            // |.A.|....D....| buf2 n2x+n1b2
+            //
+            // inbufBosf{TvORs?[
+            // CNA
+            // BCstage 1 filter
+            // DB
+            // ADstage 2 filter
+            // DA
+            // CDRs?[
+
+            buf1 =
+                    new double[nch][n1b];                                      //rawoutbuf = calloc(nch*(n2b2/osf+1),dbps);
+
+            buf2 = new double[nch][n2x + 1 + n1b2];
+
+            rawinbuf = ByteBuffer.allocate((nch * (n1b2 / osf + osf + 1)) * bps);
+            //System.err.println((double) n1b2 * sfrq / dfrq + 1);
+            rawoutbuf =
+                    ByteBuffer.allocate((int) (((double) n1b2 * dfrq / sfrq + 1) * (dbps * nch)));
+            inbuf = new double[nch * (n1b2 / osf + osf + 1)];
+            outbuf = new double[(int) (nch * ((double) n1b2 * dfrq / sfrq + 1))];
+
+            op = 0; // outbuf
+
+            s2p = 0;
+            rp = 0;
+            rps = 0;
+            ds = 0;
+            //          osc = 0;
+            rp2 = 0;
+
+            init = true;
+            ending = false;
+            delay = (int) ((double) n1 / 2 / ((double) fs1 / dfrq) +
+                    (double) n2 / 2 / ((double) fs2 / dfrq));
+            sumread = sumwrite = 0;
+
+            while (true) {
+                int nsmplread;
+                int toberead;
+                rps = 0;   //TODO settings this parameter to zero fixed a lot of problems
+                toberead = (n1b2 - rps - 1) / osf + 1;
+                if (toberead + sumread > chanklen) {
+                    toberead = chanklen - sumread;
+                }
+
+                rawinbuf.position(0);
+                rawinbuf.limit(bps * nch * toberead);
+
+                byte[] tempData = new byte[rawinbuf.limit()];
+                nsmplread = fpi.read(tempData);
+                if (nsmplread < 0) {
+                    nsmplread = 0;
+                }
+
+                //TODO sometimes happens, investigate around it
+                if (nsmplread < rawinbuf.limit()) {
+                    chanklen = sumread + nsmplread / bps * nch;
+                }
+
+                rawinbuf.limit(nsmplread);
+                rawinbuf = ByteBuffer.wrap(tempData);
+                rawinbuf.position(nsmplread);
+
+                rawinbuf.flip();
+                nsmplread /= bps * nch;
+
+                switch (bps) {
+                    case 1:
+                        for (i = 0; i < nsmplread * nch; i++) {
+                            inbuf[nch * inbuflen + i] =
+                                    (1 / (double) 0x7f) * ((rawinbuf.get(i) & 0xff) - 128);
+                        }
+                        break;
+
+                    case 2:
+                        for (i = 0; i < nsmplread * nch; i++) {
+                            int v = rawinbuf.order(byteOrder).asShortBuffer().get(i);
+                            inbuf[nch * inbuflen + i] = (1 / (double) 0x7fff) * v;
+                            //                            System.err.printf("I: %f\n", inbuf[nch * inbuflen + i]);
+                        }
+                        break;
+
+                    case 3:
+                        for (i = 0; i < nsmplread * nch; i++) {
+                            inbuf[nch * inbuflen + i] =
+                                    (1 / (double) 0x7fffff) * (((rawinbuf.get(i * 3) & 0xff) << 0) |
+                                            ((rawinbuf.get(i * 3 + 1) & 0xff) << 8) |
+                                            ((rawinbuf.get(i * 3 + 2) & 0xff) << 16));
+                        }
+                        break;
+
+                    case 4:
+                        for (i = 0; i < nsmplread * nch; i++) {
+                            int v = rawinbuf.order(byteOrder).getInt(i);
+                            inbuf[nch * inbuflen + i] = (1 / (double) 0x7fffffff) * v;
+                        }
+                        break;
+                }
+
+                for (; i < nch * toberead; i++) {
+                    inbuf[i] = 0;
+                }
+
+                sumread += nsmplread;
+
+                //                ending = sumread >= chanklen;
+                ending = fpi.available() < 0 || sumread >= chanklen;
+
+                rps_backup = rps;
+                s2p_backup = s2p;
+
+                for (ch = 0; ch < nch; ch++) {
+                    rps = rps_backup;
+
+                    for (k = 0; k < rps; k++) {
+                        buf1[ch][k] = 0;
+                    }
+
+                    for (i = rps, j = 0; i < n1b2; i += osf, j++) {
+                        assert (j < ((n1b2 - rps - 1) / osf + 1));
+
+                        buf1[ch][i] = inbuf[j * nch + ch];
+
+                        for (k = i + 1; k < i + osf; k++) {
+                            buf1[ch][k] = 0;
+                        }
+                    }
+
+                    assert (j == ((n1b2 - rps - 1) / osf + 1));
+
+                    for (k = n1b2; k < n1b; k++) {
+                        buf1[ch][k] = 0;
+                    }
+
+                    rps = i - n1b2;
+                    rp += j;
+
+                    fft.rdft(n1b, 1, buf1[ch], fft_ip, fft_w);
+
+                    buf1[ch][0] = stage1[0] * buf1[ch][0];
+                    buf1[ch][1] = stage1[1] * buf1[ch][1];
+
+                    for (i = 1; i < n1b2; i++) {
+                        double re, im;
+
+                        re = stage1[i * 2] * buf1[ch][i * 2] -
+                                stage1[i * 2 + 1] * buf1[ch][i * 2 + 1];
+                        im = stage1[i * 2 + 1] * buf1[ch][i * 2] +
+                                stage1[i * 2] * buf1[ch][i * 2 + 1];
+
+                        buf1[ch][i * 2] = re;
+                        buf1[ch][i * 2 + 1] = im;
+                    }
+
+                    fft.rdft(n1b, -1, buf1[ch], fft_ip, fft_w);
+
+                    for (i = 0; i < n1b2; i++) {
+                        buf2[ch][n2x + 1 + i] += buf1[ch][i];
+                    }
+
+                    {
+                        int t1 = rp2 / (fs2 / fs1);
+                        if (rp2 % (fs2 / fs1) != 0) {
+                            t1++;
+                        }
+
+                        bp = buf2[0].length * ch + t1; // &(buf2[ch][t1]);
+                    }
+
+                    s2p = s2p_backup;
+
+                    for (p = 0; bp - (buf2[0].length * ch) < n1b2 + 1; p++) { // buf2[ch]
+                        double tmp = 0;
+                        int bp2;
+                        int s2o;
+
+                        bp2 = bp;
+                        s2o = f2order[s2p];
+                        bp += f2inc[s2p];
+                        s2p++;
+
+                        if (s2p == n2y) {
+                            s2p = 0;
+                        }
+
+                        assert ((bp2 - (buf2[0].length * ch)) * (fs2 / fs1) -
+                                (rp2 + p * (fs2 / dfrq)) == s2o); // &(buf2[ch][0])
+                        for (i = 0; i < n2x; i++) {
+                            //System.err.printf("%d (%d, %d)\n", i, bp2 / buf2[0].length, bp2 % buf2[0].length);
+                            tmp += stage2[s2o][i] *
+                                    buf2[bp2 / buf2[0].length][bp2 % buf2[0].length]; // *bp2++
+                            bp2++;
+                        }
+
+                        outbuf[op + p * nch + ch] = tmp;
+                        //System.err.printf("O: %06d: %f\n", op + p * nch + ch, tmp);
+                    }
+
+                    nsmplwrt2 = p;
+                }
+
+                rp2 += nsmplwrt2 * (fs2 / dfrq);
+
+                rawoutbuf.clear();
+                if (twopass) {
+                    for (i = 0; i < nsmplwrt2 * nch; i++) {
+                        double f = outbuf[i] > 0 ? outbuf[i] : -outbuf[i];
+                        peak[0] = peak[0] < f ? f : peak[0];
+                        //System.err.println("p: " + rawoutbuf.position() + ", l: " + rawoutbuf.limit());
+                        rawoutbuf.asDoubleBuffer().put(i, outbuf[i]);
+                        //if (i < 100) {
+                        // System.err.printf("1: %06d: %f\n", i, outbuf[i]);
+                        //}
+                        //System.err.print(StringUtil.getDump(rawoutbuf, i, 8));
+                    }
+                } else {
+                    switch (dbps) {
+                        case 1: {
+                            double gain2 = gain * 0x7f;
+                            ch = 0;
+
+                            for (i = 0; i < nsmplwrt2 * nch; i++) {
+                                int s;
+
+                                if (dither != 0) {
+                                    s = do_shaping(outbuf[i] * gain2, peak, dither, ch);
+                                } else {
+                                    s = RINT(outbuf[i] * gain2);
+
+                                    if (s < -0x80) {
+                                        double d = (double) s / -0x80;
+                                        peak[0] = peak[0] < d ? d : peak[0];
+                                        s = -0x80;
+                                    }
+                                    if (0x7f < s) {
+                                        double d = (double) s / 0x7f;
+                                        peak[0] = peak[0] < d ? d : peak[0];
+                                        s = 0x7f;
+                                    }
+                                }
+
+                                rawoutbuf.put(i, (byte) (s + 0x80));
+
+                                ch++;
+                                if (ch == nch) {
+                                    ch = 0;
+                                }
+                            }
+                        }
+                        break;
+
+                        case 2: {
+                            double gain2 = gain * 0x7fff;
+                            ch = 0;
+
+                            for (i = 0; i < nsmplwrt2 * nch; i++) {
+                                int s;
+
+                                if (dither != 0) {
+                                    s = do_shaping(outbuf[i] * gain2, peak, dither, ch);
+                                } else {
+                                    s = RINT(outbuf[i] * gain2);
+
+                                    if (s < -0x8000) {
+                                        double d = (double) s / -0x8000;
+                                        peak[0] = peak[0] < d ? d : peak[0];
+                                        s = -0x8000;
+                                    }
+                                    if (0x7fff < s) {
+                                        double d = (double) s / 0x7fff;
+                                        peak[0] = peak[0] < d ? d : peak[0];
+                                        s = 0x7fff;
+                                    }
+                                }
+
+                                rawoutbuf.order(byteOrder).asShortBuffer().put(i, (short) s);
+
+                                ch++;
+                                if (ch == nch) {
+                                    ch = 0;
+                                }
+                            }
+                        }
+                        break;
+
+                        case 3: {
+                            double gain2 = gain * 0x7fffff;
+                            ch = 0;
+
+                            for (i = 0; i < nsmplwrt2 * nch; i++) {
+                                int s;
+
+                                if (dither != 0) {
+                                    s = do_shaping(outbuf[i] * gain2, peak, dither, ch);
+                                } else {
+                                    s = RINT(outbuf[i] * gain2);
+
+                                    if (s < -0x800000) {
+                                        double d = (double) s / -0x800000;
+                                        peak[0] = peak[0] < d ? d : peak[0];
+                                        s = -0x800000;
+                                    }
+                                    if (0x7fffff < s) {
+                                        double d = (double) s / 0x7fffff;
+                                        peak[0] = peak[0] < d ? d : peak[0];
+                                        s = 0x7fffff;
+                                    }
+                                }
+
+                                rawoutbuf.put(i * 3, (byte) (s & 255));
+                                s >>= 8;
+                                rawoutbuf.put(i * 3 + 1, (byte) (s & 255));
+                                s >>= 8;
+                                rawoutbuf.put(i * 3 + 2, (byte) (s & 255));
+
+                                ch++;
+                                if (ch == nch) {
+                                    ch = 0;
+                                }
+                            }
+                        }
+                        break;
+
+                    }
+                }
+
+                if (!init) {
+                    if (ending) {
+                        if ((double) sumread * dfrq / sfrq + 2 > sumwrite + nsmplwrt2) {
+                            rawoutbuf.position(0);
+                            rawoutbuf.limit(dbps * nch * nsmplwrt2);
+                            writeBuffers(fpo, rawoutbuf);
+                            sumwrite += nsmplwrt2;
+                        } else {
+                            rawoutbuf.position(0);
+                            int limitData = (int) (dbps * nch *
+                                    (Math.floor((double) sumread * dfrq / sfrq) + 2 - sumwrite));
+                            if (limitData > 0) {
+                                rawoutbuf.limit(limitData);
+                                writeBuffers(fpo, rawoutbuf);
+                            }
+                            break;
+                        }
+                    } else {
+                        rawoutbuf.position(0);
+                        rawoutbuf.limit(dbps * nch * nsmplwrt2);
+                        writeBuffers(fpo, rawoutbuf);
+                        sumwrite += nsmplwrt2;
+                    }
+                } else {
+                    if (nsmplwrt2 < delay) {
+                        delay -= nsmplwrt2;
+                    } else {
+                        if (ending) {
+                            if ((double) sumread * dfrq / sfrq + 2 > sumwrite + nsmplwrt2 - delay) {
+                                rawoutbuf.position(dbps * nch * delay);
+                                rawoutbuf.limit(dbps * nch * (nsmplwrt2 - delay));
+                                writeBuffers(fpo, rawoutbuf);
+                                sumwrite += nsmplwrt2 - delay;
+                            } else {
+                                rawoutbuf.position(dbps * nch * delay);
+                                rawoutbuf.limit((int) (dbps * nch *
+                                        (Math.floor((double) sumread * dfrq / sfrq) + 2 + sumwrite +
+                                                nsmplwrt2 -
+                                                delay)));  //TODO fails with short signals (think that fixed this)
+                                writeBuffers(fpo, rawoutbuf);
+                                break;
+                            }
+                        } else {
+                            rawoutbuf.position(dbps * nch * delay);
+                            rawoutbuf.limit(dbps * nch * (nsmplwrt2));
+                            writeBuffers(fpo, rawoutbuf);
+                            sumwrite += nsmplwrt2 - delay;
+                            init = false;
+                        }
+                    }
+                }
+
+                {
+                    ds = (rp2 - 1) / (fs2 / fs1);
+
+                    if (ds > n1b2) {
+                        ds = n1b2;
+                    }
+
+                    for (ch = 0; ch < nch; ch++) {
+                        System.arraycopy(buf2[ch], ds, buf2[ch], 0,
+                                n2x + 1 + n1b2 - ds); // memmove TODO overlap
+                    }
+
+                    rp2 -= ds * (fs2 / fs1);
+                }
+
+                for (ch = 0; ch < nch; ch++) {
+                    System.arraycopy(buf1[ch], n1b2, buf2[ch], n2x + 1, n1b2);
+                }
+
+                if ((spcount++ & 7) == 7) {
+                    showprogress((double) sumread / chanklen);
+                }
+            }
+        }
+
+        showprogress(1);
+
+        return peak[0];
+    }
+
+    /** */
+    public double no_src(InputStream fpi, OutputStream fpo, int nch, int bps, int dbps, double gain,
+                         int chanklen, boolean twopass, int dither) throws IOException {
+        double[] peak = new double[]{0};
+        int ch = 0, sumread = 0;
+
+        setstarttime();
+
+        ByteBuffer leos = null;
+        if (twopass) {
+            leos = ByteBuffer.allocate(8);
+        }
+
+        ByteBuffer buf = ByteBuffer.allocate(4);
+        while (sumread < chanklen * nch) {
+            double f = 0;
+            int s;
+
+            switch (bps) {
+                case 1:
+                    buf.position(0);
+                    buf.limit(1);
+
+                    byte[] tempData = new byte[buf.limit()];
+                    fpi.read(tempData);
+                    buf = ByteBuffer.wrap(tempData);
+                    buf.position(buf.limit());
+
+
+                    buf.flip();
+                    f = (1 / (double) 0x7f) * (buf.get(0) - 128);
+                    break;
+                case 2:
+                    buf.position(0);
+                    buf.limit(2);
+
+                    tempData = new byte[buf.limit()];
+                    fpi.read(tempData);
+                    buf = ByteBuffer.wrap(tempData);
+                    buf.position(buf.limit());
+
+                    buf.flip();
+                    s = buf.order(byteOrder).asShortBuffer().get(0);
+                    f = (1 / (double) 0x7fff) * s;
+                    break;
+                case 3:
+                    buf.position(0);
+                    buf.limit(3);
+
+                    tempData = new byte[buf.limit()];
+                    fpi.read(tempData);
+                    buf = ByteBuffer.wrap(tempData);
+                    buf.position(buf.limit());
+
+                    buf.flip();
+                    f = (1 / (double) 0x7fffff) * (((buf.get(0) & 0xff) << 0) |
+                            ((buf.get(1) & 0xff) << 8) |
+                            ((buf.get(2) & 0xff) << 16));
+                    break;
+                case 4:
+                    buf.position(0);
+                    buf.limit(4);
+
+                    tempData = new byte[buf.limit()];
+                    fpi.read(tempData);
+                    buf = ByteBuffer.wrap(tempData);
+                    buf.position(buf.limit());
+
+                    buf.flip();
+                    s = buf.order(byteOrder).asIntBuffer().get(0);
+                    f = (1 / (double) 0x7fffffff) * s;
+                    break;
+            }
+
+            if (fpi.available() == 0) {
+                //            if (fpi.position() == fpi.size()) {
+                break;
+            }
+            f *= gain;
+
+            if (!twopass) {
+                switch (dbps) {
+                    case 1:
+                        f *= 0x7f;
+                        s = dither != 0 ? do_shaping(f, peak, dither, ch) : RINT(f);
+                        buf.position(0);
+                        buf.limit(1);
+                        buf.put(0, (byte) (s + 128));
+                        buf.flip();
+                        writeBuffers(fpo, buf);
+                        break;
+                    case 2:
+                        f *= 0x7fff;
+                        s = dither != 0 ? do_shaping(f, peak, dither, ch) : RINT(f);
+                        buf.position(0);
+                        buf.limit(2);
+                        buf.asShortBuffer().put(0, (short) s);
+                        buf.flip();
+                        writeBuffers(fpo, buf);
+                        break;
+                    case 3:
+                        f *= 0x7fffff;
+                        s = dither != 0 ? do_shaping(f, peak, dither, ch) : RINT(f);
+                        buf.position(0);
+                        buf.limit(3);
+                        buf.put(0, (byte) (s & 255));
+                        s >>= 8;
+                        buf.put(1, (byte) (s & 255));
+                        s >>= 8;
+                        buf.put(2, (byte) (s & 255));
+                        buf.flip();
+                        writeBuffers(fpo, buf);
+                        break;
+                }
+            } else {
+                double p = f > 0 ? f : -f;
+                peak[0] = peak[0] < p ? p : peak[0];
+                leos.position(0);
+                leos.putDouble(f);
+                leos.flip();
+                writeBuffers(fpo, leos);
+            }
+
+            ch++;
+            if (ch == nch) {
+                ch = 0;
+            }
+            sumread++;
+
+            if ((sumread & 0x3ffff) == 0) {
+                showprogress((double) sumread / (chanklen * nch));
+            }
+        }
+
+        showprogress(1);
+
+        return peak[0];
+    }
+
+    /** */
+    public static void main(String[] args) throws Exception {
+        new SSRC(args);
+    }
+
+    /** */
+    private static final double presets[] = {0.7, 0.9, 0.18};
+
+    public SSRC() {
+    }
+
+    /** */
+    SSRC(String[] argv) throws IOException {
+        String sfn, dfn, tmpfn = null;
+        FileInputStream fpi = null;
+        File fo = null;
+        FileOutputStream fpo = null;
+        File ft = null;
+        FileOutputStream fpto = null;
+        boolean twopass, normalize;
+        int dither, pdf, samp = 0;
+        int nch, bps;
+        int length;
+        int sfrq, dfrq, dbps;
+        double att, noiseamp;
+        double[] peak = new double[]{0};
+        int i;
+
+        // parse command line options
+
+        dfrq = -1;
+        att = 0;
+        dbps = -1;
+        twopass = false;
+        normalize = false;
+        dither = 0;
+        pdf = 0;
+        noiseamp = 0.18;
+
+        for (i = 0; i < argv.length; i++) {
+            if (argv[i].charAt(0) != '-') {
+                break;
+            }
+
+            if (argv[i].equals("--rate")) {
+                dfrq = Integer.parseInt(argv[++i]);
+                //System.err.printf("dfrq: %d\n", dfrq);
+                continue;
+            }
+
+            if (argv[i].equals("--att")) {
+                att = Float.parseFloat(argv[++i]);
+                continue;
+            }
+
+            if (argv[i].equals("--bits")) {
+                dbps = Integer.parseInt(argv[++i]);
+                if (dbps != 8 && dbps != 16 && dbps != 24) {
+                    throw new IllegalArgumentException(
+                            "Error: Only 8bit, 16bit and 24bit PCM are supported.");
+                }
+                dbps /= 8;
+                continue;
+            }
+
+            if (argv[i].equals("--twopass")) {
+                twopass = true;
+                continue;
+            }
+
+            if (argv[i].equals("--normalize")) {
+                twopass = true;
+                normalize = true;
+                continue;
+            }
+
+            if (argv[i].equals("--dither")) {
+                try {
+                    dither = Integer.parseInt(argv[i + 1]);
+                    if (dither < 0 || dither > 4) {
+                        throw new IllegalArgumentException(
+                                "unrecognized dither type : " + argv[i + 1]);
+                    }
+                    i++;
+                } catch (NumberFormatException e) {
+                    dither = -1;
+                }
+                continue;
+            }
+
+            if (argv[i].equals("--pdf")) {
+                try {
+                    pdf = Integer.parseInt(argv[i + 1]);
+                    if (pdf < 0 || pdf > 2) {
+                        throw new IllegalArgumentException(
+                                "unrecognized p.d.f. type : " + argv[i + 1]);
+                    }
+                    i++;
+                } catch (NumberFormatException e) {
+                    throw new IllegalArgumentException("unrecognized p.d.f. type : " + argv[i + 1]);
+                }
+
+                try {
+                    noiseamp = Double.parseDouble(argv[i + 1]);
+                    i++;
+                } catch (NumberFormatException e) {
+                    noiseamp = presets[pdf];
+                }
+
+                continue;
+            }
+
+            if (argv[i].equals("--quiet")) {
+                quiet = true;
+                continue;
+            }
+
+            if (argv[i].equals("--tmpfile")) {
+                tmpfn = argv[++i];
+                continue;
+            }
+
+            if (argv[i].equals("--profile")) {
+                //noinspection IfCanBeSwitch
+                if (argv[i + 1].equals("fast")) {
+                    AA = 96;
+                    DF = 8000;
+                    FFTFIRLEN = 1024;
+                } else if (argv[i + 1].equals("standard")) {
+                    /* nothing to do */
+                } else {
+                    throw new IllegalArgumentException("unrecognized profile : " + argv[i + 1]);
+                }
+                i++;
+                continue;
+            }
+
+            throw new IllegalArgumentException("unrecognized option : " + argv[i]);
+        }
+
+        if (!quiet) {
+            System.err.printf("Shibatch sampling rate converter version " + VERSION +
+                    "(high precision/nio)\n\n");
+        }
+
+        if (argv.length - i != 2) {
+            usage();
+            throw new IllegalStateException("too few arguments");
+        }
+
+        sfn = argv[i];
+        dfn = argv[i + 1];
+
+        try {
+            fpi = new FileInputStream(sfn);
+        } catch (IOException e) {
+            throw new IllegalArgumentException("cannot open input file.");
+        }
+
+        // read wav header
+
+        {
+            @SuppressWarnings("unused") short word;
+            @SuppressWarnings("unused") int dword;
+
+            ByteBuffer bb = ByteBuffer.allocate(256).order(ByteOrder.LITTLE_ENDIAN);
+            bb.limit(36);
+            fpi.getChannel().read(bb);
+            bb.flip();
+            System.err.println("p: " + bb.position() + ", l: " + bb.limit());
+            if (bb.get() != 'R') {
+                fmterr(1);
+            }
+            if (bb.get() != 'I') {
+                fmterr(1);
+            }
+            if (bb.get() != 'F') {
+                fmterr(1);
+            }
+            if (bb.get() != 'F') {
+                fmterr(1);
+            }
+
+            dword = bb.getInt();
+
+            if (bb.get() != 'W') {
+                fmterr(2);
+            }
+            if (bb.get() != 'A') {
+                fmterr(2);
+            }
+            if (bb.get() != 'V') {
+                fmterr(2);
+            }
+            if (bb.get() != 'E') {
+                fmterr(2);
+            }
+            if (bb.get() != 'f') {
+                fmterr(2);
+            }
+            if (bb.get() != 'm') {
+                fmterr(2);
+            }
+            if (bb.get() != 't') {
+                fmterr(2);
+            }
+            if (bb.get() != ' ') {
+                fmterr(2);
+            }
+
+            int sizeOfFmt = bb.getInt();
+
+            if (bb.getShort() != 1) {
+                throw new IllegalStateException("Error: Only PCM is supported.");
+            }
+            nch = bb.getShort();
+            sfrq = bb.getInt();
+            bps = bb.getInt();
+            if (bps % sfrq * nch != 0) {
+                fmterr(4);
+            }
+
+            word = bb.getShort();
+            word = bb.getShort();
+
+            bps /= sfrq * nch;
+
+            if (sizeOfFmt > 16) {
+                bb.position(0);
+                bb.limit(2);
+                fpi.read(getDataFromByteBuffer(bb));
+                bb.flip();
+                int sizeofExtended = bb.getShort();
+                fpi.getChannel().position(fpi.getChannel().position() + sizeofExtended);
+            }
+
+            while (true) {
+                bb.position(0);
+                bb.limit(8);
+                fpi.getChannel().read(bb);
+                bb.flip();
+                int c0 = bb.get();
+                int c1 = bb.get();
+                int c2 = bb.get();
+                int c3 = bb.get();
+                length = bb.getInt();
+                System.err.printf("chunk: %c%c%c%c\n", c0, c1, c2, c3);
+                if (c0 == 'd' && c1 == 'a' && c2 == 't' && c3 == 'a') {
+                    break;
+                }
+                if (fpi.getChannel().position() == fpi.getChannel().size()) {
+                    break;
+                }
+                fpi.getChannel().position(fpi.getChannel().position() + length);
+            }
+            if (fpi.getChannel().position() == fpi.getChannel().size()) {
+                throw new IllegalStateException("Couldn't find data chank");
+            }
+        }
+
+        if (bps != 1 && bps != 2 && bps != 3 && bps != 4) {
+            throw new IllegalStateException(
+                    "Error : Only 8bit, 16bit, 24bit and 32bit PCM are supported.");
+        }
+
+        if (dbps == -1) {
+            if (bps != 1) {
+                dbps = bps;
+            } else {
+                dbps = 2;
+            }
+            if (dbps == 4) {
+                dbps = 3;
+            }
+        }
+
+        if (dfrq == -1) {
+            dfrq = sfrq;
+        }
+
+        if (dither == -1) {
+            if (dbps < bps) {
+                if (dbps == 1) {
+                    dither = 4;
+                } else {
+                    dither = 3;
+                }
+            } else {
+                dither = 1;
+            }
+        }
+
+        if (!quiet) {
+            final String[] dtype = {"none", "no noise shaping", "triangular spectral shape",
+                    "ATH based noise shaping", "ATH based noise shaping(less amplitude)"};
+            final String[] ptype = {"rectangular", "triangular", "gaussian"};
+            System.err.printf("frequency : %d -> %d\n", sfrq, dfrq);
+            System.err.printf("attenuation : %gdB\n", att);
+            System.err.printf("bits per sample : %d -> %d\n", bps * 8, dbps * 8);
+            System.err.printf("nchannels : %d\n", nch);
+            System.err.printf("length : %d bytes, %g secs\n", length,
+                    (double) length / bps / nch / sfrq);
+            if (dither == 0) {
+                System.err.printf("dither type : none\n");
+            } else {
+                System.err
+                        .printf("dither type : %s, %s p.d.f, amp = %g\n", dtype[dither], ptype[pdf],
+                                noiseamp);
+            }
+            System.err.printf("\n");
+        }
+
+        if (twopass) {
+        }
+
+        try {
+            fo = new File(dfn);
+            fpo = new FileOutputStream(fo);
+        } catch (IOException e) {
+            throw new IllegalArgumentException("cannot open output file.");
+        }
+
+        // generate wav header
+
+        {
+            short word;
+            int dword;
+
+            ByteBuffer leos = ByteBuffer.allocate(44).order(ByteOrder.LITTLE_ENDIAN);
+
+            leos.put("RIFF".getBytes());
+            dword = 0;
+            leos.putInt(dword);
+
+            leos.put("WAVEfmt ".getBytes());
+            dword = 16;
+            leos.putInt(dword);
+            word = 1;
+            leos.putShort(word); // inAudioFormat category, PCM
+            word = (short) nch;
+            leos.putShort(word); // channels
+            dword = dfrq;
+            leos.putInt(dword); // sampling rate
+            dword = dfrq * nch * dbps;
+            leos.putInt(dword); // bytes per sec
+            word = (short) (dbps * nch);
+            leos.putShort(word); // block alignment
+            word = (short) (dbps * 8);
+            leos.putShort(word); // bits per sample
+
+            leos.put("data".getBytes());
+            dword = 0;
+            leos.putInt(dword);
+
+            leos.flip();
+            writeBuffers(fpo, leos);
+        }
+
+        if (dither != 0) {
+            int min = 0, max = 0;
+            if (dbps == 1) {
+                min = -0x80;
+                max = 0x7f;
+            }
+            if (dbps == 2) {
+                min = -0x8000;
+                max = 0x7fff;
+            }
+            if (dbps == 3) {
+                min = -0x800000;
+                max = 0x7fffff;
+            }
+            if (dbps == 4) {
+                min = -0x80000000;
+                max = 0x7fffffff;
+            }
+
+            samp = init_shaper(dfrq, nch, min, max, dither, pdf, noiseamp);
+        }
+
+        if (twopass) {
+            double gain = 0;
+            int ch = 0;
+            int fptlen, sumread;
+
+            if (!quiet) {
+                System.err.printf("Pass 1\n");
+            }
+
+            try {
+                if (tmpfn != null) {
+                    ft = new File(tmpfn);
+                } else {
+                    ft = File.createTempFile("ssrc_", ".tmp");
+                }
+                fpto = new FileOutputStream(ft);
+            } catch (IOException e) {
+                throw new IllegalStateException("cannot open temporary file.");
+            }
+
+            //System.err.printf("nch: %d, bps: %d, size: %d, sfrq: %d, dfrq: %d, ???: %d, ???: %d, twopass: %b, dither: %d\n", nch, bps, 8, sfrq, dfrq, 1, length / bps / nch, twopass, dither);
+            if (normalize) {
+                if (sfrq < dfrq) {
+                    peak[0] = upsample(fpi, fpto, nch, bps, 8, sfrq, dfrq, 1, length / bps / nch,
+                            twopass, dither);
+                } else if (sfrq > dfrq) {
+                    peak[0] = downsample(fpi, fpto, nch, bps, 8, sfrq, dfrq, 1, length / bps / nch,
+                            twopass, dither);
+                } else {
+                    peak[0] =
+                            no_src(fpi, fpto, nch, bps, 8, 1, length / bps / nch, twopass, dither);
+                }
+            } else {
+                if (sfrq < dfrq) {
+                    peak[0] = upsample(fpi, fpto, nch, bps, 8, sfrq, dfrq, Math.pow(10, -att / 20),
+                            length / bps / nch, twopass, dither);
+                } else if (sfrq > dfrq) {
+                    peak[0] =
+                            downsample(fpi, fpto, nch, bps, 8, sfrq, dfrq, Math.pow(10, -att / 20),
+                                    length / bps / nch, twopass, dither);
+                } else {
+                    peak[0] = no_src(fpi, fpto, nch, bps, 8, Math.pow(10, -att / 20),
+                            length / bps / nch, twopass, dither);
+                }
+            }
+
+            fpto.close();
+
+            if (!quiet) {
+                System.err.printf("\npeak : %gdB\n", 20 * Math.log10(peak[0]));
+            }
+
+            if (!normalize) {
+                if (peak[0] < Math.pow(10, -att / 20)) {
+                    peak[0] = 1;
+                } else {
+                    peak[0] *= Math.pow(10, att / 20);
+                }
+            } else {
+                peak[0] *= Math.pow(10, att / 20);
+            }
+
+            if (!quiet) {
+                System.err.printf("\nPass 2\n");
+            }
+
+            if (dither != 0) {
+                switch (dbps) {
+                    case 1:
+                        gain = (normalize || peak[0] >= (0x7f - samp) / (double) 0x7f) ?
+                                1 / peak[0] * (0x7f - samp) : 1 / peak[0] * 0x7f;
+                        break;
+                    case 2:
+                        gain = (normalize || peak[0] >= (0x7fff - samp) / (double) 0x7fff) ?
+                                1 / peak[0] * (0x7fff - samp) : 1 / peak[0] * 0x7fff;
+                        break;
+                    case 3:
+                        gain = (normalize || peak[0] >= (0x7fffff - samp) / (double) 0x7fffff) ?
+                                1 / peak[0] * (0x7fffff - samp) : 1 / peak[0] * 0x7fffff;
+                        break;
+                }
+            } else {
+                switch (dbps) {
+                    case 1:
+                        gain = 1 / peak[0] * 0x7f;
+                        break;
+                    case 2:
+                        gain = 1 / peak[0] * 0x7fff;
+                        break;
+                    case 3:
+                        gain = 1 / peak[0] * 0x7fffff;
+                        break;
+                }
+            }
+            randptr = 0;
+
+            setstarttime();
+
+            fptlen = (int) (ft.length() / 8);
+            //System.err.println("tmp: " + fpt.getFilePointer());
+
+            FileChannel fpti = new FileInputStream(ft).getChannel();
+            ByteBuffer leis = ByteBuffer.allocate(8);
+            for (sumread = 0; sumread < fptlen; ) {
+                double f;
+                int s;
+
+                leis.clear();
+                fpti.read(leis);
+                leis.flip();
+                f = leis.getDouble();
+                //if (sumread < 100) {
+                // System.err.printf("2: %06d: %f\n", sumread, f);
+                //}
+                f *= gain;
+                sumread++;
+
+                switch (dbps) {
+                    case 1: {
+                        s = dither != 0 ? do_shaping(f, peak, dither, ch) : RINT(f);
+
+                        ByteBuffer buf = ByteBuffer.allocate(1);
+                        buf.put((byte) (s + 128));
+                        buf.flip();
+
+                        writeBuffers(fpo, buf);
+                    }
+                    break;
+                    case 2: {
+                        s = dither != 0 ? do_shaping(f, peak, dither, ch) : RINT(f);
+
+                        ByteBuffer buf = ByteBuffer.allocate(2).order(ByteOrder.LITTLE_ENDIAN);
+                        buf.putShort((short) s);
+                        buf.flip();
+
+                        writeBuffers(fpo, buf);
+                    }
+                    break;
+                    case 3: {
+                        s = dither != 0 ? do_shaping(f, peak, dither, ch) : RINT(f);
+
+                        ByteBuffer buf = ByteBuffer.allocate(3);
+                        buf.put((byte) (s & 255));
+                        s >>= 8;
+                        buf.put((byte) (s & 255));
+                        s >>= 8;
+                        buf.put((byte) (s & 255));
+                        buf.flip();
+
+                        writeBuffers(fpo, buf);
+                    }
+                    break;
+                }
+
+                ch++;
+                if (ch == nch) {
+                    ch = 0;
+                }
+
+                if ((sumread & 0x3ffff) == 0) {
+                    showprogress((double) sumread / fptlen);
+                }
+            }
+            showprogress(1);
+            if (!quiet) {
+                System.err.printf("\n");
+            }
+            fpti.close();
+            if (ft != null) {
+                //System.err.println("ft: " + ft);
+                if (!ft.delete()) {
+                    System.err.printf("Failed to remove %s\n", ft);
+                }
+            }
+        } else {
+            if (sfrq < dfrq) {
+                peak[0] = upsample(fpi, fpo, nch, bps, dbps, sfrq, dfrq, Math.pow(10, -att / 20),
+                        length / bps / nch, twopass, dither);
+            } else if (sfrq > dfrq) {
+                peak[0] = downsample(fpi, fpo, nch, bps, dbps, sfrq, dfrq, Math.pow(10, -att / 20),
+                        length / bps / nch, twopass, dither);
+            } else {
+                peak[0] = no_src(fpi, fpo, nch, bps, dbps, Math.pow(10, -att / 20),
+                        length / bps / nch, twopass, dither);
+            }
+            if (!quiet) {
+                System.err.printf("\n");
+            }
+        }
+
+        if (dither != 0) {
+            quit_shaper(nch);
+        }
+
+        if (!twopass && peak[0] > 1) {
+            if (!quiet) {
+                System.err.printf("clipping detected : %gdB\n", 20 * Math.log10(peak[0]));
+            }
+        }
+
+        {
+            int dword;
+            int len;
+
+            fpo.close();
+
+            fo = new File(dfn);
+
+            len = (int) fo.length();
+            FileChannel fpo1 = new RandomAccessFile(fo, "rw").getChannel();
+            ByteBuffer leos = ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN);
+
+            dword = len - 8;
+            leos.position(0);
+            leos.limit(4);
+            leos.putInt(dword);
+            leos.flip();
+            fpo1.write(leos, 4);
+
+            dword = len - 44;
+            leos.position(0);
+            leos.limit(4);
+            leos.putInt(dword);
+            leos.flip();
+            fpo1.write(leos, 40);
+
+            fpo1.close();
+        }
+    }
+
+
+    /** */
+    public SSRC(InputStream fpi, OutputStream fpo, int sfrq, int dfrq, int bps, int dbps, int nch,
+                int length, double att, int dither, boolean quiet_) throws IOException {
+        String tmpfn = null;
+        boolean twopass, normalize;
+        int pdf, samp = 0;
+        double noiseamp;
+        double[] peak = new double[]{0};
+        int i;
+
+        // parse command line options
+
+        twopass = false;
+        normalize = false;
+
+        pdf = 0;
+        noiseamp = 0.18;
+
+        if (dither < 0 || dither > 4) {
+            throw new IllegalArgumentException("unrecognized dither type : " + dither);
+        }
+        this.quiet = quiet_;
+
+        if (bps != 1 && bps != 2 && bps != 3 && bps != 4) {
+            throw new IllegalStateException(
+                    "Error : Only 8bit, 16bit, 24bit and 32bit PCM are supported.");
+        }
+
+        if (dbps == -1) {
+            if (bps != 1) {
+                dbps = bps;
+            } else {
+                dbps = 2;
+            }
+            if (dbps == 4) {
+                dbps = 3;
+            }
+        }
+
+        if (dfrq == -1) {
+            dfrq = sfrq;
+        }
+
+        if (dither == -1) {
+            if (dbps < bps) {
+                if (dbps == 1) {
+                    dither = 4;
+                } else {
+                    dither = 3;
+                }
+            } else {
+                dither = 1;
+            }
+        }
+
+        if (!quiet) {
+            final String[] dtype = {"none", "no noise shaping", "triangular spectral shape",
+                    "ATH based noise shaping", "ATH based noise shaping(less amplitude)"};
+            final String[] ptype = {"rectangular", "triangular", "gaussian"};
+            System.err.printf("frequency : %d -> %d\n", sfrq, dfrq);
+            System.err.printf("attenuation : %gdB\n", att);
+            System.err.printf("bits per sample : %d -> %d\n", bps * 8, dbps * 8);
+            System.err.printf("nchannels : %d\n", nch);
+            System.err.printf("length : %d bytes, %g secs\n", length,
+                    (double) length / bps / nch / sfrq);
+            if (dither == 0) {
+                System.err.printf("dither type : none\n");
+            } else {
+                System.err
+                        .printf("dither type : %s, %s p.d.f, amp = %g\n", dtype[dither], ptype[pdf],
+                                noiseamp);
+            }
+            System.err.printf("\n");
+        }
+
+
+        if (dither != 0) {
+            int min = 0, max = 0;
+            if (dbps == 1) {
+                min = -0x80;
+                max = 0x7f;
+            }
+            if (dbps == 2) {
+                min = -0x8000;
+                max = 0x7fff;
+            }
+            if (dbps == 3) {
+                min = -0x800000;
+                max = 0x7fffff;
+            }
+            if (dbps == 4) {
+                min = -0x80000000;
+                max = 0x7fffffff;
+            }
+
+            samp = init_shaper(dfrq, nch, min, max, dither, pdf, noiseamp);
+        }
+
+        if (sfrq < dfrq) {
+            peak[0] = upsample(fpi, fpo, nch, bps, dbps, sfrq, dfrq, Math.pow(10, -att / 20),
+                    length / bps / nch, twopass, dither);
+        } else if (sfrq > dfrq) {
+            peak[0] = downsample(fpi, fpo, nch, bps, dbps, sfrq, dfrq, Math.pow(10, -att / 20),
+                    length / bps / nch, twopass, dither);
+        } else {
+            peak[0] = no_src(fpi, fpo, nch, bps, dbps, Math.pow(10, -att / 20), length / bps / nch,
+                    twopass, dither);
+        }
+
+        if (!quiet) {
+            System.err.printf("\n");
+        }
+
+        if (dither != 0) {
+            quit_shaper(nch);
+        }
+
+        if (!twopass && peak[0] > 1) {
+            if (!quiet) {
+                System.err.printf("clipping detected : %gdB\n", 20 * Math.log10(peak[0]));
+            }
+        }
+    }
+
+    protected byte[] getDataFromByteBuffer(ByteBuffer rawoutbuf) {
+        byte[] tempDataWrt = new byte[rawoutbuf.limit() - rawoutbuf.position()];
+        rawoutbuf.get(tempDataWrt, 0, tempDataWrt.length);
+
+        return tempDataWrt;
+    }
+
+    protected void writeBuffers(OutputStream fpo, ByteBuffer rawoutbuf) {
+        try {
+            fpo.write(getDataFromByteBuffer(rawoutbuf));
+        } catch (IOException e) {
+            // Some problems (Read end dead)
+        }
+    }
+}
+
+/* */

+ 155 - 0
android/src/main/kotlin/cn/i2edu/speech_plugin/audioUtils/audiotransfer/vavi/util/I0Bessel.java

@@ -0,0 +1,155 @@
+/*
+ * Copyright(C) 1996 Takuya OOURA (email: ooura@mmm.t.u-tokyo.ac.jp).
+ * You may use, copy, modify this code for any purpose and
+ * without fee. You may distribute this ORIGINAL package.
+ */
+package cn.i2edu.speech_plugin.audioUtils.audiotransfer.vavi.util;
+
+
+/**
+ * Bessel I_0().
+ *
+ * @author <a href="mailto:ooura@mmm.t.u-tokyo.ac.jp">Takuya OOURA</a>
+ * @author <a href="mailto:vavivavi@yahoo.co.jp">Naohide Sano</a> (nsano)
+ * @version 0.00 060127 nsano port to java version <br>
+ */
+public class I0Bessel {
+    /** */
+    private static final double[] a = {
+        8.5246820682016865877e-11, 2.5966600546497407288e-9,
+        7.9689994568640180274e-8, 1.9906710409667748239e-6,
+        4.0312469446528002532e-5, 6.4499871606224265421e-4,
+        0.0079012345761930579108, 0.071111111109207045212,
+        0.444444444444724909, 1.7777777777777532045,
+        4.0000000000000011182, 3.99999999999999998,
+        1.0000000000000000001,
+        1.1520919130377195927e-10, 2.2287613013610985225e-9,
+        8.1903951930694585113e-8, 1.9821560631611544984e-6,
+        4.0335461940910133184e-5, 6.4495330974432203401e-4,
+        0.0079013012611467520626, 0.071111038160875566622,
+        0.44444450319062699316, 1.7777777439146450067,
+        4.0000000132337935071, 3.9999999968569015366,
+        1.0000000003426703174,
+        1.5476870780515238488e-10, 1.2685004214732975355e-9,
+        9.2776861851114223267e-8, 1.9063070109379044378e-6,
+        4.0698004389917945832e-5, 6.4370447244298070713e-4,
+        0.0079044749458444976958, 0.071105052411749363882,
+        0.44445280640924755082, 1.7777694934432109713,
+        4.0000055808824003386, 3.9999977081165740932,
+        1.0000004333949319118,
+        2.0675200625006793075e-10, -6.1689554705125681442e-10,
+        1.2436765915401571654e-7, 1.5830429403520613423e-6,
+        4.2947227560776583326e-5, 6.3249861665073441312e-4,
+        0.0079454472840953930811, 0.070994327785661860575,
+        0.44467219586283000332, 1.7774588182255374745,
+        4.0003038986252717972, 3.9998233869142057195,
+        1.0000472932961288324,
+        2.7475684794982708655e-10, -3.8991472076521332023e-9,
+        1.9730170483976049388e-7, 5.9651531561967674521e-7,
+        5.1992971474748995357e-5, 5.7327338675433770752e-4,
+        0.0082293143836530412024, 0.069990934858728039037,
+        0.44726764292723985087, 1.7726685170014087784,
+        4.0062907863712704432, 3.9952750700487845355,
+        1.0016354346654179322
+    };
+    /** */
+    private static final double[] b = {
+        6.7852367144945531383e-8, 4.6266061382821826854e-7,
+        6.9703135812354071774e-6, 7.6637663462953234134e-5,
+        7.9113515222612691636e-4, 0.0073401204731103808981,
+        0.060677114958668837046, 0.43994941411651569622,
+        2.7420017097661750609, 14.289661921740860534,
+        59.820609640320710779, 188.78998681199150629,
+        399.8731367825601118, 427.56411572180478514,
+        1.8042097874891098754e-7, 1.2277164312044637357e-6,
+        1.8484393221474274861e-5, 2.0293995900091309208e-4,
+        0.0020918539850246207459, 0.019375315654033949297,
+        0.15985869016767185908, 1.1565260527420641724,
+        7.1896341224206072113, 37.354773811947484532,
+        155.80993164266268457, 489.5211371158540918,
+        1030.9147225169564806, 1093.5883545113746958,
+        4.8017305613187493564e-7, 3.261317843912380074e-6,
+        4.9073137508166159639e-5, 5.3806506676487583755e-4,
+        0.0055387918291051866561, 0.051223717488786549025,
+        0.42190298621367914765, 3.0463625987357355872,
+        18.895299447327733204, 97.915189029455461554,
+        407.13940115493494659, 1274.3088990480582632,
+        2670.9883037012547506, 2815.7166284662544712,
+        1.2789926338424623394e-6, 8.6718263067604918916e-6,
+        1.3041508821299929489e-4, 0.001428224737372747892,
+        0.014684070635768789378, 0.13561403190404185755,
+        1.1152592585977393953, 8.0387088559465389038,
+        49.761318895895479206, 257.2684232313529138,
+        1066.8543146269566231, 3328.3874581009636362,
+        6948.8586598121634874, 7288.4893398212481055,
+        3.409350368197032893e-6, 2.3079025203103376076e-5,
+        3.4691373283901830239e-4, 0.003794994977222908545,
+        0.038974209677945602145, 0.3594948380414878371,
+        2.9522878893539528226, 21.246564609514287056,
+        131.28727387146173141, 677.38107093296675421,
+        2802.3724744545046518, 8718.5731420798254081,
+        18141.348781638832286, 18948.925349296308859
+    };
+    /** */
+    private static final double[] c = {
+        2.5568678676452702768e-15, 3.0393953792305924324e-14,
+        6.3343751991094840009e-13, 1.5041298011833009649e-11,
+        4.4569436918556541414e-10, 1.746393051427167951e-8,
+        1.0059224011079852317e-6, 1.0729838945088577089e-4,
+        0.05150322693642527738,
+        5.2527963991711562216e-15, 7.202118481421005641e-15,
+        7.2561421229904797156e-13, 1.482312146673104251e-11,
+        4.4602670450376245434e-10, 1.7463600061788679671e-8,
+        1.005922609132234756e-6, 1.0729838937545111487e-4,
+        0.051503226936437300716,
+        1.3365917359358069908e-14, -1.2932643065888544835e-13,
+        1.7450199447905602915e-12, 1.0419051209056979788e-11,
+        4.58047881980598326e-10, 1.7442405450073548966e-8,
+        1.0059461453281292278e-6, 1.0729837434500161228e-4,
+        0.051503226940658446941,
+        5.3771611477352308649e-14, -1.1396193006413731702e-12,
+        1.2858641335221653409e-11, -5.9802086004570057703e-11,
+        7.3666894305929510222e-10, 1.6731837150730356448e-8,
+        1.0070831435812128922e-6, 1.0729733111203704813e-4,
+        0.051503227360726294675,
+        3.7819492084858931093e-14, -4.8600496888588034879e-13,
+        1.6898350504817224909e-12, 4.5884624327524255865e-11,
+        1.2521615963377513729e-10, 1.8959658437754727957e-8,
+        1.0020716710561353622e-6, 1.073037119856927559e-4,
+        0.05150322383300230775
+    };
+
+    public static double value(double x) {
+        int k;
+        double w, t, y;
+        w = Math.abs(x);
+        if (w < 8.5) {
+            t = w * w * 0.0625;
+            k = 13 * ((int) t);
+            y = (((((((((((a[k] * t + a[k + 1]) * t +
+                a[k + 2]) * t + a[k + 3]) * t + a[k + 4]) * t +
+                a[k + 5]) * t + a[k + 6]) * t + a[k + 7]) * t +
+                a[k + 8]) * t + a[k + 9]) * t + a[k + 10]) * t +
+                a[k + 11]) * t + a[k + 12];
+        } else if (w < 12.5) {
+            k = (int) w;
+            t = w - k;
+            k = 14 * (k - 8);
+            y = ((((((((((((b[k] * t + b[k + 1]) * t +
+                b[k + 2]) * t + b[k + 3]) * t + b[k + 4]) * t +
+                b[k + 5]) * t + b[k + 6]) * t + b[k + 7]) * t +
+                b[k + 8]) * t + b[k + 9]) * t + b[k + 10]) * t +
+                b[k + 11]) * t + b[k + 12]) * t + b[k + 13];
+        } else {
+            t = 60 / w;
+            k = 9 * ((int) t);
+            y = ((((((((c[k] * t + c[k + 1]) * t +
+                c[k + 2]) * t + c[k + 3]) * t + c[k + 4]) * t +
+                c[k + 5]) * t + c[k + 6]) * t + c[k + 7]) * t +
+                c[k + 8]) * Math.sqrt(t) * Math.exp(w);
+        }
+        return y;
+    }
+}
+
+/* */

+ 2604 - 0
android/src/main/kotlin/cn/i2edu/speech_plugin/audioUtils/audiotransfer/vavi/util/SplitRadixFft.java

@@ -0,0 +1,2604 @@
+/*
+ * Copyright Takuya OOURA, 1996-2001
+ *
+ * You may use, copy, modify and distribute this code
+ * for any purpose (include commercial use) and without fee.
+ * Please refer to this package when you modify this code.
+ */
+package cn.i2edu.speech_plugin.audioUtils.audiotransfer.vavi.util;
+
+
+
+
+/**
+ * Fast Fourier/Cosine/Sine Transform.
+ * <pre>
+ *  dimension   :one
+ *  data length :power of 2
+ *  decimation  :frequency
+ *  radix       :<b>split-radix</b>
+ *  data        :inplace
+ *  table       :use
+ * </pre>
+ * <h4>Appendix:</h4>
+ * <p>
+ *  The cos/sin table is recalculated when the larger table required.
+ *  w[] and ip[] are compatible with all routines.
+ * </p>
+ * @author <a href="mailto:ooura@mmm.t.u-tokyo.ac.jp">Takuya OOURA</a>
+ * @author <a href="mailto:vavivavi@yahoo.co.jp">Naohide Sano</a> (nsano)
+ * @version 0.00 060127 nsano port to java version <br>
+ */
+@SuppressWarnings({"PointlessArithmeticExpression", "JavaDoc", "SameParameterValue", "FinalPrivateMethod"})
+public class SplitRadixFft {
+
+    /** */
+    private static final int CDFT_RECURSIVE_N = 512;
+
+    /**
+     * Complex Discrete Fourier Transform.
+     * <pre>
+     *  [definition]
+     *      &lt;case1&gt;
+     *          X[k] = sum_j=0&amp;circ;n-1 x[j]*exp(2*pi*i*j*k/n), 0&lt;=k&lt;n
+     *      &lt;case2&gt;
+     *          X[k] = sum_j=0&amp;circ;n-1 x[j]*exp(-2*pi*i*j*k/n), 0&lt;=k&lt;n
+     *      (notes: sum_j=0&amp;circ;n-1 is a summation from j=0 to n-1)
+     *  [usage]
+     *      &lt;case1&gt;
+     *          ip[0] = 0; // first time only
+     *          cdft(2*n, 1, a, ip, w);
+     *      &lt;case2&gt;
+     *          ip[0] = 0; // first time only
+     *          cdft(2*n, -1, a, ip, w);
+     *  [remark]
+     *      Inverse of
+     *          cdft(2*n, -1, a, ip, w);
+     *      is
+     *          cdft(2*n, 1, a, ip, w);
+     *          for (j = 0; j &lt;= 2 * n - 1; j++) {
+     *              a[j] *= 1.0 / n;
+     *          }
+     *      .
+     * </pre>
+     * @param n 2*n data length (int)
+     *          n &gt;= 1, n = power of 2
+     * @param isgn
+     * @param a a[0...2*n-1] input/output data (REAL *)
+     *                      input data
+     *                          a[2*j] = Re(x[j]),
+     *                          a[2*j+1] = Im(x[j]), 0&lt;=j&lt;n
+     *                      output data
+     *                          a[2*k] = Re(X[k]),
+     *                          a[2*k+1] = Im(X[k]), 0&lt;=k&lt;n
+     * @param ip ip[0...*] work area for bit reversal (int *)
+     *           length of ip &gt;= 2+sqrt(n)
+     *           strictly,
+     *           length of ip &gt;=
+     *              2+(1&lt;&lt;(int)(log(n+0.5)/log(2))/2).
+     *           ip[0],ip[1] are pointers of the cos/sin table.
+     * @param w w[0...n/2-1] cos/sin table (REAL *)
+     *          w[],ip[] are initialized if ip[0] == 0.
+     */
+    public void cdft(int n, int isgn, double[] a, int[] ip, double[] w) {
+        int nw;
+
+        nw = ip[0];
+        if (n > (nw << 2)) {
+            nw = n >> 2;
+            makewt(nw, ip, w);
+        }
+        if (isgn >= 0) {
+            cftfsub(n, a, ip, 2, nw, w);
+        } else {
+            cftbsub(n, a, ip, 2, nw, w);
+        }
+    }
+
+    /**
+     * Real Discrete Fourier Transform.
+     * <pre>
+     *  [definition]
+     *      &lt;case1&gt; RDFT
+     *          R[k] = sum_j = 0 &amp; &circ; (n - 1) a[j] * cos(2 * pi * j * k / n), 0 &lt;= k &lt;= n / 2
+     *          I[k] = sum_j = 0 &amp; &circ; (n - 1) a[j] * sin(2 * pi * j * k / n), 0 &lt; k &lt; n / 2
+     *      &lt;case2&gt; IRDFT (excluding scale)
+     *          a[k] = (R[0] + R[n / 2] * cos(pi * k)) / 2 +
+     *              sum_j = 1 &amp; &circ; (n / 2 - 1) R[j] * cos(2 * pi * j * k / n) +
+     *              sum_j = 1 &amp; &circ; (n / 2 - 1) I[j] * sin(2 * pi * j * k / n), 0 &lt;= k &lt; n
+     *  [usage]
+     *      &lt;case1&gt;
+     *          ip[0] = 0; // first time only
+     *          rdft(n, 1, a, ip, w);
+     *      &lt;case2&gt;
+     *          ip[0] = 0; // first time only
+     *          rdft(n, -1, a, ip, w);
+     *  [remark]
+     *      Inverse of
+     *          rdft(n, 1, a, ip, w);
+     *      is
+     *          rdft(n, -1, a, ip, w);
+     *          for (j = 0; j &lt;= n - 1; j++) {
+     *              a[j] *= 2.0 / n;
+     *          }
+     *      .
+     * </pre>
+     * @param n data length <br>
+     *  n &gt;= 2, n = power of 2
+     * @param isgn
+     * @param a [0...n-1] input/output data
+     * <pre>
+     *  &lt;case1&gt;
+     *      output data
+     *          a[2 * k] = R[k], 0 &lt;= k &lt; n / 2
+     *          a[2 * k + 1] = I[k], 0 &lt; k &lt; n / 2
+     *          a[1] = R[n/2]
+     *  &lt;case2&gt;
+     *      input data
+     *          a[2 * j] = R[j], 0 &lt;= j &lt; n / 2
+     *          a[2 * j + 1] = I[j], 0 &lt; j &lt; n / 2
+     *          a[1] = R[n / 2]
+     * </pre>
+     * @param ip [0...*] work area for bit reversal
+     * <pre>
+     *  length of ip &gt;= 2 + sqrt(n / 2)
+     *  strictly,
+     *  length of ip &gt;=
+     *      2 + (1 &lt;&lt; (int) (log(n / 2 + 0.5) / log(2)) / 2).
+     * </pre>
+     *  ip[0],ip[1] are pointers of the cos/sin table.
+     * @param w [0...n/2-1] cos/sin table <br>
+     *  w[],ip[] are initialized if ip[0] == 0.
+     */
+    public void rdft(int n, int isgn, double[] a, int[] ip, double[] w) {
+        int nw, nc;
+        double xi;
+
+        nw = ip[0];
+        if (n > (nw << 2)) {
+            nw = n >> 2;
+            makewt(nw, ip, w);
+        }
+        nc = ip[1];
+        if (n > (nc << 2)) {
+            nc = n >> 2;
+            makect(nc, ip, w, nw);
+        }
+        if (isgn >= 0) {
+            if (n > 4) {
+                cftfsub(n, a, ip, 2, nw, w);
+                rftfsub(n, a, nc, w, nw);
+            } else if (n == 4) {
+                cftfsub(n, a, ip, 2, nw, w);
+            }
+            xi = a[0] - a[1];
+            a[0] += a[1];
+            a[1] = xi;
+        } else {
+            a[1] = 0.5 * (a[0] - a[1]);
+            a[0] -= a[1];
+            if (n > 4) {
+                rftbsub(n, a, nc, w, nw);
+                cftbsub(n, a, ip, 2, nw, w);
+            } else if (n == 4) {
+                cftbsub(n, a, ip, 2, nw, w);
+            }
+        }
+    }
+
+    /**
+     * Discrete Cosine Transform.
+     * <pre>
+     *  [definition]
+     *      &lt;case1&gt; IDCT (excluding scale)
+     *          C[k] = sum_j=0&amp;circ;n-1 a[j]*cos(pi*j*(k+1/2)/n), 0&lt;=k&lt;n
+     *      &lt;case2&gt; DCT
+     *          C[k] = sum_j=0&amp;circ;n-1 a[j]*cos(pi*(j+1/2)*k/n), 0&lt;=k&lt;n
+     *  [usage]
+     *      &lt;case1&gt;
+     *          ip[0] = 0; // first time only
+     *          ddct(n, 1, a, ip, w);
+     *      &lt;case2&gt;
+     *          ip[0] = 0; // first time only
+     *          ddct(n, -1, a, ip, w);
+     *  [remark]
+     *      Inverse of
+     *          ddct(n, -1, a, ip, w);
+     *      is
+     *          a[0] *= 0.5;
+     *          ddct(n, 1, a, ip, w);
+     *          for (j = 0; j &lt;= n - 1; j++) {
+     *              a[j] *= 2.0 / n;
+     *          }
+     *      .
+     * </pre>
+     * @param n data length (int)
+     * <pre>
+     *  n &gt;= 2, n = power of 2
+     * </pre>
+     * @param isgn
+     * @param a [0...n-1] input/output data (REAL *)
+     * <pre>
+     *  output data
+     *      a[k] = C[k], 0&lt;=k&lt;n
+     * </pre>
+     * @param ip [0...*] work area for bit reversal (int *)
+     * <pre>
+     *  length of ip &gt;= 2+sqrt(n/2)
+     *  strictly,
+     *  length of ip &gt;=
+     *      2+(1&lt;&lt;(int)(log(n/2+0.5)/log(2))/2).
+     *  ip[0],ip[1] are pointers of the cos/sin table.
+     * </pre>
+     * @param w [0...n*5/4-1] cos/sin table (REAL *)
+     * <pre>
+     *  w[],ip[] are initialized if ip[0] == 0.
+     * </pre>
+     */
+    public void ddct(int n, int isgn, double[] a, int[] ip, double[] w) {
+        int j, nw, nc;
+        double xr;
+
+        nw = ip[0];
+        if (n > (nw << 2)) {
+            nw = n >> 2;
+            makewt(nw, ip, w);
+        }
+        nc = ip[1];
+        if (n > nc) {
+            nc = n;
+            makect(nc, ip, w, nw);
+        }
+        if (isgn < 0) {
+            xr = a[n - 1];
+            for (j = n - 2; j >= 2; j -= 2) {
+                a[j + 1] = a[j] - a[j - 1];
+                a[j] += a[j - 1];
+            }
+            a[1] = a[0] - xr;
+            a[0] += xr;
+            if (n > 4) {
+                rftbsub(n, a, nc, w, nw);
+                cftbsub(n, a, ip, 2, nw, w);
+            } else if (n == 4) {
+                cftbsub(n, a, ip, 2, nw, w);
+            }
+        }
+        dctsub(n, a, nc, w, nw);
+        if (isgn >= 0) {
+            if (n > 4) {
+                cftfsub(n, a, ip, 2, nw, w);
+                rftfsub(n, a, nc, w, nw);
+            } else if (n == 4) {
+                cftfsub(n, a, ip, 2, nw, w);
+            }
+            xr = a[0] - a[1];
+            a[0] += a[1];
+            for (j = 2; j < n; j += 2) {
+                a[j - 1] = a[j] - a[j + 1];
+                a[j] += a[j + 1];
+            }
+            a[n - 1] = xr;
+        }
+    }
+
+    /**
+     * Discrete Sine Transform.
+     * <pre>
+     *  [definition]
+     *      &lt;case1&gt; IDST (excluding scale)
+     *          S[k] = sum_j=1&circ;n A[j]*sin(pi*j*(k+1/2)/n), 0&lt;=k&lt;n
+     *      &lt;case2&gt; DST
+     *          S[k] = sum_j=0&circ;n-1 a[j]*sin(pi*(j+1/2)*k/n), 0&lt;k&lt;=n
+     *  [usage]
+     *      &lt;case1&gt;
+     *          ip[0] = 0; // first time only
+     *          ddst(n, 1, a, ip, w);
+     *      &lt;case2&gt;
+     *          ip[0] = 0; // first time only
+     *          ddst(n, -1, a, ip, w);
+     *  [remark]
+     *      Inverse of
+     *          ddst(n, -1, a, ip, w);
+     *      is
+     *          a[0] *= 0.5;
+     *          ddst(n, 1, a, ip, w);
+     *          for (j = 0; j &lt;= n - 1; j++) {
+     *              a[j] *= 2.0 / n;
+     *          }
+     *      .
+     * </pre>
+     * @param n data length (int)
+     *                      n &gt;= 2, n = power of 2
+     * @param isgn
+     * @param a [0...n-1] input/output data (REAL *)
+     *                      &lt;case1&gt;
+     *                          input data
+     *                              a[j] = A[j], 0&lt;j&lt;n
+     *                              a[0] = A[n]
+     *                          output data
+     *                              a[k] = S[k], 0&lt;=k&lt;n
+     *                      &lt;case2&gt;
+     *                          output data
+     *                              a[k] = S[k], 0&lt;k&lt;n
+     *                              a[0] = S[n]
+     * @param ip [0...*] work area for bit reversal (int *)
+     *                      length of ip &gt;= 2+sqrt(n/2)
+     *                      strictly,
+     *                      length of ip &gt;=
+     *                          2+(1&lt;&lt;(int)(log(n/2+0.5)/log(2))/2).
+     *                      ip[0],ip[1] are pointers of the cos/sin table.
+     * @param w [0...n*5/4-1] cos/sin table (REAL *)
+     *                      w[],ip[] are initialized if ip[0] == 0.
+     */
+    public void ddst(int n, int isgn, double[] a, int[] ip, double[] w) {
+        int j, nw, nc;
+        double xr;
+
+        nw = ip[0];
+        if (n > (nw << 2)) {
+            nw = n >> 2;
+            makewt(nw, ip, w);
+        }
+        nc = ip[1];
+        if (n > nc) {
+            nc = n;
+            makect(nc, ip, w, nw);
+        }
+        if (isgn < 0) {
+            xr = a[n - 1];
+            for (j = n - 2; j >= 2; j -= 2) {
+                a[j + 1] = -a[j] - a[j - 1];
+                a[j] -= a[j - 1];
+            }
+            a[1] = a[0] + xr;
+            a[0] -= xr;
+            if (n > 4) {
+                rftbsub(n, a, nc, w, nw);
+                cftbsub(n, a, ip, 2, nw, w);
+            } else if (n == 4) {
+                cftbsub(n, a, ip, 2, nw, w);
+            }
+        }
+        dstsub(n, a, nc, w, nw);
+        if (isgn >= 0) {
+            if (n > 4) {
+                cftfsub(n, a, ip, 2, nw, w);
+                rftfsub(n, a, nc, w, nw);
+            } else if (n == 4) {
+                cftfsub(n, a, ip, 2, nw, w);
+            }
+            xr = a[0] - a[1];
+            a[0] += a[1];
+            for (j = 2; j < n; j += 2) {
+                a[j - 1] = -a[j] - a[j + 1];
+                a[j] -= a[j + 1];
+            }
+            a[n - 1] = -xr;
+        }
+    }
+
+    /**
+     * Cosine Transform of RDFT (Real Symmetric DFT).
+     * <pre>
+     *  [definition]
+     *      C[k] = sum_j=0&circ;n a[j]*cos(pi*j*k/n), 0&lt;=k&lt;=n
+     *  [usage]
+     *      ip[0] = 0; // first time only
+     *      dfct(n, a, t, ip, w);
+     *  [parameters]
+     *  [remark]
+     *      Inverse of
+     *          a[0] *= 0.5;
+     *          a[n] *= 0.5;
+     *          dfct(n, a, t, ip, w);
+     *      is
+     *          a[0] *= 0.5;
+     *          a[n] *= 0.5;
+     *          dfct(n, a, t, ip, w);
+     *          for (j = 0; j &lt;= n; j++) {
+     *              a[j] *= 2.0 / n;
+     *          }
+     *      .
+     * </pre>
+     * @param n data length - 1 (int)
+     * <pre>
+     *  n &gt;= 2, n = power of 2
+     * </pre>
+     * @param a [0...n] input/output data (REAL *)
+     * <pre>
+     *  output data
+     *      a[k] = C[k], 0&lt;=k&lt;=n
+     * </pre>
+     * @param t [0...n/2] work area (REAL *)
+     * @param ip [0...*] work area for bit reversal (int *)
+     * <pre>
+     *  length of ip &gt;= 2+sqrt(n/4)
+     *  strictly,
+     *  length of ip &gt;=
+     *      2+(1&lt;&lt;(int)(log(n/4+0.5)/log(2))/2).
+     *  ip[0],ip[1] are pointers of the cos/sin table.
+     * </pre>
+     * @param w [0...n*5/8-1] cos/sin table (REAL *)
+     * <pre>
+     *  w[],ip[] are initialized if ip[0] == 0.
+     * </pre>
+     */
+    public void dfct(int n, double[] a, double[] t, int[] ip, double[] w) {
+        int j, k, l, m, mh, nw, nc;
+        double xr, xi, yr, yi;
+
+        nw = ip[0];
+        if (n > (nw << 3)) {
+            nw = n >> 3;
+            makewt(nw, ip, w);
+        }
+        nc = ip[1];
+        if (n > (nc << 1)) {
+            nc = n >> 1;
+            makect(nc, ip, w, nw);
+        }
+        m = n >> 1;
+        yi = a[m];
+        xi = a[0] + a[n];
+        a[0] -= a[n];
+        t[0] = xi - yi;
+        t[m] = xi + yi;
+        if (n > 2) {
+            mh = m >> 1;
+            for (j = 1; j < mh; j++) {
+                k = m - j;
+                xr = a[j] - a[n - j];
+                xi = a[j] + a[n - j];
+                yr = a[k] - a[n - k];
+                yi = a[k] + a[n - k];
+                a[j] = xr;
+                a[k] = yr;
+                t[j] = xi - yi;
+                t[k] = xi + yi;
+            }
+            t[mh] = a[mh] + a[n - mh];
+            a[mh] -= a[n - mh];
+            dctsub(m, a, nc, w, nw);
+            if (m > 4) {
+                cftfsub(m, a, ip, 2, nw, w);
+                rftfsub(m, a, nc, w, nw);
+            } else if (m == 4) {
+                cftfsub(m, a, ip, 2, nw, w);
+            }
+            a[n - 1] = a[0] - a[1];
+            a[1] = a[0] + a[1];
+            for (j = m - 2; j >= 2; j -= 2) {
+                a[2 * j + 1] = a[j] + a[j + 1];
+                a[2 * j - 1] = a[j] - a[j + 1];
+            }
+            l = 2;
+            m = mh;
+            while (m >= 2) {
+                dctsub(m, t, nc, w, nw);
+                if (m > 4) {
+                    cftfsub(m, t, ip, 2, nw, w);
+                    rftfsub(m, t, nc, w, nw);
+                } else if (m == 4) {
+                    cftfsub(m, t, ip, 2, nw, w);
+                }
+                a[n - l] = t[0] - t[1];
+                a[l] = t[0] + t[1];
+                k = 0;
+                for (j = 2; j < m; j += 2) {
+                    k += l << 2;
+                    a[k - l] = t[j] - t[j + 1];
+                    a[k + l] = t[j] + t[j + 1];
+                }
+                l <<= 1;
+                mh = m >> 1;
+                for (j = 0; j < mh; j++) {
+                    k = m - j;
+                    t[j] = t[m + k] - t[m + j];
+                    t[k] = t[m + k] + t[m + j];
+                }
+                t[mh] = t[m + mh];
+                m = mh;
+            }
+            a[l] = t[0];
+            a[n] = t[2] - t[1];
+            a[0] = t[2] + t[1];
+        } else {
+            a[1] = a[0];
+            a[2] = t[0];
+            a[0] = t[1];
+        }
+    }
+
+    /**
+     * Sine Transform of RDFT (Real Anti-symmetric DFT).
+     * <pre>
+     *  [definition]
+     *      S[k] = sum_j=1&amp;circ;n-1 a[j]*sin(pi*j*k/n), 0&lt;k&lt;n
+     *  [usage]
+     *      ip[0] = 0; // first time only
+     *      dfst(n, a, t, ip, w);
+     *  [remark]
+     *      Inverse of
+     *          dfst(n, a, t, ip, w);
+     *      is
+     *          dfst(n, a, t, ip, w);
+     *          for (j = 1; j &lt;= n - 1; j++) {
+     *              a[j] *= 2.0 / n;
+     *          }
+     *      .
+     * </pre>
+     * @param n data length + 1 (int)
+     * <pre>
+     *  n &gt;= 2, n = power of 2
+     * </pre>
+     * @param a [0...n-1] input/output data (REAL *)
+     * <pre>
+     *  output data
+     *      a[k] = S[k], 0&lt;k&lt;n
+     *      (a[0] is used for work area)
+     * </pre>
+     * @param t [0...n/2-1] work area (REAL *)
+     * @param ip [0...*] work area for bit reversal (int *)
+     * <pre>
+     *  length of ip &gt;= 2+sqrt(n/4)
+     *  strictly,
+     *  length of ip &gt;=
+     *      2+(1&lt;&lt;(int)(log(n/4+0.5)/log(2))/2).
+     *  ip[0],ip[1] are pointers of the cos/sin table.
+     * </pre>
+     * @param w [0...n*5/8-1] cos/sin table (REAL *)
+     * <pre>
+     *  w[],ip[] are initialized if ip[0] == 0.
+     * </pre>
+     */
+    public void dfst(int n, double[] a, double[] t, int[] ip, double[] w) {
+        int j, k, l, m, mh, nw, nc;
+        double xr, xi, yr, yi;
+
+        nw = ip[0];
+        if (n > (nw << 3)) {
+            nw = n >> 3;
+            makewt(nw, ip, w);
+        }
+        nc = ip[1];
+        if (n > (nc << 1)) {
+            nc = n >> 1;
+            makect(nc, ip, w, nw);
+        }
+        if (n > 2) {
+            m = n >> 1;
+            mh = m >> 1;
+            for (j = 1; j < mh; j++) {
+                k = m - j;
+                xr = a[j] + a[n - j];
+                xi = a[j] - a[n - j];
+                yr = a[k] + a[n - k];
+                yi = a[k] - a[n - k];
+                a[j] = xr;
+                a[k] = yr;
+                t[j] = xi + yi;
+                t[k] = xi - yi;
+            }
+            t[0] = a[mh] - a[n - mh];
+            a[mh] += a[n - mh];
+            a[0] = a[m];
+            dstsub(m, a, nc, w, nw);
+            if (m > 4) {
+                cftfsub(m, a, ip, 2, nw, w);
+                rftfsub(m, a, nc, w, nw);
+            } else if (m == 4) {
+                cftfsub(m, a, ip, 2, nw, w);
+            }
+            a[n - 1] = a[1] - a[0];
+            a[1] = a[0] + a[1];
+            for (j = m - 2; j >= 2; j -= 2) {
+                a[2 * j + 1] = a[j] - a[j + 1];
+                a[2 * j - 1] = -a[j] - a[j + 1];
+            }
+            l = 2;
+            m = mh;
+            while (m >= 2) {
+                dstsub(m, t, nc, w, nw);
+                if (m > 4) {
+                    cftfsub(m, t, ip, 2, nw, w);
+                    rftfsub(m, t, nc, w, nw);
+                } else if (m == 4) {
+                    cftfsub(m, t, ip, 2, nw, w);
+                }
+                a[n - l] = t[1] - t[0];
+                a[l] = t[0] + t[1];
+                k = 0;
+                for (j = 2; j < m; j += 2) {
+                    k += l << 2;
+                    a[k - l] = -t[j] - t[j + 1];
+                    a[k + l] = t[j] - t[j + 1];
+                }
+                l <<= 1;
+                mh = m >> 1;
+                for (j = 1; j < mh; j++) {
+                    k = m - j;
+                    t[j] = t[m + k] + t[m + j];
+                    t[k] = t[m + k] - t[m + j];
+                }
+                t[0] = t[m + mh];
+                m = mh;
+            }
+            a[l] = t[0];
+        }
+        a[0] = 0;
+    }
+
+    // -------- initializing routines --------
+
+    /** */
+    private void makewt(int nw, int[] ip, double[] w) {
+        int j, nwh, nw0, nw1;
+        double delta, wn4r, wk1r, wk1i, wk3r, wk3i;
+
+        ip[0] = nw;
+        ip[1] = 1;
+        if (nw > 2) {
+            nwh = nw >> 1;
+//          delta = Math.atan(1.0) / nwh;
+            delta = Math.PI / 4 / nwh;
+            wn4r = Math.cos(delta * nwh);
+            w[0] = 1;
+            w[1] = wn4r;
+            if (nwh >= 4) {
+                w[2] = 0.5 / Math.cos(delta * 2);
+                w[3] = 0.5 / Math.cos(delta * 6);
+            }
+            for (j = 4; j < nwh; j += 4) {
+                w[j] = Math.cos(delta * j);
+                w[j + 1] = Math.sin(delta * j);
+                w[j + 2] = Math.cos(3 * delta * j);
+                w[j + 3] = Math.sin(3 * delta * j);
+            }
+            nw0 = 0;
+            while (nwh > 2) {
+                nw1 = nw0 + nwh;
+                nwh >>= 1;
+                w[nw1] = 1;
+                w[nw1 + 1] = wn4r;
+                if (nwh >= 4) {
+                    wk1r = w[nw0 + 4];
+                    wk3r = w[nw0 + 6];
+                    w[nw1 + 2] = 0.5 / wk1r;
+                    w[nw1 + 3] = 0.5 / wk3r;
+                }
+                for (j = 4; j < nwh; j += 4) {
+                    wk1r = w[nw0 + 2 * j];
+                    wk1i = w[nw0 + 2 * j + 1];
+                    wk3r = w[nw0 + 2 * j + 2];
+                    wk3i = w[nw0 + 2 * j + 3];
+                    w[nw1 + j] = wk1r;
+                    w[nw1 + j + 1] = wk1i;
+                    w[nw1 + j + 2] = wk3r;
+                    w[nw1 + j + 3] = wk3i;
+                }
+                nw0 = nw1;
+            }
+        }
+    }
+
+    /** */
+    private void makect(int nc, int[] ip, double[] c, int cP) {
+        int j, nch;
+        double delta;
+
+        ip[1] = nc;
+        if (nc > 1) {
+            nch = nc >> 1;
+//          delta = Math.atan(1.0) / nch;
+            delta = Math.PI / 4 / nch;
+            c[cP + 0] = Math.cos(delta * nch);
+            c[cP + nch] = 0.5 * c[cP + 0];
+            for (j = 1; j < nch; j++) {
+                c[cP + j] = 0.5 * Math.cos(delta * j);
+                c[cP + nc - j] = 0.5 * Math.sin(delta * j);
+            }
+        }
+    }
+
+    // -------- child routines --------
+
+    /**
+     * 2nd
+     * @see #rdft(int, int, double[], int[], double[])
+     * @see #ddct(int, int, double[], int[], double[])
+     * @see #cdft(int, int, double[], int[], double[])
+     * @see #ddst(int, int, double[], int[], double[])
+     * @see #dfst(int, double[], double[], int[], double[])
+     * @see #dfct(int, double[], double[], int[], double[])
+     */
+    private void cftfsub(int n, double[] a, int[] ip, int ipP, int nw, double[] w) {
+        int m;
+
+        if (n > 32) {
+            m = n >> 2;
+            cftf1st(n, a, w, nw - m);
+            if (n > CDFT_RECURSIVE_N) {
+                cftrec1(m, a, 0, nw, w);
+                cftrec2(m, a, m, nw, w);
+                cftrec1(m, a, 2 * m, nw, w);
+                cftrec1(m, a, 3 * m, nw, w);
+            } else if (m > 32) {
+                cftexp1(n, a, 0, nw, w);
+            } else {
+                cftfx41(n, a, 0, nw, w);
+            }
+            bitrv2(n, ip, ipP, a);
+        } else if (n > 8) {
+            if (n == 32) {
+                cftf161(a, 0, w, nw - 8);
+                bitrv216(a);
+            } else {
+                cftf081(a, 0, w, 0);
+                bitrv208(a);
+            }
+        } else if (n == 8) {
+            cftf040(a);
+        } else if (n == 4) {
+            cftx020(a);
+        }
+    }
+
+    /**
+     * 2nd
+     * @see #rdft(int, int, double[], int[], double[])
+     * @see #ddct(int, int, double[], int[], double[])
+     * @see #cdft(int, int, double[], int[], double[])
+     * @see #ddst(int, int, double[], int[], double[])
+     */
+    private void cftbsub(int n, double[] a, int[] ip, int ipP, int nw, double[] w) {
+        int m;
+
+        if (n > 32) {
+            m = n >> 2;
+            cftb1st(n, a, w, nw - m);
+            if (n > CDFT_RECURSIVE_N) {
+                cftrec1(m, a, 0, nw, w);
+                cftrec2(m, a, m, nw, w);
+                cftrec1(m, a, 2 * m, nw, w);
+                cftrec1(m, a, 3 * m, nw, w);
+            } else if (m > 32) {
+                cftexp1(n, a, 0, nw, w);
+            } else {
+                cftfx41(n, a, 0, nw, w);
+            }
+            bitrv2conj(n, ip, ipP, a);
+        } else if (n > 8) {
+            if (n == 32) {
+                cftf161(a, 0, w, nw - 8);
+                bitrv216neg(a);
+            } else {
+                cftf081(a, 0, w, 0);
+                bitrv208neg(a);
+            }
+        } else if (n == 8) {
+            cftb040(a);
+        } else if (n == 4) {
+            cftx020(a);
+        }
+    }
+
+    /**
+     * 3rd
+     * @see #cftfsub(int, double[], int[], int, int, double[])
+     */
+    private final void bitrv2(int n, int[] ip, int ipP, double[] a) {
+        int j, j1, k, k1, l, m, m2;
+        double xr, xi, yr, yi;
+
+        ip[ipP + 0] = 0;
+        l = n;
+        m = 1;
+        while ((m << 3) < l) {
+            l >>= 1;
+            for (j = 0; j < m; j++) {
+                ip[ipP + m + j] = ip[ipP + j] + l;
+            }
+            m <<= 1;
+        }
+        m2 = 2 * m;
+        if ((m << 3) == l) {
+            for (k = 0; k < m; k++) {
+                for (j = 0; j < k; j++) {
+                    j1 = 2 * j + ip[ipP + k];
+                    k1 = 2 * k + ip[ipP + j];
+                    xr = a[j1];
+                    xi = a[j1 + 1];
+                    yr = a[k1];
+                    yi = a[k1 + 1];
+                    a[j1] = yr;
+                    a[j1 + 1] = yi;
+                    a[k1] = xr;
+                    a[k1 + 1] = xi;
+                    j1 += m2;
+                    k1 += 2 * m2;
+                    xr = a[j1];
+                    xi = a[j1 + 1];
+                    yr = a[k1];
+                    yi = a[k1 + 1];
+                    a[j1] = yr;
+                    a[j1 + 1] = yi;
+                    a[k1] = xr;
+                    a[k1 + 1] = xi;
+                    j1 += m2;
+                    k1 -= m2;
+                    xr = a[j1];
+                    xi = a[j1 + 1];
+                    yr = a[k1];
+                    yi = a[k1 + 1];
+                    a[j1] = yr;
+                    a[j1 + 1] = yi;
+                    a[k1] = xr;
+                    a[k1 + 1] = xi;
+                    j1 += m2;
+                    k1 += 2 * m2;
+                    xr = a[j1];
+                    xi = a[j1 + 1];
+                    yr = a[k1];
+                    yi = a[k1 + 1];
+                    a[j1] = yr;
+                    a[j1 + 1] = yi;
+                    a[k1] = xr;
+                    a[k1 + 1] = xi;
+                }
+                j1 = 2 * k + m2 + ip[ipP + k];
+                k1 = j1 + m2;
+                xr = a[j1];
+                xi = a[j1 + 1];
+                yr = a[k1];
+                yi = a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+            }
+        } else {
+            for (k = 1; k < m; k++) {
+                for (j = 0; j < k; j++) {
+                    j1 = 2 * j + ip[ipP + k];
+                    k1 = 2 * k + ip[ipP + j];
+                    xr = a[j1];
+                    xi = a[j1 + 1];
+                    yr = a[k1];
+                    yi = a[k1 + 1];
+                    a[j1] = yr;
+                    a[j1 + 1] = yi;
+                    a[k1] = xr;
+                    a[k1 + 1] = xi;
+                    j1 += m2;
+                    k1 += m2;
+                    xr = a[j1];
+                    xi = a[j1 + 1];
+                    yr = a[k1];
+                    yi = a[k1 + 1];
+                    a[j1] = yr;
+                    a[j1 + 1] = yi;
+                    a[k1] = xr;
+                    a[k1 + 1] = xi;
+                }
+            }
+        }
+    }
+
+    /**
+     * 3rd
+     * @see #cftbsub(int, double[], int[], int, int, double[])
+     */
+    private final void bitrv2conj(int n, int[] ip, int ipP, double[] a) {
+        int j, j1, k, k1, l, m, m2;
+        double xr, xi, yr, yi;
+
+        ip[ipP + 0] = 0;
+        l = n;
+        m = 1;
+        while ((m << 3) < l) {
+            l >>= 1;
+            for (j = 0; j < m; j++) {
+                ip[ipP + m + j] = ip[ipP + j] + l;
+            }
+            m <<= 1;
+        }
+        m2 = 2 * m;
+        if ((m << 3) == l) {
+            for (k = 0; k < m; k++) {
+                for (j = 0; j < k; j++) {
+                    j1 = 2 * j + ip[ipP + k];
+                    k1 = 2 * k + ip[ipP + j];
+                    xr = a[j1];
+                    xi = -a[j1 + 1];
+                    yr = a[k1];
+                    yi = -a[k1 + 1];
+                    a[j1] = yr;
+                    a[j1 + 1] = yi;
+                    a[k1] = xr;
+                    a[k1 + 1] = xi;
+                    j1 += m2;
+                    k1 += 2 * m2;
+                    xr = a[j1];
+                    xi = -a[j1 + 1];
+                    yr = a[k1];
+                    yi = -a[k1 + 1];
+                    a[j1] = yr;
+                    a[j1 + 1] = yi;
+                    a[k1] = xr;
+                    a[k1 + 1] = xi;
+                    j1 += m2;
+                    k1 -= m2;
+                    xr = a[j1];
+                    xi = -a[j1 + 1];
+                    yr = a[k1];
+                    yi = -a[k1 + 1];
+                    a[j1] = yr;
+                    a[j1 + 1] = yi;
+                    a[k1] = xr;
+                    a[k1 + 1] = xi;
+                    j1 += m2;
+                    k1 += 2 * m2;
+                    xr = a[j1];
+                    xi = -a[j1 + 1];
+                    yr = a[k1];
+                    yi = -a[k1 + 1];
+                    a[j1] = yr;
+                    a[j1 + 1] = yi;
+                    a[k1] = xr;
+                    a[k1 + 1] = xi;
+                }
+                k1 = 2 * k + ip[ipP + k];
+                a[k1 + 1] = -a[k1 + 1];
+                j1 = k1 + m2;
+                k1 = j1 + m2;
+                xr = a[j1];
+                xi = -a[j1 + 1];
+                yr = a[k1];
+                yi = -a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+                k1 += m2;
+                a[k1 + 1] = -a[k1 + 1];
+            }
+        } else {
+            a[1] = -a[1];
+            a[m2 + 1] = -a[m2 + 1];
+            for (k = 1; k < m; k++) {
+                for (j = 0; j < k; j++) {
+                    j1 = 2 * j + ip[ipP + k];
+                    k1 = 2 * k + ip[ipP + j];
+                    xr = a[j1];
+                    xi = -a[j1 + 1];
+                    yr = a[k1];
+                    yi = -a[k1 + 1];
+                    a[j1] = yr;
+                    a[j1 + 1] = yi;
+                    a[k1] = xr;
+                    a[k1 + 1] = xi;
+                    j1 += m2;
+                    k1 += m2;
+                    xr = a[j1];
+                    xi = -a[j1 + 1];
+                    yr = a[k1];
+                    yi = -a[k1 + 1];
+                    a[j1] = yr;
+                    a[j1 + 1] = yi;
+                    a[k1] = xr;
+                    a[k1 + 1] = xi;
+                }
+                k1 = 2 * k + ip[ipP + k];
+                a[k1 + 1] = -a[k1 + 1];
+                a[k1 + m2 + 1] = -a[k1 + m2 + 1];
+            }
+        }
+    }
+
+    /**
+     * 3rd
+     * @see #cftfsub(int, double[], int[], int, int, double[])
+     */
+    private void bitrv216(double[] a) {
+        double x1r, x1i, x2r, x2i, x3r, x3i, x4r, x4i, x5r, x5i, x7r, x7i, x8r, x8i, x10r, x10i, x11r, x11i, x12r, x12i, x13r, x13i, x14r, x14i;
+
+        x1r = a[2];
+        x1i = a[3];
+        x2r = a[4];
+        x2i = a[5];
+        x3r = a[6];
+        x3i = a[7];
+        x4r = a[8];
+        x4i = a[9];
+        x5r = a[10];
+        x5i = a[11];
+        x7r = a[14];
+        x7i = a[15];
+        x8r = a[16];
+        x8i = a[17];
+        x10r = a[20];
+        x10i = a[21];
+        x11r = a[22];
+        x11i = a[23];
+        x12r = a[24];
+        x12i = a[25];
+        x13r = a[26];
+        x13i = a[27];
+        x14r = a[28];
+        x14i = a[29];
+        a[2] = x8r;
+        a[3] = x8i;
+        a[4] = x4r;
+        a[5] = x4i;
+        a[6] = x12r;
+        a[7] = x12i;
+        a[8] = x2r;
+        a[9] = x2i;
+        a[10] = x10r;
+        a[11] = x10i;
+        a[14] = x14r;
+        a[15] = x14i;
+        a[16] = x1r;
+        a[17] = x1i;
+        a[20] = x5r;
+        a[21] = x5i;
+        a[22] = x13r;
+        a[23] = x13i;
+        a[24] = x3r;
+        a[25] = x3i;
+        a[26] = x11r;
+        a[27] = x11i;
+        a[28] = x7r;
+        a[29] = x7i;
+    }
+
+    /**
+     * 3rd
+     * @see #cftbsub(int, double[], int[], int, int, double[])
+     */
+    private void bitrv216neg(double[] a) {
+        double x1r, x1i, x2r, x2i, x3r, x3i, x4r, x4i, x5r, x5i, x6r, x6i, x7r, x7i, x8r, x8i, x9r, x9i, x10r, x10i, x11r, x11i, x12r, x12i, x13r, x13i, x14r, x14i, x15r, x15i;
+
+        x1r = a[2];
+        x1i = a[3];
+        x2r = a[4];
+        x2i = a[5];
+        x3r = a[6];
+        x3i = a[7];
+        x4r = a[8];
+        x4i = a[9];
+        x5r = a[10];
+        x5i = a[11];
+        x6r = a[12];
+        x6i = a[13];
+        x7r = a[14];
+        x7i = a[15];
+        x8r = a[16];
+        x8i = a[17];
+        x9r = a[18];
+        x9i = a[19];
+        x10r = a[20];
+        x10i = a[21];
+        x11r = a[22];
+        x11i = a[23];
+        x12r = a[24];
+        x12i = a[25];
+        x13r = a[26];
+        x13i = a[27];
+        x14r = a[28];
+        x14i = a[29];
+        x15r = a[30];
+        x15i = a[31];
+        a[2] = x15r;
+        a[3] = x15i;
+        a[4] = x7r;
+        a[5] = x7i;
+        a[6] = x11r;
+        a[7] = x11i;
+        a[8] = x3r;
+        a[9] = x3i;
+        a[10] = x13r;
+        a[11] = x13i;
+        a[12] = x5r;
+        a[13] = x5i;
+        a[14] = x9r;
+        a[15] = x9i;
+        a[16] = x1r;
+        a[17] = x1i;
+        a[18] = x14r;
+        a[19] = x14i;
+        a[20] = x6r;
+        a[21] = x6i;
+        a[22] = x10r;
+        a[23] = x10i;
+        a[24] = x2r;
+        a[25] = x2i;
+        a[26] = x12r;
+        a[27] = x12i;
+        a[28] = x4r;
+        a[29] = x4i;
+        a[30] = x8r;
+        a[31] = x8i;
+    }
+
+    /**
+     * 3rd
+     * @see #cftfsub(int, double[], int[], int, int, double[])
+     */
+    private void bitrv208(double[] a) {
+        double x1r, x1i, x3r, x3i, x4r, x4i, x6r, x6i;
+
+        x1r = a[2];
+        x1i = a[3];
+        x3r = a[6];
+        x3i = a[7];
+        x4r = a[8];
+        x4i = a[9];
+        x6r = a[12];
+        x6i = a[13];
+        a[2] = x4r;
+        a[3] = x4i;
+        a[6] = x6r;
+        a[7] = x6i;
+        a[8] = x1r;
+        a[9] = x1i;
+        a[12] = x3r;
+        a[13] = x3i;
+    }
+
+    /**
+     * 3rd
+     * @see #cftbsub(int, double[], int[], int, int, double[])
+     */
+    private void bitrv208neg(double[] a) {
+        double x1r, x1i, x2r, x2i, x3r, x3i, x4r, x4i, x5r, x5i, x6r, x6i, x7r, x7i;
+
+        x1r = a[2];
+        x1i = a[3];
+        x2r = a[4];
+        x2i = a[5];
+        x3r = a[6];
+        x3i = a[7];
+        x4r = a[8];
+        x4i = a[9];
+        x5r = a[10];
+        x5i = a[11];
+        x6r = a[12];
+        x6i = a[13];
+        x7r = a[14];
+        x7i = a[15];
+        a[2] = x7r;
+        a[3] = x7i;
+        a[4] = x3r;
+        a[5] = x3i;
+        a[6] = x5r;
+        a[7] = x5i;
+        a[8] = x1r;
+        a[9] = x1i;
+        a[10] = x6r;
+        a[11] = x6i;
+        a[12] = x2r;
+        a[13] = x2i;
+        a[14] = x4r;
+        a[15] = x4i;
+    }
+
+    /**
+     * 3rd
+     * @see #cftfsub(int, double[], int[], int, int, double[])
+     */
+    private void cftf1st(int n, double[] a, double[] w, int wP) {
+        int j, j0, j1, j2, j3, k, m, mh;
+        double wn4r, csc1, csc3, wk1r, wk1i, wk3r, wk3i, wd1r, wd1i, wd3r, wd3i;
+        double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i, y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i;
+
+        mh = n >> 3;
+        m = 2 * mh;
+        j1 = m;
+        j2 = j1 + m;
+        j3 = j2 + m;
+        x0r = a[0] + a[j2];
+        x0i = a[1] + a[j2 + 1];
+        x1r = a[0] - a[j2];
+        x1i = a[1] - a[j2 + 1];
+        x2r = a[j1] + a[j3];
+        x2i = a[j1 + 1] + a[j3 + 1];
+        x3r = a[j1] - a[j3];
+        x3i = a[j1 + 1] - a[j3 + 1];
+        a[0] = x0r + x2r;
+        a[1] = x0i + x2i;
+        a[j1] = x0r - x2r;
+        a[j1 + 1] = x0i - x2i;
+        a[j2] = x1r - x3i;
+        a[j2 + 1] = x1i + x3r;
+        a[j3] = x1r + x3i;
+        a[j3 + 1] = x1i - x3r;
+        wn4r = w[wP + 1];
+        csc1 = w[wP + 2];
+        csc3 = w[wP + 3];
+        wd1r = 1;
+        wd1i = 0;
+        wd3r = 1;
+        wd3i = 0;
+        k = 0;
+        for (j = 2; j < mh - 2; j += 4) {
+            k += 4;
+            wk1r = csc1 * (wd1r + w[wP + k]);
+            wk1i = csc1 * (wd1i + w[wP + k + 1]);
+            wk3r = csc3 * (wd3r + w[wP + k + 2]);
+            wk3i = csc3 * (wd3i - w[wP + k + 3]);
+            wd1r = w[wP + k];
+            wd1i = w[wP + k + 1];
+            wd3r = w[wP + k + 2];
+            wd3i = -w[wP + k + 3];
+            j1 = j + m;
+            j2 = j1 + m;
+            j3 = j2 + m;
+            x0r = a[j] + a[j2];
+            x0i = a[j + 1] + a[j2 + 1];
+            x1r = a[j] - a[j2];
+            x1i = a[j + 1] - a[j2 + 1];
+            y0r = a[j + 2] + a[j2 + 2];
+            y0i = a[j + 3] + a[j2 + 3];
+            y1r = a[j + 2] - a[j2 + 2];
+            y1i = a[j + 3] - a[j2 + 3];
+            x2r = a[j1] + a[j3];
+            x2i = a[j1 + 1] + a[j3 + 1];
+            x3r = a[j1] - a[j3];
+            x3i = a[j1 + 1] - a[j3 + 1];
+            y2r = a[j1 + 2] + a[j3 + 2];
+            y2i = a[j1 + 3] + a[j3 + 3];
+            y3r = a[j1 + 2] - a[j3 + 2];
+            y3i = a[j1 + 3] - a[j3 + 3];
+            a[j] = x0r + x2r;
+            a[j + 1] = x0i + x2i;
+            a[j + 2] = y0r + y2r;
+            a[j + 3] = y0i + y2i;
+            a[j1] = x0r - x2r;
+            a[j1 + 1] = x0i - x2i;
+            a[j1 + 2] = y0r - y2r;
+            a[j1 + 3] = y0i - y2i;
+            x0r = x1r - x3i;
+            x0i = x1i + x3r;
+            a[j2] = wk1r * x0r - wk1i * x0i;
+            a[j2 + 1] = wk1r * x0i + wk1i * x0r;
+            x0r = y1r - y3i;
+            x0i = y1i + y3r;
+            a[j2 + 2] = wd1r * x0r - wd1i * x0i;
+            a[j2 + 3] = wd1r * x0i + wd1i * x0r;
+            x0r = x1r + x3i;
+            x0i = x1i - x3r;
+            a[j3] = wk3r * x0r + wk3i * x0i;
+            a[j3 + 1] = wk3r * x0i - wk3i * x0r;
+            x0r = y1r + y3i;
+            x0i = y1i - y3r;
+            a[j3 + 2] = wd3r * x0r + wd3i * x0i;
+            a[j3 + 3] = wd3r * x0i - wd3i * x0r;
+            j0 = m - j;
+            j1 = j0 + m;
+            j2 = j1 + m;
+            j3 = j2 + m;
+            x0r = a[j0] + a[j2];
+            x0i = a[j0 + 1] + a[j2 + 1];
+            x1r = a[j0] - a[j2];
+            x1i = a[j0 + 1] - a[j2 + 1];
+            y0r = a[j0 - 2] + a[j2 - 2];
+            y0i = a[j0 - 1] + a[j2 - 1];
+            y1r = a[j0 - 2] - a[j2 - 2];
+            y1i = a[j0 - 1] - a[j2 - 1];
+            x2r = a[j1] + a[j3];
+            x2i = a[j1 + 1] + a[j3 + 1];
+            x3r = a[j1] - a[j3];
+            x3i = a[j1 + 1] - a[j3 + 1];
+            y2r = a[j1 - 2] + a[j3 - 2];
+            y2i = a[j1 - 1] + a[j3 - 1];
+            y3r = a[j1 - 2] - a[j3 - 2];
+            y3i = a[j1 - 1] - a[j3 - 1];
+            a[j0] = x0r + x2r;
+            a[j0 + 1] = x0i + x2i;
+            a[j0 - 2] = y0r + y2r;
+            a[j0 - 1] = y0i + y2i;
+            a[j1] = x0r - x2r;
+            a[j1 + 1] = x0i - x2i;
+            a[j1 - 2] = y0r - y2r;
+            a[j1 - 1] = y0i - y2i;
+            x0r = x1r - x3i;
+            x0i = x1i + x3r;
+            a[j2] = wk1i * x0r - wk1r * x0i;
+            a[j2 + 1] = wk1i * x0i + wk1r * x0r;
+            x0r = y1r - y3i;
+            x0i = y1i + y3r;
+            a[j2 - 2] = wd1i * x0r - wd1r * x0i;
+            a[j2 - 1] = wd1i * x0i + wd1r * x0r;
+            x0r = x1r + x3i;
+            x0i = x1i - x3r;
+            a[j3] = wk3i * x0r + wk3r * x0i;
+            a[j3 + 1] = wk3i * x0i - wk3r * x0r;
+            x0r = y1r + y3i;
+            x0i = y1i - y3r;
+            a[j3 - 2] = wd3i * x0r + wd3r * x0i;
+            a[j3 - 1] = wd3i * x0i - wd3r * x0r;
+        }
+        wk1r = csc1 * (wd1r + wn4r);
+        wk1i = csc1 * (wd1i + wn4r);
+        wk3r = csc3 * (wd3r - wn4r);
+        wk3i = csc3 * (wd3i - wn4r);
+        j0 = mh;
+        j1 = j0 + m;
+        j2 = j1 + m;
+        j3 = j2 + m;
+        x0r = a[j0 - 2] + a[j2 - 2];
+        x0i = a[j0 - 1] + a[j2 - 1];
+        x1r = a[j0 - 2] - a[j2 - 2];
+        x1i = a[j0 - 1] - a[j2 - 1];
+        x2r = a[j1 - 2] + a[j3 - 2];
+        x2i = a[j1 - 1] + a[j3 - 1];
+        x3r = a[j1 - 2] - a[j3 - 2];
+        x3i = a[j1 - 1] - a[j3 - 1];
+        a[j0 - 2] = x0r + x2r;
+        a[j0 - 1] = x0i + x2i;
+        a[j1 - 2] = x0r - x2r;
+        a[j1 - 1] = x0i - x2i;
+        x0r = x1r - x3i;
+        x0i = x1i + x3r;
+        a[j2 - 2] = wk1r * x0r - wk1i * x0i;
+        a[j2 - 1] = wk1r * x0i + wk1i * x0r;
+        x0r = x1r + x3i;
+        x0i = x1i - x3r;
+        a[j3 - 2] = wk3r * x0r + wk3i * x0i;
+        a[j3 - 1] = wk3r * x0i - wk3i * x0r;
+        x0r = a[j0] + a[j2];
+        x0i = a[j0 + 1] + a[j2 + 1];
+        x1r = a[j0] - a[j2];
+        x1i = a[j0 + 1] - a[j2 + 1];
+        x2r = a[j1] + a[j3];
+        x2i = a[j1 + 1] + a[j3 + 1];
+        x3r = a[j1] - a[j3];
+        x3i = a[j1 + 1] - a[j3 + 1];
+        a[j0] = x0r + x2r;
+        a[j0 + 1] = x0i + x2i;
+        a[j1] = x0r - x2r;
+        a[j1 + 1] = x0i - x2i;
+        x0r = x1r - x3i;
+        x0i = x1i + x3r;
+        a[j2] = wn4r * (x0r - x0i);
+        a[j2 + 1] = wn4r * (x0i + x0r);
+        x0r = x1r + x3i;
+        x0i = x1i - x3r;
+        a[j3] = -wn4r * (x0r + x0i);
+        a[j3 + 1] = -wn4r * (x0i - x0r);
+        x0r = a[j0 + 2] + a[j2 + 2];
+        x0i = a[j0 + 3] + a[j2 + 3];
+        x1r = a[j0 + 2] - a[j2 + 2];
+        x1i = a[j0 + 3] - a[j2 + 3];
+        x2r = a[j1 + 2] + a[j3 + 2];
+        x2i = a[j1 + 3] + a[j3 + 3];
+        x3r = a[j1 + 2] - a[j3 + 2];
+        x3i = a[j1 + 3] - a[j3 + 3];
+        a[j0 + 2] = x0r + x2r;
+        a[j0 + 3] = x0i + x2i;
+        a[j1 + 2] = x0r - x2r;
+        a[j1 + 3] = x0i - x2i;
+        x0r = x1r - x3i;
+        x0i = x1i + x3r;
+        a[j2 + 2] = wk1i * x0r - wk1r * x0i;
+        a[j2 + 3] = wk1i * x0i + wk1r * x0r;
+        x0r = x1r + x3i;
+        x0i = x1i - x3r;
+        a[j3 + 2] = wk3i * x0r + wk3r * x0i;
+        a[j3 + 3] = wk3i * x0i - wk3r * x0r;
+    }
+
+    /**
+     * 3rd
+     * @see #cftbsub(int, double[], int[], int, int, double[])
+     */
+    private final void cftb1st(int n, double[] a, double[] w, int wP) {
+        int j, j0, j1, j2, j3, k, m, mh;
+        double wn4r, csc1, csc3, wk1r, wk1i, wk3r, wk3i, wd1r, wd1i, wd3r, wd3i;
+        double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i, y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i;
+
+        mh = n >> 3;
+        m = 2 * mh;
+        j1 = m;
+        j2 = j1 + m;
+        j3 = j2 + m;
+        x0r = a[0] + a[j2];
+        x0i = -a[1] - a[j2 + 1];
+        x1r = a[0] - a[j2];
+        x1i = -a[1] + a[j2 + 1];
+        x2r = a[j1] + a[j3];
+        x2i = a[j1 + 1] + a[j3 + 1];
+        x3r = a[j1] - a[j3];
+        x3i = a[j1 + 1] - a[j3 + 1];
+        a[0] = x0r + x2r;
+        a[1] = x0i - x2i;
+        a[j1] = x0r - x2r;
+        a[j1 + 1] = x0i + x2i;
+        a[j2] = x1r + x3i;
+        a[j2 + 1] = x1i + x3r;
+        a[j3] = x1r - x3i;
+        a[j3 + 1] = x1i - x3r;
+        wn4r = w[wP + 1];
+        csc1 = w[wP + 2];
+        csc3 = w[wP + 3];
+        wd1r = 1;
+        wd1i = 0;
+        wd3r = 1;
+        wd3i = 0;
+        k = 0;
+        for (j = 2; j < mh - 2; j += 4) {
+            k += 4;
+            wk1r = csc1 * (wd1r + w[wP + k]);
+            wk1i = csc1 * (wd1i + w[wP + k + 1]);
+            wk3r = csc3 * (wd3r + w[wP + k + 2]);
+            wk3i = csc3 * (wd3i - w[wP + k + 3]);
+            wd1r = w[wP + k];
+            wd1i = w[wP + k + 1];
+            wd3r = w[wP + k + 2];
+            wd3i = -w[wP + k + 3];
+            j1 = j + m;
+            j2 = j1 + m;
+            j3 = j2 + m;
+            x0r = a[j] + a[j2];
+            x0i = -a[j + 1] - a[j2 + 1];
+            x1r = a[j] - a[j2];
+            x1i = -a[j + 1] + a[j2 + 1];
+            y0r = a[j + 2] + a[j2 + 2];
+            y0i = -a[j + 3] - a[j2 + 3];
+            y1r = a[j + 2] - a[j2 + 2];
+            y1i = -a[j + 3] + a[j2 + 3];
+            x2r = a[j1] + a[j3];
+            x2i = a[j1 + 1] + a[j3 + 1];
+            x3r = a[j1] - a[j3];
+            x3i = a[j1 + 1] - a[j3 + 1];
+            y2r = a[j1 + 2] + a[j3 + 2];
+            y2i = a[j1 + 3] + a[j3 + 3];
+            y3r = a[j1 + 2] - a[j3 + 2];
+            y3i = a[j1 + 3] - a[j3 + 3];
+            a[j] = x0r + x2r;
+            a[j + 1] = x0i - x2i;
+            a[j + 2] = y0r + y2r;
+            a[j + 3] = y0i - y2i;
+            a[j1] = x0r - x2r;
+            a[j1 + 1] = x0i + x2i;
+            a[j1 + 2] = y0r - y2r;
+            a[j1 + 3] = y0i + y2i;
+            x0r = x1r + x3i;
+            x0i = x1i + x3r;
+            a[j2] = wk1r * x0r - wk1i * x0i;
+            a[j2 + 1] = wk1r * x0i + wk1i * x0r;
+            x0r = y1r + y3i;
+            x0i = y1i + y3r;
+            a[j2 + 2] = wd1r * x0r - wd1i * x0i;
+            a[j2 + 3] = wd1r * x0i + wd1i * x0r;
+            x0r = x1r - x3i;
+            x0i = x1i - x3r;
+            a[j3] = wk3r * x0r + wk3i * x0i;
+            a[j3 + 1] = wk3r * x0i - wk3i * x0r;
+            x0r = y1r - y3i;
+            x0i = y1i - y3r;
+            a[j3 + 2] = wd3r * x0r + wd3i * x0i;
+            a[j3 + 3] = wd3r * x0i - wd3i * x0r;
+            j0 = m - j;
+            j1 = j0 + m;
+            j2 = j1 + m;
+            j3 = j2 + m;
+            x0r = a[j0] + a[j2];
+            x0i = -a[j0 + 1] - a[j2 + 1];
+            x1r = a[j0] - a[j2];
+            x1i = -a[j0 + 1] + a[j2 + 1];
+            y0r = a[j0 - 2] + a[j2 - 2];
+            y0i = -a[j0 - 1] - a[j2 - 1];
+            y1r = a[j0 - 2] - a[j2 - 2];
+            y1i = -a[j0 - 1] + a[j2 - 1];
+            x2r = a[j1] + a[j3];
+            x2i = a[j1 + 1] + a[j3 + 1];
+            x3r = a[j1] - a[j3];
+            x3i = a[j1 + 1] - a[j3 + 1];
+            y2r = a[j1 - 2] + a[j3 - 2];
+            y2i = a[j1 - 1] + a[j3 - 1];
+            y3r = a[j1 - 2] - a[j3 - 2];
+            y3i = a[j1 - 1] - a[j3 - 1];
+            a[j0] = x0r + x2r;
+            a[j0 + 1] = x0i - x2i;
+            a[j0 - 2] = y0r + y2r;
+            a[j0 - 1] = y0i - y2i;
+            a[j1] = x0r - x2r;
+            a[j1 + 1] = x0i + x2i;
+            a[j1 - 2] = y0r - y2r;
+            a[j1 - 1] = y0i + y2i;
+            x0r = x1r + x3i;
+            x0i = x1i + x3r;
+            a[j2] = wk1i * x0r - wk1r * x0i;
+            a[j2 + 1] = wk1i * x0i + wk1r * x0r;
+            x0r = y1r + y3i;
+            x0i = y1i + y3r;
+            a[j2 - 2] = wd1i * x0r - wd1r * x0i;
+            a[j2 - 1] = wd1i * x0i + wd1r * x0r;
+            x0r = x1r - x3i;
+            x0i = x1i - x3r;
+            a[j3] = wk3i * x0r + wk3r * x0i;
+            a[j3 + 1] = wk3i * x0i - wk3r * x0r;
+            x0r = y1r - y3i;
+            x0i = y1i - y3r;
+            a[j3 - 2] = wd3i * x0r + wd3r * x0i;
+            a[j3 - 1] = wd3i * x0i - wd3r * x0r;
+        }
+        wk1r = csc1 * (wd1r + wn4r);
+        wk1i = csc1 * (wd1i + wn4r);
+        wk3r = csc3 * (wd3r - wn4r);
+        wk3i = csc3 * (wd3i - wn4r);
+        j0 = mh;
+        j1 = j0 + m;
+        j2 = j1 + m;
+        j3 = j2 + m;
+        x0r = a[j0 - 2] + a[j2 - 2];
+        x0i = -a[j0 - 1] - a[j2 - 1];
+        x1r = a[j0 - 2] - a[j2 - 2];
+        x1i = -a[j0 - 1] + a[j2 - 1];
+        x2r = a[j1 - 2] + a[j3 - 2];
+        x2i = a[j1 - 1] + a[j3 - 1];
+        x3r = a[j1 - 2] - a[j3 - 2];
+        x3i = a[j1 - 1] - a[j3 - 1];
+        a[j0 - 2] = x0r + x2r;
+        a[j0 - 1] = x0i - x2i;
+        a[j1 - 2] = x0r - x2r;
+        a[j1 - 1] = x0i + x2i;
+        x0r = x1r + x3i;
+        x0i = x1i + x3r;
+        a[j2 - 2] = wk1r * x0r - wk1i * x0i;
+        a[j2 - 1] = wk1r * x0i + wk1i * x0r;
+        x0r = x1r - x3i;
+        x0i = x1i - x3r;
+        a[j3 - 2] = wk3r * x0r + wk3i * x0i;
+        a[j3 - 1] = wk3r * x0i - wk3i * x0r;
+        x0r = a[j0] + a[j2];
+        x0i = -a[j0 + 1] - a[j2 + 1];
+        x1r = a[j0] - a[j2];
+        x1i = -a[j0 + 1] + a[j2 + 1];
+        x2r = a[j1] + a[j3];
+        x2i = a[j1 + 1] + a[j3 + 1];
+        x3r = a[j1] - a[j3];
+        x3i = a[j1 + 1] - a[j3 + 1];
+        a[j0] = x0r + x2r;
+        a[j0 + 1] = x0i - x2i;
+        a[j1] = x0r - x2r;
+        a[j1 + 1] = x0i + x2i;
+        x0r = x1r + x3i;
+        x0i = x1i + x3r;
+        a[j2] = wn4r * (x0r - x0i);
+        a[j2 + 1] = wn4r * (x0i + x0r);
+        x0r = x1r - x3i;
+        x0i = x1i - x3r;
+        a[j3] = -wn4r * (x0r + x0i);
+        a[j3 + 1] = -wn4r * (x0i - x0r);
+        x0r = a[j0 + 2] + a[j2 + 2];
+        x0i = -a[j0 + 3] - a[j2 + 3];
+        x1r = a[j0 + 2] - a[j2 + 2];
+        x1i = -a[j0 + 3] + a[j2 + 3];
+        x2r = a[j1 + 2] + a[j3 + 2];
+        x2i = a[j1 + 3] + a[j3 + 3];
+        x3r = a[j1 + 2] - a[j3 + 2];
+        x3i = a[j1 + 3] - a[j3 + 3];
+        a[j0 + 2] = x0r + x2r;
+        a[j0 + 3] = x0i - x2i;
+        a[j1 + 2] = x0r - x2r;
+        a[j1 + 3] = x0i + x2i;
+        x0r = x1r + x3i;
+        x0i = x1i + x3r;
+        a[j2 + 2] = wk1i * x0r - wk1r * x0i;
+        a[j2 + 3] = wk1i * x0i + wk1r * x0r;
+        x0r = x1r - x3i;
+        x0i = x1i - x3r;
+        a[j3 + 2] = wk3i * x0r + wk3r * x0i;
+        a[j3 + 3] = wk3i * x0i - wk3r * x0r;
+    }
+
+    /** */
+    private void cftrec1(int n, double[] a, int aP, int nw, double[] w) {
+        int m;
+
+        m = n >> 2;
+        cftmdl1(n, a, aP, w, nw - 2 * m);
+        if (n > CDFT_RECURSIVE_N) {
+            cftrec1(m, a, aP, nw, w);
+            cftrec2(m, a, aP + m, nw, w);
+            cftrec1(m, a, aP + 2 * m, nw, w);
+            cftrec1(m, a, aP + 3 * m, nw, w);
+        } else {
+            cftexp1(n, a, aP, nw, w);
+        }
+    }
+
+    /** */
+    private void cftrec2(int n, double[] a, int aP, int nw, double[] w) {
+        int m;
+
+        m = n >> 2;
+        cftmdl2(n, a, aP, w, nw - n);
+        if (n > CDFT_RECURSIVE_N) {
+            cftrec1(m, a, aP, nw, w);
+            cftrec2(m, a, aP + m, nw, w);
+            cftrec1(m, a, aP + 2 * m, nw, w);
+            cftrec2(m, a, aP + 3 * m, nw, w);
+        } else {
+            cftexp2(n, a, aP, nw, w);
+        }
+    }
+
+    /** */
+    private void cftexp1(int n, double[] a, int aP, int nw, double[] w) {
+        int j, k, l;
+
+        l = n >> 2;
+        while (l > 128) {
+            for (k = l; k < n; k <<= 2) {
+                for (j = k - l; j < n; j += 4 * k) {
+                    cftmdl1(l, a, aP + j, w, nw - (l >> 1));
+                    cftmdl2(l, a, aP + k + j, w, nw - l);
+                    cftmdl1(l, a, aP + 2 * k + j, w, nw - (l >> 1));
+                }
+            }
+            cftmdl1(l, a, aP + n - l, w, nw - (l >> 1));
+            l >>= 2;
+        }
+        for (k = l; k < n; k <<= 2) {
+            for (j = k - l; j < n; j += 4 * k) {
+                cftmdl1(l, a, aP + j, w, nw - (l >> 1));
+                cftfx41(l, a, aP + j, nw, w);
+                cftmdl2(l, a, aP + k + j, w, nw - l);
+                cftfx42(l, a, aP + k + j, nw, w);
+                cftmdl1(l, a, aP + 2 * k + j, w, nw - (l >> 1));
+                cftfx41(l, a, aP + 2 * k + j, nw, w);
+            }
+        }
+        cftmdl1(l, a, aP + n - l, w, nw - (l >> 1));
+        cftfx41(l, a, aP + n - l, nw, w);
+    }
+
+    /** */
+    private void cftexp2(int n, double[] a, int aP, int nw, double[] w) {
+        int j, k, l, m;
+
+        m = n >> 1;
+        l = n >> 2;
+        while (l > 128) {
+            for (k = l; k < m; k <<= 2) {
+                for (j = k - l; j < m; j += 2 * k) {
+                    cftmdl1(l, a, aP + j, w, nw - (l >> 1));
+                    cftmdl1(l, a, aP + m + j, w, nw - (l >> 1));
+                }
+                for (j = 2 * k - l; j < m; j += 4 * k) {
+                    cftmdl2(l, a, aP + j, w, nw - l);
+                    cftmdl2(l, a, aP + m + j, w, nw - l);
+                }
+            }
+            l >>= 2;
+        }
+        for (k = l; k < m; k <<= 2) {
+            for (j = k - l; j < m; j += 2 * k) {
+                cftmdl1(l, a, aP + j, w, nw - (l >> 1));
+                cftfx41(l, a, aP + j, nw, w);
+                cftmdl1(l, a, aP + m + j, w, nw - (l >> 1));
+                cftfx41(l, a, aP + m + j, nw, w);
+            }
+            for (j = 2 * k - l; j < m; j += 4 * k) {
+                cftmdl2(l, a, aP + j, w, nw - l);
+                cftfx42(l, a, aP + j, nw, w);
+                cftmdl2(l, a, aP + m + j, w, nw - l);
+                cftfx42(l, a, aP + m + j, nw, w);
+            }
+        }
+    }
+
+    /** */
+    private final void cftmdl1(int n, double[] a, int aP, double[] w, int wP) {
+        int j, j0, j1, j2, j3, k, m, mh;
+        double wn4r, wk1r, wk1i, wk3r, wk3i;
+        double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
+
+        mh = n >> 3;
+        m = 2 * mh;
+        j1 = m;
+        j2 = j1 + m;
+        j3 = j2 + m;
+        x0r = a[aP + 0] + a[aP + j2];
+        x0i = a[aP + 1] + a[aP + j2 + 1];
+        x1r = a[aP + 0] - a[aP + j2];
+        x1i = a[aP + 1] - a[aP + j2 + 1];
+        x2r = a[aP + j1] + a[aP + j3];
+        x2i = a[aP + j1 + 1] + a[aP + j3 + 1];
+        x3r = a[aP + j1] - a[aP + j3];
+        x3i = a[aP + j1 + 1] - a[aP + j3 + 1];
+        a[aP + 0] = x0r + x2r;
+        a[aP + 1] = x0i + x2i;
+        a[aP + j1] = x0r - x2r;
+        a[aP + j1 + 1] = x0i - x2i;
+        a[aP + j2] = x1r - x3i;
+        a[aP + j2 + 1] = x1i + x3r;
+        a[aP + j3] = x1r + x3i;
+        a[aP + j3 + 1] = x1i - x3r;
+        wn4r = w[wP + 1];
+        k = 0;
+        for (j = 2; j < mh; j += 2) {
+            k += 4;
+            wk1r = w[wP + k];
+            wk1i = w[wP + k + 1];
+            wk3r = w[wP + k + 2];
+            wk3i = -w[wP + k + 3];
+            j1 = j + m;
+            j2 = j1 + m;
+            j3 = j2 + m;
+            x0r = a[aP + j] + a[aP + j2];
+            x0i = a[aP + j + 1] + a[aP + j2 + 1];
+            x1r = a[aP + j] - a[aP + j2];
+            x1i = a[aP + j + 1] - a[aP + j2 + 1];
+            x2r = a[aP + j1] + a[aP + j3];
+            x2i = a[aP + j1 + 1] + a[aP + j3 + 1];
+            x3r = a[aP + j1] - a[aP + j3];
+            x3i = a[aP + j1 + 1] - a[aP + j3 + 1];
+            a[aP + j] = x0r + x2r;
+            a[aP + j + 1] = x0i + x2i;
+            a[aP + j1] = x0r - x2r;
+            a[aP + j1 + 1] = x0i - x2i;
+            x0r = x1r - x3i;
+            x0i = x1i + x3r;
+            a[aP + j2] = wk1r * x0r - wk1i * x0i;
+            a[aP + j2 + 1] = wk1r * x0i + wk1i * x0r;
+            x0r = x1r + x3i;
+            x0i = x1i - x3r;
+            a[aP + j3] = wk3r * x0r + wk3i * x0i;
+            a[aP + j3 + 1] = wk3r * x0i - wk3i * x0r;
+            j0 = m - j;
+            j1 = j0 + m;
+            j2 = j1 + m;
+            j3 = j2 + m;
+            x0r = a[aP + j0] + a[aP + j2];
+            x0i = a[aP + j0 + 1] + a[aP + j2 + 1];
+            x1r = a[aP + j0] - a[aP + j2];
+            x1i = a[aP + j0 + 1] - a[aP + j2 + 1];
+            x2r = a[aP + j1] + a[aP + j3];
+            x2i = a[aP + j1 + 1] + a[aP + j3 + 1];
+            x3r = a[aP + j1] - a[aP + j3];
+            x3i = a[aP + j1 + 1] - a[aP + j3 + 1];
+            a[aP + j0] = x0r + x2r;
+            a[aP + j0 + 1] = x0i + x2i;
+            a[aP + j1] = x0r - x2r;
+            a[aP + j1 + 1] = x0i - x2i;
+            x0r = x1r - x3i;
+            x0i = x1i + x3r;
+            a[aP + j2] = wk1i * x0r - wk1r * x0i;
+            a[aP + j2 + 1] = wk1i * x0i + wk1r * x0r;
+            x0r = x1r + x3i;
+            x0i = x1i - x3r;
+            a[aP + j3] = wk3i * x0r + wk3r * x0i;
+            a[aP + j3 + 1] = wk3i * x0i - wk3r * x0r;
+        }
+        j0 = mh;
+        j1 = j0 + m;
+        j2 = j1 + m;
+        j3 = j2 + m;
+        x0r = a[aP + j0] + a[aP + j2];
+        x0i = a[aP + j0 + 1] + a[aP + j2 + 1];
+        x1r = a[aP + j0] - a[aP + j2];
+        x1i = a[aP + j0 + 1] - a[aP + j2 + 1];
+        x2r = a[aP + j1] + a[aP + j3];
+        x2i = a[aP + j1 + 1] + a[aP + j3 + 1];
+        x3r = a[aP + j1] - a[aP + j3];
+        x3i = a[aP + j1 + 1] - a[aP + j3 + 1];
+        a[aP + j0] = x0r + x2r;
+        a[aP + j0 + 1] = x0i + x2i;
+        a[aP + j1] = x0r - x2r;
+        a[aP + j1 + 1] = x0i - x2i;
+        x0r = x1r - x3i;
+        x0i = x1i + x3r;
+        a[aP + j2] = wn4r * (x0r - x0i);
+        a[aP + j2 + 1] = wn4r * (x0i + x0r);
+        x0r = x1r + x3i;
+        x0i = x1i - x3r;
+        a[aP + j3] = -wn4r * (x0r + x0i);
+        a[aP + j3 + 1] = -wn4r * (x0i - x0r);
+    }
+
+    /** */
+    private final void cftmdl2(int n, double[] a, int aP, double[] w, int wP) {
+        int j, j0, j1, j2, j3, k, kr, m, mh;
+        double wn4r, wk1r, wk1i, wk3r, wk3i, wd1r, wd1i, wd3r, wd3i;
+        double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i, y0r, y0i, y2r, y2i;
+
+        mh = n >> 3;
+        m = 2 * mh;
+        wn4r = w[wP + 1];
+        j1 = m;
+        j2 = j1 + m;
+        j3 = j2 + m;
+        x0r = a[aP + 0] - a[aP + j2 + 1];
+        x0i = a[aP + 1] + a[aP + j2];
+        x1r = a[aP + 0] + a[aP + j2 + 1];
+        x1i = a[aP + 1] - a[aP + j2];
+        x2r = a[aP + j1] - a[aP + j3 + 1];
+        x2i = a[aP + j1 + 1] + a[aP + j3];
+        x3r = a[aP + j1] + a[aP + j3 + 1];
+        x3i = a[aP + j1 + 1] - a[aP + j3];
+        y0r = wn4r * (x2r - x2i);
+        y0i = wn4r * (x2i + x2r);
+        a[aP + 0] = x0r + y0r;
+        a[aP + 1] = x0i + y0i;
+        a[aP + j1] = x0r - y0r;
+        a[aP + j1 + 1] = x0i - y0i;
+        y0r = wn4r * (x3r - x3i);
+        y0i = wn4r * (x3i + x3r);
+        a[aP + j2] = x1r - y0i;
+        a[aP + j2 + 1] = x1i + y0r;
+        a[aP + j3] = x1r + y0i;
+        a[aP + j3 + 1] = x1i - y0r;
+        k = 0;
+        kr = 2 * m;
+        for (j = 2; j < mh; j += 2) {
+            k += 4;
+            wk1r = w[wP + k];
+            wk1i = w[wP + k + 1];
+            wk3r = w[wP + k + 2];
+            wk3i = -w[wP + k + 3];
+            kr -= 4;
+            wd1i = w[wP + kr];
+            wd1r = w[wP + kr + 1];
+            wd3i = w[wP + kr + 2];
+            wd3r = -w[wP + kr + 3];
+            j1 = j + m;
+            j2 = j1 + m;
+            j3 = j2 + m;
+            x0r = a[aP + j] - a[aP + j2 + 1];
+            x0i = a[aP + j + 1] + a[aP + j2];
+            x1r = a[aP + j] + a[aP + j2 + 1];
+            x1i = a[aP + j + 1] - a[aP + j2];
+            x2r = a[aP + j1] - a[aP + j3 + 1];
+            x2i = a[aP + j1 + 1] + a[aP + j3];
+            x3r = a[aP + j1] + a[aP + j3 + 1];
+            x3i = a[aP + j1 + 1] - a[aP + j3];
+            y0r = wk1r * x0r - wk1i * x0i;
+            y0i = wk1r * x0i + wk1i * x0r;
+            y2r = wd1r * x2r - wd1i * x2i;
+            y2i = wd1r * x2i + wd1i * x2r;
+            a[aP + j] = y0r + y2r;
+            a[aP + j + 1] = y0i + y2i;
+            a[aP + j1] = y0r - y2r;
+            a[aP + j1 + 1] = y0i - y2i;
+            y0r = wk3r * x1r + wk3i * x1i;
+            y0i = wk3r * x1i - wk3i * x1r;
+            y2r = wd3r * x3r + wd3i * x3i;
+            y2i = wd3r * x3i - wd3i * x3r;
+            a[aP + j2] = y0r + y2r;
+            a[aP + j2 + 1] = y0i + y2i;
+            a[aP + j3] = y0r - y2r;
+            a[aP + j3 + 1] = y0i - y2i;
+            j0 = m - j;
+            j1 = j0 + m;
+            j2 = j1 + m;
+            j3 = j2 + m;
+            x0r = a[aP + j0] - a[aP + j2 + 1];
+            x0i = a[aP + j0 + 1] + a[aP + j2];
+            x1r = a[aP + j0] + a[aP + j2 + 1];
+            x1i = a[aP + j0 + 1] - a[aP + j2];
+            x2r = a[aP + j1] - a[aP + j3 + 1];
+            x2i = a[aP + j1 + 1] + a[aP + j3];
+            x3r = a[aP + j1] + a[aP + j3 + 1];
+            x3i = a[aP + j1 + 1] - a[aP + j3];
+            y0r = wd1i * x0r - wd1r * x0i;
+            y0i = wd1i * x0i + wd1r * x0r;
+            y2r = wk1i * x2r - wk1r * x2i;
+            y2i = wk1i * x2i + wk1r * x2r;
+            a[aP + j0] = y0r + y2r;
+            a[aP + j0 + 1] = y0i + y2i;
+            a[aP + j1] = y0r - y2r;
+            a[aP + j1 + 1] = y0i - y2i;
+            y0r = wd3i * x1r + wd3r * x1i;
+            y0i = wd3i * x1i - wd3r * x1r;
+            y2r = wk3i * x3r + wk3r * x3i;
+            y2i = wk3i * x3i - wk3r * x3r;
+            a[aP + j2] = y0r + y2r;
+            a[aP + j2 + 1] = y0i + y2i;
+            a[aP + j3] = y0r - y2r;
+            a[aP + j3 + 1] = y0i - y2i;
+        }
+        wk1r = w[wP + m];
+        wk1i = w[wP + m + 1];
+        j0 = mh;
+        j1 = j0 + m;
+        j2 = j1 + m;
+        j3 = j2 + m;
+        x0r = a[aP + j0] - a[aP + j2 + 1];
+        x0i = a[aP + j0 + 1] + a[aP + j2];
+        x1r = a[aP + j0] + a[aP + j2 + 1];
+        x1i = a[aP + j0 + 1] - a[aP + j2];
+        x2r = a[aP + j1] - a[aP + j3 + 1];
+        x2i = a[aP + j1 + 1] + a[aP + j3];
+        x3r = a[aP + j1] + a[aP + j3 + 1];
+        x3i = a[aP + j1 + 1] - a[aP + j3];
+        y0r = wk1r * x0r - wk1i * x0i;
+        y0i = wk1r * x0i + wk1i * x0r;
+        y2r = wk1i * x2r - wk1r * x2i;
+        y2i = wk1i * x2i + wk1r * x2r;
+        a[aP + j0] = y0r + y2r;
+        a[aP + j0 + 1] = y0i + y2i;
+        a[aP + j1] = y0r - y2r;
+        a[aP + j1 + 1] = y0i - y2i;
+        y0r = wk1i * x1r - wk1r * x1i;
+        y0i = wk1i * x1i + wk1r * x1r;
+        y2r = wk1r * x3r - wk1i * x3i;
+        y2i = wk1r * x3i + wk1i * x3r;
+        a[aP + j2] = y0r - y2r;
+        a[aP + j2 + 1] = y0i - y2i;
+        a[aP + j3] = y0r + y2r;
+        a[aP + j3 + 1] = y0i + y2i;
+    }
+
+    /** */
+    private void cftfx41(int n, double[] a, int aP, int nw, double[] w) {
+        if (n == 128) {
+            cftf161(a, aP, w, nw - 8);
+            cftf162(a, aP + 32, w, nw - 32);
+            cftf161(a, aP + 64, w, nw - 8);
+            cftf161(a, aP + 96, w, nw - 8);
+        } else {
+            cftf081(a, aP, w, nw - 16);
+            cftf082(a, aP + 16, w, nw - 16);
+            cftf081(a, aP + 32, w, nw - 16);
+            cftf081(a, aP + 48, w, nw - 16);
+        }
+    }
+
+    /** */
+    private void cftfx42(int n, double[] a, int aP, int nw, double[] w) {
+        if (n == 128) {
+            cftf161(a, aP, w, nw - 8);
+            cftf162(a, aP + 32, w, nw - 32);
+            cftf161(a, aP + 64, w, nw - 8);
+            cftf162(a, aP + 96, w, nw - 32);
+        } else {
+            cftf081(a, aP, w, nw - 16);
+            cftf082(a, aP + 16, w, nw - 16);
+            cftf081(a, aP + 32, w, nw - 16);
+            cftf082(a, aP + 48, w, nw - 16);
+        }
+    }
+
+    /** */
+    private void cftf161(double[] a, int aP, double[] w, int wP) {
+        double wn4r, wk1r, wk1i, x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i, y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i, y4r, y4i, y5r, y5i, y6r, y6i, y7r, y7i, y8r, y8i, y9r, y9i, y10r, y10i, y11r, y11i, y12r, y12i, y13r, y13i, y14r, y14i, y15r, y15i;
+
+        wn4r = w[wP + 1];
+        wk1i = wn4r * w[wP + 2];
+        wk1r = wk1i + w[wP + 2];
+        x0r = a[aP + 0] + a[aP + 16];
+        x0i = a[aP + 1] + a[aP + 17];
+        x1r = a[aP + 0] - a[aP + 16];
+        x1i = a[aP + 1] - a[aP + 17];
+        x2r = a[aP + 8] + a[aP + 24];
+        x2i = a[aP + 9] + a[aP + 25];
+        x3r = a[aP + 8] - a[aP + 24];
+        x3i = a[aP + 9] - a[aP + 25];
+        y0r = x0r + x2r;
+        y0i = x0i + x2i;
+        y4r = x0r - x2r;
+        y4i = x0i - x2i;
+        y8r = x1r - x3i;
+        y8i = x1i + x3r;
+        y12r = x1r + x3i;
+        y12i = x1i - x3r;
+        x0r = a[aP + 2] + a[aP + 18];
+        x0i = a[aP + 3] + a[aP + 19];
+        x1r = a[aP + 2] - a[aP + 18];
+        x1i = a[aP + 3] - a[aP + 19];
+        x2r = a[aP + 10] + a[aP + 26];
+        x2i = a[aP + 11] + a[aP + 27];
+        x3r = a[aP + 10] - a[aP + 26];
+        x3i = a[aP + 11] - a[aP + 27];
+        y1r = x0r + x2r;
+        y1i = x0i + x2i;
+        y5r = x0r - x2r;
+        y5i = x0i - x2i;
+        x0r = x1r - x3i;
+        x0i = x1i + x3r;
+        y9r = wk1r * x0r - wk1i * x0i;
+        y9i = wk1r * x0i + wk1i * x0r;
+        x0r = x1r + x3i;
+        x0i = x1i - x3r;
+        y13r = wk1i * x0r - wk1r * x0i;
+        y13i = wk1i * x0i + wk1r * x0r;
+        x0r = a[aP + 4] + a[aP + 20];
+        x0i = a[aP + 5] + a[aP + 21];
+        x1r = a[aP + 4] - a[aP + 20];
+        x1i = a[aP + 5] - a[aP + 21];
+        x2r = a[aP + 12] + a[aP + 28];
+        x2i = a[aP + 13] + a[aP + 29];
+        x3r = a[aP + 12] - a[aP + 28];
+        x3i = a[aP + 13] - a[aP + 29];
+        y2r = x0r + x2r;
+        y2i = x0i + x2i;
+        y6r = x0r - x2r;
+        y6i = x0i - x2i;
+        x0r = x1r - x3i;
+        x0i = x1i + x3r;
+        y10r = wn4r * (x0r - x0i);
+        y10i = wn4r * (x0i + x0r);
+        x0r = x1r + x3i;
+        x0i = x1i - x3r;
+        y14r = wn4r * (x0r + x0i);
+        y14i = wn4r * (x0i - x0r);
+        x0r = a[aP + 6] + a[aP + 22];
+        x0i = a[aP + 7] + a[aP + 23];
+        x1r = a[aP + 6] - a[aP + 22];
+        x1i = a[aP + 7] - a[aP + 23];
+        x2r = a[aP + 14] + a[aP + 30];
+        x2i = a[aP + 15] + a[aP + 31];
+        x3r = a[aP + 14] - a[aP + 30];
+        x3i = a[aP + 15] - a[aP + 31];
+        y3r = x0r + x2r;
+        y3i = x0i + x2i;
+        y7r = x0r - x2r;
+        y7i = x0i - x2i;
+        x0r = x1r - x3i;
+        x0i = x1i + x3r;
+        y11r = wk1i * x0r - wk1r * x0i;
+        y11i = wk1i * x0i + wk1r * x0r;
+        x0r = x1r + x3i;
+        x0i = x1i - x3r;
+        y15r = wk1r * x0r - wk1i * x0i;
+        y15i = wk1r * x0i + wk1i * x0r;
+        x0r = y12r - y14r;
+        x0i = y12i - y14i;
+        x1r = y12r + y14r;
+        x1i = y12i + y14i;
+        x2r = y13r - y15r;
+        x2i = y13i - y15i;
+        x3r = y13r + y15r;
+        x3i = y13i + y15i;
+        a[aP + 24] = x0r + x2r;
+        a[aP + 25] = x0i + x2i;
+        a[aP + 26] = x0r - x2r;
+        a[aP + 27] = x0i - x2i;
+        a[aP + 28] = x1r - x3i;
+        a[aP + 29] = x1i + x3r;
+        a[aP + 30] = x1r + x3i;
+        a[aP + 31] = x1i - x3r;
+        x0r = y8r + y10r;
+        x0i = y8i + y10i;
+        x1r = y8r - y10r;
+        x1i = y8i - y10i;
+        x2r = y9r + y11r;
+        x2i = y9i + y11i;
+        x3r = y9r - y11r;
+        x3i = y9i - y11i;
+        a[aP + 16] = x0r + x2r;
+        a[aP + 17] = x0i + x2i;
+        a[aP + 18] = x0r - x2r;
+        a[aP + 19] = x0i - x2i;
+        a[aP + 20] = x1r - x3i;
+        a[aP + 21] = x1i + x3r;
+        a[aP + 22] = x1r + x3i;
+        a[aP + 23] = x1i - x3r;
+        x0r = y5r - y7i;
+        x0i = y5i + y7r;
+        x2r = wn4r * (x0r - x0i);
+        x2i = wn4r * (x0i + x0r);
+        x0r = y5r + y7i;
+        x0i = y5i - y7r;
+        x3r = wn4r * (x0r - x0i);
+        x3i = wn4r * (x0i + x0r);
+        x0r = y4r - y6i;
+        x0i = y4i + y6r;
+        x1r = y4r + y6i;
+        x1i = y4i - y6r;
+        a[aP + 8] = x0r + x2r;
+        a[aP + 9] = x0i + x2i;
+        a[aP + 10] = x0r - x2r;
+        a[aP + 11] = x0i - x2i;
+        a[aP + 12] = x1r - x3i;
+        a[aP + 13] = x1i + x3r;
+        a[aP + 14] = x1r + x3i;
+        a[aP + 15] = x1i - x3r;
+        x0r = y0r + y2r;
+        x0i = y0i + y2i;
+        x1r = y0r - y2r;
+        x1i = y0i - y2i;
+        x2r = y1r + y3r;
+        x2i = y1i + y3i;
+        x3r = y1r - y3r;
+        x3i = y1i - y3i;
+        a[aP + 0] = x0r + x2r;
+        a[aP + 1] = x0i + x2i;
+        a[aP + 2] = x0r - x2r;
+        a[aP + 3] = x0i - x2i;
+        a[aP + 4] = x1r - x3i;
+        a[aP + 5] = x1i + x3r;
+        a[aP + 6] = x1r + x3i;
+        a[aP + 7] = x1i - x3r;
+    }
+
+    /** */
+    private void cftf162(double[] a, int aP, double[] w, int wP) {
+        double wn4r, wk1r, wk1i, wk2r, wk2i, wk3r, wk3i, x0r, x0i, x1r, x1i, x2r, x2i, y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i, y4r, y4i, y5r, y5i, y6r, y6i, y7r, y7i, y8r, y8i, y9r, y9i, y10r, y10i, y11r, y11i, y12r, y12i, y13r, y13i, y14r, y14i, y15r, y15i;
+
+        wn4r = w[wP + 1];
+        wk1r = w[wP + 4];
+        wk1i = w[wP + 5];
+        wk3r = w[wP + 6];
+        wk3i = w[wP + 7];
+        wk2r = w[wP + 8];
+        wk2i = w[wP + 9];
+        x1r = a[aP + 0] - a[aP + 17];
+        x1i = a[aP + 1] + a[aP + 16];
+        x0r = a[aP + 8] - a[aP + 25];
+        x0i = a[aP + 9] + a[aP + 24];
+        x2r = wn4r * (x0r - x0i);
+        x2i = wn4r * (x0i + x0r);
+        y0r = x1r + x2r;
+        y0i = x1i + x2i;
+        y4r = x1r - x2r;
+        y4i = x1i - x2i;
+        x1r = a[aP + 0] + a[aP + 17];
+        x1i = a[aP + 1] - a[aP + 16];
+        x0r = a[aP + 8] + a[aP + 25];
+        x0i = a[aP + 9] - a[aP + 24];
+        x2r = wn4r * (x0r - x0i);
+        x2i = wn4r * (x0i + x0r);
+        y8r = x1r - x2i;
+        y8i = x1i + x2r;
+        y12r = x1r + x2i;
+        y12i = x1i - x2r;
+        x0r = a[aP + 2] - a[aP + 19];
+        x0i = a[aP + 3] + a[aP + 18];
+        x1r = wk1r * x0r - wk1i * x0i;
+        x1i = wk1r * x0i + wk1i * x0r;
+        x0r = a[aP + 10] - a[aP + 27];
+        x0i = a[aP + 11] + a[aP + 26];
+        x2r = wk3i * x0r - wk3r * x0i;
+        x2i = wk3i * x0i + wk3r * x0r;
+        y1r = x1r + x2r;
+        y1i = x1i + x2i;
+        y5r = x1r - x2r;
+        y5i = x1i - x2i;
+        x0r = a[aP + 2] + a[aP + 19];
+        x0i = a[aP + 3] - a[aP + 18];
+        x1r = wk3r * x0r - wk3i * x0i;
+        x1i = wk3r * x0i + wk3i * x0r;
+        x0r = a[aP + 10] + a[aP + 27];
+        x0i = a[aP + 11] - a[aP + 26];
+        x2r = wk1r * x0r + wk1i * x0i;
+        x2i = wk1r * x0i - wk1i * x0r;
+        y9r = x1r - x2r;
+        y9i = x1i - x2i;
+        y13r = x1r + x2r;
+        y13i = x1i + x2i;
+        x0r = a[aP + 4] - a[aP + 21];
+        x0i = a[aP + 5] + a[aP + 20];
+        x1r = wk2r * x0r - wk2i * x0i;
+        x1i = wk2r * x0i + wk2i * x0r;
+        x0r = a[aP + 12] - a[aP + 29];
+        x0i = a[aP + 13] + a[aP + 28];
+        x2r = wk2i * x0r - wk2r * x0i;
+        x2i = wk2i * x0i + wk2r * x0r;
+        y2r = x1r + x2r;
+        y2i = x1i + x2i;
+        y6r = x1r - x2r;
+        y6i = x1i - x2i;
+        x0r = a[aP + 4] + a[aP + 21];
+        x0i = a[aP + 5] - a[aP + 20];
+        x1r = wk2i * x0r - wk2r * x0i;
+        x1i = wk2i * x0i + wk2r * x0r;
+        x0r = a[aP + 12] + a[aP + 29];
+        x0i = a[aP + 13] - a[aP + 28];
+        x2r = wk2r * x0r - wk2i * x0i;
+        x2i = wk2r * x0i + wk2i * x0r;
+        y10r = x1r - x2r;
+        y10i = x1i - x2i;
+        y14r = x1r + x2r;
+        y14i = x1i + x2i;
+        x0r = a[aP + 6] - a[aP + 23];
+        x0i = a[aP + 7] + a[aP + 22];
+        x1r = wk3r * x0r - wk3i * x0i;
+        x1i = wk3r * x0i + wk3i * x0r;
+        x0r = a[aP + 14] - a[aP + 31];
+        x0i = a[aP + 15] + a[aP + 30];
+        x2r = wk1i * x0r - wk1r * x0i;
+        x2i = wk1i * x0i + wk1r * x0r;
+        y3r = x1r + x2r;
+        y3i = x1i + x2i;
+        y7r = x1r - x2r;
+        y7i = x1i - x2i;
+        x0r = a[aP + 6] + a[aP + 23];
+        x0i = a[aP + 7] - a[aP + 22];
+        x1r = wk1i * x0r + wk1r * x0i;
+        x1i = wk1i * x0i - wk1r * x0r;
+        x0r = a[aP + 14] + a[aP + 31];
+        x0i = a[aP + 15] - a[aP + 30];
+        x2r = wk3i * x0r - wk3r * x0i;
+        x2i = wk3i * x0i + wk3r * x0r;
+        y11r = x1r + x2r;
+        y11i = x1i + x2i;
+        y15r = x1r - x2r;
+        y15i = x1i - x2i;
+        x1r = y0r + y2r;
+        x1i = y0i + y2i;
+        x2r = y1r + y3r;
+        x2i = y1i + y3i;
+        a[aP + 0] = x1r + x2r;
+        a[aP + 1] = x1i + x2i;
+        a[aP + 2] = x1r - x2r;
+        a[aP + 3] = x1i - x2i;
+        x1r = y0r - y2r;
+        x1i = y0i - y2i;
+        x2r = y1r - y3r;
+        x2i = y1i - y3i;
+        a[aP + 4] = x1r - x2i;
+        a[aP + 5] = x1i + x2r;
+        a[aP + 6] = x1r + x2i;
+        a[aP + 7] = x1i - x2r;
+        x1r = y4r - y6i;
+        x1i = y4i + y6r;
+        x0r = y5r - y7i;
+        x0i = y5i + y7r;
+        x2r = wn4r * (x0r - x0i);
+        x2i = wn4r * (x0i + x0r);
+        a[aP + 8] = x1r + x2r;
+        a[aP + 9] = x1i + x2i;
+        a[aP + 10] = x1r - x2r;
+        a[aP + 11] = x1i - x2i;
+        x1r = y4r + y6i;
+        x1i = y4i - y6r;
+        x0r = y5r + y7i;
+        x0i = y5i - y7r;
+        x2r = wn4r * (x0r - x0i);
+        x2i = wn4r * (x0i + x0r);
+        a[aP + 12] = x1r - x2i;
+        a[aP + 13] = x1i + x2r;
+        a[aP + 14] = x1r + x2i;
+        a[aP + 15] = x1i - x2r;
+        x1r = y8r + y10r;
+        x1i = y8i + y10i;
+        x2r = y9r - y11r;
+        x2i = y9i - y11i;
+        a[aP + 16] = x1r + x2r;
+        a[aP + 17] = x1i + x2i;
+        a[aP + 18] = x1r - x2r;
+        a[aP + 19] = x1i - x2i;
+        x1r = y8r - y10r;
+        x1i = y8i - y10i;
+        x2r = y9r + y11r;
+        x2i = y9i + y11i;
+        a[aP + 20] = x1r - x2i;
+        a[aP + 21] = x1i + x2r;
+        a[aP + 22] = x1r + x2i;
+        a[aP + 23] = x1i - x2r;
+        x1r = y12r - y14i;
+        x1i = y12i + y14r;
+        x0r = y13r + y15i;
+        x0i = y13i - y15r;
+        x2r = wn4r * (x0r - x0i);
+        x2i = wn4r * (x0i + x0r);
+        a[aP + 24] = x1r + x2r;
+        a[aP + 25] = x1i + x2i;
+        a[aP + 26] = x1r - x2r;
+        a[aP + 27] = x1i - x2i;
+        x1r = y12r + y14i;
+        x1i = y12i - y14r;
+        x0r = y13r - y15i;
+        x0i = y13i + y15r;
+        x2r = wn4r * (x0r - x0i);
+        x2i = wn4r * (x0i + x0r);
+        a[aP + 28] = x1r - x2i;
+        a[aP + 29] = x1i + x2r;
+        a[aP + 30] = x1r + x2i;
+        a[aP + 31] = x1i - x2r;
+    }
+
+    /** */
+    private void cftf081(double[] a, int aP, double[] w, int wP) {
+        double wn4r, x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i, y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i, y4r, y4i, y5r, y5i, y6r, y6i, y7r, y7i;
+
+        wn4r = w[wP + 1];
+        x0r = a[aP + 0] + a[aP + 8];
+        x0i = a[aP + 1] + a[aP + 9];
+        x1r = a[aP + 0] - a[aP + 8];
+        x1i = a[aP + 1] - a[aP + 9];
+        x2r = a[aP + 4] + a[aP + 12];
+        x2i = a[aP + 5] + a[aP + 13];
+        x3r = a[aP + 4] - a[aP + 12];
+        x3i = a[aP + 5] - a[aP + 13];
+        y0r = x0r + x2r;
+        y0i = x0i + x2i;
+        y2r = x0r - x2r;
+        y2i = x0i - x2i;
+        y1r = x1r - x3i;
+        y1i = x1i + x3r;
+        y3r = x1r + x3i;
+        y3i = x1i - x3r;
+        x0r = a[aP + 2] + a[aP + 10];
+        x0i = a[aP + 3] + a[aP + 11];
+        x1r = a[aP + 2] - a[aP + 10];
+        x1i = a[aP + 3] - a[aP + 11];
+        x2r = a[aP + 6] + a[aP + 14];
+        x2i = a[aP + 7] + a[aP + 15];
+        x3r = a[aP + 6] - a[aP + 14];
+        x3i = a[aP + 7] - a[aP + 15];
+        y4r = x0r + x2r;
+        y4i = x0i + x2i;
+        y6r = x0r - x2r;
+        y6i = x0i - x2i;
+        x0r = x1r - x3i;
+        x0i = x1i + x3r;
+        x2r = x1r + x3i;
+        x2i = x1i - x3r;
+        y5r = wn4r * (x0r - x0i);
+        y5i = wn4r * (x0r + x0i);
+        y7r = wn4r * (x2r - x2i);
+        y7i = wn4r * (x2r + x2i);
+        a[aP + 8] = y1r + y5r;
+        a[aP + 9] = y1i + y5i;
+        a[aP + 10] = y1r - y5r;
+        a[aP + 11] = y1i - y5i;
+        a[aP + 12] = y3r - y7i;
+        a[aP + 13] = y3i + y7r;
+        a[aP + 14] = y3r + y7i;
+        a[aP + 15] = y3i - y7r;
+        a[aP + 0] = y0r + y4r;
+        a[aP + 1] = y0i + y4i;
+        a[aP + 2] = y0r - y4r;
+        a[aP + 3] = y0i - y4i;
+        a[aP + 4] = y2r - y6i;
+        a[aP + 5] = y2i + y6r;
+        a[aP + 6] = y2r + y6i;
+        a[aP + 7] = y2i - y6r;
+    }
+
+    /** */
+    private void cftf082(double[] a, int aP, double[] w, int wP) {
+        double wn4r, wk1r, wk1i, x0r, x0i, x1r, x1i, y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i, y4r, y4i, y5r, y5i, y6r, y6i, y7r, y7i;
+
+        wn4r = w[wP + 1];
+        wk1r = w[wP + 4];
+        wk1i = w[wP + 5];
+        y0r = a[aP + 0] - a[aP + 9];
+        y0i = a[aP + 1] + a[aP + 8];
+        y1r = a[aP + 0] + a[aP + 9];
+        y1i = a[aP + 1] - a[aP + 8];
+        x0r = a[aP + 4] - a[aP + 13];
+        x0i = a[aP + 5] + a[aP + 12];
+        y2r = wn4r * (x0r - x0i);
+        y2i = wn4r * (x0i + x0r);
+        x0r = a[aP + 4] + a[aP + 13];
+        x0i = a[aP + 5] - a[aP + 12];
+        y3r = wn4r * (x0r - x0i);
+        y3i = wn4r * (x0i + x0r);
+        x0r = a[aP + 2] - a[aP + 11];
+        x0i = a[aP + 3] + a[aP + 10];
+        y4r = wk1r * x0r - wk1i * x0i;
+        y4i = wk1r * x0i + wk1i * x0r;
+        x0r = a[aP + 2] + a[aP + 11];
+        x0i = a[aP + 3] - a[aP + 10];
+        y5r = wk1i * x0r - wk1r * x0i;
+        y5i = wk1i * x0i + wk1r * x0r;
+        x0r = a[aP + 6] - a[aP + 15];
+        x0i = a[aP + 7] + a[aP + 14];
+        y6r = wk1i * x0r - wk1r * x0i;
+        y6i = wk1i * x0i + wk1r * x0r;
+        x0r = a[aP + 6] + a[aP + 15];
+        x0i = a[aP + 7] - a[aP + 14];
+        y7r = wk1r * x0r - wk1i * x0i;
+        y7i = wk1r * x0i + wk1i * x0r;
+        x0r = y0r + y2r;
+        x0i = y0i + y2i;
+        x1r = y4r + y6r;
+        x1i = y4i + y6i;
+        a[aP + 0] = x0r + x1r;
+        a[aP + 1] = x0i + x1i;
+        a[aP + 2] = x0r - x1r;
+        a[aP + 3] = x0i - x1i;
+        x0r = y0r - y2r;
+        x0i = y0i - y2i;
+        x1r = y4r - y6r;
+        x1i = y4i - y6i;
+        a[aP + 4] = x0r - x1i;
+        a[aP + 5] = x0i + x1r;
+        a[aP + 6] = x0r + x1i;
+        a[aP + 7] = x0i - x1r;
+        x0r = y1r - y3i;
+        x0i = y1i + y3r;
+        x1r = y5r - y7r;
+        x1i = y5i - y7i;
+        a[aP + 8] = x0r + x1r;
+        a[aP + 9] = x0i + x1i;
+        a[aP + 10] = x0r - x1r;
+        a[aP + 11] = x0i - x1i;
+        x0r = y1r + y3i;
+        x0i = y1i - y3r;
+        x1r = y5r + y7r;
+        x1i = y5i + y7i;
+        a[aP + 12] = x0r - x1i;
+        a[aP + 13] = x0i + x1r;
+        a[aP + 14] = x0r + x1i;
+        a[aP + 15] = x0i - x1r;
+    }
+
+    /**
+     * 3rd
+     * when n = 8.
+     * @see #cftfsub(int, double[], int[], int, int, double[])
+     */
+    private void cftf040(double[] a) {
+        double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
+
+        x0r = a[0] + a[4];
+        x0i = a[1] + a[5];
+        x1r = a[0] - a[4];
+        x1i = a[1] - a[5];
+        x2r = a[2] + a[6];
+        x2i = a[3] + a[7];
+        x3r = a[2] - a[6];
+        x3i = a[3] - a[7];
+        a[0] = x0r + x2r;
+        a[1] = x0i + x2i;
+        a[4] = x0r - x2r;
+        a[5] = x0i - x2i;
+        a[2] = x1r - x3i;
+        a[3] = x1i + x3r;
+        a[6] = x1r + x3i;
+        a[7] = x1i - x3r;
+    }
+
+    /**
+     * 3rd
+     * when n = 8.
+     * @see #cftbsub(int, double[], int[], int, int, double[])
+     */
+    private void cftb040(double[] a) {
+        double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
+
+        x0r = a[0] + a[4];
+        x0i = a[1] + a[5];
+        x1r = a[0] - a[4];
+        x1i = a[1] - a[5];
+        x2r = a[2] + a[6];
+        x2i = a[3] + a[7];
+        x3r = a[2] - a[6];
+        x3i = a[3] - a[7];
+        a[0] = x0r + x2r;
+        a[1] = x0i + x2i;
+        a[4] = x0r - x2r;
+        a[5] = x0i - x2i;
+        a[2] = x1r + x3i;
+        a[3] = x1i - x3r;
+        a[6] = x1r - x3i;
+        a[7] = x1i + x3r;
+    }
+
+    /**
+     * 3rd
+     * when n = 4.
+     * @see #cftbsub(int, double[], int[], int, int, double[])
+     * @see #cftfsub(int, double[], int[], int, int, double[])
+     */
+    private void cftx020(double[] a) {
+        double x0r, x0i;
+
+        x0r = a[0] - a[2];
+        x0i = a[1] - a[3];
+        a[0] += a[2];
+        a[1] += a[3];
+        a[2] = x0r;
+        a[3] = x0i;
+    }
+
+    /**
+     * 2nd
+     * @see #rdft(int, int, double[], int[], double[])
+     * @see #ddct(int, int, double[], int[], double[])
+     * @see #ddst(int, int, double[], int[], double[])
+     * @see #dfst(int, double[], double[], int[], double[])
+     * @see #dfct(int, double[], double[], int[], double[])
+     */
+    private void rftfsub(int n, double[] a, int nc, double[] c, int cP) {
+        int j, k, kk, ks, m;
+        double wkr, wki, xr, xi, yr, yi;
+
+        m = n >> 1;
+        ks = 2 * nc / m;
+        kk = 0;
+        for (j = 2; j < m; j += 2) {
+            k = n - j;
+            kk += ks;
+            wkr = 0.5 - c[cP + nc - kk];
+            wki = c[cP + kk];
+            xr = a[j] - a[k];
+            xi = a[j + 1] + a[k + 1];
+            yr = wkr * xr - wki * xi;
+            yi = wkr * xi + wki * xr;
+            a[j] -= yr;
+            a[j + 1] -= yi;
+            a[k] += yr;
+            a[k + 1] -= yi;
+        }
+    }
+
+    /**
+     * 2nd
+     * @see #rdft(int, int, double[], int[], double[])
+     * @see #ddct(int, int, double[], int[], double[])
+     * @see #ddst(int, int, double[], int[], double[])
+     */
+    private void rftbsub(int n, double[] a, int nc, double[] c, int cP) {
+        int j, k, kk, ks, m;
+        double wkr, wki, xr, xi, yr, yi;
+
+        m = n >> 1;
+        ks = 2 * nc / m;
+        kk = 0;
+        for (j = 2; j < m; j += 2) {
+            k = n - j;
+            kk += ks;
+            wkr = 0.5 - c[cP + nc - kk];
+            wki = c[cP + kk];
+            xr = a[j] - a[k];
+            xi = a[j + 1] + a[k + 1];
+            yr = wkr * xr + wki * xi;
+            yi = wkr * xi - wki * xr;
+            a[j] -= yr;
+            a[j + 1] -= yi;
+            a[k] += yr;
+            a[k + 1] -= yi;
+        }
+    }
+
+    /**
+     * 2nd
+     * @see #ddct(int, int, double[], int[], double[])
+     * @see #dfct(int, double[], double[], int[], double[])
+     */
+    private void dctsub(int n, double[] a, int nc, double[] c, int cP) {
+        int j, k, kk, ks, m;
+        double wkr, wki, xr;
+
+        m = n >> 1;
+        ks = nc / n;
+        kk = 0;
+        for (j = 1; j < m; j++) {
+            k = n - j;
+            kk += ks;
+            wkr = c[cP + kk] - c[cP + nc - kk];
+            wki = c[cP + kk] + c[cP + nc - kk];
+            xr = wki * a[j] - wkr * a[k];
+            a[j] = wkr * a[j] + wki * a[k];
+            a[k] = xr;
+        }
+        a[m] *= c[cP + 0];
+    }
+
+    /**
+     * 2nd
+     * @see #ddst(int, int, double[], int[], double[])
+     * @see #dfst(int, double[], double[], int[], double[])
+     */
+    private void dstsub(int n, double[] a, int nc, double[] c, int cP) {
+        int j, k, kk, ks, m;
+        double wkr, wki, xr;
+
+        m = n >> 1;
+        ks = nc / n;
+        kk = 0;
+        for (j = 1; j < m; j++) {
+            k = n - j;
+            kk += ks;
+            wkr = c[cP + kk] - c[cP + nc - kk];
+            wki = c[cP + kk] + c[cP + nc - kk];
+            xr = wki * a[k] - wkr * a[j];
+            a[k] = wkr * a[k] + wki * a[j];
+            a[j] = xr;
+        }
+        a[m] *= c[cP + 0];
+    }
+}
+
+/* */

+ 3 - 0
android/src/main/kotlin/cn/i2edu/speech_plugin/audioUtils/bean/SimpleWord.kt

@@ -0,0 +1,3 @@
+package cn.i2edu.dubbing_lib.bean
+
+data class SimpleWord (val content: String, val score: Float)

+ 111 - 0
android/src/main/kotlin/cn/i2edu/speech_plugin/util/AudioEvaluatorUtil.kt

@@ -0,0 +1,111 @@
+package cn.i2edu.dubbing_lib.util
+
+import android.content.Context
+import android.os.Bundle
+import android.util.Log
+import cn.i2edu.speech_plugin.audioUtils.audiotransfer.DecodeEngine
+import cn.i2edu.speech_plugin.audioUtils.audiotransfer.DecodeOperateInterface
+import com.iflytek.cloud.*
+import java.io.File
+import java.io.FileInputStream
+
+interface EvaluatorCallBack {
+    fun onResult(result: EvaluatorResult)
+    fun onError(error: SpeechError)
+}
+
+class AudioEvaluatorUtil private constructor(val context: Context){
+
+    private var evaluatorCallBack: EvaluatorCallBack? = null
+    private var speechEvaluator: SpeechEvaluator? = null
+    private val Tag: String = "AudioEvaluatorUtil"
+
+    companion object {
+        @Volatile private var instance: AudioEvaluatorUtil? = null
+        fun getInstance(context: Context) = instance
+                ?: synchronized(this) {
+            instance
+                    ?: AudioEvaluatorUtil(context)
+                    .also {
+                        it.speechEvaluator = SpeechEvaluator.createEvaluator(context, null)
+                    }
+                    .also { instance = it }
+        }
+    }
+
+    fun startEvaluator(en: String, filePath: String, decodedFilePath: String) {
+        speechEvaluator?.setParameter(SpeechConstant.LANGUAGE, "en_us")
+        speechEvaluator?.setParameter(SpeechConstant.ISE_CATEGORY, "read_sentence")
+        speechEvaluator?.setParameter(SpeechConstant.AUDIO_SOURCE,"-1")
+
+        if (!File(decodedFilePath).exists()) {
+            File(decodedFilePath).createNewFile()
+        }
+        Thread{
+            DecodeEngine.getInstance(context).beginDecodeMusicFile(filePath, decodedFilePath, 0, 16000, 1, 2, object : DecodeOperateInterface {
+                override fun updateDecodeProgress(decodeProgress: Int) {
+                }
+
+                override fun decodeSuccess() {
+                    try {
+                        val file = File(decodedFilePath)
+                        val fileInputStream = FileInputStream(file)
+                        val bytes = ByteArray(1024)
+                        speechEvaluator?.startEvaluating(en, null, object : EvaluatorListener {
+                            override fun onVolumeChanged(p0: Int, p1: ByteArray?) {
+                            }
+
+                            override fun onResult(p0: EvaluatorResult, p1: Boolean) {
+                                Log.d(Tag, p0.toString())
+                                evaluatorCallBack?.onResult(p0)
+                                file.delete()
+                                onDestory()
+                            }
+
+                            override fun onBeginOfSpeech() {
+                            }
+
+                            override fun onEvent(p0: Int, p1: Int, p2: Int, p3: Bundle?) {
+                            }
+
+                            override fun onEndOfSpeech() {
+                            }
+
+                            override fun onError(p0: SpeechError) {
+                                Log.d(Tag, p0.toString())
+                                evaluatorCallBack?.onError(p0)
+                                file.delete()
+                                onDestory()
+                            }
+                        })
+                        var byteCount = fileInputStream.read(bytes)
+                        while (byteCount > 0) {
+                            speechEvaluator?.writeAudio(bytes, 0, byteCount)
+                            Thread.sleep(10)
+                            byteCount = fileInputStream.read(bytes)
+                        }
+                        speechEvaluator?.stopEvaluating()
+                        fileInputStream.close()
+                    } catch (e: Exception) {
+                        e.printStackTrace()
+                    }
+
+                }
+
+                override fun decodeFail() {
+                    val speechError = SpeechError(1, "评测失败,请稍后再试!")
+                    evaluatorCallBack?.onError(speechError)
+                }
+            })
+        }.start()
+    }
+
+    fun setEvaluatorCallBack(callBack: EvaluatorCallBack): AudioEvaluatorUtil?{
+        this.evaluatorCallBack = callBack
+        return instance
+    }
+
+    fun onDestory() {
+        speechEvaluator?.destroy()
+    }
+}

+ 73 - 0
example/.gitignore

@@ -0,0 +1,73 @@
+# Miscellaneous
+*.class
+*.log
+*.pyc
+*.swp
+.DS_Store
+.atom/
+.buildlog/
+.history
+.svn/
+
+# IntelliJ related
+*.iml
+*.ipr
+*.iws
+.idea/
+
+# The .vscode folder contains launch configuration and tasks you configure in
+# VS Code which you may wish to be included in version control, so this line
+# is commented out by default.
+#.vscode/
+
+# Flutter/Dart/Pub related
+**/doc/api/
+.dart_tool/
+.flutter-plugins
+.packages
+.pub-cache/
+.pub/
+/build/
+
+# Android related
+**/android/**/gradle-wrapper.jar
+**/android/.gradle
+**/android/captures/
+**/android/gradlew
+**/android/gradlew.bat
+**/android/local.properties
+**/android/**/GeneratedPluginRegistrant.java
+
+# iOS/XCode related
+**/ios/**/*.mode1v3
+**/ios/**/*.mode2v3
+**/ios/**/*.moved-aside
+**/ios/**/*.pbxuser
+**/ios/**/*.perspectivev3
+**/ios/**/*sync/
+**/ios/**/.sconsign.dblite
+**/ios/**/.tags*
+**/ios/**/.vagrant/
+**/ios/**/DerivedData/
+**/ios/**/Icon?
+**/ios/**/Pods/
+**/ios/**/.symlinks/
+**/ios/**/profile
+**/ios/**/xcuserdata
+**/ios/.generated/
+**/ios/Flutter/App.framework
+**/ios/Flutter/Flutter.framework
+**/ios/Flutter/Generated.xcconfig
+**/ios/Flutter/app.flx
+**/ios/Flutter/app.zip
+**/ios/Flutter/flutter_assets/
+**/ios/Flutter/flutter_export_environment.sh
+**/ios/ServiceDefinitions.json
+**/ios/Runner/GeneratedPluginRegistrant.*
+
+# Exceptions to above rules.
+!**/ios/**/default.mode1v3
+!**/ios/**/default.mode2v3
+!**/ios/**/default.pbxuser
+!**/ios/**/default.perspectivev3
+!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages

+ 10 - 0
example/.metadata

@@ -0,0 +1,10 @@
+# This file tracks properties of this Flutter project.
+# Used by Flutter tool to assess capabilities and perform upgrades etc.
+#
+# This file should be version controlled and should not be manually edited.
+
+version:
+  revision: 68587a0916366e9512a78df22c44163d041dd5f3
+  channel: stable
+
+project_type: app

+ 16 - 0
example/README.md

@@ -0,0 +1,16 @@
+# speech_plugin_example
+
+Demonstrates how to use the speech_plugin plugin.
+
+## Getting Started
+
+This project is a starting point for a Flutter application.
+
+A few resources to get you started if this is your first Flutter project:
+
+- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab)
+- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook)
+
+For help getting started with Flutter, view our
+[online documentation](https://flutter.dev/docs), which offers tutorials,
+samples, guidance on mobile development, and a full API reference.

+ 67 - 0
example/android/app/build.gradle

@@ -0,0 +1,67 @@
+def localProperties = new Properties()
+def localPropertiesFile = rootProject.file('local.properties')
+if (localPropertiesFile.exists()) {
+    localPropertiesFile.withReader('UTF-8') { reader ->
+        localProperties.load(reader)
+    }
+}
+
+def flutterRoot = localProperties.getProperty('flutter.sdk')
+if (flutterRoot == null) {
+    throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
+}
+
+def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
+if (flutterVersionCode == null) {
+    flutterVersionCode = '1'
+}
+
+def flutterVersionName = localProperties.getProperty('flutter.versionName')
+if (flutterVersionName == null) {
+    flutterVersionName = '1.0'
+}
+
+apply plugin: 'com.android.application'
+apply plugin: 'kotlin-android'
+apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
+
+android {
+    compileSdkVersion 28
+
+    sourceSets {
+        main.java.srcDirs += 'src/main/kotlin'
+    }
+
+    lintOptions {
+        disable 'InvalidPackage'
+    }
+
+    defaultConfig {
+        // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
+        applicationId "cn.i2edu.speech_plugin_example"
+        minSdkVersion 16
+        targetSdkVersion 28
+        versionCode flutterVersionCode.toInteger()
+        versionName flutterVersionName
+        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+    }
+
+    buildTypes {
+        release {
+            // TODO: Add your own signing config for the release build.
+            // Signing with the debug keys for now, so `flutter run --release` works.
+            signingConfig signingConfigs.debug
+        }
+    }
+}
+
+flutter {
+    source '../..'
+}
+
+dependencies {
+    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+    testImplementation 'junit:junit:4.12'
+    androidTestImplementation 'com.android.support.test:runner:1.0.2'
+    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
+}

+ 7 - 0
example/android/app/src/debug/AndroidManifest.xml

@@ -0,0 +1,7 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="cn.i2edu.speech_plugin_example">
+    <!-- Flutter needs it to communicate with the running application
+         to allow setting breakpoints, to provide hot reload, etc.
+    -->
+    <uses-permission android:name="android.permission.INTERNET"/>
+</manifest>

+ 33 - 0
example/android/app/src/main/AndroidManifest.xml

@@ -0,0 +1,33 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="cn.i2edu.speech_plugin_example">
+
+    <!-- io.flutter.app.FlutterApplication is an android.app.Application that
+         calls FlutterMain.startInitialization(this); in its onCreate method.
+         In most cases you can leave this as-is, but you if you want to provide
+         additional functionality it is fine to subclass or reimplement
+         FlutterApplication and put your custom class here. -->
+    <application
+        android:name="io.flutter.app.FlutterApplication"
+        android:label="speech_plugin_example"
+        android:icon="@mipmap/ic_launcher">
+        <activity
+            android:name=".MainActivity"
+            android:launchMode="singleTop"
+            android:theme="@style/LaunchTheme"
+            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
+            android:hardwareAccelerated="true"
+            android:windowSoftInputMode="adjustResize">
+            <!-- This keeps the window background of the activity showing
+                 until Flutter renders its first frame. It can be removed if
+                 there is no splash screen (such as the default splash screen
+                 defined in @style/LaunchTheme). -->
+            <meta-data
+                android:name="io.flutter.app.android.SplashScreenUntilFirstFrame"
+                android:value="true" />
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>

+ 13 - 0
example/android/app/src/main/kotlin/cn/i2edu/speech_plugin_example/MainActivity.kt

@@ -0,0 +1,13 @@
+package cn.i2edu.speech_plugin_example
+
+import android.os.Bundle
+
+import io.flutter.app.FlutterActivity
+import io.flutter.plugins.GeneratedPluginRegistrant
+
+class MainActivity: FlutterActivity() {
+  override fun onCreate(savedInstanceState: Bundle?) {
+    super.onCreate(savedInstanceState)
+    GeneratedPluginRegistrant.registerWith(this)
+  }
+}

+ 12 - 0
example/android/app/src/main/res/drawable/launch_background.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Modify this file to customize your launch splash screen -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@android:color/white" />
+
+    <!-- You can insert your own image assets here -->
+    <!-- <item>
+        <bitmap
+            android:gravity="center"
+            android:src="@mipmap/launch_image" />
+    </item> -->
+</layer-list>

BIN
example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png


BIN
example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png


BIN
example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png


BIN
example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png


BIN
example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png


+ 8 - 0
example/android/app/src/main/res/values/styles.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
+        <!-- Show a splash screen on the activity. Automatically removed when
+             Flutter draws its first frame -->
+        <item name="android:windowBackground">@drawable/launch_background</item>
+    </style>
+</resources>

+ 7 - 0
example/android/app/src/profile/AndroidManifest.xml

@@ -0,0 +1,7 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="cn.i2edu.speech_plugin_example">
+    <!-- Flutter needs it to communicate with the running application
+         to allow setting breakpoints, to provide hot reload, etc.
+    -->
+    <uses-permission android:name="android.permission.INTERNET"/>
+</manifest>

+ 31 - 0
example/android/build.gradle

@@ -0,0 +1,31 @@
+buildscript {
+    ext.kotlin_version = '1.2.71'
+    repositories {
+        google()
+        jcenter()
+    }
+
+    dependencies {
+        classpath 'com.android.tools.build:gradle:3.2.1'
+        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+    }
+}
+
+allprojects {
+    repositories {
+        google()
+        jcenter()
+    }
+}
+
+rootProject.buildDir = '../build'
+subprojects {
+    project.buildDir = "${rootProject.buildDir}/${project.name}"
+}
+subprojects {
+    project.evaluationDependsOn(':app')
+}
+
+task clean(type: Delete) {
+    delete rootProject.buildDir
+}

+ 2 - 0
example/android/gradle.properties

@@ -0,0 +1,2 @@
+org.gradle.jvmargs=-Xmx1536M
+

+ 6 - 0
example/android/gradle/wrapper/gradle-wrapper.properties

@@ -0,0 +1,6 @@
+#Fri Jun 23 08:50:38 CEST 2017
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip

+ 15 - 0
example/android/settings.gradle

@@ -0,0 +1,15 @@
+include ':app'
+
+def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
+
+def plugins = new Properties()
+def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
+if (pluginsFile.exists()) {
+    pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
+}
+
+plugins.each { name, path ->
+    def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
+    include ":$name"
+    project(":$name").projectDir = pluginDirectory
+}

+ 26 - 0
example/ios/Flutter/AppFrameworkInfo.plist

@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+  <key>CFBundleDevelopmentRegion</key>
+  <string>$(DEVELOPMENT_LANGUAGE)</string>
+  <key>CFBundleExecutable</key>
+  <string>App</string>
+  <key>CFBundleIdentifier</key>
+  <string>io.flutter.flutter.app</string>
+  <key>CFBundleInfoDictionaryVersion</key>
+  <string>6.0</string>
+  <key>CFBundleName</key>
+  <string>App</string>
+  <key>CFBundlePackageType</key>
+  <string>FMWK</string>
+  <key>CFBundleShortVersionString</key>
+  <string>1.0</string>
+  <key>CFBundleSignature</key>
+  <string>????</string>
+  <key>CFBundleVersion</key>
+  <string>1.0</string>
+  <key>MinimumOSVersion</key>
+  <string>8.0</string>
+</dict>
+</plist>

+ 1 - 0
example/ios/Flutter/Debug.xcconfig

@@ -0,0 +1 @@
+#include "Generated.xcconfig"

+ 1 - 0
example/ios/Flutter/Release.xcconfig

@@ -0,0 +1 @@
+#include "Generated.xcconfig"

+ 519 - 0
example/ios/Runner.xcodeproj/project.pbxproj

@@ -0,0 +1,519 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 46;
+	objects = {
+
+/* Begin PBXBuildFile section */
+		1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
+		3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
+		3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; };
+		3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+		74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
+		9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; };
+		9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+		9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; };
+		97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
+		97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
+		97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+		9705A1C41CF9048500538489 /* Embed Frameworks */ = {
+			isa = PBXCopyFilesBuildPhase;
+			buildActionMask = 2147483647;
+			dstPath = "";
+			dstSubfolderSpec = 10;
+			files = (
+				3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */,
+				9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */,
+			);
+			name = "Embed Frameworks";
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+		1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
+		1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
+		3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
+		3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = "<group>"; };
+		74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
+		74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
+		7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
+		9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
+		9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
+		9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = "<group>"; };
+		97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
+		97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
+		97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
+		97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
+		97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+		97C146EB1CF9000F007C117D /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
+				3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+		9740EEB11CF90186004384FC /* Flutter */ = {
+			isa = PBXGroup;
+			children = (
+				3B80C3931E831B6300D905FE /* App.framework */,
+				3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
+				9740EEBA1CF902C7004384FC /* Flutter.framework */,
+				9740EEB21CF90195004384FC /* Debug.xcconfig */,
+				7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
+				9740EEB31CF90195004384FC /* Generated.xcconfig */,
+			);
+			name = Flutter;
+			sourceTree = "<group>";
+		};
+		97C146E51CF9000F007C117D = {
+			isa = PBXGroup;
+			children = (
+				9740EEB11CF90186004384FC /* Flutter */,
+				97C146F01CF9000F007C117D /* Runner */,
+				97C146EF1CF9000F007C117D /* Products */,
+			);
+			sourceTree = "<group>";
+		};
+		97C146EF1CF9000F007C117D /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				97C146EE1CF9000F007C117D /* Runner.app */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		97C146F01CF9000F007C117D /* Runner */ = {
+			isa = PBXGroup;
+			children = (
+				97C146FA1CF9000F007C117D /* Main.storyboard */,
+				97C146FD1CF9000F007C117D /* Assets.xcassets */,
+				97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
+				97C147021CF9000F007C117D /* Info.plist */,
+				97C146F11CF9000F007C117D /* Supporting Files */,
+				1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
+				1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
+				74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
+				74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
+			);
+			path = Runner;
+			sourceTree = "<group>";
+		};
+		97C146F11CF9000F007C117D /* Supporting Files */ = {
+			isa = PBXGroup;
+			children = (
+			);
+			name = "Supporting Files";
+			sourceTree = "<group>";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+		97C146ED1CF9000F007C117D /* Runner */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
+			buildPhases = (
+				9740EEB61CF901F6004384FC /* Run Script */,
+				97C146EA1CF9000F007C117D /* Sources */,
+				97C146EB1CF9000F007C117D /* Frameworks */,
+				97C146EC1CF9000F007C117D /* Resources */,
+				9705A1C41CF9048500538489 /* Embed Frameworks */,
+				3B06AD1E1E4923F5004D2608 /* Thin Binary */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = Runner;
+			productName = Runner;
+			productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
+			productType = "com.apple.product-type.application";
+		};
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+		97C146E61CF9000F007C117D /* Project object */ = {
+			isa = PBXProject;
+			attributes = {
+				LastUpgradeCheck = 1020;
+				ORGANIZATIONNAME = "The Chromium Authors";
+				TargetAttributes = {
+					97C146ED1CF9000F007C117D = {
+						CreatedOnToolsVersion = 7.3.1;
+						LastSwiftMigration = 0910;
+					};
+				};
+			};
+			buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
+			compatibilityVersion = "Xcode 3.2";
+			developmentRegion = en;
+			hasScannedForEncodings = 0;
+			knownRegions = (
+				en,
+				Base,
+			);
+			mainGroup = 97C146E51CF9000F007C117D;
+			productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
+			projectDirPath = "";
+			projectRoot = "";
+			targets = (
+				97C146ED1CF9000F007C117D /* Runner */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+		97C146EC1CF9000F007C117D /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
+				3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
+				9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */,
+				97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
+				97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+		3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+			);
+			name = "Thin Binary";
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin";
+		};
+		9740EEB61CF901F6004384FC /* Run Script */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+			);
+			name = "Run Script";
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
+		};
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+		97C146EA1CF9000F007C117D /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
+				1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXVariantGroup section */
+		97C146FA1CF9000F007C117D /* Main.storyboard */ = {
+			isa = PBXVariantGroup;
+			children = (
+				97C146FB1CF9000F007C117D /* Base */,
+			);
+			name = Main.storyboard;
+			sourceTree = "<group>";
+		};
+		97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
+			isa = PBXVariantGroup;
+			children = (
+				97C147001CF9000F007C117D /* Base */,
+			);
+			name = LaunchScreen.storyboard;
+			sourceTree = "<group>";
+		};
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+		249021D3217E4FDB00AE95B9 /* Profile */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_COMMA = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				ENABLE_NS_ASSERTIONS = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+				MTL_ENABLE_DEBUG_INFO = NO;
+				SDKROOT = iphoneos;
+				TARGETED_DEVICE_FAMILY = "1,2";
+				VALIDATE_PRODUCT = YES;
+			};
+			name = Profile;
+		};
+		249021D4217E4FDB00AE95B9 /* Profile */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
+			buildSettings = {
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				CLANG_ENABLE_MODULES = YES;
+				CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+				ENABLE_BITCODE = NO;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Flutter",
+				);
+				INFOPLIST_FILE = Runner/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+				LIBRARY_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Flutter",
+				);
+				PRODUCT_BUNDLE_IDENTIFIER = cn.i2edu.speechPluginExample;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
+				SWIFT_VERSION = 4.0;
+				VERSIONING_SYSTEM = "apple-generic";
+			};
+			name = Profile;
+		};
+		97C147031CF9000F007C117D /* Debug */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_COMMA = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				ENABLE_TESTABILITY = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					"DEBUG=1",
+					"$(inherited)",
+				);
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+				MTL_ENABLE_DEBUG_INFO = YES;
+				ONLY_ACTIVE_ARCH = YES;
+				SDKROOT = iphoneos;
+				TARGETED_DEVICE_FAMILY = "1,2";
+			};
+			name = Debug;
+		};
+		97C147041CF9000F007C117D /* Release */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_COMMA = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				ENABLE_NS_ASSERTIONS = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+				MTL_ENABLE_DEBUG_INFO = NO;
+				SDKROOT = iphoneos;
+				SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
+				TARGETED_DEVICE_FAMILY = "1,2";
+				VALIDATE_PRODUCT = YES;
+			};
+			name = Release;
+		};
+		97C147061CF9000F007C117D /* Debug */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
+			buildSettings = {
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				CLANG_ENABLE_MODULES = YES;
+				CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+				ENABLE_BITCODE = NO;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Flutter",
+				);
+				INFOPLIST_FILE = Runner/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+				LIBRARY_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Flutter",
+				);
+				PRODUCT_BUNDLE_IDENTIFIER = cn.i2edu.speechPluginExample;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
+				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+				SWIFT_VERSION = 4.0;
+				VERSIONING_SYSTEM = "apple-generic";
+			};
+			name = Debug;
+		};
+		97C147071CF9000F007C117D /* Release */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
+			buildSettings = {
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				CLANG_ENABLE_MODULES = YES;
+				CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+				ENABLE_BITCODE = NO;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Flutter",
+				);
+				INFOPLIST_FILE = Runner/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+				LIBRARY_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Flutter",
+				);
+				PRODUCT_BUNDLE_IDENTIFIER = cn.i2edu.speechPluginExample;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
+				SWIFT_VERSION = 4.0;
+				VERSIONING_SYSTEM = "apple-generic";
+			};
+			name = Release;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				97C147031CF9000F007C117D /* Debug */,
+				97C147041CF9000F007C117D /* Release */,
+				249021D3217E4FDB00AE95B9 /* Profile */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				97C147061CF9000F007C117D /* Debug */,
+				97C147071CF9000F007C117D /* Release */,
+				249021D4217E4FDB00AE95B9 /* Profile */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+/* End XCConfigurationList section */
+
+	};
+	rootObject = 97C146E61CF9000F007C117D /* Project object */;
+}

+ 7 - 0
example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+   version = "1.0">
+   <FileRef
+      location = "group:Runner.xcodeproj">
+   </FileRef>
+</Workspace>

+ 91 - 0
example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme

@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   LastUpgradeVersion = "1020"
+   version = "1.3">
+   <BuildAction
+      parallelizeBuildables = "YES"
+      buildImplicitDependencies = "YES">
+      <BuildActionEntries>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "YES"
+            buildForArchiving = "YES"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "97C146ED1CF9000F007C117D"
+               BuildableName = "Runner.app"
+               BlueprintName = "Runner"
+               ReferencedContainer = "container:Runner.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+      </BuildActionEntries>
+   </BuildAction>
+   <TestAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      shouldUseLaunchSchemeArgsEnv = "YES">
+      <Testables>
+      </Testables>
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "97C146ED1CF9000F007C117D"
+            BuildableName = "Runner.app"
+            BlueprintName = "Runner"
+            ReferencedContainer = "container:Runner.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </TestAction>
+   <LaunchAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      launchStyle = "0"
+      useCustomWorkingDirectory = "NO"
+      ignoresPersistentStateOnLaunch = "NO"
+      debugDocumentVersioning = "YES"
+      debugServiceExtension = "internal"
+      allowLocationSimulation = "YES">
+      <BuildableProductRunnable
+         runnableDebuggingMode = "0">
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "97C146ED1CF9000F007C117D"
+            BuildableName = "Runner.app"
+            BlueprintName = "Runner"
+            ReferencedContainer = "container:Runner.xcodeproj">
+         </BuildableReference>
+      </BuildableProductRunnable>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </LaunchAction>
+   <ProfileAction
+      buildConfiguration = "Profile"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      debugDocumentVersioning = "YES">
+      <BuildableProductRunnable
+         runnableDebuggingMode = "0">
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "97C146ED1CF9000F007C117D"
+            BuildableName = "Runner.app"
+            BlueprintName = "Runner"
+            ReferencedContainer = "container:Runner.xcodeproj">
+         </BuildableReference>
+      </BuildableProductRunnable>
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Debug">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Release"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>

+ 7 - 0
example/ios/Runner.xcworkspace/contents.xcworkspacedata

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+   version = "1.0">
+   <FileRef
+      location = "group:Runner.xcodeproj">
+   </FileRef>
+</Workspace>

+ 13 - 0
example/ios/Runner/AppDelegate.swift

@@ -0,0 +1,13 @@
+import UIKit
+import Flutter
+
+@UIApplicationMain
+@objc class AppDelegate: FlutterAppDelegate {
+  override func application(
+    _ application: UIApplication,
+    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
+  ) -> Bool {
+    GeneratedPluginRegistrant.register(with: self)
+    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
+  }
+}

+ 122 - 0
example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json

@@ -0,0 +1,122 @@
+{
+  "images" : [
+    {
+      "size" : "20x20",
+      "idiom" : "iphone",
+      "filename" : "Icon-App-20x20@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "20x20",
+      "idiom" : "iphone",
+      "filename" : "Icon-App-20x20@3x.png",
+      "scale" : "3x"
+    },
+    {
+      "size" : "29x29",
+      "idiom" : "iphone",
+      "filename" : "Icon-App-29x29@1x.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "29x29",
+      "idiom" : "iphone",
+      "filename" : "Icon-App-29x29@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "29x29",
+      "idiom" : "iphone",
+      "filename" : "Icon-App-29x29@3x.png",
+      "scale" : "3x"
+    },
+    {
+      "size" : "40x40",
+      "idiom" : "iphone",
+      "filename" : "Icon-App-40x40@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "40x40",
+      "idiom" : "iphone",
+      "filename" : "Icon-App-40x40@3x.png",
+      "scale" : "3x"
+    },
+    {
+      "size" : "60x60",
+      "idiom" : "iphone",
+      "filename" : "Icon-App-60x60@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "60x60",
+      "idiom" : "iphone",
+      "filename" : "Icon-App-60x60@3x.png",
+      "scale" : "3x"
+    },
+    {
+      "size" : "20x20",
+      "idiom" : "ipad",
+      "filename" : "Icon-App-20x20@1x.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "20x20",
+      "idiom" : "ipad",
+      "filename" : "Icon-App-20x20@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "29x29",
+      "idiom" : "ipad",
+      "filename" : "Icon-App-29x29@1x.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "29x29",
+      "idiom" : "ipad",
+      "filename" : "Icon-App-29x29@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "40x40",
+      "idiom" : "ipad",
+      "filename" : "Icon-App-40x40@1x.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "40x40",
+      "idiom" : "ipad",
+      "filename" : "Icon-App-40x40@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "76x76",
+      "idiom" : "ipad",
+      "filename" : "Icon-App-76x76@1x.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "76x76",
+      "idiom" : "ipad",
+      "filename" : "Icon-App-76x76@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "83.5x83.5",
+      "idiom" : "ipad",
+      "filename" : "Icon-App-83.5x83.5@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "1024x1024",
+      "idiom" : "ios-marketing",
+      "filename" : "Icon-App-1024x1024@1x.png",
+      "scale" : "1x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}

BIN
example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png


BIN
example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png


BIN
example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png


BIN
example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png


BIN
example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png


BIN
example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png


BIN
example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png


BIN
example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png


BIN
example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png


BIN
example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png


BIN
example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png


BIN
example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png


BIN
example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png


BIN
example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png


BIN
example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png


+ 23 - 0
example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json

@@ -0,0 +1,23 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "filename" : "LaunchImage.png",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "filename" : "LaunchImage@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "filename" : "LaunchImage@3x.png",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}

BIN
example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png


Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff