0

I have a "dial tone" python program that is imported into a Falsk webserver, and I have an html embedded roundSlider widget that I am trying to use to update the sample rate variable values inside dial tone program. Once I run the webserver and start dragging the slider, visually the value of the slider does update/change when dragging it, but there is no tone, the tone program doesn't start!

Please, I need your help to figure this out.

Here is my flask app.py:

from flask import Flask, render_template, jsonify, request,redirect,url_for
from random import randint
from top_block_22 import top_block_22

app = Flask(__name__)
# def test():
#     print("its working") 
@app.route('/')
def slide_func():
    return render_template("index.html")
    print(slide_val)
    return(slide_val)
def test():
    print("its working")

@app.route('/valueofslider')
def slide():
    slide_val = request.args.get('slide_val')
    return main(slide_val)   

def main(slide_val):

    tb = top_block_22()
    tb.start()
    samp_rate = int(slide_val) + 100
    print(samp_rate)
    return(slide_val)  
    app.debug = True
if __name__ == '__main__':
    app.run(debug=True)

Main dial tone code:

from gnuradio import analog
from gnuradio import audio

from gnuradio import blocks
from gnuradio import eng_notation
from gnuradio import gr
from gnuradio.eng_option import eng_option
from gnuradio.filter import firdes
from optparse import OptionParser
from flask import Flask, render_template, jsonify, request, redirect, url_for
from random import randint
#from app import *





class top_block_22(gr.top_block):

    def __init__(self, samp_rate):

        gr.top_block.__init__(self, "Top Block 22")        
        ##################################################
        # Variables
        ##################################################
        self.samp_rate = samp_rate = 32000

        ##################################################
        # Blocks
        ##################################################
        self.blocks_add_xx = blocks.add_vff(1)
        self.audio_sink = audio.sink(32000, '', True)
        self.analog_sig_source_x_1 = analog.sig_source_f(samp_rate, analog.GR_COS_WAVE, 440, 0.4, 0)
        self.analog_sig_source_x_0 = analog.sig_source_f(samp_rate, analog.GR_COS_WAVE, 350, 0.4, 0)
        self.analog_noise_source_x_0 = analog.noise_source_f(analog.GR_GAUSSIAN, 0.005, -42)

        ##################################################
        # Connections
        ##################################################
        self.connect((self.analog_noise_source_x_0, 0), (self.blocks_add_xx, 2))
        self.connect((self.analog_sig_source_x_0, 0), (self.blocks_add_xx, 0))
        self.connect((self.analog_sig_source_x_1, 0), (self.blocks_add_xx, 1))
        self.connect((self.blocks_add_xx, 0), (self.audio_sink, 0))



def main(top_block_cls=top_block_22, options=None):


    tb = top_block_22('samp_rate')

    tb.start()
    try:
        raw_input('Press Enter to quit: ')
    except EOFError:
        pass
    tb.stop()
    tb.wait()


if __name__ == '__main__':
        main()

index.html script:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>jQuery roundSlider - JS Bin</title>
  <link rel="icon" href="data:,">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
  <link href="https://cdnjs.cloudflare.com/ajax/libs/roundSlider/1.3.2/roundslider.min.css" rel="stylesheet" />
  <script src="https://cdnjs.cloudflare.com/ajax/libs/roundSlider/1.3.2/roundslider.min.js"></script>
</head>
<body>
  <!-- Only html needed   -->
<form class="form-inline" method="POST" action="{{ url_for('slide') }}">
  <div id="slider"></div>

  <script>
    var val;
    $("#slider").roundSlider({
      radius: 215,
        min: 0,
        max: 100000,
       change: function () {

        var obj1 = $("#slider").data("roundSlider");
        val = obj1.getValue();
        value: 10
        $.getJSON('/valueofslider', {
          slide_val: val
        });
      }
    });
  </script>
</body>
</html>

Here is an image of the slider when its updating its values:

slider

