Musicbox Exercise


In [1]:
from __future__ import division
from __future__ import print_function

from math import ceil
from math import log
from math import sin
from math import pi
from fractions import gcd

import myhdl
print(myhdl.__version__)
from myhdl import *

from test_X1_mex import test


0.9dev

Description

There was a question posted on reddit about a music box implementation. The following is an implementation of the simple example posted implemented in MyHDL. Experimenting and verifying an exmaple like this in MyHDL/Python is much easier than Verilog/VHDL (e.g. plot the outputs).


In [2]:
def m_musicbox(clock, reset, note, nv, sample_rate=48e3, clock_rate=50e6):
    """ module to generate a "tone".
    
    Port Map
    --------
      clock :input:  circuit synchronous clock
      reset :input:  circult reset
      note  :output: digital signal for the note
      nv    :output: sample valid strobe
    """
    
    # Build the ROM table to hold the "note"., this ROM table
    # should be a tuple of ints once completed
    # ...
        
    # Signals and variable for the logic
    # ...
    
    # note ROM current index
    # ...
    
    @always_seq(clock.posedge, reset=reset)
    def rtl():        
        # determine when to output a new sample and which
        # sample to output.
        pass
    
    return rtl

# quick check that Python is ok with the module
m_musicbox(Signal(bool(0)), ResetSignal(0, 0, False), 
           Signal(intbv(0, min=-16, max=16)), Signal(bool(0)) )


Out[2]:
<myhdl._always_seq._AlwaysSeq at 0x40b1978>

In [3]:
# run the simulation
Fs = 48e3         # sample rate 
Nmax = 2**(15-1)  # sample max value
tv,xv = test(m_musicbox, Nsmp=100, Fs=Fs, Nmax=Nmax, convert=False)
print("Simulation complete")


---------------------------------------------------------------------------
StandardError                             Traceback (most recent call last)
<ipython-input-3-b57532277fc4> in <module>()
      2 Fs = 48e3         # sample rate
      3 Nmax = 2**(15-1)  # sample max value
----> 4 tv,xv = test(m_musicbox, Nsmp=100, Fs=Fs, Nmax=Nmax, convert=False)
      5 print("Simulation complete")

c:\Work\misc\aaa_support\mex\test_X1_mex.py in test(mod, Nsmp, Fs, Nmax, convert)
     58 
     59     # run the simulation, using _test as the stimulus
---> 60     Simulation(traceSignals(_test)).run()
     61 
     62     if convert:

C:\Users\felton\AppData\Local\Enthought\Canopy\User\lib\site-packages\myhdl\_Simulation.pyc in run(self, duration, quiet)
    133                     waiter = _pop()
    134                     try:
--> 135                         waiter.next(waiters, actives, exc)
    136                     except StopIteration:
    137                         continue

C:\Users\felton\AppData\Local\Enthought\Canopy\User\lib\site-packages\myhdl\_Waiter.pyc in next(self, waiters, actives, exc)
     68 
     69         try:
---> 70             clause = next(self.generator)
     71         except StopIteration:
     72             if self.caller:

c:\Work\misc\aaa_support\mex\test_X1_mex.py in tbstim()
     49                 # make sure the musicbox is output samples
     50                 if tocnt >= Timeout:
---> 51                     raise StandardError("No samples")
     52 
     53                 yield clock.posedge

StandardError: No samples

In [5]:
# run the simulation and collect 1000 samples and plot
import matplotlib.pyplot as plt

tv,xv = test(Nsmp=Fs//200, Fs=Fs, Nmax=Nmax, convert=False)

fig,ax = plt.subplots(1, figsize=(9,3,))
ax.plot(tv, xv)
ax.set_ylim(-Nmax, Nmax)
ax.set_xlabel("Time [sec]")
ax.set_ylabel("Raw Amplitude")

# plot the power spectral density (see the spikes of the "tones")
fig,ax = plt.subplots(1, figsize=(9,3,))
tv,xv = test(Nsmp=Fs, Fs=Fs, Nmax=Nmax, convert=False)
p,f = ax.psd(xv, Fs=Fs, NFFT=8192)
ax.set_ylim(-60, 80)
ax.set_xlim(0, 6000)


The note has a tone at 1200.000 and 4000.000
The note has a tone at 1200.000 and 4000.000
Out[5]:
(0, 6000)

In [6]:
# the following requires the myhdl_tools package 
# (http://www.bitbucket.org/cfelton/myhdl_tools)
# >> pip install hg+https://bitbucket.org/cfelton/myhdl_tools
from myhdl_tools import vcd

# rerun the test with less samples
test(Nsmp=5, Fs=Fs, Nmax=Nmax, convert=False)

# not a great VCD plotter but enough to get an idea,
# use gtkwave for real debug
vcd.parse_and_plot("_test.vcd")


The note has a tone at 1200.000 and 4000.000
Out[6]:
(<matplotlib.figure.Figure at 0x876ef60>,
 <matplotlib.axes.AxesSubplot at 0x873bf98>)

In [7]:
# convert and run tools, this requires the gizflo
# package and can be found at http://www.github.com/cfelton/gizflo
# >> pip install git+https://github.com/cfelton/gizflo

tv,xv = test(Nsmp=2, Fs=Fs, Nmax=Nmax, convert=True)


The note has a tone at 1200.000 and 4000.000
The note has a tone at 1200.000 and 4000.000
The note has a tone at 1200.000 and 4000.000