Merge branch 'audiorecorder-3.5.22'

This commit is contained in:
Alexey Kuznetsov 2024-10-31 17:22:38 +03:00
commit 258aa21e2a
19 changed files with 198 additions and 158 deletions

View file

@ -1,16 +1,17 @@
# Translations
* japanese translation thanks to @naofumi
* german translation thanks to @s72785
* brazilian translation thanks to @vrozsas
* itallian tralslation thanks to @Agno94
* slovak translation thanks to @pvagner
* french thanks to @Nonot
* turkish thanks to @tneonflo
* spanish thanks to @sguinetti
* greek tanks to @cryoranger
* Indonesian thanks to @ditokp, @zmni
* polish thanks to @krkk
* Chinese thanks to @itoy
* Chinese translation thanks to @itoy
* Chinese (Taiwan) translation thanks to @cges30901
* Brazilian translation thanks to @vrozsas
* Danish translation thanks to @lianergoist
* Dutch translation thanks to @Stephan-P
* French translation thanks to @Nonot
* German translation thanks to @s72785
* Greek translation thanks to @cryoranger
* Indonesian translation thanks to @ditokp, @zmni
* Italian translation thanks to @Agno94
* Japanese translation thanks to @naofumi
* Polish translation thanks to @krkk
* Slovak translation thanks to @pvagner
* Spanish translation thanks to @sguinetti
* Turkish translation thanks to @tneonflo

View file

@ -16,4 +16,4 @@ If you want to translate 'Audio Recorder' to your language please read this:
# Screenshots
![shot](/docs/shot.png)
![screenshot1](./metadata/screenshots/screenshot1.png)

View file

