Changeset 430899e583d1ce72d6fb3fbf929006c61f7fdc23

Show
Ignore:
Timestamp:
06/10/09 03:08:52 (3 years ago)
Author:
Nedko Arnaudov <nedko@…>
Children:
8e197ebe8ae3d781b8662f7840b931db5122cd7d
Parents:
19123e6624236b0f9c97a3e13df1a493436350c2
git-committer:
Nedko Arnaudov <nedko@arnaudov.name> / 2009-06-10T03:08:52Z+0300
Message:

Draw frequency response curves

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • ui

    re7c6b41 r430899e  
    33# Copyright (C) 2008,2009 Nedko Arnaudov <nedko@arnaudov.name> 
    44# Copyright (C) 2006 Leonard Ritter <contact@leonard-ritter.com> 
     5# Filter response code by Fons Adriaensen 
    56# 
    67# This program is free software; you can redistribute it and/or modify 
     
    2627import xml.dom.minidom 
    2728import cairo 
    28 from math import pi, sin, cos, atan2, log 
     29from math import pi, sin, cos, atan2, log, sqrt, hypot, log10 
    2930from colorsys import hls_to_rgb, rgb_to_hls 
    3031import liblo 
     
    626627 
    627628class filter_band: 
    628     pass 
     629    def __init__(self): 
     630        self.fsamp = 48e3 
     631 
     632    def set_params(self, freq, bandw, gain): 
     633        freq_ratio = freq / self.fsamp 
     634        gain2 = pow(10.0, 0.05 * gain) 
     635        b = 7 * bandw * freq_ratio / sqrt(gain2) 
     636        self.gn = 0.5 * (gain2 - 1) 
     637        self.v1 = -cos(2 * pi * freq_ratio) 
     638        self.v2 = (1 - b) / (1 + b) 
     639        self.v1 *= (1 + self.v2) 
     640        self.gn *= (1 - self.v2) 
     641 
     642    def get_response(self, freq): 
     643        w = 2 * pi * (freq / self.fsamp) 
     644        c1 = cos(w) 
     645        s1 = sin(w) 
     646        c2 = cos(2 * w) 
     647        s2 = sin(2 * w) 
     648 
     649        x = c2 + self.v1 * c1 + self.v2 
     650        y = s2 + self.v1 * s1 
     651        t1 = hypot(x, y) 
     652        x += self.gn * (c2 - 1) 
     653        y += self.gn * s2 
     654        t2 = hypot(x, y) 
     655 
     656        #return t2 / t1 
     657        return 20 * log10(t2 / t1) 
    629658 
    630659class frequency_response(gtk.DrawingArea): 
     
    639668        self.color_value = gtk.gdk.Color(int(65535 * 0.8), int(65535 * 0.7), 0) 
    640669        self.color_mark = gtk.gdk.Color(int(65535 * 0.3), int(65535 * 0.3), int(65535 * 0.3)) 
     670        self.color_sum = gtk.gdk.Color(int(65535 * 1.0), int(65535 * 1.0), int(65535 * 1.0)) 
    641671        self.width = 0 
    642672        self.height = 0 
    643673        self.margin = 10 
    644674        self.db_range = 30 
     675        self.master_gain = 0.0 
     676        self.master_enabled = False 
    645677 
    646678        self.filters = {} 
     
    678710        #print x 
    679711        return x 
     712 
     713    def get_freq(self, x): 
     714        width = self.width - 3.5 * self.margin 
     715        return 20 * pow(1000, (x - 2.5 * self.margin) / width) 
    680716 
    681717    def get_y(self, db): 
     
    746782                self.draw_db_grid(cairo_ctx, -db) 
    747783 
    748         cairo_ctx.set_source_color(self.color_value) 
     784        curves = [[x, {}, self.master_gain, self.get_freq(x)] for x in range(int(self.get_x(20)), int(self.get_x(20e3)))] 
     785        #print repr(curves) 
     786 
     787        # calculate filter responses 
    749788        for label, filter in self.filters.items(): 
    750789            if not filter.enabled: 
    751790                continue 
    752791 
     792            for point in curves: 
     793                db = filter.get_response(point[3]) 
     794                point[1][label] = [self.get_y(db), db] 
     795 
     796        # calculate sum curve 
     797        for point in curves: 
     798            for label, filter_point in point[1].items(): 
     799                point[2] += filter_point[1] 
     800            #print point 
     801 
     802        # draw filter curves 
     803        for label, filter in self.filters.items(): 
     804            if not filter.enabled: 
     805                continue 
     806 
     807            cairo_ctx.set_source_color(filter.color) 
     808            cairo_ctx.move_to(curves[0][0], curves[0][1][label][0]) 
     809            for point in curves: 
     810                cairo_ctx.line_to(point[0], point[1][label][0]) 
     811            cairo_ctx.stroke() 
     812 
     813        if self.master_enabled: 
     814            # draw sum curve 
     815            cairo_ctx.set_source_color(self.color_sum) 
     816            cairo_ctx.set_line_width(2); 
     817            cairo_ctx.move_to(curves[0][0], self.get_y(curves[0][2])) 
     818            for point in curves: 
     819                cairo_ctx.line_to(point[0], self.get_y(point[2])) 
     820            cairo_ctx.stroke() 
     821 
     822        # draw base point markers 
     823        for label, filter in self.filters.items(): 
     824            if not filter.enabled: 
     825                continue 
     826 
     827            cairo_ctx.set_source_color(self.color_value) 
    753828            x = self.get_x(filter.adj_hz.value) 
    754829            y = self.get_y(filter.adj_db.value) 
     830 
    755831            cairo_ctx.move_to(x, y) 
    756832            cairo_ctx.show_text(label) 
    757833            cairo_ctx.stroke() 
    758834 
    759     def add_filter(self, label, adj_hz, adj_db, adj_bw): 
     835    def add_filter(self, label, adj_hz, adj_db, adj_bw, color): 
    760836        #print "filter %s added (%.2f Hz, %.2f dB, %.2f bw)" % (label, adj_hz.value, adj_db.value, adj_bw.value) 
    761837        filter = filter_band() 
    762838        filter.enabled = False 
    763839        filter.label = label 
     840        filter.color = color 
     841        filter.set_params(adj_hz.value, adj_bw.value, adj_db.value) 
     842        adj_hz.filter = filter 
     843        adj_db.filter = filter 
     844        adj_bw.filter = filter 
    764845        filter.adj_hz = adj_hz 
    765846        filter.adj_db = adj_db 
     
    784865    def on_value_change_request(self, adj): 
    785866        #print "adj changed" 
     867        adj.filter.set_params(adj.filter.adj_hz.value, adj.filter.adj_bw.value, adj.filter.adj_db.value) 
     868        self.invalidate_all() 
     869 
     870    def master_enable(self): 
     871        self.master_enabled = True; 
     872        self.invalidate_all() 
     873 
     874    def master_disable(self): 
     875        self.master_enabled = False; 
     876        self.invalidate_all() 
     877 
     878    def set_master_gain(self, gain): 
     879        self.master_gain = gain; 
    786880        self.invalidate_all() 
    787881 
     
    9521046        port_index = 2 
    9531047 
     1048        filter_colors = [gtk.gdk.Color(int(65535 * 1.0), int(65535 * 0.6), int(65535 * 0.0)), 
     1049                         gtk.gdk.Color(int(65535 * 0.6), int(65535 * 1.0), int(65535 * 0.6)), 
     1050                         gtk.gdk.Color(int(65535 * 0.0), int(65535 * 0.6), int(65535 * 1.0)), 
     1051                         gtk.gdk.Color(int(65535 * 0.9), int(65535 * 0.0), int(65535 * 0.5))] 
     1052 
    9541053        for i in [0, 1, 2, 3]: 
    9551054            band_frame = gtk.Frame("Band %d" % (i + 1)) 
     
    9811080                self.ports[port_index - 3]['adj'], # frequency 
    9821081                self.ports[port_index - 1]['adj'], # gain 
    983                 self.ports[port_index - 2]['adj']) # bandwidth 
     1082                self.ports[port_index - 2]['adj'], # bandwidth 
     1083                filter_colors[i]) 
    9841084 
    9851085            band_frame.add(band_box) 
     
    10621162        adj.label.set_text(text) 
    10631163 
     1164        if adj.port['index'] == 1: 
     1165            #print "Master gain = %.2f dB" % adj.get_value() 
     1166            self.fr.set_master_gain(adj.get_value()) 
     1167 
    10641168        if self.initator: 
    10651169            #print adj.port, adj.get_value() 
     
    10741178                if band_no > 0: 
    10751179                    self.fr.enable_filter(str(band_no)) 
     1180                else: 
     1181                    self.fr.master_enable() 
    10761182            else: 
    10771183                value = 0.0 
    10781184                if band_no > 0: 
    10791185                    self.fr.disable_filter(str(band_no)) 
     1186                else: 
     1187                    self.fr.master_disable() 
    10801188            self.send_port_value(port_index + self.port_base, value) 
    10811189