def process(self, item, file_paths, target_dir=None):
        if item.form == 'ignore':
            return

        if target_dir is None:
            raise TypeError('"target_dir" must be given')

        avg_fr = FrequencyResponse(name=item.true_name)
        avg_fr.raw = np.zeros(avg_fr.frequency.shape)
        for fp in file_paths:
            with open(fp, 'r', encoding='utf-8') as fh:
                s = fh.read()

            freq = []
            raw = []
            for line in s.split('\n'):
                if len(line) == 0 or line[0] == '*':
                    # Skip empty lines and comments
                    if 'C-weighting compensation: On' in line:
                        print(f'C-weighted measurement: {item.false_name}')
                    continue

                frp = line.split(', ')
                if len(frp) == 1:
                    frp = line.split('\t')
                if len(frp) == 1:
                    frp = line.split(' ')
                if len(frp) == 2:
                    f, r = frp
                elif len(frp) == 3:
                    f, r, p = frp
                else:
                    # Must be comment line
                    continue

                if f == '?' or r == '?':
                    # Skip lines with missing data
                    continue

                try:
                    freq.append(float(f))
                    raw.append(float(r))
                except ValueError as err:
                    # Failed to convert values to floats, must be header or comment row, skip
                    continue

            # Create standard fr object
            fr = FrequencyResponse(name=item.true_name, frequency=freq, raw=raw)
            fr.interpolate()
            fr.center()
            avg_fr.raw += fr.raw

        avg_fr.raw /= len(file_paths)

        # Save
        dir_path = os.path.join(target_dir, avg_fr.name)
        os.makedirs(dir_path, exist_ok=True)
        file_path = os.path.join(dir_path, f'{avg_fr.name}.csv')
        avg_fr.write_to_csv(file_path)
        print(f'Saved "{avg_fr.name}" to "{file_path}"')
Exemple #2
0
    def process(self, item, file_paths):
        fr = FrequencyResponse(name=item.true_name)
        fr.raw = np.zeros(fr.frequency.shape)
        for fp in file_paths:
            if re.search(r'\.mdat$', fp):
                # Read mdat file for Gras headphone measurements
                raise TypeError(
                    'Crinacle\'s Gras measurements are not supported yet!')
            else:
                # Read text file for IEM and Ears-711 headphone measurements
                with open(fp, 'r', encoding='utf-8') as fh:
                    s = fh.read()

            freq = []
            raw = []
            for line in s.split('\n'):
                if len(line) == 0 or line[0] == '*':
                    # Skip empty lines and comments
                    if 'C-weighting compensation: On' in line:
                        print(f'C-weighted measurement: {item.false_name}')
                    continue

                frp = line.split(' ')
                if len(frp) == 1:
                    frp = line.split('\t')
                if len(frp) == 2:
                    f, r = frp
                elif len(frp) == 3:
                    f, r, p = frp
                else:
                    # Must be comment line
                    continue

                if f == '?' or r == '?':
                    # Skip lines with missing data
                    continue

                try:
                    freq.append(float(f))
                    raw.append(float(r))
                except ValueError as err:
                    # Failed to convert values to floats, must be header or comment row, skip
                    continue

            # Create standard fr object
            _fr = FrequencyResponse(name=item.true_name,
                                    frequency=freq,
                                    raw=raw)
            _fr.interpolate()
            _fr.center()
            fr.raw += _fr.raw

        fr.raw /= len(file_paths)

        # Save
        dir_path = os.path.join(DIR_PATH, 'data', item.form, fr.name)
        os.makedirs(dir_path, exist_ok=True)
        file_path = os.path.join(dir_path, f'{fr.name}.csv')
        fr.write_to_csv(file_path)
        print(f'Saved "{fr.name}" to "{file_path}"')
    def parse_image(im, model):
        """Parses graph image downloaded from innerfidelity.com"""
        # Crop by left and right edges
        box = (69, 31, 550, 290)
        im = im.crop(box)

        px_a_max = 0
        px_a_min = im.size[1]
        # im.show()

        # X axis
        f_min = 20
        f_max = 20000
        f_step = (f_max / f_min)**(1 / im.size[0])
        f = [f_min]
        for _ in range(1, im.size[0]):
            f.append(f[-1] * f_step)

        # Y axis
        a_max = 150
        a_min = 66
        a_res = (a_max - a_min) / (px_a_min - px_a_max)

        # Try blue curve
        _im = im.copy()
        inspection = _im.load()
        amplitude, _im, _inspection = ReferenceAudioAnalyzerCrawler.find_curve(
            _im, inspection, 203, 206, 0.8, 1.0, a_max, a_res)
        if len([x for x in amplitude if x is None]) >= 0.5 * len(amplitude):
            # More than half of the pixels were discarded, try green curve
            _im = im.copy()
            inspection = _im.load()
            amplitude, _im, _inspection = ReferenceAudioAnalyzerCrawler.find_curve(
                _im, inspection, 119, 121, 0.8, 1.0, a_max, a_res)

        # Inspection image
        draw = ImageDraw.Draw(_im)
        x0 = np.log(30 / f_min) / np.log(f_step)
        x1 = np.log(10000 / f_min) / np.log(f_step)
        y_0 = px_a_max + 12 / a_res
        y_1 = px_a_min - 12 / a_res
        draw.rectangle(((x0, y_0), (x1, y_1)), outline='magenta')
        draw.rectangle(((x0 + 1, y_0 + 1), (x1 - 1, y_1 - 1)),
                       outline='magenta')

        # Create frequency response
        fr = FrequencyResponse(model, f, amplitude)
        fr.interpolate()
        if len(fr.frequency) < 2:
            im.show()
            raise ValueError(f'Failed to parse image for {fr.name}')
        fr.smoothen_fractional_octave(window_size=1 / 3,
                                      treble_window_size=1 / 3)
        fr.raw = fr.smoothed.copy()
        fr.smoothed = np.array([])
        fr.center()

        return fr, _im
