zoukankan      html  css  js  c++  java
  • 8.1.2 生成样本

        通过使用一点算术,就能够利用算法来创建这些样本,例如可以重新生成经典的正弦波,以下示例产生了一个440Hz的正弦波。

     1 package com.nthm.androidtestActivity;
     2 
     3 import com.nthm.androidtest.R;
     4 import android.app.Activity;
     5 import android.media.AudioFormat;
     6 import android.media.AudioManager;
     7 import android.media.AudioTrack;
     8 import android.os.AsyncTask;
     9 import android.os.Bundle;
    10 import android.view.View;
    11 import android.view.View.OnClickListener;
    12 import android.widget.Button;
    13 
    14 public class AudioSynthesis extends Activity implements OnClickListener {
    15     private Button startSound;
    16     private Button endSound;
    17     private AudioSynthesisTask audioSynth;
    18     private boolean keepGoing=false;
    19     private float synth_frequency=440;//440Hz , Middle A
    20     @Override
    21     protected void onCreate(Bundle savedInstanceState) {
    22         super.onCreate(savedInstanceState);
    23         setContentView(R.layout.audiosynthesis);
    24         startSound=(Button) findViewById(R.id.StartSound);
    25         startSound.setOnClickListener(this);
    26         endSound=(Button) findViewById(R.id.EndSound);
    27         endSound.setOnClickListener(this);
    28         
    29         endSound.setEnabled(false);
    30     }
    31      
    32     @Override
    33     protected void onPause() {
    34         super.onPause();
    35         keepGoing=false;
    36         endSound.setEnabled(false);
    37         startSound.setEnabled(true);
    38     }
    39 
    40     @Override
    41     public void onClick(View v) {
    42          if(v==startSound){
    43              keepGoing=true;
    44              audioSynth=new AudioSynthesisTask();
    45              audioSynth.execute();
    46              endSound.setEnabled(true);
    47              startSound.setEnabled(false);
    48          }else if(v==endSound){
    49              keepGoing=false;
    50              endSound.setEnabled(false);
    51              startSound.setEnabled(true);
    52          }
    53     }
    54     private class AudioSynthesisTask extends AsyncTask<Void, Void, Void>{
    55 
    56         @Override
    57         protected Void doInBackground(Void... params) {
    58             final int SAMPLE_RATE=11025;
    59             int minSize=AudioTrack.getMinBufferSize(SAMPLE_RATE, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT);
    60             AudioTrack audioTrack=new AudioTrack(AudioManager.STREAM_MUSIC, SAMPLE_RATE, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, minSize, AudioTrack.MODE_STREAM);
    61             audioTrack.play();
    62             short[] buffer=new short[minSize];
    63             float angular_frequency=(float)(2*Math.PI)*synth_frequency/SAMPLE_RATE;
    64             float angle=0;
    65             while(keepGoing){
    66                 for(int i=0;i<buffer.length;i++){
    67                     buffer[i]=(short)(Short.MAX_VALUE*((float) Math.sin(angle)));
    68                     angle+=angular_frequency;
    69                 }
    70                 audioTrack.write(buffer, 0, buffer.length);
    71             }
    72             return null;
    73         }
    74     }
    75 }

        下面是用于活动的布局XML文件:

     1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     2     android:layout_width="match_parent"
     3     android:layout_height="match_parent"
     4     android:orientation="vertical"
     5     >
     6  
     7  <Button 
     8      android:layout_width="wrap_content"
     9      android:layout_height="wrap_content"
    10      android:id="@+id/StartSound"
    11      android:text="Start Sound"/>
    12  <Button 
    13      android:layout_width="wrap_content"
    14      android:layout_height="wrap_content"
    15      android:id="@+id/EndSound"
    16      android:text="End Sound"/>
    17  
    18 </LinearLayout>

         通过更改synth_frequency,我们可以重新生成任何其他想要的频率。当然,更改用于生成值的函数同样也将改变声音。我们可能希望尝试将样本固定位Short.MAX_VALUE或Short.MIN_VALUE,以实现一个快速而平稳的方波示例。

        当然,这仅仅是在Android上处理音频合成的浅显内容。由于使用AudioTrack能够播放原始的PCM样本,因此在Android上几乎可以使用任何可用来生成数字音频的技术,不过这需要考虑到处理器的速度和内存的限制。

        下面是一个示例应用程序,其采用了一些第4章中介绍的技术来跟踪手指在触摸屏上的位置,同时采用上述示例代码生成音频。此应用程序将生成音频,同时根据用户手指在触摸屏的x轴上的位置选择频率。

     1 package com.nthm.androidtestActivity;
     2 
     3 import com.nthm.androidtest.R;
     4 import android.app.Activity;
     5 import android.media.AudioFormat;
     6 import android.media.AudioManager;
     7 import android.media.AudioTrack;
     8 import android.os.AsyncTask;
     9 import android.os.Bundle;
    10 import android.view.MotionEvent;
    11 import android.view.View;
    12 import android.view.View.OnTouchListener;

        活动将实现OnTouchListener,从而可以跟踪触摸的位置。

    1 public class FingerSynthesis extends Activity implements OnTouchListener {

        就像之前的示例一样,本示例将使用AsyncTask,以提供一个生成和播放音频样本的线程。

    1     private AudioSynthesisTask AudioSynth;

        需要一个基准音频频率,当手指放在x轴上的0位置时播放该频率。这将是播放的最低频率。

    1     private static final float BASE_FREQUENCY=440;

        随着手指的移动会变浮点数synth_frequency。在应用启动应用程序时,将它设置为BASE_FREQUENCY。

    1     private float synth_frequency=BASE_FREQUENCY;

        使用play布尔值来确定何时应该实际的播放音频。该布尔值将由触摸事件控制。

    1     private boolean play=false;
    2     @Override
    3     protected void onCreate(Bundle savedInstanceState) {
    4         super.onCreate(savedInstanceState);
    5         setContentView(R.layout.fingersynthesis);
    6          View mainView=findViewById(R.id.MainView);

        在布局中只有一个条目,即包含ID MainView的LinearLayout。获得该条目的一个引用,同时将OnTouchListener注册为当前活动。这样,当用户触摸屏时将调用活动的onTouch方法。

     1         View mainView=findViewById(R.id.MainView);
     2         mainView.setOnTouchListener(this);
     3         
     4         AudioSynth=new AudioSynthesisTask();
     5         AudioSynth.execute();
     6     }
     7 
     8     @Override
     9     protected void onPause() {
    10         super.onPause();
    11         play=false;
    12         finish();
    13     }

        当用户开始触摸,停止触摸或在屏幕上移动手指时,都将调用onTouch方法,它根据用户的操作将play布尔值设置为true或false。这将控制是否生成音频样本。该方法还将跟踪用户手指在触摸屏x轴上的位置,从而相应的调整synth_frequency变量。

     1     @Override
     2     public boolean onTouch(View v, MotionEvent event) {
     3         int action=event.getAction();
     4         switch (action) {
     5         case MotionEvent.ACTION_DOWN:
     6             play=true;
     7             synth_frequency=event.getX()+BASE_FREQUENCY;
     8             break;
     9         case MotionEvent.ACTION_MOVE:
    10             play=true;
    11             synth_frequency=event.getX()+BASE_FREQUENCY;
    12             break;
    13         case MotionEvent.ACTION_UP:
    14             play=false;
    15             break;
    16         case MotionEvent.ACTION_CANCEL:
    17             
    18             break;
    19         default:
    20             break;
    21         }
    22         return true;
    23     }
    24     private class AudioSynthesisTask extends AsyncTask<Void, Void, Void>{
    25 
    26         @Override
    27         protected Void doInBackground(Void... params) {
    28             final int SAMPLE_RATE=11025;
    29             int minSize=AudioTrack.getMinBufferSize(SAMPLE_RATE, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT);
    30             AudioTrack audioTrack=new AudioTrack(AudioManager.STREAM_MUSIC, SAMPLE_RATE, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, minSize, AudioTrack.MODE_STREAM);
    31             audioTrack.play();
    32             short[]buffer=new short[minSize];
    33             float angle=0;

        最后,在AudioSynthesisTask生成音频的循环中,检查play布尔值,同时进行计算以根据synth_frequency变量(可以根据用户的手指位置对这个变量进行更改)生成音频样本。

     1             while(true){
     2                 if(play){
     3                     for(int i=0;i<buffer.length;i++){
     4                         float angular_frequency=(float)(2*Math.PI)*synth_frequency/SAMPLE_RATE;
     5                         buffer[i]=(short)(Short.MAX_VALUE*((float) Math.sin(angle)));
     6                         angle+=angular_frequency;
     7                     }
     8                     audioTrack.write(buffer, 0, buffer.length);
     9                 }else{
    10                     try {
    11                         Thread.sleep(50);
    12                     } catch (InterruptedException e) {
    13                         e.printStackTrace();
    14                     }
    15                 }
    16             }
    17         }
    18     }
    19 }

        下面是布局XML

    1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    2     android:layout_width="match_parent"
    3     android:layout_height="match_parent"
    4     android:orientation="vertical"
    5     android:id="@+id/MainView"
    6     >
    7 
    8 </LinearLayout>

        这个示例部分演示了AudioTrack类的能力和灵活性。由于可以通过算法生成音频,因此能够使用任何想要的方法来决定音频的特征(此示例利用了音频的声调或者频率)。

  • 相关阅读:
    jQuery Ajax 实例
    jQuery Ajax 实例
    mysql中使用MySqlParameter操作数据库
    mysql中使用MySqlParameter操作数据库
    MySQL limit 分页查询数据库
    html5新特性data_*自定义属性使用
    CSS中zoom和scale的区别
    Linux下nginx编译安装教程和编译参数详解
    nginx.conf配置
    linux下tar.gz、tar、bz2、zip等解压缩、压缩命令小结
  • 原文地址:https://www.cnblogs.com/ZSS-Android/p/3951685.html
Copyright © 2011-2022 走看看