100 lines
3.2 KiB
Forth
100 lines
3.2 KiB
Forth
\ **********************************************************************
|
|
\
|
|
\ score.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 module is to provide a convenient system for
|
|
\ laying out a (single channel) musical melody in memory, and playing
|
|
\ it, using the notes.fs interface.
|
|
|
|
\ Note that, while note timing and tempo will be well within the
|
|
\ accuracy tolerances of human perception, the actual tempo will drift
|
|
\ out of sync with a precise metronome. This is for reasons described in
|
|
\ the notes module.
|
|
|
|
\ public words:
|
|
\ == nr end-score play-score
|
|
\
|
|
\ **********************************************************************
|
|
|
|
score
|
|
marker score
|
|
|
|
\ **********************************************************************
|
|
\ Internal helper words for packing and unpacking notes into the score
|
|
\ **********************************************************************
|
|
|
|
: pack-pitch ( octave u -- u ) swap #4 lshift or ;
|
|
|
|
: pack-dur ( dur-type u -- u ) swap #8 lshift or ;
|
|
|
|
: unpack-dur ( u -- dur-type u ) dup high-byte swap ;
|
|
|
|
: unpack-pitch ( u -- pitch u ) dup low-byte #4 rshift swap ;
|
|
|
|
: unpack-oct ( u -- octave ) %1111 and ;
|
|
|
|
: unpack-note ( u -- dur-type pitch octave )
|
|
unpack-dur unpack-pitch unpack-oct ;
|
|
|
|
\ **********************************************************************
|
|
\ Public words needed for laying out a score in memory. Each note should
|
|
\ be laid out in this form:
|
|
|
|
\ dur-type pitch octave ==
|
|
|
|
\ The dur-type, pitch, and octave constants are taken from the note
|
|
\ module. The `==' packs the note into a single 16-bit cell and then
|
|
\ stores it in the current memory section with the `,' word.
|
|
|
|
\ To use a rest note, use the form
|
|
|
|
\ dur-type NR NR ==
|
|
|
|
\ where NR is the `nr' constant.
|
|
|
|
\ At the end of your score, instead of inputting a note, use the
|
|
\ `end-score' word to store a end-of-score marker in memory. And example
|
|
\ score is given below.
|
|
|
|
\ Play a score by passing the memory address of your score to the
|
|
\ `play-score' word.
|
|
|
|
\ The score format is one 16-bit cell per note:
|
|
|
|
\ bits 0-3: octave
|
|
\ bits 4-7: pitch
|
|
\ bits 8-15: dur-type
|
|
|
|
\ The end-of-score marker a 16-bit cell filled with $ffff.
|
|
\ **********************************************************************
|
|
|
|
: == ( dur-type pitch octave -- ) pack-pitch pack-dur , ;
|
|
|
|
%1110 constant nr
|
|
|
|
: end-score $ffff , ;
|
|
|
|
: play-score ( a -- )
|
|
begin dup @ dup $ffff <> while
|
|
unpack-note dup %1111 and %1110 <> if
|
|
play-note else
|
|
drop drop rest then
|
|
cell + repeat drop drop ;
|