Compare commits

..

7 Commits

Author SHA1 Message Date
Seymour Shlien
d73b3682e1 2023.01.08 2023-01-08 11:10:49 -05:00
Seymour Shlien
c981535a2a 2023.01.06 2023-01-06 14:22:28 -05:00
Seymour Shlien
7fae7302c3 2022.01.05 2023-01-05 15:53:13 -05:00
Seymour Shlien
166a28d182 2022.12.30 2022-12-30 11:08:38 -05:00
Seymour Shlien
cc1a30b3b4 2022.12.27 2022-12-27 15:22:18 -05:00
Seymour Shlien
2baecffc37 2022.12.22 2022-12-22 12:08:00 -05:00
Seymour Shlien
c24f1ffdc1 2022.12.09 2022-12-09 13:31:50 -05:00
15 changed files with 380 additions and 556 deletions

View File

@@ -1,2 +1,2 @@
December 07 2022
January 08 2023

View File

@@ -14865,3 +14865,171 @@ separate applications. Midistats is a new application that will replace
the midi2abc -midistats option.
December 9 2022
Cleaning out -stats code in midi2abc.
December 21 2022
abc2midi:
Wnen <note1> equals <note2> in the instrument=<note1>/<note2> directive,
note2 should be treated as c (midi pitch 72). Fix: parsesound in
parseabc.c was modified to return a midi pitch of 72 when the two
notes are equal.
test file:
X:1
T: transpose
M: 4/4
L: 1/4
K: C instrument=F/F
FGAB|cdef|
produces a midi file which looks like
X: 1
T: from h1.mid
M: 4/4
L: 1/8
Q:1/4=120
K:C % 0 sharps
V:1
c2 d2 e2 ^f2| \
g2 a2 b2 c'2|
when it was translated back to abc using midi2abc.
Note that this change also applies to sound= and shift= even though
this may not be specified in the standard
http://abcnotation.com/wiki/abc:standard:v2.2#transposing_instrument_examples
December 22 2022
abcmidi: segementation fault. The following file produced a
segmentation fault.
X:1
T: transpose
M: 4/4
L: 1/4
K: C instrument=F
FGAB|cdef|
Analysis: there is an invisible space following F in the
line K: C instrument=F . As a result the function note2midi
called pitch2midi with an invalid note (a space). The line
p = (int) ((long) strchr(anoctave, note) - (long) anoctave);
returned a bad index into the scale array.
Fix: tested that p is in the range 0 to 7.
December 27 2022
abcmidi: The instrument=<note1>/<note2> is defined as a shorthand
for score=<note1><note2> sound=c<note2>. For instrument=,<note1>
indicates the key of the instrument and <note2> is either c or C.
The sound= directive specifies the note and how it is played.
For example, sound=c_B indicates that the note c is played as
_B on the instrument. Every note is transposed down by two semitones.
The problem is that, the notes in the instrument directive are
in the opposite order of the sound= and score= directives.
The function parsesound() in parseabc.c treats takes care of
the directives sound =, shift = and instrument =.
Unfortunately, all these directives are treated in the same
manner causing the instrument= directive to transpose
in the wrong direction.
Fix: for the special case, instrument=, transpose is set to
p1 - p2 instead of p2 - p1.
The '/' is only part of the instrument= syntax. Note2midi has
an extra parameter, word, indicating the type of directive.
It will issue a warning if it detects a '/' in the sound= or
shift= directives.
December 30 2022
abcmidi: The instrument=*/c is a special directive that suppresses
a transpose. For example:
X:2
T: transpose using instrument=_B/c
T: clarinet coded in concert pitch, displayed in Bb (as in player part)
M: 4/4
L: 1/4
K: C
V:1 nm="Flute"
CDEF|GABc|cBAG|FEDC|
V:2 instrument=_B/c nm="Clarinet\nin Bb"
CDEF|GABc|cBAG|FEDC|
The notes in V:2 are displayed up using score=_Bc, but they are still
played as written (sound=cc does nothing).
Fix: the code in the block
if (casecmp(word,"instrument") == 0 {
...
}
in parsesound() (parseabc.c) was rewritten.
January 05 2023
abc2midi: instrument =F/D transposes cdec up by 3 semitones instead of
down by 10 semitones in the following example.
X:5
T: wrong octave
M: 4/4
K:C
V:1 instrument=F/D
cdec z4
V:2
z4 c4
Fix: Hudson Lacerda supplied me with pseudo-code (doc/hudsonshift.txt)
which describes how all the transpose directives should work.
This code was implemented in parseSoundScore() which now replaces
parseSound(). It also fixes yaps.
January 06 2023
abcmidi ignores sound=cD in the following example.
X:2
T: sound + score
M: 4/4
K:C
V:1 sound=cD score=FD
cdec z4
V:2
z4 c4
Analysis: *transpose is set to -10 by parseSoundScore when it
processes sound=CD but when parseSoundScore is called again
with score=FD it sets *transpose to 0, the initialized value
of transp_sound. The last value of *transpose is used by
event_voice.
Fix: if parseSoundScore is called by the abc2midi executable,
then *transpose is not set to transp_sound when the score=
directive is processed. There is a similar issue when
parseSoundScore is called by yaps. We do not want to set
*transpose to transp_score when the sound= is processed.
January 08 2023
abc2abc should replicate the score=, shift=, sound=, and instrument=
directives but otherwise ignore them.
Fix: parseSoundScore() in parseabc.c does nothing if it is
called from abc2abc and return 0. The function parseother(),
which is called from parsevoice() or parsekey(), will output
all other directives in the K: or V: command.

57
doc/hudsonshift.txt Executable file
View File

@@ -0,0 +1,57 @@
init:
transp_sound = transp_score = 0;
ABC2MIDI: use transp_sound;
YAPS: use transp_score;
ABC2ABC: ignore and replicate instructions to output;
/******************************************/
if (p1==0) error();
sound:
if (p2==0)
error();
transp_sound = p2-p1;
/*
sound=<note1><note2> transposes the playback according to the
specified interval (the typeset score is not affected)
*/
score:
if (p2==0)
p2 = ( 72 );
transp_score = p2-p1;
/*
score=<note1><note2> transposes the typeset score according to the
specified interval (the playback is not affected); if the second note
is omitted it is assumed to be a c (see writing abc code for
transposing instruments)
*/
instrument:
if (p2==0)
p2 = p1;
transp_score = p2-p1;
transp_sound = p2-( 72 );
/*
instrument=<note1>/<note2> is defined as score=<note1><note2> sound=c<note2>
*/
shift:
if (p2==0)
error();
transp_score = transp_sound = p2-p1;
/*
shift=<note1><note2> transposes the typeset score and the playback
according to the specified interval
*/
/******************************************/

View File

@@ -172,23 +172,6 @@ the given string.
.B -origin \fistring\fP
Adds an O: field with the given string.
.TP
.B -stats
Extracts the characteristics of the given midi file. They include
ntrks - the number of tracks, ppqn - pulses per quarter note,
timesig - time signature, keysig - key signature, program - mapping
between channel number and midi program, npulses - length of the
midi file in pulses, tempocmd - number of times the tempo has
been specified, pitchbends - number of pitchbends, pitchbendin -
number of pitchbends in each of the channels, programcmd - number of
times the midi program has been revised, progs and progsact - the
programs used and the number of pulses these programs used, drums -
the drum numbers that were used, drumhits - the number of times
each of those drums were hit, pitches - the number of times the
11 pitch classes (C C# etc...) were activated and a few other
complex variables. These characteristics are used in other
applications such as midiexplorer. More details are available
in the file midi2abc-stats.txt included in the doc/ folder
of the abcmidi distribution package.
.SS FEATURES

View File

@@ -1,4 +1,4 @@
.TH MIDISTATS 1 "3 December 2022"
.TH MIDISTATS 1 "9 December 2022"
.SH NAME
\fBmidistats\fP \- program to summarize the statistical properties of a midi file
.SH SYNOPSIS
@@ -35,17 +35,12 @@ the total number of notes for this for this channel,
the sum of the MIDI pitches for all the notes,
the sum of the note durations in MIDI pulse units,
the number of control parameter messages,
and the number of pressure messages.
the number of pressure messages.
and the number of distinct rhythm patterns for each channel
.PP
After processing all the individual tracks, the following information
applies to the entire midi file.
.PP
rhythmPatterns indicates the number of distinct rhythm patterns for each
channel. A large number likely implies that the melody line occurs in
this channel, while a small number indicates that this channel probably
is used for chordal support.
.PP
npulses is the length of the longest midi track in midi pulse units
.PP
tempocmds specifies the number of times the tempo is changed in this
@@ -74,7 +69,17 @@ that occur in the midi file.
.PP
pitchact is a similar histogram but is weighted by the length of
the notes.
.PP
quietTime is used to compute the track/channel spread in midiexplorer.
It is computed by summing up all the midi pulses which occur
in gaps greater than 8 beats.
.PP
totalrhythmpatterns is the total number of bar rhythm patterns for
all channels except the percussion channel.
.PP
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.
.SH AUTHOR
Seymour Shlien <fy733@ncf.ca>

View File

@@ -1,6 +0,0 @@
/abc2midi.txt/1.1.1.1/Thu Sep 28 18:17:04 2006//
/coding.txt/1.1.1.1/Thu Sep 28 18:17:04 2006//
/midi2abc.txt/1.1.1.1/Thu Sep 28 18:17:04 2006//
/split.abc/1.1.1.1/Thu Sep 28 18:17:04 2006//
/yaps.txt/1.1.1.1/Thu Sep 28 18:17:04 2006//
D

View File

@@ -1 +0,0 @@
abcmidi/doc/programming

View File

@@ -1 +0,0 @@
/home/seymour/CVSREPOS

View File

@@ -1,12 +1,12 @@
abcMIDI : abc <-> MIDI conversion utilities
midi2abc version 3.57 September 01 2022
abc2midi version 4.76 August 01 2022
abc2abc version 2.18 June 14 2022
yaps version 1.90 June 14 2022
midi2abc version 3.58 December 09 2022
abc2midi version 4.82 January 06 2023
abc2abc version 2.19 January 08 2023
yaps version 1.92 January 06 2023
abcmatch version 1.82 June 14 2022
midicopy version 1.38 May 06 2022
midistats version 0.56 December 07 2022
midistats version 0.58 December 09 2022
24th January 2002

View File

@@ -45,7 +45,7 @@
* based on public domain 'midifilelib' package.
*/
#define VERSION "3.57 September 01 2022 midi2abc"
#define VERSION "3.58 December 09 2022 midi2abc"
#include <limits.h>
/* Microsoft Visual C++ Version 6.0 or higher */
@@ -79,12 +79,9 @@ extern char* strchr();
#define MIDDLE 72
void initfuncs();
void setupkey(int);
void stats_finish();
int testtrack(int trackno, int barbeats, int anacrusis);
int open_note(int chan, int pitch, int vol);
int close_note(int chan, int pitch, int *initvol);
float histogram_entropy (int *histogram, int size);
void stats_noteoff(int chan,int pitch,int vol);
void reset_back_array (); /* [SS] 2019-05-08 */
@@ -251,67 +248,7 @@ void txt_trackstart_type0();
void txt_noteon_type0(int,int,int);
void txt_program_type0(int,int);
/* The following variables are used by the -stats option
* which is used by a separate application called midiexplorer.tcl.
* The channel numbers go from 1 to 16 instead of 0 to 15
*/
struct trkstat {
int notecount[17];
int chordcount[17];
int notemeanpitch[17];
int notelength[17];
int pitchbend[17];
int pressure[17];
int cntlparam[17];
int program[17];
int tempo[17];
int npulses[17];
int lastNoteOff[17];
int quietTime[17];
} trkdata;
/* The trkstat references the individual channels in the midi file.
* notecount is the number of notes or bass notes in the chord.
* chordcount is the number of notes not counting the bass notes.
* notemeanpitch is the average pitch for the channel.
* notelength is the average note length.
* pitchbend is the number of pitch bends for the channel.
* pressure is the number of control pressure commands.
* cntlparam is the number of control parameter commands.
* program is number of times there is a program command for the channel.
* tempo is the number of times there is a tempo command.
* npulses is the number of pulses.
*/
int progcolor[17]; /* used by stats_program */
int drumhistogram[82]; /* counts drum noteons */
int pitchhistogram[12]; /* pitch distribution for non drum notes */
int channel2prog[17]; /* maps channel to program */
int channel2nnotes[17]; /*maps channel to note count */
int chnactivity[17]; /* [SS] 2018-02-02 */
int progactivity[128]; /* [SS] 2018-02-02 */
int pitchclass_activity[12]; /* [SS] 2018-02-02 */
/* [SS] 2017-11-01 */
static int progmapper[] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 1, 1, 1, 1, 1, 2,
3, 3, 3, 3, 3, 3, 3, 3,
2, 2, 4, 4, 4, 4, 4, 2,
5, 5, 5, 5, 5, 5, 5, 5,
6, 6, 6, 6, 6, 2, 7, 10,
7, 7, 7, 7, 8, 8, 8, 8,
9, 9, 9, 9, 9, 9, 9, 9,
11, 11, 11, 11, 11, 11, 11, 11,
12, 12, 12, 12, 12, 12, 12, 12,
13, 13, 13, 13, 13, 13, 13, 13,
14, 14, 14, 14, 14, 14, 14, 14,
15, 15, 15, 15, 15, 15, 15, 15,
2, 2, 2, 2, 2, 12, 6, 12,
1, 1, 10, 10, 10, 10, 10, 1,
16, 16, 16, 16, 16, 16, 16, 16
};
/* Stage 1. Parsing MIDI file */
@@ -609,15 +546,6 @@ char *s;
}
/* [SS] 2017-11-19 */
void stats_error(s)
char *s;
{
fprintf(stderr,"Error: %s\n",s);
fprintf(stderr,"activetrack %d\n",tracknum);
stats_finish();
}
void txt_header(xformat,ntrks,ldivision)
@@ -731,12 +659,6 @@ int chan, pitch, press;
{
}
void stats_pressure(chan,press)
int chan, press;
{
trkdata.pressure[0]++;
trkdata.pressure[chan+1]++; /* [SS] 2022.04.28 */
}
void txt_parameter(chan,control,value)
int chan, control, value;
@@ -1140,145 +1062,7 @@ void mftxt_header (int format, int ntrks, int ldivision)
}
void stats_header (int format, int ntrks, int ldivision)
{
int i;
division = ldivision;
quietLimit = ldivision*8;
printf("ntrks %d\n",ntrks);
printf("ppqn %d\n",ldivision);
chordthreshold = ldivision/16; /* [SS] 2018-01-21 */
trkdata.tempo[0] = 0;
trkdata.pressure[0] = 0;
trkdata.program[0] = 0;
for (i=0;i<17;i++) {
trkdata.npulses[i] = 0;
trkdata.pitchbend[i] = 0;
trkdata.cntlparam[i] = 0; /* [SS] 2022-03-04 */
trkdata.pressure[i] = 0; /* [SS] 2022-03-04 */
trkdata.quietTime[i] = 0; /* [SS] 2022-08-22 */
progcolor[i] = 0;
channel2prog[i] = -1;
channel2nnotes[i] = 0;
chnactivity[i] = 0; /* [SS] 2018-02-02 */
}
for (i=0;i<82;i++) drumhistogram[i] = 0;
for (i=0;i<12;i++) pitchhistogram[i] = 0; /* [SS] 2017-11-01 */
for (i=0;i<12;i++) pitchclass_activity[i] = 0; /* [SS] 2018-02-02 */
for (i=0;i<128;i++) progactivity[i] = 0; /* [SS] 2018-02-02 */
}
void determine_progcolor ()
{
int i;
for (i=0;i<17;i++) progcolor[i] =0;
for (i=0;i<128;i++) {
progcolor[progmapper[i]] += progactivity[i];
}
}
/* [SS] 2018-04-24 */
void output_progs_data () {
int i;
/* check that there is valid progactivity */
printf("progs ");
for (i=0;i<128;i++)
if(progactivity[i] > 0) printf(" %d",i);
printf("\nprogsact ");
for (i=0;i<128;i++)
if(progactivity[i] > 0) printf(" %d",progactivity[i]);
}
void stats_finish()
{
int i; /* [SDG] 2020-06-03 */
int npulses;
int nprogs;
double delta;
npulses = trkdata.npulses[0];
printf("npulses %d\n",trkdata.npulses[0]);
printf("tempocmds %d\n",trkdata.tempo[0]);
printf("pitchbends %d\n",trkdata.pitchbend[0]);
for (i=1;i<17;i++) {
if (trkdata.pitchbend[i] > 0) {
printf("pitchbendin %d %d\n",i,trkdata.pitchbend[i]); }
}
if (trkdata.pressure[0] > 0)
printf("pressure %d\n",trkdata.pressure[0]);
printf("programcmd %d\n",trkdata.program[0]);
nprogs = 0; /* [SS] 2018-04-24 */
for (i=1;i<128;i++)
if(progactivity[i] >0) nprogs++;
if (nprogs > 0) output_progs_data();
else {
for (i=0;i<17;i++)
if(chnactivity[i] > 0)
progactivity[channel2prog[i]] = chnactivity[i];
output_progs_data();
}
determine_progcolor();
printf("\nprogcolor ");
if (npulses > 0)
for (i=0;i<17;i++) printf("%5.2f ",progcolor[i]/(double) npulses);
else
for (i=0;i<17;i++) printf("%5.2f ",(double) progcolor[i]);
printf("\n");
printf("drums ");
for (i=35;i<82;i++) {
if (drumhistogram[i] > 0) printf("%d ",i);
}
printf("\ndrumhits ");
for (i=35;i<82;i++) {
if (drumhistogram[i] > 0) printf("%d ",drumhistogram[i]);
}
printf("\npitches "); /* [SS] 2017-11-01 */
for (i=0;i<12;i++) printf("%d ",pitchhistogram[i]);
printf("\npitchact "); /* [SS] 2018-02-02 */
if (npulses > 0)
for (i=0;i<12;i++) printf("%5.2f ",pitchclass_activity[i]/(double) npulses);
else
for (i=0;i<12;i++) printf("%5.2f ",(double) pitchclass_activity[i]);
printf("\nchnact "); /* [SS] 2018-02-08 */
if (npulses > 0)
for (i=1;i<17;i++) printf("%5.2f ",chnactivity[i]/(double) trkdata.npulses[0]);
else
for (i=0;i<17;i++) printf("%5.2f ",(double) chnactivity[i]);
printf("\npitchentropy %f\n",histogram_entropy(pitchclass_activity,12));
printf("\n");
}
float histogram_entropy (int *histogram, int size)
{
int i;
int total;
float entropy;
float e,p;
total = 0;
entropy = 0.0;
for (i=0;i<size;i++) {
total += histogram[i];
}
for (i=0;i<size;i++) {
if (histogram[i] < 1) continue;
p = (float) histogram[i]/total;
e = p*log(p);
entropy = entropy + e;
}
return -entropy/log(2.0);
}
@@ -1291,70 +1075,9 @@ void mftxt_trackstart()
printf("Track %d contains %d bytes\n",tracknum,numbytes);
}
void output_count_trkdata(data_array,name)
int data_array[];
char *name;
{
int i,sum;
sum = 0;
for (i=1;i<17;i++) sum += data_array[i];
if (sum != 0) {
for (i=0;i<17;i++)
if(data_array[i]>0) {
printf("%s ",name);
printf("%d %d ",i,data_array[i]);
printf("\n");
}
}
}
void output_track_summary () {
int i;
/* find first channel containing data */
for (i=0;i<17;i++) {
if(trkdata.notecount[i] == 0 && trkdata.chordcount[i] == 0) continue;
printf("trkinfo ");
printf("%d %d ",i,trkdata.program[i]); /* channel number and program*/
printf("%d %d ",trkdata.notecount[i],trkdata.chordcount[i]);
printf("%d %d ",trkdata.notemeanpitch[i], trkdata.notelength[i]);
printf("%d %d ",trkdata.cntlparam[i],trkdata.pressure[i]); /* [SS] 2022-03-04 */
printf("%d ",trkdata.quietTime[i]); /* [SS] 2022.09.01 */
trkdata.quietTime[i] = 0;
printf("\n");
channel2nnotes[i] += trkdata.notecount[i] + trkdata.chordcount[i];
}
}
void stats_trackstart()
{
int i;
tracknum++;
for (i=0;i<17;i++) {
trkdata.notecount[i] = 0;
trkdata.notemeanpitch[i] = 0;
trkdata.notelength[i] = 0;
trkdata.chordcount[i] = 0;
trkdata.cntlparam[i] = 0;
last_tick[i] = -1;
last_on_tick[i] = -1;
}
printf("trk %d \n",tracknum);
}
void stats_trackend()
{
trkdata.npulses[tracknum] = Mf_currtime;
if (trkdata.npulses[0] < Mf_currtime) trkdata.npulses[0] = Mf_currtime;
output_track_summary();
}
void mftxt_noteon(chan,pitch,vol)
int chan, pitch, vol;
{
@@ -1369,38 +1092,6 @@ int chan, pitch, vol;
printf("\n");
}
void stats_noteon(chan,pitch,vol)
int chan, pitch, vol;
{
int delta;
if (vol == 0) {
/* treat as noteoff */
stats_noteoff(chan,pitch,vol);
trkdata.lastNoteOff[chan+1] = Mf_currtime; /* [SS] 2022.08.22 */
return;
}
trkdata.notemeanpitch[chan+1] += pitch;
if (trkdata.lastNoteOff[chan+1] >= 0) {
delta = Mf_currtime - trkdata.lastNoteOff[chan+1];
trkdata.lastNoteOff[chan+1] = -1; /* in case of chord */
if (delta > quietLimit) {
trkdata.quietTime[chan+1] += delta;
}
}
if (abs(Mf_currtime - last_on_tick[chan+1]) < chordthreshold) trkdata.chordcount[chan+1]++;
else trkdata.notecount[chan+1]++; /* [SS] 2019-08-02 */
last_tick[chan+1] = Mf_currtime;
last_on_tick[chan+1] = Mf_currtime; /* [SS] 2019-08-02 */
/* last_on_tick not updated by stats_noteoff */
if (chan == 9) {
if (pitch < 0 || pitch > 81)
printf("****illegal drum value %d\n",pitch);
else drumhistogram[pitch]++;
}
else pitchhistogram[pitch % 12]++; /* [SS] 2017-11-01 */
}
void mftxt_noteoff(chan,pitch,vol)
int chan, pitch, vol;
@@ -1415,28 +1106,6 @@ int chan, pitch, vol;
}
void stats_noteoff(int chan,int pitch,int vol)
{
int length;
int program;
/* ignore if there was no noteon */
if (last_tick[chan+1] == -1) return;
length = Mf_currtime - last_tick[chan+1];
trkdata.notelength[chan+1] += length;
trkdata.lastNoteOff[chan+1] = Mf_currtime; /* [SS] 2022.08.22 */
chnactivity[chan+1] += length;
if (chan == 9) return; /* drum channel */
pitchclass_activity[pitch % 12] += length;
program = trkdata.program[chan+1];
progactivity[program] += length;
/* [SS] 2018-04-18 */
if(Mf_currtime > last_tick[chan+1]) last_tick[chan+1] = Mf_currtime;
}
void stats_eot () {
trkdata.lastNoteOff[0] = Mf_currtime; /* [SS] 2022.08.24 */
}
void mftxt_polypressure(chan,pitch,press)
@@ -1474,12 +1143,6 @@ int chan, lsb, msb;
printf("Pitchbend %2d %d cents = %6.3f (cents)\n",chan+1,pitchbend,cents);
}
void stats_pitchbend(chan,lsb,msb)
int chan, lsb, msb;
{
trkdata.pitchbend[0]++;
trkdata.pitchbend[chan+1]++;
}
void mftxt_program(chan,program)
int chan, program;
@@ -1536,23 +1199,6 @@ static char *patches[] = {
}
void stats_program(chan,program)
int chan, program;
{
int beatnumber;
if (program <0 || program > 127) return; /* [SS] 2018-03-06 */
if (trkdata.program[chan+1] != 0) {
beatnumber = Mf_currtime/division;
printf("cprogram %d %d %d\n",chan+1,program,beatnumber);
/* count number of times the program was modified for a channel */
trkdata.program[0] = trkdata.program[0]+1;
} else {
printf("program %d %d\n",chan+1,program);
trkdata.program[chan+1] = program;
}
if (channel2prog[chan+1]== -1) channel2prog[chan+1] = program;
}
void mftxt_parameter(chan,control,value)
int chan, control, value;
@@ -1631,15 +1277,6 @@ int chan, control, value;
printf("CntlParm %2d %s = %d\n",chan+1, ctype[control],value);
}
void stats_parameter(chan,control,value)
int chan, control, value;
{
/*if (control == 7) {
printf("cntrlvolume %d %d \n",chan+1,value);
}
*/
trkdata.cntlparam[chan+1]++;
}
void mftxt_metatext(type,leng,mess)
int type, leng;
@@ -1677,17 +1314,6 @@ char *mess;
}
void stats_metatext(type,leng,mess)
int type, leng;
char *mess;
{
int i;
if (type != 3) return;
printf("metatext %d ",type);
for (i=0;i<leng;i++) printf("%c",mess[i]);
printf("\n");
}
void mftxt_keysig(sf,mi)
int sf, mi;
@@ -1706,25 +1332,6 @@ int sf, mi;
}
/* [SS] 2018-01-02 */
void stats_keysig(sf,mi)
int sf, mi;
{
float beatnumber;
static char *major[] = {"Cb", "Gb", "Db", "Ab", "Eb", "Bb", "F",
"C", "G", "D", "A", "E", "B", "F#", "C#"};
static char *minor[] = {"Abmin", "Ebmin", "Bbmin", "Fmin", "Cmin",
"Gmin", "Dmin", "Amin", "Emin", "Bmin", "F#min", "C#min", "G#min"};
int index;
beatnumber = Mf_currtime/division;
index = sf + 7;
if (index < 0 || index >12) return;
if (mi)
printf("keysig %s %d %d %6.2f\n",minor[index],sf,mi,beatnumber);
else
printf("keysig %s %d %d %6.2f\n",major[index],sf,mi,beatnumber);
}
void mftxt_tempo(ltempo)
long ltempo;
@@ -1734,17 +1341,6 @@ long ltempo;
printf("Metatext tempo = %6.2f bpm\n",60000000.0/tempo);
}
/* [SS] 2018-01-02 */
void stats_tempo(ltempo)
long ltempo;
{
float beatnumber;
tempo = ltempo;
beatnumber = Mf_currtime/division;
if (trkdata.tempo[0] == 0) printf("tempo %6.2f bpm\n",60000000.0/tempo);
else if (trkdata.tempo[0] < 10) printf("ctempo %6.2f %6.2f\n",60000000.0/tempo,beatnumber);
trkdata.tempo[0]++;
}
void mftxt_timesig(nn,dd,cc,bb)
int nn, dd, cc, bb;
@@ -1758,16 +1354,6 @@ int nn, dd, cc, bb;
32nd-notes/24-MIDI-clocks=%d\n", nn,denom,cc,bb); */
}
void stats_timesig(nn,dd,cc,bb)
int nn, dd, cc, bb;
{
float beatnumber;
int denom = 1;
beatnumber = Mf_currtime/division;
while ( dd-- > 0 )
denom *= 2;
printf("timesig %d/%d %6.2f\n",nn,denom,beatnumber);
}
void mftxt_smpte(hr,mn,se,fr,ff)
int hr, mn, se, fr, ff;
@@ -1836,31 +1422,6 @@ void initfunc_for_mftext()
Mf_arbitrary = no_op2;
}
void initfunc_for_stats()
{
Mf_error = stats_error; /* [SS] 2017-11-19 */
Mf_header = stats_header;
Mf_trackstart = stats_trackstart;
Mf_trackend = stats_trackend;
Mf_noteon = stats_noteon;
Mf_noteoff = stats_noteoff;
Mf_pressure = no_op3;
Mf_parameter = stats_parameter;
Mf_pitchbend = stats_pitchbend;
Mf_program = stats_program;
Mf_chanpressure = stats_pressure;
Mf_sysex = no_op2;
Mf_metamisc = no_op3;
Mf_seqnum = no_op1;
Mf_eot = stats_eot;
Mf_timesig = stats_timesig;
Mf_smpte = no_op5;
Mf_tempo = stats_tempo;
Mf_keysig = stats_keysig;
Mf_seqspecific = no_op3;
Mf_text = stats_metatext;
Mf_arbitrary = no_op2;
}
@@ -3662,7 +3223,8 @@ int argc;
arg = getarg("-stats",argc,argv);
if (arg != -1)
{
stats = 1;
printf("\nuse the new application midistats\n");
exit(1);
}
arg = getarg("-d",argc,argv);
@@ -3875,7 +3437,6 @@ int argc;
printf(" -mftext mftext output in beats\n");
printf(" -mftextpulses mftext output in midi pulses\n");
printf(" -mftext mftext output in seconds\n");
printf(" -stats summary and statistics output\n");
printf(" -ver version number\n");
printf(" -d <number> debug parameter\n");
printf(" None or only one of the options -aul -gu, -b, -Q -u should\n");
@@ -4124,17 +3685,6 @@ mfread();
}
void midistats(argc,argv)
char *argv[];
int argc;
{
initfunc_for_stats();
Mf_getc = filegetc;
mfread();
stats_finish();
}
int main(argc,argv)
char *argv[];
@@ -4146,7 +3696,6 @@ int argc;
arg = process_command_line_arguments(argc,argv);
if(midiprint ==1) { midigram(argc,argv);
} else if(midiprint ==2) { mftext(argc,argv);
} else if(stats == 1) { midistats(argc,argv);
} else midi2abc(argc,argv);
return 0;
}

