Home | History | Annotate | Download | only in audio
      1 #!/usr/bin/env python
      2 # Copyright 2014 The Chromium OS Authors. All rights reserved.
      3 # Use of this source code is governed by a BSD-style license that can be
      4 # found in the LICENSE file.
      5 
      6 """This module provides audio test data."""
      7 
      8 import os
      9 
     10 from autotest_lib.client.cros.audio import audio_data
     11 from autotest_lib.client.cros.audio import sox_utils
     12 
     13 
     14 class AudioTestDataException(Exception):
     15     """Exception for audio test data."""
     16     pass
     17 
     18 
     19 class AudioTestData(object):
     20     """Class to represent audio test data."""
     21     def __init__(self, data_format=None, path=None, frequencies=None):
     22         """
     23         Initializes an audio test file.
     24 
     25         @param data_format: A dict containing data format including
     26                             file_type, sample_format, channel, and rate.
     27                             file_type: file type e.g. 'raw' or 'wav'.
     28                             sample_format: One of the keys in
     29                                            audio_data.SAMPLE_FORMAT.
     30                             channel: number of channels.
     31                             rate: sampling rate.
     32         @param path: The path to the file.
     33         @param frequencies: A list containing the frequency of each channel in
     34                             this file. Only applicable to data of sine tone.
     35 
     36         @raises: AudioTestDataException if the path does not exist.
     37 
     38         """
     39         self.data_format = data_format
     40         if not os.path.exists(path):
     41             raise AudioTestDataException('Can not find path %s' % path)
     42         self.path = path
     43         self.frequencies = frequencies
     44 
     45 
     46     def get_binary(self):
     47         """The binary of test data.
     48 
     49         @returns: The binary of test data.
     50 
     51         """
     52         with open(self.path, 'rb') as f:
     53             return f.read()
     54 
     55 
     56     def convert(self, data_format, volume_scale):
     57         """Converts the data format and returns a new AudioTestData object.
     58 
     59         Converts the source file at self.path to a new data format.
     60         The destination file path is self.path with a suffix. E.g.
     61         original_path = '/tmp/test.raw'
     62         data_format = dict(file_type='raw', sample_format='S32_LE',
     63                            channel=2, rate=48000)
     64         new_path = '/tmp/test_raw_48000_S32_LE_2.raw'
     65 
     66         This method returns a new AudioTestData object so the original object is
     67         not changed.
     68 
     69         @param data_format: A dict containing new data format.
     70         @param volume_scale: A float for volume scale used in sox command.
     71                               E.g. 1.0 is the same. 0.5 to scale volume by
     72                               half. -1.0 to invert the data.
     73 
     74         @returns: A new AudioTestData object with converted format and new path.
     75 
     76         """
     77         original_path_without_ext, ext = os.path.splitext(self.path)
     78         new_path = (original_path_without_ext + '_' +
     79                     '_'.join(str(x) for x in data_format.values()) + ext)
     80 
     81         sox_utils.convert_format(
     82                 path_src=self.path,
     83                 channels_src=self.data_format['channel'],
     84                 rate_src=self.data_format['rate'],
     85                 bits_src=audio_data.SAMPLE_FORMATS[
     86                         self.data_format['sample_format']]['size_bytes'] * 8,
     87                 path_dst=new_path,
     88                 channels_dst=data_format['channel'],
     89                 rate_dst=data_format['rate'],
     90                 bits_dst=audio_data.SAMPLE_FORMATS[
     91                         data_format['sample_format']]['size_bytes'] * 8,
     92                 volume_scale=volume_scale)
     93 
     94         new_test_data = AudioTestData(path=new_path,
     95                                       data_format=data_format)
     96 
     97         return new_test_data
     98 
     99 
    100     def delete(self):
    101         """Deletes the file at self.path."""
    102         os.unlink(self.path)
    103 
    104 
    105 class FakeTestData(object):
    106     def __init__(self, frequencies):
    107         """A fake test data which contains properties but no real data.
    108 
    109         This is useful when we need to pass an AudioTestData object into a test
    110         or audio_test_utils.check_recorded_frequency.
    111 
    112         @param frequencies: A list containing the frequency of each channel in
    113                             this file. Only applicable to data of sine tone.
    114 
    115         """
    116         self.frequencies = frequencies
    117 
    118 
    119 AUDIO_PATH = os.path.join(os.path.dirname(__file__))
    120 
    121 """
    122 This test data contains frequency sweep from 20Hz to 20000Hz in two channels.
    123 Left channel sweeps from 20Hz to 20000Hz, while right channel sweeps from
    124 20000Hz to 20Hz. The sweep duration is 2 seconds. The begin and end of the file
    125 is padded with 0.2 seconds of silence. The file is two-channel raw data with
    126 each sample being a signed 16-bit integer in little-endian with sampling rate
    127 48000 samples/sec.
    128 """
    129 SWEEP_TEST_FILE = AudioTestData(
    130         path=os.path.join(AUDIO_PATH, 'pad_sweep_pad_16.raw'),
    131         data_format=dict(file_type='raw',
    132                          sample_format='S16_LE',
    133                          channel=2,
    134                          rate=48000))
    135 
    136 """
    137 This test data contains fixed frequency sine wave in two channels.
    138 Left channel is 2KHz, while right channel is 1KHz. The duration is 6 seconds.
    139 The file format is two-channel raw data with each sample being a signed
    140 16-bit integer in little-endian with sampling rate 48000 samples/sec.
    141 """
    142 FREQUENCY_TEST_FILE = AudioTestData(
    143         path=os.path.join(AUDIO_PATH, 'fix_2k_1k_16.raw'),
    144         data_format=dict(file_type='raw',
    145                          sample_format='S16_LE',
    146                          channel=2,
    147                          rate=48000),
    148         frequencies=[2000, 1000])
    149 
    150 
    151 """
    152 This test data contains fixed frequency sine wave in two channels.
    153 Left and right channel are both 440Hz. The duration is 10 seconds.
    154 The file format is two-channel raw data with each sample being a signed
    155 16-bit integer in little-endian with sampling rate 48000 samples/sec.
    156 The volume is 0.1. The small volume is to avoid distortion when played
    157 on Chameleon.
    158 """
    159 SIMPLE_FREQUENCY_TEST_FILE = AudioTestData(
    160         path=os.path.join(AUDIO_PATH, 'fix_440_16.raw'),
    161         data_format=dict(file_type='raw',
    162                          sample_format='S16_LE',
    163                          channel=2,
    164                          rate=48000),
    165         frequencies=[440, 440])
    166 
    167 """
    168 This test data contains fixed frequency sine wave in two channels.
    169 Left and right channel are both 440Hz. The duration is 10 seconds.
    170 The file format is two-channel raw data with each sample being a signed
    171 16-bit integer in little-endian with sampling rate 48000 samples/sec.
    172 The volume is 0.5. The larger volume is needed to test internal
    173 speaker of Cros device because the microphone of Chameleon is not sensitive
    174 enough.
    175 """
    176 SIMPLE_FREQUENCY_SPEAKER_TEST_FILE = AudioTestData(
    177         path=os.path.join(AUDIO_PATH, 'fix_440_16_half.raw'),
    178         data_format=dict(file_type='raw',
    179                          sample_format='S16_LE',
    180                          channel=2,
    181                          rate=48000),
    182         frequencies=[440, 440])
    183 
    184 """
    185 Media test verification for 256Hz frequency (headphone audio).
    186 """
    187 MEDIA_HEADPHONE_TEST_FILE = FakeTestData(frequencies=[256, 256])
    188 
    189 """
    190 Media test verification for 512Hz frequency (onboard speakers).
    191 """
    192 MEDIA_SPEAKER_TEST_FILE = FakeTestData(frequencies=[512, 512])
    193