Compare commits

...

12 Commits

Author SHA1 Message Date
sshlien
34f6ef01e2 2024.03.13 2024-03-13 12:17:06 -04:00
sshlien
5175fc699e 2024.03.05 2024-03-05 17:31:40 -05:00
sshlien
6db6eb0979 2024.03.02 2024-03-02 19:10:18 -05:00
sshlien
4d51b779bf 2024.02.25 2024-02-25 07:53:27 -05:00
sshlien
bf013dc428 2024.02.23 2024-02-23 14:26:37 -05:00
sshlien
6441b47841 2024.02.22 2024-02-22 21:08:16 -05:00
sshlien
6a3de68779 2024.02.19 2024-02-19 12:37:50 -05:00
sshlien
c4c489d111 2024.02.14 2024-02-14 13:49:35 -05:00
sshlien
b9c48dc778 2024.02.11 2024-02-11 13:59:25 -05:00
sshlien
eac28d9489 2024-02-09 2024-02-09 16:24:21 -05:00
sshlien
135e70c5e6 2024.02.07 2024-02-07 21:41:42 -05:00
sshlien
79e7ac2d97 2024.01.15 2024-01-15 17:22:56 -05:00
11 changed files with 597 additions and 53 deletions

View File

@@ -1,2 +1,2 @@
January 02 2024
March 13 2024

View File

@@ -49,7 +49,7 @@ Matching:
#define VERSION "1.82 June 14 2022 abcmatch"
#define VERSION "1.83 Feb 19 2024 abcmatch"
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

View File

