🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Android Studio

Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

Kotlin

Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

Q&A

1回答

6529閲覧

AUDIO RECORDで取得した音声の音量を数値で表す。

yoursong

総合スコア4

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Android Studio

Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

Kotlin

Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

0グッド

0クリップ

投稿2019/09/17 12:08

編集2019/09/18 10:36

前提・実現したいこと

Androidアプリでkotlinを用いて、スマホのマイクから認識した音声をSurfaceviewを用いて波形データを表示する機能を実装しました。
音声取得はAudioRECORDを用いています。

スタートボタンを押すと、音声取得が始まり、音が大きければ波形が大きく、小さければ小さく表示されるという一般的な波形データを時間経過とともに表示します。
その波形データから、数値も同時に表示することはできないかと考えています。
音が大きければ(波形がおおきければ)、数値も上がり、小さければ下がる、といった音量レベルみたいなものを数値で表せないかと思っております。
波形を分析するにはRMS(二条平均平方根)を用いると可能らしいのですが、限定はせず色々と模索しています。

何か使えそうな検索ワードや、機能があれば教えていただければと思います。
以下、音声取得から波形を表すコードです。

SurfaceView.kt

kotlin

1 2import android.annotation.SuppressLint 3import android.content.Context 4import android.graphics.Canvas 5import android.graphics.Color 6import android.graphics.Paint 7import android.util.Log 8import android.view.SurfaceHolder 9import android.view.SurfaceView 10 11@SuppressLint("ViewConstructor") 12class VisualizerSurfaceView// 線の太さ、アンチエイリアス、色、とか 13 14// この2つを書いてフォーカスを当てないとSurfaceViewが動かない? 15// isFocusable = true 16// requestFocus() 17 (context: Context, surface: SurfaceView) : SurfaceView(context), SurfaceHolder.Callback, Runnable { 18 19 private val _paint = Paint() 20 private var _buffer: ShortArray = ShortArray(0) 21 private var _holder: SurfaceHolder = surface.holder 22 private var _thread: Thread? = null 23 24 override fun run() { 25 while (_thread != null) { 26 doDraw(_holder) 27 } 28 } 29 30 init { 31 _holder.addCallback(this) 32 _paint.strokeWidth = 2f 33 _paint.isAntiAlias = true 34 _paint.color = Color.WHITE 35 } 36 37 override fun surfaceCreated(holder: SurfaceHolder?) { 38 if (holder != null) { 39 val canvas = holder.lockCanvas() 40 41 holder.unlockCanvasAndPost(canvas) 42 } 43 } 44 45 override fun surfaceChanged(holder: SurfaceHolder?, format: Int, width: Int, height: Int) { 46 _thread = Thread(this) 47 _thread?.start() 48 } 49 50 override fun surfaceDestroyed(holder: SurfaceHolder?) { 51 _thread = null 52 } 53 54 fun update(buffer: ShortArray, size: Int) { 55 _buffer = buffer.copyOf(size) 56// postInvalidate() 57 } 58 59 private fun doDraw(holder: SurfaceHolder) { 60 if (_buffer.isEmpty()) { 61 return 62 } 63 64 try { 65 val canvas: Canvas = holder.lockCanvas() 66 67 canvas.drawColor(Color.BLACK) 68 69 val baseLine: Float = canvas.height / 2f 70 var oldX = 0f 71 var oldY: Float = baseLine 72 73 for ((index, _) in _buffer.withIndex()) { 74 val x: Float = canvas.width.toFloat() / _buffer.size.toFloat() * index.toFloat() 75 val y: Float = _buffer[index] / 128 + baseLine 76 77 canvas.drawLine(oldX, oldY, x, y, _paint) 78 79 oldX = x 80 oldY = y 81 } 82 83 _buffer = ShortArray(0) 84 85 holder.unlockCanvasAndPost(canvas) 86 } catch (e: Exception) { 87 Log.e(this.javaClass.name, "doDraw", e) 88 } 89 } 90} 91

MainActivity.kt

kotlin

