mirror of
https://github.com/sshlien/abcmidi.git
synced 2025-12-06 15:05:07 +00:00
Compare commits
8 Commits
2022.07.31
...
2022.12.30
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
166a28d182 | ||
|
|
cc1a30b3b4 | ||
|
|
2baecffc37 | ||
|
|
c24f1ffdc1 | ||
|
|
80e8dbf505 | ||
|
|
13b922827d | ||
|
|
b3562b0c92 | ||
|
|
47181bf504 |
16
Makefile
16
Makefile
@@ -53,13 +53,13 @@ datadir = ${prefix}/share
|
||||
docdir = ${prefix}/share/doc/abcmidi
|
||||
mandir = ${prefix}/share/man/man1
|
||||
|
||||
binaries=abc2midi midi2abc abc2abc mftext yaps midicopy abcmatch
|
||||
binaries=abc2midi midi2abc abc2abc mftext yaps midicopy abcmatch midistats
|
||||
|
||||
all : abc2midi midi2abc abc2abc mftext yaps midicopy abcmatch
|
||||
all : abc2midi midi2abc abc2abc mftext yaps midicopy abcmatch midistats
|
||||
|
||||
OBJECTS_ABC2MIDI=parseabc.o store.o genmidi.o midifile.o queues.o parser2.o stresspat.o music_utils.o
|
||||
abc2midi : $(OBJECTS_ABC2MIDI)
|
||||
$(CC) $(CFLAGS) -o abc2midi $(OBJECTS_ABC2MIDI) $(LDFLAGS) -lm
|
||||
$(CC) $(CFLAGS) -o abc2midi $(OBJECTS_ABC2MIDI) $(LDFLAGS)
|
||||
$(OBJECTS_ABC2MIDI): abc.h parseabc.h config.h Makefile
|
||||
|
||||
OBJECTS_ABC2ABC=parseabc.o toabc.o music_utils.o
|
||||
@@ -72,6 +72,11 @@ midi2abc : $(OBJECTS_MIDI2ABC)
|
||||
$(CC) $(CFLAGS) -o midi2abc $(OBJECTS_MIDI2ABC) $(LDFLAGS)
|
||||
$(OBJECTS_MIDI2ABC): abc.h midifile.h config.h Makefile
|
||||
|
||||
OBJECTS_MIDISTATS=midifile.o midistats.o
|
||||
midistats : $(OBJECTS_MIDISTATS)
|
||||
$(CC) $(CFLAGS) -o midistats $(OBJECTS_MIDISTATS) $(LDFLAGS)
|
||||
$(OBJECTS_MIDISTATS): abc.h midifile.h config.h Makefile
|
||||
|
||||
OBJECTS_MFTEXT=midifile.o mftext.o crack.o
|
||||
mftext : $(OBJECTS_MFTEXT)
|
||||
$(CC) $(CFLAGS) -o mftext $(OBJECTS_MFTEXT) $(LDFLAGS)
|
||||
@@ -114,6 +119,8 @@ midifile.o : midifile.c midifile.h
|
||||
|
||||
midi2abc.o : midi2abc.c midifile.h
|
||||
|
||||
midistats.o : midistats.c midifile.h
|
||||
|
||||
midicopy.o : midicopy.c midicopy.h
|
||||
|
||||
abcmatch.o: abcmatch.c abc.h
|
||||
@@ -141,7 +148,7 @@ matchsup.o : matchsup.c abc.h parseabc.h parser2.h
|
||||
clean :
|
||||
rm *.o ${binaries}
|
||||
|
||||
install: abc2midi midi2abc abc2abc mftext midicopy yaps abcmatch
|
||||
install: abc2midi midi2abc abc2abc mftext midicopy yaps abcmatch midistats
|
||||
$(INSTALL) -d $(DESTDIR)$(bindir)
|
||||
$(INSTALL) -m 755 ${binaries} $(DESTDIR)$(bindir)
|
||||
|
||||
@@ -164,6 +171,7 @@ uninstall:
|
||||
rm -f $(DESTDIR)$(bindir)/abc2abc
|
||||
rm -f $(DESTDIR)$(bindir)/yaps
|
||||
rm -f $(DESTDIR)$(bindir)/midi2abc
|
||||
rm -f $(DESTDIR)$(bindir)/midistats
|
||||
rm -f $(DESTDIR)$(bindir)/mftext
|
||||
rm -f $(DESTDIR)$(bindir)/abcmatch
|
||||
rm -f $(DESTDIR)$(bindir)/midicopy
|
||||
|
||||
16
Makefile.in
16
Makefile.in
@@ -53,13 +53,13 @@ datadir = @datarootdir@
|
||||
docdir = @datarootdir@/doc/abcmidi
|
||||
mandir = @datarootdir@/man/man1
|
||||
|
||||
binaries=abc2midi midi2abc abc2abc mftext yaps midicopy abcmatch
|
||||
binaries=abc2midi midi2abc abc2abc mftext yaps midicopy abcmatch midistats
|
||||
|
||||
all : abc2midi midi2abc abc2abc mftext yaps midicopy abcmatch
|
||||
all : abc2midi midi2abc abc2abc mftext yaps midicopy abcmatch midistats
|
||||
|
||||
OBJECTS_ABC2MIDI=parseabc.o store.o genmidi.o midifile.o queues.o parser2.o stresspat.o music_utils.o
|
||||
abc2midi : $(OBJECTS_ABC2MIDI)
|
||||
$(CC) $(CFLAGS) -o abc2midi $(OBJECTS_ABC2MIDI) $(LDFLAGS) -lm
|
||||
$(CC) $(CFLAGS) -o abc2midi $(OBJECTS_ABC2MIDI) $(LDFLAGS)
|
||||
$(OBJECTS_ABC2MIDI): abc.h parseabc.h config.h Makefile
|
||||
|
||||
OBJECTS_ABC2ABC=parseabc.o toabc.o music_utils.o
|
||||
@@ -72,6 +72,11 @@ midi2abc : $(OBJECTS_MIDI2ABC)
|
||||
$(CC) $(CFLAGS) -o midi2abc $(OBJECTS_MIDI2ABC) $(LDFLAGS)
|
||||
$(OBJECTS_MIDI2ABC): abc.h midifile.h config.h Makefile
|
||||
|
||||
OBJECTS_MIDISTATS=midifile.o midistats.o
|
||||
midistats : $(OBJECTS_MIDISTATS)
|
||||
$(CC) $(CFLAGS) -o midistats $(OBJECTS_MIDISTATS) $(LDFLAGS)
|
||||
$(OBJECTS_MIDISTATS): abc.h midifile.h config.h Makefile
|
||||
|
||||
OBJECTS_MFTEXT=midifile.o mftext.o crack.o
|
||||
mftext : $(OBJECTS_MFTEXT)
|
||||
$(CC) $(CFLAGS) -o mftext $(OBJECTS_MFTEXT) $(LDFLAGS)
|
||||
@@ -114,6 +119,8 @@ midifile.o : midifile.c midifile.h
|
||||
|
||||
midi2abc.o : midi2abc.c midifile.h
|
||||
|
||||
midistats.o : midistats.c midifile.h
|
||||
|
||||
midicopy.o : midicopy.c midicopy.h
|
||||
|
||||
abcmatch.o: abcmatch.c abc.h
|
||||
@@ -141,7 +148,7 @@ matchsup.o : matchsup.c abc.h parseabc.h parser2.h
|
||||
clean :
|
||||
rm *.o ${binaries}
|
||||
|
||||
install: abc2midi midi2abc abc2abc mftext midicopy yaps abcmatch
|
||||
install: abc2midi midi2abc abc2abc mftext midicopy yaps abcmatch midistats
|
||||
$(INSTALL) -d $(DESTDIR)$(bindir)
|
||||
$(INSTALL) -m 755 ${binaries} $(DESTDIR)$(bindir)
|
||||
|
||||
@@ -164,6 +171,7 @@ uninstall:
|
||||
rm -f $(DESTDIR)$(bindir)/abc2abc
|
||||
rm -f $(DESTDIR)$(bindir)/yaps
|
||||
rm -f $(DESTDIR)$(bindir)/midi2abc
|
||||
rm -f $(DESTDIR)$(bindir)/midistats
|
||||
rm -f $(DESTDIR)$(bindir)/mftext
|
||||
rm -f $(DESTDIR)$(bindir)/abcmatch
|
||||
rm -f $(DESTDIR)$(bindir)/midicopy
|
||||
|
||||
322
config.log
322
config.log
@@ -12,14 +12,14 @@ generated by GNU Autoconf 2.67. Invocation command line was
|
||||
|
||||
hostname = seymour-VirtualBox
|
||||
uname -m = x86_64
|
||||
uname -r = 5.4.0-51-generic
|
||||
uname -r = 5.15.0-56-generic
|
||||
uname -s = Linux
|
||||
uname -v = #56-Ubuntu SMP Mon Oct 5 14:28:49 UTC 2020
|
||||
uname -v = #62-Ubuntu SMP Tue Nov 22 19:54:14 UTC 2022
|
||||
|
||||
/usr/bin/uname -p = unknown
|
||||
/usr/bin/uname -p = x86_64
|
||||
/bin/uname -X = unknown
|
||||
|
||||
/bin/arch = unknown
|
||||
/bin/arch = x86_64
|
||||
/usr/bin/arch -k = unknown
|
||||
/usr/convex/getsysinfo = unknown
|
||||
/usr/bin/hostinfo = unknown
|
||||
@@ -27,7 +27,6 @@ uname -v = #56-Ubuntu SMP Mon Oct 5 14:28:49 UTC 2020
|
||||
/usr/bin/oslevel = unknown
|
||||
/bin/universe = unknown
|
||||
|
||||
PATH: /home/seymour/bin
|
||||
PATH: /usr/local/sbin
|
||||
PATH: /usr/local/bin
|
||||
PATH: /usr/sbin
|
||||
@@ -37,9 +36,7 @@ PATH: /bin
|
||||
PATH: /usr/games
|
||||
PATH: /usr/local/games
|
||||
PATH: /snap/bin
|
||||
PATH: /usr/local/bin
|
||||
PATH: /home/seymour/jdk1.6.0_02/bin
|
||||
PATH: /home/seymour/bin
|
||||
PATH: /home/seymour/humdrum-tools/humextra/bin
|
||||
PATH: .
|
||||
|
||||
|
||||
@@ -47,85 +44,87 @@ PATH: .
|
||||
## Core tests. ##
|
||||
## ----------- ##
|
||||
|
||||
configure:2174: checking for gcc
|
||||
configure:2190: found /usr/bin/gcc
|
||||
configure:2201: result: gcc
|
||||
configure:2430: checking for C compiler version
|
||||
configure:2439: gcc --version >&5
|
||||
gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0
|
||||
Copyright (C) 2019 Free Software Foundation, Inc.
|
||||
configure:2178: checking for gcc
|
||||
configure:2194: found /usr/bin/gcc
|
||||
configure:2205: result: gcc
|
||||
configure:2434: checking for C compiler version
|
||||
configure:2443: gcc --version >&5
|
||||
gcc (Ubuntu 11.3.0-1ubuntu1~22.04) 11.3.0
|
||||
Copyright (C) 2021 Free Software Foundation, Inc.
|
||||
This is free software; see the source for copying conditions. There is NO
|
||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
configure:2450: $? = 0
|
||||
configure:2439: gcc -v >&5
|
||||
configure:2454: $? = 0
|
||||
configure:2443: gcc -v >&5
|
||||
Using built-in specs.
|
||||
COLLECT_GCC=gcc
|
||||
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/9/lto-wrapper
|
||||
OFFLOAD_TARGET_NAMES=nvptx-none:hsa
|
||||
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/11/lto-wrapper
|
||||
OFFLOAD_TARGET_NAMES=nvptx-none:amdgcn-amdhsa
|
||||
OFFLOAD_TARGET_DEFAULT=1
|
||||
Target: x86_64-linux-gnu
|
||||
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 9.3.0-17ubuntu1~20.04' --with-bugurl=file:///usr/share/doc/gcc-9/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++,gm2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-9 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-9-HskZEa/gcc-9-9.3.0/debian/tmp-nvptx/usr,hsa --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
|
||||
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 11.3.0-1ubuntu1~22.04' --with-bugurl=file:///usr/share/doc/gcc-11/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++,m2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-11 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --enable-libphobos-checking=release --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --enable-cet --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-11-xKiWfi/gcc-11-11.3.0/debian/tmp-nvptx/usr,amdgcn-amdhsa=/build/gcc-11-xKiWfi/gcc-11-11.3.0/debian/tmp-gcn/usr --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu --with-build-config=bootstrap-lto-lean --enable-link-serialization=2
|
||||
Thread model: posix
|
||||
gcc version 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04)
|
||||
configure:2450: $? = 0
|
||||
configure:2439: gcc -V >&5
|
||||
gcc: error: unrecognized command line option '-V'
|
||||
Supported LTO compression algorithms: zlib zstd
|
||||
gcc version 11.3.0 (Ubuntu 11.3.0-1ubuntu1~22.04)
|
||||
... rest of stderr output deleted ...
|
||||
configure:2454: $? = 0
|
||||
configure:2443: gcc -V >&5
|
||||
gcc: error: unrecognized command-line option '-V'
|
||||
gcc: fatal error: no input files
|
||||
compilation terminated.
|
||||
configure:2450: $? = 1
|
||||
configure:2439: gcc -qversion >&5
|
||||
gcc: error: unrecognized command line option '-qversion'; did you mean '--version'?
|
||||
configure:2454: $? = 1
|
||||
configure:2443: gcc -qversion >&5
|
||||
gcc: error: unrecognized command-line option '-qversion'; did you mean '--version'?
|
||||
gcc: fatal error: no input files
|
||||
compilation terminated.
|
||||
configure:2450: $? = 1
|
||||
configure:2470: checking whether the C compiler works
|
||||
configure:2492: gcc conftest.c >&5
|
||||
configure:2496: $? = 0
|
||||
configure:2544: result: yes
|
||||
configure:2547: checking for C compiler default output file name
|
||||
configure:2549: result: a.out
|
||||
configure:2555: checking for suffix of executables
|
||||
configure:2562: gcc -o conftest conftest.c >&5
|
||||
configure:2566: $? = 0
|
||||
configure:2588: result:
|
||||
configure:2610: checking whether we are cross compiling
|
||||
configure:2618: gcc -o conftest conftest.c >&5
|
||||
configure:2622: $? = 0
|
||||
configure:2629: ./conftest
|
||||
configure:2633: $? = 0
|
||||
configure:2621: result: no
|
||||
configure:2626: checking for suffix of object files
|
||||
configure:2648: gcc -c conftest.c >&5
|
||||
configure:2652: $? = 0
|
||||
configure:2673: result: o
|
||||
configure:2677: checking whether we are using the GNU C compiler
|
||||
configure:2696: gcc -c conftest.c >&5
|
||||
configure:2696: $? = 0
|
||||
configure:2705: result: yes
|
||||
configure:2714: checking whether gcc accepts -g
|
||||
configure:2734: gcc -c -g conftest.c >&5
|
||||
configure:2734: $? = 0
|
||||
configure:2775: result: yes
|
||||
configure:2792: checking for gcc option to accept ISO C89
|
||||
configure:2856: gcc -c -g -O2 conftest.c >&5
|
||||
configure:2856: $? = 0
|
||||
configure:2869: result: none needed
|
||||
configure:2947: checking for a BSD-compatible install
|
||||
configure:3015: result: /usr/bin/install -c
|
||||
configure:3030: checking for main in -lm
|
||||
configure:3049: gcc -o conftest -O2 conftest.c -lm >&5
|
||||
configure:3049: $? = 0
|
||||
configure:3058: result: yes
|
||||
configure:3076: checking how to run the C preprocessor
|
||||
configure:3107: gcc -E conftest.c
|
||||
configure:3107: $? = 0
|
||||
configure:3121: gcc -E conftest.c
|
||||
configure:2454: $? = 1
|
||||
configure:2474: checking whether the C compiler works
|
||||
configure:2496: gcc conftest.c >&5
|
||||
configure:2500: $? = 0
|
||||
configure:2548: result: yes
|
||||
configure:2551: checking for C compiler default output file name
|
||||
configure:2553: result: a.out
|
||||
configure:2559: checking for suffix of executables
|
||||
configure:2566: gcc -o conftest conftest.c >&5
|
||||
configure:2570: $? = 0
|
||||
configure:2592: result:
|
||||
configure:2614: checking whether we are cross compiling
|
||||
configure:2622: gcc -o conftest conftest.c >&5
|
||||
configure:2626: $? = 0
|
||||
configure:2633: ./conftest
|
||||
configure:2637: $? = 0
|
||||
configure:2652: result: no
|
||||
configure:2657: checking for suffix of object files
|
||||
configure:2679: gcc -c conftest.c >&5
|
||||
configure:2683: $? = 0
|
||||
configure:2704: result: o
|
||||
configure:2708: checking whether we are using the GNU C compiler
|
||||
configure:2727: gcc -c conftest.c >&5
|
||||
configure:2727: $? = 0
|
||||
configure:2736: result: yes
|
||||
configure:2745: checking whether gcc accepts -g
|
||||
configure:2765: gcc -c -g conftest.c >&5
|
||||
configure:2765: $? = 0
|
||||
configure:2806: result: yes
|
||||
configure:2823: checking for gcc option to accept ISO C89
|
||||
configure:2887: gcc -c -g -O2 conftest.c >&5
|
||||
configure:2887: $? = 0
|
||||
configure:2900: result: none needed
|
||||
configure:2978: checking for a BSD-compatible install
|
||||
configure:3046: result: /usr/bin/install -c
|
||||
configure:3061: checking for main in -lm
|
||||
configure:3080: gcc -o conftest -O2 conftest.c -lm >&5
|
||||
configure:3080: $? = 0
|
||||
configure:3089: result: yes
|
||||
configure:3107: checking how to run the C preprocessor
|
||||
configure:3138: gcc -E conftest.c
|
||||
configure:3138: $? = 0
|
||||
configure:3152: gcc -E conftest.c
|
||||
conftest.c:10:10: fatal error: ac_nonexistent.h: No such file or directory
|
||||
10 | #include <ac_nonexistent.h>
|
||||
| ^~~~~~~~~~~~~~~~~~
|
||||
compilation terminated.
|
||||
configure:3121: $? = 1
|
||||
configure:3152: $? = 1
|
||||
configure: failed program was:
|
||||
| /* confdefs.h */
|
||||
| #define PACKAGE_NAME "abcmidi"
|
||||
@@ -137,15 +136,15 @@ configure: failed program was:
|
||||
| #define HAVE_LIBM 1
|
||||
| /* end confdefs.h. */
|
||||
| #include <ac_nonexistent.h>
|
||||
configure:3146: result: gcc -E
|
||||
configure:3166: gcc -E conftest.c
|
||||
configure:3166: $? = 0
|
||||
configure:3180: gcc -E conftest.c
|
||||
configure:3177: result: gcc -E
|
||||
configure:3197: gcc -E conftest.c
|
||||
configure:3197: $? = 0
|
||||
configure:3211: gcc -E conftest.c
|
||||
conftest.c:10:10: fatal error: ac_nonexistent.h: No such file or directory
|
||||
10 | #include <ac_nonexistent.h>
|
||||
| ^~~~~~~~~~~~~~~~~~
|
||||
compilation terminated.
|
||||
configure:3180: $? = 1
|
||||
configure:3211: $? = 1
|
||||
configure: failed program was:
|
||||
| /* confdefs.h */
|
||||
| #define PACKAGE_NAME "abcmidi"
|
||||
@@ -157,67 +156,67 @@ configure: failed program was:
|
||||
| #define HAVE_LIBM 1
|
||||
| /* end confdefs.h. */
|
||||
| #include <ac_nonexistent.h>
|
||||
configure:3209: checking for grep that handles long lines and -e
|
||||
configure:3267: result: /bin/grep
|
||||
configure:3272: checking for egrep
|
||||
configure:3334: result: /bin/grep -E
|
||||
configure:3339: checking for ANSI C header files
|
||||
configure:3359: gcc -c -O2 conftest.c >&5
|
||||
configure:3359: $? = 0
|
||||
configure:3432: gcc -o conftest -O2 conftest.c -lm >&5
|
||||
configure:3432: $? = 0
|
||||
configure:3432: ./conftest
|
||||
configure:3432: $? = 0
|
||||
configure:3443: result: yes
|
||||
configure:3456: checking for sys/types.h
|
||||
configure:3456: gcc -c -O2 conftest.c >&5
|
||||
configure:3456: $? = 0
|
||||
configure:3456: result: yes
|
||||
configure:3456: checking for sys/stat.h
|
||||
configure:3456: gcc -c -O2 conftest.c >&5
|
||||
configure:3456: $? = 0
|
||||
configure:3456: result: yes
|
||||
configure:3456: checking for stdlib.h
|
||||
configure:3456: gcc -c -O2 conftest.c >&5
|
||||
configure:3456: $? = 0
|
||||
configure:3456: result: yes
|
||||
configure:3456: checking for string.h
|
||||
configure:3456: gcc -c -O2 conftest.c >&5
|
||||
configure:3456: $? = 0
|
||||
configure:3456: result: yes
|
||||
configure:3456: checking for memory.h
|
||||
configure:3456: gcc -c -O2 conftest.c >&5
|
||||
configure:3456: $? = 0
|
||||
configure:3456: result: yes
|
||||
configure:3456: checking for strings.h
|
||||
configure:3456: gcc -c -O2 conftest.c >&5
|
||||
configure:3456: $? = 0
|
||||
configure:3456: result: yes
|
||||
configure:3456: checking for inttypes.h
|
||||
configure:3456: gcc -c -O2 conftest.c >&5
|
||||
configure:3456: $? = 0
|
||||
configure:3456: result: yes
|
||||
configure:3456: checking for stdint.h
|
||||
configure:3456: gcc -c -O2 conftest.c >&5
|
||||
configure:3456: $? = 0
|
||||
configure:3456: result: yes
|
||||
configure:3456: checking for unistd.h
|
||||
configure:3456: gcc -c -O2 conftest.c >&5
|
||||
configure:3456: $? = 0
|
||||
configure:3456: result: yes
|
||||
configure:3471: checking for stdlib.h
|
||||
configure:3471: result: yes
|
||||
configure:3471: checking for string.h
|
||||
configure:3471: result: yes
|
||||
configure:3483: checking for size_t
|
||||
configure:3483: gcc -c -O2 conftest.c >&5
|
||||
configure:3483: $? = 0
|
||||
configure:3483: gcc -c -O2 conftest.c >&5
|
||||
configure:3240: checking for grep that handles long lines and -e
|
||||
configure:3298: result: /usr/bin/grep
|
||||
configure:3303: checking for egrep
|
||||
configure:3365: result: /usr/bin/grep -E
|
||||
configure:3370: checking for ANSI C header files
|
||||
configure:3390: gcc -c -O2 conftest.c >&5
|
||||
configure:3390: $? = 0
|
||||
configure:3463: gcc -o conftest -O2 conftest.c -lm >&5
|
||||
configure:3463: $? = 0
|
||||
configure:3463: ./conftest
|
||||
configure:3463: $? = 0
|
||||
configure:3474: result: yes
|
||||
configure:3487: checking for sys/types.h
|
||||
configure:3487: gcc -c -O2 conftest.c >&5
|
||||
configure:3487: $? = 0
|
||||
configure:3487: result: yes
|
||||
configure:3487: checking for sys/stat.h
|
||||
configure:3487: gcc -c -O2 conftest.c >&5
|
||||
configure:3487: $? = 0
|
||||
configure:3487: result: yes
|
||||
configure:3487: checking for stdlib.h
|
||||
configure:3487: gcc -c -O2 conftest.c >&5
|
||||
configure:3487: $? = 0
|
||||
configure:3487: result: yes
|
||||
configure:3487: checking for string.h
|
||||
configure:3487: gcc -c -O2 conftest.c >&5
|
||||
configure:3487: $? = 0
|
||||
configure:3487: result: yes
|
||||
configure:3487: checking for memory.h
|
||||
configure:3487: gcc -c -O2 conftest.c >&5
|
||||
configure:3487: $? = 0
|
||||
configure:3487: result: yes
|
||||
configure:3487: checking for strings.h
|
||||
configure:3487: gcc -c -O2 conftest.c >&5
|
||||
configure:3487: $? = 0
|
||||
configure:3487: result: yes
|
||||
configure:3487: checking for inttypes.h
|
||||
configure:3487: gcc -c -O2 conftest.c >&5
|
||||
configure:3487: $? = 0
|
||||
configure:3487: result: yes
|
||||
configure:3487: checking for stdint.h
|
||||
configure:3487: gcc -c -O2 conftest.c >&5
|
||||
configure:3487: $? = 0
|
||||
configure:3487: result: yes
|
||||
configure:3487: checking for unistd.h
|
||||
configure:3487: gcc -c -O2 conftest.c >&5
|
||||
configure:3487: $? = 0
|
||||
configure:3487: result: yes
|
||||
configure:3502: checking for stdlib.h
|
||||
configure:3502: result: yes
|
||||
configure:3502: checking for string.h
|
||||
configure:3502: result: yes
|
||||
configure:3514: checking for size_t
|
||||
configure:3514: gcc -c -O2 conftest.c >&5
|
||||
configure:3514: $? = 0
|
||||
configure:3514: gcc -c -O2 conftest.c >&5
|
||||
conftest.c: In function 'main':
|
||||
conftest.c:58:21: error: expected expression before ')' token
|
||||
58 | if (sizeof ((size_t)))
|
||||
| ^
|
||||
configure:3483: $? = 1
|
||||
configure:3514: $? = 1
|
||||
configure: failed program was:
|
||||
| /* confdefs.h */
|
||||
| #define PACKAGE_NAME "abcmidi"
|
||||
@@ -281,37 +280,37 @@ configure: failed program was:
|
||||
| ;
|
||||
| return 0;
|
||||
| }
|
||||
configure:3483: result: yes
|
||||
configure:3496: checking for error_at_line
|
||||
configure:3512: gcc -o conftest -O2 conftest.c -lm >&5
|
||||
configure:3512: $? = 0
|
||||
configure:3520: result: yes
|
||||
configure:3533: checking for stdlib.h
|
||||
configure:3533: result: yes
|
||||
configure:3543: checking for GNU libc compatible malloc
|
||||
configure:3567: gcc -o conftest -O2 conftest.c -lm >&5
|
||||
configure:3567: $? = 0
|
||||
configure:3567: ./conftest
|
||||
configure:3567: $? = 0
|
||||
configure:3577: result: yes
|
||||
configure:3601: checking for strcasecmp
|
||||
configure:3601: gcc -o conftest -O2 conftest.c -lm >&5
|
||||
configure:3514: result: yes
|
||||
configure:3527: checking for error_at_line
|
||||
configure:3543: gcc -o conftest -O2 conftest.c -lm >&5
|
||||
configure:3543: $? = 0
|
||||
configure:3551: result: yes
|
||||
configure:3564: checking for stdlib.h
|
||||
configure:3564: result: yes
|
||||
configure:3574: checking for GNU libc compatible malloc
|
||||
configure:3598: gcc -o conftest -O2 conftest.c -lm >&5
|
||||
configure:3598: $? = 0
|
||||
configure:3598: ./conftest
|
||||
configure:3598: $? = 0
|
||||
configure:3608: result: yes
|
||||
configure:3632: checking for strcasecmp
|
||||
configure:3632: gcc -o conftest -O2 conftest.c -lm >&5
|
||||
conftest.c:47:6: warning: conflicting types for built-in function 'strcasecmp'; expected 'int(const char *, const char *)' [-Wbuiltin-declaration-mismatch]
|
||||
47 | char strcasecmp ();
|
||||
| ^~~~~~~~~~
|
||||
configure:3601: $? = 0
|
||||
configure:3601: result: yes
|
||||
configure:3601: checking for strchr
|
||||
configure:3601: gcc -o conftest -O2 conftest.c -lm >&5
|
||||
configure:3632: $? = 0
|
||||
configure:3632: result: yes
|
||||
configure:3632: checking for strchr
|
||||
configure:3632: gcc -o conftest -O2 conftest.c -lm >&5
|
||||
conftest.c:48:6: warning: conflicting types for built-in function 'strchr'; expected 'char *(const char *, int)' [-Wbuiltin-declaration-mismatch]
|
||||
48 | char strchr ();
|
||||
| ^~~~~~
|
||||
conftest.c:36:1: note: 'strchr' is declared in header '<string.h>'
|
||||
35 | # include <limits.h>
|
||||
36 | #else
|
||||
configure:3601: $? = 0
|
||||
configure:3601: result: yes
|
||||
configure:3708: creating ./config.status
|
||||
configure:3632: $? = 0
|
||||
configure:3632: result: yes
|
||||
configure:3739: creating ./config.status
|
||||
|
||||
## ---------------------- ##
|
||||
## Running config.status. ##
|
||||
@@ -328,8 +327,9 @@ generated by GNU Autoconf 2.67. Invocation command line was
|
||||
|
||||
on seymour-VirtualBox
|
||||
|
||||
config.status:813: creating Makefile
|
||||
config.status:813: creating config.h
|
||||
config.status:817: creating Makefile
|
||||
config.status:817: creating config.h
|
||||
config.status:991: config.h is unchanged
|
||||
|
||||
## ---------------- ##
|
||||
## Cache variables. ##
|
||||
@@ -370,8 +370,8 @@ ac_cv_header_unistd_h=yes
|
||||
ac_cv_lib_error_at_line=yes
|
||||
ac_cv_lib_m_main=yes
|
||||
ac_cv_objext=o
|
||||
ac_cv_path_EGREP='/bin/grep -E'
|
||||
ac_cv_path_GREP=/bin/grep
|
||||
ac_cv_path_EGREP='/usr/bin/grep -E'
|
||||
ac_cv_path_GREP=/usr/bin/grep
|
||||
ac_cv_path_install='/usr/bin/install -c'
|
||||
ac_cv_prog_CPP='gcc -E'
|
||||
ac_cv_prog_ac_ct_CC=gcc
|
||||
@@ -391,9 +391,9 @@ DEFS='-DHAVE_CONFIG_H'
|
||||
ECHO_C=''
|
||||
ECHO_N='-n'
|
||||
ECHO_T=''
|
||||
EGREP='/bin/grep -E'
|
||||
EGREP='/usr/bin/grep -E'
|
||||
EXEEXT=''
|
||||
GREP='/bin/grep'
|
||||
GREP='/usr/bin/grep'
|
||||
INSTALL_DATA='${INSTALL} -m 644'
|
||||
INSTALL_PROGRAM='${INSTALL}'
|
||||
INSTALL_SCRIPT='${INSTALL}'
|
||||
|
||||
@@ -612,8 +612,8 @@ echo 'BEGIN {' >"$tmp/subs1.awk" &&
|
||||
cat >>"$tmp/subs1.awk" <<\_ACAWK &&
|
||||
S["LTLIBOBJS"]=""
|
||||
S["LIBOBJS"]=""
|
||||
S["EGREP"]="/bin/grep -E"
|
||||
S["GREP"]="/bin/grep"
|
||||
S["EGREP"]="/usr/bin/grep -E"
|
||||
S["GREP"]="/usr/bin/grep"
|
||||
S["CPP"]="gcc -E"
|
||||
S["INSTALL_DATA"]="${INSTALL} -m 644"
|
||||
S["INSTALL_SCRIPT"]="${INSTALL}"
|
||||
|
||||
128
doc/CHANGES
128
doc/CHANGES
@@ -14847,4 +14847,132 @@ Fix: parseabc.c and music_utils.c was modified to ignore
|
||||
the clef=tab indication.
|
||||
|
||||
|
||||
August 1 2022
|
||||
|
||||
Fixed the abc parser so it does not report a malformed note
|
||||
when it encounters a dotted bar line .| -- (in parsemusic() in parseabc.c).
|
||||
The dotted bar line is treated as a regular bar line.
|
||||
|
||||
|
||||
August 23 2022, September 01 2022
|
||||
|
||||
midi2abc -midistats introducing quietTime.
|
||||
|
||||
December 5 2022
|
||||
|
||||
Midi2abc has been getting too big and it is time to split it into
|
||||
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.
|
||||
|
||||
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
The output of midi2abc with the -stats is used by
|
||||
the midiexplorer application which can by found on
|
||||
sourceforge.net. The output looks something like this
|
||||
|
||||
seymour@corsair:~/abc$ midi2abc summer.mid -stats
|
||||
ntrks 10
|
||||
ppqn 120
|
||||
trk 1
|
||||
timesig 4/4 0.00
|
||||
keysig C 0 0 0.00
|
||||
tempo 132.00 bpm
|
||||
trk 2
|
||||
metatext 3 Synth Bass 1
|
||||
program 1 38
|
||||
trkinfo 1 38 156 774 41022 50468
|
||||
trk 3
|
||||
metatext 3 Brass 1
|
||||
program 2 61
|
||||
trkinfo 2 61 102 0 6618 2982
|
||||
trk 4
|
||||
...
|
||||
trk 10
|
||||
metatext 3 Drums
|
||||
program 10 17
|
||||
trkinfo 10 17 1390 1158 108340 25777
|
||||
npulses 58552
|
||||
tempocmds 1
|
||||
pitchbends 0
|
||||
programcmd 0
|
||||
progs 35 38 50 54 61 80 81 102
|
||||
progsact 49460 50468 15426 3237 2982 22295 15938 4703
|
||||
progcolor 0.00 0.00 0.00 0.00 0.00 1.71 0.00 0.26 0.06 0.05 0.00 0.00 0.00 0.65 0.00 0.08 0.00
|
||||
drums 36 38 39 42 54
|
||||
drumhits 548 287 128 1073 512
|
||||
pitches 473 0 1267 216 20 344 36 717 0 321 364 0
|
||||
pitchact 0.32 0.00 1.10 0.15 0.03 0.22 0.03 0.51 0.00 0.26 0.20 0.00
|
||||
chnact 0.86 0.05 0.06 0.27 0.38 0.26 0.08 0.84 0.00 0.44 0.00 0.00 0.00 0.00 0.00 0.00
|
||||
pitchentropy 2.567729
|
||||
|
||||
|
||||
Here is a description of some of the values which are outputted.
|
||||
|
||||
timesig 4/4 beat number
|
||||
is issued each time the time signature is redefined. The beat number
|
||||
is a decimal number in quarter beats.
|
||||
|
||||
The same apples for keysig (key signature) and tempo redefinition.
|
||||
|
||||
For each channel, midi2abc prints a trkinfo vector which contains
|
||||
the following information.
|
||||
|
||||
the channel number
|
||||
the first program number assigned to the channel
|
||||
the number of notes not appearing inside a chord
|
||||
the number of notes appearing in a chord
|
||||
the sum of all the MIDI pitches of the notes
|
||||
the sum of all the note durations in pulses
|
||||
|
||||
Finally, midi2abc outputs the following data.
|
||||
|
||||
npulses -- the length of the longest track in pulses
|
||||
tempocmds - the number of tempo commands encountered
|
||||
pitchbends - the number of pitchbend commands encountered
|
||||
programcmd - the number of times the program assignment is
|
||||
reassigned
|
||||
progs vector - list of all the MIDI programs used
|
||||
progsact vector - the activity for each of the above MIDI programs. The
|
||||
activity is the sum of the note durations in pulses for each of the
|
||||
above programs.
|
||||
progcolor - described below
|
||||
drums - a list of all the MIDI percussion numbers used
|
||||
drumhits - the number of note on commands for each of the above percussion
|
||||
instruments.
|
||||
pitches - the number of note on commands for each of the 12 pitch
|
||||
classes (C, C#, D, D# ... B)
|
||||
pitchact - duration in pulses of all notes grouped by pitch classes
|
||||
chnact - duration in pulses of all notes grouped by channel
|
||||
pitchentropy - entropy of the pitchact probability density function
|
||||
|
||||
|
||||
progcolor: The 128 MIDI program numbers are mapped into 17 classes.
|
||||
These classes group keyboard instruments, brass instruments, guitar
|
||||
instruments etc into separate groups defined here.
|
||||
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
|
||||
};
|
||||
|
||||
The activity in each of these programs is measured, normalized to
|
||||
a unit length vector and returned in the progcolor vector.
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
87
doc/midistats.1
Normal file
87
doc/midistats.1
Normal file
@@ -0,0 +1,87 @@
|
||||
.TH MIDISTATS 1 "9 December 2022"
|
||||
.SH NAME
|
||||
\fBmidistats\fP \- program to summarize the statistical properties of a midi file
|
||||
.SH SYNOPSIS
|
||||
midistats \fIinfile\fP
|
||||
|
||||
.SH DESCRIPTION
|
||||
\fImidistats\fP analyzes the contents of a midi file and outputs key
|
||||
information and various statistical measures. Each line of output
|
||||
starts with the name of the variable or variable array and the
|
||||
associated values. The output is interpreted by the user interface
|
||||
midiexplorer.tcl. Both programs are still being improved. Here
|
||||
is an explanation of some of the output.
|
||||
.PP
|
||||
ntrks indicates the number of tracks in the midi file.
|
||||
.PP
|
||||
ppqn the number of midi pulses per quarter note.
|
||||
.PP
|
||||
keysig the key signature, followed by a major/minor flag, the number
|
||||
of sharps (positive) or flats (negative) in the key, and the beat number
|
||||
where the key signature was found.
|
||||
.PP
|
||||
trk is followed by the track number for which the following information
|
||||
applies.
|
||||
.PP
|
||||
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
|
||||
of the track of interest. The following data is given:
|
||||
the channel number,
|
||||
the first program assigned to this channel,
|
||||
the number of notes for this channel counting any chords as one note,
|
||||
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,
|
||||
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
|
||||
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
|
||||
file.
|
||||
.PP
|
||||
pitchbends specifies the total number of pitchbends in this file.
|
||||
.PP
|
||||
progs is a list of all the midi programs addressed
|
||||
.PP
|
||||
progsact the amount of activity for each of the above midi programs.
|
||||
The activity is the sum of the note durations in midi pulse units.
|
||||
.PP
|
||||
progcolor: is a 17 dimensional vector where each component maps into
|
||||
a specific group of MIDI programs. Some of these groups are, keyboard
|
||||
instruments, brass instruments, wind instruments, and etc. More information
|
||||
can be found in the midiexplorer documentation.
|
||||
.PP
|
||||
drums is a list of all the percussion instruments (channel 9) that were
|
||||
used.
|
||||
.PP
|
||||
drumhits indicates the number of notes for each of the above percussion
|
||||
instruments.
|
||||
.PP
|
||||
pitches is a histogram for the 11 pitch classes (C, C#, D ...B)
|
||||
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>
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -1 +0,0 @@
|
||||
abcmidi/doc/programming
|
||||
@@ -1 +0,0 @@
|
||||
/home/seymour/CVSREPOS
|
||||
@@ -1,11 +1,12 @@
|
||||
abcMIDI : abc <-> MIDI conversion utilities
|
||||
|
||||
midi2abc version 3.54 April 28 2022
|
||||
abc2midi version 4.75 July 31 2022
|
||||
midi2abc version 3.58 December 09 2022
|
||||
abc2midi version 4.80 December 30 2022
|
||||
abc2abc version 2.18 June 14 2022
|
||||
yaps version 1.90 June 14 2022
|
||||
abcmatch version 1.82 June 14 2022
|
||||
midicopy version 1.38 May 06 2022
|
||||
midistats version 0.58 December 09 2022
|
||||
|
||||
24th January 2002
|
||||
|
||||
|
||||
435
midi2abc.c
435
midi2abc.c
@@ -45,7 +45,7 @@
|
||||
* based on public domain 'midifilelib' package.
|
||||
*/
|
||||
|
||||
#define VERSION "3.54 April 28 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 */
|
||||
|
||||
|
||||
@@ -97,6 +94,7 @@ static FILE *outhandle; /* for producing the abc file */
|
||||
|
||||
int tracknum=0; /* track number */
|
||||
int division; /* pulses per quarter note defined in MIDI header */
|
||||
int quietLimit; /* minumum number of pulses with no activity */
|
||||
long tempo = 500000; /* the default tempo is 120 quarter notes/minute */
|
||||
int unitlen; /* abc unit length usually defined in L: field */
|
||||
int header_unitlen; /* first unitlen set */
|
||||
@@ -250,65 +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];
|
||||
} 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 */
|
||||
|
||||
@@ -606,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)
|
||||
@@ -728,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;
|
||||
@@ -1137,141 +1062,7 @@ void mftxt_header (int format, int ntrks, int ldivision)
|
||||
}
|
||||
|
||||
|
||||
void stats_header (int format, int ntrks, int ldivision)
|
||||
{
|
||||
int i;
|
||||
division = ldivision;
|
||||
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 */
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1284,68 +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("\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;
|
||||
{
|
||||
@@ -1360,28 +1092,6 @@ int chan, pitch, vol;
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void stats_noteon(chan,pitch,vol)
|
||||
int chan, pitch, vol;
|
||||
{
|
||||
if (vol == 0) {
|
||||
/* treat as noteoff */
|
||||
stats_noteoff(chan,pitch,vol);
|
||||
return;
|
||||
}
|
||||
trkdata.notemeanpitch[chan+1] += pitch;
|
||||
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;
|
||||
@@ -1396,22 +1106,7 @@ 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;
|
||||
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 mftxt_polypressure(chan,pitch,press)
|
||||
int chan, pitch, press;
|
||||
@@ -1448,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;
|
||||
@@ -1510,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;
|
||||
@@ -1605,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;
|
||||
@@ -1651,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;
|
||||
@@ -1680,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;
|
||||
@@ -1708,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;
|
||||
@@ -1732,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;
|
||||
@@ -1810,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 = no_op0;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -3636,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);
|
||||
@@ -3849,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");
|
||||
@@ -4098,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[];
|
||||
@@ -4120,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;
|
||||
}
|
||||
|
||||
970
midistats.c
Normal file
970
midistats.c
Normal file
@@ -0,0 +1,970 @@
|
||||
/* midistats - program to extract statistics from MIDI files
|
||||
* Derived from midi2abc.c
|
||||
* Copyright (C) 1998 James Allwright
|
||||
* e-mail: J.R.Allwright@westminster.ac.uk
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#define VERSION "0.58 December 08 2022 midistats"
|
||||
|
||||
#include <limits.h>
|
||||
/* Microsoft Visual C++ Version 6.0 or higher */
|
||||
#ifdef _MSC_VER
|
||||
#define snprintf _snprintf
|
||||
#define ANSILIBS
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#ifdef PCCFIX
|
||||
#define stdout 1
|
||||
#endif
|
||||
|
||||
/* define USE_INDEX if your C libraries have index() instead of strchr() */
|
||||
#ifdef USE_INDEX
|
||||
#define strchr index
|
||||
#endif
|
||||
|
||||
#ifdef ANSILIBS
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#else
|
||||
extern char* malloc();
|
||||
extern char* strchr();
|
||||
#endif
|
||||
#include "midifile.h"
|
||||
void initfuncs();
|
||||
void stats_finish();
|
||||
float histogram_entropy (int *histogram, int size);
|
||||
void stats_noteoff(int chan,int pitch,int vol);
|
||||
void stats_eot ();
|
||||
|
||||
|
||||
/* Global variables and structures */
|
||||
|
||||
extern long Mf_toberead;
|
||||
|
||||
static FILE *F;
|
||||
static FILE *outhandle; /* for producing the abc file */
|
||||
|
||||
int tracknum=0; /* track number */
|
||||
int division; /* pulses per quarter note defined in MIDI header */
|
||||
int quietLimit; /* minimum number of pulses with no activity */
|
||||
long tempo = 500000; /* the default tempo is 120 quarter notes/minute */
|
||||
long laston = 0; /* length of MIDI track in pulses or ticks */
|
||||
int key[12];
|
||||
int sharps;
|
||||
int trackno;
|
||||
int maintrack;
|
||||
int format; /* MIDI file type */
|
||||
int debug;
|
||||
int chordthreshold; /* number of maximum number of pulses separating note */
|
||||
int beatsPerBar = 4; /* 4/4 time */
|
||||
int divisionsPerBar;
|
||||
int unitDivision;
|
||||
|
||||
|
||||
|
||||
int tempocount=0; /* number of tempo indications in MIDI file */
|
||||
|
||||
int stats = 0; /* flag - gather and print statistics */
|
||||
|
||||
|
||||
|
||||
/* can cope with up to 64 track MIDI files */
|
||||
int trackcount = 0;
|
||||
|
||||
int notechan[2048],notechanvol[2048]; /*for linking on and off midi
|
||||
channel commands */
|
||||
int last_tick[17]; /* for getting last pulse number in MIDI file */
|
||||
int last_on_tick[17]; /* for detecting chords [SS] 2019-08-02 */
|
||||
|
||||
|
||||
|
||||
|
||||
/* 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];
|
||||
int rhythmpatterns[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
|
||||
};
|
||||
|
||||
|
||||
struct barPattern {
|
||||
int activeBarNumber;
|
||||
int rhythmPattern;
|
||||
} barChn[17];
|
||||
|
||||
|
||||
#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) {
|
||||
/* printf("collision\n"); */
|
||||
handle_collision ();
|
||||
} else {
|
||||
hasher[chan].count[hashindex]++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int count_patterns_for (int chan) {
|
||||
int i;
|
||||
int sum;
|
||||
sum = 0;
|
||||
for (i = 0; i<HashSize; i++) {
|
||||
if (hasher[chan].pattern[i] > 0) sum++;
|
||||
/* hasher[chan].pattern[i] = 0; reset hasher */
|
||||
}
|
||||
trkdata.rhythmpatterns[chan] = sum;
|
||||
return sum;
|
||||
}
|
||||
|
||||
|
||||
void output_hasher_results () {
|
||||
int i;
|
||||
/* printf("rhythmPatterns ");*/
|
||||
for (i = 0; i<17; i++) {
|
||||
trkdata.rhythmpatterns[i] = count_patterns_for(i);
|
||||
/* printf("%d ",count_patterns_for (i)); */
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
int filegetc()
|
||||
{
|
||||
return(getc(F));
|
||||
}
|
||||
|
||||
|
||||
void fatal_error(s)
|
||||
char* s;
|
||||
/* fatal error encounterd - abort program */
|
||||
{
|
||||
fprintf(stderr, "%s\n", s);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
void event_error(s)
|
||||
char *s;
|
||||
/* problem encountered but OK to continue */
|
||||
{
|
||||
char msg[256];
|
||||
|
||||
sprintf(msg, "Error: Time=%ld Track=%d %s\n", Mf_currtime, trackno, s);
|
||||
printf("%s",msg);
|
||||
}
|
||||
|
||||
|
||||
int* checkmalloc(bytes)
|
||||
/* malloc with error checking */
|
||||
int bytes;
|
||||
{
|
||||
int *p;
|
||||
|
||||
p = (int*) malloc(bytes);
|
||||
if (p == NULL) {
|
||||
fatal_error("Out of memory error - cannot malloc!");
|
||||
};
|
||||
return (p);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
FILE *
|
||||
efopen(name,mode)
|
||||
char *name;
|
||||
char *mode;
|
||||
{
|
||||
FILE *f;
|
||||
|
||||
if ( (f=fopen(name,mode)) == NULL ) {
|
||||
char msg[256];
|
||||
sprintf(msg,"Error - Cannot open file %s",name);
|
||||
fatal_error(msg);
|
||||
}
|
||||
return(f);
|
||||
}
|
||||
|
||||
void error(s)
|
||||
char *s;
|
||||
{
|
||||
fprintf(stderr,"Error: %s\n",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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* Dummy functions for handling MIDI messages.
|
||||
* */
|
||||
void no_op0() {}
|
||||
void no_op1(int dummy1) {}
|
||||
void no_op2(int dummy1, int dummy2) {}
|
||||
void no_op3(int dummy1, int dummy2, int dummy3) { }
|
||||
void no_op4(int dummy1, int dummy2, int dummy3, int dummy4) { }
|
||||
void no_op5(int dummy1, int dummy2, int dummy3, int dummy4, int dummy5) { }
|
||||
|
||||
|
||||
|
||||
/* In order to associate a channel note off message with its
|
||||
* corresponding note on message, we maintain the information
|
||||
* the notechan array. When a midi pitch (0-127) is switched
|
||||
* on for a particular channel, we record the time that it
|
||||
* was turned on in the notechan array. As there are 16 channels
|
||||
* and 128 pitches, we initialize an array 128*16 = 2048 elements
|
||||
* long.
|
||||
**/
|
||||
void init_notechan()
|
||||
{
|
||||
/* signal that there are no active notes */
|
||||
int i;
|
||||
for (i = 0; i < 2048; i++) notechan[i] = -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
char * pitch2key(int note)
|
||||
{
|
||||
static char name[16]; /* [SDG] 2020-06-03 */
|
||||
char* s = name;
|
||||
switch(note % 12)
|
||||
{
|
||||
case 0: *s++ = 'c'; break;
|
||||
case 1: *s++ = 'c'; *s++ = '#'; break;
|
||||
case 2: *s++ = 'd'; break;
|
||||
case 3: *s++ = 'd'; *s++ = '#'; break;
|
||||
case 4: *s++ = 'e'; break;
|
||||
case 5: *s++ = 'f'; break;
|
||||
case 6: *s++ = 'f'; *s++ = '#'; break;
|
||||
case 7: *s++ = 'g'; break;
|
||||
case 8: *s++ = 'g'; *s++ = '#'; break;
|
||||
case 9: *s++ = 'a'; break;
|
||||
case 10: *s++ = 'a'; *s++ = '#'; break;
|
||||
case 11: *s++ = 'b'; break;
|
||||
}
|
||||
sprintf(s, "%d", (note / 12)-1); /* octave (assuming Piano C4 is 60)*/
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
void pitch2drum(midipitch)
|
||||
int midipitch;
|
||||
{
|
||||
static char *drumpatches[] = {
|
||||
"Acoustic Bass Drum", "Bass Drum 1", "Side Stick", "Acoustic Snare",
|
||||
"Hand Clap", "Electric Snare", "Low Floor Tom", "Closed Hi Hat",
|
||||
"High Floor Tom", "Pedal Hi-Hat", "Low Tom", "Open Hi-Hat",
|
||||
"Low-Mid Tom", "Hi Mid Tom", "Crash Cymbal 1", "High Tom",
|
||||
"Ride Cymbal 1", "Chinese Cymbal", "Ride Bell", "Tambourine",
|
||||
"Splash Cymbal", "Cowbell", "Crash Cymbal 2", "Vibraslap",
|
||||
"Ride Cymbal 2", "Hi Bongo", "Low Bongo", "Mute Hi Conga",
|
||||
"Open Hi Conga", "Low Conga", "High Timbale", "Low Timbale",
|
||||
"High Agogo", "Low Agogo", "Cabasa", "Maracas",
|
||||
"Short Whistle", "Long Whistle", "Short Guiro", "Long Guiro",
|
||||
"Claves", "Hi Wood Block", "Low Wood Block", "Mute Cuica",
|
||||
"Open Cuica", "Mute Triangle", "Open Triangle" };
|
||||
if (midipitch >= 35 && midipitch <= 81) {
|
||||
printf(" (%s)",drumpatches[midipitch-35]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void stats_header (int format, int ntrks, int ldivision)
|
||||
{
|
||||
int i;
|
||||
division = ldivision;
|
||||
quietLimit = ldivision*8;
|
||||
divisionsPerBar = division*beatsPerBar;
|
||||
unitDivision = divisionsPerBar/24;
|
||||
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("\nquietTime ");
|
||||
for (i=1;i<17;i++) {
|
||||
delta = trkdata.npulses[0] - trkdata.quietTime[i];
|
||||
if (trkdata.quietTime[i] < quietLimit) delta = 0;
|
||||
delta = delta / (double) trkdata.npulses[0];
|
||||
/* printf (" %5.3f ", delta); */
|
||||
printf (" %d ", trkdata.quietTime[i]);
|
||||
}
|
||||
|
||||
printf("\npitchentropy %f\n",histogram_entropy(pitchclass_activity,12));
|
||||
printf("totalrhythmpatterns =%d\n",nrpatterns);
|
||||
printf("collisions = %d\n",ncollisions);
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
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 */
|
||||
output_hasher_results();
|
||||
for (i=1;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 %d",trkdata.quietTime[i],trkdata.rhythmpatterns[i]);
|
||||
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 stats_noteon(chan,pitch,vol)
|
||||
int chan, pitch, vol;
|
||||
{
|
||||
int delta;
|
||||
int barnum;
|
||||
int unit;
|
||||
|
||||
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) {
|
||||
barnum = Mf_currtime/divisionsPerBar;
|
||||
if (barnum != barChn[chan].activeBarNumber) {
|
||||
/*printf("%d %d %d\n",chan,barChn[chan].activeBarNumber,
|
||||
barChn[chan].rhythmPattern); */
|
||||
put_pattern (chan+1, barChn[chan].rhythmPattern);
|
||||
|
||||
barChn[chan].rhythmPattern = 0;
|
||||
barChn[chan].activeBarNumber = barnum;
|
||||
}
|
||||
unit = (Mf_currtime % divisionsPerBar)/unitDivision;
|
||||
//printf("unit = %d pattern = %d \n",unit,barChn[chan].rhythmPattern);
|
||||
barChn[chan].rhythmPattern = barChn[chan].rhythmPattern |= (1UL << unit);
|
||||
}
|
||||
|
||||
|
||||
|
||||
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 stats_eot () {
|
||||
trkdata.lastNoteOff[0] = Mf_currtime; /* [SS] 2022.08.24 */
|
||||
}
|
||||
|
||||
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_pitchbend(chan,lsb,msb)
|
||||
int chan, lsb, msb;
|
||||
{
|
||||
trkdata.pitchbend[0]++;
|
||||
trkdata.pitchbend[chan+1]++;
|
||||
}
|
||||
|
||||
void stats_pressure(chan,press)
|
||||
int chan, press;
|
||||
{
|
||||
trkdata.pressure[0]++;
|
||||
trkdata.pressure[chan+1]++; /* [SS] 2022.04.28 */
|
||||
}
|
||||
|
||||
|
||||
|
||||
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 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 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");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* [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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* [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 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 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;
|
||||
}
|
||||
|
||||
|
||||
int readnum(num)
|
||||
/* read a number from a string */
|
||||
/* used for processing command line */
|
||||
char *num;
|
||||
{
|
||||
int t;
|
||||
char *p;
|
||||
int neg;
|
||||
|
||||
t = 0;
|
||||
neg = 1;
|
||||
p = num;
|
||||
if (*p == '-') {
|
||||
p = p + 1;
|
||||
neg = -1;
|
||||
};
|
||||
/* [JA] 2021-05-25 */
|
||||
while (((int)*p >= '0') && ((int)*p <= '9') && (t < (INT_MAX-9)/10)) {
|
||||
t = t * 10 + (int) *p - '0';
|
||||
p = p + 1;
|
||||
};
|
||||
return neg*t;
|
||||
}
|
||||
|
||||
|
||||
int readnump(p)
|
||||
/* read a number from a string (subtly different) */
|
||||
/* used for processing command line */
|
||||
char **p;
|
||||
{
|
||||
int t;
|
||||
|
||||
t = 0;
|
||||
/* [JA] 2021-05-25 */
|
||||
while (((int)**p >= '0') && ((int)**p <= '9') && (t < (INT_MAX-9)/10)) {
|
||||
t = t * 10 + (int) **p - '0';
|
||||
*p = *p + 1;
|
||||
};
|
||||
/* advance over any spurious extra digits */
|
||||
while (isdigit(**p)) {
|
||||
*p = *p + 1;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
int getarg(option, argc, argv)
|
||||
/* extract arguments from command line */
|
||||
char *option;
|
||||
char *argv[];
|
||||
int argc;
|
||||
{
|
||||
int j, place;
|
||||
|
||||
place = -1;
|
||||
for (j=0; j<argc; j++) {
|
||||
if (strcmp(option, argv[j]) == 0) {
|
||||
place = j + 1;
|
||||
};
|
||||
};
|
||||
return (place);
|
||||
}
|
||||
|
||||
int huntfilename(argc, argv)
|
||||
/* look for filename argument if -f option is missing */
|
||||
/* assumes filename does not begin with '-' */
|
||||
char *argv[];
|
||||
int argc;
|
||||
{
|
||||
int j, place;
|
||||
|
||||
place = -1;
|
||||
j = 1;
|
||||
while ((place == -1) && (j < argc)) {
|
||||
if (strncmp("-", argv[j], 1) != 0) {
|
||||
place = j;
|
||||
}
|
||||
else {
|
||||
if (strchr("ambQkcou", *(argv[j]+1)) == NULL) {
|
||||
j = j + 1;
|
||||
}
|
||||
else {
|
||||
j = j + 2;
|
||||
};
|
||||
};
|
||||
};
|
||||
return(place);
|
||||
}
|
||||
|
||||
int process_command_line_arguments(argc,argv)
|
||||
char *argv[];
|
||||
int argc;
|
||||
{
|
||||
int val;
|
||||
int arg;
|
||||
arg = getarg("-ver",argc,argv);
|
||||
if (arg != -1) {printf("%s\n",VERSION); exit(0);}
|
||||
|
||||
stats = 1;
|
||||
|
||||
arg = getarg("-d",argc,argv);
|
||||
if ((arg != -1) && (arg <argc)) {
|
||||
debug = readnum(argv[arg]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
arg = getarg("-o",argc,argv);
|
||||
if ((arg != -1) && (arg < argc)) {
|
||||
outhandle = efopen(argv[arg],"w"); /* open output abc file */
|
||||
}
|
||||
else {
|
||||
outhandle = stdout;
|
||||
};
|
||||
|
||||
arg = getarg("-f", argc, argv);
|
||||
if (arg == -1) {
|
||||
arg = huntfilename(argc, argv);
|
||||
};
|
||||
|
||||
if ((arg != -1) && (arg < argc)) {
|
||||
F = efopen(argv[arg],"rb");
|
||||
/* fprintf(outhandle,"%% input file %s\n", argv[arg]); */
|
||||
}
|
||||
else {
|
||||
printf("midistats version %s\n usage :\n",VERSION);
|
||||
printf("midistats filename <options>\n");
|
||||
printf(" -ver version number\n");
|
||||
printf(" -d <number> debug parameter\n");
|
||||
printf(" The input filename is assumed to be any string not\n");
|
||||
printf(" beginning with a - (hyphen). It may be placed anywhere.\n");
|
||||
exit(0);
|
||||
};
|
||||
return arg;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void midistats(argc,argv)
|
||||
char *argv[];
|
||||
int argc;
|
||||
{
|
||||
initfunc_for_stats();
|
||||
Mf_getc = filegetc;
|
||||
mfread();
|
||||
stats_finish();
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main(argc,argv)
|
||||
char *argv[];
|
||||
int argc;
|
||||
{
|
||||
FILE *efopen();
|
||||
int arg;
|
||||
|
||||
arg = process_command_line_arguments(argc,argv);
|
||||
if(stats == 1) midistats(argc,argv);
|
||||
return 0;
|
||||
}
|
||||
62
parseabc.c
62
parseabc.c
@@ -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;
|
||||
@@ -1022,8 +1022,7 @@ parsetranspose (s, word, gottranspose, transpose)
|
||||
};
|
||||
|
||||
/* [SS] 2021-10-11 */
|
||||
int
|
||||
parsesound (s, word, gottranspose, transpose)
|
||||
int parsesound (s, word, gottranspose, transpose)
|
||||
/* parses string sound =
|
||||
shift =
|
||||
instrument = note1note2 or note1/note2
|
||||
@@ -1049,18 +1048,30 @@ parsesound (s, word, gottranspose, transpose)
|
||||
} 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); */
|
||||
p1 = note2midi (s,word);
|
||||
/*printf("p1 midi note = %d\n",p1);*/
|
||||
p2 = note2midi (s,word);
|
||||
/*printf("p2 midi note = %d\n",p2);*/
|
||||
|
||||
if (p2 == p1 || p2 == 0) {
|
||||
*transpose = 72 - p1; /* [SS] 2022.12.30 */
|
||||
}
|
||||
if (casecmp(word,"instrument") == 0) { /*2022.12.27 */
|
||||
*transpose = p1 - p2; /* [SS] 2022.02.18 2022.04.27 */
|
||||
if (p2 == 0) { /* <note2> is missing */
|
||||
*transpose = p1 - 72;
|
||||
}
|
||||
if (p2 == p1 || p2 == 0) {
|
||||
*transpose = p1 - 72; /* [SS] 2022.12.30 */
|
||||
}
|
||||
if (p2 == 72 && fileprogram == ABC2MIDI) {
|
||||
*transpose = 0;
|
||||
} /* [SS] 2022.12.30 */
|
||||
} else {
|
||||
*transpose = p2 - p1; /* [SS] 2022.02.18 2022.04.27 */
|
||||
/* printf("transpose = %d\n",*transpose); */
|
||||
*gottranspose = 1;
|
||||
}
|
||||
}
|
||||
*gottranspose = 1;
|
||||
/*printf("p1 = %d p2 = %d transpose = %d\n",p1,p2,*transpose);*/
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@@ -2618,6 +2629,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 +2649,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 +2747,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 +2761,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 +2771,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 +2828,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 +2873,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;
|
||||
@@ -2910,6 +2929,11 @@ parsemusic (field)
|
||||
p = p+1;
|
||||
}
|
||||
|
||||
if (*p == '.' && *(p+1) == '|') { /* [SS] 2022-08.01 dotted bar */
|
||||
p = p +1;
|
||||
/* ignore dotted bar */
|
||||
}
|
||||
|
||||
if (((*p >= 'a') && (*p <= 'g')) || ((*p >= 'A') && (*p <= 'G')) ||
|
||||
(strchr ("_^=", *p) != NULL) || (strchr (decorations, *p) != NULL))
|
||||
{
|
||||
|
||||
4
store.c
4
store.c
@@ -186,7 +186,7 @@ int main()
|
||||
|
||||
*/
|
||||
|
||||
#define VERSION "4.75 July 30 2022 abc2midi"
|
||||
#define VERSION "4.80 December 30 2022 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",
|
||||
|
||||
Reference in New Issue
Block a user