Changeset 430899e583d1ce72d6fb3fbf929006c61f7fdc23
- 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:
-
Legend:
- Unmodified
- Added
- Removed
-
|
re7c6b41
|
r430899e
|
|
| 3 | 3 | # Copyright (C) 2008,2009 Nedko Arnaudov <nedko@arnaudov.name> |
| 4 | 4 | # Copyright (C) 2006 Leonard Ritter <contact@leonard-ritter.com> |
| | 5 | # Filter response code by Fons Adriaensen |
| 5 | 6 | # |
| 6 | 7 | # This program is free software; you can redistribute it and/or modify |
| … |
… |
|
| 26 | 27 | import xml.dom.minidom |
| 27 | 28 | import cairo |
| 28 | | from math import pi, sin, cos, atan2, log |
| | 29 | from math import pi, sin, cos, atan2, log, sqrt, hypot, log10 |
| 29 | 30 | from colorsys import hls_to_rgb, rgb_to_hls |
| 30 | 31 | import liblo |
| … |
… |
|
| 626 | 627 | |
| 627 | 628 | class 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) |
| 629 | 658 | |
| 630 | 659 | class frequency_response(gtk.DrawingArea): |
| … |
… |
|
| 639 | 668 | self.color_value = gtk.gdk.Color(int(65535 * 0.8), int(65535 * 0.7), 0) |
| 640 | 669 | 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)) |
| 641 | 671 | self.width = 0 |
| 642 | 672 | self.height = 0 |
| 643 | 673 | self.margin = 10 |
| 644 | 674 | self.db_range = 30 |
| | 675 | self.master_gain = 0.0 |
| | 676 | self.master_enabled = False |
| 645 | 677 | |
| 646 | 678 | self.filters = {} |
| … |
… |
|
| 678 | 710 | #print x |
| 679 | 711 | 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) |
| 680 | 716 | |
| 681 | 717 | def get_y(self, db): |
| … |
… |
|
| 746 | 782 | self.draw_db_grid(cairo_ctx, -db) |
| 747 | 783 | |
| 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 |
| 749 | 788 | for label, filter in self.filters.items(): |
| 750 | 789 | if not filter.enabled: |
| 751 | 790 | continue |
| 752 | 791 | |
| | 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) |
| 753 | 828 | x = self.get_x(filter.adj_hz.value) |
| 754 | 829 | y = self.get_y(filter.adj_db.value) |
| | 830 | |
| 755 | 831 | cairo_ctx.move_to(x, y) |
| 756 | 832 | cairo_ctx.show_text(label) |
| 757 | 833 | cairo_ctx.stroke() |
| 758 | 834 | |
| 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): |
| 760 | 836 | #print "filter %s added (%.2f Hz, %.2f dB, %.2f bw)" % (label, adj_hz.value, adj_db.value, adj_bw.value) |
| 761 | 837 | filter = filter_band() |
| 762 | 838 | filter.enabled = False |
| 763 | 839 | 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 |
| 764 | 845 | filter.adj_hz = adj_hz |
| 765 | 846 | filter.adj_db = adj_db |
| … |
… |
|
| 784 | 865 | def on_value_change_request(self, adj): |
| 785 | 866 | #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; |
| 786 | 880 | self.invalidate_all() |
| 787 | 881 | |
| … |
… |
|
| 952 | 1046 | port_index = 2 |
| 953 | 1047 | |
| | 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 | |
| 954 | 1053 | for i in [0, 1, 2, 3]: |
| 955 | 1054 | band_frame = gtk.Frame("Band %d" % (i + 1)) |
| … |
… |
|
| 981 | 1080 | self.ports[port_index - 3]['adj'], # frequency |
| 982 | 1081 | 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]) |
| 984 | 1084 | |
| 985 | 1085 | band_frame.add(band_box) |
| … |
… |
|
| 1062 | 1162 | adj.label.set_text(text) |
| 1063 | 1163 | |
| | 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 | |
| 1064 | 1168 | if self.initator: |
| 1065 | 1169 | #print adj.port, adj.get_value() |
| … |
… |
|
| 1074 | 1178 | if band_no > 0: |
| 1075 | 1179 | self.fr.enable_filter(str(band_no)) |
| | 1180 | else: |
| | 1181 | self.fr.master_enable() |
| 1076 | 1182 | else: |
| 1077 | 1183 | value = 0.0 |
| 1078 | 1184 | if band_no > 0: |
| 1079 | 1185 | self.fr.disable_filter(str(band_no)) |
| | 1186 | else: |
| | 1187 | self.fr.master_disable() |
| 1080 | 1188 | self.send_port_value(port_index + self.port_base, value) |
| 1081 | 1189 | |