@ -9,8 +9,8 @@ android {
applicationId "com.github.axet.audiorecorder"
minSdkVersion 9
targetSdkVersion 31
versionCode 377
versionName "3.5.21"
versionCode 378
versionName "3.5.22"
}
signingConfigs {
release {
@ -53,7 +53,7 @@ android {
dependencies {
testImplementation 'junit:junit:4.12'
implementation ('com.github.axet:android-audio-library:1.1.23') // implementation project(':android-audio-library')
implementation ('com.github.axet:android-audio-library:1.1.24') // implementation project(':android-audio-library')
implementation ('com.github.axet:wget:1.7.0') { exclude group: 'org.json', module: 'json' }
assets('com.google.android.exoplayer:exoplayer:2.7.3') { exclude group: 'com.android.support' }
assets('com.github.axet.exoplayer:exoplayer:2.7.3') { exclude group: 'com.android.support' }
}

View file

@ -1,16 +0,0 @@
package com.github.axet.audiorecorder;
import android.app.Application;
import android.test.ApplicationTestCase;
/**
* <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
*/
public class ApplicationTest extends ApplicationTestCase<Application> {
public ApplicationTest() {
super(Application.class);
}
public void testFFT() {
}
}

View file

@ -23,15 +23,18 @@
android:requestLegacyExternalStorage="true"
android:roundIcon="@mipmap/ic_launcher"
android:supportsRtl="true"
android:theme="@style/Translucent">
<service android:name=".services.RecordingService" android:foregroundServiceType="mediaProjection" />
android:theme="@android:style/Theme.Translucent.NoTitleBar">
<service
android:name=".services.RecordingService"
android:foregroundServiceType="mediaProjection" />
<service android:name=".services.EncodingService" />
<service android:name=".services.ControlsService" />
<service
android:name=".services.TileService"
android:exported="true"
android:icon="@drawable/ic_mic_24dp"
android:label="@string/tile_start_recording"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE" android:exported="true">
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE" />
</intent-filter>
@ -39,14 +42,15 @@
<activity
android:name=".activities.SettingsActivity"
android:label="@string/app_name" />
android:label="@string/app_name"
android:theme="@android:style/Theme.Translucent.NoTitleBar" />
<activity
android:name=".activities.MainActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:exported="true"
android:label="@string/app_name"
android:launchMode="singleInstance"
android:theme="@style/Translucent">
android:theme="@android:style/Theme.Translucent.NoTitleBar">
<meta-data
android:name="android.app.searchable"
android:resource="@xml/searchable" />
@ -62,7 +66,8 @@
android:configChanges="orientation|keyboardHidden|screenSize"
android:exported="true"
android:launchMode="singleInstance"
android:showOnLockScreen="true">
android:showOnLockScreen="true"
android:theme="@android:style/Theme.Translucent.NoTitleBar">
<intent-filter>
<action android:name="android.provider.MediaStore.RECORD_SOUND" />
<category android:name="android.intent.category.DEFAULT" />
@ -79,14 +84,18 @@
<action android:name="com.htc.intent.action.QUICKBOOT_POWERON" />
</intent-filter>
</receiver>
<receiver android:name=".services.OnUpgradeReceiver" android:exported="true">
<receiver
android:name=".services.OnUpgradeReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.PACKAGE_REPLACED" />
<data android:scheme="package" />
</intent-filter>
</receiver>
<receiver android:name=".services.OnExternalReceiver" android:exported="true">
<receiver
android:name=".services.OnExternalReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.EXTERNAL_APPLICATIONS_AVAILABLE" />
</intent-filter>

View file

@ -35,6 +35,7 @@ import android.widget.Toast;
import com.github.axet.androidlibrary.activities.AppCompatThemeActivity;
import com.github.axet.androidlibrary.preferences.AboutPreferenceCompat;
import com.github.axet.androidlibrary.preferences.OptimizationPreferenceCompat;
import com.github.axet.androidlibrary.preferences.ScreenlockPreference;
import com.github.axet.androidlibrary.services.StorageProvider;
import com.github.axet.androidlibrary.widgets.ErrorDialog;
import com.github.axet.androidlibrary.widgets.OpenFileDialog;
@ -54,6 +55,7 @@ import com.github.axet.audiorecorder.services.RecordingService;
import org.json.JSONException;
import java.io.File;
import java.io.IOException;
public class MainActivity extends AppCompatThemeActivity {
public final static String TAG = MainActivity.class.getSimpleName();
@ -398,7 +400,7 @@ public class MainActivity extends AppCompatThemeActivity {
@Override
public int getAppTheme() {
return AudioApplication.getTheme(this, R.style.RecThemeLight_NoActionBar, R.style.RecThemeDark_NoActionBar);
return AudioApplication.getTheme(this, R.style.RecThemeLight_NoActionBar, R.style.RecThemeDark_NoActionBar, R.style.RecThemeDarkBlack_NoActionBar);
}
@Override
@ -488,8 +490,7 @@ public class MainActivity extends AppCompatThemeActivity {
getMenuInflater().inflate(R.menu.menu_main, menu);
KeyguardManager myKM = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
if (myKM.inKeyguardRestrictedInputMode())
if (ScreenlockPreference.isLocked(this))
menu.findItem(R.id.action_settings).setVisible(false);
MenuItem item = menu.findItem(R.id.action_show_folder);
@ -513,11 +514,10 @@ public class MainActivity extends AppCompatThemeActivity {
return false;
}
});
searchView.setOnCloseListener(new SearchView.OnCloseListener() {
searchView.setOnCollapsedListener(new SearchView.OnCollapsedListener() {
@Override
public boolean onClose() {
public void onCollapsed() {
recordings.searchClose();
return true;
}
});
@ -636,7 +636,7 @@ public class MainActivity extends AppCompatThemeActivity {
if (Storage.permitted(MainActivity.this, permissions)) {
try {
storage.migrateLocalStorage();
} catch (RuntimeException e) {
} catch (RuntimeException | IOException e) {
ErrorDialog.Error(MainActivity.this, e);
}
recordings.load(false, null);

View file

@ -10,8 +10,6 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.graphics.Rect;
import android.media.AudioFormat;
import android.media.MediaRecorder;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
@ -22,7 +20,6 @@ import android.provider.MediaStore;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.view.WindowCallbackWrapper;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.DisplayMetrics;
import android.util.Log;
@ -38,6 +35,7 @@ import android.widget.TextView;
import com.github.axet.androidlibrary.activities.AppCompatThemeActivity;
import com.github.axet.androidlibrary.animations.MarginBottomAnimation;
import com.github.axet.androidlibrary.app.PhoneStateChangeListener;
import com.github.axet.androidlibrary.services.FileProvider;
import com.github.axet.androidlibrary.services.StorageProvider;
import com.github.axet.androidlibrary.sound.AudioTrack;
@ -61,12 +59,7 @@ import com.github.axet.audiorecorder.services.EncodingService;
import com.github.axet.audiorecorder.services.RecordingService;
import java.io.File;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.nio.ShortBuffer;
import java.util.concurrent.Executor;
import java.io.IOException;
public class RecordingActivity extends AppCompatThemeActivity {
public static final String TAG = RecordingActivity.class.getSimpleName();
@ -86,7 +79,7 @@ public class RecordingActivity extends AppCompatThemeActivity {
public static final String START_RECORDING = RecordingService.class.getCanonicalName() + ".START_RECORDING";
public static final String STOP_RECORDING = RecordingService.class.getCanonicalName() + ".STOP_RECORDING";
PhoneStateChangeListener pscl = new PhoneStateChangeListener();
PhoneStateChangeListener pscl;
Headset headset;
Intent recordSoundIntent = null;
@ -300,65 +293,29 @@ public class RecordingActivity extends AppCompatThemeActivity {
}
}
class PhoneStateChangeListener extends PhoneStateListener {
public boolean wasRinging;
class PhoneStateChangeListener extends com.github.axet.androidlibrary.app.PhoneStateChangeListener {
public boolean pausedByCall;
@TargetApi(31)
TelephonyCallback e;
@TargetApi(31)
public class TelephonyCallback extends android.telephony.TelephonyCallback implements android.telephony.TelephonyCallback.CallStateListener {
@Override
public void onCallStateChanged(int i) {
PhoneStateChangeListener.this.onCallStateChanged(i, "");
}
public PhoneStateChangeListener(Context context) {
super(context);
}
public void create() {
Context context = RecordingActivity.this;
TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
if (Build.VERSION.SDK_INT >= 31 && getApplicationInfo().targetSdkVersion >= 31) {
if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) {
e = new TelephonyCallback();
tm.registerTelephonyCallback(getMainExecutor(), e);
}
} else {
tm.listen(this, PhoneStateListener.LISTEN_CALL_STATE);
}
}
public void close() {
Context context = RecordingActivity.this;
TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
if (Build.VERSION.SDK_INT >= 31 && getApplicationInfo().targetSdkVersion >= 31) {
if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED)
tm.unregisterTelephonyCallback(e);
} else {
tm.listen(this, PhoneStateListener.LISTEN_NONE);
@Override
public void onAnswered() {
super.onAnswered();
if (recording.thread != null) {
stopRecording(getString(R.string.hold_by_call), false);
pausedByCall = true;
}
}
@Override
public void onCallStateChanged(int s, String incomingNumber) {
switch (s) {
case TelephonyManager.CALL_STATE_RINGING:
wasRinging = true;
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
wasRinging = true;
if (recording.thread != null) {
stopRecording(getString(R.string.hold_by_call), false);
pausedByCall = true;
}
break;
case TelephonyManager.CALL_STATE_IDLE:
if (pausedByCall) {
if (receiver.isRecordingReady())
; // startRecording();
}
wasRinging = false;
pausedByCall = false;
break;
public void onIdle() {
super.onIdle();
if (pausedByCall) {
// if (receiver.isRecordingReady())
// startRecording();
pausedByCall = false;
}
}
}
@ -413,7 +370,7 @@ public class RecordingActivity extends AppCompatThemeActivity {
@Override
public int getAppTheme() {
return AudioApplication.getTheme(this, R.style.RecThemeLight, R.style.RecThemeDark);
return AudioApplication.getTheme(this, R.style.RecThemeLight, R.style.RecThemeDark, R.style.RecThemeDarkBlack);
}
@Override
@ -439,6 +396,7 @@ public class RecordingActivity extends AppCompatThemeActivity {
receiver.filter.addAction(ACTION_FINISH_RECORDING);
receiver.registerReceiver(this);
pscl = new PhoneStateChangeListener(this);
final SharedPreferences shared = PreferenceManager.getDefaultSharedPreferences(this);
if (shared.getBoolean(AudioApplication.PREFERENCE_CALL, false))
pscl.create();

View file

@ -60,7 +60,7 @@ public class SettingsActivity extends AppCompatSettingsThemeActivity implements
@Override
public int getAppTheme() {
return AudioApplication.getTheme(this, R.style.RecThemeLight, R.style.RecThemeDark);
return AudioApplication.getTheme(this, R.style.RecThemeLight, R.style.RecThemeDark, R.style.RecThemeDarkBlack);
}
@Override

View file

@ -22,6 +22,7 @@ import org.json.JSONObject;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
@ -201,8 +202,8 @@ public class EncodingStorage extends HashMap<File, EncodingStorage.Info> {
}, new Runnable() {
@Override
public void run() { // or error
Storage.delete(storage.getContext(), fly.targetUri); // fly has fd, delete target manually
try {
Storage.delete(storage.getContext(), fly.targetUri); // fly has fd, delete target manually
Intent intent = new Intent()
.putExtra("in", encoder.in)
.putExtra("info", info.save().toString())

View file

@ -1,6 +1,5 @@
package com.github.axet.audiorecorder.app;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.media.AudioFormat;
@ -18,20 +17,8 @@ import com.github.axet.audiolibrary.app.Sound;
import com.github.axet.audiolibrary.encoders.Encoder;
import com.github.axet.audiolibrary.encoders.OnFlyEncoding;
import com.github.axet.audiorecorder.BuildConfig;
import com.github.axet.audiorecorder.R;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.json.JSONException;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ShortBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Locale;
import java.util.concurrent.atomic.AtomicBoolean;
public class RecordingStorage {
@ -78,7 +65,7 @@ public class RecordingStorage {
info = new RawSamples.Info(format, sampleRate, Sound.getChannels(context));
}
public void startRecording(int source) {
public void startRecording(final int source) {
final SharedPreferences shared = android.preference.PreferenceManager.getDefaultSharedPreferences(context);
sound.silent();
@ -240,17 +227,20 @@ public class RecordingStorage {
}
session += samples;
if (samplesTime - silence > 2 * sampleRate) { // 2 second of mic muted
if (!silenceDetected) {
silenceDetected = true;
Post(MUTED, null);
}
} else {
if (silenceDetected) {
silenceDetected = false;
Post(UNMUTED, null);
if (source != Sound.SOURCE_INTERNAL_AUDIO) {
if (samplesTime - silence > 2 * sampleRate) { // 2 second of mic muted
if (!silenceDetected) {
silenceDetected = true;
Post(MUTED, null);
}
} else {
if (silenceDetected) {
silenceDetected = false;
Post(UNMUTED, null);
}
}
}
diff = (now - start) * sampleRate / 1000; // number of samples we expect by this moment
if (diff - session > 2 * sampleRate) { // 2 second of silence / paused by os
Post(PAUSED, null);

View file

@ -10,6 +10,8 @@ import android.preference.PreferenceManager;
import com.github.axet.androidlibrary.services.StorageProvider;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
@ -135,7 +137,7 @@ public class Storage extends com.github.axet.audiolibrary.app.Storage {
}
@Override
public void migrateLocalStorage() {
public void migrateLocalStorage() throws IOException {
super.migrateLocalStorage();
deleteTmp();
}

View file

@ -0,0 +1,23 @@
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1">
<style>
a { white-space: pre-wrap; word-wrap:break-word; }
</style>
</head>
<body>
<h3>Over</h3>
<p>
Android-vriendelijk!
</p>
<p>Audio Recorder met aangepaste map voor opnames, fraaie indicatie van opnamevolume, opnamemelding, opname-activiteit op het vergrendelingsscherm.</p>
<dl>
<dt><b>Licentie:</b></dt>
<dd>GPLv3</dd>
<dt><b>Broncode:</b></dt>
<dd><a href="https://gitlab.com/axet/android-audio-recorder">https://gitlab.com/axet/android-audio-recorder</a></dd>
</dl>
</body>
</html>

View file

@ -0,0 +1,74 @@
<resources>
<string name="app_name">Audio Recorder</string>
<string-array name="sample_rate_text">
<item>48 kHz</item>
<item>44.1 kHz (CD)</item>
<item>32 kHz</item>
<item>22 kHz</item>
<item>16 kHz (standaard)</item>
<item>11 kHz</item>
<item>8 kHz (telefoon)</item>
</string-array>
<string-array name="source_text">
<item>Microfoon</item>
<item>Onbewerkt</item>
<item>Bluetooth</item>
<item>Interne audio</item>
</string-array>
<string-array name="channels_text">
<item>Mono (standaard)</item>
<item>Stereo</item>
</string-array>
<string name="no_folder_app">Geen app voor bestandsbeheer beschikbaar</string>
<string name="hold_by_call">pauzeren (onderbreking bij oproep)</string>
<string name="recording_status_recording">opname</string>
<string name="recording_status_encoding">coderen</string>
<string name="recording_status_pause">pauze</string>
<string name="recording_status_edit">bewerken</string>
<string name="confirm_cancel">Annulering bevestigen</string>
<string name="encoding_title">Coderen…</string>
<string name="pause_title">Pauzeren…</string>
<string name="recording_title">Opname</string>
<string name="open_recording_folder">Map met opnames openen</string>
<string name="recording_list_is_empty">Opnamelijst is leeg\n\nKlik om een opname te starten</string>
<string name="record_button">Opname</string>
<string name="cut_button">Knippen</string>
<string name="stop_button">Stoppen</string>
<string name="cancel_button">Annuleren</string>
<string name="pause_button">Pauzeren</string>
<string name="pref_storage_title">Map met opnames</string>
<string name="pref_rate_title">Samplerate</string>
<string name="pref_encoding_title">Codering</string>
<string name="pref_encoding_summary">Uitvoerformaat (.wav, .m4a, …)</string>
<string name="pref_mode_title">Audiokanalen</string>
<string name="pref_mode_summary">Opnamekanalen</string>
<string name="pref_nameformat_title">Bestandsnaam-opmaak</string>
<string name="pref_pausecalls_title">Pauzeren tijdens oproep</string>
<string name="pref_pausecalls_summary">Stop de opname bij een oproep en hervat deze bij het ophangen</string>
<string name="pref_silence_title">Stille modus</string>
<string name="pref_silence_summary">\'Stille modus\' activeren tijdens opname</string>
<string name="pref_lockscreen_title">Bediening op vergrendelingsscherm</string>
<string name="pref_lockscreen_summary">Bediening weergeven als de telefoon vergrendeld is</string>
<string name="pref_theme_title">App-thema</string>
<string name="pref_theme_summary">App-thema instellen (donker/licht)</string>
<string name="pref_application">Applicatie</string>
<string name="pref_recordings">Opnames</string>
<string name="pref_fly_title">Direct coderen</string>
<string name="pref_fly_summary">Met Direct coderen is bewerking niet mogelijk, evenals herstel van een crash</string>
<string name="hold_by_bluetooth">pauze (bluetooth niet verbonden)</string>
<string name="menu_search">Zoeken</string>
<string name="save_as_wav">Opslaan als WAV</string>
<string name="auto_close">Automatisch sluiten in (%1$d)</string>
<string name="mic_muted_error">Microfoon gedempt</string>
<string name="mic_muted_pie">Android 9 (Pie) en hoger verhinderen dat inactieve achtergrondapps de microfoon gebruiken. Schakel SeLinux uit of downgrade naar een eerdere Android-release!</string>
<string name="mic_paused">De microfoon is door Android gepauzeerd. De opnametijd is korter dan de geregistreerde gegevens. Controleer of jouw apparaat opnames in de achtergrond ondersteunt of dat het krachtig genoeg is voor de geselecteerde instellingen</string>
<string name="tile_start_recording">Opname starten</string>
<string name="tile_stop_recording">Opname beëindigen</string>
<string name="encoding_optimization">Achtergrondcodering onderbroken door Android-batterijoptimalisatie. Sta toe dat deze applicatie in de achtergrond kan werken</string>
<string name="per_second">/s</string>
</resources>

View file

@ -28,7 +28,7 @@
<string-array name="audioformat_text">
<item>16-bit PCM</item>
<item>24-bit PCM (float)</item>
<item>32-bit float</item>
</string-array>
<string-array name="audioformat_values" translatable="false">

View file

@ -6,20 +6,31 @@
<item name="cutColor">#b1b1b1</item>
</style>
<style name="RecThemeLight.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
<style name="RecThemeDark" parent="AppThemeDark">
<item name="preferenceTheme">@style/PreferenceThemeOverlay</item>
<item name="recColor">#c6c6c6</item>
<item name="cutColor">#0e0e0e</item>
</style>
<style name="RecThemeLight.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
<style name="RecThemeDark.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
<style name="RecThemeDarkBlack" parent="AppThemeDarkBlack">
<item name="preferenceTheme">@style/PreferenceThemeOverlay</item>
<item name="recColor">#c6c6c6</item>
<item name="cutColor">#0e0e0e</item>
</style>
<style name="RecThemeDarkBlack.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
</resources>

View file

@ -1,15 +0,0 @@
package com.github.axet.audiorecorder;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* To work on unit tests, switch the Test Artifact in the Build Variants view.
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() throws Exception {
assertEquals(4, 2 + 2);
}
}

View file

@ -32,16 +32,18 @@ For example:
# Raw format
* Signed 16-bit PCM or float (depends on user settings)
Temporary recordings stored inside application specific data folders (described in Recording locations) with following format:
* Signed 16-bit PCM (2 bytes) or (4 bytes) Float (depends on Settings/Audio Format user setup)
* Big Endian
* 1 or 2 channels (depends on user settings). First 2 bytes for left channel, Second 2 bytes for right channel.
* 1 or 2 channels (depends on user settings). First 2/4 bytes for left channel, second 2/4 bytes for right channel.
* 16hz to 48hz Sample Rate / Frequincy (depends on user settings)
Android supports 16-bit PCM format or PCM float. Android recomends to use PCM float over 24-bit PCM format or 16-bit PCM if possible.
* https://developer.android.com/reference/android/media/AudioFormat#encoding
float mantisa is 23 bits (plus sign bit and float point bits) persition in range from -1..1 can hold about 2130706431 unique numbers which is equivalent to 31 bits integer. When 24-bit PCM only gives you 2^24=16,777,216 unique values.
float mantisa is 23 bits (plus sign bit and float point bits) persition in range from -1..1 can hold about 2,130,706,431 unique numbers which is equivalent to 31 bits integer. When 24-bit PCM only gives you 2^24=16,777,216 unique values.
# Adb commands

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

View file

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Before After
Before After