furas
  • 134,197
  • 12
  • 106
  • 148
  • remove `= 32000` and keep only `self.samp_rate = samp_rate`. And use it in `tb = top_block_22(32000)` – furas Aug 01 '19 at 20:02
  • @furas, it didn't change the case. By the way, the way I run this is from my terminal on the same computer, is that the right way to do it? I mean everything on one computer! –  Aug 01 '19 at 20:14
  • Problem can be simply. It runs `top_block_22` for so short time that you can't hear sound. If you add ie. `time.sleep(2)` then you may hear sound. I run your code with `time.sleep(2)` and hear sound but there is other problem and I don't know what is problem – furas Aug 01 '19 at 20:44
  • @furas, where I should place this time.sleep(2)? –  Aug 01 '19 at 20:49
  • @furas, is there another approach to accomplish this project? I started to give on doing it through Flask and this roundSlider. Do you think there is a simpler approach? –  Aug 01 '19 at 20:54
  • if you want to run it on one computer then more natural could be use GUI instead of Web page. – furas Aug 01 '19 at 21:13

1 Answers1

1

This code works for me.

Main problem was that function runs so fast that nobody can hear sound - so I added time.sleep(0.5)

I put all code in one file so it is easier to copy and paste to file to run it.

Main page http://localhost:5000/ displays few links with different values to test it.

from gnuradio import analog
from gnuradio import audio

from gnuradio import blocks
from gnuradio import eng_notation
from gnuradio import gr
from gnuradio.eng_option import eng_option
from gnuradio.filter import firdes
from optparse import OptionParser


class top_block_22(gr.top_block):

    def __init__(self, samp_rate=32000): # default value for samp_rate

        gr.top_block.__init__(self, "Top Block 22")        
        ##################################################
        # Variables
        ##################################################
        self.samp_rate = samp_rate   # without "= 32000"
        print('[DEBUG] top_block_22:', self.samp_rate)

        ##################################################
        # Blocks
        ##################################################
        self.blocks_add_xx = blocks.add_vff(1)
        self.audio_sink = audio.sink(32000, '', True)
        self.analog_sig_source_x_1 = analog.sig_source_f(samp_rate, analog.GR_COS_WAVE, 440, 0.4, 0)
        self.analog_sig_source_x_0 = analog.sig_source_f(samp_rate, analog.GR_COS_WAVE, 350, 0.4, 0)
        self.analog_noise_source_x_0 = analog.noise_source_f(analog.GR_GAUSSIAN, 0.005, -42)

        ##################################################
        # Connections
        ##################################################
        self.connect((self.analog_noise_source_x_0, 0), (self.blocks_add_xx, 2))
        self.connect((self.analog_sig_source_x_0, 0), (self.blocks_add_xx, 0))
        self.connect((self.analog_sig_source_x_1, 0), (self.blocks_add_xx, 1))
        self.connect((self.blocks_add_xx, 0), (self.audio_sink, 0))

# -----------------------------------------------------------------------------

from flask import Flask, request
#from top_block_22 import top_block_22 
import time


app = Flask(__name__)


@app.route('/')
def index():
    HTML = 'HEAR:'
    for item in (20000, 25000, 32000):
        HTML += ' <a href="/valueofslider?slide_val={}">{}</a>'.format(item, item)
    return HTML

@app.route('/valueofslider')
def slide():
    slide_val = request.args.get('slide_val', 32000) # default value 32000
    main(slide_val)
    return slide_val

def main(slide_val):
    samp_rate = int(slide_val) + 100
    print('[DEBUG] main:', samp_rate)

    tb = top_block_22(samp_rate) # run with value from variable
    tb.start()

    time.sleep(0.5)

    tb.stop()
    tb.wait()


if __name__ == '__main__':    
    app.run(debug=True)

EDIT: This version displays slider and it uses Thread to play sound all time (after selecting first value on slider).

When slider sends new value then it stops old thread and creates new one with new samp_rate.

But maybe it can be done without Thread but using only tb.start, tb.stop, etc. It seems top_block_22 already uses thread to work.

It also uses http://localhost:5000/off to send samp_rate=0 which stop sound.

from gnuradio import analog
from gnuradio import audio

from gnuradio import blocks
from gnuradio import eng_notation
from gnuradio import gr
from gnuradio.eng_option import eng_option
from gnuradio.filter import firdes
from optparse import OptionParser


