質問をすることでしか得られない、回答やアドバイスがある。

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

新規登録して質問してみよう
ただいま回答率
85.50%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Android

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

Q&A

解決済

2回答

3112閲覧

AudioTrack 矩形波・正弦波とノイズの関係についての質問

tcb78

総合スコア5

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Android

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

1グッド

1クリップ

投稿2018/09/05 12:02

編集2018/09/06 04:18

前提・実現したいこと

音波を生成して送信するAndroidアプリを作成しています。
開始画面で送信したい周波数と音量を入力してスイッチを押すと、その周波数の音波を生成して指定した音量で送信するシステムです。

矩形波を生成するアプリと正弦波を生成するアプリの2つを作ったのですが、
矩形波送信ではノイズがほとんどなく、正弦波送信ではたくさんのノイズが発生します。

本来は矩形波送信にノイズが発生して正弦波送信にはノイズはほとんど発生しないと考えているのですが、
私の理解が間違えているのか、プログラムが間違えているのか、どちらなのでしょうか。

開始画面

該当のソースコード

矩形波送信

lang

1package com.example.xxx.rectanglesender; 2 3import java.util.ArrayList; 4import java.util.List; 5import android.app.Activity; 6import android.content.Context; 7import android.media.AudioFormat; 8import android.media.AudioManager; 9import android.media.AudioTrack; 10import android.os.Bundle; 11import android.util.Log; 12import android.widget.CompoundButton; 13import android.widget.CompoundButton.OnCheckedChangeListener; 14import android.widget.Switch; 15import android.widget.EditText; 16import android.widget.TextView; 17 18public class MainActivity extends Activity implements OnCheckedChangeListener { 19 20 int SENDFREQ; 21 int VOLUME; 22 int SendSR; 23 int SendBufSize; 24 int musicVolume = 0; 25 26 AudioManager audioManager; 27 AudioTrack audioTrack = null; 28 private List<SoundDto> soundList = new ArrayList<SoundDto>(); 29 Thread send; 30 boolean bIsPlaying = false; 31 32 @Override 33 public void onCreate(Bundle savedInstanceState) { 34 super.onCreate(savedInstanceState); 35 setContentView(R.layout.activity_main); 36 37 TextView SendfreqText = findViewById(R.id.SendfreqText); 38 SendfreqText.setText(R.string.SendfreqText); 39 TextView volumeText = findViewById(R.id.volumeText); 40 volumeText.setText(R.string.volumeText); 41 Switch switch1 = findViewById(R.id.Switch); 42 switch1.setOnCheckedChangeListener(this); 43 } 44 45 @Override 46 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 47 48 if(isChecked) { 49 EditText SendfreqEdit = findViewById(R.id.SendfreqEdit); 50 EditText volumeEdit = findViewById(R.id.volumeEdit); 51 52 SENDFREQ = Integer.parseInt(SendfreqEdit.getText().toString()); 53 VOLUME = Integer.parseInt(volumeEdit.getText().toString()); 54 55 SendSR = 4 * SENDFREQ; 56 SendBufSize = 4 * SENDFREQ; 57 58 audioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE); 59 60 audioTrack = new AudioTrack( 61 AudioManager.STREAM_MUSIC, 62 SendSR, 63 AudioFormat.CHANNEL_OUT_MONO, 64 AudioFormat.ENCODING_PCM_16BIT, 65 SendBufSize, 66 AudioTrack.MODE_STREAM); 67 68 soundList.add(new SoundDto(createWaves(SendSR))); 69 70 musicVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC); 71 audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, VOLUME, 0); 72 73 audioTrack.play(); 74 bIsPlaying = true; 75 send = new Thread(new Runnable() { 76 @Override 77 public void run() { 78 while(bIsPlaying) { 79 for(SoundDto sound : soundList) { 80 audioTrack.write(sound.getSound(), 0, sound.getSound().length); 81 } 82 } 83 audioTrack.stop(); 84 audioTrack.release(); 85 } 86 }); 87 send.start(); 88 } else { 89 90 if(audioTrack.getPlayState() == AudioTrack.PLAYSTATE_PLAYING) { 91 audioTrack.stop(); 92 bIsPlaying = false; 93 } 94 audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, musicVolume, 0); 95 } 96 } 97 98 //波形データ生成 99 public byte[] createWaves(int sampleRate) { 100 byte[] data = new byte[sampleRate]; 101 int flag = 0; 102 103 for(int i = 0; i < sampleRate; i = i + 2) { 104 if(flag == 0) { 105 data[i] = (byte)0xff; 106 data[i + 1] = (byte)0xff; 107 flag++; 108 } else { 109 data[i] = (byte)0x00; 110 data[i + 1] = (byte)0x00; 111 flag--; 112 } 113 } 114 return data; 115 } 116 117}

