Prof.Dr.Godfried-Willem RAES
<GMT> - G_MUS.DLL
< Harmony Library> : Reference Manual: Module 4: Harm_psy functions
<Index > | <Introduction> | <General Functions> |
<Fuzzy Functions> | <Analysis Functions> | <Acoustical Functions> |
<Visualisation Functions> | <File Management> | <Spectral Functions> |
Harmony functions and procedures based on audioperception theory
These functions do use an extended form of shepard chord description.Here the harmonic situation on a given time is represented by a structure (implemented as a variable of user-type named and declared HarmType - the prototype declaration can be found in the file g_type.inc)). The fundamental harmonic data reside in a string of fixed lenght (128 bytes, named Har.Vel in the code, if Har is defined as DIM Har AS Harmtype).
Each byte in this string represents the absolute loudness of a pitch in the totality. Pitches are represented as midi-note numbers and correspond to the individual byte positions (pointer) in the string. The string should be set to contain only ASC(0) before using the string. (Use of Har.Vel = STRING$(128,0) works perfect to this end). The basic-default otherwize would be the space character, since that's what Basic assumes as a default for fixed-lenght strings...). The highest bit should never be set in any byte of the string (7-bit numbers only, for compatibility with the midi standard). The conversion to a shepard-format is performed by either the procedure GetHarmPsy, returning the array Har.C() within the structure, or by calling FillHarType with the structure as input. (cfr. the examples given further). In this array (Har.C() in our example) the pointer represents the individual tones of the shepard chord, whereas the (normalized) values represent the strenght of each tone component. The structure HarmType can be understood from studying its declaration as type in the type declaration include file. (cfr. g_type.bi headers, for the most up-to-date version):
- Vel AS STRING * 128 ' complete harmony descriptor
- C(0 TO 11) AS SINGLE ' fuzzy shepard chord descriptor
- Dis AS SINGLE ' fuzzy dissonance of the harmony
- Kon AS SINGLE ' fuzzy consonance of the harmony
- Iprop(0 TO 6) AS SINGLE ' interval property strenghts
Alphabetical list of procedures and functions in 'HARM_PSY'
- FUNCTION AbsDifHar$ (H1 AS HarmType, H2 AS HarmType)
- SUB AddCnr2Har (H AS HarmType, chordnumber%,l%, h%, velo%)
- SUB AddNote2Har (H AS HarmType, note, velo)
- SUB AddShNo2Har (H AS HarmType, note, velo)
- FUNCTION CommonHar$ (H1 AS HarmType, H2 AS HarmType)
- FUNCTION ComplementHar$ (H AS Harmtype, BYVAL ltes AS BYTE, BYVAL hTes AS BYTE)
- FUNCTION ConvergeHar$ (H AS HarmType, refnote%, factor!)
- SUB DelNote2Har (H AS HarmType, note%)
- SUB DelShNo2Har (H AS HarmType, note%)
- FUNCTION DifHar$ (H1 AS HarmType, H2 AS HarmType)
- FUNCTION DimIntInHar$ (H AS HarmType, tc%, mode%, degree%, sign%)
- FUNCTION DiminuteHar$ (H AS HarmType, tc%, mode%, steps%)
- SUB FillHarType (H AS HarmType)
- FUNCTION Fit2Mode$ (H AS HarmType, mode%, tc%)
- FUNCTION GetConPsy! (H AS HarmType)
- FUNCTION GetDisPsy! (H AS HarmType)
- SUB GetIntProp (H AS HarmType)
- FUNCTION GetNrInt% (H AS HarmType, interval%, norm!)
- SUB GetPsiChord (H AS HarmType)
- FUNCTION GetScaleHar$ (mode%, tc%, vel%)
- FUNCTION GetShepVal! (note%)
- FUNCTION GetStrongest% (H AS HarmType, n%)
- FUNCTION GetHighestNote (h as HarmType, byval lowlimit as byte, byval highlimit as byte) as integer
- FUNCTION Har2Cnr% (H AS HarmType, norm!)
- FUNCTION Har2Mel (BYVAL nInst AS BYTE, h AS harmtype,BYVAL ltes AS BYTE, BYVAL htes AS BYTE) AS WORD
- FUNCTION Har2MelAr (H AS Harmtype, m() as WORD) AS LONG
- FUNCTION InBetweenHar$ (H1 AS HarmType, H2 AS HarmType)
- FUNCTION InBetweenHarDown$ (H1 AS HarmType, H2 AS HarmType)
- FUNCTION InBetweenHarUp$ (H1 AS HarmType, H2 AS HarmType)
- FUNCTION MorfHar$ (H1 AS HarmType, H2 AS HarmType, modus%, tc%,db%)
- SUB P2Har (H AS HarmType, i&, p%())
- FUNCTION SolveHar$ (H AS HarmType, note%, norm!)
- FUNCTION SolveMaj2$ (H AS HarmType, note%, norm!)
- FUNCTION SolveMin2$ (H AS HarmType, note%, norm!)
- FUNCTION SolveTrit$ (H AS HarmType, note%, norm!)
- SUB SubstNtInHar (H AS HarmType, note1%, note2%)
- FUNCTION SumHar$ (H1 AS HarmType, H2 AS HarmType)
- FUNCTION SumVelo (v1, v2)
- FUNCTION SymDimHar$ (H AS HarmType, Tc%, sign%)
- FUNCTION StealNoteFromHar (H AS HarmType, oldnoot%, lowtes%, hightes%)
- SUB TransHarm (h AS Harmtype, BYVAL n AS INTEGER)
Structure-creating functions and procedures:
SUB FillHarType (H AS HarmType)
This procedure updates the whole data-structure according to the harmony string passed via H.vel. It calls all the following procedures and functions in a row:
- GetPsichord ()
- GetIntProp ()
- GetDisPsy ()
- GetConPsy ()
After calling this procedure, all fields of the datastructure will be updated based on the contents of the harmony string contained in H.Vel.
Application code example:
' find a chord with non-zero consonance...
- DIM Har AS HarmType : DIM vel AS BYTE
- modus%= 3
- tc%= 5
- DO
- Har.vel = STRING$(128, 0): ' blank harmony string
- note1% = GetRndNote%(modus%, tc%) + 12
- note2% = GetRndNote%(modus%, tc%) + 12
- note3% = GetRndNote%(modus%, tc%) + 12
- crd% = Make3ChordNum%(note1%, note2%, note3%)
- crd% = SetTc%(crd%, tc%)
- FOR il% = 0 TO 11
- IF IsNoteInChord% (crd%,i%) THEN
- vel = RND(1) * 127
- AddNote2Har Har, 60 + il%, vel
- END IF
- NEXT il%
- ' here we call the procedure to fill the whole type:
- FillHarType Har
- LOOP UNTIL Har.Kon > 0
- ShowPsiChord Har, 1, 200, 120, 120
- ShowHar Har, 50, 440, 1: '1.5
- #IF %DEF(%pb_cc32)
- LOCATE 1, 1: PRINT "D=";
- PRINT USING "#.######"; Har.Dis;
- LOCATE 2, 1: PRINT "C=";
- PRINT USING "#.######"; Har.Kon;
- #ELSE
- MSGBOX " D=" & STR$(Har.Dis) & " C=" & STR$(Har.Kon)
- #ENDIF
SUB GetPsiChord (H AS HarmType)
This procedure operates as a function and returns the H.C() array (enclosed in the H-type) with weighted values for the toneness of each note in the global harmony given in H.Vel (a string of 128 bytes). The values in the returned array are normalized. A call to GetPsiChord is required for all functions and procedures included herein making use of weighted shepard arrays, unless FillHarType was called in full.
SUB GetIntProp (H AS HarmType)
This procedure calculates the normalized strenght values for individual interval-strenght for intervals 0 to 6. The result is returned in Har.Iprop(0 TO 6), single precision and is normalized. Its values can be interpreted as the 'major-third-ness' of a give chord in Har.Iprop(4), or, the 'Fourth/Fifth ness ' of a given chord in Har.Iprop(5) etc... Composers can use these values to determine the 'hours' for triads in conformance with Peter Schat's tone clock. The 1's in the table below can be read as any non-zero value.
hour | H.Iprop(0) prime | H.Iprop(1) semitone | H.Iprop(2) tone | H.Iprop(3) minor thirth | H.Iprop(4) major thirth | H.Iprop(5) fourth | H.Iprop(6) triton |
1 | 0 | 1 | 1 | 0 | 0 | 0 | 0 |
2 | 0 | 1 | 1 | 1 | 0 | 0 | 0 |
3 | 0 | 1 | 0 | 1 | 1 | 0 | 0 |
4 | 0 | 1 | 0 | 0 | 1 | 1 | 0 |
5 | 0 | 1 | 0 | 0 | 0 | 1 | 1 |
6 | 0 | 0 | 1 | 0 | 1 | 0 | 0 |
7 | 0 | 0 | 1 | 1 | 0 | 1 | 0 |
8 | 0 | 0 | 1 | 0 | 1 | 0 | 1 |
9 | 0 | 0 | 1 | 0 | 0 | 1 | 0 |
10 | 0 | 0 | 0 | 1 | 0 | 0 | 1 |
11 | 0 | 0 | 0 | 1 | 1 | 1 | 0 |
12 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
If a chord contains only a single note, only H.Iprop(0) will have a value.
All diads are given by:
diad | H.Iprop(0) prime | H.Iprop(1) semitone | H.Iprop(2) tone | H.Iprop(3) minor thirth | H.Iprop(4) major thirth | H.Iprop(5) fourth | H.Iprop(6) triton |
1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
2 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
3 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
4 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
5 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
6 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
Note that the 4th diad is harmonically equivalent to hour 12 in the tone clock. In this reduction it cannot be distinguished from the triad.
FUNCTION GetDisPsy (H AS HarmType)
Returns the normalized value for the dissonance of the H.C() chordal constellation. As can be expected from this series of functions, it does take into account amplitude relationships.
FUNCTION GetConPsy (H AS HarmType)
Returns the normalized value for the consonance of the H.C() chordal constellation. This function is NOT the numeric complement of GetDisPsy. Consonance is considered an independent property of a chordal constellation.
Translation and conversion utilities:
FUNCTION Har2Cnr% (H AS HarmType, norm!)
SUB AddCnr2Har (H AS HarmType, cnr%, low%, high%, velo%)
This procedure allows the user to add the contents of a chordnumber (cfr. chapter 1) to a harmony string. It operates similarly to AddShNo2Har() but in this case it is possible to specify range limits using the parameters low% and high%. These parameters must be legal midi-note values and low% must be smaller than high%. The velo% parameter functions as in AddShNo2Har such that all occurences of notes contained in the chordnumber Cnr% within the range low% to high% will be set in the result.If a note was already present in the input harmonystring, the velocities will be summed using the function SumVelo%(). The procedure does not update the whole structure. To do that, call FillHarType (H) after this one.
SUB P2Har (H AS HarmType, i&, P%())
FUNCTION Har2Mel (BYVAL nInst AS BYTE, h AS harmtype,BYVAL ltes AS BYTE, BYVAL htes AS BYTE) AS WORD
- nv = Har2Mel (tasknr, Task(tasknr).Har, 50, 90)
- IF ISFALSE BIT(nv,15) THEN
- noot = hibyt(nv )
- velo = lobyt(nv)
- END IF
The function is particularly usefull when there is a need to play harmony structures as arpeggios. The direction of the arpeggio depends on the order or ltes and htes. If you first pass ltes followed by htes, the arpeggio will be upwards, in the other case, downwards.
FUNCTION Har2MelAr (h AS harmtype,BYREF m() AS WORD) AS LONG
DIM m(127) as WORD
- n = Har2MelAr (Har, m())
IF n then
FOR i = 0 to n
- noot = hibyt(m(i))
- velo = lobyt(m(i))
NEXT i
END IF
The function is particularly usefull when there is a need to play harmony structures as arpeggios or broken chords.
Structure modifiers:
SUB TransHarm (h AS Harmtype, BYVAL n AS INTEGER)
This procedure performs transposition on the complete harmony string passed in h.vel. The parameter n allow you to specify the interval in number of semitones. Positive values for n cause upward transpositions, negative values, downward transpositions. If n = %False, the procedure returns h unmodified. If the absolute value of n exceeds 127, the h.vel string returned will be blank. The procedure does not update the other elements in the h structure. So the user has to call FillHarmonytype separately, of he needs updates of the h.psy, h.dis, h.kon... fields of the structure.
SUB AddNote2Har (H AS HarmType, note, velo)
- DIM Har(0 TO 10) AS HarmType
- note%=64
- DO
- AddNote2Har H(i%), note%, 86
- note% = note% + 3
- i% = i%+1
- LOOP UNTIL i%> UBOUND(Har)
SUB DelNote2Har (H AS HarmType, note)
- DIM Har AS HarmType
- i%=0
- DO
- ' make a random harmony string:
- AddNote2Har Har, RND(1) * 127, RND(1) * 127
- i%= i%+1
- LOOP UNTIL i%= 20
- note=64
- DelNote2Har H(i%), note
- ' the harmony string in Har.Vel will no longer contain the note 64
SUB DelShNo2Har (H AS HarmType, note)
- DIM Har AS HarmType
- i%=0
- DO
- ' make a random harmony string with shepard tones:
- AddShNt2Har Har, RND(1) * 127, RND(1) * 127
- i%= i%+1
- LOOP UNTIL i%= 6
- DelShNt2Har H(i%), 64
- ' the harmony string in Har.Vel will no longer contain any occurence of E
SUB AddShNo2Har (H AS HarmType, note, velo)
- DIM Har(0 TO 4) AS HarmType
- note%=64
- DO
- AddShNt2Har H(i%), note%, 86
- AddShNt2Har H(i%), note%-4, 86
- AddShNt2Har H(i%), note%-8, 86
- note% = note% + 3
- i% = i%+1
- LOOP UNTIL i%> UBOUND(Har)
SUB SubstNtInHar (H AS HarmType, n1, n2)
- DIM Har AS HarmType
- 'suppose Har.vel has been stuffed with notes in previous code...
- ' ...
- oldnote%= 64
- newnote%= 69
- 'suppose we want to replace all occurances of oldnote% in the harmony string with newnote%, we could code a procedure as follows:
- okt%=0
- bo%= oldnote% MOD 12
- bn%= newnote% MOD 12
- DO
- SubstNtInHar H, bo% + okt%, bn% + okt%
- okt% = okt% + 12
- LOOP UNTIL okt% > 120
Mathematical chordal functions and procedures:
This function is used for summing up unison velocities assuming 90dB dynamic range and Log scaling for velocities on midi-equipment. Hence v1 and v2 are midi-numbers. (7-bit bytes) The maximum value of 127 cannot be exceeded. We suppose midi-range 0-127 to correspond to 90dB. So, 1dB = 127/90 = 1.4111. Two equal velocities should yield a 3dB increase in volume. Thus we calculate the scaling constant as 3dB= 128*3/90 = 4.233! This calculation is handled within the function. The information is given for the users knowledge and insight only. Since our scaling assumption is in no way trivial, it is up to the user to remap eventually the values, either to continuous controllers, patches, or combination of different midicontrollable parameters. We have used them succesfully to controll directly a set of LogDacs (operating as volume controllers or digital VCA's) of our own design with great success, but since such a sollution involves dedicated hardware, it is not further commented here.
This function returns a normalized value for the pitch dependent weight of a midi-note byte. It holds an internal look-up table, filled the first time the function is called. Later calls are performed a lot faster. The centroid for the shephard chords is around note nr.64.
Operations and analysis functions and procedures:
FUNCTION GetNrInt% (H AS HarmType, interval%, norm!)
Returns the number of intervals of a type specified in interval% (integer from 0 to 6, for prime, minor second, major second, minor third, major third, fourth and triton) wherefore the strenght is larger than the value specified in norm!. If norm! is set to 0, the function returns the amount of specified intervals in the chord represented by H.C(). Since the function is based on a weighted-shepard chord analysis, we can only distinguish 6 intervals. Fifths are detected and counted as fourths, sixths as thirds, sevenths as seconds.
FUNCTION GetStrongest% (H AS HarmType, n%)
Returns the n% strongest note-components from H.C(). If no n% components are found, the function returns -1. If n%=1 the returned values will be a single note (0-11). For larger values of n%, the returned value will be a binary chordnumber. If this chordnumber is of a classic form, the tonality nibble will be set in the chordnumber for n%=3 and n%=4. For n%=3 and 4, if no classic form could be detected, the high nibble will be set to -1 (&HFxxx), atonal. For n%= 2 to tonality nibble will be set. For n% > 4 the tonality nibble will always be set to the value of the strongest note-component in H.C().
Returns the highest note and its velocity found within the limits passed as found in the harmstring passed. If no note was found matching the condition, -1 will be returned. Else the note number will be returned in the high byte of the integer, the corresponding velocity will be returned in the low byte of the returned integer.
FUNCTION AbsDifHar$ (H1 AS HarmType, H2 AS HarmType)
- DIM Har(0 TO 3) AS HarmType
- FOR i%= 0 TO 3
- Har(i%).Vel = STRING$(128,0)
- NEXT i%
- AddShNo2Har (Har(0), 60, 120)
- AddShNo2Har (Har(0), 64, 120)
- AddShNo2Har (Har(1), 60, 120)
- AddShNo2Har (Har(1), 67, 120)
- Har(2).Vel = AbsDifHar$ (Har(0), Har(1))
- Har(3).Vel = AbsDifHar$ (Har(1), Har(0))
FUNCTION CommonHar$(H1 AS HarmType, H2 AS HarmType)
- DIM Har(0 TO 3) AS HarmType
- FOR i%= 0 TO 3
- Har(i%).Vel = STRING$(128,0)
- NEXT i%
- AddNote2Har (Har(0), 60, 10)
- AddNote2Har (Har(0), 64, 20)
- AddNote2Har (Har(1),60, 30)
- AddNote2Har (Har(1),67, 40)
- Har(2).Vel = CommonHar$ (Har(0), Har(1))
- Har(3).Vel = CommonHar$ (Har(1), Har(0))
FUNCTION ComplementHar$ (H AS Harmtype, BYVAL ltes AS BYTE, BYVAL hTes AS BYTE)
This function returns -limited by the range set in the parameters ltes and htes (7-bit midi note values)- a string consisting of all notes not found to be present in the harmony string passed in H.vel.
The output string is limited to the boundaries set by ltes and htes as well. The velocity values returned reflect the integrated values found in the input string.
FUNCTION StealNoteFromHar% (H AS HarmType, BYVAL oldnoot%, Lowtes%, Hites%)
'This functions returns from a given Har-type passed in H the most suitable single note found in the harmony string, for the 'instrument' given. The instrument is defined by its ambitus boundaries LowTes and HiTes. Har.C() -the psychord- is filled within the function, so the user does not have to call FillChordType prior to calling this function. This function will always return the most melodic note (taking into consideration the value of oldnoot, representing the reference note) from the possibilities presented in Har. The function will remove the note it returns from H.If the function is unsuccessfull, it will return -1. The function will always be unsuccessfull if an empty harmony structure is passed.
If the value for oldnoot% is passed as -1, or any other negative integer, the function will consider the average between LowTes% and HiTes% as a point of departure.
FUNCTION GetScaleHar$(mode%, tc%, vel%)
FUNCTION Fit2Mode$ (H AS HarmType, mode%, tc%)
INPUT | OUTPUT | ||||
note | vel | name | note | vel | name |
70 | 68 | Bb | 71 | 68 | B |
63 | 100 | Eb | 67 | 100 | G |
60 | 100 | C | 64 | 100 | E |
40 | 50 | C# | 60 | 50 | C |
48 | 80 | C | 50 | 84 | C |
48 | 80 | C | |||
18 | 80 | F# | 17 | 80 | F |
- ' fill the harmony string with 14 random notes:
- cnt%=0 :' reset counter
- DIM Har(0 TO 1) AS HarmType :' create type
- Har(0).Vel=STRING$(128,0)
- Har(1).Vel=STRING$(128,0) :' blank on entry
- DO
- note% = RND(1)*127 :' get a random note
- cnt% = cnt%+1 :' increment counter
- 'add the note to the string
- AddNote2Har ( Har(0), note%, 120)
- LOOP UNTIL cnt% = 14
- ShowHar Har(0), 50, 440, 1 :' Show input to function
- mode%= 0 :' set mode to major
- tc% = 7 :' set to G-major
- Har(1).vel = Fit2Mode$(Har(0), mode%, tc%)
- SLEEP 1000 ' in milliseconds
- dcnr% = Har2Cnr%(Har(1), 0)
- ShowLargeStaff dcnr%, 5, 20 :' display chord result
- ShowHar Har(1), 50, 440, 1 :' display all
FUNCTION InBetweenHar$ (H1 AS HarmType, H2 AS HarmType)
FUNCTION InBetweenHarDown$ (H1 AS HarmType, H2 AS HarmType)
FUNCTION InBetweenHarUp$ (H1 AS HarmType, H2 AS HarmType)
Harmony Constructors:
FUNCTION SolveHar$ (H AS HarmType, note%, norm!)
- SCREEN 12 : WIDTH 80,60
- DIM Har AS HarmType
- ' code wherin Har.Vel gets some content...
- DIM Ant AS HarmType
- Ant.vel = STRING$(128, 0)
- Ant.vel = SolveHar$(Har, (RND(1) * 12) - 1, 0)
- FillHarType Ant
- ShowPsiChord Ant, 128, 200, 120, 120
- PRINT " Nr-Tritons ="; GetNrInt%(Ant, 6, 0)
- PRINT " Nr-Minor seconds="; GetNrInt%(Ant, 1, 0)
- PRINT " Nr-Major seconds="; GetNrInt%(Ant, 2, 0)
FUNCTION SolveTrit$ (H AS HarmType, note%, norm!)
- ' suppose we have a harmony string in Har.Vel...
- SCREEN 12: WIDTH 80,60
- ntt% = GetNrInt%(Har, 6, 0)
- DIM Ant AS HarmType
- Ant.vel = STRING$(128, 0)
- ERASE Ant.c
- IF ntt% > 0 THEN
- venoot% = (RND(1) * 12) - 1
- Ant.vel = SolveTrit$(Har, solvenoot%, 0)
- FillHarType Ant
- nta% = GetNrInt%(Ant2, 6, 0)
- LOCATE 4, 32: PRINT " NrAnsTrit="; nta%;
- ELSE
- LOCATE 4, 32: PRINT SPACE$(15);
- END IF
- ShowPsiChord Ant, 256, 200, 120, 120
FUNCTION SolveMin2$ (H AS HarmType, note%, norm!)
This function returns a harmony string in which at least 1 of the minor seconds -if H.C() contained any- will be solved. Note% is the note to which a solution should be forced. If you want a free solution, the function will return the most appropriate contextual solution with note%=-1 as parameter. The norm! parameter sets the weight-level from which the seconds will be considered. If set to 0, it will consider all minor seconds regardless their weight and/or amplitude.
Application example:
- ' test the minor second-solver on input harmony string Har.Vel
- SCREEN 12: WIDTH 80,60: LOCATE 3, 48
- nks% = GetNrInt%(Har, 1, 0)
- PRINT " Nr-Min2 ="; nks%;
- DIM Ant AS HarmType
- Ant.vel = STRING$(128, 0)
- ERASE Ant.c
- IF nks% > 0 THEN
- solvenoot% = (RND(1) * 12) - 1
- Ant.vel = SolveMin2$(Har, solvenoot%, 0)
- FillHarType Ant
- nta% = GetNrInt%(Ant, 1, 0)
- LOCATE 4, 48: PRINT " NrAnsSec="; nta%; : ' legacy code
- ELSE
- LOCATE 4, 48: PRINT SPACE$(15); : ' legacy code
- END IF
- ShowPsiChord Ant, 384, 200, 120, 120
FUNCTION SolveMaj2$ (H AS HarmType, note%, norm!)
- ' test for the major second-solver on harmony string Har.Ver
- SCREEN 12: WIDTH 80,60: LOCATE 3, 64
- nks% = GetNrInt%(Har, 2, 0)
- PRINT " Nr-Maj2 ="; nks%;
- DIM Ant AS HarmType
- Ant.vel = STRING$(128, 0)
- ERASE Ant.c
- IF nks% > 0 THEN
- solvenoot% = (RND(1) * 12) - 1
- Ant.vel = SolveMaj2$(Har, solvenoot%, 0)
- FillHarType Ant
- nta% = GetNrInt%(Ant, 2, 0)
- LOCATE 4, 64: PRINT " NrAnsSec="; nta%;
- ELSE
- LOCATE 4, 64: PRINT SPACE$(15);
- END IF
- ShowPsiChord Ant, 512, 200, 120, 120
FUNCTION SumHar$ (H1 AS HarmType, H2 AS HarmType)
This function returns the fuzzy sum of 2 harmony structures as a 128-byte string. Weights of individual notes are summed if the notes are present in the harmony strings. The summing makes use of the function Sumvelo%().
FUNCTION DifHar$ (H1 AS HarmType, H2 AS HarmType)
This function returns the fuzzy difference of 2 harmony structures as a 128-byte string. Weights of individual notes are subtracted, using a fuzzy algorithm.
FUNCTION MorfHar$ (H1 AS HarmType, H2 AS HarmType, m%, tc%,d%)
- DIM Harmfram(0 TO 10) AS HarmType
- ... ...
- ' suppose the input harmonystring is in HarmFrames(0).Vel
- ' and the harmony string we want to morph towards in HarmFram(10)
- DO
- HarmFram(1).Vel = MorfHar$(HarmFram(1), HarmFram(10), 3, 4, 3)
- ' now on every pass through the loop, HarmFram(1).Vel will
- ' contain another step in the morphing process.
- LOOP UNTIL HarmFram(1).Vel = HarmFram(10).Vel
- DIM NulHar AS HarmType
- NulHar.Vel= STRING$(128,0) :' makes an empty harmony string.
- ' suppose the input harmony string is in Inhar.Vel
- DO
- Inhar.Vel= MorfHar$(Inhar, NulHar, 0, 0, 2)
- ' procedure to play Inhar.Vel ...
- LOOP UNTIL Inhar.Vel= NulHar.Vel
- DIM FadeIn AS HarmType
- FadeIn.Vel= STRING$(128,0) :' makes an empty harmony string.
- ' suppose the output harmony string is in Uithar.Vel
- DO
- FadeIn.Vel= MorfHar$(FadeIn, UitHar, 0, 0, 1)
- ' procedure to play FadeIn.Vel ...
- LOOP UNTIL FadeIn.Vel= UitHar.Vel
FUNCTION ConvergeHar$ (H AS HarmType, refnote%, factor!)
This function can be used to let all notes contained in H.Vel - the input harmony string- converge or diverge towards or from a given reference note passed in the parameter refnote%. The amount of convergence/divergence can be set in the single precision parameter factor!. For values larger than 1 the function will diverge , for values smaller than 1, it will converge. This means: when diverging . all intervals in the harmony string as seen from refnote will be found enlarged by the given factor in the output harmonystring. At the other hand, when set to converge, all intervals referend to refnote% will be smaller by the given factor. If the refnote% was present in the input string, the only note left after complete convergence or divergence will be that note.
If factor!=1 the returned string will equal the input harmonystring. The function multiplies/divides the size of all intervals between all notes in the input string and the reference note by factor. The result is rounded to the nearest integer value. The function does not adjust the result to a scale or a mode. Notes that after the operation fall out of the legal midi note-range are discarded. For this reason, after a finite amount of steps the function will always return either an empty string, or just the reference note itself.
- Dim Har(0 TO 1) AS HarmType
- Har(0)=STRING$(128,0)
- Har(1)=STRING$(128,0)
- tc%= 6
- '... code wherein the harmony string H(0).Vel gets stuffed with notes...
- Har(1).Vel = Har(0).Vel
- DO
- ShowHar Har(1), 50, 440, 1 :' display procedure
- ' factor is set to diverge:
- Har(1).Vel = ConvergeHar$(Har(1), 60 + tc%, 1.1)
- dcnr% = Har2Cnr%(Har(1), 0)
- ' here we could have a procedure playing the chord...
- ShowLargeStaff dcnr%, 5, 20 :' display procedure
- LOOP UNTIL GetNrNotes%(dcnr%) <= 1
- ShowHar Har(1), 50, 440, 1
FUNCTION DimIntInHar$(H AS HarmType,tc%,mode%,deg%,sg%)
- DIM Har(0 TO 1) AS HarmType
- Har(0).Vel= STRING$(128,0)
- Har(1).Vel= STRING$(128,0)
- ' write the notes C, Eb, G and B to the chord:
- AddNote2Har (Har(0), 60, 75)
- AddNote2Har (Har(0), 63, 60)
- AddNote2Har (Har(0), 67, 45)
- AddNote2Har (Har(0),71, 80)
- ShowHar Har(0), 50, 440, 1
- ' invoke the function using the parameters tc%=0, mode%= 1 (C-minor)
- ' degree%= 7 (seventh degree), and -1, to diminute
- Har(1).vel = DimIntInHar$(Har(0), 0, 1, 7, 1)
- dcnr% = Har2Cnr%(Har(1), 0)
- ' display result:
- ShowLargeStaff dcnr%, 5, 20
- ShowHar Har(1), 50, 440, 1
- ' the result will be C-Eb-G-Bb
FUNCTION DiminuteHar$(H AS HarmType, tc%, mode%, steps%)
input | after pass 1 | pass 2 | pass 3 | pass 4 | pass 5 | pass 6 | pass 7 |
B | A | G | F | F | E | D | C |
G | F | E | D | C | C | C | |
E | D | C | C | ||||
C | C |
With the same input, but steps set to +1 augmentation the result would be:
input | after pass 1 | pass 2 | pass 3 | pass 4 | pass 5 | pass 6 | pass 7 |
B | C | C | C | C | C | ||
G | A | B | A | B | C | ||
E | F | G | C | C | |||
C | C | C |
If the user wants to diminute or augment only a single interval wherever it occurs in the harmonystring, he is advized to use the specific function DimIntInHar$.
- Dim Har(0 TO 1) AS HarmType
- Har(0)=STRING$(128,0)
- Har(1)=STRING$(128,0)
- tc%= 0
- '... code wherein the harmony string H(0).Vel gets stuffed with notes...
- Har(1).Vel = Har(0).Vel
- DO
- ShowHar Har(1), 50, 440, 1 :' display procedure
- Har(2).Vel = DiminuteHar$(Har(1), tc%, mode%, 2)
- dcnr% = Har2Cnr%(Har(1), 0) :' conversion
- '... insert code to play or save or process the chord...
- ShowLargeStaff dcnr%, 5, 20 :' display procedure
- LOOP UNTIL GetNrNotes%(dcnr%) <= 1
- ShowHar Har(1), 50, 440, 1 :' display procedure
FUNCTION SymDimHar$(H AS HarmType, tc%, sign%)
This function can be used to diminute as well as to augment intervals within a given harmonystring. The reference note for the diminution/augmentation should be given in the parameter tc%. It can be any legal midi note (0-127). The function operates in a symmetrical way. All intervals are treated in their smallest inverted format ( fifths become fourths, sixths, thirds and so on). The size of the intervals thus found will be reduced (Diminished) or increased (Augmented) one chromatic step. Diminution is applied when sign% is negative, else the result will be augmentation. Notes contained in the harmonystring that correspond to the setting for tc% in any octave will remain unchanged. Notes that are a triton away from tc% will equally be kept, since the triton is the axis of symmetry for this operation.
The function always performs a single step diminution or augmentation. If the user wishes more steps, he has to call the function recursive.
Example of chord sequences returned for tc% set to 0 (C) and sign to -1:
input | after pass 1 | pass 2 | pass 3 | pass 4 | pass 5 |
B | C | C | C | C | C |
G | G# | A | Bb | B | C |
E | Eb | D | C# | C | |
C | C | C | C |
Example of chord sequences returned for tc% set to 0 (C) and sign to +1:
input | after pass 1 | pass 2 | pass 3 | pass 4 | pass 5 |
B | Ab | A | G# | G | F# |
G | F# | F# | F# | F# | C |
E | F | C | C | C | |
C | C |
- Dim Har(0 TO 1) AS HarmType
- Har(0)=STRING$(128,0)
- Har(1)=STRING$(128,0)
- tc%= 0
- '... code wherein the harmony string H(0).Vel gets stuffed
- ' with notes...
- Har(1).Vel = Har(0).Vel
- cnt%=0
- DO
- ShowHar Har(1), 50, 440, 1
- Har(1).vel = SymDimHar$(Har(1), tc%, -1)
- cnt%=cnt%+1
- '... insert code to play, save or process the chord...
- LOOP UNTIL cnt% > 6
- ShowHar Har(1), 50, 440, 1
COMING SOON:
FUNCTION HarmFrame$ (H() AS HarmType, framesize%)
Timeframed psycho-fuzzy functions
FUNCTION TendHar$ (H() AS HarmType, note%, tc% )
This function should be an inverse function for the harmony-solving function. It will try to bend the harmony in such a way that the returned string will be a harmony string seeking a solution towards note% in tc%. The dissonance of the chord returned will generally be larger than that of the harmony string at its input.. However the function is not the mathematical inverse of any of the solve functions. After all, if that were what we needed, we could just inverse the order in time for the in- and output parameters of the Solve- functions...
Filedate: 971122 - last updated: 2011-11-29
<Reference INDEX> | <Introduction> | <General Functions> |
<Fuzzy Functions> | <Analysis Functions> | <Acoustical Functions> |
<Visualisation Functions> | <File Management> | <Spectral Functions> |
To homepage dr.Godfried-Willem RAES |