class top_block_22(gr.top_block):

    def __init__(self, samp_rate):

        gr.top_block.__init__(self, "Top Block 22")        
        ##################################################
        # Variables
        ##################################################
        self.samp_rate = samp_rate
        print('[DEBUG] top_block_22:', self.samp_rate)

        ##################################################
        # Blocks
        ##################################################
        self.blocks_add_xx = blocks.add_vff(1)
        self.audio_sink = audio.sink(32000, '', True)
        self.analog_sig_source_x_1 = analog.sig_source_f(samp_rate, analog.GR_COS_WAVE, 440, 0.4, 0)
        self.analog_sig_source_x_0 = analog.sig_source_f(samp_rate, analog.GR_COS_WAVE, 350, 0.4, 0)
        self.analog_noise_source_x_0 = analog.noise_source_f(analog.GR_GAUSSIAN, 0.005, -42)

        ##################################################
        # Connections
        ##################################################
        self.connect((self.analog_noise_source_x_0, 0), (self.blocks_add_xx, 2))
        self.connect((self.analog_sig_source_x_0, 0), (self.blocks_add_xx, 0))
        self.connect((self.analog_sig_source_x_1, 0), (self.blocks_add_xx, 1))
        self.connect((self.blocks_add_xx, 0), (self.audio_sink, 0))

# -----------------------------------------------------------------------------

from threading import Thread

class MyThread(Thread):

    def __init__(self, samp_rate):
        Thread.__init__(self)
        self.running = True
        self.samp_rate = samp_rate

    def run(self):

        tb = top_block_22(self.samp_rate)
        tb.start()

        while self.running:
            time.sleep(0.5)  # need it to head sound

        tb.stop()
        tb.wait()

# -----------------------------------------------------------------------------

from flask import Flask, request
#from top_block_22 import top_block_22 
import time


app = Flask(__name__)

my_thread = None


@app.route('/')
def index():
    return '''<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>jQuery roundSlider - JS Bin</title>
  <link rel="icon" href="data:,">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
  <link href="https://cdnjs.cloudflare.com/ajax/libs/roundSlider/1.3.2/roundslider.min.css" rel="stylesheet" />
  <script src="https://cdnjs.cloudflare.com/ajax/libs/roundSlider/1.3.2/roundslider.min.js"></script>
</head>
<body>
  <!-- Only html needed   -->
<form class="form-inline" method="POST" action="{{ url_for('slide') }}">
  <div id="slider"></div>

  <script>
    var val;
    $("#slider").roundSlider({
      radius: 215,
        min: 0,
        max: 100000,
       change: function () {

        var obj1 = $("#slider").data("roundSlider");
        val = obj1.getValue();
        value: 10
        $.getJSON('/valueofslider', {
          slide_val: val
        });
      }
    });
  </script>
</body>
</html>'''

@app.route('/off')
def off():
    '''use `slide_val=0` to turn it off'''
    main(0)
    return 'off'

@app.route('/valueofslider')
def slide():
    slide_val = request.args.get('slide_val', 32000)
    main(slide_val)
    return slide_val

def main(slide_val):
    global my_thread

    print('[DEBUG] main:', slide_val)
    samp_rate = int(slide_val)

    if my_thread: # if my_thread is not None
        my_thread.running = False
        my_thread.join()
        my_thread = None

    if samp_rate > 0:
        my_thread = MyThread(samp_rate)
        my_thread.start()


if __name__ == '__main__':    
    app.run(debug=True)

EDIT: Version without Thread.

As before it display slider and it play sound all time after selecting first value. It use global value tb to keep access to object and stop it when it get new samp_rate, and run new object.

It also uses http://localhost:5000/off to send samp_rate=0 which stop sound.

from gnuradio import analog
from gnuradio import audio

from gnuradio import blocks
from gnuradio import eng_notation
from gnuradio import gr
from gnuradio.eng_option import eng_option
from gnuradio.filter import firdes
from optparse import OptionParser