Exemple #4
0
def pop_frequency_distribution():
    # Approximation of pop music frequency distribution
    fr = FrequencyResponse(name='Pop Music Frequency Distribution',
                           frequency=[
                               20, 100, 100 * math.sqrt(10), 1000,
                               1000 * math.sqrt(10), 10000, 20000
                           ],
                           raw=[-30, 0, -3, -6, -10, -20, -50])
    fr.raw += 80
    fr.interpolate(pol_order=3, f_min=20, f_max=12500)
    #fr.center()
    return fr
Exemple #5
0
def save(df, column, name):
    fr = FrequencyResponse(name=name,
                           frequency=df['Frequency'],
                           raw=df[column])
    fr.interpolate()
    fr.center()
    name = name.lower().replace(' ', '_')
    fr.write_to_csv('compensation/{}.csv'.format(name))
    fr.plot_graph(file_path='compensation/{}.png'.format(name),
                  show=False,
                  color=None)

    ind = np.argmin(fr.raw[:400])
    fr.raw[:ind] = fr.raw[ind]
    fr.write_to_csv('compensation/{}_wo_bass.csv'.format(name))
    fr.plot_graph(file_path='compensation/{}_wo_bass.png'.format(name),
                  show=False,
                  color=None)
Exemple #6
0
def main():
    pop = pop_frequency_distribution()

    elc = equal_loudness_contour(80)
    elc.center()
    elc.raw = -elc.raw

    loudness = FrequencyResponse('Loudness',
                                 frequency=pop.frequency,
                                 raw=pop.raw + elc.raw)
    #loudness.center()

    fig, ax = pop.plot_graph(show=False)
    #elc.plot_graph(fig=fig, ax=ax, show=False)
    loudness.plot_graph(fig=fig, ax=ax, show=False)

    v = FrequencyResponse(name='V',
                          frequency=[20, 1000, 20000],
                          raw=[10, -10, 10])
    v.interpolate(pol_order=2)
    v.interpolate(f=loudness.frequency)
    v.plot_graph(fig=fig, ax=ax, show=False)

    v_l = FrequencyResponse(name='V Loudness',
                            frequency=v.frequency,
                            raw=v.raw + loudness.raw)
    v_l.plot_graph(fig=fig, ax=ax, show=False)

    a = FrequencyResponse(name='A',
                          frequency=[20, 1000, 20000],
                          raw=[-10, 5, -10])
    a.interpolate(pol_order=2)
    a.interpolate(f=loudness.frequency)
    a.plot_graph(fig=fig, ax=ax, show=False)

    a_l = FrequencyResponse(name='A Loudness',
                            frequency=a.frequency,
                            raw=a.raw + loudness.raw)
    a_l.plot_graph(fig=fig, ax=ax, show=False, a_min=-20, a_max=90)

    plt.legend([
        'Pop Music Frequency Distribution', 'Loudness', 'V', 'V+L', 'A', 'A+L'
    ])
    print('V: {}'.format(20 * np.log10(np.mean(np.power(v.raw / 20, 10)))))
    print('V loudness: {}'.format(
        20 * np.log10(np.mean(np.power(v_l.raw / 20, 10)))))
    print('A: {}'.format(20 * np.log10(np.mean(np.power(a.raw / 20, 10)))))
    print('A loudness: {}'.format(
        20 * np.log10(np.mean(np.power(a_l.raw / 20, 10)))))
    plt.show()
    loudness.write_to_csv('music_loudness_contour.csv')
    plt.close(fig)
