Wavetable Oscillator with Phase Reset

The Faust oscillators.lib comes with many different implementations of oscillators for various waveforms. At some point one might still need a behavior not included and lower level approaches are necessary.

This example shows how to use a phasor to read a wavetable with a sine waveform. This implementation has an additional trigger input for resetting the phase of the oscillator on each positive zero crossing. This can come handy in various applications, especially for phase-sensitive transients, as for example in kick drums.

The example is derived from Barkati et. al (2013) and part of the repository:

import("stdfaust.lib");

// some basic stuff
sr = SR;
twopi = 2.0*ma.PI;

// define the waveform in table
ts =  1<<16; // size = 65536 samples (max of unsigned short)
time = (+(1) ~ _ ) , 1 : - ;
sinewave =  ((float(time) / float(ts)) * twopi) : sin;

phase = os.hs_phasor(ts,freq,trig);

// read from table
sin_osc( freq) = rdtable(ts ,sinewave , int(phase)) ;

// generate a one sample impulse from the gate
trig =  pm.impulseExcitation(reset);

reset = button ("reset");
freq = hslider("freq", 100, 0, 16000, 0.00001);

// offset = hslider("offset", 0, 0, 1, 0.00001);

process = sin_osc(freq);
  • Karim Barkati and Pierre Jouvelot. Synchronous programming in audio processing: a lookup table oscillator case study. ACM Computing Surveys (CSUR), 46(2):1–35, 2013.
    [BibTeX▼]
  • NIME 2020: Spatialization

    Virtual Source Model

    Spectral spatialization in this system is based on a virtual sound source with a position an space and spatial extent, as shown in [Fig.1]. The source center is defined by two angles (Azimuth, Elevation) and the Distance. The Spread defines the diameter of the virtual source. This model is compliant with many theoretical frameworks from the fields of electroacoustic music and virtual acoustics.

    /images/NIME_2020/source_in_space.png
    [Fig.1] (1, 2) Virtual sound source with position an space and spatial extent.

    Point Cloud Realization

    The virtual source from [Fig.1] is realized as a cloud of point sources in an Ambisonics system using the IRCAM software Panoramix. 24 point sources can be controlled jointly. The following figures show the viewer of Panoramix, the left half representing the top view, the right half the rear view.


    [Fig.2] shows a dense point cloud of a confined virtual sound source without elevation:

    /images/NIME_2020/panoramix_confined.png
    [Fig.2] Confined virtual sound source.

    The virtual sound source in [Fig.3] has a wider spread and is elevated:

    /images/NIME_2020/panoramix_spread.png
    [Fig.3] Spread virtual sound source with elevation.

    For small distances and large spreads, the source is enveloping the listener, as shown in [Fig.4]:

    /images/NIME_2020/panoramix_enveloping.png
    [Fig.4] Enveloping virtual sound source.

    Dispersion

    In a nutshell, the synthesizer outputs the spectral components of a violin sound to 24 individual outputs. Different ways of assigning spectral content to the outputs are possible, shown as Partial to Source Mapping in [Fig.5]. In these experiments, each output represents a Bark scale frequency band. For the point cloud shown above, the distribution of spectral content is thus neither homogenous nor stationary.

    /images/NIME_2020/dispersion.png
    [Fig.5] Dispersion - routing partials to point sources.

    Back to NIME 2020 Contents

    NIME 2020: Mapping

    Extended DMI Model

    The typical DMI model connects the musical interface with the sound generation through a mapping stage. [Fig.1] shows the extended DMI model for spatial sound synthesis. The joint control of spatial and timbral characteristics offers new possibilities yet makes the mapping and the resulting control more complex.

    /images/NIME_2020/mapping_dmi.png
    [Fig.1] Mapping in the extended DMI model.

    Mapping in Puredata

    We chose Puredata as a graphical interface for mapping controller parameters to sound synthesis and spatialization. Especially in the early stage of development this solution offers maximum flexibility. [Fig.2] shows the mapping GUI as it was used by the participants in the mapping study:

    /images/NIME_2020/patching.png
    [Fig.2] Puredata patch for user-defined mappings.

    Back to NIME 2020 Contents

    NIME 2020: User Study

    User-defined Mappings

    In the first stage of the user study, participants had 30 minutes to create their own mapping, following this basic instruction:

    The objective of this part is to create an enjoyable mapping, which offers the most expressive control over all synthesis and spatialization parameters.

    A set of rules allowed one to many mappings and excluded many to one mappings:

    • Every rendering parameter of synthesis and spatialization must be influenced through the mapping.
    • Control parameters may remain unconnected.
    • A single control parameter may be mapped to multiple synthesizer or spatialization parameters.
    • A synthesis or spatialization parameter must not have more than one control parameter connected to its input.

    Mapping Frequencies

    The mapping matrix shows how some control parameters are preferred for specific tasks, considering the final mappings of all participants:

    /images/NIME_2020/matrix.png
    [Fig.1] Mapping matrix: how often was a control parameter mapped to a specific rendering parameter?

    Back to NIME 2020 Contents

    Physical Modeling: Advanced Models

    More advanced physical models can be designed, based on the principles explained in the previous sections.


    Resonant Bodies & Coupling

    The simple lowpass filter in the example can be replaced by more sophisticated models. For instruments with multiple strings, coupling between strings can be implemented.

    /images/Sound_Synthesis/physical_modeling/plucked-string-instrument.png

    Model of a wind instrument with several waveguides, connected with scattering junctions (de Bruin, 1995):

    /images/Sound_Synthesis/physical_modeling/wind_waveguide.jpg

    References

  • Vesa Välimäki. Discrete-time modeling of acoustic tubes using fractional delay filters. Helsinki University of Technology, 1995.
    [BibTeX▼]
  • Gijs de Bruin and Maarten van Walstijn. Physical models of wind instruments: A generalized excitation coupled with a modular tube simulation platform*. Journal of New Music Research, 24(2):148–163, 1995.
    [BibTeX▼]
  • Matti Karjalainen, Vesa Välimäki, and Zoltán Jánosy. Towards High-Quality Sound Synthesis of the Guitar and String Instruments. In Computer Music Association, 56–63. 1993.
    [BibTeX▼]
  • Julius O Smith. Physical modeling using digital waveguides. Computer music journal, 16(4):74–91, 1992.
    [BibTeX▼]
  • Lejaren Hiller and Pierre Ruiz. Synthesizing musical sounds by solving the wave equation for vibrating objects: part 1. Journal of the Audio Engineering Society, 19(6):462–470, 1971.
    [BibTeX▼]
  • Lejaren Hiller and Pierre Ruiz. Synthesizing musical sounds by solving the wave equation for vibrating objects: part 2. Journal of the Audio Engineering Society, 19(7):542–551, 1971.
    [BibTeX▼]
  • Physical Modeling: Faust Examples

    The functional principle of Faust is very well suited for programming physical models for sound synthesis, since these are usually described in block diagrams. Working with physical modeling in Faust can happen on many levels of complexity, from using ready instruments to basic operations.

    Ready Instruments

    For a quick start, fully functional physical modeling instruments can be used from the physmodels.lib library. These *_ui_MIDI functions just need to be called in the process function:

    import("all.lib");
    
    process = nylonGuitar_ui_MIDI : _;
    

    The same algortithms can also be used on a slightly lower level, combining them with custom control and embedding them into larger models:

    import("all.lib");
    
    process = nylonGuitarModel(3,1,button("trigger")) : _;
    

    Ready Elements

    The physmodels.lib library comes with many building blocks for physical modeling, which can be used to compose instruments. These blocks are instrument-specific, as for example:

    • (pm.)nylonString
    • (pm.)violinBridge
    • (pm.)fluteHead

    Bidirectional Utilities & Basic Elements

    The bidirectional utitlities and basic elements in Faust's physical modeling library offer a more direct way of assembling physical models. This includes waveguides, terminations, excitation and others:

    • (pm.)chain
    • (pm.)waveguide
    • (pm.)lTermination
    • (pm.)rTermination
    • (pm.)in

    From Scratch

    Taking a look at the physmodels.lib library, even the bidirectional utilities and basic elements are made of standard faust functions:

    https://github.com/grame-cncm/faustlibraries/blob/master/physmodels.lib

    chain(A:As) = ((ro.crossnn(1),_',_ : _,A : ro.crossnn(1),_,_ : _,chain(As) : ro.crossnn(1),_,_)) ~ _ : !,_,_,_;
    chain(A) = A;
    

    Karplus-Strong in Faust

    // karplus_strong.dsp
    //
    // Slightly modified version of the
    // Karplus-Strong plucked string algorithm.
    //
    // see: 'Making Virtual Electric Guitars and Associated Effects Using Faust'
    //             (Smith, )
    //
    // - one-pole lowpass in the feedback
    //
    // Henrik von Coler
    // 2020-06-07
    
    import("all.lib");
    
    ////////////////////////////////////////////////////////////////////////////////
    // Control parameters as horizonal sliders:
    ////////////////////////////////////////////////////////////////////////////////
    
    freq = hslider("freq Hz", 50, 20, 1000, 1) : si.smoo; // Hz
    
    // initial filter for the excitation noise
    initial_filter = hslider("initial_filter Hz",1000,10,10000,1) : si.smoo;
    lop = hslider("lop Hz",1000,10,10000,1) : si.smoo;
    
    level = hslider("level", 1, 0, 10, 0.01);
    gate = button("gate");
    gain = hslider("gain",  1, 0, 1, 0.01);
    
    ////////////////////////////////////////////////////////////////////////////////
    // processing elements:
    ////////////////////////////////////////////////////////////////////////////////
    
    diffgtz(x) = (x-x') > 0;
    decay(n,x) = x - (x>0)/n;
    release(n) = + ~ decay(n);
    trigger(n) = diffgtz : release(n) : > (0.0);
    
    
    P = SR/freq;
    
    // Resonator:
    resonator = (+ : delay(4096, P) * gain) ~ si.smooth(1.0-2*(lop/ma.SR));
    
    ////////////////////////////////////////////////////////////////////////////////
    // processing function:
    ////////////////////////////////////////////////////////////////////////////////
    
    
    process = noise : si.smooth(1.0-2*(initial_filter/ma.SR)):*(level)
    : *(gate : trigger(P)): resonator <: _,_;
    

    Waveguide-Strings in Faust

    // waveguide_string.dsp
    //
    // waveguide model of a string
    //
    // - one-pole lowpass termination
    //
    // Henrik von Coler
    // 2020-06-09
    
    
    import("all.lib");
    
    // use '(pm.)l2s' to calculate number of samples
    // from length in meters:
    
    segment(maxLength,length) = waveguide(nMax,n)
    with{
    nMax = maxLength : l2s;
    n = length : l2s/2;
    };
    
    
    
    
    // one lowpass terminator
    fc = hslider("lowpass",1000,10,10000,1);
    rt = rTermination(basicBlock,*(-1) : si.smooth(1.0-2*(fc/ma.SR)));
    
    // one gain terminator with control
    gain = hslider("gain",0.99,0,1,0.01);
    lt = lTermination(*(-1)* gain,basicBlock);
    
    
    idString(length,pos,excite) = endChain(wg)
    with{
    
    nUp   = length*pos;
    
    nDown = length*(1-pos);
    
    wg = chain(lt : segment(6,nUp) : in(excite) : out : segment(6,nDown) : rt); // waveguide chain
    };
    
    length = hslider("length",1,0.1,10,0.01);
    process = idString(length,0.15, button("pluck")) <: _,_;
    

    Physical Modeling: Karplus Strong - Implementation

    plucked_string_444.png


    import numpy as np
    from   numpy import linspace, sin, zeros
    from   math import pi
    %matplotlib notebook
    import matplotlib.pyplot as plt
    from   tikzplotlib import save as tikz_save
    
    from   IPython.display import display, Markdown, clear_output
    import IPython.display as ipd
    import ipywidgets as widgets
    from   ipywidgets import *
    
    
    
    
    fs          = 48000
    L           = 500
    
    
    
    # a function for appending the array again and again
    # arbitrary 300 times ...
    def appender(x):
        y = np.array([])
    
        for i in range(300):
            y = np.append(y,x*0.33)
    
        return y
    
    
    x = np.random.standard_normal(L)
    y = appender(x)
    
    t = np.linspace(0,len(y)/fs,len(y))
    f = np.linspace(0,1,len(y))
    
    fig   = plt.figure()
    ax    = fig.add_subplot(2, 1, 1)
    line, = ax.plot(t,y)
    
    ax2    = fig.add_subplot(2, 1, 2)
    Y = abs(np.fft.fft(y))
    
    Y = Y[0:5000]
    f = f[0:5000]
    
    line2, = ax2.plot(f,Y)
    
    def update(L = widgets.IntSlider(min = 10, max= 1500, step=1, value=500)):
    
        x = np.random.standard_normal(L)
        y = appender(x)
    
        t = np.linspace(0,len(y)/fs,len(y))
        f = np.linspace(0,1,len(y))
    
        Y = abs(np.fft.fft(y))
        Y = Y[0:5000]
        f = f[0:5000]
    
        line.set_ydata(y)
        line2.set_ydata(Y)
    
        fig.canvas.draw_idle()
        ipd.display(ipd.Audio(y, rate=fs))
    
    
    
    interact(update);
    
    <IPython.core.display.Javascript object>
    
    interactive(children=(IntSlider(value=500, description='L', max=1500, min=10), Output()), _dom_classes=('widge…
    

    Karplus-Strong

    Karplus-Strong makes use of the random buffer.

    # this implementation serves for a better
    # understanding and is not efficient
    #
    # - wait for process to be finished in
    #   interactive use
    
    
    fs          = 48000
    L           = 500
    
    # the feedback gain
    gain   = 0.99
    
    # the number of samples used for smoothing
    smooth = 10
    
    
    def karplus_strong(L,gain,smooth):
    
        x = np.random.standard_normal(L)
        y = np.array([])
    
    
        for i in range(96000):
            k   = i%L
            tmp = 0;
    
            for j in range(smooth):
                tmp += x[(k+j) %L]
    
            tmp = tmp/smooth
    
            x[k] = gain*tmp
            y = np.append(y,tmp)
    
        return y
    
    
    y = karplus_strong(L,gain,smooth)
    
    t = np.linspace(0,len(y)/fs,len(y))
    f = np.linspace(0,1,len(y))
    
    fig   = plt.figure()
    ax    = fig.add_subplot(2, 1, 1)
    line, = ax.plot(t,y)
    
    ax2    = fig.add_subplot(2, 1, 2)
    Y = abs(np.fft.fft(y))
    
    Y = Y[0:5000]
    f = f[0:5000]
    
    line2, = ax2.plot(f,Y)
    
    def update(b = widgets.ToggleButtons( options=['Recalculate','Recalculate'],disabled=False),
              L = widgets.IntSlider(min = 10, max= 1500, step=1, value=500),
               gain = widgets.FloatSlider(min = 0.8, max= 1, step=0.01, value=0.99),
              smooth = widgets.IntSlider(min = 1, max= 20, step=1, value=10)):
    
        print(b)
        y = karplus_strong(L,gain,smooth)
    
        t = np.linspace(0,len(y)/fs,len(y))
        f = np.linspace(0,1,len(y))
    
        Y = abs(np.fft.fft(y))
        Y = Y[0:5000]
        f = f[0:5000]
    
        line.set_ydata(y)
        line2.set_ydata(Y)
    
        fig.canvas.draw_idle()
        ipd.display(ipd.Audio(y, rate=fs))
    
    
    
    interact(update);
    
    <IPython.core.display.Javascript object>
    
    interactive(children=(ToggleButtons(description='b', options=('Recalculate', 'Recalculate'), value='Recalculat…
    

    References

  • Vesa Välimäki. Discrete-time modeling of acoustic tubes using fractional delay filters. Helsinki University of Technology, 1995.
    [BibTeX▼]
  • Gijs de Bruin and Maarten van Walstijn. Physical models of wind instruments: A generalized excitation coupled with a modular tube simulation platform*. Journal of New Music Research, 24(2):148–163, 1995.
    [BibTeX▼]
  • Matti Karjalainen, Vesa Välimäki, and Zoltán Jánosy. Towards High-Quality Sound Synthesis of the Guitar and String Instruments. In Computer Music Association, 56–63. 1993.
    [BibTeX▼]
  • Julius O Smith. Physical modeling using digital waveguides. Computer music journal, 16(4):74–91, 1992.
    [BibTeX▼]
  • Lejaren Hiller and Pierre Ruiz. Synthesizing musical sounds by solving the wave equation for vibrating objects: part 1. Journal of the Audio Engineering Society, 19(6):462–470, 1971.
    [BibTeX▼]
  • Lejaren Hiller and Pierre Ruiz. Synthesizing musical sounds by solving the wave equation for vibrating objects: part 2. Journal of the Audio Engineering Society, 19(7):542–551, 1971.
    [BibTeX▼]
  • Physical Modeling: Karplus Strong Algorithm

    References

  • Vesa Välimäki. Discrete-time modeling of acoustic tubes using fractional delay filters. Helsinki University of Technology, 1995.
    [BibTeX▼]
  • Gijs de Bruin and Maarten van Walstijn. Physical models of wind instruments: A generalized excitation coupled with a modular tube simulation platform*. Journal of New Music Research, 24(2):148–163, 1995.
    [BibTeX▼]
  • Matti Karjalainen, Vesa Välimäki, and Zoltán Jánosy. Towards High-Quality Sound Synthesis of the Guitar and String Instruments. In Computer Music Association, 56–63. 1993.
    [BibTeX▼]
  • Julius O Smith. Physical modeling using digital waveguides. Computer music journal, 16(4):74–91, 1992.
    [BibTeX▼]
  • Lejaren Hiller and Pierre Ruiz. Synthesizing musical sounds by solving the wave equation for vibrating objects: part 1. Journal of the Audio Engineering Society, 19(6):462–470, 1971.
    [BibTeX▼]
  • Lejaren Hiller and Pierre Ruiz. Synthesizing musical sounds by solving the wave equation for vibrating objects: part 2. Journal of the Audio Engineering Society, 19(7):542–551, 1971.
    [BibTeX▼]
  • Physical Modeling: Waveguides - Implementation

    import numpy as np
    from   numpy import linspace, sin, zeros
    from   math import pi
    %matplotlib notebook
    import matplotlib.pyplot as plt
    from   tikzplotlib import save as tikz_save
    
    from   IPython.display import display, Markdown, clear_output
    import IPython.display as ipd
    import ipywidgets as widgets
    from   ipywidgets import *
    
    
    
    fs          = 48000
    
    ###################################################################
    # function for plucking the string
    
    def pluck(L,P):
    
        x_L = np.zeros(L);
        x_R = np.zeros(L);
    
        x_L[1:P] = np.linspace(0,1,P-1)
        x_R[1:P] = np.linspace(0,1,P-1)
    
        x_L[P:L-1] = np.linspace(1,0,L-P-1)
        x_R[P:L-1] = np.linspace(1,0,L-P-1)
    
        return x_L, x_R
    
    ###################################################################
    # function: - get the next output sample
    #           - shift all buffers
    
    def next_step(x_L, x_R, filt, g, pick):
    
        # delay line outputs
        l_out = x_L[0]
        r_out = x_R[len(x_R)-1]
    
        # filter output
        f_out = sum(filt)/len(filt)
    
        # shift all arrays
        x_L   = np.roll(x_L,-1)
        x_R   = np.roll(x_R,1)
        filt  = np.roll(filt,1)
    
        # insert output values
        x_L[len(x_L)-1] = -f_out
        x_R[0]          = -l_out * g
        filt[0]         = r_out
    
        out =  x_L[pick] + x_L[pick]
    
        return x_L, x_R, filt, out
    
    
    ###################################################################
    
    # length of the delay line:
    L = 300
    # feedback gain:
    g = 0.95
    # pluck position:
    pluck_pos = 3
    # pickup position:
    pick = 5
    # filter length:
    N = 20
    
    
    ###################################################################
    # the update function offers control over all parameters
    # - wait for the process to be finished
    # - it can take a couple of seconds until the new sound is ready
    
    def update(L     = widgets.IntSlider(min = 100, max= 500, step=1, value=300, continuous_update=False),
               g     = widgets.FloatSlider(min = 0.5, max= 1, step=0.01, value=0.95, continuous_update=False),
               pluck_pos = widgets.IntSlider(min = 0, max= 99, step=1, value=3, continuous_update=False),
               pick_pos  = widgets.IntSlider(min = 0, max= 99, step=1, value=5, continuous_update=False),
               N     = widgets.IntSlider(min = 1, max= 50, step=1, value=20, continuous_update=False)):
    
        x_L, x_R = pluck(L,pluck_pos)
    
        y = np.array([])
    
        # the filter is a simple moving average
        filt = np.zeros(N)
    
        for idx in range(2*fs):
    
            x_L, x_R, filt, out = next_step(x_L, x_R, filt, g, pick_pos)
            y = np.append(y,out)
    
        ipd.display(ipd.Audio(y, rate=fs))
    
    interact(update);
    
    interactive(children=(IntSlider(value=300, continuous_update=False, description='L', max=500, min=100), FloatS…
    

    References

  • Vesa Välimäki. Discrete-time modeling of acoustic tubes using fractional delay filters. Helsinki University of Technology, 1995.
    [BibTeX▼]
  • Gijs de Bruin and Maarten van Walstijn. Physical models of wind instruments: A generalized excitation coupled with a modular tube simulation platform*. Journal of New Music Research, 24(2):148–163, 1995.
    [BibTeX▼]
  • Matti Karjalainen, Vesa Välimäki, and Zoltán Jánosy. Towards High-Quality Sound Synthesis of the Guitar and String Instruments. In Computer Music Association, 56–63. 1993.
    [BibTeX▼]
  • Julius O Smith. Physical modeling using digital waveguides. Computer music journal, 16(4):74–91, 1992.
    [BibTeX▼]
  • Lejaren Hiller and Pierre Ruiz. Synthesizing musical sounds by solving the wave equation for vibrating objects: part 1. Journal of the Audio Engineering Society, 19(6):462–470, 1971.
    [BibTeX▼]
  • Lejaren Hiller and Pierre Ruiz. Synthesizing musical sounds by solving the wave equation for vibrating objects: part 2. Journal of the Audio Engineering Society, 19(7):542–551, 1971.
    [BibTeX▼]
  • Physical Modeling: Waveguides

    Wave Equation for Virtual Strings

    The wave-equation for the one dimensional ideal string:

    \(\frac{\partial^2 y}{\partial t^2} = c^2 \frac{\partial^2 y}{\partial x^2}\)

    Solution without losses (d'Alembert):

    \(y(x,t) = y^+ (x-ct) + y^- (x+ct)$\)

    • \(y^+\) = left traveling wave
    • \(y^-\) = right traveling wave

    Tuning the String

    The velocity \(c\) depends on tension \(K\) and mass-density \(\epsilon\) of the string:

    \(c^2 = \sqrt{\frac{K}{\epsilon}} = \sqrt{\frac{K}{\rho S}}\)

    With tension \(K\), cross sectional area \(S\) and density \(\rho\) in \({\frac{g}{cm^3}}\).

    Frequency \(f\) of the vibrating string depends on the velocity and the string length:

    \(f = \frac{c}{2 L}\)

    Make it Discrete

    \(y(m,n) = y^+ (m,n) + y^- (m,n)\)

    \(t = \ nT\)

    \(x = \ mX\)

    Spatial sample distance \(X\) depends on sampling-rate \(f_s = \frac{1}{T}\) and velocity \(c\):

    \(X = cT\)


    An ideal, lossless string is represented by two delay lines with direct coupling.

    /images/Sound_Synthesis/physical_modeling/schematic_3.png

    Losses

    Losses can be implemented by inserting filters between the delay lines.

    /images/Sound_Synthesis/physical_modeling/schematic_1.png

    References

  • Vesa Välimäki. Discrete-time modeling of acoustic tubes using fractional delay filters. Helsinki University of Technology, 1995.
    [BibTeX▼]
  • Gijs de Bruin and Maarten van Walstijn. Physical models of wind instruments: A generalized excitation coupled with a modular tube simulation platform*. Journal of New Music Research, 24(2):148–163, 1995.
    [BibTeX▼]
  • Matti Karjalainen, Vesa Välimäki, and Zoltán Jánosy. Towards High-Quality Sound Synthesis of the Guitar and String Instruments. In Computer Music Association, 56–63. 1993.
    [BibTeX▼]
  • Julius O Smith. Physical modeling using digital waveguides. Computer music journal, 16(4):74–91, 1992.
    [BibTeX▼]
  • Lejaren Hiller and Pierre Ruiz. Synthesizing musical sounds by solving the wave equation for vibrating objects: part 1. Journal of the Audio Engineering Society, 19(6):462–470, 1971.
    [BibTeX▼]
  • Lejaren Hiller and Pierre Ruiz. Synthesizing musical sounds by solving the wave equation for vibrating objects: part 2. Journal of the Audio Engineering Society, 19(7):542–551, 1971.
    [BibTeX▼]


  • Contents © Henrik von Coler 2020 - Contact