class top_block_22(gr.top_block):

    def __init__(self, samp_rate):

        gr.top_block.__init__(self, "Top Block 22")        
        ##################################################
        # Variables
        ##################################################
        self.samp_rate = samp_rate
        print('[DEBUG] top_block_22:', self.samp_rate)

        ##################################################
        # Blocks
        ##################################################
        self.blocks_add_xx = blocks.add_vff(1)
        self.audio_sink = audio.sink(32000, '', True)
        self.analog_sig_source_x_1 = analog.sig_source_f(samp_rate, analog.GR_COS_WAVE, 440, 0.4, 0)
        self.analog_sig_source_x_0 = analog.sig_source_f(samp_rate, analog.GR_COS_WAVE, 350, 0.4, 0)
        self.analog_noise_source_x_0 = analog.noise_source_f(analog.GR_GAUSSIAN, 0.005, -42)

        ##################################################
        # Connections
        ##################################################
        self.connect((self.analog_noise_source_x_0, 0), (self.blocks_add_xx, 2))
        self.connect((self.analog_sig_source_x_0, 0), (self.blocks_add_xx, 0))
        self.connect((self.analog_sig_source_x_1, 0), (self.blocks_add_xx, 1))
        self.connect((self.blocks_add_xx, 0), (self.audio_sink, 0))

# -----------------------------------------------------------------------------

from flask import Flask, request
#from top_block_22 import top_block_22 


app = Flask(__name__)

tb = None  # global variable to keep it between requests


@app.route('/')
def index():
    return '''<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>jQuery roundSlider - JS Bin</title>
  <link rel="icon" href="data:,">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
  <link href="https://cdnjs.cloudflare.com/ajax/libs/roundSlider/1.3.2/roundslider.min.css" rel="stylesheet" />
  <script src="https://cdnjs.cloudflare.com/ajax/libs/roundSlider/1.3.2/roundslider.min.js"></script>
</head>
<body>
  <!-- Only html needed   -->
<form class="form-inline" method="POST" action="{{ url_for('slide') }}">
  <div id="slider"></div>

  <script>
    var val;
    $("#slider").roundSlider({
      radius: 215,
        min: 0,
        max: 100000,
       change: function () {

        var obj1 = $("#slider").data("roundSlider");
        val = obj1.getValue();
        value: 10
        $.getJSON('/valueofslider', {
          slide_val: val
        });
      }
    });
  </script>
</body>
</html>'''

@app.route('/off')
def off():
    '''use `slide_val=0` to turn it off'''
    main(0)
    return 'off'

@app.route('/valueofslider')
def slide():
    slide_val = request.args.get('slide_val', 32000)
    main(slide_val)
    return slide_val

def main(slide_val):
    global tb

    print('[DEBUG] main:', slide_val)
    samp_rate = int(slide_val)

    # stop old sound
    if tb: # if tb is not None
        tb.stop()
        tb.wait()
        tb = None 

    # create new sound (if not zero)
    if samp_rate > 0:
        tb = top_block_22(samp_rate)
        tb.start()


if __name__ == '__main__':    
    app.run(debug=True)

EDIT: last version

Few changes in JavaScript:

  • it sets default value at start - 32000. There was mistake in JS.
  • it sends request at start so it starts sound after loading page. There is no need to select value on slider.

Changes in Python:

  • as suggest PEP 8 -- Style Guide for Python Code I set UpperCaseName for class - TopBlock22
  • renamed main to sound which better describe what function is doing
  • http://localhost/set/<value> sets sample rate so it can be used instead of http://localhost/valueofslider?slider_val=<value>.
  • http://localhost/get gets current sample rate
  • http://localhost/off sets value to 0 so it turns off sound. I used it to fast turn off sound when it was too annoying.
  • print_function from __future__ to use print(text) like in Python 3
  • functions return value as text but there are lines with jsonify() so they can retun it as JSON. Maybe it can be useful later.

In FAQ I found How can I reconfigure a flow graph? How do I use lock(), unlock()? so maybe it can change sample rate without creating new object and maybe it gives better sound. I head click when it change sample rate.

Code:

from __future__ import print_function

from gnuradio import analog
from gnuradio import audio

from gnuradio import blocks
from gnuradio import eng_notation
from gnuradio import gr
from gnuradio.eng_option import eng_option
from gnuradio.filter import firdes
from optparse import OptionParser