Exemple #7
0
def equal_loudness_contour(phon):
    f = [
        20, 25, 31.5, 40, 50, 63, 80, 100, 125, 160, 200, 250, 315, 400, 500,
        630, 800, 1000, 1250, 1600, 2000, 2500, 3150, 4000, 5000, 6300, 8000,
        10000, 12500
    ]
    af = [
        0.532, 0.506, 0.480, 0.455, 0.432, 0.409, 0.387, 0.367, 0.349, 0.330,
        0.315, 0.301, 0.288, 0.276, 0.267, 0.259, 0.253, 0.250, 0.246, 0.244,
        0.243, 0.243, 0.243, 0.242, 0.242, 0.245, 0.254, 0.271, 0.301
    ]
    Lu = [
        -31.6, -27.2, -23.0, -19.1, -15.9, -13.0, -10.3, -8.1, -6.2, -4.5,
        -3.1, -2.0, -1.1, -0.4, 0.0, 0.3, 0.5, 0.0, -2.7, -4.1, -1.0, 1.7, 2.5,
        1.2, -2.1, -7.1, -11.2, -10.7, -3.1
    ]
    Tf = [
        78.5, 68.7, 59.5, 51.1, 44.0, 37.5, 31.5, 26.5, 22.1, 17.9, 14.4, 11.4,
        8.6, 6.2, 4.4, 3.0, 2.2, 2.4, 3.5, 1.7, -1.3, -4.2, -6.0, -5.4, -1.5,
        6.0, 12.6, 13.9, 12.3
    ]

    Ln = phon
    Lps = []
    for i in range(0, len(f)):
        Af = 0.00447 * (10.0**(Ln / 40.0) - 1.15) + (10.0**((
            (Tf[i] + Lu[i]) / 10.0) - 9.0) / 2.5)**af[i]
        Lp = ((10.0 / af[i]) * math.log10(Af)) - Lu[i] + 94.0
        Lps.append(Lp)
    Lps = np.array(Lps)

    fr = FrequencyResponse(name='{} phon Equal Loudness Contour'.format(phon),
                           frequency=f,
                           raw=Lps)
    fr.interpolate(pol_order=3, f_min=20, f_max=12500)
    fr.center()
    return fr
