Home | History | Annotate | Download | only in audio_analysis_lib
      1 #!/usr/bin/env python3.4
      2 #
      3 #   Copyright 2017 - The Android Open Source Project
      4 #
      5 #   Licensed under the Apache License, Version 2.0 (the "License");
      6 #   you may not use this file except in compliance with the License.
      7 #   You may obtain a copy of the License at
      8 #
      9 #       http://www.apache.org/licenses/LICENSE-2.0
     10 #
     11 #   Unless required by applicable law or agreed to in writing, software
     12 #   distributed under the License is distributed on an "AS IS" BASIS,
     13 #   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14 #   See the License for the specific language governing permissions and
     15 #   limitations under the License.
     16 """This module provides abstraction of audio data."""
     17 
     18 import contextlib
     19 import copy
     20 import numpy
     21 import struct
     22 from io import StringIO
     23 """The dict containing information on how to parse sample from raw data.
     24 
     25 Keys: The sample format as in aplay command.
     26 Values: A dict containing:
     27     message: Human-readable sample format.
     28     dtype_str: Data type used in numpy dtype.  Check
     29                https://docs.scipy.org/doc/numpy/reference/arrays.dtypes.html
     30                for supported data type.
     31     size_bytes: Number of bytes for one sample.
     32 """
     33 SAMPLE_FORMATS = dict(
     34     S32_LE=dict(
     35         message='Signed 32-bit integer, little-endian',
     36         dtype_str='<i',
     37         size_bytes=4),
     38     S16_LE=dict(
     39         message='Signed 16-bit integer, little-endian',
     40         dtype_str='<i',
     41         size_bytes=2))
     42 
     43 
     44 def get_maximum_value_from_sample_format(sample_format):
     45     """Gets the maximum value from sample format.
     46 
     47     Args:
     48         sample_format: A key in SAMPLE_FORMAT.
     49 
     50     Returns:The maximum value the sample can hold + 1.
     51 
     52     """
     53     size_bits = SAMPLE_FORMATS[sample_format]['size_bytes'] * 8
     54     return 1 << (size_bits - 1)
     55 
     56 
     57 class AudioRawDataError(Exception):
     58     """Error in AudioRawData."""
     59     pass
     60 
     61 
     62 class AudioRawData(object):
     63     """The abstraction of audio raw data.
     64 
     65     @property channel: The number of channels.
     66     @property channel_data: A list of lists containing samples in each channel.
     67                             E.g., The third sample in the second channel is
     68                             channel_data[1][2].
     69     @property sample_format: The sample format which should be one of the keys
     70                              in audio_data.SAMPLE_FORMATS.
     71     """
     72 
     73     def __init__(self, binary, channel, sample_format):
     74         """Initializes an AudioRawData.
     75 
     76         Args:
     77             binary: A string containing binary data. If binary is not None,
     78                        The samples in binary will be parsed and be filled into
     79                        channel_data.
     80             channel: The number of channels.
     81             sample_format: One of the keys in audio_data.SAMPLE_FORMATS.
     82         """
     83         self.channel = channel
     84         self.channel_data = [[] for _ in range(self.channel)]
     85         self.sample_format = sample_format
     86         if binary:
     87             self.read_binary(binary)
     88 
     89     def read_binary(self, binary):
     90         """Reads samples from binary and fills channel_data.
     91 
     92         Reads samples of fixed width from binary string into a numpy array
     93         and shapes them into each channel.
     94 
     95         Args:
     96             binary: A string containing binary data.
     97         """
     98         sample_format_dict = SAMPLE_FORMATS[self.sample_format]
     99 
    100         # The data type used in numpy fromstring function. For example,
    101         # <i4 for 32-bit signed int.
    102         np_dtype = '%s%d' % (sample_format_dict['dtype_str'],
    103                              sample_format_dict['size_bytes'])
    104 
    105         # Reads data from a string into 1-D array.
    106         np_array = numpy.fromstring(binary, dtype=np_dtype)
    107 
    108         n_frames = len(np_array) / self.channel
    109         # Reshape np_array into an array of shape (n_frames, channel).
    110         np_array = np_array.reshape(int(n_frames), self.channel)
    111         # Transpose np_arrya so it becomes of shape (channel, n_frames).
    112         self.channel_data = np_array.transpose()
    113