class TopBlock22(gr.top_block): # PEP8: CamelCaseName for classes

    def __init__(self, sample_rate=32000):

        gr.top_block.__init__(self, "Top Block 22")        
        ##################################################
        # Variables
        ##################################################
        self.sample_rate = sample_rate
        print('[TopBlock22] sample_rate:', self.sample_rate)

        ##################################################
        # Blocks
        ##################################################
        self.blocks_add_xx = blocks.add_vff(1)
        self.audio_sink = audio.sink(32000, '', True)
        self.analog_sig_source_x_1 = analog.sig_source_f(sample_rate, analog.GR_COS_WAVE, 440, 0.4, 0)
        self.analog_sig_source_x_0 = analog.sig_source_f(sample_rate, analog.GR_COS_WAVE, 350, 0.4, 0)
        self.analog_noise_source_x_0 = analog.noise_source_f(analog.GR_GAUSSIAN, 0.005, -42)

        ##################################################
        # Connections
        ##################################################
        self.connect((self.analog_noise_source_x_0, 0), (self.blocks_add_xx, 2))
        self.connect((self.analog_sig_source_x_0, 0), (self.blocks_add_xx, 0))
        self.connect((self.analog_sig_source_x_1, 0), (self.blocks_add_xx, 1))
        self.connect((self.blocks_add_xx, 0), (self.audio_sink, 0))

# -----------------------------------------------------------------------------

from flask import Flask, request, jsonify
#from top_block_22 import TopBlock22 
import time


app = Flask(__name__)

tb = None  # global variable to keep it between requests


@app.route('/')
def index():
    return '''<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>GNURadio Slider Example</title>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
  <link href="https://cdnjs.cloudflare.com/ajax/libs/roundSlider/1.3.2/roundslider.min.css" rel="stylesheet" />
  <script src="https://cdnjs.cloudflare.com/ajax/libs/roundSlider/1.3.2/roundslider.min.js"></script>
</head>
<body>

<div id="slider"></div>

<script>

  // keep slider's value
  var val;

  // create slider
  $("#slider").roundSlider({
    radius: 215,
    min: 0,
    max: 100000,
    value: 32000, // default value at start
    change: function () {
      var obj = $("#slider").data("roundSlider");
      val = obj.getValue();
      $.getJSON('/valueofslider', {
        slide_val: val
      });
    }
  });

  // play sound at start
  $.getJSON('/valueofslider', {slide_val: val});

</script>

</body>
</html>'''

@app.route('/test')
def test():
    HTML = 'HEAR:'
    for item in (0, 10000, 20000, 25000, 32000):
        HTML += ' <a href="/set/{}">{}</a>'.format(item, item)
    return HTML

@app.route('/off')
def off():
    """Turn off sound."""
    sound(0)
    #return jsonify({'val': 0})
    return 'off'

@app.route('/set/<int:value>')
def set_value(value):
    """Set value. Use 0 to turn it off."""
    sound(value)
    #return jsonify({'val': value})
    return str(value)

@app.route('/get')
def get_value():
    """Get current value."""
    if tb:
        value = tb.sample_rate
    else:
        value = 0
    #return jsonify({'val': value})
    return str(value)

@app.route('/valueofslider')
def slide():
    sample_rate = request.args.get('slide_val', '32000')
    sample_rate = int(sample_rate)
    sound(sample_rate)
    #return jsonify({'val': sample_rate})
    return str(sample_rate)

def sound(sample_rate):
    global tb

    print('[sound] sample_rate:', sample_rate)
    sample_rate = int(sample_rate)

    # stop old sound
    if tb: # if tb is not None
        tb.stop()
        tb.wait()
        tb = None 

    # create new sound (if not zero)
    if sample_rate > 0:
        tb = TopBlock22(sample_rate)
        tb.start()


if __name__ == '__main__':    
    app.run(debug=True)

EDIT: this time last version.

It uses lock/unlock and disconnect/connect to change sound without creating new object. Based on example from FAQ (How can I reconfigure a flow graph? How do I use lock(), unlock()?) but disconnect needed two endpoints like connect.

from __future__ import print_function

from gnuradio import analog
from gnuradio import audio

from gnuradio import blocks
from gnuradio import eng_notation
from gnuradio import gr
from gnuradio.eng_option import eng_option
from gnuradio.filter import firdes
from optparse import OptionParser


