Android Audio: How to use Audiotrack to play a WAV format file?

Source: Internet
Author: User
Tags rewind unsupported

translation by Long LuoOriginal link: Android audio:play a WAV file on an audiotrack
译者注:1. 由于这是技术文章,所以有些词句使用原文,表达更准确。2. 由于水平有效,有些地方可能翻译的不够准确,如有不当之处,敬请批评指正.3. 针对某些语句,适当补充了上下文及更适合中文阅读,尽量做到信达雅。

If you have been successful in understanding about audiotrack some topics, then you might enjoy the benefits it brings, such as low latency (in static mode), the ability to generate streaming audio (in stream mode), and before playback, will be able to access and modify the original sound data.

However, the question now is how to get data from the source. Many applications require the use of does not simply generate PCM audio (for example, ethereal Dialpad or any other similar app). You may need to load data from a file source, such as WAV or mp3 file.

Don't expect to use MediaPlayer , to decode WAV Documents and MP3 audio. Although MediaPlayer The plays these files very well, but their playback logic is entirely in the native layer, and does not provide us with additional options that allow us to use other decoders for our purposes. Therefore, we must decode from the audio file manually from the PCM .

In this article, you will discuss WAV format files. In the next lesson, we'll take a step further and discuss how to read audio from a MP3 file.

Background knowledge: Some digital audio terminology

If your app isn't specifically designed for digital audio, you may need to know some basic acronyms before continuing our discussion. Don't worry, it's easy, we don't need to dig into it.

  • PCM ( pulse modulation mode ) – The simplest way to make a physical audio signal a digital one. The basic principle is that the signal becomes a digital array where each number represents the level at which the sound is instantaneous at a particular time. The can also be said to be energy (amplitude). (If this explanation may not be scientifically accurate, then I can only say sorry.) Believe it or not, you can use this method to express any complex sound, And it's very accurate to release it. Here, we will only talk about linear PCM. In linear PCM, where each number in the array is the original sound amplitude linear means . In some cases, logarithmic mappings better represent the original scale of the sound amplitude-but we will not discuss those situations.

  • Sampling rate:-How many samples of your digital sound per second (the sound amplitude is represented by numbers). The more samples you have, the better the sound quality you can get. The current sampling rates used in consumer audio systems are usually 22050,44100 and 48000hz/s.

  • Each sample resolution/sample size/bit – defines the size and format of the amplitude numbers. For example, if you are using a 8-bit integer, you can only express the magnitude of level 256, so the original physical waveform will be reduced to 256 discrete levels, at the same time, you will lose some of the sound accuracy is also said to be quality. If you use 16-bit, the sound quality becomes better. In fact, most of the time you might be using 16-bit audio. Other options include 24-bit, 32-bit (these are not supported by Android now), or use floating-point numbers.

  • Channel – can be mono or stereo (2 channels), or more (but Android does not support it). If you want to have stereo, you need to have stereo audio, you must have a separate PCM array in each channel, and the corresponding amount of information will double.

The above definitions also help you to understand the amount of data in a particular format and length of the audio buffer in order to prepare buffers in advance. That is, you need a buffer to be used to store stereo 16-bit linear PCM data with a 44100Hz sample rate for a length of 5 seconds. The data calculation formula is as follows:

5 sec * 44100 Samples per sec * 2 bytes per sample * 2 channels = 882,000 bytes /p>

This amount of memory required may be surprising to beginners, because when you store audio on your disk, a MP3 file, a 880KB file can accommodate audio tracks with the same sample rate and resolution of 1 minutes. What is this for? Because of the advanced format, such as the MP3 format. Because our brains are unable to distinguish the content of some audio, we use a lot of complicated ways to get rid of it in the process of compression. However, most low-grade audio APIs, including Android Audiotrack , can only accept linear PCM. That's why if we can't put the entire sample in memory, we need to deal with the data stream, loop buffers and other clever ways to use the audio API.

Hopefully this explanation doesn't confuse you, now let's go on to actually do some work on Android digital audio!

WAV file format

Our goal is to use a inputstream , from which a wav file loads the PCM data to provide raw byte data. We can then push the original PCM data directly to the audiotrack.write , by using AudioTrack.write () this API.

