shepard_scale Program

Uses

  • program~~shepard_scale~~UsesGraph program~shepard_scale shepard_scale module~audio_effects audio_effects program~shepard_scale->module~audio_effects module~forsynth forsynth program~shepard_scale->module~forsynth module~wav_file_class wav_file_class program~shepard_scale->module~wav_file_class module~audio_effects->module~forsynth module~tape_recorder_class tape_recorder_class module~audio_effects->module~tape_recorder_class iso_fortran_env iso_fortran_env module~forsynth->iso_fortran_env module~wav_file_class->module~forsynth module~wav_file_class->iso_fortran_env module~wav_file_class->module~tape_recorder_class module~tape_recorder_class->module~forsynth

A Shepard scale, giving the illusion of an ever increasing pitch in the first half of the tape and an ever decreasing pitch in the 2nd half. Shepard, Roger N. "Circularity in Judgments of Relative Pitch", The Journal of the Acoustical Society of America 36, no. 12, (December 1, 1964): 2346–53. https://doi.org/10.1121/1.1919362. https://en.wikipedia.org/wiki/Shepard_tone


Calls

program~~shepard_scale~~CallsGraph program~shepard_scale shepard_scale proc~apply_reverse_effect apply_reverse_effect program~shepard_scale->proc~apply_reverse_effect proc~close_wav_file WAV_file%close_WAV_file program~shepard_scale->proc~close_wav_file proc~create_wav_file WAV_file%create_WAV_file program~shepard_scale->proc~create_wav_file proc~get_name WAV_file%get_name program~shepard_scale->proc~get_name proc~mix_tracks tape_recorder%mix_tracks program~shepard_scale->proc~mix_tracks proc~finalize tape_recorder%finalize proc~close_wav_file->proc~finalize proc~write_normalized_data WAV_file%write_normalized_data proc~close_wav_file->proc~write_normalized_data proc~new tape_recorder%new proc~create_wav_file->proc~new proc~write_header WAV_file%write_header proc~create_wav_file->proc~write_header proc~clear_tracks tape_recorder%clear_tracks proc~new->proc~clear_tracks

Variables

Type Attributes Name Initial
real(kind=wp) :: Amp
real(kind=wp) :: L
real(kind=wp), parameter :: Lmax = 56._wp
real(kind=wp), parameter :: Lmin = 22._wp
integer :: c
integer, parameter :: cmax = 12
real(kind=wp), parameter :: d = 0.125_wp
type(WAV_file) :: demo
real(kind=wp), parameter :: ds = 0.840_wp
real(kind=wp) :: f
real(kind=wp), parameter :: fmin = 4.863_wp
integer :: i
integer :: k
integer, parameter :: kmax = 9
real(kind=wp) :: omega
integer :: t
real(kind=wp) :: teta
real(kind=wp) :: ti
real(kind=wp) :: ti0
integer, parameter :: tmax = 12

Source Code

program shepard_scale
    use forsynth, only: wp, dt, RATE, PI
    use wav_file_class, only: WAV_file
    use audio_effects, only: apply_reverse_effect

    implicit none
    type(WAV_file) :: demo
    ! Time in seconds:
    real(wp) :: ti, ti0
    ! Pulsation (radians/second):
    real(wp) :: omega
    real(wp) :: Amp
    integer  :: i, k
    !--------------------------
    ! Shepard scale parameters:
    !--------------------------
    ! t th tone:
    integer :: t
    integer, parameter :: tmax = 12
    ! Components of each tone:
    integer :: c
    ! The number of components was 10 in the paper, but the bandwidth was
    ! 5 kHz instead of 20 kHz. We have therefore added two octaves:
    integer, parameter  :: cmax = 12
    ! Sound pressure levels in dB for the components:
    real(wp) :: L
    real(wp), parameter :: Lmin = 22._wp
    real(wp), parameter :: Lmax = 56._wp
    ! Frequency of the lowest component of the first tone:
    real(wp), parameter :: fmin = 4.863_wp      ! D#
    ! Duration of a tone and of the following silence:
    real(wp), parameter :: d = 0.125_wp
    real(wp), parameter :: ds = 0.840_wp
    real(wp) :: teta, f
    ! Number of repetitions:
    integer, parameter ::  kmax = 9

    print *, "**** Creating shepard_scale.wav ****"
    ! We create a new WAV file, and define the number of tracks and its duration:
    call demo%create_WAV_file('shepard_scale.wav', tracks=1, duration=120._wp)

    associate(tape => demo%tape_recorder)

    ! Repeat the Shepard scale:
    do k = 0, kmax
        ! Tones loop:
        do t = 1, tmax
            ! Components loop:
            do c = 1, cmax
                ! Equations from the Shepard paper:
                f = fmin * 2._wp**(((c-1)*tmax + t -1) / real(tmax, kind=wp))
                omega = 2*PI*f
                teta = (2*PI * (c-1)*tmax + t -1) / (tmax*cmax)
                L = Lmin + (Lmax-Lmin) * (1._wp - cos(teta)) / 2._wp
                ! Converting dB to linear amplitude:
                Amp = 10._wp ** (L / 20._wp)

                ! Writing a sinusoidal signal at ti0, for a duration d.
                ! We do not write silences (the tape is initially silent).
                ti0 = k*tmax*(d + ds) + t*(d + ds)
                ti = ti0
                do i = nint(ti0*RATE), nint((ti0+d)*RATE)-1
                    tape%left(1, i)  = tape%left(1, i) + Amp * sin(omega*ti)
                    ti = ti + dt
                end do
            end do
        end do
    end do
    tape%right = tape%left
    ! The 2nd half of the track is reversed to obtain an ever decreasing pitch:
    call apply_reverse_effect(tape, track=1, t1=(1+kmax)/2*tmax*(d+ds), t2=(1+kmax)*tmax*(d+ds) + d)
    end associate

    ! All tracks will be mixed on track 0.
    ! Needed even if there is only one track!
    call demo%mix_tracks()
    call demo%close_WAV_file()

    print *,"You can now play the file ", demo%get_name()
end program shepard_scale