View File

@@ -18,7 +18,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#define VERSION "0.56 December 07 2022 midistats"
#define VERSION "0.58 December 08 2022 midistats"
#include <limits.h>
/* Microsoft Visual C++ Version 6.0 or higher */
@@ -166,29 +166,35 @@ struct barPattern {
} barChn[17];
#define HashSize 255
#define HashSize 257
struct hashStruct {
int pattern[HashSize];
int count[HashSize];
} hasher[17] = {0};
int ncollisions = 0;
int nrpatterns = 0;
void handle_collision () {
ncollisions++;
}
void put_pattern (int chan, int pattern) {
int hashindex;
hashindex = pattern % HashSize;
if (hasher[chan].pattern[hashindex] == 0) {
hasher[chan].pattern[hashindex] = pattern;
nrpatterns++;
/*printf ("hasher[%d].pattern[%d] = %d\n",chan,hashindex,pattern);*/
} else {
if (hasher[chan].pattern[hashindex] != pattern) {
} else if (hasher[chan].pattern[hashindex] != pattern) {
/* printf("collision\n"); */
ncollisions++;
}
handle_collision ();
} else {
hasher[chan].count[hashindex]++;
}
hasher[chan].count[hashindex]++;
}
int count_patterns_for (int chan) {
int i;
int sum;
@@ -204,14 +210,12 @@ return sum;
void output_hasher_results () {
int i;
printf("rhythmPatterns ");
for (i = 0; i<16; i++) {
/* printf("rhythmPatterns ");*/
for (i = 0; i<17; i++) {
trkdata.rhythmpatterns[i] = count_patterns_for(i);
printf("%d ",count_patterns_for (i));
/* printf("%d ",count_patterns_for (i)); */
}
printf("\n");
printf("collisions %d\n",ncollisions);
ncollisions = 0;
}
@@ -493,6 +497,8 @@ for (i=1;i<17;i++) {
}
printf("\npitchentropy %f\n",histogram_entropy(pitchclass_activity,12));
printf("totalrhythmpatterns =%d\n",nrpatterns);
printf("collisions = %d\n",ncollisions);
printf("\n");
}

View File

@@ -82,7 +82,7 @@ extern char *malloc ();
extern char *strchr ();
#endif
int note2midi (char** s);
int note2midi (char** s, char* word); /*[SS] 2022-12-27 added word */
int lineno;
int parsing_started = 0;
int parsing, slur;
@@ -942,7 +942,7 @@ int interpret_voice_label (char *s, int num, int *is_new)
}
/* The following four functions parseclefs, parsetranspose,
* parsesound, parseoctave are used to parse the K: field which not
* parseSoundScore, parseoctave are used to parse the K: field which not
* only specifies the key signature but also other descriptors
* used for producing a midi file or postscript file.
*
@@ -1021,49 +1021,105 @@ parsetranspose (s, word, gottranspose, transpose)
return 1;
};
/* [SS] 2021-10-11 */
int
parsesound (s, word, gottranspose, transpose)
/* parses string sound =
shift =
instrument = note1note2 or note1/note2
for parsekey() or parsevoice()
and returns the transpose value
*/
char **s;
char *word;
int *gottranspose;
int *transpose;
{
int p1,p2;
if (casecmp(word,"sound") != 0
&& casecmp(word,"shift") != 0
&& casecmp(word,"instrument") != 0
)
return 0;
skipspace (s);
if (**s != '=')
int parseSoundScore (char **s,
char *word,
int *gottranspose,
int *transpose
)
/* parses sound, score, instrument, and shift
* according to Hudson Lacerda's pseudo code file
* doc/hudsonshift.txt.
*/
{
int p1,p2;
int transp_sound;
int transp_score;
transp_sound = 0;
transp_score = 0;
if (casecmp(word,"sound") != 0
&& casecmp(word,"shift") != 0
&& casecmp(word,"instrument") != 0
&& casecmp(word,"score") != 0) return 0;
if ( fileprogram == ABC2ABC) {
return 0;
}
skipspace (s);
if (**s != '=')
{
event_error ("sound must be followed by '='");
event_error ("expecting '=' after sound, score, instrument or shift");
return 0;
} else {
*s = *s + 1;
skipspace (s);
p1 = note2midi (s);
/* printf("midi note = %d\n",p1); */
p2 = note2midi (s);
if (p2 == p1) {
*gottranspose = 0;
*transpose = 0;
} else {
/* printf("midi note = %d\n",p2); */
*transpose = p2 - p1; /* [SS] 2022.02.18 2022.04.27 */
/* printf("transpose = %d\n",*transpose); */
*gottranspose = 1;
}
p1 = note2midi (s,word);
p2 = note2midi (s,word);
if (p1 == 0) {
event_error ("<note1> missing. cannot do anything");
}
/* p2 = 0 implies that <note2> is not given */
if (casecmp(word,"sound") == 0) {
if (p2 == 0) event_error("sound = requires <note2>");
transp_sound = p2-p1;
/*
sound=<note1><note2> transposes the playback according to the
specified interval (the typeset score is not affected)
*/
}
if (casecmp(word,"score") == 0) {
if (p2 == 0) p2 = 72;
transp_score = p2 - p1;
/*
score=<note1><note2> transposes the typeset score according to the
specified interval (the playback is not affected); if the second note
is omitted it is assumed to be a c (see writing abc code for
transposing instruments)
*/
}
if (casecmp(word,"instrument") == 0) {
if (p2 == 0) p2 = p1;
transp_score = p2 - p1;
transp_sound = p2 - 72;
/*
instrument=<note1>/<note2> is defined as
score=<note1><note2> sound=c<note2>
*/
}
if (casecmp(word,"shift") == 0) {
if (p2 == 0) event_error("shift = requires <note2>");
transp_score = p2 - p1;
transp_sound = p2 - p1;
/*
shift=<note1><note2> transposes the typeset score and the playback
according to the specified interval
*/
}
*gottranspose = 1;
if (fileprogram == ABC2MIDI) {
/* [SS] 2023.01.06 */
if (casecmp(word,"score") != 0) *transpose = transp_sound;
}
if (fileprogram == YAPS) {
/* [SS] 2023.01.06 */
if (casecmp(word,"sound") != 0) *transpose = transp_score;
}
return(1);
}
return 1;
}
}
int
parseoctave (s, word, gotoctave, octave)
@@ -1410,7 +1466,7 @@ parsekey (str)
parsed = parseoctave (&s, word, &gotoctave, &octave);
if (!parsed)
parsed = parsesound (&s, word, &gottranspose, &transpose);
parsed = parseSoundScore (&s, word, &gottranspose, &transpose);
if ((parsed == 0) && (casecmp (word, "Hp") == 0))
{
@@ -1657,7 +1713,7 @@ parsevoice (s)
if (!parsed)
parsed = parseoctave (&s, word, &vparams.gotoctave, &vparams.octave);
if (!parsed)
parsed = parsesound (&s, word, &vparams.gottranspose, &vparams.transpose);
parsed = parseSoundScore (&s, word, &vparams.gottranspose, &vparams.transpose);
/* Code changed JA 20 May 2022 */
if ((!parsed) && (strcasecmp (word, "name") == 0)) {
parsed =
@@ -2618,6 +2674,7 @@ print_inputline ()
static void check_bar_repeats (int bar_type, char *replist)
{
voice_context_t *cv = &voicecode[voicenum];
char error_message[140];
switch (bar_type) {
case SINGLE_BAR:
@@ -2637,7 +2694,6 @@ static void check_bar_repeats (int bar_type, char *replist)
break;
case REP_BAR:
if (!cv->expect_repeat) {
char error_message[80];
if (cv->repeat_count == 0)
{
@@ -2736,6 +2792,10 @@ int mult, octave;
noteno = (int)note - 'a';
p = (int) ((long) strchr(anoctave, note) - (long) anoctave);
if (p < 0 || p > 6) { /* [SS] 2022-12-22 */
printf("illegal note %c\n",note);
return 72;
}
p = scale[p];
if (acc == '^') p = p + mul;
if (acc == '_') p = p - mul;
@@ -2746,8 +2806,7 @@ return p;
/* [SS] 2021-10-11 */
int
note2midi (char** s)
int note2midi (char** s, char *word)
{
/* for implementing sound=, shift= and instrument= key signature options */
@@ -2757,8 +2816,9 @@ char msg[80];
int octave;
int mult;
int pitch;
/*printf("note2midi: %c\n",**s); */
/*printf("note2midi: %c\n",**s);*/
if (**s == '\0') return 72;
note = **s;
mult = 1;
accidental = ' ';
switch (**s)
@@ -2813,6 +2873,10 @@ switch (**s)
/* skip / which occurs in instrument = command */
*s = *s + 1;
/* printf("note = %c accidental = %c mult = %d octave= %d \n",note,accidental,mult,octave); */
if (casecmp(word,"instrument") != 0) { /* [SS] 2022-12-27 */
event_warning("score and shift directives do not expect an embedded '/'");
}
pitch = pitch2midi(note, accidental, mult, octave);
return pitch;
}
@@ -2854,7 +2918,7 @@ switch (**s)
}
if (note == ' ')
{
event_error ("Malformed note : expecting a-g or A-G");
return 0;
}
pitch = pitch2midi(note, accidental, mult, octave);
return pitch;

View File

@@ -186,7 +186,7 @@ int main()
*/
#define VERSION "4.76 August 01 2022 abc2midi"
#define VERSION "4.82 January 06 2023 abc2midi"
/* enables reading V: indication in header */
#define XTEN1 1
@@ -3450,7 +3450,7 @@ static void brokenadjust()
};
};
if (failed) {
event_error("Cannot apply broken rhythm");
event_error("Cannot apply broken rhythm. Notes not equal durations");
} else {
/*
printf("Adjusting %d to %d and %d to %d\n",

View File

@@ -21,7 +21,7 @@
/* back-end for outputting (possibly modified) abc */
#define VERSION "2.18 June 14 2022 abc2abc"
#define VERSION "2.19 Jan 08 2022 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.90 June 14 2022 yaps"
#define VERSION "1.92 January 06 2023 yaps"
#include <stdio.h>
#ifdef USE_INDEX
#define strchr index