Exemple #8
0
    def parse_image(im,
                    model,
                    px_top=800,
                    px_bottom=4400,
                    px_left=0,
                    px_right=2500):
        """Parses graph image downloaded from innerfidelity.com"""
        # Crop out everything but graph area (roughly)
        box = (px_left, px_top, im.size[0] - px_right, im.size[1] - px_bottom)
        im = im.crop(box)
        # im.show()

        # Find graph edges
        v_lines = ImageGraphParser.find_lines(im, 'vertical')
        h_lines = ImageGraphParser.find_lines(im, 'horizontal')

        # Crop by graph edges
        box = (v_lines[0], h_lines[0], v_lines[1], h_lines[1])
        im = im.crop(box)
        # im.show()

        # X axis
        f_min = 10
        f_max = 20000
        f_step = (f_max / f_min)**(1 / im.size[0])
        f = [f_min]
        for _ in range(1, im.size[0]):
            f.append(f[-1] * f_step)

        # Y axis
        a_max = 30
        a_min = -20
        a_res = (a_max - a_min) / im.size[1]

        _im = im.copy()
        pix = _im.load()
        amplitude = []
        y_legend = 40 / 50 * im.size[1]
        x0_legend = np.log(70 / f_min) / np.log(f_step)
        x1_legend = np.log(1000 / f_min) / np.log(f_step)
        # Iterate each column
        for x in range(im.size[0]):
            pxs = []  # Graph pixels
            # Iterate each row (pixel in column)
            for y in range(im.size[1]):
                if y > y_legend and x0_legend < x < x1_legend:
                    # Skip pixels in the legend box
                    continue

                # Convert read RGB pixel values and convert to HSV
                h, s, v = colorsys.rgb_to_hsv(
                    *[v / 255.0 for v in im.getpixel((x, y))])
                # Graph pixels are colored
                if 0.7 < s < 0.9 and 20 / 360 < h < 30 / 360:
                    pxs.append(float(y))
                else:
                    p = im.getpixel((x, y))
                    pix[x, y] = (int(0.3 * p[0]), int(255 * 0.7 + 0.3 * p[1]),
                                 int(0.3 * p[2]))
            if not pxs:
                # No graph pixels found on this column
                amplitude.append(None)
            else:
                # Mean of recorded pixels
                v = np.mean(pxs)
                # Convert to dB value
                v = a_max - v * a_res
                amplitude.append(v)

        # Inspection image
        draw = ImageDraw.Draw(_im)
        x0 = np.log(20 / f_min) / np.log(f_step)
        x1 = np.log(10000 / f_min) / np.log(f_step)
        draw.rectangle(((x0, 10 / a_res), (x1, 40 / a_res)), outline='magenta')
        draw.rectangle(((x0 + 1, 10 / a_res + 1), (x1 - 1, 40 / a_res - 1)),
                       outline='magenta')

        fr = FrequencyResponse(model, f, amplitude)
        fr.interpolate()
        fr.center()
        return fr, _im
Exemple #9
0
def parse_image(im, model):
    """Parses graph image downloaded from innerfidelity.com"""
    # Crop by left and right edges
    box = (69, 31, 550, 290)
    im = im.crop(box)

    px_a_max = 0
    px_a_min = im.size[1]
    #im.show()

    # X axis
    f_min = 20
    f_max = 20000
    f_step = (f_max / f_min)**(1 / im.size[0])
    f = [f_min]
    for _ in range(1, im.size[0]):
        f.append(f[-1] * f_step)

    # Y axis
    a_max = 150
    a_min = 66
    a_res = (a_max - a_min) / (px_a_min - px_a_max)

    # Colors
    #line_color = np.array([50, 155, 254])
    line_color = np.array([0, 135, 0])

    _im = im.copy()
    inspection = _im.load()
    amplitude = []
    # Iterate each column
    for x in range(im.size[0]):
        pxs = []  # Graph pixels
        # Iterate each row (pixel in column)
        for y in range(im.size[1]):
            # Convert read RGB pixel values and convert to HSV
            rgba = im.getpixel((x, y))
            # Graph pixels are colored
            if np.mean(np.abs(line_color - rgba[:3])) < 15:
                pxs.append(float(y))
            else:
                p = im.getpixel((x, y))
                inspection[x,
                           y] = (int(0.3 * p[0]), int(255 * 0.7 + 0.3 * p[1]),
                                 int(0 + 0.3 * p[2]))
        if not pxs:
            # No graph pixels found on this column
            amplitude.append(None)
        else:
            # Mean of recorded pixels
            v = np.mean(pxs)
            # Convert to dB value
            v = a_max - v * a_res
            amplitude.append(v)

    # Inspection image
    draw = ImageDraw.Draw(_im)
    x0 = np.log(30 / f_min) / np.log(f_step)
    x1 = np.log(10000 / f_min) / np.log(f_step)
    y_0 = px_a_max + 12 / a_res
    y_1 = px_a_min - 12 / a_res
    draw.rectangle(((x0, y_0), (x1, y_1)), outline='magenta')
    draw.rectangle(((x0 + 1, y_0 + 1), (x1 - 1, y_1 - 1)), outline='magenta')

    # Create frequency response
    fr = FrequencyResponse(model, f, amplitude)
    fr.interpolate()
    fr.center()

    return fr, _im
