From ed32891202f65f5d08f136497f1e9df22fd53f44 Mon Sep 17 00:00:00 2001 From: Lukas Ringeisen Date: Fri, 5 Sep 2025 14:42:59 +0200 Subject: [PATCH] =?UTF-8?q?Initial=20commit:=20Android=20App=20f=C3=BCr=20?= =?UTF-8?q?Music=20Separation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitattributes | 1 + .gitignore | 15 + .idea/.gitignore | 3 + .idea/compiler.xml | 6 + .idea/deploymentTargetSelector.xml | 18 + .idea/gradle.xml | 20 + .idea/migrations.xml | 10 + .idea/misc.xml | 10 + .idea/runConfigurations.xml | 17 + app/.gitignore | 1 + app/build.gradle.kts | 55 ++ app/proguard-rules.pro | 21 + .../ExampleInstrumentedTest.java | 26 + app/src/main/AndroidManifest.xml | 38 + .../assets/spleeter_2stems_optimized.tflite | 3 + .../assets/spleeter_4stems_optimized.tflite | 3 + .../assets/spleeter_5stems_optimized.tflite | 3 + .../example/musicseparation/MainActivity.java | 199 +++++ .../musicseparation/SeparationActivity.java | 805 ++++++++++++++++++ .../musicseparation/TFLiteModelProcessor.java | 177 ++++ .../TFLiteModelProcessor2Stems.java | 73 ++ .../TFLiteModelProcessor4Stems.java | 80 ++ .../TFLiteModelProcessor5Stems.java | 74 ++ .../musicseparation/WavDataHolder.java | 29 + .../musicseparation/WavFileLoader.java | 125 +++ .../example/musicseparation/WaveformView.java | 179 ++++ .../res/drawable/ic_launcher_background.xml | 170 ++++ .../res/drawable/ic_launcher_foreground.xml | 30 + app/src/main/res/layout/activity_main.xml | 175 ++++ .../main/res/layout/activity_separation.xml | 11 + .../res/layout/activity_separation_2stems.xml | 31 + .../res/layout/activity_separation_4stems.xml | 36 + .../res/layout/activity_separation_5stems.xml | 39 + .../main/res/layout/waveform_element_0.xml | 52 ++ .../main/res/layout/waveform_element_1.xml | 51 ++ .../main/res/layout/waveform_element_2.xml | 51 ++ .../main/res/layout/waveform_element_3.xml | 51 ++ .../main/res/layout/waveform_element_4.xml | 51 ++ .../main/res/layout/waveform_element_5.xml | 52 ++ app/src/main/res/menu/menu_main.xml | 10 + .../main/res/mipmap-anydpi/ic_launcher.xml | 6 + .../res/mipmap-anydpi/ic_launcher_round.xml | 6 + app/src/main/res/mipmap-hdpi/ic_launcher.webp | Bin 0 -> 1404 bytes .../res/mipmap-hdpi/ic_launcher_round.webp | Bin 0 -> 2898 bytes app/src/main/res/mipmap-mdpi/ic_launcher.webp | Bin 0 -> 982 bytes .../res/mipmap-mdpi/ic_launcher_round.webp | Bin 0 -> 1772 bytes .../main/res/mipmap-xhdpi/ic_launcher.webp | Bin 0 -> 1900 bytes .../res/mipmap-xhdpi/ic_launcher_round.webp | Bin 0 -> 3918 bytes .../main/res/mipmap-xxhdpi/ic_launcher.webp | Bin 0 -> 2884 bytes .../res/mipmap-xxhdpi/ic_launcher_round.webp | Bin 0 -> 5914 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.webp | Bin 0 -> 3844 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.webp | Bin 0 -> 7778 bytes app/src/main/res/navigation/nav_graph.xml | 28 + app/src/main/res/values-land/dimens.xml | 3 + app/src/main/res/values-night/themes.xml | 7 + app/src/main/res/values-v23/themes.xml | 9 + app/src/main/res/values-w1240dp/dimens.xml | 3 + app/src/main/res/values-w600dp/dimens.xml | 3 + app/src/main/res/values/colors.xml | 5 + app/src/main/res/values/dimens.xml | 3 + app/src/main/res/values/strings.xml | 46 + app/src/main/res/values/themes.xml | 9 + app/src/main/res/xml/backup_rules.xml | 13 + .../main/res/xml/data_extraction_rules.xml | 19 + .../musicseparation/ExampleUnitTest.java | 17 + build.gradle.kts | 4 + gradle.properties | 21 + gradle/libs.versions.toml | 24 + gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 59203 bytes gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 185 ++++ gradlew.bat | 89 ++ settings.gradle.kts | 24 + 73 files changed, 3331 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 .idea/.gitignore create mode 100644 .idea/compiler.xml create mode 100644 .idea/deploymentTargetSelector.xml create mode 100644 .idea/gradle.xml create mode 100644 .idea/migrations.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/runConfigurations.xml create mode 100644 app/.gitignore create mode 100644 app/build.gradle.kts create mode 100644 app/proguard-rules.pro create mode 100644 app/src/androidTest/java/com/example/musicseparation/ExampleInstrumentedTest.java create mode 100644 app/src/main/AndroidManifest.xml create mode 100644 app/src/main/assets/spleeter_2stems_optimized.tflite create mode 100644 app/src/main/assets/spleeter_4stems_optimized.tflite create mode 100644 app/src/main/assets/spleeter_5stems_optimized.tflite create mode 100644 app/src/main/java/com/example/musicseparation/MainActivity.java create mode 100644 app/src/main/java/com/example/musicseparation/SeparationActivity.java create mode 100644 app/src/main/java/com/example/musicseparation/TFLiteModelProcessor.java create mode 100644 app/src/main/java/com/example/musicseparation/TFLiteModelProcessor2Stems.java create mode 100644 app/src/main/java/com/example/musicseparation/TFLiteModelProcessor4Stems.java create mode 100644 app/src/main/java/com/example/musicseparation/TFLiteModelProcessor5Stems.java create mode 100644 app/src/main/java/com/example/musicseparation/WavDataHolder.java create mode 100644 app/src/main/java/com/example/musicseparation/WavFileLoader.java create mode 100644 app/src/main/java/com/example/musicseparation/WaveformView.java create mode 100644 app/src/main/res/drawable/ic_launcher_background.xml create mode 100644 app/src/main/res/drawable/ic_launcher_foreground.xml create mode 100644 app/src/main/res/layout/activity_main.xml create mode 100644 app/src/main/res/layout/activity_separation.xml create mode 100644 app/src/main/res/layout/activity_separation_2stems.xml create mode 100644 app/src/main/res/layout/activity_separation_4stems.xml create mode 100644 app/src/main/res/layout/activity_separation_5stems.xml create mode 100644 app/src/main/res/layout/waveform_element_0.xml create mode 100644 app/src/main/res/layout/waveform_element_1.xml create mode 100644 app/src/main/res/layout/waveform_element_2.xml create mode 100644 app/src/main/res/layout/waveform_element_3.xml create mode 100644 app/src/main/res/layout/waveform_element_4.xml create mode 100644 app/src/main/res/layout/waveform_element_5.xml create mode 100644 app/src/main/res/menu/menu_main.xml create mode 100644 app/src/main/res/mipmap-anydpi/ic_launcher.xml create mode 100644 app/src/main/res/mipmap-anydpi/ic_launcher_round.xml create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher.webp create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher_round.webp create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher.webp create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher_round.webp create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher.webp create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher.webp create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp create mode 100644 app/src/main/res/navigation/nav_graph.xml create mode 100644 app/src/main/res/values-land/dimens.xml create mode 100644 app/src/main/res/values-night/themes.xml create mode 100644 app/src/main/res/values-v23/themes.xml create mode 100644 app/src/main/res/values-w1240dp/dimens.xml create mode 100644 app/src/main/res/values-w600dp/dimens.xml create mode 100644 app/src/main/res/values/colors.xml create mode 100644 app/src/main/res/values/dimens.xml create mode 100644 app/src/main/res/values/strings.xml create mode 100644 app/src/main/res/values/themes.xml create mode 100644 app/src/main/res/xml/backup_rules.xml create mode 100644 app/src/main/res/xml/data_extraction_rules.xml create mode 100644 app/src/test/java/com/example/musicseparation/ExampleUnitTest.java create mode 100644 build.gradle.kts create mode 100644 gradle.properties create mode 100644 gradle/libs.versions.toml create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 gradlew create mode 100644 gradlew.bat create mode 100644 settings.gradle.kts diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..45e1443 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +app/src/main/assets/*.tflite filter=lfs diff=lfs merge=lfs -text diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..aa724b7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx +local.properties diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..b86273d --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml new file mode 100644 index 0000000..f081756 --- /dev/null +++ b/.idea/deploymentTargetSelector.xml @@ -0,0 +1,18 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..7b3006b --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,20 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/migrations.xml b/.idea/migrations.xml new file mode 100644 index 0000000..f8051a6 --- /dev/null +++ b/.idea/migrations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..74dd639 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..16660f1 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 0000000..655327c --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,55 @@ +plugins { + alias(libs.plugins.android.application) +} + +android { + namespace = "com.example.musicseparation" + compileSdk = 34 + + defaultConfig { + applicationId = "com.example.musicseparation" + minSdk = 26 + targetSdk = 34 + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + buildFeatures { + viewBinding = true + } +} + +dependencies { + + implementation(libs.appcompat) + implementation(libs.material) + implementation(libs.constraintlayout) + implementation(libs.navigation.fragment) + implementation(libs.navigation.ui) + testImplementation(libs.junit) + androidTestImplementation(libs.ext.junit) + androidTestImplementation(libs.espresso.core) + + implementation("org.tensorflow:tensorflow-lite:2.15.0") + implementation("org.tensorflow:tensorflow-lite-select-tf-ops:2.15.0") + + + implementation("org.tensorflow:tensorflow-lite-support:0.4.0") + implementation("org.tensorflow:tensorflow-lite-metadata:0.4.0") + implementation("org.tensorflow:tensorflow-lite-gpu:2.9.0") +} \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/app/src/androidTest/java/com/example/musicseparation/ExampleInstrumentedTest.java b/app/src/androidTest/java/com/example/musicseparation/ExampleInstrumentedTest.java new file mode 100644 index 0000000..2c0ae83 --- /dev/null +++ b/app/src/androidTest/java/com/example/musicseparation/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package com.example.musicseparation; + +import android.content.Context; + +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + assertEquals("com.example.musicseparation", appContext.getPackageName()); + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..8116768 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/assets/spleeter_2stems_optimized.tflite b/app/src/main/assets/spleeter_2stems_optimized.tflite new file mode 100644 index 0000000..c6bdafb --- /dev/null +++ b/app/src/main/assets/spleeter_2stems_optimized.tflite @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c1257ac585934fe392ce9ce1c794eccdfa0e3b31f48743e38304fcc39bd25858 +size 39444808 diff --git a/app/src/main/assets/spleeter_4stems_optimized.tflite b/app/src/main/assets/spleeter_4stems_optimized.tflite new file mode 100644 index 0000000..13a6ae9 --- /dev/null +++ b/app/src/main/assets/spleeter_4stems_optimized.tflite @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ecb22e7a5fa421eed83f3c9b36865ec3fb462884a3e3d134127e06fae8a91ce9 +size 78854592 diff --git a/app/src/main/assets/spleeter_5stems_optimized.tflite b/app/src/main/assets/spleeter_5stems_optimized.tflite new file mode 100644 index 0000000..2ece743 --- /dev/null +++ b/app/src/main/assets/spleeter_5stems_optimized.tflite @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3bf1d58abb530bebf3769051ed97a90a6b3e91f11c67b7d2b5a2ac095a3c3333 +size 98561300 diff --git a/app/src/main/java/com/example/musicseparation/MainActivity.java b/app/src/main/java/com/example/musicseparation/MainActivity.java new file mode 100644 index 0000000..b5f5e8b --- /dev/null +++ b/app/src/main/java/com/example/musicseparation/MainActivity.java @@ -0,0 +1,199 @@ +package com.example.musicseparation; + +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.os.Handler; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.RadioGroup; +import android.widget.SeekBar; +import android.widget.TextView; + +import androidx.appcompat.app.AppCompatActivity; + +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts; +import java.io.IOException; + +public class MainActivity extends AppCompatActivity { + + private Button buttonLoadAudio; + private Button buttonStartSeparation; + //private EditText editTextAudioInfo; + private RadioGroup radioGroupStems; + private RadioGroup radioGroupChunks; + + + private WavFileLoader wavFileLoader; + private TextView textViewInfo; + private WaveformView waveformView; + private Uri selectedAudioUri; + private SeekBar seekBar; + private Handler handler = new Handler(); + private WavFileLoader.WavData wavData; + + @Override + protected void onCreate(Bundle savedInstanceState) { + Log.d("MainActivity", "onCreate called"); + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + // Initialisierung der UI-Elemente + buttonLoadAudio = findViewById(R.id.buttonLoadAudio); + buttonStartSeparation = findViewById(R.id.buttonStartSeparation); + //editTextAudioInfo = findViewById(R.id.editTextAudioInfo); + radioGroupStems = findViewById(R.id.radioGroupStems); + radioGroupChunks = findViewById(R.id.radioGroupChunks); + + // Initialisierung des WavFileLoaders + wavFileLoader = new WavFileLoader(); + + // Initialisierung der WaveformView-Elemente + Button buttonPlay1 = findViewById(R.id.buttonPlay); + Button buttonStop1 = findViewById(R.id.buttonStop); + textViewInfo = findViewById(R.id.textViewInfo); + waveformView = findViewById(R.id.waveformOriginal); + seekBar = findViewById(R.id.seekBar); + setupSeekBar(seekBar, waveformView); + + // Registrierung des ActivityResultLauncher + ActivityResultLauncher filePickerLauncher = registerForActivityResult( + new ActivityResultContracts.StartActivityForResult(), + result -> { + Log.d("MainActivity", "ActivityResultLauncher called"); + if (result.getResultCode() == RESULT_OK && result.getData() != null) { + Uri uri = result.getData().getData(); + + try { + getContentResolver().takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION); + + Log.d("MainActivity", "Uri: " + uri); + wavData = wavFileLoader.loadWavFile(this, uri); + //float[] normalizedSamples = normalizeSamples(wavData.audioData); + float[] normalizedSamples = wavData.audioData; + + selectedAudioUri = uri; + waveformView.setAudioUri(uri); + waveformView.setSamples(normalizedSamples); + textViewInfo.setText("Länge: " + wavData.audioData.length + " Samples\nSamplerate: " + wavData.sampleRate + " Hz"); + + + } catch (IOException e) { + textViewInfo.setText("Fehler beim Laden: " + e.getMessage()); + } + } + }); + + buttonLoadAudio.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Log.d("MainActivity", "buttonLoad1 clicked"); + Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); + intent.setType("audio/*"); + intent.addCategory(Intent.CATEGORY_OPENABLE); + filePickerLauncher.launch(intent); + } + }); + + buttonPlay1.setOnClickListener(v -> { + Log.d("MainActivity", "buttonPlay1 clicked"); + if (selectedAudioUri != null) { + waveformView.playAudio(this); + } + }); + + buttonStop1.setOnClickListener(v -> waveformView.stopAudio()); + + + buttonStartSeparation.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Log.d("MainActivity", "Separation Button clicked"); + Intent intent = new Intent(MainActivity.this, SeparationActivity.class); + + // WavData und Stem-Option übergeben + //intent.putExtra("audioData", wavData.audioData); + //intent.putExtra("sampleRate", wavData.sampleRate); + //intent.putExtra("audioUri", selectedAudioUri); + WavDataHolder.setWavData(wavData); + WavDataHolder.setAudioUri(selectedAudioUri); + + if (radioGroupStems.getCheckedRadioButtonId() == R.id.radioButton2Stems) { + intent.putExtra("stemOption", 2); + } else if (radioGroupStems.getCheckedRadioButtonId() == R.id.radioButton4Stems) { + intent.putExtra("stemOption", 4); + } else if (radioGroupStems.getCheckedRadioButtonId() == R.id.radioButton5Stems) { + intent.putExtra("stemOption", 5); + } + + if(radioGroupChunks.getCheckedRadioButtonId() == R.id.radioButton1){ + intent.putExtra("chunkSize", 220500); + }else if(radioGroupChunks.getCheckedRadioButtonId() == R.id.radioButton2){ + intent.putExtra("chunkSize", 441000); + }else if(radioGroupChunks.getCheckedRadioButtonId() == R.id.radioButton3){ + intent.putExtra("chunkSize", 882000); + }else if(radioGroupChunks.getCheckedRadioButtonId() == R.id.radioButton4){ + intent.putExtra("chunkSize", 1764000); + }else if(radioGroupChunks.getCheckedRadioButtonId() == R.id.radioButton5){ + intent.putExtra("chunkSize", 3528000); + } + + // selectedStemOption = (radioGroupStems.getCheckedRadioButtonId() == R.id.radioButton2Stems) ? 2 : 4; + //intent.putExtra("stemOption", selectedStemOption); + + startActivity(intent); + } + }); + } + + @Override + protected void onPause() { + super.onPause(); + waveformView.stopAudio(); + } + + private void setupSeekBar(SeekBar seekBar, WaveformView waveformView) { + seekBar.setMax(1000); + seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { + boolean touching = false; + + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + if (fromUser && waveformView != null && waveformView.isPlaying()) { + int duration = waveformView.getDuration(); + int position = (int) (progress / 1000f * duration); + waveformView.seekTo(position); + } + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + touching = true; + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + touching = false; + } + }); + + Runnable updater = new Runnable() { + @Override + public void run() { + if (waveformView != null && waveformView.isPlaying()) { + int duration = waveformView.getDuration(); + int current = waveformView.getCurrentPosition(); + int progress = (int) (current / (float) duration * 1000); + + seekBar.setProgress(progress); + waveformView.updatePlaybackPosition(current); + } + handler.postDelayed(this, 200); + } + }; + handler.post(updater); + } +} diff --git a/app/src/main/java/com/example/musicseparation/SeparationActivity.java b/app/src/main/java/com/example/musicseparation/SeparationActivity.java new file mode 100644 index 0000000..be07fad --- /dev/null +++ b/app/src/main/java/com/example/musicseparation/SeparationActivity.java @@ -0,0 +1,805 @@ +package com.example.musicseparation; + +import android.Manifest; +import android.content.ContentResolver; +import android.content.ContentValues; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.Environment; +import android.os.Handler; +import android.provider.MediaStore; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.SeekBar; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; + +import com.example.musicseparation.WaveformView; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.RandomAccessFile; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.ArrayList; +import java.util.List; + +import java.text.SimpleDateFormat; +import java.util.Date; + +public class SeparationActivity extends AppCompatActivity { + + private float[] audioData; + private int sampleRate; + private int stemOption; + private int chunkoption; + + private Uri audioUri; + + private TextView textViewProgress; + + private List waveformViews = new ArrayList<>(); + private List