class TopBlock22(gr.top_block): # PEP8: CamelCaseName for classes

    def __init__(self, sample_rate=32000):

        gr.top_block.__init__(self, "Top Block 22")        
        ##################################################
        # Variables
        ##################################################
        self.sample_rate = sample_rate
        print('[TopBlock22] __init__: sample_rate:', self.sample_rate)

        ##################################################
        # Blocks
        ##################################################
        self.blocks_add_xx = blocks.add_vff(1)
        self.audio_sink = audio.sink(32000, '', True)
        self.analog_sig_source_x_1 = analog.sig_source_f(sample_rate, analog.GR_COS_WAVE, 440, 0.4, 0)
        self.analog_sig_source_x_0 = analog.sig_source_f(sample_rate, analog.GR_COS_WAVE, 350, 0.4, 0)
        self.analog_noise_source_x_0 = analog.noise_source_f(analog.GR_GAUSSIAN, 0.005, -42)

        ##################################################
        # Connections
        ##################################################
        self.connect((self.analog_noise_source_x_0, 0), (self.blocks_add_xx, 2))
        self.connect((self.analog_sig_source_x_0, 0), (self.blocks_add_xx, 0))
        self.connect((self.analog_sig_source_x_1, 0), (self.blocks_add_xx, 1))
        self.connect((self.blocks_add_xx, 0), (self.audio_sink, 0))

    def change(self, sample_rate):
        self.sample_rate = sample_rate
        print('[TopBlock22] change: sample_rate:', self.sample_rate)

        # lock
        self.lock()

        # disconect - needs two endpoints (not like in FAQ)
        self.disconnect((self.analog_sig_source_x_0, 0), (self.blocks_add_xx, 0))
        self.disconnect((self.analog_sig_source_x_1, 0), (self.blocks_add_xx, 1))

        # create new
        self.analog_sig_source_x_1 = analog.sig_source_f(sample_rate, analog.GR_COS_WAVE, 440, 0.4, 0)
        self.analog_sig_source_x_0 = analog.sig_source_f(sample_rate, analog.GR_COS_WAVE, 350, 0.4, 0)

        # connect again
        self.connect((self.analog_sig_source_x_0, 0), (self.blocks_add_xx, 0))
        self.connect((self.analog_sig_source_x_1, 0), (self.blocks_add_xx, 1))

        # unlock
        self.unlock()

# -----------------------------------------------------------------------------

from flask import Flask, request, jsonify


app = Flask(__name__)

tb = None  # global variable to keep it between requests


@app.route('/')
def index():
    return '''<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>GNURadio Slider Example</title>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
  <link href="https://cdnjs.cloudflare.com/ajax/libs/roundSlider/1.3.2/roundslider.min.css" rel="stylesheet" />
  <script src="https://cdnjs.cloudflare.com/ajax/libs/roundSlider/1.3.2/roundslider.min.js"></script>
</head>
<body>

<div id="slider"></div>

<script>

  // keep slider's value
  var val;

  // create slider
  $("#slider").roundSlider({
    radius: 215,
    min: 0,
    max: 100000,
    value: 32000, // default value at start
    change: function () {
      var obj = $("#slider").data("roundSlider");
      val = obj.getValue();
      $.getJSON('/valueofslider', {
        slide_val: val
      });
    }
  });

  // play sound at start
  $.getJSON('/valueofslider', {slide_val: val});

</script>

</body>
</html>'''

@app.route('/test')
def test():
    HTML = 'HEAR:'
    for item in (0, 10000, 20000, 25000, 32000):
        HTML += ' <a href="/set/{}">{}</a>'.format(item, item)
    return HTML

@app.route('/off')
def off():
    """Turn off sound."""
    sound(0)
    #return jsonify({'val': 0})
    return 'off'

@app.route('/set/<int:value>')
def set_value(value):
    """Set value. Use 0 to turn it off."""
    sound(value)
    #return jsonify({'val': value})
    return str(value)

@app.route('/get')
def get_value():
    """Get value. Returns 0 when turned off."""
    if tb:
        value = tb.sample_rate
    else:
        value = 0
    #return jsonify({'val': value})
    return str(value)

@app.route('/valueofslider')
def slide():
    sample_rate = request.args.get('slide_val', '32000')
    sample_rate = int(sample_rate)
    sound(sample_rate)
    #return jsonify({'val': sample_rate})
    return str(sample_rate)

def sound_old(sample_rate):
    """version which doesn't use `change()`"""
    global tb

    print('[sound] sample_rate:', sample_rate)
    sample_rate = int(sample_rate)

    # stop old sound
    if tb: # if tb is not None
        tb.stop()
        tb.wait()
        tb = None 

    # create new sound (if not zero)
    if sample_rate > 0:
        tb = TopBlock22(sample_rate)
        tb.start()

