diff --git a/README b/README
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..d248f6e27c05a99209a9d98935e6bb60763dde14 100644
--- a/README
+++ b/README
@@ -0,0 +1,2 @@
+This software is quite experimental. Contact the OpenWebRX Team at <ha5kfu@sdr.hu>
+
diff --git a/config_rtl.py b/config_rtl.py
new file mode 100755
index 0000000000000000000000000000000000000000..52e572228395630a0dfd87bba2d4048e3ddf4f6e
--- /dev/null
+++ b/config_rtl.py
@@ -0,0 +1,59 @@
+'''
+This file is part of RTL Multi-User Server, 
+	that makes multi-user access to your DVB-T dongle used as an SDR.
+Copyright (c) 2013 by Andras Retzler <retzlerandras@gmail.com>
+
+RTL Multi-User Server is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+RTL Multi-User Server is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with RTL Multi-User Server.  If not, see <http://www.gnu.org/licenses/>.
+'''
+
+my_ip=''	# all interfaces
+my_listening_port = 7373
+
+#send_first=chr(9)+chr(0)+chr(0)+chr(0)+chr(1) # set direct sampling
+rtl_tcp_host = 'sdr3.sch.bme.hu'
+rtl_tcp_port = 8888
+send_first=""
+
+setuid_on_start = 0						# we normally start with root privileges and setuid() to another user
+uid = 999 									# determine by issuing: $ id -u username
+ignore_clients_without_commands = 1 # we won't serve data to telnet sessions and things like that
+												# we'll start to serve data after getting the first valid command 
+freq_allowed_ranges = [[0000000,2200000000]]
+# Allow from all: freq_allowed_ranges = [[24000000,2200000000]]
+
+client_cant_set_until=0
+buffer_size=25000000	# per client
+log_file_path = "/dev/null" # Might be set to /dev/null to turn off logging
+'''
+Allow any host to connect:
+	use_ip_access_control=0
+
+Allow from specific ranges:
+	use_ip_access_control=1
+	order_allow_deny=0 # deny and then allow
+	denied_ip_ranges=() # deny from all
+	allowed_ip_ranges=('192.168.','44.','127.0.0.1') # allow only from ...
+
+Deny from specific ranges:
+	use_ip_access_control=1
+	order_allow_deny=0 # allow and then deny
+	allowed_ip_ranges=() # allow from all
+	denied_ip_ranges=('192.168.') # deny any hosts from ...
+'''
+use_ip_access_control=1
+order_allow_deny=0
+denied_ip_ranges=() # deny from all
+allowed_ip_ranges=('152.66.','127.0.0.1') # allow only from local connections (from openwebrx)
+allow_gain_set=1
+
diff --git a/config_webrx.py b/config_webrx.py
new file mode 100755
index 0000000000000000000000000000000000000000..088ebb0af1ab3d55d49ffca8b3d1ce036259e45a
--- /dev/null
+++ b/config_webrx.py
@@ -0,0 +1,52 @@
+# -*- coding: utf-8 -*- 
+
+"""
+config_webrx: configuration options for OpenWebRX
+
+This file is part of OpenWebRX.
+
+    OpenWebRX is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenWebRX is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenWebRX.  If not, see <http://www.gnu.org/licenses/>.
+
+Authors:
+    Andras Retzler, HA7ILM <retzlerandras@gmail.com>
+
+"""
+
+receiver_name="HA5KFU Amateur Radio Club"
+receiver_location="Budapest, Hungary"
+receiver_qra="JN97ML"
+receiver_asl=182
+receiver_ant="/dev/null"
+receiver_device="RTL-SDR on Raspberry Pi"
+receiver_admin="retzlerandras@gmail.com"
+photo_title="Panorama of Budapest from Schönherz"
+photo_desc="Weather: no information for now.<br/>Receiver: RTL-SDR (R820T)<br/><a href=\"http://ha5kfu.sch.bme.hu\" target=\"_blank\">http://ha5kfu.sch.bme.hu</a>"
+photo_height=350
+fft_fps=8
+fft_size=4096
+
+
+change_admin_password_to="1234568"
+admin_password_md5=""
+start_rtl_thread=False
+
+web_port=8073
+server_hostname="sdr.sch.bme.hu"
+
+admin_param_dict={"samp_rate":250000,"center_freq":145525000,"rf_gain":10, "if_gain":10, "auto_gain":False}
+#{"samp_rate":250000,"center_freq":145525000,"rf_gain":0, "if_gain":0, "auto_gain":True}
+#admin_param_dict={"samp_rate":250000,"center_freq":14100000,"rf_gain":20, "if_gain":10, "auto_gain":True}
+#admin_param_dict={"samp_rate":2048000,"center_freq":103000000,"rf_gain":20, "if_gain":10, "auto_gain":True}
+
+
diff --git a/demod/__init__.py b/demod/__init__.py
new file mode 100755
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/demod/am/__init__.py b/demod/am/__init__.py
new file mode 100755
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/demod/am/client_am.grc b/demod/am/client_am.grc
new file mode 100755
index 0000000000000000000000000000000000000000..85b5d2248d08aa22e629882bf37cad6cc87ac927
--- /dev/null
+++ b/demod/am/client_am.grc
@@ -0,0 +1,976 @@
+<?xml version='1.0' encoding='ASCII'?>
+<flow_graph>
+  <timestamp>Sat Nov 23 01:06:14 2013</timestamp>
+  <block>
+    <key>options</key>
+    <param>
+      <key>id</key>
+      <value>top_block</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>title</key>
+      <value></value>
+    </param>
+    <param>
+      <key>author</key>
+      <value></value>
+    </param>
+    <param>
+      <key>description</key>
+      <value></value>
+    </param>
+    <param>
+      <key>window_size</key>
+      <value>1280, 1024</value>
+    </param>
+    <param>
+      <key>generate_options</key>
+      <value>no_gui</value>
+    </param>
+    <param>
+      <key>category</key>
+      <value>Custom</value>
+    </param>
+    <param>
+      <key>run_options</key>
+      <value>run</value>
+    </param>
+    <param>
+      <key>run</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>max_nouts</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>realtime_scheduling</key>
+      <value></value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(0, 8)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>audio_rate</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>44100</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(129, 98)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>demod_rate</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>samp_rate/(samp_rate/16000)</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(627, 101)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>high_cut</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>4000</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(532, 99)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>samp_rate</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>2048000</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(320, 29)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>low_cut</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>-2000</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(533, 26)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>center_freq</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>103000000</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(205, 29)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>offset_freq</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>300000</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(426, 28)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>rf_gain</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>10</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(234, 98)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>if_gain</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(321, 98)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>auto_gain</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(407, 98)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>blocks_message_sink</key>
+    <param>
+      <key>id</key>
+      <value>blocks_message_sink_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>short</value>
+    </param>
+    <param>
+      <key>dont_block</key>
+      <value>False</value>
+    </param>
+    <param>
+      <key>vlen</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>affinity</key>
+      <value></value>
+    </param>
+    <param>
+      <key>minoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>maxoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(883, 420)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>pad_sink</key>
+    <param>
+      <key>id</key>
+      <value>pad_sink_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>label</key>
+      <value>out</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value></value>
+    </param>
+    <param>
+      <key>vlen</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>num_streams</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>optional</key>
+      <value>False</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(1094, 420)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>rtlsdr_source</key>
+    <param>
+      <key>id</key>
+      <value>rtlsdr_source_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>fc32</value>
+    </param>
+    <param>
+      <key>args</key>
+      <value>rtl_tcp=127.0.0.1:7373</value>
+    </param>
+    <param>
+      <key>nchan</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>sample_rate</key>
+      <value>samp_rate</value>
+    </param>
+    <param>
+      <key>freq0</key>
+      <value>center_freq</value>
+    </param>
+    <param>
+      <key>corr0</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>dc_offset_mode0</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>iq_balance_mode0</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain_mode0</key>
+      <value>auto_gain</value>
+    </param>
+    <param>
+      <key>gain0</key>
+      <value>rf_gain</value>
+    </param>
+    <param>
+      <key>if_gain0</key>
+      <value>if_gain</value>
+    </param>
+    <param>
+      <key>bb_gain0</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>ant0</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw0</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>freq1</key>
+      <value>100e6</value>
+    </param>
+    <param>
+      <key>corr1</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>dc_offset_mode1</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>iq_balance_mode1</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain_mode1</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain1</key>
+      <value>10</value>
+    </param>
+    <param>
+      <key>if_gain1</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>bb_gain1</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>ant1</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw1</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>freq2</key>
+      <value>100e6</value>
+    </param>
+    <param>
+      <key>corr2</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>dc_offset_mode2</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>iq_balance_mode2</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain_mode2</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain2</key>
+      <value>10</value>
+    </param>
+    <param>
+      <key>if_gain2</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>bb_gain2</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>ant2</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw2</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>freq3</key>
+      <value>100e6</value>
+    </param>
+    <param>
+      <key>corr3</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>dc_offset_mode3</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>iq_balance_mode3</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain_mode3</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain3</key>
+      <value>10</value>
+    </param>
+    <param>
+      <key>if_gain3</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>bb_gain3</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>ant3</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw3</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>freq4</key>
+      <value>100e6</value>
+    </param>
+    <param>
+      <key>corr4</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>dc_offset_mode4</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>iq_balance_mode4</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain_mode4</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain4</key>
+      <value>10</value>
+    </param>
+    <param>
+      <key>if_gain4</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>bb_gain4</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>ant4</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw4</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>affinity</key>
+      <value></value>
+    </param>
+    <param>
+      <key>minoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>maxoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(14, 169)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>band_pass_filter</key>
+    <param>
+      <key>id</key>
+      <value>band_pass_filter_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>fir_filter_ccc</value>
+    </param>
+    <param>
+      <key>decim</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>interp</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>gain</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>samp_rate</key>
+      <value>demod_rate</value>
+    </param>
+    <param>
+      <key>low_cutoff_freq</key>
+      <value>low_cut</value>
+    </param>
+    <param>
+      <key>high_cutoff_freq</key>
+      <value>high_cut</value>
+    </param>
+    <param>
+      <key>width</key>
+      <value>500</value>
+    </param>
+    <param>
+      <key>win</key>
+      <value>firdes.WIN_HAMMING</value>
+    </param>
+    <param>
+      <key>beta</key>
+      <value>6.76</value>
+    </param>
+    <param>
+      <key>affinity</key>
+      <value></value>
+    </param>
+    <param>
+      <key>minoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>maxoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(563, 188)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>freq_xlating_fir_filter_xxx</key>
+    <param>
+      <key>id</key>
+      <value>freq_xlating_fir_filter_xxx_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>ccf</value>
+    </param>
+    <param>
+      <key>decim</key>
+      <value>samp_rate/demod_rate</value>
+    </param>
+    <param>
+      <key>taps</key>
+      <value>firdes.low_pass(1,samp_rate,demod_rate*0.8,demod_rate*0.3)</value>
+    </param>
+    <param>
+      <key>center_freq</key>
+      <value>offset_freq</value>
+    </param>
+    <param>
+      <key>samp_rate</key>
+      <value>samp_rate</value>
+    </param>
+    <param>
+      <key>affinity</key>
+      <value></value>
+    </param>
+    <param>
+      <key>minoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>maxoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(283, 210)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>analog_agc2_xx</key>
+    <param>
+      <key>id</key>
+      <value>analog_agc2_xx_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>complex</value>
+    </param>
+    <param>
+      <key>attack_rate</key>
+      <value>1e-3</value>
+    </param>
+    <param>
+      <key>decay_rate</key>
+      <value>208e-5</value>
+    </param>
+    <param>
+      <key>reference</key>
+      <value>1.0</value>
+    </param>
+    <param>
+      <key>gain</key>
+      <value>1.0</value>
+    </param>
+    <param>
+      <key>max_gain</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>affinity</key>
+      <value></value>
+    </param>
+    <param>
+      <key>minoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>maxoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(772, 225)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>fractional_resampler_xx</key>
+    <param>
+      <key>id</key>
+      <value>fractional_resampler_xx_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>float</value>
+    </param>
+    <param>
+      <key>phase_shift</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>resamp_ratio</key>
+      <value>demod_rate/float(audio_rate)</value>
+    </param>
+    <param>
+      <key>affinity</key>
+      <value></value>
+    </param>
+    <param>
+      <key>minoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>maxoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(440, 410)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>analog_am_demod_cf</key>
+    <param>
+      <key>id</key>
+      <value>analog_am_demod_cf_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>chan_rate</key>
+      <value>demod_rate</value>
+    </param>
+    <param>
+      <key>audio_decim</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>audio_pass</key>
+      <value>5000</value>
+    </param>
+    <param>
+      <key>audio_stop</key>
+      <value>5500</value>
+    </param>
+    <param>
+      <key>affinity</key>
+      <value></value>
+    </param>
+    <param>
+      <key>minoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>maxoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(964, 232)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>blocks_float_to_short</key>
+    <param>
+      <key>id</key>
+      <value>blocks_float_to_short_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>vlen</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>scale</key>
+      <value>5000</value>
+    </param>
+    <param>
+      <key>affinity</key>
+      <value></value>
+    </param>
+    <param>
+      <key>minoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>maxoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(680, 423)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <connection>
+    <source_block_id>rtlsdr_source_0</source_block_id>
+    <sink_block_id>freq_xlating_fir_filter_xxx_0</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+  <connection>
+    <source_block_id>blocks_float_to_short_0</source_block_id>
+    <sink_block_id>blocks_message_sink_0</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+  <connection>
+    <source_block_id>blocks_message_sink_0</source_block_id>
+    <sink_block_id>pad_sink_0</sink_block_id>
+    <source_key>msg</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+  <connection>
+    <source_block_id>fractional_resampler_xx_0</source_block_id>
+    <sink_block_id>blocks_float_to_short_0</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+  <connection>
+    <source_block_id>band_pass_filter_0</source_block_id>
+    <sink_block_id>analog_agc2_xx_0</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+  <connection>
+    <source_block_id>freq_xlating_fir_filter_xxx_0</source_block_id>
+    <sink_block_id>band_pass_filter_0</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+  <connection>
+    <source_block_id>analog_agc2_xx_0</source_block_id>
+    <sink_block_id>analog_am_demod_cf_0</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+  <connection>
+    <source_block_id>analog_am_demod_cf_0</source_block_id>
+    <sink_block_id>fractional_resampler_xx_0</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+</flow_graph>
diff --git a/demod/am/top_block.py b/demod/am/top_block.py
new file mode 100755
index 0000000000000000000000000000000000000000..d7f7e75c3ffbc41bc85dc7bbcedf27dfcb1a014a
--- /dev/null
+++ b/demod/am/top_block.py
@@ -0,0 +1,168 @@
+#!/usr/bin/env python
+##################################################
+# Gnuradio Python Flow Graph
+# Title: Top Block
+# Generated: Mon Nov 25 22:15:07 2013
+##################################################
+
+from gnuradio import analog
+from gnuradio import blocks
+from gnuradio import eng_notation
+from gnuradio import filter
+from gnuradio import gr
+from gnuradio.eng_option import eng_option
+from gnuradio.filter import firdes
+from optparse import OptionParser
+import osmosdr
+
+class top_block(gr.top_block):
+
+    def __init__(self,sample_rate_param): # added by grcconvert
+        gr.top_block.__init__(self, "Top Block")
+
+        ##################################################
+        # Variables
+        ##################################################
+        self.samp_rate = samp_rate = sample_rate_param # added by grcconvert
+        self.rf_gain = rf_gain = 10
+        self.offset_freq = offset_freq = 300000
+        self.low_cut = low_cut = -2000
+        self.if_gain = if_gain = 20
+        self.high_cut = high_cut = 4000
+        self.demod_rate = demod_rate = samp_rate/(samp_rate/16000)
+        self.center_freq = center_freq = 103000000
+        self.auto_gain = auto_gain = True
+        self.audio_rate = audio_rate = 44100
+
+        ##################################################
+        # Message queues (added by grcconvert)
+        ##################################################
+        self.msgq_out = blocks_message_sink_0_msgq_out = gr.msg_queue(2)
+
+        ##################################################
+        # Blocks
+        ##################################################
+        self.rtlsdr_source_0 = osmosdr.source( args="numchan=" + str(1) + " " + "rtl_tcp=127.0.0.1:7373" )
+        self.rtlsdr_source_0.set_sample_rate(samp_rate)
+        self.rtlsdr_source_0.set_center_freq(center_freq, 0)
+        self.rtlsdr_source_0.set_freq_corr(0, 0)
+        self.rtlsdr_source_0.set_dc_offset_mode(0, 0)
+        self.rtlsdr_source_0.set_iq_balance_mode(0, 0)
+        self.rtlsdr_source_0.set_gain_mode(auto_gain, 0)
+        self.rtlsdr_source_0.set_gain(rf_gain, 0)
+        self.rtlsdr_source_0.set_if_gain(if_gain, 0)
+        self.rtlsdr_source_0.set_bb_gain(20, 0)
+        self.rtlsdr_source_0.set_antenna("", 0)
+        self.rtlsdr_source_0.set_bandwidth(0, 0)
+          
+        self.freq_xlating_fir_filter_xxx_0 = filter.freq_xlating_fir_filter_ccf(samp_rate/demod_rate, (firdes.low_pass(1,samp_rate,demod_rate*0.8,demod_rate*0.3)), offset_freq, samp_rate)
+        self.fractional_resampler_xx_0 = filter.fractional_resampler_ff(0, demod_rate/float(audio_rate))
+        self.blocks_message_sink_0 = blocks.message_sink(gr.sizeof_short*1, blocks_message_sink_0_msgq_out, False)
+        self.blocks_float_to_short_0 = blocks.float_to_short(1, 5000)
+        self.band_pass_filter_0 = filter.fir_filter_ccc(1, firdes.complex_band_pass(
+        	1, demod_rate, low_cut, high_cut, 500, firdes.WIN_HAMMING, 6.76))
+        self.analog_am_demod_cf_0 = analog.am_demod_cf(
+        	channel_rate=demod_rate,
+        	audio_decim=1,
+        	audio_pass=5000,
+        	audio_stop=5500,
+        )
+        self.analog_agc2_xx_0 = analog.agc2_cc(1e-3, 208e-5, 1.0, 1.0)
+        self.analog_agc2_xx_0.set_max_gain(20)
+
+        ##################################################
+        # Connections
+        ##################################################
+        self.connect((self.rtlsdr_source_0, 0), (self.freq_xlating_fir_filter_xxx_0, 0))
+        self.connect((self.blocks_float_to_short_0, 0), (self.blocks_message_sink_0, 0))
+        # removed by grcconvert: # self.connect((self.blocks_message_sink_0, msg), (self, 0))
+        self.connect((self.fractional_resampler_xx_0, 0), (self.blocks_float_to_short_0, 0))
+        self.connect((self.band_pass_filter_0, 0), (self.analog_agc2_xx_0, 0))
+        self.connect((self.freq_xlating_fir_filter_xxx_0, 0), (self.band_pass_filter_0, 0))
+        self.connect((self.analog_agc2_xx_0, 0), (self.analog_am_demod_cf_0, 0))
+        self.connect((self.analog_am_demod_cf_0, 0), (self.fractional_resampler_xx_0, 0))
+
+
+# QT sink close method reimplementation
+
+    def get_samp_rate(self):
+        return self.samp_rate
+
+    def set_samp_rate(self, samp_rate):
+        self.samp_rate = samp_rate
+        self.set_demod_rate(self.samp_rate/(self.samp_rate/16000))
+        self.rtlsdr_source_0.set_sample_rate(self.samp_rate)
+        self.freq_xlating_fir_filter_xxx_0.set_taps((firdes.low_pass(1,self.samp_rate,self.demod_rate*0.8,self.demod_rate*0.3)))
+
+    def get_rf_gain(self):
+        return self.rf_gain
+
+    def set_rf_gain(self, rf_gain):
+        self.rf_gain = rf_gain
+        self.rtlsdr_source_0.set_gain(self.rf_gain, 0)
+
+    def get_offset_freq(self):
+        return self.offset_freq
+
+    def set_offset_freq(self, offset_freq):
+        self.offset_freq = offset_freq
+        self.freq_xlating_fir_filter_xxx_0.set_center_freq(self.offset_freq)
+
+    def get_low_cut(self):
+        return self.low_cut
+
+    def set_low_cut(self, low_cut):
+        self.low_cut = low_cut
+        self.band_pass_filter_0.set_taps(firdes.complex_band_pass(1, self.demod_rate, self.low_cut, self.high_cut, 500, firdes.WIN_HAMMING, 6.76))
+
+    def get_if_gain(self):
+        return self.if_gain
+
+    def set_if_gain(self, if_gain):
+        self.if_gain = if_gain
+        self.rtlsdr_source_0.set_if_gain(self.if_gain, 0)
+
+    def get_high_cut(self):
+        return self.high_cut
+
+    def set_high_cut(self, high_cut):
+        self.high_cut = high_cut
+        self.band_pass_filter_0.set_taps(firdes.complex_band_pass(1, self.demod_rate, self.low_cut, self.high_cut, 500, firdes.WIN_HAMMING, 6.76))
+
+    def get_demod_rate(self):
+        return self.demod_rate
+
+    def set_demod_rate(self, demod_rate):
+        self.demod_rate = demod_rate
+        self.band_pass_filter_0.set_taps(firdes.complex_band_pass(1, self.demod_rate, self.low_cut, self.high_cut, 500, firdes.WIN_HAMMING, 6.76))
+        self.freq_xlating_fir_filter_xxx_0.set_taps((firdes.low_pass(1,self.samp_rate,self.demod_rate*0.8,self.demod_rate*0.3)))
+        self.fractional_resampler_xx_0.set_resamp_ratio(self.demod_rate/float(self.audio_rate))
+
+    def get_center_freq(self):
+        return self.center_freq
+
+    def set_center_freq(self, center_freq):
+        self.center_freq = center_freq
+        self.rtlsdr_source_0.set_center_freq(self.center_freq, 0)
+
+    def get_auto_gain(self):
+        return self.auto_gain
+
+    def set_auto_gain(self, auto_gain):
+        self.auto_gain = auto_gain
+        self.rtlsdr_source_0.set_gain_mode(self.auto_gain, 0)
+
+    def get_audio_rate(self):
+        return self.audio_rate
+
+    def set_audio_rate(self, audio_rate):
+        self.audio_rate = audio_rate
+        self.fractional_resampler_xx_0.set_resamp_ratio(self.demod_rate/float(self.audio_rate))
+
+if __name__ == '__main__':
+    parser = OptionParser(option_class=eng_option, usage="%prog: [options]")
+    (options, args) = parser.parse_args()
+    tb = top_block()
+    tb.start()
+    tb.wait()
+
diff --git a/demod/nfm/__init__.py b/demod/nfm/__init__.py
new file mode 100755
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/demod/nfm/client_nfm.grc b/demod/nfm/client_nfm.grc
new file mode 100755
index 0000000000000000000000000000000000000000..b56607dffcde1046a97ec49a73e1b8a8e2a1f30d
--- /dev/null
+++ b/demod/nfm/client_nfm.grc
@@ -0,0 +1,915 @@
+<?xml version='1.0' encoding='ASCII'?>
+<flow_graph>
+  <timestamp>Mon Feb 17 22:04:30 2014</timestamp>
+  <block>
+    <key>options</key>
+    <param>
+      <key>id</key>
+      <value>top_block</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>title</key>
+      <value></value>
+    </param>
+    <param>
+      <key>author</key>
+      <value></value>
+    </param>
+    <param>
+      <key>description</key>
+      <value></value>
+    </param>
+    <param>
+      <key>window_size</key>
+      <value>1280, 1024</value>
+    </param>
+    <param>
+      <key>generate_options</key>
+      <value>no_gui</value>
+    </param>
+    <param>
+      <key>category</key>
+      <value>Custom</value>
+    </param>
+    <param>
+      <key>run_options</key>
+      <value>run</value>
+    </param>
+    <param>
+      <key>run</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>max_nouts</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>realtime_scheduling</key>
+      <value></value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(0, 8)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>audio_rate</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>44100</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(129, 98)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>demod_rate</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>samp_rate/(samp_rate/16000)</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(627, 101)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>high_cut</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>4000</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(532, 99)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>samp_rate</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>2048000</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(320, 29)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>low_cut</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>-2000</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(533, 26)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>center_freq</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>103000000</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(205, 29)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>offset_freq</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>300000</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(426, 28)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>rf_gain</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>10</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(234, 98)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>if_gain</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(321, 98)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>auto_gain</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(407, 98)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>blocks_message_sink</key>
+    <param>
+      <key>id</key>
+      <value>blocks_message_sink_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>short</value>
+    </param>
+    <param>
+      <key>dont_block</key>
+      <value>False</value>
+    </param>
+    <param>
+      <key>vlen</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>affinity</key>
+      <value></value>
+    </param>
+    <param>
+      <key>minoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>maxoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(883, 420)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>pad_sink</key>
+    <param>
+      <key>id</key>
+      <value>pad_sink_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>label</key>
+      <value>out</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value></value>
+    </param>
+    <param>
+      <key>vlen</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>num_streams</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>optional</key>
+      <value>False</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(1094, 420)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>rtlsdr_source</key>
+    <param>
+      <key>id</key>
+      <value>rtlsdr_source_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>fc32</value>
+    </param>
+    <param>
+      <key>args</key>
+      <value>rtl_tcp=127.0.0.1:7373</value>
+    </param>
+    <param>
+      <key>nchan</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>sample_rate</key>
+      <value>samp_rate</value>
+    </param>
+    <param>
+      <key>freq0</key>
+      <value>center_freq</value>
+    </param>
+    <param>
+      <key>corr0</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>dc_offset_mode0</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>iq_balance_mode0</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain_mode0</key>
+      <value>auto_gain</value>
+    </param>
+    <param>
+      <key>gain0</key>
+      <value>rf_gain</value>
+    </param>
+    <param>
+      <key>if_gain0</key>
+      <value>if_gain</value>
+    </param>
+    <param>
+      <key>bb_gain0</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>ant0</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw0</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>freq1</key>
+      <value>100e6</value>
+    </param>
+    <param>
+      <key>corr1</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>dc_offset_mode1</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>iq_balance_mode1</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain_mode1</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain1</key>
+      <value>10</value>
+    </param>
+    <param>
+      <key>if_gain1</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>bb_gain1</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>ant1</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw1</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>freq2</key>
+      <value>100e6</value>
+    </param>
+    <param>
+      <key>corr2</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>dc_offset_mode2</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>iq_balance_mode2</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain_mode2</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain2</key>
+      <value>10</value>
+    </param>
+    <param>
+      <key>if_gain2</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>bb_gain2</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>ant2</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw2</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>freq3</key>
+      <value>100e6</value>
+    </param>
+    <param>
+      <key>corr3</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>dc_offset_mode3</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>iq_balance_mode3</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain_mode3</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain3</key>
+      <value>10</value>
+    </param>
+    <param>
+      <key>if_gain3</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>bb_gain3</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>ant3</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw3</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>freq4</key>
+      <value>100e6</value>
+    </param>
+    <param>
+      <key>corr4</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>dc_offset_mode4</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>iq_balance_mode4</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain_mode4</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain4</key>
+      <value>10</value>
+    </param>
+    <param>
+      <key>if_gain4</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>bb_gain4</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>ant4</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw4</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>affinity</key>
+      <value></value>
+    </param>
+    <param>
+      <key>minoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>maxoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(14, 169)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>freq_xlating_fir_filter_xxx</key>
+    <param>
+      <key>id</key>
+      <value>freq_xlating_fir_filter_xxx_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>ccf</value>
+    </param>
+    <param>
+      <key>decim</key>
+      <value>samp_rate/demod_rate</value>
+    </param>
+    <param>
+      <key>taps</key>
+      <value>firdes.low_pass(1,samp_rate,demod_rate*0.8,demod_rate*0.3)</value>
+    </param>
+    <param>
+      <key>center_freq</key>
+      <value>offset_freq</value>
+    </param>
+    <param>
+      <key>samp_rate</key>
+      <value>samp_rate</value>
+    </param>
+    <param>
+      <key>affinity</key>
+      <value></value>
+    </param>
+    <param>
+      <key>minoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>maxoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(283, 210)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>band_pass_filter</key>
+    <param>
+      <key>id</key>
+      <value>band_pass_filter_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>fir_filter_ccc</value>
+    </param>
+    <param>
+      <key>decim</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>interp</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>gain</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>samp_rate</key>
+      <value>demod_rate</value>
+    </param>
+    <param>
+      <key>low_cutoff_freq</key>
+      <value>low_cut</value>
+    </param>
+    <param>
+      <key>high_cutoff_freq</key>
+      <value>high_cut</value>
+    </param>
+    <param>
+      <key>width</key>
+      <value>500</value>
+    </param>
+    <param>
+      <key>win</key>
+      <value>firdes.WIN_HAMMING</value>
+    </param>
+    <param>
+      <key>beta</key>
+      <value>6.76</value>
+    </param>
+    <param>
+      <key>affinity</key>
+      <value></value>
+    </param>
+    <param>
+      <key>minoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>maxoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(563, 188)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>analog_nbfm_rx</key>
+    <param>
+      <key>id</key>
+      <value>analog_nbfm_rx_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>audio_rate</key>
+      <value>demod_rate</value>
+    </param>
+    <param>
+      <key>quad_rate</key>
+      <value>demod_rate</value>
+    </param>
+    <param>
+      <key>tau</key>
+      <value>75e-6</value>
+    </param>
+    <param>
+      <key>max_dev</key>
+      <value>5e3</value>
+    </param>
+    <param>
+      <key>affinity</key>
+      <value></value>
+    </param>
+    <param>
+      <key>minoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>maxoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(998, 232)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>fractional_resampler_xx</key>
+    <param>
+      <key>id</key>
+      <value>fractional_resampler_xx_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>float</value>
+    </param>
+    <param>
+      <key>phase_shift</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>resamp_ratio</key>
+      <value>demod_rate/float(audio_rate)</value>
+    </param>
+    <param>
+      <key>affinity</key>
+      <value></value>
+    </param>
+    <param>
+      <key>minoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>maxoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(440, 410)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>blocks_float_to_short</key>
+    <param>
+      <key>id</key>
+      <value>blocks_float_to_short_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>vlen</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>scale</key>
+      <value>25000</value>
+    </param>
+    <param>
+      <key>affinity</key>
+      <value></value>
+    </param>
+    <param>
+      <key>minoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>maxoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(680, 421)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <connection>
+    <source_block_id>rtlsdr_source_0</source_block_id>
+    <sink_block_id>freq_xlating_fir_filter_xxx_0</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+  <connection>
+    <source_block_id>blocks_float_to_short_0</source_block_id>
+    <sink_block_id>blocks_message_sink_0</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+  <connection>
+    <source_block_id>blocks_message_sink_0</source_block_id>
+    <sink_block_id>pad_sink_0</sink_block_id>
+    <source_key>msg</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+  <connection>
+    <source_block_id>fractional_resampler_xx_0</source_block_id>
+    <sink_block_id>blocks_float_to_short_0</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+  <connection>
+    <source_block_id>freq_xlating_fir_filter_xxx_0</source_block_id>
+    <sink_block_id>band_pass_filter_0</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+  <connection>
+    <source_block_id>band_pass_filter_0</source_block_id>
+    <sink_block_id>analog_nbfm_rx_0</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+  <connection>
+    <source_block_id>analog_nbfm_rx_0</source_block_id>
+    <sink_block_id>fractional_resampler_xx_0</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+</flow_graph>
diff --git a/demod/nfm/top_block.py b/demod/nfm/top_block.py
new file mode 100755
index 0000000000000000000000000000000000000000..f279517830da7470d4eb1c291b0a136b17ef58f1
--- /dev/null
+++ b/demod/nfm/top_block.py
@@ -0,0 +1,165 @@
+#!/usr/bin/env python
+##################################################
+# Gnuradio Python Flow Graph
+# Title: Top Block
+# Generated: Mon Feb 17 22:04:32 2014
+##################################################
+
+from gnuradio import analog
+from gnuradio import blocks
+from gnuradio import eng_notation
+from gnuradio import filter
+from gnuradio import gr
+from gnuradio.eng_option import eng_option
+from gnuradio.filter import firdes
+from optparse import OptionParser
+import osmosdr
+
+class top_block(gr.top_block):
+
+    def __init__(self,sample_rate_param): # added by grcconvert
+        gr.top_block.__init__(self, "Top Block")
+
+        ##################################################
+        # Variables
+        ##################################################
+        self.samp_rate = samp_rate = sample_rate_param # added by grcconvert
+        self.rf_gain = rf_gain = 10
+        self.offset_freq = offset_freq = 300000
+        self.low_cut = low_cut = -2000
+        self.if_gain = if_gain = 20
+        self.high_cut = high_cut = 4000
+        self.demod_rate = demod_rate = samp_rate/(samp_rate/16000)
+        self.center_freq = center_freq = 103000000
+        self.auto_gain = auto_gain = True
+        self.audio_rate = audio_rate = 44100
+
+        ##################################################
+        # Message queues (added by grcconvert)
+        ##################################################
+        self.msgq_out = blocks_message_sink_0_msgq_out = gr.msg_queue(2)
+
+        ##################################################
+        # Blocks
+        ##################################################
+        self.rtlsdr_source_0 = osmosdr.source( args="numchan=" + str(1) + " " + "rtl_tcp=127.0.0.1:7373" )
+        self.rtlsdr_source_0.set_sample_rate(samp_rate)
+        self.rtlsdr_source_0.set_center_freq(center_freq, 0)
+        self.rtlsdr_source_0.set_freq_corr(0, 0)
+        self.rtlsdr_source_0.set_dc_offset_mode(0, 0)
+        self.rtlsdr_source_0.set_iq_balance_mode(0, 0)
+        self.rtlsdr_source_0.set_gain_mode(auto_gain, 0)
+        self.rtlsdr_source_0.set_gain(rf_gain, 0)
+        self.rtlsdr_source_0.set_if_gain(if_gain, 0)
+        self.rtlsdr_source_0.set_bb_gain(20, 0)
+        self.rtlsdr_source_0.set_antenna("", 0)
+        self.rtlsdr_source_0.set_bandwidth(0, 0)
+          
+        self.freq_xlating_fir_filter_xxx_0 = filter.freq_xlating_fir_filter_ccf(samp_rate/demod_rate, (firdes.low_pass(1,samp_rate,demod_rate*0.8,demod_rate*0.3)), offset_freq, samp_rate)
+        self.fractional_resampler_xx_0 = filter.fractional_resampler_ff(0, demod_rate/float(audio_rate))
+        self.blocks_message_sink_0 = blocks.message_sink(gr.sizeof_short*1, blocks_message_sink_0_msgq_out, False)
+        self.blocks_float_to_short_0 = blocks.float_to_short(1, 25000)
+        self.band_pass_filter_0 = filter.fir_filter_ccc(1, firdes.complex_band_pass(
+        	1, demod_rate, low_cut, high_cut, 500, firdes.WIN_HAMMING, 6.76))
+        self.analog_nbfm_rx_0 = analog.nbfm_rx(
+        	audio_rate=demod_rate,
+        	quad_rate=demod_rate,
+        	tau=75e-6,
+        	max_dev=5e3,
+        )
+
+        ##################################################
+        # Connections
+        ##################################################
+        self.connect((self.rtlsdr_source_0, 0), (self.freq_xlating_fir_filter_xxx_0, 0))
+        self.connect((self.blocks_float_to_short_0, 0), (self.blocks_message_sink_0, 0))
+        # removed by grcconvert: # self.connect((self.blocks_message_sink_0, msg), (self, 0))
+        self.connect((self.fractional_resampler_xx_0, 0), (self.blocks_float_to_short_0, 0))
+        self.connect((self.freq_xlating_fir_filter_xxx_0, 0), (self.band_pass_filter_0, 0))
+        self.connect((self.band_pass_filter_0, 0), (self.analog_nbfm_rx_0, 0))
+        self.connect((self.analog_nbfm_rx_0, 0), (self.fractional_resampler_xx_0, 0))
+
+
+# QT sink close method reimplementation
+
+    def get_samp_rate(self):
+        return self.samp_rate
+
+    def set_samp_rate(self, samp_rate):
+        self.samp_rate = samp_rate
+        self.set_demod_rate(self.samp_rate/(self.samp_rate/16000))
+        self.rtlsdr_source_0.set_sample_rate(self.samp_rate)
+        self.freq_xlating_fir_filter_xxx_0.set_taps((firdes.low_pass(1,self.samp_rate,self.demod_rate*0.8,self.demod_rate*0.3)))
+
+    def get_rf_gain(self):
+        return self.rf_gain
+
+    def set_rf_gain(self, rf_gain):
+        self.rf_gain = rf_gain
+        self.rtlsdr_source_0.set_gain(self.rf_gain, 0)
+
+    def get_offset_freq(self):
+        return self.offset_freq
+
+    def set_offset_freq(self, offset_freq):
+        self.offset_freq = offset_freq
+        self.freq_xlating_fir_filter_xxx_0.set_center_freq(self.offset_freq)
+
+    def get_low_cut(self):
+        return self.low_cut
+
+    def set_low_cut(self, low_cut):
+        self.low_cut = low_cut
+        self.band_pass_filter_0.set_taps(firdes.complex_band_pass(1, self.demod_rate, self.low_cut, self.high_cut, 500, firdes.WIN_HAMMING, 6.76))
+
+    def get_if_gain(self):
+        return self.if_gain
+
+    def set_if_gain(self, if_gain):
+        self.if_gain = if_gain
+        self.rtlsdr_source_0.set_if_gain(self.if_gain, 0)
+
+    def get_high_cut(self):
+        return self.high_cut
+
+    def set_high_cut(self, high_cut):
+        self.high_cut = high_cut
+        self.band_pass_filter_0.set_taps(firdes.complex_band_pass(1, self.demod_rate, self.low_cut, self.high_cut, 500, firdes.WIN_HAMMING, 6.76))
+
+    def get_demod_rate(self):
+        return self.demod_rate
+
+    def set_demod_rate(self, demod_rate):
+        self.demod_rate = demod_rate
+        self.freq_xlating_fir_filter_xxx_0.set_taps((firdes.low_pass(1,self.samp_rate,self.demod_rate*0.8,self.demod_rate*0.3)))
+        self.band_pass_filter_0.set_taps(firdes.complex_band_pass(1, self.demod_rate, self.low_cut, self.high_cut, 500, firdes.WIN_HAMMING, 6.76))
+        self.fractional_resampler_xx_0.set_resamp_ratio(self.demod_rate/float(self.audio_rate))
+
+    def get_center_freq(self):
+        return self.center_freq
+
+    def set_center_freq(self, center_freq):
+        self.center_freq = center_freq
+        self.rtlsdr_source_0.set_center_freq(self.center_freq, 0)
+
+    def get_auto_gain(self):
+        return self.auto_gain
+
+    def set_auto_gain(self, auto_gain):
+        self.auto_gain = auto_gain
+        self.rtlsdr_source_0.set_gain_mode(self.auto_gain, 0)
+
+    def get_audio_rate(self):
+        return self.audio_rate
+
+    def set_audio_rate(self, audio_rate):
+        self.audio_rate = audio_rate
+        self.fractional_resampler_xx_0.set_resamp_ratio(self.demod_rate/float(self.audio_rate))
+
+if __name__ == '__main__':
+    parser = OptionParser(option_class=eng_option, usage="%prog: [options]")
+    (options, args) = parser.parse_args()
+    tb = top_block()
+    tb.start()
+    tb.wait()
+
diff --git a/demod/spectrum/__init__.py b/demod/spectrum/__init__.py
new file mode 100755
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/demod/spectrum/logpowfft.grc b/demod/spectrum/logpowfft.grc
new file mode 100755
index 0000000000000000000000000000000000000000..2d8f0dd5ad5c3ae88ab6c9a8618f217fe64fdc2f
--- /dev/null
+++ b/demod/spectrum/logpowfft.grc
@@ -0,0 +1,538 @@
+<?xml version='1.0' encoding='ASCII'?>
+<flow_graph>
+  <timestamp>Fri Dec 13 23:28:34 2013</timestamp>
+  <block>
+    <key>options</key>
+    <param>
+      <key>id</key>
+      <value>top_block</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>title</key>
+      <value></value>
+    </param>
+    <param>
+      <key>author</key>
+      <value></value>
+    </param>
+    <param>
+      <key>description</key>
+      <value></value>
+    </param>
+    <param>
+      <key>window_size</key>
+      <value>1280, 1024</value>
+    </param>
+    <param>
+      <key>generate_options</key>
+      <value>no_gui</value>
+    </param>
+    <param>
+      <key>category</key>
+      <value>Custom</value>
+    </param>
+    <param>
+      <key>run_options</key>
+      <value>run</value>
+    </param>
+    <param>
+      <key>run</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>max_nouts</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>realtime_scheduling</key>
+      <value></value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(10, 10)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>fps</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>8</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(423, 16)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>fft_size</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>4096</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(325, 16)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>samp_rate</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>2048000</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(223, 9)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>blocks_message_sink</key>
+    <param>
+      <key>id</key>
+      <value>blocks_message_sink_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>float</value>
+    </param>
+    <param>
+      <key>dont_block</key>
+      <value>False</value>
+    </param>
+    <param>
+      <key>vlen</key>
+      <value>fft_size</value>
+    </param>
+    <param>
+      <key>affinity</key>
+      <value></value>
+    </param>
+    <param>
+      <key>minoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>maxoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(753, 186)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>pad_sink</key>
+    <param>
+      <key>id</key>
+      <value>pad_sink_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>label</key>
+      <value>out</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value></value>
+    </param>
+    <param>
+      <key>vlen</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>num_streams</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>optional</key>
+      <value>False</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(945, 193)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>rtlsdr_source</key>
+    <param>
+      <key>id</key>
+      <value>rtlsdr_source_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>fc32</value>
+    </param>
+    <param>
+      <key>args</key>
+      <value>rtl_tcp=127.0.0.1:7373</value>
+    </param>
+    <param>
+      <key>nchan</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>sample_rate</key>
+      <value>samp_rate</value>
+    </param>
+    <param>
+      <key>freq0</key>
+      <value>100e6</value>
+    </param>
+    <param>
+      <key>corr0</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>dc_offset_mode0</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>iq_balance_mode0</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain_mode0</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain0</key>
+      <value>10</value>
+    </param>
+    <param>
+      <key>if_gain0</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>bb_gain0</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>ant0</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw0</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>freq1</key>
+      <value>100e6</value>
+    </param>
+    <param>
+      <key>corr1</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>dc_offset_mode1</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>iq_balance_mode1</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain_mode1</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain1</key>
+      <value>10</value>
+    </param>
+    <param>
+      <key>if_gain1</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>bb_gain1</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>ant1</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw1</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>freq2</key>
+      <value>100e6</value>
+    </param>
+    <param>
+      <key>corr2</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>dc_offset_mode2</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>iq_balance_mode2</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain_mode2</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain2</key>
+      <value>10</value>
+    </param>
+    <param>
+      <key>if_gain2</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>bb_gain2</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>ant2</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw2</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>freq3</key>
+      <value>100e6</value>
+    </param>
+    <param>
+      <key>corr3</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>dc_offset_mode3</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>iq_balance_mode3</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain_mode3</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain3</key>
+      <value>10</value>
+    </param>
+    <param>
+      <key>if_gain3</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>bb_gain3</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>ant3</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw3</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>freq4</key>
+      <value>100e6</value>
+    </param>
+    <param>
+      <key>corr4</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>dc_offset_mode4</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>iq_balance_mode4</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain_mode4</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain4</key>
+      <value>10</value>
+    </param>
+    <param>
+      <key>if_gain4</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>bb_gain4</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>ant4</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw4</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>affinity</key>
+      <value></value>
+    </param>
+    <param>
+      <key>minoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>maxoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(190, 95)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>logpwrfft_x</key>
+    <param>
+      <key>id</key>
+      <value>logpwrfft_x_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>complex</value>
+    </param>
+    <param>
+      <key>sample_rate</key>
+      <value>samp_rate</value>
+    </param>
+    <param>
+      <key>fft_size</key>
+      <value>fft_size</value>
+    </param>
+    <param>
+      <key>ref_scale</key>
+      <value>2</value>
+    </param>
+    <param>
+      <key>frame_rate</key>
+      <value>fps</value>
+    </param>
+    <param>
+      <key>average</key>
+      <value>False</value>
+    </param>
+    <param>
+      <key>avg_alpha</key>
+      <value>1.0</value>
+    </param>
+    <param>
+      <key>affinity</key>
+      <value></value>
+    </param>
+    <param>
+      <key>minoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>maxoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(513, 157)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <connection>
+    <source_block_id>logpwrfft_x_0</source_block_id>
+    <sink_block_id>blocks_message_sink_0</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+  <connection>
+    <source_block_id>blocks_message_sink_0</source_block_id>
+    <sink_block_id>pad_sink_0</sink_block_id>
+    <source_key>msg</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+  <connection>
+    <source_block_id>rtlsdr_source_0</source_block_id>
+    <sink_block_id>logpwrfft_x_0</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+</flow_graph>
diff --git a/demod/spectrum/testr.py b/demod/spectrum/testr.py
new file mode 100755
index 0000000000000000000000000000000000000000..e8a43ac3b6347292a00088ebc9f1a4927f3f52a1
--- /dev/null
+++ b/demod/spectrum/testr.py
@@ -0,0 +1,8 @@
+import top_block
+import os
+
+print 'Blocked waiting for GDB attach (pid = %d)' % (os.getpid(),)
+raw_input ('Press Enter to continue: ')
+print "   ------- top_block() -------"
+tb=top_block.top_block()
+print "   ------- start() -------"
diff --git a/demod/spectrum/top_block.py b/demod/spectrum/top_block.py
new file mode 100755
index 0000000000000000000000000000000000000000..7976dcd730b0a274f31355b01915b4723bb54dca
--- /dev/null
+++ b/demod/spectrum/top_block.py
@@ -0,0 +1,96 @@
+#!/usr/bin/env python
+##################################################
+# Gnuradio Python Flow Graph
+# Title: Top Block
+# Generated: Fri Dec 13 23:30:36 2013
+##################################################
+
+from gnuradio import blocks
+from gnuradio import eng_notation
+from gnuradio import gr
+from gnuradio.eng_option import eng_option
+from gnuradio.fft import logpwrfft
+from gnuradio.filter import firdes
+from optparse import OptionParser
+import osmosdr
+
+class top_block(gr.top_block):
+
+    def __init__(self,sample_rate_param): # added by grcconvert
+        gr.top_block.__init__(self, "Top Block")
+
+        ##################################################
+        # Variables
+        ##################################################
+        self.samp_rate = samp_rate = sample_rate_param # added by grcconvert
+        self.fps = fps = 8
+        self.fft_size = fft_size = 4096
+
+        ##################################################
+        # Message queues (added by grcconvert)
+        ##################################################
+        self.msgq_out = blocks_message_sink_0_msgq_out = gr.msg_queue(2)
+
+        ##################################################
+        # Blocks
+        ##################################################
+        self.rtlsdr_source_0 = osmosdr.source( args="numchan=" + str(1) + " " + "rtl_tcp=127.0.0.1:7373" )
+        self.rtlsdr_source_0.set_sample_rate(samp_rate)
+        self.rtlsdr_source_0.set_center_freq(100e6, 0)
+        self.rtlsdr_source_0.set_freq_corr(0, 0)
+        self.rtlsdr_source_0.set_dc_offset_mode(0, 0)
+        self.rtlsdr_source_0.set_iq_balance_mode(0, 0)
+        self.rtlsdr_source_0.set_gain_mode(0, 0)
+        self.rtlsdr_source_0.set_gain(10, 0)
+        self.rtlsdr_source_0.set_if_gain(20, 0)
+        self.rtlsdr_source_0.set_bb_gain(20, 0)
+        self.rtlsdr_source_0.set_antenna("", 0)
+        self.rtlsdr_source_0.set_bandwidth(0, 0)
+          
+        self.logpwrfft_x_0 = logpwrfft.logpwrfft_c(
+        	sample_rate=samp_rate,
+        	fft_size=fft_size,
+        	ref_scale=2,
+        	frame_rate=fps,
+        	avg_alpha=1.0,
+        	average=False,
+        )
+        self.blocks_message_sink_0 = blocks.message_sink(gr.sizeof_float*fft_size, blocks_message_sink_0_msgq_out, False)
+
+        ##################################################
+        # Connections
+        ##################################################
+        self.connect((self.logpwrfft_x_0, 0), (self.blocks_message_sink_0, 0))
+        # removed by grcconvert: # self.connect((self.blocks_message_sink_0, msg), (self, 0))
+        self.connect((self.rtlsdr_source_0, 0), (self.logpwrfft_x_0, 0))
+
+
+# QT sink close method reimplementation
+
+    def get_samp_rate(self):
+        return self.samp_rate
+
+    def set_samp_rate(self, samp_rate):
+        self.samp_rate = samp_rate
+        self.rtlsdr_source_0.set_sample_rate(self.samp_rate)
+        self.logpwrfft_x_0.set_sample_rate(self.samp_rate)
+
+    def get_fps(self):
+        return self.fps
+
+    def set_fps(self, fps):
+        self.fps = fps
+
+    def get_fft_size(self):
+        return self.fft_size
+
+    def set_fft_size(self, fft_size):
+        self.fft_size = fft_size
+
+if __name__ == '__main__':
+    parser = OptionParser(option_class=eng_option, usage="%prog: [options]")
+    (options, args) = parser.parse_args()
+    tb = top_block()
+    tb.start()
+    tb.wait()
+
diff --git a/demod/ssb/__init__.py b/demod/ssb/__init__.py
new file mode 100755
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/demod/ssb/client_ssb.grc b/demod/ssb/client_ssb.grc
new file mode 100755
index 0000000000000000000000000000000000000000..3596b85bc2ef56e6eb1cda0d35cde4771d586934
--- /dev/null
+++ b/demod/ssb/client_ssb.grc
@@ -0,0 +1,1015 @@
+<?xml version='1.0' encoding='ASCII'?>
+<flow_graph>
+  <timestamp>Sat Nov 23 18:35:41 2013</timestamp>
+  <block>
+    <key>options</key>
+    <param>
+      <key>id</key>
+      <value>top_block</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>title</key>
+      <value></value>
+    </param>
+    <param>
+      <key>author</key>
+      <value></value>
+    </param>
+    <param>
+      <key>description</key>
+      <value></value>
+    </param>
+    <param>
+      <key>window_size</key>
+      <value>1280, 1024</value>
+    </param>
+    <param>
+      <key>generate_options</key>
+      <value>no_gui</value>
+    </param>
+    <param>
+      <key>category</key>
+      <value>Custom</value>
+    </param>
+    <param>
+      <key>run_options</key>
+      <value>run</value>
+    </param>
+    <param>
+      <key>run</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>max_nouts</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>realtime_scheduling</key>
+      <value></value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(0, 8)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>auto_gain</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(407, 98)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>if_gain</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(321, 98)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>rf_gain</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>10</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(234, 98)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>offset_freq</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>300000</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(426, 28)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>center_freq</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>103000000</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(205, 29)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>samp_rate</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>2048000</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(320, 29)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>demod_rate</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>samp_rate/(samp_rate/16000)</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(627, 101)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>audio_rate</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>44100</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(129, 98)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>low_cut</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>-3000</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(533, 26)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>high_cut</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(532, 99)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>blocks_message_sink</key>
+    <param>
+      <key>id</key>
+      <value>blocks_message_sink_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>short</value>
+    </param>
+    <param>
+      <key>dont_block</key>
+      <value>False</value>
+    </param>
+    <param>
+      <key>vlen</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>affinity</key>
+      <value></value>
+    </param>
+    <param>
+      <key>minoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>maxoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(883, 420)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>pad_sink</key>
+    <param>
+      <key>id</key>
+      <value>pad_sink_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>label</key>
+      <value>out</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value></value>
+    </param>
+    <param>
+      <key>vlen</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>num_streams</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>optional</key>
+      <value>False</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(1094, 420)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>rtlsdr_source</key>
+    <param>
+      <key>id</key>
+      <value>rtlsdr_source_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>fc32</value>
+    </param>
+    <param>
+      <key>args</key>
+      <value>rtl_tcp=127.0.0.1:7373</value>
+    </param>
+    <param>
+      <key>nchan</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>sample_rate</key>
+      <value>samp_rate</value>
+    </param>
+    <param>
+      <key>freq0</key>
+      <value>center_freq</value>
+    </param>
+    <param>
+      <key>corr0</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>dc_offset_mode0</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>iq_balance_mode0</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain_mode0</key>
+      <value>auto_gain</value>
+    </param>
+    <param>
+      <key>gain0</key>
+      <value>rf_gain</value>
+    </param>
+    <param>
+      <key>if_gain0</key>
+      <value>if_gain</value>
+    </param>
+    <param>
+      <key>bb_gain0</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>ant0</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw0</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>freq1</key>
+      <value>100e6</value>
+    </param>
+    <param>
+      <key>corr1</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>dc_offset_mode1</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>iq_balance_mode1</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain_mode1</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain1</key>
+      <value>10</value>
+    </param>
+    <param>
+      <key>if_gain1</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>bb_gain1</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>ant1</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw1</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>freq2</key>
+      <value>100e6</value>
+    </param>
+    <param>
+      <key>corr2</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>dc_offset_mode2</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>iq_balance_mode2</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain_mode2</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain2</key>
+      <value>10</value>
+    </param>
+    <param>
+      <key>if_gain2</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>bb_gain2</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>ant2</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw2</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>freq3</key>
+      <value>100e6</value>
+    </param>
+    <param>
+      <key>corr3</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>dc_offset_mode3</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>iq_balance_mode3</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain_mode3</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain3</key>
+      <value>10</value>
+    </param>
+    <param>
+      <key>if_gain3</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>bb_gain3</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>ant3</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw3</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>freq4</key>
+      <value>100e6</value>
+    </param>
+    <param>
+      <key>corr4</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>dc_offset_mode4</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>iq_balance_mode4</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain_mode4</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain4</key>
+      <value>10</value>
+    </param>
+    <param>
+      <key>if_gain4</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>bb_gain4</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>ant4</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw4</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>affinity</key>
+      <value></value>
+    </param>
+    <param>
+      <key>minoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>maxoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(14, 169)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>analog_agc2_xx</key>
+    <param>
+      <key>id</key>
+      <value>analog_agc2_xx_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>complex</value>
+    </param>
+    <param>
+      <key>attack_rate</key>
+      <value>1e-3</value>
+    </param>
+    <param>
+      <key>decay_rate</key>
+      <value>208e-5</value>
+    </param>
+    <param>
+      <key>reference</key>
+      <value>1.0</value>
+    </param>
+    <param>
+      <key>gain</key>
+      <value>1.0</value>
+    </param>
+    <param>
+      <key>max_gain</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>affinity</key>
+      <value></value>
+    </param>
+    <param>
+      <key>minoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>maxoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(772, 225)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>blocks_complex_to_imag</key>
+    <param>
+      <key>id</key>
+      <value>blocks_complex_to_imag_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>vlen</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>affinity</key>
+      <value></value>
+    </param>
+    <param>
+      <key>minoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>maxoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(984, 256)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>freq_xlating_fir_filter_xxx</key>
+    <param>
+      <key>id</key>
+      <value>freq_xlating_fir_filter_xxx_0_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>False</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>ccc</value>
+    </param>
+    <param>
+      <key>decim</key>
+      <value>samp_rate/demod_rate</value>
+    </param>
+    <param>
+      <key>taps</key>
+      <value>firdes.complex_band_pass(1,samp_rate,low_cut,high_cut,1000)</value>
+    </param>
+    <param>
+      <key>center_freq</key>
+      <value>offset_freq</value>
+    </param>
+    <param>
+      <key>samp_rate</key>
+      <value>samp_rate</value>
+    </param>
+    <param>
+      <key>affinity</key>
+      <value></value>
+    </param>
+    <param>
+      <key>minoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>maxoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(147, 372)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>band_pass_filter</key>
+    <param>
+      <key>id</key>
+      <value>band_pass_filter_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>fir_filter_ccc</value>
+    </param>
+    <param>
+      <key>decim</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>interp</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>gain</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>samp_rate</key>
+      <value>demod_rate</value>
+    </param>
+    <param>
+      <key>low_cutoff_freq</key>
+      <value>low_cut</value>
+    </param>
+    <param>
+      <key>high_cutoff_freq</key>
+      <value>high_cut</value>
+    </param>
+    <param>
+      <key>width</key>
+      <value>500</value>
+    </param>
+    <param>
+      <key>win</key>
+      <value>firdes.WIN_HAMMING</value>
+    </param>
+    <param>
+      <key>beta</key>
+      <value>6.76</value>
+    </param>
+    <param>
+      <key>affinity</key>
+      <value></value>
+    </param>
+    <param>
+      <key>minoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>maxoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(563, 188)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>fractional_resampler_xx</key>
+    <param>
+      <key>id</key>
+      <value>fractional_resampler_xx_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>float</value>
+    </param>
+    <param>
+      <key>phase_shift</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>resamp_ratio</key>
+      <value>demod_rate/float(audio_rate)</value>
+    </param>
+    <param>
+      <key>affinity</key>
+      <value></value>
+    </param>
+    <param>
+      <key>minoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>maxoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(440, 411)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>blocks_float_to_short</key>
+    <param>
+      <key>id</key>
+      <value>blocks_float_to_short_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>vlen</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>scale</key>
+      <value>3000</value>
+    </param>
+    <param>
+      <key>affinity</key>
+      <value></value>
+    </param>
+    <param>
+      <key>minoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>maxoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(680, 421)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>freq_xlating_fir_filter_xxx</key>
+    <param>
+      <key>id</key>
+      <value>freq_xlating_fir_filter_xxx_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>ccf</value>
+    </param>
+    <param>
+      <key>decim</key>
+      <value>samp_rate/demod_rate</value>
+    </param>
+    <param>
+      <key>taps</key>
+      <value>firdes.low_pass(1,samp_rate,demod_rate*0.8,demod_rate*0.3)</value>
+    </param>
+    <param>
+      <key>center_freq</key>
+      <value>offset_freq</value>
+    </param>
+    <param>
+      <key>samp_rate</key>
+      <value>samp_rate</value>
+    </param>
+    <param>
+      <key>affinity</key>
+      <value></value>
+    </param>
+    <param>
+      <key>minoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>maxoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(282, 211)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <connection>
+    <source_block_id>rtlsdr_source_0</source_block_id>
+    <sink_block_id>freq_xlating_fir_filter_xxx_0</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+  <connection>
+    <source_block_id>blocks_float_to_short_0</source_block_id>
+    <sink_block_id>blocks_message_sink_0</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+  <connection>
+    <source_block_id>blocks_message_sink_0</source_block_id>
+    <sink_block_id>pad_sink_0</sink_block_id>
+    <source_key>msg</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+  <connection>
+    <source_block_id>analog_agc2_xx_0</source_block_id>
+    <sink_block_id>blocks_complex_to_imag_0</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+  <connection>
+    <source_block_id>fractional_resampler_xx_0</source_block_id>
+    <sink_block_id>blocks_float_to_short_0</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+  <connection>
+    <source_block_id>blocks_complex_to_imag_0</source_block_id>
+    <sink_block_id>fractional_resampler_xx_0</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+  <connection>
+    <source_block_id>band_pass_filter_0</source_block_id>
+    <sink_block_id>analog_agc2_xx_0</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+  <connection>
+    <source_block_id>freq_xlating_fir_filter_xxx_0</source_block_id>
+    <sink_block_id>band_pass_filter_0</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+</flow_graph>
diff --git a/demod/ssb/top_block.py b/demod/ssb/top_block.py
new file mode 100755
index 0000000000000000000000000000000000000000..a3ce65b42fd22b400baaec2045eff2c35154f20d
--- /dev/null
+++ b/demod/ssb/top_block.py
@@ -0,0 +1,163 @@
+#!/usr/bin/env python
+##################################################
+# Gnuradio Python Flow Graph
+# Title: Top Block
+# Generated: Mon Nov 25 22:14:50 2013
+##################################################
+
+from gnuradio import analog
+from gnuradio import blocks
+from gnuradio import eng_notation
+from gnuradio import filter
+from gnuradio import gr
+from gnuradio.eng_option import eng_option
+from gnuradio.filter import firdes
+from optparse import OptionParser
+import osmosdr
+
+class top_block(gr.top_block):
+
+    def __init__(self,sample_rate_param): # added by grcconvert
+        gr.top_block.__init__(self, "Top Block")
+
+        ##################################################
+        # Variables
+        ##################################################
+        self.samp_rate = samp_rate = sample_rate_param # added by grcconvert
+        self.rf_gain = rf_gain = 10
+        self.offset_freq = offset_freq = 300000
+        self.low_cut = low_cut = -3000
+        self.if_gain = if_gain = 20
+        self.high_cut = high_cut = 0
+        self.demod_rate = demod_rate = samp_rate/(samp_rate/16000)
+        self.center_freq = center_freq = 103000000
+        self.auto_gain = auto_gain = True
+        self.audio_rate = audio_rate = 44100
+
+        ##################################################
+        # Message queues (added by grcconvert)
+        ##################################################
+        self.msgq_out = blocks_message_sink_0_msgq_out = gr.msg_queue(2)
+
+        ##################################################
+        # Blocks
+        ##################################################
+        self.rtlsdr_source_0 = osmosdr.source( args="numchan=" + str(1) + " " + "rtl_tcp=127.0.0.1:7373" )
+        self.rtlsdr_source_0.set_sample_rate(samp_rate)
+        self.rtlsdr_source_0.set_center_freq(center_freq, 0)
+        self.rtlsdr_source_0.set_freq_corr(0, 0)
+        self.rtlsdr_source_0.set_dc_offset_mode(0, 0)
+        self.rtlsdr_source_0.set_iq_balance_mode(0, 0)
+        self.rtlsdr_source_0.set_gain_mode(auto_gain, 0)
+        self.rtlsdr_source_0.set_gain(rf_gain, 0)
+        self.rtlsdr_source_0.set_if_gain(if_gain, 0)
+        self.rtlsdr_source_0.set_bb_gain(20, 0)
+        self.rtlsdr_source_0.set_antenna("", 0)
+        self.rtlsdr_source_0.set_bandwidth(0, 0)
+          
+        self.freq_xlating_fir_filter_xxx_0 = filter.freq_xlating_fir_filter_ccf(samp_rate/demod_rate, (firdes.low_pass(1,samp_rate,demod_rate*0.8,demod_rate*0.3)), offset_freq, samp_rate)
+        self.fractional_resampler_xx_0 = filter.fractional_resampler_ff(0, demod_rate/float(audio_rate))
+        self.blocks_message_sink_0 = blocks.message_sink(gr.sizeof_short*1, blocks_message_sink_0_msgq_out, False)
+        self.blocks_float_to_short_0 = blocks.float_to_short(1, 3000)
+        self.blocks_complex_to_imag_0 = blocks.complex_to_imag(1)
+        self.band_pass_filter_0 = filter.fir_filter_ccc(1, firdes.complex_band_pass(
+        	1, demod_rate, low_cut, high_cut, 500, firdes.WIN_HAMMING, 6.76))
+        self.analog_agc2_xx_0 = analog.agc2_cc(1e-3, 208e-5, 1.0, 1.0)
+        self.analog_agc2_xx_0.set_max_gain(20)
+
+        ##################################################
+        # Connections
+        ##################################################
+        self.connect((self.rtlsdr_source_0, 0), (self.freq_xlating_fir_filter_xxx_0, 0))
+        self.connect((self.blocks_float_to_short_0, 0), (self.blocks_message_sink_0, 0))
+        # removed by grcconvert: # self.connect((self.blocks_message_sink_0, msg), (self, 0))
+        self.connect((self.analog_agc2_xx_0, 0), (self.blocks_complex_to_imag_0, 0))
+        self.connect((self.fractional_resampler_xx_0, 0), (self.blocks_float_to_short_0, 0))
+        self.connect((self.blocks_complex_to_imag_0, 0), (self.fractional_resampler_xx_0, 0))
+        self.connect((self.band_pass_filter_0, 0), (self.analog_agc2_xx_0, 0))
+        self.connect((self.freq_xlating_fir_filter_xxx_0, 0), (self.band_pass_filter_0, 0))
+
+
+# QT sink close method reimplementation
+
+    def get_samp_rate(self):
+        return self.samp_rate
+
+    def set_samp_rate(self, samp_rate):
+        self.samp_rate = samp_rate
+        self.set_demod_rate(self.samp_rate/(self.samp_rate/16000))
+        self.rtlsdr_source_0.set_sample_rate(self.samp_rate)
+        self.freq_xlating_fir_filter_xxx_0.set_taps((firdes.low_pass(1,self.samp_rate,self.demod_rate*0.8,self.demod_rate*0.3)))
+
+    def get_rf_gain(self):
+        return self.rf_gain
+
+    def set_rf_gain(self, rf_gain):
+        self.rf_gain = rf_gain
+        self.rtlsdr_source_0.set_gain(self.rf_gain, 0)
+
+    def get_offset_freq(self):
+        return self.offset_freq
+
+    def set_offset_freq(self, offset_freq):
+        self.offset_freq = offset_freq
+        self.freq_xlating_fir_filter_xxx_0.set_center_freq(self.offset_freq)
+
+    def get_low_cut(self):
+        return self.low_cut
+
+    def set_low_cut(self, low_cut):
+        self.low_cut = low_cut
+        self.band_pass_filter_0.set_taps(firdes.complex_band_pass(1, self.demod_rate, self.low_cut, self.high_cut, 500, firdes.WIN_HAMMING, 6.76))
+
+    def get_if_gain(self):
+        return self.if_gain
+
+    def set_if_gain(self, if_gain):
+        self.if_gain = if_gain
+        self.rtlsdr_source_0.set_if_gain(self.if_gain, 0)
+
+    def get_high_cut(self):
+        return self.high_cut
+
+    def set_high_cut(self, high_cut):
+        self.high_cut = high_cut
+        self.band_pass_filter_0.set_taps(firdes.complex_band_pass(1, self.demod_rate, self.low_cut, self.high_cut, 500, firdes.WIN_HAMMING, 6.76))
+
+    def get_demod_rate(self):
+        return self.demod_rate
+
+    def set_demod_rate(self, demod_rate):
+        self.demod_rate = demod_rate
+        self.band_pass_filter_0.set_taps(firdes.complex_band_pass(1, self.demod_rate, self.low_cut, self.high_cut, 500, firdes.WIN_HAMMING, 6.76))
+        self.fractional_resampler_xx_0.set_resamp_ratio(self.demod_rate/float(self.audio_rate))
+        self.freq_xlating_fir_filter_xxx_0.set_taps((firdes.low_pass(1,self.samp_rate,self.demod_rate*0.8,self.demod_rate*0.3)))
+
+    def get_center_freq(self):
+        return self.center_freq
+
+    def set_center_freq(self, center_freq):
+        self.center_freq = center_freq
+        self.rtlsdr_source_0.set_center_freq(self.center_freq, 0)
+
+    def get_auto_gain(self):
+        return self.auto_gain
+
+    def set_auto_gain(self, auto_gain):
+        self.auto_gain = auto_gain
+        self.rtlsdr_source_0.set_gain_mode(self.auto_gain, 0)
+
+    def get_audio_rate(self):
+        return self.audio_rate
+
+    def set_audio_rate(self, audio_rate):
+        self.audio_rate = audio_rate
+        self.fractional_resampler_xx_0.set_resamp_ratio(self.demod_rate/float(self.audio_rate))
+
+if __name__ == '__main__':
+    parser = OptionParser(option_class=eng_option, usage="%prog: [options]")
+    (options, args) = parser.parse_args()
+    tb = top_block()
+    tb.start()
+    tb.wait()
+
diff --git a/demod/wfm/__init__.py b/demod/wfm/__init__.py
new file mode 100755
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/demod/wfm/client_wfm.grc b/demod/wfm/client_wfm.grc
new file mode 100755
index 0000000000000000000000000000000000000000..6798bb300f037aeedd01cc3b350c53f583bad725
--- /dev/null
+++ b/demod/wfm/client_wfm.grc
@@ -0,0 +1,853 @@
+<?xml version='1.0' encoding='ASCII'?>
+<flow_graph>
+  <timestamp>Sat Nov 23 18:26:30 2013</timestamp>
+  <block>
+    <key>options</key>
+    <param>
+      <key>id</key>
+      <value>top_block</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>title</key>
+      <value></value>
+    </param>
+    <param>
+      <key>author</key>
+      <value></value>
+    </param>
+    <param>
+      <key>description</key>
+      <value></value>
+    </param>
+    <param>
+      <key>window_size</key>
+      <value>1280, 1024</value>
+    </param>
+    <param>
+      <key>generate_options</key>
+      <value>no_gui</value>
+    </param>
+    <param>
+      <key>category</key>
+      <value>Custom</value>
+    </param>
+    <param>
+      <key>run_options</key>
+      <value>run</value>
+    </param>
+    <param>
+      <key>run</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>max_nouts</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>realtime_scheduling</key>
+      <value></value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(12, -1)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>high_cut</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(577, 14)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>low_cut</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(584, 75)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>auto_gain</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(494, 81)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>demod_rate</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>samp_rate/(samp_rate/180000)</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(10, 77)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>audio_rate</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>48000</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(123, 78)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>samp_rate</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>2048000</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(311, 10)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>offset_freq</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>300000</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(420, 10)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>filter_bw</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>200000</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(228, 77)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>rf_gain</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>10</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(321, 78)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>if_gain</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(411, 80)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>variable</key>
+    <param>
+      <key>id</key>
+      <value>center_freq</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>value</key>
+      <value>103000000</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(202, 11)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>analog_wfm_rcv</key>
+    <param>
+      <key>id</key>
+      <value>analog_wfm_rcv_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>quad_rate</key>
+      <value>samp_rate/(int(samp_rate)/demod_rate)</value>
+    </param>
+    <param>
+      <key>audio_decimation</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>affinity</key>
+      <value></value>
+    </param>
+    <param>
+      <key>minoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>maxoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(670, 210)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>fractional_resampler_xx</key>
+    <param>
+      <key>id</key>
+      <value>fractional_resampler_xx_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>float</value>
+    </param>
+    <param>
+      <key>phase_shift</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>resamp_ratio</key>
+      <value>(samp_rate/(int(samp_rate)/demod_rate))/float(audio_rate)</value>
+    </param>
+    <param>
+      <key>affinity</key>
+      <value></value>
+    </param>
+    <param>
+      <key>minoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>maxoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(955, 221)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>pad_sink</key>
+    <param>
+      <key>id</key>
+      <value>pad_sink_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>label</key>
+      <value>out</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value></value>
+    </param>
+    <param>
+      <key>vlen</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>num_streams</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>optional</key>
+      <value>False</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(1169, 48)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>blocks_message_sink</key>
+    <param>
+      <key>id</key>
+      <value>blocks_message_sink_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>short</value>
+    </param>
+    <param>
+      <key>dont_block</key>
+      <value>False</value>
+    </param>
+    <param>
+      <key>vlen</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>affinity</key>
+      <value></value>
+    </param>
+    <param>
+      <key>minoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>maxoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(928, 48)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>blocks_float_to_short</key>
+    <param>
+      <key>id</key>
+      <value>blocks_float_to_short_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>vlen</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>scale</key>
+      <value>300000</value>
+    </param>
+    <param>
+      <key>affinity</key>
+      <value></value>
+    </param>
+    <param>
+      <key>minoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>maxoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(713, 48)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>freq_xlating_fir_filter_xxx</key>
+    <param>
+      <key>id</key>
+      <value>freq_xlating_fir_filter_xxx_0</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>ccc</value>
+    </param>
+    <param>
+      <key>decim</key>
+      <value>samp_rate/demod_rate</value>
+    </param>
+    <param>
+      <key>taps</key>
+      <value>firdes.low_pass(1,samp_rate,filter_bw,demod_rate*0.7)</value>
+    </param>
+    <param>
+      <key>center_freq</key>
+      <value>offset_freq</value>
+    </param>
+    <param>
+      <key>samp_rate</key>
+      <value>samp_rate</value>
+    </param>
+    <param>
+      <key>affinity</key>
+      <value></value>
+    </param>
+    <param>
+      <key>minoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>maxoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(320, 196)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <block>
+    <key>rtlsdr_source</key>
+    <param>
+      <key>id</key>
+      <value>rtlsdr_source</value>
+    </param>
+    <param>
+      <key>_enabled</key>
+      <value>True</value>
+    </param>
+    <param>
+      <key>type</key>
+      <value>fc32</value>
+    </param>
+    <param>
+      <key>args</key>
+      <value>rtl_tcp=127.0.0.1:7373</value>
+    </param>
+    <param>
+      <key>nchan</key>
+      <value>1</value>
+    </param>
+    <param>
+      <key>sample_rate</key>
+      <value>samp_rate</value>
+    </param>
+    <param>
+      <key>freq0</key>
+      <value>center_freq</value>
+    </param>
+    <param>
+      <key>corr0</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>dc_offset_mode0</key>
+      <value>2</value>
+    </param>
+    <param>
+      <key>iq_balance_mode0</key>
+      <value>2</value>
+    </param>
+    <param>
+      <key>gain_mode0</key>
+      <value>auto_gain</value>
+    </param>
+    <param>
+      <key>gain0</key>
+      <value>rf_gain</value>
+    </param>
+    <param>
+      <key>if_gain0</key>
+      <value>if_gain</value>
+    </param>
+    <param>
+      <key>bb_gain0</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>ant0</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw0</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>freq1</key>
+      <value>100e6</value>
+    </param>
+    <param>
+      <key>corr1</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>dc_offset_mode1</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>iq_balance_mode1</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain_mode1</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain1</key>
+      <value>10</value>
+    </param>
+    <param>
+      <key>if_gain1</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>bb_gain1</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>ant1</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw1</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>freq2</key>
+      <value>100e6</value>
+    </param>
+    <param>
+      <key>corr2</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>dc_offset_mode2</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>iq_balance_mode2</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain_mode2</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain2</key>
+      <value>10</value>
+    </param>
+    <param>
+      <key>if_gain2</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>bb_gain2</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>ant2</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw2</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>freq3</key>
+      <value>100e6</value>
+    </param>
+    <param>
+      <key>corr3</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>dc_offset_mode3</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>iq_balance_mode3</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain_mode3</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain3</key>
+      <value>10</value>
+    </param>
+    <param>
+      <key>if_gain3</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>bb_gain3</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>ant3</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw3</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>freq4</key>
+      <value>100e6</value>
+    </param>
+    <param>
+      <key>corr4</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>dc_offset_mode4</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>iq_balance_mode4</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain_mode4</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>gain4</key>
+      <value>10</value>
+    </param>
+    <param>
+      <key>if_gain4</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>bb_gain4</key>
+      <value>20</value>
+    </param>
+    <param>
+      <key>ant4</key>
+      <value></value>
+    </param>
+    <param>
+      <key>bw4</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>affinity</key>
+      <value></value>
+    </param>
+    <param>
+      <key>minoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>maxoutbuf</key>
+      <value>0</value>
+    </param>
+    <param>
+      <key>_coordinate</key>
+      <value>(21, 154)</value>
+    </param>
+    <param>
+      <key>_rotation</key>
+      <value>0</value>
+    </param>
+  </block>
+  <connection>
+    <source_block_id>blocks_message_sink_0</source_block_id>
+    <sink_block_id>pad_sink_0</sink_block_id>
+    <source_key>msg</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+  <connection>
+    <source_block_id>blocks_float_to_short_0</source_block_id>
+    <sink_block_id>blocks_message_sink_0</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+  <connection>
+    <source_block_id>freq_xlating_fir_filter_xxx_0</source_block_id>
+    <sink_block_id>analog_wfm_rcv_0</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+  <connection>
+    <source_block_id>rtlsdr_source</source_block_id>
+    <sink_block_id>freq_xlating_fir_filter_xxx_0</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+  <connection>
+    <source_block_id>analog_wfm_rcv_0</source_block_id>
+    <sink_block_id>fractional_resampler_xx_0</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+  <connection>
+    <source_block_id>fractional_resampler_xx_0</source_block_id>
+    <sink_block_id>blocks_float_to_short_0</sink_block_id>
+    <source_key>0</source_key>
+    <sink_key>0</sink_key>
+  </connection>
+</flow_graph>
diff --git a/demod/wfm/top_block.py b/demod/wfm/top_block.py
new file mode 100755
index 0000000000000000000000000000000000000000..813fea06b17101929172e28c97622ce42c1ac224
--- /dev/null
+++ b/demod/wfm/top_block.py
@@ -0,0 +1,166 @@
+#!/usr/bin/env python
+##################################################
+# Gnuradio Python Flow Graph
+# Title: Top Block
+# Generated: Mon Nov 25 22:14:56 2013
+##################################################
+
+from gnuradio import analog
+from gnuradio import blocks
+from gnuradio import eng_notation
+from gnuradio import filter
+from gnuradio import gr
+from gnuradio.eng_option import eng_option
+from gnuradio.filter import firdes
+from optparse import OptionParser
+import osmosdr
+
+class top_block(gr.top_block):
+
+    def __init__(self,sample_rate_param): # added by grcconvert
+        gr.top_block.__init__(self, "Top Block")
+
+        ##################################################
+        # Variables
+        ##################################################
+        self.samp_rate = samp_rate = sample_rate_param # added by grcconvert
+        self.rf_gain = rf_gain = 10
+        self.offset_freq = offset_freq = 300000
+        self.low_cut = low_cut = 0
+        self.if_gain = if_gain = 20
+        self.high_cut = high_cut = 0
+        self.filter_bw = filter_bw = 200000
+        self.demod_rate = demod_rate = samp_rate/(samp_rate/180000)
+        self.center_freq = center_freq = 103000000
+        self.auto_gain = auto_gain = True
+        self.audio_rate = audio_rate = 48000
+
+        ##################################################
+        # Message queues (added by grcconvert)
+        ##################################################
+        self.msgq_out = blocks_message_sink_0_msgq_out = gr.msg_queue(2)
+
+        ##################################################
+        # Blocks
+        ##################################################
+        self.rtlsdr_source = osmosdr.source( args="numchan=" + str(1) + " " + "rtl_tcp=127.0.0.1:7373" )
+        self.rtlsdr_source.set_sample_rate(samp_rate)
+        self.rtlsdr_source.set_center_freq(center_freq, 0)
+        self.rtlsdr_source.set_freq_corr(0, 0)
+        self.rtlsdr_source.set_dc_offset_mode(2, 0)
+        self.rtlsdr_source.set_iq_balance_mode(2, 0)
+        self.rtlsdr_source.set_gain_mode(auto_gain, 0)
+        self.rtlsdr_source.set_gain(rf_gain, 0)
+        self.rtlsdr_source.set_if_gain(if_gain, 0)
+        self.rtlsdr_source.set_bb_gain(20, 0)
+        self.rtlsdr_source.set_antenna("", 0)
+        self.rtlsdr_source.set_bandwidth(0, 0)
+          
+        self.freq_xlating_fir_filter_xxx_0 = filter.freq_xlating_fir_filter_ccc(samp_rate/demod_rate, (firdes.low_pass(1,samp_rate,filter_bw,demod_rate*0.7)), offset_freq, samp_rate)
+        self.fractional_resampler_xx_0 = filter.fractional_resampler_ff(0, (samp_rate/(int(samp_rate)/demod_rate))/float(audio_rate))
+        self.blocks_message_sink_0 = blocks.message_sink(gr.sizeof_short*1, blocks_message_sink_0_msgq_out, False)
+        self.blocks_float_to_short_0 = blocks.float_to_short(1, 300000)
+        self.analog_wfm_rcv_0 = analog.wfm_rcv(
+        	quad_rate=samp_rate/(int(samp_rate)/demod_rate),
+        	audio_decimation=1,
+        )
+
+        ##################################################
+        # Connections
+        ##################################################
+        # removed by grcconvert: # self.connect((self.blocks_message_sink_0, msg), (self, 0))
+        self.connect((self.blocks_float_to_short_0, 0), (self.blocks_message_sink_0, 0))
+        self.connect((self.freq_xlating_fir_filter_xxx_0, 0), (self.analog_wfm_rcv_0, 0))
+        self.connect((self.rtlsdr_source, 0), (self.freq_xlating_fir_filter_xxx_0, 0))
+        self.connect((self.analog_wfm_rcv_0, 0), (self.fractional_resampler_xx_0, 0))
+        self.connect((self.fractional_resampler_xx_0, 0), (self.blocks_float_to_short_0, 0))
+
+
+# QT sink close method reimplementation
+
+    def get_samp_rate(self):
+        return self.samp_rate
+
+    def set_samp_rate(self, samp_rate):
+        self.samp_rate = samp_rate
+        self.set_demod_rate(self.samp_rate/(self.samp_rate/180000))
+        self.fractional_resampler_xx_0.set_resamp_ratio((self.samp_rate/(int(self.samp_rate)/self.demod_rate))/float(self.audio_rate))
+        self.freq_xlating_fir_filter_xxx_0.set_taps((firdes.low_pass(1,self.samp_rate,self.filter_bw,self.demod_rate*0.7)))
+        self.rtlsdr_source.set_sample_rate(self.samp_rate)
+
+    def get_rf_gain(self):
+        return self.rf_gain
+
+    def set_rf_gain(self, rf_gain):
+        self.rf_gain = rf_gain
+        self.rtlsdr_source.set_gain(self.rf_gain, 0)
+
+    def get_offset_freq(self):
+        return self.offset_freq
+
+    def set_offset_freq(self, offset_freq):
+        self.offset_freq = offset_freq
+        self.freq_xlating_fir_filter_xxx_0.set_center_freq(self.offset_freq)
+
+    def get_low_cut(self):
+        return self.low_cut
+
+    def set_low_cut(self, low_cut):
+        self.low_cut = low_cut
+
+    def get_if_gain(self):
+        return self.if_gain
+
+    def set_if_gain(self, if_gain):
+        self.if_gain = if_gain
+        self.rtlsdr_source.set_if_gain(self.if_gain, 0)
+
+    def get_high_cut(self):
+        return self.high_cut
+
+    def set_high_cut(self, high_cut):
+        self.high_cut = high_cut
+
+    def get_filter_bw(self):
+        return self.filter_bw
+
+    def set_filter_bw(self, filter_bw):
+        self.filter_bw = filter_bw
+        self.freq_xlating_fir_filter_xxx_0.set_taps((firdes.low_pass(1,self.samp_rate,self.filter_bw,self.demod_rate*0.7)))
+
+    def get_demod_rate(self):
+        return self.demod_rate
+
+    def set_demod_rate(self, demod_rate):
+        self.demod_rate = demod_rate
+        self.fractional_resampler_xx_0.set_resamp_ratio((self.samp_rate/(int(self.samp_rate)/self.demod_rate))/float(self.audio_rate))
+        self.freq_xlating_fir_filter_xxx_0.set_taps((firdes.low_pass(1,self.samp_rate,self.filter_bw,self.demod_rate*0.7)))
+
+    def get_center_freq(self):
+        return self.center_freq
+
+    def set_center_freq(self, center_freq):
+        self.center_freq = center_freq
+        self.rtlsdr_source.set_center_freq(self.center_freq, 0)
+
+    def get_auto_gain(self):
+        return self.auto_gain
+
+    def set_auto_gain(self, auto_gain):
+        self.auto_gain = auto_gain
+        self.rtlsdr_source.set_gain_mode(self.auto_gain, 0)
+
+    def get_audio_rate(self):
+        return self.audio_rate
+
+    def set_audio_rate(self, audio_rate):
+        self.audio_rate = audio_rate
+        self.fractional_resampler_xx_0.set_resamp_ratio((self.samp_rate/(int(self.samp_rate)/self.demod_rate))/float(self.audio_rate))
+
+if __name__ == '__main__':
+    parser = OptionParser(option_class=eng_option, usage="%prog: [options]")
+    (options, args) = parser.parse_args()
+    tb = top_block()
+    tb.start()
+    tb.wait()
+
diff --git a/grcconvert.py b/grcconvert.py
new file mode 100755
index 0000000000000000000000000000000000000000..ea89929a26b180d8081e0d59ad2e116ecdfb27cd
--- /dev/null
+++ b/grcconvert.py
@@ -0,0 +1,88 @@
+"""
+Copyright (c) 2013 Andras Retzler
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+Version history
+---------------
+2013-08
+- initial version
+
+2013-11-12
+- updated to GNU Radio 3.7
+  - changed gr_message_sink_0_msgq_out to blocks_message_sink_0_msgq_out
+
+2013-11-25
+- almost rewritten, now supports multiple message sinks, and regexp_replaces
+
+"""
+
+import sys
+import re
+
+def main(filename, regexp_replaces=[]):
+	f=open(filename,"r")
+	data=f.read()
+	f.close()
+	
+	#is it already converted?
+	if data.count("(added by grcconvert)"):
+		print "[grcconvert:info] File has already been converted: "+filename
+		return 
+
+	# process regexps
+	for anything in regexp_replaces:
+		data=re.sub(anything[0],anything[1],data)
+
+	# count how many message sinks we have
+	n_sinks=data.count("self.connect((self.blocks_message_sink_")
+	print "[grcconvert:info] "+filename+" has {0} message sinks.".format(n_sinks)
+	data=data.replace("self.connect((self.blocks_message_sink_","# removed by grcconvert: # self.connect((self.blocks_message_sink_")
+	if not n_sinks:
+		print "[grcconvert:error] No message sinks found."
+		return
+
+	lines=data.split("\n")
+
+	# we find out where we should insert our line
+	insert_here=0
+	for i, l in enumerate(lines):
+		if l.count("# Blocks"):
+			insert_here=i
+			break
+	insert_here-=1
+	if insert_here<=0:
+		print "[grcconvert:error] Not a GNUradio-companion generated top_level.py file."
+		return
+
+	text="        ##################################################\n        # Message queues (added by grcconvert)\n        ##################################################\n"
+	for i in range(0,n_sinks): text+="        self.msgq_out = blocks_message_sink_{0}_msgq_out = gr.msg_queue(2)\n".format(i)
+	lines=lines[:insert_here]+[text]+lines[insert_here:]
+
+	f=open(filename,"w")
+
+	f.write("\n".join(lines))
+	f.close()
+	print "[grcconvert:info] converted:", filename
+		
+if __name__=="__main__":
+	print "[grcconvert:info] msgq code inserter for GNUradio-companion generated top_level.py files"
+	filename=sys.argv[1] if len(sys.argv)>1 else "top_block.py"
+	main(filename)
+
diff --git a/htdocs/favicon.ico b/htdocs/favicon.ico
new file mode 100644
index 0000000000000000000000000000000000000000..f8c9a2ae9562c79442e884e6e4b23fc43ec14f42
Binary files /dev/null and b/htdocs/favicon.ico differ
diff --git a/htdocs/gfx/get_unibody8pro.txt b/htdocs/gfx/get_unibody8pro.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c1a4d3c9100de96e7ecd634cafad4b2977c8c466
--- /dev/null
+++ b/htdocs/gfx/get_unibody8pro.txt
@@ -0,0 +1,20 @@
+You can get that font from here: 
+
+http://www.underware.nl/fonts/unibody/download/
+
+You will have to convert it to a web font by using this tool:
+
+http://www.fontsquirrel.com/tools/webfont-generator
+
+You will get:
+
+unibody8pro-regular-webfont.eot 
+unibody8pro-regular-webfont.ttf 
+
+Copy these over here, and frequency will look okay.
+
+As we don't like these kind of dependencies, later this font will be replaced with an open-source one.
+
+Regards,
+
+Andris, HA7ILM
diff --git a/htdocs/gfx/openwebrx-avatar-background.png b/htdocs/gfx/openwebrx-avatar-background.png
new file mode 100755
index 0000000000000000000000000000000000000000..e52cb0b951a27ae1e759d229c802e98b16ae5067
Binary files /dev/null and b/htdocs/gfx/openwebrx-avatar-background.png differ
diff --git a/htdocs/gfx/openwebrx-avatar.png b/htdocs/gfx/openwebrx-avatar.png
new file mode 100755
index 0000000000000000000000000000000000000000..91486a61d0d47522ce07d48c579771a825f9efef
Binary files /dev/null and b/htdocs/gfx/openwebrx-avatar.png differ
diff --git a/htdocs/gfx/openwebrx-background-cool-blue.png b/htdocs/gfx/openwebrx-background-cool-blue.png
new file mode 100755
index 0000000000000000000000000000000000000000..7430bd8a8461217a5c07ef86558afc2bcfcf98c3
Binary files /dev/null and b/htdocs/gfx/openwebrx-background-cool-blue.png differ
diff --git a/htdocs/gfx/openwebrx-background-lingrad.png b/htdocs/gfx/openwebrx-background-lingrad.png
new file mode 100755
index 0000000000000000000000000000000000000000..48537f7a0ffbe3921191cda68f325e30420b5943
Binary files /dev/null and b/htdocs/gfx/openwebrx-background-lingrad.png differ
diff --git a/htdocs/gfx/openwebrx-logo-big.png b/htdocs/gfx/openwebrx-logo-big.png
new file mode 100755
index 0000000000000000000000000000000000000000..dcafb2ee3778bc1d880ab32e650d36fab91b0957
Binary files /dev/null and b/htdocs/gfx/openwebrx-logo-big.png differ
diff --git a/htdocs/gfx/openwebrx-rx-details-arrow-up.png b/htdocs/gfx/openwebrx-rx-details-arrow-up.png
new file mode 100755
index 0000000000000000000000000000000000000000..0baccd041dbba4f6807b3ba87436f6998af9e540
Binary files /dev/null and b/htdocs/gfx/openwebrx-rx-details-arrow-up.png differ
diff --git a/htdocs/gfx/openwebrx-rx-details-arrow.png b/htdocs/gfx/openwebrx-rx-details-arrow.png
new file mode 100755
index 0000000000000000000000000000000000000000..9995118f0d1c4e705687a3ed9a5dfe7952e6e13c
Binary files /dev/null and b/htdocs/gfx/openwebrx-rx-details-arrow.png differ
diff --git a/htdocs/gfx/openwebrx-scale-background.png b/htdocs/gfx/openwebrx-scale-background.png
new file mode 100755
index 0000000000000000000000000000000000000000..7fbb4d2490317a99bde1d4882e72713ae0ce31f4
Binary files /dev/null and b/htdocs/gfx/openwebrx-scale-background.png differ
diff --git a/htdocs/gfx/openwebrx-top-logo.png b/htdocs/gfx/openwebrx-top-logo.png
new file mode 100755
index 0000000000000000000000000000000000000000..477242524b9434230467dcccadfbd489c37607e0
Binary files /dev/null and b/htdocs/gfx/openwebrx-top-logo.png differ
diff --git a/htdocs/gfx/openwebrx-top-photo.jpg b/htdocs/gfx/openwebrx-top-photo.jpg
new file mode 100755
index 0000000000000000000000000000000000000000..cf521c75251ca17ab939a00643212f61358c662d
Binary files /dev/null and b/htdocs/gfx/openwebrx-top-photo.jpg differ
diff --git a/htdocs/gfx/webrx-bottom-bar.png b/htdocs/gfx/webrx-bottom-bar.png
new file mode 100755
index 0000000000000000000000000000000000000000..023a16a719a63466eae092911703ef858e05a742
Binary files /dev/null and b/htdocs/gfx/webrx-bottom-bar.png differ
diff --git a/htdocs/gfx/webrx-ha5kfu-top-logo.png b/htdocs/gfx/webrx-ha5kfu-top-logo.png
new file mode 100755
index 0000000000000000000000000000000000000000..2686eef0aa16eceddfa68cc79dbcd626de4bec4d
Binary files /dev/null and b/htdocs/gfx/webrx-ha5kfu-top-logo.png differ
diff --git a/htdocs/gfx/webrx-top-photo.jpg b/htdocs/gfx/webrx-top-photo.jpg
new file mode 100755
index 0000000000000000000000000000000000000000..47846bc80fff59b51284b266ab31a00352f179b0
Binary files /dev/null and b/htdocs/gfx/webrx-top-photo.jpg differ
diff --git a/htdocs/index.wrx b/htdocs/index.wrx
new file mode 100755
index 0000000000000000000000000000000000000000..a3c617dd618fc6fd9f0120dca8145d18b84015e0
--- /dev/null
+++ b/htdocs/index.wrx
@@ -0,0 +1,95 @@
+<!DOCTYPE HTML>
+<!--
+OpenWebRX (c) Copyright 2013 Andras Retzler <ha7ilm@sdr.hu>
+
+This file is part of OpenWebRX.
+
+    OpenWebRX is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenWebRX is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenWebRX. If not, see <http://www.gnu.org/licenses/>.
+-->
+<html>
+	<head>
+		<title>OpenWebRX | Open Source Web-based SDR for everyone!</title>
+		<script type="text/javascript">
+			//Local variables
+			client_id="%[CLIENT_ID]";
+			ws_url="%[WS_URL]";
+			rx_photo_height=%[RX_PHOTO_HEIGHT];
+		</script>
+		<script src="openwebrx.js"></script>
+		<link rel="stylesheet" type="text/css" href="openwebrx.css" />
+		<meta charset="utf-8">
+	</head>
+	<body onload="webrx_init();" onresize="webrx_resize();">
+<div id="webrx-page-container">
+	<div id="webrx-top-container">
+		<div id="webrx-top-photo-clip"> 
+			<img src="gfx/openwebrx-top-photo.jpg" id="webrx-top-photo"/> 
+			<div id="webrx-rx-photo-title">%[RX_PHOTO_TITLE]</div>
+			<div id="webrx-rx-photo-desc">%[RX_PHOTO_DESC]</div>
+		</div>
+		<div id="webrx-top-bar-background" class="webrx-top-bar-parts"></div>
+		<div id="webrx-top-bar" class="webrx-top-bar-parts">
+			<a href="http://openwebrx.org/" target="_blank"><img src="gfx/openwebrx-top-logo.png" id="webrx-top-logo" /></a>
+			<a href="http://ha5kfu.sch.bme.hu/" target="_blank"><img src="gfx/webrx-ha5kfu-top-logo.png" id="webrx-ha5kfu-top-logo" /></a>
+			<img id="webrx-rx-avatar-background" src="gfx/openwebrx-avatar-background.png" onclick="toggle_rx_photo();"/>
+			<img id="webrx-rx-avatar" src="gfx/openwebrx-avatar.png" onclick="toggle_rx_photo();"/>
+			<div id="webrx-rx-title" onclick="toggle_rx_photo();">%[RX_TITLE]</div>
+			<div id="webrx-rx-desc" onclick="toggle_rx_photo();">%[RX_DESC]</div>
+			<div id="openwebrx-rx-details-arrow">
+				<a id="openwebrx-rx-details-arrow-up" onclick="toggle_rx_photo();"><img src="gfx/openwebrx-rx-details-arrow-up.png" /></a>
+				<a id="openwebrx-rx-details-arrow-down" onclick="toggle_rx_photo();"><img src="gfx/openwebrx-rx-details-arrow.png" /></a>
+			</div>
+		</div>
+	</div>
+	<div id="webrx-main-container">
+			<div id="openwebrx-scale-container">
+				<canvas id="openwebrx-scale-canvas" width="0" height="0"></canvas>
+			</div>
+			<div id="webrx-canvas-container">
+				<div id="openwebrx-phantom-canvas"></div>
+				<!-- add canvas here by javascript -->
+			</div>
+			<div id="openwebrx-panels-container">
+				<div class="openwebrx-panel" data-panel-name="client-params" data-panel-pos="right" data-panel-order="0" data-panel-size="245,70">
+					<div id="webrx-actual-freq">---.--- MHz</div>
+					<div id="webrx-mouse-freq">---.--- MHz</div>
+					<!--<div class="openwebrx-button" onclick="ws.send('SET mod=wfm');" >WFM</div>-->
+					<div class="openwebrx-button" onclick="demodulator_analog_replace('nfm');">FM</div>
+					<div class="openwebrx-button" onclick="demodulator_analog_replace('am');">AM</div>					
+					<div class="openwebrx-button" onclick="demodulator_analog_replace('lsb');">LSB</div>
+					<div class="openwebrx-button" onclick="demodulator_analog_replace('usb');">USB</div>
+					<div class="openwebrx-button" onclick="demodulator_analog_replace('cw');">CW</div>
+				</div>
+				<div class="openwebrx-panel" id="webrx-config" data-panel-name="debug" data-panel-pos="left" data-panel-order="0" data-panel-size="570,180">
+					<div class="openwebrx-panel-inner">
+						<strong> openwebrx.js (pre-alpha) client log </strong><br />
+						Authors: <a href="javascript:sendmail2('pi7qtu=alz$pc');">HA7ILM</a>; please send us bug reports and suggestions.<br/>
+						Warning! OpenWebRX is still in the pre-alpha stage.<br/>
+						Client status: <span id="openwebrx-client-status">
+							audio received with <span id="openwebrx-audio-sps">-</span> sps
+							<span id="openwebrx-problems"></span><br/>
+						Server status: <span id="openwebrx-server-status">no information</span><br/>
+						Your client ID is: %[CLIENT_ID]<br />
+						<div id="openwebrx-debugdiv"></div>
+					</div>
+				</div>
+				<div class="openwebrx-panel" data-panel-name="client-under-devel" data-panel-pos="none" data-panel-order="0" data-panel-size="245,55" style="background-color: Red;">
+					<span style="font-size: 15pt; font-weight: bold;">Under construction</span>
+					<br />We're working on the code right now, so the application might fail.
+				</div>
+			</div>
+	</div>
+</div>
+	</body>
+</html>
diff --git a/htdocs/openwebrx.css b/htdocs/openwebrx.css
new file mode 100755
index 0000000000000000000000000000000000000000..3c9f67d23dd8698d6151ed617d317832bd35eba8
--- /dev/null
+++ b/htdocs/openwebrx.css
@@ -0,0 +1,414 @@
+/*
+OpenWebRX (c) Copyright 2013 Andras Retzler <ha7ilm@sdr.hu>
+
+This file is part of OpenWebRX.
+
+    OpenWebRX is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenWebRX is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenWebRX. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+html, body
+{
+	margin: 0;
+	padding: 0;
+   height: 100%;
+	font-family: "DejaVu Sans", Verdana, Geneva, sans-serif;
+	overflow: hidden;
+}
+
+#webrx-top-container
+{
+	position: relative;
+	z-index:1000;
+}
+
+.webrx-top-bar-parts
+{
+	position: absolute;
+	top: 0px;
+	left: 0px;
+	width:100%;
+	height:67px;
+}
+
+#webrx-top-bar-background
+{
+	background-color: #808080;
+	opacity: 0.15;
+	filter:alpha(opacity=15);
+}
+
+#webrx-top-bar
+{
+	margin:0;
+	padding:0;
+}
+
+
+#webrx-top-logo
+{
+	position: absolute;
+	top: 12px;
+	left: 15px;
+}
+
+#webrx-ha5kfu-top-logo
+{
+	position: absolute;
+	top: 19px;
+	right: 15px;
+}
+
+#webrx-top-photo
+{
+	width: 100%;
+	display: block;
+}
+
+#webrx-rx-avatar-background
+{
+	cursor:pointer;
+	position: absolute;
+	left: 285px;
+	top: 6px;
+}
+
+#webrx-rx-avatar
+{
+	cursor:pointer;
+	position: absolute;
+	left: 289px;
+	top: 10px;
+	width: 46px;
+	height: 46px;
+}
+
+#webrx-top-photo-clip
+{
+	max-height: 350px;
+	overflow: hidden;
+	position: relative;
+}
+
+/*#webrx-bottom-bar
+{
+	position: absolute;
+	bottom: 0px;
+	width: 100%;
+	height: 117px;
+	background-image:url(gfx/webrx-bottom-bar.png);
+}*/
+
+#webrx-page-container
+{
+   min-height:100%;
+   position:relative;
+}
+
+/*#webrx-photo-gradient-left
+{
+	position: absolute;
+	bottom: 0px;
+	left: 0px;
+	background-image:url(gfx/webrx-photo-gradient-corner.png);	
+	width: 59px;
+	height: 92px;
+
+}
+
+#webrx-photo-gradient-middle
+{
+	position: absolute;
+	bottom: 0px;
+	left: 59px;
+	right: 59px;
+	height: 92px;
+	background-image:url(gfx/webrx-photo-gradient-middle.png);	
+}
+
+#webrx-photo-gradient-right
+{
+	position: absolute;
+	bottom: 0px;
+	right: 0px;
+	background-image:url(gfx/webrx-photo-gradient-corner.png);	
+	width: 59px;
+	height: 92px;
+   -webkit-transform:scaleX(-1);
+   -moz-transform:scaleX(-1);
+   -ms-transform:scaleX(-1);
+   -o-transform:scaleX(-1);
+   transform:scaleX(-1);
+}*/
+
+#webrx-rx-photo-title
+{
+	position: absolute;
+	left: 15px;
+	top: 78px;
+	color: White;
+	font-size: 16pt;
+	text-shadow: 1px 1px 4px #444;
+	opacity: 1;
+}
+
+#webrx-rx-photo-desc
+{
+	position: absolute;
+	left: 15px;
+	top: 105px;
+	color: White;
+	font-size: 10pt;
+	font-weight: bold;
+	text-shadow: 0px 0px 6px #444;
+	opacity: 1;
+}
+
+#webrx-rx-photo-desc a
+{
+	color: #5ca8ff;
+	text-shadow: none;
+}
+
+#webrx-rx-title
+{
+	white-space:nowrap;
+	overflow: hidden;
+	cursor:pointer;
+	position: absolute;
+	left: 350px;
+	top: 13px;
+	font-family: "DejaVu Sans", Verdana, Geneva, sans-serif;
+	color: #909090;
+	font-size: 11pt;
+	font-weight: bold;
+}
+
+#webrx-rx-desc
+{
+	white-space:nowrap;
+	overflow: hidden;
+	cursor:pointer;
+	font-size: 10pt;
+	color: #909090;
+	position: absolute;
+	left: 350px;
+	top: 34px;
+}
+
+#openwebrx-rx-details-arrow
+{
+	cursor:pointer;
+	position: absolute;
+	left: 470px;
+	top: 51px;
+}
+
+#openwebrx-rx-details-arrow a
+{
+	margin: 0;
+	padding: 0;
+}
+
+#openwebrx-rx-details-arrow-down
+{
+	display:none;
+}
+
+/*canvas#waterfall-canvas
+{
+	border-style: none;
+	border-width: 1px;
+	height: 150px;
+	width: 100%;
+}*/
+
+#openwebrx-scale-container
+{
+	height: 47px;
+	background-image: url("gfx/openwebrx-scale-background.png");
+	background-repeat: repeat-x;
+	overflow: hidden;
+	z-index:1000;
+	position: relative;
+}
+
+#webrx-canvas-container
+{
+	/*background-image:url('gfx/openwebrx-blank-background-1.jpg');*/
+	position: relative;
+	height: 2000px;
+	overflow-y: scroll;
+	overflow-x: hidden;
+	/*background-color: #646464;*/
+	/*background-image: -webkit-linear-gradient(top, rgba(247,247,247,1) 0%, rgba(0,0,0,1) 100%);*/
+	background-image: url('gfx/openwebrx-background-cool-blue.png');
+	background-repeat: no-repeat;
+	background-color: #1e5f7f;
+	cursor: crosshair;
+}
+
+#webrx-canvas-container canvas
+{
+	position: absolute;
+	border-style: none;
+}
+
+#openwebrx-phantom-canvas
+{
+	position: absolute;
+	width: 0px;
+	height: 0px;
+}
+
+/*#openwebrx-canvas-gradient-background
+{
+	overflow: hidden;
+	width: 100%;
+	height: 396px;
+}*/
+
+/*#webrx-debugdiv
+{
+	font-size: 10pt;
+	/*overflow-y:scroll;*/
+/*}*/
+
+#webrx-main-container
+{
+	position: relative;
+	width: 100%;
+	margin: 0;
+	padding: 0;
+}
+
+.webrx-error
+{
+	font-weight: bold;
+	color: #ff6262;
+}
+
+#openwebrx-problems span
+{
+	background: #ff6262;
+	padding: 3px;
+	font-size: 8pt;
+	color: white;
+	font-weight: bold;
+	border-radius: 4px;
+	-moz-border-radius: 4px;
+	margin: 0px 2px 0px 2px;
+}
+
+/*#webrx-freq-show
+{
+	visibility: hidden;
+	position: absolute;
+	top: 0px;
+	left: 0px;
+	padding: 5px;
+	font-weight: bold;
+	border-radius: 10px;
+	-moz-border-radius: 10px;
+	background-color: #999999;
+	color: White;
+	z-index:9999; /*should be higher?
+	
+}*/
+
+@font-face {
+    font-family: 'unibody_8_pro_regregular';
+    src: url('gfx/unibody8pro-regular-webfont.eot');
+    src: url('gfx/unibody8pro-regular-webfont.ttf');
+    font-weight: normal;
+    font-style: normal;
+}
+
+#webrx-actual-freq
+{
+	width: 100%;
+	text-align: left;
+	font-size: 16pt;
+	font-family: 'unibody_8_pro_regregular';
+	padding: 0;
+	margin: 0;
+	line-height:22px;
+	
+}
+
+#webrx-mouse-freq
+{
+	width: 100%;
+	text-align: left;
+	font-size: 10pt;
+	color: #AAA;
+	font-family: 'unibody_8_pro_regregular';
+	margin-bottom: 5px;
+}
+
+.openwebrx-panel
+{
+	visibility: hidden;
+	background-color: #575757;
+	padding: 10px;
+	color: white;
+	position: fixed;
+	font-size: 10pt;
+	border-radius: 15px;
+	-moz-border-radius: 15px;
+}
+
+.openwebrx-panel a
+{
+	color: #5ca8ff;
+	text-shadow: none;
+}
+
+.openwebrx-panel-inner
+{
+	overflow-y: auto;
+	overflow-x: hidden;
+	height: 100%;
+}
+
+.openwebrx-button
+{
+	background-color: #373737;
+	padding: 5px;
+	border-radius: 5px;
+	-moz-border-radius: 5px;
+	color: White;
+	font-weight: bold;
+	width: auto;
+	float: left;
+	margin-right: 5px;
+	cursor: pointer;
+	background:-webkit-gradient( linear, left top, left bottom, color-stop(0.0	, #373737), color-stop(1, #4F4F4F) );
+	background:-moz-linear-gradient( center top, #373737 0%, #4F4F4F 100% );
+}
+
+.openwebrx-button:hover
+{
+	/*background:-webkit-gradient( linear, left top, left bottom, color-stop(0.0	, #3F3F3F), color-stop(1, #777777) );
+	background:-moz-linear-gradient( center top, #373737 5%, #4F4F4F 100% );*/
+	background: #474747;
+	color: #FFFF50;
+}
+
+.openwebrx-button:active 
+{
+	background: #777777;
+	color: #FFFF50;	
+}
+
+. 
diff --git a/htdocs/openwebrx.js b/htdocs/openwebrx.js
new file mode 100755
index 0000000000000000000000000000000000000000..db5c265285bbda372781280852c641289e4c985c
--- /dev/null
+++ b/htdocs/openwebrx.js
@@ -0,0 +1,1532 @@
+/*
+
+OpenWebRX (c) Copyright 2013 Andras Retzler <ha7ilm@sdr.hu>
+
+This file is part of OpenWebRX.
+
+    OpenWebRX is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenWebRX is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenWebRX. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+function arrayBufferToString(buf) {
+	//http://stackoverflow.com/questions/6965107/converting-between-strings-and-arraybuffers
+	return String.fromCharCode.apply(null, new Uint8Array(buf));
+}
+
+//Chrome console:
+//ws.send("SET center_freq=100000000")
+
+var bandwidth;
+var center_freq;
+var audio_buffer_current_size_debug=0;
+var audio_buffer_current_size=0;
+var fft_size;
+var fft_fps;
+var waterfall_setup_done=0;
+var waterfall_queue = [];
+var waterfall_timer;
+
+/*function fade(something,from,to,time_ms,fps)
+{
+	something.style.opacity=from;
+	something.fade_i=0;
+	n_of_iters=time_ms/(1000/fps);
+	change=(to-from)/(n_of_iters-1);
+	
+	something.fade_timer=window.setInterval(
+		function(){
+			if(something.fade_i++<n_of_iters)
+				something.style.opacity=parseFloat(something.style.opacity)+change;
+			else 
+				{something.style.opacity=to; window.clearInterval(something.fade_timer); }
+		},1000/fps);
+}*/
+
+var rx_photo_state=1;
+
+function e(what) { return document.getElementById(what); }
+
+function init_rx_photo()
+{
+	e("webrx-top-photo-clip").style.maxHeight=rx_photo_height.toString()+"px";
+	window.setTimeout(function() { animate(e("webrx-rx-photo-title"),"opacity","",1,0,1,500,30); },1000);
+	window.setTimeout(function() { animate(e("webrx-rx-photo-desc"),"opacity","",1,0,1,500,30); },1500);
+	window.setTimeout(function() { close_rx_photo() },2500);
+}
+
+function toggle_rx_photo()
+{
+	if(rx_photo_state) close_rx_photo();
+	else open_rx_photo()
+}
+
+function close_rx_photo()
+{
+	rx_photo_state=0;
+	animate_to(e("webrx-top-photo-clip"),"maxHeight","px",67,0.93,1000,60,function(){resize_waterfall_container(true);});
+	e("openwebrx-rx-details-arrow-down").style.display="block";
+	e("openwebrx-rx-details-arrow-up").style.display="none";
+}
+
+function open_rx_photo()
+{
+	rx_photo_state=1;
+	e("webrx-rx-photo-desc").style.opacity=1;
+	e("webrx-rx-photo-title").style.opacity=1;
+	animate_to(e("webrx-top-photo-clip"),"maxHeight","px",rx_photo_height,0.93,1000,60,function(){resize_waterfall_container(true);});
+	e("openwebrx-rx-details-arrow-down").style.display="none";
+	e("openwebrx-rx-details-arrow-up").style.display="block";
+}
+
+function style_value(of_what,which)
+{
+	if(of_what.currentStyle) return of_what.currentStyle[which];
+	else if (window.getComputedStyle) return document.defaultView.getComputedStyle(of_what,null).getPropertyValue(which); 	
+}
+
+// ========================================================
+// =================  ANIMATION ROUTINES  =================
+// ========================================================
+
+function animate(object,style_name,unit,from,to,accel,time_ms,fps,to_exec)
+{
+	//console.log(object.className);
+	if(typeof to_exec=="undefined") to_exec=0;
+	object.style[style_name]=from.toString()+unit;
+	object.anim_i=0;
+	n_of_iters=time_ms/(1000/fps);
+	change=(to-from)/(n_of_iters);
+	if(typeof object.anim_timer!="undefined") { window.clearInterval(object.anim_timer);  }
+	object.anim_timer=window.setInterval(
+		function(){
+			if(object.anim_i++<n_of_iters)
+			{
+				if(accel==1) object.style[style_name]=(parseFloat(object.style[style_name])+change).toString()+unit;
+				else 
+				{ 
+					remain=parseFloat(object.style[style_name])-to;
+					if(Math.abs(remain)>9||unit!="px") new_val=(to+accel*remain);
+					else {if(Math.abs(remain)<2) new_val=to;
+					else new_val=to+remain-(remain/Math.abs(remain));}
+					object.style[style_name]=new_val.toString()+unit;
+				}
+			}
+			else 
+				{object.style[style_name]=to.toString()+unit; window.clearInterval(object.anim_timer); delete object.anim_timer; }
+			if(to_exec!=0) to_exec();
+		},1000/fps);
+}
+
+function animate_to(object,style_name,unit,to,accel,time_ms,fps,to_exec)
+{
+	from=parseFloat(style_value(object,style_name));
+	animate(object,style_name,unit,from,to,accel,time_ms,fps,to_exec);
+}
+
+
+// ========================================================
+// ================  DEMODULATOR ROUTINES  ================
+// ========================================================
+
+demodulators=[]
+
+demodulator_color_index=0;
+demodulator_colors=["#ffff00", "#00ff00", "#00ffff", "#058cff", "#ff9600", "#a1ff39", "#ff4e39", "#ff5dbd"]
+function demodulators_get_next_color()
+{
+	if(demodulator_color_index>=demodulator_colors.length) demodulator_color_index=0;
+	return(demodulator_colors[demodulator_color_index++]);
+}
+
+function demod_envelope_draw(range, from, to, color, line)
+{  //                                               ____
+	// Draws a standard filter envelope like this: _/    \_
+   // Parameters are given in offset frequency (Hz).
+   // Envelope is drawn on the scale canvas.
+	// A "drag range" object is returned, containing information about the draggable areas of the envelope
+	// (beginning, ending and the line showing the offset frequency).
+	if(typeof color == "undefined") color="#ffff00"; //yellow
+	env_bounding_line_w=5;   //    
+	env_att_w=5;             //     _______   ___env_h2 in px   ___|_____
+	env_h1=17;               //   _/|      \_ ___env_h1 in px _/   |_    \_
+	env_h2=5;                //   |||env_att_line_w                |_env_lineplus
+	env_lineplus=1;          //   ||env_bounding_line_w
+	env_line_click_area=6;
+	//range=get_visible_freq_range();
+	from_px=scale_px_from_freq(from,range);
+	to_px=scale_px_from_freq(to,range);
+	if(to_px<from_px) /* swap'em */ { temp_px=to_px; to_px=from_px; from_px=temp_px; }
+	
+	/*from_px-=env_bounding_line_w/2;
+	to_px+=env_bounding_line_w/2;*/
+	from_px-=(env_att_w+env_bounding_line_w);
+	to_px+=(env_att_w+env_bounding_line_w); 
+	// do drawing:
+	scale_ctx.lineWidth=3;
+	scale_ctx.strokeStyle=color;
+	scale_ctx.fillStyle = color;
+	var drag_ranges={ envelope_on_screen: false, line_on_screen: false };
+	if(!(to_px<0||from_px>window.innerWidth)) // out of screen?
+	{
+		drag_ranges.beginning={x1:from_px, x2: from_px+env_bounding_line_w+env_att_w};
+		drag_ranges.ending={x1:to_px-env_bounding_line_w-env_att_w, x2: to_px};
+		drag_ranges.whole_envelope={x1:from_px, x2: to_px};
+		drag_ranges.envelope_on_screen=true;
+		scale_ctx.beginPath();
+		scale_ctx.moveTo(from_px,env_h1);
+		scale_ctx.lineTo(from_px+env_bounding_line_w, env_h1);
+		scale_ctx.lineTo(from_px+env_bounding_line_w+env_att_w, env_h2);
+		scale_ctx.lineTo(to_px-env_bounding_line_w-env_att_w, env_h2);
+		scale_ctx.lineTo(to_px-env_bounding_line_w, env_h1);
+		scale_ctx.lineTo(to_px, env_h1);
+		scale_ctx.globalAlpha = 0.3;
+		scale_ctx.fill();
+		scale_ctx.globalAlpha = 1;
+		scale_ctx.stroke();
+	}
+	if(typeof line != "undefined") // out of screen? 
+	{
+		line_px=scale_px_from_freq(line,range);
+		if(!(line_px<0||line_px>window.innerWidth))
+		{
+			drag_ranges.line={x1:line_px-env_line_click_area/2, x2: line_px+env_line_click_area/2};
+			drag_ranges.line_on_screen=true;
+			scale_ctx.moveTo(line_px,env_h1+env_lineplus);
+			scale_ctx.lineTo(line_px,env_h2-env_lineplus);
+			scale_ctx.stroke();
+		}
+	}
+	return drag_ranges;
+}
+
+function demod_envelope_where_clicked(x, drag_ranges, key_modifiers)
+{  // Check exactly what the user has clicked based on ranges returned by demod_envelope_draw().
+	in_range=function(x,range) { return range.x1<=x&&range.x2>=x; }
+	dr=demodulator.draggable_ranges;
+
+	if(key_modifiers.shiftKey)
+	{
+		//Check first: shift + center drag emulates BFO knob
+		if(drag_ranges.line_on_screen&&in_range(x,drag_ranges.line)) return dr.bfo;
+		//Check second: shift + envelope drag emulates PBF knob
+		if(drag_ranges.envelope_on_screen&&in_range(x,drag_ranges.whole_envelope)) return dr.pbs;
+	}
+	if(drag_ranges.envelope_on_screen)
+	{ 
+		// For low and high cut:
+		if(in_range(x,drag_ranges.beginning)) return dr.beginning;
+		if(in_range(x,drag_ranges.ending)) return dr.ending;
+		// Last priority: having clicked anything else on the envelope, without holding the shift key
+		if(in_range(x,drag_ranges.whole_envelope)) return dr.anything_else; 
+	}
+	return dr.none; //User doesn't drag the envelope for this demodulator
+}
+
+//******* class demodulator *******
+// this can be used as a base class for ANY demodulator
+demodulator=function(offset_frequency)
+{
+	//console.log("this too");
+	this.offset_frequency=offset_frequency;
+	this.has_audio_output=true;
+	this.has_text_output=false;
+	this.envelope={};
+	this.color=demodulators_get_next_color();
+	this.stop=function(){};
+}
+//ranges on filter envelope that can be dragged:
+demodulator.draggable_ranges={none: 0, beginning:1 /*from*/, ending: 2 /*to*/, anything_else: 3, bfo: 4 /*line (while holding shift)*/, pbs: 5 } //to which parameter these correspond in demod_envelope_draw()
+
+//******* class demodulator_default_analog *******
+// This can be used as a base for basic audio demodulators.
+// It already supports most basic modulations used for ham radio and commercial services: AM/FM/LSB/USB
+
+demodulator_response_time=100; 
+//in ms; if we don't limit the number of SETs sent to the server, audio will underrun (possibly output buffer is cleared on SETs in GNU Radio
+
+function demodulator_default_analog(offset_frequency,subtype)
+{
+	//console.log("hopefully this happens");
+	//http://stackoverflow.com/questions/4152931/javascript-inheritance-call-super-constructor-or-use-prototype-chain
+	demodulator.call(this,offset_frequency);
+	this.subtype=subtype;
+	this.filter={
+		min_passband: 100,
+		high_cut_limit: audio_context.sampleRate/2,
+		low_cut_limit: -audio_context.sampleRate/2
+	};
+	//Subtypes only define some filter parameters and the mod string sent to server, 
+	//so you may set these parameters in your custom child class.
+	//Why? As of demodulation is done on the server, difference is mainly on the server side.
+	this.server_mod=subtype;
+	if(subtype=="lsb")
+	{
+		this.low_cut=-3000;
+		this.high_cut=-300;
+		this.server_mod="ssb";
+	}
+	else if(subtype=="usb")
+	{
+		this.low_cut=300;
+		this.high_cut=3000;
+		this.server_mod="ssb";
+	}
+	else if(subtype=="cw")
+	{
+		this.low_cut=700;
+		this.high_cut=900;
+		this.server_mod="ssb";
+	} 
+	else if(subtype=="nfm")
+	{
+		this.low_cut=-4000;
+		this.high_cut=4000;
+	}	
+	else if(subtype=="am")
+	{
+		this.low_cut=-4000;
+		this.high_cut=4000;
+	}	
+
+	this.wait_for_timer=false;
+	this.set_after=false;
+	this.set=function()
+	{ //set() is a wrapper to call doset(), but it ensures that doset won't execute more frequently than demodulator_response_time.
+		if(!this.wait_for_timer) 
+		{
+			this.doset(false);
+			this.set_after=false;
+			this.wait_for_timer=true;
+			timeout_this=this; //http://stackoverflow.com/a/2130411
+			window.setTimeout(function() {
+				timeout_this.wait_for_timer=false;
+				if(timeout_this.set_after) timeout_this.set();
+			},demodulator_response_time);
+		}
+		else
+		{
+			this.set_after=true;
+		}
+	}
+
+	this.doset=function(first_time)
+	{  //this function sends demodulator parameters to the server
+		ws.send("SET"+((first_time)?" mod="+this.server_mod:"")+
+			" low_cut="+this.low_cut.toString()+" high_cut="+this.high_cut.toString()+
+			" offset_freq="+this.offset_frequency.toString());
+	}
+	this.doset(true); //we set parameters on object creation
+
+	//******* envelope object *******
+   // for drawing the filter envelope above scale
+	this.envelope.parent=this;
+
+	this.envelope.draw=function(visible_range) 
+	{
+		this.visible_range=visible_range;
+		this.drag_ranges=demod_envelope_draw(range,
+				center_freq+this.parent.offset_frequency+this.parent.low_cut,
+				center_freq+this.parent.offset_frequency+this.parent.high_cut,
+				this.color,center_freq+this.parent.offset_frequency);
+	};
+
+	// event handlers
+	this.envelope.drag_start=function(x, key_modifiers)
+	{
+		this.key_modifiers=key_modifiers;
+		this.dragged_range=demod_envelope_where_clicked(x,this.drag_ranges, key_modifiers);
+		//console.log("dragged_range: "+this.dragged_range.toString());
+		this.drag_origin={
+			x: x,
+			low_cut: this.parent.low_cut,
+			high_cut: this.parent.high_cut,
+			offset_frequency: this.parent.offset_frequency
+		};
+		return this.dragged_range!=demodulator.draggable_ranges.none;
+	};
+
+	this.envelope.drag_move=function(x)
+	{
+		dr=demodulator.draggable_ranges;
+		if(this.dragged_range==dr.none) return false; // we return if user is not dragging (us) at all
+		freq_change=Math.round(this.visible_range.hps*(x-this.drag_origin.x));
+		/*if(this.dragged_range==dr.beginning||this.dragged_range==dr.ending)
+		{
+			//we don't let the passband be too small
+			if(this.parent.low_cut+new_freq_change<=this.parent.high_cut-this.parent.filter.min_passband) this.freq_change=new_freq_change;
+			else return;
+		}
+		var new_value;*/
+
+		//dragging the line in the middle of the filter envelope while holding Shift does emulate
+		//the BFO knob on radio equipment: moving offset frequency, while passband remains unchanged
+		//Filter passband moves in the opposite direction than dragged, hence the minus below.
+		minus=(this.dragged_range==dr.bfo)?-1:1;
+		//dragging any other parts of the filter envelope while holding Shift does emulate the PBS knob
+		//(PassBand Shift) on radio equipment: PBS does move the whole passband without moving the offset
+		//frequency.
+		if(this.dragged_range==dr.beginning||this.dragged_range==dr.bfo||this.dragged_range==dr.pbs) 
+		{
+			//we don't let low_cut go beyond its limits
+			if((new_value=this.drag_origin.low_cut+minus*freq_change)<this.parent.filter.low_cut_limit) return true;
+			//nor the filter passband be too small
+			if(this.parent.high_cut-new_value<this.parent.filter.min_passband) return true; 
+			//sanity check to prevent GNU Radio "firdes check failed: fa <= fb"
+			if(new_value>=this.parent.high_cut) return true;
+			this.parent.low_cut=new_value;
+		}
+		if(this.dragged_range==dr.ending||this.dragged_range==dr.bfo||this.dragged_range==dr.pbs) 
+		{
+			//we don't let high_cut go beyond its limits
+			if((new_value=this.drag_origin.high_cut+minus*freq_change)>this.parent.filter.high_cut_limit) return true;
+			//nor the filter passband be too small
+			if(new_value-this.parent.low_cut<this.parent.filter.min_passband) return true; 
+			//sanity check to prevent GNU Radio "firdes check failed: fa <= fb"
+			if(new_value<=this.parent.low_cut) return true;
+			this.parent.high_cut=new_value;
+		}
+		if(this.dragged_range==dr.anything_else||this.dragged_range==dr.bfo)
+		{
+			//when any other part of the envelope is dragged, the offset frequency is changed (whole passband also moves with it)
+			new_value=this.drag_origin.offset_frequency+freq_change;
+			if(new_value>bandwidth/2||new_value<-bandwidth/2) return true; //we don't allow tuning above Nyquist frequency :-)
+			this.parent.offset_frequency=new_value;
+		}
+		//now do the actual modifications:
+		mkenvelopes(this.visible_range);
+		this.parent.set();
+		//will have to change this when changing to multi-demodulator mode:
+		e("webrx-actual-freq").innerHTML=format_frequency("{x} MHz",center_freq+this.parent.offset_frequency,1e6,4); 
+		return true;
+	};
+	
+	this.envelope.drag_end=function(x)
+	{ //in this demodulator we've already changed values in the drag_move() function so we shouldn't do too much here.
+		to_return=this.dragged_range!=demodulator.draggable_ranges.none; //this part is required for cliking anywhere on the scale to set offset
+		this.dragged_range=demodulator.draggable_ranges.none;
+		return to_return;
+	};
+	
+}
+
+demodulator_default_analog.prototype=new demodulator();
+
+function mkenvelopes(visible_range) //called from mkscale
+{
+	scale_ctx.clearRect(0,0,scale_ctx.canvas.width,22); //clear the upper part of the canvas (where filter envelopes reside)
+	for (var i=0;i<demodulators.length;i++)
+	{
+		demodulators[i].envelope.draw(visible_range);
+	}
+}
+
+function demodulator_remove(which)
+{
+	demodulators[which].stop();
+	demodulators.splice(which,1);
+}
+
+function demodulator_add(what)
+{
+	demodulators.push(what);
+	mkenvelopes(get_visible_freq_range());
+}
+
+function demodulator_analog_replace(subtype)
+{ //this function should only exist until the multi-demodulator capability is added	
+	var temp_offset=0;
+	if(demodulators.length) 
+	{
+		temp_offset=demodulators[0].offset_frequency;
+		demodulator_remove(0);
+	}
+	demodulator_add(new demodulator_default_analog(temp_offset,subtype));
+}
+
+function demodulator_set_offset_frequency(which,to_what)
+{
+	if(to_what>bandwidth/2||to_what<-bandwidth/2) return;
+	demodulators[0].offset_frequency=Math.round(to_what);
+	demodulators[0].set();
+	mkenvelopes(get_visible_freq_range());
+}
+
+
+// ========================================================
+// ===================  SCALE ROUTINES  ===================
+// ========================================================
+
+var scale_ctx;
+var scale_canvas;
+
+function scale_setup()
+{
+	e("webrx-actual-freq").innerHTML=format_frequency("{x} MHz",canvas_get_frequency(window.innerWidth/2),1e6,4);
+	scale_canvas=e("openwebrx-scale-canvas");	
+	scale_ctx=scale_canvas.getContext("2d");
+	scale_canvas.addEventListener("mousedown", scale_canvas_mousedown, false);
+	scale_canvas.addEventListener("mousemove", scale_canvas_mousemove, false);
+	scale_canvas.addEventListener("mouseup", scale_canvas_mouseup, false);
+	resize_scale();
+}
+
+var scale_canvas_drag_params={
+	mouse_down: false,
+	drag: false,
+	start_x: 0,
+	key_modifiers: {shiftKey:false, altKey: false, ctrlKey: false}
+};
+
+function scale_canvas_mousedown(evt)
+{
+	with(scale_canvas_drag_params)
+	{
+		mouse_down=true;
+		drag=false;
+		start_x=evt.pageX;
+		key_modifiers.shiftKey=evt.shiftKey;
+		key_modifiers.altKey=evt.altKey;
+		key_modifiers.ctrlKey=evt.ctrlKey;
+	}
+	evt.preventDefault();
+}
+
+function scale_offset_freq_from_px(x, visible_range)
+{
+	if(typeof visible_range === "undefined") visible_range=get_visible_freq_range();
+	return (visible_range.start+visible_range.bw*(x/canvas_container.clientWidth))-center_freq;
+}
+
+function scale_canvas_mousemove(evt)
+{
+	var event_handled;
+	if(scale_canvas_drag_params.mouse_down&&!scale_canvas_drag_params.drag&&Math.abs(evt.pageX-scale_canvas_drag_params.start_x)>canvas_drag_min_delta) 
+	//we can use the main drag_min_delta thing of the main canvas
+	{
+		scale_canvas_drag_params.drag=true;
+		//call the drag_start for all demodulators (and they will decide if they're dragged, based on X coordinate)
+		for (var i=0;i<demodulators.length;i++) event_handled|=demodulators[i].envelope.drag_start(evt.pageX,scale_canvas_drag_params.key_modifiers);
+		scale_canvas.style.cursor="move";
+	}
+	else if(scale_canvas_drag_params.drag)
+	{
+		//call the drag_move for all demodulators (and they will decide if they're dragged)
+		for (var i=0;i<demodulators.length;i++) event_handled|=demodulators[i].envelope.drag_move(evt.pageX);
+		if (!event_handled) demodulator_set_offset_frequency(0,scale_offset_freq_from_px(evt.pageX));
+	}
+	
+}
+
+function scale_canvas_end_drag(x)
+{
+	canvas_container.style.cursor="default";
+	scale_canvas_drag_params.drag=false;
+	scale_canvas_drag_params.mouse_down=false;
+	var event_handled=false;
+	for (var i=0;i<demodulators.length;i++) event_handled|=demodulators[i].envelope.drag_end(x);
+	//console.log(event_handled);
+	if (!event_handled) demodulator_set_offset_frequency(0,scale_offset_freq_from_px(x));
+}
+
+function scale_canvas_mouseup(evt)
+{
+	scale_canvas_end_drag(evt.pageX);
+}
+
+function scale_px_from_freq(f,range) { return Math.round(((f-range.start)/range.bw)*canvas_container.clientWidth); }
+
+function get_visible_freq_range()
+{
+	out={};
+	fcalc=function(x) { return Math.round(((-zoom_offset_px+x)/canvases[0].clientWidth)*bandwidth)+(center_freq-bandwidth/2); }
+	out.start=fcalc(0);
+	out.center=fcalc(canvas_container.clientWidth/2);
+	out.end=fcalc(canvas_container.clientWidth);
+	out.bw=out.end-out.start;
+	out.hps=out.bw/canvas_container.clientWidth;
+	return out;
+}
+
+var scale_markers_levels=[
+	{
+		"large_marker_per_hz":10000000, //large
+		"estimated_text_width":70,
+		"format":"{x} MHz",
+		"pre_divide":1000000,
+		"decimals":0
+	},
+	{
+		"large_marker_per_hz":5000000,
+		"estimated_text_width":70,
+		"format":"{x} MHz",
+		"pre_divide":1000000,
+		"decimals":0
+	},
+	{
+		"large_marker_per_hz":1000000,
+		"estimated_text_width":70,
+		"format":"{x} MHz",
+		"pre_divide":1000000,
+		"decimals":0
+	},
+	{
+		"large_marker_per_hz":500000,
+		"estimated_text_width":70,
+		"format":"{x} MHz",
+		"pre_divide":1000000,
+		"decimals":1
+	},
+	{
+		"large_marker_per_hz":100000,
+		"estimated_text_width":70,
+		"format":"{x} MHz",
+		"pre_divide":1000000,
+		"decimals":1
+	},
+	{
+		"large_marker_per_hz":50000,
+		"estimated_text_width":70,
+		"format":"{x} MHz",
+		"pre_divide":1000000,
+		"decimals":2
+	},
+	{
+		"large_marker_per_hz":10000,
+		"estimated_text_width":70,
+		"format":"{x} MHz",
+		"pre_divide":1000000,
+		"decimals":2
+	},
+	{
+		"large_marker_per_hz":5000,
+		"estimated_text_width":70,
+		"format":"{x} MHz",
+		"pre_divide":1000000,
+		"decimals":3
+	},
+	{
+		"large_marker_per_hz":1000,
+		"estimated_text_width":70,
+		"format":"{x} MHz",
+		"pre_divide":1000000,
+		"decimals":1
+	}
+];
+var scale_min_space_bw_texts=50;
+var scale_min_space_bw_small_markers=7;
+
+function get_scale_mark_spacing(range)
+{
+	out={};
+	fcalc=function(freq) 
+	{ 
+		out.numlarge=(range.bw/freq);
+		out.large=canvas_container.clientWidth/out.numlarge; 	//distance between large markers (these have text)
+		out.ratio=5; 														//(ratio-1) small markers exist per large marker
+		out.small=out.large/out.ratio; 								//distance between small markers
+		if(out.small<scale_min_space_bw_small_markers) return false; 
+		if(out.small/2>=scale_min_space_bw_small_markers&&freq.toString()[0]!="5") {out.small/=2; out.ratio*=2; }
+		out.smallbw=freq/out.ratio;
+		return true;
+	}
+	for(i=scale_markers_levels.length-1;i>=0;i--)
+	{
+		mp=scale_markers_levels[i];
+		if (!fcalc(mp.large_marker_per_hz)) continue;
+		//console.log(mp.large_marker_per_hz);
+		//console.log(out);
+		if (out.large-mp.estimated_text_width>scale_min_space_bw_texts) break;
+	}
+	out.params=mp;
+	return out;
+}
+
+function mkscale()
+{
+	//clear the lower part of the canvas (where frequency scale resides; the upper part is used by filter envelopes):
+	range=get_visible_freq_range();
+	mkenvelopes(range); //when scale changes we will always have to redraw filter envelopes, too
+	scale_ctx.clearRect(0,22,scale_ctx.canvas.width,scale_ctx.canvas.height-22);
+	scale_ctx.strokeStyle = "#fff";
+	scale_ctx.font = "bold 11px sans-serif";
+	scale_ctx.textBaseline = "top";
+	scale_ctx.fillStyle = "#fff";
+	spacing=get_scale_mark_spacing(range);
+	//console.log(spacing);
+	marker_hz=Math.ceil(range.start/spacing.smallbw)*spacing.smallbw;
+	var text_to_draw;
+	var ftext=function(f) {text_to_draw=format_frequency(spacing.params.format,f,spacing.params.pre_divide,spacing.params.decimals);}
+	var last_large;
+	for(;;)
+	{
+		var x=scale_px_from_freq(marker_hz,range);
+		if(x>window.innerWidth) break;
+		scale_ctx.beginPath();		
+		scale_ctx.moveTo(x, 22);
+		if(marker_hz%spacing.params.large_marker_per_hz==0)
+		{  //large marker
+			if(typeof first_large == "undefined") var first_large=marker_hz; 
+			last_large=marker_hz;
+			scale_ctx.lineWidth=3.5;
+			scale_ctx.lineTo(x,22+11);
+			ftext(marker_hz);
+			var text_measured=scale_ctx.measureText(text_to_draw);
+			scale_ctx.textAlign = "center";
+			//advanced text drawing begins
+			if(zoom_level==0&&range.start+spacing.smallbw*spacing.ratio>marker_hz)
+			{ //if this is the first overall marker when zoomed out
+				if(x<text_measured.width/2)
+				{ //and if it would be clipped off the screen
+					if(scale_px_from_freq(marker_hz+spacing.smallbw*spacing.ratio,range)-text_measured.width>=scale_min_space_bw_texts)
+					{ //and if we have enough space to draw it correctly without clipping
+						scale_ctx.textAlign = "left";
+						scale_ctx.fillText(text_to_draw, 0, 22+10); 
+					}
+				}
+			}
+			else if(zoom_level==0&&range.end-spacing.smallbw*spacing.ratio<marker_hz)  
+			{ //if this is the last overall marker when zoomed out
+				if(x>window.innerWidth-text_measured.width/2) 
+				{ //and if it would be clipped off the screen
+					if(window.innerWidth-text_measured.width-scale_px_from_freq(marker_hz-spacing.smallbw*spacing.ratio,range)>=scale_min_space_bw_texts)
+					{ //and if we have enough space to draw it correctly without clipping
+						scale_ctx.textAlign = "right";
+						scale_ctx.fillText(text_to_draw, window.innerWidth, 22+10); 
+					}	
+				}		
+			}
+			else scale_ctx.fillText(text_to_draw, x, 22+10); //draw text normally
+		}
+		else
+		{  //small marker
+			scale_ctx.lineWidth=2;
+			scale_ctx.lineTo(x,22+8);
+		}
+		marker_hz+=spacing.smallbw;
+		scale_ctx.stroke();
+	}
+	if(zoom_level!=0)
+	{ // if zoomed, we don't want the texts to disappear because their markers can't be seen
+		// on the left side
+		scale_ctx.textAlign = "center";
+		var f=first_large-spacing.smallbw*spacing.ratio;
+		var x=scale_px_from_freq(f,range);
+		ftext(f);
+		var w=scale_ctx.measureText(text_to_draw).width;
+		if(x+w/2>0) scale_ctx.fillText(text_to_draw, x, 22+10);
+		// on the right side
+		f=last_large+spacing.smallbw*spacing.ratio;
+		x=scale_px_from_freq(f,range);
+		ftext(f);
+		w=scale_ctx.measureText(text_to_draw).width;
+		if(x-w/2<window.innerWidth) scale_ctx.fillText(text_to_draw, x, 22+10);
+	}
+}
+
+function resize_scale()
+{
+	scale_ctx.canvas.width  = window.innerWidth;
+	scale_ctx.canvas.height = 47;
+	mkscale();
+}
+
+function canvas_mouseover(evt)
+{
+	if(!waterfall_setup_done) return;
+	//e("webrx-freq-show").style.visibility="visible";	
+}
+
+function canvas_mouseout(evt)
+{
+	if(!waterfall_setup_done) return;
+	//e("webrx-freq-show").style.visibility="hidden";
+}
+
+function canvas_get_freq_offset(relativeX)
+{
+	rel=(relativeX/canvases[0].clientWidth);
+	return Math.round((bandwidth*rel)-(bandwidth/2));
+}
+
+function canvas_get_frequency(relativeX)
+{
+	return center_freq+canvas_get_freq_offset(relativeX);
+}
+
+/*function canvas_format_frequency(relativeX)
+{
+	return (canvas_get_frequency(relativeX)/1e6).toFixed(3)+" MHz";
+}*/
+
+function format_frequency(format, freq_hz, pre_divide, decimals)
+{
+	out=format.replace("{x}",(freq_hz/pre_divide).toFixed(decimals));
+	at=out.indexOf(".")+4;
+	while(decimals>3)
+	{
+		out=out.substr(0,at)+","+out.substr(at);
+		at+=4;
+		decimals-=3;
+	}
+	return out;
+}
+
+canvas_drag=false;
+canvas_drag_min_delta=1;
+canvas_mouse_down=false;
+
+function canvas_mousedown(evt)
+{
+	canvas_mouse_down=true;
+	canvas_drag=false;
+	canvas_drag_last_x=canvas_drag_start_x=evt.pageX;
+	canvas_drag_last_y=canvas_drag_start_y=evt.pageY;
+	evt.preventDefault(); //don't show text selection mouse pointer
+}
+
+function canvas_mousemove(evt)
+{
+	if(!waterfall_setup_done) return;
+	//element=e("webrx-freq-show");
+	relativeX=(evt.offsetX)?evt.offsetX:evt.layerX;
+	/*realX=(relativeX-element.clientWidth/2);
+	maxX=(canvases[0].clientWidth-element.clientWidth);
+	if(realX>maxX) realX=maxX;
+	if(realX<0) realX=0;
+	element.style.left=realX.toString()+"px";*/
+	if(canvas_mouse_down)
+	{
+		if(!canvas_drag&&Math.abs(evt.pageX-canvas_drag_start_x)>canvas_drag_min_delta) 
+		{
+			canvas_drag=true;
+			canvas_container.style.cursor="move";
+		}
+		if(canvas_drag) 
+		{
+			var deltaX=canvas_drag_last_x-evt.pageX;
+			var deltaY=canvas_drag_last_y-evt.pageY;
+			//zoom_center_where=zoom_center_where_calc(evt.pageX);
+			var dpx=range.hps*deltaX;			
+			if(
+				!(zoom_center_rel+dpx>(bandwidth/2-canvas_container.clientWidth*(1-zoom_center_where)*range.hps)) &&
+				!(zoom_center_rel+dpx<-bandwidth/2+canvas_container.clientWidth*zoom_center_where*range.hps)
+			) { zoom_center_rel+=dpx; }
+//			-((canvases_new_width*(0.5+zoom_center_rel/bandwidth))-(winsize*zoom_center_where));
+			resize_canvases(false);
+			canvas_drag_last_x=evt.pageX;
+			canvas_drag_last_y=evt.pageY;
+			mkscale();
+		}
+	}
+	else e("webrx-mouse-freq").innerHTML=format_frequency("{x} MHz",canvas_get_frequency(relativeX),1e6,4);
+}
+
+function canvas_container_mouseout(evt)
+{
+	canvas_end_drag();
+}
+
+//function body_mouseup() { canvas_end_drag(); console.log("body_mouseup"); }
+//function window_mouseout() { canvas_end_drag(); console.log("document_mouseout"); }
+
+function canvas_mouseup(evt)
+{
+	if(!waterfall_setup_done) return;
+	relativeX=(evt.offsetX)?evt.offsetX:evt.layerX;
+
+	if(!canvas_drag) 
+	{
+		//ws.send("SET offset_freq="+canvas_get_freq_offset(relativeX).toString());
+		//e("webrx-actual-freq").innerHTML=format_frequency("{x} MHz",canvas_get_frequency(relativeX),1e6,4);
+		 demodulator_set_offset_frequency(0, canvas_get_freq_offset(relativeX));		
+	}
+	else
+	{
+		canvas_end_drag();
+	}
+	canvas_mouse_down=false;
+}
+
+function canvas_end_drag()
+{
+	canvas_container.style.cursor="crosshair";
+	canvas_mouse_down=false;
+}
+
+function zoom_center_where_calc(screenposX)
+{
+	//return (screenposX-(window.innerWidth-canvas_container.clientWidth))/canvas_container.clientWidth;
+	return screenposX/canvas_container.clientWidth;
+}
+
+function canvas_mousewheel(evt)
+{
+	if(!waterfall_setup_done) return;
+	var i=Math.abs(evt.wheelDelta);
+	var dir=(i/evt.wheelDelta)<0;
+	var relativeX=(evt.offsetX)?evt.offsetX:evt.layerX;
+	i/=120;
+	while (i--) zoom_step(dir, relativeX, zoom_center_where_calc(evt.pageX));
+	evt.preventDefault();	
+	//evt.returnValue = false; //disable scrollbar move
+}
+
+
+zoom_max_level_hps=33; //Hz/pixel
+zoom_levels_count=5;
+
+function get_zoom_coeff_from_hps(hps)
+{
+	var shown_bw=(window.innerWidth*hps);
+	return bandwidth/shown_bw;
+}
+
+zoom_levels=[1];
+zoom_level=0;
+zoom_freq=0;
+zoom_offset_px=0;
+zoom_center_rel=0;
+zoom_center_where=0;
+
+function mkzoomlevels()
+{
+	zoom_levels=[1];
+	maxc=get_zoom_coeff_from_hps(zoom_max_level_hps);
+	if(maxc<1) return;
+	for(i=1;i<zoom_levels_count;i++)
+		zoom_levels.push(1+(maxc-1)*(i/(zoom_levels_count-1)));
+}
+
+function zoom_step(out, where, onscreen)
+{
+	if((out&&zoom_level==0)||(!out&&zoom_level>=zoom_levels_count-1)) return;
+	
+	if(out) --zoom_level;
+	else ++zoom_level;
+	zoom_center_rel=canvas_get_freq_offset(where);
+	//console.log("zoom_step || zlevel: "+zoom_level.toString()+" zlevel_val: "+zoom_levels[zoom_level].toString()+" zoom_center_rel: "+zoom_center_rel.toString());
+	zoom_center_where=onscreen;
+	resize_canvases(true);
+	mkscale();
+}
+
+function zoom_calc()
+{
+	winsize=canvas_container.clientWidth;
+	var canvases_new_width=winsize*zoom_levels[zoom_level];
+	zoom_offset_px=-((canvases_new_width*(0.5+zoom_center_rel/bandwidth))-(winsize*zoom_center_where));
+	if(zoom_offset_px>0) zoom_offset_px=0;
+	if(zoom_offset_px<winsize-canvases_new_width) 
+		zoom_offset_px=winsize-canvases_new_width;
+	//console.log("zoom_calc || zopx:"+zoom_offset_px.toString()+ " maxoff:"+(winsize-canvases_new_width).toString()+" relval:"+(0.5+zoom_center_rel/bandwidth).toString() );
+}
+
+function resize_waterfall_container(check_init)
+{
+	if(check_init&&!waterfall_setup_done) return;
+	canvas_container.style.height=(window.innerHeight-e("webrx-top-container").clientHeight-e("openwebrx-scale-container").clientHeight).toString()+"px";
+}
+
+
+function on_ws_recv(evt)
+{
+	/*var f = new FileReader();
+   f.onload = function(e) {
+   	//alert(e.target.result);
+	};
+	f.readAsText(evt.data);*/
+   if(!(evt.data instanceof ArrayBuffer))
+   { divlog("on_ws_recv(): Not ArrayBuffer received...",1); return; }
+	stringData=arrayBufferToString(evt.data);
+	firstChars=stringData.substring(0,3);
+	//alert(firstChars);
+	if(firstChars=="CLI" && stringData.substring(0,16)=="CLIENT DE SERVER")
+		divlog("Acknowledged WebSocket connection: "+stringData);
+	if(firstChars=="AUD")
+	{
+		audio_received[audio_received.length] = new Int16Array(evt.data,4);
+		var audio_recv_len=audio_received[audio_received.length-1].length;
+		//console.log("on_ws_recv() :: recv: "+audio_recv_len.toString());
+		audio_buffer_current_size_debug+=audio_recv_len;
+		audio_buffer_current_size+=audio_recv_len;
+		if(audio_initialized==0 && audio_received.length>10) audio_init()
+	}
+	else if(firstChars=="FFT")
+	{
+		//alert("Yupee! Doing FFT");
+		var floatArray = new Float32Array(evt.data,4);
+		waterfall_add_queue(floatArray);
+	} else if(firstChars=="MSG")
+	{
+		/*try
+		{*/
+			params=stringData.substring(4).split(" ");
+			for(i=0;i<params.length;i++)
+			{
+				param=params[i].split("=");
+				switch(param[0])
+				{
+					case "setup":
+						waterfall_init();
+						break;					
+					case "bandwidth":
+						bandwidth=parseInt(param[1])
+						break;		
+					case "center_freq":
+						center_freq=parseInt(param[1])
+						break;
+					case "fft_size":
+						fft_size=parseInt(param[1])
+						break;
+					case "fft_fps":
+						fft_fps=parseInt(param[1])
+						break;
+
+				}
+			}
+		/*}
+		catch(err)
+		{
+			divlog("Received invalid message over WebSocket.");
+		}*/
+	}
+
+}
+
+function add_problem(what)
+{
+	problems_span=e("openwebrx-problems");
+	for(var i=0;i<problems_span.children.length;i++) if(problems_span.children[i].innerHTML==what) return;
+	new_span = document.createElement("span");
+	new_span.innerHTML=what;
+	problems_span.appendChild(new_span);
+	window.setTimeout(function(ps,ns) {  ps.removeChild(ns); }, 1000,problems_span,new_span);
+}
+
+function waterfall_add_queue(what)
+{
+	waterfall_queue.push(what);
+}
+
+function waterfall_dequeue()
+{
+	if(waterfall_queue.length) waterfall_add(waterfall_queue.shift());
+	if(waterfall_queue.length>fft_fps/2) //in case of emergency 
+	{
+		add_problem("fft overflow");
+		while(waterfall_queue.length) waterfall_add(waterfall_queue.shift());
+	}
+}
+
+function on_ws_opened()
+{
+	ws.send("SERVER DE CLIENT openwebrx.js");
+	divlog("WebSocket opened to "+ws_url);
+}
+
+function divlog(what, is_error)
+{
+	if(typeof is_error !== undefined && is_error == 1) what="<span class=\"webrx-error\">"+what+"</span>";
+	e("openwebrx-debugdiv").innerHTML+=what+"<br />";
+}
+
+var audio_context;
+var audio_initialized=0;
+
+var audio_received = Array();
+var audio_buffer_index = 0;
+var audio_resampler;
+var audio_node;
+//var audio_received_sample_rate = 48000;
+var audio_input_buffer_size;
+
+// Optimalise these if audio lags or is choppy:
+var audio_buffer_size = 8192;//2048 was choppy
+var audio_buffer_maximal_length_sec=2; //actual number of samples are calculated from sample rate
+var audio_flush_interval_ms=250; //the interval in which audio_flush() is called
+
+function audio_onprocess(e) 
+{
+	//https://github.com/0xfe/experiments/blob/master/www/tone/js/sinewave.js
+	if(audio_received.length==0) 
+	{ add_problem("audio underrun"); return; }
+	output = e.outputBuffer.getChannelData(0);
+	int_buffer = audio_received[0];
+	read_remain = audio_buffer_size;
+	//audio_buffer_maximal_length=120;
+
+	obi=0; //output buffer index
+	debug_str=""
+	while(1)	
+	{
+		if(int_buffer.length-audio_buffer_index>read_remain)
+		{
+			for (i=audio_buffer_index; i<audio_buffer_index+read_remain; i++)
+				output[obi++] = int_buffer[i]/32768;
+			//debug_str+="added whole ibl="+int_buffer.length.toString()+" abi="+audio_buffer_index.toString()+" "+(int_buffer.length-audio_buffer_index).toString()+">"+read_remain.toString()+" obi="+obi.toString()+"\n";
+			audio_buffer_index+=read_remain;
+			break;
+		}
+		else
+		{	
+			for (i=audio_buffer_index; i<int_buffer.length; i++)
+				output[obi++] = int_buffer[i]/32768;
+			read_remain-=(int_buffer.length-audio_buffer_index);
+			audio_buffer_current_size-=audio_received[0].length;
+			/*if (audio_received.length>audio_buffer_maximal_length)
+			{
+				add_problem("audio overrun");
+				audio_received.splice(0,audio_received.length-audio_buffer_maximal_length);
+			}
+			else*/
+				audio_received.splice(0,1);
+			//debug_str+="added remain, remain="+read_remain.toString()+" abi="+audio_buffer_index.toString()+" alen="+int_buffer.length.toString()+" i="+i.toString()+" arecva="+audio_received.length.toString()+" obi="+obi.toString()+"\n";
+			audio_buffer_index = 0;			
+			if(audio_received.length == 0 || read_remain == 0) return;
+			int_buffer = audio_received[0];
+		}
+	}
+	//debug_str+="obi="+obi.toString();
+	//alert(debug_str);
+}
+
+function audio_flush()
+{
+	if (audio_buffer_current_size>audio_buffer_maximal_length_sec*audio_context.sampleRate)
+	{ 
+		add_problem("audio overrun");
+		console.log("audio_flush() :: size: "+audio_buffer_current_size.toString()+" allowed: "+(audio_buffer_maximal_length_sec*audio_context.sampleRate).toString());
+		while (audio_buffer_current_size>audio_buffer_maximal_length_sec*audio_context.sampleRate*0.5)
+		{
+			audio_buffer_current_size-=audio_received[0].length;
+			audio_received.splice(0,1);
+		}
+	}
+	
+}
+
+function webrx_set_param(what, value)
+{
+	ws.send("SET "+what+"="+value.toString());
+}
+
+function audio_init()
+{
+	//https://github.com/0xfe/experiments/blob/master/www/tone/js/sinewave.js
+	audio_initialized=1; // only tell on_ws_recv() not to call it again
+	try 
+	{
+		window.AudioContext = window.AudioContext||window.webkitAudioContext;
+		audio_context = new AudioContext();
+	}
+	catch(e) 
+	{
+		divlog('Your browser does not support Web Audio API, which is required for WebRX to run. Please upgrade to a HTML5 compatible browser.', 1);
+	}
+	audio_node = audio_context.createJavaScriptNode(audio_buffer_size, 0, 1);
+	audio_node.onaudioprocess = audio_onprocess;
+	audio_node.connect(audio_context.destination);
+	// --- Resampling ---	
+	//https://github.com/grantgalitz/XAudioJS/blob/master/XAudioServer.js
+	//audio_resampler = new Resampler(audio_received_sample_rate, audio_context.sampleRate, 1, audio_buffer_size, true);
+	//audio_input_buffer_size = audio_buffer_size*(audio_received_sample_rate/audio_context.sampleRate);
+	webrx_set_param("audio_rate",audio_context.sampleRate); //Don't try to resample
+	window.setInterval(audio_flush,audio_flush_interval_ms);
+	divlog('Web Audio API succesfully initialized, sample rate: '+audio_context.sampleRate.toString());
+	/*audio_source=audio_context.createBufferSource();
+   audio_buffer = audio_context.createBuffer(xhr.response, false);
+	audio_source.buffer = buffer;
+	audio_source.noteOn(0);*/
+	demodulator_analog_replace('nfm'); //needs audio_context.sampleRate to exist
+}
+
+function on_ws_closed()
+{
+	try
+	{ 	
+		audio_node.disconnect();
+	}
+	catch (dont_care) {}
+	divlog("WebSocket has closed unexpectedly. Please reload the page.", 1);
+}
+
+function on_ws_error(event)
+{
+	divlog(event.toString(),1);
+}
+
+function open_websocket()
+{
+	if (!("WebSocket" in window)) 
+		divlog("Your browser does not support WebSocket, which is required for WebRX to run. Please upgrade to a HTML5 compatible browser.");
+	ws = new WebSocket(ws_url+client_id);
+	ws.onopen = on_ws_opened;
+	ws.onmessage = on_ws_recv;
+	ws.onclose = on_ws_closed;
+	ws.binaryType = "arraybuffer";
+	window.onbeforeunload = function() { //http://stackoverflow.com/questions/4812686/closing-websocket-correctly-html5-javascript
+		ws.onclose = function () {};
+		ws.close();
+	};
+	//ws.onerror = on_ws_error;
+}
+
+//var color_scale=[0xFFFFFFFF, 0x000000FF];
+//var color_scale=[0x000000FF, 0x000000FF, 0x3a0090ff, 0x10c400ff, 0xffef00ff, 0xff5656ff];
+//var color_scale=[0x000000FF, 0x000000FF, 0x534b37ff, 0xcedffaff, 0x8899a9ff,  0xfff775ff, 0xff8a8aff, 0xb20000ff];
+var color_scale=[0x2e6893ff, 0x69a5d0ff, 0x214b69ff, 0x9dc4e0ff,  0xfff775ff, 0xff8a8aff, 0xb20000ff];
+//var color_scale=[ 0x000000FF, 0xff5656ff, 0xffffffff];
+
+function waterfall_mkcolor(db_value)
+{
+	min_value=-100; //in dB
+	max_value=10
+	if(db_value<min_value) db_value=min_value
+	if(db_value>max_value) db_value=max_value
+	full_scale=max_value-min_value;
+	relative_value=db_value-min_value;
+	value_percent=relative_value/full_scale;
+	percent_for_one_color=1/(color_scale.length-1);
+	index=Math.floor(value_percent/percent_for_one_color);
+	remain=(value_percent-percent_for_one_color*index)/percent_for_one_color;
+	return color_between(color_scale[index+1],color_scale[index],remain);
+}
+
+function color_between(first, second, percent)
+{
+	output=0;
+	for(i=0;i<4;i++)
+	{
+		add = ((((first&(0xff<<(i*8)))>>>0)*percent) + (((second&(0xff<<(i*8)))>>>0)*(1-percent))) & (0xff<<(i*8));
+		output |= add>>>0;
+	}
+	return output>>>0;
+}
+
+
+var canvas_context;
+var canvases = [];
+var canvas_default_height = 200;
+var canvas_container;
+var canvas_phantom;
+
+function add_canvas()
+{	
+	new_canvas = document.createElement("canvas");
+	new_canvas.width=fft_size;
+	new_canvas.height=canvas_default_height;
+	canvas_actual_line=canvas_default_height-1;
+	new_canvas.style.width=(canvas_container.clientWidth*zoom_levels[zoom_level]).toString()+"px";	
+	new_canvas.style.left=zoom_offset_px.toString()+"px";
+	new_canvas.style.height=canvas_default_height.toString()+"px";
+	new_canvas.openwebrx_top=(-canvas_default_height+1);	
+	new_canvas.style.top=new_canvas.openwebrx_top.toString()+"px";
+	canvas_context = new_canvas.getContext("2d");
+	canvas_container.appendChild(new_canvas);
+	new_canvas.addEventListener("mouseover", canvas_mouseover, false);
+	new_canvas.addEventListener("mouseout", canvas_mouseout, false);
+	new_canvas.addEventListener("mousemove", canvas_mousemove, false);
+	new_canvas.addEventListener("mouseup", canvas_mouseup, false);
+	new_canvas.addEventListener("mousedown", canvas_mousedown, false);
+	new_canvas.addEventListener("mousewheel",canvas_mousewheel, false);
+	canvases.push(new_canvas);
+}
+
+function init_canvas_container()
+{
+	canvas_container=e("webrx-canvas-container");
+	canvas_container.addEventListener("mouseout",canvas_container_mouseout, false);
+	//window.addEventListener("mouseout",window_mouseout,false);
+	//document.body.addEventListener("mouseup",body_mouseup,false);
+	canvas_phantom=e("openwebrx-phantom-canvas");
+	canvas_phantom.addEventListener("mouseover", canvas_mouseover, false);
+	canvas_phantom.addEventListener("mouseout", canvas_mouseout, false);
+	canvas_phantom.addEventListener("mousemove", canvas_mousemove, false);
+	canvas_phantom.addEventListener("mouseup", canvas_mouseup, false);
+	canvas_phantom.addEventListener("mousedown", canvas_mousedown, false);
+	canvas_phantom.addEventListener("mousewheel",canvas_mousewheel, false);
+	canvas_phantom.style.width=canvas_container.clientWidth+"px";
+	add_canvas();
+}
+
+canvas_maxshift=0;
+
+function shift_canvases()
+{
+	canvases.forEach(function(p) 
+	{
+		p.style.top=(p.openwebrx_top++).toString()+"px";
+	});
+	canvas_maxshift++;
+	if(canvas_container.clientHeight>canvas_maxshift)
+	{
+		canvas_phantom.style.top=canvas_maxshift.toString()+"px";
+		canvas_phantom.style.height=(canvas_container.clientHeight-canvas_maxshift).toString()+"px";
+		canvas_phantom.style.display="block";
+	}
+	else
+		canvas_phantom.style.display="none";
+	
+	
+	//canvas_container.style.height=(((canvases.length-1)*canvas_default_height)+(canvas_default_height-canvas_actual_line)).toString()+"px";
+	//canvas_container.style.height="100%";
+}
+
+function resize_canvases(zoom)
+{
+	if(typeof zoom == "undefined") zoom=false;
+	if(!zoom) mkzoomlevels();
+	zoom_calc();
+	new_width=(canvas_container.clientWidth*zoom_levels[zoom_level]).toString()+"px";
+	var zoom_value=zoom_offset_px.toString()+"px";
+	canvases.forEach(function(p) 
+	{
+		p.style.width=new_width;
+		p.style.left=zoom_value;
+	});
+	canvas_phantom.style.width=new_width;
+	canvas_phantom.style.left=zoom_value;
+}
+
+function waterfall_init()
+{
+	init_canvas_container();
+	waterfall_timer = window.setInterval(waterfall_dequeue,900/fft_fps);
+	resize_waterfall_container(false); /* then */ resize_canvases();
+	scale_setup();
+	mkzoomlevels();
+	waterfall_setup_done=1;
+}
+
+var waterfall_dont_scale=0;
+
+function waterfall_add(data)
+{
+	if(!waterfall_setup_done) return;
+	var w=fft_size;
+
+	//waterfall_shift();
+	// ==== do scaling if required ====
+	/*if(waterfall_dont_scale)
+	{
+		scaled=data;
+		for(i=scaled.length;i<w;i++) scaled[i]=-100;
+	}
+	else
+	{
+		if ((to-from)==w)
+		{
+			scaled=data;
+		}
+		else if ((to-from)<w)
+		{	//make line bigger
+			pixel_per_point=w/(to-from);
+			scaled=Array();
+			j=0;
+			remain=pixel_per_point;
+			for(i=0; i<w; i++)
+			{
+				//thiscolor=data[j]*(remain-floor(remain))+data[j+1]*(1-(remain-floor(remain)))
+				//nextcolor=data[j+1]*(remain-floor(remain))+data[j+2]*(1-(remain-floor(remain)))
+				if(remain>1)
+				{
+					scaled[i]=data[j]*(remain/pixel_per_point)+data[j+1]*((1-remain)/pixel_per_point);
+					remain--;
+				}
+				else
+				{
+					j++;
+					scaled[i]=data[j]*(remain/pixel_per_point)+data[j+1]*((1-remain)/pixel_per_point);
+					remain=pixel_per_point-(1-remain);
+				}
+			}
+		
+		}
+		else
+		{  //make line smaller (linear decimation, moving average)
+			point_per_pixel=(to-from)/w;
+			scaled=Array();
+			j=0;
+			remain=point_per_pixel;
+			last_pixel=0;
+			for(i=from; i<to; i++)
+			{
+				if(remain>1)
+				{
+					last_pixel+=data[i];	
+					remain--;
+				}
+				else
+				{
+					last_pixel+=data[i]*remain;
+					scaled[j++]=last_pixel/point_per_pixel;
+					last_pixel=data[i]*(1-remain);
+					remain=point_per_pixel-(1-remain); //?
+				}
+			}
+		}
+	}
+
+	//Add line to waterfall image			
+	base=(h-1)*w*4;		
+	for(x=0;x<w;x++)
+	{
+		color=waterfall_mkcolor(scaled[x]);
+		for(i=0;i<4;i++)
+			waterfall_image.data[base+x*4+i] = ((color>>>0)>>((3-i)*8))&0xff;
+	}*/
+
+	//Add line to waterfall image			
+	oneline_image = canvas_context.createImageData(w,1);
+	for(x=0;x<w;x++)
+	{
+		color=waterfall_mkcolor(data[x]);
+		for(i=0;i<4;i++)
+			oneline_image.data[x*4+i] = ((color>>>0)>>((3-i)*8))&0xff;
+	}
+
+
+	//Draw image
+	canvas_context.putImageData(oneline_image, 0, canvas_actual_line--);
+	shift_canvases();
+	if(canvas_actual_line<0) add_canvas();
+	//divlog("Drawn FFT");
+}
+
+/*
+function waterfall_shift()
+{
+	w=canvas.width;
+	h=canvas.height;
+	for(y=0; y<h-1; y++)
+	{
+		for(i=0; i<w*4; i++)
+			waterfall_image.data[y*w*4+i] = waterfall_image.data[(y+1)*w*4+i];
+	}
+}*/
+
+function check_top_bar_congestion()
+{
+	var wt=e("webrx-rx-title");
+	var tl=e("webrx-ha5kfu-top-logo");
+	if(wt.offsetLeft+wt.offsetWidth>tl.offsetLeft-20) tl.style.display="none";
+	else tl.style.display="block";
+}
+
+function webrx_resize() 
+{
+	resize_canvases();
+	resize_waterfall_container(true);
+	resize_scale();
+	check_top_bar_congestion();
+}
+
+function webrx_init()
+{
+	init_rx_photo();
+	open_websocket();
+	place_panels();
+	window.setInterval(debug_audio,1000);
+}
+
+/*
+window.setInterval(function(){ 
+	sum=0;
+	for(i=0;i<audio_received.length;i++)
+		sum+=audio_received[i].length;
+	divlog("audio buffer bytes: "+sum);
+}, 2000);*/
+
+/*function email(what)
+{
+	//| http://stackoverflow.com/questions/617647/where-is-my-one-line-implementation-of-rot13-in-javascript-going-wrong
+	what=what.replace(/[a-zA-Z]/g,function(c){return String.fromCharCode((c<="Z"?90:122)>=(c=c.charCodeAt(0)+13)?c:c-26);});
+	window.location.href="mailto:"+what;
+}*/
+
+var rt = function (s,n) {return s.replace(/[a-zA-Z]/g,function(c){return String.fromCharCode((c<="Z"?90:122)>=(c=c.charCodeAt(0)+n)?c:c-26);});}
+var irt = function (s,n) {return s.replace(/[a-zA-Z]/g,function(c){return String.fromCharCode((c>="a"?97:65)<=(c=c.charCodeAt(0)-n)?c:c+26);});}
+var sendmail2 = function (s) { window.location.href="mailto:"+irt(s.replace("=",String.fromCharCode(0100)).replace("$","."),8); }
+
+function debug_audio()
+{
+
+	e("openwebrx-audio-sps").innerHTML=audio_buffer_current_size_debug.toString();
+	audio_buffer_current_size_debug=0;
+}
+
+// ========================================================
+// =======================  PANELS  =======================
+// ========================================================
+
+panel_margin=10;
+
+function pop_bottommost_panel(from)
+{
+	min_order=parseInt(from[0].dataset.panelOrder);
+	min_index=0;
+	for(i=0;i<from.length;i++)	
+	{
+		actual_order=parseInt(from[i].dataset.panelOrder);
+		if(actual_order<min_order) 
+		{
+			min_index=i;
+			min_order=actual_order;
+		}
+	}
+	to_return=from[min_index];
+	from.splice(min_index,1);
+	return to_return;
+}
+
+function place_panels()
+{
+	var left_col=[];
+	var right_col=[];
+	var plist=e("openwebrx-panels-container").children;
+	for(i=0;i<plist.length;i++)
+	{
+		c=plist[i];
+		if(c.className=="openwebrx-panel")
+		{
+			newSize=c.dataset.panelSize.split(",");
+			if (c.dataset.panelPos=="left") { left_col.push(c); }
+			else if(c.dataset.panelPos=="right") { right_col.push(c); }
+			c.style.width=newSize[0]+"px";
+			c.style.height=newSize[1]+"px";
+			c.style.margin=panel_margin.toString()+"px";
+			c.openwebrxPanelWidth=parseInt(newSize[0]);			
+			c.openwebrxPanelHeight=parseInt(newSize[1]);
+		}
+	}
+	y=0;
+	while(left_col.length>0)
+	{
+		p=pop_bottommost_panel(left_col);
+		p.style.left="0px";
+		p.style.bottom=y.toString()+"px";
+		p.style.visibility="visible";
+		y+=p.openwebrxPanelHeight+3*panel_margin;
+	}
+	y=0;
+	while(right_col.length>0)
+	{
+		p=pop_bottommost_panel(right_col);
+		p.style.right="10px";
+		p.style.bottom=y.toString()+"px";
+		p.style.visibility="visible";
+		y+=p.openwebrxPanelHeight+3*panel_margin;
+	}
+}
+
diff --git a/htdocs/upgrade.html b/htdocs/upgrade.html
new file mode 100644
index 0000000000000000000000000000000000000000..b9a498d7cfd30fef532eb899b7812824c8ecfc53
--- /dev/null
+++ b/htdocs/upgrade.html
@@ -0,0 +1,93 @@
+<html>
+<!--
+OpenWebRX (c) Copyright 2013 Andras Retzler <ha7ilm@sdr.hu>
+
+This file is part of OpenWebRX.
+
+    OpenWebRX is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenWebRX is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenWebRX. If not, see <http://www.gnu.org/licenses/>.
+-->
+<head><title>OpenWebRX</title><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<style>
+html, body
+{
+	font-family: "DejaVu Sans", Verdana, Geneva, sans-serif;
+	width: 100%;
+	text-align: center;
+	margin: 0;
+	padding: 0;
+}
+img.logo
+{ 
+	margin-top: 120px;
+}
+div.frame
+{
+	text-align: left;
+	margin:0px auto;
+	width: 800px;
+}
+
+div.panel
+{
+	text-align: center;
+	background-color:#777777; 
+	border-radius: 15px;
+	padding: 12px;
+	font-weight: bold;
+	color: White;
+	font-size: 13pt;
+	/*text-shadow: 1px 1px 4px #444;*/
+	font-family: sans;
+}
+
+div.alt
+{
+	font-size: 10pt;
+	padding-top: 10px;
+}
+
+
+body div a
+{
+	color: #5ca8ff;
+	text-shadow: none;
+}
+
+span.browser
+{
+}
+
+</style>
+<script>
+var irt = function (s,n) {return s.replace(/[a-zA-Z]/g,function(c){return String.fromCharCode((c>="a"?97:65)<=(c=c.charCodeAt(0)-n)?c:c+26);});}
+var sendmail2 = function (s) { window.location.href="mailto:"+irt(s.replace("=",String.fromCharCode(0100)).replace("$","."),8); }
+</script>
+
+</head>
+<body>
+
+<div class="frame">
+	<img class="logo" src="gfx/openwebrx-logo-big.png" style="height: 60px;"/>
+	<div class="panel">
+		Only the latest <span class="browser">Google Chrome</span> browser is supported at the moment.<br/>
+		Please <a href="http://chrome.google.com/">download and install Google Chrome.</a><br />
+		<div class="alt">
+			Alternatively, you may proceed to OpenWebRX, but it's not supposed to work as expected. <br />
+			<a href="/?unsupported">Click here</a> if you still want to try OpenWebRX.</a>
+		</div>
+	</div>
+</div>
+</body>
+</html>
+
diff --git a/lwebrx b/lwebrx
new file mode 100755
index 0000000000000000000000000000000000000000..cdf0c2598f8e0107428d22213767bb5f777c2d99
--- /dev/null
+++ b/lwebrx
@@ -0,0 +1,7 @@
+#!/bin/bash
+#sudo rmmod dvb_usb_rtl28xxu
+#sudo killall -9 rtl_tcp
+while true; do python openwebrx.py; done
+#echo "Quit at:"
+#date
+#sudo killall -9 rtl_tcp
diff --git a/openwebrx.py b/openwebrx.py
new file mode 100755
index 0000000000000000000000000000000000000000..89a9d27ab02bab757f4c3e3ec2d74278a69f57b4
--- /dev/null
+++ b/openwebrx.py
@@ -0,0 +1,467 @@
+
+"""
+OpenWebRX: open-source web based SDR for everyone!
+
+This file is part of OpenWebRX.
+
+    OpenWebRX is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenWebRX is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+
+Authors:
+    Andras Retzler, HA7ILM <retzlerandras@gmail.com>
+
+"""
+
+# http://www.codeproject.com/Articles/462525/Simple-HTTP-Server-and-Client-in-Python
+# some ideas are used from the artice above
+
+import grcconvert
+import os
+import code
+import importlib
+
+regexp_for_grcconvert=((r"def __init__\(self\):",r"def __init__(self,sample_rate_param): # added by grcconvert"),(r"self.samp_rate = samp_rate = ([0-9]*)","self.samp_rate = samp_rate = sample_rate_param # added by grcconvert"))
+
+demods=[]
+import demod
+for subdir in os.listdir("demod"):
+	if os.path.isdir("demod/"+subdir) and not subdir[0]=="_":
+		exact_path="demod/"+subdir+"/top_block.py"
+		if os.path.isfile(exact_path):
+			grcconvert.main(exact_path,regexp_for_grcconvert)
+			if(subdir!="spectrum"): demods.append(subdir)
+			importlib.import_module("demod."+subdir+".top_block")
+			#setattr(demod, subdir, __import__("demod."+subdir))
+
+import thread
+import time
+import subprocess
+import os 
+from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
+from SocketServer import ThreadingMixIn
+import fcntl
+import time
+import md5
+import random
+import threading
+import dl
+import sys
+import traceback
+from collections import namedtuple
+import Queue
+
+#import rtl_mus
+import rxws
+import uuid
+import config_webrx
+
+class MultiThreadHTTPServer(ThreadingMixIn, HTTPServer):
+    pass 
+
+def main():
+	global clients
+	global clients_mutex
+	global server_hostname
+	global web_port
+	global config_webrx
+	global admin_param_dict
+
+	try:
+		for libcpath in ["/lib/i386-linux-gnu/libc.so.6","/lib/libc.so.6"]:
+			if os.path.exists(libcpath):
+				libc = dl.open(libcpath)
+				libc.call("prctl", 15, "openwebrx-sdr", 0, 0, 0)
+				break
+	except:
+		pass
+
+	#Configuration
+	config_file=open("config_webrx.py","r")
+	config_lines=config_file.readlines()
+	config_changed=0
+	admin_pw_md5=""
+	for i in range(0,len(config_lines)):
+		if(config_lines[i][:17]=="receiver_token=\"\""):
+			my_uid=str(uuid.uuid4()).replace("-","")
+			config_lines[i]="receiver_token=\""+my_uid+"\" # generated on the first run\n"
+			config_changed=1
+			print "[openwebrx-main] New receiver token generated and written into config_webrx.py: "+my_uid
+		elif(config_lines[i][:24]=="change_admin_password_to" and config_lines[i][27:28]!="\"\""):
+			line_parts=config_lines[i].split("\"")
+			admin_pw_md5=md5.md5(line_parts[1]).hexdigest()
+			config_lines[i]=line_parts[0]+"\"\""+line_parts[2]
+			print "[openwebrx-main] New admin password md5 hashed."
+		elif(config_lines[i][:19]=="admin_password_md5=" and config_lines[i][27:28]!="\"\""):
+			if admin_pw_md5!="":
+				config_lines[i]="admin_password_md5=\""+admin_pw_md5+"\"\n"
+				config_changed=1
+			print "[openwebrx-main] Old md5 hash replaced."
+	if(config_changed): 
+		config_file.close()
+		config_file=open("config_webrx.py","w")
+		config_file.writelines(config_lines)
+		config_file.close()
+		print "[openwebrx-main] Changes have been written to config_webrx.py"
+	config_webrx=__import__("config_webrx")
+
+	admin_param_dict=config_webrx.admin_param_dict
+	print admin_param_dict, "main"
+	
+	if config_webrx.start_rtl_thread:
+		rtl_tcp_thread=threading.Thread(target = lambda:subprocess.Popen(config_webrx.start_rtl_tcp_command, shell=True), args=())
+		rtl_tcp_thread.start()
+		print "[openwebrx-main] Started rtl_tcp thread: "+config_webrx.start_rtl_tcp_command
+	
+	#rtl_mus.cfg=__import__("config_rtl")
+	#rtl_mus_thread=threading.Thread(target = rtl_mus.main, args = ())
+	#rtl_mus_thread.start()
+	rtl_mus_thread=threading.Thread(target = lambda:subprocess.Popen("python rtl_mus.py config_rtl", shell=True), args=())
+	rtl_mus_thread.start() # The new feature in GNU Radio 3.7: top_block() locks up ALL python threads until it gets the TCP connection.
+	print "[openwebrx-main] Started rtl_mus"
+
+	clients=[]
+	clients_mutex=threading.Lock()
+
+	print "[openwebrx-main] Starting spectrum thread. (You should get another message about success, or the program has hanged up.)"
+	spectrum_thread=threading.Thread(target = spectrum_thread_function, args = ())
+	spectrum_thread.start()
+	
+	#threading.Thread(target = measure_thread_function, args = ()).start()
+	
+	httpd = MultiThreadHTTPServer(('', config_webrx.web_port), WebRXHandler)
+	print('[openwebrx-main] Starting HTTP server.')
+	httpd.serve_forever()
+
+
+# This is a debug function below:
+measure_value=0
+def measure_thread_function():
+	global measure_value
+	while True:	
+		print "[openwebrx-measure] value is",measure_value
+		measure_value=0
+		time.sleep(1)
+
+
+def spectrum_thread_function():
+	global clients_mutex
+	global clients
+	tb=demod.spectrum.top_block.top_block(admin_param_dict["samp_rate"])
+	tb.set_fps(config_webrx.fft_fps)
+	tb.set_fft_size(config_webrx.fft_size)
+	sleep_sec=0.87/config_webrx.fft_fps
+	print "[openwebrx-spectrum] Spectrum thread initialized successfully." 
+	tb.start()
+	print "[openwebrx-spectrum] Spectrum thread started." 
+	while True:
+		data=tb.msgq_out.delete_head().to_string()
+		#print "gotcha",len(data),"bytes of spectrum data via spectrum_thread_function()"
+		clients_mutex.acquire()
+		for i in range(0,len(clients)):
+			if (clients[i].ws_started):
+				if clients[i].spectrum_queue.full():
+					close_client(i, False)
+				else:
+					clients[i].spectrum_queue.put([data]) # add new string by "reference" to all clients
+		clients_mutex.release()
+	
+def get_client_by_id(client_id, use_mutex=True):
+	global clients_mutex
+	global clients
+	output=-1
+	if use_mutex: clients_mutex.acquire()
+	for i in range(0,len(clients)):
+		if(clients[i].id==client_id):
+			output=i
+			break
+	if use_mutex: clients_mutex.release()
+	if output==-1:
+		raise ClientNotFoundException
+	else:
+		return output
+
+def log_client(client, what):
+	print "[openwebrx-httpd] client {0}#{1} :: {2}".format(client.ip,client.id,what)
+
+def cleanup_clients():
+	# if client doesn't open websocket for too long time, we drop it
+	global clients_mutex
+	global clients
+	clients_mutex.acquire()
+	correction=0
+	for i in range(0,len(clients)):
+		i-=correction
+		#print "cleanup_clients:: len(clients)=", len(clients), "i=", i
+		if (not clients[i].ws_started) and (time.time()-clients[i].gen_time)>180:
+			close_client(i, False)
+			correction+=1
+	clients_mutex.release()
+
+def generate_client_id(ip):
+	#add a client
+	global clients
+	global clients_mutex
+	new_client=namedtuple("ClientStruct", "id gen_time ws_started sprectum_queue ip")	
+	new_client.id=md5.md5(str(random.random())).hexdigest()
+	new_client.gen_time=time.time()
+	new_client.ws_started=False # to check whether client has ever tried to open the websocket
+	new_client.spectrum_queue=Queue.Queue(1000)
+	new_client.ip=ip
+	clients_mutex.acquire()
+	clients.append(new_client)
+	log_client(new_client,"client added. Clients now: {0}".format(len(clients)))
+	clients_mutex.release()
+	cleanup_clients()
+	return new_client.id
+
+def close_client(i, use_mutex=True):
+	global clients_mutex
+	global clients
+	log_client(clients[i],"client being closed.")
+	if use_mutex: clients_mutex.acquire()
+	del clients[i]
+	if use_mutex: clients_mutex.release()
+	
+class WebRXHandler(BaseHTTPRequestHandler):    
+	def proc_read_thread():
+		pass
+
+	def do_GET(self):
+		print "does GET"
+		global admin_param_dict
+		rootdir = 'htdocs' 
+		self.path=self.path.replace("..","")
+		path_temp_parts=self.path.split("?")
+		self.path=path_temp_parts[0]
+		request_param=path_temp_parts[1] if(len(path_temp_parts)>1) else "" 
+		try:
+			if self.path=="/":
+				self.path="/index.wrx"
+			# there's even another cool tip at http://stackoverflow.com/questions/4419650/how-to-implement-timeout-in-basehttpserver-basehttprequesthandler-python
+			if self.path[:4]=="/ws/":
+				try:
+					try:				
+						rxws.handshake(self)
+						clients_mutex.acquire()				
+						client_i=get_client_by_id(self.path[4:], False)
+						myclient=clients[client_i]
+						clients_mutex.release()
+					except WebSocketException:
+						self.send_error(400, 'Bad request.')
+						return
+					except ClientNotFoundException:
+						self.send_error(400, 'Bad request.')
+						return
+					modulation="null"
+					#tb=client_ssb.top_block.top_block()
+					#tb.start()
+					#data=tb.msgq_out.delete_head().to_string()
+					data=""
+					rxws.send(self, "CLIENT DE SERVER openwebrx.py")
+					client_ans=rxws.recv(self, True)
+					if client_ans[:16]!="SERVER DE CLIENT":
+						rxws.send("ERR Bad answer.")
+						return
+					myclient.ws_started=True
+					rxws.send(self, "MSG center_freq={0} bandwidth={1} fft_size={2} fft_fps={3} setup".format(str(admin_param_dict["center_freq"]),str(admin_param_dict["samp_rate"]),config_webrx.fft_size,config_webrx.fft_fps))
+					session_param_dict={ "offset_freq":(0,0,0), "audio_rate":(44100,0,48000), "low_cut":(-4000,-8000,8000), "high_cut":(4000,-8000,8000) }
+					while True:
+						if modulation!="null":
+							rxws.send(self, tb.msgq_out.delete_head().to_string(), "AUD ")
+						else:
+							print "modulation is null, didn't send audio"
+						while not myclient.spectrum_queue.empty():
+							spectrum_data=myclient.spectrum_queue.get()
+							spectrum_data_mid=len(spectrum_data[0])/2
+							rxws.send(self, spectrum_data[0][spectrum_data_mid:]+spectrum_data[0][:spectrum_data_mid], "FFT ") 
+							# (it seems GNU Radio exchanges the first and second part of the FFT output, we correct it)					
+						while True:				
+							if modulation=="null":
+								rdata="SET mod=nfm"
+							else:
+								rdata=rxws.recv(self, False)
+							if not rdata: break
+							#try:
+							if rdata[:3]=="GET":
+								if rdata=="GET info":
+									for key,val in admin_param_dict.iteritems():
+										print key,"=",getattr(tb, "get_"+key)(),"| should be",val
+									for key,val in session_param_dict.iteritems():
+										print key,"=",getattr(tb, "get_"+key)(),"| should be",val[0]
+							elif rdata[:3]=="SET":
+								print rdata
+								pairs=rdata[4:].split(" ")
+								for pair in pairs:
+									param_name, param_value = pair.split("=")
+									if param_name in admin_param_dict: #TODO check if admin
+										setter_method = getattr(tb, "set_"+param_name)
+										setter_method(int(param_value))
+										admin_param_dict[param_name]=int(param_value)
+									elif param_name in session_param_dict:
+										pval=int(param_value)
+										pbefore, pmin, pmax = session_param_dict[param_name]
+										if (pmax==0 and pmin==0) or (pval>=pmin and pval<=pmax):
+											if param_name=="low_cut" and pval>=tb.get_high_cut(): 
+												tb.set_high_cut(tb.get_demod_rate()/2-1)
+												print "saved the wold today (lc); set_high_cut =",tb.get_demod_rate()/2-1
+											elif param_name=="high_cut" and pval<=tb.get_low_cut(): 
+												tb.set_low_cut(-tb.get_demod_rate()/2+1)
+												print "saved the wold today (hc); set_low_cut =",-tb.get_demod_rate()/2+1
+											setter_method = getattr(tb, "set_"+param_name)
+											setter_method(pval)
+											session_param_dict[param_name]=(pval,pmin,pmax)
+									elif param_name=="mod":
+										if modulation!="null":
+											tb.stop()
+										invalid_modulation=0
+										if param_value in demods:
+											tb=getattr(demod, param_value).top_block.top_block(admin_param_dict["samp_rate"]) 
+											# you don't have any chance to set decimation rate in frequency_xlating_... block after having called
+											# top_block(), so I solved this by adding samplerate (of which decimation rate is calculated) 
+											# as a parameter to top_block()
+										else:
+											print "ERR invalid modulation =", param_value
+											invalid_modulation=1
+										if not invalid_modulation:
+											modulation=param_value
+										#code.interact(local=locals())
+										tb.set_low_cut(-tb.get_demod_rate()/2+1)
+										tb.set_high_cut(tb.get_demod_rate()/2-1)
+										for key,val in admin_param_dict.iteritems():
+											print key, val, "anew demod set"
+											setter_method = getattr(tb, "set_"+key)
+											setter_method(val)
+										for key,val in session_param_dict.iteritems():
+											print key, val[0], "new demod set"
+											if key+"=" in rdata: continue
+											setter_method = getattr(tb, "set_"+key)
+											print tb.low_cut, tb.high_cut, tb.demod_rate
+											setter_method(val[0])
+										tb.start() #tried tb.start(768) but is caused audio lagging sometimes
+									else:
+										print "[openwebrx-httpd:ws] invalid parameter"
+				except:
+					exc_type, exc_value, exc_traceback = sys.exc_info()
+					if exc_value[0]==32: #"broken pipe", client disconnected
+						pass
+					elif exc_value[0]==11: #"resource unavailable" on recv, client disconnected					
+						pass
+					else:	
+						print "[openwebrx-httpd] error: ",exc_type,exc_value
+						traceback.print_tb(exc_traceback)
+				#delete disconnected client
+				try:
+					if modulation!="null": tb.stop()
+					del tb
+				except:
+					pass
+				clients_mutex.acquire()
+				id_to_close=get_client_by_id(myclient.id,False)
+				close_client(id_to_close,False)
+				clients_mutex.release()
+				return
+			else:
+				f=open(rootdir+self.path)
+				data=f.read()
+				extension=self.path[(len(self.path)-4):len(self.path)]
+				extension=extension[2:] if extension[1]=='.' else extension[1:]
+				if extension == "wrx" and (not self.headers['user-agent'].count("Chrome")) and (not request_param.count("unsupported")):
+					self.send_response(302)
+					self.send_header('Content-type','text/html')
+					self.send_header("Location", "http://{0}:{1}/upgrade.html".format(config_webrx.server_hostname,config_webrx.web_port))
+					self.end_headers()
+					self.wfile.write("<html><body><h1>Object moved</h1>Please <a href=\"/upgrade.html\">click here</a> to continue.</body></html>")
+					return
+				self.send_response(200)
+				if(("wrx","html","htm").count(extension)):
+					self.send_header('Content-type','text/html')
+				elif(extension=="js"):
+					self.send_header('Content-type','text/javascript')
+				elif(extension=="css"):
+					self.send_header('Content-type','text/css')
+				self.end_headers()
+				if extension == "wrx":
+					replace_dictionary=(("%[CLIENT_ID]",generate_client_id(self.client_address[0])),("%[WS_URL]","ws://"+config_webrx.server_hostname+":"+str(config_webrx.web_port)+"/ws/"),("%[RX_TITLE]",config_webrx.receiver_name),("%[RX_DESC]","{0} (Loc: {1}, ASL: {2} m)".format(config_webrx.receiver_location, config_webrx.receiver_qra, config_webrx.receiver_asl)),("%[RX_PHOTO_HEIGHT]",str(config_webrx.photo_height)),("%[RX_PHOTO_TITLE]",config_webrx.photo_title),("%[RX_PHOTO_DESC]",config_webrx.photo_desc))
+					for rule in replace_dictionary:
+						while data.find(rule[0])!=-1:
+							data=data.replace(rule[0],rule[1])
+				self.wfile.write(data)
+				f.close()
+			return
+		except IOError:
+			self.send_error(404, 'Invalid path.')
+
+
+
+class ClientNotFoundException(Exception):
+	pass
+
+if __name__=="__main__":
+	main()
+
+"""
+TODO
+- image decimate interpolate, implement as draw from-to
+- wget Web Audio API
+- javascript strings API
+- replace readAsText with blob and use that
+
+SET samplerate=48000&center=89500000&modulation=
+
+SET audio
+
+IDEAS
+resample.js
+auto-md5 admin passwd (lock icon for admin access)
+osmosdr_mus
+- both TCP and UCP
+- password
+GPU
+PREDICT
+Cloud Demodulator
+search freq by search bar on top
+the whole screen is fft
+animated photo of site on start
+sdr.hu/b
+play parts already played
+multi-demodulator
+demod implemented in JS
+PSK31/balloon decoder
+save last frequency and mode to cookie
+space invaders
+record audio html5
+rf history (x minutes)
+equalizer
+
+BUGS:
++ small window: white line under photo
++ clicking on canvas-container won't set frequency
+------
++ up arrow down arrow background transparent
++ small window: top bar congested
+- small window: panels congested
++ avatar
+- toggling photo on start will cause faulty animation
+- Spectrum history - button to rewind to pos 0 and restart live fft
+- Spectrum history - scrolled when looking at old signal
++ openwebrx-scale-container could go under panels
++ memory leak: eats memory
++ scale markers
++ spectrum pan
++ draw scale text corretly at edges
++ both zoom and pan fail to work on big screen
+- remember last freq used
+- rolling on scrollbar while panning stops pan operation
++ rtl_mus: ERROR client cache full
+- improve latency (http://nutaq.com/en/blog/configure-latency-gnu-radio
+"""
diff --git a/rtl_mus.py b/rtl_mus.py
new file mode 100755
index 0000000000000000000000000000000000000000..2c04572f65116f56f8faf9cc4ea74be12edd06c0
--- /dev/null
+++ b/rtl_mus.py
@@ -0,0 +1,326 @@
+'''
+This file is part of RTL Multi-User Server, 
+	that makes multi-user access to your DVB-T dongle used as an SDR.
+Copyright (c) 2013 Andras Retzler <retzlerandras@gmail.com>
+
+RTL Multi-User Server is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+RTL Multi-User Server is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with RTL Multi-User Server.  If not, see <http://www.gnu.org/licenses/>.
+'''
+
+import socket 
+import sys
+import array
+import time
+import logging
+import os
+import dl #[openwebrx]
+
+def ip_match(this,ip_ranges,for_allow):
+	if not len(ip_ranges):
+		return 1 #empty list matches all ip addresses 
+	for ip_range in ip_ranges:
+		#print this[0:len(ip_range)], ip_range # [openwebrx]
+		if this[0:len(ip_range)]==ip_range:
+			return 1
+	return 0
+
+def ip_access_control(ip):
+	if(not cfg.use_ip_access_control): return 1
+	allowed=0
+	if(cfg.order_allow_deny):
+		if ip_match(ip,cfg.allowed_ip_ranges,1): allowed=1
+		if ip_match(ip,cfg.denied_ip_ranges,0): allowed=0
+	else:
+		if ip_match(ip,cfg.denied_ip_ranges,0): # [openwebrx] removed print
+			allowed=0
+		if ip_match(ip,cfg.allowed_ip_ranges,1): # [openwebrx] removed print
+			allowed=1
+	return allowed
+		
+def rtl_tcp_connect(close=0):
+	global rtltcp_client_socket
+	global server_missing_logged
+	global rtl_dongle_identifier
+	if not server_missing_logged:
+		log.info("rtl_tcp host connection init: host=" + cfg.rtl_tcp_host + " port="+ str(cfg.rtl_tcp_port))
+	if close:
+		try:
+			rtltcp_client_socket.close()
+		except socket.error as err:
+			log.error("rtl_tcp host connection close: "+str(err[0])+" "+err[1])
+	rtltcp_client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+	try:
+		rtltcp_client_socket.connect((cfg.rtl_tcp_host, cfg.rtl_tcp_port))
+		rtl_dongle_identifier=rtltcp_client_socket.recv(12)
+		#rtl_tcp server sends us a 12 byte info on the dongle used at server init
+		#we'll send it to any clients connected to us
+		rtltcp_client_socket.send(cfg.send_first) # [openwebrx]	we can set to direct sampling here
+	except socket.error as err:
+		if not server_missing_logged:
+			log.error("rtl_tcp host connection: "+str(err[0])+" "+err[1])
+			server_missing_logged=1
+		return 0
+	rtltcp_client_socket.setblocking(1)	# this does the trick, this is the ONLY blocking IO used
+	rtltcp_client_socket.settimeout(3)
+	log.info("rtl_tcp host connection estabilished")
+	server_missing_logged=0
+	return 1
+
+def handle_command(command, client_id):
+	param=array.array("I", command[1:5])[0]
+	param=socket.ntohl(param)
+	command_id=ord(command[0])
+	client_info=str(client_id)+"@"+client_sockets[client_id][1][0]+":"+str(client_sockets[client_id][1][1])
+	if(time.time()-client_start_times[client_id]<cfg.client_cant_set_until):
+		log.info("deny: "+client_info+" -> client can't set anything until "+str(cfg.client_cant_set_until)+" seconds")
+		return 0
+	if command_id == 1:
+		if max(map((lambda r: param>=r[0] and param<=r[1]),cfg.freq_allowed_ranges)):
+			log.debug("allow: "+client_info+" -> set freq "+str(param))
+			return 1
+		else:
+			log.debug("deny: "+client_info+" -> set freq - out of range: "+str(param))
+	elif command_id == 2:
+		log.debug("deny: "+client_info+" -> set sample rate: "+str(param))
+		return 0 # ordinary clients are not allowed to do this
+	elif command_id == 3:
+		log.debug("deny/allow: "+client_info+" -> set gain mode: "+str(param))
+		return cfg.allow_gain_set # for ordinary clients auto-gain will be set
+	elif command_id == 4:
+		log.debug("deny/allow: "+client_info+" -> set gain: "+str(param))
+		return cfg.allow_gain_set  # for ordinary clients auto-gain will be set
+	elif command_id == 5:
+		log.debug("deny: "+client_info+" -> set freq correction: "+str(param))
+		return 0  # ordinary clients are not allowed to do this
+	elif command_id == 6:
+		log.debug("deny/allow: set if stage gain")
+		return cfg.allow_gain_set
+	elif command_id == 7:
+		log.debug("deny: set test mode")
+		return 0
+	elif command_id == 8:
+		log.debug("deny/allow: set agc mode")
+		return cfg.allow_gain_set
+	elif command_id == 9:
+		log.debug("deny: set direct sampling")
+		return 0
+	elif command_id == 10:
+		log.debug("deny: set offset tuning")
+		return 0
+	elif command_id == 11:
+		log.debug("deny: set rtl xtal")
+		return 0
+	elif command_id == 12:
+		log.debug("deny: set tuner xtal")
+		return 0
+	elif command_id == 13:
+		log.debug("deny/allow: set tuner gain by index")
+		return cfg.allow_gain_set
+	else:
+		log.debug("deny: "+client_info+" sent an ivalid command: "+str(param))
+	return 0
+
+def close_clients():
+	for which in client_indexes_to_close:
+		try:	
+			log.info("client disconnected: "+str(which)+"@"+client_sockets[which][1][0])
+			client_sockets[which][0].close()
+		except socket.error as err:
+			log.error("can't close client socket: "+ str(err[0])+" "+err[1])
+		except IndexError:
+			log.error("can't close client socket: weird IndexError")
+		
+		del client_sockets[which]
+		del client_waiting_data[which]
+		del client_start_times[which]
+
+#I might implement decimation later, but not this way. - Andris, HA7ILM
+'''
+def average(input_data,average_items):
+	if average_items==1 or len(input_data)==0:
+		return input_data
+	input_bytes=bytearray(input_data)
+	output_bytes=bytearray()	
+	j=0
+	averaged_i=0
+	averaged_q=0
+	i_or_q_sample=0
+	for i in range(0,len(input_data)):
+		if i_or_q_sample:
+			averaged_q+=input_bytes[i]
+		else:
+			averaged_i+=input_bytes[i]
+		if i_or_q_sample==0:
+			j+=1
+		if j>=average_items:
+			j=0
+			output_bytes.append(averaged_i/average_items)
+			output_bytes.append(averaged_q/average_items)
+			averaged_i=0
+			averaged_q=0
+		i_or_q_sample=~i_or_q_sample
+	return output_bytes
+'''
+
+def main():
+	global rtltcp_client_socket
+	global server_missing_logged
+	global rtl_dongle_identifier
+	global log
+	global client_indexes_to_close
+	global client_sockets
+	global client_start_times
+	global client_waiting_data
+	global command_send_errors
+
+	#[openwebrx]
+	try:
+		for libcpath in ["/lib/i386-linux-gnu/libc.so.6","/lib/libc.so.6"]:
+			if os.path.exists(libcpath):
+				libc = dl.open(libcpath)
+				libc.call("prctl", 15, "rtl_mus-sdr", 0, 0, 0)
+				break
+	except:
+		pass
+	#/[openwebrx]
+
+	# === Set up logging ===
+	log = logging.getLogger("rtl_mus")
+	log.setLevel(logging.DEBUG)
+	formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
+	stream_handler = logging.StreamHandler()
+	stream_handler.setLevel(logging.DEBUG)
+	stream_handler.setFormatter(formatter)
+	log.addHandler(stream_handler)
+	file_handler = logging.FileHandler(cfg.log_file_path)
+	file_handler.setLevel(logging.INFO)
+	file_handler.setFormatter(formatter)
+	log.addHandler(file_handler)
+	log.info("Server is UP")
+	server_missing_logged=0
+	rtl_dongle_identifier=''
+	rtl_tcp_connect()
+	my_listening_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+	my_listening_socket.bind((cfg.my_ip, cfg.my_listening_port))
+	my_listening_socket.listen(5)
+	my_listening_socket.setblocking(0)
+	log.info("server listening on port: "+str(cfg.my_listening_port))
+	client_sockets=[]
+	client_waiting_data=[]
+	client_start_times=[]
+	commands=''
+	command_send_errors=0
+
+	while 1:
+		#First we try to ACCEPT new connections
+		try:
+			temp_client_socket = my_listening_socket.accept() # we get [socket, address]
+			temp_client_socket[0].setblocking(0)
+			if(ip_access_control(temp_client_socket[1][0])):
+				client_sockets.append(temp_client_socket)
+				client_start_times.append(time.time())
+				client_waiting_data.append([])
+				temp_client_socket[0].send(rtl_dongle_identifier)
+				log.info("client accepted: "+str(len(client_sockets)-1)+"@"+temp_client_socket[1][0]+":"+str(temp_client_socket[1][1])+"  users now: "+str(len(client_sockets)))
+			else:
+				log.info("client denied: "+str(len(client_sockets)-1)+"@"+temp_client_socket[1][0]+":"+str(temp_client_socket[1][1])+" blocked by ip")
+				temp_client_socket[0].close()
+		except socket.error as err:
+			if err[0] != 11:
+				log.error("client accept(): "+str(err[0])+" "+err[1])
+
+		#We try to RECEIVE COMMANDS from our clients already connected
+		for client_id in range(len(client_sockets)):
+			client=client_sockets[client_id]
+			try:		
+				for i in range(1, 10): # we only take care of ten commands per loop from a client
+					new_command = client[0].recv(5) # this is because sizeof(struct command) is 5 in rtl_tcp.
+					if len(new_command)>=5:
+						if handle_command(new_command, client_id):		
+							commands+=new_command
+			except socket.error as err:
+				if err[0] != 11:
+					log.error("client recv(): "+str(err[0])+" "+err[1])
+
+		#We send the commands to the rtl_tcp server
+		if len(commands)>0:
+			try:
+				rtltcp_client_socket.send(commands)
+				command_send_errors=0
+				commands=''
+			except socket.error as err:
+				command_send_errors+=1
+				log.error("can't send command to RTL_TCP server, this happened",command_send_errors,"times continously.")
+			except msg:
+				log.error("rtl_tcp send(): "+msg) # might remove this	
+
+		#We get data from the rtl_tcp server	
+		new_data=''
+		try:
+			while len(new_data)<16348:
+				new_data+=rtltcp_client_socket.recv(1024)	# should do LPF and decimation here, if required for slower download speeds
+		except socket.error as err:
+			if err[0] != 11:   
+				log.error("socket - "+`err`) # Bugfix/Andris/2013-05-10 (Tuple index out of range)
+				while not rtl_tcp_connect(1):
+					time.sleep(1)
+		if(len(new_data)==0): continue #!
+		# print len(new_data), "bytes of data acquired from RTL_TCP server"
+
+		#We send data to all client sockets
+		client_indexes_to_close=[]
+		for client_i in range(0,len(client_sockets)):		
+			client=client_sockets[client_i]		
+			try:
+				waiting_data_len=0
+				if len(client_waiting_data[client_i]):
+					waiting_data_len=reduce((lambda x,y:x+y),map(len,client_waiting_data[client_i]))
+				if len(new_data)+waiting_data_len<cfg.buffer_size:
+					client_waiting_data[client_i].append(new_data) 
+					#http://itamarst.org/writings/pycon05/fast.html "Bad String Concatenation" was a cool tip
+				else:
+					log.error("client cache full: "+str(client_i)+"@"+client[1][0]+" now clearing cache")
+					client_waiting_data[client_i]=[new_data]
+					# print waiting_data_len, len(client_waiting_data[client_i])
+					client_indexes_to_close.append(client_i) # We rather clear cache and hope client to resync soon | [openwebrx] patched
+				while len(client_waiting_data[client_i]):
+					client[0].send(client_waiting_data[client_i][0]) # FIXME might be problems here if we do it in the wrong order
+					del client_waiting_data[client_i][0]
+				#print "info: client", client_i, "got", len(client_waiting_data[client_i]), "bytes"
+			except socket.error as err:
+				if(err[0]==32): # broken pipe
+					client_indexes_to_close.append(client_i)	
+				if(err[0]!=11):		
+					log.error("client send(): "+str(err[0])+" "+err[1])
+		close_clients()
+
+	rtltcp_client_socket.close()
+
+
+if __name__=="__main__":
+	print "RTL Multi-User Server v0.1a, made at HA5KFU Amateur Radio Club (http://ha5kfu.hu)"
+	print "    code by Andras Retzler, HA7ILM"
+	print "    distributed under GNU GPL v3"
+	print 
+	# === Load configuration script ===
+	if len(sys.argv)==1:
+		print "Warning! Configuration script not specified. I will use: \"config_rtl.py\""
+		config_script="config_rtl"
+	else:
+		config_script=sys.argv[1]
+	cfg=__import__(config_script)
+	# print "debug config allow gain set:", cfg.allow_gain_set # [openwebrx] removed print
+	if cfg.setuid_on_start:
+		os.setuid(cfg.uid)
+	main()
+
diff --git a/rxws.py b/rxws.py
new file mode 100644
index 0000000000000000000000000000000000000000..0b42d6cabbb348c35f798a51a01e6cf01dc999f3
--- /dev/null
+++ b/rxws.py
@@ -0,0 +1,148 @@
+"""
+rxws: WebSocket methods implemented for OpenWebRX
+
+This file is part of OpenWebRX.
+
+    OpenWebRX is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenWebRX is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenWebRX.  If not, see <http://www.gnu.org/licenses/>.
+
+Authors:
+    Andras Retzler, HA7ILM <retzlerandras@gmail.com>
+
+"""
+
+import base64
+import sha
+import select
+
+class WebSocketException(Exception):
+	pass
+
+def handshake(myself):
+	my_client_id=myself.path[4:]
+	my_headers=myself.headers.items()
+	my_header_keys=map(lambda x:x[0],my_headers)
+	h_key_exists=lambda x:my_header_keys.count(x)
+	h_value=lambda x:my_headers[my_header_keys.index(x)][1]
+	#print "The Lambdas(tm)"
+	#print h_key_exists("upgrade")
+	#print h_value("upgrade")
+	#print h_key_exists("sec-websocket-key")
+	if (not h_key_exists("upgrade")) or not (h_value("upgrade")=="websocket") or (not h_key_exists("sec-websocket-key")):
+		raise WebSocketException
+	ws_key=h_value("sec-websocket-key")
+	ws_key_toreturn=base64.b64encode(sha.new(ws_key+"258EAFA5-E914-47DA-95CA-C5AB0DC85B11").digest())
+	#A sample list of keys we get: [('origin', 'http://localhost:8073'), ('upgrade', 'websocket'), ('sec-websocket-extensions', 'x-webkit-deflate-frame'), ('sec-websocket-version', '13'), ('host', 'localhost:8073'), ('sec-websocket-key', 't9J1rgy4fc9fg2Hshhnkmg=='), ('connection', 'Upgrade'), ('pragma', 'no-cache'), ('cache-control', 'no-cache')]
+	myself.connection.send("HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: "+ws_key_toreturn+"\r\nCQ-CQ-de: HA5KFU\r\n\r\n")
+
+def get_header(size):
+	#this does something similar: https://github.com/lemmingzshadow/php-websocket/blob/master/server/lib/WebSocket/Connection.php
+	ws_first_byte=0b10000010 # FIN=1, OP=2
+	if(size>125):
+		ws_second_byte=126 # The following two bytes will indicate frame size
+		extended_size=chr((size>>8)&0xff)+chr(size&0xff) #Okay, it uses reverse byte order (little-endian) compared to anything else sent on TCP
+	else:
+		ws_second_byte=size
+		#256 bytes binary message in a single unmasked frame | 0x82 0x7E 0x0100 [256 bytes of binary data]
+		extended_size=""
+	return chr(ws_first_byte)+chr(ws_second_byte)+extended_size
+
+def code_payload(data, masking_key=""):
+	# both encode or decode
+	if masking_key=="":
+		key = (61, 84, 35, 6)
+	else:
+		key = [ord(i) for i in masking_key]
+	encoded=""
+	for i in range(0,len(data)):
+		encoded+=chr(ord(data[i])^key[i%4])
+	return encoded
+
+def xxdg(data):
+	output=""
+	for i in range(0,len(data)/8):
+		output+=xxd(data[i:i+8])
+		if i%2: output+="\n"
+		else: output+="  "
+	return output
+		
+
+def xxd(data):
+	#diagnostic purposes only
+	output=""
+	for d in data:
+		output+=hex(ord(d))[2:].zfill(2)+" " 
+	return output
+
+def recv(myself, blocking=False, debug=False):
+	bufsize=70000
+	myself.connection.setblocking(blocking)
+	if debug: print "ws_recv begin"
+	try:
+		data=myself.connection.recv(6)
+		#print "rxws.recv bytes:",xxd(data)	
+	except:
+		if debug: print "ws_recv error"	
+		return ""
+	if debug: print "ws_recv recved"
+	if(len(data)==0): return ""
+	fin=ord(data[0])&128!=0
+	is_text_frame=ord(data[0])&15==1
+	length=ord(data[1])&0x7f
+	data+=myself.connection.recv(length)
+	#print "rxws.recv length is ",length," (multiple packets together?) len(data) =",len(data)
+	has_one_byte_length=length<125
+	masked=ord(data[1])&0x80!=0
+	#print "len=", length, len(data)-2
+	#print "fin, is_text_frame, has_one_byte_length, masked = ", (fin, is_text_frame, has_one_byte_length, masked)
+	#print xxd(data)
+	if fin and is_text_frame and has_one_byte_length:
+		if masked:
+			return code_payload(data[6:], data[2:6])
+		else:
+			return data[2:]
+
+#Useful links for ideas on WebSockets:
+#  http://stackoverflow.com/questions/8125507/how-can-i-send-and-receive-websocket-messages-on-the-server-side
+#  https://developer.mozilla.org/en-US/docs/WebSockets/Writing_WebSocket_server
+#  http://tools.ietf.org/html/rfc6455#section-5.2	
+
+
+def flush(myself):
+	lR,lW,lX = select.select([],[myself.connection,],[],60)
+	
+
+def send(myself, data, begin_id="", debug=0):
+	base_frame_size=35000 #could guess by MTU?
+	debug=0
+	#try:
+	while True:
+		counter=0
+		from_end=len(data)-counter
+		if from_end+len(begin_id)>base_frame_size:
+			data_to_send=begin_id+data[counter:counter+base_frame_size-len(begin_id)]
+			header=get_header(len(data_to_send))
+			flush(myself)
+			myself.connection.send(header+data_to_send)
+			if debug: print "rxws.send ==================== #1 if branch :: from={0} to={1} dlen={2} hlen={3}".format(counter,counter+base_frame_size-len(begin_id),len(data_to_send),len(header))
+		else:
+			data_to_send=begin_id+data[counter:]
+			header=get_header(len(data_to_send))
+			flush(myself)
+			myself.connection.send(header+data_to_send)
+			if debug: print "rxws.send :: #2 else branch :: dlen={0} hlen={1}".format(len(data_to_send),len(header))
+			#if debug: print "header:\n"+xxdg(header)+"\n\nws data:\n"+xxdg(data_to_send)
+			break
+		counter+=base_frame_size-len(begin_id)
+	#except:
+	#	pass