【问题标题】:How to play two sine wave on left and right channel separately with 16-bit format?16位格式的左右声道如何分别播放两个正弦波?
【发布时间】:2013-12-26 00:12:27
【问题描述】:

我需要生成 2 个不同频率的正弦波音调,并在 Android 上以立体声模式分别播放到左右声道。

这是我的代码:

int sample;
double sampleRate;
double duration;    
double time;
double f1;
double f2;
double amplitude1;
double amplitude2;
double sineWave1;
double sineWave2;
float[] buffer1;
float[] buffer2;
byte[] byteBuffer1;
byte[] byteBuffer2;
byte[] byteBufferFinal;
int bufferIndex;    
short x; 
short y;    
AudioTrack audioTrack;

@Override
public void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    sampleRate = 44100.0;
    duration = 20.0;
    f1 = 440.0;
    amplitude1= 1;
    f2 = 444.0;
    amplitude2 = 0;

    buffer1 = new float[(int)(duration*sampleRate)];
    buffer2 = new float[(int)(duration*sampleRate)];

    for(sample = 0; sample < buffer1.length; sample ++){
        time = sample / sampleRate;
        buffer1[sample] = (float)(amplitude1*Math.sin(2*Math.PI*f1*time));
        buffer2[sample] = (float)(amplitude2*Math.sin(2*Math.PI*f2*time));  
    }

    byteBuffer1 = new byte[buffer1.length*2]; //two bytes per audio frame, 16 bits

    for(int i = 0, bufferIndex=0; i < byteBuffer1.length; i++){
        x = (short) (buffer1[bufferIndex++]*32767.0); // [2^16 - 1]/2 = 32767.0
        byteBuffer1[i] = (byte) x; // low byte
        byteBuffer1[++i] = (byte) (x >>> 8);  // high byte          
    }


    byteBuffer2 = new byte[buffer2.length*2];

    for(int j = 0, bufferIndex=0; j < byteBuffer2.length; j++){
        y = (short) (buffer2[bufferIndex++]*32767.0);
        byteBuffer2[j] = (byte) y;         // low byte
        byteBuffer2[++j] = (byte) (y >>> 8);  // high byte

    }

    byteBufferFinal = new byte[byteBuffer1.length*2]; 
    //LL RR LL RR LL RR 
    for(int k = 0, index = 0; index < byteBufferFinal.length - 4; k=k+2){
        byteBufferFinal[index] = byteBuffer1[k]; // LEFT {0,1/4,5/8,9/12,13;...}
        byteBufferFinal[index+1] = byteBuffer1[k+1];
        index = index + 2;
        byteBufferFinal[index] = byteBuffer2[k]; // RIGHT {2,3/6,7/10,11;...}
        byteBufferFinal[index+1] = byteBuffer2[k+1];
        index = index + 2;
    }

    audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
            (int) sampleRate,AudioFormat.CHANNEL_OUT_STEREO,
            AudioFormat.ENCODING_PCM_16BIT,byteBufferFinal.length,
            AudioTrack.MODE_STATIC);

   audioTrack.write(byteBufferFinal, 0, byteBufferFinal.length);
   audioTrack.play();
   }

输出缓冲区(byteBufferFinal)具有 16 位格式:LL RR LL RR LL RR LL(其中每个字符为 1 个字节)

我的代码没有很好地分配左右声道的声音。我证明它在“1”中留下一个幅度,在“0”中留下另一个幅度,因此 2 个通道中的 1 个没有声音,但都发出声音

我的代码有什么问题?

【问题讨论】:

  • 音频被路由到什么地方(扬声器、耳机、USB……)?如果是扬声器;您正在测试的设备是否真的有立体声扬声器?
  • 我用立体声耳机!
  • @Michael 嘿,我偶然发现了这一点,这对我的实现很有用,但在我实现之前,我想了解一些基本概念 1. 缓冲区用于什么(例如:buffer1、buffer2、 byteBuffer) 2.为什么缓冲区的大小是44.1k(缓冲区和采样率有什么关系) 3.还有哪里用到的缓冲区 谢谢!祝您有愉快的一天!

标签: android audio frequency channel pcm


【解决方案1】:

我在我的三星 S4 上运行 API 18 Eclipse Kepler 进行了尝试,它运行良好。右声道静音,左声道播放 440Hz 正弦波。

我在阅读代码时注意到的唯一错误是播放时长是应有的 1/2:行“byteBufferFinal = new byte[buffer1.length*2];”应该改为“byteBufferFinal = new byte[byteBuffer1.length*2];”

遗憾的是,问题可能只是您的音频线或扬声器:音频插头可能没有完全插入电话插孔,导致两个扬声器都播放一个声道。

【讨论】:

  • 我在三星 Galaxy Ace 上使用 API 16 进行了尝试,但无法正常工作(左右声道发出声音)。然后,由于您的回答,我在 NEXUS 7(带耳机)上使用 API 18 进行了尝试,但无法正常工作。您必须以手机上的最大音量运行我的代码,您会发现两个声道都发声(一个声音比另一个声音低)。如果你不这样做,你会认为一个通道发声而另一个不发声。所以,问题不在于音频线或扬声器:(。我仍然不知道是什么问题!
  • PD:我更改了行“byteBufferFinal = new byte[buffer1.length*2];”到“byteBufferFinal = 新字节[byteBuffer1.length*2];”我错了,当我转移代码时。谢谢!!
  • "你必须在手机上以最大音量运行我的代码,你会发现两个声道的声音(一个声音比另一个低)。如果你不不,你会认为一个频道发声,另一个不发声。”表示您面临的可能不是软件问题,而是音频输出电路中的有限通道隔离。考虑使用 audacity 生成仅在一个通道中包含音频的测试文件,并使用各种播放器应用在桌面和手机上播放。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多