1import android.annotation.SuppressLint 2import android.content.Intent 3import android.media.AudioFormat 4import android.media.AudioRecord 5import android.media.MediaRecorder 6import android.os.AsyncTask 7import android.os.Bundle 8import android.os.Parcel 9import android.os.Parcelable 10import android.support.v7.app.AppCompatActivity 11import android.view.SurfaceView 12import android.view.inputmethod.EditorInfo 13import android.widget.Button 14import android.widget.TextView 15import kotlinx.android.synthetic.main.activity_main.* 16import kotlinx.coroutines.GlobalScope 17import kotlinx.coroutines.delay 18import kotlinx.coroutines.launch 19 20 21class MainActivity() : AppCompatActivity(), Parcelable { 22 23 private var _record: Record? = null 24 private var _isRecording = false 25 private var _visualizer: VisualizerSurfaceView? = null 26 private var _button: Button? = null 27 28 constructor(parcel: Parcel) : this() { 29 _isRecording = parcel.readByte() != 0.toByte() 30 } 31 32 override fun onCreate(savedInstanceState: Bundle?) { 33 super.onCreate(savedInstanceState) 34 setContentView(R.layout.activity_main) 35 36 37 val surface = findViewById<SurfaceView>(R.id.visualizer) 38 _visualizer = VisualizerSurfaceView(this, surface) 39 40 _button = this.findViewById(R.id.buttonStart) 41 _button?.setOnClickListener { 42 if(_isRecording) 43 stopRecord() 44 else 45 doRecord() 46 } 47 } 48 49 override fun onPause() { 50 super.onPause() 51 stopRecord() 52 } 53 54 @SuppressLint("SetTextI18n") 55 private fun stopRecord(){ 56 _isRecording = false 57 _button?.text = "start" 58 _record?.cancel(true) 59 } 60 61 @SuppressLint("SetTextI18n") 62 private fun doRecord(){ 63 _isRecording = true 64 _button?.text = "stop" 65 66 // AsyncTaskは使い捨て1回こっきりなので毎回作ります 67 _record = Record() 68 _record?.execute() 69 } 70 71 @SuppressLint("StaticFieldLeak") 72 inner class Record : AsyncTask<Void, DoubleArray, Void>() { 73 override fun doInBackground(vararg params: Void): Void? { 74 // サンプリングレート。1秒あたりのサンプル数 75 // (8000, 11025, 22050, 44100, エミュでは8kbじゃないとだめ?) 76 val sampleRate = 8000 77 78 // 最低限のバッファサイズ 79 val minBufferSize = AudioRecord.getMinBufferSize( 80 sampleRate, 81 AudioFormat.CHANNEL_IN_MONO, 82 AudioFormat.ENCODING_PCM_16BIT) * 2 83 84 // バッファサイズが取得できない。サンプリングレート等の設定を端末がサポートしていない可能性がある。 85 if(minBufferSize < 0){ 86 return null 87 } 88 89 val audioRecord = AudioRecord( 90 MediaRecorder.AudioSource.MIC, 91 sampleRate, 92 AudioFormat.CHANNEL_IN_MONO, 93 AudioFormat.ENCODING_PCM_16BIT, 94 minBufferSize) 95 96 val sec = 1 97 val buffer = ShortArray(sampleRate * (16 / 8) * 1 * sec) 98 99 audioRecord.startRecording() 100 101 try { 102 while (_isRecording) { 103 val readSize = audioRecord.read(buffer, 0, minBufferSize) 104 105 if (readSize < 0) { 106 break 107 } 108 if (readSize == 0) { 109 continue 110 } 111 112 _visualizer?.update(buffer, readSize) 113 } 114 } finally { 115 audioRecord.stop() 116 audioRecord.release() 117 } 118 119 return null 120 } 121 } 122 123 override fun writeToParcel(parcel: Parcel, flags: Int) { 124 parcel.writeByte(if (_isRecording) 1 else 0) 125 } 126 127 override fun describeContents(): Int { 128 return 0 129 } 130 131 companion object CREATOR : Parcelable.Creator<MainActivity> { 132 override fun createFromParcel(parcel: Parcel): MainActivity { 133 return MainActivity(parcel) 134 } 135 136 override fun newArray(size: Int): Array<MainActivity?> { 137 return arrayOfNulls(size) 138 } 139 } 140} 141 142

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

t_obara

2019/09/18 01:31

「音声レベルメーター 算出」とかでググればそれなりに出てきますが、kotlinでのソースコード丸のままが欲しいのでしょうか?
yoursong

2019/09/18 10:33

コメントありがとうございます。 教えていただいた通り、検索して見ましたら大体は同じようなことを考えておりました。 私、kotlinもAndroidも習いたてて、今後使うことはないのですが、ある課題で、短期間で本題の機能を実装しなければならない状態のため、kotlinコードがあると大変助かります。
guest

回答1

0

たんにピーク値をとっていけばいいんでは。

投稿2019/09/17 12:37

y_waiwai

総合スコア88038

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yoursong

2019/09/18 10:31

回答ありがとうございます。 仰る通り、波形の振幅のピーク値から算出できるのではないかと考えているのですが、 どのようにコードを書き加えていいものか、何度検索しても検討がつかない状況です。 何か参考になるサイトや検索ワードがありましたら教えていただけると助かります。
y_waiwai

2019/09/18 13:56

マイナスのピークとプラスのピーク取って差分を求めればいいのでは。 あまりに基本的なもんなんでサイトと言われても困りますね
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問