├── fastlane └── metadata │ └── android │ ├── en-US │ ├── changelogs │ │ ├── 250.txt │ │ ├── 310.txt │ │ ├── 200.txt │ │ ├── 240.txt │ │ ├── 280.txt │ │ ├── 180.txt │ │ ├── 270.txt │ │ ├── 170.txt │ │ ├── 220.txt │ │ ├── 260.txt │ │ ├── 290.txt │ │ ├── 300.txt │ │ ├── 190.txt │ │ ├── 210.txt │ │ └── 230.txt │ ├── short_description.txt │ ├── images │ │ ├── icon.png │ │ └── phoneScreenshots │ │ │ ├── 01.png │ │ │ └── 02.png │ └── full_description.txt │ ├── de-DE │ ├── changelogs │ │ ├── 250.txt │ │ ├── 310.txt │ │ ├── 170.txt │ │ ├── 280.txt │ │ ├── 180.txt │ │ ├── 200.txt │ │ ├── 240.txt │ │ ├── 260.txt │ │ ├── 290.txt │ │ ├── 190.txt │ │ ├── 220.txt │ │ ├── 300.txt │ │ ├── 270.txt │ │ ├── 210.txt │ │ └── 230.txt │ └── short_description.txt │ ├── zh-CN │ └── short_description.txt │ └── ru-RU │ ├── short_description.txt │ └── full_description.txt ├── gradle.properties ├── settings.gradle ├── FFTLibrary ├── lint.xml ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── com │ │ └── google │ │ └── corp │ │ └── productivity │ │ └── specialprojects │ │ └── android │ │ └── fft │ │ └── RealDoubleFFT.java └── build.gradle ├── .gitignore ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── audioSpectrumAnalyzer ├── src │ └── main │ │ ├── ic_launcher-playstore.png │ │ ├── res │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_foreground.png │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_foreground.png │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_foreground.png │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_foreground.png │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_foreground.png │ │ ├── values │ │ │ ├── ic_launcher_background.xml │ │ │ ├── attrs.xml │ │ │ ├── dimens.xml │ │ │ ├── internal_defaults.xml │ │ │ ├── styles.xml │ │ │ ├── audio_source.xml │ │ │ ├── arrays.xml │ │ │ └── instructions.xml │ │ ├── values-sw600dp │ │ │ └── dimens.xml │ │ ├── xml │ │ │ ├── backup_descriptor.xml │ │ │ └── preferences.xml │ │ ├── values-sw720dp-land │ │ │ └── dimens.xml │ │ ├── mipmap-anydpi-v26 │ │ │ └── ic_launcher.xml │ │ ├── drawable │ │ │ ├── ic_fullscreen_24dp.xml │ │ │ ├── ic_fullscreen_exit_24dp.xml │ │ │ ├── ic_screenshot.xml │ │ │ └── ic_launcher_monochrome.xml │ │ ├── layout │ │ │ ├── settings_activity.xml │ │ │ ├── activity_info_rec.xml │ │ │ ├── dialog_set_cursor_freq.xml │ │ │ └── dialog_view_range.xml │ │ ├── menu │ │ │ ├── info_rec.xml │ │ │ └── info.xml │ │ ├── values-ru │ │ │ └── strings.xml │ │ └── values-zh-rTW │ │ │ └── strings.xml │ │ ├── java │ │ └── org │ │ │ └── woheller69 │ │ │ └── audio_analyzer_for_android │ │ │ ├── FPSCounter.java │ │ │ ├── ScreenCapture.java │ │ │ ├── SetCursorFreqDialog.java │ │ │ ├── AnalyzerParameters.java │ │ │ ├── GithubStar.java │ │ │ ├── SineGenerator.java │ │ │ ├── MyPreferences.java │ │ │ ├── CalibrationLoad.java │ │ │ ├── SBNumFormat.java │ │ │ ├── RecorderMonitor.java │ │ │ ├── besselCal.java │ │ │ ├── SelectorText.java │ │ │ ├── AxisTickLabels.java │ │ │ ├── ScreenPhysicalMapping.java │ │ │ ├── SpectrumPlot.java │ │ │ └── WavWriter.java │ │ └── AndroidManifest.xml └── build.gradle ├── README.old ├── util ├── cm_list.py ├── blackbody.m ├── ciexyzjv.csv ├── inferno.csv ├── magma.csv ├── plasma.csv └── viridis.csv ├── gradlew.bat ├── example_calibration.txt └── gradlew /fastlane/metadata/android/en-US/changelogs/250.txt: -------------------------------------------------------------------------------- 1 | Bugfix -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/310.txt: -------------------------------------------------------------------------------- 1 | Bugfix -------------------------------------------------------------------------------- /fastlane/metadata/android/de-DE/changelogs/250.txt: -------------------------------------------------------------------------------- 1 | Fehlerbehebung -------------------------------------------------------------------------------- /fastlane/metadata/android/de-DE/changelogs/310.txt: -------------------------------------------------------------------------------- 1 | Fehlerbehebung -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/200.txt: -------------------------------------------------------------------------------- 1 | Add screenshot button -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/240.txt: -------------------------------------------------------------------------------- 1 | Bugfixes for Android 13 -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/280.txt: -------------------------------------------------------------------------------- 1 | Russian translation -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | android.enableJetifier=true 2 | android.useAndroidX=true -------------------------------------------------------------------------------- /fastlane/metadata/android/de-DE/changelogs/170.txt: -------------------------------------------------------------------------------- 1 | Erstes F-Droid Release 2 | -------------------------------------------------------------------------------- /fastlane/metadata/android/de-DE/changelogs/280.txt: -------------------------------------------------------------------------------- 1 | Übersetzung für Russisch -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/180.txt: -------------------------------------------------------------------------------- 1 | Library updates 2 | Bugfixes -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/270.txt: -------------------------------------------------------------------------------- 1 | New options for peak hold -------------------------------------------------------------------------------- /fastlane/metadata/android/zh-CN/short_description.txt: -------------------------------------------------------------------------------- 1 | 一款便捷的实时音频频谱和频谱分析仪 2 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':FFTLibrary' 2 | include ':audioSpectrumAnalyzer' 3 | -------------------------------------------------------------------------------- /FFTLibrary/lint.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /fastlane/metadata/android/de-DE/changelogs/180.txt: -------------------------------------------------------------------------------- 1 | Bibliothek-Updates 2 | Bugfixes -------------------------------------------------------------------------------- /fastlane/metadata/android/de-DE/changelogs/200.txt: -------------------------------------------------------------------------------- 1 | Screenshot button hinzugefügt -------------------------------------------------------------------------------- /fastlane/metadata/android/de-DE/changelogs/240.txt: -------------------------------------------------------------------------------- 1 | Fehlerbehebung für Android 13 -------------------------------------------------------------------------------- /fastlane/metadata/android/de-DE/changelogs/260.txt: -------------------------------------------------------------------------------- 1 | Update für Android 14 (SDK 34) -------------------------------------------------------------------------------- /fastlane/metadata/android/de-DE/changelogs/290.txt: -------------------------------------------------------------------------------- 1 | Update für Android 15 (SDK 35) -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/170.txt: -------------------------------------------------------------------------------- 1 | Initial F-Droid release 2 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/220.txt: -------------------------------------------------------------------------------- 1 | Switch to AndroidX preferences -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/260.txt: -------------------------------------------------------------------------------- 1 | Update for Android 14 (SDK 34) -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/290.txt: -------------------------------------------------------------------------------- 1 | Update for Android 15 (SDK 35) -------------------------------------------------------------------------------- /fastlane/metadata/android/de-DE/changelogs/190.txt: -------------------------------------------------------------------------------- 1 | Neue Option Zero Padding 2 | Bugfixes -------------------------------------------------------------------------------- /fastlane/metadata/android/de-DE/changelogs/220.txt: -------------------------------------------------------------------------------- 1 | Umstellung auf AndroidX Preferences -------------------------------------------------------------------------------- /fastlane/metadata/android/de-DE/changelogs/300.txt: -------------------------------------------------------------------------------- 1 | Translations 2 | Deprecation warning -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/300.txt: -------------------------------------------------------------------------------- 1 | Translations 2 | Deprecation warning -------------------------------------------------------------------------------- /fastlane/metadata/android/de-DE/changelogs/270.txt: -------------------------------------------------------------------------------- 1 | Neue Einstellmöglichkeiten für Peak Hold -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/190.txt: -------------------------------------------------------------------------------- 1 | Add support for zero padding 2 | Bugfixes -------------------------------------------------------------------------------- /fastlane/metadata/android/ru-RU/short_description.txt: -------------------------------------------------------------------------------- 1 | Удобный анализатор спектра звука и спектрограммы 2 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/short_description.txt: -------------------------------------------------------------------------------- 1 | A handy real-time audio spectrum and spectrogram analyzer -------------------------------------------------------------------------------- /fastlane/metadata/android/de-DE/short_description.txt: -------------------------------------------------------------------------------- 1 | Ein handlicher Real-Time Audio Spektrum und Spektrogramm Analyzer -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle/ 2 | local.properties 3 | *.DS_Store 4 | build/ 5 | 6 | .idea/ 7 | *.iml 8 | 9 | *~ 10 | *.swp -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/210.txt: -------------------------------------------------------------------------------- 1 | Add fullscreen mode 2 | Option for smaller FFT length and higher overlap -------------------------------------------------------------------------------- /fastlane/metadata/android/de-DE/changelogs/210.txt: -------------------------------------------------------------------------------- 1 | Fullscreen Modus hinzugefügt 2 | Option für kleiner FFT Länge und FFT Überlapp -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/230.txt: -------------------------------------------------------------------------------- 1 | Update for Android 13 (SDK 33) 2 | Monochrome icon support 3 | Removed Chinese and Taiwanese -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/woheller69/audio-analyzer-for-android/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /fastlane/metadata/android/de-DE/changelogs/230.txt: -------------------------------------------------------------------------------- 1 | Update für Android 13 (SDK 33) 2 | Unterstützung für monochromes Icon 3 | Chinesisch und Taiwanesisch entfernt -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/woheller69/audio-analyzer-for-android/HEAD/fastlane/metadata/android/en-US/images/icon.png -------------------------------------------------------------------------------- /audioSpectrumAnalyzer/src/main/ic_launcher-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/woheller69/audio-analyzer-for-android/HEAD/audioSpectrumAnalyzer/src/main/ic_launcher-playstore.png -------------------------------------------------------------------------------- /audioSpectrumAnalyzer/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/woheller69/audio-analyzer-for-android/HEAD/audioSpectrumAnalyzer/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /audioSpectrumAnalyzer/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/woheller69/audio-analyzer-for-android/HEAD/audioSpectrumAnalyzer/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/woheller69/audio-analyzer-for-android/HEAD/fastlane/metadata/android/en-US/images/phoneScreenshots/01.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/woheller69/audio-analyzer-for-android/HEAD/fastlane/metadata/android/en-US/images/phoneScreenshots/02.png -------------------------------------------------------------------------------- /audioSpectrumAnalyzer/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/woheller69/audio-analyzer-for-android/HEAD/audioSpectrumAnalyzer/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /audioSpectrumAnalyzer/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/woheller69/audio-analyzer-for-android/HEAD/audioSpectrumAnalyzer/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /audioSpectrumAnalyzer/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/woheller69/audio-analyzer-for-android/HEAD/audioSpectrumAnalyzer/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /audioSpectrumAnalyzer/src/main/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #D7D7D7 4 | -------------------------------------------------------------------------------- /audioSpectrumAnalyzer/src/main/res/mipmap-hdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/woheller69/audio-analyzer-for-android/HEAD/audioSpectrumAnalyzer/src/main/res/mipmap-hdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /audioSpectrumAnalyzer/src/main/res/mipmap-mdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/woheller69/audio-analyzer-for-android/HEAD/audioSpectrumAnalyzer/src/main/res/mipmap-mdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /audioSpectrumAnalyzer/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/woheller69/audio-analyzer-for-android/HEAD/audioSpectrumAnalyzer/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /audioSpectrumAnalyzer/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/woheller69/audio-analyzer-for-android/HEAD/audioSpectrumAnalyzer/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /audioSpectrumAnalyzer/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/woheller69/audio-analyzer-for-android/HEAD/audioSpectrumAnalyzer/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /FFTLibrary/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | -------------------------------------------------------------------------------- /audioSpectrumAnalyzer/src/main/res/values-sw600dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /audioSpectrumAnalyzer/src/main/res/xml/backup_descriptor.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip 3 | distributionPath=wrapper/dists 4 | zipStorePath=wrapper/dists 5 | zipStoreBase=GRADLE_USER_HOME 6 | distributionSha256Sum=9631d53cf3e74bfa726893aee1f8994fee4e060c401335946dba2156f440f24c 7 | -------------------------------------------------------------------------------- /audioSpectrumAnalyzer/src/main/res/values-sw720dp-land/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 128dp 8 | 9 | 10 | -------------------------------------------------------------------------------- /audioSpectrumAnalyzer/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /audioSpectrumAnalyzer/src/main/res/drawable/ic_fullscreen_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /audioSpectrumAnalyzer/src/main/res/drawable/ic_fullscreen_exit_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /README.old: -------------------------------------------------------------------------------- 1 | Audio spectrum Analyzer for Android. 2 | 3 | I wrote this small (but potentially useful) Android app to experiment with and 4 | understand various features of the Android SDK, including: 5 | 6 | - Pan and pinch to zoom 7 | - User preferences 8 | - Custom attributes 9 | - View animations 10 | - Audio subsystem 11 | 12 | Files: 13 | - fftLibrary: a library project containing the FFT code 14 | - audioAnalyzer: A simple android app to exercise the FFT library 15 | 16 | I'm making this available in the hope that it is useful. 17 | Stephen Uhler 18 | -------------------------------------------------------------------------------- /audioSpectrumAnalyzer/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /audioSpectrumAnalyzer/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16dp 5 | 16dp 6 | 7 | 70dp 8 | 40sp 9 | 20sp 10 | 5sp 11 | 12sp 12 | 13 | 14 | -------------------------------------------------------------------------------- /FFTLibrary/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | android { 3 | namespace 'com.google.corp.productivity.specialprojects.android.fft' 4 | compileSdk 35 5 | 6 | defaultConfig { 7 | minSdk 14 8 | targetSdk 35 9 | } 10 | 11 | buildTypes { 12 | release { 13 | minifyEnabled false 14 | proguardFiles getDefaultProguardFile('proguard-android.txt') 15 | } 16 | } 17 | compileOptions { 18 | sourceCompatibility JavaVersion.VERSION_1_8 19 | targetCompatibility JavaVersion.VERSION_1_8 20 | } 21 | } 22 | 23 | dependencies { 24 | implementation 'androidx.appcompat:appcompat:1.6.1' 25 | } -------------------------------------------------------------------------------- /audioSpectrumAnalyzer/src/main/res/layout/settings_activity.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | 14 | 15 | -------------------------------------------------------------------------------- /audioSpectrumAnalyzer/src/main/res/values/internal_defaults.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -150 5 | 440.0 6 | -6.0 7 | 625.0 8 | -6.0 9 | 1875.0 10 | -12.0 11 | 12 | -------------------------------------------------------------------------------- /audioSpectrumAnalyzer/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 11 | 12 | 15 | 16 | -------------------------------------------------------------------------------- /audioSpectrumAnalyzer/src/main/res/drawable/ic_screenshot.xml: -------------------------------------------------------------------------------- 1 | 7 | 11 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /audioSpectrumAnalyzer/src/main/res/layout/activity_info_rec.xml: -------------------------------------------------------------------------------- 1 | 6 | 11 | 12 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /audioSpectrumAnalyzer/src/main/res/menu/info_rec.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 19 | 20 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /util/cm_list.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Ref: 4 | # Origin (mpl colormaps): 5 | # https://bids.github.io/colormap/ 6 | # Raw data: 7 | # https://github.com/BIDS/colormap/blob/master/colormaps.py 8 | 9 | import csv 10 | import numpy as np 11 | #import matplotlib.pyplot as plt # matplotlib ver >= 1.5 12 | names = ['magma', 'inferno', 'plasma', 'viridis', 'blackbody_uniform'] 13 | 14 | for c_name in names: 15 | # cmap = np.array(plt.get_cmap(c_name).colors) # if use matplotlib 16 | with open(c_name+'.csv', 'rb') as f: 17 | reader = csv.reader(f) 18 | cmap = np.array(list(reader)).astype(np.float) 19 | #Note: len(cmap) == 256 20 | if len(cmap)==256: 21 | cm = np.floor(cmap[::-1] * 255.99); 22 | else: 23 | cm = np.vstack((np.floor(cmap[::-1] * 255.99),[0,0,0])) 24 | cm[-1] = [0, 0, 0] # make last block black 25 | s = ", ".join([("0x%06x" % (c[0] * 2**16 + c[1] * 2**8 + c[2])) for c in cm]) 26 | s2 = '\n'.join([s[0+i:80+i] for i in range(0, len(s), 80)]) 27 | print("static final int[] " + c_name + " = {\n" + s2 + "\n};\n") 28 | 29 | -------------------------------------------------------------------------------- /audioSpectrumAnalyzer/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdk 35 5 | namespace 'org.woheller69.audio_analyzer_for_android' 6 | android.buildFeatures.buildConfig true 7 | 8 | defaultConfig { 9 | applicationId "org.woheller69.audio_analyzer_for_android" 10 | minSdkVersion 14 11 | targetSdk 35 12 | versionCode 310 13 | versionName "3.1" 14 | } 15 | 16 | compileOptions { 17 | sourceCompatibility JavaVersion.VERSION_1_8 18 | targetCompatibility JavaVersion.VERSION_1_8 19 | } 20 | 21 | buildTypes { 22 | release { 23 | shrinkResources true 24 | minifyEnabled true 25 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt') 26 | } 27 | } 28 | 29 | } 30 | 31 | dependencies { 32 | implementation project(':FFTLibrary') 33 | implementation 'androidx.legacy:legacy-support-v4:1.0.0' 34 | implementation 'androidx.appcompat:appcompat:1.6.1' //1.7.1 requires minSDK 21 35 | implementation 'androidx.preference:preference:1.2.1' 36 | implementation 'com.github.woheller69:FreeDroidWarn:V1.6' 37 | } 38 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/full_description.txt: -------------------------------------------------------------------------------- 1 | Audio Spectrum Analyzer was designed with accuracy and ease of use in mind. It can be used for monitoring or measuring environmental sound or noise; help tuning instruments; timing short sound events; and educational purpose. 2 | 3 |
Features: 4 | 5 | * No Ads. 6 | * With log or linear frequency axis. 7 | * Can label frequency axis using music pitch note. 8 | * Support all possible sampling rates and almost all recorder sources of your device. 9 | * Graph with nice grid lines and labels, easy to operate. 10 | * FFT sample size range from 64 to 32768. Using half-overlapped (adjustable) time window to increase time resolution. 11 | * Various window functions provided, for different frequency resolution and dynamical range. 12 | * Peak frequency detection (in unit of Hz and note+cent), with a moderate accuracy (FFT + interpolation). 13 | * With dB or A-weighting dB (dBA). 14 | * Can record the audio in wav (PCM) format. 15 | * Pinch to zoom, drag or swipe to move, long-press to place cursor, double touch to reset zoom. 16 | 17 | Notes: May need some knowledge of discrete Fourier transform and spectrum analysis to use it well. The actual accuracy mainly depends on your device. No calibration interface provided. 18 | -------------------------------------------------------------------------------- /audioSpectrumAnalyzer/src/main/res/layout/dialog_set_cursor_freq.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 12 | 13 | 22 | 23 | 31 | 32 | -------------------------------------------------------------------------------- /fastlane/metadata/android/ru-RU/full_description.txt: -------------------------------------------------------------------------------- 1 | Audio Spectrum Analyzer был разработан быть точным и простотым в использовании. Его можно использовать для отслеживания или измерения окружающего звука или шума; помогает в настройке инструментов; замер коротких звуковых событий; и в образовательной цели. 2 | 3 |
Возможности: 4 | 5 | * Без рекламы. 6 | * С ординатой логарифимической или линейной частоты. 7 | * Может пометить частоту оси ординаты с использованием музыкальной ноты. 8 | * Поддерживает все возможные скорости выборки (семплинга) и почти все источники звука на вашем устройстве. 9 | * График с хорошими сетками и метками, с ними легко работать. 10 | * Размер выборки FFT варьируется от 64 до 32768. Используя полу-перекрытое (регулируемое) временное окно для увеличения разрешения времени. 11 | * Различные оконные функции, предоставленные для различного частотного разрешения и динамического диапазона. 12 | * Обнаружение пиковой частоты (в еденицах Гц и нота+процент), с умеренной точностью (FFT + интерполяция). 13 | * С дБ или A-весовым дБ (дБА). 14 | * Может записать аудио в формате WAV (PCM). 15 | * Зажмите для масштабирования, перетащите или проведите чтобы передвинуть, долгое нажатие чтобы поместить курсор, двойной нажатие чтобы сбросить увеличение. 16 | 17 | Примечание: может потребоваться некоторое знание дискретного преобразования Фурье и спектрального анализа чтобы использовать его правильно. Фактическая точность в основном зависит от вашего устройства. Калибровочный интерфейс отсутсвует. 18 | -------------------------------------------------------------------------------- /audioSpectrumAnalyzer/src/main/java/org/woheller69/audio_analyzer_for_android/FPSCounter.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2014 Eddy Xiao 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package org.woheller69.audio_analyzer_for_android; 17 | 18 | import android.os.SystemClock; 19 | import android.util.Log; 20 | 21 | // Frames Per Second Counter 22 | 23 | class FPSCounter { 24 | private long frameCount; 25 | private long timeOld, timeUpdateInterval; // in ms 26 | private double fps; 27 | private String TAG_OUTSIDE; 28 | 29 | FPSCounter(String TAG) { 30 | timeUpdateInterval = 2000; 31 | TAG_OUTSIDE = TAG; 32 | frameCount = 0; 33 | timeOld = SystemClock.uptimeMillis(); 34 | } 35 | 36 | // call this when number of frames plus one 37 | void inc() { 38 | frameCount++; 39 | long timeNow = SystemClock.uptimeMillis(); 40 | if (timeOld + timeUpdateInterval <= timeNow) { 41 | fps = 1000 * (double) frameCount / (timeNow - timeOld); 42 | Log.d(TAG_OUTSIDE, "FPS: " + Math.round(100*fps)/100.0 + 43 | " (" + frameCount + "/" + (timeNow - timeOld) + "ms)"); 44 | timeOld = timeNow; 45 | frameCount = 0; 46 | } 47 | } 48 | 49 | public double getFPS() { 50 | return fps; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /audioSpectrumAnalyzer/src/main/java/org/woheller69/audio_analyzer_for_android/ScreenCapture.java: -------------------------------------------------------------------------------- 1 | package org.woheller69.audio_analyzer_for_android; 2 | 3 | import static android.os.Environment.DIRECTORY_PICTURES; 4 | 5 | import android.app.Activity; 6 | import android.graphics.Bitmap; 7 | import android.os.Environment; 8 | import android.util.Log; 9 | import android.view.View; 10 | import android.widget.Toast; 11 | 12 | import java.io.File; 13 | import java.io.FileOutputStream; 14 | import java.text.DateFormat; 15 | import java.text.SimpleDateFormat; 16 | import java.util.Date; 17 | import java.util.Locale; 18 | 19 | public class ScreenCapture { 20 | 21 | public static boolean ScreenCapture(Activity activity){ 22 | 23 | File path = Environment.getExternalStoragePublicDirectory(DIRECTORY_PICTURES); 24 | if (!path.exists() && !path.mkdirs()) { 25 | Log.e("Screencapture", "Failed to make directory: " + path.toString()); 26 | return false; 27 | } 28 | DateFormat df = new SimpleDateFormat("yyyy-MM-dd_HH'h'mm'm'ss.SS's'", Locale.US); 29 | String nowStr = df.format(new Date()); 30 | File imageFile = new File(path, "sc" + nowStr + ".jpg"); 31 | try { 32 | Log.e("Screencapture", String.valueOf(imageFile)); 33 | // create bitmap screen capture 34 | View view = activity.getWindow().getDecorView().getRootView(); 35 | view.setDrawingCacheEnabled(true); 36 | Bitmap bitmap = Bitmap.createBitmap(view.getDrawingCache()); 37 | view.setDrawingCacheEnabled(false); 38 | 39 | FileOutputStream outputStream = new FileOutputStream(imageFile); 40 | int quality = 95; 41 | bitmap.compress(Bitmap.CompressFormat.JPEG, quality, outputStream); 42 | outputStream.flush(); 43 | outputStream.close(); 44 | Toast.makeText(activity,activity.getString(R.string.screenshot)+String.valueOf(imageFile),Toast.LENGTH_LONG).show(); 45 | return true; 46 | } catch (Throwable e) { 47 | e.printStackTrace(); 48 | } 49 | return false; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /audioSpectrumAnalyzer/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 21 | 25 | 26 | 27 | 28 | 29 | 30 | 35 | 38 | 39 | 43 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /audioSpectrumAnalyzer/src/main/res/values/audio_source.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 0 21 | 1 22 | 2 23 | 3 24 | 4 25 | 5 26 | 6 27 | 7 28 | 8 29 | 9 30 | 31 | 32 | 33 | DEFAULT 34 | MIC 35 | VOICE_UPLINK 36 | VOICE_DOWNLINK 37 | VOICE_CALL 38 | CAMCORDER 39 | VOICE_RECOGNITION 40 | VOICE_COMMUNICATION 41 | REMOTE_SUBMIX 42 | UNPROCESSED 43 | 44 | 45 | 46 | 47 | 1 48 | 1 49 | 4 50 | 4 51 | 4 52 | 7 53 | 7 54 | 11 55 | 19 56 | 24 57 | 58 | 59 | 60 | 61 | "" 62 | "" 63 | "CAPTURE_AUDIO_OUTPUT" 64 | "CAPTURE_AUDIO_OUTPUT" 65 | "" 66 | "" 67 | "" 68 | "" 69 | "CAPTURE_AUDIO_OUTPUT" 70 | "" 71 | 72 | 73 | 74 | 8000 75 | 11025 76 | 16000 77 | 22050 78 | 32000 79 | 44100 80 | 48000 81 | 96000 82 | 192000 83 | 84 | -------------------------------------------------------------------------------- /audioSpectrumAnalyzer/src/main/java/org/woheller69/audio_analyzer_for_android/SetCursorFreqDialog.java: -------------------------------------------------------------------------------- 1 | package org.woheller69.audio_analyzer_for_android; 2 | 3 | import android.content.Context; 4 | import android.content.DialogInterface; 5 | import android.util.Log; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.widget.EditText; 9 | 10 | import androidx.appcompat.app.AlertDialog; 11 | 12 | import java.text.DecimalFormat; 13 | 14 | public class SetCursorFreqDialog { 15 | private static final String TAG = "CursorFreqDialog:"; 16 | 17 | private final AnalyzerActivity ct; 18 | private final AnalyzerGraphic graphView; 19 | private View setCursorFrequencyView; 20 | private EditText et_cursor_freq; 21 | private AlertDialog setCursorFreqDialog; 22 | 23 | SetCursorFreqDialog(AnalyzerActivity _ct, AnalyzerGraphic _graphView) { 24 | ct = _ct; 25 | graphView = _graphView; 26 | buildDialog(ct); 27 | } 28 | 29 | void ShowSetCursorFreqDialog() { 30 | Log.d(TAG, "ShowSetCursorFreqDialog(): SetCursorFreqDialog is not prepared."); 31 | 32 | double current_cursor_freq = graphView.getCursorFreq(); 33 | DecimalFormat df = new DecimalFormat("#.##"); 34 | ((EditText) setCursorFrequencyView.findViewById(R.id.et_cursor_freq)).setText(df.format(current_cursor_freq)); 35 | setCursorFreqDialog.show(); 36 | } 37 | 38 | private void buildDialog(Context context) { 39 | LayoutInflater inflater = LayoutInflater.from(context); 40 | setCursorFrequencyView = inflater.inflate(R.layout.dialog_set_cursor_freq, null); 41 | et_cursor_freq = setCursorFrequencyView.findViewById(R.id.et_cursor_freq); 42 | AlertDialog.Builder setCursorFreqBuilder = new AlertDialog.Builder(context); 43 | setCursorFreqBuilder 44 | .setView(setCursorFrequencyView) 45 | .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { 46 | @Override 47 | public void onClick(DialogInterface dialog, int id) { 48 | setCursorFrequencyView.findViewById(R.id.et_cursor_freq); 49 | if (!et_cursor_freq.getText().toString().equals("")) 50 | graphView.setCursorFreq(Double.parseDouble(et_cursor_freq.getText().toString().replaceAll(",","."))); 51 | // Save setting to preference, after sanitized. 52 | } 53 | }) 54 | .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { 55 | public void onClick(DialogInterface dialog, int id) { 56 | Log.v(TAG, "cursor frequency dialog: Canceled"); 57 | } 58 | }); 59 | 60 | setCursorFreqDialog = setCursorFreqBuilder.create(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /audioSpectrumAnalyzer/src/main/java/org/woheller69/audio_analyzer_for_android/AnalyzerParameters.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Eddy Xiao 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package org.woheller69.audio_analyzer_for_android; 17 | 18 | import android.content.res.Resources; 19 | import android.media.MediaRecorder; 20 | import android.util.Log; 21 | 22 | /** 23 | * Basic properties of Analyzer. 24 | */ 25 | 26 | class AnalyzerParameters { 27 | final int RECORDER_AGC_OFF = MediaRecorder.AudioSource.VOICE_RECOGNITION; 28 | int audioSourceId = RECORDER_AGC_OFF; 29 | int sampleRate = 16000; 30 | int fftLen = 2048; 31 | int hopLen = 1024; 32 | int zeroPadFac = 1; 33 | double overlapPercent = 50; // = (1 - hopLen/fftLen) * 100% 34 | String wndFuncName; 35 | int nFFTAverage = 2; 36 | boolean isAWeighting = false; 37 | final int BYTE_OF_SAMPLE = 2; 38 | final double SAMPLE_VALUE_MAX = 32767.0; // Maximum signal value 39 | double spectrogramDuration = 4.0; 40 | 41 | double[] micGainDB = null; // should have fftLen/2+1 elements, i.e. include DC. 42 | String calibName = null; 43 | 44 | AnalyzerParameters(Resources res) { 45 | getAudioSourceNameFromIdPrepare(res); 46 | } 47 | 48 | String[] audioSourceNames; 49 | int[] audioSourceIDs; 50 | private void getAudioSourceNameFromIdPrepare(Resources res) { 51 | audioSourceNames = res.getStringArray(R.array.audio_source); 52 | String[] sasid = res.getStringArray(R.array.audio_source_id); 53 | audioSourceIDs = new int[audioSourceNames.length]; 54 | for (int i = 0; i < audioSourceNames.length; i++) { 55 | audioSourceIDs[i] = Integer.parseInt(sasid[i]); 56 | } 57 | } 58 | 59 | // Get audio source name from its ID 60 | // Tell me if there is better way to do it. 61 | String getAudioSourceNameFromId(int id) { 62 | for (int i = 0; i < audioSourceNames.length; i++) { 63 | if (audioSourceIDs[i] == id) { 64 | return audioSourceNames[i]; 65 | } 66 | } 67 | Log.i("AnalyzerParameters", "getAudioSourceName(): non-standard entry."); 68 | return ((Integer)(id)).toString(); 69 | } 70 | 71 | String getAudioSourceName() { 72 | return getAudioSourceNameFromId(audioSourceId); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /audioSpectrumAnalyzer/src/main/res/menu/info.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | 18 | 25 | 26 | 33 | 34 | 41 | 42 | 49 | 50 | 57 | 58 | 66 | 67 | 75 | 76 | -------------------------------------------------------------------------------- /audioSpectrumAnalyzer/src/main/java/org/woheller69/audio_analyzer_for_android/GithubStar.java: -------------------------------------------------------------------------------- 1 | package org.woheller69.audio_analyzer_for_android; 2 | 3 | import android.content.Context; 4 | import android.content.DialogInterface; 5 | import android.content.Intent; 6 | import android.content.SharedPreferences; 7 | import android.net.Uri; 8 | 9 | import androidx.appcompat.app.AlertDialog; 10 | import androidx.preference.PreferenceManager; 11 | 12 | public class GithubStar { 13 | public static void setAskForStar(Context context, boolean askForStar){ 14 | SharedPreferences prefManager = PreferenceManager.getDefaultSharedPreferences(context); 15 | SharedPreferences.Editor editor = prefManager.edit(); 16 | editor.putBoolean("askForStar", askForStar); 17 | editor.apply(); 18 | } 19 | 20 | public static boolean shouldShowStarDialog(Context context) { 21 | SharedPreferences prefManager = PreferenceManager.getDefaultSharedPreferences(context); 22 | int versionCode = prefManager.getInt("versionCode",0); 23 | boolean askForStar=prefManager.getBoolean("askForStar",true); 24 | 25 | if (prefManager.contains("versionCode") && BuildConfig.VERSION_CODE>versionCode && askForStar){ //not at first start, only after upgrade and only if use has not yet given a star or has declined 26 | SharedPreferences.Editor editor = prefManager.edit(); 27 | editor.putInt("versionCode", BuildConfig.VERSION_CODE); 28 | editor.apply(); 29 | return true; 30 | } else { 31 | SharedPreferences.Editor editor = prefManager.edit(); 32 | editor.putInt("versionCode", BuildConfig.VERSION_CODE); 33 | editor.apply(); 34 | return false; 35 | } 36 | } 37 | 38 | public static void starDialog(final Context context, final String url){ 39 | SharedPreferences prefManager = PreferenceManager.getDefaultSharedPreferences(context); 40 | if (prefManager.getBoolean("askForStar",true)) { 41 | AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(context); 42 | alertDialogBuilder.setMessage(R.string.dialog_StarOnGitHub); 43 | alertDialogBuilder.setPositiveButton(context.getString(R.string.dialog_OK_button), new DialogInterface.OnClickListener() { 44 | @Override 45 | public void onClick(DialogInterface dialog, int which) { 46 | context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url))); 47 | setAskForStar(context,false); 48 | } 49 | }); 50 | alertDialogBuilder.setNegativeButton(context.getString(R.string.dialog_NO_button), new DialogInterface.OnClickListener() { 51 | @Override 52 | public void onClick(DialogInterface dialog, int which) { 53 | setAskForStar(context,false); 54 | } 55 | }); 56 | alertDialogBuilder.setNeutralButton(context.getString(R.string.dialog_Later_button), null); 57 | 58 | AlertDialog alertDialog = alertDialogBuilder.create(); 59 | alertDialog.show(); 60 | } 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /audioSpectrumAnalyzer/src/main/res/drawable/ic_launcher_monochrome.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 10 | 14 | 18 | 22 | 26 | 30 | 34 | 38 | 42 | 46 | 50 | 54 | 55 | -------------------------------------------------------------------------------- /util/blackbody.m: -------------------------------------------------------------------------------- 1 | % GNU Octave script 2 | warning ("off", "Octave:broadcast"); 3 | 4 | % Physical constants, from CODATA 2014 5 | c = 299792458; 6 | h = 6.626070040e-34; % Planck constant 7 | kB = 1.38064852e-23; % Boltzmann constant 8 | c1 = 2 * h * c * c; 9 | c2 = h * c / kB; 10 | PlanksLaw = @(T, lambda) c1 ./ lambda .^ 5 ./ (exp(c2 ./ lambda ./ T) - 1); 11 | 12 | % Temperature range 13 | T0 = 300; 14 | T1 = 12000; 15 | n_div = 256; 16 | 17 | % Calculate CIE XYZ of the blackbody spectrum 18 | cmf = load('ciexyzjv.csv'); 19 | %T_s = fliplr(1 ./ linspace(1/T1, 1/T0, n_div)); 20 | %T_s = linspace(T0, T1, n_div); 21 | e_T = 4; 22 | T_s = linspace(T0^(1/e_T), T1^(1/e_T), n_div).^e_T; 23 | rgb = zeros(length(T_s), 3); 24 | for id_T = 1:length(T_s) 25 | rgb(id_T, :) = cmf(:, 2:4)' * PlanksLaw(T_s(id_T), cmf(:, 1)*1e-9); 26 | end 27 | rgb ./= rgb(:, 2); % more uniform lighting 28 | rgb .*= 1 - atan(1 ./ ((T_s-T0+1)' / 2000) .^ 1.5) / pi * 2; % light adjust 29 | rgb *= 0.8; % factor to make RGB brighter 30 | 31 | % Convert to sRGB 32 | sRGB_M = [ 33 | 3.2406 -1.5372 -0.4986 34 | -0.9689 1.8758 0.0415 35 | 0.0557 -0.2040 1.0570]; 36 | 37 | CSRGB = @(c) (12.92*c).*(c<=0.0031308) + (1.055*c.^(1/2.4)-0.055) .* (1-(c<=0.0031308)); 38 | 39 | rgb = rgb * sRGB_M'; % CIE XYZ to sRGB RGB (linear) 40 | rgb = CSRGB(rgb); 41 | 42 | rgb(rgb>1) = 1; 43 | rgb(rgb<0) = 0; 44 | 45 | figure(1); 46 | subplot(2,1,1); 47 | rgbplot(rgb, 'profile'); 48 | xlim([0 length(rgb)]); 49 | subplot(2,1,2); 50 | rgbplot(rgb, 'composite'); 51 | 52 | % inv gamma 53 | invCSRGB = @(cs) (cs/12.92).*(cs<=0.040449936) + (((cs+0.055)/1.055).^2.4) .* (1 - (cs<=0.040449936)); 54 | figure(2); 55 | plot(1:length(T_s), invCSRGB(rgb) * [0.2126 0.7152 0.0722]'); 56 | title('Relative luminance'); 57 | 58 | c = rgb; 59 | c(2,:) = [5/255 0 0]; % hand tune, make it brighter 60 | 61 | fid = fopen('./blackbody.csv', 'w'); 62 | for i=2:length(c) % ignore the first value, which should be filled by black 63 | fprintf(fid, '%.16f, %.16f, %.16f\n', c(i,1), c(i,2), c(i,3)); 64 | end 65 | fclose(fid); 66 | # then the file balckbody.csv can be read by cm_list.py 67 | 68 | %v=int32(floor(flipud(c)*255.99)*[0x10000 0x100 1]'); 69 | %s=reshape(sprintf('0x%06x, ', v), 10*8, [])(1:end-1,:)'; s(end)=' ' 70 | 71 | cm_ex1 = hot(256); 72 | 73 | figure(9); 74 | subplot(2,1,1); 75 | rgbplot(cm_ex1, 'profile'); 76 | xlim([0 length(cm_ex1)]); 77 | subplot(2,1,2); 78 | rgbplot(cm_ex1, 'composite'); 79 | title('hot'); 80 | 81 | figure(10); 82 | plot(1:length(cm_ex1), invCSRGB(cm_ex1) * [0.2126 0.7152 0.0722]'); 83 | title('Relative luminance (hot)'); 84 | 85 | %{ 86 | % approximation 87 | function [x y] = CIE_xy_Temp(T) 88 | % in CIE xy 89 | if (T < 4000) 90 | x = -0.2661239*1e9/T/T/T - 0.2343580*1e6/T/T + 0.8776956*1e3/T + 0.179910; 91 | else 92 | x = -3.0258469*1e9/T/T/T + 2.1070379*1e6/T/T + 0.2226347*1e3/T + 0.240390; 93 | end 94 | if (T < 2222) 95 | y = -1.1063814*x*x*x - 1.34811020*x*x + 2.18555832*x - 0.20219683; 96 | elseif (T < 4000) 97 | y = -0.9549476*x*x*x - 1.37418593*x*x + 2.09137015*x - 0.16748867; 98 | else 99 | y = 3.0817580*x*x*x - 5.87338670*x*x + 3.75112997*x - 0.37001483; 100 | end 101 | endfunction 102 | 103 | function [r,g,b] = rgb_temp(T, Y) 104 | [x y] = CIE_xy_Temp(T); 105 | X = Y * x / y; 106 | Z = Y * (1-x-y) / y; 107 | CSRGB = @(c) (12.92*c).*(c<=0.0031308) + (1.055*c^(1/2.4)-0.055) .* (1-(c<=0.0031308)); 108 | r = CSRGB( 3.2406*X - 1.5372*Y - 0.4986*Z); 109 | g = CSRGB(-0.9689*X + 1.8758*Y + 0.0415*Z); 110 | b = CSRGB( 0.0557*X - 0.2040*Y + 1.0570*Z); 111 | endfunction 112 | %} 113 | -------------------------------------------------------------------------------- /audioSpectrumAnalyzer/src/main/java/org/woheller69/audio_analyzer_for_android/SineGenerator.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2011 Google Inc. 2 | * 3 | *Licensed under the Apache License, Version 2.0 (the "License"); 4 | *you may not use this file except in compliance with the License. 5 | *You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | *Unless required by applicable law or agreed to in writing, software 10 | *distributed under the License is distributed on an "AS IS" BASIS, 11 | *WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | *See the License for the specific language governing permissions and 13 | *limitations under the License. 14 | * 15 | * @author Stephen Uhler 16 | */ 17 | 18 | package org.woheller69.audio_analyzer_for_android; 19 | 20 | /** 21 | * Recursive sine wave generator 22 | * - compute parameters using double() 23 | * 24 | * y[n] = 2cos(w)y[n-1] - y[n-2] 25 | * w = 2 pi f / fs 26 | */ 27 | 28 | class SineGenerator { 29 | private double fs; // sampling frequency 30 | private double k; // recursion constant 31 | private double n0, n1; // first (next) 2 samples 32 | 33 | /** 34 | * Create a sine wave generator: 35 | * @param f frequency of the sine wave (hz) 36 | * @param fs Sampling rate (hz) 37 | * @param a Amplitude 38 | */ 39 | 40 | SineGenerator(double f, double fs, double a) { 41 | this.fs = fs; 42 | double w = 2.0 * Math.PI * f / fs; 43 | this.n0 = 0d; 44 | this.n1 = a * Math.cos(w + Math.PI/2.0); 45 | this.k = 2.0 * Math.cos(w); 46 | } 47 | 48 | /** 49 | * Set the new frequency, maintaining the phase 50 | * @param f New frequency, hz 51 | */ 52 | 53 | public void setF(double f) { 54 | double w = 2.0 * Math.PI * f / fs; 55 | k = getK(f); 56 | 57 | double theta = Math.acos(n0); 58 | if (n1 > n0) theta = 2 * Math.PI - theta; 59 | n0 = Math.cos(theta); 60 | n1 = Math.cos(w + theta); 61 | } 62 | 63 | /** 64 | * Compute the recursion coefficient "k" 65 | */ 66 | private double getK(double f) { 67 | double w = 2.0 * Math.PI * f / fs; 68 | return 2.0 * Math.cos(w); 69 | } 70 | 71 | /** 72 | * Generate the next batch of samples. 73 | * @param samples Where to put the samples 74 | * @param start Start sample 75 | * @param count # of samples (must be even) 76 | */ 77 | 78 | private void getSamples(double[] samples, int start, int count) { 79 | for(int cnt = start; cnt < count; cnt += 2) { 80 | samples[cnt] = n0 = (k * n1) - n0; 81 | samples[cnt + 1] = n1 = (k * n0) - n1; 82 | } 83 | } 84 | 85 | /** 86 | * Fill the supplied (even length) array with samples. 87 | */ 88 | 89 | void getSamples(double[] samples) { 90 | getSamples(samples, 0, samples.length); 91 | } 92 | 93 | /** 94 | * Add samples to an existing buffer 95 | * @param samples Where to put the samples 96 | * @param start Start sample 97 | * @param count # of samples (must be even) 98 | */ 99 | private void addSamples(double[] samples, int start, int count) { 100 | for(int cnt=start; cntnorm_factor can be used to normalize this FFT transform. This is because 33 | * a call of forward transform (ft) followed by a call of backward transform 34 | * (bt) will multiply the input sequence by norm_factor. 35 | */ 36 | public double norm_factor; 37 | private double wavetable[]; 38 | private double[] ch; // reusable work array 39 | private int ndim; 40 | 41 | /** 42 | * Construct a wavenumber table with size n. 43 | * The sequences with the same size can share a wavenumber table. The prime 44 | * factorization of n together with a tabulation of the trigonometric functions 45 | * are computed and stored. 46 | * 47 | * @param n the size of a real data sequence. When n is a multiplication of small 48 | * numbers (4, 2, 3, 5), this FFT transform is very efficient. 49 | */ 50 | public RealDoubleFFT(int n) 51 | { 52 | ndim = n; 53 | norm_factor = n; 54 | if(wavetable == null || wavetable.length !=(2*ndim+15)) { 55 | wavetable = new double[2*ndim + 15]; 56 | } 57 | rffti(ndim, wavetable); 58 | ch = new double[n]; 59 | } 60 | 61 | /** 62 | * Forward real FFT transform. It computes the discrete transform of a real data sequence. 63 | * 64 | * @param x an array which contains the sequence to be transformed. After FFT, 65 | * x contains the transform coeffients used to construct n complex FFT coeffients. 66 | *
67 | * The real part of the first complex FFT coeffients is x[0]; its imaginary part 68 | * is 0. If n is even set m = n/2, if n is odd set 69 | * m = n/2, then for 70 | *
71 | * k = 1, ..., m-1
72 | * the real part of k-th complex FFT coeffients is x[2*k-1]; 73 | *
74 | * the imaginary part of k-th complex FFT coeffients is x[2*k-2]. 75 | *
76 | * If n is even, 77 | * the real of part of (n/2)-th complex FFT coeffients is x[n]; its imaginary part is 0. 78 | * The remaining complex FFT coeffients can be obtained by the symmetry relation: 79 | * the (n-k)-th complex FFT coeffient is the conjugate of n-th complex FFT coeffient. 80 | * 81 | */ 82 | public void ft(double x[]) { 83 | if(x.length != ndim) 84 | throw new IllegalArgumentException("The length of data can not match that of the wavetable"); 85 | rfftf(ndim, x, wavetable, ch); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /example_calibration.txt: -------------------------------------------------------------------------------- 1 | "miniDSP PMIK-1 calibration file, serial: 8000234, format: txt" 2 | 20.00 -4.2 3 | 20.55 -3.8 4 | 21.11 -3.4 5 | 21.69 -3.0 6 | 22.29 -2.6 7 | 22.90 -2.3 8 | 23.53 -2.0 9 | 24.18 -1.7 10 | 24.84 -1.5 11 | 25.52 -1.3 12 | 26.22 -1.1 13 | 26.94 -0.9 14 | 27.68 -0.8 15 | 28.44 -0.7 16 | 29.22 -0.6 17 | 30.03 -0.5 18 | 30.85 -0.4 19 | 31.70 -0.3 20 | 32.57 -0.2 21 | 33.46 -0.2 22 | 34.38 -0.1 23 | 35.33 -0.1 24 | 36.30 0.0 25 | 37.29 0.0 26 | 38.32 0.0 27 | 39.37 0.1 28 | 40.45 0.1 29 | 41.56 0.1 30 | 42.70 0.2 31 | 43.87 0.2 32 | 45.08 0.2 33 | 46.32 0.3 34 | 47.59 0.3 35 | 48.90 0.4 36 | 50.24 0.4 37 | 51.62 0.4 38 | 53.03 0.5 39 | 54.49 0.5 40 | 55.99 0.5 41 | 57.52 0.6 42 | 59.10 0.6 43 | 60.73 0.6 44 | 62.39 0.6 45 | 64.11 0.6 46 | 65.87 0.6 47 | 67.68 0.6 48 | 69.54 0.7 49 | 71.44 0.7 50 | 73.41 0.7 51 | 75.42 0.7 52 | 77.49 0.8 53 | 79.62 0.8 54 | 81.81 0.8 55 | 84.05 0.8 56 | 86.36 0.8 57 | 88.73 0.8 58 | 91.17 0.8 59 | 93.67 0.7 60 | 96.25 0.7 61 | 98.89 0.7 62 | 101.60 0.7 63 | 104.39 0.6 64 | 107.26 0.6 65 | 110.21 0.5 66 | 113.23 0.5 67 | 116.34 0.4 68 | 119.54 0.4 69 | 122.82 0.4 70 | 126.19 0.3 71 | 129.66 0.3 72 | 133.22 0.3 73 | 136.87 0.3 74 | 140.63 0.4 75 | 144.50 0.4 76 | 148.46 0.5 77 | 152.54 0.6 78 | 156.73 0.6 79 | 161.03 0.7 80 | 165.45 0.7 81 | 170.00 0.8 82 | 174.67 0.8 83 | 179.46 0.9 84 | 184.39 1.0 85 | 189.45 1.0 86 | 194.65 0.9 87 | 200.00 0.9 88 | 205.49 0.8 89 | 211.13 0.8 90 | 216.93 0.8 91 | 222.89 0.7 92 | 229.01 0.7 93 | 235.30 0.6 94 | 241.76 0.6 95 | 248.40 0.6 96 | 255.22 0.7 97 | 262.23 0.8 98 | 269.43 0.9 99 | 276.83 0.9 100 | 284.43 0.9 101 | 292.24 0.9 102 | 300.26 0.9 103 | 308.51 0.9 104 | 316.98 0.8 105 | 325.68 0.7 106 | 334.63 0.6 107 | 343.81 0.5 108 | 353.26 0.4 109 | 362.96 0.3 110 | 372.92 0.3 111 | 383.16 0.3 112 | 393.68 0.4 113 | 404.49 0.4 114 | 415.60 0.4 115 | 427.01 0.5 116 | 438.74 0.5 117 | 450.79 0.6 118 | 463.17 0.6 119 | 475.88 0.6 120 | 488.95 0.5 121 | 502.38 0.4 122 | 516.17 0.3 123 | 530.35 0.3 124 | 544.91 0.3 125 | 559.87 0.2 126 | 575.25 0.2 127 | 591.04 0.2 128 | 607.27 0.2 129 | 623.95 0.2 130 | 641.08 0.3 131 | 658.68 0.3 132 | 676.77 0.3 133 | 695.35 0.3 134 | 714.45 0.3 135 | 734.07 0.3 136 | 754.22 0.3 137 | 774.94 0.3 138 | 796.21 0.3 139 | 818.08 0.3 140 | 840.54 0.3 141 | 863.62 0.3 142 | 887.34 0.3 143 | 911.70 0.2 144 | 936.74 0.2 145 | 962.46 0.2 146 | 988.89 0.1 147 | 1016.04 0.0 148 | 1043.94 -0.1 149 | 1072.61 -0.2 150 | 1102.06 -0.2 151 | 1132.33 -0.2 152 | 1163.42 -0.2 153 | 1195.37 -0.1 154 | 1228.19 0.0 155 | 1261.91 0.1 156 | 1296.57 0.1 157 | 1332.17 0.2 158 | 1368.75 0.2 159 | 1406.34 0.2 160 | 1444.95 0.2 161 | 1484.63 0.2 162 | 1525.40 0.1 163 | 1567.28 0.2 164 | 1610.32 0.2 165 | 1654.54 0.2 166 | 1699.97 0.2 167 | 1746.65 0.3 168 | 1794.61 0.4 169 | 1843.89 0.5 170 | 1894.53 0.6 171 | 1946.55 0.5 172 | 2000.00 0.3 173 | 2054.92 0.1 174 | 2111.35 0.0 175 | 2169.32 0.0 176 | 2228.89 0.2 177 | 2290.10 0.2 178 | 2352.98 0.1 179 | 2417.59 0.0 180 | 2483.98 0.0 181 | 2552.19 0.3 182 | 2622.27 0.5 183 | 2694.27 0.8 184 | 2768.26 1.0 185 | 2844.27 1.2 186 | 2922.37 1.4 187 | 3002.62 1.5 188 | 3085.07 1.4 189 | 3169.79 1.4 190 | 3256.83 1.2 191 | 3346.26 1.1 192 | 3438.14 1.0 193 | 3532.55 0.8 194 | 3629.56 0.8 195 | 3729.22 0.8 196 | 3831.62 1.1 197 | 3936.84 1.5 198 | 4044.94 1.9 199 | 4156.01 2.1 200 | 4270.14 2.3 201 | 4387.39 2.3 202 | 4507.87 2.2 203 | 4631.65 2.0 204 | 4758.83 1.8 205 | 4889.51 1.8 206 | 5023.77 2.0 207 | 5161.72 2.0 208 | 5303.46 2.1 209 | 5449.09 1.9 210 | 5598.72 1.6 211 | 5752.46 1.2 212 | 5910.42 0.9 213 | 6072.72 0.8 214 | 6239.47 0.7 215 | 6410.80 0.6 216 | 6586.84 0.5 217 | 6767.71 0.5 218 | 6953.55 0.7 219 | 7144.49 0.9 220 | 7340.67 0.9 221 | 7542.24 0.6 222 | 7749.35 0.4 223 | 7962.14 0.5 224 | 8180.78 1.1 225 | 8405.42 1.4 226 | 8636.23 1.5 227 | 8873.37 1.4 228 | 9117.03 1.5 229 | 9367.38 1.8 230 | 9624.61 1.8 231 | 9888.89 1.4 232 | 10160.44 1.2 233 | 10439.44 1.1 234 | 10726.10 0.6 235 | 11020.63 -0.3 236 | 11323.25 -1.1 237 | 11634.18 -1.1 238 | 11953.65 -0.6 239 | 12281.89 -0.3 240 | 12619.15 -0.2 241 | 12965.66 -0.2 242 | 13321.69 -0.7 243 | 13687.50 -1.4 244 | 14063.35 -1.9 245 | 14449.52 -2.6 246 | 14846.30 -3.2 247 | 15253.97 -3.2 248 | 15672.84 -3.2 249 | 16103.21 -3.2 250 | 16545.39 -3.0 251 | 16999.72 -3.0 252 | 17466.52 -3.5 253 | 17946.14 -3.8 254 | 18438.94 -4.1 255 | 18945.26 -4.2 256 | 19465.49 -4.9 257 | 20000.00 -5.0 258 | -------------------------------------------------------------------------------- /util/ciexyzjv.csv: -------------------------------------------------------------------------------- 1 | 380,2.689900e-003,2.000000e-004,1.226000e-002 2 | 385,5.310500e-003,3.955600e-004,2.422200e-002 3 | 390,1.078100e-002,8.000000e-004,4.925000e-002 4 | 395,2.079200e-002,1.545700e-003,9.513500e-002 5 | 400,3.798100e-002,2.800000e-003,1.740900e-001 6 | 405,6.315700e-002,4.656200e-003,2.901300e-001 7 | 410,9.994100e-002,7.400000e-003,4.605300e-001 8 | 415,1.582400e-001,1.177900e-002,7.316600e-001 9 | 420,2.294800e-001,1.750000e-002,1.065800e+000 10 | 425,2.810800e-001,2.267800e-002,1.314600e+000 11 | 430,3.109500e-001,2.730000e-002,1.467200e+000 12 | 435,3.307200e-001,3.258400e-002,1.579600e+000 13 | 440,3.333600e-001,3.790000e-002,1.616600e+000 14 | 445,3.167200e-001,4.239100e-002,1.568200e+000 15 | 450,2.888200e-001,4.680000e-002,1.471700e+000 16 | 455,2.596900e-001,5.212200e-002,1.374000e+000 17 | 460,2.327600e-001,6.000000e-002,1.291700e+000 18 | 465,2.099900e-001,7.294200e-002,1.235600e+000 19 | 470,1.747600e-001,9.098000e-002,1.113800e+000 20 | 475,1.328700e-001,1.128400e-001,9.422000e-001 21 | 480,9.194400e-002,1.390200e-001,7.559600e-001 22 | 485,5.698500e-002,1.698700e-001,5.864000e-001 23 | 490,3.173100e-002,2.080200e-001,4.466900e-001 24 | 495,1.461300e-002,2.580800e-001,3.411600e-001 25 | 500,4.849100e-003,3.230000e-001,2.643700e-001 26 | 505,2.321500e-003,4.054000e-001,2.059400e-001 27 | 510,9.289900e-003,5.030000e-001,1.544500e-001 28 | 515,2.927800e-002,6.081100e-001,1.091800e-001 29 | 520,6.379100e-002,7.100000e-001,7.658500e-002 30 | 525,1.108100e-001,7.951000e-001,5.622700e-002 31 | 530,1.669200e-001,8.620000e-001,4.136600e-002 32 | 535,2.276800e-001,9.150500e-001,2.935300e-002 33 | 540,2.926900e-001,9.540000e-001,2.004200e-002 34 | 545,3.622500e-001,9.800400e-001,1.331200e-002 35 | 550,4.363500e-001,9.949500e-001,8.782300e-003 36 | 555,5.151300e-001,1.000100e+000,5.857300e-003 37 | 560,5.974800e-001,9.950000e-001,4.049300e-003 38 | 565,6.812100e-001,9.787500e-001,2.921700e-003 39 | 570,7.642500e-001,9.520000e-001,2.277100e-003 40 | 575,8.439400e-001,9.155800e-001,1.970600e-003 41 | 580,9.163500e-001,8.700000e-001,1.806600e-003 42 | 585,9.770300e-001,8.162300e-001,1.544900e-003 43 | 590,1.023000e+000,7.570000e-001,1.234800e-003 44 | 595,1.051300e+000,6.948300e-001,1.117700e-003 45 | 600,1.055000e+000,6.310000e-001,9.056400e-004 46 | 605,1.036200e+000,5.665400e-001,6.946700e-004 47 | 610,9.923900e-001,5.030000e-001,4.288500e-004 48 | 615,9.286100e-001,4.417200e-001,3.181700e-004 49 | 620,8.434600e-001,3.810000e-001,2.559800e-004 50 | 625,7.398300e-001,3.205200e-001,1.567900e-004 51 | 630,6.328900e-001,2.650000e-001,9.769400e-005 52 | 635,5.335100e-001,2.170200e-001,6.894400e-005 53 | 640,4.406200e-001,1.750000e-001,5.116500e-005 54 | 645,3.545300e-001,1.381200e-001,3.601600e-005 55 | 650,2.786200e-001,1.070000e-001,2.423800e-005 56 | 655,2.148500e-001,8.165200e-002,1.691500e-005 57 | 660,1.616100e-001,6.100000e-002,1.190600e-005 58 | 665,1.182000e-001,4.432700e-002,8.148900e-006 59 | 670,8.575300e-002,3.200000e-002,5.600600e-006 60 | 675,6.307700e-002,2.345400e-002,3.954400e-006 61 | 680,4.583400e-002,1.700000e-002,2.791200e-006 62 | 685,3.205700e-002,1.187200e-002,1.917600e-006 63 | 690,2.218700e-002,8.210000e-003,1.313500e-006 64 | 695,1.561200e-002,5.772300e-003,9.151900e-007 65 | 700,1.109800e-002,4.102000e-003,6.476700e-007 66 | 705,7.923300e-003,2.929100e-003,4.635200e-007 67 | 710,5.653100e-003,2.091000e-003,3.330400e-007 68 | 715,4.003900e-003,1.482200e-003,2.382300e-007 69 | 720,2.825300e-003,1.047000e-003,1.702600e-007 70 | 725,1.994700e-003,7.401500e-004,1.220700e-007 71 | 730,1.399400e-003,5.200000e-004,8.710700e-008 72 | 735,9.698000e-004,3.609300e-004,6.145500e-008 73 | 740,6.684700e-004,2.492000e-004,4.316200e-008 74 | 745,4.614100e-004,1.723100e-004,3.037900e-008 75 | 750,3.207300e-004,1.200000e-004,2.155400e-008 76 | 755,2.257300e-004,8.462000e-005,1.549300e-008 77 | 760,1.597300e-004,6.000000e-005,1.120400e-008 78 | 765,1.127500e-004,4.244600e-005,8.087300e-009 79 | 770,7.951300e-005,3.000000e-005,5.834000e-009 80 | 775,5.608700e-005,2.121000e-005,4.211000e-009 81 | 780,3.954100e-005,1.498900e-005,3.038300e-009 82 | 785,2.785200e-005,1.058400e-005,2.190700e-009 83 | 790,1.959700e-005,7.465600e-006,1.577800e-009 84 | 795,1.377000e-005,5.259200e-006,1.134800e-009 85 | 800,9.670000e-006,3.702800e-006,8.156500e-010 86 | 805,6.791800e-006,2.607600e-006,5.862600e-010 87 | 810,4.770600e-006,1.836500e-006,4.213800e-010 88 | 815,3.355000e-006,1.295000e-006,3.031900e-010 89 | 820,2.353400e-006,9.109200e-007,2.175300e-010 90 | 825,1.637700e-006,6.356400e-007,1.547600e-010 -------------------------------------------------------------------------------- /audioSpectrumAnalyzer/src/main/java/org/woheller69/audio_analyzer_for_android/MyPreferences.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2014 Eddy Xiao 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package org.woheller69.audio_analyzer_for_android; 17 | 18 | import android.content.Context; 19 | import android.content.Intent; 20 | import android.media.MediaRecorder; 21 | import android.os.Bundle; 22 | import androidx.preference.ListPreference; 23 | import android.util.Log; 24 | import androidx.appcompat.app.ActionBar; 25 | import androidx.appcompat.app.AppCompatActivity; 26 | 27 | import androidx.preference.PreferenceFragmentCompat; 28 | 29 | public class MyPreferences extends AppCompatActivity { 30 | 31 | private static final String TAG = "MyPreference"; 32 | private static String[] audioSources; 33 | private static String[] audioSourcesName; 34 | 35 | @Override 36 | protected void onCreate(Bundle savedInstanceState) { 37 | super.onCreate(savedInstanceState); 38 | setContentView(R.layout.settings_activity); 39 | 40 | ActionBar actionBar = getSupportActionBar(); 41 | if (actionBar != null) { 42 | actionBar.setDisplayHomeAsUpEnabled(true); 43 | } 44 | } 45 | 46 | public static class SettingsFragment extends PreferenceFragmentCompat { 47 | Context context; 48 | Intent intent; 49 | public SettingsFragment(Context context, Intent intent){ 50 | this.context = context; 51 | this.intent = intent; 52 | } 53 | @Override 54 | public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { 55 | setPreferencesFromResource(R.xml.preferences, rootKey); 56 | // Get list of default sources 57 | final int[] asid = intent.getIntArrayExtra(AnalyzerActivity.MYPREFERENCES_MSG_SOURCE_ID); 58 | final String[] as = intent.getStringArrayExtra(AnalyzerActivity.MYPREFERENCES_MSG_SOURCE_NAME); 59 | 60 | int nExtraSources = 0; 61 | for (int id : asid) { 62 | // See SamplingLoop::run() for the magic number 1000 63 | if (id >= 1000) nExtraSources++; 64 | } 65 | 66 | // Get list of supported sources 67 | AnalyzerUtil au = new AnalyzerUtil(context); 68 | final int[] audioSourcesId = au.GetAllAudioSource(4); 69 | Log.i(TAG, " n_as = " + audioSourcesId.length); 70 | Log.i(TAG, " n_ex = " + nExtraSources); 71 | audioSourcesName = new String[audioSourcesId.length + nExtraSources]; 72 | for (int i = 0; i < audioSourcesId.length; i++) { 73 | audioSourcesName[i] = au.getAudioSourceName(audioSourcesId[i]); 74 | } 75 | 76 | // Combine these two sources 77 | audioSources = new String[audioSourcesName.length]; 78 | int j = 0; 79 | for (; j < audioSourcesId.length; j++) { 80 | audioSources[j] = String.valueOf(audioSourcesId[j]); 81 | } 82 | for (int i = 0; i < asid.length; i++) { 83 | // See SamplingLoop::run() for the magic number 1000 84 | if (asid[i] >= 1000) { 85 | audioSources[j] = String.valueOf(asid[i]); 86 | audioSourcesName[j] = as[i]; 87 | j++; 88 | } 89 | } 90 | 91 | final ListPreference lp = findPreference("audioSource"); 92 | if (lp != null) { 93 | lp.setDefaultValue(MediaRecorder.AudioSource.VOICE_RECOGNITION); 94 | lp.setEntries(audioSourcesName); 95 | lp.setEntryValues(audioSources); 96 | } 97 | } 98 | } 99 | 100 | @Override 101 | protected void onResume() { 102 | super.onResume(); 103 | getSupportFragmentManager() 104 | .beginTransaction() 105 | .replace(R.id.settings, new SettingsFragment(this, getIntent())) 106 | .commit(); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /audioSpectrumAnalyzer/src/main/java/org/woheller69/audio_analyzer_for_android/CalibrationLoad.java: -------------------------------------------------------------------------------- 1 | package org.woheller69.audio_analyzer_for_android; 2 | 3 | import android.content.Context; 4 | import android.net.Uri; 5 | import android.util.Log; 6 | 7 | import java.io.BufferedReader; 8 | import java.io.FileNotFoundException; 9 | import java.io.IOException; 10 | import java.io.InputStream; 11 | import java.io.InputStreamReader; 12 | import java.util.ArrayList; 13 | import java.util.Iterator; 14 | 15 | /** 16 | * Load calibration file. 17 | */ 18 | 19 | class CalibrationLoad { 20 | final static String TAG = "CalibrationLoad"; 21 | 22 | double[] freq = new double[0]; 23 | double[] gain = new double[0]; 24 | double centralFreq = 1000; 25 | double centralGain = -37.4; 26 | String name = null; 27 | 28 | void loadFile(Uri calibUri, Context context) { 29 | String calibPath = calibUri.getPath(); 30 | BufferedReader br; 31 | InputStream inputStream; 32 | try { 33 | inputStream = context.getContentResolver().openInputStream(calibUri); 34 | } catch (FileNotFoundException e) { 35 | Log.e(TAG, "no calib file found: " + calibPath); 36 | return; 37 | } 38 | if (inputStream == null) { 39 | Log.e(TAG, "open calib file fail: " + calibPath); 40 | return; 41 | } 42 | br = new BufferedReader(new InputStreamReader(inputStream)); 43 | 44 | String line = null; 45 | try { 46 | int lineCount = 0; 47 | ArrayList freqList = new ArrayList<>(); 48 | ArrayList amplitudeDBList = new ArrayList<>(); 49 | while (true) { 50 | line = br.readLine(); 51 | if (line == null) break; 52 | lineCount ++; 53 | line = line.trim(); 54 | if (line.length() == 0) { // skip empty line 55 | continue; 56 | } 57 | char c = line.charAt(0); 58 | if ('0' <= c && c <= '9' || c == '.' || c == '-') { // Should be a number 59 | // 20.00 -4.2 60 | String[] strs = line.split("[ \t]+"); 61 | if (strs.length != 2) { 62 | Log.w(TAG, "Fail to parse line " + lineCount + " :" + line); 63 | continue; 64 | } 65 | freqList .add(Double.valueOf(strs[0])); 66 | amplitudeDBList.add(Double.valueOf(strs[1])); 67 | } else if (line.charAt(0) == '*') { // Dayton Audio txt/cal or miniDSP cal file 68 | // parse Only the Dayton Audio header: 69 | //*1000Hz -37.4 70 | String[] strs = line.substring(1).split("Hz[ \t]+"); 71 | if (strs.length == 2) { 72 | Log.i(TAG, "Dayton Audio header"); 73 | centralFreq = Double.valueOf(strs[0]); 74 | centralGain = Double.valueOf(strs[1]); 75 | } 76 | // miniDSP cal header: 77 | //* miniDSP PMIK-1 calibration file, serial: 8000234, format: cal 78 | // Skip 79 | } else if (line.charAt(0) == '"') { 80 | // miniDSP txt header: 81 | //"miniDSP PMIK-1 calibration file, serial: 8000234, format: frd" 82 | // Skip 83 | // miniDSP frd header: 84 | //"miniDSP PMIK-1 calibration file, serial: 8000234, format: frd" 85 | // Skip 86 | } else if (line.charAt(0) == '#') { 87 | // Shell style comment line 88 | // Skip 89 | } else { 90 | Log.e(TAG, "Bad calibration file."); 91 | freqList.clear(); 92 | amplitudeDBList.clear(); 93 | break; 94 | } 95 | } 96 | br.close(); 97 | 98 | freq = new double[freqList.size()]; 99 | gain = new double[freqList.size()]; 100 | Iterator itr = freqList.iterator(); 101 | Iterator itr2 = amplitudeDBList.iterator(); 102 | for (int j=0; itr.hasNext(); j++ ) { 103 | freq[j] = (double)itr.next(); 104 | gain[j] = (double)itr2.next(); 105 | } 106 | } catch (IOException e) { 107 | Log.e(TAG, "Fail to read file: " + calibPath); 108 | } 109 | name = calibPath.substring(calibPath.lastIndexOf("/")+1); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /audioSpectrumAnalyzer/src/main/res/values-ru/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Настройки 4 | RMS:дБ \n-XXX.X 5 | Сейчас: 6 | Пик:XXXXX.XГц(AX#+XX) -XXX.XдБ 7 | Пик: 8 | ", Осталось: " 9 | Зап: 10 | Зап: 00:00:00.0, Осталось: 0000:00:00 11 | Предотвращать отключение дисплея 12 | Тестирование аудио возможностей.. 13 | Оконная функция для (локального) быстрого преобразования Фурье (STFT) 14 | ДЛИНА FFT 15 | дБ::дБА 16 | Отмена 17 | Курс 18 | Установить нижний и верхний границы дБ 19 | нижная граница частоты 20 | верхняя граница частоты 21 | дБ нижней границы 22 | Загрузить прошлые 23 | Установить частоту курсора [Гц] 24 | част [Гц] 25 | Руководство пользователя 26 | Настройки 27 | Вручную 28 | Тест 29 | Установить вид 30 | Стандартные источники 31 | Подерживаемые источники 32 | Все источники 33 | не удалось прочесть семпл 34 | Главные настройки 35 | Держать экран включённым 36 | " Гц ОШИБКА\n" 37 | "%1$5d Гц %2$4d Байт (%3$4.1f мс)\n" 38 | МОН::ЗАП 39 | Инфо про Аудио Вход 40 | \n--- Тест Аудио Источника ---\n 41 | \nИсточник: %1$s\n 42 | "%1$5d Гц " 43 | Установите нижнюю и верхнюю границы частот 44 | (%1$.2f<= Гц <=%2$.2f) 45 | Тест источника записывания 46 | Отображение спектра 47 | Включить или выключить название оси 48 | Показывать временную ось 49 | Цветовая карта 50 | НЕТ 51 | Ладно 52 | Может позже 53 | Аудио источник для спектра 54 | Различное 55 | Экспериментальные 56 | "Снимок экрана сохранён в " 57 | Частота как ось X 58 | Анализатор звукового спектра 59 | Сейчас :XXXXX.XГц(AX#+XX) -XXX.XдБ 60 | НАЧАТЬ::СТОП 61 | Ладно 62 | (%1$.2f<= дБ <=%2$.2f) 63 | дБ верхней границы 64 | Настройки 65 | успешно 66 | Источник звука 67 | Оконная функция 68 | Настройки для разработчика 69 | в секундах 70 | ОБРАЗОВ/С 71 | 72 | -------------------------------------------------------------------------------- /audioSpectrumAnalyzer/src/main/java/org/woheller69/audio_analyzer_for_android/SBNumFormat.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2014 Eddy Xiao 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | package org.woheller69.audio_analyzer_for_android; 17 | 18 | import android.util.Log; 19 | 20 | class SBNumFormat { 21 | private static final char charDigits[] = {'0','1','2','3','4','5','6','7','8','9'}; 22 | 23 | // Invent wheel... so we can eliminate GC 24 | static void fillInNumFixedWidthPositive(StringBuilder sb, double d, int nInt, int nFrac, char padChar) { 25 | if (d<0) { 26 | for (int i = 0; i < nInt+nFrac+(nFrac>0?1:0); i++) { 27 | sb.append(padChar); 28 | } 29 | Log.w("SBNumFormat", "fillInNumFixedWidthPositive: negative number"); 30 | return; 31 | } 32 | if (d >= Math.pow(10,nInt)) { 33 | sb.append("OFL"); 34 | for (int i = 3; i < nInt+nFrac+(nFrac>0?1:0); i++) { 35 | sb.append(' '); 36 | } 37 | return; 38 | } 39 | if (Double.isNaN(d)) { 40 | sb.append("NaN"); 41 | for (int i = 3; i < nInt+nFrac+(nFrac>0?1:0); i++) { 42 | sb.append(' '); 43 | } 44 | return; 45 | } 46 | while (nInt > 0) { 47 | nInt--; 48 | if (d < Math.pow(10,nInt) && nInt>0) { 49 | if (padChar != '\0') { 50 | sb.append(padChar); 51 | } 52 | } else { 53 | sb.append(charDigits[(int)(d / Math.pow(10,nInt) % 10.0)]); 54 | } 55 | } 56 | if (nFrac > 0) { 57 | sb.append('.'); 58 | for (int i = 1; i <= nFrac; i++) { 59 | sb.append(charDigits[(int)(d * Math.pow(10,i) % 10.0)]); 60 | } 61 | } 62 | } 63 | 64 | static void fillInNumFixedWidthPositive(StringBuilder sb, double d, int nInt, int nFrac) { 65 | fillInNumFixedWidthPositive(sb, d, nInt, nFrac, ' '); 66 | } 67 | 68 | static void fillInNumFixedFrac(StringBuilder sb, double d, int nInt, int nFrac) { 69 | if (d < 0) { 70 | sb.append('-'); 71 | d = -d; 72 | } 73 | fillInNumFixedWidthPositive(sb, d, nInt, nFrac, '\0'); 74 | } 75 | 76 | static void fillInNumFixedWidth(StringBuilder sb, double d, int nInt, int nFrac) { 77 | int it = sb.length(); 78 | sb.append(' '); 79 | if (d < 0) { 80 | fillInNumFixedWidthPositive(sb, -d, nInt, nFrac); 81 | for (int i = it; i < sb.length(); i++) { 82 | if (sb.charAt(i+1) != ' ') { 83 | sb.setCharAt(i, '-'); 84 | return; 85 | } 86 | } 87 | } 88 | fillInNumFixedWidthPositive(sb, d, nInt, nFrac); 89 | } 90 | 91 | static void fillInNumFixedWidthSigned(StringBuilder sb, double d, int nInt, int nFrac) { 92 | int it = sb.length(); 93 | sb.append(' '); 94 | fillInNumFixedWidthPositive(sb, Math.abs(d), nInt, nFrac); 95 | for (int i = it; i < sb.length(); i++) { 96 | if (sb.charAt(i+1) != ' ') { 97 | if (d < 0) { 98 | sb.setCharAt(i, '-'); 99 | } else { 100 | sb.setCharAt(i, '+'); 101 | } 102 | return; 103 | } 104 | } 105 | } 106 | 107 | static void fillInNumFixedWidthSignedFirst(StringBuilder sb, double d, int nInt, int nFrac) { 108 | if (d < 0) { 109 | sb.append('-'); 110 | } else { 111 | sb.append('+'); 112 | } 113 | fillInNumFixedWidthPositive(sb, Math.abs(d), nInt, nFrac); 114 | } 115 | 116 | static void fillInInt(StringBuilder sb, int in) { 117 | if (in == 0) { 118 | sb.append('0'); 119 | return; 120 | } 121 | if (in<0) { 122 | sb.append('-'); 123 | in = -in; 124 | } 125 | int it = sb.length(); 126 | while (in > 0) { 127 | sb.insert(it, in%10); 128 | in /= 10; 129 | } 130 | } 131 | 132 | static void fillTime(StringBuilder sb, double t, int nFrac) { 133 | // in format x0:00:00.x 134 | if (t<0) { 135 | t = -t; 136 | sb.append('-'); 137 | } 138 | double u; 139 | // hours 140 | u = Math.floor(t/3600.0); 141 | fillInInt(sb, (int)u); 142 | sb.append(':'); 143 | // minutes 144 | t -= u * 3600; 145 | u = Math.floor(t/60.0); 146 | fillInNumFixedWidthPositive(sb, u, 2, 0, '0'); 147 | sb.append(':'); 148 | // seconds 149 | t -= u * 60; 150 | fillInNumFixedWidthPositive(sb, t, 2, nFrac, '0'); 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /audioSpectrumAnalyzer/src/main/res/layout/dialog_view_range.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 17 | 18 | 26 | 27 | 28 | 37 | 38 | 49 | 50 | 58 | 59 | 67 | 68 | 77 | 78 | 89 | 90 | 99 | 100 | 107 | 108 |