diff --git a/app/build.gradle b/app/build.gradle
index 5e657ba..053dafb 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -8,8 +8,8 @@ android {
applicationId "com.github.axet.audiorecorder"
minSdkVersion 16
targetSdkVersion 23
- versionCode 54
- versionName "1.1.33"
+ versionCode 55
+ versionName "1.1.34"
}
signingConfigs {
release {
@@ -36,5 +36,6 @@ dependencies {
compile 'com.android.support:preference-v14:23.2.1'
compile 'com.android.support:design:23.2.1'
compile 'com.google.android.gms:play-services-appindexing:8.1.0'
+ compile 'org.apache.commons:commons-math3:3.6.1'
compile project(":android-library")
}
diff --git a/app/src/androidTest/java/com/github/axet/audiorecorder/ApplicationTest.java b/app/src/androidTest/java/com/github/axet/audiorecorder/ApplicationTest.java
index 9e55e4f..0e33c79 100644
--- a/app/src/androidTest/java/com/github/axet/audiorecorder/ApplicationTest.java
+++ b/app/src/androidTest/java/com/github/axet/audiorecorder/ApplicationTest.java
@@ -2,6 +2,9 @@ package com.github.axet.audiorecorder;
import android.app.Application;
import android.test.ApplicationTestCase;
+import android.util.Log;
+
+import com.github.axet.audiorecorder.app.RawSamples;
/**
* Testing Fundamentals
@@ -10,4 +13,7 @@ public class ApplicationTest extends ApplicationTestCase {
public ApplicationTest() {
super(Application.class);
}
-}
\ No newline at end of file
+
+ public void testFFT() {
+ }
+}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 2d94f30..a753a6d 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -14,7 +14,7 @@
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
- android:theme="@style/AppTheme">
+ android:theme="@style/AppThemeLight">
+ android:theme="@style/AppThemeLight.NoActionBar">
diff --git a/app/src/main/java/com/github/axet/audiorecorder/activities/AppCompatPreferenceActivity.java b/app/src/main/java/com/github/axet/audiorecorder/activities/AppCompatPreferenceActivity.java
index 9b0052d..bc6ae27 100644
--- a/app/src/main/java/com/github/axet/audiorecorder/activities/AppCompatPreferenceActivity.java
+++ b/app/src/main/java/com/github/axet/audiorecorder/activities/AppCompatPreferenceActivity.java
@@ -12,6 +12,8 @@ import android.view.MenuInflater;
import android.view.View;
import android.view.ViewGroup;
+import com.github.axet.audiorecorder.app.MainApplication;
+
/**
* A {@link android.preference.PreferenceActivity} which implements and proxies the necessary calls
* to be used with AppCompat.
@@ -22,6 +24,7 @@ public abstract class AppCompatPreferenceActivity extends PreferenceActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
+ setTheme(((MainApplication) getApplication()).getUserTheme());
getDelegate().installViewFactory();
getDelegate().onCreate(savedInstanceState);
super.onCreate(savedInstanceState);
diff --git a/app/src/main/java/com/github/axet/audiorecorder/activities/MainActivity.java b/app/src/main/java/com/github/axet/audiorecorder/activities/MainActivity.java
index 896a5d7..03082ce 100644
--- a/app/src/main/java/com/github/axet/audiorecorder/activities/MainActivity.java
+++ b/app/src/main/java/com/github/axet/audiorecorder/activities/MainActivity.java
@@ -74,6 +74,7 @@ public class MainActivity extends AppCompatActivity implements AbsListView.OnScr
Storage storage;
ListView list;
Handler handler;
+ PopupShareActionProvider shareProvider;
public static void startActivity(Context context) {
Intent i = new Intent(context, MainActivity.class);
@@ -234,7 +235,7 @@ public class MainActivity extends AppCompatActivity implements AbsListView.OnScr
share.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- PopupShareActionProvider shareProvider = new PopupShareActionProvider(getContext(), share);
+ shareProvider = new PopupShareActionProvider(getContext(), share);
Intent emailIntent = new Intent(Intent.ACTION_SEND);
emailIntent.setType("audio/mp4a-latm");
@@ -435,6 +436,9 @@ public class MainActivity extends AppCompatActivity implements AbsListView.OnScr
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+
+ setTheme(((MainApplication) getApplication()).getMainTheme());
+
setContentView(R.layout.activity_main);
// ATTENTION: This was auto-generated to implement the App Indexing API.
@@ -533,19 +537,10 @@ public class MainActivity extends AppCompatActivity implements AbsListView.OnScr
updateHeader();
final int selected = getLastRecording();
- list.setSelection(selected);
if (selected != -1) {
- handler.post(new Runnable() {
- @Override
- public void run() {
- recordings.select(selected);
- }
- });
+ list.setSelection(selected);
+ recordings.select(selected);
}
- final SharedPreferences shared = PreferenceManager.getDefaultSharedPreferences(MainActivity.this);
- SharedPreferences.Editor edit = shared.edit();
- edit.putString(MainApplication.PREFERENCE_LAST, "");
- edit.commit();
}
int getLastRecording() {
@@ -556,8 +551,12 @@ public class MainActivity extends AppCompatActivity implements AbsListView.OnScr
for (int i = 0; i < recordings.getCount(); i++) {
File f = recordings.getItem(i);
String n = f.getName().toLowerCase();
- if (n.equals(last))
+ if (n.equals(last)) {
+ SharedPreferences.Editor edit = shared.edit();
+ edit.putString(MainApplication.PREFERENCE_LAST, "");
+ edit.commit();
return i;
+ }
}
return -1;
}
@@ -672,6 +671,6 @@ public class MainActivity extends AppCompatActivity implements AbsListView.OnScr
long free = storage.getFree(f);
long sec = storage.average(free);
TextView text = (TextView) findViewById(R.id.space_left);
- text.setText(((MainApplication)getApplication()).formatFree(free, sec));
+ text.setText(((MainApplication) getApplication()).formatFree(free, sec));
}
}
diff --git a/app/src/main/java/com/github/axet/audiorecorder/activities/RecordingActivity.java b/app/src/main/java/com/github/axet/audiorecorder/activities/RecordingActivity.java
index 50eedb0..1670e24 100644
--- a/app/src/main/java/com/github/axet/audiorecorder/activities/RecordingActivity.java
+++ b/app/src/main/java/com/github/axet/audiorecorder/activities/RecordingActivity.java
@@ -147,6 +147,9 @@ public class RecordingActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+
+ setTheme(((MainApplication) getApplication()).getUserTheme());
+
setContentView(R.layout.activity_recording);
pitch = (PitchView) findViewById(R.id.recording_pitch);
diff --git a/app/src/main/java/com/github/axet/audiorecorder/activities/SettingsActivity.java b/app/src/main/java/com/github/axet/audiorecorder/activities/SettingsActivity.java
index b468dcd..4fa81ae 100644
--- a/app/src/main/java/com/github/axet/audiorecorder/activities/SettingsActivity.java
+++ b/app/src/main/java/com/github/axet/audiorecorder/activities/SettingsActivity.java
@@ -6,6 +6,7 @@ import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
+import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.media.Ringtone;
@@ -23,6 +24,7 @@ import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.ActionBar;
import android.view.MenuItem;
+import android.widget.ListView;
import android.widget.Toast;
import com.github.axet.audiorecorder.R;
@@ -41,7 +43,7 @@ import java.util.List;
* href="http://developer.android.com/guide/topics/ui/settings.html">Settings
* API Guide for more information on developing a Settings UI.
*/
-public class SettingsActivity extends AppCompatPreferenceActivity {
+public class SettingsActivity extends AppCompatPreferenceActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
/**
* A preference value change listener that updates the preference's summary
* to reflect its new value.
@@ -120,8 +122,12 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+
setupActionBar();
+ final SharedPreferences shared = PreferenceManager.getDefaultSharedPreferences(this);
+ shared.registerOnSharedPreferenceChangeListener(this);
+
getFragmentManager().beginTransaction().replace(android.R.id.content, new GeneralPreferenceFragment()).commit();
}
@@ -195,6 +201,23 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
return true;
}
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
+ if(key.equals(MainApplication.PREFERENCE_THEME)) {
+ finish();
+ startActivity(new Intent(this, SettingsActivity.class));
+ overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
+ }
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+
+ final SharedPreferences shared = PreferenceManager.getDefaultSharedPreferences(this);
+ shared.unregisterOnSharedPreferenceChangeListener(this);
+ }
+
/**
* This fragment shows general preferences only. It is used when the
* activity is showing a two-pane settings UI.
@@ -226,6 +249,7 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
}
bindPreferenceSummaryToValue(findPreference(MainApplication.PREFERENCE_RATE));
+ bindPreferenceSummaryToValue(findPreference(MainApplication.PREFERENCE_THEME));
}
@Override
diff --git a/app/src/main/java/com/github/axet/audiorecorder/animations/RecordingAnimation.java b/app/src/main/java/com/github/axet/audiorecorder/animations/RecordingAnimation.java
index 34ddddb..eb13e12 100644
--- a/app/src/main/java/com/github/axet/audiorecorder/animations/RecordingAnimation.java
+++ b/app/src/main/java/com/github/axet/audiorecorder/animations/RecordingAnimation.java
@@ -3,6 +3,7 @@ package com.github.axet.audiorecorder.animations;
import android.annotation.TargetApi;
import android.os.Build;
import android.os.Handler;
+import android.util.Log;
import android.view.View;
import android.view.animation.Transformation;
import android.widget.ListView;
diff --git a/app/src/main/java/com/github/axet/audiorecorder/app/MainApplication.java b/app/src/main/java/com/github/axet/audiorecorder/app/MainApplication.java
index 793d3fd..fdf7213 100644
--- a/app/src/main/java/com/github/axet/audiorecorder/app/MainApplication.java
+++ b/app/src/main/java/com/github/axet/audiorecorder/app/MainApplication.java
@@ -1,9 +1,14 @@
package com.github.axet.audiorecorder.app;
import android.app.Application;
+import android.content.Context;
import android.content.SharedPreferences;
+import android.content.res.TypedArray;
import android.preference.PreferenceManager;
+import android.util.Log;
+import android.util.TypedValue;
+import com.github.axet.androidlibrary.widgets.ThemeUtils;
import com.github.axet.audiorecorder.R;
public class MainApplication extends Application {
@@ -13,12 +18,37 @@ public class MainApplication extends Application {
public static final String PREFERENCE_SILENT = "silence";
public static final String PREFERENCE_ENCODING = "encoding";
public static final String PREFERENCE_LAST = "last_recording";
+ public static final String PREFERENCE_THEME = "theme";
@Override
public void onCreate() {
super.onCreate();
PreferenceManager.setDefaultValues(this, R.xml.pref_general, false);
+
+ Context context = this;
+ context.setTheme(getUserTheme());
+ Log.d("123", "color " + Integer.toHexString(ThemeUtils.getThemeColor(context, android.R.attr.textColorSecondary)));
+ }
+
+ public int getUserTheme() {
+ final SharedPreferences shared = PreferenceManager.getDefaultSharedPreferences(this);
+ String theme = shared.getString(MainApplication.PREFERENCE_THEME, "");
+ if (theme.equals("Theme_Dark")) {
+ return R.style.AppThemeDark;
+ } else {
+ return R.style.AppThemeLight;
+ }
+ }
+
+ public int getMainTheme() {
+ final SharedPreferences shared = PreferenceManager.getDefaultSharedPreferences(this);
+ String theme = shared.getString(MainApplication.PREFERENCE_THEME, "");
+ if (theme.equals("Theme_Dark")) {
+ return R.style.AppThemeDark_NoActionBar;
+ } else {
+ return R.style.AppThemeLight_NoActionBar;
+ }
}
static public String formatTime(int tt) {
diff --git a/app/src/main/java/com/github/axet/audiorecorder/app/RawSamples.java b/app/src/main/java/com/github/axet/audiorecorder/app/RawSamples.java
index 79af854..6e704d1 100644
--- a/app/src/main/java/com/github/axet/audiorecorder/app/RawSamples.java
+++ b/app/src/main/java/com/github/axet/audiorecorder/app/RawSamples.java
@@ -5,6 +5,12 @@ import android.util.Log;
import com.github.axet.audiorecorder.activities.RecordingActivity;
+import org.apache.commons.math3.complex.Complex;
+import org.apache.commons.math3.transform.DftNormalization;
+import org.apache.commons.math3.transform.FastFourierTransformer;
+import org.apache.commons.math3.transform.TransformType;
+import org.apache.commons.math3.util.MathArrays;
+
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
@@ -137,7 +143,7 @@ public class RawSamples {
public static double getDB(double amplitude) {
// https://en.wikipedia.org/wiki/Sound_pressure
- return 20.0 * Math.log10(amplitude / 32768d);
+ return 20.0 * Math.log10(amplitude / 0x7FFF);
}
public void close() {
diff --git a/app/src/main/java/com/github/axet/audiorecorder/services/RecordingService.java b/app/src/main/java/com/github/axet/audiorecorder/services/RecordingService.java
index adfb693..b05f623 100644
--- a/app/src/main/java/com/github/axet/audiorecorder/services/RecordingService.java
+++ b/app/src/main/java/com/github/axet/audiorecorder/services/RecordingService.java
@@ -5,8 +5,11 @@ import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.ContextWrapper;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
import android.os.Build;
import android.os.IBinder;
import android.support.annotation.Nullable;
@@ -16,6 +19,7 @@ import android.widget.RemoteViews;
import com.github.axet.audiorecorder.R;
import com.github.axet.audiorecorder.activities.RecordingActivity;
+import com.github.axet.audiorecorder.app.MainApplication;
/**
* RecordingActivity more likly to be removed from memory when paused then service. Notification button
@@ -140,6 +144,19 @@ public class RecordingService extends Service {
view.setOnClickPendingIntent(R.id.notification_pause, pe);
view.setImageViewResource(R.id.notification_pause, !recording ? R.drawable.play : R.drawable.pause);
+ getBaseContext().setTheme(((MainApplication) getApplication()).getUserTheme());
+
+ view.apply(new ContextWrapper(getBaseContext()) {
+ public Context createPackageContext(String packageName, int flags) throws PackageManager.NameNotFoundException {
+ return new ContextWrapper(getBaseContext().createPackageContext(packageName, flags)) {
+ @Override
+ public Resources.Theme getTheme() {
+ return getBaseContext().getTheme();
+ }
+ };
+ }
+ }, null);
+
NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
.setOngoing(true)
.setContentTitle("Recording")
diff --git a/app/src/main/java/com/github/axet/audiorecorder/widgets/FFTBarView.java b/app/src/main/java/com/github/axet/audiorecorder/widgets/FFTBarView.java
new file mode 100644
index 0000000..a2bee4b
--- /dev/null
+++ b/app/src/main/java/com/github/axet/audiorecorder/widgets/FFTBarView.java
@@ -0,0 +1,105 @@
+package com.github.axet.audiorecorder.widgets;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.View;
+
+import com.github.axet.audiorecorder.app.RawSamples;
+
+public class FFTBarView extends FFTView {
+ public static final String TAG = FFTBarView.class.getSimpleName();
+
+ int barCount;
+ float barWidth;
+ float barDeli;
+
+ public FFTBarView(Context context) {
+ this(context, null);
+ }
+
+ public FFTBarView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public FFTBarView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+
+ create();
+ }
+
+ void create() {
+ super.create();
+ }
+
+ public void setBuffer(double[] buf) {
+ super.setBuffer(buf);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+ // set initial width
+ int w = dp2px(15);
+ int d = dp2px(4);
+ int s = w + d;
+
+ int mw = getMeasuredWidth() - getPaddingLeft() - getPaddingRight();
+
+ // get count of bars and delimeters
+ int dc = (mw - w) / s;
+ int bc = dc + 1;
+
+ // get rate
+ float k = w / d;
+
+ // get one part of (bar+del) size
+ float e = mw / (bc * k + dc);
+
+ barCount = bc;
+ barWidth = e * k;
+ barDeli = e;
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ }
+
+ @Override
+ public void onDraw(Canvas canvas) {
+ if (barCount == 0)
+ return;
+
+ int h = getHeight() - getPaddingTop() - getPaddingBottom();
+
+ float left = getPaddingLeft();
+
+ for (int i = 0; i < barCount; i++) {
+ double max = 0;
+
+ if (buffer != null) {
+ int step = buffer.length / barCount;
+ int offset = i * step;
+ int end = Math.min(offset + step, buffer.length);
+ for (int k = offset; k < end; k++) {
+ double s = buffer[k];
+ max = Math.max(max, s);
+ }
+ }
+
+ float y = getPaddingTop() + h - h * ((float) max / 0x7fff) - dp2px(1);
+
+ if (y < getPaddingTop())
+ y = getPaddingTop();
+
+ canvas.drawRect(left, y, left + barWidth, getPaddingTop() + h, paint);
+ left += barWidth + barDeli;
+ }
+ }
+
+}
diff --git a/app/src/main/java/com/github/axet/audiorecorder/widgets/FFTChartView.java b/app/src/main/java/com/github/axet/audiorecorder/widgets/FFTChartView.java
new file mode 100644
index 0000000..dfcd50e
--- /dev/null
+++ b/app/src/main/java/com/github/axet/audiorecorder/widgets/FFTChartView.java
@@ -0,0 +1,94 @@
+package com.github.axet.audiorecorder.widgets;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.View;
+
+import com.github.axet.audiorecorder.app.RawSamples;
+
+public class FFTChartView extends FFTView {
+ public static final String TAG = FFTChartView.class.getSimpleName();
+
+ public FFTChartView(Context context) {
+ this(context, null);
+ }
+
+ public FFTChartView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public FFTChartView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+
+ create();
+ }
+
+ void create() {
+ super.create();
+ }
+
+ public void setBuffer(double[] buf) {
+ super.setBuffer(buf);
+ }
+
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ }
+
+ @Override
+ public void onDraw(Canvas canvas) {
+ if (buffer == null)
+ return;
+
+ canvas.drawColor(Color.RED);
+
+ int h = getHeight();
+
+ float startX = 0, startY = h;
+
+ int w = getWidth() - getPaddingLeft() - getPaddingRight();
+
+ float step = w / (float) buffer.length;
+
+ double min = Integer.MAX_VALUE;
+ double max = Integer.MIN_VALUE;
+
+ for (int i = 0; i < buffer.length; i++) {
+ double v = buffer[i];
+
+ min = Math.min(v, min);
+ max = Math.max(v, max);
+
+ v = (RawSamples.MAXIMUM_DB + v) / RawSamples.MAXIMUM_DB;
+
+ float endX = startX;
+ float endY = (float) (h - h * v);
+
+ canvas.drawLine(startX, startY, endX, endY, paint);
+
+ startX = endX + step;
+ startY = endY;
+ }
+
+ String tMin = "" + min;
+ canvas.drawText(tMin, 0, getHeight(), textPaint);
+
+ String tMax = "" + max;
+ textPaint.getTextBounds(tMax, 0, tMax.length(), textBounds);
+ canvas.drawText("" + max, w - textBounds.width(), getHeight(), textPaint);
+ }
+
+}
diff --git a/app/src/main/java/com/github/axet/audiorecorder/widgets/FFTView.java b/app/src/main/java/com/github/axet/audiorecorder/widgets/FFTView.java
new file mode 100644
index 0000000..3a57222
--- /dev/null
+++ b/app/src/main/java/com/github/axet/audiorecorder/widgets/FFTView.java
@@ -0,0 +1,151 @@
+package com.github.axet.audiorecorder.widgets;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.View;
+
+import com.github.axet.audiorecorder.app.RawSamples;
+
+import org.apache.commons.math3.complex.Complex;
+import org.apache.commons.math3.transform.DftNormalization;
+import org.apache.commons.math3.transform.FastFourierTransformer;
+import org.apache.commons.math3.transform.TransformType;
+
+public class FFTView extends View {
+ public static final String TAG = FFTView.class.getSimpleName();
+
+ Paint paint;
+ double[] buffer;
+
+ Paint textPaint;
+ Rect textBounds;
+
+ public FFTView(Context context) {
+ this(context, null);
+ }
+
+ public FFTView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public FFTView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+
+ create();
+ }
+
+ void create() {
+ paint = new Paint();
+ paint.setColor(0xff0433AE);
+ paint.setStrokeWidth(dp2px(1));
+
+ textBounds = new Rect();
+
+ textPaint = new Paint();
+ textPaint.setColor(Color.GRAY);
+ textPaint.setAntiAlias(true);
+ textPaint.setTextSize(20f);
+
+ if (isInEditMode()) {
+ short[] b = simple();
+ b = generateSound(16000, 4000, 100);
+ buffer = fft(b, 0, b.length);
+ //buffer = RawSamples.generateSound(16000, 4000, 100);
+ //buffer = RawSamples.fft(buffer, 0, buffer.length);
+ }
+ }
+
+ public void setBuffer(double[] buf) {
+ buffer = buf;
+ }
+
+ public static short[] generateSound(int sampleRate, int freqHz, int durationMs) {
+ int count = sampleRate * durationMs / 1000;
+ short[] samples = new short[count];
+ for (int i = 0; i < count; i++) {
+ short sample = (short) (Math.sin(2 * Math.PI * i / (sampleRate / freqHz)) * 0x7FFF);
+ samples[i] = sample;
+ }
+ return samples;
+ }
+
+ public static double[] asDouble(short[] buffer, int offset, int len) {
+ double[] dd = new double[len];
+ for (int i = 0; i < len; i++) {
+ dd[i] = buffer[offset + i] / (float) 0x7fff;
+ }
+ return dd;
+ }
+
+ public static double[] fft(short[] buffer, int offset, int len) {
+ int len2 = (int) Math.pow(2, Math.ceil(Math.log(len) / Math.log(2)));
+
+ final double[][] dataRI = new double[][]{
+ new double[len2], new double[len2]
+ };
+
+ double[] dataR = dataRI[0];
+ double[] dataI = dataRI[1];
+
+ double powerInput = 0;
+ for (int i = 0; i < len; i++) {
+ dataR[i] = buffer[offset + i] / (float) 0x7fff;
+ powerInput += dataR[i] * dataR[i];
+ }
+ powerInput = Math.sqrt(powerInput / len);
+
+ FastFourierTransformer.transformInPlace(dataRI, DftNormalization.STANDARD, TransformType.FORWARD);
+
+ double[] data = new double[len2 / 2];
+
+ data[0] = 10 * Math.log10(Math.pow(new Complex(dataR[0], dataI[0]).abs() / len2, 2));
+
+ double powerOutput = 0;
+ for (int i = 1; i < data.length; i++) {
+ Complex c = new Complex(dataR[i], dataI[i]);
+ double p = c.abs();
+ p = p / len2;
+ p = p * p;
+ p = p * 2;
+ double dB = 10 * Math.log10(p);
+
+ powerOutput += p;
+ data[i] = dB;
+ }
+ powerOutput = Math.sqrt(powerOutput);
+
+// if(powerInput != powerOutput) {
+// throw new RuntimeException("in " + powerInput + " out " + powerOutput);
+// }
+
+ return data;
+ }
+
+ public static short[] simple() {
+ int sampleRate = 1000;
+ int count = sampleRate;
+ short[] samples = new short[count];
+ for (int i = 0; i < count; i++) {
+ double x = i / (double) count;
+ double y = 0;
+ //y += 0.6 * Math.sin(20 * 2 * Math.PI * x);
+ //y += 0.4 * Math.sin(50 * 2 * Math.PI * x);
+ //y += 0.2 * Math.sin(80 * 2 * Math.PI * x);
+ y += Math.sin(100 * 2 * Math.PI * x);
+ y += Math.sin(200 * 2 * Math.PI * x);
+ y += Math.sin(300 * 2 * Math.PI * x);
+ // max = 2.2;
+ samples[i] = (short) (y / 3 * 0x7fff);
+ }
+ return samples;
+ }
+
+ int dp2px(float dp) {
+ return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());
+ }
+
+}
diff --git a/app/src/main/java/com/github/axet/audiorecorder/widgets/PitchView.java b/app/src/main/java/com/github/axet/audiorecorder/widgets/PitchView.java
index ccd664c..272bdf4 100644
--- a/app/src/main/java/com/github/axet/audiorecorder/widgets/PitchView.java
+++ b/app/src/main/java/com/github/axet/audiorecorder/widgets/PitchView.java
@@ -2,6 +2,7 @@ package com.github.axet.audiorecorder.widgets;
import android.content.Context;
import android.content.res.Resources;
+import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
@@ -15,6 +16,9 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
+import com.github.axet.androidlibrary.widgets.ThemeUtils;
+import com.github.axet.audiorecorder.R;
+import com.github.axet.audiorecorder.app.MainApplication;
import com.github.axet.audiorecorder.app.RawSamples;
import java.util.LinkedList;
@@ -39,8 +43,6 @@ public class PitchView extends ViewGroup {
// in other words how many milliseconds do we need to show whole pitch.
int pitchTime;
- Paint paint;
- Paint paintRed;
List data = new LinkedList<>();
// how many pitches we can fit on screen
@@ -75,12 +77,54 @@ public class PitchView extends ViewGroup {
Handler handler;
- int pitchColor = 0xff0433AE;
- Paint cutColor = new Paint();
+ public static class HandlerUpdate implements Runnable {
+ long start;
+ long updateSpeed;
+ Handler handler;
+ Runnable run;
+
+ public static HandlerUpdate start(Handler handler, Runnable run, long updateSpeed) {
+ HandlerUpdate r = new HandlerUpdate();
+ r.run = run;
+ r.start = System.currentTimeMillis();
+ r.updateSpeed = updateSpeed;
+ r.handler = handler;
+ // post instead of draw.run() so 'start' will measure actual queue time
+ handler.postDelayed(r, updateSpeed);
+ return r;
+ }
+
+ public static void stop(Handler handler, Runnable run) {
+ handler.removeCallbacks(run);
+ }
+
+ @Override
+ public void run() {
+ this.run.run();
+
+ long cur = System.currentTimeMillis();
+
+ long diff = cur - start;
+
+ start = cur;
+
+ long delay = updateSpeed + (updateSpeed - diff);
+ if (delay > updateSpeed)
+ delay = updateSpeed;
+
+ if (delay > 0)
+ this.handler.postDelayed(this, delay);
+ else
+ this.handler.post(this);
+ }
+ }
public class PitchGraphView extends View {
+ Paint paint;
+ Paint paintRed;
Paint editPaint;
Paint playPaint;
+ Paint cutColor;
public PitchGraphView(Context context) {
this(context, null);
@@ -93,12 +137,24 @@ public class PitchView extends ViewGroup {
public PitchGraphView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
+ paint = new Paint();
+ paint.setColor(getThemeColor(R.attr.colorPrimary));
+ paint.setStrokeWidth(pitchWidth);
+
+ paintRed = new Paint();
+ paintRed.setColor(Color.RED);
+ paintRed.setStrokeWidth(pitchWidth);
+
+ cutColor = new Paint();
+ cutColor.setColor(getThemeColor(android.R.attr.textColorHint));
+ cutColor.setStrokeWidth(pitchWidth);
+
editPaint = new Paint();
- editPaint.setColor(Color.BLACK);
+ editPaint.setColor(getThemeColor(R.attr.colorPrimaryDark));
editPaint.setStrokeWidth(pitchWidth);
playPaint = new Paint();
- playPaint.setColor(Color.BLUE);
+ playPaint.setColor(getThemeColor(R.attr.colorPrimaryDark));
playPaint.setStrokeWidth(pitchWidth / 2);
}
@@ -141,8 +197,7 @@ public class PitchView extends ViewGroup {
tick = 0;
time = cur;
}
- data.subList(0, 1).clear();
- samples += 1;
+ fit(data.size() - 1);
}
offset = pitchSize * tick;
@@ -192,7 +247,7 @@ public class PitchView extends ViewGroup {
}
// paint play mark
- if (playPos != -1) {
+ if (playPos > 0) {
float x = playPos * pitchSize + pitchSize / 2f;
canvas.drawLine(x, 0, x, getHeight(), playPaint);
}
@@ -205,6 +260,8 @@ public class PitchView extends ViewGroup {
String text;
Rect textBounds;
+ double dB;
+
public PitchCurrentView(Context context) {
this(context, null);
}
@@ -225,19 +282,19 @@ public class PitchView extends ViewGroup {
textPaint.setTextSize(20f);
paint = new Paint();
- paint.setColor(pitchColor);
+ paint.setColor(getThemeColor(R.attr.colorPrimary));
paint.setStrokeWidth(pitchWidth);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int w = MeasureSpec.getSize(widthMeasureSpec);
- int h = 0;
-
textPaint.getTextBounds(this.text, 0, this.text.length(), textBounds);
+
+ int h = getPaddingTop();
h += textBounds.height();
h += dp2px(2);
- h += dp2px(pitchDlimiter) + getPaddingTop() + getPaddingBottom();
+ h += pitchWidth + getPaddingBottom();
setMeasuredDimension(w, h);
}
@@ -252,20 +309,9 @@ public class PitchView extends ViewGroup {
super.onLayout(changed, left, top, right, bottom);
}
- public int getEnd() {
- int end = data.size() - 1;
+ void update(int end) {
+ dB = getDB(end) / RawSamples.MAXIMUM_DB;
- if (editPos != -1) {
- end = editPos;
- }
- if (playPos != -1) {
- end = (int) playPos;
- }
-
- return end;
- }
-
- void updateText(int end) {
String str = "";
str = Integer.toString((int) getDB(end)) + " dB";
@@ -276,29 +322,25 @@ public class PitchView extends ViewGroup {
@Override
public void onDraw(Canvas canvas) {
if (data.size() > 0) {
- int end = getEnd();
-
- updateText(end);
-
- float y = getPaddingTop() + textBounds.height();
-
- int x = getWidth() / 2 - textBounds.width() / 2;
- canvas.drawText(text, x, y, textPaint);
-
- y += dp2px(2);
-
- double dB = getDB(end) / RawSamples.MAXIMUM_DB;
-
- float left = (float) dB;
- float right = (float) dB;
-
- float mid = getWidth() / 2f;
-
- y = y + dp2px(pitchDlimiter) / 2;
-
- canvas.drawLine(mid, y, mid - mid * left - 1, y, paint);
- canvas.drawLine(mid, y, mid + mid * right + 1, y, paint);
+ current.update(getEnd());
}
+
+ float y = getPaddingTop() + textBounds.height();
+
+ int x = getWidth() / 2 - textBounds.width() / 2;
+ canvas.drawText(text, x, y, textPaint);
+
+ y += dp2px(2);
+
+ float left = (float) dB;
+ float right = (float) dB;
+
+ float mid = getWidth() / 2f;
+
+ y += pitchWidth / 2;
+
+ canvas.drawLine(mid, y, mid - mid * left - 1, y, paint);
+ canvas.drawLine(mid, y, mid + mid * right + 1, y, paint);
}
}
@@ -325,33 +367,42 @@ public class PitchView extends ViewGroup {
pitchTime = pitchSize * UPDATE_SPEED;
- // bg = getThemeColor(android.R.attr.windowBackground);
- cutColor.setColor(0xff0443BE); // getThemeColor(android.R.attr.textColorPrimaryDisableOnly));
-
graph = new PitchGraphView(getContext());
addView(graph);
+// fft = new FFTChartView(getContext()) {
+// @Override
+// public void onDraw(Canvas canvas) {
+// if (data.size() > 0) {
+// short[] buf = dataSamples.get(getEnd());
+// double[] d = FFTView.fft(buf, 0, buf.length);
+// //double[] d = asDouble(buf, 0, buf.length);
+// fft.setBuffer(d);
+// }
+//
+// super.onDraw(canvas);
+// }
+// };
+// fft.setPadding(0, dp2px(2), 0, 0);
+// addView(fft);
+
current = new PitchCurrentView(getContext());
current.setPadding(0, dp2px(2), 0, 0);
addView(current);
if (isInEditMode()) {
for (int i = 0; i < 3000; i++) {
- data.add((Math.random() * RawSamples.MAXIMUM_DB));
+ data.add(-Math.sin(i) * RawSamples.MAXIMUM_DB);
}
}
- paint = new Paint();
- paint.setColor(0xff0433AE);
- paint.setStrokeWidth(pitchWidth);
-
- paintRed = new Paint();
- paintRed.setColor(Color.RED);
- paintRed.setStrokeWidth(pitchWidth);
-
time = System.currentTimeMillis();
}
+ public int getThemeColor(int id) {
+ return ThemeUtils.getThemeColor(getContext(), id);
+ }
+
public int getMaxPitchCount(int width) {
int pitchScreenCount = width / pitchSize + 1;
@@ -390,8 +441,7 @@ public class PitchView extends ViewGroup {
public void drawCalc() {
graph.calc();
- graph.invalidate();
- current.invalidate();
+ draw();
}
public void drawEnd() {
@@ -400,6 +450,19 @@ public class PitchView extends ViewGroup {
draw();
}
+ public int getEnd() {
+ int end = data.size() - 1;
+
+ if (editPos != -1) {
+ end = editPos;
+ }
+ if (playPos > 0) {
+ end = (int) playPos;
+ }
+
+ return end;
+ }
+
public double getDB(int i) {
double db = data.get(i);
@@ -433,56 +496,46 @@ public class PitchView extends ViewGroup {
return pitchTime;
}
- int getThemeColor(int id) {
- TypedValue typedValue = new TypedValue();
- Context context = getContext();
- Resources.Theme theme = context.getTheme();
- if (theme.resolveAttribute(id, typedValue, true)) {
- if (Build.VERSION.SDK_INT >= 23)
- return context.getResources().getColor(typedValue.resourceId, theme);
- else
- return context.getResources().getColor(typedValue.resourceId);
- } else {
- return Color.TRANSPARENT;
- }
- }
-
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- graph.measure(widthMeasureSpec, heightMeasureSpec);
- current.measure(widthMeasureSpec, heightMeasureSpec);
+ int ww = getMeasuredWidth() - getPaddingRight() - getPaddingLeft();
+ int hh = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
+
+ current.measure(MeasureSpec.makeMeasureSpec(ww, MeasureSpec.AT_MOST),
+ MeasureSpec.makeMeasureSpec(hh, MeasureSpec.AT_MOST));
+
+ hh = hh - current.getMeasuredHeight();
+
+ graph.measure(MeasureSpec.makeMeasureSpec(ww, MeasureSpec.AT_MOST),
+ MeasureSpec.makeMeasureSpec(hh, MeasureSpec.AT_MOST));
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
- int gb = graph.getMeasuredHeight() - current.getMeasuredHeight();
- graph.layout(0, 0, graph.getMeasuredWidth(), gb);
- current.layout(0, gb, current.getMeasuredWidth(), gb + current.getMeasuredHeight());
+ graph.layout(getPaddingLeft(), getPaddingTop(),
+ getPaddingLeft() + graph.getMeasuredWidth(), getPaddingTop() + graph.getMeasuredHeight());
+
+ current.layout(getPaddingLeft(), graph.getBottom(),
+ getPaddingLeft() + current.getMeasuredWidth(), graph.getBottom() + current.getMeasuredHeight());
}
int dp2px(float dp) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());
}
- @Override
- protected void onDraw(Canvas canvas) {
- graph.draw(canvas);
- current.draw(canvas);
- }
-
public void stop() {
if (edit != null)
- handler.removeCallbacks(edit);
+ HandlerUpdate.stop(handler, edit);
edit = null;
if (draw != null)
- handler.removeCallbacks(draw);
+ HandlerUpdate.stop(handler, draw);
draw = null;
if (play != null)
- handler.removeCallbacks(play);
+ HandlerUpdate.stop(handler, play);
play = null;
draw();
@@ -503,12 +556,12 @@ public class PitchView extends ViewGroup {
editPos = data.size() - 1;
if (draw != null) {
- handler.removeCallbacks(draw);
+ HandlerUpdate.stop(handler, draw);
draw = null;
}
if (play != null) {
- handler.removeCallbacks(play);
+ HandlerUpdate.stop(handler, play);
play = null;
}
@@ -523,92 +576,45 @@ public class PitchView extends ViewGroup {
if (edit == null) {
editFlash = true;
- edit = new Runnable() {
- long start = System.currentTimeMillis();
-
+ edit = HandlerUpdate.start(handler, new Runnable() {
@Override
public void run() {
draw();
-
editFlash = !editFlash;
-
- long cur = System.currentTimeMillis();
-
- long diff = cur - start;
-
- long delay = EDIT_UPDATE_SPEED + (EDIT_UPDATE_SPEED - diff);
- if (delay > EDIT_UPDATE_SPEED)
- delay = EDIT_UPDATE_SPEED;
-
- start = cur;
-
- if (delay > 0)
- handler.postDelayed(edit, delay);
- else
- handler.post(edit);
}
- };
- // post instead of draw.run() so 'start' will measure actual queue time
- handler.postDelayed(edit, EDIT_UPDATE_SPEED);
+ }, EDIT_UPDATE_SPEED);
}
}
public void record() {
if (edit != null)
- handler.removeCallbacks(edit);
+ HandlerUpdate.stop(handler, edit);
edit = null;
editPos = -1;
if (play != null)
- handler.removeCallbacks(play);
+ HandlerUpdate.stop(handler, play);
play = null;
playPos = -1;
if (draw == null) {
time = System.currentTimeMillis();
- draw = new Runnable() {
- long start = System.currentTimeMillis();
- int stableCount = 0;
-
+ draw = HandlerUpdate.start(handler, new Runnable() {
@Override
public void run() {
drawCalc();
- long cur = System.currentTimeMillis();
-
- long diff = cur - start;
-
- long delay = UPDATE_SPEED + (UPDATE_SPEED - diff);
- if (delay > UPDATE_SPEED)
- delay = UPDATE_SPEED;
-
- start = cur;
-
- if (delay > 0)
- handler.postDelayed(draw, delay);
- else
- handler.post(draw);
}
- };
- // post instead of draw.run() so 'start' will measure actual queue time
- handler.postDelayed(draw, UPDATE_SPEED);
+ }, UPDATE_SPEED);
}
}
// current paying pos in actual samples
public void play(float pos) {
- playPos = pos - samples;
-
- editFlash = true;
-
- int max = data.size() - 1;
-
- if (playPos < 0 || playPos > max)
+ if (pos < 0) {
playPos = -1;
-
- if (playPos < 0) {
if (play != null) {
- handler.removeCallbacks(play);
+ HandlerUpdate.stop(handler, play);
play = null;
}
if (edit == null) {
@@ -617,40 +623,31 @@ public class PitchView extends ViewGroup {
return;
}
+ playPos = pos - samples;
+
+ editFlash = true;
+
+ int max = data.size() - 1;
+
+ if (playPos > max)
+ playPos = max;
+
if (edit != null)
- handler.removeCallbacks(edit);
+ HandlerUpdate.stop(handler, edit);
edit = null;
if (draw != null)
- handler.removeCallbacks(draw);
+ HandlerUpdate.stop(handler, draw);
draw = null;
if (play == null) {
time = System.currentTimeMillis();
- play = new Runnable() {
- long start = System.currentTimeMillis();
-
+ play = HandlerUpdate.start(handler, new Runnable() {
@Override
public void run() {
draw();
- long cur = System.currentTimeMillis();
-
- long diff = cur - start;
-
- start = cur;
-
- long delay = UPDATE_SPEED + (UPDATE_SPEED - diff);
- if (delay > UPDATE_SPEED)
- delay = UPDATE_SPEED;
-
- if (delay > 0)
- handler.postDelayed(play, delay);
- else
- handler.post(play);
}
- };
- // post instead of draw.run() so 'start' will measure actual queue time
- handler.postDelayed(play, UPDATE_SPEED);
+ }, UPDATE_SPEED);
}
}
}
diff --git a/app/src/main/res/drawable/round.xml b/app/src/main/res/drawable/round.xml
deleted file mode 100644
index 5589315..0000000
--- a/app/src/main/res/drawable/round.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 6700b32..e6f67ec 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -10,14 +10,14 @@
+ android:theme="@style/AppThemeLight.AppBarOverlay">
+ app:popupTheme="@style/AppThemeLight.PopupOverlay" />
diff --git a/app/src/main/res/layout/activity_recording.xml b/app/src/main/res/layout/activity_recording.xml
index 70748fb..1bb525a 100644
--- a/app/src/main/res/layout/activity_recording.xml
+++ b/app/src/main/res/layout/activity_recording.xml
@@ -38,7 +38,8 @@
android:id="@+id/recording_pitch"
android:layout_width="match_parent"
android:layout_height="120dp"
- android:layout_centerInParent="true" />
+ android:layout_centerInParent="true"
+ android:padding="5dp" />
-
-
-
-
@@ -96,28 +93,24 @@
android:layout_width="match_parent"
android:layout_height="wrap_content">
-
-
-
-
diff --git a/app/src/main/res/layout/content_main.xml b/app/src/main/res/layout/content_main.xml
index 63256d6..8d13482 100644
--- a/app/src/main/res/layout/content_main.xml
+++ b/app/src/main/res/layout/content_main.xml
@@ -43,7 +43,7 @@
diff --git a/app/src/main/res/layout/notifictaion_recording.xml b/app/src/main/res/layout/notifictaion_recording.xml
index 0e921aa..7caff47 100644
--- a/app/src/main/res/layout/notifictaion_recording.xml
+++ b/app/src/main/res/layout/notifictaion_recording.xml
@@ -3,13 +3,13 @@
android:id="@+id/status_bar_latest_event_content"
android:layout_width="match_parent"
android:layout_height="64dp"
- android:background="@android:color/white">
+ android:background="?android:windowBackground">
+ android:tint="?android:attr/colorForeground" />
+ android:textColor="?android:attr/colorForeground" />
diff --git a/app/src/main/res/layout/recording.xml b/app/src/main/res/layout/recording.xml
index 19391cb..461335b 100644
--- a/app/src/main/res/layout/recording.xml
+++ b/app/src/main/res/layout/recording.xml
@@ -70,8 +70,8 @@
android:layout_marginBottom="5dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
- android:background="#dedede"
android:orientation="vertical"
+ android:background="?attr/secondBackground"
android:padding="5dp">
+ android:tint="?attr/colorAccent" />
+ android:tint="?attr/colorAccent" />
+ android:tint="?attr/colorAccent" />
diff --git a/app/src/main/res/values-v21/styles.xml b/app/src/main/res/values-v21/styles.xml
index 251fb9f..d7d6ad1 100644
--- a/app/src/main/res/values-v21/styles.xml
+++ b/app/src/main/res/values-v21/styles.xml
@@ -1,6 +1,11 @@
->
-
-
+
-
-
+
-
+
+
+
+
+
diff --git a/app/src/main/res/xml/pref_general.xml b/app/src/main/res/xml/pref_general.xml
index a031aa0..d4d59d5 100644
--- a/app/src/main/res/xml/pref_general.xml
+++ b/app/src/main/res/xml/pref_general.xml
@@ -1,4 +1,5 @@
-
+
+
+
diff --git a/docs/fft.py b/docs/fft.py
new file mode 100644
index 0000000..a3547ea
--- /dev/null
+++ b/docs/fft.py
@@ -0,0 +1,80 @@
+import numpy as np
+import matplotlib.pyplot as plt
+import scipy.fftpack
+import random
+
+#
+# https://web.archive.org/web/20120615002031/http://www.mathworks.com/support/tech-notes/1700/1702.html
+#
+
+def noise(y, amp):
+ return y + amp * np.random.sample(len(y))
+
+# Fe = sample rate
+# N = samples count
+def plot(Fe, N, x, y):
+ plt.subplot(2, 1, 1)
+ print "power wav = %s" % np.sqrt(np.mean(y**2))
+ plt.plot(x, y)
+
+ plt.subplot(2, 1, 2)
+ yf = scipy.fftpack.fft(y)
+
+ NumUniquePts = np.ceil((N+1)/2)
+ # Bin 0 contains the value for the DC component that the signal is riding on.
+ fftx = yf[1:NumUniquePts]
+ mx = np.abs(fftx)
+ mx = mx / N
+ mx = mx**2
+ if N % 2 > 0:
+ mx[2:len(mx)] = mx[2:len(mx)]*2
+ else:
+ mx[2:len(mx)-1] = mx[2:len(mx)-1]*2
+ print "power fft = %s" % np.sqrt(np.sum(mx))
+
+ end = Fe/2
+ start = end / (N/2)
+ xf = np.linspace(start, end, N/2 - 1)
+ mx = np.sqrt(mx)
+ plt.plot(xf, mx)
+
+ plt.show()
+
+def simple(Fe):
+ N = Fe
+ x = np.linspace(0.0, 1.0, N)
+
+ y = np.zeros(len(x))
+
+ y += 0.9 * np.sin(50.0 * 2.0*np.pi*x) + 0.5*np.sin(80.0 * 2.0*np.pi*x)
+ y += 0.6 * np.sin(20.0 * 2.0*np.pi*x) + 0.5*np.sin(80.0 * 2.0*np.pi*x)
+ y += 0.2 * np.sin(80.0 * 2.0*np.pi*x) + 0.5*np.sin(80.0 * 2.0*np.pi*x)
+
+ #y = noise(y, 2)
+
+ plot(Fe, N, x, y)
+
+def real_sound_weave(durationMs):
+ Fe = 16000
+ N = Fe * durationMs / 1000
+ x = np.linspace(0.0, N, N)
+
+ y = np.zeros(len(x))
+
+ y += np.sin(2.0 * np.pi * x / (Fe / float(4500)))
+ y += 0.5 * np.sin(2.0 * np.pi * x / (Fe / float(4000)))
+ y += 0.5 * np.sin(2.0 * np.pi * x / (Fe / float(1000)))
+ y += 0.9 * np.sin(2.0 * np.pi * x / (Fe / float(7500)))
+ y += 1 * np.sin(2.0 * np.pi * x / (Fe / float(3000)))
+
+ m = np.max(np.abs(y))
+
+ y = y * 0x7fff
+# y = y / m
+
+ #y = noise(y, 0x7fff)
+
+ plot(Fe, N, x, y)
+
+#simple(1000)
+real_sound_weave(100)
\ No newline at end of file