213 lines
6.7 KiB
Forth
213 lines
6.7 KiB
Forth
\ **********************************************************************
|
|
\
|
|
\ notes.fs is part of the ff-ad9833 project
|
|
\ ff-ad9833 is an audio project for FlashForth and the AD9833
|
|
\ Copyright (C) 2021 Christopher Howard
|
|
|
|
\ SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
\ This program 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.
|
|
|
|
\ This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
\ The purpose of this file is to provide words for playing musical
|
|
\ notes from several octaves of the equal temperament musical tuning
|
|
\ system. Pitches are available from the 4th, 5th, and 6th octaves,
|
|
\ and note durations are available from a double-whole-note down to a
|
|
\ 16th note. The critical words for the user to be familiar with are
|
|
\ `init-durations', `play-note', and `rest', along with the associated
|
|
\ constants.
|
|
|
|
\ Note that the system provided here does not guarantee precise timing
|
|
\ and some notes will be at least a millisecond or two off in duration
|
|
\ compared to what they should be ideally. This is due to the
|
|
\ resolution of the duration calculations, as well as the fact that we
|
|
\ are using ms to wait instead of tracking ticks.
|
|
|
|
\ public words:
|
|
\ na na# nb nc nc# nd nd# ne nf nf# ng ng# o4 o5 o6 silence pitch-on
|
|
\ d_double d_dt-whole d_whole d_dt-half d_half d_dt-quarter d_quarter
|
|
\ d_dt-8th d_8th d_dt-16th d_16th init-durations play-note rest
|
|
\
|
|
\ **********************************************************************
|
|
|
|
notes
|
|
marker notes
|
|
|
|
\ **********************************************************************
|
|
\ This section contains a frequency data table and corresponding index
|
|
\ constants for three octaves. Freq register data is packed as follows
|
|
\ (lsb to msb numbering):
|
|
\ 0-13: the 14 LSBs of the lsb register load
|
|
\ 14-15: the 2 LSBs of the msb register load
|
|
\ **********************************************************************
|
|
|
|
flash
|
|
create packed-pitches
|
|
$1274 , $138d ,
|
|
$14b7 , $15f2 ,
|
|
$1740 , $18a2 ,
|
|
$1a19 , $1ba7 ,
|
|
$1d4c , $1f0a ,
|
|
$20e2 , $22d7 ,
|
|
$24e9 , $271b ,
|
|
$296e , $2be5 ,
|
|
$2e81 , $3145 ,
|
|
$3433 , $374d ,
|
|
$3a97 , $3e13 ,
|
|
$41c4 , $45ad ,
|
|
$49d2 , $4e36 ,
|
|
$52dc , $57c9 ,
|
|
$5d02 , $628a ,
|
|
$6866 , $6e9b ,
|
|
$752e , $7c26 ,
|
|
$8388 , $8b5a ,
|
|
ram
|
|
|
|
0 constant na
|
|
1 constant na#
|
|
2 constant nb
|
|
3 constant nc
|
|
4 constant nc#
|
|
5 constant nd
|
|
6 constant nd#
|
|
7 constant ne
|
|
8 constant nf
|
|
9 constant nf#
|
|
10 constant ng
|
|
11 constant ng#
|
|
|
|
0 constant o4
|
|
1 constant o5
|
|
2 constant o6
|
|
|
|
\ **********************************************************************
|
|
\ Code for enabling and silencing pitch output
|
|
\ **********************************************************************
|
|
|
|
: pull-pitch ( note octave -- u ) 12 * + cells packed-pitches + @ ;
|
|
|
|
: pull-14lsb ( u - u ) %0011111111111111 and ;
|
|
|
|
: pull-2msb ( u - u ) %1100000000000000 and 14 rshift ;
|
|
|
|
: tx-pitch ( note octave -- )
|
|
pull-pitch cp>r pull-14lsb FREG0_PF or 2tx-spi
|
|
r> pull-2msb FREG0_PF or 2tx-spi ;
|
|
|
|
: rst-load-16 ( -- )
|
|
[ 1 B28_BT lshift ] literal
|
|
[ 1 RESET_BT lshift ] literal or 2tx-spi ;
|
|
|
|
: pitch-on ( note octave -- )
|
|
fsync-low rst-load-16 tx-pitch 0 2tx-spi fsync-high ;
|
|
|
|
: silence ( -- )
|
|
fsync-low [ 1 RESET_BT lshift ] literal 2tx-spi fsync-high ;
|
|
|
|
\ **********************************************************************
|
|
\ The system which calculates and remembers the duration of different
|
|
\ note duration types, for example, whole notes and quarter notes. It
|
|
\ keeps track of ms duration values for each duration type, with one
|
|
\ value for how long the note should be held (sustain) and one value for
|
|
\ how long to rest afterwards (release).
|
|
\
|
|
\ These values are calculated based on what value is passed to
|
|
\ `init-durations', which should be the desired duration in milliseconds
|
|
\ of a whole note. `init-durations' must be run at least once after
|
|
\ every reset and before notes are played, since the calculated values
|
|
\ are stored in ram.
|
|
\
|
|
\ The `sustain-fract' and `release-fract' constants could be edited here
|
|
\ in the code to alter the sustain and release time calculations.
|
|
\ **********************************************************************
|
|
|
|
#00 constant d_double
|
|
#01 constant d_dt-whole
|
|
#02 constant d_whole
|
|
#03 constant d_dt-half
|
|
#04 constant d_half
|
|
#05 constant d_dt-quarter
|
|
#06 constant d_quarter
|
|
#07 constant d_dt-8th
|
|
#08 constant d_8th
|
|
#09 constant d_dt-16th
|
|
#10 constant d_16th
|
|
|
|
flash
|
|
create dur-fracts
|
|
#2 c, #1 c, \ d_double
|
|
#3 c, #2 c, \ d_dt-whole
|
|
#1 c, #1 c, \ d_whole
|
|
#3 c, #4 c, \ d_dt-half
|
|
#1 c, #2 c, \ d_half
|
|
#3 c, #8 c, \ d_dt-quarter
|
|
#1 c, #4 c, \ d_quarter
|
|
#3 c, #16 c, \ d_dt-8th
|
|
#1 c, #8 c, \ d_8th
|
|
#3 c, #32 c, \ d_dt-16th
|
|
#1 c, #16 c, \ d_16th
|
|
ram
|
|
|
|
7 8 2constant sustain-frac
|
|
1 8 2constant release-frac
|
|
|
|
: base-dur ( ms dur-type -- ms )
|
|
>r dur-fracts r@ ncell+ @ low-byte *
|
|
dur-fracts r> ncell+ @ high-byte / ;
|
|
|
|
: calc-sust-dur ( ms -- ms ) sustain-frac drop * sustain-frac nip / ;
|
|
|
|
: calc-rel-dur ( ms -- ms ) release-frac drop * release-frac nip / ;
|
|
|
|
create durations 22 cells allot
|
|
|
|
: init-durations ( ms -- )
|
|
11 0 do
|
|
dup i base-dur cp>r calc-sust-dur r> calc-rel-dur
|
|
durations i 2* ncell+ 2!
|
|
loop drop ;
|
|
|
|
: sustain-dur ( dur-type -- ms ) durations swap 2* ncell+ @ ;
|
|
|
|
: release-dur ( dur-type -- ms ) durations swap 2* 1 + ncell+ @ ;
|
|
|
|
\ **********************************************************************
|
|
\ Playing notes - pitch and duration in combination.
|
|
\ **********************************************************************
|
|
|
|
: play-note ( dur-type note octave -- )
|
|
pitch-on dup sustain-dur ms silence release-dur ms ;
|
|
|
|
: rest ( dur-type -- ) silence dup sustain-dur ms release-dur ms ;
|
|
|
|
\ **********************************************************************
|
|
\ The demo code completes the following steps:
|
|
\ 1. initializes spi communications with the ad9833
|
|
\ 2. sets the fsync pin to output mode
|
|
\ 3. sets the tempo to a 1000 ms whole-note
|
|
\ 4. nulls phase register 0
|
|
\ 5. plays a brief tune
|
|
\ **********************************************************************
|
|
|
|
: demo-play-note
|
|
init-spi init-fsync 2000 init-durations
|
|
fsync-low PHREG0_PF 2tx-spi fsync-high
|
|
d_quarter nc o4 play-note
|
|
d_quarter nd# o4 play-note
|
|
d_half ng o4 play-note
|
|
d_quarter rest
|
|
d_quarter nc o5 play-note
|
|
d_8th ng o4 play-note
|
|
d_8th nd# o4 play-note
|
|
d_half nc o4 play-note ;
|