diff options
| author | Robert Jonsson <spamatica@gmail.com> | 2010-10-13 19:34:22 +0000 |
|---|---|---|
| committer | Robert Jonsson <spamatica@gmail.com> | 2010-10-13 19:34:22 +0000 |
| commit | 8a2c2824a59d7644e13bc52c9a0ecbd641f21f95 (patch) | |
| tree | 064ad3f2bf8daab0ad27b128abd86a9bbdb1e496 /muse2/muse/midiedit | |
| parent | a27706d9629e8b592cca4659f865b70adef24e6d (diff) | |
new branch muse2, first checkin
Diffstat (limited to 'muse2/muse/midiedit')
| -rw-r--r-- | muse2/muse/midiedit/Makefile.am | 36 | ||||
| -rw-r--r-- | muse2/muse/midiedit/Makefile.in | 636 | ||||
| -rw-r--r-- | muse2/muse/midiedit/cmd.h | 26 | ||||
| -rw-r--r-- | muse2/muse/midiedit/dcanvas.cpp | 1291 | ||||
| -rw-r--r-- | muse2/muse/midiedit/dcanvas.h | 93 | ||||
| -rw-r--r-- | muse2/muse/midiedit/dlist.cpp | 754 | ||||
| -rw-r--r-- | muse2/muse/midiedit/dlist.h | 105 | ||||
| -rw-r--r-- | muse2/muse/midiedit/drumedit.cpp | 1167 | ||||
| -rw-r--r-- | muse2/muse/midiedit/drumedit.h | 151 | ||||
| -rw-r--r-- | muse2/muse/midiedit/drummap.cpp | 503 | ||||
| -rw-r--r-- | muse2/muse/midiedit/drummap.h | 47 | ||||
| -rw-r--r-- | muse2/muse/midiedit/ecanvas.cpp | 363 | ||||
| -rw-r--r-- | muse2/muse/midiedit/ecanvas.h | 87 | ||||
| -rw-r--r-- | muse2/muse/midiedit/piano.cpp | 557 | ||||
| -rw-r--r-- | muse2/muse/midiedit/piano.h | 63 | ||||
| -rw-r--r-- | muse2/muse/midiedit/pianoroll.cpp | 1107 | ||||
| -rw-r--r-- | muse2/muse/midiedit/pianoroll.h | 146 | ||||
| -rw-r--r-- | muse2/muse/midiedit/prcanvas.cpp | 1695 | ||||
| -rw-r--r-- | muse2/muse/midiedit/prcanvas.h | 113 | ||||
| -rw-r--r-- | muse2/muse/midiedit/quantconfig.cpp | 59 | ||||
| -rw-r--r-- | muse2/muse/midiedit/quantconfig.h | 32 |
21 files changed, 9031 insertions, 0 deletions
diff --git a/muse2/muse/midiedit/Makefile.am b/muse2/muse/midiedit/Makefile.am new file mode 100644 index 00000000..e817dc99 --- /dev/null +++ b/muse2/muse/midiedit/Makefile.am @@ -0,0 +1,36 @@ +include $(top_srcdir)/common.am + +if PCH +AM_CXXFLAGS += -include $(top_srcdir)/all.h +endif + +noinst_LIBRARIES = libmidiedit.a + +if PCH +AM_CXXFLAGS += -include $(top_srcdir)/all-pic.h -DINSTPREFIX=\"$(prefix)\" +else +AM_CXXFLAGS += -DINSTPREFIX=\"$(prefix)\" +endif + +dist_libmidiedit_a_SOURCES = \ + drummap.cpp drummap.h \ + cmd.h \ + pianoroll.cpp pianoroll.h \ + piano.cpp piano.h \ + prcanvas.cpp prcanvas.h \ + quantconfig.cpp quantconfig.h \ + drumedit.cpp drumedit.h \ + dlist.cpp dlist.h \ + dcanvas.cpp dcanvas.h \ + ecanvas.cpp ecanvas.h + +nodist_libmidiedit_a_SOURCES = \ + moc_pianoroll.cpp \ + moc_piano.cpp \ + moc_prcanvas.cpp \ + moc_quantconfig.cpp \ + moc_drumedit.cpp \ + moc_dlist.cpp \ + moc_dcanvas.cpp \ + moc_ecanvas.cpp + diff --git a/muse2/muse/midiedit/Makefile.in b/muse2/muse/midiedit/Makefile.in new file mode 100644 index 00000000..01425ebc --- /dev/null +++ b/muse2/muse/midiedit/Makefile.in @@ -0,0 +1,636 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(top_srcdir)/common.am +@PCH_TRUE@am__append_1 = -include $(top_srcdir)/all.h -include \ +@PCH_TRUE@ $(top_srcdir)/all-pic.h -DINSTPREFIX=\"$(prefix)\" +@PCH_FALSE@am__append_2 = -DINSTPREFIX=\"$(prefix)\" +subdir = muse/midiedit +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/aclocal-include.m4 \ + $(top_srcdir)/m4/alsa.m4 $(top_srcdir)/m4/docbook.m4 \ + $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ + $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ + $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LIBRARIES = $(noinst_LIBRARIES) +ARFLAGS = cru +libmidiedit_a_AR = $(AR) $(ARFLAGS) +libmidiedit_a_LIBADD = +dist_libmidiedit_a_OBJECTS = drummap.$(OBJEXT) pianoroll.$(OBJEXT) \ + piano.$(OBJEXT) prcanvas.$(OBJEXT) quantconfig.$(OBJEXT) \ + drumedit.$(OBJEXT) dlist.$(OBJEXT) dcanvas.$(OBJEXT) \ + ecanvas.$(OBJEXT) +nodist_libmidiedit_a_OBJECTS = moc_pianoroll.$(OBJEXT) \ + moc_piano.$(OBJEXT) moc_prcanvas.$(OBJEXT) \ + moc_quantconfig.$(OBJEXT) moc_drumedit.$(OBJEXT) \ + moc_dlist.$(OBJEXT) moc_dcanvas.$(OBJEXT) \ + moc_ecanvas.$(OBJEXT) +libmidiedit_a_OBJECTS = $(dist_libmidiedit_a_OBJECTS) \ + $(nodist_libmidiedit_a_OBJECTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(dist_libmidiedit_a_SOURCES) \ + $(nodist_libmidiedit_a_SOURCES) +DIST_SOURCES = $(dist_libmidiedit_a_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALSA_CFLAGS = @ALSA_CFLAGS@ +ALSA_LIBS = @ALSA_LIBS@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DOCBOOKSTYLE = @DOCBOOKSTYLE@ +DOCBOOKTARGETS = @DOCBOOKTARGETS@ +DOT = @DOT@ +DOTPATH = @DOTPATH@ +DOXYGEN = @DOXYGEN@ +DOXYGEN_TREEVIEW = @DOXYGEN_TREEVIEW@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FLUIDSYNTHDIRS = @FLUIDSYNTHDIRS@ +FST_CFLAGS = @FST_CFLAGS@ +FST_LIBS = @FST_LIBS@ +Fluidsynth_CFLAGS = @Fluidsynth_CFLAGS@ +Fluidsynth_LIBS = @Fluidsynth_LIBS@ +GIVERTCAP = @GIVERTCAP@ +GREP = @GREP@ +HAVEDOT = @HAVEDOT@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JACK_CFLAGS = @JACK_CFLAGS@ +JACK_LIBS = @JACK_LIBS@ +JADE = @JADE@ +LASH_CFLAGS = @LASH_CFLAGS@ +LASH_LIBS = @LASH_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LO_CFLAGS = @LO_CFLAGS@ +LO_LIBS = @LO_LIBS@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MUSECXXFLAGS = @MUSECXXFLAGS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NSGMLS = @NSGMLS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PCH = @PCH@ +PERL = @PERL@ +PKG_CONFIG = @PKG_CONFIG@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_INCLUDES = @PYTHON_INCLUDES@ +PYTHON_LIB = @PYTHON_LIB@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +QTDIR_BIN = @QTDIR_BIN@ +QTDIR_INC = @QTDIR_INC@ +QT_LIBS = @QT_LIBS@ +RANLIB = @RANLIB@ +SAMPLERATE_CFLAGS = @SAMPLERATE_CFLAGS@ +SAMPLERATE_LIBS = @SAMPLERATE_LIBS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SNDFILE_CFLAGS = @SNDFILE_CFLAGS@ +SNDFILE_LIBS = @SNDFILE_LIBS@ +STRIP = @STRIP@ +SUIDBUILD = @SUIDBUILD@ +SUIDINSTALL = @SUIDINSTALL@ +USE_SSE = @USE_SSE@ +UUID_CFLAGS = @UUID_CFLAGS@ +UUID_LIBS = @UUID_LIBS@ +VERSION = @VERSION@ +XMKMF = @XMKMF@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +have_docbook = @have_docbook@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +synth_fluid = @synth_fluid@ +synth_fluidsynth = @synth_fluidsynth@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AM_CXXFLAGS = $(MUSECXXFLAGS) -I.. -I$(top_srcdir)/synti \ + -I$(top_srcdir)/muse/widgets -DQT_SHARED -DQT_THREAD_SUPPORT \ + -DQT_PLUGIN $(QTDIR_INC) -DQT3_SUPPORT $(am__append_1) \ + $(am__append_2) +AM_CPPFLAGS = +MOC = $(QTDIR_BIN)/moc +#UIC = $(QTDIR_BIN)/uic3 +UIC = /usr/bin/uic3 +UIFILES = $(wildcard *.ui) +MOCFILES = $(shell for h in $(filter %.h,$(SOURCES)); do \ + if grep -q Q_OBJECT $$h; then \ + echo $$h | sed "s/\(.*\)\.h/moc_\1.cpp/"; \ + fi; \ + done) + +BUILT_SOURCES = $(MOCFILES) $(UIFILES:%.ui=%.h) +MOSTLYCLEANFILES = $(MOCFILES) $(UIFILES:%.ui=%.h) +SUFFIXES = .ui .h.gch +noinst_LIBRARIES = libmidiedit.a +dist_libmidiedit_a_SOURCES = \ + drummap.cpp drummap.h \ + cmd.h \ + pianoroll.cpp pianoroll.h \ + piano.cpp piano.h \ + prcanvas.cpp prcanvas.h \ + quantconfig.cpp quantconfig.h \ + drumedit.cpp drumedit.h \ + dlist.cpp dlist.h \ + dcanvas.cpp dcanvas.h \ + ecanvas.cpp ecanvas.h + +nodist_libmidiedit_a_SOURCES = \ + moc_pianoroll.cpp \ + moc_piano.cpp \ + moc_prcanvas.cpp \ + moc_quantconfig.cpp \ + moc_drumedit.cpp \ + moc_dlist.cpp \ + moc_dcanvas.cpp \ + moc_ecanvas.cpp + +all: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) all-am + +.SUFFIXES: +.SUFFIXES: .ui .h.gch .cpp .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(top_srcdir)/common.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu muse/midiedit/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu muse/midiedit/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libmidiedit.a: $(libmidiedit_a_OBJECTS) $(libmidiedit_a_DEPENDENCIES) + -rm -f libmidiedit.a + $(libmidiedit_a_AR) libmidiedit.a $(libmidiedit_a_OBJECTS) $(libmidiedit_a_LIBADD) + $(RANLIB) libmidiedit.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dcanvas.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dlist.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/drumedit.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/drummap.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ecanvas.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/moc_dcanvas.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/moc_dlist.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/moc_drumedit.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/moc_ecanvas.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/moc_piano.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/moc_pianoroll.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/moc_prcanvas.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/moc_quantconfig.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/piano.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pianoroll.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/prcanvas.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/quantconfig.Po@am__quote@ + +.cpp.o: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< + +.cpp.obj: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cpp.lo: +@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) check-am +all-am: Makefile $(LIBRARIES) +installdirs: +install: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES) + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: all check install install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am + + +de: + @for base in $(MOCFILES); do echo -e "\t$${base}.cpp $${base}.h \\"; done + +nde: + @for base in $(MOCFILES); do echo -e "\tmoc_$${base}.cpp \\"; done + +.ui.o: %.h + $(UIC) -L $(top_srcdir)/muse/widgets -o $*.cpp -impl $*.h $*.ui + $(MOC) $*.h >> $*.cpp + $(CXXCOMPILE) -c $*.cpp -o $*.o + $(RM) $*.cpp moc_$*.cpp moc_$*.o + +.ui.lo: %.h + $(UIC) -L $(top_srcdir)/muse/widgets -o $*.cpp -impl $*.h $*.ui + $(MOC) $*.h >> $*.cpp + $(LTCXXCOMPILE) -c $*.cpp -o $*.lo + $(RM) $*.cpp moc_$*.cpp moc_$*.lo moc_$*.o + +moc_%.cpp: %.h + $(MOC) $< -o $@ + +%.h: %.ui + $(UIC) -o $@ $< +# $(UIC) -L $(top_srcdir)/muse/widgets -o $@ $< + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/muse2/muse/midiedit/cmd.h b/muse2/muse/midiedit/cmd.h new file mode 100644 index 00000000..abbcdcf3 --- /dev/null +++ b/muse2/muse/midiedit/cmd.h @@ -0,0 +1,26 @@ +//========================================================= +// MusE +// Linux Music Editor +// $Id: cmd.h,v 1.1.1.1 2003/10/27 18:52:20 wschweer Exp $ +// (C) Copyright 2000 Werner Schweer (ws@seh.de) +//========================================================= + +#ifndef __CMD_H__ +#define __CMD_H__ + +#define CMD_LEFT 0 +#define CMD_RIGHT 1 +#define CMD_INSERT 2 +#define CMD_DELETE 3 +#define CMD_1 4 +#define CMD_2 5 +#define CMD_3 6 +#define CMD_4 7 +#define CMD_5 8 +#define CMD_6 9 +#define CMD_7 10 +#define CMD_T 11 +#define CMD_period 12 + +#endif + diff --git a/muse2/muse/midiedit/dcanvas.cpp b/muse2/muse/midiedit/dcanvas.cpp new file mode 100644 index 00000000..65138bb4 --- /dev/null +++ b/muse2/muse/midiedit/dcanvas.cpp @@ -0,0 +1,1291 @@ +//========================================================= +// MusE +// Linux Music Editor +// $Id: dcanvas.cpp,v 1.16.2.10 2009/10/15 22:45:50 terminator356 Exp $ +// (C) Copyright 1999 Werner Schweer (ws@seh.de) +//========================================================= + +#include <qpainter.h> +#include <qapplication.h> +#include <qclipboard.h> +#include <q3dragobject.h> +//Added by qt3to4: +#include <QDragLeaveEvent> +#include <Q3PointArray> +#include <Q3CString> +#include <QDragEnterEvent> +#include <QDragMoveEvent> +#include <QDropEvent> +#include <QResizeEvent> + +#include <stdio.h> +#include <values.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/mman.h> + +#include "dcanvas.h" +#include "midieditor.h" +#include "drummap.h" +#include "event.h" +#include "mpevent.h" +#include "xml.h" +#include "globals.h" +#include "midiport.h" +#include "audio.h" +#include "velocity.h" + +#define CARET 10 +#define CARET2 5 + +//--------------------------------------------------------- +// DEvent +//--------------------------------------------------------- + +DEvent::DEvent(Event e, Part* p) + : CItem(e, p) + { + int instr = e.pitch(); + int y = instr * TH + TH/2; + int tick = e.tick() + p->tick(); + setPos(QPoint(tick, y)); + setBBox(QRect(-CARET2, -CARET2, CARET, CARET)); + } + +//--------------------------------------------------------- +// addItem +//--------------------------------------------------------- + +void DrumCanvas::addItem(Part* part, Event& event) + { + if (signed(event.tick())<0) { + printf("ERROR: trying to add event before current part!\n"); + return; + } + + DEvent* ev = new DEvent(event, part); + items.add(ev); + + int diff = event.endTick()-part->lenTick(); + if (diff > 0) {// too short part? extend it + //printf("addItem - this code should not be run!\n"); + //Part* newPart = part->clone(); + //newPart->setLenTick(newPart->lenTick()+diff); + //audio->msgChangePart(part, newPart,false); + //part = newPart; + part->setLenTick(part->lenTick()+diff); + } + } + +//--------------------------------------------------------- +// DrumCanvas +//--------------------------------------------------------- + +DrumCanvas::DrumCanvas(MidiEditor* pr, QWidget* parent, int sx, + int sy, const char* name) + : EventCanvas(pr, parent, sx, sy, name) + { + setVirt(false); + songChanged(SC_TRACK_INSERTED); + } + +//--------------------------------------------------------- +// moveCanvasItems +//--------------------------------------------------------- + +void DrumCanvas::moveCanvasItems(CItemList& items, int dp, int dx, DragType dtype, int* pflags) +{ + if(editor->parts()->empty()) + return; + + PartsToChangeMap parts2change; + + int modified = 0; + for(iPart ip = editor->parts()->begin(); ip != editor->parts()->end(); ++ip) + { + Part* part = ip->second; + if(!part) + continue; + + int npartoffset = 0; + for(iCItem ici = items.begin(); ici != items.end(); ++ici) + { + CItem* ci = ici->second; + if(ci->part() != part) + continue; + + int x = ci->pos().x() + dx; + int y = pitch2y(y2pitch(ci->pos().y()) + dp); + QPoint newpos = raster(QPoint(x, y)); + + // Test moving the item... + DEvent* nevent = (DEvent*) ci; + Event event = nevent->event(); + x = newpos.x(); + if(x < 0) + x = 0; + int ntick = editor->rasterVal(x) - part->tick(); + if(ntick < 0) + ntick = 0; + int diff = ntick + event.lenTick() - part->lenTick(); + + // If moving the item would require a new part size... + if(diff > npartoffset) + npartoffset = diff; + } + + if(npartoffset > 0) + { + // Create new part... + // if there are several events that are moved outside the part, it will be recreated for each + // so the part _in_ the event will not be valid, ask the authority. +// Part* newPart = part->clone(); + //Part* newPart = Canvas::part()->clone(); + +// newPart->setLenTick(newPart->lenTick() + npartoffset); + //audio->msgChangePart(part, newPart,false); + +// modified = SC_PART_MODIFIED; + + // BUG FIX: #1650953 + // Added by T356. + // Fixes posted "select and drag past end of part - crashing" bug +// for(iPart ip = editor->parts()->begin(); ip != editor->parts()->end(); ++ip) +// { +// if(ip->second == part) +// { +// editor->parts()->erase(ip); +// break; +// } +// } + +// editor->parts()->add(newPart); +// audio->msgChangePart(part, newPart,false); + +// if(parts2change.find(part) == parts2change.end()) +// parts2change.insert(std::pair<Part*, Part*> (part, newPart)); + iPartToChange ip2c = parts2change.find(part); + if(ip2c == parts2change.end()) + { + PartToChange p2c = {0, npartoffset}; + parts2change.insert(std::pair<Part*, PartToChange> (part, p2c)); + } + else + ip2c->second.xdiff = npartoffset; + + + //part = newPart; // reassign + //item->setPart(part); + //item->setEvent(newEvent); + //curPart = part; + //curPartId = curPart->sn(); + + } + } + + for(iPartToChange ip2c = parts2change.begin(); ip2c != parts2change.end(); ++ip2c) + { + Part* opart = ip2c->first; + int diff = ip2c->second.xdiff; + + Part* newPart = opart->clone(); + + newPart->setLenTick(newPart->lenTick() + diff); + + modified = SC_PART_MODIFIED; + + // BUG FIX: #1650953 + // Added by T356. + // Fixes posted "select and drag past end of part - crashing" bug + for(iPart ip = editor->parts()->begin(); ip != editor->parts()->end(); ++ip) + { + if(ip->second == opart) + { + editor->parts()->erase(ip); + break; + } + } + + editor->parts()->add(newPart); + // Indicate no undo, and do port controller values but not clone parts. + //audio->msgChangePart(opart, newPart, false); + audio->msgChangePart(opart, newPart, false, true, false); + + ip2c->second.npart = newPart; + + } + + iPartToChange icp = parts2change.find(curPart); + if(icp != parts2change.end()) + { + curPart = icp->second.npart; + curPartId = curPart->sn(); + } + + std::vector< CItem* > doneList; + typedef std::vector< CItem* >::iterator iDoneList; + + for(iCItem ici = items.begin(); ici != items.end(); ++ici) + { + CItem* ci = ici->second; + + // If this item's part is in the parts2change list, change the item's part to the new part. + Part* pt = ci->part(); + iPartToChange ip2c = parts2change.find(pt); + if(ip2c != parts2change.end()) + ci->setPart(ip2c->second.npart); + + int x = ci->pos().x(); + int y = ci->pos().y(); + int nx = x + dx; + int ny = pitch2y(y2pitch(y) + dp); + QPoint newpos = raster(QPoint(nx, ny)); + selectItem(ci, true); + + iDoneList idl; + for(idl = doneList.begin(); idl != doneList.end(); ++idl) + // This compares EventBase pointers to see if they're the same... + if((*idl)->event() == ci->event()) + break; + + // Do not process if the event has already been processed (meaning it's an event in a clone part)... + //if(moveItem(ci, newpos, dtype)) + if(idl != doneList.end()) + // Just move the canvas item. + ci->move(newpos); + else + { + // Currently moveItem always returns true. + if(moveItem(ci, newpos, dtype)) + { + // Add the canvas item to the list of done items. + doneList.push_back(ci); + // Move the canvas item. + ci->move(newpos); + } + } + + if(moving.size() == 1) { + itemReleased(curItem, newpos); + } + if(dtype == MOVE_COPY || dtype == MOVE_CLONE) + selectItem(ci, false); + } + + if(pflags) + *pflags = modified; +} + +//--------------------------------------------------------- +// moveItem +//--------------------------------------------------------- + +// Changed by T356. +//bool DrumCanvas::moveItem(CItem* item, const QPoint& pos, DragType dtype, int* pflags) +bool DrumCanvas::moveItem(CItem* item, const QPoint& pos, DragType dtype) + { + DEvent* nevent = (DEvent*) item; + + // Changed by T356. + //MidiPart* part = (MidiPart*)Canvas::part(); // part can be dynamically recreated, ask the authority + MidiPart* part = (MidiPart*)nevent->part(); + + Event event = nevent->event(); + int x = pos.x(); + if (x < 0) + x = 0; + int ntick = editor->rasterVal(x) - part->tick(); + if (ntick < 0) + ntick = 0; + int npitch = y2pitch(pos.y()); + Event newEvent = event.clone(); + + newEvent.setPitch(npitch); + newEvent.setTick(ntick); + + // Removed by T356. + /* + // Added by T356. + int modified = 0; + //song->startUndo(); + int diff = newEvent.endTick()-part->lenTick(); + if (diff > 0) // too short part? extend it + { + // if there are several events that are moved outside the part, it will be recreated for each + // so the part _in_ the event will not be valid, ask the authority. + //Part* newPart = part->clone(); + MidiPart* newPart = (MidiPart*)Canvas::part()->clone(); + newPart->setLenTick(newPart->lenTick()+diff); + audio->msgChangePart(Canvas::part(), newPart,false); + + modified = SC_PART_MODIFIED; + part = newPart; // reassign + for(iPart i = editor->parts()->begin(); i != editor->parts()->end(); ++i) + { + if(i->second == Canvas::part()) + { + editor->parts()->erase(i); + break; + } + } + editor->parts()->add(part); + item->setPart(part); + item->setEvent(newEvent); + curPart = part; + curPartId = curPart->sn(); + } + */ + + // Added by T356. + // msgAddEvent and msgChangeEvent (below) will set these, but set them here first? + //item->setPart(part); + item->setEvent(newEvent); + + // Added by T356. + if(((int)newEvent.endTick() - (int)part->lenTick()) > 0) + printf("DrumCanvas::moveItem Error! New event end:%d exceeds length:%d of part:%s\n", newEvent.endTick(), part->lenTick(), part->name().latin1()); + + if (dtype == MOVE_COPY || dtype == MOVE_CLONE) { + // Indicate no undo, and do not do port controller values and clone parts. + //audio->msgAddEvent(newEvent, part, false); + audio->msgAddEvent(newEvent, part, false, false, false); + } + else { + // Indicate no undo, and do not do port controller values and clone parts. + //audio->msgChangeEvent(event, newEvent, part, false); + audio->msgChangeEvent(event, newEvent, part, false, false, false); + } + + // Removed by T356. + //if(pflags) + // *pflags = modified; + + return true; + } + +//--------------------------------------------------------- +// newItem +//--------------------------------------------------------- + +CItem* DrumCanvas::newItem(const QPoint& p, int state) + { + int instr = y2pitch(p.y()); //drumInmap[y2pitch(p.y())]; + int velo = drumMap[instr].lv4; + if (state == Qt::ShiftModifier) + velo = drumMap[instr].lv3; + else if (state == Qt::ControlModifier) + velo = drumMap[instr].lv2; + else if (state == (Qt::ControlModifier | Qt::ShiftModifier)) + velo = drumMap[instr].lv1; + int tick = editor->rasterVal(p.x()); + tick -= curPart->tick(); + Event e(Note); + e.setTick(tick); + e.setPitch(instr); + e.setVelo(velo); + e.setLenTick(drumMap[instr].len); + return new DEvent(e, curPart); + } + +//--------------------------------------------------------- +// resizeItem +//--------------------------------------------------------- + +void DrumCanvas::resizeItem(CItem* item, bool) + { + DEvent* nevent = (DEvent*) item; + Event ev = nevent->event(); + // Indicate do undo, and do not do port controller values and clone parts. + //audio->msgDeleteEvent(ev, nevent->part()); + audio->msgDeleteEvent(ev, nevent->part(), true, false, false); + } + +//--------------------------------------------------------- +// newItem +//--------------------------------------------------------- + +void DrumCanvas::newItem(CItem* item, bool noSnap) + { + DEvent* nevent = (DEvent*) item; + Event event = nevent->event(); + int x = item->x(); + if (!noSnap) + x = editor->rasterVal(x); + event.setTick(x - nevent->part()->tick()); + //int npitch = drumMap[y2pitch(item->y())].enote; + int npitch = event.pitch(); + event.setPitch(npitch); + + // + // check for existing event + // if found change command semantic from insert to delete + // + EventList* el = nevent->part()->events(); + iEvent lower = el->lower_bound(event.tick()); + iEvent upper = el->upper_bound(event.tick()); + + for (iEvent i = lower; i != upper; ++i) { + Event ev = i->second; + // Added by T356. Only do notes. + if(!ev.isNote()) + continue; + + if (ev.pitch() == npitch) { + // Indicate do undo, and do not do port controller values and clone parts. + //audio->msgDeleteEvent(ev, nevent->part()); + audio->msgDeleteEvent(ev, nevent->part(), true, false, false); + return; + } + } + + // Added by T356. + Part* part = nevent->part(); + song->startUndo(); + int modified=SC_EVENT_MODIFIED; + int diff = event.endTick()-part->lenTick(); + if (diff > 0) {// too short part? extend it + //printf("extend Part!\n"); + Part* newPart = part->clone(); + newPart->setLenTick(newPart->lenTick()+diff); + // Indicate no undo, and do port controller values but not clone parts. + //audio->msgChangePart(part, newPart,false); + audio->msgChangePart(part, newPart, false, true, false); + modified=modified|SC_PART_MODIFIED; + part = newPart; // reassign + } + // Indicate no undo, and do not do port controller values and clone parts. + //audio->msgAddEvent(event, part,false); + audio->msgAddEvent(event, part, false, false, false); + song->endUndo(modified); + + //audio->msgAddEvent(event, nevent->part()); + } + +//--------------------------------------------------------- +// deleteItem +//--------------------------------------------------------- + +bool DrumCanvas::deleteItem(CItem* item) + { + Event ev = ((DEvent*)item)->event(); + // Indicate do undo, and do not do port controller values and clone parts. + //audio->msgDeleteEvent(ev, ((DEvent*)item)->part()); + audio->msgDeleteEvent(ev, ((DEvent*)item)->part(), true, false, false); + return false; + } + +//--------------------------------------------------------- +// drawItem +//--------------------------------------------------------- + +void DrumCanvas::drawItem(QPainter&p, const CItem*item, const QRect& rect) + { + DEvent* e = (DEvent*) item; + int x = 0, y = 0; + x = mapx(item->pos().x()); + y = mapy(item->pos().y()); + Q3PointArray pa(4); + pa.setPoint(0, x - CARET2, y); + pa.setPoint(1, x, y - CARET2); + pa.setPoint(2, x + CARET2, y); + pa.setPoint(3, x, y + CARET2); + QRect r(pa.boundingRect()); + r = r.intersect(rect); + if(!r.isValid()) + return; + + p.setPen(Qt::black); + + if (e->part() != curPart) + { + if(item->isMoving()) + p.setBrush(Qt::gray); + else if(item->isSelected()) + p.setBrush(Qt::black); + else + p.setBrush(Qt::lightGray); + } + else if (item->isMoving()) { + p.setBrush(Qt::gray); + } + else if (item->isSelected()) + { + p.setBrush(Qt::black); + } + else + { + int velo = e->event().velo(); + DrumMap* dm = &drumMap[y2pitch(y)]; //Get the drum item + QColor color; + if (velo < dm->lv1) + color.setRgb(240, 240, 255); + else if (velo < dm->lv2) + color.setRgb(200, 200, 255); + else if (velo < dm->lv3) + color.setRgb(170, 170, 255); + else + color.setRgb(0, 0, 255); + p.setBrush(color); + } + + p.drawPolygon(pa); + } + +//--------------------------------------------------------- +// drawMoving +// draws moving items +//--------------------------------------------------------- + +void DrumCanvas::drawMoving(QPainter& p, const CItem* item, const QRect& rect) + { + //if(((DEvent*)item)->part() != curPart) + // return; + //if(!item->isMoving()) + // return; + Q3PointArray pa(4); + QPoint pt = map(item->mp()); + int x = pt.x(); + int y = pt.y(); + pa.setPoint(0, x-CARET2, y + TH/2); + pa.setPoint(1, x, y + TH/2+CARET2); + pa.setPoint(2, x+CARET2, y + TH/2); + pa.setPoint(3, x, y + (TH-CARET)/2); + QRect mr(pa.boundingRect()); + mr = mr.intersect(rect); + if(!mr.isValid()) + return; + p.setPen(Qt::black); + p.setBrush(Qt::black); + p.drawPolygon(pa); + } + +//--------------------------------------------------------- +// drawCanvas +//--------------------------------------------------------- + +extern void drawTickRaster(QPainter& p, int, int, int, int, int); + +void DrumCanvas::drawCanvas(QPainter& p, const QRect& rect) + { + int x = rect.x(); + int y = rect.y(); + int w = rect.width(); + int h = rect.height(); + + //--------------------------------------------------- + // horizontal lines + //--------------------------------------------------- + + int yy = ((y-1) / TH) * TH + TH; + for (; yy < y + h; yy += TH) { + p.setPen(Qt::gray); + p.drawLine(x, yy, x + w, yy); + } + + //--------------------------------------------------- + // vertical lines + //--------------------------------------------------- + + drawTickRaster(p, x, y, w, h, editor->raster()); + } + +//--------------------------------------------------------- +// y2pitch +//--------------------------------------------------------- + +int DrumCanvas::y2pitch(int y) const + { + int pitch = y/TH; + if (pitch >= DRUM_MAPSIZE) + pitch = DRUM_MAPSIZE-1; + return pitch; + } + +//--------------------------------------------------------- +// pitch2y +//--------------------------------------------------------- + +int DrumCanvas::pitch2y(int pitch) const + { + return pitch * TH; + } + +//--------------------------------------------------------- +// cmd +//--------------------------------------------------------- + +void DrumCanvas::cmd(int cmd) + { + switch(cmd) { + case CMD_CUT: + copy(); + song->startUndo(); + for (iCItem i = items.begin(); i != items.end(); ++i) { + if (!i->second->isSelected()) + continue; + DEvent* e = (DEvent*)(i->second); + Event event = e->event(); + // Indicate no undo, and do not do port controller values and clone parts. + //audio->msgDeleteEvent(event, e->part(), false); + audio->msgDeleteEvent(event, e->part(), false, false, false); + } + song->endUndo(SC_EVENT_REMOVED); + break; + case CMD_COPY: + copy(); + break; + case CMD_PASTE: + paste(); + break; + case CMD_SELECT_ALL: // select all + for (iCItem k = items.begin(); k != items.end(); ++k) { + if (!k->second->isSelected()) + selectItem(k->second, true); + } + break; + case CMD_SELECT_NONE: // select none + deselectAll(); + break; + case CMD_SELECT_INVERT: // invert selection + for (iCItem k = items.begin(); k != items.end(); ++k) { + selectItem(k->second, !k->second->isSelected()); + } + break; + case CMD_SELECT_ILOOP: // select inside loop + for (iCItem k = items.begin(); k != items.end(); ++k) { + DEvent* nevent =(DEvent*)(k->second); + Part* part = nevent->part(); + Event event = nevent->event(); + unsigned tick = event.tick() + part->tick(); + if (tick < song->lpos() || tick >= song->rpos()) + selectItem(k->second, false); + else + selectItem(k->second, true); + } + break; + case CMD_SELECT_OLOOP: // select outside loop + for (iCItem k = items.begin(); k != items.end(); ++k) { + DEvent* nevent = (DEvent*)(k->second); + Part* part = nevent->part(); + Event event = nevent->event(); + unsigned tick = event.tick() + part->tick(); + if (tick < song->lpos() || tick >= song->rpos()) + selectItem(k->second, true); + else + selectItem(k->second, false); + } + break; + case CMD_SELECT_PREV_PART: // select previous part + { + Part* pt = editor->curCanvasPart(); + Part* newpt = pt; + PartList* pl = editor->parts(); + for(iPart ip = pl->begin(); ip != pl->end(); ++ip) + if(ip->second == pt) + { + if(ip == pl->begin()) + ip = pl->end(); + --ip; + newpt = ip->second; + break; + } + if(newpt != pt) + editor->setCurCanvasPart(newpt); + } + break; + case CMD_SELECT_NEXT_PART: // select next part + { + Part* pt = editor->curCanvasPart(); + Part* newpt = pt; + PartList* pl = editor->parts(); + for(iPart ip = pl->begin(); ip != pl->end(); ++ip) + if(ip->second == pt) + { + ++ip; + if(ip == pl->end()) + ip = pl->begin(); + newpt = ip->second; + break; + } + if(newpt != pt) + editor->setCurCanvasPart(newpt); + } + break; + case CMD_DEL: + if (selectionSize()) { + song->startUndo(); + for (iCItem i = items.begin(); i != items.end(); ++i) { + if (!i->second->isSelected()) + continue; + Event ev = i->second->event(); + // Indicate no undo, and do not do port controller values and clone parts. + //audio->msgDeleteEvent(ev, i->second->part(), false); + audio->msgDeleteEvent(ev, i->second->part(), false, false, false); + } + song->endUndo(SC_EVENT_REMOVED); + } + return; + + case CMD_SAVE: + case CMD_LOAD: + printf("DrumCanvas:: cmd not implemented %d\n", cmd); + break; + + case CMD_FIXED_LEN: //Set notes to the length specified in the drummap + if (!selectionSize()) + break; + song->startUndo(); + for (iCItem k = items.begin(); k != items.end(); ++k) { + if (k->second->isSelected()) { + DEvent* devent = (DEvent*)(k->second); + Event event = devent->event(); + Event newEvent = event.clone(); + newEvent.setLenTick(drumMap[event.pitch()].len); + // Indicate no undo, and do not do port controller values and clone parts. + //audio->msgChangeEvent(event, newEvent, devent->part() , false); + audio->msgChangeEvent(event, newEvent, devent->part(), false, false, false); + } + } + song->endUndo(SC_EVENT_MODIFIED); + break; + case CMD_LEFT: + { + int frames = pos[0] - editor->rasterStep(pos[0]); + if (frames < 0) + frames = 0; + Pos p(frames,true); + song->setPos(0, p, true, true, true); + } + break; + case CMD_RIGHT: + { + Pos p(pos[0] + editor->rasterStep(pos[0]), true); + song->setPos(0, p, true, true, true); + } + break; + case CMD_MODIFY_VELOCITY: + { + Velocity w(this); + w.setRange(0); //TODO: Make this work! Probably put _to & _toInit in ecanvas instead + if (!w.exec()) + break; + int range = w.range(); // all, selected, looped, sel+loop + int rate = w.rateVal(); + int offset = w.offsetVal(); + + song->startUndo(); + for (iCItem k = items.begin(); k != items.end(); ++k) { + DEvent* devent = (DEvent*)(k->second); + Event event = devent->event(); + if (event.type() != Note) + continue; + unsigned tick = event.tick(); + bool selected = k->second->isSelected(); + bool inLoop = (tick >= song->lpos()) && (tick < song->rpos()); + + if ((range == 0) + || (range == 1 && selected) + || (range == 2 && inLoop) + || (range == 3 && selected && inLoop)) { + int velo = event.velo(); + + //velo = rate ? (velo * 100) / rate : 64; + velo = (velo * rate) / 100; + velo += offset; + + if (velo <= 0) + velo = 1; + if (velo > 127) + velo = 127; + if (event.velo() != velo) { + Event newEvent = event.clone(); + newEvent.setVelo(velo); + // Indicate no undo, and do not do port controller values and clone parts. + //audio->msgChangeEvent(event, newEvent, devent->part(), false); + audio->msgChangeEvent(event, newEvent, devent->part(), false, false, false); + } + } + } + song->endUndo(SC_EVENT_MODIFIED); + } + break; + } + updateSelection(); + redraw(); + } + +//--------------------------------------------------------- +// getTextDrag +//--------------------------------------------------------- + +Q3TextDrag* DrumCanvas::getTextDrag(QWidget* parent) + { + //--------------------------------------------------- + // generate event list from selected events + //--------------------------------------------------- + + EventList el; + unsigned startTick = MAXINT; + for (iCItem i = items.begin(); i != items.end(); ++i) { + if (!i->second->isSelected()) + continue; + DEvent* ne = (DEvent*)(i->second); + Event e = ne->event(); + if (startTick == MAXINT) + startTick = e.tick(); + el.add(e); + } + + //--------------------------------------------------- + // write events as XML into tmp file + //--------------------------------------------------- + + FILE* tmp = tmpfile(); + if (tmp == 0) { + fprintf(stderr, "EventCanvas::copy() fopen failed: %s\n", + strerror(errno)); + return 0; + } + Xml xml(tmp); + + int level = 0; + for (ciEvent e = el.begin(); e != el.end(); ++e) + e->second.write(level, xml, -startTick); + + //--------------------------------------------------- + // read tmp file into QTextDrag Object + //--------------------------------------------------- + + fflush(tmp); + struct stat f_stat; + if (fstat(fileno(tmp), &f_stat) == -1) { + fprintf(stderr, "EventCanvas::copy() fstat failes:<%s>\n", + strerror(errno)); + fclose(tmp); + return 0; + } + int n = f_stat.st_size; + char* fbuf = (char*)mmap(0, n+1, PROT_READ|PROT_WRITE, + MAP_PRIVATE, fileno(tmp), 0); + fbuf[n] = 0; + Q3TextDrag* drag = new Q3TextDrag(QString(fbuf), parent); + drag->setSubtype("eventlist"); + munmap(fbuf, n); + fclose(tmp); + return drag; + } + +//--------------------------------------------------------- +// copy +// cut copy paste +//--------------------------------------------------------- + +void DrumCanvas::copy() + { + Q3TextDrag* drag = getTextDrag(0); + if (drag) + QApplication::clipboard()->setData(drag, QClipboard::Clipboard); + } + +//--------------------------------------------------------- +// paste +//--------------------------------------------------------- + +int DrumCanvas::pasteAt(const QString& pt, int pos) + { + const char* p = pt.latin1(); + Xml xml(p); + + // Added by T356. + int modified = SC_EVENT_INSERTED; + + song->startUndo(); + for (;;) { + Xml::Token token = xml.parse(); + QString tag = xml.s1(); + switch (token) { + case Xml::Error: + case Xml::End: + //song->endUndo(SC_EVENT_INSERTED); By T356 + song->endUndo(modified); + return pos; + case Xml::TagStart: + if (tag == "event") { + Event e(Note); + e.read(xml); + + // Added by T356. + int tick = e.tick() + pos - curPart->tick(); + if (tick<0) { + printf("DrumCanvas::pasteAt ERROR: trying to add event before current part!\n"); + song->endUndo(SC_EVENT_INSERTED); + //delete el; + return pos; + } + e.setTick(tick); + int diff = e.endTick() - curPart->lenTick(); + if (diff > 0) {// too short part? extend it + Part* newPart = curPart->clone(); + newPart->setLenTick(newPart->lenTick()+diff); + // Indicate no undo, and do port controller values but not clone parts. + //audio->msgChangePart(curPart, newPart,false); + audio->msgChangePart(curPart, newPart, false, true, false); + + modified=modified|SC_PART_MODIFIED; + curPart = newPart; // reassign + } + + // Indicate no undo, and do not do port controller values and clone parts. + //audio->msgAddEvent(e, curPart, false); + audio->msgAddEvent(e, curPart, false, false, false); + } + else + //xml.unknown("EventCanvas::paste"); By T356 + xml.unknown("DCanvas::pasteAt"); + break; + case Xml::TagEnd: + default: + break; + } + } + } + +//--------------------------------------------------------- +// paste +// paste events +//--------------------------------------------------------- + +void DrumCanvas::paste() + { +// Q3CString subtype("eventlist"); // ddskrjo + QString subtype("eventlist"); + QMimeSource* ms = QApplication::clipboard()->data(); + QString pt; + if (!Q3TextDrag::decode(ms, pt, subtype)) { + printf("cannot paste: bad data type\n"); + return; + } + pasteAt(pt, song->cpos()); + } + +//--------------------------------------------------------- +// startDrag +//--------------------------------------------------------- + +void DrumCanvas::startDrag(CItem* /* item*/, bool copymode) + { + Q3TextDrag* drag = getTextDrag(this); + if (drag) { +// QApplication::clipboard()->setData(drag, QClipboard::Clipboard); + + if (copymode) + drag->dragCopy(); + else + drag->dragMove(); + } + } + +//--------------------------------------------------------- +// dragEnterEvent +//--------------------------------------------------------- + +void DrumCanvas::dragEnterEvent(QDragEnterEvent* event) + { + event->accept(Q3TextDrag::canDecode(event)); + } + +//--------------------------------------------------------- +// dragMoveEvent +//--------------------------------------------------------- + +void DrumCanvas::dragMoveEvent(QDragMoveEvent*) + { +// printf("drag move %x\n", this); + } + +//--------------------------------------------------------- +// dragLeaveEvent +//--------------------------------------------------------- + +void DrumCanvas::dragLeaveEvent(QDragLeaveEvent*) + { +// printf("drag leave\n"); + } + +//--------------------------------------------------------- +// dropEvent +//--------------------------------------------------------- + +void DrumCanvas::viewDropEvent(QDropEvent* event) + { + QString text; + if (event->source() == this) { + printf("local DROP\n"); + return; + } + if (Q3TextDrag::decode(event, text)) { +// printf("drop <%s>\n", text.ascii()); + int x = editor->rasterVal(event->pos().x()); + if (x < 0) + x = 0; + pasteAt(text, x); + } + } + +//--------------------------------------------------------- +// keyPressed +//--------------------------------------------------------- + +void DrumCanvas::keyPressed(int index, bool) + { + int port = drumMap[index].port; + int channel = drumMap[index].channel; + int pitch = drumMap[index].anote; + + // play note: + MidiPlayEvent e(0, port, channel, 0x90, pitch, 127); + audio->msgPlayMidiEvent(&e); + } + +//--------------------------------------------------------- +// keyReleased +//--------------------------------------------------------- + +void DrumCanvas::keyReleased(int index, bool) + { + int port = drumMap[index].port; + int channel = drumMap[index].channel; + int pitch = drumMap[index].anote; + + // release note: + MidiPlayEvent e(0, port, channel, 0x90, pitch, 0); + audio->msgPlayMidiEvent(&e); + } + +//--------------------------------------------------------- +// mapChanged +//--------------------------------------------------------- + +void DrumCanvas::mapChanged(int spitch, int dpitch) + { + //TODO: Circumvent undo behaviour, since this isn't really a true change of the events, + // but merely a change in pitch because the pitch relates to the order of the dlist. + // Right now the sequencer spits out internalError: undoOp without startUndo() if start/stopundo is there, which is misleading + // If start/stopundo is there, undo misbehaves since it doesn't undo but messes things up + // Other solution: implement a specific undo-event for this (SC_DRUMMAP_MODIFIED or something) which undoes movement of + // dlist-items (ml) + + std::vector< std::pair<Part*, Event*> > delete_events; + std::vector< std::pair<Part*, Event> > add_events; + + typedef std::vector< std::pair<Part*, Event*> >::iterator idel_ev; + typedef std::vector< std::pair<Part*, Event> >::iterator iadd_ev; + + /* + class delete_events : public std::vector< Part*, Event* > + { + public: + idel_ev find(Part* p, Event* e) + { + + }; + }; + class add_events : public std::vector< Part*, Event > + { + public: + iadd_ev find(Part* p, Event& e) + { + + }; + }; + */ + + MidiTrackList* tracks = song->midis(); + for (ciMidiTrack t = tracks->begin(); t != tracks->end(); t++) { + MidiTrack* curTrack = *t; + if (curTrack->type() != Track::DRUM) + continue; + + MidiPort* mp = &midiPorts[curTrack->outPort()]; + PartList* parts= curTrack->parts(); + for (iPart part = parts->begin(); part != parts->end(); ++part) { + EventList* events = part->second->events(); + Part* thePart = part->second; + for (iEvent i = events->begin(); i != events->end(); ++i) { + Event event = i->second; + if(event.type() != Controller && event.type() != Note) + continue; + int pitch = event.pitch(); + bool drc = false; + // Is it a drum controller event, according to the track port's instrument? + if(event.type() == Controller && mp->drumController(event.dataA())) + { + drc = true; + pitch = event.dataA() & 0x7f; + } + + if (pitch == spitch) { + Event* spitch_event = &(i->second); + delete_events.push_back(std::pair<Part*, Event*>(thePart, spitch_event)); + Event newEvent = spitch_event->clone(); + if(drc) + newEvent.setA((newEvent.dataA() & ~0xff) | dpitch); + else + newEvent.setPitch(dpitch); + add_events.push_back(std::pair<Part*, Event>(thePart, newEvent)); + } + else if (pitch == dpitch) { + Event* dpitch_event = &(i->second); + delete_events.push_back(std::pair<Part*, Event*>(thePart, dpitch_event)); + Event newEvent = dpitch_event->clone(); + if(drc) + newEvent.setA((newEvent.dataA() & ~0xff) | spitch); + else + newEvent.setPitch(spitch); + add_events.push_back(std::pair<Part*, Event>(thePart, newEvent)); + } + } + } + } + + song->startUndo(); + for (idel_ev i = delete_events.begin(); i != delete_events.end(); i++) { + //std::pair<Part*, Event*> pair = *i; + //Part* thePart = pair.first; + //Event* theEvent = pair.second; + Part* thePart = (*i).first; + Event* theEvent = (*i).second; + // Indicate no undo, and do port controller values but not clone parts. + //audio->msgDeleteEvent(*theEvent, thePart, false); + audio->msgDeleteEvent(*theEvent, thePart, false, true, false); + } + + DrumMap dm = drumMap[spitch]; + drumMap[spitch] = drumMap[dpitch]; + drumMap[dpitch] = dm; + drumInmap[int(drumMap[spitch].enote)] = spitch; + drumOutmap[int(drumMap[int(spitch)].anote)] = spitch; + drumInmap[int(drumMap[int(dpitch)].enote)] = dpitch; + drumOutmap[int(drumMap[int(dpitch)].anote)] = dpitch; + + for (iadd_ev i = add_events.begin(); i != add_events.end(); i++) { + //std::pair<Part*, Event> pair = *i; + //Part* thePart = pair.first; + //Event& theEvent = pair.second; + Part* thePart = (*i).first; + Event& theEvent = (*i).second; + // Indicate no undo, and do port controller values but not clone parts. + //audio->msgAddEvent(theEvent, thePart, false); + audio->msgAddEvent(theEvent, thePart, false, true, false); + } + + song->endUndo(SC_EVENT_MODIFIED); + song->update(SC_DRUMMAP); + } + +//--------------------------------------------------------- +// resizeEvent +//--------------------------------------------------------- + +void DrumCanvas::resizeEvent(QResizeEvent* ev) + { + if (ev->size().width() != ev->oldSize().width()) + emit newWidth(ev->size().width()); + EventCanvas::resizeEvent(ev); + } + + +//--------------------------------------------------------- +// modifySelected +//--------------------------------------------------------- + +void DrumCanvas::modifySelected(NoteInfo::ValType type, int delta) + { + audio->msgIdle(true); + song->startUndo(); + for (iCItem i = items.begin(); i != items.end(); ++i) { + if (!(i->second->isSelected())) + continue; + DEvent* e = (DEvent*)(i->second); + Event event = e->event(); + if (event.type() != Note) + continue; + + MidiPart* part = (MidiPart*)(e->part()); + Event newEvent = event.clone(); + + switch (type) { + case NoteInfo::VAL_TIME: + { + int newTime = event.tick() + delta; + if (newTime < 0) + newTime = 0; + newEvent.setTick(newTime); + } + break; + case NoteInfo::VAL_LEN: + /* + { + int len = event.lenTick() + delta; + if (len < 1) + len = 1; + newEvent.setLenTick(len); + } + */ + printf("DrumCanvas::modifySelected - NoteInfo::VAL_LEN not implemented\n"); + break; + case NoteInfo::VAL_VELON: + /* + { + int velo = event->velo() + delta; + if (velo > 127) + velo = 127; + else if (velo < 0) + velo = 0; + newEvent.setVelo(velo); + } + */ + printf("DrumCanvas::modifySelected - NoteInfo::VAL_VELON not implemented\n"); + break; + case NoteInfo::VAL_VELOFF: + /* + { + int velo = event.veloOff() + delta; + if (velo > 127) + velo = 127; + else if (velo < 0) + velo = 0; + newEvent.setVeloOff(velo); + } + */ + printf("DrumCanvas::modifySelected - NoteInfo::VAL_VELOFF not implemented\n"); + break; + case NoteInfo::VAL_PITCH: + { + int pitch = event.pitch() - delta; // Reversing order since the drumlist is displayed in increasing order + if (pitch > 127) + pitch = 127; + else if (pitch < 0) + pitch = 0; + newEvent.setPitch(pitch); + } + break; + } + song->changeEvent(event, newEvent, part); + // Indicate do not do port controller values and clone parts. + //song->undoOp(UndoOp::ModifyEvent, newEvent, event, part); + song->undoOp(UndoOp::ModifyEvent, newEvent, event, part, false, false); + } + song->endUndo(SC_EVENT_MODIFIED); + audio->msgIdle(false); + } + +//--------------------------------------------------------- +// curPartChanged +//--------------------------------------------------------- + +void DrumCanvas::curPartChanged() + { + editor->setCaption(getCaption()); + } + diff --git a/muse2/muse/midiedit/dcanvas.h b/muse2/muse/midiedit/dcanvas.h new file mode 100644 index 00000000..7f5034fc --- /dev/null +++ b/muse2/muse/midiedit/dcanvas.h @@ -0,0 +1,93 @@ +//========================================================= +// MusE +// Linux Music Editor +// $Id: dcanvas.h,v 1.8.2.2 2009/02/02 21:38:00 terminator356 Exp $ +// (C) Copyright 1999 Werner Schweer (ws@seh.de) +//========================================================= + +#ifndef __DCANVAS_H__ +#define __DCANVAS_H__ + +#include "ecanvas.h" +#include "song.h" +//Added by qt3to4: +#include <QResizeEvent> +#include <QDragEnterEvent> +#include <QDropEvent> +#include <QDragMoveEvent> +#include <QDragLeaveEvent> + +#define TH 18 + +class MidiEditor; + +//--------------------------------------------------------- +// DEvent +// ''visual'' Drum Event +//--------------------------------------------------------- + +class DEvent : public CItem { + public: + DEvent(Event e, Part* p); + }; + +class ScrollScale; +class PianoRoll; +class Q3TextDrag; + +//--------------------------------------------------------- +// DrumCanvas +//--------------------------------------------------------- + +class DrumCanvas : public EventCanvas { + + Q_OBJECT + virtual void drawCanvas(QPainter&, const QRect&); + virtual void drawItem(QPainter&, const CItem*, const QRect&); + virtual void drawMoving(QPainter&, const CItem*, const QRect&); + virtual void moveCanvasItems(CItemList&, int, int, DragType, int*); + // Changed by T356. + //virtual bool moveItem(CItem*, const QPoint&, DragType, int*); + virtual bool moveItem(CItem*, const QPoint&, DragType); + virtual CItem* newItem(const QPoint&, int); + virtual void resizeItem(CItem*, bool); + virtual void newItem(CItem*, bool); + virtual bool deleteItem(CItem*); + + int y2pitch(int y) const; + int pitch2y(int pitch) const; + Q3TextDrag* getTextDrag(QWidget* parent); + void copy(); + int pasteAt(const QString& pt, int pos); + void paste(); + void startDrag(CItem*, bool copymode); + void dragEnterEvent(QDragEnterEvent* event); + void dragMoveEvent(QDragMoveEvent*); + void dragLeaveEvent(QDragLeaveEvent*); + void viewDropEvent(QDropEvent* event); + virtual void addItem(Part*, Event&); + virtual void resizeEvent(QResizeEvent*); + virtual void curPartChanged(); + + signals: + void newWidth(int); + + public slots: + void mapChanged(int, int); + void keyPressed(int, bool); + void keyReleased(int, bool); + + public: + enum { + CMD_CUT, CMD_COPY, CMD_PASTE, CMD_SAVE, CMD_LOAD, CMD_RESET, + CMD_SELECT_ALL, CMD_SELECT_NONE, CMD_SELECT_INVERT, + CMD_SELECT_ILOOP, CMD_SELECT_OLOOP, CMD_SELECT_PREV_PART, CMD_SELECT_NEXT_PART, + CMD_DEL, CMD_FIXED_LEN, CMD_RIGHT, CMD_LEFT, CMD_MODIFY_VELOCITY + }; + DrumCanvas(MidiEditor*, QWidget*, int, int, + const char* name = 0); + void cmd(int); + virtual void modifySelected(NoteInfo::ValType type, int delta); + }; +#endif + diff --git a/muse2/muse/midiedit/dlist.cpp b/muse2/muse/midiedit/dlist.cpp new file mode 100644 index 00000000..24ced3d0 --- /dev/null +++ b/muse2/muse/midiedit/dlist.cpp @@ -0,0 +1,754 @@ +//========================================================= +// MusE +// Linux Music Editor +// $Id: dlist.cpp,v 1.9.2.7 2009/10/16 21:50:16 terminator356 Exp $ +// (C) Copyright 1999 Werner Schweer (ws@seh.de) +//========================================================= + +#include <qpainter.h> +#include <q3header.h> +#include <qcursor.h> +#include <q3popupmenu.h> +#include <qlineedit.h> +//Added by qt3to4: +#include <QPixmap> +#include <QMouseEvent> + +#include <stdio.h> + +#include "audio.h" +#include "pitchedit.h" +#include "midiport.h" +#include "drummap.h" +#include "icons.h" +#include "dlist.h" +#include "song.h" +#include "scrollscale.h" + +// enum DCols { COL_MUTE=0, COL_NAME, COL_QNT, COL_ENOTE, COL_LEN, +// COL_ANOTE, COL_CHANNEL, COL_PORT, +// COL_LV1, COL_LV2, COL_LV3, COL_LV4, COL_NONE=-1}; + +//--------------------------------------------------------- +// draw +//--------------------------------------------------------- + +void DList::draw(QPainter& p, const QRect& rect) + { + int x = rect.x(); + int y = rect.y(); + int w = rect.width(); + int h = rect.height(); + + //--------------------------------------------------- + // Tracks + //--------------------------------------------------- + + p.setPen(Qt::black); + + for (int i = 0; i < DRUM_MAPSIZE; ++i) { + int yy = i * TH; + if (yy+TH < y) + continue; + if (yy > y + h) + break; + DrumMap* dm = &drumMap[i]; +// if (dm->selected) + if (dm == currentlySelected) + p.fillRect(x, yy, w, TH, Qt::yellow); +// else +// p.eraseRect(x, yy, w, TH); + for (int k = 0; k < header->count(); ++k) { + int x = header->sectionPos(k); + int w = header->sectionSize(k); + QRect r = p.xForm(QRect(x+2, yy, w-4, TH)); + QString s; + int align = Qt::AlignVCenter | Qt::AlignHCenter; + + p.save(); + p.setWorldXForm(false); + switch (k) { + case COL_VOL: + s.setNum(dm->vol); + break; + case COL_QNT: + s.setNum(dm->quant); + break; + case COL_LEN: + s.setNum(dm->len); + break; + case COL_ANOTE: + s = pitch2string(dm->anote); + break; + case COL_ENOTE: + s = pitch2string(dm->enote); + break; + case COL_LV1: + s.setNum(dm->lv1); + break; + case COL_LV2: + s.setNum(dm->lv2); + break; + case COL_LV3: + s.setNum(dm->lv3); + break; + case COL_LV4: + s.setNum(dm->lv4); + break; + case COL_MUTE: + if (dm->mute) { + p.setPen(Qt::red); + const QPixmap& pm = *muteIcon; + p.drawPixmap( + r.x() + r.width()/2 - pm.width()/2, + r.y() + r.height()/2 - pm.height()/2, + pm); + p.setPen(Qt::black); + } + break; + case COL_NAME: + s = dm->name; + align = Qt::AlignVCenter | Qt::AlignLeft; + break; + case COL_CHANNEL: + s.setNum(dm->channel+1); + break; + case COL_PORT: + s.sprintf("%d:%s", dm->port+1, midiPorts[dm->port].portname().latin1()); + align = Qt::AlignVCenter | Qt::AlignLeft; + break; + } + if (!s.isEmpty()) + p.drawText(r, align, s); + p.restore(); + } + } + + //--------------------------------------------------- + // horizontal lines + //--------------------------------------------------- + + p.setPen(Qt::gray); + int yy = (y / TH) * TH; + for (; yy < y + h; yy += TH) { + p.drawLine(x, yy, x + w, yy); + } + + if (drag == DRAG) { + int y = (startY/TH) * TH; + int dy = startY - y; + int yy = curY - dy; + p.setPen(Qt::green); + p.drawLine(x, yy, x + w, yy); + p.drawLine(x, yy+TH, x + w, yy+TH); + p.setPen(Qt::gray); + } + + //--------------------------------------------------- + // vertical Lines + //--------------------------------------------------- + + p.setWorldXForm(false); + int n = header->count(); + x = 0; + for (int i = 0; i < n; i++) { + //x += header->sectionSize(i); + x += header->sectionSize(header->mapToSection(i)); + p.drawLine(x, 0, x, height()); + } + p.setWorldXForm(true); + } + +//--------------------------------------------------------- +// devicesPopupMenu +//--------------------------------------------------------- + +void DList::devicesPopupMenu(DrumMap* t, int x, int y, bool changeAll) + { + Q3PopupMenu* p = midiPortsPopup(this); + int n = p->exec(mapToGlobal(QPoint(x, y)), 0); + bool doemit = false; + if (n != -1) { + if (!changeAll) + { + if(n != t->port) + { + audio->msgIdle(true); + //audio->msgRemapPortDrumCtlEvents(getSelectedInstrument(), -1, -1, n); + song->remapPortDrumCtrlEvents(getSelectedInstrument(), -1, -1, n); + audio->msgIdle(false); + t->port = n; + doemit = true; + } + } + else { + audio->msgIdle(true); + // Delete all port controller events. + //audio->msgChangeAllPortDrumCtrlEvents(false); + song->changeAllPortDrumCtrlEvents(false); + + for (int i = 0; i < DRUM_MAPSIZE; i++) + drumMap[i].port = n; + // Add all port controller events. + //audio->msgChangeAllPortDrumCtrlEvents(true); + song->changeAllPortDrumCtrlEvents(true); + + audio->msgIdle(false); + doemit = true; + } + } + delete p; + if(doemit) + { + int instr = getSelectedInstrument(); + if(instr != -1) + //emit curDrumInstrumentChanged(instr); + song->update(SC_DRUMMAP); + } + } + +//--------------------------------------------------------- +// viewMousePressEvent +//--------------------------------------------------------- + +void DList::viewMousePressEvent(QMouseEvent* ev) + { + int x = ev->x(); + int y = ev->y(); + int button = ev->button(); + bool shift = ev->state() & Qt::ShiftButton; + unsigned pitch = y / TH; + DrumMap* dm = &drumMap[pitch]; + + setCurDrumInstrument(pitch); + + startY = y; + sPitch = pitch; + drag = START_DRAG; + + DCols col = DCols(x2col(x)); + + int val; + int incVal = 0; + if (button == Qt::RightButton) + incVal = 1; + else if (button == Qt::MidButton) + incVal = -1; + + // Check if we're already editing anything and have pressed the mouse + // elsewhere + // In that case, treat it as if a return was pressed + + if (button == Qt::LeftButton) { + if (((editEntry && editEntry != dm) || col != selectedColumn) && editEntry != 0) { + returnPressed(); + } + } + + switch (col) { + case COL_NONE: + break; + case COL_MUTE: + if (button == Qt::LeftButton) + dm->mute = !dm->mute; + break; + case COL_PORT: + if (button == Qt::RightButton) { + bool changeAll = ev->state() & Qt::ControlButton; + devicesPopupMenu(dm, mapx(x), mapy(pitch * TH), changeAll); + } + break; + case COL_VOL: + val = dm->vol + incVal; + if (val < 0) + val = 0; + else if (val > 200) + val = 200; + dm->vol = (unsigned char)val; + break; + case COL_QNT: + dm->quant += incVal; + // ?? range + break; + case COL_ENOTE: + val = dm->enote + incVal; + if (val < 0) + val = 0; + else if (val > 127) + val = 127; + //Check if there is any other drumMap with the same inmap value (there should be one (and only one):-) + //If so, switch the inmap between the instruments + for (int i=0; i<DRUM_MAPSIZE; i++) { + if (drumMap[i].enote == val && &drumMap[i] != dm) { + drumInmap[int(dm->enote)] = i; + drumMap[i].enote = dm->enote; + break; + } + } + //TODO: Set all the notes on the track with pitch=dm->enote to pitch=val + dm->enote = val; + drumInmap[val] = pitch; + break; + case COL_LEN: + val = dm->len + incVal; + if (val < 0) + val = 0; + dm->len = val; + break; + case COL_ANOTE: + val = dm->anote + incVal; + if (val < 0) + val = 0; + else if (val > 127) + val = 127; + if(val != dm->anote) + { + audio->msgIdle(true); + //audio->msgRemapPortDrumCtlEvents(pitch, val, -1, -1); + song->remapPortDrumCtrlEvents(pitch, val, -1, -1); + audio->msgIdle(false); + dm->anote = val; + song->update(SC_DRUMMAP); + } + emit keyPressed(pitch, shift);//(dm->anote, shift); + break; + case COL_CHANNEL: + val = dm->channel + incVal; + if (val < 0) + val = 0; + else if (val > 127) + val = 127; + + if (ev->state() & Qt::ControlButton) { + audio->msgIdle(true); + // Delete all port controller events. + //audio->msgChangeAllPortDrumCtrlEvents(false); + song->changeAllPortDrumCtrlEvents(false, true); + + for (int i = 0; i < DRUM_MAPSIZE; i++) + drumMap[i].channel = val; + // Add all port controller events. + //audio->msgChangeAllPortDrumCtrlEvents(true); + song->changeAllPortDrumCtrlEvents(true, true); + audio->msgIdle(false); + song->update(SC_DRUMMAP); + } + else + { + if(val != dm->channel) + { + audio->msgIdle(true); + //audio->msgRemapPortDrumCtlEvents(pitch, -1, val, -1); + song->remapPortDrumCtrlEvents(pitch, -1, val, -1); + audio->msgIdle(false); + dm->channel = val; + song->update(SC_DRUMMAP); + } + } + break; + case COL_LV1: + val = dm->lv1 + incVal; + if (val < 0) + val = 0; + else if (val > 127) + val = 127; + dm->lv1 = val; + break; + case COL_LV2: + val = dm->lv2 + incVal; + if (val < 0) + val = 0; + else if (val > 127) + val = 127; + dm->lv2 = val; + break; + case COL_LV3: + val = dm->lv3 + incVal; + if (val < 0) + val = 0; + else if (val > 127) + val = 127; + dm->lv3 = val; + break; + case COL_LV4: + val = dm->lv4 + incVal; + if (val < 0) + val = 0; + else if (val > 127) + val = 127; + dm->lv4 = val; + break; + case COL_NAME: + emit keyPressed(pitch, shift); //Mapping done on other side, send index + break; +#if 0 + case COL_CHANNEL: + { + int channel = t->channel(); + if (button == Qt::RightButton) { + if (channel < 15) + ++channel; + } + else if (button == Qt::MidButton) { + if (channel > 0) + --channel; + } + if (channel != t->channel()) { + t->setChannel(channel); + emit channelChanged(); + } + } +#endif + default: + break; + } + redraw(); + } + +//--------------------------------------------------------- +// viewMouseDoubleClickEvent +//--------------------------------------------------------- + +void DList::viewMouseDoubleClickEvent(QMouseEvent* ev) + { + int x = ev->x(); + int y = ev->y(); +// int button = ev->button(); + unsigned pitch = y / TH; + + int section = header->sectionAt(x); + + if ((section == COL_NAME || section == COL_VOL || section == COL_LEN || section == COL_LV1 || + section == COL_LV2 || section == COL_LV3 || section == COL_LV4) && (ev->button() == Qt::LeftButton)) + { + lineEdit(pitch, section); + } + else + viewMousePressEvent(ev); + } + + + +//--------------------------------------------------------- +// lineEdit +//--------------------------------------------------------- +void DList::lineEdit(int line, int section) + { + DrumMap* dm = &drumMap[line]; + editEntry = dm; + if (editor == 0) { + editor = new DLineEdit(this); + connect(editor, SIGNAL(returnPressed()), + SLOT(returnPressed())); + editor->setFrame(true); + } + int colx = mapx(header->sectionPos(section)); + int colw = rmapx(header->sectionSize(section)); + int coly = mapy(line * TH); + int colh = rmapy(TH); + selectedColumn = section; //Store selected column to have an idea of which one was selected when return is pressed + switch (section) { + case COL_NAME: + editor->setText(dm->name); + break; + + case COL_VOL: { + editor->setText(QString::number(dm->vol)); + break; + } + + case COL_LEN: { + editor->setText(QString::number(dm->len)); + break; + } + + case COL_LV1: + editor->setText(QString::number(dm->lv1)); + break; + + case COL_LV2: + editor->setText(QString::number(dm->lv2)); + break; + + case COL_LV3: + editor->setText(QString::number(dm->lv3)); + break; + + case COL_LV4: + editor->setText(QString::number(dm->lv4)); + break; + } + + // editor->setText(dm->name); + editor->end(false); + editor->setGeometry(colx, coly, colw, colh); + // In all cases but the column name, select all text: + if (section != COL_NAME) + editor->selectAll(); + editor->show(); + editor->setFocus(); + + } + + + + + + + + + + + + + + + +//--------------------------------------------------------- +// x2col +//--------------------------------------------------------- + +int DList::x2col(int x) const + { + int col = 0; + int w = 0; + for (; col < header->count(); col++) { + w += header->cellSize(col); + if (x < w) + break; + } + if (col == header->count()) + return -1; + return header->mapToLogical(col); + } + +//--------------------------------------------------------- +// setCurDrumInstrument +//--------------------------------------------------------- + +void DList::setCurDrumInstrument(int instr) + { + if (instr < 0 || instr >= DRUM_MAPSIZE -1) + return; // illegal instrument + DrumMap* dm = &drumMap[instr]; + if (currentlySelected != dm) { + currentlySelected = &drumMap[instr]; + emit curDrumInstrumentChanged(instr); + song->update(SC_DRUMMAP); + } + } + +//--------------------------------------------------------- +// sizeChange +//--------------------------------------------------------- + +void DList::sizeChange(int, int, int) + { + redraw(); + } + +//--------------------------------------------------------- +// returnPressed +//--------------------------------------------------------- + +void DList::returnPressed() + { + int val = -1; + if (selectedColumn != COL_NAME) + { + val = atoi(editor->text().ascii()); + if (selectedColumn != COL_LEN) + { + if(selectedColumn == COL_VOL) + { + if (val > 200) //Check bounds for volume + val = 200; + if (val < 0) + val = 0; + } + else + { + if (val > 127) //Check bounds for lv1-lv4 values + val = 127; + if (val < 0) + val = 0; + } + } + } + + switch(selectedColumn) { + case COL_NAME: + editEntry->name = editor->text(); + break; + + case COL_LEN: + editEntry->len = atoi(editor->text().ascii()); + break; + + case COL_VOL: + editEntry->vol = val; + break; + + case COL_LV1: + editEntry->lv1 = val; + break; + + case COL_LV2: + editEntry->lv2 = val; + break; + + case COL_LV3: + editEntry->lv3 = val; + break; + + case COL_LV4: + editEntry->lv4 = val; + break; + + default: + printf("Return pressed in unknown column\n"); + break; + } + selectedColumn = -1; + editor->hide(); + editEntry = 0; + setFocus(); + redraw(); + } + +//--------------------------------------------------------- +// moved +//--------------------------------------------------------- + +void DList::moved(int, int) + { + redraw(); + } + +//--------------------------------------------------------- +// tracklistChanged +//--------------------------------------------------------- + +void DList::tracklistChanged() + { + } + +//--------------------------------------------------------- +// songChanged +//--------------------------------------------------------- + +void DList::songChanged(int flags) + { + if (flags & SC_DRUMMAP) { + redraw(); + } + } + + +//--------------------------------------------------------- +// DList +//--------------------------------------------------------- + +DList::DList(Q3Header* h, QWidget* parent, int ymag) + : View(parent, 1, ymag) + { + setBg(Qt::white); + header = h; + scroll = 0; + header->setTracking(true); + connect(header, SIGNAL(sizeChange(int,int,int)), + SLOT(sizeChange(int,int,int))); + connect(header, SIGNAL(moved(int,int)), SLOT(moved(int,int))); + setFocusPolicy(Qt::StrongFocus); + drag = NORMAL; + editor = 0; + editEntry = 0; + // always select an drum instrument + currentlySelected = &drumMap[0]; + selectedColumn = -1; + } + +//--------------------------------------------------------- +// ~DList +//--------------------------------------------------------- + +DList::~DList() + { +// if (currentlySelected != 0) +// currentlySelected->selected = false; //Reset the global thingie + } + +//--------------------------------------------------------- +// viewMouseMoveEvent +//--------------------------------------------------------- + +void DList::viewMouseMoveEvent(QMouseEvent* ev) + { + curY = ev->y(); + int delta = curY - startY; + switch (drag) { + case START_DRAG: + if (delta < 0) + delta = -delta; + if (delta <= 2) + return; + drag = DRAG; + setCursor(QCursor(Qt::sizeVerCursor)); + redraw(); + break; + case NORMAL: + break; + case DRAG: + redraw(); + break; + } + } + +//--------------------------------------------------------- +// viewMouseReleaseEvent +//--------------------------------------------------------- + +void DList::viewMouseReleaseEvent(QMouseEvent* ev) + { + if (drag == DRAG) { + int y = ev->y(); + unsigned dPitch = y / TH; + setCursor(QCursor(Qt::arrowCursor)); + currentlySelected = &drumMap[int(dPitch)]; + emit curDrumInstrumentChanged(dPitch); + emit mapChanged(sPitch, dPitch); //Track pitch change done in canvas + } + drag = NORMAL; +//?? redraw(); + if (editEntry) + editor->setFocus(); + int x = ev->x(); + int y = ev->y(); + bool shift = ev->state() & Qt::ShiftButton; + unsigned pitch = y / TH; + + DCols col = DCols(x2col(x)); + + switch (col) { + case COL_NAME: + emit keyReleased(pitch, shift); + break; + case COL_ANOTE: + emit keyReleased(pitch, shift); + break; + default: + break; + } + } + +//--------------------------------------------------------- +// getSelectedInstrument +//--------------------------------------------------------- + +int DList::getSelectedInstrument() + { + if (currentlySelected == 0) + return -1; + return drumInmap[int(currentlySelected->enote)]; + } + diff --git a/muse2/muse/midiedit/dlist.h b/muse2/muse/midiedit/dlist.h new file mode 100644 index 00000000..1d7e0114 --- /dev/null +++ b/muse2/muse/midiedit/dlist.h @@ -0,0 +1,105 @@ +//========================================================= +// MusE +// Linux Music Editor +// $Id: dlist.h,v 1.5.2.3 2009/10/16 21:50:16 terminator356 Exp $ +// (C) Copyright 1999 Werner Schweer (ws@seh.de) +//========================================================= + +#ifndef __DLIST_H__ +#define __DLIST_H__ + +#include <qlineedit.h> +//Added by qt3to4: +#include <QMouseEvent> +#include <QKeyEvent> +#include "view.h" + +#define TH 18 // normal Track-hight + +class QPainter; +class Q3Header; +class ScrollScale; +class Device; +class QLineEdit; +class DrumMap; + + +//--------------------------------------------------------- +// DLineEdit +//--------------------------------------------------------- +class DLineEdit: public QLineEdit +{ + public: + DLineEdit(QWidget* parent) : QLineEdit(parent) {} + virtual ~DLineEdit() {}; + + virtual void keyPressEvent(QKeyEvent* keyItem) { + if(keyItem->key() == Qt::Key_Escape) { + parentWidget()->setFocus(); + hide(); + } + else + QLineEdit::keyPressEvent(keyItem); + + } +}; + +//--------------------------------------------------------- +// DList +//--------------------------------------------------------- + +class DList : public View { + Q3Header* header; + ScrollScale* scroll; + QLineEdit* editor; + DrumMap* editEntry; + DrumMap* currentlySelected; + int selectedColumn; + + + int startY; + int curY; + int sPitch; + enum { NORMAL, START_DRAG, DRAG } drag; + + virtual void draw(QPainter& p, const QRect&); + virtual void viewMousePressEvent(QMouseEvent* event); + virtual void viewMouseReleaseEvent(QMouseEvent* event); + virtual void viewMouseDoubleClickEvent(QMouseEvent*); + virtual void viewMouseMoveEvent(QMouseEvent*); + + int x2col(int x) const; + void devicesPopupMenu(DrumMap* t, int x, int y, bool changeAll); + Q_OBJECT + //void setCurDrumInstrument(int n); + + private slots: + void sizeChange(int, int, int); + void returnPressed(); + void moved(int, int); + + signals: + void channelChanged(); + void mapChanged(int, int); + void keyPressed(int, bool); + void keyReleased(int, bool); + void curDrumInstrumentChanged(int); + + public slots: + void tracklistChanged(); + void songChanged(int); + public: + void lineEdit(int line, int section); + void setCurDrumInstrument(int n); + DList(Q3Header*, QWidget* parent, int ymag); + ~DList(); + void setScroll(ScrollScale* s) { scroll = s; } + int getSelectedInstrument(); + +enum DCols { COL_MUTE=0, COL_NAME, COL_VOL, COL_QNT, COL_ENOTE, COL_LEN, + COL_ANOTE, COL_CHANNEL, COL_PORT, + COL_LV1, COL_LV2, COL_LV3, COL_LV4, COL_NONE=-1}; + }; + +#endif // __DLIST_H_ + diff --git a/muse2/muse/midiedit/drumedit.cpp b/muse2/muse/midiedit/drumedit.cpp new file mode 100644 index 00000000..ebe89ac6 --- /dev/null +++ b/muse2/muse/midiedit/drumedit.cpp @@ -0,0 +1,1167 @@ +//========================================================= +// MusE +// Linux Music Editor +// $Id: drumedit.cpp,v 1.22.2.21 2009/11/16 11:29:33 lunar_shuttle Exp $ +// (C) Copyright 1999 Werner Schweer (ws@seh.de) +//========================================================= + +#include <qtoolbutton.h> +#include <q3accel.h> +#include <qlayout.h> +#include <q3hbox.h> +#include <qsizegrip.h> +#include <qscrollbar.h> +#include <qlabel.h> +#include <qpushbutton.h> +#include <qradiobutton.h> +#include <q3buttongroup.h> +#include <q3listbox.h> +#include <q3popupmenu.h> +#include <qmenubar.h> +#include <qtooltip.h> +#include <qapplication.h> +#include <qclipboard.h> +#include <qmessagebox.h> +#include <qaction.h> +//Added by qt3to4: +#include <QKeyEvent> +#include <Q3ValueList> +#include <Q3GridLayout> +#include <QResizeEvent> +#include <QCloseEvent> + +#include "drumedit.h" +#include "mtscale.h" +#include "scrollscale.h" +#include "xml.h" +#include "dlist.h" +#include "dcanvas.h" +#include "ttoolbar.h" +#include "tb1.h" +#include "splitter.h" +#include "utils.h" +#include "../ctrl/ctrledit.h" +#include "vscale.h" +#include "swidget.h" +#include "globals.h" +#include "icons.h" +#include "filedialog.h" +#include "drummap.h" +#include "audio.h" +#include "gconfig.h" + +/* +static const char* map_file_pattern[] = { + "Presets (*.map *.map.gz *.map.bz2)", + "All Files (*)", + 0 + }; +static const char* map_file_save_pattern[] = { + "Presets (*.map)", + "gzip compressed presets (*.map.gz)", + "bzip2 compressed presets (*.map.bz2)", + "All Files (*)", + 0 + }; +*/ + +int DrumEdit::_quantInit = 96; +int DrumEdit::_rasterInit = 96; +int DrumEdit::_widthInit = 600; +int DrumEdit::_heightInit = 400; +int DrumEdit::_dlistWidthInit = 50; +int DrumEdit::_dcanvasWidthInit = 300; +int DrumEdit::_toInit = 0; + +static const int xscale = -10; +static const int yscale = 1; +static const int drumeditTools = PointerTool | PencilTool | RubberTool; + +//--------------------------------------------------------- +// DWhatsThis::text +//--------------------------------------------------------- + +QString DWhatsThis::text(const QPoint& pos) + { + int section = header->sectionAt(pos.x()); + if (section == -1) + return QString::null; + switch(section) { + case 0: return Q3Header::tr("mute instrument"); break; + case 1: return Q3Header::tr("sound name"); break; + case 2: return Q3Header::tr("volume percent"); break; + case 3: return Q3Header::tr("quantisation"); break; + case 4: return Q3Header::tr("this input note triggers the sound"); break; + case 5: return Q3Header::tr("note length"); break; + case 6: return Q3Header::tr("this is the note which is played"); break; + case 7: return Q3Header::tr("output channel (hold ctl to affect all rows)"); break; + case 8: return Q3Header::tr("output port"); break; + case 9: return Q3Header::tr("shift + control key: draw velocity level 1"); break; + case 10: return Q3Header::tr("control key: draw velocity level 2"); break; + case 11: return Q3Header::tr("shift key: draw velocity level 3"); break; + case 12: return Q3Header::tr("draw velocity level 4"); break; + default: break; + } + return QString::null; + } + +//--------------------------------------------------------- +// DHeaderTip::maybeTip +//--------------------------------------------------------- + +void DHeaderTip::maybeTip(const QPoint &pos) + { +#if 0 // ddskrjo + Header* w = (Header*)parentWidget(); + int section = w->sectionAt(pos.x()); + if (section == -1) + return; + QRect r(w->sectionPos(section), 0, w->sectionSize(section), + w->height()); + QString p; + switch(section) { + case 0: p = Q3Header::tr("mute instrument"); break; + case 1: p = Q3Header::tr("sound name"); break; + case 2: p = Q3Header::tr("volume percent"); break; + case 3: p = Q3Header::tr("quantisation"); break; + case 4: p = Q3Header::tr("this input note triggers the sound"); break; + case 5: p = Q3Header::tr("note length"); break; + case 6: p = Q3Header::tr("this is the note which is played"); break; + case 7: p = Q3Header::tr("output channel (ctl: affect all rows)"); break; + case 8: p = Q3Header::tr("output port"); break; + case 9: p = Q3Header::tr("shift + control key: draw velocity level 1"); break; + case 10: p = Q3Header::tr("control key: draw velocity level 2"); break; + case 11: p = Q3Header::tr("shift key: draw velocity level 3"); break; + case 12: p = Q3Header::tr("draw velocity level 4"); break; + default: return; + } + tip(r, p); +#endif + } + +//--------------------------------------------------------- +// closeEvent +//--------------------------------------------------------- + +void DrumEdit::closeEvent(QCloseEvent* e) + { + //Store values of the horizontal splitter + Q3ValueList<int> sizes = split2->sizes(); + Q3ValueList<int>::Iterator it = sizes.begin(); + _dlistWidthInit = *it; //There are only 2 values stored in the sizelist, size of dlist widget and dcanvas widget + it++; + _dcanvasWidthInit = *it; + emit deleted((unsigned long)this); + e->accept(); + } + +//--------------------------------------------------------- +// DrumEdit +//--------------------------------------------------------- + +DrumEdit::DrumEdit(PartList* pl, QWidget* parent, const char* name, unsigned initPos) + : MidiEditor(_quantInit, _rasterInit, pl, parent, name) + { + split1w1 = 0; + resize(_widthInit, _heightInit); + selPart = 0; + _to = _toInit; + //---------Pulldown Menu---------------------------- + menuFile = new Q3PopupMenu(this); + menuBar()->insertItem(tr("&File"), menuFile); + + menuFile->insertItem(QIcon(*openIcon), tr("Load Map"), DrumCanvas::CMD_LOAD); + menuFile->insertItem(QIcon(*saveIcon), tr("Save Map"), DrumCanvas::CMD_SAVE); + menuFile->insertItem(tr("Reset GM Map"), DrumCanvas::CMD_RESET); + + menuEdit = new Q3PopupMenu(this); + menuBar()->insertItem(tr("&Edit"), menuEdit); + undoRedo->addTo(menuEdit); + Q3Accel* qa = new Q3Accel(this); + qa->connectItem(qa->insertItem(Qt::CTRL+Qt::Key_Z), song, SLOT(undo())); + menuEdit->insertSeparator(); + menuEdit->insertItem(tr("Cut"), DrumCanvas::CMD_CUT); + menuEdit->insertItem(tr("Copy"), DrumCanvas::CMD_COPY); + menuEdit->insertItem(tr("Paste"), DrumCanvas::CMD_PASTE); + menuEdit->insertSeparator(); + menuEdit->insertItem(tr("Delete Events"), DrumCanvas::CMD_DEL); + + // Functions + menuFunctions = new Q3PopupMenu(this); + menuBar()->insertItem(tr("&Functions"), menuFunctions); + menuFunctions->insertTearOffHandle(); + menuFunctions->insertItem(tr("Set fixed length"), DrumCanvas::CMD_FIXED_LEN); + menuFunctions->insertItem(tr("Modify Velocity"), DrumCanvas::CMD_MODIFY_VELOCITY); + + menuSelect = new Q3PopupMenu(this); + menuSelect->insertItem(tr("Select All"), DrumCanvas::CMD_SELECT_ALL); + menuSelect->insertItem(tr("Select None"), DrumCanvas::CMD_SELECT_NONE); + menuSelect->insertItem(tr("Invert"), DrumCanvas::CMD_SELECT_INVERT); + menuSelect->insertSeparator(); + menuSelect->insertItem(tr("Inside Loop"), DrumCanvas::CMD_SELECT_ILOOP); + menuSelect->insertItem(tr("Outside Loop"), DrumCanvas::CMD_SELECT_OLOOP); + + menuSelect->insertSeparator(); + + menuSelect->insertItem(tr("Previous Part"), DrumCanvas::CMD_SELECT_PREV_PART); + menuSelect->insertItem(tr("Next Part"), DrumCanvas::CMD_SELECT_NEXT_PART); + + menuEdit->insertItem(tr("&Select"), menuSelect); + + Q3PopupMenu* menuScriptPlugins = new Q3PopupMenu(this); + song->populateScriptMenu(menuScriptPlugins, this); + menuBar()->insertItem(tr("&Plugins"), menuScriptPlugins); + + connect(menuFile, SIGNAL(activated(int)), SLOT(cmd(int))); + connect(menuEdit, SIGNAL(activated(int)), SLOT(cmd(int))); + connect(menuSelect, SIGNAL(activated(int)), SLOT(cmd(int))); + connect(menuFunctions, SIGNAL(activated(int)), SLOT(cmd(int))); + + //--------------------------------------------------- + // Toolbars + //--------------------------------------------------- + + tools = new Q3ToolBar(this, "drum-tools"); + new QToolButton(*openIcon, tr("Load Drummap"), + QString::null, this, SLOT(load()), + tools, "load drummap from file"); + + new QToolButton(*saveIcon, tr("Store Drummap"), + QString::null, + this, SLOT(save()), + tools, "store drummap to file"); + + Q3WhatsThis::whatsThisButton(tools); + + tools->addSeparator(); + undoRedo->addTo(tools); + tools->addSeparator(); + + srec = new QToolButton(tools, "srec"); + QToolTip::add(srec, tr("Step Record")); + srec->setPixmap(*steprecIcon); + srec->setToggleButton(true); + + midiin = new QToolButton(tools, "midiin"); + QToolTip::add(midiin, tr("Midi Input")); + midiin->setPixmap(*midiinIcon); + midiin->setToggleButton(true); + + tools2 = new EditToolBar(this, drumeditTools); + + Q3ToolBar* transport = new Q3ToolBar(this); + transportAction->addTo(transport); + + // dontt show pitch value in toolbar + //toolbar = new Toolbar1(this, _rasterInit, _quantInit, false); + toolbar = new Toolbar1(this, _rasterInit, _quantInit); + info = new NoteInfo(this); + + //--------------------------------------------------- + // split + //--------------------------------------------------- + + split1 = new Splitter(Qt::Vertical, mainw, "split1"); + QPushButton* ctrl = new QPushButton(tr("ctrl"), mainw, "Ctrl"); + ctrl->setFont(config.fonts[3]); + hscroll = new ScrollScale(-25, -2, xscale, 20000, Qt::Horizontal, mainw); + ctrl->setFixedSize(40, hscroll->sizeHint().height()); + QToolTip::add(ctrl, tr("Add Controller View")); + + QSizeGrip* corner = new QSizeGrip(mainw); + corner->setFixedHeight(hscroll->sizeHint().height()); + + mainGrid->setRowStretch(0, 100); + mainGrid->setColStretch(1, 100); + + mainGrid->addMultiCellWidget(split1, 0, 0, 0, 2); + mainGrid->addWidget(ctrl, 1, 0); + mainGrid->addWidget(hscroll, 1, 1); + mainGrid->addWidget(corner, 1, 2, Qt::AlignBottom|Qt::AlignRight); +// mainGrid->addRowSpacing(1, hscroll->sizeHint().height()); + + split2 = new Splitter(Qt::Horizontal, split1, "split2"); + split1w1 = new QWidget(split2, "split1w1"); + QWidget* split1w2 = new QWidget(split2, "split1w2"); + Q3GridLayout* gridS1 = new Q3GridLayout(split1w1); + Q3GridLayout* gridS2 = new Q3GridLayout(split1w2); + time = new MTScale(&_raster, split1w2, xscale); + canvas = new DrumCanvas(this, split1w2, xscale, yscale); + vscroll = new ScrollScale(-4, 1, yscale, DRUM_MAPSIZE*TH, Qt::Vertical, split1w2); + int offset = -(config.division/4); + canvas->setOrigin(offset, 0); + canvas->setCanvasTools(drumeditTools); + canvas->setFocus(); + connect(canvas, SIGNAL(toolChanged(int)), tools2, SLOT(set(int))); + time->setOrigin(offset, 0); + + Q3ValueList<int> mops; + mops.append(_dlistWidthInit); + mops.append(_dcanvasWidthInit); + split2->setSizes(mops); + // By T356. Not much choice but to disable this for now, to stop runaway resize bug. + // Can't seem to get the splitter to readjust when manually setting sizes. + //split2->setResizeMode(split1w1, QSplitter::KeepSize); + + gridS2->setRowStretch(1, 100); + gridS2->setColStretch(0, 100); + + gridS2->addMultiCellWidget(time, 0, 0, 0, 1); + gridS2->addMultiCellWidget(hLine(split1w2), 1, 1, 0, 1); + gridS2->addWidget(canvas, 2, 0); + + gridS2->addWidget(vscroll, 2, 1); + // + // Reihenfolge in dlist.c festgeschrieben ("Dcols") + // + header = new Header(split1w1, "header"); + header->setFixedHeight(30); + header->addLabel(tr("M"), 20); + header->addLabel(tr("Sound"), 100); + header->addLabel(tr("Vol")); + header->addLabel(tr("QNT")); + header->addLabel(tr("E-Note")); + header->addLabel(tr("Len")); + header->addLabel(tr("A-Note")); + header->addLabel(tr("Ch")); + header->addLabel(tr("Port"), 60); + header->addLabel(tr("LV1")); + header->addLabel(tr("LV2")); + header->addLabel(tr("LV3")); + header->addLabel(tr("LV4")); + new DHeaderTip(header); + new DWhatsThis(header, header); + + dlist = new DList(header, split1w1, yscale); + // p3.3.44 + setCurDrumInstrument(dlist->getSelectedInstrument()); + + connect(dlist, SIGNAL(keyPressed(int, bool)), canvas, SLOT(keyPressed(int, bool))); + connect(dlist, SIGNAL(keyReleased(int, bool)), canvas, SLOT(keyReleased(int, bool))); + connect(dlist, SIGNAL(mapChanged(int, int)), canvas, SLOT(mapChanged(int, int))); + + gridS1->setRowStretch(1, 100); + gridS1->setColStretch(0, 100); + gridS1->addWidget(header, 0, 0); + gridS1->addWidget(dlist, 1, 0); + + connect(canvas, SIGNAL(newWidth(int)), SLOT(newCanvasWidth(int))); + connect(canvas, SIGNAL(verticalScroll(unsigned)), vscroll, SLOT(setPos(unsigned))); + connect(canvas, SIGNAL(horizontalScroll(unsigned)),hscroll, SLOT(setPos(unsigned))); + connect(canvas, SIGNAL(horizontalScrollNoLimit(unsigned)),hscroll, SLOT(setPosNoLimit(unsigned))); + connect(song, SIGNAL(songChanged(int)), SLOT(songChanged1(int))); + connect(song, SIGNAL(songChanged(int)), dlist, SLOT(songChanged(int))); + connect(vscroll, SIGNAL(scrollChanged(int)), canvas, SLOT(setYPos(int))); + connect(vscroll, SIGNAL(scaleChanged(int)), canvas, SLOT(setYMag(int))); + connect(vscroll, SIGNAL(scaleChanged(int)), dlist, SLOT(setYMag(int))); + connect(hscroll, SIGNAL(scrollChanged(int)), canvas, SLOT(setXPos(int))); + connect(hscroll, SIGNAL(scaleChanged(int)), canvas, SLOT(setXMag(int))); + connect(srec, SIGNAL(toggled(bool)), canvas, SLOT(setSteprec(bool))); + connect(midiin, SIGNAL(toggled(bool)), canvas, SLOT(setMidiin(bool))); + + connect(vscroll, SIGNAL(scrollChanged(int)), dlist, SLOT(setYPos(int))); + connect(hscroll, SIGNAL(scrollChanged(int)), time, SLOT(setXPos(int))); + connect(hscroll, SIGNAL(scaleChanged(int)), time, SLOT(setXMag(int))); + + connect(tools2, SIGNAL(toolChanged(int)), canvas, SLOT(setTool(int))); + + connect(canvas, SIGNAL(selectionChanged(int, Event&, Part*)), this, + SLOT(setSelection(int, Event&, Part*))); + connect(canvas, SIGNAL(followEvent(int)), SLOT(follow(int))); + + connect(hscroll, SIGNAL(scaleChanged(int)), SLOT(updateHScrollRange())); + setCaption(canvas->getCaption()); + + updateHScrollRange(); + + // connect toolbar + connect(canvas, SIGNAL(timeChanged(unsigned)), SLOT(setTime(unsigned))); + connect(time, SIGNAL(timeChanged(unsigned)), SLOT(setTime(unsigned))); + connect(toolbar, SIGNAL(quantChanged(int)), SLOT(setQuant(int))); + connect(toolbar, SIGNAL(rasterChanged(int)), SLOT(setRaster(int))); + connect(toolbar, SIGNAL(soloChanged(bool)), SLOT(soloChanged(bool))); + connect(info, SIGNAL(valueChanged(NoteInfo::ValType, int)), SLOT(noteinfoChanged(NoteInfo::ValType, int))); + + connect(ctrl, SIGNAL(clicked()), SLOT(addCtrl())); + + QClipboard* cb = QApplication::clipboard(); + connect(cb, SIGNAL(dataChanged()), SLOT(clipboardChanged())); + + clipboardChanged(); // enable/disable "Paste" + selectionChanged(); // enable/disable "Copy" & "Paste" + initShortcuts(); + + const Pos cpos=song->cPos(); + canvas->setPos(0, cpos.tick(), true); + canvas->selectAtTick(cpos.tick()); + //canvas->selectFirst(); + + if(canvas->track()) + toolbar->setSolo(canvas->track()->solo()); + + unsigned pos; + if(initPos >= MAXINT) + pos = song->cpos(); + else + pos = initPos; + if(pos > MAXINT) + pos = MAXINT; + hscroll->setOffset((int)pos); + } + +//--------------------------------------------------------- +// songChanged1 +//--------------------------------------------------------- + +void DrumEdit::songChanged1(int bits) + { + if (bits & SC_SOLO) + { + toolbar->setSolo(canvas->track()->solo()); + return; + } + songChanged(bits); + + } + +//--------------------------------------------------------- +// updateHScrollRange +//--------------------------------------------------------- + +void DrumEdit::updateHScrollRange() +{ + int s, e; + canvas->range(&s, &e); + // Show one more measure. + e += sigmap.ticksMeasure(e); + // Show another quarter measure due to imprecise drawing at canvas end point. + e += sigmap.ticksMeasure(e) / 4; + // Compensate for drum list, splitter handle, and vscroll widths. + e += canvas->rmapxDev(dlist->width() + split2->handleWidth() - vscroll->width()); + int s1, e1; + hscroll->range(&s1, &e1); + if(s != s1 || e != e1) + hscroll->setRange(s, e); +} + +//--------------------------------------------------------- +// follow +//--------------------------------------------------------- + +void DrumEdit::follow(int pos) + { + int s, e; + canvas->range(&s, &e); + + if (pos < e && pos >= s) + hscroll->setOffset(pos); + if (pos < s) + hscroll->setOffset(s); + } + +//--------------------------------------------------------- +// setTime +//--------------------------------------------------------- + +void DrumEdit::setTime(unsigned tick) + { + toolbar->setTime(tick); + time->setPos(3, tick, false); + } + +//--------------------------------------------------------- +// ~DrumEdit +//--------------------------------------------------------- + +DrumEdit::~DrumEdit() + { + undoRedo->removeFrom(tools); + } + +//--------------------------------------------------------- +// setSelection +// update Info Line +//--------------------------------------------------------- + +void DrumEdit::setSelection(int tick, Event& e, Part* p) + { + selEvent = e; + selPart = (MidiPart*)p; + selTick = tick; + info->setEnabled(!e.empty()); + if (!e.empty()) { + info->setValues(tick, + selEvent.lenTick(), + selEvent.pitch(), + selEvent.velo(), + selEvent.veloOff()); + } + selectionChanged(); + } + +//--------------------------------------------------------- +// soloChanged +//--------------------------------------------------------- + +void DrumEdit::soloChanged(bool flag) + { + audio->msgSetSolo(canvas->track(), flag); + song->update(SC_SOLO); + } + +//--------------------------------------------------------- +// setRaster +//--------------------------------------------------------- + +void DrumEdit::setRaster(int val) + { + _rasterInit = val; + MidiEditor::setRaster(val); + canvas->redrawGrid(); + } + +//--------------------------------------------------------- +// setQuant +//--------------------------------------------------------- + +void DrumEdit::setQuant(int val) + { + _quantInit = val; + MidiEditor::setQuant(val); + } + +//--------------------------------------------------------- +// edit currently selected Event +//--------------------------------------------------------- + +void DrumEdit::noteinfoChanged(NoteInfo::ValType type, int val) + { + if (selEvent.empty()) { + printf("noteinfoChanged while note is zero %d\n", type); + return; + } + Event event = selEvent.clone(); + switch (type) { + case NoteInfo::VAL_TIME: + event.setTick(val - selPart->tick()); + break; + case NoteInfo::VAL_LEN: + event.setLenTick(val); + break; + case NoteInfo::VAL_VELON: + event.setVelo(val); + break; + case NoteInfo::VAL_VELOFF: + event.setVeloOff(val); + break; + case NoteInfo::VAL_PITCH: + event.setPitch(val); + break; + } + // Indicate do undo, and do not do port controller values and clone parts. + //audio->msgChangeEvent(selEvent, event, selPart); + audio->msgChangeEvent(selEvent, event, selPart, true, false, false); + } + +//--------------------------------------------------------- +// writeStatus +//--------------------------------------------------------- + +void DrumEdit::writeStatus(int level, Xml& xml) const + { + writePartList(level, xml); + xml.tag(level++, "drumedit"); + MidiEditor::writeStatus(level, xml); + + for (std::list<CtrlEdit*>::const_iterator i = ctrlEditList.begin(); + i != ctrlEditList.end(); ++i) { + (*i)->writeStatus(level, xml); + } + + split1->writeStatus(level, xml); + split2->writeStatus(level, xml); + + header->writeStatus(level, xml); + xml.intTag(level, "steprec", canvas->steprec()); + xml.intTag(level, "midiin", canvas->midiin()); + xml.intTag(level, "xpos", hscroll->pos()); + xml.intTag(level, "xmag", hscroll->mag()); + xml.intTag(level, "ypos", vscroll->pos()); + xml.intTag(level, "ymag", vscroll->mag()); + xml.tag(level, "/drumedit"); + } + +//--------------------------------------------------------- +// readStatus +//--------------------------------------------------------- + +void DrumEdit::readStatus(Xml& xml) + { + for (;;) { + Xml::Token token = xml.parse(); + const QString& tag = xml.s1(); + switch (token) { + case Xml::Error: + case Xml::End: + return; + case Xml::TagStart: + if (tag == "steprec") { + int val = xml.parseInt(); + canvas->setSteprec(val); + srec->setOn(val); + } + else if (tag == "midiin") { + int val = xml.parseInt(); + canvas->setMidiin(val); + midiin->setOn(val); + } + else if (tag == "ctrledit") { + CtrlEdit* ctrl = addCtrl(); + ctrl->readStatus(xml); + } + else if (tag == split1->name()) + split1->readStatus(xml); + else if (tag == split2->name()) + split2->readStatus(xml); + else if (tag == "midieditor") + MidiEditor::readStatus(xml); + else if (tag == header->name()) + header->readStatus(xml); + else if (tag == "xmag") + hscroll->setMag(xml.parseInt()); + else if (tag == "xpos") + hscroll->setPos(xml.parseInt()); + else if (tag == "ymag") + vscroll->setMag(xml.parseInt()); + else if (tag == "ypos") + vscroll->setPos(xml.parseInt()); + else + xml.unknown("DrumEdit"); + break; + case Xml::TagEnd: + if (tag == "drumedit") { + _quantInit = _quant; + _rasterInit = _raster; + toolbar->setRaster(_raster); + toolbar->setQuant(_quant); + canvas->redrawGrid(); + return; + } + default: + break; + } + } + } + +//--------------------------------------------------------- +// readConfiguration +//--------------------------------------------------------- + +void DrumEdit::readConfiguration(Xml& xml) + { + for (;;) { + Xml::Token token = xml.parse(); + const QString& tag = xml.s1(); + switch (token) { + case Xml::Error: + case Xml::End: + return; + case Xml::TagStart: + if (tag == "quant") + _quantInit = xml.parseInt(); + else if (tag == "raster") + _rasterInit = xml.parseInt(); + else if (tag == "width") + _widthInit = xml.parseInt(); + else if (tag == "height") + _heightInit = xml.parseInt(); + else if (tag == "dcanvaswidth") + _dcanvasWidthInit = xml.parseInt(); + else if (tag == "dlistwidth") + _dlistWidthInit = xml.parseInt(); + else if (tag == "to") { + _toInit = xml.parseInt(); + } + else + xml.unknown("DrumEdit"); + break; + case Xml::TagEnd: + if (tag == "drumedit") { + return; + } + default: + break; + } + } + } + +//--------------------------------------------------------- +// writeConfiguration +//--------------------------------------------------------- + +void DrumEdit::writeConfiguration(int level, Xml& xml) + { + xml.tag(level++, "drumedit"); + xml.intTag(level, "quant", _quantInit); + xml.intTag(level, "raster", _rasterInit); + xml.intTag(level, "width", _widthInit); + xml.intTag(level, "height", _heightInit); + xml.intTag(level, "dlistwidth", _dlistWidthInit); + xml.intTag(level, "dcanvaswidth", _dcanvasWidthInit); + xml.intTag(level, "to", _toInit); + xml.tag(level, "/drumedit"); + } + +//--------------------------------------------------------- +// load +//--------------------------------------------------------- + +void DrumEdit::load() + { + //QString fn = getOpenFileName("drummaps", map_file_pattern, + QString fn = getOpenFileName("drummaps", drum_map_file_pattern, + this, tr("Muse: Load Drum Map"), 0); + if (fn.isEmpty()) + return; + bool popenFlag; + FILE* f = fileOpen(this, fn, QString(".map"), "r", popenFlag, true); + if (f == 0) + return; + + Xml xml(f); + int mode = 0; + for (;;) { + Xml::Token token = xml.parse(); + const QString& tag = xml.s1(); + switch (token) { + case Xml::Error: + case Xml::End: + return; + case Xml::TagStart: + if (mode == 0 && tag == "muse") + mode = 1; + else if (mode == 1 && tag == "drummap") { + readDrumMap(xml, true); + mode = 0; + } + else + xml.unknown("DrumEdit"); + break; + case Xml::Attribut: + break; + case Xml::TagEnd: + if (!mode && tag == "muse") + goto ende; + default: + break; + } + } +ende: + if (popenFlag) + pclose(f); + else + fclose(f); + dlist->redraw(); + canvas->redraw(); + } + +//--------------------------------------------------------- +// save +//--------------------------------------------------------- + +void DrumEdit::save() + { + //QString fn = getSaveFileName(QString("drummaps"), map_file_pattern, + QString fn = getSaveFileName(QString("drummaps"), drum_map_file_save_pattern, + this, tr("MusE: Store Drum Map")); + if (fn.isEmpty()) + return; + bool popenFlag; + FILE* f = fileOpen(this, fn, QString(".map"), "w", popenFlag, false, true); + if (f == 0) + return; + Xml xml(f); + xml.header(); + xml.tag(0, "muse version=\"1.0\""); + writeDrumMap(1, xml, true); + xml.tag(1, "/muse"); + + if (popenFlag) + pclose(f); + else + fclose(f); + } + +//--------------------------------------------------------- +// reset +//--------------------------------------------------------- + +void DrumEdit::reset() +{ + if(QMessageBox::warning(this, tr("Drum map"), + tr("Reset the drum map with GM defaults?"), + QMessageBox::Ok | QMessageBox::Default, QMessageBox::Cancel | QMessageBox::Escape, Qt::NoButton) == QMessageBox::Ok) + { + resetGMDrumMap(); + dlist->redraw(); + canvas->redraw(); + } +} + +//--------------------------------------------------------- +// cmd +// pulldown menu commands +//--------------------------------------------------------- + +void DrumEdit::cmd(int cmd) + { + switch(cmd) { + case DrumCanvas::CMD_LOAD: + load(); + break; + case DrumCanvas::CMD_SAVE: + save(); + break; + case DrumCanvas::CMD_RESET: + reset(); + break; + default: + ((DrumCanvas*)(canvas))->cmd(cmd); + break; + } + } + +//--------------------------------------------------------- +// clipboardChanged +//--------------------------------------------------------- + +void DrumEdit::clipboardChanged() + { + QMimeSource* ms = QApplication::clipboard()->data(QClipboard::Clipboard); + if (ms && ms->format(0)) { + bool flag = strcmp(ms->format(0), "text/eventlist;charset=UTF-8") == 0; + menuEdit->setItemEnabled(DrumCanvas::CMD_PASTE, flag); + } + } + +//--------------------------------------------------------- +// selectionChanged +//--------------------------------------------------------- + +void DrumEdit::selectionChanged() + { + bool flag = canvas->selectionSize() > 0; + menuEdit->setItemEnabled(DrumCanvas::CMD_CUT, flag); + menuEdit->setItemEnabled(DrumCanvas::CMD_COPY, flag); + menuEdit->setItemEnabled(DrumCanvas::CMD_DEL, flag); + } + +//--------------------------------------------------------- +// addCtrl +//--------------------------------------------------------- + +CtrlEdit* DrumEdit::addCtrl() + { + CtrlEdit* ctrlEdit = new CtrlEdit(split1, this, xscale, true, "drumCtrlEdit"); + connect(hscroll, SIGNAL(scrollChanged(int)), ctrlEdit, SLOT(setXPos(int))); + connect(hscroll, SIGNAL(scaleChanged(int)), ctrlEdit, SLOT(setXMag(int))); + connect(ctrlEdit, SIGNAL(timeChanged(unsigned)), SLOT(setTime(unsigned))); + connect(ctrlEdit, SIGNAL(destroyedCtrl(CtrlEdit*)), SLOT(removeCtrl(CtrlEdit*))); + connect(ctrlEdit, SIGNAL(yposChanged(int)), toolbar, SLOT(setInt(int))); + connect(tools2, SIGNAL(toolChanged(int)), ctrlEdit, SLOT(setTool(int))); + connect(dlist, SIGNAL(curDrumInstrumentChanged(int)), SLOT(setCurDrumInstrument(int))); + + //printf("DrumEdit::addCtrl curDrumInstrument:%d\n", dlist->getSelectedInstrument()); + + setCurDrumInstrument(dlist->getSelectedInstrument()); + + // p3.3.44 + ctrlEdit->setTool(tools2->curTool()); + + ctrlEdit->setXPos(hscroll->pos()); + ctrlEdit->setXMag(hscroll->getScaleValue()); + + if(split1w1) + { + split2->setCollapsible(split1w1, false); + split1w1->setMinimumWidth(CTRL_PANEL_FIXED_WIDTH); + } + ctrlEdit->setCanvasWidth(canvas->width()); + + ctrlEdit->show(); + ctrlEditList.push_back(ctrlEdit); + return ctrlEdit; + } + +//--------------------------------------------------------- +// removeCtrl +//--------------------------------------------------------- + +void DrumEdit::removeCtrl(CtrlEdit* ctrl) + { + for (std::list<CtrlEdit*>::iterator i = ctrlEditList.begin(); + i != ctrlEditList.end(); ++i) { + if (*i == ctrl) { + ctrlEditList.erase(i); + break; + } + } + + if(split1w1) + { + if(ctrlEditList.empty()) + { + split1w1->setMinimumWidth(0); + split2->setCollapsible(split1w1, true); + } + } + } +//--------------------------------------------------------- +// newCanvasWidth +//--------------------------------------------------------- + +void DrumEdit::newCanvasWidth(int w) + { + int nw = w + (vscroll->width() - 18); // 18 is the fixed width of the CtlEdit VScale widget. + if(nw < 1) + nw = 1; + + for (std::list<CtrlEdit*>::iterator i = ctrlEditList.begin(); + i != ctrlEditList.end(); ++i) { + // Changed by Tim. p3.3.7 + //(*i)->setCanvasWidth(w); + (*i)->setCanvasWidth(nw); + } + + updateHScrollRange(); + } + +//--------------------------------------------------------- +// resizeEvent +//--------------------------------------------------------- + +void DrumEdit::resizeEvent(QResizeEvent* ev) + { + QWidget::resizeEvent(ev); + _widthInit = ev->size().width(); + _heightInit = ev->size().height(); + + //TODO: Make the dlist not expand/shrink, but the canvas instead + } + + +//--------------------------------------------------------- +// configChanged +//--------------------------------------------------------- + +void DrumEdit::configChanged() + { + initShortcuts(); + } + +static int rasterTable[] = { + //-9----8- 7 6 5 4 3(1/4) 2 1 + 4, 8, 16, 32, 64, 128, 256, 512, 1024, // triple + 6, 12, 24, 48, 96, 192, 384, 768, 1536, + 9, 18, 36, 72, 144, 288, 576, 1152, 2304 // dot + }; + +//--------------------------------------------------------- +// keyPressEvent +//--------------------------------------------------------- +void DrumEdit::keyPressEvent(QKeyEvent* event) + { + DrumCanvas* dc = (DrumCanvas*)canvas; + int index = 0; + int n = sizeof(rasterTable); + for (; index < n; ++index) + if (rasterTable[index] == raster()) + break; + int off = (index / 9) * 9; + index = index % 9; + int val; + int key = event->key(); + + if (event->state() & Qt::ShiftButton) + key += Qt::SHIFT; + if (event->state() & Qt::AltButton) + key += Qt::ALT; + if (event->state() & Qt::ControlButton) + key+= Qt::CTRL; + + if (key == Qt::Key_Escape) { + close(); + return; + } + else if (key == Qt::Key_Up) { + dlist->setCurDrumInstrument(dlist->getSelectedInstrument()-1); + dlist->redraw(); + return; + } + else if (key == Qt::Key_F2) { + dlist->lineEdit(dlist->getSelectedInstrument(),(int)DList::COL_NAME); + return; + } + else if (key == Qt::Key_Down) { + dlist->setCurDrumInstrument(dlist->getSelectedInstrument()+1); + dlist->redraw(); + return; + } + + else if (key == shortcuts[SHRT_POS_INC].key) { + dc->cmd(DrumCanvas::CMD_RIGHT); + return; + } + else if (key == shortcuts[SHRT_POS_DEC].key) { + dc->cmd(DrumCanvas::CMD_LEFT); + return; + } + + else if (key == shortcuts[SHRT_TOOL_POINTER].key) { + tools2->set(PointerTool); + return; + } + else if (key == shortcuts[SHRT_TOOL_PENCIL].key) { + tools2->set(PencilTool); + return; + } + else if (key == shortcuts[SHRT_TOOL_RUBBER].key) { + tools2->set(RubberTool); + return; + } + else if (key == shortcuts[SHRT_ZOOM_IN].key) { + int mag = hscroll->mag(); + int zoomlvl = ScrollScale::getQuickZoomLevel(mag); + if (zoomlvl < 23) + zoomlvl++; + + int newmag = ScrollScale::convertQuickZoomLevelToMag(zoomlvl); + hscroll->setMag(newmag); + //printf("mag = %d zoomlvl = %d newmag = %d\n", mag, zoomlvl, newmag); + return; + } + else if (key == shortcuts[SHRT_ZOOM_OUT].key) { + int mag = hscroll->mag(); + int zoomlvl = ScrollScale::getQuickZoomLevel(mag); + if (zoomlvl > 1) + zoomlvl--; + + int newmag = ScrollScale::convertQuickZoomLevelToMag(zoomlvl); + hscroll->setMag(newmag); + //printf("mag = %d zoomlvl = %d newmag = %d\n", mag, zoomlvl, newmag); + return; + } + else if (key == shortcuts[SHRT_SCROLL_LEFT].key) { + int pos = hscroll->pos() - config.division; + if (pos < 0) + pos = 0; + hscroll->setPos(pos); + return; + } + else if (key == shortcuts[SHRT_SCROLL_RIGHT].key) { + int pos = hscroll->pos() + config.division; + hscroll->setPos(pos); + return; + } + + /* + else if (key == shortcuts[SHRT_INSERT_AT_LOCATION].key) { + pc->pianoCmd(CMD_INSERT); + return; + } + */ + else if (key == shortcuts[SHRT_SET_QUANT_1].key) + val = rasterTable[8 + off]; + else if (key == shortcuts[SHRT_SET_QUANT_2].key) + val = rasterTable[7 + off]; + else if (key == shortcuts[SHRT_SET_QUANT_3].key) + val = rasterTable[6 + off]; + else if (key == shortcuts[SHRT_SET_QUANT_4].key) + val = rasterTable[5 + off]; + else if (key == shortcuts[SHRT_SET_QUANT_5].key) + val = rasterTable[4 + off]; + else if (key == shortcuts[SHRT_SET_QUANT_6].key) + val = rasterTable[3 + off]; + else if (key == shortcuts[SHRT_SET_QUANT_7].key) + val = rasterTable[2 + off]; + else if (key == shortcuts[SHRT_TOGGLE_TRIOL].key) + val = rasterTable[index + ((off == 0) ? 9 : 0)]; + /* + else if (key == shortcuts[SHRT_EVENT_COLOR].key) { + if (colorMode == 0) + colorMode = 1; + else if (colorMode == 1) + colorMode = 2; + else + colorMode = 0; + setEventColorMode(colorMode); + return; + }*/ + else if (key == shortcuts[SHRT_TOGGLE_PUNCT].key) + val = rasterTable[index + ((off == 18) ? 9 : 18)]; + + else if (key == shortcuts[SHRT_TOGGLE_PUNCT2].key) {//CDW + if ((off == 18) && (index > 2)) { + val = rasterTable[index + 9 - 1]; + } + else if ((off == 9) && (index < 8)) { + val = rasterTable[index + 18 + 1]; + } + else + return; + } + else { //Default: + event->ignore(); + return; + } + setQuant(val); + setRaster(val); + toolbar->setQuant(_quant); + toolbar->setRaster(_raster); + } + + + +//--------------------------------------------------------- +// initShortcuts +//--------------------------------------------------------- + +void DrumEdit::initShortcuts() + { + menuEdit->setAccel(shortcuts[SHRT_CUT].key, DrumCanvas::CMD_CUT); + menuEdit->setAccel(shortcuts[SHRT_COPY].key, DrumCanvas::CMD_COPY);; + menuEdit->setAccel(shortcuts[SHRT_PASTE].key, DrumCanvas::CMD_PASTE); + menuEdit->setAccel(shortcuts[SHRT_DELETE].key, DrumCanvas::CMD_DEL); + menuFile->setAccel(shortcuts[SHRT_OPEN].key, DrumCanvas::CMD_LOAD); + menuFile->setAccel(shortcuts[SHRT_SAVE].key, DrumCanvas::CMD_SAVE); + menuFunctions->setAccel(shortcuts[SHRT_FIXED_LEN].key, DrumCanvas::CMD_FIXED_LEN); + menuFunctions->setAccel(shortcuts[SHRT_MODIFY_VELOCITY].key, DrumCanvas::CMD_MODIFY_VELOCITY); + menuSelect->setAccel(shortcuts[SHRT_SELECT_ALL].key, DrumCanvas::CMD_SELECT_ALL); + menuSelect->setAccel(shortcuts[SHRT_SELECT_NONE].key, DrumCanvas::CMD_SELECT_NONE); + menuSelect->setAccel(shortcuts[SHRT_SELECT_INVERT].key, DrumCanvas::CMD_SELECT_INVERT); + menuSelect->setAccel(shortcuts[SHRT_SELECT_ILOOP].key, DrumCanvas::CMD_SELECT_ILOOP); + menuSelect->setAccel(shortcuts[SHRT_SELECT_OLOOP].key, DrumCanvas::CMD_SELECT_OLOOP); + + menuSelect->setAccel(shortcuts[SHRT_SELECT_PREV_PART].key, DrumCanvas::CMD_SELECT_PREV_PART); + menuSelect->setAccel(shortcuts[SHRT_SELECT_NEXT_PART].key, DrumCanvas::CMD_SELECT_NEXT_PART); + } + +//--------------------------------------------------------- +// execDeliveredScript +//--------------------------------------------------------- +void DrumEdit::execDeliveredScript(int id) +{ + //QString scriptfile = QString(INSTPREFIX) + SCRIPTSSUFFIX + deliveredScriptNames[id]; + QString scriptfile = song->getScriptPath(id, true); + song->executeScript(scriptfile.latin1(), parts(), quant(), true); +} + +//--------------------------------------------------------- +// execUserScript +//--------------------------------------------------------- +void DrumEdit::execUserScript(int id) +{ + QString scriptfile = song->getScriptPath(id, false); + song->executeScript(scriptfile.latin1(), parts(), quant(), true); +} + diff --git a/muse2/muse/midiedit/drumedit.h b/muse2/muse/midiedit/drumedit.h new file mode 100644 index 00000000..5043412f --- /dev/null +++ b/muse2/muse/midiedit/drumedit.h @@ -0,0 +1,151 @@ +//========================================================= +// MusE +// Linux Music Editor +// $Id: drumedit.h,v 1.9.2.7 2009/11/16 11:29:33 lunar_shuttle Exp $ +// (C) Copyright 1999 Werner Schweer (ws@seh.de) +//========================================================= + +#ifndef __DRUM_EDIT_H__ +#define __DRUM_EDIT_H__ + +#include <qwidget.h> +#include <q3mainwindow.h> +#include <qtooltip.h> +#include <q3whatsthis.h> +//Added by qt3to4: +#include <QResizeEvent> +#include <QLabel> +#include <QKeyEvent> +#include <Q3PopupMenu> +#include <QCloseEvent> + +#include <values.h> +#include "midieditor.h" +#include "noteinfo.h" +#include "cobject.h" +#include "tools.h" +#include "header.h" +#include "shortcuts.h" +#include "event.h" + +class MidiPart; +class QLabel; +class DrumCanvas; +class ScrollScale; +class ScoreConfig; +class QToolButton; +class MTScale; +class Splitter; +class PartList; +class Toolbar1; +class CtrlCanvas; +class Xml; +class Q3PopupMenu; +class DList; +class Header; +class CtrlEdit; +class Part; +class SNode; + +//--------------------------------------------------------- +// DWhatsThis +//--------------------------------------------------------- + +class DWhatsThis : public Q3WhatsThis { + Header* header; + protected: + QString text(const QPoint&); + public: + DWhatsThis(QWidget* parent, Header* h) : Q3WhatsThis(parent) { + header = h; + } + }; + +//---------------------------------------------------------- +// DHeaderTip +//---------------------------------------------------------- + +class DHeaderTip { // : public QToolTip { ddskrjo + public: + DHeaderTip(QWidget * parent) {} // : QToolTip(parent) {} ddskrjo + virtual ~DHeaderTip(){} + protected: + void maybeTip(const QPoint &); + }; + +//--------------------------------------------------------- +// DrumEdit +//--------------------------------------------------------- + +class DrumEdit : public MidiEditor { + Event selEvent; + MidiPart* selPart; + int selTick; + Q3PopupMenu* menuEdit, *menuFunctions, *menuFile, *menuSelect; + + NoteInfo* info; + QToolButton* srec; + QToolButton* midiin; + EditToolBar* tools2; + + Toolbar1* toolbar; + Splitter* split1; + Splitter* split2; + QWidget* split1w1; + DList* dlist; + Header* header; + Q3ToolBar* tools; + + static int _quantInit, _rasterInit; + static int _widthInit, _heightInit; + static int _dlistWidthInit, _dcanvasWidthInit; + + static int _toInit; //Used in function dialog for applying modification to selection + Q_OBJECT + void initShortcuts(); + + virtual void closeEvent(QCloseEvent*); + QWidget* genToolbar(QWidget* parent); + virtual void resizeEvent(QResizeEvent*); + virtual void keyPressEvent(QKeyEvent*); + int _to;//TODO: Make this work + + + private slots: + void setRaster(int); + void setQuant(int); + void noteinfoChanged(NoteInfo::ValType type, int val); + CtrlEdit* addCtrl(); + void removeCtrl(CtrlEdit* ctrl); + void cmd(int); + void clipboardChanged(); // enable/disable "Paste" + void selectionChanged(); // enable/disable "Copy" & "Paste" + void load(); + void save(); + void reset(); + void setTime(unsigned); + void follow(int); + void newCanvasWidth(int); + void configChanged(); + void songChanged1(int); + + public slots: + void setSelection(int, Event&, Part*); + void soloChanged(bool); // called by Solo button + void execDeliveredScript(int); + void execUserScript(int); + + virtual void updateHScrollRange(); + signals: + void deleted(unsigned long); + + public: + DrumEdit(PartList*, QWidget* parent = 0, const char* name = 0, unsigned initPos = MAXINT); + virtual ~DrumEdit(); + virtual void readStatus(Xml&); + virtual void writeStatus(int, Xml&) const; + static void readConfiguration(Xml& xml); + static void writeConfiguration(int, Xml&); + }; + +#endif diff --git a/muse2/muse/midiedit/drummap.cpp b/muse2/muse/midiedit/drummap.cpp new file mode 100644 index 00000000..46bf2057 --- /dev/null +++ b/muse2/muse/midiedit/drummap.cpp @@ -0,0 +1,503 @@ +//========================================================= +// MusE +// Linux Music Editor +// $Id: drummap.cpp,v 1.3.2.6 2009/10/29 02:14:37 terminator356 Exp $ +// +// (C) Copyright 1999/2000 Werner Schweer (ws@seh.de) +//========================================================= + +#include "audio.h" +#include "drummap.h" +#include "xml.h" +#include "song.h" + +char drumOutmap[DRUM_MAPSIZE]; +char drumInmap[128]; + +DrumMap drumMap[DRUM_MAPSIZE]; + +//--------------------------------------------------------- +// GM default drum map +//--------------------------------------------------------- + +const DrumMap blankdm = { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 127, 127, false }; + +const DrumMap idrumMap[DRUM_MAPSIZE] = { + { QString("Acoustic Bass Drum"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 35, 35, false }, + { QString("Bass Drum 1"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 36, 36, false }, + { QString("Side Stick"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 37, 37, false }, + { QString("Acoustic Snare"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 38, 38, false }, + { QString("Hand Clap"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 39, 39, false }, + { QString("Electric Snare"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 40, 40, false }, + { QString("Low Floor Tom"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 41, 41, false }, + { QString("Closed Hi-Hat"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 42, 42, false }, + { QString("High Floor Tom"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 43, 43, false }, + { QString("Pedal Hi-Hat"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 44, 44, false }, + { QString("Low Tom"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 45, 45, false }, + { QString("Open Hi-Hat"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 46, 46, false }, + { QString("Low-Mid Tom"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 47, 47, false }, + { QString("Hi-Mid Tom"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 48, 48, false }, + { QString("Crash Cymbal 1"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 49, 49, false }, + { QString("High Tom"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 50, 50, false }, + + { QString("Ride Cymbal 1"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 51, 51, false }, + { QString("Chinese Cymbal"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 52, 52, false }, + { QString("Ride Bell"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 53, 53, false }, + { QString("Tambourine"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 54, 54, false }, + { QString("Splash Cymbal"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 55, 55, false }, + { QString("Cowbell"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 56, 56, false }, + { QString("Crash Cymbal 2"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 57, 57, false }, + { QString("Vibraslap"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 58, 58, false }, + { QString("Ride Cymbal 2"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 59, 59, false }, + { QString("Hi Bongo"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 60, 60, false }, + { QString("Low Bongo"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 61, 61, false }, + { QString("Mute Hi Conga"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 62, 62, false }, + { QString("Open Hi Conga"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 63, 63, false }, + { QString("Low Conga"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 64, 64, false }, + { QString("High Timbale"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 65, 65, false }, + { QString("Low Timbale"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 66, 66, false }, + + { QString("High Agogo"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 67, 67, false }, + { QString("Low Agogo"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 68, 68, false }, + { QString("Cabasa"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 69, 69, false }, + { QString("Maracas"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 70, 70, false }, + { QString("Short Whistle"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 71, 71, false }, + { QString("Long Whistle"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 72, 72, false }, + { QString("Short Guiro"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 73, 73, false }, + { QString("Long Guiro"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 74, 74, false }, + { QString("Claves"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 75, 75, false }, + { QString("Hi Wood Block"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 76, 76, false }, + { QString("Low Wood Block"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 77, 77, false }, + { QString("Mute Cuica"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 78, 78, false }, + { QString("Open Cuica"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 79, 79, false }, + { QString("Mute Triangle"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 80, 80, false }, + { QString("Open Triangle"), 100, 16, 32, 9, 0, 70, 90, 127, 110, 81, 81, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 82, 82, false }, + + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 83, 83, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 84, 84, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 85, 85, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 86, 86, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 87, 87, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 88, 88, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 89, 89, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 90, 90, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 91, 91, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 92, 92, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 93, 93, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 94, 94, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 95, 95, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 96, 96, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 97, 97, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 98, 98, false }, + + /* + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 83, 83, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 84, 84, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 85, 85, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 86, 86, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 87, 87, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 88, 88, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 89, 89, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 90, 90, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 91, 91, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 92, 92, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 93, 93, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 94, 94, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 95, 95, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 96, 96, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 97, 97, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 98, 98, false }, + + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 83, 83, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 84, 84, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 85, 85, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 86, 86, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 87, 87, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 88, 88, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 89, 89, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 90, 90, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 91, 91, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 92, 92, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 93, 93, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 94, 94, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 95, 95, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 96, 96, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 97, 97, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 98, 98, false }, + + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 83, 83, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 84, 84, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 85, 85, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 86, 86, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 87, 87, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 88, 88, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 89, 89, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 90, 90, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 91, 91, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 92, 92, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 93, 93, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 94, 94, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 95, 95, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 96, 96, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 97, 97, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 98, 98, false }, + + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 83, 83, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 84, 84, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 85, 85, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 86, 86, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 87, 87, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 88, 88, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 89, 89, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 90, 90, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 91, 91, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 92, 92, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 93, 93, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 94, 94, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 95, 95, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 96, 96, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 97, 97, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 98, 98, false } + }; + */ + + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 99, 99, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 100, 100, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 101, 101, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 102, 102, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 103, 103, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 104, 104, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 105, 105, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 106, 106, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 107, 107, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 108, 108, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 109, 109, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 110, 110, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 111, 111, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 112, 112, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 113, 113, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 114, 114, false }, + + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 115, 115, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 116, 116, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 117, 117, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 118, 118, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 119, 119, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 120, 120, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 121, 121, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 122, 122, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 123, 123, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 124, 124, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 125, 125, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 126, 126, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 127, 127, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 0, 0, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 1, 1, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 2, 2, false }, + + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 3, 3, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 4, 4, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 5, 5, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 6, 6, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 7, 7, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 8, 8, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 9, 9, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 10, 10, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 11, 11, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 12, 12, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 13, 13, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 14, 14, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 15, 15, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 16, 16, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 17, 17, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 18, 18, false }, + + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 19, 19, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 20, 20, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 21, 21, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 22, 22, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 23, 23, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 24, 24, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 25, 25, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 26, 26, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 27, 27, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 28, 28, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 29, 29, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 30, 30, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 31, 31, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 32, 32, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 33, 33, false }, + { QString(""), 100, 16, 32, 9, 0, 70, 90, 127, 110, 34, 34, false } + }; + + +//--------------------------------------------------------- +// initDrumMap +// populate Inmap and Outmap +//--------------------------------------------------------- + +void initDrumMap() + { + for (int i = 0; i < DRUM_MAPSIZE; ++i) { + DrumMap d = drumMap[i]; + //Make sure we're not overwriting any values loaded + //On init, all these values are zero. If so, just set the drummap entry to the initial drummap entry. + if (!(d.vol || d.len || d.channel || d.port || d.lv1 || d.lv2 || d.lv3 || d.lv4 || d.enote || d.anote || d.mute)) + drumMap[i] = idrumMap[i]; + } + //Finally, setup the inMap, outMap-values + memset(drumInmap, 0, sizeof(drumInmap)); + memset(drumOutmap, 0, sizeof(drumOutmap)); + for (int i = 0; i < DRUM_MAPSIZE; ++i) { + drumInmap[(unsigned int)(drumMap[i].enote)] = i; + drumOutmap[(unsigned int)(drumMap[i].anote)] = i; + } + } + +//--------------------------------------------------------- +// resetGMDrumMap +//--------------------------------------------------------- + +void resetGMDrumMap() + { + audio->msgIdle(true); + // Delete all port controller events. + //audio->msgChangeAllPortDrumCtrlEvents(false); + song->changeAllPortDrumCtrlEvents(false); + + for(int i = 0; i < DRUM_MAPSIZE; ++i) + drumMap[i] = idrumMap[i]; + memset(drumInmap, 0, sizeof(drumInmap)); + memset(drumOutmap, 0, sizeof(drumOutmap)); + for (int i = 0; i < DRUM_MAPSIZE; ++i) { + drumInmap[(unsigned int)(drumMap[i].enote)] = i; + drumOutmap[(unsigned int)(drumMap[i].anote)] = i; + } + // Add all port controller events. + //audio->msgChangeAllPortDrumCtrlEvents(true); + song->changeAllPortDrumCtrlEvents(true); + audio->msgIdle(false); + } + +//--------------------------------------------------------- +// operator == +//--------------------------------------------------------- + +//bool const DrumMap::operator==(const DrumMap& map) const +bool DrumMap::operator==(const DrumMap& map) const + { + return + (name == map.name) + && vol == map.vol + && quant == map.quant + && len == map.len + && channel == map.channel + && port == map.port + && lv1 == map.lv1 + && lv2 == map.lv2 + && lv3 == map.lv3 + && lv4 == map.lv4 + && enote == map.enote + && anote == map.anote + && mute == map.mute; + } + +//--------------------------------------------------------- +// writeDrumMap +//--------------------------------------------------------- + +void writeDrumMap(int level, Xml& xml, bool external) + { + xml.tag(level++, "drummap"); + for (int i = 0; i < DRUM_MAPSIZE; ++i) { + DrumMap* dm = &drumMap[i]; + const DrumMap* idm = &idrumMap[i]; + + if (external) { + xml.tag(level++, "entry"); + xml.strTag(level, "name", dm->name); + xml.intTag(level, "vol", dm->vol); + xml.intTag(level, "quant", dm->quant); + xml.intTag(level, "len", dm->len); + xml.intTag(level, "channel", dm->channel); + xml.intTag(level, "port", dm->port); + xml.intTag(level, "lv1", dm->lv1); + xml.intTag(level, "lv2", dm->lv2); + xml.intTag(level, "lv3", dm->lv3); + xml.intTag(level, "lv4", dm->lv4); + xml.intTag(level, "enote", dm->enote); + xml.intTag(level, "anote", dm->anote); + } + else { + // write only, if entry is different from initial entry + if (!external && *dm == *idm) + continue; + xml.tag(level++, "entry idx=\"%d\"", i); + if (dm->name != idm->name) + xml.strTag(level, "name", dm->name); + if (dm->vol != idm->vol) + xml.intTag(level, "vol", dm->vol); + if (dm->quant != idm->quant) + xml.intTag(level, "quant", dm->quant); + if (dm->len != idm->len) + xml.intTag(level, "len", dm->len); + if (dm->channel != idm->channel) + xml.intTag(level, "channel", dm->channel); + if (dm->port != idm->port) + xml.intTag(level, "port", dm->port); + if (dm->lv1 != idm->lv1) + xml.intTag(level, "lv1", dm->lv1); + if (dm->lv2 != idm->lv2) + xml.intTag(level, "lv2", dm->lv2); + if (dm->lv3 != idm->lv3) + xml.intTag(level, "lv3", dm->lv3); + if (dm->lv4 != idm->lv4) + xml.intTag(level, "lv4", dm->lv4); + if (dm->enote != idm->enote) + xml.intTag(level, "enote", dm->enote); + if (dm->anote != idm->anote) + xml.intTag(level, "anote", dm->anote); + if (dm->mute != idm->mute) + xml.intTag(level, "mute", dm->mute); + } + xml.tag(level--, "/entry"); + } + xml.tag(level--, "/drummap"); + } + +//--------------------------------------------------------- +// readDrummapEntry +//--------------------------------------------------------- + +static void readDrummapEntry(Xml& xml, DrumMap* dm) + { + + for (;;) { + Xml::Token token = xml.parse(); + const QString& tag = xml.s1(); + switch (token) { + case Xml::Error: + case Xml::End: + return; + case Xml::TagStart: + if (tag == "name") + dm->name = xml.parse(QString("name")); + else if (tag == "vol") + dm->vol = (unsigned char)xml.parseInt(); + else if (tag == "quant") + dm->quant = xml.parseInt(); + else if (tag == "len") + dm->len = xml.parseInt(); + else if (tag == "channel") + dm->channel = xml.parseInt(); + else if (tag == "port") + dm->port = xml.parseInt(); + else if (tag == "lv1") + dm->lv1 = xml.parseInt(); + else if (tag == "lv2") + dm->lv2 = xml.parseInt(); + else if (tag == "lv3") + dm->lv3 = xml.parseInt(); + else if (tag == "lv4") + dm->lv4 = xml.parseInt(); + else if (tag == "enote") + dm->enote = xml.parseInt(); + else if (tag == "anote") + dm->anote = xml.parseInt(); + else if (tag == "mute") + dm->mute = xml.parseInt(); + else if (tag == "selected") + //; // dm->selected = xml.parseInt(); + xml.skip(tag); + else + xml.unknown("DrumMapEntry"); + break; + case Xml::Attribut: + if (tag == "idx") { + int idx = xml.s2().toInt() & 0x7f; + dm = &drumMap[idx]; + + } + break; + case Xml::TagEnd: + if (tag == "entry") + { + return; + } + default: + break; + } + } + } + +//--------------------------------------------------------- +// readDrummap +//--------------------------------------------------------- + +void readDrumMap(Xml& xml, bool external) + { + audio->msgIdle(true); + // Delete all port controller events. + //audio->msgChangeAllPortDrumCtrlEvents(false); + song->changeAllPortDrumCtrlEvents(false); + + if (external) { + for (int i = 0; i < DRUM_MAPSIZE; ++i) + drumMap[i] = blankdm; + } + else { + for (int i = 0; i < DRUM_MAPSIZE; ++i) + drumMap[i] = idrumMap[i]; + } + int i = 0; + for (;;) { + Xml::Token token = xml.parse(); + const QString& tag = xml.s1(); + switch (token) { + case Xml::Error: + case Xml::End: + audio->msgIdle(false); + return; + case Xml::TagStart: + if (tag == "entry") { + if(i >= DRUM_MAPSIZE) + { + audio->msgIdle(false); + return; + } + readDrummapEntry(xml, external ? &drumMap[i] : 0); + ++i; + } + else if (tag == "comment") + xml.parse(); + else + xml.unknown("DrumMap"); + break; + case Xml::Attribut: + break; + case Xml::TagEnd: + if (tag == "drummap") { + memset(drumInmap, 0, sizeof(drumInmap)); + memset(drumOutmap, 0, sizeof(drumOutmap)); + for (int i = 0; i < DRUM_MAPSIZE; ++i) { + drumInmap[(unsigned int)(drumMap[i].enote)] = i; + drumOutmap[(unsigned int)(drumMap[i].anote)] = i; + } + // Add all port controller events. + //audio->msgChangeAllPortDrumCtrlEvents(true); + song->changeAllPortDrumCtrlEvents(true); + + audio->msgIdle(false); + return; + } + default: + break; + } + } + // Add all port controller events. + //audio->msgChangeAllPortDrumCtrlEvents(true); + song->changeAllPortDrumCtrlEvents(true); + audio->msgIdle(false); + } + diff --git a/muse2/muse/midiedit/drummap.h b/muse2/muse/midiedit/drummap.h new file mode 100644 index 00000000..dfe67254 --- /dev/null +++ b/muse2/muse/midiedit/drummap.h @@ -0,0 +1,47 @@ +//========================================================= +// MusE +// Linux Music Editor +// $Id: drummap.h,v 1.3.2.3 2009/10/29 02:14:37 terminator356 Exp $ +// +// (C) Copyright 1999/2000 Werner Schweer (ws@seh.de) +//========================================================= + +#ifndef __DRUMMAP_H__ +#define __DRUMMAP_H__ + +#include <qstring.h> + +class Xml; + +//--------------------------------------------------------- +// DrumMap +//--------------------------------------------------------- + +struct DrumMap { + QString name; + unsigned char vol; // playback volume, percent. + int quant; + int len; // len of event in ticks + int channel; // midi channel + int port; // midi port + char lv1, lv2, lv3, lv4; // velocities + char enote, anote; // input note - output note + bool mute; +// bool selected; + + //bool const operator==(const DrumMap& map) const; + bool operator==(const DrumMap& map) const; + }; + +#define DRUM_MAPSIZE 128 + +extern char drumOutmap[DRUM_MAPSIZE]; +extern char drumInmap[DRUM_MAPSIZE]; +extern DrumMap drumMap[DRUM_MAPSIZE]; +extern void initDrumMap(); +extern void writeDrumMap(int level, Xml& xml, bool external); +extern void readDrumMap(Xml& xml, bool external); +extern void resetGMDrumMap(); + +#endif + diff --git a/muse2/muse/midiedit/ecanvas.cpp b/muse2/muse/midiedit/ecanvas.cpp new file mode 100644 index 00000000..7fc7002d --- /dev/null +++ b/muse2/muse/midiedit/ecanvas.cpp @@ -0,0 +1,363 @@ +//========================================================= +// MusE +// Linux Music Editor +// $Id: ecanvas.cpp,v 1.8.2.6 2009/05/03 04:14:00 terminator356 Exp $ +// (C) Copyright 2001 Werner Schweer (ws@seh.de) +//========================================================= + +#include <values.h> + +#include "midieditor.h" +#include "ecanvas.h" +#include "song.h" +#include "event.h" +#include "shortcuts.h" +//Added by qt3to4: +#include <QKeyEvent> +#include <QEvent> + +//--------------------------------------------------------- +// EventCanvas +//--------------------------------------------------------- + +EventCanvas::EventCanvas(MidiEditor* pr, QWidget* parent, int sx, + int sy, const char* name) + : Canvas(parent, sx, sy, name) + { + editor = pr; + _steprec = false; + _midiin = false; + _playEvents = false; + curVelo = 70; + + setBg(Qt::white); + setAcceptDrops(true); + setFocusPolicy(Qt::StrongFocus); + setMouseTracking(true); + + curPart = (MidiPart*)(editor->parts()->begin()->second); + curPartId = curPart->sn(); + } + +//--------------------------------------------------------- +// getCaption +//--------------------------------------------------------- + +QString EventCanvas::getCaption() const + { + int bar1, bar2, xx; + unsigned x; + sigmap.tickValues(curPart->tick(), &bar1, &xx, &x); + sigmap.tickValues(curPart->tick() + curPart->lenTick(), &bar2, &xx, &x); + + return QString("MusE: Part <") + curPart->name() + + QString("> %1-%2").arg(bar1+1).arg(bar2+1); + } + +//--------------------------------------------------------- +// leaveEvent +//--------------------------------------------------------- + +void EventCanvas::leaveEvent(QEvent*) + { + emit pitchChanged(-1); + emit timeChanged(MAXINT); + } + +//--------------------------------------------------------- +// enterEvent +//--------------------------------------------------------- + +void EventCanvas::enterEvent(QEvent*) + { + emit enterCanvas(); + } + +//--------------------------------------------------------- +// raster +//--------------------------------------------------------- + +QPoint EventCanvas::raster(const QPoint& p) const + { + int x = p.x(); + if (x < 0) + x = 0; + x = editor->rasterVal(x); + int pitch = y2pitch(p.y()); + int y = pitch2y(pitch); + return QPoint(x, y); + } + +//--------------------------------------------------------- +// startUndo +//--------------------------------------------------------- + +void EventCanvas::startUndo(DragType) + { + song->startUndo(); + } + +//--------------------------------------------------------- +// endUndo +//--------------------------------------------------------- + +void EventCanvas::endUndo(DragType dtype, int flags) + { + song->endUndo(flags | ((dtype == MOVE_COPY || dtype == MOVE_CLONE) + ? SC_EVENT_INSERTED : SC_EVENT_MODIFIED)); + } + +//--------------------------------------------------------- +// mouseMove +//--------------------------------------------------------- + +void EventCanvas::mouseMove(const QPoint& pos) + { + emit pitchChanged(y2pitch(pos.y())); + int x = pos.x(); + emit timeChanged(editor->rasterVal(x)); + } + +//--------------------------------------------------------- +// updateSelection +//--------------------------------------------------------- + +void EventCanvas::updateSelection() + { + song->update(SC_SELECTION); + } + +//--------------------------------------------------------- +// songChanged(type) +//--------------------------------------------------------- + +void EventCanvas::songChanged(int flags) + { + // Is it simply a midi controller value adjustment? Forget it. + if(flags == SC_MIDI_CONTROLLER) + return; + + if (flags & ~SC_SELECTION) { + items.clear(); + start_tick = MAXINT; + end_tick = 0; + curPart = 0; + for (iPart p = editor->parts()->begin(); p != editor->parts()->end(); ++p) { + MidiPart* part = (MidiPart*)(p->second); + if (part->sn() == curPartId) + curPart = part; + unsigned stick = part->tick(); + unsigned len = part->lenTick(); + unsigned etick = stick + len; + if (stick < start_tick) + start_tick = stick; + if (etick > end_tick) + end_tick = etick; + + EventList* el = part->events(); + for (iEvent i = el->begin(); i != el->end(); ++i) { + Event e = i->second; + // Added by T356. Do not add events which are either past, or extend past the end of the part. + //if(e.tick() > len) + if(e.endTick() > len) + break; + + if (e.isNote()) { + addItem(part, e); + } + } + } + } + + Event event; + MidiPart* part = 0; + int x = 0; + CItem* nevent = 0; + + int n = 0; // count selections + for (iCItem k = items.begin(); k != items.end(); ++k) { + Event ev = k->second->event(); + bool selected = ev.selected(); + if (selected) { + k->second->setSelected(true); + ++n; + if (!nevent) { + nevent = k->second; + Event mi = nevent->event(); + curVelo = mi.velo(); + } + } + } + start_tick = song->roundDownBar(start_tick); + end_tick = song->roundUpBar(end_tick); + + if (n == 1) { + x = nevent->x(); + event = nevent->event(); + part = (MidiPart*)nevent->part(); + if (curPart != part) { + curPart = part; + curPartId = curPart->sn(); + curPartChanged(); + } + } + emit selectionChanged(x, event, part); + if (curPart == 0) + curPart = (MidiPart*)(editor->parts()->begin()->second); + redraw(); + } + +//--------------------------------------------------------- +// selectAtTick +//--------------------------------------------------------- +void EventCanvas::selectAtTick(unsigned int tick) + { + //Select note nearest tick, if none selected and there are any + if (!items.empty() && selectionSize() == 0) { + iCItem i = items.begin(); + CItem* nearest = i->second; + + while (i != items.end()) { + CItem* cur=i->second; + unsigned int curtk=abs(cur->x() + cur->part()->tick() - tick); + unsigned int neartk=abs(nearest->x() + nearest->part()->tick() - tick); + + if (curtk < neartk) { + nearest=cur; + } + + i++; + } + + if (!nearest->isSelected()) { + selectItem(nearest, true); + songChanged(SC_SELECTION); + } + } + } + +//--------------------------------------------------------- +// track +//--------------------------------------------------------- + +MidiTrack* EventCanvas::track() const + { + return ((MidiPart*)curPart)->track(); + } + + +//--------------------------------------------------------- +// keyPress +//--------------------------------------------------------- + +void EventCanvas::keyPress(QKeyEvent* event) + { + int key = event->key(); + if (event->state() & Qt::ShiftButton) + key += Qt::SHIFT; + if (event->state() & Qt::AltButton) + key += Qt::ALT; + if (event->state() & Qt::ControlButton) + key+= Qt::CTRL; + + // + // Shortcut for DrumEditor & PianoRoll + // Sets locators to selected events + // + if (key == shortcuts[SHRT_LOCATORS_TO_SELECTION].key) { + int tick_max = 0; + int tick_min = INT_MAX; + bool found = false; + + for (iCItem i= items.begin(); i != items.end(); i++) { + if (!i->second->isSelected()) + continue; + + int tick = i->second->x(); + int len = i->second->event().lenTick(); + found = true; + if (tick + len > tick_max) + tick_max = tick + len; + if (tick < tick_min) + tick_min = tick; + } + if (found) { + Pos p1(tick_min, true); + Pos p2(tick_max, true); + song->setPos(1, p1); + song->setPos(2, p2); + } + } + // Select items by key (PianoRoll & DrumEditor) + else if (key == shortcuts[SHRT_SEL_RIGHT].key || key == shortcuts[SHRT_SEL_RIGHT_ADD].key) { + iCItem i, iRightmost; + CItem* rightmost = NULL; + //Get the rightmost selected note (if any) + for (i = items.begin(); i != items.end(); ++i) { + if (i->second->isSelected()) { + iRightmost = i; rightmost = i->second; + } + } + if (rightmost) { + iCItem temp = iRightmost; temp++; + //If so, deselect current note and select the one to the right + if (temp != items.end()) { + if (key != shortcuts[SHRT_SEL_RIGHT_ADD].key) + deselectAll(); + + iRightmost++; + iRightmost->second->setSelected(true); + updateSelection(); + } + } + } + //Select items by key: (PianoRoll & DrumEditor) + else if (key == shortcuts[SHRT_SEL_LEFT].key || key == shortcuts[SHRT_SEL_LEFT_ADD].key) { + iCItem i, iLeftmost; + CItem* leftmost = NULL; + if (items.size() > 0 ) { + for (i = items.end(), i--; i != items.begin(); i--) { + if (i->second->isSelected()) { + iLeftmost = i; leftmost = i->second; + } + } + if (leftmost) { + if (iLeftmost != items.begin()) { + //Add item + if (key != shortcuts[SHRT_SEL_LEFT_ADD].key) + deselectAll(); + + iLeftmost--; + iLeftmost->second->setSelected(true); + updateSelection(); + } + } + } + } + else if (key == shortcuts[SHRT_INC_PITCH].key) { + modifySelected(NoteInfo::VAL_PITCH, 1); + } + else if (key == shortcuts[SHRT_DEC_PITCH].key) { + modifySelected(NoteInfo::VAL_PITCH, -1); + } + else if (key == shortcuts[SHRT_INC_POS].key) { + // TODO: Check boundaries + modifySelected(NoteInfo::VAL_TIME, editor->raster()); + } + else if (key == shortcuts[SHRT_DEC_POS].key) { + // TODO: Check boundaries + modifySelected(NoteInfo::VAL_TIME, 0 - editor->raster()); + } + + else if (key == shortcuts[SHRT_INCREASE_LEN].key) { + // TODO: Check boundaries + modifySelected(NoteInfo::VAL_LEN, editor->raster()); + } + else if (key == shortcuts[SHRT_DECREASE_LEN].key) { + // TODO: Check boundaries + modifySelected(NoteInfo::VAL_LEN, 0 - editor->raster()); + } + + else + event->ignore(); + } diff --git a/muse2/muse/midiedit/ecanvas.h b/muse2/muse/midiedit/ecanvas.h new file mode 100644 index 00000000..58df80b5 --- /dev/null +++ b/muse2/muse/midiedit/ecanvas.h @@ -0,0 +1,87 @@ +//========================================================= +// MusE +// Linux Music Editor +// $Id: ecanvas.h,v 1.5.2.4 2009/02/02 21:38:00 terminator356 Exp $ +// (C) Copyright 2001 Werner Schweer (ws@seh.de) +//========================================================= + +#ifndef __ECANVAS_H__ +#define __ECANVAS_H__ + +#include "canvas.h" +#include "noteinfo.h" +//Added by qt3to4: +#include <QEvent> +#include <QKeyEvent> + +class MidiPart; +class MidiTrack; +class MidiEditor; +class Part; + +struct PartToChange +{ + Part* npart; + int xdiff; +}; +typedef std::map<Part*, PartToChange> PartsToChangeMap; +typedef std::map<Part*, PartToChange>::iterator iPartToChange; + +//--------------------------------------------------------- +// EventCanvas +//--------------------------------------------------------- + +class EventCanvas : public Canvas { + Q_OBJECT + virtual void leaveEvent(QEvent*e); + virtual void enterEvent(QEvent*e); + // Removed by T356. + //virtual QPoint raster(const QPoint&) const; + + virtual void startUndo(DragType); + + virtual void endUndo(DragType, int flags = 0); + virtual void mouseMove(const QPoint&); + + protected: + bool _playEvents; + MidiEditor* editor; + unsigned start_tick, end_tick; + int curVelo; + bool _steprec; + bool _midiin; + + void updateSelection(); + virtual void addItem(Part*, Event&) = 0; + // Added by T356. + virtual QPoint raster(const QPoint&) const; + + public slots: + void redrawGrid() { redraw(); } + void setSteprec(bool f) { _steprec = f; } + void setMidiin(bool f) { _midiin = f; } + + signals: + void pitchChanged(int); // current cursor position + void timeChanged(unsigned); + void selectionChanged(int, Event&, Part*); + void enterCanvas(); + + public: + EventCanvas(MidiEditor*, QWidget*, int, int, const char* name = 0); + MidiTrack* track() const; + unsigned start() const { return start_tick; } + unsigned end() const { return end_tick; } + bool midiin() const { return _midiin; } + bool steprec() const { return _steprec; } + QString getCaption() const; + void songChanged(int); + void range(int* s, int* e) const { *s = start_tick; *e = end_tick; } + void playEvents(bool flag) { _playEvents = flag; } + void selectAtTick(unsigned int tick); + virtual void modifySelected(NoteInfo::ValType, int) {} + virtual void keyPress(QKeyEvent*); + }; + +#endif + diff --git a/muse2/muse/midiedit/piano.cpp b/muse2/muse/midiedit/piano.cpp new file mode 100644 index 00000000..ed7ac9f5 --- /dev/null +++ b/muse2/muse/midiedit/piano.cpp @@ -0,0 +1,557 @@ +//========================================================= +// MusE +// Linux Music Editor +// $Id: piano.cpp,v 1.3 2004/05/31 11:48:55 lunar_shuttle Exp $ +// (C) Copyright 1999 Werner Schweer (ws@seh.de) +//========================================================= + +#include <qpainter.h> +//Added by qt3to4: +#include <QPixmap> +#include <QEvent> +#include <QMouseEvent> + +#include <stdio.h> + +#include "piano.h" + +static const char *oct_xpm[] = { +// w h colors + "40 91 2 1", + ". c #c0c0c0", + "# c #000000", + // x + "####################################### ", + ".......................................#", + ".......................................#", + ".......................................#", + ".......................................#", + ".......................................#", // 10 + ".......................................#", + ".......................................#", + ".......................................#", + ".......................................#", //------------------------ + "#######################................#", + "########################...............#", + "########################...............#", + "####################################### ", // 7 + "########################...............#", + "########################...............#", + "#######################................#", //------------------------ + ".......................................#", + ".......................................#", + ".......................................#", // 6 + ".......................................#", + ".......................................#", + ".......................................#", //------------------------ + "#######################................#", + "########################...............#", + "########################...............#", // 7 + "####################################### ", + "########################...............#", + "########################...............#", + "#######################................#", //------------------------ + ".......................................#", + ".......................................#", + ".......................................#", // 6 + ".......................................#", + ".......................................#", + ".......................................#", //------------------------ + "#######################................#", + "########################...............#", + "########################...............#", // 7 + "####################################### ", + "########################...............#", + "########################...............#", + "#######################................#", //------------------------ + ".......................................#", + ".......................................#", + ".......................................#", + ".......................................#", // 10 + ".......................................#", + ".......................................#", + ".......................................#", + ".......................................#", + ".......................................#", + "####################################### ", //---------------------- + ".......................................#", + ".......................................#", + ".......................................#", + ".......................................#", // 9 + ".......................................#", + ".......................................#", + ".......................................#", + ".......................................#", + ".......................................#", //------------------------ + "#######################................#", + "########################...............#", + "########################...............#", + "####################################### ", // 7 + "########################...............#", + "########################...............#", + "#######################................#", //------------------------ + ".......................................#", + ".......................................#", + ".......................................#", // 6 + ".......................................#", + ".......................................#", + ".......................................#", //-------------------------- + "#######################................#", + "########################...............#", + "########################...............#", // 7 + "####################################### ", + "########################...............#", + "########################...............#", + "#######################................#", //------------------------ + ".......................................#", + "..........................###..........#", + ".........................#...#.........#", + ".........................#.............#", + ".........................#.............#", + ".........................#...#.........#", // 10 + "..........................###..........#", + ".......................................#", + ".......................................#", + ".......................................#", + }; + +static const char *mk1_xpmC1[] = { + "40 10 2 1", + ". c #c0c0c0", + "# c #000000", + ".......................................#", + "..........................###.....#....#", + ".........................#...#...##....#", + ".........................#........#....#", + ".........................#........#....#", + ".........................#...#....#....#", // 10 + "..........................###....###...#", + ".......................................#", + ".......................................#", + ".......................................#", + }; +static const char *mk1_xpmC2[] = { + "40 10 2 1", + ". c #c0c0c0", + "# c #000000", + ".......................................#", + "..........................###....##....#", + ".........................#...#..#..#...#", + ".........................#........#....#", + ".........................#.......#.....#", + ".........................#...#..#......#", // 10 + "..........................###...####...#", + ".......................................#", + ".......................................#", + ".......................................#", + }; +static const char *mk1_xpmC3[] = { + "40 10 2 1", + ". c #c0c0c0", + "# c #000000", + ".......................................#", + "..........................###....##....#", + ".........................#...#..#..#...#", + ".........................#........#....#", + ".........................#.........#...#", + ".........................#...#..#..#...#", // 10 + "..........................###....##....#", + ".......................................#", + ".......................................#", + ".......................................#", + }; +static const char *mk1_xpmC4[] = { + "40 10 2 1", + ". c #c0c0c0", + "# c #000000", + ".......................................#", + "..........................###...#..#...#", + ".........................#...#..#..#...#", + ".........................#......####...#", + ".........................#.........#...#", + ".........................#...#.....#...#", // 10 + "..........................###......#...#", + ".......................................#", + ".......................................#", + ".......................................#", + }; +static const char *mk1_xpmC5[] = { + "40 10 2 1", + ". c #c0c0c0", + "# c #000000", + ".......................................#", + "..........................###...####...#", + ".........................#...#..#......#", + ".........................#......###....#", + ".........................#.........#...#", + ".........................#...#.....#...#", // 10 + "..........................###...###....#", + ".......................................#", + ".......................................#", + ".......................................#", + }; + +static const char *mk1_xpmC6[] = { + "40 10 2 1", + ". c #c0c0c0", + "# c #000000", + ".......................................#", + "..........................###....###...#", + ".........................#...#..#......#", + ".........................#......###....#", + ".........................#......#..#...#", + ".........................#...#..#..#...#", // 10 + "..........................###...###....#", + ".......................................#", + ".......................................#", + ".......................................#", + }; + +static const char *mk1_xpmC7[] = { + "40 10 2 1", + ". c #c0c0c0", + "# c #000000", + ".......................................#", + "..........................###...####...#", + ".........................#...#.....#...#", + ".........................#........#....#", + ".........................#.......#.....#", + ".........................#...#..#......#", // 10 + "..........................###...#......#", + ".......................................#", + ".......................................#", + ".......................................#", + }; +static const char *mk1_xpmC8[] = { + "40 10 2 1", + ". c #c0c0c0", + "# c #000000", + ".......................................#", + "..........................###....##....#", + ".........................#...#..#..#....#", + ".........................#.......##....#", + ".........................#......#..#...#", + ".........................#...#..#..#...#", // 10 + "..........................###....##....#", + ".......................................#", + ".......................................#", + ".......................................#", + }; + +static const char *mk1_xpm[] = { + "40 13 2 1", + ". c #ff0000", + "# c none", + ".......................................#", + ".......................................#", + ".......................................#", + ".......................................#", + ".......................................#", + ".......................................#", + ".......................................#", + ".......................................#", + ".......................................#", + "#######################................#", + "########################...............#", + "########################...............#", + "####################################### ", + }; + +static const char *mk2_xpm[] = { + "40 13 2 1", + ". c #ff0000", + "# c none", + "########################...............#", + "########################...............#", + "#######################................#", //------------------------ + ".......................................#", + ".......................................#", + ".......................................#", // 6 + ".......................................#", + ".......................................#", + ".......................................#", //-------------------------- + "#######################................#", + "########################...............#", + "########################...............#", // 7 + "####################################### ", + }; + +static const char *mk3_xpm[] = { + "40 13 2 1", + ". c #ff0000", + "# c none", + "########################...............#", + "########################...............#", + "#######################................#", + ".......................................#", + ".......................................#", + ".......................................#", + ".......................................#", + ".......................................#", + ".......................................#", + ".......................................#", + ".......................................#", + ".......................................#", + "########################################", + }; + +static const char *mk4_xpm[] = { + "40 13 2 1", + "# c #ff0000", + ". c none", + "........................................", + "........................................", + "........................................", + "#######################.................", + "########################................", + "########################................", + "########################................", + "########################................", + "########################................", + "#######################.................", + "........................................", + "........................................", + "........................................", + }; +/* + 0 1 2 3 4 5 6 7 8 9 10 + c-2 c-1 C0 C1 C2 C3 C4 C5 C6 C7 C8 - G8 + + Grid über Oktave: + + +------------+ ------------------------------ + 11 | | + | h | 7 + +------+ | + 10 | a# +-----+ .............................. + +------+ a | + 9 | | 6 + +------+ | + 8 | g# +-----+ .............................. + +------+ g | + 7 | | 5 + +------+ | + 6 | f# +-----+ .............................. + +------+ f | + 5 | | 4 + | | + +------------+ ------------------------------ + 4 | | + | e | 3 + +------+ | + 3 | d# +-----+ .............................. + +------+ d | + 2 | | 2 + +------+ | + 1 | c# +-----+ .............................. + +------+ c | + | | 1 + 0 | | + +------------+ ------------------------------ + */ + +//--------------------------------------------------------- +// Piano +//--------------------------------------------------------- + +Piano::Piano(QWidget* parent, int ymag) + : View(parent, 1, ymag) + { + setMouseTracking(true); + curPitch = -1; + octave = new QPixmap(oct_xpm); + c_keys[0] = new QPixmap(mk1_xpmC8); + c_keys[1] = new QPixmap(mk1_xpmC7); + c_keys[2] = new QPixmap(mk1_xpmC6); + c_keys[3] = new QPixmap(mk1_xpmC5); + c_keys[4] = new QPixmap(mk1_xpmC4); + c_keys[5] = new QPixmap(mk1_xpmC3); + c_keys[6] = new QPixmap(mk1_xpmC2); + c_keys[7] = new QPixmap(mk1_xpmC1); + + mk1 = new QPixmap(mk1_xpm); + mk2 = new QPixmap(mk2_xpm); + mk3 = new QPixmap(mk3_xpm); + mk4 = new QPixmap(mk4_xpm); + keyDown = -1; + button = Qt::NoButton; + } + +//--------------------------------------------------------- +// draw +//--------------------------------------------------------- + +void Piano::draw(QPainter& p, const QRect& r) + { + QPoint offset(0, KH*2); + p.drawTiledPixmap(r, *octave, r.topLeft()+offset); + + // draw C notes + for (int drawKey = 0; drawKey < 8;drawKey++) { + int octaveSize=91; + + int drawY = octaveSize * drawKey + 81 - KH*2; + if (drawY > r.y() && drawY < r.y() + r.height()) { + //printf("drawing c %d at %d r.y %d r.x %d\n",drawKey, drawY, r.y(), r.x()); + p.drawPixmap(0,drawY,*c_keys[drawKey]); + } + } + //p.drawTiledPixmap(r, *c1, r.topLeft()+offset + coffset); + //printf("drawText KH %d %d, x %d y %d\n",KH, curPitch, r.x(), r.y()); + //p.drawText(r,Qt::AlignAuto,"A"); + if (curPitch == -1) + return; + int y = pitch2y(curPitch); + QPixmap* pm; + switch(curPitch % 12) { + case 0: + case 5: + pm = mk3; + break; + case 2: + case 7: + case 9: + pm = mk2; + break; + case 4: + case 11: + pm = mk1; + break; + default: + pm = mk4; + break; + } + p.drawPixmap(0, y, *pm); + } + +//--------------------------------------------------------- +// pitch2y +//--------------------------------------------------------- + +int Piano::pitch2y(int pitch) const + { + int tt[] = { + 12, 19, 25, 32, 38, 51, 58, 64, 71, 77, 84, 90 + }; + int y = (75 * KH) - (tt[pitch%12] + (7 * KH) * (pitch/12)); + if (y < 0) + y = 0; + return y; + } + +//--------------------------------------------------------- +// y2pitch +//--------------------------------------------------------- + +int Piano::y2pitch(int y) const + { + const int total = (10 * 7 + 5) * KH; // 75 Ganztonschritte + y = total - y; + int oct = (y / (7 * KH)) * 12; + char kt[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, + 7, 7, 7, 7, 7, 7, + 8, 8, 8, 8, 8, 8, 8, + 9, 9, 9, 9, 9, 9, + 10, 10, 10, 10, 10, 10, 10, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11 + }; + return kt[y % 91] + oct; + } + +//--------------------------------------------------------- +// leaveEvent +//--------------------------------------------------------- + +void Piano::leaveEvent(QEvent*) + { + if (keyDown != -1) { + emit keyReleased(keyDown, shift); + keyDown = -1; + } + emit pitchChanged(-1); + setPitch(-1); + } + +//--------------------------------------------------------- +// setPitch +//--------------------------------------------------------- + +void Piano::setPitch(int pitch) + { + if (curPitch == pitch) + return; + curPitch = pitch; + redraw(); + } + +//--------------------------------------------------------- +// viewMouseMoveEvent +//--------------------------------------------------------- + +void Piano::viewMouseMoveEvent(QMouseEvent* event) + { + int pitch = y2pitch(event->y()); + emit pitchChanged(pitch); + setPitch(pitch); + + if (button != Qt::NoButton) { + int nk = y2pitch(event->y()); + if (nk < 0 || nk > 127) + nk = -1; + if (nk != keyDown) { + if (keyDown != -1) { + emit keyReleased(keyDown, shift); + } + keyDown = nk; + if (keyDown != -1) { + int velocity = event->x()*127/40; + //emit keyPressed(keyDown, shift); + emit keyPressed(keyDown, velocity>127 ? 127 : velocity, shift); + } + } + } + } + +//--------------------------------------------------------- +// viewMousePressEvent +//--------------------------------------------------------- + +void Piano::viewMousePressEvent(QMouseEvent* event) + { + button = event->button(); + shift = event->state() & Qt::ShiftButton; + if (keyDown != -1) { + emit keyReleased(keyDown, shift); + keyDown = -1; + } + keyDown = y2pitch(event->y()); + if (keyDown < 0 || keyDown > 127) { + keyDown = -1; + } + else { + int velocity = event->x()*127/40; + emit keyPressed(keyDown, velocity>127 ? 127 : velocity, shift); //emit keyPressed(keyDown, shift); + } + } + +//--------------------------------------------------------- +// viewMouseReleaseEvent +//--------------------------------------------------------- + +void Piano::viewMouseReleaseEvent(QMouseEvent* event) + { + button = Qt::NoButton; + shift = event->state() & Qt::ShiftButton; + if (keyDown != -1) { + emit keyReleased(keyDown, shift); + keyDown = -1; + } + } + diff --git a/muse2/muse/midiedit/piano.h b/muse2/muse/midiedit/piano.h new file mode 100644 index 00000000..2f06b810 --- /dev/null +++ b/muse2/muse/midiedit/piano.h @@ -0,0 +1,63 @@ +//========================================================= +// MusE +// Linux Music Editor +// $Id: piano.h,v 1.2 2004/05/31 11:48:55 lunar_shuttle Exp $ +// (C) Copyright 1999 Werner Schweer (ws@seh.de) +//========================================================= + +#ifndef __PIANO_H__ +#define __PIANO_H__ + +#include "view.h" +//Added by qt3to4: +#include <QMouseEvent> +#include <QEvent> +#include <QPixmap> + +class QPainter; + +#define KH 13 + +//--------------------------------------------------------- +// Piano +//--------------------------------------------------------- + +class Piano : public View + { + int curPitch; + QPixmap* octave; + QPixmap* c_keys[10]; + QPixmap* mk1; + QPixmap* mk2; + QPixmap* mk3; + QPixmap* mk4; + int keyDown; + bool shift; + int button; + + Q_OBJECT + int y2pitch(int) const; + int pitch2y(int) const; + void viewMouseMoveEvent(QMouseEvent* event); + virtual void leaveEvent(QEvent*e); + + virtual void viewMousePressEvent(QMouseEvent* event); + virtual void viewMouseReleaseEvent(QMouseEvent*); + + protected: + virtual void draw(QPainter&, const QRect&); + + signals: + void pitchChanged(int); + void keyPressed(int, int, bool); + void keyReleased(int, bool); + + public slots: + void setPitch(int); + + public: + Piano(QWidget*, int); + }; + +#endif + diff --git a/muse2/muse/midiedit/pianoroll.cpp b/muse2/muse/midiedit/pianoroll.cpp new file mode 100644 index 00000000..93bf615c --- /dev/null +++ b/muse2/muse/midiedit/pianoroll.cpp @@ -0,0 +1,1107 @@ +//========================================================= +// MusE +// Linux Music Editor +// $Id: pianoroll.cpp,v 1.25.2.15 2009/11/16 11:29:33 lunar_shuttle Exp $ +// (C) Copyright 1999 Werner Schweer (ws@seh.de) +//========================================================= + +#include <q3accel.h> +#include <qlayout.h> +#include <q3hbox.h> +#include <qsizegrip.h> +#include <qlabel.h> +#include <qpushbutton.h> +#include <q3buttongroup.h> +#include <qtoolbutton.h> +#include <qtooltip.h> +#include <q3popupmenu.h> +#include <qmenubar.h> +#include <qapplication.h> +#include <qclipboard.h> +#include <qdir.h> +#include <qaction.h> +//Added by qt3to4: +#include <QKeyEvent> +#include <Q3GridLayout> +#include <QResizeEvent> +#include <QCloseEvent> + +#include <stdio.h> + +#include "xml.h" +#include "mtscale.h" +#include "prcanvas.h" +#include "pianoroll.h" +#include "scrollscale.h" +#include "piano.h" +#include "../ctrl/ctrledit.h" +#include "splitter.h" +#include "ttoolbar.h" +#include "tb1.h" +#include "utils.h" +#include "globals.h" +#include "gconfig.h" +#include "icons.h" +#include "audio.h" + +#include "cmd.h" +#include "quantconfig.h" +#include "shortcuts.h" + +int PianoRoll::_quantInit = 96; +int PianoRoll::_rasterInit = 96; +int PianoRoll::_widthInit = 600; +int PianoRoll::_heightInit = 400; +int PianoRoll::_quantStrengthInit = 80; // 1 - 100% +int PianoRoll::_quantLimitInit = 50; // tick value +bool PianoRoll::_quantLenInit = false; +int PianoRoll::_toInit = 0; +int PianoRoll::colorModeInit = 0; + +static const int xscale = -10; +static const int yscale = 1; +static const int pianoWidth = 40; +static int pianorollTools = PointerTool | PencilTool | RubberTool | DrawTool; + + + + +//--------------------------------------------------------- +// PianoRoll +//--------------------------------------------------------- + +PianoRoll::PianoRoll(PartList* pl, QWidget* parent, const char* name, unsigned initPos) + : MidiEditor(_quantInit, _rasterInit, pl, parent, name) + { + deltaMode = false; + resize(_widthInit, _heightInit); + selPart = 0; + quantConfig = 0; + _playEvents = false; + _quantStrength = _quantStrengthInit; + _quantLimit = _quantLimitInit; + _quantLen = _quantLenInit; + _to = _toInit; + colorMode = colorModeInit; + //---------Men---------------------------------- + menuEdit = new Q3PopupMenu(this); + menuBar()->insertItem(tr("&Edit"), menuEdit); + undoRedo->addTo(menuEdit); + Q3Accel* ud = new Q3Accel(this); + ud->connectItem(ud->insertItem(Qt::CTRL+Qt::Key_Z), song, SLOT(undo())); + Q3Accel* rd = new Q3Accel(this); + rd->connectItem(rd->insertItem(Qt::CTRL+Qt::Key_Y), song, SLOT(redo())); + + menuEdit->insertSeparator(); + menuEdit->insertItem(tr("Cut"), PianoCanvas::CMD_CUT); + menuEdit->setAccel(Qt::CTRL+Qt::Key_X, PianoCanvas::CMD_CUT); + menuEdit->insertItem(tr("Copy"), PianoCanvas::CMD_COPY); + menuEdit->setAccel(Qt::CTRL+Qt::Key_C, PianoCanvas::CMD_COPY); + menuEdit->insertItem(tr("Paste"), PianoCanvas::CMD_PASTE); + menuEdit->setAccel(Qt::CTRL+Qt::Key_V, PianoCanvas::CMD_PASTE); + menuEdit->insertSeparator(); + menuEdit->insertItem(tr("Delete Events"), PianoCanvas::CMD_DEL); + menuEdit->setAccel(Qt::Key_Delete, PianoCanvas::CMD_DEL); + menuEdit->insertSeparator(); + + menuSelect = new Q3PopupMenu(this); + menuSelect->insertItem(tr("Select All"), PianoCanvas::CMD_SELECT_ALL); + menuSelect->insertItem(tr("Select None"), PianoCanvas::CMD_SELECT_NONE); + menuSelect->insertItem(tr("Invert"), PianoCanvas::CMD_SELECT_INVERT); + + menuSelect->insertSeparator(); + menuSelect->insertItem(tr("Inside Loop"), PianoCanvas::CMD_SELECT_ILOOP); + + menuSelect->insertItem(tr("Outside Loop"), PianoCanvas::CMD_SELECT_OLOOP); + + menuSelect->insertSeparator(); + + menuSelect->insertItem(tr("Previous Part"), PianoCanvas::CMD_SELECT_PREV_PART); + menuSelect->insertItem(tr("Next Part"), PianoCanvas::CMD_SELECT_NEXT_PART); + + menuEdit->insertItem(tr("&Select"), menuSelect); + + eventColor = new Q3PopupMenu(this); + eventColor->insertItem(tr("blue"), 0); + eventColor->insertItem(tr("pitch colors"), 1); + eventColor->insertItem(tr("velocity colors"), 2); + connect(eventColor, SIGNAL(activated(int)), SLOT(setEventColorMode(int))); + + menuConfig = new Q3PopupMenu(this); + menuBar()->insertItem(tr("&Config"), menuConfig); + menu_ids[CMD_EVENT_COLOR] = menuConfig->insertItem(tr("event color"), eventColor, 0); + + menuFunctions = new Q3PopupMenu(this); + menuBar()->insertItem(tr("&Functions"), menuFunctions); + menuFunctions->insertTearOffHandle(); + menuFunctions->insertItem(tr("Over Quantize"), PianoCanvas::CMD_OVER_QUANTIZE); + + menuFunctions->insertItem(tr("Note On Quantize"), PianoCanvas::CMD_ON_QUANTIZE); + + menuFunctions->insertItem(tr("Note On/Off Quantize"), PianoCanvas::CMD_ONOFF_QUANTIZE); + menuFunctions->insertItem(tr("Iterative Quantize"), PianoCanvas::CMD_ITERATIVE_QUANTIZE); + + menuFunctions->insertSeparator(); + menu_ids[CMD_CONFIG_QUANT] = menuFunctions->insertItem(tr("Config Quant..."), this, SLOT(configQuant()), 0); + menuFunctions->insertSeparator(); + menuFunctions->insertItem(tr("Modify Gate Time"), PianoCanvas::CMD_MODIFY_GATE_TIME); + menuFunctions->insertItem(tr("Modify Velocity"), PianoCanvas::CMD_MODIFY_VELOCITY); + menuFunctions->insertItem(tr("Crescendo"), PianoCanvas::CMD_CRESCENDO); + menuFunctions->insertItem(tr("Transpose"), PianoCanvas::CMD_TRANSPOSE); + menuFunctions->insertItem(tr("Thin Out"), PianoCanvas::CMD_THIN_OUT); + menuFunctions->insertItem(tr("Erase Event"), PianoCanvas::CMD_ERASE_EVENT); + menuFunctions->insertItem(tr("Note Shift"), PianoCanvas::CMD_NOTE_SHIFT); + menuFunctions->insertItem(tr("Move Clock"), PianoCanvas::CMD_MOVE_CLOCK); + menuFunctions->insertItem(tr("Copy Measure"), PianoCanvas::CMD_COPY_MEASURE); + menuFunctions->insertItem(tr("Erase Measure"), PianoCanvas::CMD_ERASE_MEASURE); + menuFunctions->insertItem(tr("Delete Measure"), PianoCanvas::CMD_DELETE_MEASURE); + menuFunctions->insertItem(tr("Create Measure"), PianoCanvas::CMD_CREATE_MEASURE); + menuFunctions->insertItem(tr("Set fixed length"), PianoCanvas::CMD_FIXED_LEN); + menuFunctions->insertItem(tr("Delete overlaps"), PianoCanvas::CMD_DELETE_OVERLAPS); + + menuFunctions->setItemEnabled(PianoCanvas::CMD_CRESCENDO, false); + menuFunctions->setItemEnabled(PianoCanvas::CMD_TRANSPOSE, false); + menuFunctions->setItemEnabled(PianoCanvas::CMD_THIN_OUT, false); + menuFunctions->setItemEnabled(PianoCanvas::CMD_ERASE_EVENT, false); + menuFunctions->setItemEnabled(PianoCanvas::CMD_NOTE_SHIFT, false); + menuFunctions->setItemEnabled(PianoCanvas::CMD_MOVE_CLOCK, false); + menuFunctions->setItemEnabled(PianoCanvas::CMD_COPY_MEASURE, false); + menuFunctions->setItemEnabled(PianoCanvas::CMD_ERASE_MEASURE, false); + menuFunctions->setItemEnabled(PianoCanvas::CMD_DELETE_MEASURE, false); + menuFunctions->setItemEnabled(PianoCanvas::CMD_CREATE_MEASURE, false); + + menuPlugins = new Q3PopupMenu(this); + song->populateScriptMenu(menuPlugins, this); + menuBar()->insertItem(tr("&Plugins"), menuPlugins); + connect(menuEdit, SIGNAL(activated(int)), SLOT(cmd(int))); + connect(menuSelect, SIGNAL(activated(int)), SLOT(cmd(int))); + connect(menuFunctions, SIGNAL(activated(int)), SLOT(cmd(int))); + + //---------ToolBar---------------------------------- + tools = new Q3ToolBar(this, "pianoroll-tools"); + tools->setLabel(tr("Pianoroll Tools")); + undoRedo->addTo(tools); + tools->addSeparator(); + + srec = new QToolButton(tools, "srec"); + QToolTip::add(srec, tr("Step Record")); + srec->setPixmap(*steprecIcon); + srec->setToggleButton(true); + + midiin = new QToolButton(tools, "midiin"); + QToolTip::add(midiin, tr("Midi Input")); + midiin->setPixmap(*midiinIcon); + midiin->setToggleButton(true); + + speaker = new QToolButton(tools, "speaker"); + QToolTip::add(speaker, tr("Play Events")); + speaker->setPixmap(*speakerIcon); + speaker->setToggleButton(true); + + tools2 = new EditToolBar(this, pianorollTools); + + Q3ToolBar* panicToolbar = new Q3ToolBar(this); + panicAction->addTo(panicToolbar); + + //------------------------------------------------------------- + // Transport Bar + Q3ToolBar* transport = new Q3ToolBar(this); + transportAction->addTo(transport); + + toolbar = new Toolbar1(this, _rasterInit, _quantInit); + info = new NoteInfo(this); + + //--------------------------------------------------- + // split + //--------------------------------------------------- + + splitter = new Splitter(Qt::Vertical, mainw, "splitter"); + QPushButton* ctrl = new QPushButton(tr("ctrl"), mainw, "Ctrl"); + ctrl->setFont(config.fonts[3]); + QToolTip::add(ctrl, tr("Add Controller View")); + hscroll = new ScrollScale(-25, -2, xscale, 20000, Qt::Horizontal, mainw); + ctrl->setFixedSize(pianoWidth, hscroll->sizeHint().height()); + + QSizeGrip* corner = new QSizeGrip(mainw); + + mainGrid->setRowStretch(0, 100); + mainGrid->setColStretch(1, 100); + mainGrid->addMultiCellWidget(splitter, 0, 0, 0, 2); + mainGrid->addWidget(ctrl, 1, 0); + mainGrid->addWidget(hscroll, 1, 1); + mainGrid->addWidget(corner, 1, 2, Qt::AlignBottom|Qt::AlignRight); + mainGrid->addRowSpacing(1, hscroll->sizeHint().height()); + + QWidget* split1 = new QWidget(splitter, "split1"); + Q3GridLayout* gridS1 = new Q3GridLayout(split1); + time = new MTScale(&_raster, split1, xscale); + Piano* piano = new Piano(split1, yscale); + canvas = new PianoCanvas(this, split1, xscale, yscale); + vscroll = new ScrollScale(-3, 7, yscale, KH * 75, Qt::Vertical, split1); + + int offset = -(config.division/4); + canvas->setOrigin(offset, 0); + canvas->setCanvasTools(pianorollTools); + canvas->setFocus(); + connect(canvas, SIGNAL(toolChanged(int)), tools2, SLOT(set(int))); + time->setOrigin(offset, 0); + + gridS1->setRowStretch(2, 100); + gridS1->setColStretch(1, 100); + + gridS1->addMultiCellWidget(time, 0, 0, 1, 2); + gridS1->addMultiCellWidget(hLine(split1), 1, 1, 0, 2); + gridS1->addWidget(piano, 2, 0); + gridS1->addWidget(canvas, 2, 1); + + gridS1->addWidget(vscroll, 2, 2); +// gridS1->addWidget(time, 0, 1); +// gridS1->addWidget(hLine(split1), 1, 1); +// gridS1->addWidget(piano, 2, 0); +// gridS1->addWidget(canvas, 2, 1); +// gridS1->addMultiCellWidget(vscroll, 1, 2, 2, 2); + + piano->setFixedWidth(pianoWidth); + + connect(tools2, SIGNAL(toolChanged(int)), canvas, SLOT(setTool(int))); + + connect(ctrl, SIGNAL(clicked()), SLOT(addCtrl())); + connect(info, SIGNAL(valueChanged(NoteInfo::ValType, int)), SLOT(noteinfoChanged(NoteInfo::ValType, int))); + connect(vscroll, SIGNAL(scrollChanged(int)), piano, SLOT(setYPos(int))); + connect(vscroll, SIGNAL(scrollChanged(int)), canvas, SLOT(setYPos(int))); + connect(vscroll, SIGNAL(scaleChanged(int)), canvas, SLOT(setYMag(int))); + connect(vscroll, SIGNAL(scaleChanged(int)), piano, SLOT(setYMag(int))); + + connect(hscroll, SIGNAL(scrollChanged(int)), canvas, SLOT(setXPos(int))); + connect(hscroll, SIGNAL(scrollChanged(int)), time, SLOT(setXPos(int))); + + connect(hscroll, SIGNAL(scaleChanged(int)), canvas, SLOT(setXMag(int))); + connect(hscroll, SIGNAL(scaleChanged(int)), time, SLOT(setXMag(int))); + + connect(canvas, SIGNAL(pitchChanged(int)), piano, SLOT(setPitch(int))); + connect(canvas, SIGNAL(verticalScroll(unsigned)), vscroll, SLOT(setPos(unsigned))); + connect(canvas, SIGNAL(horizontalScroll(unsigned)),hscroll, SLOT(setPos(unsigned))); + connect(canvas, SIGNAL(horizontalScrollNoLimit(unsigned)),hscroll, SLOT(setPosNoLimit(unsigned))); + connect(canvas, SIGNAL(selectionChanged(int, Event&, Part*)), this, + SLOT(setSelection(int, Event&, Part*))); + + connect(piano, SIGNAL(keyPressed(int, int, bool)), canvas, SLOT(pianoPressed(int, int, bool))); + connect(piano, SIGNAL(keyReleased(int, bool)), canvas, SLOT(pianoReleased(int, bool))); + connect(srec, SIGNAL(toggled(bool)), SLOT(setSteprec(bool))); + connect(midiin, SIGNAL(toggled(bool)), canvas, SLOT(setMidiin(bool))); + connect(speaker, SIGNAL(toggled(bool)), SLOT(setSpeaker(bool))); + connect(canvas, SIGNAL(followEvent(int)), SLOT(follow(int))); + + connect(hscroll, SIGNAL(scaleChanged(int)), SLOT(updateHScrollRange())); + piano->setYPos(KH * 30); + canvas->setYPos(KH * 30); + vscroll->setPos(KH * 30); + //setSelection(0, 0, 0); //Really necessary? Causes segfault when only 1 item selected, replaced by the following: + info->setEnabled(false); + + connect(song, SIGNAL(songChanged(int)), SLOT(songChanged1(int))); + + setCaption(canvas->getCaption()); + + updateHScrollRange(); + // connect to toolbar + connect(canvas, SIGNAL(pitchChanged(int)), toolbar, SLOT(setPitch(int))); + connect(canvas, SIGNAL(timeChanged(unsigned)), SLOT(setTime(unsigned))); + connect(piano, SIGNAL(pitchChanged(int)), toolbar, SLOT(setPitch(int))); + connect(time, SIGNAL(timeChanged(unsigned)), SLOT(setTime(unsigned))); + connect(toolbar, SIGNAL(quantChanged(int)), SLOT(setQuant(int))); + connect(toolbar, SIGNAL(rasterChanged(int)),SLOT(setRaster(int))); + connect(toolbar, SIGNAL(toChanged(int)), SLOT(setTo(int))); + connect(toolbar, SIGNAL(soloChanged(bool)), SLOT(soloChanged(bool))); + + setFocusPolicy(Qt::StrongFocus); + setEventColorMode(colorMode); + + QClipboard* cb = QApplication::clipboard(); + connect(cb, SIGNAL(dataChanged()), SLOT(clipboardChanged())); + + clipboardChanged(); // enable/disable "Paste" + selectionChanged(); // enable/disable "Copy" & "Paste" + initShortcuts(); // initialize shortcuts + + const Pos cpos=song->cPos(); + canvas->setPos(0, cpos.tick(), true); + canvas->selectAtTick(cpos.tick()); + //canvas->selectFirst(); +// + if(canvas->track()) + toolbar->setSolo(canvas->track()->solo()); + + unsigned pos; + if(initPos >= MAXINT) + pos = song->cpos(); + else + pos = initPos; + if(pos > MAXINT) + pos = MAXINT; + hscroll->setOffset((int)pos); + } + +//--------------------------------------------------------- +// songChanged1 +//--------------------------------------------------------- + +void PianoRoll::songChanged1(int bits) + { + + if (bits & SC_SOLO) + { + toolbar->setSolo(canvas->track()->solo()); + return; + } + songChanged(bits); + } + +//--------------------------------------------------------- +// configChanged +//--------------------------------------------------------- + +void PianoRoll::configChanged() + { + initShortcuts(); + } + +//--------------------------------------------------------- +// updateHScrollRange +//--------------------------------------------------------- + +void PianoRoll::updateHScrollRange() +{ + int s, e; + canvas->range(&s, &e); + // Show one more measure. + e += sigmap.ticksMeasure(e); + // Show another quarter measure due to imprecise drawing at canvas end point. + e += sigmap.ticksMeasure(e) / 4; + // Compensate for the fixed piano and vscroll widths. + e += canvas->rmapxDev(pianoWidth - vscroll->width()); + int s1, e1; + hscroll->range(&s1, &e1); + if(s != s1 || e != e1) + hscroll->setRange(s, e); +} + +//--------------------------------------------------------- +// follow +//--------------------------------------------------------- + +void PianoRoll::follow(int pos) + { + int s, e; + canvas->range(&s, &e); + + if (pos < e && pos >= s) + hscroll->setOffset(pos); + if (pos < s) + hscroll->setOffset(s); + } + +//--------------------------------------------------------- +// setTime +//--------------------------------------------------------- + +void PianoRoll::setTime(unsigned tick) + { + toolbar->setTime(tick); + time->setPos(3, tick, false); + } + +//--------------------------------------------------------- +// ~Pianoroll +//--------------------------------------------------------- + +PianoRoll::~PianoRoll() + { + undoRedo->removeFrom(tools); + } + +//--------------------------------------------------------- +// cmd +// pulldown menu commands +//--------------------------------------------------------- + +void PianoRoll::cmd(int cmd) + { + ((PianoCanvas*)canvas)->cmd(cmd, _quantStrength, _quantLimit, _quantLen, _to); + } + +//--------------------------------------------------------- +// setSelection +// update Info Line +//--------------------------------------------------------- + +void PianoRoll::setSelection(int tick, Event& e, Part* p) + { + int selections = canvas->selectionSize(); + + selEvent = e; + selPart = (MidiPart*)p; + selTick = tick; + + if (selections > 1) { + info->setEnabled(true); + info->setDeltaMode(true); + if (!deltaMode) { + deltaMode = true; + info->setValues(0, 0, 0, 0, 0); + tickOffset = 0; + lenOffset = 0; + pitchOffset = 0; + veloOnOffset = 0; + veloOffOffset = 0; + } + } + else if (selections == 1) { + deltaMode = false; + info->setEnabled(true); + info->setDeltaMode(false); + info->setValues(tick, + selEvent.lenTick(), + selEvent.pitch(), + selEvent.velo(), + selEvent.veloOff()); + } + else { + deltaMode = false; + info->setEnabled(false); + } + selectionChanged(); + } + +//--------------------------------------------------------- +// edit currently selected Event +//--------------------------------------------------------- + +void PianoRoll::noteinfoChanged(NoteInfo::ValType type, int val) + { + int selections = canvas->selectionSize(); + + if (selections == 0) { + printf("noteinfoChanged while nothing selected\n"); + } + else if (selections == 1) { + Event event = selEvent.clone(); + switch(type) { + case NoteInfo::VAL_TIME: + event.setTick(val - selPart->tick()); + break; + case NoteInfo::VAL_LEN: + event.setLenTick(val); + break; + case NoteInfo::VAL_VELON: + event.setVelo(val); + break; + case NoteInfo::VAL_VELOFF: + event.setVeloOff(val); + break; + case NoteInfo::VAL_PITCH: + event.setPitch(val); + break; + } + // Indicate do undo, and do not do port controller values and clone parts. + //audio->msgChangeEvent(selEvent, event, selPart); + audio->msgChangeEvent(selEvent, event, selPart, true, false, false); + } + else { + // multiple events are selected; treat noteinfo values + // as offsets to event values + + int delta = 0; + switch (type) { + case NoteInfo::VAL_TIME: + delta = val - tickOffset; + tickOffset = val; + break; + case NoteInfo::VAL_LEN: + delta = val - lenOffset; + lenOffset = val; + break; + case NoteInfo::VAL_VELON: + delta = val - veloOnOffset; + veloOnOffset = val; + break; + case NoteInfo::VAL_VELOFF: + delta = val - veloOffOffset; + veloOffOffset = val; + break; + case NoteInfo::VAL_PITCH: + delta = val - pitchOffset; + pitchOffset = val; + break; + } + if (delta) + canvas->modifySelected(type, delta); + } + } + +//--------------------------------------------------------- +// addCtrl +//--------------------------------------------------------- + +CtrlEdit* PianoRoll::addCtrl() + { + CtrlEdit* ctrlEdit = new CtrlEdit(splitter, this, xscale, false, "pianoCtrlEdit"); + connect(tools2, SIGNAL(toolChanged(int)), ctrlEdit, SLOT(setTool(int))); + connect(hscroll, SIGNAL(scrollChanged(int)), ctrlEdit, SLOT(setXPos(int))); + connect(hscroll, SIGNAL(scaleChanged(int)), ctrlEdit, SLOT(setXMag(int))); + connect(ctrlEdit, SIGNAL(timeChanged(unsigned)), SLOT(setTime(unsigned))); + connect(ctrlEdit, SIGNAL(destroyedCtrl(CtrlEdit*)), SLOT(removeCtrl(CtrlEdit*))); + connect(ctrlEdit, SIGNAL(yposChanged(int)), toolbar, SLOT(setInt(int))); + + ctrlEdit->setTool(tools2->curTool()); + ctrlEdit->setXPos(hscroll->pos()); + ctrlEdit->setXMag(hscroll->getScaleValue()); + + ctrlEdit->show(); + ctrlEditList.push_back(ctrlEdit); + return ctrlEdit; + } + +//--------------------------------------------------------- +// removeCtrl +//--------------------------------------------------------- + +void PianoRoll::removeCtrl(CtrlEdit* ctrl) + { + for (std::list<CtrlEdit*>::iterator i = ctrlEditList.begin(); + i != ctrlEditList.end(); ++i) { + if (*i == ctrl) { + ctrlEditList.erase(i); + break; + } + } + } + +//--------------------------------------------------------- +// closeEvent +//--------------------------------------------------------- + +void PianoRoll::closeEvent(QCloseEvent* e) + { + emit deleted((unsigned long)this); + e->accept(); + } + +//--------------------------------------------------------- +// readConfiguration +//--------------------------------------------------------- + +void PianoRoll::readConfiguration(Xml& xml) + { + for (;;) { + Xml::Token token = xml.parse(); + if (token == Xml::Error || token == Xml::End) + break; + const QString& tag = xml.s1(); + switch (token) { + case Xml::TagStart: + if (tag == "quant") + _quantInit = xml.parseInt(); + else if (tag == "raster") + _rasterInit = xml.parseInt(); + else if (tag == "quantStrength") + _quantStrengthInit = xml.parseInt(); + else if (tag == "quantLimit") + _quantLimitInit = xml.parseInt(); + else if (tag == "quantLen") + _quantLenInit = xml.parseInt(); + else if (tag == "to") + _toInit = xml.parseInt(); + else if (tag == "colormode") + colorModeInit = xml.parseInt(); + else if (tag == "width") + _widthInit = xml.parseInt(); + else if (tag == "height") + _heightInit = xml.parseInt(); + else + xml.unknown("PianoRoll"); + break; + case Xml::TagEnd: + if (tag == "pianoroll") + return; + default: + break; + } + } + } + +//--------------------------------------------------------- +// writeConfiguration +//--------------------------------------------------------- + +void PianoRoll::writeConfiguration(int level, Xml& xml) + { + xml.tag(level++, "pianoroll"); + xml.intTag(level, "quant", _quantInit); + xml.intTag(level, "raster", _rasterInit); + xml.intTag(level, "quantStrength", _quantStrengthInit); + xml.intTag(level, "quantLimit", _quantLimitInit); + xml.intTag(level, "quantLen", _quantLenInit); + xml.intTag(level, "to", _toInit); + xml.intTag(level, "width", _widthInit); + xml.intTag(level, "height", _heightInit); + xml.intTag(level, "colormode", colorModeInit); + xml.etag(level, "pianoroll"); + } + +//--------------------------------------------------------- +// soloChanged +// signal from solo button +//--------------------------------------------------------- + +void PianoRoll::soloChanged(bool flag) + { + audio->msgSetSolo(canvas->track(), flag); + song->update(SC_SOLO); + } + +//--------------------------------------------------------- +// setRaster +//--------------------------------------------------------- + +void PianoRoll::setRaster(int val) + { + _rasterInit = val; + MidiEditor::setRaster(val); + canvas->redrawGrid(); + canvas->setFocus(); // give back focus after kb input + } + +//--------------------------------------------------------- +// setQuant +//--------------------------------------------------------- + +void PianoRoll::setQuant(int val) + { + _quantInit = val; + MidiEditor::setQuant(val); + canvas->setFocus(); + } + +//--------------------------------------------------------- +// writeStatus +//--------------------------------------------------------- + +void PianoRoll::writeStatus(int level, Xml& xml) const + { + writePartList(level, xml); + xml.tag(level++, "pianoroll"); + MidiEditor::writeStatus(level, xml); + splitter->writeStatus(level, xml); + + for (std::list<CtrlEdit*>::const_iterator i = ctrlEditList.begin(); + i != ctrlEditList.end(); ++i) { + (*i)->writeStatus(level, xml); + } + + xml.intTag(level, "steprec", canvas->steprec()); + xml.intTag(level, "midiin", canvas->midiin()); + xml.intTag(level, "tool", int(canvas->tool())); + xml.intTag(level, "quantStrength", _quantStrength); + xml.intTag(level, "quantLimit", _quantLimit); + xml.intTag(level, "quantLen", _quantLen); + xml.intTag(level, "playEvents", _playEvents); + xml.intTag(level, "xpos", hscroll->pos()); + xml.intTag(level, "xmag", hscroll->mag()); + xml.intTag(level, "ypos", vscroll->pos()); + xml.intTag(level, "ymag", vscroll->mag()); + xml.tag(level, "/pianoroll"); + } + +//--------------------------------------------------------- +// readStatus +//--------------------------------------------------------- + +void PianoRoll::readStatus(Xml& xml) + { + for (;;) { + Xml::Token token = xml.parse(); + if (token == Xml::Error || token == Xml::End) + break; + const QString& tag = xml.s1(); + switch (token) { + case Xml::TagStart: + if (tag == "steprec") { + int val = xml.parseInt(); + canvas->setSteprec(val); + srec->setOn(val); + } + else if (tag == "midiin") { + int val = xml.parseInt(); + canvas->setMidiin(val); + midiin->setOn(val); + } + else if (tag == "tool") { + int tool = xml.parseInt(); + canvas->setTool(tool); + tools2->set(tool); + } + else if (tag == "midieditor") + MidiEditor::readStatus(xml); + else if (tag == "ctrledit") { + CtrlEdit* ctrl = addCtrl(); + ctrl->readStatus(xml); + } + else if (tag == splitter->name()) + splitter->readStatus(xml); + else if (tag == "quantStrength") + _quantStrength = xml.parseInt(); + else if (tag == "quantLimit") + _quantLimit = xml.parseInt(); + else if (tag == "quantLen") + _quantLen = xml.parseInt(); + else if (tag == "playEvents") { + _playEvents = xml.parseInt(); + canvas->playEvents(_playEvents); + speaker->setOn(_playEvents); + } + else if (tag == "xmag") + hscroll->setMag(xml.parseInt()); + else if (tag == "xpos") + hscroll->setPos(xml.parseInt()); + else if (tag == "ymag") + vscroll->setMag(xml.parseInt()); + else if (tag == "ypos") + vscroll->setPos(xml.parseInt()); + else + xml.unknown("PianoRoll"); + break; + case Xml::TagEnd: + if (tag == "pianoroll") { + _quantInit = _quant; + _rasterInit = _raster; + toolbar->setRaster(_raster); + toolbar->setQuant(_quant); + canvas->redrawGrid(); + return; + } + default: + break; + } + } + } + +static int rasterTable[] = { + //-9----8- 7 6 5 4 3(1/4) 2 1 + 4, 8, 16, 32, 64, 128, 256, 512, 1024, // triple + 6, 12, 24, 48, 96, 192, 384, 768, 1536, + 9, 18, 36, 72, 144, 288, 576, 1152, 2304 // dot + }; + +//--------------------------------------------------------- +// viewKeyPressEvent +//--------------------------------------------------------- + +void PianoRoll::keyPressEvent(QKeyEvent* event) + { + if (info->hasFocus()) { + event->ignore(); + return; + } + + int index; + int n = sizeof(rasterTable)/sizeof(*rasterTable); + for (index = 0; index < n; ++index) + if (rasterTable[index] == raster()) + break; + if (index == n) { + index = 0; + // raster 1 is not in table + } + int off = (index / 9) * 9; + index = index % 9; + + int val = 0; + + PianoCanvas* pc = (PianoCanvas*)canvas; + int key = event->key(); + + if (event->state() & Qt::ShiftButton) + key += Qt::SHIFT; + if (event->state() & Qt::AltButton) + key += Qt::ALT; + if (event->state() & Qt::ControlButton) + key+= Qt::CTRL; + + if (key == Qt::Key_Escape) { + close(); + return; + } + else if (key == shortcuts[SHRT_TOOL_POINTER].key) { + tools2->set(PointerTool); + return; + } + else if (key == shortcuts[SHRT_TOOL_PENCIL].key) { + tools2->set(PencilTool); + return; + } + else if (key == shortcuts[SHRT_TOOL_RUBBER].key) { + tools2->set(RubberTool); + return; + } + else if (key == shortcuts[SHRT_TOOL_LINEDRAW].key) { + tools2->set(DrawTool); + return; + } + else if (key == shortcuts[SHRT_POS_INC].key) { + pc->pianoCmd(CMD_RIGHT); + return; + } + else if (key == shortcuts[SHRT_POS_DEC].key) { + pc->pianoCmd(CMD_LEFT); + return; + } + else if (key == shortcuts[SHRT_INSERT_AT_LOCATION].key) { + pc->pianoCmd(CMD_INSERT); + return; + } + else if (key == Qt::Key_Delete) { + pc->pianoCmd(CMD_DELETE); + return; + } + else if (key == shortcuts[SHRT_ZOOM_IN].key) { + int mag = hscroll->mag(); + int zoomlvl = ScrollScale::getQuickZoomLevel(mag); + if (zoomlvl < 23) + zoomlvl++; + + int newmag = ScrollScale::convertQuickZoomLevelToMag(zoomlvl); + hscroll->setMag(newmag); + //printf("mag = %d zoomlvl = %d newmag = %d\n", mag, zoomlvl, newmag); + return; + } + else if (key == shortcuts[SHRT_ZOOM_OUT].key) { + int mag = hscroll->mag(); + int zoomlvl = ScrollScale::getQuickZoomLevel(mag); + if (zoomlvl > 1) + zoomlvl--; + + int newmag = ScrollScale::convertQuickZoomLevelToMag(zoomlvl); + hscroll->setMag(newmag); + //printf("mag = %d zoomlvl = %d newmag = %d\n", mag, zoomlvl, newmag); + return; + } + else if (key == shortcuts[SHRT_GOTO_CPOS].key) { + PartList* p = this->parts(); + Part* first = p->begin()->second; + hscroll->setPos(song->cpos() - first->tick() ); + return; + } + else if (key == shortcuts[SHRT_SCROLL_LEFT].key) { + int pos = hscroll->pos() - config.division; + if (pos < 0) + pos = 0; + hscroll->setPos(pos); + return; + } + else if (key == shortcuts[SHRT_SCROLL_RIGHT].key) { + int pos = hscroll->pos() + config.division; + hscroll->setPos(pos); + return; + } + else if (key == shortcuts[SHRT_SET_QUANT_1].key) + val = rasterTable[8 + off]; + else if (key == shortcuts[SHRT_SET_QUANT_2].key) + val = rasterTable[7 + off]; + else if (key == shortcuts[SHRT_SET_QUANT_3].key) + val = rasterTable[6 + off]; + else if (key == shortcuts[SHRT_SET_QUANT_4].key) + val = rasterTable[5 + off]; + else if (key == shortcuts[SHRT_SET_QUANT_5].key) + val = rasterTable[4 + off]; + else if (key == shortcuts[SHRT_SET_QUANT_6].key) + val = rasterTable[3 + off]; + else if (key == shortcuts[SHRT_SET_QUANT_7].key) + val = rasterTable[2 + off]; + else if (key == shortcuts[SHRT_TOGGLE_TRIOL].key) + val = rasterTable[index + ((off == 0) ? 9 : 0)]; + else if (key == shortcuts[SHRT_EVENT_COLOR].key) { + if (colorMode == 0) + colorMode = 1; + else if (colorMode == 1) + colorMode = 2; + else + colorMode = 0; + setEventColorMode(colorMode); + return; + } + else if (key == shortcuts[SHRT_TOGGLE_PUNCT].key) + val = rasterTable[index + ((off == 18) ? 9 : 18)]; + + else if (key == shortcuts[SHRT_TOGGLE_PUNCT2].key) {//CDW + if ((off == 18) && (index > 2)) { + val = rasterTable[index + 9 - 1]; + } + else if ((off == 9) && (index < 8)) { + val = rasterTable[index + 18 + 1]; + } + else + return; + } + else { //Default: + event->ignore(); + return; + } + setQuant(val); + setRaster(val); + toolbar->setQuant(_quant); + toolbar->setRaster(_raster); + } + +//--------------------------------------------------------- +// configQuant +//--------------------------------------------------------- + +void PianoRoll::configQuant() + { + if (!quantConfig) { + quantConfig = new QuantConfig(_quantStrength, _quantLimit, _quantLen); + connect(quantConfig, SIGNAL(setQuantStrength(int)), SLOT(setQuantStrength(int))); + connect(quantConfig, SIGNAL(setQuantLimit(int)), SLOT(setQuantLimit(int))); + connect(quantConfig, SIGNAL(setQuantLen(bool)), SLOT(setQuantLen(bool))); + } + quantConfig->show(); + } + +//--------------------------------------------------------- +// setSteprec +//--------------------------------------------------------- + +void PianoRoll::setSteprec(bool flag) + { + canvas->setSteprec(flag); + if (flag == false) + midiin->setOn(flag); + } + +//--------------------------------------------------------- +// setEventColorMode +//--------------------------------------------------------- + +void PianoRoll::setEventColorMode(int mode) + { + colorMode = mode; + colorModeInit = colorMode; + eventColor->setItemChecked(0, mode == 0); + eventColor->setItemChecked(1, mode == 1); + eventColor->setItemChecked(2, mode == 2); + ((PianoCanvas*)(canvas))->setColorMode(colorMode); + } + +//--------------------------------------------------------- +// clipboardChanged +//--------------------------------------------------------- + +void PianoRoll::clipboardChanged() + { + QMimeSource* ms = QApplication::clipboard()->data(QClipboard::Clipboard); + bool flag = false; + if (ms) { + for (int i = 0;; ++i) { + if (ms->format(i) == 0) + break; +// printf("clipboard changed %s\n", ms->format(i)); + flag = strcmp(ms->format(i), "text/eventlist;charset=UTF-8") == 0; + if (flag) + break; + } + } + menuEdit->setItemEnabled(PianoCanvas::CMD_PASTE, flag); + } + +//--------------------------------------------------------- +// selectionChanged +//--------------------------------------------------------- + +void PianoRoll::selectionChanged() + { + bool flag = canvas->selectionSize() > 0; + menuEdit->setItemEnabled(PianoCanvas::CMD_CUT, flag); + menuEdit->setItemEnabled(PianoCanvas::CMD_COPY, flag); + menuEdit->setItemEnabled(PianoCanvas::CMD_DEL, flag); + } + +//--------------------------------------------------------- +// setSpeaker +//--------------------------------------------------------- + +void PianoRoll::setSpeaker(bool val) + { + _playEvents = val; + canvas->playEvents(_playEvents); + } + +//--------------------------------------------------------- +// resizeEvent +//--------------------------------------------------------- + +void PianoRoll::resizeEvent(QResizeEvent* ev) + { + QWidget::resizeEvent(ev); + _widthInit = ev->size().width(); + _heightInit = ev->size().height(); + } + + +//--------------------------------------------------------- +// initShortcuts +//--------------------------------------------------------- + +void PianoRoll::initShortcuts() + { + menuSelect->setAccel(shortcuts[SHRT_SELECT_ALL].key, PianoCanvas::CMD_SELECT_ALL); + menuSelect->setAccel(shortcuts[SHRT_SELECT_NONE].key, PianoCanvas::CMD_SELECT_NONE); + menuSelect->setAccel(shortcuts[SHRT_SELECT_INVERT].key, PianoCanvas::CMD_SELECT_INVERT); + menuSelect->setAccel(shortcuts[SHRT_SELECT_ILOOP].key, PianoCanvas::CMD_SELECT_ILOOP); + menuSelect->setAccel(shortcuts[SHRT_SELECT_OLOOP].key, PianoCanvas::CMD_SELECT_OLOOP); + + menuSelect->setAccel(shortcuts[SHRT_SELECT_PREV_PART].key, PianoCanvas::CMD_SELECT_PREV_PART); + menuSelect->setAccel(shortcuts[SHRT_SELECT_NEXT_PART].key, PianoCanvas::CMD_SELECT_NEXT_PART); + + menuConfig->setAccel(shortcuts[SHRT_EVENT_COLOR].key, menu_ids[CMD_EVENT_COLOR]); + + menuFunctions->setAccel(shortcuts[SHRT_OVER_QUANTIZE].key, PianoCanvas::CMD_OVER_QUANTIZE); + menuFunctions->setAccel(shortcuts[SHRT_ON_QUANTIZE].key, PianoCanvas::CMD_ON_QUANTIZE); + menuFunctions->setAccel(shortcuts[SHRT_ONOFF_QUANTIZE].key, PianoCanvas::CMD_ONOFF_QUANTIZE); + menuFunctions->setAccel(shortcuts[SHRT_ITERATIVE_QUANTIZE].key, PianoCanvas::CMD_ITERATIVE_QUANTIZE); + menuFunctions->setAccel(shortcuts[SHRT_MODIFY_GATE_TIME].key, PianoCanvas::CMD_MODIFY_GATE_TIME); + menuFunctions->setAccel(shortcuts[SHRT_MODIFY_VELOCITY].key, PianoCanvas::CMD_MODIFY_VELOCITY); + menuFunctions->setAccel(shortcuts[SHRT_CRESCENDO].key, PianoCanvas::CMD_CRESCENDO); + menuFunctions->setAccel(shortcuts[SHRT_TRANSPOSE].key, PianoCanvas::CMD_TRANSPOSE); + menuFunctions->setAccel(shortcuts[SHRT_THIN_OUT].key, PianoCanvas::CMD_THIN_OUT); + menuFunctions->setAccel(shortcuts[SHRT_ERASE_EVENT].key, PianoCanvas::CMD_ERASE_EVENT); + menuFunctions->setAccel(shortcuts[SHRT_NOTE_SHIFT].key, PianoCanvas::CMD_NOTE_SHIFT); + menuFunctions->setAccel(shortcuts[SHRT_MOVE_CLOCK].key, PianoCanvas::CMD_MOVE_CLOCK); + menuFunctions->setAccel(shortcuts[SHRT_COPY_MEASURE].key, PianoCanvas::CMD_COPY_MEASURE); + menuFunctions->setAccel(shortcuts[SHRT_ERASE_MEASURE].key, PianoCanvas::CMD_ERASE_MEASURE); + menuFunctions->setAccel(shortcuts[SHRT_DELETE_MEASURE].key, PianoCanvas::CMD_DELETE_MEASURE); + menuFunctions->setAccel(shortcuts[SHRT_CREATE_MEASURE].key, PianoCanvas::CMD_CREATE_MEASURE); + menuFunctions->setAccel(shortcuts[SHRT_CONFIG_QUANT].key, menu_ids[CMD_CONFIG_QUANT]); + menuFunctions->setAccel(shortcuts[SHRT_FIXED_LEN].key, PianoCanvas::CMD_FIXED_LEN); + menuFunctions->setAccel(shortcuts[SHRT_DELETE_OVERLAPS].key, PianoCanvas::CMD_DELETE_OVERLAPS); + } + +//--------------------------------------------------------- +// execDeliveredScript +//--------------------------------------------------------- +void PianoRoll::execDeliveredScript(int id) +{ + //QString scriptfile = QString(INSTPREFIX) + SCRIPTSSUFFIX + deliveredScriptNames[id]; + QString scriptfile = song->getScriptPath(id, true); + song->executeScript(scriptfile.latin1(), parts(), quant(), true); +} + +//--------------------------------------------------------- +// execUserScript +//--------------------------------------------------------- +void PianoRoll::execUserScript(int id) +{ + QString scriptfile = song->getScriptPath(id, false); + song->executeScript(scriptfile.latin1(), parts(), quant(), true); +} + diff --git a/muse2/muse/midiedit/pianoroll.h b/muse2/muse/midiedit/pianoroll.h new file mode 100644 index 00000000..8987915a --- /dev/null +++ b/muse2/muse/midiedit/pianoroll.h @@ -0,0 +1,146 @@ +//========================================================= +// MusE +// Linux Music Editor +// $Id: pianoroll.h,v 1.5.2.4 2009/11/16 11:29:33 lunar_shuttle Exp $ +// (C) Copyright 1999 Werner Schweer (ws@seh.de) +//========================================================= + +#ifndef __PIANOROLL_H__ +#define __PIANOROLL_H__ + +#include <qwidget.h> +#include <q3mainwindow.h> +//Added by qt3to4: +#include <QCloseEvent> +#include <QResizeEvent> +#include <QLabel> +#include <Q3PopupMenu> +#include <QKeyEvent> + +#include <values.h> +#include "noteinfo.h" +#include "cobject.h" +#include "midieditor.h" +#include "tools.h" +#include "event.h" + +class MidiPart; +class TimeLabel; +class PitchLabel; +class QLabel; +class PianoCanvas; +class IntLabel; +class MTScale; +class Track; +class QToolButton; +class QPushButton; +class CtrlEdit; +class Splitter; +class PartList; +class Toolbar1; +class Xml; +class QuantConfig; +class ScrollScale; +class Part; +class SNode; + +//--------------------------------------------------------- +// PianoRoll +//--------------------------------------------------------- + +class PianoRoll : public MidiEditor { + Event selEvent; + MidiPart* selPart; + int selTick; + + enum { CMD_EVENT_COLOR, CMD_CONFIG_QUANT, CMD_LAST }; + int menu_ids[CMD_LAST]; + Q3PopupMenu *menuEdit, *menuFunctions, *menuSelect, *menuConfig, *menuPlugins; + + int tickOffset; + int lenOffset; + int pitchOffset; + int veloOnOffset; + int veloOffOffset; + bool deltaMode; + + NoteInfo* info; + QToolButton* srec; + QToolButton* midiin; + + Toolbar1* toolbar; + Splitter* splitter; + + QToolButton* speaker; + Q3ToolBar* tools; + EditToolBar* tools2; + + Q3PopupMenu* eventColor; + int colorMode; + + static int _quantInit, _rasterInit; + static int _widthInit, _heightInit; + + static int _quantStrengthInit; + static int _quantLimitInit; + static bool _quantLenInit; + static int _toInit; + static int colorModeInit; + + int _quantStrength; + int _quantLimit; + int _to; + bool _quantLen; + QuantConfig* quantConfig; + bool _playEvents; + + + Q_OBJECT + void initShortcuts(); + QWidget* genToolbar(QWidget* parent); + virtual void closeEvent(QCloseEvent*); + virtual void keyPressEvent(QKeyEvent*); + virtual void resizeEvent(QResizeEvent*); + + private slots: + void setSelection(int, Event&, Part*); + void noteinfoChanged(NoteInfo::ValType, int); + CtrlEdit* addCtrl(); + void removeCtrl(CtrlEdit* ctrl); + void soloChanged(bool flag); + void setRaster(int); + void setQuant(int); + void configQuant(); + void setQuantStrength(int val) { _quantStrength = val; } + void setQuantLimit(int val) { _quantLimit = val; } + void setQuantLen(bool val) { _quantLen = val; } + void cmd(int); + void setSteprec(bool); + void setTo(int val) { _to = val; } + void setEventColorMode(int); + void clipboardChanged(); // enable/disable "Paste" + void selectionChanged(); // enable/disable "Copy" & "Paste" + void setSpeaker(bool); + void setTime(unsigned); + void follow(int pos); + void songChanged1(int); + void configChanged(); + + signals: + void deleted(unsigned long); + + public slots: + virtual void updateHScrollRange(); + void execDeliveredScript(int id); + void execUserScript(int id); + public: + PianoRoll(PartList*, QWidget* parent = 0, const char* name = 0, unsigned initPos = MAXINT); + ~PianoRoll(); + virtual void readStatus(Xml&); + virtual void writeStatus(int, Xml&) const; + static void readConfiguration(Xml&); + static void writeConfiguration(int, Xml&); + }; + +#endif + diff --git a/muse2/muse/midiedit/prcanvas.cpp b/muse2/muse/midiedit/prcanvas.cpp new file mode 100644 index 00000000..484a12ad --- /dev/null +++ b/muse2/muse/midiedit/prcanvas.cpp @@ -0,0 +1,1695 @@ +//========================================================= +// MusE +// Linux Music Editor +// $Id: prcanvas.cpp,v 1.20.2.19 2009/11/16 11:29:33 lunar_shuttle Exp $ +// (C) Copyright 1999-2004 Werner Schweer (ws@seh.de) +//========================================================= + +#include <qapplication.h> +#include <qclipboard.h> +#include <qpainter.h> +#include <q3dragobject.h> +#include <qmessagebox.h> +//Added by qt3to4: +#include <QDragLeaveEvent> +#include <Q3CString> +#include <QDragEnterEvent> +#include <QDragMoveEvent> +#include <QDropEvent> +#include <QMouseEvent> + +#include <values.h> +#include <stdio.h> +#include <math.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <fcntl.h> +#include <dirent.h> + +#include "xml.h" +#include "prcanvas.h" +#include "midiport.h" +#include "event.h" +#include "mpevent.h" +#include "globals.h" +#include "cmd.h" +#include "gatetime.h" +#include "velocity.h" +#include "song.h" +#include "audio.h" + +//--------------------------------------------------------- +// NEvent +//--------------------------------------------------------- + +NEvent::NEvent(Event& e, Part* p, int y) : CItem(e, p) + { + y = y - KH/4; + unsigned tick = e.tick() + p->tick(); + setPos(QPoint(tick, y)); + setBBox(QRect(tick, y, e.lenTick(), KH/2)); + } + +//--------------------------------------------------------- +// addItem +//--------------------------------------------------------- + +void PianoCanvas::addItem(Part* part, Event& event) + { + if (signed(event.tick())<0) { + printf("ERROR: trying to add event before current part!\n"); + return; + } + + NEvent* ev = new NEvent(event, part, pitch2y(event.pitch())); + items.add(ev); + + int diff = event.endTick()-part->lenTick(); + if (diff > 0) {// too short part? extend it + //printf("addItem - this code should not be run!\n"); + //Part* newPart = part->clone(); + //newPart->setLenTick(newPart->lenTick()+diff); + //audio->msgChangePart(part, newPart,false); + //part = newPart; + part->setLenTick(part->lenTick()+diff); + } + } + +//--------------------------------------------------------- +// PianoCanvas +//--------------------------------------------------------- + +PianoCanvas::PianoCanvas(MidiEditor* pr, QWidget* parent, int sx, int sy) + : EventCanvas(pr, parent, sx, sy) + { + colorMode = 0; + cmdRange = 0; // all Events + playedPitch = -1; + + songChanged(SC_TRACK_INSERTED); + connect(song, SIGNAL(midiNote(int, int)), SLOT(midiNote(int,int))); + } + +//--------------------------------------------------------- +// pitch2y +//--------------------------------------------------------- + +int PianoCanvas::pitch2y(int pitch) const + { + int tt[] = { + 5, 12, 19, 26, 33, 44, 51, 58, 64, 71, 78, 85 + }; + int y = (75 * KH) - (tt[pitch%12] + (7 * KH) * (pitch/12)); + if (y < 0) + y = 0; + return y; + } + +//--------------------------------------------------------- +// y2pitch +//--------------------------------------------------------- + +int PianoCanvas::y2pitch(int y) const + { + const int total = (10 * 7 + 5) * KH; // 75 Ganztonschritte + y = total - y; + int oct = (y / (7 * KH)) * 12; + char kt[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 5 + 1, 1, 1, 1, 1, 1, 1, // 13 + 2, 2, 2, 2, 2, 2, // 19 + 3, 3, 3, 3, 3, 3, 3, // 26 + 4, 4, 4, 4, 4, 4, 4, 4, 4, // 34 + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // 43 + 6, 6, 6, 6, 6, 6, 6, // 52 + 7, 7, 7, 7, 7, 7, // 58 + 8, 8, 8, 8, 8, 8, 8, // 65 + 9, 9, 9, 9, 9, 9, // 71 + 10, 10, 10, 10, 10, 10, 10, // 78 + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11 // 87 + }; + return kt[y % 91] + oct; + } + +//--------------------------------------------------------- +// drawEvent +// draws a note +//--------------------------------------------------------- + +void PianoCanvas::drawItem(QPainter& p, const CItem* item, + const QRect& rect) + { + QRect r = item->bbox(); + if(!virt()) + r.moveCenter(map(item->pos())); + r = r.intersect(rect); + if(!r.isValid()) + return; + p.setPen(Qt::black); + struct Triple { + int r, g, b; + }; + + static Triple myColors /*Qt::color1*/[12] = { // ddskrjp + { 0xff, 0x3d, 0x39 }, + { 0x39, 0xff, 0x39 }, + { 0x39, 0x3d, 0xff }, + { 0xff, 0xff, 0x39 }, + { 0xff, 0x3d, 0xff }, + { 0x39, 0xff, 0xff }, + { 0xff, 0x7e, 0x7a }, + { 0x7a, 0x7e, 0xff }, + { 0x7a, 0xff, 0x7a }, + { 0xff, 0x7e, 0xbf }, + { 0x7a, 0xbf, 0xff }, + { 0xff, 0xbf, 0x7a } + }; + + NEvent* nevent = (NEvent*) item; + Event event = nevent->event(); + if (nevent->part() != curPart){ + if(item->isMoving()) + p.setBrush(Qt::gray); + else if(item->isSelected()) + p.setBrush(Qt::black); + else + p.setBrush(Qt::lightGray); + } + else { + if (item->isMoving()) { + p.setBrush(Qt::gray); + } + else if (item->isSelected()) { + p.setBrush(Qt::black); + } + else { + QColor color; + color.setRgb(0, 0, 255); + switch(colorMode) { + case 0: + break; + case 1: // pitch + { + Triple* c = &myColors/*Qt::color1*/[event.pitch() % 12]; + color.setRgb(c->r, c->g, c->b); + } + break; + case 2: // velocity + { + int velo = event.velo(); + if (velo < 64) + color.setRgb(velo*4, 0, 0xff); + else + color.setRgb(0xff, 0, (127-velo) * 4); + } + break; + } + p.setBrush(color); + } + } + p.drawRect(r); + } + + +//--------------------------------------------------------- +// drawMoving +// draws moving items +//--------------------------------------------------------- + +void PianoCanvas::drawMoving(QPainter& p, const CItem* item, const QRect& rect) + { + //if(((NEvent*)item)->part() != curPart) + // return; + //if(!item->isMoving()) + // return; + QRect mr = QRect(item->mp().x(), item->mp().y() - item->height()/2, item->width(), item->height()); + mr = mr.intersect(rect); + if(!mr.isValid()) + return; + p.setPen(Qt::black); + p.setBrush(Qt::NoBrush); + p.drawRect(mr); + } + +//--------------------------------------------------------- +// viewMouseDoubleClickEvent +//--------------------------------------------------------- + +void PianoCanvas::viewMouseDoubleClickEvent(QMouseEvent* event) + { + if ((_tool != PointerTool) && (event->button() != Qt::LeftButton)) { + mousePress(event); + return; + } + } + +//--------------------------------------------------------- +// moveCanvasItems +//--------------------------------------------------------- + +void PianoCanvas::moveCanvasItems(CItemList& items, int dp, int dx, DragType dtype, int* pflags) +{ + if(editor->parts()->empty()) + return; + + PartsToChangeMap parts2change; + + int modified = 0; + for(iPart ip = editor->parts()->begin(); ip != editor->parts()->end(); ++ip) + { + Part* part = ip->second; + if(!part) + continue; + + int npartoffset = 0; + for(iCItem ici = items.begin(); ici != items.end(); ++ici) + { + CItem* ci = ici->second; + if(ci->part() != part) + continue; + + int x = ci->pos().x() + dx; + int y = pitch2y(y2pitch(ci->pos().y()) + dp); + QPoint newpos = raster(QPoint(x, y)); + + // Test moving the item... + NEvent* nevent = (NEvent*) ci; + Event event = nevent->event(); + x = newpos.x(); + if(x < 0) + x = 0; + int ntick = editor->rasterVal(x) - part->tick(); + if(ntick < 0) + ntick = 0; + int diff = ntick + event.lenTick() - part->lenTick(); + + // If moving the item would require a new part size... + if(diff > npartoffset) + npartoffset = diff; + } + + if(npartoffset > 0) + { + // Create new part... + // if there are several events that are moved outside the part, it will be recreated for each + // so the part _in_ the event will not be valid, ask the authority. +// Part* newPart = part->clone(); + //Part* newPart = Canvas::part()->clone(); + +// newPart->setLenTick(newPart->lenTick() + npartoffset); + //audio->msgChangePart(part, newPart,false); + +// modified = SC_PART_MODIFIED; + + // BUG FIX: #1650953 + // Added by T356. + // Fixes posted "select and drag past end of part - crashing" bug +// for(iPart ip = editor->parts()->begin(); ip != editor->parts()->end(); ++ip) +// { +// if(ip->second == part) +// { +// editor->parts()->erase(ip); +// break; +// } +// } + +// editor->parts()->add(newPart); +// audio->msgChangePart(part, newPart,false); + + //if(parts2change.find(part) == parts2change.end()) + // parts2change.insert(std::pair<Part*, Part*> (part, newPart)); + iPartToChange ip2c = parts2change.find(part); + if(ip2c == parts2change.end()) + { + PartToChange p2c = {0, npartoffset}; + parts2change.insert(std::pair<Part*, PartToChange> (part, p2c)); + } + else + ip2c->second.xdiff = npartoffset; + + //part = newPart; // reassign + //item->setPart(part); + //item->setEvent(newEvent); + //curPart = part; + //curPartId = curPart->sn(); + + } + } + + for(iPartToChange ip2c = parts2change.begin(); ip2c != parts2change.end(); ++ip2c) + { + Part* opart = ip2c->first; + int diff = ip2c->second.xdiff; + + Part* newPart = opart->clone(); + + newPart->setLenTick(newPart->lenTick() + diff); + + modified = SC_PART_MODIFIED; + + // BUG FIX: #1650953 + // Added by T356. + // Fixes posted "select and drag past end of part - crashing" bug + for(iPart ip = editor->parts()->begin(); ip != editor->parts()->end(); ++ip) + { + if(ip->second == opart) + { + editor->parts()->erase(ip); + break; + } + } + + editor->parts()->add(newPart); + // Indicate no undo, and do port controller values but not clone parts. + audio->msgChangePart(opart, newPart, false, true, false); + + ip2c->second.npart = newPart; + + } + + iPartToChange icp = parts2change.find(curPart); + if(icp != parts2change.end()) + { + curPart = icp->second.npart; + curPartId = curPart->sn(); + } + + std::vector< CItem* > doneList; + typedef std::vector< CItem* >::iterator iDoneList; + + for(iCItem ici = items.begin(); ici != items.end(); ++ici) + { + CItem* ci = ici->second; + + // If this item's part is in the parts2change list, change the item's part to the new part. + Part* pt = ci->part(); + iPartToChange ip2c = parts2change.find(pt); + if(ip2c != parts2change.end()) + ci->setPart(ip2c->second.npart); + + int x = ci->pos().x(); + int y = ci->pos().y(); + int nx = x + dx; + int ny = pitch2y(y2pitch(y) + dp); + QPoint newpos = raster(QPoint(nx, ny)); + selectItem(ci, true); + + iDoneList idl; + for(idl = doneList.begin(); idl != doneList.end(); ++idl) + // This compares EventBase pointers to see if they're the same... + if((*idl)->event() == ci->event()) + break; + + // Do not process if the event has already been processed (meaning it's an event in a clone part)... + //if(moveItem(ci, newpos, dtype)) + if(idl != doneList.end()) + // Just move the canvas item. + ci->move(newpos); + else + { + // Currently moveItem always returns true. + if(moveItem(ci, newpos, dtype)) + { + // Add the canvas item to the list of done items. + doneList.push_back(ci); + // Move the canvas item. + ci->move(newpos); + } + } + + if(moving.size() == 1) + itemReleased(curItem, newpos); + if(dtype == MOVE_COPY || dtype == MOVE_CLONE) + selectItem(ci, false); + } + + if(pflags) + *pflags = modified; +} + +//--------------------------------------------------------- +// moveItem +// called after moving an object +//--------------------------------------------------------- + +// Changed by T356. +//bool PianoCanvas::moveItem(CItem* item, const QPoint& pos, DragType dtype, int* pflags) +bool PianoCanvas::moveItem(CItem* item, const QPoint& pos, DragType dtype) + { + NEvent* nevent = (NEvent*) item; + Event event = nevent->event(); + int npitch = y2pitch(pos.y()); + Event newEvent = event.clone(); + int x = pos.x(); + if (x < 0) + x = 0; + if (event.pitch() != npitch && _playEvents) { + int port = track()->outPort(); + int channel = track()->outChannel(); + // release note: + MidiPlayEvent ev1(0, port, channel, 0x90, event.pitch() + track()->transposition, 0); + audio->msgPlayMidiEvent(&ev1); + MidiPlayEvent ev2(0, port, channel, 0x90, npitch + track()->transposition, event.velo()); + audio->msgPlayMidiEvent(&ev2); + } + + // Changed by T356. + Part* part = nevent->part(); // + //Part * part = Canvas::part(); // part can be dynamically recreated, ask the authority + + newEvent.setPitch(npitch); + int ntick = editor->rasterVal(x) - part->tick(); + if (ntick < 0) + ntick = 0; + newEvent.setTick(ntick); + newEvent.setLenTick(event.lenTick()); + + // Removed by T356. + /* + int modified=0; + //song->startUndo(); + int diff = newEvent.endTick()-part->lenTick(); + if (diff > 0){// too short part? extend it + // if there are several events that are moved outside the part, it will be recreated for each + // so the part _in_ the event will not be valid, ask the authority. + //Part* newPart = part->clone(); + Part* newPart = Canvas::part()->clone(); + + newPart->setLenTick(newPart->lenTick()+diff); + audio->msgChangePart(Canvas::part(), newPart,false); + + modified = SC_PART_MODIFIED; + part = newPart; // reassign + + // BUG FIX: #1650953 + // Added by T356. + // Fixes posted "select and drag past end of part - crashing" bug + for(iPart i = editor->parts()->begin(); i != editor->parts()->end(); ++i) + { + if(i->second == Canvas::part()) + { + editor->parts()->erase(i); + break; + } + } + editor->parts()->add(part); + item->setPart(part); + item->setEvent(newEvent); + curPart = part; + curPartId = curPart->sn(); + + } + */ + + // Added by T356. + // msgAddEvent and msgChangeEvent (below) will set these, but set them here first? + //item->setPart(part); + item->setEvent(newEvent); + + // Added by T356. + if(((int)newEvent.endTick() - (int)part->lenTick()) > 0) + printf("PianoCanvas::moveItem Error! New event end:%d exceeds length:%d of part:%s\n", newEvent.endTick(), part->lenTick(), part->name().latin1()); + + if (dtype == MOVE_COPY || dtype == MOVE_CLONE) + // Indicate no undo, and do not do port controller values and clone parts. + //audio->msgAddEvent(newEvent, part, false); + audio->msgAddEvent(newEvent, part, false, false, false); + else + // Indicate no undo, and do not do port controller values and clone parts. + //audio->msgChangeEvent(event, newEvent, part, false); + audio->msgChangeEvent(event, newEvent, part, false, false, false); + //song->endUndo(modified); + + // Removed by T356. + //if(pflags) + // *pflags = modified; + + return true; + } + +//--------------------------------------------------------- +// newItem(p, state) +//--------------------------------------------------------- + +CItem* PianoCanvas::newItem(const QPoint& p, int) + { + //printf("newItem point\n"); + int pitch = y2pitch(p.y()); + int tick = editor->rasterVal1(p.x()); + int len = p.x() - tick; + tick -= curPart->tick(); + if (tick < 0) + tick=0; + Event e = Event(Note); + e.setTick(tick); + e.setPitch(pitch); + e.setVelo(curVelo); + e.setLenTick(len); + return new NEvent(e, curPart, pitch2y(pitch)); + } + +void PianoCanvas::newItem(CItem* item, bool noSnap) + { + //printf("newItem citem\n"); + NEvent* nevent = (NEvent*) item; + Event event = nevent->event(); + int x = item->x(); + if (x<0) + x=0; + int w = item->width(); + + if (!noSnap) { + x = editor->rasterVal1(x); //round down + w = editor->rasterVal(x + w) - x; + if (w == 0) + w = editor->raster(); + } + Part* part = nevent->part(); + event.setTick(x - part->tick()); + event.setLenTick(w); + event.setPitch(y2pitch(item->y())); + + song->startUndo(); + int modified=SC_EVENT_MODIFIED; + int diff = event.endTick()-part->lenTick(); + if (diff > 0) {// too short part? extend it + //printf("extend Part!\n"); + Part* newPart = part->clone(); + newPart->setLenTick(newPart->lenTick()+diff); + // Indicate no undo, and do port controller values but not clone parts. + //audio->msgChangePart(part, newPart,false); + audio->msgChangePart(part, newPart, false, true, false); + modified=modified|SC_PART_MODIFIED; + part = newPart; // reassign + } + // Indicate no undo, and do not do port controller values and clone parts. + //audio->msgAddEvent(event, part,false); + audio->msgAddEvent(event, part, false, false, false); + song->endUndo(modified); + } + +//--------------------------------------------------------- +// resizeItem +//--------------------------------------------------------- + +void PianoCanvas::resizeItem(CItem* item, bool noSnap) // experimental changes to try dynamically extending parts + { + //printf("resizeItem!\n"); + NEvent* nevent = (NEvent*) item; + Event event = nevent->event(); + Event newEvent = event.clone(); + int len; + + Part* part = nevent->part(); + + if (noSnap) + len = nevent->width(); + else { + //Part* part = nevent->part(); + unsigned tick = event.tick() + part->tick(); + len = editor->rasterVal(tick + nevent->width()) - tick; + if (len <= 0) + len = editor->raster(); + } + song->startUndo(); + int modified=SC_EVENT_MODIFIED; + //printf("event.tick()=%d len=%d part->lenTick()=%d\n",event.endTick(),len,part->lenTick()); + int diff = event.tick()+len-part->lenTick(); + if (diff > 0) {// too short part? extend it + //printf("extend Part!\n"); + Part* newPart = part->clone(); + newPart->setLenTick(newPart->lenTick()+diff); + // Indicate no undo, and do port controller values but not clone parts. + //audio->msgChangePart(part, newPart,false); + audio->msgChangePart(part, newPart, false, true, false); + modified=modified|SC_PART_MODIFIED; + part = newPart; // reassign + } + + newEvent.setLenTick(len); + // Indicate no undo, and do not do port controller values and clone parts. + //audio->msgChangeEvent(event, newEvent, nevent->part(),false); + audio->msgChangeEvent(event, newEvent, nevent->part(), false, false, false); + song->endUndo(modified); + } + +//--------------------------------------------------------- +// deleteItem +//--------------------------------------------------------- + +bool PianoCanvas::deleteItem(CItem* item) + { + NEvent* nevent = (NEvent*) item; + if (nevent->part() == curPart) { + Event ev = nevent->event(); + // Indicate do undo, and do not do port controller values and clone parts. + //audio->msgDeleteEvent(ev, curPart); + audio->msgDeleteEvent(ev, curPart, true, false, false); + return true; + } + return false; + } + +//--------------------------------------------------------- +// pianoCmd +//--------------------------------------------------------- + +void PianoCanvas::pianoCmd(int cmd) + { + switch(cmd) { + case CMD_LEFT: + { + int frames = pos[0] - editor->rasterStep(pos[0]); + if (frames < 0) + frames = 0; + Pos p(frames,true); + song->setPos(0, p, true, true, true); //CDW + } + break; + case CMD_RIGHT: + { + Pos p(pos[0] + editor->rasterStep(pos[0]), true); + //if (p > part->tick()) + // p = part->tick(); + song->setPos(0, p, true, true, true); //CDW + } + break; + case CMD_INSERT: + { + if (pos[0] < start() || pos[0] >= end()) + break; + MidiPart* part = (MidiPart*)curPart; + + if (part == 0) + break; + song->startUndo(); + EventList* el = part->events(); + + std::list <Event> elist; + for (iEvent e = el->lower_bound(pos[0] - part->tick()); e != el->end(); ++e) + elist.push_back((Event)e->second); + for (std::list<Event>::iterator i = elist.begin(); i != elist.end(); ++i) { + Event event = *i; + Event newEvent = event.clone(); + newEvent.setTick(event.tick() + editor->raster());// - part->tick()); + // Indicate no undo, and do not do port controller values and clone parts. + //audio->msgChangeEvent(event, newEvent, part, false); + audio->msgChangeEvent(event, newEvent, part, false, false, false); + } + song->endUndo(SC_EVENT_MODIFIED); + Pos p(editor->rasterVal(pos[0] + editor->rasterStep(pos[0])), true); + song->setPos(0, p, true, false, true); + } + return; + case CMD_DELETE: + if (pos[0] < start() || pos[0] >= end()) + break; + { + MidiPart* part = (MidiPart*)curPart; + if (part == 0) + break; + song->startUndo(); + EventList* el = part->events(); + + std::list<Event> elist; + for (iEvent e = el->lower_bound(pos[0]); e != el->end(); ++e) + elist.push_back((Event)e->second); + for (std::list<Event>::iterator i = elist.begin(); i != elist.end(); ++i) { + Event event = *i; + Event newEvent = event.clone(); + newEvent.setTick(event.tick() - editor->raster() - part->tick()); + // Indicate no undo, and do not do port controller values and clone parts. + //audio->msgChangeEvent(event, newEvent, part, false); + audio->msgChangeEvent(event, newEvent, part, false, false, false); + } + song->endUndo(SC_EVENT_MODIFIED); + Pos p(editor->rasterVal(pos[0] - editor->rasterStep(pos[0])), true); + song->setPos(0, p, true, false, true); + } + break; + } + } + +//--------------------------------------------------------- +// pianoPressed +//--------------------------------------------------------- + +void PianoCanvas::pianoPressed(int pitch, int velocity, bool shift) + { + int port = track()->outPort(); + int channel = track()->outChannel(); + pitch += track()->transposition; + + // play note: + //MidiPlayEvent e(0, port, channel, 0x90, pitch, 127); + MidiPlayEvent e(0, port, channel, 0x90, pitch, velocity); + audio->msgPlayMidiEvent(&e); + + if (_steprec && pos[0] >= start_tick && pos[0] < end_tick) { + if (curPart == 0) + return; + int len = editor->raster(); + unsigned tick = pos[0] - curPart->tick(); //CDW + if (shift) + tick -= editor->rasterStep(tick); + Event e(Note); + e.setTick(tick); + e.setPitch(pitch); + e.setVelo(127); + e.setLenTick(len); + // Indicate do undo, and do not do port controller values and clone parts. + //audio->msgAddEvent(e, curPart); + audio->msgAddEvent(e, curPart, true, false, false); + tick += editor->rasterStep(tick) + curPart->tick(); + if (tick != song->cpos()) { + Pos p(tick, true); + song->setPos(0, p, true, false, true); + } + } + } + +//--------------------------------------------------------- +// pianoReleased +//--------------------------------------------------------- + +void PianoCanvas::pianoReleased(int pitch, bool) + { + int port = track()->outPort(); + int channel = track()->outChannel(); + pitch += track()->transposition; + + // release key: + MidiPlayEvent e(0, port, channel, 0x90, pitch, 0); + audio->msgPlayMidiEvent(&e); + } + +//--------------------------------------------------------- +// drawTickRaster +//--------------------------------------------------------- + +void drawTickRaster(QPainter& p, int x, int y, int w, int h, int raster) + { + int bar1, bar2, beat; + unsigned tick; + sigmap.tickValues(x, &bar1, &beat, &tick); + sigmap.tickValues(x+w, &bar2, &beat, &tick); + ++bar2; + int y2 = y + h; + for (int bar = bar1; bar < bar2; ++bar) { + unsigned x = sigmap.bar2tick(bar, 0, 0); + p.setPen(Qt::black); + p.drawLine(x, y, x, y2); + int z, n; + sigmap.timesig(x, z, n); + int q = p.xForm(QPoint(raster, 0)).x() - p.xForm(QPoint(0, 0)).x(); + int qq = raster; + if (q < 8) // grid too dense + qq *= 2; + //switch (quant) { + // case 32: + // case 48: + // case 64: + // case 96: + // case 192: // 8tel + // case 128: // 8tel Triolen + // case 288: + p.setPen(Qt::lightGray); + if (raster>=4) { + int xx = x + qq; + int xxx = sigmap.bar2tick(bar, z, 0); + while (xx <= xxx) { + p.drawLine(xx, y, xx, y2); + xx += qq; + } + xx = xxx; + } + // break; + // default: + // break; + // } + p.setPen(Qt::gray); + for (int beat = 1; beat < z; beat++) { + int xx = sigmap.bar2tick(bar, beat, 0); + p.drawLine(xx, y, xx, y2); + } + + } + } + +//--------------------------------------------------------- +// draw +//--------------------------------------------------------- + +void PianoCanvas::drawCanvas(QPainter& p, const QRect& rect) + { + int x = rect.x(); + int y = rect.y(); + int w = rect.width(); + int h = rect.height(); + + //--------------------------------------------------- + // horizontal lines + //--------------------------------------------------- + + int yy = ((y-1) / KH) * KH + KH; + int key = 75 - (yy / KH); + for (; yy < y + h; yy += KH) { + switch (key % 7) { + case 0: + case 3: + p.setPen(Qt::black); + p.drawLine(x, yy, x + w, yy); + break; + default: + //p.setPen(lightGray); + p.fillRect(x, yy-3, w, 6, QBrush(QColor(230,230,230))); + //p.drawLine(x, yy, x + w, yy); + break; + } + --key; + } + + //--------------------------------------------------- + // vertical lines + //--------------------------------------------------- + + drawTickRaster(p, x, y, w, h, editor->raster()); + } + +//--------------------------------------------------------- +// cmd +// pulldown menu commands +//--------------------------------------------------------- + +void PianoCanvas::cmd(int cmd, int quantStrength, + int quantLimit, bool quantLen, int range) + { + cmdRange = range; + switch (cmd) { + case CMD_CUT: + copy(); + song->startUndo(); + for (iCItem i = items.begin(); i != items.end(); ++i) { + if (!(i->second->isSelected())) + continue; + NEvent* e = (NEvent*)(i->second); + Event ev = e->event(); + // Indicate no undo, and do not do port controller values and clone parts. + //audio->msgDeleteEvent(ev, e->part(), false); + audio->msgDeleteEvent(ev, e->part(), false, false, false); + } + song->endUndo(SC_EVENT_REMOVED); + break; + case CMD_COPY: + copy(); + break; + case CMD_PASTE: + paste(); + break; + case CMD_DEL: + if (selectionSize()) { + song->startUndo(); + for (iCItem i = items.begin(); i != items.end(); ++i) { + if (!i->second->isSelected()) + continue; + Event ev = i->second->event(); + // Indicate no undo, and do not do port controller values and clone parts. + //audio->msgDeleteEvent(ev, i->second->part(), false); + audio->msgDeleteEvent(ev, i->second->part(), false, false, false); + } + song->endUndo(SC_EVENT_REMOVED); + } + return; + case CMD_OVER_QUANTIZE: // over quantize + quantize(100, 1, quantLen); + break; + case CMD_ON_QUANTIZE: // note on quantize + quantize(50, 1, false); + break; + case CMD_ONOFF_QUANTIZE: // note on/off quantize + quantize(50, 1, true); + break; + case CMD_ITERATIVE_QUANTIZE: // Iterative Quantize + quantize(quantStrength, quantLimit, quantLen); + break; + case CMD_SELECT_ALL: // select all + for (iCItem k = items.begin(); k != items.end(); ++k) { + if (!k->second->isSelected()) + selectItem(k->second, true); + } + break; + case CMD_SELECT_NONE: // select none + deselectAll(); + break; + case CMD_SELECT_INVERT: // invert selection + for (iCItem k = items.begin(); k != items.end(); ++k) { + selectItem(k->second, !k->second->isSelected()); + } + break; + case CMD_SELECT_ILOOP: // select inside loop + for (iCItem k = items.begin(); k != items.end(); ++k) { + NEvent* nevent = (NEvent*)(k->second); + Part* part = nevent->part(); + Event event = nevent->event(); + unsigned tick = event.tick() + part->tick(); + if (tick < song->lpos() || tick >= song->rpos()) + selectItem(k->second, false); + else + selectItem(k->second, true); + } + break; + case CMD_SELECT_OLOOP: // select outside loop + for (iCItem k = items.begin(); k != items.end(); ++k) { + NEvent* nevent = (NEvent*)(k->second); + Part* part = nevent->part(); + Event event = nevent->event(); + unsigned tick = event.tick() + part->tick(); + if (tick < song->lpos() || tick >= song->rpos()) + selectItem(k->second, true); + else + selectItem(k->second, false); + } + break; + case CMD_SELECT_PREV_PART: // select previous part + { + Part* pt = editor->curCanvasPart(); + Part* newpt = pt; + PartList* pl = editor->parts(); + for(iPart ip = pl->begin(); ip != pl->end(); ++ip) + if(ip->second == pt) + { + if(ip == pl->begin()) + ip = pl->end(); + --ip; + newpt = ip->second; + break; + } + if(newpt != pt) + editor->setCurCanvasPart(newpt); + } + break; + case CMD_SELECT_NEXT_PART: // select next part + { + Part* pt = editor->curCanvasPart(); + Part* newpt = pt; + PartList* pl = editor->parts(); + for(iPart ip = pl->begin(); ip != pl->end(); ++ip) + if(ip->second == pt) + { + ++ip; + if(ip == pl->end()) + ip = pl->begin(); + newpt = ip->second; + break; + } + if(newpt != pt) + editor->setCurCanvasPart(newpt); + } + break; + case CMD_MODIFY_GATE_TIME: + { + GateTime w(this); + w.setRange(range); + if (!w.exec()) + break; + int range = w.range(); // all, selected, looped, sel+loop + int rate = w.rateVal(); + int offset = w.offsetVal(); + + song->startUndo(); + for (iCItem k = items.begin(); k != items.end(); ++k) { + NEvent* nevent =(NEvent*)(k->second); + Event event = nevent->event(); + if (event.type() != Note) + continue; + unsigned tick = event.tick(); + bool selected = k->second->isSelected(); + bool inLoop = (tick >= song->lpos()) && (tick < song->rpos()); + + if ((range == 0) + || (range == 1 && selected) + || (range == 2 && inLoop) + || (range == 3 && selected && inLoop)) { + unsigned int len = event.lenTick(); //prevent compiler warning: comparison singed/unsigned + + len = rate ? (len * 100) / rate : 1; + len += offset; + if (len < 1) + len = 1; + + if (event.lenTick() != len) { + Event newEvent = event.clone(); + newEvent.setLenTick(len); + // Indicate no undo, and do not do port controller values and clone parts. + //audio->msgChangeEvent(event, newEvent, nevent->part(), false); + audio->msgChangeEvent(event, newEvent, nevent->part(), false, false, false); + } + } + } + song->endUndo(SC_EVENT_MODIFIED); + } + break; + + case CMD_MODIFY_VELOCITY: + { + Velocity w(this); + w.setRange(range); + if (!w.exec()) + break; + int range = w.range(); // all, selected, looped, sel+loop + int rate = w.rateVal(); + int offset = w.offsetVal(); + + song->startUndo(); + for (iCItem k = items.begin(); k != items.end(); ++k) { + NEvent* nevent = (NEvent*)(k->second); + Event event = nevent->event(); + if (event.type() != Note) + continue; + unsigned tick = event.tick(); + bool selected = k->second->isSelected(); + bool inLoop = (tick >= song->lpos()) && (tick < song->rpos()); + + if ((range == 0) + || (range == 1 && selected) + || (range == 2 && inLoop) + || (range == 3 && selected && inLoop)) { + int velo = event.velo(); + + //velo = rate ? (velo * 100) / rate : 64; + velo = (velo * rate) / 100; + velo += offset; + + if (velo <= 0) + velo = 1; + if (velo > 127) + velo = 127; + if (event.velo() != velo) { + Event newEvent = event.clone(); + newEvent.setVelo(velo); + // Indicate no undo, and do not do port controller values and clone parts. + //audio->msgChangeEvent(event, newEvent, nevent->part(), false); + audio->msgChangeEvent(event, newEvent, nevent->part(), false, false, false); + } + } + } + song->endUndo(SC_EVENT_MODIFIED); + } + break; + + case CMD_FIXED_LEN: //Set notes to the length specified in the drummap + if (!selectionSize()) + break; + song->startUndo(); + for (iCItem k = items.begin(); k != items.end(); ++k) { + if (k->second->isSelected()) { + NEvent* nevent = (NEvent*)(k->second); + Event event = nevent->event(); + Event newEvent = event.clone(); + newEvent.setLenTick(editor->raster()); + // Indicate no undo, and do not do port controller values and clone parts. + //audio->msgChangeEvent(event, newEvent, nevent->part() , false); + audio->msgChangeEvent(event, newEvent, nevent->part(), false, false, false); + } + } + song->endUndo(SC_EVENT_MODIFIED); + break; + + case CMD_DELETE_OVERLAPS: + if (!selectionSize()) + break; + + song->startUndo(); + for (iCItem k = items.begin(); k != items.end(); k++) { + if (k->second->isSelected() == false) + continue; + + NEvent* e1 = (NEvent*) (k->second); // first note + NEvent* e2 = NULL; // ptr to next selected note (which will be checked for overlap) + Event ce1 = e1->event(); + Event ce2; + + if (ce1.type() != Note) + continue; + + // Find next selected item on the same pitch + iCItem l = k; l++; + for (; l != items.end(); l++) { + if (l->second->isSelected() == false) + continue; + + e2 = (NEvent*) l->second; + ce2 = e2->event(); + + // Same pitch? + if (ce1.dataA() == ce2.dataA()) + break; + + // If the note has the same len and place we treat it as a duplicate note and not a following note + // The best thing to do would probably be to delete the duplicate note, we just want to avoid + // matching against the same note + if ( ce1.tick() + e1->part()->tick() == ce2.tick() + e2->part()->tick() + && ce1.lenTick() + e1->part()->tick() == ce2.lenTick() + e2->part()->tick()) + { + e2 = NULL; // this wasn't what we were looking for + continue; + } + + } + + if (e2 == NULL) // None found + break; + + Part* part1 = e1->part(); + Part* part2 = e2->part(); + if (ce2.type() != Note) + continue; + + + unsigned event1pos = ce1.tick() + part1->tick(); + unsigned event1end = event1pos + ce1.lenTick(); + unsigned event2pos = ce2.tick() + part2->tick(); + + //printf("event1pos %u event1end %u event2pos %u\n", event1pos, event1end, event2pos); + if (event1end > event2pos) { + Event newEvent = ce1.clone(); + unsigned newlen = ce1.lenTick() - (event1end - event2pos); + //printf("newlen: %u\n", newlen); + newEvent.setLenTick(newlen); + // Indicate no undo, and do not do port controller values and clone parts. + //audio->msgChangeEvent(ce1, newEvent, e1->part(), false); + audio->msgChangeEvent(ce1, newEvent, e1->part(), false, false, false); + } + } + song->endUndo(SC_EVENT_MODIFIED); + break; + + + case CMD_CRESCENDO: + case CMD_TRANSPOSE: + case CMD_THIN_OUT: + case CMD_ERASE_EVENT: + case CMD_NOTE_SHIFT: + case CMD_MOVE_CLOCK: + case CMD_COPY_MEASURE: + case CMD_ERASE_MEASURE: + case CMD_DELETE_MEASURE: + case CMD_CREATE_MEASURE: + break; + default: +// printf("unknown ecanvas cmd %d\n", cmd); + break; + } + updateSelection(); + redraw(); + } + +//--------------------------------------------------------- +// quantize +//--------------------------------------------------------- + +void PianoCanvas::quantize(int strength, int limit, bool quantLen) + { + song->startUndo(); + for (iCItem k = items.begin(); k != items.end(); ++k) { + NEvent* nevent = (NEvent*)(k->second); + Event event = nevent->event(); + Part* part = nevent->part(); + if (event.type() != Note) + continue; + + if ((cmdRange & CMD_RANGE_SELECTED) && !k->second->isSelected()) + continue; + + unsigned tick = event.tick() + part->tick(); + + if ((cmdRange & CMD_RANGE_LOOP) + && ((tick < song->lpos() || tick >= song->rpos()))) + continue; + + unsigned int len = event.lenTick(); //prevent compiler warning: comparison singed/unsigned + int tick2 = tick + len; + + // quant start position + int diff = sigmap.raster(tick, editor->quant()) - tick; + if (abs(diff) > limit) + tick += ((diff * strength) / 100); + + // quant len + diff = sigmap.raster(tick2, editor->quant()) - tick2; + if (quantLen && (abs(diff) > limit)) + len += ((diff * strength) / 100); + + // something changed? + if (((event.tick() + part->tick()) != tick) || (event.lenTick() != len)) { + Event newEvent = event.clone(); + newEvent.setTick(tick - part->tick()); + newEvent.setLenTick(len); + // Indicate no undo, and do not do port controller values and clone parts. + //audio->msgChangeEvent(event, newEvent, part, false); + audio->msgChangeEvent(event, newEvent, part, false, false, false); + } + } + song->endUndo(SC_EVENT_MODIFIED); + } + +//--------------------------------------------------------- +// midiNote +//--------------------------------------------------------- + +void PianoCanvas::midiNote(int pitch, int velo) + { + if (_midiin && _steprec && curPart + && !audio->isPlaying() && velo && pos[0] >= start_tick + && pos[0] < end_tick + && !(globalKeyState & Qt::AltButton)) { + unsigned int len = editor->quant();//prevent compiler warning: comparison singed/unsigned + unsigned tick = pos[0]; //CDW + unsigned starttick = tick; + if (globalKeyState & Qt::ShiftButton) + tick -= editor->rasterStep(tick); + + // + // extend len of last note? + // + EventList* events = curPart->events(); + if (globalKeyState & Qt::ControlButton) { + for (iEvent i = events->begin(); i != events->end(); ++i) { + Event ev = i->second; + if (!ev.isNote()) + continue; + if (ev.pitch() == pitch && ((ev.tick() + ev.lenTick()) == /*(int)*/starttick)) { + Event e = ev.clone(); + e.setLenTick(ev.lenTick() + editor->rasterStep(starttick)); + // Indicate do undo, and do not do port controller values and clone parts. + //audio->msgChangeEvent(ev, e, curPart); + audio->msgChangeEvent(ev, e, curPart, true, false, false); + tick += editor->rasterStep(tick); + if (tick != song->cpos()) { + Pos p(tick, true); + song->setPos(0, p, true, false, true); + } + return; + } + } + } + + // + // if we already entered the note, delete it + // + EventRange range = events->equal_range(tick); + for (iEvent i = range.first; i != range.second; ++i) { + Event ev = i->second; + if (ev.isNote() && ev.pitch() == pitch) { + // Indicate do undo, and do not do port controller values and clone parts. + //audio->msgDeleteEvent(ev, curPart); + audio->msgDeleteEvent(ev, curPart, true, false, false); + if (globalKeyState & Qt::ShiftButton) + tick += editor->rasterStep(tick); + return; + } + } + Event e(Note); + e.setTick(tick - curPart->tick()); + e.setPitch(pitch); + e.setVelo(velo); + e.setLenTick(len); + // Indicate do undo, and do not do port controller values and clone parts. + //audio->msgAddEvent(e, curPart); + audio->msgAddEvent(e, curPart, true, false, false); + tick += editor->rasterStep(tick); + if (tick != song->cpos()) { + Pos p(tick, true); + song->setPos(0, p, true, false, true); + } + } + } + +//--------------------------------------------------------- +// getTextDrag +//--------------------------------------------------------- + +Q3TextDrag* PianoCanvas::getTextDrag(QWidget* parent) + { + //--------------------------------------------------- + // generate event list from selected events + //--------------------------------------------------- + + EventList el; + unsigned startTick = MAXINT; + for (iCItem i = items.begin(); i != items.end(); ++i) { + if (!i->second->isSelected()) + continue; + NEvent* ne = (NEvent*)(i->second); + Event e = ne->event(); + if (startTick == MAXINT) + startTick = e.tick(); + el.add(e); + } + + //--------------------------------------------------- + // write events as XML into tmp file + //--------------------------------------------------- + + FILE* tmp = tmpfile(); + if (tmp == 0) { + fprintf(stderr, "PianoCanvas::copy() fopen failed: %s\n", + strerror(errno)); + return 0; + } + Xml xml(tmp); + + int level = 0; + xml.tag(level++, "eventlist"); + for (ciEvent e = el.begin(); e != el.end(); ++e) + e->second.write(level, xml, -startTick); + xml.etag(--level, "eventlist"); + + //--------------------------------------------------- + // read tmp file into QTextDrag Object + //--------------------------------------------------- + + fflush(tmp); + struct stat f_stat; + if (fstat(fileno(tmp), &f_stat) == -1) { + fprintf(stderr, "PianoCanvas::copy() fstat failes:<%s>\n", + strerror(errno)); + fclose(tmp); + return 0; + } + int n = f_stat.st_size; + char* fbuf = (char*)mmap(0, n+1, PROT_READ|PROT_WRITE, + MAP_PRIVATE, fileno(tmp), 0); + fbuf[n] = 0; + Q3TextDrag* drag = new Q3TextDrag(QString(fbuf), parent); + drag->setSubtype("eventlist"); + munmap(fbuf, n); + fclose(tmp); + return drag; + } + +//--------------------------------------------------------- +// copy +// cut copy paste +//--------------------------------------------------------- + +void PianoCanvas::copy() + { + Q3TextDrag* drag = getTextDrag(0); + if (drag) + QApplication::clipboard()->setData(drag, QClipboard::Clipboard); + } + +//--------------------------------------------------------- +// paste +//--------------------------------------------------------- + +void PianoCanvas::pasteAt(const QString& pt, int pos) + { + const char* p = pt.latin1(); + Xml xml(p); + for (;;) { + Xml::Token token = xml.parse(); + const QString& tag = xml.s1(); + switch (token) { + case Xml::Error: + case Xml::End: + return; + case Xml::TagStart: + if (tag == "eventlist") { + song->startUndo(); + EventList* el = new EventList(); + el->read(xml, "eventlist", true); + int modified = SC_EVENT_INSERTED; + for (iEvent i = el->begin(); i != el->end(); ++i) { + Event e = i->second; + int tick = e.tick() + pos - curPart->tick(); + if (tick<0) { + printf("ERROR: trying to add event before current part!\n"); + song->endUndo(SC_EVENT_INSERTED); + delete el; + return; + } + + e.setTick(tick); + int diff = e.endTick()-curPart->lenTick(); + if (diff > 0) {// too short part? extend it + Part* newPart = curPart->clone(); + newPart->setLenTick(newPart->lenTick()+diff); + // Indicate no undo, and do port controller values but not clone parts. + //audio->msgChangePart(curPart, newPart,false); + audio->msgChangePart(curPart, newPart, false, true, false); + modified=modified|SC_PART_MODIFIED; + curPart = newPart; // reassign + } + // Indicate no undo, and do not do port controller values and clone parts. + //audio->msgAddEvent(e, curPart, false); + audio->msgAddEvent(e, curPart, false, false, false); + } + song->endUndo(modified); + delete el; + return; + } + else + xml.unknown("pasteAt"); + break; + case Xml::Attribut: + case Xml::TagEnd: + default: + break; + } + } + } +//--------------------------------------------------------- +// paste +// paste events +//--------------------------------------------------------- + +void PianoCanvas::paste() + { + //Q3CString subtype("eventlist"); ddskrjo + QString subtype("eventlist"); + QMimeSource* ms = QApplication::clipboard()->data(QClipboard::Clipboard); + QString pt; + if (!Q3TextDrag::decode(ms, pt, subtype)) { + printf("cannot paste: bad data type\n"); + return; + } + pasteAt(pt, song->cpos()); + } + +//--------------------------------------------------------- +// startDrag +//--------------------------------------------------------- + +void PianoCanvas::startDrag(CItem* /* item*/, bool copymode) + { + Q3TextDrag* drag = getTextDrag(this); + if (drag) { +// QApplication::clipboard()->setData(drag, QClipboard::Clipboard); + + if (copymode) + drag->dragCopy(); + else + drag->dragMove(); + } + } + +//--------------------------------------------------------- +// dragEnterEvent +//--------------------------------------------------------- + +void PianoCanvas::dragEnterEvent(QDragEnterEvent* event) + { + event->accept(Q3TextDrag::canDecode(event)); + } + +//--------------------------------------------------------- +// dragMoveEvent +//--------------------------------------------------------- + +void PianoCanvas::dragMoveEvent(QDragMoveEvent*) + { +// printf("drag move %x\n", this); + } + +//--------------------------------------------------------- +// dragLeaveEvent +//--------------------------------------------------------- + +void PianoCanvas::dragLeaveEvent(QDragLeaveEvent*) + { +// printf("drag leave\n"); + } + +//--------------------------------------------------------- +// dropEvent +//--------------------------------------------------------- + +void PianoCanvas::viewDropEvent(QDropEvent* event) + { + QString text; + if (event->source() == this) { + printf("local DROP\n"); + return; + } + if (Q3TextDrag::decode(event, text)) { + int x = editor->rasterVal(event->pos().x()); + if (x < 0) + x = 0; + pasteAt(text, x); + } + else { + printf("cannot decode drop\n"); + } + } + +//--------------------------------------------------------- +// itemPressed +//--------------------------------------------------------- + +void PianoCanvas::itemPressed(const CItem* item) + { + if (!_playEvents) + return; + + int port = track()->outPort(); + int channel = track()->outChannel(); + NEvent* nevent = (NEvent*) item; + Event event = nevent->event(); + playedPitch = event.pitch() + track()->transposition; + int velo = event.velo(); + + // play note: + MidiPlayEvent e(0, port, channel, 0x90, playedPitch, velo); + audio->msgPlayMidiEvent(&e); + } + +//--------------------------------------------------------- +// itemReleased +//--------------------------------------------------------- + +void PianoCanvas::itemReleased(const CItem*, const QPoint&) + { + if (!_playEvents) + return; + int port = track()->outPort(); + int channel = track()->outChannel(); + + // release note: + MidiPlayEvent ev(0, port, channel, 0x90, playedPitch, 0); + audio->msgPlayMidiEvent(&ev); + playedPitch = -1; + } + +//--------------------------------------------------------- +// itemMoved +//--------------------------------------------------------- + +void PianoCanvas::itemMoved(const CItem* item, const QPoint& pos) + { + int npitch = y2pitch(pos.y()); + if ((playedPitch != -1) && (playedPitch != npitch)) { + int port = track()->outPort(); + int channel = track()->outChannel(); + NEvent* nevent = (NEvent*) item; + Event event = nevent->event(); + + // release note: + MidiPlayEvent ev1(0, port, channel, 0x90, playedPitch, 0); + audio->msgPlayMidiEvent(&ev1); + // play note: + MidiPlayEvent e2(0, port, channel, 0x90, npitch + track()->transposition, event.velo()); + audio->msgPlayMidiEvent(&e2); + playedPitch = npitch + track()->transposition; + } + } + +//--------------------------------------------------------- +// curPartChanged +//--------------------------------------------------------- + +void PianoCanvas::curPartChanged() + { + editor->setCaption(getCaption()); + } + +//--------------------------------------------------------- +// modifySelected +//--------------------------------------------------------- + +void PianoCanvas::modifySelected(NoteInfo::ValType type, int delta) + { + audio->msgIdle(true); + song->startUndo(); + for (iCItem i = items.begin(); i != items.end(); ++i) { + if (!(i->second->isSelected())) + continue; + NEvent* e = (NEvent*)(i->second); + Event event = e->event(); + if (event.type() != Note) + continue; + + MidiPart* part = (MidiPart*)(e->part()); + Event newEvent = event.clone(); + + switch (type) { + case NoteInfo::VAL_TIME: + { + int newTime = event.tick() + delta; + if (newTime < 0) + newTime = 0; + newEvent.setTick(newTime); + } + break; + case NoteInfo::VAL_LEN: + { + int len = event.lenTick() + delta; + if (len < 1) + len = 1; + newEvent.setLenTick(len); + } + break; + case NoteInfo::VAL_VELON: + { + int velo = event.velo() + delta; + if (velo > 127) + velo = 127; + else if (velo < 0) + velo = 0; + newEvent.setVelo(velo); + } + break; + case NoteInfo::VAL_VELOFF: + { + int velo = event.veloOff() + delta; + if (velo > 127) + velo = 127; + else if (velo < 0) + velo = 0; + newEvent.setVeloOff(velo); + } + break; + case NoteInfo::VAL_PITCH: + { + int pitch = event.pitch() + delta; + if (pitch > 127) + pitch = 127; + else if (pitch < 0) + pitch = 0; + newEvent.setPitch(pitch); + } + break; + } + song->changeEvent(event, newEvent, part); + // Indicate do not do port controller values and clone parts. + //song->undoOp(UndoOp::ModifyEvent, newEvent, event, part); + song->undoOp(UndoOp::ModifyEvent, newEvent, event, part, false, false); + } + song->endUndo(SC_EVENT_MODIFIED); + audio->msgIdle(false); + } + diff --git a/muse2/muse/midiedit/prcanvas.h b/muse2/muse/midiedit/prcanvas.h new file mode 100644 index 00000000..2f50be2e --- /dev/null +++ b/muse2/muse/midiedit/prcanvas.h @@ -0,0 +1,113 @@ +//========================================================= +// MusE +// Linux Music Editor +// $Id: prcanvas.h,v 1.5.2.6 2009/11/16 11:29:33 lunar_shuttle Exp $ +// (C) Copyright 1999 Werner Schweer (ws@seh.de) +//========================================================= + +#ifndef __PRCANVAS_H__ +#define __PRCANVAS_H__ + +#include "ecanvas.h" +#include "pianoroll.h" +//Added by qt3to4: +#include <QDragEnterEvent> +#include <QDropEvent> +#include <QMouseEvent> +#include <QDragMoveEvent> +#include <QDragLeaveEvent> + +#define KH 13 + +//--------------------------------------------------------- +// NEvent +// ''visual'' Note Event +//--------------------------------------------------------- + +class NEvent : public CItem { + public: + NEvent(Event& e, Part* p, int y); + }; + +class ScrollScale; +class PianoRoll; +class Q3TextDrag; +class QRect; + +//--------------------------------------------------------- +// PianoCanvas +//--------------------------------------------------------- + +class PianoCanvas : public EventCanvas { + int cmdRange; + int colorMode; + int playedPitch; + + Q_OBJECT + virtual void viewMouseDoubleClickEvent(QMouseEvent*); + virtual void drawItem(QPainter&, const CItem*, const QRect&); + virtual void drawMoving(QPainter&, const CItem*, const QRect&); + virtual void moveCanvasItems(CItemList&, int, int, DragType, int*); + // Changed by T356. + //virtual bool moveItem(CItem*, const QPoint&, DragType, int*); + virtual bool moveItem(CItem*, const QPoint&, DragType); + virtual CItem* newItem(const QPoint&, int); + virtual void resizeItem(CItem*, bool noSnap); + virtual void newItem(CItem*, bool noSnap); + virtual bool deleteItem(CItem*); + virtual void startDrag(CItem* item, bool copymode); + virtual void dragEnterEvent(QDragEnterEvent* event); + virtual void dragMoveEvent(QDragMoveEvent*); + virtual void dragLeaveEvent(QDragLeaveEvent*); + virtual void viewDropEvent(QDropEvent* event); + virtual void addItem(Part*, Event&); + + int y2pitch(int) const; + int pitch2y(int) const; + virtual void drawCanvas(QPainter&, const QRect&); + void quantize(int, int, bool); + void copy(); + void paste(); + void pasteAt(const QString& pt, int pos); + Q3TextDrag* getTextDrag(QWidget*); + virtual void itemPressed(const CItem*); + virtual void itemReleased(const CItem*, const QPoint&); + virtual void itemMoved(const CItem*, const QPoint&); + virtual void curPartChanged(); + + private slots: + void midiNote(int pitch, int velo); + + signals: + void quantChanged(int); + void rasterChanged(int); + + public slots: + void pianoCmd(int); + void pianoPressed(int pitch, int velocity, bool shift); + void pianoReleased(int pitch, bool); + + public: + enum { + CMD_CUT, CMD_COPY, CMD_PASTE, CMD_DEL, + CMD_OVER_QUANTIZE, CMD_ON_QUANTIZE, CMD_ONOFF_QUANTIZE, + CMD_ITERATIVE_QUANTIZE, + CMD_SELECT_ALL, CMD_SELECT_NONE, CMD_SELECT_INVERT, + CMD_SELECT_ILOOP, CMD_SELECT_OLOOP, CMD_SELECT_PREV_PART, CMD_SELECT_NEXT_PART, + CMD_MODIFY_GATE_TIME, CMD_MODIFY_VELOCITY, + CMD_CRESCENDO, CMD_TRANSPOSE, CMD_THIN_OUT, CMD_ERASE_EVENT, + CMD_NOTE_SHIFT, CMD_MOVE_CLOCK, CMD_COPY_MEASURE, + CMD_ERASE_MEASURE, CMD_DELETE_MEASURE, CMD_CREATE_MEASURE, + CMD_FIXED_LEN, CMD_DELETE_OVERLAPS + }; + + PianoCanvas(MidiEditor*, QWidget*, int, int); + void cmd(int, int, int, bool, int); + void setColorMode(int mode) { + colorMode = mode; + redraw(); + } + virtual void modifySelected(NoteInfo::ValType type, int delta); + }; +#endif + diff --git a/muse2/muse/midiedit/quantconfig.cpp b/muse2/muse/midiedit/quantconfig.cpp new file mode 100644 index 00000000..f00b713f --- /dev/null +++ b/muse2/muse/midiedit/quantconfig.cpp @@ -0,0 +1,59 @@ +//========================================================= +// MusE +// Linux Music Editor +// $Id: quantconfig.cpp,v 1.2 2004/04/24 14:58:52 wschweer Exp $ +// +// (C) Copyright 1999/2003 Werner Schweer (ws@seh.de) +//========================================================= + +#include <qspinbox.h> +#include <qlayout.h> +#include <qlabel.h> +#include <qradiobutton.h> +#include <q3groupbox.h> +#include <q3whatsthis.h> + +#include "quantconfig.h" +//Added by qt3to4: +#include <Q3VBoxLayout> + +const char* wtStrengthTxt = QT_TR_NOOP("sets amount of quantization:\n" + "0 - no quantization\n" + "100 - full quantization"); +const char* wtQLimitTxt = QT_TR_NOOP("don't quantize notes above this tick limit"); +const char* wtQLenTxt = QT_TR_NOOP("quantize also note len as default"); + +//--------------------------------------------------------- +// QuantConfig +//--------------------------------------------------------- + +QuantConfig::QuantConfig(int s, int l, bool lenFlag) + : QDialog() + { + setCaption(tr("MusE: Config Quantize")); + Q3VBoxLayout* layout = new Q3VBoxLayout(this); + Q3GroupBox* gb = new Q3GroupBox(2, Qt::Horizontal, tr("Config Quantize"), this); + layout->addWidget(gb); + + QLabel* l1 = new QLabel(tr("Strength"), gb); + QSpinBox* sb1 = new QSpinBox(0, 100, 1, gb); + sb1->setSuffix(QString("%")); + sb1->setValue(s); + QLabel* l2 = new QLabel(tr("Donīt Quantize"), gb); + QSpinBox* sb2 = new QSpinBox(0, 500, 1, gb); + sb2->setValue(l); + QLabel* l3 = new QLabel(tr("Quant Len"), gb); + QRadioButton* but = new QRadioButton(gb); + but->setChecked(lenFlag); + connect(sb1, SIGNAL(valueChanged(int)), SIGNAL(setQuantStrength(int))); + connect(sb2, SIGNAL(valueChanged(int)), SIGNAL(setQuantLimit(int))); + connect(but, SIGNAL(toggled(bool)), SIGNAL(setQuantLen(bool))); + + Q3WhatsThis::add(l1, tr(wtStrengthTxt)); + Q3WhatsThis::add(sb1, tr(wtStrengthTxt)); + Q3WhatsThis::add(l2, tr(wtQLimitTxt)); + Q3WhatsThis::add(sb2, tr(wtQLimitTxt)); + Q3WhatsThis::add(l3, tr(wtQLenTxt)); + Q3WhatsThis::add(but, tr(wtQLenTxt)); + } + diff --git a/muse2/muse/midiedit/quantconfig.h b/muse2/muse/midiedit/quantconfig.h new file mode 100644 index 00000000..31ab2285 --- /dev/null +++ b/muse2/muse/midiedit/quantconfig.h @@ -0,0 +1,32 @@ +//========================================================= +// MusE +// Linux Music Editor +// $Id: quantconfig.h,v 1.1.1.1 2003/10/27 18:52:23 wschweer Exp $ +// +// (C) Copyright 1999/2000 Werner Schweer (ws@seh.de) +//========================================================= + +#ifndef __QCONFIG_H__ +#define __QCONFIG_H__ + +#include <qdialog.h> + +//--------------------------------------------------------- +// QuantConfig +//--------------------------------------------------------- + +class QuantConfig : public QDialog { + Q_OBJECT + + signals: + void setQuantStrength(int); + void setQuantLimit(int); + void setQuantLen(bool); + + public: + QuantConfig(int, int, bool); + }; + + +#endif + |
