├── .gitignore ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── libs │ └── TarsosDSP-Android-2.2.jar ├── manifest-merger-release-report.txt ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── lilithwittmann │ │ └── de │ │ └── voicepitchanalyzer │ │ ├── ApplicationTest.java │ │ └── TextsTest.java │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── de │ │ └── lilithwittmann │ │ └── voicepitchanalyzer │ │ ├── ApplicationContext.java │ │ ├── activities │ │ ├── AboutActivity.java │ │ ├── ProgressActivity.java │ │ ├── RecordViewActivity.java │ │ ├── RecordingActivity.java │ │ └── RecordingListActivity.java │ │ ├── adapters │ │ └── SwipeAdapter.java │ │ ├── callbacks │ │ └── ItemTouchHelperCallback.java │ │ ├── fragments │ │ ├── AboutFragment.java │ │ ├── ProgressFragment.java │ │ ├── ReadingFragment.java │ │ ├── RecordGraphFragment.java │ │ ├── RecordingFragment.java │ │ ├── RecordingListFragment.java │ │ ├── RecordingOverviewFragment.java │ │ ├── RecordingPlayFragment.java │ │ └── WelcomeFragment.java │ │ ├── listeners │ │ └── RecyclerItemClickListener.java │ │ ├── models │ │ ├── PitchRange.java │ │ ├── Recording.java │ │ ├── RecordingList.java │ │ ├── Texts.java │ │ └── database │ │ │ └── RecordingDB.java │ │ └── utils │ │ ├── CountingWriterProcessor.java │ │ ├── DateValueFormatter.java │ │ ├── ExecutorUtils.java │ │ ├── GraphLayout.java │ │ ├── GraphValueFormatter.java │ │ ├── PitchCalculator.java │ │ ├── RecordingCleaner.java │ │ ├── RecordingPaths.java │ │ └── SampleRateCalculator.java │ └── res │ ├── color │ └── button_text_color.xml │ ├── drawable-hdpi │ ├── ab_bottom_solid_example.9.png │ ├── ab_solid_example.9.png │ ├── ab_stacked_solid_example.9.png │ ├── ab_texture_tile_example.png │ ├── ab_transparent_example.9.png │ ├── app_icon.png │ ├── btn_cab_done_default_example.9.png │ ├── btn_cab_done_focused_example.9.png │ ├── btn_cab_done_pressed_example.9.png │ ├── cab_background_bottom_example.9.png │ ├── cab_background_top_example.9.png │ ├── ic_assessment_white_48dp.png │ ├── ic_delete_white_48dp.png │ ├── ic_info_outline_white_48dp.png │ ├── ic_info_white_48dp.png │ ├── ic_launcher.png │ ├── ic_play_circle_filled_black_24dp.png │ ├── ic_settings_voice_black_48dp.png │ ├── ic_settings_voice_white_48dp.png │ ├── list_focused_example.9.png │ ├── list_pressed_example.9.png │ ├── menu_dropdown_panel_example.9.png │ ├── progress_bg_example.9.png │ ├── progress_primary_example.9.png │ ├── progress_secondary_example.9.png │ ├── spinner_ab_default_example.9.png │ ├── spinner_ab_disabled_example.9.png │ ├── spinner_ab_focused_example.9.png │ ├── spinner_ab_pressed_example.9.png │ ├── tab_selected_example.9.png │ ├── tab_selected_focused_example.9.png │ ├── tab_selected_pressed_example.9.png │ ├── tab_unselected_example.9.png │ ├── tab_unselected_focused_example.9.png │ └── tab_unselected_pressed_example.9.png │ ├── drawable-mdpi │ ├── ab_bottom_solid_example.9.png │ ├── ab_solid_example.9.png │ ├── ab_stacked_solid_example.9.png │ ├── ab_texture_tile_example.png │ ├── ab_transparent_example.9.png │ ├── app_icon.png │ ├── btn_cab_done_default_example.9.png │ ├── btn_cab_done_focused_example.9.png │ ├── btn_cab_done_pressed_example.9.png │ ├── cab_background_bottom_example.9.png │ ├── cab_background_top_example.9.png │ ├── ic_assessment_white_48dp.png │ ├── ic_delete_white_48dp.png │ ├── ic_info_outline_white_48dp.png │ ├── ic_info_white_48dp.png │ ├── ic_launcher.png │ ├── ic_play_circle_filled_black_24dp.png │ ├── ic_settings_voice_black_48dp.png │ ├── ic_settings_voice_white_48dp.png │ ├── list_focused_example.9.png │ ├── list_pressed_example.9.png │ ├── menu_dropdown_panel_example.9.png │ ├── progress_bg_example.9.png │ ├── progress_primary_example.9.png │ ├── progress_secondary_example.9.png │ ├── spinner_ab_default_example.9.png │ ├── spinner_ab_disabled_example.9.png │ ├── spinner_ab_focused_example.9.png │ ├── spinner_ab_pressed_example.9.png │ ├── tab_selected_example.9.png │ ├── tab_selected_focused_example.9.png │ ├── tab_selected_pressed_example.9.png │ ├── tab_unselected_example.9.png │ ├── tab_unselected_focused_example.9.png │ └── tab_unselected_pressed_example.9.png │ ├── drawable-xhdpi │ ├── ab_bottom_solid_example.9.png │ ├── ab_solid_example.9.png │ ├── ab_stacked_solid_example.9.png │ ├── ab_texture_tile_example.png │ ├── ab_transparent_example.9.png │ ├── app_icon.png │ ├── btn_cab_done_default_example.9.png │ ├── btn_cab_done_focused_example.9.png │ ├── btn_cab_done_pressed_example.9.png │ ├── cab_background_bottom_example.9.png │ ├── cab_background_top_example.9.png │ ├── ic_assessment_white_48dp.png │ ├── ic_delete_white_48dp.png │ ├── ic_info_outline_white_48dp.png │ ├── ic_info_white_48dp.png │ ├── ic_launcher.png │ ├── ic_play_circle_filled_black_24dp.png │ ├── ic_settings_voice_black_48dp.png │ ├── ic_settings_voice_white_48dp.png │ ├── list_focused_example.9.png │ ├── list_pressed_example.9.png │ ├── menu_dropdown_panel_example.9.png │ ├── progress_bg_example.9.png │ ├── progress_primary_example.9.png │ ├── progress_secondary_example.9.png │ ├── spinner_ab_default_example.9.png │ ├── spinner_ab_disabled_example.9.png │ ├── spinner_ab_focused_example.9.png │ ├── spinner_ab_pressed_example.9.png │ ├── tab_selected_example.9.png │ ├── tab_selected_focused_example.9.png │ ├── tab_selected_pressed_example.9.png │ ├── tab_unselected_example.9.png │ ├── tab_unselected_focused_example.9.png │ └── tab_unselected_pressed_example.9.png │ ├── drawable-xxhdpi │ ├── ab_bottom_solid_example.9.png │ ├── ab_solid_example.9.png │ ├── ab_stacked_solid_example.9.png │ ├── ab_texture_tile_example.png │ ├── ab_transparent_example.9.png │ ├── app_icon.png │ ├── btn_cab_done_default_example.9.png │ ├── btn_cab_done_focused_example.9.png │ ├── btn_cab_done_pressed_example.9.png │ ├── cab_background_bottom_example.9.png │ ├── cab_background_top_example.9.png │ ├── drawable-xxhdpi │ │ └── ic_delete_white_48dp.png │ ├── ic_assessment_white_48dp.png │ ├── ic_info_outline_white_48dp.png │ ├── ic_info_white_48dp.png │ ├── ic_launcher.png │ ├── ic_play_circle_filled_black_24dp.png │ ├── ic_settings_voice_black_48dp.png │ ├── ic_settings_voice_white_48dp.png │ ├── list_focused_example.9.png │ ├── list_pressed_example.9.png │ ├── menu_dropdown_panel_example.9.png │ ├── progress_bg_example.9.png │ ├── progress_primary_example.9.png │ ├── progress_secondary_example.9.png │ ├── spinner_ab_default_example.9.png │ ├── spinner_ab_disabled_example.9.png │ ├── spinner_ab_focused_example.9.png │ ├── spinner_ab_pressed_example.9.png │ ├── tab_selected_example.9.png │ ├── tab_selected_focused_example.9.png │ ├── tab_selected_pressed_example.9.png │ ├── tab_unselected_example.9.png │ ├── tab_unselected_focused_example.9.png │ └── tab_unselected_pressed_example.9.png │ ├── drawable-xxxhdpi │ ├── app_icon.png │ ├── ic_assessment_white_48dp.png │ ├── ic_delete_white_48dp.png │ ├── ic_info_outline_white_48dp.png │ ├── ic_info_white_48dp.png │ ├── ic_play_circle_filled_black_24dp.png │ └── ic_settings_voice_white_48dp.png │ ├── drawable │ ├── ab_background_textured_example.xml │ ├── btn_cab_done_example.xml │ ├── progress_horizontal_example.xml │ ├── ripple.xml │ ├── selectable_background_example.xml │ ├── spinner_background_ab_example.xml │ ├── tab_bg.xml │ ├── tab_indicator.xml │ └── tab_text_selector.xml │ ├── layout │ ├── activity_about.xml │ ├── activity_progress.xml │ ├── activity_record_view.xml │ ├── activity_recording.xml │ ├── activity_recording_list.xml │ ├── fragment_about.xml │ ├── fragment_progress.xml │ ├── fragment_reading.xml │ ├── fragment_record_graph.xml │ ├── fragment_record_view.xml │ ├── fragment_recording.xml │ ├── fragment_recording_grid.xml │ ├── fragment_recording_list.xml │ ├── fragment_recording_overview.xml │ ├── fragment_recording_play.xml │ ├── fragment_welcome.xml │ ├── listview.xml │ ├── row_swipe_bg.xml │ └── tabs_bg.xml │ ├── menu │ ├── menu.xml │ └── menu_about.xml │ ├── raw │ ├── de.json │ ├── en.json │ ├── it.json │ └── pt.json │ ├── values-de │ └── strings.xml │ ├── values-it │ └── strings.xml │ ├── values-large │ └── refs.xml │ ├── values-pt │ └── strings.xml │ ├── values-sw600dp │ ├── refs.xml │ └── styles.xml │ ├── values-v21 │ └── styles.xml │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── refs.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── privacy_policy.md └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /local.properties 3 | /.idea/workspace.xml 4 | /.idea/libraries 5 | .DS_Store 6 | /build 7 | 8 | # Created by https://www.gitignore.io 9 | 10 | ### Android ### 11 | # Built application files 12 | *.apk 13 | *.ap_ 14 | 15 | # Files for the Dalvik VM 16 | *.dex 17 | 18 | # Java class files 19 | *.class 20 | 21 | # Generated files 22 | bin/ 23 | gen/ 24 | 25 | # Gradle files 26 | .gradle/ 27 | build/ 28 | /*/build/ 29 | 30 | # Local configuration file (sdk path, etc) 31 | local.properties 32 | 33 | # private Fabric API key 34 | fabric.properties 35 | 36 | # Proguard folder generated by Eclipse 37 | proguard/ 38 | 39 | # Log Files 40 | *.log 41 | 42 | ### Android Patch ### 43 | gen-external-apklibs 44 | 45 | 46 | ### Intellij ### 47 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm 48 | 49 | *.iml 50 | 51 | ## Directory-based project format: 52 | .idea/ 53 | # if you remove the above rule, at least ignore the following: 54 | 55 | # User-specific stuff: 56 | # .idea/workspace.xml 57 | # .idea/tasks.xml 58 | # .idea/dictionaries 59 | 60 | # Sensitive or high-churn files: 61 | # .idea/dataSources.ids 62 | # .idea/dataSources.xml 63 | # .idea/sqlDataSources.xml 64 | # .idea/dynamic.xml 65 | # .idea/uiDesigner.xml 66 | 67 | # Gradle: 68 | # .idea/gradle.xml 69 | # .idea/libraries 70 | 71 | # Mongo Explorer plugin: 72 | # .idea/mongoSettings.xml 73 | 74 | ## File-based project format: 75 | *.ipr 76 | *.iws 77 | 78 | ## Plugin-specific files: 79 | 80 | # IntelliJ 81 | /out/ 82 | 83 | # mpeltonen/sbt-idea plugin 84 | .idea_modules/ 85 | 86 | # JIRA plugin 87 | atlassian-ide-plugin.xml 88 | 89 | # Crashlytics plugin (for Android Studio and IntelliJ) 90 | com_crashlytics_export_strings.xml 91 | crashlytics.properties 92 | crashlytics-build.properties 93 | 94 | 95 | ### Gradle ### 96 | .gradle 97 | build/ 98 | 99 | # Ignore Gradle GUI config 100 | gradle-app.setting 101 | 102 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 103 | !gradle-wrapper.jar 104 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## [Download on Playstore](https://play.google.com/store/apps/details?id=de.lilithwittmann.voicepitchanalyzer) 2 | Made by Yuri Ichijō and Lilith Wittmann. <3 3 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 30 5 | 6 | defaultConfig { 7 | applicationId "de.lilithwittmann.voicepitchanalyzer" 8 | minSdkVersion 26 9 | targetSdkVersion 30 10 | versionCode 9 11 | versionName "1.3.0" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | } 20 | 21 | repositories { 22 | mavenCentral() 23 | maven { url "https://jitpack.io" } 24 | } 25 | 26 | 27 | dependencies { 28 | implementation fileTree(dir: 'libs', include: ['*.jar']) 29 | implementation files('libs/TarsosDSP-Android-2.2.jar') 30 | // implementation 'com.baoyz.swipemenulistview:library:1.3.0' 31 | // implementation 'com.wdullaer:swipeactionadapter:1.4.4' 32 | implementation 'com.google.android.exoplayer:exoplayer-core:2.13.3' 33 | implementation 'androidx.recyclerview:recyclerview:1.2.0' 34 | implementation 'androidx.appcompat:appcompat:1.2.0' 35 | implementation 'com.google.android.material:material:1.3.0' 36 | implementation 'androidx.legacy:legacy-support-v4:1.0.0' 37 | implementation 'com.google.code.gson:gson:2.8.6' 38 | implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0' 39 | implementation 'joda-time:joda-time:2.10.10' 40 | } 41 | -------------------------------------------------------------------------------- /app/libs/TarsosDSP-Android-2.2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/libs/TarsosDSP-Android-2.2.jar -------------------------------------------------------------------------------- /app/manifest-merger-release-report.txt: -------------------------------------------------------------------------------- 1 | -- Merging decision tree log --- 2 | manifest 3 | ADDED from AndroidManifest.xml:2:1 4 | package 5 | ADDED from AndroidManifest.xml:3:5 6 | INJECTED from AndroidManifest.xml:0:0 7 | INJECTED from AndroidManifest.xml:0:0 8 | android:versionName 9 | INJECTED from AndroidManifest.xml:0:0 10 | INJECTED from AndroidManifest.xml:0:0 11 | xmlns:android 12 | ADDED from AndroidManifest.xml:2:11 13 | android:versionCode 14 | INJECTED from AndroidManifest.xml:0:0 15 | INJECTED from AndroidManifest.xml:0:0 16 | uses-permission#android.permission.RECORD_AUDIO 17 | ADDED from AndroidManifest.xml:5:5 18 | android:name 19 | ADDED from AndroidManifest.xml:5:22 20 | application 21 | ADDED from AndroidManifest.xml:7:5 22 | MERGED from com.android.support:appcompat-v7:22.0.0:22:5 23 | MERGED from com.android.support:support-v4:22.0.0:22:5 24 | android:label 25 | ADDED from AndroidManifest.xml:10:9 26 | android:allowBackup 27 | ADDED from AndroidManifest.xml:8:9 28 | android:icon 29 | ADDED from AndroidManifest.xml:9:9 30 | android:theme 31 | ADDED from AndroidManifest.xml:11:9 32 | activity#lilithwittmann.de.voicepitchanalyzer.RecordingListActivity 33 | ADDED from AndroidManifest.xml:12:9 34 | android:label 35 | ADDED from AndroidManifest.xml:14:13 36 | android:name 37 | ADDED from AndroidManifest.xml:13:13 38 | intent-filter#android.intent.action.MAIN+android.intent.category.LAUNCHER 39 | ADDED from AndroidManifest.xml:15:9 40 | action#android.intent.action.MAIN 41 | ADDED from AndroidManifest.xml:16:17 42 | android:name 43 | ADDED from AndroidManifest.xml:16:25 44 | category#android.intent.category.LAUNCHER 45 | ADDED from AndroidManifest.xml:18:17 46 | android:name 47 | ADDED from AndroidManifest.xml:18:27 48 | activity#lilithwittmann.de.voicepitchanalyzer.RecordingActivity 49 | ADDED from AndroidManifest.xml:21:9 50 | android:label 51 | ADDED from AndroidManifest.xml:23:13 52 | android:theme 53 | ADDED from AndroidManifest.xml:24:13 54 | android:name 55 | ADDED from AndroidManifest.xml:22:13 56 | activity#lilithwittmann.de.voicepitchanalyzer.RecordViewActivity 57 | ADDED from AndroidManifest.xml:25:9 58 | android:parentActivityName 59 | ADDED from AndroidManifest.xml:27:13 60 | android:name 61 | ADDED from AndroidManifest.xml:26:13 62 | meta-data#android.support.PARENT_ACTIVITY 63 | ADDED from AndroidManifest.xml:28:13 64 | android:value 65 | ADDED from AndroidManifest.xml:30:17 66 | android:name 67 | ADDED from AndroidManifest.xml:29:17 68 | uses-sdk 69 | INJECTED from AndroidManifest.xml:0:0 reason: use-sdk injection requested 70 | MERGED from com.android.support:appcompat-v7:22.0.0:20:5 71 | MERGED from com.android.support:support-v4:22.0.0:20:5 72 | android:targetSdkVersion 73 | INJECTED from AndroidManifest.xml:0:0 74 | INJECTED from AndroidManifest.xml:0:0 75 | android:minSdkVersion 76 | INJECTED from AndroidManifest.xml:0:0 77 | INJECTED from AndroidManifest.xml:0:0 78 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/felix/android-sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/lilithwittmann/de/voicepitchanalyzer/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package de.lilithwittmann.de.voicepitchanalyzer; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/androidTest/java/lilithwittmann/de/voicepitchanalyzer/TextsTest.java: -------------------------------------------------------------------------------- 1 | package de.lilithwittmann.voicepitchanalyzer; 2 | 3 | import android.test.ActivityUnitTestCase; 4 | import android.test.suitebuilder.annotation.SmallTest; 5 | 6 | import de.lilithwittmann.voicepitchanalyzer.activities.RecordingListActivity; 7 | import de.lilithwittmann.voicepitchanalyzer.models.Texts; 8 | 9 | /** 10 | * Created by lilith on 7/5/15. 11 | */ 12 | public class TextsTest extends ActivityUnitTestCase { 13 | 14 | public TextsTest() { 15 | super(RecordingListActivity.class); 16 | } 17 | 18 | Texts texts; 19 | protected void setUp() throws Exception { 20 | super.setUp(); 21 | this.texts = new Texts(); 22 | } 23 | @SmallTest 24 | public void testGetText(){ 25 | this.texts.getText("de", 3); 26 | assertEquals(1,1); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 15 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 29 | 32 | 35 | 36 | 40 | 43 | 44 | 45 | 48 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /app/src/main/java/de/lilithwittmann/voicepitchanalyzer/ApplicationContext.java: -------------------------------------------------------------------------------- 1 | package de.lilithwittmann.voicepitchanalyzer; 2 | 3 | import android.app.Application; 4 | import android.util.Log; 5 | 6 | import java.util.concurrent.ExecutorService; 7 | 8 | import de.lilithwittmann.voicepitchanalyzer.utils.ExecutorUtils; 9 | import de.lilithwittmann.voicepitchanalyzer.utils.RecordingCleaner; 10 | 11 | public class ApplicationContext extends Application { 12 | private static final String LOG_TAG = ApplicationContext.class.getSimpleName(); 13 | 14 | @Override 15 | public void onCreate() { 16 | super.onCreate(); 17 | 18 | Log.i(LOG_TAG, "onCreate()"); 19 | 20 | ExecutorService executor = ExecutorUtils.getBoundedExecutor(); 21 | executor.execute(new RecordingCleaner(this.getApplicationContext())); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/de/lilithwittmann/voicepitchanalyzer/activities/AboutActivity.java: -------------------------------------------------------------------------------- 1 | package de.lilithwittmann.voicepitchanalyzer.activities; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import androidx.appcompat.app.AppCompatActivity; 6 | import android.util.Log; 7 | import android.view.Menu; 8 | import android.view.MenuItem; 9 | 10 | import de.lilithwittmann.voicepitchanalyzer.R; 11 | 12 | public class AboutActivity extends AppCompatActivity 13 | { 14 | private static final String LOG_TAG = AboutActivity.class.getSimpleName(); 15 | 16 | @Override 17 | protected void onCreate(Bundle savedInstanceState) 18 | { 19 | super.onCreate(savedInstanceState); 20 | setContentView(R.layout.activity_about); 21 | getSupportActionBar().setDisplayHomeAsUpEnabled(true); 22 | } 23 | 24 | @Override 25 | public boolean onCreateOptionsMenu(Menu menu) 26 | { 27 | // Inflate the menu; this adds items to the action bar if it is present. 28 | getMenuInflater().inflate(R.menu.menu_about, menu); 29 | return true; 30 | } 31 | 32 | @Override 33 | public boolean onOptionsItemSelected(MenuItem item) 34 | { 35 | switch (item.getItemId()) 36 | { 37 | case android.R.id.home: 38 | { 39 | Log.i(LOG_TAG, "back pressed"); 40 | this.onBackPressed(); 41 | } 42 | 43 | case R.id.action_record: 44 | { 45 | startActivity(new Intent(this, RecordingActivity.class)); 46 | } 47 | } 48 | 49 | return super.onOptionsItemSelected(item); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/java/de/lilithwittmann/voicepitchanalyzer/activities/ProgressActivity.java: -------------------------------------------------------------------------------- 1 | package de.lilithwittmann.voicepitchanalyzer.activities; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import androidx.appcompat.app.AppCompatActivity; 6 | import android.view.Menu; 7 | import android.view.MenuItem; 8 | 9 | import de.lilithwittmann.voicepitchanalyzer.R; 10 | 11 | public class ProgressActivity extends AppCompatActivity 12 | { 13 | @Override 14 | protected void onCreate(Bundle savedInstanceState) 15 | { 16 | super.onCreate(savedInstanceState); 17 | setContentView(R.layout.activity_progress); 18 | } 19 | 20 | @Override 21 | public boolean onCreateOptionsMenu(Menu menu) 22 | { 23 | // Inflate the menu; this adds items to the action bar if it is present. 24 | getMenuInflater().inflate(R.menu.menu_about, menu); 25 | return true; 26 | } 27 | 28 | @Override 29 | public boolean onOptionsItemSelected(MenuItem item) 30 | { 31 | switch (item.getItemId()) 32 | { 33 | case android.R.id.home: 34 | { 35 | this.onBackPressed(); 36 | } 37 | 38 | case R.id.action_record: 39 | { 40 | startActivity(new Intent(this, RecordingActivity.class)); 41 | } 42 | } 43 | 44 | return super.onOptionsItemSelected(item); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/java/de/lilithwittmann/voicepitchanalyzer/activities/RecordingActivity.java: -------------------------------------------------------------------------------- 1 | package de.lilithwittmann.voicepitchanalyzer.activities; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.content.SharedPreferences; 6 | import android.os.Bundle; 7 | import android.os.PersistableBundle; 8 | import androidx.fragment.app.FragmentTabHost; 9 | import androidx.appcompat.app.AppCompatActivity; 10 | import android.view.LayoutInflater; 11 | import android.view.View; 12 | import android.widget.TabHost; 13 | import android.widget.TextView; 14 | 15 | import com.github.mikephil.charting.data.Entry; 16 | 17 | import java.util.LinkedList; 18 | import java.util.List; 19 | 20 | import de.lilithwittmann.voicepitchanalyzer.R; 21 | import de.lilithwittmann.voicepitchanalyzer.fragments.ReadingFragment; 22 | import de.lilithwittmann.voicepitchanalyzer.fragments.RecordGraphFragment; 23 | import de.lilithwittmann.voicepitchanalyzer.fragments.RecordingFragment; 24 | import de.lilithwittmann.voicepitchanalyzer.models.Recording; 25 | import de.lilithwittmann.voicepitchanalyzer.utils.PitchCalculator; 26 | 27 | /*** 28 | * activity containing RecordingFragment with which a new record can be made 29 | */ 30 | 31 | public class RecordingActivity extends AppCompatActivity implements RecordingFragment.OnFragmentInteractionListener, RecordGraphFragment.OnFragmentInteractionListener 32 | { 33 | private static final String LOG_TAG = RecordingActivity.class.getSimpleName(); 34 | private FragmentTabHost tabHost; 35 | private PitchCalculator calculator = new PitchCalculator(); 36 | 37 | @Override 38 | protected void onCreate(Bundle savedInstanceState) 39 | { 40 | super.onCreate(savedInstanceState); 41 | setContentView(R.layout.activity_recording); 42 | 43 | tabHost = (FragmentTabHost)findViewById(R.id.tabhost); 44 | tabHost.setup(this, getSupportFragmentManager(), R.id.realtabcontent); 45 | 46 | this.addTab(ReadingFragment.class, getString(R.string.title_text)); 47 | this.addTab(RecordGraphFragment.class, getString(R.string.realtime_graph)); 48 | 49 | SharedPreferences sharedPref = 50 | getSharedPreferences(getString(R.string.preference_file_key), Context.MODE_PRIVATE); 51 | 52 | Integer tabIndex = sharedPref.getInt(getString(R.string.recording_tab_index), 0); 53 | tabHost.setCurrentTab(tabIndex); 54 | } 55 | 56 | private void addTab(final Class view, String tag) { 57 | View tabview = this.createStyledTabView(tabHost.getContext(), tag); 58 | TabHost.TabSpec setContent = tabHost.newTabSpec(tag).setIndicator(tabview); 59 | 60 | tabHost.addTab(setContent, view, null); 61 | } 62 | 63 | private static View createStyledTabView(final Context context, String text) { 64 | View view = LayoutInflater.from(context).inflate(R.layout.tabs_bg, null); 65 | 66 | TextView tv = (TextView) view.findViewById(R.id.tabsText); 67 | tv.setText(text.toUpperCase()); 68 | 69 | return view; 70 | } 71 | 72 | @Override 73 | public void onCancel() 74 | { 75 | Intent intent = new Intent(this, RecordingListActivity.class); 76 | startActivity(intent); 77 | } 78 | 79 | public void onPitchDetected(float pitchInHz) { 80 | boolean pitchAccepted = calculator.addPitch((double) pitchInHz); 81 | 82 | RecordGraphFragment graph = (RecordGraphFragment) getSupportFragmentManager() 83 | .findFragmentByTag(getString(R.string.realtime_graph)); 84 | 85 | if (graph != null && pitchAccepted) 86 | graph.addNewPitch(new Entry(calculator.getPitches().size() - 1, pitchInHz)); 87 | } 88 | 89 | @Override 90 | public void onRecordFinished(long recordingID) 91 | { 92 | savePreferences(); 93 | ReadingFragment.incrementTextPage(this); 94 | 95 | Intent intent = new Intent(this, RecordViewActivity.class); 96 | intent.putExtra(Recording.KEY, recordingID); 97 | startActivity(intent); 98 | } 99 | 100 | public List startingPitchEntries() { 101 | return getPitchEntries(); 102 | } 103 | 104 | private List getPitchEntries() { 105 | List pitchEntries = new LinkedList<>(); 106 | 107 | List pitches = calculator.getPitches(); 108 | for (int i = 0; i < pitches.size(); i++) { 109 | Double pitchOn = pitches.get(i); 110 | pitchEntries.add(new Entry(i, pitchOn.floatValue())); 111 | } 112 | 113 | return pitchEntries; 114 | } 115 | 116 | private void savePreferences() { 117 | SharedPreferences sharedPref = 118 | getSharedPreferences(getString(R.string.preference_file_key), Context.MODE_PRIVATE); 119 | 120 | sharedPref.edit().putInt(getString(R.string.recording_tab_index), tabHost.getCurrentTab()).apply(); 121 | } 122 | 123 | @Override 124 | protected void onPause() { 125 | super.onPause(); 126 | savePreferences(); 127 | } 128 | 129 | @Override 130 | public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) { 131 | super.onSaveInstanceState(outState, outPersistentState); 132 | savePreferences(); 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /app/src/main/java/de/lilithwittmann/voicepitchanalyzer/activities/RecordingListActivity.java: -------------------------------------------------------------------------------- 1 | package de.lilithwittmann.voicepitchanalyzer.activities; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.content.SharedPreferences; 6 | import android.os.Bundle; 7 | import androidx.appcompat.app.AppCompatActivity; 8 | import android.view.Menu; 9 | import android.view.MenuItem; 10 | import android.view.View; 11 | 12 | import de.lilithwittmann.voicepitchanalyzer.R; 13 | import de.lilithwittmann.voicepitchanalyzer.fragments.RecordingListFragment; 14 | import de.lilithwittmann.voicepitchanalyzer.fragments.WelcomeFragment; 15 | import de.lilithwittmann.voicepitchanalyzer.models.Recording; 16 | 17 | 18 | public class RecordingListActivity extends AppCompatActivity implements RecordingListFragment.OnFragmentInteractionListener { 19 | private static final String LOG_TAG = RecordingActivity.class.getSimpleName(); 20 | 21 | @Override 22 | protected void onCreate(Bundle savedInstanceState) { 23 | super.onCreate(savedInstanceState); 24 | setContentView(R.layout.activity_recording_list); 25 | 26 | if (savedInstanceState == null) { 27 | 28 | SharedPreferences sharedPref = getSharedPreferences( 29 | getString(R.string.preference_file_key), Context.MODE_PRIVATE); 30 | if (sharedPref.getBoolean(getString(R.string.first_start), true)) 31 | { 32 | // open welcome screen 33 | getSupportFragmentManager().beginTransaction() 34 | .add(R.id.container, new WelcomeFragment()) 35 | .commit(); 36 | 37 | getSupportActionBar().hide(); 38 | 39 | // hide welcome fragment next time the app/this activity is opened 40 | // SharedPreferences.Editor editor = sharedPref.edit(); 41 | sharedPref.edit().putBoolean(getString(R.string.first_start), false).apply(); 42 | } 43 | 44 | else 45 | { 46 | // open list fragment 47 | getSupportFragmentManager().beginTransaction() 48 | .add(R.id.container, new RecordingListFragment()) 49 | .commit(); 50 | } 51 | } 52 | } 53 | 54 | public void onNextClick(View view) 55 | { 56 | // getSupportFragmentManager().beginTransaction() 57 | // .add(R.id.container, new RecordingFragment()) 58 | // .commit(); 59 | startActivity(new Intent(this, RecordingActivity.class)); 60 | } 61 | 62 | @Override 63 | public boolean onCreateOptionsMenu(Menu menu) { 64 | // Inflate the menu; this adds items to the action bar if it is present. 65 | getMenuInflater().inflate(R.menu.menu, menu); 66 | return super.onCreateOptionsMenu(menu); 67 | } 68 | 69 | @Override 70 | public boolean onOptionsItemSelected(MenuItem item) { 71 | // Handle action bar item clicks here. The action bar will 72 | // automatically handle clicks on the Home/Up button, so long 73 | // as you specify a parent activity in AndroidManifest.xml. 74 | switch (item.getItemId()) { 75 | case R.id.action_record: { 76 | startActivity(new Intent(this, RecordingActivity.class)); 77 | return true; 78 | } 79 | 80 | case R.id.action_progress: 81 | { 82 | startActivity(new Intent(this, ProgressActivity.class)); 83 | // this.getSupportFragmentManager().beginTransaction() 84 | // .add(R.id.container, new ProgressFragment()) 85 | // .commit(); 86 | return true; 87 | } 88 | 89 | case R.id.action_about: { 90 | startActivity(new Intent(this, AboutActivity.class)); 91 | return true; 92 | } 93 | } 94 | 95 | return super.onOptionsItemSelected(item); 96 | } 97 | 98 | @Override 99 | public void onFragmentInteraction(long recordID) { 100 | Intent intent = new Intent(this, RecordViewActivity.class); 101 | intent.putExtra(Recording.KEY, recordID); 102 | startActivity(intent); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /app/src/main/java/de/lilithwittmann/voicepitchanalyzer/callbacks/ItemTouchHelperCallback.java: -------------------------------------------------------------------------------- 1 | package de.lilithwittmann.voicepitchanalyzer.callbacks; 2 | 3 | import androidx.recyclerview.widget.RecyclerView; 4 | import androidx.recyclerview.widget.ItemTouchHelper; 5 | 6 | import de.lilithwittmann.voicepitchanalyzer.adapters.SwipeAdapter; 7 | 8 | /** 9 | * An implementation of {@link ItemTouchHelper.Callback} that enables basic drag & drop and 10 | * swipe-to-dismiss. Drag events are automatically started by an item long-press.
11 | *
12 | * Expects the RecyclerView.Adapter to react to {@link 13 | * SwipeAdapter} callbacks and the RecyclerView.SwipeViewHolder to implement 14 | * {@link SwipeAdapter.SwipeViewHolder}. 15 | * 16 | * @author Paul Burke (ipaulpro) 17 | */ 18 | public class ItemTouchHelperCallback extends ItemTouchHelper.Callback 19 | { 20 | 21 | private final SwipeAdapter mAdapter; 22 | 23 | public ItemTouchHelperCallback(SwipeAdapter adapter) 24 | { 25 | mAdapter = adapter; 26 | } 27 | 28 | @Override 29 | public boolean isLongPressDragEnabled() 30 | { 31 | return true; 32 | } 33 | 34 | @Override 35 | public boolean isItemViewSwipeEnabled() 36 | { 37 | return true; 38 | } 39 | 40 | @Override 41 | public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) 42 | { 43 | final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN; 44 | final int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END; 45 | return makeMovementFlags(dragFlags, swipeFlags); 46 | } 47 | 48 | @Override 49 | public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) 50 | { 51 | // mAdapter.onItemMove(source.getAdapterPosition(), target.getAdapterPosition()); 52 | return true; 53 | } 54 | 55 | @Override 56 | public void onSwiped(RecyclerView.ViewHolder viewHolder, int i) 57 | { 58 | mAdapter.onItemDismiss(viewHolder.getAdapterPosition()); 59 | } 60 | 61 | @Override 62 | public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) 63 | { 64 | if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) 65 | { 66 | SwipeAdapter.SwipeViewHolder itemViewHolder = (SwipeAdapter.SwipeViewHolder) viewHolder; 67 | itemViewHolder.onItemSelected(); 68 | } 69 | 70 | super.onSelectedChanged(viewHolder, actionState); 71 | } 72 | 73 | @Override 74 | public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) 75 | { 76 | super.clearView(recyclerView, viewHolder); 77 | 78 | SwipeAdapter.SwipeViewHolder itemViewHolder = (SwipeAdapter.SwipeViewHolder) viewHolder; 79 | itemViewHolder.onItemClear(); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /app/src/main/java/de/lilithwittmann/voicepitchanalyzer/fragments/AboutFragment.java: -------------------------------------------------------------------------------- 1 | package de.lilithwittmann.voicepitchanalyzer.fragments; 2 | 3 | 4 | import android.os.Bundle; 5 | import androidx.fragment.app.Fragment; 6 | import android.view.LayoutInflater; 7 | import android.view.Menu; 8 | import android.view.MenuInflater; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.widget.TextView; 12 | 13 | import de.lilithwittmann.voicepitchanalyzer.R; 14 | 15 | 16 | /** 17 | * A simple {@link Fragment} subclass. 18 | */ 19 | public class AboutFragment extends Fragment 20 | { 21 | private static final String LOG_TAG = AboutFragment.class.getSimpleName(); 22 | 23 | public AboutFragment() 24 | { 25 | // Required empty public constructor 26 | } 27 | 28 | @Override 29 | public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) 30 | { 31 | super.onCreateOptionsMenu(menu, inflater); 32 | } 33 | 34 | @Override 35 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 36 | Bundle savedInstanceState) 37 | { 38 | // Inflate the layout for this fragment 39 | return inflater.inflate(R.layout.fragment_about, container, false); 40 | } 41 | 42 | @Override 43 | public void onViewCreated(View view, Bundle savedInstanceState) 44 | { 45 | super.onViewCreated(view, savedInstanceState); 46 | 47 | // enable text links for licences etc. 48 | TextView apacheLicence = (TextView) view.findViewById(R.id.apache); 49 | TextView apacheLicence2 = (TextView) view.findViewById(R.id.apache2); 50 | TextView gpl = (TextView) view.findViewById(R.id.gpl); 51 | TextView programming = (TextView) view.findViewById(R.id.programming); 52 | TextView design = (TextView) view.findViewById(R.id.design); 53 | TextView contributors = (TextView) view.findViewById(R.id.contributors); 54 | TextView github = (TextView) view.findViewById(R.id.github); 55 | 56 | apacheLicence.setMovementMethod(android.text.method.LinkMovementMethod.getInstance()); 57 | apacheLicence2.setMovementMethod(android.text.method.LinkMovementMethod.getInstance()); 58 | gpl.setMovementMethod(android.text.method.LinkMovementMethod.getInstance()); 59 | programming.setMovementMethod(android.text.method.LinkMovementMethod.getInstance()); 60 | design.setMovementMethod(android.text.method.LinkMovementMethod.getInstance()); 61 | contributors.setMovementMethod(android.text.method.LinkMovementMethod.getInstance()); 62 | github.setMovementMethod(android.text.method.LinkMovementMethod.getInstance()); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /app/src/main/java/de/lilithwittmann/voicepitchanalyzer/fragments/ProgressFragment.java: -------------------------------------------------------------------------------- 1 | package de.lilithwittmann.voicepitchanalyzer.fragments; 2 | 3 | 4 | import android.os.Bundle; 5 | import androidx.fragment.app.Fragment; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | 10 | import com.github.mikephil.charting.charts.CombinedChart; 11 | import com.github.mikephil.charting.charts.CombinedChart.DrawOrder; 12 | import com.github.mikephil.charting.components.YAxis; 13 | import com.github.mikephil.charting.data.BarData; 14 | import com.github.mikephil.charting.data.CombinedData; 15 | import com.github.mikephil.charting.data.Entry; 16 | import com.github.mikephil.charting.data.LineData; 17 | import com.github.mikephil.charting.data.LineDataSet; 18 | 19 | import java.util.List; 20 | 21 | import de.lilithwittmann.voicepitchanalyzer.R; 22 | import de.lilithwittmann.voicepitchanalyzer.models.RecordingList; 23 | import de.lilithwittmann.voicepitchanalyzer.utils.DateValueFormatter; 24 | import de.lilithwittmann.voicepitchanalyzer.utils.GraphLayout; 25 | 26 | /** 27 | * Fragment containing a graph showing pitch data from all recordings 28 | */ 29 | public class ProgressFragment extends Fragment 30 | { 31 | private RecordingList recordings; 32 | 33 | public ProgressFragment() 34 | { 35 | // Required empty public constructor 36 | } 37 | 38 | @Override 39 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 40 | Bundle savedInstanceState) 41 | { 42 | // Inflate the layout for this fragment 43 | return inflater.inflate(R.layout.fragment_progress, container, false); 44 | } 45 | 46 | @Override 47 | public void onViewCreated(View view, Bundle savedInstanceState) 48 | { 49 | CombinedChart chart = (CombinedChart) view.findViewById(R.id.progress_chart); 50 | this.recordings = new RecordingList(this.getContext()); 51 | 52 | if (this.recordings != null) 53 | { 54 | CombinedData data = new CombinedData(); 55 | 56 | List entries = this.recordings.getGraphEntries(); 57 | float lastEntryX = 0.0f; 58 | if (entries.size() != 0) 59 | { 60 | lastEntryX = entries.get(entries.size() - 1).getX(); 61 | } 62 | 63 | LineDataSet dataSet = new LineDataSet(entries, getResources().getString(R.string.progress)); 64 | LineData lineData = new LineData(dataSet); 65 | BarData barData = new BarData(GraphLayout.getOverallRange(this.getContext(), ((int) lastEntryX) + 1)); 66 | 67 | chart.getXAxis().setValueFormatter(new DateValueFormatter(this.recordings.getBeginningAsDate())); 68 | chart.getXAxis().setGranularity(1f); 69 | chart.getXAxis().setAxisMinimum(-0.5f); 70 | chart.getXAxis().setAxisMaximum(lastEntryX + 0.5f); 71 | 72 | dataSet.setMode(LineDataSet.Mode.CUBIC_BEZIER); 73 | dataSet.enableDashedLine(10, 10, 0); 74 | dataSet.setLineWidth(3f); 75 | dataSet.setDrawValues(false); 76 | 77 | dataSet.setCircleColor(getResources().getColor(R.color.canvas_dark)); 78 | dataSet.setColor(getResources().getColor(R.color.canvas_dark)); 79 | dataSet.setCircleRadius(5f); 80 | 81 | dataSet.setCubicIntensity(0.05f); 82 | dataSet.setAxisDependency(YAxis.AxisDependency.LEFT); 83 | 84 | data.setData(lineData); 85 | data.setData(barData); 86 | chart.setData(data); 87 | GraphLayout.FormatChart(chart); 88 | 89 | chart.setTouchEnabled(true); 90 | // chart.setScaleEnabled(true); 91 | chart.setPinchZoom(true); 92 | // chart.setDoubleTapToZoomEnabled(true); 93 | 94 | chart.setDrawValueAboveBar(false); 95 | chart.setDrawOrder(new DrawOrder[]{ 96 | DrawOrder.BAR, 97 | DrawOrder.BUBBLE, 98 | DrawOrder.CANDLE, 99 | DrawOrder.LINE, 100 | DrawOrder.SCATTER 101 | }); 102 | } 103 | 104 | super.onViewCreated(view, savedInstanceState); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /app/src/main/java/de/lilithwittmann/voicepitchanalyzer/fragments/ReadingFragment.java: -------------------------------------------------------------------------------- 1 | package de.lilithwittmann.voicepitchanalyzer.fragments; 2 | 3 | import android.content.Context; 4 | import android.content.SharedPreferences; 5 | import android.os.Bundle; 6 | import androidx.fragment.app.Fragment; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.TextView; 11 | import de.lilithwittmann.voicepitchanalyzer.R; 12 | import de.lilithwittmann.voicepitchanalyzer.models.Texts; 13 | 14 | import java.util.Locale; 15 | 16 | /** 17 | * Reading material for display while doing a recording. 18 | */ 19 | public class ReadingFragment extends Fragment { 20 | public ReadingFragment() 21 | { 22 | // Required empty public constructor 23 | } 24 | 25 | @Override 26 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 27 | return inflater.inflate(R.layout.fragment_reading, container, false); 28 | } 29 | 30 | @Override 31 | public void onViewCreated(final View view, Bundle savedInstanceState) { 32 | super.onViewCreated(view, savedInstanceState); 33 | 34 | Texts texts = new Texts(); 35 | Context context = getActivity(); 36 | String lang = getLanguage(texts); 37 | 38 | int textNumber = getCurrentTextPage(context); 39 | 40 | //render text 41 | final TextView recording_text = (TextView) view.findViewById(R.id.recording_text); 42 | recording_text.setText(texts.getText(lang, textNumber)); 43 | } 44 | 45 | private static int getCurrentTextPage(Context context) { 46 | Texts texts = new Texts(); 47 | SharedPreferences sharedPref = getPreferences(context); 48 | 49 | int textNumber = sharedPref.getInt(context.getString(R.string.saved_text_number), 1); 50 | 51 | if (textNumber > texts.countTexts(getLanguage(texts))) { 52 | textNumber = 1; 53 | } 54 | 55 | return textNumber; 56 | } 57 | 58 | public static void incrementTextPage(Context context) { 59 | int textNumber = getCurrentTextPage(context); 60 | Texts texts = new Texts(); 61 | String lang = getLanguage(texts); 62 | SharedPreferences sharedPref = getPreferences(context); 63 | 64 | // calculate next textNumber 65 | Integer nextText = 1; 66 | if (textNumber + 1 < texts.countTexts(lang)) { 67 | nextText = textNumber + 1; 68 | } else if (textNumber > texts.countTexts(lang)) { 69 | //really special case - if the user changes the device language and in the new language there are 70 | // less text samples available than in the previous one, set the text number back to one 71 | nextText = 2; 72 | } 73 | 74 | //save next textNumber 75 | sharedPref.edit().putInt(context.getString(R.string.saved_text_number), nextText).apply(); 76 | } 77 | 78 | private static SharedPreferences getPreferences(Context context) { 79 | return context.getSharedPreferences( 80 | context.getString(R.string.preference_file_key), Context.MODE_PRIVATE); 81 | } 82 | 83 | private static String getLanguage(Texts texts) { 84 | String lang = "en"; 85 | if (texts.supportsLocale(Locale.getDefault().getLanguage()) == Boolean.TRUE) { 86 | lang = Locale.getDefault().getLanguage(); 87 | } 88 | 89 | return lang; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /app/src/main/java/de/lilithwittmann/voicepitchanalyzer/fragments/RecordGraphFragment.java: -------------------------------------------------------------------------------- 1 | package de.lilithwittmann.voicepitchanalyzer.fragments; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import androidx.annotation.Nullable; 6 | import androidx.fragment.app.Fragment; 7 | import android.util.Log; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | 12 | import com.github.mikephil.charting.charts.CombinedChart; 13 | import com.github.mikephil.charting.components.YAxis; 14 | import com.github.mikephil.charting.data.BarData; 15 | import com.github.mikephil.charting.data.ChartData; 16 | import com.github.mikephil.charting.data.CombinedData; 17 | import com.github.mikephil.charting.data.Entry; 18 | import com.github.mikephil.charting.data.LineData; 19 | import com.github.mikephil.charting.data.LineDataSet; 20 | import com.github.mikephil.charting.highlight.Highlight; 21 | import com.github.mikephil.charting.listener.OnChartValueSelectedListener; 22 | 23 | import java.util.List; 24 | 25 | import de.lilithwittmann.voicepitchanalyzer.R; 26 | import de.lilithwittmann.voicepitchanalyzer.utils.GraphLayout; 27 | 28 | /** 29 | * A simple {@link Fragment} subclass. 30 | * Activities that contain this fragment must implement the 31 | * {@link RecordGraphFragment.OnFragmentInteractionListener} interface 32 | * to handle interaction events. 33 | */ 34 | public class RecordGraphFragment extends Fragment implements OnChartValueSelectedListener 35 | { 36 | 37 | private static final String LOG_TAG = RecordGraphFragment.class.getSimpleName(); 38 | /** 39 | * The fragment argument representing the section number for this 40 | * fragment. 41 | */ 42 | private static final String ARG_SECTION_NUMBER = "section_number"; 43 | private OnFragmentInteractionListener mListener; 44 | private LineDataSet pitchDataSet; 45 | private LineData pitchData; 46 | private BarData genderBarData; 47 | private CombinedData chartData; 48 | 49 | public RecordGraphFragment() 50 | { 51 | // Required empty public constructor 52 | } 53 | 54 | /** 55 | * Returns a new instance of this fragment for the given section 56 | * number. 57 | */ 58 | public static RecordGraphFragment newInstance(int sectionNumber) 59 | { 60 | Bundle bundle = new Bundle(); 61 | // bundle.putParcelable(Recording.KEY, recording); 62 | bundle.putInt(ARG_SECTION_NUMBER, sectionNumber); 63 | 64 | RecordGraphFragment recordFragment = new RecordGraphFragment(); 65 | recordFragment.setArguments(bundle); 66 | // getSupportFragmentManager().beginTransaction().replace(R.id.container, recordFragment).commit(); 67 | 68 | return recordFragment; 69 | } 70 | 71 | @Override 72 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 73 | Bundle savedInstanceState) 74 | { 75 | // Inflate the layout for this fragment 76 | return inflater.inflate(R.layout.fragment_record_graph, container, false); 77 | } 78 | 79 | @Override 80 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) 81 | { 82 | CombinedChart chart = (CombinedChart) view.findViewById(R.id.recording_chart); 83 | 84 | pitchDataSet = new LineDataSet(mListener.startingPitchEntries(), getResources().getString(R.string.progress)); 85 | chartData = new CombinedData(); 86 | 87 | pitchDataSet.setColor(getResources().getColor(R.color.canvas_dark)); 88 | pitchDataSet.setDrawCircles(false); 89 | pitchDataSet.setLineWidth(2f); 90 | pitchDataSet.setDrawValues(false); 91 | pitchDataSet.setDrawIcons(false); 92 | pitchDataSet.setAxisDependency(YAxis.AxisDependency.LEFT); 93 | 94 | pitchData = new LineData(pitchDataSet); 95 | chartData.setData(pitchData); 96 | 97 | genderBarData = new BarData(GraphLayout.getOverallRange(this.getContext(), pitchDataSet.getEntryCount())); 98 | 99 | // Bug with chart lib that throws exception for empty bar charts so must skip adding it on init 100 | // if were coming from the live pitch graph. 101 | chartData.setData(genderBarData); 102 | 103 | chart.setData(chartData); 104 | 105 | chart.getXAxis().setDrawLabels(false); 106 | chart.getXAxis().setGranularity(1.0f); 107 | chart.getXAxis().setAxisMinimum(-0.5f); 108 | chart.getXAxis().setAxisMaximum(Math.max(pitchDataSet.getEntryCount(), 1) - 0.5f); 109 | 110 | chart.setDrawValueAboveBar(false); 111 | chart.setDrawOrder(new CombinedChart.DrawOrder[]{ 112 | CombinedChart.DrawOrder.BAR, 113 | CombinedChart.DrawOrder.BUBBLE, 114 | CombinedChart.DrawOrder.CANDLE, 115 | CombinedChart.DrawOrder.LINE, 116 | CombinedChart.DrawOrder.SCATTER 117 | }); 118 | 119 | GraphLayout.FormatChart(chart); 120 | 121 | super.onViewCreated(view, savedInstanceState); 122 | } 123 | 124 | public void addNewPitch(Entry pitch) { 125 | if (pitchDataSet == null || getView() == null) 126 | return; 127 | 128 | pitchDataSet.addEntry(pitch); 129 | 130 | genderBarData.clearValues(); 131 | genderBarData.addDataSet(GraphLayout.getOverallRange(this.getContext(), pitchDataSet.getEntryCount())); 132 | 133 | CombinedChart chart = (CombinedChart) getView().findViewById(R.id.recording_chart); 134 | chart.getXAxis().setAxisMinimum(-0.5f); 135 | chart.getXAxis().setAxisMaximum(pitchDataSet.getEntryCount() - 0.5f); 136 | chartData.notifyDataChanged(); 137 | chart.notifyDataSetChanged(); 138 | chart.invalidate(); 139 | } 140 | 141 | @Override 142 | public void onAttach(Activity activity) 143 | { 144 | super.onAttach(activity); 145 | try 146 | { 147 | mListener = (OnFragmentInteractionListener) activity; 148 | } catch (ClassCastException e) 149 | { 150 | throw new ClassCastException(activity.toString() 151 | + " must implement OnFragmentInteractionListener"); 152 | } 153 | } 154 | 155 | @Override 156 | public void onDetach() 157 | { 158 | super.onDetach(); 159 | mListener = null; 160 | } 161 | 162 | @Override 163 | public void onValueSelected(Entry e, Highlight h) 164 | { 165 | e.getY(); 166 | Log.i(LOG_TAG, String.format("highlight %s selected", h.toString())); 167 | } 168 | 169 | @Override 170 | public void onNothingSelected() 171 | { 172 | 173 | } 174 | 175 | public interface OnFragmentInteractionListener 176 | { 177 | List startingPitchEntries(); 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /app/src/main/java/de/lilithwittmann/voicepitchanalyzer/fragments/WelcomeFragment.java: -------------------------------------------------------------------------------- 1 | package de.lilithwittmann.voicepitchanalyzer.fragments; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import androidx.fragment.app.Fragment; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | 10 | import de.lilithwittmann.voicepitchanalyzer.R; 11 | 12 | 13 | /** 14 | * A simple {@link Fragment} subclass. 15 | * Activities that contain this fragment must implement the 16 | * {@link WelcomeFragment.OnFragmentInteractionListener} interface 17 | * to handle interaction events. 18 | */ 19 | public class WelcomeFragment extends Fragment 20 | { 21 | 22 | // private OnFragmentInteractionListener mListener; 23 | 24 | public WelcomeFragment() 25 | { 26 | // Required empty public constructor 27 | } 28 | 29 | 30 | @Override 31 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 32 | Bundle savedInstanceState) 33 | { 34 | // Inflate the layout for this fragment 35 | return inflater.inflate(R.layout.fragment_welcome, container, false); 36 | } 37 | 38 | // TODO: Rename method, update argument and hook method into UI event 39 | // public void onButtonPressed(Uri uri) 40 | // { 41 | // if (mListener != null) 42 | // { 43 | // mListener.onFragmentInteraction(uri); 44 | // } 45 | // } 46 | 47 | @Override 48 | public void onAttach(Activity activity) 49 | { 50 | super.onAttach(activity); 51 | // try 52 | // { 53 | // mListener = (OnFragmentInteractionListener) activity; 54 | // } catch (ClassCastException e) 55 | // { 56 | // throw new ClassCastException(activity.toString() 57 | // + " must implement OnFragmentInteractionListener"); 58 | // } 59 | } 60 | 61 | @Override 62 | public void onDetach() 63 | { 64 | super.onDetach(); 65 | // mListener = null; 66 | } 67 | 68 | /** 69 | * This interface must be implemented by activities that contain this 70 | * fragment to allow an interaction in this fragment to be communicated 71 | * to the activity and potentially other fragments contained in that 72 | * activity. 73 | *

74 | * See the Android Training lesson Communicating with Other Fragments for more information. 77 | */ 78 | // public interface OnFragmentInteractionListener 79 | // { 80 | // // TODO: Update argument type and name 81 | // public void onFragmentInteraction(Uri uri); 82 | // } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /app/src/main/java/de/lilithwittmann/voicepitchanalyzer/listeners/RecyclerItemClickListener.java: -------------------------------------------------------------------------------- 1 | package de.lilithwittmann.voicepitchanalyzer.listeners; 2 | 3 | import android.content.Context; 4 | import androidx.recyclerview.widget.RecyclerView; 5 | import android.view.GestureDetector; 6 | import android.view.MotionEvent; 7 | import android.view.View; 8 | 9 | /** 10 | * Created by Yuri on 22-09-15 11 | */ 12 | public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener 13 | { 14 | private OnItemClickListener mListener; 15 | 16 | public interface OnItemClickListener 17 | { 18 | public void onItemClick(View view, int position); 19 | } 20 | 21 | GestureDetector mGestureDetector; 22 | 23 | public RecyclerItemClickListener(Context context, OnItemClickListener listener) 24 | { 25 | mListener = listener; 26 | mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() 27 | { 28 | @Override 29 | public boolean onSingleTapUp(MotionEvent e) 30 | { 31 | return true; 32 | } 33 | }); 34 | } 35 | 36 | @Override 37 | public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) 38 | { 39 | View childView = view.findChildViewUnder(e.getX(), e.getY()); 40 | if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) 41 | { 42 | mListener.onItemClick(childView, view.getChildAdapterPosition(childView)); 43 | } 44 | return false; 45 | } 46 | 47 | @Override 48 | public void onTouchEvent(RecyclerView view, MotionEvent motionEvent) 49 | { 50 | } 51 | 52 | @Override 53 | public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) 54 | { 55 | 56 | } 57 | } -------------------------------------------------------------------------------- /app/src/main/java/de/lilithwittmann/voicepitchanalyzer/models/PitchRange.java: -------------------------------------------------------------------------------- 1 | package de.lilithwittmann.voicepitchanalyzer.models; 2 | 3 | import android.os.Parcel; 4 | import android.os.Parcelable; 5 | 6 | import com.github.mikephil.charting.data.Entry; 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | /** 12 | * Created by Yuri on 04/07/15. 13 | */ 14 | public class PitchRange implements Parcelable { 15 | public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { 16 | public PitchRange createFromParcel(Parcel in) { 17 | return new PitchRange(in); 18 | } 19 | 20 | public PitchRange[] newArray(int size) { 21 | return new PitchRange[size]; 22 | } 23 | }; 24 | private double avg; 25 | private double min; 26 | private double max; 27 | private List pitches = new ArrayList(); 28 | 29 | public PitchRange() { 30 | } 31 | 32 | protected PitchRange(Parcel src) { 33 | this.setAvg(src.readDouble()); 34 | this.setMin(src.readDouble()); 35 | this.setMax(src.readDouble()); 36 | this.setPitches(src.readArrayList(Double.class.getClassLoader())); 37 | } 38 | 39 | public double getMin() { 40 | return min; 41 | } 42 | 43 | public void setMin(double min) { 44 | this.min = min; 45 | } 46 | 47 | public double getMax() { 48 | return max; 49 | } 50 | 51 | public void setMax(double max) { 52 | this.max = max; 53 | } 54 | 55 | public double getAvg() { 56 | return avg; 57 | } 58 | 59 | public void setAvg(double avg) { 60 | this.avg = avg; 61 | } 62 | 63 | public List getPitches() { 64 | return pitches; 65 | } 66 | 67 | public void setPitches(List pitches) { 68 | this.pitches = pitches; 69 | } 70 | 71 | public List getGraphEntries() { 72 | List list = new ArrayList(); 73 | 74 | for (int i = 0; i < this.getPitches().size(); i++) { 75 | list.add(new Entry(i, this.getPitches().get(i).floatValue())); 76 | } 77 | 78 | return list; 79 | } 80 | 81 | @Override 82 | public int describeContents() { 83 | return 0; 84 | } 85 | 86 | @Override 87 | public void writeToParcel(Parcel dest, int flags) { 88 | dest.writeDouble(this.getAvg()); 89 | dest.writeDouble(this.getMin()); 90 | dest.writeDouble(this.getMax()); 91 | dest.writeList(this.getPitches()); 92 | } 93 | } -------------------------------------------------------------------------------- /app/src/main/java/de/lilithwittmann/voicepitchanalyzer/models/Recording.java: -------------------------------------------------------------------------------- 1 | package de.lilithwittmann.voicepitchanalyzer.models; 2 | 3 | import android.content.Context; 4 | import android.os.Parcel; 5 | import android.os.Parcelable; 6 | import android.text.format.DateFormat; 7 | 8 | import com.github.mikephil.charting.data.Entry; 9 | 10 | import java.util.Date; 11 | 12 | /** 13 | * Created by Yuri on 04/07/15. 14 | */ 15 | public class Recording implements Parcelable { 16 | public static final String KEY = Recording.class.getSimpleName(); 17 | public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { 18 | public Recording createFromParcel(Parcel in) { 19 | return new Recording(in); 20 | } 21 | 22 | public Recording[] newArray(int size) { 23 | return new Recording[size]; 24 | } 25 | }; 26 | private String recording; 27 | private long recordingFileSize; 28 | private long id = -1; 29 | private Date date; 30 | private PitchRange range; 31 | private String name; 32 | 33 | public Recording(Date date) { 34 | setDate(date); 35 | } 36 | 37 | public Recording() { 38 | 39 | } 40 | 41 | protected Recording(Parcel src) { 42 | this.setDate(new Date(src.readLong())); 43 | this.setName(src.readString()); 44 | this.setRange((PitchRange) src.readParcelable(PitchRange.class.getClassLoader())); 45 | } 46 | 47 | /** 48 | * formats recording's date & time to display anywhere in app 49 | * 50 | * @param context calling activity's context [to retrieve locale] 51 | * @return recording's date/time formatted according to device's locale 52 | */ 53 | public String getDisplayDate(Context context) { 54 | return String.format("%s – %s", DateFormat.getDateFormat(context).format(this.getDate()), DateFormat.getTimeFormat(context).format(this.getDate())); 55 | } 56 | 57 | public long getId() { 58 | return id; 59 | } 60 | 61 | public void setId(long id) { 62 | this.id = id; 63 | } 64 | 65 | public Date getDate() { 66 | return date; 67 | } 68 | 69 | public void setDate(Date date) { 70 | this.date = date; 71 | } 72 | 73 | public PitchRange getRange() { 74 | return range; 75 | } 76 | 77 | public void setRange(PitchRange range) { 78 | this.range = range; 79 | } 80 | 81 | public String getName() { 82 | return name; 83 | } 84 | 85 | public void setName(String name) { 86 | this.name = name; 87 | } 88 | 89 | public String getRecording() { 90 | return recording; 91 | } 92 | 93 | public void setRecording(String recording) { 94 | this.recording = recording; 95 | } 96 | 97 | public long getRecordingFileSize() { 98 | return recordingFileSize; 99 | } 100 | 101 | public void setRecordingFileSize(long recordingFileSize) { 102 | this.recordingFileSize = recordingFileSize; 103 | } 104 | 105 | public Entry getGraphEntry() 106 | { 107 | return new Entry((float) this.getDate().getTime(), (float) this.getRange().getAvg()); 108 | } 109 | 110 | @Override 111 | public int describeContents() { 112 | return 0; 113 | } 114 | 115 | @Override 116 | public void writeToParcel(Parcel dest, int flags) { 117 | dest.writeLong(this.getDate().getTime()); 118 | dest.writeString(this.getName()); 119 | dest.writeParcelable(this.range, flags); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /app/src/main/java/de/lilithwittmann/voicepitchanalyzer/models/RecordingList.java: -------------------------------------------------------------------------------- 1 | package de.lilithwittmann.voicepitchanalyzer.models; 2 | 3 | import android.content.Context; 4 | import android.util.Log; 5 | 6 | import com.github.mikephil.charting.data.Entry; 7 | 8 | import org.joda.time.DateTime; 9 | import org.joda.time.Duration; 10 | 11 | import java.text.DateFormat; 12 | import java.util.ArrayList; 13 | import java.util.Date; 14 | import java.util.Hashtable; 15 | import java.util.List; 16 | import java.util.TreeMap; 17 | 18 | import de.lilithwittmann.voicepitchanalyzer.models.database.RecordingDB; 19 | 20 | /** 21 | * Created by Yuri on 30.01.16. 22 | */ 23 | public class RecordingList 24 | { 25 | private Hashtable recordings = new Hashtable<>(); 26 | private double avg = -1; 27 | private double min = -1; 28 | private double max = -1; 29 | // initialise to 'now' so that checking works correctly in constructor 30 | private long beginning = new Date().getTime(); 31 | private long end = 0; 32 | 33 | public RecordingList(Context context) 34 | { 35 | List list = new RecordingDB(context).getRecordings(); 36 | 37 | for (Recording recording : list) 38 | { 39 | // set beginning & end correctly 40 | if (recording.getDate().getTime() < this.getBeginning()) 41 | { 42 | this.setBeginning(recording.getDate().getTime()); 43 | } 44 | 45 | if (recording.getDate().getTime() > this.getEnd()) 46 | { 47 | this.setEnd(recording.getDate().getTime()); 48 | } 49 | 50 | this.getRecordings().put(new DateTime(recording.getDate()), recording); 51 | } 52 | } 53 | 54 | /*** 55 | * get the graph entries for progress fragment 56 | * only one entry per day 57 | * if there are more than one recordings per day, 58 | * only use the first entry of that day 59 | * for future: calculate average as this day's value 60 | * 61 | * @return 62 | */ 63 | public List getGraphEntries() 64 | { 65 | TreeMap result = new TreeMap<>(); 66 | 67 | Log.i("test", String.format("duration: %s", (int) new Duration(new DateTime(this.getBeginning()), new DateTime(this.getEnd())).getStandardDays())); 68 | 69 | for (Hashtable.Entry record : this.getRecordings().entrySet()) 70 | { 71 | // reset time of day so .getDuration() will always calculate a duration of one day between two different dates 72 | DateTime recordTime = new DateTime(record.getKey().getYear(), record.getKey().getMonthOfYear(), record.getKey().getDayOfMonth(), 0, 0, 0, 0); 73 | 74 | // list index as duration in days since first recording 75 | int index = (int) new Duration(this.getBeginningAsDate(), recordTime).getStandardDays(); 76 | 77 | // check if there are multiple entries for this date 78 | // and only add date if recording contains any pitch data 79 | if (!result.containsKey(index) && record.getValue().getRange().getAvg() > 0) 80 | { 81 | Log.i("RecordingList", String.format("beginning: %s", new DateTime(this.getBeginning()).toDateTime())); 82 | result.put(index, new Entry(index, (float) record.getValue().getRange().getAvg())); 83 | } 84 | } 85 | 86 | for (TreeMap.Entry entry : result.entrySet()) 87 | { 88 | Log.i("result", String.format("%s: %s", entry.getKey(), entry.getValue().getY())); 89 | } 90 | 91 | return new ArrayList<>(result.values()); 92 | } 93 | 94 | public Hashtable getRecordings() 95 | { 96 | return this.recordings; 97 | } 98 | 99 | public void setRecordings(Hashtable recordings) 100 | { 101 | this.recordings = recordings; 102 | } 103 | 104 | public double getAvg() 105 | { 106 | return avg; 107 | } 108 | 109 | public void setAvg(double avg) 110 | { 111 | this.avg = avg; 112 | } 113 | 114 | public double getMin() 115 | { 116 | if (this.min < 0) 117 | { 118 | double min = 10000; 119 | 120 | for (Hashtable.Entry recording : this.getRecordings().entrySet()) 121 | { 122 | double current = recording.getValue().getRange().getAvg(); 123 | 124 | if (min > current) 125 | { 126 | min = current; 127 | } 128 | } 129 | 130 | this.setMin(min); 131 | } 132 | 133 | return this.min; 134 | } 135 | 136 | public void setMin(double min) 137 | { 138 | this.min = min; 139 | } 140 | 141 | public double getMax() 142 | { 143 | if (this.max < 0) 144 | { 145 | double max = 0; 146 | 147 | for (Hashtable.Entry recording : this.getRecordings().entrySet()) 148 | { 149 | double current = recording.getValue().getRange().getAvg(); 150 | 151 | if (max < current) 152 | { 153 | max = current; 154 | } 155 | } 156 | 157 | this.setMax(max); 158 | } 159 | 160 | return this.max; 161 | } 162 | 163 | public void setMax(double max) 164 | { 165 | this.max = max; 166 | } 167 | 168 | public long getBeginning() 169 | { 170 | return this.beginning; 171 | } 172 | 173 | /** 174 | * get beginning as date time with time set to 00:00:00:00 175 | * 176 | * @return 177 | */ 178 | public DateTime getBeginningAsDate() 179 | { 180 | DateTime beginning = new DateTime(this.beginning); 181 | return new DateTime(beginning.getYear(), beginning.getMonthOfYear(), beginning.getDayOfMonth(), 0, 0, 0, 0); 182 | } 183 | 184 | public long getEnd() 185 | { 186 | return this.end; 187 | } 188 | 189 | private void setEnd(long end) 190 | { 191 | this.end = end; 192 | } 193 | 194 | public void setBeginning(long beginning) 195 | { 196 | this.beginning = beginning; 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /app/src/main/java/de/lilithwittmann/voicepitchanalyzer/models/Texts.java: -------------------------------------------------------------------------------- 1 | package de.lilithwittmann.voicepitchanalyzer.models; 2 | 3 | 4 | import com.google.gson.JsonArray; 5 | import com.google.gson.JsonElement; 6 | import com.google.gson.JsonObject; 7 | import com.google.gson.JsonParser; 8 | 9 | import java.io.BufferedReader; 10 | import java.io.IOException; 11 | import java.io.InputStream; 12 | import java.io.InputStreamReader; 13 | import java.io.Reader; 14 | import java.io.StringWriter; 15 | import java.io.UnsupportedEncodingException; 16 | import java.io.Writer; 17 | import java.util.ArrayList; 18 | import java.util.List; 19 | 20 | /** 21 | * Created by lilith on 7/5/15. 22 | */ 23 | public class Texts { 24 | 25 | public Texts() { 26 | 27 | } 28 | 29 | public String getText(String lang, Integer id) { 30 | JsonElement jelement = new JsonParser().parse(getJsonData(lang)); 31 | JsonObject jobject = jelement.getAsJsonObject(); 32 | JsonObject langs = jobject.getAsJsonObject("texts"); 33 | JsonArray texts = langs.getAsJsonArray(lang); 34 | return texts.get(id - 1).getAsString(); 35 | } 36 | 37 | public Integer countTexts(String lang) { 38 | JsonElement jelement = new JsonParser().parse(getJsonData(lang)); 39 | JsonObject jobject = jelement.getAsJsonObject(); 40 | JsonObject langs = jobject.getAsJsonObject("texts"); 41 | JsonArray texts = langs.getAsJsonArray(lang); 42 | return texts.getAsJsonArray().size(); 43 | } 44 | 45 | private String jsonFolder = "res/raw/"; 46 | private String jsonData = null; 47 | 48 | private List supportedLanguages = new ArrayList() {{add("de"); add("en"); add("it"); add("pt");}}; 49 | 50 | String getJsonData(String country) { 51 | if (this.jsonData != null) { 52 | return jsonData; 53 | } else { 54 | try { 55 | this.jsonData = this.readJsonNFile(this.jsonFolder+country+".json"); 56 | } catch (IOException e) { 57 | e.printStackTrace(); 58 | } 59 | return this.jsonData; 60 | 61 | } 62 | } 63 | 64 | private String readJsonNFile(String jsonFile) throws IOException { 65 | InputStream is = this.getClass().getClassLoader().getResourceAsStream(jsonFile); 66 | Writer writer = new StringWriter(); 67 | char[] buffer = new char[1024]; 68 | try { 69 | Reader reader = new BufferedReader(new InputStreamReader(is, "UTF-8")); 70 | int n; 71 | while ((n = reader.read(buffer)) != -1) { 72 | writer.write(buffer, 0, n); 73 | } 74 | } catch (UnsupportedEncodingException e) { 75 | e.printStackTrace(); 76 | } catch (IOException e) { 77 | e.printStackTrace(); 78 | } finally { 79 | is.close(); 80 | } 81 | 82 | String jsonString = writer.toString(); 83 | 84 | return jsonString; 85 | } 86 | 87 | public boolean supportsLocale(String language) { 88 | if(this.supportedLanguages.contains(language)) 89 | { 90 | return Boolean.TRUE; 91 | } 92 | return Boolean.FALSE; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /app/src/main/java/de/lilithwittmann/voicepitchanalyzer/utils/CountingWriterProcessor.java: -------------------------------------------------------------------------------- 1 | package de.lilithwittmann.voicepitchanalyzer.utils; 2 | 3 | import java.io.RandomAccessFile; 4 | import java.util.concurrent.atomic.AtomicLong; 5 | 6 | import be.tarsos.dsp.AudioEvent; 7 | import be.tarsos.dsp.io.TarsosDSPAudioFormat; 8 | import be.tarsos.dsp.writer.WriterProcessor; 9 | 10 | public class CountingWriterProcessor extends WriterProcessor { 11 | private static final long HEADER_LENGTH = 44; 12 | 13 | private final TarsosDSPAudioFormat format; 14 | private final AtomicLong fileSize = new AtomicLong(HEADER_LENGTH); 15 | 16 | public CountingWriterProcessor(TarsosDSPAudioFormat format, RandomAccessFile file) { 17 | super(format, file); 18 | this.format = format; 19 | } 20 | 21 | @Override 22 | public boolean process(AudioEvent audioEvent) { 23 | fileSize.getAndAdd(audioEvent.getBufferSize() * format.getFrameSize()); 24 | return super.process(audioEvent); 25 | } 26 | 27 | public long getFileSize() { 28 | return fileSize.get(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/de/lilithwittmann/voicepitchanalyzer/utils/DateValueFormatter.java: -------------------------------------------------------------------------------- 1 | package de.lilithwittmann.voicepitchanalyzer.utils; 2 | 3 | import com.github.mikephil.charting.components.AxisBase; 4 | import com.github.mikephil.charting.formatter.ValueFormatter; 5 | 6 | import org.joda.time.DateTime; 7 | 8 | import java.text.DateFormat; 9 | import java.util.HashMap; 10 | 11 | public class DateValueFormatter extends ValueFormatter 12 | { 13 | private final DateTime beginningDate; 14 | private final HashMap formattedCache = new HashMap<>(); 15 | 16 | public DateValueFormatter(DateTime beginningDate) 17 | { 18 | this.beginningDate = beginningDate; 19 | } 20 | 21 | @Override 22 | public String getFormattedValue(float value) 23 | { 24 | int days = (int) value; 25 | 26 | String cachedFormatted = this.formattedCache.get(days); 27 | if (cachedFormatted != null) 28 | { 29 | return cachedFormatted; 30 | } 31 | 32 | String formatted = DateFormat.getDateInstance().format(beginningDate.plusDays(days).toDate()); 33 | this.formattedCache.put(days, formatted); 34 | return formatted; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/java/de/lilithwittmann/voicepitchanalyzer/utils/ExecutorUtils.java: -------------------------------------------------------------------------------- 1 | package de.lilithwittmann.voicepitchanalyzer.utils; 2 | 3 | import java.util.concurrent.ExecutorService; 4 | import java.util.concurrent.Executors; 5 | 6 | public class ExecutorUtils { 7 | private static final ExecutorService BOUNDED = Executors.newFixedThreadPool( 8 | Runtime.getRuntime().availableProcessors(), 9 | r -> new Thread(r, "bounded-executor") 10 | ); 11 | 12 | public static ExecutorService getBoundedExecutor() { 13 | return BOUNDED; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/de/lilithwittmann/voicepitchanalyzer/utils/GraphLayout.java: -------------------------------------------------------------------------------- 1 | package de.lilithwittmann.voicepitchanalyzer.utils; 2 | 3 | import android.content.Context; 4 | 5 | import com.github.mikephil.charting.charts.BarLineChartBase; 6 | import com.github.mikephil.charting.components.Description; 7 | import com.github.mikephil.charting.components.Legend; 8 | import com.github.mikephil.charting.data.BarDataSet; 9 | import com.github.mikephil.charting.data.BarEntry; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | 14 | import de.lilithwittmann.voicepitchanalyzer.R; 15 | 16 | /** 17 | * Created by Yuri on 30.01.16 n. Chr. 18 | */ 19 | public class GraphLayout 20 | { 21 | /** 22 | * style a basic chart in app style 23 | * 24 | * @param chart chart object to be styled 25 | * @return styled chart object 26 | */ 27 | public static BarLineChartBase FormatChart(BarLineChartBase chart) 28 | { 29 | chart.getAxisLeft().resetAxisMinimum(); 30 | chart.getAxisRight().resetAxisMinimum(); 31 | 32 | // hide grid lines & borders 33 | chart.getAxisLeft().setDrawGridLines(false); 34 | chart.getAxisRight().setDrawGridLines(false); 35 | chart.getXAxis().setDrawGridLines(false); 36 | chart.getAxisLeft().setValueFormatter(new GraphValueFormatter()); 37 | chart.getAxisRight().setValueFormatter(new GraphValueFormatter()); 38 | chart.setDrawBorders(false); 39 | 40 | Description emptyDescription = new Description(); 41 | emptyDescription.setText(""); 42 | chart.setDescription(emptyDescription); 43 | 44 | // disable all interactions except highlighting selection 45 | chart.setTouchEnabled(false); 46 | chart.setScaleEnabled(false); 47 | chart.setPinchZoom(false); 48 | chart.setDoubleTapToZoomEnabled(false); 49 | chart.setDrawGridBackground(false); 50 | 51 | chart.getData().setHighlightEnabled(true); 52 | 53 | chart.getAxisLeft().setAxisMaximum(PitchCalculator.maxPitch.floatValue()); 54 | chart.getAxisRight().setAxisMaximum(PitchCalculator.maxPitch.floatValue()); 55 | chart.getAxisRight().setAxisMinimum(PitchCalculator.minPitch.floatValue()); 56 | chart.getAxisLeft().setAxisMinimum(PitchCalculator.minPitch.floatValue()); 57 | 58 | chart.getAxisLeft().setValueFormatter(new GraphValueFormatter()); 59 | chart.getAxisRight().setValueFormatter(new GraphValueFormatter()); 60 | chart.setDrawBorders(false); 61 | 62 | // set min/max values etc. for axes 63 | chart.getAxisLeft().setAxisMinimum(PitchCalculator.minMalePitch.floatValue()); 64 | chart.getAxisRight().setAxisMinimum(PitchCalculator.minMalePitch.floatValue()); 65 | // chart.getAxisRight().setStartAtZero(false); 66 | 67 | chart.setHardwareAccelerationEnabled(true); 68 | // chart.getLegend().setEnabled(false); 69 | 70 | Legend legend = chart.getLegend(); 71 | legend.setHorizontalAlignment(Legend.LegendHorizontalAlignment.CENTER); 72 | legend.setVerticalAlignment(Legend.LegendVerticalAlignment.BOTTOM); 73 | legend.setOrientation(Legend.LegendOrientation.HORIZONTAL); 74 | 75 | return chart; 76 | } 77 | 78 | /** 79 | * get bar chart data for male/female vocal ranges 80 | * to display them as bars beneath other chart data 81 | * 82 | * @param amount amount of entries needed 83 | * @return bar data to add to chart 84 | */ 85 | public static BarDataSet getOverallRange(Context context, int amount) 86 | { 87 | BarDataSet set = new BarDataSet(GraphLayout.getRangeEntries(amount), ""); 88 | set.setDrawValues(false); 89 | set.setColors(new int[]{context.getResources().getColor(R.color.male_range), 90 | context.getResources().getColor(R.color.androgynous_range), 91 | context.getResources().getColor(R.color.female_range)}); 92 | set.setStackLabels(new String[]{context.getResources().getString(R.string.male_range), 93 | context.getResources().getString(R.string.androgynous_range), 94 | context.getResources().getString(R.string.female_range) 95 | }); 96 | 97 | // List setList = new ArrayList(); 98 | // setList.add(set); 99 | // 100 | // return setList; 101 | 102 | return set; 103 | } 104 | 105 | /*** 106 | * @param amount 107 | * @return 108 | */ 109 | private static List getRangeEntries(int amount) 110 | { 111 | List result = new ArrayList(); 112 | 113 | for (int i = 0; i < amount; i++) 114 | { 115 | result.add(new BarEntry(i, new float[]{ 116 | PitchCalculator.minMalePitch.floatValue()*2, 117 | PitchCalculator.maxMalePitch.floatValue() - PitchCalculator.minFemalePitch.floatValue(), 118 | PitchCalculator.maxFemalePitch.floatValue() - PitchCalculator.maxMalePitch.floatValue(), 119 | })); 120 | } 121 | 122 | return result; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /app/src/main/java/de/lilithwittmann/voicepitchanalyzer/utils/GraphValueFormatter.java: -------------------------------------------------------------------------------- 1 | package de.lilithwittmann.voicepitchanalyzer.utils; 2 | 3 | import com.github.mikephil.charting.formatter.ValueFormatter; 4 | 5 | import java.text.DecimalFormat; 6 | 7 | /** 8 | * Created by Yuri on 06/07/15. 9 | */ 10 | public class GraphValueFormatter extends ValueFormatter { 11 | private DecimalFormat format = new DecimalFormat("###,###,##0.0"); 12 | 13 | public GraphValueFormatter() { 14 | } 15 | 16 | @Override 17 | public String getFormattedValue(float value) { 18 | return String.format("%sHz", format.format(value)); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/de/lilithwittmann/voicepitchanalyzer/utils/PitchCalculator.java: -------------------------------------------------------------------------------- 1 | package de.lilithwittmann.voicepitchanalyzer.utils; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.List; 6 | 7 | /** 8 | * Created by Lilith on 04/07/15. 9 | */ 10 | public class PitchCalculator { 11 | // Yes the range is very large - test it and maybe change to something like 85-255 12 | public static Double minPitch = 65.0; 13 | public static Double maxPitch = 300.0; 14 | public static Double minFemalePitch = 165.0; 15 | public static Double maxFemalePitch = 255.0; 16 | public static Double minMalePitch = 85.0; 17 | public static Double maxMalePitch = 180.0; 18 | 19 | private static final Double HIGHER_VOICE_CUT_OFF = 145.0; 20 | private static final Double LOWER_VOICE_CUT_OFF = 110.0; 21 | 22 | private List pitches = new ArrayList(); 23 | 24 | public static List copyList(List source) { 25 | List dest = new ArrayList(); 26 | for (T item : source) { 27 | dest.add(item); 28 | } 29 | return dest; 30 | } 31 | 32 | public Boolean addPitch(Double pitch) { 33 | // if voice is a 'high' voice we can confidently bump up the minPitch a little to remove 34 | // annoying extraneous pitch result points and same for low voices 35 | Double minPitchCutoff = getMinPitchCutoff(); 36 | Double maxPitchCutoff = getMaxPitchCutoff(); 37 | 38 | if (pitch > minPitchCutoff && pitch < maxPitchCutoff) { 39 | this.pitches.add(pitch); 40 | return Boolean.TRUE; 41 | } 42 | 43 | return Boolean.FALSE; 44 | } 45 | 46 | public List getPitches() { 47 | return this.pitches; 48 | } 49 | 50 | public void setPitches(List pitches) { 51 | this.pitches = pitches; 52 | } 53 | 54 | public Double calculatePitchAverage() { 55 | return this.calculateAverage(this.pitches); 56 | } 57 | 58 | public Double calculateMaxAverage() { 59 | List maxSorted = PitchCalculator.copyList(this.pitches); 60 | Collections.sort(maxSorted); 61 | Collections.reverse(maxSorted); 62 | Integer elements = maxSorted.size() / 3; 63 | return this.calculateAverage(maxSorted.subList(0, elements)); 64 | } 65 | 66 | public Double calculateMinAverage() { 67 | List minSorted = PitchCalculator.copyList(this.pitches); 68 | Collections.sort(minSorted); 69 | Integer elements = minSorted.size() / 3; 70 | return this.calculateAverage(minSorted.subList(0, elements)); 71 | } 72 | 73 | public Double getMax() { 74 | Double max_pitch = null; 75 | for (Double pitch: this.pitches) { 76 | if(max_pitch == null || max_pitch < pitch) { 77 | max_pitch = pitch; 78 | } 79 | } 80 | 81 | return max_pitch; 82 | } 83 | 84 | public Double getMin() { 85 | Double min_pitch = null; 86 | for (Double pitch: this.pitches) { 87 | if(min_pitch == null || min_pitch > pitch) { 88 | min_pitch = pitch; 89 | } 90 | } 91 | 92 | return min_pitch; 93 | } 94 | 95 | private Double calculateAverage(List pitches) { 96 | Double sum = 0.0; 97 | if (!pitches.isEmpty()) { 98 | for (Double pitch : pitches) { 99 | sum += pitch; 100 | } 101 | return sum.doubleValue() / pitches.size(); 102 | } 103 | return sum; 104 | } 105 | 106 | private Double getMinPitchCutoff() { 107 | Double minPitchCutoff = minPitch; 108 | if (calculatePitchAverage() > HIGHER_VOICE_CUT_OFF) 109 | minPitchCutoff = 85.0; 110 | 111 | return minPitchCutoff; 112 | } 113 | 114 | private Double getMaxPitchCutoff() { 115 | Double maxPitchCutoff = maxPitch; 116 | if (calculatePitchAverage() < LOWER_VOICE_CUT_OFF) 117 | maxPitchCutoff = 255.0; 118 | 119 | return maxPitchCutoff; 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /app/src/main/java/de/lilithwittmann/voicepitchanalyzer/utils/RecordingCleaner.java: -------------------------------------------------------------------------------- 1 | package de.lilithwittmann.voicepitchanalyzer.utils; 2 | 3 | import android.content.Context; 4 | import android.util.Log; 5 | 6 | import java.io.IOException; 7 | import java.nio.file.DirectoryStream; 8 | import java.nio.file.Files; 9 | import java.nio.file.NoSuchFileException; 10 | import java.nio.file.Path; 11 | import java.time.Duration; 12 | import java.time.Instant; 13 | import java.util.Date; 14 | import java.util.HashSet; 15 | import java.util.Optional; 16 | import java.util.stream.Collectors; 17 | 18 | import de.lilithwittmann.voicepitchanalyzer.models.Recording; 19 | import de.lilithwittmann.voicepitchanalyzer.models.database.RecordingDB; 20 | 21 | public class RecordingCleaner implements Runnable { 22 | private static final String LOG_TAG = RecordingCleaner.class.getSimpleName(); 23 | 24 | private final Context context; 25 | 26 | private static final long MAX_RECORDINGS_SIZE = 1024 * 1024 * 100; 27 | private static final int MIN_RECORDING_DAYS = 1; 28 | 29 | public RecordingCleaner(Context context) { 30 | this.context = context; 31 | } 32 | 33 | @Override 34 | public void run() { 35 | cleanUnfinishedRecordings(this.context); 36 | cleanRecordings(this.context); 37 | } 38 | 39 | public static void cleanUnfinishedRecordings(Context context) { 40 | Path directory = RecordingPaths.getUnfinishedRecordingsDirectoryPath(context); 41 | if (directory == null || !Files.isDirectory(directory)) { 42 | return; 43 | } 44 | DirectoryStream directoryStream; 45 | try { 46 | directoryStream = Files.newDirectoryStream(directory); 47 | } catch (IOException ex) { 48 | Log.w(LOG_TAG, "error opening recording directory " + directory + ": " + ex); 49 | return; 50 | } 51 | 52 | long deleteCount = 0; 53 | for (Path filePath : directoryStream) { 54 | try { 55 | Files.deleteIfExists(filePath); 56 | deleteCount += 1; 57 | } catch (IOException ex) { 58 | Log.w(LOG_TAG, "error deleting unfinished recording " + filePath + ": " + ex); 59 | } 60 | } 61 | 62 | Log.i(LOG_TAG, "deleted " + deleteCount + " unfinished recording files"); 63 | } 64 | 65 | public static void cleanRecordings(Context context) { 66 | HashSet remainingFiles; 67 | try { 68 | remainingFiles = getRecordingFiles(context); 69 | } catch (IOException ex) { 70 | Log.w(LOG_TAG, "error listing recordings directory: " + ex); 71 | remainingFiles = null; 72 | } 73 | 74 | RecordingDB db = new RecordingDB(context); 75 | 76 | Date newestDeleteDate = Date.from(Instant.now().minus(Duration.ofDays(MIN_RECORDING_DAYS))); 77 | long runningSize = 0; 78 | long deletedSize = 0; 79 | long runningCount = 0; 80 | long deleteCount = 0; 81 | long oldCount = 0; 82 | for (Recording recording : db.getRecordingsWithFiles()) { 83 | runningCount += 1; 84 | runningSize += recording.getRecordingFileSize(); 85 | if (remainingFiles != null && recording.getRecording() != null) { 86 | remainingFiles.remove(recording.getRecording()); 87 | } 88 | if (recording.getDate().before(newestDeleteDate)) { 89 | oldCount += 1; 90 | if (runningSize > MAX_RECORDINGS_SIZE) { 91 | DeleteResult deleteResult = deleteRecording(context, db, recording); 92 | if (deleteResult == DeleteResult.OK || deleteResult == DeleteResult.MISSING) { 93 | deleteCount += 1; 94 | } 95 | if (deleteResult == DeleteResult.OK) { 96 | deletedSize += recording.getRecordingFileSize(); 97 | } 98 | } 99 | } 100 | } 101 | 102 | Log.i(LOG_TAG, "deleted " + deleteCount + " of " + oldCount + " old recording files (of " + runningCount + " total) freeing " + deletedSize 103 | + " of " + runningSize + " bytes"); 104 | 105 | long deletedOrphanCount = 0; 106 | for (String file : Optional.ofNullable(remainingFiles).orElseGet(HashSet::new)) { 107 | Path path = RecordingPaths.getRecordingPath(context, file); 108 | if (path != null) { 109 | try { 110 | Files.delete(path); 111 | deletedOrphanCount += 1; 112 | } catch (IOException ex) { 113 | Log.w(LOG_TAG, "failed to delete orphaned recording file " + path + ": " + ex); 114 | } 115 | } else { 116 | Log.w(LOG_TAG, "could not determine path for orphaned recording file " + file); 117 | } 118 | } 119 | 120 | Log.i(LOG_TAG, "deleted " + deletedOrphanCount + " orphaned recording files"); 121 | } 122 | 123 | private static HashSet getRecordingFiles(Context context) throws IOException { 124 | Path path = RecordingPaths.getRecordingsDirectoryPath(context); 125 | if (path == null) { 126 | Log.w(LOG_TAG, "could not determine recordings path"); 127 | return null; 128 | } 129 | return Files.list(path) 130 | .map(filePath -> filePath.getFileName().toString()) 131 | .collect(Collectors.toCollection(HashSet::new)); 132 | } 133 | 134 | private static DeleteResult deleteRecording(Context context, RecordingDB db, Recording recording) { 135 | Optional path = Optional.ofNullable(recording.getRecording()) 136 | .map(name -> RecordingPaths.getRecordingPath(context, name)); 137 | if (!path.isPresent()) { 138 | Log.w(LOG_TAG, "could not determine path for recording file " + recording.getRecording()); 139 | return DeleteResult.ERROR; 140 | } 141 | DeleteResult result; 142 | try { 143 | Files.delete(path.get()); 144 | result = DeleteResult.OK; 145 | } catch (NoSuchFileException ex) { 146 | Log.w(LOG_TAG, "recording file " + path.get() + " missing"); 147 | result = DeleteResult.MISSING; 148 | } catch (IOException ex) { 149 | Log.w(LOG_TAG, "error deleting recording file " + path.get() + ": ", ex); 150 | return DeleteResult.ERROR; 151 | } 152 | db.updateRecordingFilename(recording.getId(), null); 153 | return result; 154 | } 155 | 156 | private enum DeleteResult { 157 | OK, 158 | ERROR, 159 | MISSING, 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /app/src/main/java/de/lilithwittmann/voicepitchanalyzer/utils/RecordingPaths.java: -------------------------------------------------------------------------------- 1 | package de.lilithwittmann.voicepitchanalyzer.utils; 2 | 3 | import android.content.Context; 4 | 5 | import java.nio.file.Path; 6 | import java.util.Optional; 7 | 8 | public class RecordingPaths { 9 | private static String RECORDING_DIR = "recordings"; 10 | private static String UNFINISHED_RECORDING_DIR = "unfinished_recordings"; 11 | 12 | public static Path getUnfinishedRecordingsDirectoryPath(Context context) { 13 | return Optional.ofNullable(context.getFilesDir()) 14 | .map(dir -> dir.toPath().resolve(UNFINISHED_RECORDING_DIR)) 15 | .orElse(null); 16 | } 17 | 18 | public static Path getUnfinishedRecordingPath(Context context, String name) { 19 | return Optional.ofNullable(getUnfinishedRecordingsDirectoryPath(context)) 20 | .map(dir -> dir.resolve(name)) 21 | .orElse(null); 22 | } 23 | 24 | public static Path getRecordingsDirectoryPath(Context context) { 25 | return Optional.ofNullable(context.getFilesDir()) 26 | .map(dir -> dir.toPath().resolve(RECORDING_DIR)) 27 | .orElse(null); 28 | } 29 | 30 | public static Path getRecordingPath(Context context, String name) { 31 | return Optional.ofNullable(getRecordingsDirectoryPath(context)) 32 | .map(dir -> dir.resolve(name)) 33 | .orElse(null); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/java/de/lilithwittmann/voicepitchanalyzer/utils/SampleRateCalculator.java: -------------------------------------------------------------------------------- 1 | package de.lilithwittmann.voicepitchanalyzer.utils; 2 | 3 | import android.media.AudioRecord; 4 | 5 | import java.util.ArrayList; 6 | 7 | /** 8 | * Created by lilith on 7/6/15. 9 | */ 10 | public class SampleRateCalculator { 11 | 12 | public static int getMaxSupportedSampleRate() { 13 | /* 14 | * Valid Audio Sample rates 15 | * 16 | * @see Wikipedia 19 | */ 20 | final int validSampleRates[] = new int[]{ 21 | 47250, 44100, 44056, 37800, 32000, 22050, 16000, 11025, 4800, 8000,}; 22 | /* 23 | * Selecting default audio input source for recording since 24 | * AudioFormat.CHANNEL_CONFIGURATION_DEFAULT is deprecated and selecting 25 | * default encoding format. 26 | */ 27 | for (int i = 0; i < validSampleRates.length; i++) { 28 | int result = AudioRecord.getMinBufferSize(validSampleRates[i], 29 | android.media.AudioFormat.CHANNEL_IN_MONO, 30 | android.media.AudioFormat.ENCODING_PCM_16BIT); 31 | if (result != AudioRecord.ERROR 32 | && result != AudioRecord.ERROR_BAD_VALUE && result > 0) { 33 | // return the mininum supported audio sample rate 34 | return validSampleRates[i]; 35 | } 36 | } 37 | // If none of the sample rates are supported return -1 handle it in 38 | // calling method 39 | return -1; 40 | } 41 | 42 | 43 | public static ArrayList getAllSupportedSampleRates() { 44 | /* 45 | *get all supported sample rates 46 | * 47 | * @see Wikipedia 50 | */ 51 | final int validSampleRates[] = new int[]{ 5644800, 2822400, 352800, 192000, 176400, 96000, 52 | 88200, 50400, 50000, 4800, 47250, 44100, 44056, 37800, 32000, 22050, 16000, 11025, 8000, }; 53 | /* 54 | * Selecting default audio input source for recording since 55 | * AudioFormat.CHANNEL_CONFIGURATION_DEFAULT is deprecated and selecting 56 | * default encoding format. 57 | */ 58 | 59 | ArrayList supportedSampleRates = new ArrayList(); 60 | for (int i = 0; i < validSampleRates.length; i++) { 61 | int result = AudioRecord.getMinBufferSize(validSampleRates[i], 62 | android.media.AudioFormat.CHANNEL_IN_MONO, 63 | android.media.AudioFormat.ENCODING_PCM_16BIT); 64 | if (result != AudioRecord.ERROR 65 | && result != AudioRecord.ERROR_BAD_VALUE && result > 0) { 66 | // return the mininum supported audio sample rate 67 | supportedSampleRates.add(validSampleRates[i]); 68 | } 69 | } 70 | // If none of the sample rates are supported return -1 handle it in 71 | // calling method 72 | return supportedSampleRates; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /app/src/main/res/color/button_text_color.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ab_bottom_solid_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-hdpi/ab_bottom_solid_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ab_solid_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-hdpi/ab_solid_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ab_stacked_solid_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-hdpi/ab_stacked_solid_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ab_texture_tile_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-hdpi/ab_texture_tile_example.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ab_transparent_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-hdpi/ab_transparent_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/app_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-hdpi/app_icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/btn_cab_done_default_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-hdpi/btn_cab_done_default_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/btn_cab_done_focused_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-hdpi/btn_cab_done_focused_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/btn_cab_done_pressed_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-hdpi/btn_cab_done_pressed_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/cab_background_bottom_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-hdpi/cab_background_bottom_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/cab_background_top_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-hdpi/cab_background_top_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_assessment_white_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-hdpi/ic_assessment_white_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_delete_white_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-hdpi/ic_delete_white_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_info_outline_white_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-hdpi/ic_info_outline_white_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_info_white_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-hdpi/ic_info_white_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_play_circle_filled_black_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-hdpi/ic_play_circle_filled_black_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_settings_voice_black_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-hdpi/ic_settings_voice_black_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_settings_voice_white_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-hdpi/ic_settings_voice_white_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/list_focused_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-hdpi/list_focused_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/list_pressed_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-hdpi/list_pressed_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/menu_dropdown_panel_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-hdpi/menu_dropdown_panel_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/progress_bg_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-hdpi/progress_bg_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/progress_primary_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-hdpi/progress_primary_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/progress_secondary_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-hdpi/progress_secondary_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/spinner_ab_default_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-hdpi/spinner_ab_default_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/spinner_ab_disabled_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-hdpi/spinner_ab_disabled_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/spinner_ab_focused_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-hdpi/spinner_ab_focused_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/spinner_ab_pressed_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-hdpi/spinner_ab_pressed_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/tab_selected_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-hdpi/tab_selected_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/tab_selected_focused_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-hdpi/tab_selected_focused_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/tab_selected_pressed_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-hdpi/tab_selected_pressed_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/tab_unselected_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-hdpi/tab_unselected_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/tab_unselected_focused_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-hdpi/tab_unselected_focused_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/tab_unselected_pressed_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-hdpi/tab_unselected_pressed_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ab_bottom_solid_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-mdpi/ab_bottom_solid_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ab_solid_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-mdpi/ab_solid_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ab_stacked_solid_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-mdpi/ab_stacked_solid_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ab_texture_tile_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-mdpi/ab_texture_tile_example.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ab_transparent_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-mdpi/ab_transparent_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/app_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-mdpi/app_icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/btn_cab_done_default_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-mdpi/btn_cab_done_default_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/btn_cab_done_focused_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-mdpi/btn_cab_done_focused_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/btn_cab_done_pressed_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-mdpi/btn_cab_done_pressed_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/cab_background_bottom_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-mdpi/cab_background_bottom_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/cab_background_top_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-mdpi/cab_background_top_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_assessment_white_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-mdpi/ic_assessment_white_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_delete_white_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-mdpi/ic_delete_white_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_info_outline_white_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-mdpi/ic_info_outline_white_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_info_white_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-mdpi/ic_info_white_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_play_circle_filled_black_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-mdpi/ic_play_circle_filled_black_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_settings_voice_black_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-mdpi/ic_settings_voice_black_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_settings_voice_white_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-mdpi/ic_settings_voice_white_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/list_focused_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-mdpi/list_focused_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/list_pressed_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-mdpi/list_pressed_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/menu_dropdown_panel_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-mdpi/menu_dropdown_panel_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/progress_bg_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-mdpi/progress_bg_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/progress_primary_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-mdpi/progress_primary_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/progress_secondary_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-mdpi/progress_secondary_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/spinner_ab_default_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-mdpi/spinner_ab_default_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/spinner_ab_disabled_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-mdpi/spinner_ab_disabled_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/spinner_ab_focused_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-mdpi/spinner_ab_focused_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/spinner_ab_pressed_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-mdpi/spinner_ab_pressed_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/tab_selected_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-mdpi/tab_selected_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/tab_selected_focused_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-mdpi/tab_selected_focused_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/tab_selected_pressed_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-mdpi/tab_selected_pressed_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/tab_unselected_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-mdpi/tab_unselected_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/tab_unselected_focused_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-mdpi/tab_unselected_focused_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/tab_unselected_pressed_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-mdpi/tab_unselected_pressed_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ab_bottom_solid_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xhdpi/ab_bottom_solid_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ab_solid_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xhdpi/ab_solid_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ab_stacked_solid_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xhdpi/ab_stacked_solid_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ab_texture_tile_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xhdpi/ab_texture_tile_example.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ab_transparent_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xhdpi/ab_transparent_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/app_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xhdpi/app_icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/btn_cab_done_default_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xhdpi/btn_cab_done_default_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/btn_cab_done_focused_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xhdpi/btn_cab_done_focused_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/btn_cab_done_pressed_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xhdpi/btn_cab_done_pressed_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/cab_background_bottom_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xhdpi/cab_background_bottom_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/cab_background_top_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xhdpi/cab_background_top_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_assessment_white_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xhdpi/ic_assessment_white_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_delete_white_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xhdpi/ic_delete_white_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_info_outline_white_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xhdpi/ic_info_outline_white_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_info_white_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xhdpi/ic_info_white_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_play_circle_filled_black_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xhdpi/ic_play_circle_filled_black_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_settings_voice_black_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xhdpi/ic_settings_voice_black_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_settings_voice_white_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xhdpi/ic_settings_voice_white_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/list_focused_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xhdpi/list_focused_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/list_pressed_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xhdpi/list_pressed_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/menu_dropdown_panel_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xhdpi/menu_dropdown_panel_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/progress_bg_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xhdpi/progress_bg_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/progress_primary_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xhdpi/progress_primary_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/progress_secondary_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xhdpi/progress_secondary_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/spinner_ab_default_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xhdpi/spinner_ab_default_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/spinner_ab_disabled_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xhdpi/spinner_ab_disabled_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/spinner_ab_focused_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xhdpi/spinner_ab_focused_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/spinner_ab_pressed_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xhdpi/spinner_ab_pressed_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/tab_selected_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xhdpi/tab_selected_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/tab_selected_focused_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xhdpi/tab_selected_focused_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/tab_selected_pressed_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xhdpi/tab_selected_pressed_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/tab_unselected_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xhdpi/tab_unselected_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/tab_unselected_focused_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xhdpi/tab_unselected_focused_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/tab_unselected_pressed_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xhdpi/tab_unselected_pressed_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ab_bottom_solid_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xxhdpi/ab_bottom_solid_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ab_solid_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xxhdpi/ab_solid_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ab_stacked_solid_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xxhdpi/ab_stacked_solid_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ab_texture_tile_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xxhdpi/ab_texture_tile_example.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ab_transparent_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xxhdpi/ab_transparent_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/app_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xxhdpi/app_icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/btn_cab_done_default_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xxhdpi/btn_cab_done_default_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/btn_cab_done_focused_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xxhdpi/btn_cab_done_focused_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/btn_cab_done_pressed_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xxhdpi/btn_cab_done_pressed_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/cab_background_bottom_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xxhdpi/cab_background_bottom_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/cab_background_top_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xxhdpi/cab_background_top_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/drawable-xxhdpi/ic_delete_white_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xxhdpi/drawable-xxhdpi/ic_delete_white_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_assessment_white_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xxhdpi/ic_assessment_white_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_info_outline_white_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xxhdpi/ic_info_outline_white_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_info_white_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xxhdpi/ic_info_white_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_play_circle_filled_black_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xxhdpi/ic_play_circle_filled_black_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_settings_voice_black_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xxhdpi/ic_settings_voice_black_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_settings_voice_white_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xxhdpi/ic_settings_voice_white_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/list_focused_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xxhdpi/list_focused_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/list_pressed_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xxhdpi/list_pressed_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/menu_dropdown_panel_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xxhdpi/menu_dropdown_panel_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/progress_bg_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xxhdpi/progress_bg_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/progress_primary_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xxhdpi/progress_primary_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/progress_secondary_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xxhdpi/progress_secondary_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/spinner_ab_default_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xxhdpi/spinner_ab_default_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/spinner_ab_disabled_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xxhdpi/spinner_ab_disabled_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/spinner_ab_focused_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xxhdpi/spinner_ab_focused_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/spinner_ab_pressed_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xxhdpi/spinner_ab_pressed_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/tab_selected_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xxhdpi/tab_selected_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/tab_selected_focused_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xxhdpi/tab_selected_focused_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/tab_selected_pressed_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xxhdpi/tab_selected_pressed_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/tab_unselected_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xxhdpi/tab_unselected_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/tab_unselected_focused_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xxhdpi/tab_unselected_focused_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/tab_unselected_pressed_example.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xxhdpi/tab_unselected_pressed_example.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/app_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xxxhdpi/app_icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_assessment_white_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xxxhdpi/ic_assessment_white_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_delete_white_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xxxhdpi/ic_delete_white_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_info_outline_white_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xxxhdpi/ic_info_outline_white_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_info_white_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xxxhdpi/ic_info_white_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_play_circle_filled_black_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xxxhdpi/ic_play_circle_filled_black_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_settings_voice_white_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purrprogramming/voice-pitch-analyzer/ac0c62ea8f08d1c7f58e8b21e5bc45d7527e3099/app/src/main/res/drawable-xxxhdpi/ic_settings_voice_white_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ab_background_textured_example.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/btn_cab_done_example.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/progress_horizontal_example.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 21 | 24 | 25 | 26 | 29 | 30 | 31 | 32 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ripple.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/selectable_background_example.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/spinner_background_ab_example.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/tab_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/tab_indicator.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/tab_text_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_about.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_progress.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_record_view.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_recording.xml: -------------------------------------------------------------------------------- 1 | 9 | 10 | 15 | 16 | 20 | 21 | 28 | 29 | 34 | 35 | 40 | 41 | 42 | 43 | 44 | 48 | 49 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_recording_list.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_progress.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_reading.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_record_graph.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 11 | 12 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_record_view.xml: -------------------------------------------------------------------------------- 1 | 10 | 11 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_recording.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 10 | 11 | 20 | 21 | 22 | 26 | 27 | 34 | 35 |