@@ -15207,3 +15207,246 @@ not adjusted by event_chordoff to compensate by the length value
specified at the end of the [ac'] chord, resulting in the problem.
January 15 2024
abc2midi bug: the following example produces a warning, but the
the output midi file is correct.
Warning in line-char 7-23 : Track 1 Bar 1 has 1 time units while the time signature has 2
X:1
T:Test trill
L:1/4
M:2/2
Q:1/2=60
K:Dm
!trill!"C"g4- | g2^c2 |
Analysis: this warning is produced by checkbar() in genmidi.c. This problem was
reported in this file on November 23 2012. The code for handling tied notes is
quite intricate and I do not understand it. I am hesitant in tampering with the code.
February 14 2024
abc2midi: repeat bug
For the following example:
X:1
T: Repeat bug
M: 1/4
L: 1/4
P:A
K:C
P:A
A | B & C :|
Abc2midi produces a midi file which looks like this
V:1
A | B |
V:2
Z | C | Z | C|
the second voice is repeated by the first voice is not.
Removing the P:A prior to K:C fixes the problem.
Alternatively, inserting the missing left repeat |:
(eg) |: A | B & C :|
also resolves the problem.
Apparently, abc2midi does not insert the left repeat in the
correct position.
Analysis: abc2midi produces an internal representation of the
music using the feature[] array. Since this tune uses split
voices using the & character, the internal representation now
contains two voices. abc2midi then calls scan_for_missing_repeats()
and add_missing_repeats() in store.c in order to insert the missing
left repeats in the internal representation. Unfortunately,
scan_for_missing_repeats puts the left repeat in the wrong place where
it is ineffective.
The code in scan_for_missing_repeats is quite complicated
because it has to work for either voices or parts. It searches
for either VOICE or PART code in the feature array and inserts
the left repeat immediately following this code. If both
VOICE and PART are present, VOICE should immediately follow PART
in order that scan_for_missing_repeats works correctly. Unfortunately,
they occur in the opposite order. The function event_split_voice()
inserts the VOICE code in the wrong position, mainly because
the v1index address is incorrect.
Fix: event_part() in store.c, I added the line
v1index = notes; /* [SS] 2024-02-14 */
following
addfeature(PART, (int)*p, 0, 0);
This appears to resolve this issue.
abc2midi: another related repeat bug
For the following example:
X:1
T: A related repeat bug
P:A
M:3/4
L:1/4
K:D
P:X
Z | zzz & b'b'b' :|
P:A
CCC | DDD :|
abc2midi produces incorrect output for this file. It does not
insert the left repeats in the right place in its internal
representation.
Fix: for the present time you need to put the left repeats in the
file like this.
|:Z | zzz & b'b'b' :|
P:A
|:CCC | DDD :|
February 19 2024
abc2midi bug and fix submitted by James Allwright.
The parser recognizes |: but not |::
In the following example,
X:1
T: ||: bug
M: 2/4
L: 1/4
K: G
G||:AB|[1cz:||[2ed|
the repeat goes back to 0th bar (containing G) instead of
bar 1 (containing AB).
Fix: in parsemusic() in parseabc.c, the following lines were
added.
if (*(p+1) == ':') {
/* handle ||: as a variant of |: [JA] 2024-02-19 */
check_and_call_bar (BAR_REP, "");
p = p + 2;
The change also has impact on yaps, abc2abc, and abcmatch.
February 22 2024
abc2midi bug
Adding snm=something after a clef= declaration
removes the offset from the clef. In the following
example,
X:1
T: with snm
M:4/4
L:1/4
V:1 clef=treble-8
V:2 clef=treble-8 snm=anything
K:C
[V:1] z z C z |
[V:2] z z z C |
C in voice 1 is shifted down an octave but C in voice 2
is untouched.
Analysis: parsevoice attempts to parse each token (clef=, octave=,
transpose=, sound=, name= and etc.) by calling various functions
parseclef(), parsetranspose(), parseoctave(), and etc.) until it
succeeds. parseclef is thus called on every token and returns either
1 or 0 depending whether it was successful or not. parseclef calls
the function isclef() to do the work. Unfortunately, isclef()
zeros the variable new_clef->octave_offset whether or not a
clef is declared in the token. Therefore the token snm=...
causes new_clef->octave_offset to be zeroed. The next function
which follows, get_extended_clef_details does set the octave_offset, but
it is only called if the token was a clef.
Fix: commented out the line in isclef() which zeros the octave_offset.
February 25 2024
abc2midi note:
Besides clef=treble-8, the abcmidi 2.2 standard also recognizes
clef=treble_8, clef=treble^8 and etc. These clefs do not transpose
the notes in the midi file but merely put the appropriate symbol
on the clef. Abc2midi presently ignores these endings in the
function get_clef_octave_offset() in music_utils.c. When it is
necessary for the parseclef to see these endings the following fix
is necessary.
Fix: readword() called by parseclef breaks the clef string
when it encounters either a ^ or _ in order to handle sharps
and flats in the K: declaration. (See note above April 8 2015.)
It is necessary to use the new function, readword_with_()
which does not break the string on encountering either
the underscore _ or caret ^.
March 02 2024
abc2midi deviance from abc standard 2.2
The clef=, octave=, and transpose= in the V: command are
expected to be persistant and independent of each other. They
are changed independently any time a new clef=, octave=,
or transpose= appears. These are stored in 3 variables.
And the pitch of a note is assigned the sum of these values.
Analysis:
event_note computes the midi pitch from note (one of a,b,c,d,e,f,g),
the xoctave, clef, accidental, and mult which are all input
parameters to that function. In addition it accesses the global
voice structure v of the active voice to get the octaveshift
for that voice. The function computes the local variable octave
from xoctave, clef->octave_offset and v->octaveshift.
Prior to this fix and since May 21 2021, the local variable
octave was either assigned to the value of
clef->octave_offset + xoctave or to v->octaveshift + xoctave when
v->octaveshift is nonzero. In addition, event_voice also changes
v->octaveshift when it encounters a new clef=.
Fix:
In order to comply with this standard, the code in event_voice
was modified to prevent clef= from modifying v->octaveshift. In
addition event_note now computes octave as below.
octave = clef->octave_offset + v->octaveshift + xoctave; /*[SS] 2024-03-02*/
Note this is a significant change as it could break some abc
files. For example, if the user put clef=treble+8 and also
octave=+1, just to be safe, then the resulting octave would be higher
than expected. Fortunately, octave= is still rarely used.
Here is the test file for verifying this fix.
X:1
T:Test for octave shifts in sound
M:4/4
K:C
% The following seven notes should have equal sound
V:1 clef=treble
d8 |\
[V:1 clef=treble+8] D8 |\
[V:1 octave=-1] d8 |\
[V:1 transpose=12] D8 |\
[V:1 clef=treble] d8 |\
[V:1 octave=0] D8 |\
[V:1 transpose=0] d8 |]

View File

@@ -1,4 +1,4 @@
.TH MIDISTATS 1 "02 January 2024"
.TH MIDISTATS 1 "18 February 2024"
.SH NAME
\fBmidistats\fP \- program to summarize the statistical properties of a midi file
.SH SYNOPSIS
@@ -26,7 +26,7 @@ applies.
program is followed by the channel number and the General Midi Program
number.
.PP
trkinfo is an array of 8 numbers which indicates the statistical properties
trkinfo is an array of 19 numbers which indicates the statistical properties
of the track of interest. The following data is given:
the channel number,
the first program assigned to this channel,
@@ -44,6 +44,10 @@ the minimum note length in pulses
the maximum note length in pulses
the number of gaps in the channel
the entropy of the pitch class histogram for that channel
the number of notes whose pitch were the same as the previous note
the number of notes whose pitch changed by less than 4 semitones
the number of notes whose pitch changed by 4 or more semitones
(In event of a chords the maximum pitches are compared.)
.PP
After processing all the individual tracks, the following information
applies to the entire midi file.
@@ -108,6 +112,39 @@ collisions. Midistats counts the bar rhythm patterns using a hashing
function. Presently collisions are ignored so occasionally two
distinct rhythm patterns are counted as one.
.PP
Midistats prints a number of arrays which may be useful in
determining where the music in the track is a melody line or
chordal rhythmic support. These arrays indicate the properties
for each of the 16 channels. (The percussion channel 9 contains
zeros.) In the case same channel occurs in several tracks, these
numbers are the totals for all track containing that channel.
Here is a description of these properties.
.PP
programs: channel to midi program mapping
.PP
cnotes: the total number of notes in each channel
.PP
nnotes: the number of notes in each channel not including
those playing in the same time interval.
.br
nzeros: the number of notes whose previous note was the same pitch
.br
nsteps: the number of notes whose pitch difference with the previous
note was less than 4 semitones.
.br
njumps: the number of notes whose pitch difference with the previous
note was 4 or more semitones.
.br
rpats: the number of rhythmpatterns for each channels. This is a
duplication of data printed previously.
.br
pavg: the average pitch of all the notes for each channel.
.br
spread: the percentage of the track that each channel is active.
.PP
If some of the channels appear in more than one track, then
some of the above values may be incorrect.
.PP
In addition the midistats may return other codes that describe
other characteristics. They include
@@ -250,8 +287,9 @@ splits the two 4-bit values with a period. Thus 33 = (2*16 + 1).
-pitchclass
.br
Returns the pitch class distribution for the entire midi file.
.PP
-nseqfor
-nseqfor n
.br
Note sequence for channel n. This option produces a string of bytes
indicating the presence of a note in a time unit corresponding to
@@ -269,13 +307,24 @@ twice of much memory.
Though the pitch resolution is not sufficient to distinguish
major or minor chords, it should be sufficient to be identify some
repeating patterns.
.PP
-nseq
.br
Same as above except it is applied to all channels except the
percussion channel.
.br
.PP
-nseqtokens
Returns the number of distinct sequence elements for each channel.
The channel number and number of distinct elements separated by
a comma is returned in a tab separated list for all active channels
except the percussion channel. Here is an example.
.br
2,3 3,4 4,11 5,6 6,3 7,3 8,6 9,3 11,2 12,1
.br
-ver (version number)
.B etc. (See drums.txt in doc folder.)
.SH AUTHOR
Seymour Shlien <fy733@ncf.ca>

View File

@@ -1,12 +1,12 @@
abcMIDI : abc <-> MIDI conversion utilities
midi2abc version 3.59 February 08 2023
abc2midi version 4.85 December 23 2023
abc2abc version 2.20 February 07 2023
yaps version 1.92 January 06 2023
abcmatch version 1.82 June 14 2022
abc2midi version 4.91 March 02 2024
abc2abc version 2.21 February 19 2024
yaps version 1.93 February 19 2024
abcmatch version 1.83 February 19 2024
midicopy version 1.39 November 08 2022
midistats version 0.84 January 02 2023
midistats version 0.89 March 13 2024
24th January 2002
Copyright James Allwright

View File

@@ -1,5 +1,4 @@
/* midistats - program to extract statistics from MIDI files
* Derived from midi2abc.c
/* Derived from midi2abc.c
* Copyright (C) 1998 James Allwright
* e-mail: J.R.Allwright@westminster.ac.uk
*
@@ -18,7 +17,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#define VERSION "0.84 December 29 2023 midistats"
#define VERSION "0.89 March 13 2024 midistats"
/* midistrats.c is a descendent of midi2abc.c which was becoming to
large. The object of the program is to extract statistical characterisitic
@@ -69,6 +68,9 @@ float histogram_perplexity (int *histogram, int size);
void stats_noteoff(int chan,int pitch,int vol);
void stats_eot ();
void keymatch();
void outputChannelSummary();
void clearTrackNm ();
#define max(a,b) (( a > b ? a : b))
#define min(a,b) (( a < b ? a : b))
@@ -82,6 +84,7 @@ static FILE *outhandle; /* for producing the abc file */
int tracknum=0; /* track number */
int lasttrack = 0; /* lasttrack */
int division; /* pulses per quarter note defined in MIDI header */
int halfdivision; /* pulses per eighth note */
int quietLimit; /* minimum number of pulses with no activity */
long tempo = 500000; /* the default tempo is 120 quarter notes/minute */
int bpm = 120; /*default tempo */
@@ -145,8 +148,10 @@ int channel_used_in_track[17]; /* for dealing with quietTime [SS] 2023-09-06 */
int histogram[256];
unsigned char drumpat[8000];
unsigned char pseq[8000];
int pseqhist[128];
int percnum;
int nseqchn;
int nseqdistinct;
@@ -190,6 +195,21 @@ struct trkstat {
* npulses is the number of pulses.
*/
struct notememory {int eighthUnit;
int nowPitch;
int beforePitch;
int previousPitch;
int zeroCount;
int stepCount;
int jumpCount;
int totalNotes;
int totalPitches;
int quietTime;
int used;
} nm[17];
struct notememory tracknm;
int progcolor[17]; /* used by stats_program */
int drumhistogram[100]; /* counts drum noteons */
int pitchhistogram[12]; /* pitch distribution for non drum notes */
@@ -239,6 +259,7 @@ struct hashStruct {
int ncollisions = 0;
int nrpatterns = 0;
int nseqdistinct = 0;
void handle_collision () {
ncollisions++;
@@ -440,6 +461,7 @@ void stats_header (int format, int ntrks, int ldivision)
{
int i;
division = ldivision;
halfdivision = ldivision/2;
quietLimit = ldivision*8;
divisionsPerBar = division*beatsPerBar;
unitDivision = divisionsPerBar/24;
@@ -542,12 +564,6 @@ tripletsCriterion8 = (float) pulseDistribution[8]/ (float) ncounts;
tripletsCriterion4 = (float) pulseDistribution[4]/ (float) ncounts;
if (tripletsCriterion8 > 0.10 || tripletsCriterion4 > 0.10) printf("triplets\n");
if (pulseDistribution[0]/(float) ncounts > 0.95) printf("qnotes");
/*
printf("pulseDistribution:");
for (i=0;i<resolution;i++) printf("%6.3f",(float) pulseDistribution[i]/(float) ncounts);
printf("\n");
printf("nzeros = %d npeaks = %d \n",nzeros,npeaks);
*/
}
void stats_finish()
@@ -625,6 +641,7 @@ printf("collisions = %d\n",ncollisions);
if (hasLyrics) printf("Lyrics\n");
stats_interpret_pulseCounter ();
printf("\n");
outputChannelSummary();
}
@@ -694,8 +711,13 @@ for (i=1;i<17;i++) {
printf(" %f",trkdata.pitchEntropy[i]);
} else
printf("-1 0");
nm[i].quietTime += trkdata.quietTime[i];
nm[i].used = channel_used_in_track[i];
trkdata.quietTime[i] = 0; /* in case channel i is used in another track */
trkdata.numberOfGaps[i] = 0;
if (lasttrack > 1) printf(" %d %d %d\n",tracknm.zeroCount,tracknm.stepCount,tracknm.jumpCount);
else
printf(" %d %d %d\n",nm[i-1].zeroCount,nm[i-1].stepCount,nm[i-1].jumpCount);
printf("\n");
channel2nnotes[i] += trkdata.notecount[i] + trkdata.chordcount[i];
@@ -709,6 +731,7 @@ void stats_trackstart()
{
int i;
tracknum++;
clearTrackNm ();
for (i=0;i<17;i++) {
trkdata.notecount[i] = 0;
trkdata.notemeanpitch[i] = 0;
@@ -745,6 +768,88 @@ void stats_trackend()
}
void clearNotememory () {
int i;
for (i=0;i<17;i++) {
nm[i].eighthUnit = 0;
nm[i].nowPitch = 0;
nm[i].beforePitch = 0;
nm[i].previousPitch = 0;
nm[i].zeroCount = 0;
nm[i].stepCount = 0;
nm[i].jumpCount = 0;
nm[i].totalNotes =0;
nm[i].totalPitches =0;
nm[i].quietTime = 0;
nm[i].used = 0;
}
}
void clearTrackNm () {
tracknm.eighthUnit = 0;
tracknm.nowPitch = 0;
tracknm.beforePitch = 0;
tracknm.previousPitch = 0;
tracknm.zeroCount = 0;
tracknm.stepCount = 0;
tracknm.jumpCount = 0;
tracknm.totalNotes = 0;
tracknm.totalPitches = 0;
}
void updateNotememory (int unit, int chn, int pitch) {
int deltaPitch;
if (chn == 9) return;
if (unit == nm[chn].eighthUnit) {
if (pitch > nm[chn].nowPitch) nm[chn].nowPitch = pitch;
return;
}
/* unit is different */
nm[chn].beforePitch = nm[chn].nowPitch;
nm[chn].nowPitch = pitch;
if (nm[chn].previousPitch > 0)
{
deltaPitch = nm[chn].beforePitch - nm[chn].previousPitch;
if (deltaPitch < 0) deltaPitch = -deltaPitch;
if (deltaPitch == 0) nm[chn].zeroCount++;
else if (deltaPitch < 4) nm[chn].stepCount++;
else nm[chn].jumpCount++;
}
if (nm[chn].beforePitch != 0) nm[chn].previousPitch = nm[chn].beforePitch;
nm[chn].eighthUnit = unit;
nm[chn].totalNotes++;
nm[chn].totalPitches = nm[chn].totalPitches + pitch;
}
void updateTrackNotememory (int unit, int chn, int pitch) {
int deltaPitch;
if (chn == 9) return;
if (unit == tracknm.eighthUnit) {
if (pitch > tracknm.nowPitch) tracknm.nowPitch = pitch;
return;
}
/* unit is different */
tracknm.beforePitch = tracknm.nowPitch;
tracknm.nowPitch = pitch;
if (tracknm.previousPitch > 0)
{
deltaPitch = tracknm.beforePitch - tracknm.previousPitch;
if (deltaPitch < 0) deltaPitch = -deltaPitch;
if (deltaPitch == 0) tracknm.zeroCount++;
else if (deltaPitch < 4) tracknm.stepCount++;
else tracknm.jumpCount++;
}
if (tracknm.beforePitch != 0) tracknm.previousPitch = tracknm.beforePitch;
tracknm.eighthUnit = unit;
/*printf("%d, %d, %d, %d, %d, %d %d\n",unit,nm[chn].beforePitch,nm[chn].previousPitch,\
deltaPitch,nm[chn].zeroCount,nm[chn].stepCount,nm[chn].jumpCount);
*/
}
void stats_noteon(chan,pitch,vol)
int chan, pitch, vol;
@@ -752,6 +857,7 @@ int chan, pitch, vol;
int delta;
int barnum;
int unit;
int eigthunit;
int dithermargin; /* [SS] 2023-08-22 */
int cpitch; /* [SS] 2023-09-13 */
int pulsePosition;
@@ -803,6 +909,10 @@ int chan, pitch, vol;
//printf("unit = %d pattern = %d \n",unit,barChn[chan].rhythmPattern);
barChn[chan].rhythmPattern = barChn[chan].rhythmPattern |= (1UL << unit);
chanpitchhistogram[chan*12+cpitch]++; /* [SS] 2023-09-13 */
eigthunit = Mf_currtime/halfdivision;
updateNotememory (eigthunit, chan, pitch);
updateTrackNotememory (eigthunit, chan, pitch);
}
@@ -975,6 +1085,7 @@ lastEvent++;
if (lastEvent > 49999) {printf("ran out of space in midievents structure\n");
exit(1);
}
/*if (lastEvent < 20) {printf("record_noteon %d %d %d %ld\n",chan,pitch,vol,Mf_currtime/halfdivision);}*/
channel_active[chan+1]++;
}
@@ -1005,6 +1116,7 @@ void load_header (int format, int ntrks, int ldivision)
{
int i;
division = ldivision;
halfdivision = ldivision/2;
lasttrack = ntrks;
for (i=0;i<17;i++) channel_active[i] = 0; /* for counting number of channels*/
}
@@ -1173,23 +1285,27 @@ int index;
int remainder;
int noteNum;
int part;
printf("noteseqmap %d\n",chn);
half = division/2;
for (i = 0; i<8000; i++) pseq[i] = 0;
for (i = 0; i <lastEvent; i++) {
channel = midievents[i].channel;
if (channel != chn) continue;
pitchclass = midievents[i].pitch % 12;
noteNum = pitch2noteseq[pitchclass];
onset = midievents[i].onsetTime;
index = onset/half;
if (index >= 8000) {printf("index too large in drumpattern\n");
if (channel == 9) continue; /* ignore percussion channel */
if (channel == chn || chn == -1) {
pitchclass = midievents[i].pitch % 12;
noteNum = pitch2noteseq[pitchclass];
onset = midievents[i].onsetTime;
index = onset/half;
if (index >= 8000) {printf("index too large in drumpattern\n");
break;
}
pseq[index] = pseq[index] |= 1 << noteNum;
pseq[index] = pseq[index] |= 1 << noteNum;
}
/*printf("pitchclass = %d noteNum =%d index = %d pseq[index] %d \n",pitchclass, noteNum, index, pseq[index]); */
}
printf("lastBeat = %d\n",lastBeat);
}
void print_pseq () {
int i;
for (i=0;i<(lastBeat+1)*2;i++) {
printf("%d ",pseq[i]);
if (i >= 8000) break;
@@ -1197,6 +1313,68 @@ for (i=0;i<(lastBeat+1)*2;i++) {
printf("\n");
}
int noteseqhist(int chan) {
int nonzeros;
int i;
nonzeros = 0;
noteseqmap(chan);
for (i=0;i<128;i++) {
pseqhist[i] = 0;
}
for (i=0;i<lastBeat;i++) {
pseqhist[pseq[i]]++;
}
for (i=0;i<128;i++) {
if (pseqhist[i] > 0)
nonzeros++;;
}
return nonzeros;
}
void allDistinctNoteSeq() {
int i;
int nonzeros;
for (i=0;i<17;i++) {
/*printf("\n%d,%d",i,channel_active[i+1]);*/
if (i == 9) continue;
if (channel_active[i+1] == 0) continue;
nonzeros = noteseqhist(i);
if (channel_active[i+1] > 0) printf("\t%d,%d",i+1,nonzeros);
}
printf("\n");
}
void outputChannelSummary() {
int i;
printf("\nprograms: ");
for(i=1;i<17;i++) printf(" %d",channel2prog[i]);
printf("\ncnotes: ");
for(i=1;i<17;i++) printf(" %d",channel2nnotes[i]);
printf("\nnnotes: ");
for(i=0;i<16;i++) printf(" %d",nm[i].totalNotes);
printf("\nnzeros: ");
for(i=0;i<16;i++) printf(" %d",nm[i].zeroCount);
printf("\nnsteps: ");
for(i=0;i<16;i++) printf(" %d",nm[i].stepCount);
printf("\nnjumps: ");
for(i=0;i<16;i++) printf(" %d",nm[i].jumpCount);
printf("\nrpats: ");
for(i=1;i<17;i++) printf(" %d",trkdata.rhythmpatterns[i]);
printf("\npavg: ");
/* avoid dividing by 0 */
for(i=0;i<16;i++) printf(" %d",nm[i].totalPitches/(1+nm[i].totalNotes));
printf("\nspread: ");
for(i=1;i<17;i++) if(nm[i].used > 0) printf(" %d",100*(trkdata.npulses[0] - nm[i].quietTime)/trkdata.npulses[0]);
else printf(" %d",0);
printf("\n");
}
void dualDrumPattern (int perc1, int perc2) {
int i;
int channel;
@@ -1589,6 +1767,21 @@ int argc;
}
}
arg = getarg("-nseq",argc,argv);
if (arg != -1) {
nseqfor = 1;
stats = 0;
nseqchn = -1;
}
arg = getarg("-nseqtokens",argc,argv);
if (arg != -1) {
nseqdistinct = 1;
stats = 0;
}
arg = getarg("-ppathist",argc,argv);
if (arg != -1) {
percpatternhist = 1;
@@ -1626,10 +1819,12 @@ int argc;
printf(" -pulseanalysis\n");
printf(" -panal\n");
printf(" -ppat\n");
printf(" -ppatfor\n");
printf(" -ppatfor pitch\n");
printf(" -ppathist\n");
printf(" -pitchclass\n");
printf(" -nseqfor\n");
printf(" -nseq\n");
printf(" -nseqfor channel\n");
printf(" -nseqtokens\n");
printf(" -ver version number\n");
printf(" -d <number> debug parameter\n");
printf(" The input filename is assumed to be any string not\n");
@@ -1683,7 +1878,11 @@ if (percpatternhist) {
}
if (nseqfor) {
noteseqmap(nseqchn);
print_pseq();
}
if (nseqdistinct) {
allDistinctNoteSeq();
}
if (corestats) corestatsOutput();
if (pitchclassanalysis) {
pitchClassAnalysis();
@@ -1704,6 +1903,6 @@ int argc;
if(stats == 1) midistats(argc,argv);
if(pulseanalysis || corestats || percanalysis ||\
percpatternfor || percpattern || percpatternhist ||\
pitchclassanalysis || nseqfor) loadEvents();
pitchclassanalysis || nseqfor || nseqdistinct) loadEvents();
return 0;
}

View File

@@ -205,6 +205,26 @@ static int get_clef_octave_offset (char *clef_ending)
if (strncmp (clef_ending, "-15", 2) == 0) {
return -2;
}
/* ^8, ^15, _8, _15 does not transpose the notes in
the midi output according to the abc standard 2.2;
though it should display the appropriate symbol in
the clef. For the time being I am commenting
the other endings so abc2midi runs correctly.
[SS] 2024.02.24
if (strncmp (clef_ending, "^8", 2) == 0) {
return 1;
}
if (strncmp (clef_ending, "^15", 2) == 0) {
return 2;
}
if (strncmp (clef_ending, "_8", 2) == 0) {
return -1;
}
if (strncmp (clef_ending, "_15", 2) == 0) {
return -2;
}
*/
return 0;
}

View File

@@ -688,7 +688,7 @@ int isclef (char *s, cleftype_t * new_clef,
int gotclef;
gotclef = 0;
new_clef->octave_offset = 0;
/*new_clef->octave_offset = 0; [SS] 2024-02.22 */
gotclef = get_standard_clef (s, new_clef);
if (!gotclef && expect_clef) {
/* do we have a clef in letter format ? e.g. C1, F3, G3 */
@@ -742,6 +742,33 @@ readword (word, s)
return (p);
}
char *
readword_with_ (word, s)
/* This version allows ^ and _ characters to be embedded in*/
/* the string. It is needed to parse clef=treble_8 or
/* clef=treble^8 . [SS] 2024-02-23 */
char word[];
char *s;
{
char *p;
int i;
p = s;
i = 0;
/* [SS] 2015-04-08 */
while ((*p != '\0') && (*p != ' ') && (*p != '\t') && ((i == 0) ||
((*p != '='))))
{
if (i < 29)
{
word[i] = *p;
i = i + 1;
};
p = p + 1;
};
word[i] = '\0';
return (p);
}
void
lcase (s)
/* convert word to lower case */
@@ -965,7 +992,7 @@ parseclef (s, word, gotclef, clefstr, newclef, gotoctave, octave)
{
int successful;
skipspace (s);
*s = readword (word, *s);
*s = readword_with_ (word, *s);
successful = 0;
if (casecmp (word, "clef") == 0)
{
@@ -978,7 +1005,7 @@ parseclef (s, word, gotclef, clefstr, newclef, gotoctave, octave)
{
*s = *s + 1;
skipspace (s);
*s = readword (clefstr, *s);
*s = readword_with_ (clefstr, *s);
if (isclef (clefstr, newclef, gotoctave, octave, 1))
{
*gotclef = 1;
@@ -1743,13 +1770,6 @@ parsevoice (s)
}
event_voice (num, s, &vparams);
/*
if (gottranspose) printf("transpose = %d\n", vparams.transpose);
if (gotoctave) printf("octave= %d\n", vparams.octave);
if (gotclef) printf("clef= %s\n", vparams.clefstr);
if (gotname) printf("parsevoice: name= %s\n", vparams.namestring);
if(gotmiddle) printf("parsevoice: middle= %s\n", vparams.middlestring);
*/
}
@@ -3020,8 +3040,14 @@ parsemusic (field)
p = p + 1;
break;
case '|':
check_and_call_bar (DOUBLE_BAR, "");
p = p + 1;
if (*(p+1) == ':') {
/* handle ||: as a variant of |: [JA] 2024-02-19 */
check_and_call_bar (BAR_REP, "");
p = p + 2;
} else {
check_and_call_bar (DOUBLE_BAR, "");
p = p + 1;
}
break;
case ']':
check_and_call_bar (THIN_THICK, "");

15
store.c
View File

@@ -186,7 +186,7 @@ int main()
*/
#define VERSION "4.85 December 23 2023 abc2midi"
#define VERSION "4.91 March 02 2024 abc2midi"
/* enables reading V: indication in header */
#define XTEN1 1
@@ -2946,6 +2946,7 @@ char* s;
part_start[(int)*p - (int)'A'] = notes;
addfeature(PART, (int)*p, 0, 0);
checkbreak();
v1index = notes; /* [SS] 2024-02-14 */
v = getvoicecontext(1);
} else {
parts = 0;
@@ -2975,10 +2976,11 @@ struct voice_params *vp;
v = getvoicecontext(n);
addfeature(VOICE, v->indexno, 0, 0);
if (vp->gotclef)
/*****if (vp->gotclef)
{
event_octave(vp->new_clef.octave_offset, 1);
}
}*** [SS] 2024-03.02 */
if (vp->gotoctave) {
event_octave(vp->octave,1);
};
@@ -4303,11 +4305,16 @@ int xoctave, n, m;
event_fatal_error("Internal error - no voice allocated");
};
if (gracenotes && ignore_gracenotes) return; /* [SS] 2010-01-08 */
if (v->octaveshift == 0) { /* [JA] 2021-05-21 */
/* [SS] 2024-03-02
printf("clef->octave_offset = %d v->octaveshift = %d\n",clef->octave_offset,v->octaveshift);
if (v->octaveshift == 0) { [JA] 2021-05-21
octave = xoctave + clef->octave_offset;
} else {
octave = xoctave + v->octaveshift;
}
*/
octave = clef->octave_offset + v->octaveshift + xoctave; /*[SS] 2024-03-02*/
num = n;
denom = m;
if (v->inchord) v->chordcount = v->chordcount + 1;

View File

@@ -21,7 +21,7 @@
/* back-end for outputting (possibly modified) abc */
#define VERSION "2.20 Feb 07 2023 abc2abc"
#define VERSION "2.21 Feb 19 2024 abc2abc"
/* for Microsoft Visual C++ 6.0 or higher */
#ifdef _MSC_VER

View File

@@ -22,7 +22,7 @@
/* yapstree.c - back-end for abc parser. */
/* generates a data structure suitable for typeset music */
#define VERSION "1.92 January 06 2023 yaps"
#define VERSION "1.93 February 19 2024 yaps"
#include <stdio.h>
#ifdef USE_INDEX
#define strchr index