Exemple #10
0
def main():
    # Read name index
    name_index = dict()
    df = pd.read_csv(os.path.join(DIR_PATH, 'name_index.tsv'),
                     sep='\t',
                     header=None)
    # Replace empty cells with empty strings
    df = df.fillna('')
    df.columns = ['name', 'full_name', 'comment']
    records = df.to_dict('records')
    full_names = set()
    for record in records:
        if record['full_name'] in full_names:
            warnings.warn(
                'Duplicate entry in name index with full name: "{}".'.format(
                    record['full_name']))
            continue
        name_index[record['name']] = record

    data = dict()
    for file_path in glob(os.path.join(DIR_PATH, 'raw_data', '*.txt')):
        name = os.path.split(file_path)[1]
        # Remove ".txt" and " R" or " L" suffix
        name = re.sub('\.txt$', '', name)
        name = re.sub(' (L|R)', '', name)
        if name not in name_index:
            warnings.warn(
                '"{}" missing from name index, skipping.'.format(name))
            continue
        if name_index[name]['comment'] in [
                'ignore', 'onear'
        ] or not name_index[name]['full_name']:
            warnings.warn('Skipping "{}".'.format(name))
            continue
        name = name_index[name]['full_name']
        if name not in data:
            data[name] = []

        # Read file
        with open(file_path, 'r') as f:
            s = f.read()

        freq = []
        raw = []
        for line in s.split('\n'):
            if len(line) == 0 or line[0] == '*':
                # Skip empty lines and comments
                if 'C-weighting compensation: On' in line:
                    warnings.warn('C-weighted measurement: ' + name)
                continue

            frp = line.split(' ')
            if len(frp) == 1:
                frp = line.split('\t')
            if len(frp) == 2:
                f, r = frp
            elif len(frp) == 3:
                f, r, p = frp
            else:
                # Must be comment line
                continue

            if f == '?' or r == '?':
                # Skip lines with missing data
                continue

            try:
                freq.append(float(f))
                raw.append(float(r))
            except ValueError as err:
                # Failed to convert values to floats, must be header or comment row, skip
                continue

        # Create standard fr object
        fr = FrequencyResponse(name=name, frequency=freq, raw=raw)
        fr.interpolate()
        fr.center()
        data[name].append(fr)

    if not os.path.isdir(os.path.join(DIR_PATH, 'inspection')):
        os.makedirs(os.path.join(DIR_PATH, 'inspection'))

    # Iterate all models
    for name, frs in data.items():
        # Average SPL data from all measurements for this model (so Left and Right)
        raw = np.mean([fr.raw for fr in frs], axis=0)
        # Save as CSV
        fr = FrequencyResponse(name=name, frequency=frs[0].frequency, raw=raw)
        dir_path = os.path.join(DIR_PATH, 'data', 'inear', name)
        if not os.path.isdir(dir_path):
            os.makedirs(dir_path)
        fr.write_to_csv(os.path.join(dir_path, name + '.csv'))
        # Save inspection image
        fr.plot_graph(show=False,
                      file_path=os.path.join(DIR_PATH, 'inspection',
                                             name + '.png'))
        plt.close()
