Initial commit: Android App für Music Separation
1
.gitattributes
vendored
Normal file
@ -0,0 +1 @@
|
||||
app/src/main/assets/*.tflite filter=lfs diff=lfs merge=lfs -text
|
15
.gitignore
vendored
Normal file
@ -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
|
3
.idea/.gitignore
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
6
.idea/compiler.xml
generated
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<bytecodeTargetLevel target="21" />
|
||||
</component>
|
||||
</project>
|
18
.idea/deploymentTargetSelector.xml
generated
Normal file
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="deploymentTargetSelector">
|
||||
<selectionStates>
|
||||
<SelectionState runConfigName="app">
|
||||
<option name="selectionMode" value="DROPDOWN" />
|
||||
<DropdownSelection timestamp="2025-05-22T09:38:46.863315900Z">
|
||||
<Target type="DEFAULT_BOOT">
|
||||
<handle>
|
||||
<DeviceId pluginId="LocalEmulator" identifier="path=C:\Users\Lukas\.android\avd\More_Ram_API_35.avd" />
|
||||
</handle>
|
||||
</Target>
|
||||
</DropdownSelection>
|
||||
<DialogSelection />
|
||||
</SelectionState>
|
||||
</selectionStates>
|
||||
</component>
|
||||
</project>
|
20
.idea/gradle.xml
generated
Normal file
@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="GradleMigrationSettings" migrationVersion="1" />
|
||||
<component name="GradleSettings">
|
||||
<option name="linkedExternalProjectsSettings">
|
||||
<GradleProjectSettings>
|
||||
<option name="testRunner" value="CHOOSE_PER_TEST" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
|
||||
<option name="modules">
|
||||
<set>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
<option value="$PROJECT_DIR$/app" />
|
||||
</set>
|
||||
</option>
|
||||
<option name="resolveExternalAnnotations" value="false" />
|
||||
</GradleProjectSettings>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
10
.idea/migrations.xml
generated
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectMigrations">
|
||||
<option name="MigrateToGradleLocalJavaHome">
|
||||
<set>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
</set>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
10
.idea/misc.xml
generated
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
<option name="id" value="Android" />
|
||||
</component>
|
||||
</project>
|
17
.idea/runConfigurations.xml
generated
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RunConfigurationProducerService">
|
||||
<option name="ignoredProducers">
|
||||
<set>
|
||||
<option value="com.intellij.execution.junit.AbstractAllInDirectoryConfigurationProducer" />
|
||||
<option value="com.intellij.execution.junit.AllInPackageConfigurationProducer" />
|
||||
<option value="com.intellij.execution.junit.PatternConfigurationProducer" />
|
||||
<option value="com.intellij.execution.junit.TestInClassConfigurationProducer" />
|
||||
<option value="com.intellij.execution.junit.UniqueIdConfigurationProducer" />
|
||||
<option value="com.intellij.execution.junit.testDiscovery.JUnitTestDiscoveryConfigurationProducer" />
|
||||
<option value="org.jetbrains.kotlin.idea.junit.KotlinJUnitRunConfigurationProducer" />
|
||||
<option value="org.jetbrains.kotlin.idea.junit.KotlinPatternConfigurationProducer" />
|
||||
</set>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
1
app/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/build
|
55
app/build.gradle.kts
Normal file
@ -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")
|
||||
}
|
21
app/proguard-rules.pro
vendored
Normal file
@ -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
|
@ -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 <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
@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());
|
||||
}
|
||||
}
|
38
app/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||
android:fullBackupContent="@xml/backup_rules"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.MusicSeparation"
|
||||
tools:targetApi="31">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:screenOrientation="portrait"
|
||||
android:theme="@style/Theme.MusicSeparation">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name=".SeparationActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:screenOrientation="portrait"/>
|
||||
</application>
|
||||
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
||||
android:maxSdkVersion="28" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
|
||||
android:maxSdkVersion="32" />
|
||||
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
|
||||
|
||||
</manifest>
|
BIN
app/src/main/assets/spleeter_2stems_optimized.tflite
(Stored with Git LFS)
Normal file
BIN
app/src/main/assets/spleeter_4stems_optimized.tflite
(Stored with Git LFS)
Normal file
BIN
app/src/main/assets/spleeter_5stems_optimized.tflite
(Stored with Git LFS)
Normal file
199
app/src/main/java/com/example/musicseparation/MainActivity.java
Normal file
@ -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<Intent> 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);
|
||||
}
|
||||
}
|
@ -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<WaveformView> waveformViews = new ArrayList<>();
|
||||
private List<Button> playButtons = new ArrayList<>();
|
||||
private List<Button> stopButtons = new ArrayList<>();
|
||||
private List<TextView> infoTexts = new ArrayList<>();
|
||||
private List<SeekBar> seekBars = new ArrayList<>();
|
||||
|
||||
private Handler handler = new Handler();
|
||||
|
||||
private String timestamp;
|
||||
|
||||
WavFileLoader wavFileLoader;
|
||||
WavFileLoader.WavData wavData;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
Log.d("SeparationActivity", "onCreate called");
|
||||
super.onCreate(savedInstanceState);
|
||||
//System.out.println("SeparationActivity onCreate() called");
|
||||
|
||||
|
||||
stemOption = getIntent().getIntExtra("stemOption", 2);
|
||||
if (stemOption == 2) {
|
||||
Log.d("SeparationActivity", "onCreate called with stemOption 2");
|
||||
setContentView(R.layout.activity_separation_2stems);
|
||||
} else if (stemOption == 4) {
|
||||
Log.d("SeparationActivity", "onCreate called with stemOption 4");
|
||||
setContentView(R.layout.activity_separation_4stems);
|
||||
} else if (stemOption == 5) {
|
||||
Log.d("SeparationActivity", "onCreate called with stemOption 5");
|
||||
setContentView(R.layout.activity_separation_5stems);
|
||||
}
|
||||
|
||||
// Get Data from MainActivity
|
||||
chunkoption = getIntent().getIntExtra("chunkSize", 882000);
|
||||
|
||||
WavFileLoader.WavData wavData = WavDataHolder.getWavData();
|
||||
if (wavData != null) {
|
||||
audioData = wavData.audioData;
|
||||
sampleRate = wavData.sampleRate;
|
||||
audioUri = WavDataHolder.getAudioUri();
|
||||
// Weiterarbeiten...
|
||||
} else {
|
||||
// Fehlerbehandlung (z.B. Fehlermeldung oder Activity schließen)
|
||||
}
|
||||
|
||||
|
||||
//audioData = getIntent().getFloatArrayExtra("audioData");
|
||||
//sampleRate = getIntent().getIntExtra("sampleRate", 44100);
|
||||
|
||||
// Initialisierung der UI-Elemente
|
||||
textViewProgress = findViewById(R.id.textViewProgress);
|
||||
|
||||
// Jetzt dynamisch alle Sets holen
|
||||
setupWaveformElements();
|
||||
setupButtonListeners();
|
||||
|
||||
|
||||
//TextView infoText = findViewById(R.id.textViewInfo0);
|
||||
//infoTexts.get(0).setText();
|
||||
//WaveformView waveformView = findViewById(R.id.waveformView0);
|
||||
//waveformView.setAudioUri(audioUri);
|
||||
//waveformView.setSamples(audioData);
|
||||
waveformViews.get(0).setSamples(audioData);
|
||||
waveformViews.get(0).setAudioUri(audioUri);
|
||||
|
||||
infoTexts.get(0).setText("Pfad: " + audioUri.toString() + "\nLänge: " + wavData.audioData.length + " Samples\nSamplerate: " + wavData.sampleRate + " Hz");
|
||||
//infoText.setText("Pfad: " + audioUri.toString() + "\nLänge: " + wavData.audioData.length + " Samples\nSamplerate: " + wavData.sampleRate + " Hz");
|
||||
setupSeekBar(seekBars.get(0), waveformViews.get(0));
|
||||
|
||||
|
||||
// Aufrufen der AsyncTask
|
||||
if (stemOption == 2) {
|
||||
new SeparationTask2Stems().execute();
|
||||
} else if (stemOption == 4) {
|
||||
new SeparationTask4Stems().execute();
|
||||
} else if (stemOption == 5) {
|
||||
new SeparationTask5Stems().execute();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
Log.d("SeparationActivity", "onPause called");
|
||||
super.onPause();
|
||||
stopAllAudioPlayback();
|
||||
}
|
||||
|
||||
private void stopAllAudioPlayback() {
|
||||
for (WaveformView view : waveformViews) {
|
||||
if (view != null) {
|
||||
view.stopAudio();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void setupWaveformElements() {
|
||||
Log.d("SeparationActivity", "setupWaveformElements() called");
|
||||
//System.out.println("SeparationActivity.setupWaveformElements() called");
|
||||
int numberOfElements = 1 + stemOption; // 1 Original + X Stems
|
||||
|
||||
for (int i = 0; i < numberOfElements; i++) {
|
||||
// Waveform-Elemente suchen
|
||||
int playButtonId = getResources().getIdentifier("buttonPlay" + i, "id", getPackageName());
|
||||
int stopButtonId = getResources().getIdentifier("buttonStop" + i, "id", getPackageName());
|
||||
int textViewInfoId = getResources().getIdentifier("textViewInfo" + i, "id", getPackageName());
|
||||
int waveformViewId = getResources().getIdentifier("waveformView" + i, "id", getPackageName());
|
||||
int seekBarId = getResources().getIdentifier("seekBar" + i, "id", getPackageName());
|
||||
|
||||
// Falls existieren
|
||||
Button playButton = findViewById(playButtonId);
|
||||
Button stopButton = findViewById(stopButtonId);
|
||||
TextView infoText = findViewById(textViewInfoId);
|
||||
WaveformView waveformView = findViewById(waveformViewId);
|
||||
SeekBar seekBar = findViewById(seekBarId);
|
||||
|
||||
if (playButton != null && stopButton != null && infoText != null && waveformView != null && seekBar != null) {
|
||||
playButtons.add(playButton);
|
||||
stopButtons.add(stopButton);
|
||||
infoTexts.add(infoText);
|
||||
waveformViews.add(waveformView);
|
||||
seekBars.add(seekBar);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void setupButtonListeners() {
|
||||
Log.d("SeparationActivity", "setupButtonListeners() called");
|
||||
//System.out.println("SeparationActivity.setupButtonListeners() called");
|
||||
for (int i = 0; i < playButtons.size(); i++) {
|
||||
final int index = i;
|
||||
playButtons.get(i).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
// Beispiel-Logik
|
||||
System.out.println("Play Button " + index + " gedrückt");
|
||||
waveformViews.get(index).playAudio(SeparationActivity.this);
|
||||
}
|
||||
});
|
||||
|
||||
stopButtons.get(i).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
// Beispiel-Logik
|
||||
System.out.println("Stop Button " + index + " gedrückt");
|
||||
waveformViews.get(index).stopAudio();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void setupSeekBar(SeekBar seekBar, WaveformView waveformView) {
|
||||
Log.d("SeparationActivity", "setupSeekBar() called");
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private class SeparationTask extends AsyncTask<Void, Integer, Void> {
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
//progressBar.setVisibility(View.VISIBLE);
|
||||
textViewProgress.setVisibility(View.VISIBLE);
|
||||
//progressBar.setProgress(0);
|
||||
textViewProgress.setText("Separation startet...");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... voids) {
|
||||
try {
|
||||
Log.d("Debug", "doInBackground called!");
|
||||
TFLiteModelProcessor modelProcessor = new TFLiteModelProcessor(SeparationActivity.this, "spleeter_2stems_optimized.tflite");
|
||||
|
||||
int chunkSize = 882000; // Falls nötig anpassen
|
||||
int overlapSize = chunkSize / 2; // 50% Overlap
|
||||
int stepSize = chunkSize - overlapSize; // Schrittweite für Overlap-Add
|
||||
int numChunks = (int) Math.ceil((double) audioData.length / stepSize);
|
||||
|
||||
Log.d("Debug", "numChunks: " + numChunks + " von " + (audioData.length / stepSize) + ", Audiolänge: " + audioData.length);
|
||||
|
||||
File appDownloadDir = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "SeparatedAudio");
|
||||
if (!appDownloadDir.exists()) {
|
||||
appDownloadDir.mkdirs();
|
||||
}
|
||||
|
||||
//File vocalsFile = new File(appDownloadDir, "vocals.wav");
|
||||
File vocalsFile = new File(appDownloadDir, "vocals.wav");
|
||||
File instrumentalsFile = new File(appDownloadDir, "instrumentals.wav");
|
||||
|
||||
FileOutputStream vocalsStream = new FileOutputStream(vocalsFile);
|
||||
FileOutputStream instrumentalsStream = new FileOutputStream(instrumentalsFile);
|
||||
|
||||
//File vocalsFile = new File(getExternalFilesDir(null), "vocals.wav");
|
||||
//File instrumentalsFile = new File(getExternalFilesDir(null), "instrumentals.wav");
|
||||
|
||||
//FileOutputStream vocalsStream = new FileOutputStream(vocalsFile);
|
||||
//FileOutputStream instrumentalsStream = new FileOutputStream(instrumentalsFile);
|
||||
|
||||
writeEmptyWavHeader(vocalsStream);
|
||||
writeEmptyWavHeader(instrumentalsStream);
|
||||
|
||||
Log.d("Debug", "WAV-Dateien geöffnet");
|
||||
|
||||
// **Letzte gespeicherte Overlap-Daten für die Glättung**
|
||||
float[] prevVocalsOverlap = new float[overlapSize];
|
||||
float[] prevInstrumentalsOverlap = new float[overlapSize];
|
||||
|
||||
for (int chunkIndex = 0; chunkIndex < numChunks; chunkIndex++) {
|
||||
int start = chunkIndex * stepSize;
|
||||
int end = Math.min(start + chunkSize, audioData.length);
|
||||
|
||||
Log.d("Debug", "chunkIndex: " + chunkIndex + " von " + numChunks);
|
||||
Log.d("Debug", "start: " + start + ", end: " + end + ", audiolänge: " + audioData.length);
|
||||
|
||||
// **Chunk mit Overlap vorbereiten**
|
||||
float[][] inputAudio = new float[2][chunkSize];
|
||||
for (int i = start; i < end; i++) {
|
||||
inputAudio[0][i - start] = audioData[i]; // Linker Kanal
|
||||
inputAudio[1][i - start] = audioData[i]; // Rechter Kanal
|
||||
}
|
||||
|
||||
for (int i = end - start; i < chunkSize; i++) {
|
||||
inputAudio[0][i] = 0f;
|
||||
inputAudio[1][i] = 0f;
|
||||
}
|
||||
|
||||
Log.d("AudioSeparation", "inputAudio Length: " + inputAudio[0].length);
|
||||
|
||||
// **Model-Prozessierung**
|
||||
float[][] separatedAudio = modelProcessor.processAudio(inputAudio);
|
||||
float[] chunkVocals = separatedAudio[0];
|
||||
float[] chunkInstrumentals = separatedAudio[1];
|
||||
|
||||
Log.d("AudioSeparation", "ChunkVocals Length: " + chunkVocals.length);
|
||||
Log.d("AudioSeparation", "ChunkInstrumentals Length: " + chunkInstrumentals.length);
|
||||
|
||||
// **Overlap-Add für Übergänge**
|
||||
applyOverlapAdd(prevVocalsOverlap, chunkVocals, overlapSize);
|
||||
applyOverlapAdd(prevInstrumentalsOverlap, chunkInstrumentals, overlapSize);
|
||||
|
||||
// **Direktes Schreiben in WAV**
|
||||
// Statt: writeAudioToStream(vocalsStream, chunkVocals, overlapSize);
|
||||
int writeFrom = (chunkIndex == 0) ? 0 : overlapSize;
|
||||
int validLength = (chunkIndex == numChunks - 1) ? (end - start) : chunkVocals.length;
|
||||
|
||||
writeAudioToStream(vocalsStream, chunkVocals, writeFrom, validLength);
|
||||
writeAudioToStream(instrumentalsStream, chunkInstrumentals, writeFrom, validLength);
|
||||
//writeAudioToStream(vocalsStream, chunkVocals, writeFrom);
|
||||
//writeAudioToStream(instrumentalsStream, chunkInstrumentals, writeFrom);
|
||||
|
||||
//writeAudioToStream(vocalsStream, chunkVocals, overlapSize);
|
||||
//writeAudioToStream(instrumentalsStream, chunkInstrumentals, overlapSize);
|
||||
|
||||
publishProgress((int) ((chunkIndex / (float) numChunks) * 100), chunkIndex, numChunks);
|
||||
}
|
||||
|
||||
updateWavHeader(vocalsFile);
|
||||
updateWavHeader(instrumentalsFile);
|
||||
|
||||
vocalsStream.close();
|
||||
instrumentalsStream.close();
|
||||
modelProcessor.close();
|
||||
|
||||
loadAndDisplayStems(new String[]{"vocals", "instrumentals"});
|
||||
|
||||
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onProgressUpdate(Integer... values) {
|
||||
//progressBar.setProgress(values[0]);
|
||||
textViewProgress.setText("Verarbeite Chunk " + values[1] + " von " + values[2]);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void aVoid) {
|
||||
//progressBar.setVisibility(View.GONE);
|
||||
textViewProgress.setText("Separation abgeschlossen!");
|
||||
}
|
||||
}
|
||||
|
||||
private class SeparationTask2Stems extends AsyncTask<Void, Integer, Void> {
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
textViewProgress.setVisibility(View.VISIBLE);
|
||||
textViewProgress.setText("2-Stem Separation startet...");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... voids) {
|
||||
try {
|
||||
Log.d("SeparationActivity", "SeparationTask2Stems doInBackground called!");
|
||||
TFLiteModelProcessor2Stems modelProcessor = new TFLiteModelProcessor2Stems(SeparationActivity.this, "spleeter_2stems_optimized.tflite");
|
||||
|
||||
int chunkSize = chunkoption;
|
||||
int overlapSize = chunkSize / 2;
|
||||
int stepSize = chunkSize - overlapSize;
|
||||
int numChunks = (int) Math.ceil((double) audioData.length / stepSize);
|
||||
|
||||
timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
|
||||
File dir = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "2stems_" + timestamp);
|
||||
dir.mkdirs();
|
||||
|
||||
//File dir = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "SeparatedAudio_2stems");
|
||||
//dir.mkdirs();
|
||||
|
||||
File[] stemFiles = new File[] {
|
||||
new File(dir, "vocals.wav"),
|
||||
new File(dir, "instrumentals.wav")
|
||||
};
|
||||
|
||||
FileOutputStream[] outputStreams = new FileOutputStream[2];
|
||||
for (int i = 0; i < 2; i++) {
|
||||
outputStreams[i] = new FileOutputStream(stemFiles[i]);
|
||||
writeEmptyWavHeader(outputStreams[i]);
|
||||
}
|
||||
|
||||
float[][] prevOverlap = new float[2][overlapSize];
|
||||
|
||||
for (int chunkIndex = 0; chunkIndex < numChunks; chunkIndex++) {
|
||||
int start = chunkIndex * stepSize;
|
||||
int end = Math.min(start + chunkSize, audioData.length);
|
||||
|
||||
float[][] input = new float[2][chunkSize];
|
||||
for (int i = start; i < end; i++) {
|
||||
input[0][i - start] = audioData[i];
|
||||
input[1][i - start] = audioData[i];
|
||||
}
|
||||
|
||||
Log.d("SeparationActivity", "modelProcessor about to start");
|
||||
float[][] separated = modelProcessor.processAudio(input);
|
||||
/*
|
||||
int writeFrom = (chunkIndex == 0) ? 0 : overlapSize;
|
||||
int validLength = (chunkIndex == numChunks - 1) ? (end - start) : separated[0].length;
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
applyOverlapAdd(prevOverlap[i], separated[i], overlapSize);
|
||||
writeAudioToStream(outputStreams[i], separated[i], writeFrom, validLength);
|
||||
}
|
||||
*/
|
||||
for (int i = 0; i < 2; i++) {
|
||||
applyOverlapAdd(prevOverlap[i], separated[i], overlapSize);
|
||||
int writeFrom = (chunkIndex == 0) ? 0 : overlapSize;
|
||||
int validLength = (chunkIndex == numChunks - 1) ? (end - start) : separated[i].length;
|
||||
writeAudioToStream(outputStreams[i], separated[i], writeFrom, validLength);
|
||||
}
|
||||
|
||||
publishProgress((int) ((chunkIndex / (float) numChunks) * 100), chunkIndex, numChunks);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
outputStreams[i].close();
|
||||
updateWavHeader(stemFiles[i]);
|
||||
}
|
||||
|
||||
modelProcessor.close();
|
||||
|
||||
//loadAndDisplayStems(new String[]{"vocals", "instrumentals"});
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onProgressUpdate(Integer... values) {
|
||||
textViewProgress.setText("Chunk " + values[1] + " von " + values[2]);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void aVoid) {
|
||||
textViewProgress.setText("2-Stem Separation abgeschlossen!");
|
||||
loadAndDisplayStems(new String[]{"vocals", "instrumentals"});
|
||||
}
|
||||
}
|
||||
|
||||
private class SeparationTask4Stems extends AsyncTask<Void, Integer, Void> {
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
textViewProgress.setVisibility(View.VISIBLE);
|
||||
textViewProgress.setText("4-Stem Separation startet...");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... voids) {
|
||||
try {
|
||||
Log.d("SeparationActivity", "SeparationTask4Stems doInBackground called!");
|
||||
TFLiteModelProcessor4Stems modelProcessor = new TFLiteModelProcessor4Stems(SeparationActivity.this, "spleeter_4stems_optimized.tflite");
|
||||
|
||||
int chunkSize = chunkoption;
|
||||
int overlapSize = chunkSize / 2;
|
||||
int stepSize = chunkSize - overlapSize;
|
||||
int numChunks = (int) Math.ceil((double) audioData.length / stepSize);
|
||||
|
||||
timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
|
||||
File dir = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "4stems_" + timestamp);
|
||||
dir.mkdirs();
|
||||
|
||||
//File dir = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "SeparatedAudio_4stems");
|
||||
//dir.mkdirs();
|
||||
|
||||
File[] stemFiles = new File[] {
|
||||
new File(dir, "vocals.wav"),
|
||||
new File(dir, "drums.wav"),
|
||||
new File(dir, "bass.wav"),
|
||||
new File(dir, "other.wav")
|
||||
};
|
||||
|
||||
FileOutputStream[] outputStreams = new FileOutputStream[4];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
outputStreams[i] = new FileOutputStream(stemFiles[i]);
|
||||
writeEmptyWavHeader(outputStreams[i]);
|
||||
}
|
||||
|
||||
float[][] prevOverlap = new float[4][overlapSize];
|
||||
|
||||
for (int chunkIndex = 0; chunkIndex < numChunks; chunkIndex++) {
|
||||
int start = chunkIndex * stepSize;
|
||||
int end = Math.min(start + chunkSize, audioData.length);
|
||||
|
||||
float[][] input = new float[2][chunkSize];
|
||||
for (int i = start; i < end; i++) {
|
||||
input[0][i - start] = audioData[i];
|
||||
input[1][i - start] = audioData[i];
|
||||
}
|
||||
|
||||
Log.d("SeparationActivity", "modelProcessor about to start");
|
||||
float[][] separated = modelProcessor.processAudio(input);
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
applyOverlapAdd(prevOverlap[i], separated[i], overlapSize);
|
||||
int writeFrom = (chunkIndex == 0) ? 0 : overlapSize;
|
||||
int validLength = (chunkIndex == numChunks - 1) ? (end - start) : separated[i].length;
|
||||
writeAudioToStream(outputStreams[i], separated[i], writeFrom, validLength);
|
||||
//writeAudioToStream(outputStreams[i], separated[i], writeFrom);
|
||||
|
||||
//writeAudioToStream(outputStreams[i], separated[i], overlapSize);
|
||||
}
|
||||
|
||||
publishProgress((int) ((chunkIndex / (float) numChunks) * 100), chunkIndex, numChunks);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
outputStreams[i].close();
|
||||
updateWavHeader(stemFiles[i]);
|
||||
}
|
||||
|
||||
modelProcessor.close();
|
||||
|
||||
//loadAndDisplayStems(new String[]{"vocals", "drums", "bass", "other"});
|
||||
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onProgressUpdate(Integer... values) {
|
||||
textViewProgress.setText("Chunk " + values[1] + " von " + values[2]);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void aVoid) {
|
||||
textViewProgress.setText("4-Stem Separation abgeschlossen!");
|
||||
loadAndDisplayStems(new String[]{"vocals", "drums", "bass", "other"});
|
||||
}
|
||||
}
|
||||
|
||||
private class SeparationTask5Stems extends AsyncTask<Void, Integer, Void> {
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
textViewProgress.setVisibility(View.VISIBLE);
|
||||
textViewProgress.setText("5-Stem Separation startet...");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... voids) {
|
||||
try {
|
||||
Log.d("SeparationActivity", "SeparationTask5Stems doInBackground called!");
|
||||
TFLiteModelProcessor5Stems modelProcessor = new TFLiteModelProcessor5Stems(SeparationActivity.this, "spleeter_5stems_optimized.tflite");
|
||||
|
||||
int chunkSize = chunkoption; //882000
|
||||
int overlapSize = chunkSize / 2;
|
||||
int stepSize = chunkSize - overlapSize;
|
||||
int numChunks = (int) Math.ceil((double) audioData.length / stepSize);
|
||||
|
||||
timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
|
||||
File dir = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "5stems_" + timestamp);
|
||||
dir.mkdirs();
|
||||
|
||||
//File dir = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "SeparatedAudio_5stems");
|
||||
//dir.mkdirs();
|
||||
|
||||
File[] stemFiles = new File[] {
|
||||
new File(dir, "vocals.wav"),
|
||||
new File(dir, "piano.wav"),
|
||||
new File(dir, "drums.wav"),
|
||||
new File(dir, "bass.wav"),
|
||||
new File(dir, "other.wav")
|
||||
};
|
||||
|
||||
FileOutputStream[] outputStreams = new FileOutputStream[5];
|
||||
for (int i = 0; i < 5; i++) {
|
||||
outputStreams[i] = new FileOutputStream(stemFiles[i]);
|
||||
writeEmptyWavHeader(outputStreams[i]);
|
||||
}
|
||||
|
||||
float[][] prevOverlap = new float[5][overlapSize];
|
||||
|
||||
for (int chunkIndex = 0; chunkIndex < numChunks; chunkIndex++) {
|
||||
int start = chunkIndex * stepSize;
|
||||
int end = Math.min(start + chunkSize, audioData.length);
|
||||
|
||||
float[][] input = new float[2][chunkSize];
|
||||
for (int i = start; i < end; i++) {
|
||||
input[0][i - start] = audioData[i];
|
||||
input[1][i - start] = audioData[i];
|
||||
}
|
||||
|
||||
Log.d("SeparationActivity", "modelProcessor about to start");
|
||||
float[][] separated = modelProcessor.processAudio(input);
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
applyOverlapAdd(prevOverlap[i], separated[i], overlapSize);
|
||||
|
||||
int writeFrom = (chunkIndex == 0) ? 0 : overlapSize;
|
||||
int validLength = (chunkIndex == numChunks - 1) ? (end - start) : separated[i].length;
|
||||
writeAudioToStream(outputStreams[i], separated[i], writeFrom, validLength);
|
||||
//writeAudioToStream(outputStreams[i], separated[i], writeFrom);
|
||||
|
||||
//writeAudioToStream(outputStreams[i], separated[i], overlapSize);
|
||||
}
|
||||
|
||||
publishProgress((int) ((chunkIndex / (float) numChunks) * 100), chunkIndex, numChunks);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
outputStreams[i].close();
|
||||
updateWavHeader(stemFiles[i]);
|
||||
}
|
||||
|
||||
modelProcessor.close();
|
||||
|
||||
//loadAndDisplayStems(new String[]{"vocals", "piano", "drums", "bass", "other"});
|
||||
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onProgressUpdate(Integer... values) {
|
||||
textViewProgress.setText("Chunk " + values[1] + " von " + values[2]);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void aVoid) {
|
||||
textViewProgress.setText("5-Stem Separation abgeschlossen!");
|
||||
loadAndDisplayStems(new String[]{"vocals", "piano", "drums", "bass", "other"});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void loadAndDisplayStems(String[] stemNames) {
|
||||
Log.d("SeparationActivity", "loadAndDisplayStems called!");
|
||||
File baseDir = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "SeparatedAudio");
|
||||
if (stemOption == 2) {
|
||||
baseDir = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "2stems_" + timestamp);
|
||||
} else if (stemOption == 4) {
|
||||
baseDir = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "4stems_" + timestamp);
|
||||
} else if (stemOption == 5) {
|
||||
baseDir = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "5stems_" + timestamp);
|
||||
}
|
||||
//File baseDir = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "SeparatedAudio");
|
||||
WavFileLoader loader = new WavFileLoader();
|
||||
|
||||
for (int i = 0; i < stemNames.length; i++) {
|
||||
try {
|
||||
File file = new File(baseDir, stemNames[i] + ".wav");
|
||||
Uri uri = Uri.fromFile(file);
|
||||
WavFileLoader.WavData stemData = loader.loadWavFile(this, uri);
|
||||
|
||||
waveformViews.get(i + 1).setSamples(stemData.audioData);
|
||||
waveformViews.get(i + 1).setAudioUri(uri);
|
||||
setupSeekBar(seekBars.get(i + 1), waveformViews.get(i + 1));
|
||||
Log.d("SeparationActivity", "loadAndDisplayStems: stemName: " + stemNames[i] + ", uri: " + uri);
|
||||
|
||||
infoTexts.get(i + 1).setText(
|
||||
stemNames[i]
|
||||
);
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
infoTexts.get(i + 1).setText("Fehler beim Laden von: " + stemNames[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// **Overlap-Add direkt auf den nächsten Chunk anwenden**
|
||||
private void applyOverlapAdd(float[] prevOverlap, float[] currentChunk, int overlapSize) {
|
||||
Log.d("AudioSeparation", "applyOverlapAdd called!");
|
||||
for (int i = 0; i < overlapSize; i++) {
|
||||
float hannWeight = getHannWindowValue(i, overlapSize);
|
||||
float linearWeight = (float) i / overlapSize;
|
||||
|
||||
// **Berechnung der Gesamtgewichtung**
|
||||
float combinedWeight = 0.5f * (hannWeight + linearWeight);
|
||||
|
||||
// **Overlap korrekt verrechnen**
|
||||
currentChunk[i] = (prevOverlap[i] * (1 - combinedWeight) + currentChunk[i] * combinedWeight);
|
||||
}
|
||||
|
||||
// **Speichere den neuen Overlap für den nächsten Chunk**
|
||||
System.arraycopy(currentChunk, currentChunk.length - overlapSize, prevOverlap, 0, overlapSize);
|
||||
}
|
||||
|
||||
// **Hanning-Fenster für sanfte Übergänge**
|
||||
private float getHannWindowValue(int index, int totalSize) {
|
||||
return 0.5f * (1 - (float) Math.cos(2 * Math.PI * (index + 0.5) / (totalSize - 1)));
|
||||
}
|
||||
|
||||
// **Audio mit Overlap direkt in WAV-Datei schreiben**
|
||||
/*
|
||||
private void writeAudioToStream(FileOutputStream stream, float[] audioData, int overlapSize) throws IOException {
|
||||
ByteBuffer buffer = ByteBuffer.allocate((audioData.length - overlapSize) * 2).order(ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
for (int i = overlapSize; i < audioData.length; i++) { // ⚠️ Jetzt ohne doppelten Overlap!
|
||||
short pcmSample = (short) Math.max(Math.min(audioData[i] * 32767, Short.MAX_VALUE), Short.MIN_VALUE);
|
||||
buffer.putShort(pcmSample);
|
||||
}
|
||||
|
||||
stream.write(buffer.array());
|
||||
}
|
||||
*/
|
||||
/*
|
||||
private void writeAudioToStream(FileOutputStream stream, float[] audioData, int startIndex) throws IOException {
|
||||
ByteBuffer buffer = ByteBuffer.allocate((audioData.length - startIndex) * 2).order(ByteOrder.LITTLE_ENDIAN);
|
||||
for (int i = startIndex; i < audioData.length; i++) {
|
||||
short pcmSample = (short) Math.max(Math.min(audioData[i] * 32767, Short.MAX_VALUE), Short.MIN_VALUE);
|
||||
buffer.putShort(pcmSample);
|
||||
}
|
||||
stream.write(buffer.array());
|
||||
}
|
||||
*/
|
||||
|
||||
// Create WaveFiles
|
||||
private void writeAudioToStream(FileOutputStream stream, float[] audioData, int startIndex, int validLength) throws IOException {
|
||||
Log.d("AudioSeparation", "writeAudioToStream called!");
|
||||
if (validLength <= startIndex) {
|
||||
return; // Sicherheits-Exit: nichts zu schreiben
|
||||
}
|
||||
|
||||
ByteBuffer buffer = ByteBuffer.allocate((validLength - startIndex) * 2).order(ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
for (int i = startIndex; i < validLength; i++) {
|
||||
short pcmSample = (short) Math.max(Math.min(audioData[i] * 32767, Short.MAX_VALUE), Short.MIN_VALUE);
|
||||
buffer.putShort(pcmSample);
|
||||
}
|
||||
|
||||
stream.write(buffer.array());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private void writeEmptyWavHeader(FileOutputStream stream) throws IOException {
|
||||
Log.d("AudioSeparation", "writeEmptyWavHeader called!");
|
||||
byte[] header = new byte[44];
|
||||
stream.write(header);
|
||||
}
|
||||
|
||||
private void updateWavHeader(File file) throws IOException {
|
||||
Log.d("AudioSeparation", "updateWavHeader called!");
|
||||
RandomAccessFile raf = new RandomAccessFile(file, "rw");
|
||||
int totalAudioLen = (int) (raf.length() - 44);
|
||||
int totalDataLen = totalAudioLen + 36;
|
||||
//int sampleRate = sampleRate; // 44100 48000
|
||||
int byteRate = sampleRate * 2;
|
||||
|
||||
raf.seek(0);
|
||||
raf.writeBytes("RIFF");
|
||||
raf.writeInt(Integer.reverseBytes(totalDataLen));
|
||||
raf.writeBytes("WAVE");
|
||||
raf.writeBytes("fmt ");
|
||||
raf.writeInt(Integer.reverseBytes(16));
|
||||
raf.writeShort(Short.reverseBytes((short) 1));
|
||||
raf.writeShort(Short.reverseBytes((short) 1));
|
||||
raf.writeInt(Integer.reverseBytes(sampleRate));
|
||||
raf.writeInt(Integer.reverseBytes(byteRate));
|
||||
raf.writeShort(Short.reverseBytes((short) 2));
|
||||
raf.writeShort(Short.reverseBytes((short) 16));
|
||||
raf.writeBytes("data");
|
||||
raf.writeInt(Integer.reverseBytes(totalAudioLen));
|
||||
|
||||
raf.close();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,177 @@
|
||||
package com.example.musicseparation;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.AssetFileDescriptor;
|
||||
import android.util.Log;
|
||||
|
||||
import org.tensorflow.lite.DataType;
|
||||
import org.tensorflow.lite.Interpreter;
|
||||
import org.tensorflow.lite.support.tensorbuffer.TensorBuffer;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.MappedByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class TFLiteModelProcessor {
|
||||
private Interpreter interpreter;
|
||||
|
||||
public TFLiteModelProcessor(Context context, String modelPath) throws IOException {
|
||||
this.interpreter = new Interpreter(loadModelFile(context, modelPath));
|
||||
|
||||
// Hole die Eingabeform des Modells
|
||||
int[] inputShape = interpreter.getInputTensor(0).shape();
|
||||
Log.d("ModelProcessor", "Initial Input Shape: [" + inputShape[0] + "][" + inputShape[1] + "]");
|
||||
|
||||
// Setze dynamische Eingabegröße
|
||||
interpreter.resizeInput(0, new int[]{882000, 2}); // Falls nötig anpassen!
|
||||
interpreter.allocateTensors();
|
||||
|
||||
|
||||
int[] newInputShape = interpreter.getInputTensor(0).shape();
|
||||
Log.d("ModelProcessor", "New Input Shape: [" + newInputShape[0] + "][" + newInputShape[1] + "]");
|
||||
}
|
||||
|
||||
private MappedByteBuffer loadModelFile(Context context, String modelPath) throws IOException {
|
||||
AssetFileDescriptor fileDescriptor = context.getAssets().openFd(modelPath);
|
||||
FileInputStream inputStream = new FileInputStream(fileDescriptor.getFileDescriptor());
|
||||
FileChannel fileChannel = inputStream.getChannel();
|
||||
return fileChannel.map(FileChannel.MapMode.READ_ONLY, fileDescriptor.getStartOffset(), fileDescriptor.getDeclaredLength());
|
||||
}
|
||||
|
||||
public float[][] processAudio(float[][] inputAudio) {
|
||||
Log.d("ModelProcessor", "processAudio called");
|
||||
int numSamples = inputAudio[0].length; // Anzahl der Samples
|
||||
|
||||
// Transponiere inputAudio von [2][1024] zu [1024][2]
|
||||
float[][] transposedInput = new float[inputAudio[0].length][inputAudio.length];
|
||||
for (int i = 0; i < inputAudio.length; i++) {
|
||||
for (int j = 0; j < inputAudio[0].length; j++) {
|
||||
transposedInput[j][i] = inputAudio[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
float[][] vocalsOutput = new float[2][1]; // Ändere die Größe entsprechend
|
||||
float[][] instrumentsOutput = new float[2][1];
|
||||
|
||||
|
||||
int[] Outputtensor1 = interpreter.getOutputTensor(0).shapeSignature();
|
||||
Log.d("ModelProcessor", "Output 1 Shape Signature: [" + Outputtensor1[0] + "][" + Outputtensor1[1] + "]");
|
||||
int[] Outputtensor2 = interpreter.getOutputTensor(1).shapeSignature();
|
||||
Log.d("ModelProcessor", "Output 2 Shape Signature: [" + Outputtensor2[0] + "][" + Outputtensor2[1] + "]");
|
||||
|
||||
int add = 4028;
|
||||
int[] outputShape = interpreter.getOutputTensor(0).shapeSignature();
|
||||
if (outputShape[1] == -1) {
|
||||
outputShape[1] = numSamples + add; // Falls dynamisch, setze erwartete Länge
|
||||
}
|
||||
Log.d("ModelProcessor", "Resized Output Shape: [" + outputShape[0] + "][" + outputShape[1] + "]");
|
||||
|
||||
int[] outputShape2 = interpreter.getOutputTensor(1).shapeSignature();
|
||||
if (outputShape2[1] == -1) {
|
||||
outputShape2[1] = numSamples + add; // Falls dynamisch, setze erwartete Länge
|
||||
}
|
||||
Log.d("ModelProcessor", "Resized Output 2 Shape: [" + outputShape2[0] + "][" + outputShape2[1] + "]");
|
||||
|
||||
TensorBuffer vocalsBuffer = TensorBuffer.createFixedSize(outputShape, DataType.FLOAT32);
|
||||
TensorBuffer instrumentalsBuffer = TensorBuffer.createFixedSize(outputShape2, DataType.FLOAT32);
|
||||
|
||||
Object[] inputArray = {transposedInput};
|
||||
Map<Integer, Object> outputMap = new HashMap<>();
|
||||
outputMap.put(0, vocalsBuffer.getBuffer());
|
||||
outputMap.put(1, instrumentalsBuffer.getBuffer());
|
||||
//Log.d("ModelProcessor", "outputArrays created");
|
||||
|
||||
|
||||
int[] newInputShape = interpreter.getInputTensor(0).shape();
|
||||
Log.d("ModelProcessor", "Input Shape: [" + newInputShape[0] + "][" + newInputShape[1] + "]");
|
||||
//Log.d("ModelProcessor", "Input Audio: [" + inputAudio.length + "][" + inputAudio[0].length + "]");
|
||||
|
||||
|
||||
// Logge die neue Form nach der Transposition
|
||||
Log.d("ModelProcessor", "Transposed Input Shape: [" + transposedInput.length + "][" + transposedInput[0].length + "]");
|
||||
|
||||
|
||||
|
||||
int count = interpreter.getOutputTensorCount();
|
||||
Log.d("ModelProcessor", "Output Tensor Count: " + count);
|
||||
int[] OutputShape = interpreter.getOutputTensor(0).shape();
|
||||
Log.d("ModelProcessor", "Output 1 Shape: [" + OutputShape[0] + "][" + OutputShape[1] + "]");
|
||||
int[] OutputShape2 = interpreter.getOutputTensor(1).shape();
|
||||
Log.d("ModelProcessor", "Output 2 Shape: [" + OutputShape2[0] + "][" + OutputShape2[1] + "]");
|
||||
Outputtensor1 = interpreter.getOutputTensor(0).shapeSignature();
|
||||
Log.d("ModelProcessor", "Output 1 Shape Signature: [" + Outputtensor1[0] + "][" + Outputtensor1[1] + "]");
|
||||
Outputtensor2 = interpreter.getOutputTensor(1).shapeSignature();
|
||||
Log.d("ModelProcessor", "Output 2 Shape Signature: [" + Outputtensor2[0] + "][" + Outputtensor2[1] + "]");
|
||||
|
||||
Log.d("TFLite", "Vocals Output Shape: [" + vocalsOutput.length + "][" + vocalsOutput[0].length + "]");
|
||||
Log.d("TFLite", "Instrumentals Output Shape: [" + instrumentsOutput.length + "][" + instrumentsOutput[0].length + "]");
|
||||
|
||||
|
||||
// Modell ausführen
|
||||
//interpreter.run(transposedInput, outputBuffer);
|
||||
interpreter.runForMultipleInputsOutputs(inputArray, outputMap);
|
||||
Log.d("ModelProcessor", "Interpreter run completed");
|
||||
|
||||
Log.d("ModelProcessor", "Vocals Output Shape: [" + vocalsOutput.length + "][" + vocalsOutput[0].length + "]");
|
||||
Log.d("ModelProcessor", "Instrumentals Output Shape: [" + instrumentsOutput.length + "][" + instrumentsOutput[0].length + "]");
|
||||
|
||||
Log.d("ModelProcessor", "Actual Output Shape: [" + vocalsBuffer.getShape()[0] + "][" + vocalsBuffer.getShape()[1] + "]");
|
||||
|
||||
// Konvertiere TensorBuffer zurück zu float[]
|
||||
float[] chunkVocals = vocalsBuffer.getFloatArray();
|
||||
float[] chunkInstrumentals = instrumentalsBuffer.getFloatArray();
|
||||
|
||||
Log.d("ModelProcessor", "chunkVocals Shape: [" + chunkVocals.length + "]");
|
||||
Log.d("ModelProcessor", "chunkInstrumentals Shape: [" + chunkInstrumentals.length + "]");
|
||||
|
||||
int numChannels = vocalsBuffer.getShape()[0]; // = 2
|
||||
int numSamples_vocals = vocalsBuffer.getShape()[1]; // = 4096
|
||||
|
||||
float[][] separatedVocals = new float[numChannels][numSamples_vocals - add];
|
||||
|
||||
for (int i = 0; i < numSamples_vocals - add; i++) {
|
||||
separatedVocals[0][i] = chunkVocals[i]; // Linker Kanal
|
||||
separatedVocals[1][i] = chunkVocals[i + numSamples_vocals]; // Rechter Kanal
|
||||
}
|
||||
|
||||
float[][] separatedInstrumentals = new float[numChannels][numSamples_vocals - add];
|
||||
|
||||
for (int i = 0; i < numSamples_vocals - add; i++) {
|
||||
separatedInstrumentals[0][i] = chunkInstrumentals[i]; // Linker Kanal
|
||||
separatedInstrumentals[1][i] = chunkInstrumentals[i + numSamples_vocals]; // Rechter Kanal
|
||||
}
|
||||
|
||||
// Debugging
|
||||
Log.d("ModelProcessor", "Separated Vocals Shape: [" + separatedVocals.length + "][" + separatedVocals[0].length + "]");
|
||||
|
||||
|
||||
|
||||
//interpreter.getOutputTensor(0).
|
||||
//TensorBuffer outputBuffer = TensorBuffer.createFixedSize(interpreter.getOutputTensor(0).shapeSignature(), interpreter.getOutputTensor(0).dataType());
|
||||
|
||||
// Gib beide Tensoren als separate Arrays zurück
|
||||
//return new float[][] { chunkVocals, chunkInstrumentals };
|
||||
return new float[][] { flattenArray(separatedVocals), flattenArray(separatedInstrumentals) };
|
||||
}
|
||||
|
||||
private float[] flattenArray(float[][] array) {
|
||||
float[] flattened = new float[array[0].length];
|
||||
for (int i = 0; i < array[0].length; i++) {
|
||||
flattened[i] = array[0][i]; // Extrahiere das erste Element jeder Zeile
|
||||
}
|
||||
return flattened;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public void close() {
|
||||
interpreter.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,73 @@
|
||||
package com.example.musicseparation;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.AssetFileDescriptor;
|
||||
import android.util.Log;
|
||||
|
||||
import org.tensorflow.lite.Interpreter;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.MappedByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class TFLiteModelProcessor2Stems {
|
||||
private final Interpreter interpreter;
|
||||
|
||||
public TFLiteModelProcessor2Stems(Context context, String modelPath) throws IOException {
|
||||
this.interpreter = new Interpreter(loadModelFile(context, modelPath));
|
||||
interpreter.allocateTensors();
|
||||
}
|
||||
|
||||
private MappedByteBuffer loadModelFile(Context context, String modelPath) throws IOException {
|
||||
AssetFileDescriptor fileDescriptor = context.getAssets().openFd(modelPath);
|
||||
FileInputStream inputStream = new FileInputStream(fileDescriptor.getFileDescriptor());
|
||||
FileChannel fileChannel = inputStream.getChannel();
|
||||
return fileChannel.map(FileChannel.MapMode.READ_ONLY,
|
||||
fileDescriptor.getStartOffset(),
|
||||
fileDescriptor.getDeclaredLength());
|
||||
}
|
||||
|
||||
public float[][] processAudio(float[][] stereoInput) {
|
||||
Log.d("TFLiteModelProcessor2Stems", "processAudio called!");
|
||||
int numSamples = stereoInput[0].length;
|
||||
float[][] input = new float[numSamples][2];
|
||||
|
||||
for (int i = 0; i < numSamples; i++) {
|
||||
input[i][0] = stereoInput[0][i];
|
||||
input[i][1] = stereoInput[1][i];
|
||||
}
|
||||
|
||||
int add = 0;
|
||||
if (numSamples == 220500) add = 3756;
|
||||
else if (numSamples == 441000) add = 3416;
|
||||
else if (numSamples == 882000) add = 3760;
|
||||
else if (numSamples == 1764000) add = 3424;
|
||||
else if (numSamples == 3528000) add = 3776;
|
||||
|
||||
float[][][] outputs = new float[2][2][numSamples + add];
|
||||
Map<Integer, Object> outputMap = new HashMap<>();
|
||||
for (int i = 0; i < 2; i++) {
|
||||
outputMap.put(i, outputs[i]);
|
||||
}
|
||||
|
||||
Log.d("TFLiteModelProcessor2Stems", "Model about to run");
|
||||
interpreter.runForMultipleInputsOutputs(new Object[]{input}, outputMap);
|
||||
Log.d("TFLiteModelProcessor2Stems", "Model finished running");
|
||||
|
||||
float[][] separated = new float[2][numSamples];
|
||||
for (int stem = 0; stem < 2; stem++) {
|
||||
for (int i = 0; i < numSamples; i++) {
|
||||
separated[stem][i] = (outputs[stem][0][i] + outputs[stem][1][i]) / 2f;
|
||||
}
|
||||
}
|
||||
return separated;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
interpreter.close();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,80 @@
|
||||
package com.example.musicseparation;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.AssetFileDescriptor;
|
||||
import android.util.Log;
|
||||
|
||||
import org.tensorflow.lite.Interpreter;
|
||||
import org.tensorflow.lite.support.tensorbuffer.TensorBuffer;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.MappedByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class TFLiteModelProcessor4Stems {
|
||||
private final Interpreter interpreter;
|
||||
|
||||
public TFLiteModelProcessor4Stems(Context context, String modelPath) throws IOException {
|
||||
this.interpreter = new Interpreter(loadModelFile(context, modelPath));
|
||||
|
||||
int[] inputShape = interpreter.getInputTensor(0).shape();
|
||||
Log.d("ModelProcessor", "Initial Input Shape: [" + inputShape[0] + "][" + inputShape[1] + "]");
|
||||
//interpreter.resizeInput(0, new int[]{882000, 2}); // Falls nötig anpassen!
|
||||
|
||||
interpreter.allocateTensors();
|
||||
}
|
||||
|
||||
private MappedByteBuffer loadModelFile(Context context, String modelPath) throws IOException {
|
||||
AssetFileDescriptor fileDescriptor = context.getAssets().openFd(modelPath);
|
||||
FileInputStream inputStream = new FileInputStream(fileDescriptor.getFileDescriptor());
|
||||
FileChannel fileChannel = inputStream.getChannel();
|
||||
return fileChannel.map(FileChannel.MapMode.READ_ONLY,
|
||||
fileDescriptor.getStartOffset(),
|
||||
fileDescriptor.getDeclaredLength());
|
||||
}
|
||||
|
||||
public float[][] processAudio(float[][] stereoInput) {
|
||||
Log.d("TFLiteModelProcessor4Stems", "processAudio called!");
|
||||
int numSamples = stereoInput[0].length;
|
||||
float[][] input = new float[numSamples][2]; // [samples][channels]
|
||||
|
||||
for (int i = 0; i < numSamples; i++) {
|
||||
input[i][0] = stereoInput[0][i];
|
||||
input[i][1] = stereoInput[1][i];
|
||||
}
|
||||
|
||||
int add = 0;
|
||||
if (numSamples == 220500) add = 3756;
|
||||
else if (numSamples == 441000) add = 3416;
|
||||
else if (numSamples == 882000) add = 3760;
|
||||
else if (numSamples == 1764000) add = 3424;
|
||||
else if (numSamples == 3528000) add = 3776;
|
||||
|
||||
float[][][] outputs = new float[4][2][numSamples + add];
|
||||
Map<Integer, Object> outputMap = new HashMap<>();
|
||||
for (int i = 0; i < 4; i++) {
|
||||
outputMap.put(i, outputs[i]);
|
||||
}
|
||||
|
||||
Log.d("TFLiteModelProcessor4Stems", "Model about to run");
|
||||
interpreter.runForMultipleInputsOutputs(new Object[]{input}, outputMap);
|
||||
Log.d("TFLiteModelProcessor4Stems", "Model finished running");
|
||||
|
||||
float[][] separated = new float[4][numSamples];
|
||||
for (int stem = 0; stem < 4; stem++) {
|
||||
for (int i = 0; i < numSamples; i++) {
|
||||
// Mono-Mix
|
||||
separated[stem][i] = (outputs[stem][0][i] + outputs[stem][1][i]) / 2f;
|
||||
}
|
||||
}
|
||||
return separated;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
interpreter.close();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,74 @@
|
||||
package com.example.musicseparation;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.AssetFileDescriptor;
|
||||
import android.util.Log;
|
||||
|
||||
import org.tensorflow.lite.Interpreter;
|
||||
import org.tensorflow.lite.support.tensorbuffer.TensorBuffer;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.MappedByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class TFLiteModelProcessor5Stems {
|
||||
private final Interpreter interpreter;
|
||||
|
||||
public TFLiteModelProcessor5Stems(Context context, String modelPath) throws IOException {
|
||||
this.interpreter = new Interpreter(loadModelFile(context, modelPath));
|
||||
interpreter.allocateTensors();
|
||||
}
|
||||
|
||||
private MappedByteBuffer loadModelFile(Context context, String modelPath) throws IOException {
|
||||
AssetFileDescriptor fileDescriptor = context.getAssets().openFd(modelPath);
|
||||
FileInputStream inputStream = new FileInputStream(fileDescriptor.getFileDescriptor());
|
||||
FileChannel fileChannel = inputStream.getChannel();
|
||||
return fileChannel.map(FileChannel.MapMode.READ_ONLY,
|
||||
fileDescriptor.getStartOffset(),
|
||||
fileDescriptor.getDeclaredLength());
|
||||
}
|
||||
|
||||
public float[][] processAudio(float[][] stereoInput) {
|
||||
Log.d("TFLiteModelProcessor5Stems", "processAudio called!");
|
||||
int numSamples = stereoInput[0].length;
|
||||
float[][] input = new float[numSamples][2]; // [samples][channels]
|
||||
|
||||
for (int i = 0; i < numSamples; i++) {
|
||||
input[i][0] = stereoInput[0][i];
|
||||
input[i][1] = stereoInput[1][i];
|
||||
}
|
||||
|
||||
int add = 0;
|
||||
if (numSamples == 220500) add = 3756;
|
||||
else if (numSamples == 441000) add = 3416;
|
||||
else if (numSamples == 882000) add = 3760;
|
||||
else if (numSamples == 1764000) add = 3424;
|
||||
else if (numSamples == 3528000) add = 3776;
|
||||
|
||||
float[][][] outputs = new float[5][2][numSamples + add];
|
||||
Map<Integer, Object> outputMap = new HashMap<>();
|
||||
for (int i = 0; i < 5; i++) {
|
||||
outputMap.put(i, outputs[i]);
|
||||
}
|
||||
|
||||
Log.d("TFLiteModelProcessor5Stems", "Model about to run");
|
||||
interpreter.runForMultipleInputsOutputs(new Object[]{input}, outputMap);
|
||||
Log.d("TFLiteModelProcessor5Stems", "Model finished running");
|
||||
|
||||
float[][] separated = new float[5][numSamples];
|
||||
for (int stem = 0; stem < 5; stem++) {
|
||||
for (int i = 0; i < numSamples; i++) {
|
||||
separated[stem][i] = (outputs[stem][0][i] + outputs[stem][1][i]) / 2f;
|
||||
}
|
||||
}
|
||||
return separated;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
interpreter.close();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,29 @@
|
||||
package com.example.musicseparation;
|
||||
|
||||
import android.net.Uri;
|
||||
|
||||
public class WavDataHolder {
|
||||
private static WavFileLoader.WavData wavData;
|
||||
private static Uri audioUri;
|
||||
|
||||
public static void setWavData(WavFileLoader.WavData data) {
|
||||
wavData = data;
|
||||
}
|
||||
|
||||
public static WavFileLoader.WavData getWavData() {
|
||||
return wavData;
|
||||
}
|
||||
public static void setAudioUri(Uri uri) {
|
||||
audioUri = uri;
|
||||
}
|
||||
|
||||
public static Uri getAudioUri() {
|
||||
return audioUri;
|
||||
}
|
||||
|
||||
public static void clear() {
|
||||
wavData = null;
|
||||
audioUri = null;
|
||||
}
|
||||
}
|
||||
|
125
app/src/main/java/com/example/musicseparation/WavFileLoader.java
Normal file
@ -0,0 +1,125 @@
|
||||
// WavFileLoader.java
|
||||
package com.example.musicseparation;
|
||||
|
||||
import static java.nio.ByteOrder.BIG_ENDIAN;
|
||||
import static java.nio.ByteOrder.LITTLE_ENDIAN;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.ArrayList;
|
||||
|
||||
|
||||
public class WavFileLoader {
|
||||
public static class WavData {
|
||||
//public short[] audioData;
|
||||
public float[] audioData;
|
||||
public int sampleRate;
|
||||
}
|
||||
|
||||
public WavData loadWavFile(Context context, Uri uri) throws IOException {
|
||||
Log.d("WavFileLoader", "loadWavFile called");
|
||||
InputStream inputStream = context.getContentResolver().openInputStream(uri);
|
||||
|
||||
//AssetManager assetManager = getAssets();
|
||||
//AssetManager assetManager = context.getAssets();
|
||||
//InputStream inputStream = assetManager.open("uri");
|
||||
DataInputStream dis = new DataInputStream(new BufferedInputStream(inputStream));
|
||||
|
||||
// **Lese die ersten 12 Bytes (RIFF-Header)**
|
||||
byte[] riffHeader = new byte[12];
|
||||
dis.readFully(riffHeader);
|
||||
|
||||
if (!new String(riffHeader, 0, 4).equals("RIFF") || !new String(riffHeader, 8, 4).equals("WAVE")) {
|
||||
throw new IOException("Ungültiges WAV-Format (kein RIFF/WAVE Header gefunden)");
|
||||
}
|
||||
|
||||
// **Suche den "data"-Chunk**
|
||||
int sampleRate = 0, bitsPerSample = 0, numChannels = 0, dataSize = 0;
|
||||
while (dis.available() > 0) {
|
||||
byte[] chunkHeader = new byte[8];
|
||||
dis.readFully(chunkHeader);
|
||||
String chunkName = new String(chunkHeader, 0, 4);
|
||||
int chunkSize = ByteBuffer.wrap(chunkHeader, 4, 4).order(ByteOrder.LITTLE_ENDIAN).getInt();
|
||||
|
||||
if (chunkName.equals("fmt ")) {
|
||||
byte[] fmtChunk = new byte[chunkSize];
|
||||
dis.readFully(fmtChunk);
|
||||
|
||||
ByteBuffer fmtBuffer = ByteBuffer.wrap(fmtChunk).order(ByteOrder.LITTLE_ENDIAN);
|
||||
fmtBuffer.position(0);
|
||||
int audioFormat = fmtBuffer.getShort(); // 1 = PCM
|
||||
numChannels = fmtBuffer.getShort(); // **WICHTIG**
|
||||
sampleRate = fmtBuffer.getInt();
|
||||
fmtBuffer.getInt(); // ByteRate (ignorieren)
|
||||
fmtBuffer.getShort(); // BlockAlign (ignorieren)
|
||||
bitsPerSample = fmtBuffer.getShort();
|
||||
} else if (chunkName.equals("data")) {
|
||||
dataSize = chunkSize;
|
||||
break; // Wir haben den Daten-Chunk gefunden!
|
||||
} else {
|
||||
dis.skipBytes(chunkSize);
|
||||
}
|
||||
}
|
||||
|
||||
Log.d("WavFileLoader", "number of channels: " + numChannels);
|
||||
|
||||
if (dataSize == 0) {
|
||||
throw new IOException("Kein 'data' Chunk in WAV-Datei gefunden!");
|
||||
}
|
||||
|
||||
// **❌ FALSCHE Sample-Berechnung**
|
||||
// int numSamples = dataSize / (bitsPerSample / 8);
|
||||
|
||||
// **✅ KORREKTE Sample-Berechnung (Stereo wird berücksichtigt!)**
|
||||
int numSamples = (dataSize / (bitsPerSample / 8)) / numChannels;
|
||||
|
||||
float[] samples = new float[numSamples];
|
||||
|
||||
// **Lese die PCM-Daten**
|
||||
byte[] audioData = new byte[dataSize];
|
||||
dis.readFully(audioData);
|
||||
dis.close();
|
||||
|
||||
ByteBuffer byteBuffer = ByteBuffer.wrap(audioData).order(ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
// **Stereo auf Mono reduzieren**
|
||||
if (numChannels > 1) {
|
||||
for (int i = 0; i < numSamples; i++) {
|
||||
float left = byteBuffer.getShort() / 32768.0f;
|
||||
float right = byteBuffer.getShort() / 32768.0f;
|
||||
samples[i] = (left + right) / 2; // Durchschnitt von L+R für Mono
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < numSamples; i++) {
|
||||
samples[i] = byteBuffer.getShort() / 32768.0f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// **Debug-Log zur Überprüfung**
|
||||
System.out.println("Sample-Rate: " + sampleRate);
|
||||
System.out.println("Kanäle: " + numChannels);
|
||||
System.out.println("Bits per Sample: " + bitsPerSample);
|
||||
System.out.println("Daten-Größe: " + dataSize);
|
||||
System.out.println("Berechnete Samples: " + numSamples);
|
||||
System.out.println("Berechnete Dauer (s): " + (numSamples / (float) sampleRate));
|
||||
|
||||
WavData wavData = new WavData();
|
||||
//wavData.audioData = float32ToInt16(samples);
|
||||
wavData.audioData = samples;;
|
||||
//wavData.audioData = float32ToInt16(test);
|
||||
wavData.sampleRate = sampleRate;
|
||||
return wavData;
|
||||
}
|
||||
}
|
||||
|
179
app/src/main/java/com/example/musicseparation/WaveformView.java
Normal file
@ -0,0 +1,179 @@
|
||||
// WaveformView.java
|
||||
package com.example.musicseparation;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.media.MediaPlayer;
|
||||
import android.net.Uri;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class WaveformView extends View {
|
||||
private Paint paint = new Paint();
|
||||
private float[] samples; // Downsampled and normalized samples
|
||||
private MediaPlayer mediaPlayer;
|
||||
private Uri audioUri;
|
||||
|
||||
|
||||
private int playbackPositionMs = 0;
|
||||
private final Paint markerPaint = new Paint();
|
||||
|
||||
|
||||
public WaveformView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
public WaveformView(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
paint.setColor(Color.BLUE);
|
||||
paint.setStrokeWidth(2);
|
||||
//paint.setAntiAlias(true); // Glattere Darstellung
|
||||
|
||||
markerPaint.setColor(Color.RED);
|
||||
markerPaint.setStrokeWidth(3);
|
||||
markerPaint.setAntiAlias(true);
|
||||
|
||||
mediaPlayer = new MediaPlayer();
|
||||
}
|
||||
|
||||
public void updatePlaybackPosition(int positionMs) {
|
||||
this.playbackPositionMs = positionMs;
|
||||
invalidate(); // Neu zeichnen, um Marker zu zeigen
|
||||
}
|
||||
|
||||
|
||||
public void setAudioUri(Uri uri) {
|
||||
this.audioUri = uri;
|
||||
}
|
||||
|
||||
public void playAudio(Context context) {
|
||||
if (audioUri == null) return;
|
||||
try {
|
||||
mediaPlayer.reset();
|
||||
mediaPlayer.setDataSource(context, audioUri);
|
||||
mediaPlayer.prepare();
|
||||
mediaPlayer.start();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void stopAudio() {
|
||||
if (mediaPlayer.isPlaying()) {
|
||||
mediaPlayer.stop();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isPlaying() {
|
||||
return mediaPlayer != null && mediaPlayer.isPlaying();
|
||||
}
|
||||
|
||||
public int getCurrentPosition() {
|
||||
return mediaPlayer != null ? mediaPlayer.getCurrentPosition() : 0;
|
||||
}
|
||||
|
||||
public int getDuration() {
|
||||
return mediaPlayer != null ? mediaPlayer.getDuration() : 1; // 1 zur Sicherheit gegen Division durch 0
|
||||
}
|
||||
|
||||
public void seekTo(int positionMs) {
|
||||
if (mediaPlayer != null) {
|
||||
mediaPlayer.seekTo(positionMs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Übergibt rohe Audiodaten (z. B. PCM float-Werte) und berechnet daraus
|
||||
* eine vereinfachte Darstellung für die Breite des Views.
|
||||
*/
|
||||
public void setSamples(float[] rawSamples) {
|
||||
int viewWidth = getWidth();
|
||||
if (viewWidth == 0) viewWidth = 1000; // Fallback für nicht gemessenen View
|
||||
|
||||
float[] downsampled = new float[viewWidth];
|
||||
int samplesPerPixel = rawSamples.length / viewWidth;
|
||||
samplesPerPixel = Math.max(1, samplesPerPixel);
|
||||
|
||||
for (int i = 0; i < viewWidth; i++) {
|
||||
float sum = 0f;
|
||||
int count = 0;
|
||||
for (int j = 0; j < samplesPerPixel; j++) {
|
||||
int index = i * samplesPerPixel + j;
|
||||
if (index < rawSamples.length) {
|
||||
sum += Math.abs(rawSamples[index]);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
downsampled[i] = (count > 0) ? (sum / count) : 0f; // Durchschnitt der Absolutwerte
|
||||
}
|
||||
|
||||
this.samples = downsampled;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
if (samples == null || samples.length == 0) return;
|
||||
|
||||
int width = getWidth();
|
||||
int height = getHeight();
|
||||
int centerY = height / 2;
|
||||
|
||||
for (int i = 0; i < samples.length && i < width; i++) {
|
||||
float sampleValue = samples[i] * centerY;
|
||||
canvas.drawLine(i, centerY - sampleValue, i, centerY + sampleValue, paint);
|
||||
}
|
||||
|
||||
if (mediaPlayer != null && mediaPlayer.getDuration() > 0) {
|
||||
float progress = playbackPositionMs / (float) mediaPlayer.getDuration();
|
||||
int markerX = (int) (progress * getWidth());
|
||||
canvas.drawLine(markerX, 0, markerX, getHeight(), markerPaint);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
if (samples == null || samples.length == 0) return;
|
||||
|
||||
int width = getWidth();
|
||||
int height = getHeight();
|
||||
int centerY = height / 2;
|
||||
|
||||
Path path = new Path();
|
||||
|
||||
// Startpunkt der Linie
|
||||
path.moveTo(0, centerY - samples[0] * centerY);
|
||||
|
||||
// Linie durch alle Samples
|
||||
for (int i = 1; i < samples.length && i < width; i++) {
|
||||
float x = i;
|
||||
float y = centerY - samples[i] * centerY;
|
||||
path.lineTo(x, y);
|
||||
}
|
||||
|
||||
canvas.drawPath(path, paint);
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
|
170
app/src/main/res/drawable/ic_launcher_background.xml
Normal file
@ -0,0 +1,170 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path
|
||||
android:fillColor="#3DDC84"
|
||||
android:pathData="M0,0h108v108h-108z" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M9,0L9,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,0L19,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,0L29,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,0L39,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,0L49,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,0L59,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,0L69,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,0L79,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M89,0L89,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M99,0L99,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,9L108,9"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,19L108,19"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,29L108,29"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,39L108,39"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,49L108,49"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,59L108,59"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,69L108,69"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,79L108,79"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,89L108,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,99L108,99"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,29L89,29"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,39L89,39"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,49L89,49"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,59L89,59"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,69L89,69"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,79L89,79"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,19L29,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,19L39,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,19L49,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,19L59,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,19L69,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,19L79,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
</vector>
|
30
app/src/main/res/drawable/ic_launcher_foreground.xml
Normal file
@ -0,0 +1,30 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:endX="85.84757"
|
||||
android:endY="92.4963"
|
||||
android:startX="42.9492"
|
||||
android:startY="49.59793"
|
||||
android:type="linear">
|
||||
<item
|
||||
android:color="#44000000"
|
||||
android:offset="0.0" />
|
||||
<item
|
||||
android:color="#00000000"
|
||||
android:offset="1.0" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
|
||||
android:strokeWidth="1"
|
||||
android:strokeColor="#00000000" />
|
||||
</vector>
|
175
app/src/main/res/layout/activity_main.xml
Normal file
@ -0,0 +1,175 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="8dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_horizontal">
|
||||
|
||||
<Button
|
||||
android:id="@+id/buttonLoadAudio"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Audio laden" />
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textViewa"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="2 Stems: Vocals and Instrumental \n4 Stems: Vocals, Bass, Drums, Other \n5 Stems: Vocals, Piano, Bass, Drums, Other"
|
||||
android:paddingTop="4dp" />
|
||||
|
||||
<RadioGroup
|
||||
android:id="@+id/radioGroupStems"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_horizontal"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginBottom="0dp">
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/radioButton2Stems"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:checked="true"
|
||||
android:text="2 Stems" />
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/radioButton4Stems"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="4 Stems"
|
||||
android:layout_marginStart="16dp" />
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/radioButton5Stems"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="5 Stems"
|
||||
android:layout_marginStart="16dp" />
|
||||
|
||||
</RadioGroup>
|
||||
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textViewInfo"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Datei 1 Info erscheint hier..."
|
||||
android:paddingTop="0dp" />
|
||||
|
||||
<com.example.musicseparation.WaveformView
|
||||
android:id="@+id/waveformOriginal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="150dp"
|
||||
android:background="#DDDDDD"
|
||||
android:layout_marginBottom="4dp" />
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/seekBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="4dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_horizontal">
|
||||
|
||||
|
||||
<Button
|
||||
android:id="@+id/buttonPlay"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Play 1" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/buttonStop"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Stop 1" />
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textViewb"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="How many Samples should be processed? \n 1: 220500 - 5: 3528000"
|
||||
android:paddingTop="4dp" />
|
||||
|
||||
<RadioGroup
|
||||
android:id="@+id/radioGroupChunks"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_horizontal"
|
||||
android:layout_marginTop="4dp">
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/radioButton1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:checked="true"
|
||||
android:text="1" />
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/radioButton2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="2"
|
||||
android:layout_marginStart="16dp" />
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/radioButton3"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="3"
|
||||
android:layout_marginStart="16dp" />
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/radioButton4"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="4"
|
||||
android:layout_marginStart="16dp" />
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/radioButton5"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="5"
|
||||
android:layout_marginStart="16dp" />
|
||||
|
||||
</RadioGroup>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_horizontal">
|
||||
|
||||
|
||||
<Button
|
||||
android:id="@+id/buttonStartSeparation"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:text="Separation starten" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
11
app/src/main/res/layout/activity_separation.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center">
|
||||
|
||||
<!-- Hier später UI-Elemente hinzufügen -->
|
||||
|
||||
</LinearLayout>
|
31
app/src/main/res/layout/activity_separation_2stems.xml
Normal file
@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textViewProgress"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Separation wird vorbereitet..."
|
||||
android:textSize="18sp"
|
||||
android:paddingBottom="16dp" />
|
||||
|
||||
<!-- Original Audio -->
|
||||
<include layout="@layout/waveform_element_0" />
|
||||
|
||||
<!-- Stem 1 -->
|
||||
<include layout="@layout/waveform_element_1" />
|
||||
|
||||
<!-- Stem 2 -->
|
||||
<include layout="@layout/waveform_element_2" />
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
36
app/src/main/res/layout/activity_separation_4stems.xml
Normal file
@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textViewProgress"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Separation wird vorbereitet..."
|
||||
android:textSize="18sp"
|
||||
android:paddingBottom="16dp" />
|
||||
|
||||
<!-- Original Audio -->
|
||||
<include layout="@layout/waveform_element_0" />
|
||||
|
||||
<!-- Stem 1 -->
|
||||
<include layout="@layout/waveform_element_1" />
|
||||
|
||||
<!-- Stem 2 -->
|
||||
<include layout="@layout/waveform_element_2" />
|
||||
|
||||
<!-- Stem 3 -->
|
||||
<include layout="@layout/waveform_element_3" />
|
||||
|
||||
<!-- Stem 4 -->
|
||||
<include layout="@layout/waveform_element_4" />
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
39
app/src/main/res/layout/activity_separation_5stems.xml
Normal file
@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textViewProgress"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Separation wird vorbereitet..."
|
||||
android:textSize="18sp"
|
||||
android:paddingBottom="16dp" />
|
||||
|
||||
<!-- Original Audio -->
|
||||
<include layout="@layout/waveform_element_0" />
|
||||
|
||||
<!-- Stem 1 -->
|
||||
<include layout="@layout/waveform_element_1" />
|
||||
|
||||
<!-- Stem 2 -->
|
||||
<include layout="@layout/waveform_element_2" />
|
||||
|
||||
<!-- Stem 3 -->
|
||||
<include layout="@layout/waveform_element_3" />
|
||||
|
||||
<!-- Stem 4 -->
|
||||
<include layout="@layout/waveform_element_4" />
|
||||
|
||||
<!-- Stem 5 -->
|
||||
<include layout="@layout/waveform_element_5" />
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
52
app/src/main/res/layout/waveform_element_0.xml
Normal file
@ -0,0 +1,52 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="16dp">
|
||||
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textViewInfo0"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Datei Info 0 erscheint hier..."
|
||||
android:paddingTop="8dp" />
|
||||
|
||||
<com.example.musicseparation.WaveformView
|
||||
android:id="@+id/waveformView0"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="150dp"
|
||||
android:background="#DDDDDD"
|
||||
android:layout_marginTop="8dp" />
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/seekBar0"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_horizontal">
|
||||
|
||||
<Button
|
||||
android:id="@+id/buttonPlay0"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Play" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/buttonStop0"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Stop" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
51
app/src/main/res/layout/waveform_element_1.xml
Normal file
@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="16dp">
|
||||
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textViewInfo1"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Datei Info 1 erscheint hier..."
|
||||
android:paddingTop="8dp" />
|
||||
|
||||
<com.example.musicseparation.WaveformView
|
||||
android:id="@+id/waveformView1"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="150dp"
|
||||
android:background="#DDDDDD"
|
||||
android:layout_marginTop="8dp" />
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/seekBar1"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_horizontal">
|
||||
|
||||
<Button
|
||||
android:id="@+id/buttonPlay1"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Play" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/buttonStop1"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Stop" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
51
app/src/main/res/layout/waveform_element_2.xml
Normal file
@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="16dp">
|
||||
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textViewInfo2"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Datei Info 2 erscheint hier..."
|
||||
android:paddingTop="8dp" />
|
||||
|
||||
<com.example.musicseparation.WaveformView
|
||||
android:id="@+id/waveformView2"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="150dp"
|
||||
android:background="#DDDDDD"
|
||||
android:layout_marginTop="8dp" />
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/seekBar2"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_horizontal">
|
||||
|
||||
<Button
|
||||
android:id="@+id/buttonPlay2"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Play" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/buttonStop2"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Stop" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
51
app/src/main/res/layout/waveform_element_3.xml
Normal file
@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="16dp">
|
||||
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textViewInfo3"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Datei Info 3 erscheint hier..."
|
||||
android:paddingTop="8dp" />
|
||||
|
||||
<com.example.musicseparation.WaveformView
|
||||
android:id="@+id/waveformView3"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="150dp"
|
||||
android:background="#DDDDDD"
|
||||
android:layout_marginTop="8dp" />
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/seekBar3"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_horizontal">
|
||||
|
||||
<Button
|
||||
android:id="@+id/buttonPlay3"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Play" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/buttonStop3"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Stop" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
51
app/src/main/res/layout/waveform_element_4.xml
Normal file
@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="16dp">
|
||||
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textViewInfo4"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Datei Info 4 erscheint hier..."
|
||||
android:paddingTop="8dp" />
|
||||
|
||||
<com.example.musicseparation.WaveformView
|
||||
android:id="@+id/waveformView4"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="150dp"
|
||||
android:background="#DDDDDD"
|
||||
android:layout_marginTop="8dp" />
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/seekBar4"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_horizontal">
|
||||
|
||||
<Button
|
||||
android:id="@+id/buttonPlay4"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Play" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/buttonStop4"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Stop" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
52
app/src/main/res/layout/waveform_element_5.xml
Normal file
@ -0,0 +1,52 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="16dp">
|
||||
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textViewInfo5"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Datei Info 5 erscheint hier..."
|
||||
android:paddingTop="8dp" />
|
||||
|
||||
<com.example.musicseparation.WaveformView
|
||||
android:id="@+id/waveformView5"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="150dp"
|
||||
android:background="#DDDDDD"
|
||||
android:layout_marginTop="8dp" />
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/seekBar5"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_horizontal">
|
||||
|
||||
<Button
|
||||
android:id="@+id/buttonPlay5"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Play" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/buttonStop5"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Stop" />
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
10
app/src/main/res/menu/menu_main.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
tools:context="com.example.musicseparation.MainActivity">
|
||||
<item
|
||||
android:id="@+id/action_settings"
|
||||
android:orderInCategory="100"
|
||||
android:title="@string/action_settings"
|
||||
app:showAsAction="never" />
|
||||
</menu>
|
6
app/src/main/res/mipmap-anydpi/ic_launcher.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
6
app/src/main/res/mipmap-anydpi/ic_launcher_round.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
BIN
app/src/main/res/mipmap-hdpi/ic_launcher.webp
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
app/src/main/res/mipmap-mdpi/ic_launcher.webp
Normal file
After Width: | Height: | Size: 982 B |
BIN
app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
app/src/main/res/mipmap-xhdpi/ic_launcher.webp
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
Normal file
After Width: | Height: | Size: 5.8 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
Normal file
After Width: | Height: | Size: 7.6 KiB |
28
app/src/main/res/navigation/nav_graph.xml
Normal file
@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/nav_graph"
|
||||
app:startDestination="@id/FirstFragment">
|
||||
|
||||
<fragment
|
||||
android:id="@+id/FirstFragment"
|
||||
android:name="com.example.musicseparation.FirstFragment"
|
||||
android:label="@string/first_fragment_label"
|
||||
tools:layout="@layout/fragment_first">
|
||||
|
||||
<action
|
||||
android:id="@+id/action_FirstFragment_to_SecondFragment"
|
||||
app:destination="@id/SecondFragment" />
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/SecondFragment"
|
||||
android:name="com.example.musicseparation.SecondFragment"
|
||||
android:label="@string/second_fragment_label"
|
||||
tools:layout="@layout/fragment_second">
|
||||
|
||||
<action
|
||||
android:id="@+id/action_SecondFragment_to_FirstFragment"
|
||||
app:destination="@id/FirstFragment" />
|
||||
</fragment>
|
||||
</navigation>
|
3
app/src/main/res/values-land/dimens.xml
Normal file
@ -0,0 +1,3 @@
|
||||
<resources>
|
||||
<dimen name="fab_margin">48dp</dimen>
|
||||
</resources>
|
7
app/src/main/res/values-night/themes.xml
Normal file
@ -0,0 +1,7 @@
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<!-- Base application theme. -->
|
||||
<style name="Base.Theme.MusicSeparation" parent="Theme.Material3.DayNight.NoActionBar">
|
||||
<!-- Customize your dark theme here. -->
|
||||
<!-- <item name="colorPrimary">@color/my_dark_primary</item> -->
|
||||
</style>
|
||||
</resources>
|
9
app/src/main/res/values-v23/themes.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<style name="Theme.MusicSeparation" parent="Base.Theme.MusicSeparation">
|
||||
<!-- Transparent system bars for edge-to-edge. -->
|
||||
<item name="android:navigationBarColor">@android:color/transparent</item>
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:windowLightStatusBar">?attr/isLightTheme</item>
|
||||
</style>
|
||||
</resources>
|
3
app/src/main/res/values-w1240dp/dimens.xml
Normal file
@ -0,0 +1,3 @@
|
||||
<resources>
|
||||
<dimen name="fab_margin">200dp</dimen>
|
||||
</resources>
|
3
app/src/main/res/values-w600dp/dimens.xml
Normal file
@ -0,0 +1,3 @@
|
||||
<resources>
|
||||
<dimen name="fab_margin">48dp</dimen>
|
||||
</resources>
|
5
app/src/main/res/values/colors.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="black">#FF000000</color>
|
||||
<color name="white">#FFFFFFFF</color>
|
||||
</resources>
|
3
app/src/main/res/values/dimens.xml
Normal file
@ -0,0 +1,3 @@
|
||||
<resources>
|
||||
<dimen name="fab_margin">16dp</dimen>
|
||||
</resources>
|
46
app/src/main/res/values/strings.xml
Normal file
@ -0,0 +1,46 @@
|
||||
<resources>
|
||||
<string name="app_name">MusicSeparation</string>
|
||||
<string name="action_settings">Settings</string>
|
||||
<!-- Strings used for fragments for navigation -->
|
||||
<string name="first_fragment_label">First Fragment</string>
|
||||
<string name="second_fragment_label">Second Fragment</string>
|
||||
<string name="next">Next</string>
|
||||
<string name="previous">Previous</string>
|
||||
|
||||
<string name="lorem_ipsum">
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam in scelerisque sem. Mauris
|
||||
volutpat, dolor id interdum ullamcorper, risus dolor egestas lectus, sit amet mattis purus
|
||||
dui nec risus. Maecenas non sodales nisi, vel dictum dolor. Class aptent taciti sociosqu ad
|
||||
litora torquent per conubia nostra, per inceptos himenaeos. Suspendisse blandit eleifend
|
||||
diam, vel rutrum tellus vulputate quis. Aliquam eget libero aliquet, imperdiet nisl a,
|
||||
ornare ex. Sed rhoncus est ut libero porta lobortis. Fusce in dictum tellus.\n\n
|
||||
Suspendisse interdum ornare ante. Aliquam nec cursus lorem. Morbi id magna felis. Vivamus
|
||||
egestas, est a condimentum egestas, turpis nisl iaculis ipsum, in dictum tellus dolor sed
|
||||
neque. Morbi tellus erat, dapibus ut sem a, iaculis tincidunt dui. Interdum et malesuada
|
||||
fames ac ante ipsum primis in faucibus. Curabitur et eros porttitor, ultricies urna vitae,
|
||||
molestie nibh. Phasellus at commodo eros, non aliquet metus. Sed maximus nisl nec dolor
|
||||
bibendum, vel congue leo egestas.\n\n
|
||||
Sed interdum tortor nibh, in sagittis risus mollis quis. Curabitur mi odio, condimentum sit
|
||||
amet auctor at, mollis non turpis. Nullam pretium libero vestibulum, finibus orci vel,
|
||||
molestie quam. Fusce blandit tincidunt nulla, quis sollicitudin libero facilisis et. Integer
|
||||
interdum nunc ligula, et fermentum metus hendrerit id. Vestibulum lectus felis, dictum at
|
||||
lacinia sit amet, tristique id quam. Cras eu consequat dui. Suspendisse sodales nunc ligula,
|
||||
in lobortis sem porta sed. Integer id ultrices magna, in luctus elit. Sed a pellentesque
|
||||
est.\n\n
|
||||
Aenean nunc velit, lacinia sed dolor sed, ultrices viverra nulla. Etiam a venenatis nibh.
|
||||
Morbi laoreet, tortor sed facilisis varius, nibh orci rhoncus nulla, id elementum leo dui
|
||||
non lorem. Nam mollis ipsum quis auctor varius. Quisque elementum eu libero sed commodo. In
|
||||
eros nisl, imperdiet vel imperdiet et, scelerisque a mauris. Pellentesque varius ex nunc,
|
||||
quis imperdiet eros placerat ac. Duis finibus orci et est auctor tincidunt. Sed non viverra
|
||||
ipsum. Nunc quis augue egestas, cursus lorem at, molestie sem. Morbi a consectetur ipsum, a
|
||||
placerat diam. Etiam vulputate dignissim convallis. Integer faucibus mauris sit amet finibus
|
||||
convallis.\n\n
|
||||
Phasellus in aliquet mi. Pellentesque habitant morbi tristique senectus et netus et
|
||||
malesuada fames ac turpis egestas. In volutpat arcu ut felis sagittis, in finibus massa
|
||||
gravida. Pellentesque id tellus orci. Integer dictum, lorem sed efficitur ullamcorper,
|
||||
libero justo consectetur ipsum, in mollis nisl ex sed nisl. Donec maximus ullamcorper
|
||||
sodales. Praesent bibendum rhoncus tellus nec feugiat. In a ornare nulla. Donec rhoncus
|
||||
libero vel nunc consequat, quis tincidunt nisl eleifend. Cras bibendum enim a justo luctus
|
||||
vestibulum. Fusce dictum libero quis erat maximus, vitae volutpat diam dignissim.
|
||||
</string>
|
||||
</resources>
|
9
app/src/main/res/values/themes.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<!-- Base application theme. -->
|
||||
<style name="Base.Theme.MusicSeparation" parent="Theme.Material3.DayNight.NoActionBar">
|
||||
<!-- Customize your light theme here. -->
|
||||
<!-- <item name="colorPrimary">@color/my_light_primary</item> -->
|
||||
</style>
|
||||
|
||||
<style name="Theme.MusicSeparation" parent="Base.Theme.MusicSeparation" />
|
||||
</resources>
|
13
app/src/main/res/xml/backup_rules.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
Sample backup rules file; uncomment and customize as necessary.
|
||||
See https://developer.android.com/guide/topics/data/autobackup
|
||||
for details.
|
||||
Note: This file is ignored for devices older that API 31
|
||||
See https://developer.android.com/about/versions/12/backup-restore
|
||||
-->
|
||||
<full-backup-content>
|
||||
<!--
|
||||
<include domain="sharedpref" path="."/>
|
||||
<exclude domain="sharedpref" path="device.xml"/>
|
||||
-->
|
||||
</full-backup-content>
|
19
app/src/main/res/xml/data_extraction_rules.xml
Normal file
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
Sample data extraction rules file; uncomment and customize as necessary.
|
||||
See https://developer.android.com/about/versions/12/backup-restore#xml-changes
|
||||
for details.
|
||||
-->
|
||||
<data-extraction-rules>
|
||||
<cloud-backup>
|
||||
<!-- TODO: Use <include> and <exclude> to control what is backed up.
|
||||
<include .../>
|
||||
<exclude .../>
|
||||
-->
|
||||
</cloud-backup>
|
||||
<!--
|
||||
<device-transfer>
|
||||
<include .../>
|
||||
<exclude .../>
|
||||
</device-transfer>
|
||||
-->
|
||||
</data-extraction-rules>
|
@ -0,0 +1,17 @@
|
||||
package com.example.musicseparation;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
public class ExampleUnitTest {
|
||||
@Test
|
||||
public void addition_isCorrect() {
|
||||
assertEquals(4, 2 + 2);
|
||||
}
|
||||
}
|
4
build.gradle.kts
Normal file
@ -0,0 +1,4 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
plugins {
|
||||
alias(libs.plugins.android.application) apply false
|
||||
}
|
21
gradle.properties
Normal file
@ -0,0 +1,21 @@
|
||||
# Project-wide Gradle settings.
|
||||
# IDE (e.g. Android Studio) users:
|
||||
# Gradle settings configured through the IDE *will override*
|
||||
# any settings specified in this file.
|
||||
# For more details on how to configure your build environment visit
|
||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. For more details, visit
|
||||
# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects
|
||||
# org.gradle.parallel=true
|
||||
# AndroidX package structure to make it clearer which packages are bundled with the
|
||||
# Android operating system, and which are packaged with your app's APK
|
||||
# https://developer.android.com/topic/libraries/support-library/androidx-rn
|
||||
android.useAndroidX=true
|
||||
# Enables namespacing of each library's R class so that its R class includes only the
|
||||
# resources declared in the library itself and none from the library's dependencies,
|
||||
# thereby reducing the size of the R class for that library
|
||||
android.nonTransitiveRClass=true
|
24
gradle/libs.versions.toml
Normal file
@ -0,0 +1,24 @@
|
||||
[versions]
|
||||
agp = "8.7.3"
|
||||
junit = "4.13.2"
|
||||
junitVersion = "1.2.1"
|
||||
espressoCore = "3.6.1"
|
||||
appcompat = "1.7.0"
|
||||
material = "1.12.0"
|
||||
constraintlayout = "2.2.1"
|
||||
navigationFragment = "2.8.9"
|
||||
navigationUi = "2.8.9"
|
||||
|
||||
[libraries]
|
||||
junit = { group = "junit", name = "junit", version.ref = "junit" }
|
||||
ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
|
||||
espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
|
||||
appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
|
||||
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
|
||||
constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
|
||||
navigation-fragment = { group = "androidx.navigation", name = "navigation-fragment", version.ref = "navigationFragment" }
|
||||
navigation-ui = { group = "androidx.navigation", name = "navigation-ui", version.ref = "navigationUi" }
|
||||
|
||||
[plugins]
|
||||
android-application = { id = "com.android.application", version.ref = "agp" }
|
||||
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
6
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
#Mon Apr 28 12:51:47 CEST 2025
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
185
gradlew
vendored
Normal file
@ -0,0 +1,185 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
# Copyright 2015 the original author or authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=`expr $i + 1`
|
||||
done
|
||||
case $i in
|
||||
0) set -- ;;
|
||||
1) set -- "$args0" ;;
|
||||
2) set -- "$args0" "$args1" ;;
|
||||
3) set -- "$args0" "$args1" "$args2" ;;
|
||||
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=`save "$@"`
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
exec "$JAVACMD" "$@"
|
89
gradlew.bat
vendored
Normal file
@ -0,0 +1,89 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
24
settings.gradle.kts
Normal file
@ -0,0 +1,24 @@
|
||||
pluginManagement {
|
||||
repositories {
|
||||
google {
|
||||
content {
|
||||
includeGroupByRegex("com\\.android.*")
|
||||
includeGroupByRegex("com\\.google.*")
|
||||
includeGroupByRegex("androidx.*")
|
||||
}
|
||||
}
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
}
|
||||
}
|
||||
dependencyResolutionManagement {
|
||||
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.name = "MusicSeparation"
|
||||
include(":app")
|
||||
|