def sound(sample_rate):
    """version which uses `change()`"""
    global tb

    print('[sound] sample_rate:', sample_rate)
    sample_rate = int(sample_rate)

    # change or stop old sound
    if tb: # if tb is not None
        if sample_rate > 0:
            tb.change(sample_rate)
        else:        
            tb.stop()
            tb.wait()
            tb = None 

    # create new sound (if not zero)
    if not tb:
        if sample_rate > 0:
            tb = TopBlock22(sample_rate)
            tb.start()


if __name__ == '__main__':    
    app.run(debug=True)

EDIT: I found that sample rate can be change with

 self.analog_sig_source_x_1.set_sampling_freq(sample_rate)

so it doesn't have to create new sig_source_f

class TopBlock22(gr.top_block):

    # ... rest ...

    def change(self, sample_rate):
        self.sample_rate = sample_rate
        print('[TopBlock22] change: sample_rate:', self.sample_rate)

        self.analog_sig_source_x_1.set_sampling_freq(sample_rate)
        self.analog_sig_source_x_0.set_sampling_freq(sample_rate)

I think that now I don't hear clicks when it changes sample rate but now I fill it has small delay before it change it after mouse click.

To see other functions in this object you can use dir(self.analog_sig_source_x_1)

    print('\n'.join(dir(self.analog_sig_source_x_1)))

    ...        
    set_amplitude
    set_block_alias
    set_frequency
    set_max_noutput_items
    set_max_output_buffer
    set_min_noutput_items
    set_min_output_buffer
    set_offset
    set_processor_affinity
    set_sampling_freq
    set_thread_priority
    set_waveform
    ...

Source: Choosing, defining and configuring blocks, documentation for C/C++ version

furas
  • 134,197
  • 12
  • 106
  • 148
  • That sounds great, but I will be limited with values range here. If we cannot have a slider here, can we have at least a sort of little box there that can take whatever values we want to input, then we hit enter button or something like that? –  Aug 01 '19 at 21:50
  • it is only example which everyone can easily copy and run it. But you can use it with your slider. Problem wasin't slider but `time.sleep()` – furas Aug 01 '19 at 21:54
  • if you want to hear sound all time then you may have to run `top_block_22` in separated thread which will run all time. Normal version use `raw_input()` to run all time. Thread would use `while True` loop or `while running:` so you could stop it but setting `running = False` – furas Aug 01 '19 at 22:17
  • I created version without `Thread` which play sound all time. – furas Aug 01 '19 at 23:16
  • I am in a shock now! :D This one piece of code is my whole program, right? I tried and it works just like the way I wanted it! I can use it like that without having it in a separate files, right? –  Aug 01 '19 at 23:59
  • I can't really thank you enough. You are so nice, kind, generous, and talented. Thank you sooooooooooooooo much! –  Aug 02 '19 at 00:06
  • I played a bit with the code and I put last version. – furas Aug 02 '19 at 00:45
  • This time last version. It use `lock/unlock` and `disconnect/connect` to change sound. I didn't check how it would work without `lock/unlock`. – furas Aug 02 '19 at 01:19
  • I found `.set_sampling_freq(sample_rate)` for `analog.sig_source_f` and put code which use it. – furas Aug 02 '19 at 02:21
  • I'm back. Man that's such an amazing work. I am going through the updates you added and I am speechless, you literally saved me! Again, thanks a LOT furas. –  Aug 02 '19 at 13:22
  • I was thinking about another version with more sliders which use `set_amplitude`, `set_frequency`, `set_waveform`, etc. but I skip this. – furas Aug 02 '19 at 14:07
  • thats what I have to do next. Currently I am replicating the rounSlider widget to have 4 or 5 of them in my webpage because my next step is to build more variables sliders, i.e, CW, broadband noise, ...etc. This samp_rate was just the beginning for me to learn how it works and whether it can be done or not! But a HUGE thanks to you, I know now it works. –  Aug 02 '19 at 14:23
  • Thanks again furas. –  Aug 02 '19 at 14:41
  • Hi, I just posted a new thread about the same project, just another hardship :) : https://stackoverflow.com/questions/57397344/a-problem-with-value-sliders-they-are-interfering-with-each-other –  Aug 07 '19 at 15:05