Exemple #11
0
def parse_image(im, model, channel):
    """Parses graph image downloaded from innerfidelity.com"""
    # Find graph edges
    v_lines = ImageGraphParser.find_lines(im,
                                          'vertical',
                                          line_color=(204, 204, 204))
    h_lines = ImageGraphParser.find_lines(im,
                                          'horizontal',
                                          line_color=(204, 204, 204))
    h_lines = np.array(h_lines)

    # Crop by left and right edges
    box = (v_lines[0], h_lines[0], v_lines[-1], im.size[1])
    im = im.crop(box)
    h_lines -= h_lines[
        0]  # Cropped to first line, subtract distance from all lines

    # Add missing horizontal lines 115 - 55
    deltas = []
    for i in range(1, len(h_lines)):
        deltas.append(h_lines[i] - h_lines[i - 1])
    delta = max(deltas, key=deltas.count)
    _h_lines = list(h_lines[:1])
    for _ in range(12):  # First line + 12 additional lines
        # Estimate where the line should be
        estimate = _h_lines[-1] + delta
        # Get original lines which are at most 1 pixel away from the estimate
        originals = h_lines[np.abs(np.array(h_lines) - estimate) <= 1]
        if len(originals):
            # Original line found, use it
            estimate = originals[0]
        # Add new line
        _h_lines.append(estimate)
    h_lines = _h_lines

    # Crop bottom
    box = (0, 0, im.size[0], h_lines[-1])
    im = im.crop(box)

    px_a_max = 0
    px_a_min = h_lines[-1]
    #im.show()

    # X axis
    f_min = 20
    f_max = 20000
    f_step = (f_max / f_min)**(1 / im.size[0])
    f = [f_min]
    for _ in range(1, im.size[0]):
        f.append(f[-1] * f_step)

    # Y axis
    a_max = 115
    a_min = 55
    a_res = (a_max - a_min) / (px_a_min - px_a_max)

    # Colors
    color_left = (79, 129, 189)
    color_right = (119, 119, 119)

    _im = im.copy()
    inspection = _im.load()
    amplitude = []
    # Iterate each column
    for x in range(im.size[0]):
        pxs = []  # Graph pixels
        # Iterate each row (pixel in column)
        for y in range(im.size[1]):
            # Convert read RGB pixel values and convert to HSV
            rgba = im.getpixel((x, y))
            r, g, b = rgba[:3]
            # Graph pixels are colored
            if (channel == 'left' and
                (r, g, b) == color_left) or (channel == 'right' and
                                             (r, g, b) == color_right):
                pxs.append(float(y))
            else:
                p = im.getpixel((x, y))
                inspection[x,
                           y] = (int(0.3 * p[0]), int(255 * 0.7 + 0.3 * p[1]),
                                 int(0 + 0.3 * p[2]))
        if not pxs:
            # No graph pixels found on this column
            amplitude.append(None)
        else:
            # Mean of recorded pixels
            v = np.mean(pxs)
            # Convert to dB value
            v = a_max - v * a_res
            amplitude.append(v)

    # Inspection image
    draw = ImageDraw.Draw(_im)
    x0 = np.log(30 / f_min) / np.log(f_step)
    x1 = np.log(10000 / f_min) / np.log(f_step)
    y_0 = px_a_max + 10 / a_res
    y_1 = px_a_min - 10 / a_res
    draw.rectangle(((x0, y_0), (x1, y_1)), outline='magenta')
    draw.rectangle(((x0 + 1, y_0 + 1), (x1 - 1, y_1 - 1)), outline='magenta')

    # Create frequency response
    fr = FrequencyResponse(model, f, amplitude)
    fr.interpolate()
    fr.center()

    return fr, _im