WAV The file contains a header and a specific data will. We need to read the file header to know such information as sample rate, resolution, and so on. In addition, we can also know whether this format is supported through the file header. WAV Can be encapsulated in a variety of formats and we can't support it all. Maybe, just a reasonable sampling rate, resolution and channel linearity PCM format.

The details of WAV format can be found on the Internet, you just need to search on Google. However, unfortunately, I did not search for a good Java library to read WAV files, and can be ported to Android . So, I wrote some simple code myself.

The following method is how to read the head of a WAV file:

private static final String riff_header = "RIFF";p rivate static final String wave_header = "WAVE";p rivate static final Str  ing fmt_header = "FMT";p rivate static final String Data_header = "DATA";p rivate static final int header_size = 44;private Static final String CHARSET = "ASCII";/* */public static Wavinfo Readheader (InputStream wavstream) throws IOException    , decoderexception {Bytebuffer buffer = bytebuffer.allocate (header_size);    Buffer.order (Byteorder.little_endian);    Wavstream.read (Buffer.array (), Buffer.arrayoffset (), buffer.capacity ());    Buffer.rewind ();    Buffer.position (buffer.position () + 20);    int format = Buffer.getshort (); Checkformat (format = = 1, "Unsupported encoding:" + format);                                                                    1 means//Linear    PCM int channels = Buffer.getshort (); Checkformat (Channels = = 1 | | channels = = 2, "Unsupported channels: "+ channels);    int rate = Buffer.getint ();    Checkformat (Rate <= 48000 && rate >= 11025, "Unsupported rate:" + rate);    Buffer.position (Buffer.position () + 6);    int bits = Buffer.getshort ();    Checkformat (bits = =, "Unsupported bits:" + bits);    int datasize = 0;        while (Buffer.getint ()! = 0x61746164) {//"data" marker log.d (TAG, "skipping non-data chunk");        int size = Buffer.getint ();        Wavstream.skip (size);        Buffer.rewind ();        Wavstream.read (Buffer.array (), Buffer.arrayoffset (), 8);    Buffer.rewind ();    } datasize = Buffer.getint ();    Checkformat (datasize > 0, "wrong datasize:" + datasize); return new Wavinfo (new Formatspec (rate, channels = = 2), datasize);}

The missing part of the above code should be obvious. As you can see, only 16 bits are supported, but in the you could modify the code to support 8-bit (audiotrack does not support any other resolution).

The following method is used to read the remainder of the file – the audio data .

public static byte[" READWAVPCM (wavinfo info, InputStream stream) throws IOException    {byte[] data = new byte[info.getdatasize ()];    Stream.read (data, 0, data.length); return data;}  

The wavinfo structure We read, which contains the sample rate, resolution and number of channels, is enough for us to play the audio we read.

If we do not need to put all the audio data into memory once, we can use a inputstream, 1.1 point to read.

Passing PCM to Audiotrack

We are now facing 2 scenarios, creating a new Audiotrackfor this format, or using an existing audiotrack, but may not match the format of our WAV audio data.

In the first case, it's very simple, we just need to construct a Audiotrack constructor that we've already mapped from the WAV header.

In the second case, we need to turn our audio into the desired format for audiotrack . We need to do several conversions:

If the sampling rate is different, either discard or copy a sample to match the target rate. If the resolution is different, map the source signal resolution to the target resolution, from 16 bits to 8 bits, and vice versa. If the channels are different, we either mix the stereo channels into a mono or repeating mono data to turn it into quasi-stereo. (Consider putting the implementation of these algorithms on the native layer, because the native layer has a great advantage in doing this kind of processing.) )

In other cases, we have determined that the format has been matched. We use writes the buffer for playback.

Remember, if you use static mode, you need to create a new Audiotrack that contains the exact buffer size before play () and write the Write () audio data. In streaming mode, we can first use Audiotrack 's play ()and then write the data section using Write ()

Summarize

There are a number of reasons why you might want to implement WAV audio on audiotrack . Sometimes, it may be that Soundpool has a size limit, or mediaplayer can have delays and a high resource footprint, which allows you to consider using this approach. Sometimes you need to modify audio or mix audio. In any case, this article tries to tell you what to do.

In the next article, we will discuss MP3 audio, so please look forward to:-)

Long Luo for Part 1 created in 23:15 ~ 00:33 June 21th, @Shenzhen, China.Long Luo for Part 2 created in 16:00 ~ 17:15 June 22th, @Shenzhen, China.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.