正弦波送信

main

lang

1package com.example.xxx.sinusoidsender; 2 3import java.util.ArrayList; 4import java.util.List; 5 6import android.app.Activity; 7import android.content.Context; 8import android.media.AudioFormat; 9import android.media.AudioManager; 10import android.media.AudioTrack; 11import android.os.Bundle; 12import android.util.Log; 13import android.widget.CompoundButton; 14import android.widget.CompoundButton.OnCheckedChangeListener; 15import android.widget.EditText; 16import android.widget.Switch; 17import android.widget.TextView; 18 19public class MainActivity extends Activity implements OnCheckedChangeListener { 20 21 //音を何秒鳴らすか 22 public static final double WHOLE_NOTE = 1.0; 23 24 //信号音の周波数 25 public static final double SIGNAL = 20000; 26 public static final double START = 1000; 27 28 int SENDFREQ; 29 int VOLUME; 30 int SendSR = 44100; 31 int SendBufSize = 44100; 32 int musicVolume = 0; 33 34 AudioManager audioManager; 35 AudioTrack audioTrack = null; 36 private List<SoundDto> soundList = new ArrayList<SoundDto>(); 37 Thread send; 38 boolean bIsPlaying = false; 39 40 // Sound生成クラス 41 DigitalSoundGenerator soundGenerator; 42 43 @Override 44 protected void onCreate(Bundle savedInstanceState) { 45 super.onCreate(savedInstanceState); 46 setContentView(R.layout.activity_main); 47 48 TextView SendfreqText = findViewById(R.id.SendfreqText); 49 SendfreqText.setText(R.string.SendfreqText); 50 TextView volumeText = findViewById(R.id.volumeText); 51 volumeText.setText(R.string.volumeText); 52 Switch switch1 = findViewById(R.id.Switch); 53 switch1.setOnCheckedChangeListener(this); 54 55 } 56 57 @Override 58 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 59 60 if(isChecked) { 61 62 EditText SendfreqEdit = findViewById(R.id.SendfreqEdit); 63 EditText volumeEdit = findViewById(R.id.volumeEdit); 64 65 SENDFREQ = Integer.parseInt(SendfreqEdit.getText().toString()); 66 VOLUME = Integer.parseInt(volumeEdit.getText().toString()); 67 68 audioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE); 69 70 // SoundGeneratorクラスをサンプルレート44100で作成 71 soundGenerator = new DigitalSoundGenerator(44100, 44100); 72 73 // 再生用AudioTrackは、同じサンプルレートで初期化したものを利用する 74 audioTrack = soundGenerator.getAudioTrack(); 75 76 soundList.add(new SoundDto(generateSound(soundGenerator,SIGNAL), WHOLE_NOTE)); 77 78 musicVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC); 79 audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, VOLUME, 0); 80 81 audioTrack.play(); 82 bIsPlaying = true; 83 send = new Thread(new Runnable() { 84 @Override 85 public void run() { 86 while(bIsPlaying) { 87 for(SoundDto sound : soundList) { 88 audioTrack.write(sound.getSound(), 0, sound.getSound().length); 89 } 90 } 91 audioTrack.stop(); 92 audioTrack.release(); 93 } 94 }); 95 send.start(); 96 97 } else { 98 99 if(audioTrack.getPlayState() == AudioTrack.PLAYSTATE_PLAYING) { 100 audioTrack.stop(); 101 bIsPlaying = false; 102 } 103 audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, musicVolume, 0); 104 105 } 106 107 } 108 109 /** 110 * 8ビットのピコピコ音を生成する 111 * @param gen Generator 112 * @param freq 周波数(音階) 113 * @return 音データ 114 */ 115 public byte[] generateSound(DigitalSoundGenerator gen, double freq) { 116 return gen.getSound(freq); 117 } 118}

sound生成

lang

1package com.example.xxx.sinusoidsender; 2 3import android.media.AudioFormat; 4import android.media.AudioManager; 5import android.media.AudioTrack; 6 7public class DigitalSoundGenerator { 8 9 private AudioTrack audioTrack; 10 11 private int sampleRate; 12 private int bufferSize; 13 14 /** 15 * コンストラクタ 16 */ 17 public DigitalSoundGenerator(int sampleRate, int bufferSize) { 18 this.sampleRate = sampleRate; 19 this.bufferSize = bufferSize; 20 21 // AudioTrackを作成 22 this.audioTrack = new AudioTrack( 23 AudioManager.STREAM_MUSIC, 24 sampleRate, 25 AudioFormat.CHANNEL_OUT_MONO, 26 AudioFormat.ENCODING_PCM_16BIT, 27 bufferSize, 28 AudioTrack.MODE_STREAM); 29 } 30 31 /** 32 * サウンド生成 33 * @param frequency 鳴らしたい音の周波数 34 * @return 音声データ 35 */ 36 public byte[] getSound(double frequency) { 37 frequency = frequency / 2; 38 // byteバッファを作成 39 byte[] buffer = new byte[(int)Math.ceil(bufferSize)]; 40 double hz; 41 double amplitude = 10; //振幅 42 int i; 43 double max=0; 44 double trans; 45 double[] t=new double[buffer.length]; 46 hz=frequency/this.sampleRate; 47 for(i=0;i<buffer.length;i++){ 48 t[i]=Math.sin(i*2*Math.PI*hz); 49 //t[i]=amplitude * Math.sin(i*2*Math.PI*hz); 50 if(t[i]>max) 51 max=t[i]; 52 } 53 trans=127/max; 54 for(i=0;i<buffer.length;i++){ 55 buffer[i]= (byte) Math.round(t[i]*trans); 56 57 } 58 return buffer; 59 } 60 61 public AudioTrack getAudioTrack() { 62 return this.audioTrack; 63 } 64}
set0gut1👍を押しています

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

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

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

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

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

ikadzuchi

2018/09/05 12:08

「本来は矩形波送信にノイズが発生して正弦波送信にはノイズはほとんど発生しないと考えている」のはなぜですか? また、ノイズとは何のことですか?
y_waiwai

2018/09/05 12:44

音を出してるところが見当たりませんが、どうやって音を出してる/送信してるんでしょうか
tcb78

2018/09/06 04:22

ここでのノイズとは音声としての雑音のことです。「本来は矩形波送信にノイズが発生して正弦波送信にはノイズはほとんど発生しないと考えている」というのは普段我々が耳にする音声は正弦波であるから矩形波には再生したい周波数以外の音が現れるだろうと考えていました。
tcb78

2018/09/06 04:23

私の考え方が間違っていれば矩形波に雑音が発生せず正弦波に雑音が発生しない理由を教えていただけないでしょうか。
guest

回答2

0

自己解決

解決方法

生成する音声データをbyte型からshort型にすることで雑音がなくなりました。

質問時のコードでは音声データをbyte型で生成しており、byte型の値の範囲である-128127で正規化しています。
それをshort型で生成し、short型の値の範囲である-32768
32767で正規化することにより雑音のない単音が再生出来ました。

おそらく音声データを正規化するための分解能が高くなったことで誤差が小さくなり、雑音が発生しにくくなったのだと考えています。

修正後のコード

java:

1/** 2 * 正弦波生成 3 * @param frequency 音の周波数 4 * @return 音声データ 5 */ 6public short[] getSoundShort(double frequency) { 7 double[] value = new double[sampleRate]; 8 double max = 0.0; 9 for(int i = 0; i < sampleRate; i++) { 10 value[i] = Math.sin(2.0 * Math.PI * frequency * i / sampleRate); 11 if(value[i] > max) { 12 max = value[i]; 13 } 14 } 15 short[] buffer = toShort(value, max); 16 17 return buffer; 18} 19 20/** 21 * double型をshort型に変換(-32768~32767で正規化) 22 * @param val double型音声データ 23 * @param max 最大値 24 * @return short型音声データ 25 */ 26public short[] toShort(double[] val, double max) { 27 double trans = 32767 / max; 28 short[] buf = new short[sampleRate]; 29 for(int i = 0; i < sampleRate; i++) { 30 buf[i] = (short)Math.round(val[i] * trans); 31 } 32 return buf; 33}

投稿2019/08/28 17:56

tcb78

総合スコア5

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

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

ikadzuchi

2019/08/29 00:26

いえですからbyteは符号なしであるべきところ符号付きで使っていたからノイズが出ていて、shortは符号付きであるべきで正しく符号付きにしたからノイズが出なくなったのだと思います。
y_waiwai

2019/08/29 00:28

まあそりゃ矩形波というのは0か1かですから、ノイズの乗りようもないし。
tcb78

2019/08/30 04:36

そういうことなんですね。いろいろとコメントをくださりありがとうございます。
guest

0

あ、正弦波の方が値が符号付きになっているようですね。
(矩形波の方では正しく扱っているように)8bitのwavは符号なしです。

投稿2018/09/05 12:59

ikadzuchi

総合スコア3047

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

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

tcb78

2018/09/06 04:25

符号付きになっていることがどこから判断できるか今の私では分からないのでどこから分かったか教えていただけないでしょうか。
ikadzuchi

2018/09/07 00:40

符号付きといいますか、入れる値が「Math.sin(i*2*Math.PI*hz);」で正負あるまま、振幅を調整するだけでbyte変数まで入っているように見えます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問