Exemple #12
0
def main():
    data = dict()
    i = 0
    for file_path in glob(os.path.join(DIR_PATH, 'raw_data', '*.txt')):
        # Read name of the IEM from file path
        _, file_name = os.path.split(file_path)
        name = '.'.join(file_name.split('.')[:-1])
        channel = name[-1]
        name = name[:-2]  # Remove channel from name
        if name not in data:
            data[name] = dict()

        # Read file
        with open(file_path, 'r') as f:
            s = f.read()

        freq = []
        raw = []
        for line in s.split('\n'):
            if len(line) == 0 or line[0] == '*':
                # Skip empty lines and comments
                if 'C-weighting compensation: On' in line:
                    warnings.warn('C-weighted measurement: ' + name)
                continue

            frp = line.split(' ')
            if len(frp) == 1:
                frp = line.split('\t')
            if len(frp) == 2:
                f, r = frp
            elif len(frp) == 3:
                f, r, p = frp
            else:
                # Must be comment line
                continue

            if f == '?' or r == '?':
                # Skip lines with missing data
                continue

            try:
                freq.append(float(f))
                raw.append(float(r))
            except ValueError as err:
                # Failed to convert values to floats, must be header or comment row, skip
                continue

        # Create standard fr object
        fr = FrequencyResponse(name=name, frequency=freq, raw=raw)
        fr.interpolate()
        data[name][channel] = fr
        i += 1
        if i > 11:
            break

    bg = Image.open('crinacle.png')
    bg = bg.convert('RGBA')

    for name, frs in data.items():
        file_path = 'images/{}.png'.format(name)
        fig, ax = plt.subplots()
        fig.set_size_inches(20, 10)
        #ax.imshow(img, aspect='equal', extent=[100, 2000, 40, 75], alpha=0.3)
        plt.plot(frs['L'].frequency, frs['L'].raw, color='blue')
        plt.plot(frs['R'].frequency, frs['R'].raw, color='red')
        plt.xlabel('Frequency (Hz)')
        plt.semilogx()
        plt.xlim([20, 20000])
        plt.ylabel('SPL (dB)')
        plt.ylim([30, 85])
        plt.title(name)
        plt.grid(True,
                 which='major',
                 color=(0.7, 0.7, 0.7),
                 alpha=0.35,
                 linewidth=1)
        plt.xticks(FREQ_LOCS, FREQ_NAMES, rotation=30)
        plt.yticks(np.arange(30, 90, 5))
        fig.savefig(file_path, bbox_inches='tight', transparent=True, dpi=120)
        graph = Image.open(file_path)
        graph = graph.convert('RGBA')
        im = bg.copy()
        im.paste(graph, (0, 0), mask=graph)
        #im = graph.copy()
        im = im.convert('P', palette=Image.ADAPTIVE, colors=60)
        im.save(file_path, optimize=True)
Exemple #13
0
    def process(self, item, url):
        json_file = Crawler.download(url, item.true_name,
                                     os.path.join(DIR_PATH, 'json'))
        if json_file is not None:
            with open(os.path.join(DIR_PATH, 'json', f'{item.true_name}.json'),
                      'r',
                      encoding='utf-8') as fh:
                json_data = json.load(fh)
            fr, target = RtingsCrawler.parse_json(json_data)
            fr.name = item.true_name
        else:
            # No frequency response available, download bass, mid and treble
            # Bass
            Crawler.download(
                url.replace('frequency-response-14.json', 'bass.json'),
                f'{item.true_name}-bass', os.path.join(DIR_PATH, 'json'))
            with open(os.path.join(DIR_PATH, 'json',
                                   f'{item.true_name}-bass.json'),
                      'r',
                      encoding='utf-8') as fh:
                bass_fr, bass_target = self.parse_json(json.load(fh))
            # Mid
            Crawler.download(
                url.replace('frequency-response-14.json', 'mid.json'),
                f'{item.true_name}-mid', os.path.join(DIR_PATH, 'json'))
            with open(os.path.join(DIR_PATH, 'json',
                                   f'{item.true_name}-mid.json'),
                      'r',
                      encoding='utf-8') as fh:
                mid_fr, mid_target = self.parse_json(json.load(fh))
            # Treble
            Crawler.download(
                url.replace('frequency-response-14.json', 'treble.json'),
                f'{item.true_name}-treble', os.path.join(DIR_PATH, 'json'))
            with open(os.path.join(DIR_PATH, 'json',
                                   f'{item.true_name}-treble.json'),
                      'r',
                      encoding='utf-8') as fh:
                treble_fr, treble_target = self.parse_json(json.load(fh))
            fr = FrequencyResponse(
                name=item.true_name,
                frequency=np.concatenate(
                    [bass_fr.frequency, mid_fr.frequency,
                     treble_fr.frequency]),
                raw=np.concatenate([bass_fr.raw, mid_fr.raw, treble_fr.raw]))
            target = FrequencyResponse(name=item.true_name,
                                       frequency=np.concatenate([
                                           bass_target.frequency,
                                           mid_target.frequency,
                                           treble_target.frequency
                                       ]),
                                       raw=np.concatenate([
                                           bass_target.raw, mid_target.raw,
                                           treble_target.raw
                                       ]))

        fr.interpolate()
        if np.std(fr.raw) == 0:
            # Frequency response data has non-zero target response, use that
            target.interpolate()
            target = target
            print(f'Using target for {fr.name}')
        elif item.form == 'inear':
            # Using in-ear target response
            target = INEAR_TARGET
        else:
            # Using on-ear or earbud target response
            target = ONEAR_TARGET
        target.center()
        fr.raw += target.raw
        fr.center()

        # Inspection
        dir_path = os.path.join(DIR_PATH, 'inspection')
        os.makedirs(dir_path, exist_ok=True)
        file_path = os.path.join(dir_path, f'{fr.name}.png')
        fig, ax = fr.plot_graph(file_path=file_path, show=False)
        plt.close(fig)

        # Write to file
        dir_path = os.path.join(DIR_PATH, 'data', item.form, fr.name)
        os.makedirs(dir_path, exist_ok=True)
        file_path = os.path.join(dir_path, fr.name + '.csv')
        fr.write_to_csv(file_path)
        print(f'Saved "{fr.name}" to "{file_path}"')
Exemple #14
0
def main():
    data = dict()
    for file_path in glob(os.path.join(DIR_PATH, 'raw_data', '*.txt')):
        # Read name of the IEM from file path
        _, file_name = os.path.split(file_path)
        name = '.'.join(file_name.split('.')[:-1])
        name = name[:-2]  # Remove channel from name
        if name not in data:
            data[name] = []

        # Read file
        with open(file_path, 'r') as f:
            s = f.read()

        freq = []
        raw = []
        for line in s.split('\n'):
            if len(line) == 0 or line[0] == '*':
                # Skip empty lines and comments
                if 'C-weighting compensation: On' in line:
                    warnings.warn('C-weighted measurement: ' + name)
                continue

            frp = line.split(' ')
            if len(frp) == 1:
                frp = line.split('\t')
            if len(frp) == 2:
                f, r = frp
            elif len(frp) == 3:
                f, r, p = frp
            else:
                # Must be comment line
                continue

            if f == '?' or r == '?':
                # Skip lines with missing data
                continue

            try:
                freq.append(float(f))
                raw.append(float(r))
            except ValueError as err:
                # Failed to convert values to floats, must be header or comment row, skip
                continue

        # Create standard fr object
        fr = FrequencyResponse(name=name, frequency=freq, raw=raw)
        fr.interpolate()
        fr.center()
        data[name].append(fr)

    if os.path.exists(os.path.join(DIR_PATH, 'inspection')):
        os.makedirs(os.path.join(DIR_PATH, 'inspection'))

    # Iterate all models
    for name, frs in data.items():
        # Average SPL data from all measurements for this model (so Left and Right)
        raw = np.mean([fr.raw for fr in frs], axis=0)
        # Save as CSV
        fr = FrequencyResponse(name=name, frequency=frs[0].frequency, raw=raw)
        fr.write_to_csv(os.path.join(DIR_PATH, 'data', name + '.csv'))
        # Save inspection image
        fr.plot_graph(show=False,
                      file_path=os.path.join(DIR_PATH, 'inspection',
                                             name + '.png'))