[SCM] petri-foo/upstream: Imported Upstream version 0.0.2+20110904.gitbdb1bee1
alessio at users.alioth.debian.org
alessio at users.alioth.debian.org
Mon Jan 16 11:48:09 UTC 2012
The following commit has been merged in the upstream branch:
commit 6b49f65896d18e1f4035edae979b6cf909bb9677
Author: Alessio Treglia <alessio at debian.org>
Date: Mon Jan 16 12:45:48 2012 +0100
Imported Upstream version 0.0.2+20110904.gitbdb1bee1
diff --git a/AUTHORS b/AUTHORS
index 86bd45f..53e0701 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,3 +1,27 @@
+Petri-Foo AUTHORS
+-----------------
+
+* James W. Morris <james at jwm-art.net>
+
+ forker of Specimen to Petri-Foo, primary developer of Petri-Foo
+ added modulation routing, midi-cc as modulation sources, remover
+ of deprecated GUI code, etc, etc, etc.
+
+
+* Brenden Jones <brendan.jones.it at gmail.com>
+
+ Added auto-preview and a keyboard shortcut to sample-selector,
+ and minimum and maximum velocity values for patch.
+
+
+
+Specimen AUTHORS
+----------------
+
+Petri-Foo began as a fork of Specimen.
+
+Specimen was written by the following people:
+
-*- text -*-
* Pete Bessman <ninjadroid at gazuga.net>
@@ -58,10 +82,3 @@
* Eric Dantan Rzewnicki <eric at zhevny.com>
maintainer
-
-
-* James W. Morris <james at jwm-art.net>
-
- forker of Specimen to Petri-Foo, primary developer of Petri-Foo
- added modulation routing, midi-cc as modulation sources, remover
- of deprecated GUI code, etc, etc, etc.
diff --git a/AUTHORSRv b/AUTHORSRv
deleted file mode 100644
index 0f33114..0000000
--- a/AUTHORSRv
+++ /dev/null
@@ -1,65 +0,0 @@
--*- text -*-
-
-* Pete Bessman <ninjadroid at gazuga.net>
-
- Founder, primary developer untill 2005-09-14
-
-
-
-* Alexander <aharvey at ij.net>
-
- modified midi.c to treat note-on events with velocity of 0x00 as
- note-offs.
-
-* Dave Robillard <drobilla at connect.carleton.ca>
-
- Lash support. Removed Gnome-ui requirement for about dialog.
-
-* David R. Clark <davidrclark at earthlink.net>
-
- Invaluable testing, feedback, and discussion, as well as some nifty
- sample generating programs.
-
-* Dimitry Baikov <dsbaikov at gmail.com>
-
- Added support for MIDI CC events.
- Update to jack_midi API.
-
-* Lars Luthman <lars.luthman at gmail.com>
-
- Jack-midi implementation.
-
-* Loki Davison <ltdav1 at student.monash.edu>
-
- Sync code, and initial implementation of lots of stuff which got
- lost during The Cleansing. Responsible for convincing ninjadroid to
- keep on hacking.
-
-* Nedko Arnaudov <nedko at arnaudov.name>
-
- Made specimen window resizeable.
-
-* peter <kickback at users.sourceforge.net>
-
- Rewrote the build system during the year of limbo.
-
-* Sacha Berger <sacha at woanders.de>
-
- updated beef.c to reflect newly gained parameters.
-
-* Thorsten Wilms <t_w_ at freenet.de>
-
- UI advice, and designed the fansliders used extensively in the GUI.
-
-* Torben Hohn <torbenh at users.sourceforge.net>
-
- was an immense help to Pete in optimizing the waveform code (and he
- pointed out that it needed to be done in the first place).
-
-
-
-
-
-* Eric Dantan Rzewnicki <eric at zhevny.com>
-
- maintainer
diff --git a/BUGS b/BUGS
index debbf39..a76cdb1 100644
--- a/BUGS
+++ b/BUGS
@@ -1,42 +1,5 @@
-KNOWN BUGS
-==========
+File all bug reports in the bug tracker at https://sourceforge.net/tracker/?group_id=404816
-* mixer_mixdown is sometimes called before mixer_set_jack_client
-resulting in a segfault. i've not yet determined if that statement
-is true or not, but it seems likely.
+Thanks.
-
-
-
-
--------------------------
-the list that follows is inherited from Specimen. i've not actually checked
-if it is still relevant or not - jwm 2011/03/28
-
-Known Bugs
-==========
-
-* Create some patches, load some samples, connect to JACK, and start
-running a MIDI pattern . Then, flick back and forth between the
-patches quickly (a mousewheel is handy for this). JACK will fail with
-something along the lines of "unable to execute processing graph
-(invalid file descriptor)". JACK will stop processing data until
-Specimen is closed (it will exit with a segfault); JACK and all of
-it's clients will then resume normal operation. [This seems to have
-magically disappeared, which I find quite disturbing. Can anybody
-reproduce it? --pete]
-
-* Sample start/stop and loop points don't behave properly when
-switching audio sample rates. It's probably time to store the audio
-sample rate along with the session file, BTW.
-
-* Midi syncing appears to be broken with Fedora Core 2's kernel. If
-you compile --enable-debug you'll see the gory details.
-
-* Midi syncing drifts like a bitch anyway.
-
-* Help -> About -> credits causes a segfault.
-
-* audio settings dialog currently resets jack client name to default
-"specimen" instead of using previously set name.
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..de5169f
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,156 @@
+cmake_minimum_required(VERSION 2.6)
+
+if (COMMAND CMAKE_POLICY)
+ cmake_policy (SET CMP0011 NEW)
+endif (COMMAND CMAKE_POLICY)
+
+project(Petri-Foo)
+
+set(Petri-Foo_VERSION_MAJOR 0)
+set(Petri-Foo_VERSION_MINOR 3)
+set(BINDIR "bin" CACHE STRING "Where to install binaries")
+set(DATADIR "share/petri-foo" CACHE STRING "Where to install data files")
+set(APPLICATIONS_DIR "share/applications" CACHE STRING "Where to install desktop files")
+set(PIXMAPS_DIR "share/pixmaps" CACHE STRING "Where to install icons")
+set(MIME_DIR "share/mime" CACHE STRING "Where MIME definitions are located")
+set(UpdateMime "ON" CACHE BOOL "Update Mime Database")
+
+mark_as_advanced(EXECUTABLE_OUTPUT_PATH)
+mark_as_advanced(LIBRARY_OUTPUT_PATH)
+mark_as_advanced(CMAKE_BUILD_TYPE)
+mark_as_advanced(CMAKE_INSTALL_PREFIX)
+
+option (BuildForDebug "Include gdb debugging support" ON)
+
+# DEBUG
+set (BuildOptionsDebug "-O0 -ggdb" CACHE STRING "Debug build flags")
+
+# additional compiler flags
+add_definitions(-Wall -Wextra)
+
+if (BuildForDebug)
+ set (CMAKE_BUILD_TYPE "Debug")
+ set (DEBUG 1)
+ set (CMAKE_C_FLAGS_DEBUG ${BuildOptionsDebug})
+ message (STATUS "Building for ${CMAKE_BUILD_TYPE}, flags: ${CMAKE_C_FLAGS_DEBUG}")
+else (BuildForDebug)
+ set (CMAKE_BUILD_TYPE "Release")
+ set (DEBUG 0)
+ set (CMAKE_C_FLAGS_RELEASE ${BuildOptionsBasic})
+ message (STATUS "Building for ${CMAKE_BUILD_TYPE}, flags: ${CMAKE_C_FLAGS_RELEASE}")
+endif (BuildForDebug)
+
+
+# PKG-CONFIG
+find_package(PkgConfig REQUIRED)
+if(PKG_CONFIG_FOUND)
+ message(STATUS "Found pkg-config ${PKG_CONFIG_EXECUTABLE}")
+else(PKG_CONFIG_FOUND)
+ message(FATAL_ERROR "pkg-config required but not found")
+endif(PKG_CONFIG_FOUND)
+
+
+# JACK
+pkg_check_modules(JACK REQUIRED jack>=0.120.0)
+if (JACK_FOUND)
+ message(STATUS "Found jack ${JACK_VERSION}")
+else (JACK_FOUND)
+ message(FATAL_ERROR "Jack >= 0.120.0 not found.")
+endif (JACK_FOUND)
+
+
+# ALSA
+pkg_check_modules(ALSA REQUIRED alsa>=1.0.17)
+if (ALSA_FOUND)
+ message(STATUS "Found alsa ${ALSA_VERSION}")
+else (ALSA_FOUND)
+ message(FATAL_ERROR "alsa not found.")
+endif (ALSA_FOUND)
+
+
+# SNDFILE
+pkg_check_modules (SNDFILE REQUIRED sndfile)
+if (SNDFILE_FOUND)
+ message(STATUS "Found sndfile ${SNDFILE_VERSION}")
+else (SNDFILE_FOUND)
+ message(FATAL_ERROR "sndfile not found")
+endif (SNDFILE_FOUND)
+
+
+# SAMPLERATE
+pkg_check_modules (SAMPLERATE REQUIRED samplerate)
+if (SAMPLERATE_FOUND)
+ message(STATUS "Found secret rabbit code ${SAMPLERATE_VERSION}")
+else (SAMPLERATE_FOUND)
+ message(FATAL_ERROR "secret rabbit code not found")
+endif (SAMPLERATE_FOUND)
+
+
+# GLIB2
+pkg_check_modules (GLIB2 REQUIRED glib-2.0>=2.16)
+if (GLIB2_FOUND)
+ message(STATUS "Found glib2 ${GLIB2_VERSION}")
+else (GLIB2_FOUND)
+ message(FATAL_ERROR "glib2 was not found.")
+endif (GLIB2_FOUND)
+
+
+# GTK2
+pkg_check_modules (GTK2 REQUIRED gtk+-2.0)
+if(GTK2_FOUND)
+ message(STATUS "Found gtk2 ${GTK2_VERSION}")
+else(GTK2_FOUND)
+ message(FATAL_ERROR "gtk2 required but not found")
+endif(GTK2_FOUND)
+
+
+# LIBGNOMECANVAS2
+pkg_check_modules (LIBGNOMECANVAS2 REQUIRED libgnomecanvas-2.0)
+if (LIBGNOMECANVAS2_FOUND)
+ message(STATUS "Found libgnomecanvas2 ${LIBGNOMECANVAS2_VERSION}")
+else (LIBGNOMECANVAS2_FOUND)
+ message(FATAL_ERROR "libgnomecanvas2 was not found.")
+endif (LIBGNOMECANVAS2_FOUND)
+
+
+# LIBXML2
+pkg_check_modules (LIBXML2 REQUIRED libxml-2.0)
+if (LIBXML2_FOUND)
+ message(STATUS "Found libxml2 ${LIBXML2_VERSION}")
+else (LIBXML2_FOUND)
+ message(FATAL_ERROR "libxml2 was not found")
+endif (LIBXML2_FOUND)
+
+
+INCLUDE (CheckIncludeFiles)
+CHECK_INCLUDE_FILES (malloc.h HAVE_MALLOC_H)
+CHECK_INCLUDE_FILES (jack/session.h HAVE_JACK_SESSION_H)
+CONFIGURE_FILE( ${CMAKE_CURRENT_SOURCE_DIR}/config.h.in
+ ${CMAKE_CURRENT_BINARY_DIR}/config.h )
+
+link_libraries(m)
+
+include_directories ( . )
+
+# Install targets
+
+ADD_SUBDIRECTORY( libpetrifoo )
+ADD_SUBDIRECTORY( libpetrifui )
+ADD_SUBDIRECTORY( libphin )
+ADD_SUBDIRECTORY( gui )
+
+#ADD_SUBDIRECTORY( pixmaps )
+
+install (DIRECTORY pixmaps/ DESTINATION ${DATADIR}/pixmaps
+ FILES_MATCHING PATTERN "*.png")
+install (FILES petri-foo.xml DESTINATION ${MIME_DIR}/packages)
+install (FILES pixmaps/petri-foo.png DESTINATION ${PIXMAPS_DIR})
+install (FILES petri-foo.desktop DESTINATION ${APPLICATIONS_DIR})
+
+if (UpdateMime)
+ install (CODE
+ "EXEC_PROGRAM ( \"update-mime-database ${CMAKE_INSTALL_PREFIX}/${MIME_DIR}\" ) "
+ )
+endif (UpdateMime)
+
+
diff --git a/ChangeLog b/ChangeLog
index ac423fb..da1726e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,115 @@
+2011-08-06 Brendan Jones <brendan.jones.it at gmail.com>
+
+ * gui/global_settings.[ch]
+ Stores last-used sample and bank directories into
+ XDG_CONFIG_HOME/petri-foo/rc.xml
+
+
+2011-08-06 James Morris <james at jwm-art.net>
+
+ * New zoom-in, zoom-out, zoom-fit, and zoom-1:1 buttons
+ these buttons replace the cruddy oldspin button previously
+ used for zooming and which the values of were meaningless.
+
+ * Mouse-wheel zooming.
+ Moving the mouse-wheel down will zoom in to wherever the
+ pointer is pointing in the waveform.
+
+ * Probably stuff which I've forgotten and not added into
+ this Changelog.
+
+ * PHIN fan sliders have fans disabled by default.
+ the fans of the fan sliders require desktop compositing
+ so are disabled by default.
+
+ * PHIN fan slider setting stored via global_settings
+
+ * sample.c: Fixed raw/headerless sample loading
+
+ * float_section.c: Fixed portamento time setting.
+
+
+2011-07-26 James Morris <james at jwm-art.net>
+
+ * new build system using cmake. alter dir structures.
+
+ * include subset of PHAT in build and call it phin.
+
+
+2011-07-23 James Morris <james at jwm-art.net>
+
+ * patch_util.c, new function: patch_get_samplerate(void)
+
+ * dish_file.c: current samplerate is written into the
+ dish_file within the "Master" node. This means that if the
+ bank is loaded at a later date and JACK is running at a
+ different samplerate, the values for the play+loop points
+ can be adjusted accordingly for the resampled audio-data.
+
+ * sample.[ch]: removed resample_ratio from struct _Sample.
+ the resample_ratio member was added in the previous commit
+ and removed again due to the dish_file being responsible
+ for calculating differences in play+loop points when
+ JACK samplerate changes (between instances, not during a
+ single instance).
+
+ * sample.c, sample_default: scaled output of LFO.
+ scale output of LFO to prevent the default sample having
+ samples exceeding the range -1.0 to +1.0.
+
+
+2011-07-20 James Morris <james at jwm-art.net>
+
+ * dish_file.c: fix/restore read/write of Portamento/Legato
+
+ * sample.[ch]: added sample_get_resampled_size
+ this function provides a means to get the size the
+ sample will use once loaded. this is required for when
+ soft-limits to the size of samples petri-foo will load
+ is implemented.
+
+ * sample.[ch]: addition and usage of MAX_SAMPLE_FRAMES
+ enumeration MAX_SAMPLE_FRAMES = INT32_MAX; replaces
+ previous detection of overly-large samples by casting
+ sf_count_t variables to int and noticing difference.
+
+ * patch_util.c, patch_sample_load: scale loop points.
+ loop points of the default sample are now scaled to
+ the global sample rate as they should.
+
+
+2011-07-19 James Morris <james at jwm-art.net>
+
+ * Minimum and maximum Velocity value specification
+ for patche to allow velocity layering of patches.
+ Thanks to Brendan Jones for submitting patch.
+
+ * mod_section.c: fix bug in amplitude modulation amount
+ Finally fixed this bug by the removal of a dangerously
+ misplaced else.
+
+ * --unconnected command line option to not auto-connect
+ JACK ports. This is required for JACK Session to work
+ properly.
+
+ * patch.c, patch_set_and_get.c, mod_section.c:
+ inverted velocity mapping
+ Allows negative setting of velocity sensitivity. Means
+ you can cause low velocity to have the effect of high
+ velocity and vice-versa.
+
+
+2011-07-14 James Morris <james at jwm-art.net>
+
+ * Auto preview toggle added to the sample selector
+ dialog so that samples automatically play without
+ loading.
+
+ * Added keyboard shortcut for 'Loa_d' in sample selector.
+
+Thanks to Brendan Jones for submitting these additions.
+
+
2011-06-30 James Morris <james at jwm-art.net>
* added gpl header to all source files
diff --git a/INSTALL b/INSTALL
deleted file mode 100644
index 54caf7c..0000000
--- a/INSTALL
+++ /dev/null
@@ -1,229 +0,0 @@
-Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software
-Foundation, Inc.
-
- This file is free documentation; the Free Software Foundation gives
-unlimited permission to copy, distribute and modify it.
-
-Basic Installation
-==================
-
- These are generic installation instructions.
-
- The `configure' shell script attempts to guess correct values for
-various system-dependent variables used during compilation. It uses
-those values to create a `Makefile' in each directory of the package.
-It may also create one or more `.h' files containing system-dependent
-definitions. Finally, it creates a shell script `config.status' that
-you can run in the future to recreate the current configuration, and a
-file `config.log' containing compiler output (useful mainly for
-debugging `configure').
-
- It can also use an optional file (typically called `config.cache'
-and enabled with `--cache-file=config.cache' or simply `-C') that saves
-the results of its tests to speed up reconfiguring. (Caching is
-disabled by default to prevent problems with accidental use of stale
-cache files.)
-
- If you need to do unusual things to compile the package, please try
-to figure out how `configure' could check whether to do them, and mail
-diffs or instructions to the address given in the `README' so they can
-be considered for the next release. If you are using the cache, and at
-some point `config.cache' contains results you don't want to keep, you
-may remove or edit it.
-
- The file `configure.ac' (or `configure.in') is used to create
-`configure' by a program called `autoconf'. You only need
-`configure.ac' if you want to change it or regenerate `configure' using
-a newer version of `autoconf'.
-
-The simplest way to compile this package is:
-
- 1. `cd' to the directory containing the package's source code and type
- `./configure' to configure the package for your system. If you're
- using `csh' on an old version of System V, you might need to type
- `sh ./configure' instead to prevent `csh' from trying to execute
- `configure' itself.
-
- Running `configure' takes awhile. While running, it prints some
- messages telling which features it is checking for.
-
- 2. Type `make' to compile the package.
-
- 3. Optionally, type `make check' to run any self-tests that come with
- the package.
-
- 4. Type `make install' to install the programs and any data files and
- documentation.
-
- 5. You can remove the program binaries and object files from the
- source code directory by typing `make clean'. To also remove the
- files that `configure' created (so you can compile the package for
- a different kind of computer), type `make distclean'. There is
- also a `make maintainer-clean' target, but that is intended mainly
- for the package's developers. If you use it, you may have to get
- all sorts of other programs in order to regenerate files that came
- with the distribution.
-
-Compilers and Options
-=====================
-
- Some systems require unusual options for compilation or linking that
-the `configure' script does not know about. Run `./configure --help'
-for details on some of the pertinent environment variables.
-
- You can give `configure' initial values for configuration parameters
-by setting variables in the command line or in the environment. Here
-is an example:
-
- ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix
-
- *Note Defining Variables::, for more details.
-
-Compiling For Multiple Architectures
-====================================
-
- You can compile the package for more than one kind of computer at the
-same time, by placing the object files for each architecture in their
-own directory. To do this, you must use a version of `make' that
-supports the `VPATH' variable, such as GNU `make'. `cd' to the
-directory where you want the object files and executables to go and run
-the `configure' script. `configure' automatically checks for the
-source code in the directory that `configure' is in and in `..'.
-
- If you have to use a `make' that does not support the `VPATH'
-variable, you have to compile the package for one architecture at a
-time in the source code directory. After you have installed the
-package for one architecture, use `make distclean' before reconfiguring
-for another architecture.
-
-Installation Names
-==================
-
- By default, `make install' will install the package's files in
-`/usr/local/bin', `/usr/local/man', etc. You can specify an
-installation prefix other than `/usr/local' by giving `configure' the
-option `--prefix=PATH'.
-
- You can specify separate installation prefixes for
-architecture-specific files and architecture-independent files. If you
-give `configure' the option `--exec-prefix=PATH', the package will use
-PATH as the prefix for installing programs and libraries.
-Documentation and other data files will still use the regular prefix.
-
- In addition, if you use an unusual directory layout you can give
-options like `--bindir=PATH' to specify different values for particular
-kinds of files. Run `configure --help' for a list of the directories
-you can set and what kinds of files go in them.
-
- If the package supports it, you can cause programs to be installed
-with an extra prefix or suffix on their names by giving `configure' the
-option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
-
-Optional Features
-=================
-
- Some packages pay attention to `--enable-FEATURE' options to
-`configure', where FEATURE indicates an optional part of the package.
-They may also pay attention to `--with-PACKAGE' options, where PACKAGE
-is something like `gnu-as' or `x' (for the X Window System). The
-`README' should mention any `--enable-' and `--with-' options that the
-package recognizes.
-
- For packages that use the X Window System, `configure' can usually
-find the X include and library files automatically, but if it doesn't,
-you can use the `configure' options `--x-includes=DIR' and
-`--x-libraries=DIR' to specify their locations.
-
-Specifying the System Type
-==========================
-
- There may be some features `configure' cannot figure out
-automatically, but needs to determine by the type of machine the package
-will run on. Usually, assuming the package is built to be run on the
-_same_ architectures, `configure' can figure that out, but if it prints
-a message saying it cannot guess the machine type, give it the
-`--build=TYPE' option. TYPE can either be a short name for the system
-type, such as `sun4', or a canonical name which has the form:
-
- CPU-COMPANY-SYSTEM
-
-where SYSTEM can have one of these forms:
-
- OS KERNEL-OS
-
- See the file `config.sub' for the possible values of each field. If
-`config.sub' isn't included in this package, then this package doesn't
-need to know the machine type.
-
- If you are _building_ compiler tools for cross-compiling, you should
-use the `--target=TYPE' option to select the type of system they will
-produce code for.
-
- If you want to _use_ a cross compiler, that generates code for a
-platform different from the build platform, you should specify the
-"host" platform (i.e., that on which the generated programs will
-eventually be run) with `--host=TYPE'.
-
-Sharing Defaults
-================
-
- If you want to set default values for `configure' scripts to share,
-you can create a site shell script called `config.site' that gives
-default values for variables like `CC', `cache_file', and `prefix'.
-`configure' looks for `PREFIX/share/config.site' if it exists, then
-`PREFIX/etc/config.site' if it exists. Or, you can set the
-`CONFIG_SITE' environment variable to the location of the site script.
-A warning: not all `configure' scripts look for a site script.
-
-Defining Variables
-==================
-
- Variables not defined in a site shell script can be set in the
-environment passed to `configure'. However, some packages may run
-configure again during the build, and the customized values of these
-variables may be lost. In order to avoid this problem, you should set
-them in the `configure' command line, using `VAR=value'. For example:
-
- ./configure CC=/usr/local2/bin/gcc
-
-will cause the specified gcc to be used as the C compiler (unless it is
-overridden in the site shell script).
-
-`configure' Invocation
-======================
-
- `configure' recognizes the following options to control how it
-operates.
-
-`--help'
-`-h'
- Print a summary of the options to `configure', and exit.
-
-`--version'
-`-V'
- Print the version of Autoconf used to generate the `configure'
- script, and exit.
-
-`--cache-file=FILE'
- Enable the cache: use and save the results of the tests in FILE,
- traditionally `config.cache'. FILE defaults to `/dev/null' to
- disable caching.
-
-`--config-cache'
-`-C'
- Alias for `--cache-file=config.cache'.
-
-`--quiet'
-`--silent'
-`-q'
- Do not print messages saying which checks are being made. To
- suppress all normal output, redirect it to `/dev/null' (any error
- messages will still be shown).
-
-`--srcdir=DIR'
- Look for the package's source code in directory DIR. Usually
- `configure' can determine that directory automatically.
-
-`configure' also accepts some other, not widely useful, options. Run
-`configure --help' for more details.
-
diff --git a/Makefile.am b/Makefile.am
deleted file mode 100644
index 35b0918..0000000
--- a/Makefile.am
+++ /dev/null
@@ -1,3 +0,0 @@
-SUBDIRS = src pixmaps
-
-EXTRA_DIST = acx_pthread.m4 petri-foo.spec bootstrap BUGS ROADMAP WISHLIST
diff --git a/NEWS b/NEWS
index e69de29..cf9f12e 100644
--- a/NEWS
+++ b/NEWS
@@ -0,0 +1 @@
+See the Changelog and/or mailing list.
diff --git a/README b/README
index 2ee8752..9eabe88 100644
--- a/README
+++ b/README
@@ -5,75 +5,37 @@ Petri-Foo is a fork of the Specimen Sampler project. Specimen was
originally developed by Pete Bessman. See the AUTHORS file for
the list of other authors who've made contributions.
-Petri-Foo is forked and developed by James Morris.
-
-
-STAGE I GOALS
--------------
-
-The primary goal of forking Specimen to create Petri-Foo was to allow
-frequency modulation of the LFOs, and to allow user selection of
-modulation sources throughout the program.
-
-This has been accomplished.
-
-
-STAGE II GOALS
---------------
-
-Once stage 1 was complete, these were ideas I originally planned upon
-implementing:
-
- * Sample position retrigger by LFO. TODO.
- * Sample start position modulation. TODO.
- * Sample loop position modulation. TODO.
- * X-fades for loops/retriggers. Basic implementation..
-
- * Replace existing filter implementation. TODO.
- * Visual display of ADSRs and LFOs. FORGOTTEN.
- * Noise modulation source. TODO.
- * Sample and Hold. TODO.
-
- * Effects via LADSPA/LV2 UNNECESSARY
-
-
-WHAT HAPPENED INSTEAD
----------------------
-
- * Removal of deprecated GTK/GDK code
- * Default auto-generated patch/sample
- * Many code re-arrangements
- * Mark navigation in waveform display
- * Opening of raw audio formats
- * Complete rewrite of bank file I/O code and XML file layout.
- * MIDI Controllers subsumed as modulation sources.
- * Amplitude modulation added to LFOs.
-
-
-STAGE III GOALS
----------------
-
- * Obtain a stable feature set
- * Sort out value mapping of MIDI controllers
- * Figure out how to best handle state/switchable items that are
- often controlled by MIDI controllers (ie portamento on/off)
- + Sample point modulation as listed in stage 2 goals
- + Figure out how to best handle things that are triggered
- - Random/noise source
- - Sample and hold
-
-
-DEVELOPMENT
------------
-
-Development can be followed at http://github.com/jwm-art-net/Petri-Foo
-
-
-
-WHY HAVE I FORKED SPECIMEN?
----------------------------
-
-1) I think my changes are too much of a departure.
-2) Development of Specimen was dead.
-3) I had ideas for which I wanted the freedom to follow.
-
+Petri-Foo is forked and developed by James Morris (Feb 2011 +),
+with recent code contributions by Brendan Jones (July 2011 +).
+
+
+Differences, additions and improvements over Specimen
+------------------------------------------------------
+
+ * Default patch with saw-wave sample.
+ * Raw/Headerless sample file loading.
+ * JACK session support.
+ * Auto-Preview samples within the file selector.
+ * User-interface updated to contemporary GTK2 standards.
+ * Improved waveform rendering.
+ * Improved visual indication of play and loop selections.
+ * Play and loop point navigation.
+ * Improved waveform zooming, and addition of mouse-wheel zooming.
+ * Fading and X-Fading of sample.
+ * Improved MIDI CC handling.
+ * User-configurable modulation routing of ADSR, LFO, and MIDI CC.
+ * Keyboard tracking, and inverted keyboard tracking.
+ * Overall ADSR time scalable by keyboard tracking.
+ * Per-patch velocity range.
+ * Invertible velocity sensing.
+ * Amplitude modulation of LFO output.
+ * Removal of deprecated code, and customized PHAT library
+ for an improved life-span.
+ * Last-used directory recall.
+ * Shift/Control + Left-Mouse-Click for increased slider precision.
+ * JACK Audio output only, ALSA audio output removed[2].
+ * Removed LASH support.
+
+
+Further information about Petri-Foo can always be found at:
+http://petri-foo.sourceforge.net
diff --git a/ROADMAP b/ROADMAP
deleted file mode 100644
index de9f38f..0000000
--- a/ROADMAP
+++ /dev/null
@@ -1,15 +0,0 @@
-strip out old build system
-add new build system from peter <zenadsl6252 at zen.co.uk>
- make it work with just specimen devel
-merge jack midi
- test build
- test functionality
-merge lash patch
- test build
- test functionality
-jack_client_new vs _open change
-release 0.5.2rcN
- fix bugs
- repeat
-release 0.5.2
-
diff --git a/TODO b/TODO
index 2a65517..261a3ad 100644
--- a/TODO
+++ b/TODO
@@ -1,16 +1,4 @@
-
-***********************************************************************
--Engine: specimen can have portamento turned on/off via midi cc,
-
- petri-foo is not currently capable of such a thing.
- implement method of doing so, giving user same range of
- choice as existing modulation slots.
-
- the method should be capable to be used by other parameters
- such as playback mode, sample positions, monophonic + legato
- operation
-***********************************************************************
-
+-Engine: Mono/Poly mode switching via midi-cc (see notes on petri-foo-devel)
-Engine: Voice modes
+polyphonic re-trigger mode (new note repetition cuts old note).
@@ -20,6 +8,7 @@
-Engine: Velocity sensitivity
+add to eg's for amplitude modulation (i'm not convinced by this)
+ (note this has been coded but was commented out).
-Engine: Logarithmic Amplitudes
+Fix and remove artefacts arising from use of LAT for log_amplitude
@@ -29,6 +18,10 @@
-GUI: general
+replace PHAT widgets with something else?
+custom cairo based widgets?
+ Petri-Foo now uses Phin instead of PHAT. Phin is a modified
+ fork of PHAT which uses Cairo and avoids deprecated GTK/GDK code,
+ with the fans on the sliders disabled but default by allowed to
+ be enabled by users of compositing desktop environments.
-GUI: Patch List:
diff --git a/TODO.specimen b/TODO.specimen
index 0d00347..acb2fec 100644
--- a/TODO.specimen
+++ b/TODO.specimen
@@ -1,4 +1,4 @@
-(TODO file from the Specimen project)
+(TODO file from the Specimen project, edited: 19/07/2011)
-Add per-channel volume and panning parameters
@@ -11,15 +11,8 @@
-Make "loop to end" optional
--Create a better file format
-
--Make a sample browser
-
-Allow patches to have their own JACK ports
--Automatically append .beef to a filename when saving a bank if it
- doesn't have that already
-
-Make it possible to copy and paste whole parameter tabs
-A way to import a bunch of samples at once
@@ -27,18 +20,10 @@
-TOOLTIPS! Or a status bar... or tooltips AND a statusbar! This is
low hanging fruit, any takers? Please? FOR THE LOVE OF GOD!!!
--Make the bank save-as dialog prompt you before overwriting
-an existing file
-
--Allow patches to host a few effects
-
-Allow for longer times in the Envelopes and LFOs using non-linear sliders
-Add more filter types
--Figure out why some parts of the gui don't redraw properly, such as
-the waveform and the audio-settings window
-
-Add a progressbar when loading soundfiles and banks
-Fix syncing drift
@@ -66,4 +51,3 @@ the waveform and the audio-settings window
-Add a sampling capability
--Fix --enable-debug, which currently does nothing
diff --git a/WISHLIST b/WISHLIST
index 6126ae5..6f104e5 100644
--- a/WISHLIST
+++ b/WISHLIST
@@ -1,6 +1,3 @@
-lash -everyone
-jack-midi -everyone
-
multiple jack outs -thorwil, yves potin
envelope, velocity controllable plugins -thorwil, larsl
diff --git a/acx_pthread.m4 b/acx_pthread.m4
deleted file mode 100644
index 27079de..0000000
--- a/acx_pthread.m4
+++ /dev/null
@@ -1,199 +0,0 @@
-dnl Available from the GNU Autoconf Macro Archive at:
-dnl http://www.gnu.org/software/ac-archive/htmldoc/acx_pthread.html
-dnl
-AC_DEFUN([ACX_PTHREAD], [
-AC_REQUIRE([AC_CANONICAL_HOST])
-AC_LANG_SAVE
-AC_LANG_C
-acx_pthread_ok=no
-
-# We used to check for pthread.h first, but this fails if pthread.h
-# requires special compiler flags (e.g. on True64 or Sequent).
-# It gets checked for in the link test anyway.
-
-# First of all, check if the user has set any of the PTHREAD_LIBS,
-# etcetera environment variables, and if threads linking works using
-# them:
-if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
- save_CFLAGS="$CFLAGS"
- CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
- save_LIBS="$LIBS"
- LIBS="$PTHREAD_LIBS $LIBS"
- AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
- AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes)
- AC_MSG_RESULT($acx_pthread_ok)
- if test x"$acx_pthread_ok" = xno; then
- PTHREAD_LIBS=""
- PTHREAD_CFLAGS=""
- fi
- LIBS="$save_LIBS"
- CFLAGS="$save_CFLAGS"
-fi
-
-# We must check for the threads library under a number of different
-# names; the ordering is very important because some systems
-# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
-# libraries is broken (non-POSIX).
-
-# Create a list of thread flags to try. Items starting with a "-" are
-# C compiler flags, and other items are library names, except for "none"
-# which indicates that we try without any flags at all, and "pthread-config"
-# which is a program returning the flags for the Pth emulation library.
-
-acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
-
-# The ordering *is* (sometimes) important. Some notes on the
-# individual items follow:
-
-# pthreads: AIX (must check this before -lpthread)
-# none: in case threads are in libc; should be tried before -Kthread and
-# other compiler flags to prevent continual compiler warnings
-# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
-# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
-# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
-# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
-# -pthreads: Solaris/gcc
-# -mthreads: Mingw32/gcc, Lynx/gcc
-# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
-# doesn't hurt to check since this sometimes defines pthreads too;
-# also defines -D_REENTRANT)
-# pthread: Linux, etcetera
-# --thread-safe: KAI C++
-# pthread-config: use pthread-config program (for GNU Pth library)
-
-case "${host_cpu}-${host_os}" in
- *solaris*)
-
- # On Solaris (at least, for some versions), libc contains stubbed
- # (non-functional) versions of the pthreads routines, so link-based
- # tests will erroneously succeed. (We need to link with -pthread or
- # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
- # a function called by this macro, so we could check for that, but
- # who knows whether they'll stub that too in a future libc.) So,
- # we'll just look for -pthreads and -lpthread first:
-
- acx_pthread_flags="-pthread -pthreads pthread -mt $acx_pthread_flags"
- ;;
-esac
-
-if test x"$acx_pthread_ok" = xno; then
-for flag in $acx_pthread_flags; do
-
- case $flag in
- none)
- AC_MSG_CHECKING([whether pthreads work without any flags])
- ;;
-
- -*)
- AC_MSG_CHECKING([whether pthreads work with $flag])
- PTHREAD_CFLAGS="$flag"
- ;;
-
- pthread-config)
- AC_CHECK_PROG(acx_pthread_config, pthread-config, yes, no)
- if test x"$acx_pthread_config" = xno; then continue; fi
- PTHREAD_CFLAGS="`pthread-config --cflags`"
- PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
- ;;
-
- *)
- AC_MSG_CHECKING([for the pthreads library -l$flag])
- PTHREAD_LIBS="-l$flag"
- ;;
- esac
-
- save_LIBS="$LIBS"
- save_CFLAGS="$CFLAGS"
- LIBS="$PTHREAD_LIBS $LIBS"
- CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
-
- # Check for various functions. We must include pthread.h,
- # since some functions may be macros. (On the Sequent, we
- # need a special flag -Kthread to make this header compile.)
- # We check for pthread_join because it is in -lpthread on IRIX
- # while pthread_create is in libc. We check for pthread_attr_init
- # due to DEC craziness with -lpthreads. We check for
- # pthread_cleanup_push because it is one of the few pthread
- # functions on Solaris that doesn't have a non-functional libc stub.
- # We try pthread_create on general principles.
- AC_TRY_LINK([#include <pthread.h>],
- [pthread_t th; pthread_join(th, 0);
- pthread_attr_init(0); pthread_cleanup_push(0, 0);
- pthread_create(0,0,0,0); pthread_cleanup_pop(0); ],
- [acx_pthread_ok=yes])
-
- LIBS="$save_LIBS"
- CFLAGS="$save_CFLAGS"
-
- AC_MSG_RESULT($acx_pthread_ok)
- if test "x$acx_pthread_ok" = xyes; then
- break;
- fi
-
- PTHREAD_LIBS=""
- PTHREAD_CFLAGS=""
-done
-fi
-
-# Various other checks:
-if test "x$acx_pthread_ok" = xyes; then
- save_LIBS="$LIBS"
- LIBS="$PTHREAD_LIBS $LIBS"
- save_CFLAGS="$CFLAGS"
- CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
-
- # Detect AIX lossage: threads are created detached by default
- # and the JOINABLE attribute has a nonstandard name (UNDETACHED).
- AC_MSG_CHECKING([for joinable pthread attribute])
- AC_TRY_LINK([#include <pthread.h>],
- [int attr=PTHREAD_CREATE_JOINABLE;],
- ok=PTHREAD_CREATE_JOINABLE, ok=unknown)
- if test x"$ok" = xunknown; then
- AC_TRY_LINK([#include <pthread.h>],
- [int attr=PTHREAD_CREATE_UNDETACHED;],
- ok=PTHREAD_CREATE_UNDETACHED, ok=unknown)
- fi
- if test x"$ok" != xPTHREAD_CREATE_JOINABLE; then
- AC_DEFINE(PTHREAD_CREATE_JOINABLE, $ok,
- [Define to the necessary symbol if this constant
- uses a non-standard name on your system.])
- fi
- AC_MSG_RESULT(${ok})
- if test x"$ok" = xunknown; then
- AC_MSG_WARN([we do not know how to create joinable pthreads])
- fi
-
- AC_MSG_CHECKING([if more special flags are required for pthreads])
- flag=no
- case "${host_cpu}-${host_os}" in
- *-aix* | *-freebsd*) flag="-D_THREAD_SAFE";;
- *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";;
- esac
- AC_MSG_RESULT(${flag})
- if test "x$flag" != xno; then
- PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
- fi
-
- LIBS="$save_LIBS"
- CFLAGS="$save_CFLAGS"
-
- # More AIX lossage: must compile with cc_r
- AC_CHECK_PROG(PTHREAD_CC, cc_r, cc_r, ${CC})
-else
- PTHREAD_CC="$CC"
-fi
-
-AC_SUBST(PTHREAD_LIBS)
-AC_SUBST(PTHREAD_CFLAGS)
-AC_SUBST(PTHREAD_CC)
-
-# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
-if test x"$acx_pthread_ok" = xyes; then
- ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1])
- :
-else
- acx_pthread_ok=no
- $2
-fi
-AC_LANG_RESTORE
-])dnl ACX_PTHREAD
diff --git a/autogen.sh b/autogen.sh
deleted file mode 100755
index c1be260..0000000
--- a/autogen.sh
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/bin/bash
-
-set -x
-
-aclocal -I .
-autoheader
-autoconf -f
-automake -a
-
diff --git a/bootstrap b/bootstrap
deleted file mode 100755
index c1be260..0000000
--- a/bootstrap
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/bin/bash
-
-set -x
-
-aclocal -I .
-autoheader
-autoconf -f
-automake -a
-
diff --git a/config.h.in b/config.h.in
new file mode 100644
index 0000000..0e184a4
--- /dev/null
+++ b/config.h.in
@@ -0,0 +1,11 @@
+#define PACKAGE "${PROJECT_NAME}"
+#define VERSION \
+ "0.${Petri-Foo_VERSION_MAJOR}.${Petri-Foo_VERSION_MINOR}"
+
+#ifndef PIXMAPS_DIR
+#define PIXMAPS_DIR "${CMAKE_INSTALL_PREFIX}/${DATADIR}/pixmaps"
+#endif
+
+#cmakedefine HAVE_MALLOC_H 1
+#cmakedefine HAVE_JACK_SESSION_H 1
+#cmakedefine DEBUG 1
diff --git a/configure.ac b/configure.ac
deleted file mode 100644
index 4c7d6cc..0000000
--- a/configure.ac
+++ /dev/null
@@ -1,200 +0,0 @@
-# -*- autoconf -*-
-# Process this file with autoconf to produce a configure script.
-
-AC_INIT(configure.ac)
-AM_INIT_AUTOMAKE(petri-foo, 0.0.2)
-AM_CONFIG_HEADER(src/config.h)
-
-# compilation
-with_debug="no"
-AC_ARG_ENABLE([debug],
- [AC_HELP_STRING([--enable-debug],
- [enable debugging information, accepting a performance penalty (default is NO)])],
- [if test x$enable_debug = xyes; then with_debug=yes ; fi])
-
-if test x$with_debug = xno; then
- CFLAGS="-O3 -std=gnu99"
-else
- CFLAGS="-O0 -std=gnu99 -ggdb -Wextra -DGTK_DISABLE_DEPRECATED -DGDK_DISABLE_DEPRECATED -DGSEAL_ENABLE"
- AC_DEFINE(DEBUG, 1, [[whether to display debugging output or not]])
-fi
-
-
-# standard autoconf checks
-AC_PROG_CC
-AM_PROG_CC_C_O
-AC_PROG_CPP
-AC_PROG_RANLIB
-AC_HEADER_STDC
-AC_CHECK_HEADERS([stdlib.h string.h sys/time.h unistd.h])
-AC_C_CONST
-AC_C_INLINE
-AC_HEADER_TIME
-AC_FUNC_MALLOC
-AC_CHECK_FUNCS([floor gettimeofday pow strchr strdup])
-
-# pthreads
-ACX_PTHREAD
-
-PETRI_FOO_CFLAGS="-Wall"
-AC_SUBST(PETRI_FOO_CFLAGS)
-CFLAGS="$PETRI_FOO_CFLAGS $CFLAGS"
-
-config_error="no"
-
-# gtk
-PKG_CHECK_MODULES(GTK, gtk+-2.0, HAVE_GTK="yes", config_error="yes")
-AC_SUBST(GTK_CFLAGS)
-AC_SUBST(GTK_LIBS)
-
-# libxml
-PKG_CHECK_MODULES(LIBXML, libxml-2.0, HAVE_LIBXML="yes", config_error="yes")
-AC_SUBST(LIBXML_CFLAGS)
-AC_SUBST(LIBXML_LIBS)
-
-# libgnomecanvas
-PKG_CHECK_MODULES(LIBGNOMECANVAS, libgnomecanvas-2.0, HAVE_LIBGNOMECANVAS="yes", config_error="yes")
-AC_SUBST(LIBGNOMECANVAS_CFLAGS)
-AC_SUBST(LIBGNOMECANVAS_LIBS)
-
-# alsa
-PKG_CHECK_MODULES(ALSA, alsa, HAVE_ALSA="yes", config_error="yes")
-AC_SUBST(ALSA_CFLAGS)
-AC_SUBST(ALSA_LIBS)
-
-# libsndfile
-PKG_CHECK_MODULES(LIBSNDFILE, sndfile, HAVE_LIBSNDFILE="yes", config_error="yes")
-AC_SUBST(LIBSNDFILE_CFLAGS)
-AC_SUBST(LIBSNDFILE_LIBS)
-
-# libsamplerate
-PKG_CHECK_MODULES(LIBSAMPLERATE, samplerate, HAVE_LIBSAMPLERATE="yes", config_error="yes")
-AC_SUBST(LIBSAMPLERATE_CFLAGS)
-AC_SUBST(LIBSAMPLERATE_LIBS)
-
-# jack
-PKG_CHECK_MODULES(JACK, jack >= 0.116.0, HAVE_JACK="yes", config_error="yes")
-if test "x$HAVE_JACK" = xyes ; then
- AC_CHECK_HEADER( jack/session.h, HAVE_JACK_SESSION="yes", HAVE_JACK_SESSION="no" )
- if test "x$HAVE_JACK_SESSION" = xyes; then
- AC_DEFINE([HAVE_JACK_SESSION], [], [Define if we have jack session support.])
- fi
-fi
-AC_SUBST(JACK_CFLAGS)
-AC_SUBST(JACK_LIBS)
-
-# phat
-PKG_CHECK_MODULES(PHAT, phat >= 0.3.1, HAVE_PHAT="yes", config_error="yes")
-AC_SUBST(PHAT_CFLAGS)
-AC_SUBST(PHAT_LIBS)
-
-
-CC="$PTHREAD_CC"
-
-# print build summary
-AC_CONFIG_COMMANDS_POST([
-echo
-echo " BUILD SUMMARY"
-echo " ============="
-echo " Compiler full flags: $CFLAGS"
-echo -n " Build type: "
-if test x$with_debug = xyes; then
- echo "debugging"
-else
- echo "optimized"
-fi
-echo -n " Jack midi support: "
-if test "x$HAVE_JACK" = xyes ; then
- echo "yes with jack >= 0.116.0"
-fi
-echo -n " Jack session support: "
-if test "x$HAVE_JACK_SESSION" = xyes ; then
- echo "yes"
-else
- echo "not found"
-fi
-
-echo
-echo
-])
-
-# are we good to go?
-
-if test x$config_error = "xyes"; then
-
-AC_MSG_RESULT([
-*** ERROR: the following required packages are missing ***
-])
-
-if test "x$HAVE_GTK" != xyes ; then
- AC_MSG_RESULT([
-*** GTK+ version 2.2.x or greater, available from :
- http://www.gtk.org/
-])
-fi
-
-if test "x$HAVE_LIBGNOMECANVAS" != xyes ; then
- AC_MSG_RESULT([
-*** libgnomecanvas, available from :
- http://ftp.gnome.org/pub/gnome/sources/libgnomecanvas/
-])
-fi
-
-if test "x$HAVE_PHAT" != xyes ; then
- AC_MSG_RESULT([
-*** Phat 0.4.0 or greater, available from:
- http://phat.berlios.de/
-])
-fi
-
-if test "x$HAVE_JACK" != xyes ; then
- AC_MSG_RESULT([
-*** JACK 0.99.0 or greater, available from:
- http://www.jackaudio.org/
-])
-fi
-
-if test "x$HAVE_LIBSAMPLERATE" != xyes ; then
- AC_MSG_RESULT([
-*** libsamplerate, available from:
- http://www.mega-nerd.com/SRC/
-])
-fi
-
-if test "x$HAVE_LIBSNDFILE" != xyes ; then
- AC_MSG_RESULT([
-*** libsndfile, available from:
- http://www.mega-nerd.com/libsndfile/
-])
-fi
-
-if test "x$HAVE_LIBXML" != xyes ; then
- AC_MSG_RESULT([
-*** libxml2, available from:
- http://ftp.gnome.org/pub/gnome/sources/libxml2/
-])
-fi
-
-
-AC_MSG_RESULT([
-Please ensure that all the above software is properly installed
-before running configure again. To do this, use your package
-manager to install the correct versions of the binary AND
-development (dev) packages or, download them from the
-above link(s) and build and install them from source manually.
-])
-
-AC_MSG_ERROR([
-*************************************************
-see ./config.log for full details.
-])
-else
-AC_OUTPUT([
-Makefile
-pixmaps/Makefile
-src/Makefile
-src/gui/Makefile
-src/patch_private/Makefile
-petri-foo.spec
-])
-fi
diff --git a/gui/CMakeLists.txt b/gui/CMakeLists.txt
new file mode 100644
index 0000000..803a142
--- /dev/null
+++ b/gui/CMakeLists.txt
@@ -0,0 +1,25 @@
+file (GLOB PETRI_FOO_SOURCES *.c)
+
+include_directories (
+ ${Petri-Foo_SOURCE_DIR}/libpetrifoo
+ ${Petri-Foo_SOURCE_DIR}/libpetrifui
+ ${Petri-Foo_SOURCE_DIR}/libphin
+ ${GTK2_INCLUDE_DIRS}
+ ${LIBGNOMECANVAS2_INCLUDE_DIRS}
+ ${LIBXML2_INCLUDE_DIRS}
+ )
+
+link_directories (
+ ${GTK2_LIBRARY_DIRS}
+ )
+
+add_definitions (
+ ${GTK2_CFLAGS_OTHER}
+ )
+
+add_executable(petri-foo ${PETRI_FOO_SOURCES})
+
+
+target_link_Libraries(petri-foo petrifoo petrifui pthread phin )
+
+install (TARGETS petri-foo DESTINATION ${BINDIR})
diff --git a/src/gui/audio-settings.c b/gui/audio-settings.c
similarity index 98%
rename from src/gui/audio-settings.c
rename to gui/audio-settings.c
index e111df3..8a0ce12 100644
--- a/src/gui/audio-settings.c
+++ b/gui/audio-settings.c
@@ -38,7 +38,7 @@
static GtkWidget* window;
-#ifdef HAVE_JACK_SESSION
+#ifdef HAVE_JACK_SESSION_H
static gboolean gui_session_cb(void *data)
{
size_t len;
@@ -62,7 +62,7 @@ static gboolean gui_session_cb(void *data)
debug("filename:%s\n",filename);
snprintf(command, sizeof(command),
- "petri-foo -U %s ${SESSION_DIR}%s",
+ "petri-foo --unconnected -U %s ${SESSION_DIR}%s",
ev->client_uuid, bankfilename);
debug("command:%s\n",command);
diff --git a/src/gui/audio-settings.h b/gui/audio-settings.h
similarity index 95%
rename from src/gui/audio-settings.h
rename to gui/audio-settings.h
index 8aa9ae8..9a9a784 100644
--- a/src/gui/audio-settings.h
+++ b/gui/audio-settings.h
@@ -29,7 +29,7 @@
#include "config.h"
-#ifdef HAVE_JACK_SESSION
+#ifdef HAVE_JACK_SESSION_H
#include <jack/session.h>
#endif
@@ -38,7 +38,7 @@ void audio_settings_init(GtkWidget* parent);
void audio_settings_show(void);
-#ifdef HAVE_JACK_SESSION
+#ifdef HAVE_JACK_SESSION_H
void audio_settings_session_cb(jack_session_event_t *event, void *arg);
#endif
diff --git a/src/gui/bank-ops.c b/gui/bank-ops.c
similarity index 64%
rename from src/gui/bank-ops.c
rename to gui/bank-ops.c
index 0f850a2..8f488e6 100644
--- a/src/gui/bank-ops.c
+++ b/gui/bank-ops.c
@@ -28,10 +28,13 @@
#include <string.h>
#include "dish_file.h"
+#include "log_display.h"
#include "patch.h"
#include "patch_util.h"
#include "petri-foo.h"
+#include "msg_log.h"
#include "gui.h"
+#include "global_settings.h"
static char *last_bank = 0;
@@ -55,15 +58,6 @@ static void set_bankname(const char* name)
gui_set_window_title(bankname);
}
-
-inline static char* strconcat(const char* str1, const char* str2)
-{
- char* str = malloc(strlen(str1) + strlen(str2) + 1);
- strcpy(str, str1);
- strcat(str, str2);
- return str;
-}
-
/* unused... reason/purpose ???
static char* get_file_filter(void)
{
@@ -99,6 +93,8 @@ int bank_ops_save_as (GtkWidget* parent_window)
char* filter = strconcat("*", dish_file_extension());
char* untitled_dish = strconcat("untitled", dish_file_extension());
+
+ global_settings* settings = settings_get();
dialog = gtk_file_chooser_dialog_new("Save Bank",
GTK_WINDOW(parent_window),
@@ -110,6 +106,13 @@ int bank_ops_save_as (GtkWidget* parent_window)
gtk_file_chooser_set_do_overwrite_confirmation(
GTK_FILE_CHOOSER(dialog), TRUE);
+ if ( last_bank == 0)
+ gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),
+ settings->last_bank_dir);
+ else
+ gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),
+ g_path_get_dirname(last_bank));
+
gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog),
(last_bank != 0) ? last_bank : untitled_dish);
@@ -123,7 +126,7 @@ int bank_ops_save_as (GtkWidget* parent_window)
if ((val = dish_file_write(name)) < 0)
{
- errmsg ("Failed to write file %s\n", name);
+ msg_log(MSG_ERROR, "Failed to write file %s\n", name);
GtkWidget* msg = gtk_message_dialog_new(GTK_WINDOW(dialog),
GTK_DIALOG_MODAL,
GTK_MESSAGE_ERROR,
@@ -136,7 +139,10 @@ int bank_ops_save_as (GtkWidget* parent_window)
}
else
{
- debug ("Succesfully wrote file %s\n", name);
+
+ gtk_recent_manager_add_item (recent_manager,
+ g_filename_to_uri(name, NULL, NULL));
+ msg_log(MSG_MESSAGE, "Succesfully wrote file %s\n", name);
free(last_bank);
last_bank = strdup(name);
set_bankname(name);
@@ -174,6 +180,7 @@ int bank_ops_open(GtkWidget* parent_window)
GtkWidget* dialog;
int val;
char* filter = strconcat("*", dish_file_extension());
+ global_settings* settings = settings_get();
dialog = gtk_file_chooser_dialog_new("Open Bank",
GTK_WINDOW(parent_window),
@@ -182,26 +189,33 @@ int bank_ops_open(GtkWidget* parent_window)
GTK_RESPONSE_CANCEL,
GTK_STOCK_OPEN,
GTK_RESPONSE_ACCEPT, NULL);
- if (last_bank)
- gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(dialog),
+ if (last_bank)
+ gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(dialog),
last_bank);
+ else
+ gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),
+ settings->last_bank_dir);
file_chooser_add_filter(dialog, "Petri-Foo files", filter);
file_chooser_add_filter(dialog, "All files", "*");
if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
{
- char *name = (char *)
- gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
+ char* name = (char*) gtk_file_chooser_get_filename(
+ GTK_FILE_CHOOSER(dialog));
+
+ msg_log(MSG_MESSAGE, "Loading bank %s\n", name);
+ msg_log_reset_notification_state();
+ val = dish_file_read(name);
- if ((val = dish_file_read(name)) < 0)
+ if (val < 0)
{
- errmsg("Failed to read file %s\n", name);
+ msg_log(MSG_ERROR, "Failed to read bank %s\n", name);
GtkWidget* msg = gtk_message_dialog_new(GTK_WINDOW(dialog),
GTK_DIALOG_MODAL,
GTK_MESSAGE_ERROR,
GTK_BUTTONS_CLOSE,
- "Failed to read file %s\n.", name);
+ "Failed to read bank %s\n.", name);
g_signal_connect_swapped(G_OBJECT(msg), "response",
G_CALLBACK(gtk_widget_destroy), msg);
@@ -209,9 +223,23 @@ int bank_ops_open(GtkWidget* parent_window)
}
else
{
- debug ("Succesfully read file %s\n", name);
+ if (msg_log_get_notification_state())
+ {
+ msg_log(MSG_WARNING, "Bank %s read with errors\n", name);
+ log_display_show();
+ }
+ else
+ msg_log(MSG_MESSAGE, "Succesfully read bank %s\n", name);
+
+ gtk_recent_manager_add_item(recent_manager,
+ g_filename_to_uri(name, NULL, NULL));
free(last_bank);
last_bank = strdup(name);
+
+ if (settings->last_bank_dir)
+ free(settings->last_bank_dir);
+
+ settings->last_bank_dir = g_path_get_dirname(name);
set_bankname(name);
}
}
@@ -236,3 +264,45 @@ int bank_ops_new(void)
set_bankname(NULL);
return 0;
}
+
+int bank_ops_open_recent(GtkWidget* parent_window, char* filename)
+{
+ int val;
+
+ msg_log(MSG_MESSAGE, "Loading bank %s\n", filename);
+ msg_log_reset_notification_state();
+ val = dish_file_read(filename);
+
+ if (val < 0)
+ {
+ msg_log(MSG_ERROR, "Failed to read bank %s\n", filename);
+ GtkWidget* msg = gtk_message_dialog_new(GTK_WINDOW(parent_window),
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ "Failed to read bank %s\n.", filename);
+
+ g_signal_connect_swapped(G_OBJECT(msg), "response",
+ G_CALLBACK(gtk_widget_destroy), msg);
+ gtk_widget_show (msg);
+ }
+ else
+ {
+ if (msg_log_get_notification_state())
+ {
+ msg_log(MSG_WARNING, "Bank %s read with errors\n", filename);
+ log_display_show();
+ }
+ else
+ msg_log(MSG_MESSAGE, "Succesfully read bank %s\n", filename);
+
+ gtk_recent_manager_add_item (recent_manager,
+ g_filename_to_uri(filename, NULL, NULL));
+ free(last_bank);
+ last_bank = strdup(filename);
+ set_bankname(filename);
+ }
+
+ return val;
+}
+
diff --git a/src/gui/bank-ops.h b/gui/bank-ops.h
similarity index 92%
rename from src/gui/bank-ops.h
rename to gui/bank-ops.h
index 760d2e0..ef388f7 100644
--- a/src/gui/bank-ops.h
+++ b/gui/bank-ops.h
@@ -34,5 +34,7 @@ int bank_ops_open (GtkWidget* parent_window);
int bank_ops_save_as (GtkWidget* parent_window);
int bank_ops_save (GtkWidget* parent_window);
const char* bank_ops_bank (void);
+int bank_ops_open_recent (GtkWidget* parent_window
+ , char* filename);
#endif /* __BANK_OPS_H__ */
diff --git a/src/gui/basic_combos.c b/gui/basic_combos.c
similarity index 100%
rename from src/gui/basic_combos.c
rename to gui/basic_combos.c
diff --git a/src/gui/basic_combos.h b/gui/basic_combos.h
similarity index 100%
rename from src/gui/basic_combos.h
rename to gui/basic_combos.h
diff --git a/gui/bool_section.c b/gui/bool_section.c
new file mode 100644
index 0000000..0bad112
--- /dev/null
+++ b/gui/bool_section.c
@@ -0,0 +1,275 @@
+/* Petri-Foo is a fork of the Specimen audio sampler.
+
+ Copyright 2011 James W. Morris
+
+ This file is part of Petri-Foo.
+
+ Petri-Foo is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+
+ Petri-Foo is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Petri-Foo. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#include <gtk/gtk.h>
+
+#include "phin.h"
+
+#include "bool_section.h"
+#include "gui.h"
+#include "patch_set_and_get.h"
+#include "names.h"
+
+#include "mod_src_gui.h"
+
+
+typedef struct _BoolSectionPrivate BoolSectionPrivate;
+
+#define BOOL_SECTION_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE((obj), \
+ BOOL_SECTION_TYPE, BoolSectionPrivate))
+
+struct _BoolSectionPrivate
+{
+ int patch_id;
+ PatchBoolType bool_type;
+
+ GtkWidget* set_check;
+ GtkWidget* mod_combo;
+ GtkWidget* thresh;
+
+ GtkWidget* mod_label;
+};
+
+/* signals */
+enum
+{
+ TOGGLED,
+ LAST_SIGNAL,
+};
+
+static int signals[LAST_SIGNAL];
+
+
+G_DEFINE_TYPE(BoolSection, bool_section, GTK_TYPE_VBOX);
+
+
+static void bool_section_class_init(BoolSectionClass* klass)
+{
+ GObjectClass* object_class = G_OBJECT_CLASS(klass);
+ bool_section_parent_class = g_type_class_peek_parent(klass);
+
+ signals[TOGGLED] =
+ g_signal_new ("toggled",
+ G_TYPE_FROM_CLASS(klass),
+ G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET(BoolSectionClass, set_toggled),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID, G_TYPE_NONE,
+ 0, NULL);
+
+ g_type_class_add_private(object_class, sizeof(BoolSectionPrivate));
+}
+
+
+static void set_check_cb(GtkToggleButton* button, BoolSection* self)
+{
+ BoolSectionPrivate* p = BOOL_SECTION_GET_PRIVATE(self);
+ int mod_src = mod_src_combo_get_mod_src_id(GTK_COMBO_BOX(p->mod_combo));
+ gboolean active = gtk_toggle_button_get_active(button);
+
+ gtk_widget_set_sensitive(p->mod_label, active);
+ gtk_widget_set_sensitive(p->mod_combo, active);
+ gtk_widget_set_sensitive(p->thresh, active && mod_src != MOD_SRC_NONE);
+
+ patch_bool_set_active(p->patch_id, p->bool_type, active);
+
+ g_signal_emit_by_name(G_OBJECT(self), "toggled");
+}
+
+
+static void mod_combo_cb(GtkComboBox* combo, BoolSectionPrivate* p)
+{
+ int mod_src = mod_src_combo_get_mod_src_id(combo);
+
+ patch_bool_set_mod_src( p->patch_id, p->bool_type, mod_src);
+
+ gtk_widget_set_sensitive(p->thresh, (mod_src != MOD_SRC_NONE));
+}
+
+
+static void thresh_cb(GtkWidget* w, BoolSectionPrivate* p)
+{
+ patch_bool_set_thresh( p->patch_id,
+ p->bool_type,
+ phin_fan_slider_get_value(PHIN_FAN_SLIDER(w)));
+}
+
+
+static void block(BoolSectionPrivate* p)
+{
+ g_signal_handlers_block_by_func(p->set_check, set_check_cb, p);
+ g_signal_handlers_block_by_func(p->thresh, thresh_cb, p);
+ g_signal_handlers_block_by_func(p->mod_combo, mod_combo_cb, p);
+}
+
+
+static void unblock(BoolSectionPrivate* p)
+{
+ g_signal_handlers_unblock_by_func(p->set_check, set_check_cb, p);
+ g_signal_handlers_unblock_by_func(p->thresh, thresh_cb, p);
+ g_signal_handlers_unblock_by_func(p->mod_combo, mod_combo_cb, p);
+}
+
+
+
+static void bool_section_init(BoolSection* self)
+{
+ BoolSectionPrivate* p = BOOL_SECTION_GET_PRIVATE(self);
+ p->patch_id = -1;
+ p->bool_type = PATCH_BOOL_INVALID;
+ p->set_check = 0;
+ p->mod_combo = 0;
+ p->thresh = 0;
+}
+
+
+void bool_section_set_bool( BoolSection* self, PatchBoolType bool_type)
+{
+ BoolSectionPrivate* p = BOOL_SECTION_GET_PRIVATE(self);
+ GtkBox* box;
+ GtkWidget* table;
+ GtkTable* t;
+ GtkWidget* title;
+
+ int y = 0;
+
+ int a1 = 0, a2 = 1;
+ int b1 = 1, b2 = 2;
+ int c1 = 2, c2 = 3;
+
+ const char* bool_names[] = { "Portamento", "Mono", "Legato" };
+
+ box = GTK_BOX(self);
+
+ p->bool_type = bool_type;
+
+ if (bool_type < 0 || bool_type > 2)
+ {
+ debug("Bad News! unknown bool type!\n");
+ return;
+ }
+
+ gtk_container_set_border_width(GTK_CONTAINER(self), GUI_BORDERSPACE);
+
+ table = gtk_table_new(3, 3, FALSE);
+ t = (GtkTable*)table;
+ gui_pack(box, table);
+
+ title = gui_title_new(bool_names[bool_type]);
+ p->set_check = gtk_check_button_new();
+ gtk_container_add(GTK_CONTAINER(p->set_check), title);
+ gui_attach(t, p->set_check, a1, c2, y, y + 1);
+ gtk_widget_show(title);
+ ++y;
+
+ /* title padding */
+ gui_attach(t, gui_vpad_new(GUI_TITLESPACE), a1, c2, y, y + 1);
+ ++y;
+
+ /* label column spacing (of some description!?) */
+ gui_attach(t, gui_hpad_new(GUI_TEXTSPACE), c1, c2, y, y + 1);
+ ++y;
+
+ p->mod_label = gui_label_attach("Switch:", t, a1, a2, y, y + 1);
+
+ p->mod_combo = mod_src_new_combo_with_cell();
+ mod_src_combo_set_model(GTK_COMBO_BOX(p->mod_combo), MOD_SRC_GLOBALS);
+ gui_attach(t, p->mod_combo, b1, b2, y, y + 1);
+
+ p->thresh = phin_hfan_slider_new_with_range(0.0, -1.0, 1.0, 0.1);
+ gui_attach(t, p->thresh, c1, c2, y, y + 1);
+ gtk_widget_set_tooltip_text(p->thresh, "Switch threshold");
+ ++y;
+
+ g_signal_connect(G_OBJECT(p->set_check), "toggled",
+ G_CALLBACK(set_check_cb), (gpointer)self);
+
+ g_signal_connect(G_OBJECT(p->thresh), "value-changed",
+ G_CALLBACK(thresh_cb), (gpointer)p);
+
+ g_signal_connect(G_OBJECT(p->mod_combo), "changed",
+ G_CALLBACK(mod_combo_cb), (gpointer)p);
+}
+
+
+void bool_section_set_list_global(BoolSection* self)
+{
+ BoolSectionPrivate* p = BOOL_SECTION_GET_PRIVATE(self);
+
+ mod_src_combo_set_model(GTK_COMBO_BOX(p->mod_combo), MOD_SRC_GLOBALS);
+}
+
+
+void bool_section_set_list_all(BoolSection* self)
+{
+ BoolSectionPrivate* p = BOOL_SECTION_GET_PRIVATE(self);
+
+ mod_src_combo_set_model(GTK_COMBO_BOX(p->mod_combo), MOD_SRC_ALL);
+}
+
+
+GtkWidget* bool_section_new(void)
+{
+ return (GtkWidget*)g_object_new(BOOL_SECTION_TYPE, NULL);
+}
+
+
+void bool_section_set_patch(BoolSection* self, int patch_id)
+{
+ BoolSectionPrivate* p = BOOL_SECTION_GET_PRIVATE(self);
+
+ bool set;
+ float thresh;
+ int modsrc;
+
+ GtkTreeIter moditer;
+
+ p->patch_id = patch_id;
+
+ if (patch_id < 0)
+ return;
+
+ patch_bool_get_all(patch_id, p->bool_type, &set, &thresh, &modsrc);
+
+ block(p);
+
+ phin_fan_slider_set_value(PHIN_FAN_SLIDER(p->thresh), thresh);
+
+ if (!mod_src_combo_get_iter_with_id(GTK_COMBO_BOX(p->mod_combo),
+ modsrc,
+ &moditer))
+ {
+ debug("failed to get mod source id from combo box\n");
+ }
+
+ gtk_combo_box_set_active_iter(GTK_COMBO_BOX(p->mod_combo), &moditer);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p->set_check), set);
+
+ unblock(p);
+}
+
+
+gboolean bool_section_get_active(BoolSection* self)
+{
+ BoolSectionPrivate* p = BOOL_SECTION_GET_PRIVATE(self);
+
+ return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(p->set_check));
+}
diff --git a/gui/bool_section.h b/gui/bool_section.h
new file mode 100644
index 0000000..4ac1d32
--- /dev/null
+++ b/gui/bool_section.h
@@ -0,0 +1,76 @@
+/* Petri-Foo is a fork of the Specimen audio sampler.
+
+ Copyright 2011 James W. Morris
+
+ This file is part of Petri-Foo.
+
+ Petri-Foo is free software: you can redistribute it and/or Boolify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+
+ Petri-Foo is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Petri-Foo. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#ifndef __BOOL_SECTION__
+#define __BOOL_SECTION__
+
+#include <gtk/gtk.h>
+
+
+#include "patch.h"
+
+
+G_BEGIN_DECLS
+
+#define BOOL_SECTION_TYPE (bool_section_get_type())
+#define BOOL_SECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ BOOL_SECTION_TYPE, BoolSection))
+
+#define IS_BOOL_SECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ BOOL_SECTION_TYPE))
+
+#define BOOL_SECTION_CLASS(klass)(G_TYPE_CHECK_CLASS_CAST ((klass), \
+ BOOL_SECTION_TYPE, BoolSectionClass))
+
+#define IS_BOOL_SECTION_CLASS(klass) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((klass), BOOL_SECTION_TYPE))
+
+
+typedef struct _BoolSectionClass BoolSectionClass;
+typedef struct _BoolSection BoolSection;
+
+
+struct _BoolSection
+{
+ GtkVBox parent_instance;
+};
+
+
+struct _BoolSectionClass
+{
+ GtkVBoxClass parent_class;
+ /* <private> */
+ void (*set_toggled)(BoolSection*);
+};
+
+
+GType bool_section_get_type(void);
+
+GtkWidget* bool_section_new(void);
+
+void bool_section_set_bool( BoolSection*, PatchBoolType);
+void bool_section_set_patch(BoolSection*, int patch_id);
+
+gboolean bool_section_get_active(BoolSection*);
+
+G_END_DECLS
+
+
+#endif /* __BOOL_SECTION__ */
diff --git a/gui/channelsection.c b/gui/channelsection.c
new file mode 100644
index 0000000..ab6723e
--- /dev/null
+++ b/gui/channelsection.c
@@ -0,0 +1,191 @@
+/* Petri-Foo is a fork of the Specimen audio sampler.
+
+ Original Specimen author Pete Bessman
+ Copyright 2005 Pete Bessman
+ Copyright 2011 James W. Morris
+
+ This file is part of Petri-Foo.
+
+ Petri-Foo is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+
+ Petri-Foo is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Petri-Foo. If not, see <http://www.gnu.org/licenses/>.
+
+ This file is a derivative of a Specimen original, modified 2011
+*/
+
+
+#include <gtk/gtk.h>
+
+#include "phin.h"
+
+#include "channelsection.h"
+#include "gui.h"
+#include "patchlist.h"
+#include "midi.h"
+#include "patch_set_and_get.h"
+
+
+
+G_DEFINE_TYPE(ChannelSection, channel_section, GTK_TYPE_VBOX)
+
+
+static void channel_section_class_init(ChannelSectionClass* klass)
+{
+ channel_section_parent_class = g_type_class_peek_parent(klass);
+}
+
+
+static void channel_cb(PhinSliderButton* button, ChannelSection* self)
+{
+ int channel = (int)phin_slider_button_get_value(button);
+ PatchList* list = gui_get_patch_list();
+
+ patch_set_channel(self->patch, channel-1);
+ patch_list_update(list, patch_list_get_current_patch(list),
+ PATCH_LIST_PATCH);
+}
+
+
+static void lower_vel_cb(PhinSliderButton* button, ChannelSection* self)
+{
+ int lower_vel = (int)phin_slider_button_get_value(button);
+ PatchList* list = gui_get_patch_list();
+
+ patch_set_lower_vel(self->patch, lower_vel);
+ patch_list_update(list, patch_list_get_current_patch(list),
+ PATCH_LIST_PATCH);
+}
+
+
+static void upper_vel_cb(PhinSliderButton* button, ChannelSection* self)
+{
+ int upper_vel = (int)phin_slider_button_get_value(button);
+ PatchList* list = gui_get_patch_list();
+
+ patch_set_upper_vel(self->patch, upper_vel);
+ patch_list_update(list, patch_list_get_current_patch(list),
+ PATCH_LIST_PATCH);
+}
+
+
+static void connect(ChannelSection* self)
+{
+ g_signal_connect(G_OBJECT(self->chan_sb), "value-changed",
+ G_CALLBACK(channel_cb), (gpointer) self);
+ g_signal_connect(G_OBJECT(self->lower_vel_sb), "value-changed",
+ G_CALLBACK(lower_vel_cb), (gpointer) self);
+ g_signal_connect(G_OBJECT(self->upper_vel_sb), "value-changed",
+ G_CALLBACK(upper_vel_cb), (gpointer) self);
+}
+
+
+static void channel_section_init(ChannelSection* self)
+{
+ GtkBox* box = GTK_BOX(self);
+ GtkWidget* table = gtk_table_new( 3, 2, 1);
+ GtkWidget* lbl_chan = gtk_label_new("Channel");
+ GtkWidget* lbl_lower = gtk_label_new("Lower Vel.");
+ GtkWidget* lbl_upper = gtk_label_new("Upper Vel.");
+
+ self->patch = -1;
+
+ gtk_table_attach_defaults(GTK_TABLE(table),lbl_chan,0,1,0,1);
+ gtk_widget_show(lbl_chan);
+ gtk_table_attach_defaults(GTK_TABLE(table),lbl_lower,0,1,1,2);
+ gtk_widget_show(lbl_lower);
+ gtk_table_attach_defaults(GTK_TABLE(table),lbl_upper,0,1,2,3);
+ gtk_widget_show(lbl_upper);
+
+ /* channel sliderbutton */
+ self->chan_sb = phin_slider_button_new_with_range(1, 1, MIDI_CHANS,1,0);
+ phin_slider_button_set_threshold(PHIN_SLIDER_BUTTON(self->chan_sb),
+ GUI_THRESHOLD);
+ gtk_table_attach_defaults(GTK_TABLE(table),self->chan_sb,1,2,0,1);
+ gtk_widget_show(self->chan_sb);
+
+ /* lower velocity slide */
+ self->lower_vel_sb = phin_slider_button_new_with_range(0, 0, 127, 1, 0);
+ phin_slider_button_set_threshold(PHIN_SLIDER_BUTTON(self->lower_vel_sb),
+ GUI_THRESHOLD);
+ gtk_table_attach_defaults(GTK_TABLE(table),self->lower_vel_sb,1,2,1,2);
+ gtk_widget_show(self->lower_vel_sb);
+
+ /* upper velocity slider */
+ self->upper_vel_sb = phin_slider_button_new_with_range(127, 0, 127, 1, 0);
+ phin_slider_button_set_threshold(PHIN_SLIDER_BUTTON(self->upper_vel_sb),
+ GUI_THRESHOLD);
+ gtk_table_attach_defaults(GTK_TABLE(table),self->upper_vel_sb,1,2,2,3);
+ gtk_widget_show(self->upper_vel_sb);
+
+ gui_pack(box, table);
+
+ /* done */
+ connect(self);
+}
+
+
+static void block(ChannelSection* self)
+{
+ g_signal_handlers_block_by_func(self->chan_sb, channel_cb, self);
+}
+
+
+static void unblock(ChannelSection* self)
+{
+ g_signal_handlers_unblock_by_func(self->chan_sb, channel_cb, self);
+}
+
+
+static void set_sensitive(ChannelSection* self, gboolean val)
+{
+ gtk_widget_set_sensitive(self->chan_sb, val);
+ gtk_widget_set_sensitive(self->lower_vel_sb, val);
+ gtk_widget_set_sensitive(self->upper_vel_sb, val);
+}
+
+
+GtkWidget* channel_section_new(void)
+{
+ return (GtkWidget*) g_object_new(CHANNEL_SECTION_TYPE, NULL);
+}
+
+
+void channel_section_set_patch(ChannelSection* self, int patch)
+{
+ int channel, lower_vel, upper_vel;
+
+ self->patch = patch;
+
+ if (patch < 0)
+ set_sensitive(self, FALSE);
+ else
+ {
+ set_sensitive(self, TRUE);
+ channel = patch_get_channel(patch);
+ lower_vel = patch_get_lower_vel(patch);
+ upper_vel = patch_get_upper_vel(patch);
+
+ block(self);
+ phin_slider_button_set_value(PHIN_SLIDER_BUTTON(self->chan_sb),
+ channel+1);
+ phin_slider_button_set_value(PHIN_SLIDER_BUTTON(self->lower_vel_sb),
+ lower_vel);
+ phin_slider_button_set_value(PHIN_SLIDER_BUTTON(self->upper_vel_sb),
+ upper_vel);
+ unblock(self);
+ }
+}
+
+
+int channel_section_get_channel(ChannelSection* self)
+{
+ return (self->patch < 0) ? 0 : patch_get_channel(self->patch);
+}
diff --git a/src/gui/channelsection.h b/gui/channelsection.h
similarity index 97%
rename from src/gui/channelsection.h
rename to gui/channelsection.h
index c3f33bf..23de74a 100644
--- a/src/gui/channelsection.h
+++ b/gui/channelsection.h
@@ -58,6 +58,8 @@ struct _ChannelSection
/* <private> */
int patch;
GtkWidget* chan_sb;
+ GtkWidget* lower_vel_sb;
+ GtkWidget* upper_vel_sb;
};
diff --git a/src/gui/envelopetab.c b/gui/envelopetab.c
similarity index 80%
rename from src/gui/envelopetab.c
rename to gui/envelopetab.c
index 58e655c..0a5ae6b 100644
--- a/src/gui/envelopetab.c
+++ b/gui/envelopetab.c
@@ -23,7 +23,9 @@
#include <gtk/gtk.h>
-#include <phat/phat.h>
+
+#include "phin.h"
+
#include "envelopetab.h"
#include "gui.h"
#include "idselector.h"
@@ -79,7 +81,7 @@ static void envelope_tab_class_init(EnvelopeTabClass* klass)
static void set_sensitive(EnvelopeTabPrivate* p, gboolean val)
{
/* setting the table itself takes care of the labels,
- * but still need to set the phat widgets...
+ * but still need to set the phin widgets...
*/
gtk_widget_set_sensitive(p->env_table, val);
gtk_widget_set_sensitive(p->delay_fan, val);
@@ -104,7 +106,7 @@ static void id_selector_cb(IDSelector* ids, EnvelopeTabPrivate* p)
static void on_cb(GtkToggleButton* button, EnvelopeTabPrivate* p)
{
- patch_set_env_on(p->patch,
+ patch_set_env_active(p->patch,
id_selector_get_id(ID_SELECTOR(p->idsel)),
gtk_toggle_button_get_active(button));
}
@@ -116,65 +118,65 @@ static void on_cb2(GtkToggleButton* button, EnvelopeTabPrivate* p)
}
-static void delay_cb(PhatFanSlider* fan, EnvelopeTabPrivate* p)
+static void delay_cb(PhinFanSlider* fan, EnvelopeTabPrivate* p)
{
- float val = phat_fan_slider_get_value(fan);
+ float val = phin_fan_slider_get_value(fan);
patch_set_env_delay(p->patch,
id_selector_get_id(ID_SELECTOR(p->idsel)),val);
}
-static void attack_cb(PhatFanSlider* fan, EnvelopeTabPrivate* p)
+static void attack_cb(PhinFanSlider* fan, EnvelopeTabPrivate* p)
{
- float val = phat_fan_slider_get_value(fan);
+ float val = phin_fan_slider_get_value(fan);
patch_set_env_attack(p->patch,
id_selector_get_id(ID_SELECTOR(p->idsel)), val);
}
-static void hold_cb(PhatFanSlider* fan, EnvelopeTabPrivate* p)
+static void hold_cb(PhinFanSlider* fan, EnvelopeTabPrivate* p)
{
- float val = phat_fan_slider_get_value(fan);
+ float val = phin_fan_slider_get_value(fan);
patch_set_env_hold(p->patch,
id_selector_get_id(ID_SELECTOR(p->idsel)), val);
}
-static void decay_cb(PhatFanSlider* fan, EnvelopeTabPrivate* p)
+static void decay_cb(PhinFanSlider* fan, EnvelopeTabPrivate* p)
{
- float val = phat_fan_slider_get_value(fan);
+ float val = phin_fan_slider_get_value(fan);
patch_set_env_decay(p->patch,
id_selector_get_id(ID_SELECTOR(p->idsel)), val);
}
-static void sustain_cb(PhatFanSlider* fan, EnvelopeTabPrivate* p)
+static void sustain_cb(PhinFanSlider* fan, EnvelopeTabPrivate* p)
{
- float val = phat_fan_slider_get_value(fan);
+ float val = phin_fan_slider_get_value(fan);
patch_set_env_sustain(p->patch,
id_selector_get_id(ID_SELECTOR(p->idsel)), val);
}
-static void release_cb(PhatFanSlider* fan, EnvelopeTabPrivate* p)
+static void release_cb(PhinFanSlider* fan, EnvelopeTabPrivate* p)
{
- float val = phat_fan_slider_get_value(fan);
+ float val = phin_fan_slider_get_value(fan);
patch_set_env_release(p->patch,
id_selector_get_id(ID_SELECTOR(p->idsel)), val);
}
-static void key_cb(PhatFanSlider* fan, EnvelopeTabPrivate* p)
+static void key_cb(PhinFanSlider* fan, EnvelopeTabPrivate* p)
{
- float val = phat_fan_slider_get_value(fan);
+ float val = phin_fan_slider_get_value(fan);
patch_set_env_key_amt(p->patch,
id_selector_get_id(ID_SELECTOR(p->idsel)), val);
}
/*
-static void vel_cb(PhatFanSlider* fan, EnvelopeTabPrivate* p)
+static void vel_cb(PhinFanSlider* fan, EnvelopeTabPrivate* p)
{
- float val = phat_fan_slider_get_value(fan);
+ float val = phin_fan_slider_get_value(fan);
patch_set_env_vel_amt(p->patch,
id_selector_get_id(ID_SELECTOR(p->idsel)), val);
}
@@ -279,49 +281,49 @@ static void envelope_tab_init(EnvelopeTab* self)
/* delay fan */
gui_label_attach("Delay:", t, a1, a2, y, y + 1);
- p->delay_fan = phat_hfan_slider_new_with_range(0.1, 0.0, 1.0, 0.01);
+ p->delay_fan = phin_hfan_slider_new_with_range(0.1, 0.0, 1.0, 0.01);
gui_attach(t, p->delay_fan, b1, b2, y, y + 1);
++y;
/* attack fan */
gui_label_attach("Attack:", t, a1, a2, y, y + 1);
- p->attack_fan = phat_hfan_slider_new_with_range(0.1, 0.0, 1.0, 0.01);
+ p->attack_fan = phin_hfan_slider_new_with_range(0.1, 0.0, 1.0, 0.01);
gui_attach(t, p->attack_fan, b1, b2, y, y + 1);
++y;
/* hold fan */
gui_label_attach("Hold:", t, a1, a2, y, y + 1);
- p->hold_fan = phat_hfan_slider_new_with_range(0.1, 0.0, 1.0, 0.01);
+ p->hold_fan = phin_hfan_slider_new_with_range(0.1, 0.0, 1.0, 0.01);
gui_attach(t, p->hold_fan, b1, b2, y, y + 1);
++y;
/* decay fan */
gui_label_attach("Decay:", t, a1, a2, y, y + 1);
- p->decay_fan = phat_hfan_slider_new_with_range(0.1, 0.0, 1.0, 0.01);
+ p->decay_fan = phin_hfan_slider_new_with_range(0.1, 0.0, 1.0, 0.01);
gui_attach(t, p->decay_fan, b1, b2, y, y + 1);
++y;
/* sustain fan */
gui_label_attach("Sustain:", t, a1, a2, y, y + 1);
- p->sustain_fan = phat_hfan_slider_new_with_range(0.7, 0.0, 1.0, 0.01);
+ p->sustain_fan = phin_hfan_slider_new_with_range(0.7, 0.0, 1.0, 0.01);
gui_attach(t, p->sustain_fan, b1, b2, y, y + 1);
++y;
/* release fan */
gui_label_attach("Release:", t, a1, a2, y, y + 1);
- p->release_fan = phat_hfan_slider_new_with_range(0.1, 0.0, 1.0, 0.01);
+ p->release_fan = phin_hfan_slider_new_with_range(0.1, 0.0, 1.0, 0.01);
gui_attach(t, p->release_fan, b1, b2, y, y + 1);
++y;
/* key fan */
gui_label_attach("Key Track:", t, a1, a2, y, y + 1);
- p->key_fan = phat_hfan_slider_new_with_range(0.1, -1.0, 1.0, 0.01);
+ p->key_fan = phin_hfan_slider_new_with_range(0.1, -1.0, 1.0, 0.01);
gui_attach(t, p->key_fan, b1, b2, y, y + 1);
++y;
/* vel fan
gui_label_attach("Vel.Sens:", t, a1, a2, y, y + 1);
- p->vel_fan = phat_hfan_slider_new_with_range(0.1, -1.0, 1.0, 0.01);
+ p->vel_fan = phin_hfan_slider_new_with_range(0.1, -1.0, 1.0, 0.01);
gui_attach(t, p->vel_fan, b1, b2, y, y + 1);
++y;
*/
@@ -334,33 +336,33 @@ static void envelope_tab_init(EnvelopeTab* self)
static void update_env(EnvelopeTabPrivate* p)
{
int i = p->patch;
- float l, a, h, d, s, r, key, vel;
+ float l, a, h, d, s, r, key;
bool on;
int id;
id = id_selector_get_id(ID_SELECTOR(p->idsel));
- patch_get_env_delay(i, id, &l);
- patch_get_env_attack(i, id, &a);
- patch_get_env_hold(i, id, &h);
- patch_get_env_decay(i, id, &d);
- patch_get_env_sustain(i, id, &s);
- patch_get_env_release(i, id, &r);
- patch_get_env_on(i, id, &on);
- patch_get_env_key_amt(i, id, &key);
+ l = patch_get_env_delay(i, id);
+ a = patch_get_env_attack(i, id);
+ h = patch_get_env_hold(i, id);
+ d = patch_get_env_decay(i, id);
+ s = patch_get_env_sustain(i, id);
+ r = patch_get_env_release(i, id);
+ on = patch_get_env_active(i, id);
+ key = patch_get_env_key_amt(i, id);
/* patch_get_env_vel_amt(i, id, &vel); */
block(p);
- phat_fan_slider_set_value(PHAT_FAN_SLIDER(p->delay_fan), l);
- phat_fan_slider_set_value(PHAT_FAN_SLIDER(p->attack_fan), a);
- phat_fan_slider_set_value(PHAT_FAN_SLIDER(p->hold_fan), h);
- phat_fan_slider_set_value(PHAT_FAN_SLIDER(p->decay_fan), d);
- phat_fan_slider_set_value(PHAT_FAN_SLIDER(p->sustain_fan), s);
- phat_fan_slider_set_value(PHAT_FAN_SLIDER(p->release_fan), r);
- phat_fan_slider_set_value(PHAT_FAN_SLIDER(p->key_fan), key);
-/* phat_fan_slider_set_value(PHAT_FAN_SLIDER(p->vel_fan), vel); */
+ phin_fan_slider_set_value(PHIN_FAN_SLIDER(p->delay_fan), l);
+ phin_fan_slider_set_value(PHIN_FAN_SLIDER(p->attack_fan), a);
+ phin_fan_slider_set_value(PHIN_FAN_SLIDER(p->hold_fan), h);
+ phin_fan_slider_set_value(PHIN_FAN_SLIDER(p->decay_fan), d);
+ phin_fan_slider_set_value(PHIN_FAN_SLIDER(p->sustain_fan), s);
+ phin_fan_slider_set_value(PHIN_FAN_SLIDER(p->release_fan), r);
+ phin_fan_slider_set_value(PHIN_FAN_SLIDER(p->key_fan), key);
+/* phin_fan_slider_set_value(PHIN_FAN_SLIDER(p->vel_fan), vel); */
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p->env_check), on);
diff --git a/src/gui/envelopetab.h b/gui/envelopetab.h
similarity index 100%
rename from src/gui/envelopetab.h
rename to gui/envelopetab.h
diff --git a/gui/float_section.c b/gui/float_section.c
new file mode 100644
index 0000000..ff1487f
--- /dev/null
+++ b/gui/float_section.c
@@ -0,0 +1,246 @@
+/* Petri-Foo is a fork of the Specimen audio sampler.
+
+ Copyright 2011 James W. Morris
+
+ This file is part of Petri-Foo.
+
+ Petri-Foo is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+
+ Petri-Foo is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Petri-Foo. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#include <gtk/gtk.h>
+
+#include "phin.h"
+
+#include "float_section.h"
+#include "gui.h"
+#include "patch_set_and_get.h"
+#include "names.h"
+
+#include "mod_src_gui.h"
+
+
+typedef struct _FloatSectionPrivate FloatSectionPrivate;
+
+#define FLOAT_SECTION_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE((obj), \
+ FLOAT_SECTION_TYPE, FloatSectionPrivate))
+
+struct _FloatSectionPrivate
+{
+ int patch_id;
+ PatchFloatType float_type;
+
+ GtkWidget* float_fan;
+ GtkWidget* mod_combo;
+ GtkWidget* mod_amt;
+};
+
+
+G_DEFINE_TYPE(FloatSection, float_section, GTK_TYPE_VBOX);
+
+
+static void float_section_class_init(FloatSectionClass* klass)
+{
+ GObjectClass* object_class = G_OBJECT_CLASS(klass);
+ float_section_parent_class = g_type_class_peek_parent(klass);
+ g_type_class_add_private(object_class, sizeof(FloatSectionPrivate));
+}
+
+
+static void float_cb(GtkWidget* w, FloatSectionPrivate* p)
+{
+ float val = phin_fan_slider_get_value(PHIN_FAN_SLIDER(w));
+ patch_float_set_value(p->patch_id, p->float_type, val);
+}
+
+
+static void mod_combo_cb(GtkComboBox* combo, FloatSectionPrivate* p)
+{
+ int mod_src = mod_src_combo_get_mod_src_id(combo);
+ patch_float_set_mod_src(p->patch_id, p->float_type, mod_src);
+ gtk_widget_set_sensitive(p->mod_amt, (mod_src != MOD_SRC_NONE));
+}
+
+
+static void mod_amt_cb(GtkWidget* w, FloatSectionPrivate* p)
+{
+ patch_float_set_mod_amt(p->patch_id,
+ p->float_type,
+ phin_fan_slider_get_value(PHIN_FAN_SLIDER(w)));
+}
+
+
+static void block(FloatSectionPrivate* p)
+{
+ g_signal_handlers_block_by_func(p->float_fan, float_cb, p);
+ g_signal_handlers_block_by_func(p->mod_amt, mod_amt_cb, p);
+ g_signal_handlers_block_by_func(p->mod_combo, mod_combo_cb, p);
+}
+
+
+static void unblock(FloatSectionPrivate* p)
+{
+ g_signal_handlers_unblock_by_func(p->float_fan, float_cb, p);
+ g_signal_handlers_unblock_by_func(p->mod_amt, mod_amt_cb, p);
+ g_signal_handlers_unblock_by_func(p->mod_combo, mod_combo_cb, p);
+}
+
+
+
+static void float_section_init(FloatSection* self)
+{
+ FloatSectionPrivate* p = FLOAT_SECTION_GET_PRIVATE(self);
+ p->patch_id = -1;
+ p->float_type = PATCH_FLOAT_INVALID;
+ p->float_fan = 0;
+ p->mod_combo = 0;
+ p->mod_amt = 0;
+}
+
+
+void float_section_set_float( FloatSection* self, PatchFloatType float_type)
+{
+ FloatSectionPrivate* p = FLOAT_SECTION_GET_PRIVATE(self);
+ GtkBox* box;
+ GtkWidget* table;
+ GtkTable* t;
+
+ int y = 0;
+
+ int a1 = 0, a2 = 1;
+ int b1 = 1, b2 = 2;
+ int c1 = 2, c2 = 3;
+
+ float floatmin, floatmax, floatstep;
+
+ const char* float_names[] = { "Portamento Time" };
+
+ box = GTK_BOX(self);
+
+ p->float_type = float_type;
+
+ switch(float_type)
+ {
+ case PATCH_FLOAT_PORTAMENTO_TIME:
+ floatmin = 0.0;
+ floatmax = 1.0;
+ floatstep = 0.01;
+ break;
+
+ default:
+ debug("Bad News! unknown float type!\n");
+ return;
+ }
+
+ gtk_container_set_border_width(GTK_CONTAINER(self), GUI_BORDERSPACE);
+
+ table = gtk_table_new(3, 3, FALSE);
+ t = (GtkTable*)table;
+ gui_pack(box, table);
+
+ gui_attach(t, gui_title_new(float_names[float_type]), a1, c2, y, y + 1);
+ ++y;
+
+ /* title padding */
+ gui_attach(t, gui_vpad_new(GUI_TITLESPACE), a1, c2, y, y + 1);
+ ++y;
+
+ /* label column spacing (of some description!?) */
+ gui_attach(t, gui_hpad_new(GUI_TEXTSPACE), c1, c2, y, y + 1);
+ ++y;
+
+ p->float_fan = phin_hfan_slider_new_with_range(0.0, floatmin,
+ floatmax,
+ floatstep);
+ gui_attach(t, p->float_fan, b1, b2, y, y + 1);
+ ++y;
+
+ gui_label_attach("Mod:", t, a1, a2, y, y + 1);
+
+ p->mod_combo = mod_src_new_combo_with_cell();
+ mod_src_combo_set_model(GTK_COMBO_BOX(p->mod_combo), MOD_SRC_GLOBALS);
+ gui_attach(t, p->mod_combo, b1, b2, y, y + 1);
+
+ p->mod_amt = phin_hfan_slider_new_with_range(0.0, -1.0, 1.0, 0.1);
+ gui_attach(t, p->mod_amt, c1, c2, y, y + 1);
+ ++y;
+
+ g_signal_connect(G_OBJECT(p->float_fan), "value-changed",
+ G_CALLBACK(float_cb), (gpointer)p);
+
+ g_signal_connect(G_OBJECT(p->mod_amt), "value-changed",
+ G_CALLBACK(mod_amt_cb), (gpointer)p);
+
+ g_signal_connect(G_OBJECT(p->mod_combo), "changed",
+ G_CALLBACK(mod_combo_cb), (gpointer)p);
+}
+
+
+void float_section_set_list_global(FloatSection* self)
+{
+ FloatSectionPrivate* p = FLOAT_SECTION_GET_PRIVATE(self);
+
+ mod_src_combo_set_model(GTK_COMBO_BOX(p->mod_combo), MOD_SRC_GLOBALS);
+}
+
+
+void float_section_set_list_all(FloatSection* self)
+{
+ FloatSectionPrivate* p = FLOAT_SECTION_GET_PRIVATE(self);
+
+ mod_src_combo_set_model(GTK_COMBO_BOX(p->mod_combo), MOD_SRC_ALL);
+}
+
+
+GtkWidget* float_section_new(void)
+{
+ return (GtkWidget*)g_object_new(FLOAT_SECTION_TYPE, NULL);
+}
+
+
+void float_section_set_patch(FloatSection* self, int patch_id)
+{
+ FloatSectionPrivate* p = FLOAT_SECTION_GET_PRIVATE(self);
+
+ float assign;
+ int modsrc;
+ float mod_amt;
+
+ GtkTreeIter moditer;
+
+ p->patch_id = patch_id;
+
+ if (patch_id < 0)
+ return;
+
+ patch_float_get_all(patch_id, p->float_type, &assign,
+ &mod_amt,
+ &modsrc);
+ block(p);
+
+ phin_fan_slider_set_value(PHIN_FAN_SLIDER(p->float_fan), assign);
+ phin_fan_slider_set_value(PHIN_FAN_SLIDER(p->mod_amt), mod_amt);
+
+ if (!mod_src_combo_get_iter_with_id(GTK_COMBO_BOX(p->mod_combo),
+ modsrc,
+ &moditer))
+ {
+ debug("failed to get mod source id from combo box\n");
+ }
+
+ gtk_combo_box_set_active_iter(GTK_COMBO_BOX(p->mod_combo), &moditer);
+
+ unblock(p);
+}
+
diff --git a/gui/float_section.h b/gui/float_section.h
new file mode 100644
index 0000000..5509ca0
--- /dev/null
+++ b/gui/float_section.h
@@ -0,0 +1,75 @@
+/* Petri-Foo is a fork of the Specimen audio sampler.
+
+ Copyright 2011 James W. Morris
+
+ This file is part of Petri-Foo.
+
+ Petri-Foo is free software: you can redistribute it and/or Boolify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+
+ Petri-Foo is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Petri-Foo. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#ifndef __FLOAT_SECTION__
+#define __FLOAT_SECTION__
+
+#include <gtk/gtk.h>
+
+
+#include "patch.h"
+
+
+G_BEGIN_DECLS
+
+#define FLOAT_SECTION_TYPE (float_section_get_type())
+#define FLOAT_SECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ FLOAT_SECTION_TYPE, FloatSection))
+
+#define IS_FLOAT_SECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ FLOAT_SECTION_TYPE))
+
+#define FLOAT_SECTION_CLASS(klass)(G_TYPE_CHECK_CLASS_CAST ((klass), \
+ FLOAT_SECTION_TYPE, FloatSectionClass))
+
+#define IS_FLOAT_SECTION_CLASS(klass) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((klass), FLOAT_SECTION_TYPE))
+
+
+typedef struct _FloatSectionClass FloatSectionClass;
+typedef struct _FloatSection FloatSection;
+
+
+struct _FloatSection
+{
+ GtkVBox parent_instance;
+};
+
+
+struct _FloatSectionClass
+{
+ GtkVBoxClass parent_class;
+ /* <private> */
+ void (*set_toggled)(FloatSection*);
+};
+
+
+GType float_section_get_type(void);
+
+GtkWidget* float_section_new(void);
+
+void float_section_set_float(FloatSection*, PatchFloatType);
+void float_section_set_patch(FloatSection*, int patch_id);
+
+
+G_END_DECLS
+
+
+#endif /* __FLOAT_SECTION__ */
diff --git a/gui/global_settings.c b/gui/global_settings.c
new file mode 100644
index 0000000..23c679b
--- /dev/null
+++ b/gui/global_settings.c
@@ -0,0 +1,287 @@
+/* Petri-Foo is a fork of the Specimen audio sampler.
+
+ Copyright 2011 Brendan S. Jones
+
+ This file is part of Petri-Foo.
+
+ Petri-Foo is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+
+ Petri-Foo is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Petri-Foo. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include <libxml/parser.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+
+
+#include "phin.h"
+#include "global_settings.h"
+#include "petri-foo.h"
+#include "msg_log.h"
+
+
+#define SETTINGS_BASENAME "rc.xml"
+
+
+static global_settings* gbl_settings = 0;
+/*
+ init and read settings
+*/
+void settings_init()
+{
+ if (gbl_settings) settings_free();
+
+ gbl_settings = malloc(sizeof(global_settings));
+ gbl_settings->last_sample_dir = strdup(getenv("HOME"));
+ gbl_settings->last_bank_dir = strdup(getenv("HOME"));
+
+ gbl_settings->filename = (char*) g_build_filename(
+ g_get_user_config_dir(),
+ g_get_prgname(),
+ SETTINGS_BASENAME,
+ NULL);
+
+ gbl_settings->log_lines = DEFAULT_LOG_LINES;
+/*
+ gbl_settings->abs_max_sample_size = DEFAULT_ABS_MAX_SAMPLE;
+ gbl_settings->max_sample_size = DEFAULT_MAX_SAMPLE;
+ */
+ settings_read((char*) gbl_settings->filename);
+}
+
+
+static gboolean xmlstr_to_gboolean(xmlChar* str)
+{
+ if (xmlStrcasecmp(str, BAD_CAST "true") == 0
+ || xmlStrcasecmp(str, BAD_CAST "on") == 0
+ || xmlStrcasecmp(str, BAD_CAST "yes") == 0)
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+int settings_read(const char* path)
+{
+ xmlDocPtr doc;
+ xmlNodePtr noderoot;
+ xmlNodePtr node1;
+ xmlNodePtr node2;
+ xmlChar* prop;
+
+ msg_log(MSG_MESSAGE, "Reading global settings from: %s\n",path);
+
+ doc = xmlParseFile (path);
+
+ if (doc == NULL)
+ {
+ msg_log(MSG_ERROR, "Failed to parse %s\n", path);
+ return -1;
+ }
+
+ noderoot = xmlDocGetRootElement(doc);
+
+ if (noderoot == NULL)
+ {
+ msg_log(MSG_WARNING, "%s is empty\n", path);
+ xmlFreeDoc(doc);
+ return -1;
+ }
+
+ if (xmlStrcmp(noderoot->name, BAD_CAST "Petri-Foo-Settings") != 0)
+ {
+ msg_log(MSG_ERROR,
+ "%s is not a valid 'Petri-Foo-Settings' file\n", path);
+ xmlFreeDoc(doc);
+ return -1;
+ }
+
+ for (node1 = noderoot->children;
+ node1 != NULL;
+ node1 = node1->next)
+ {
+ if (node1->type != XML_ELEMENT_NODE)
+ continue;
+
+ for ( node2 = node1->children;
+ node2 != NULL;
+ node2 = node2->next)
+ {
+ int n;
+
+ if (xmlStrcmp(node2->name, BAD_CAST "property") == 0)
+ {
+ prop = BAD_CAST xmlGetProp(node2, BAD_CAST "name");
+
+ if (xmlStrcmp(prop, BAD_CAST "last-sample-directory") == 0)
+ {
+ free(gbl_settings->last_sample_dir);
+ gbl_settings->last_sample_dir =
+ (char*) xmlGetProp(node2, BAD_CAST "value");
+ }
+
+ if (xmlStrcmp(prop, BAD_CAST "last-bank-directory") == 0)
+ {
+ free(gbl_settings->last_bank_dir);
+ gbl_settings->last_bank_dir =
+ (char*) xmlGetProp(node2, BAD_CAST "value");
+ }
+
+ if (xmlStrcmp(prop, BAD_CAST "sliders-use-fans") == 0)
+ {
+ phin_fan_slider_set_fans_active(
+ xmlstr_to_gboolean(xmlGetProp(node2,
+ BAD_CAST "value")));
+ }
+
+ if (xmlStrcmp(prop, BAD_CAST "log-lines") == 0)
+ {
+ xmlChar* vprop = xmlGetProp(node2, BAD_CAST "value");
+
+ if (sscanf((const char*)vprop, "%d", &n) == 1)
+ gbl_settings->log_lines = n;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+int settings_write()
+{
+ int rc;
+ char* config_dir;
+ char buf[CHARBUFSIZE];
+
+ xmlDocPtr doc;
+ xmlNodePtr noderoot;
+ xmlNodePtr node1;
+ xmlNodePtr node2;
+
+ msg_log(MSG_MESSAGE, "Writing global settings to: %s\n",
+ gbl_settings->filename);
+
+ doc = xmlNewDoc(BAD_CAST "1.0");
+
+ if (!doc)
+ {
+ msg_log(MSG_ERROR, "XML error!\n");
+ return -1;
+ }
+
+ config_dir = (char*) g_build_filename(g_get_user_config_dir(),
+ g_get_prgname(), NULL);
+
+ if (mkdir(config_dir, S_IRWXU) != 0)
+ {
+ if (errno != EEXIST)
+ {
+ msg_log(MSG_ERROR,
+ "Could not create config directory: %s.\n",
+ config_dir);
+ free(config_dir);
+ return -1;
+ }
+ }
+
+ free(gbl_settings->filename);
+ gbl_settings->filename = (char*) g_build_filename(config_dir,
+ SETTINGS_BASENAME,
+ NULL);
+ free(config_dir);
+
+ noderoot = xmlNewDocNode(doc, NULL, BAD_CAST "Petri-Foo-Settings",NULL);
+
+ if (!noderoot)
+ {
+ msg_log(MSG_ERROR, "XML error!\n");
+ return -1;
+ }
+
+ xmlDocSetRootElement(doc, noderoot);
+
+ node1 = xmlNewTextChild(noderoot, NULL, BAD_CAST "global", NULL);
+
+ node2 = xmlNewTextChild(node1, NULL, BAD_CAST "property", NULL);
+ xmlNewProp(node2, BAD_CAST "name", BAD_CAST "last-sample-directory");
+ xmlNewProp(node2, BAD_CAST "type", BAD_CAST "string");
+ xmlNewProp(node2, BAD_CAST "value",
+ BAD_CAST gbl_settings->last_sample_dir);
+
+ node2 = xmlNewTextChild(node1, NULL, BAD_CAST "property", NULL);
+ xmlNewProp(node2, BAD_CAST "name", BAD_CAST "last-bank-directory");
+ xmlNewProp(node2, BAD_CAST "type", BAD_CAST "string");
+ xmlNewProp(node2, BAD_CAST "value",
+ BAD_CAST gbl_settings->last_bank_dir);
+
+ node2 = xmlNewTextChild(node1, NULL, BAD_CAST "property", NULL);
+ xmlNewProp(node2, BAD_CAST "name", BAD_CAST "sliders-use-fans");
+ xmlNewProp(node2, BAD_CAST "type", BAD_CAST "boolean");
+ xmlNewProp(node2, BAD_CAST "value",
+ BAD_CAST (phin_fan_slider_get_fans_active()
+ ? "true"
+ : "false"));
+
+ node2 = xmlNewTextChild(node1, NULL, BAD_CAST "property", NULL);
+ xmlNewProp(node2, BAD_CAST "name", BAD_CAST "last-bank-directory");
+ xmlNewProp(node2, BAD_CAST "type", BAD_CAST "string");
+ xmlNewProp(node2, BAD_CAST "value",
+ BAD_CAST gbl_settings->last_bank_dir);
+
+ node2 = xmlNewTextChild(node1, NULL, BAD_CAST "property", NULL);
+ xmlNewProp(node2, BAD_CAST "name", BAD_CAST "log-lines");
+ xmlNewProp(node2, BAD_CAST "type", BAD_CAST "int");
+
+ snprintf(buf, CHARBUFSIZE, "%d", gbl_settings->log_lines);
+
+ xmlNewProp(node2, BAD_CAST "value", BAD_CAST buf);
+
+ debug("attempting to write file:%s\n",gbl_settings->filename);
+
+ rc = xmlSaveFormatFile(gbl_settings->filename, doc, 1);
+ xmlFreeDoc(doc);
+
+ return rc;
+}
+
+
+global_settings* settings_get(void)
+{
+ return gbl_settings;
+}
+
+
+void settings_free(void)
+{
+ if (gbl_settings == NULL)
+ return;
+
+ if (gbl_settings->filename)
+ free(gbl_settings->filename);
+
+ if (gbl_settings->last_sample_dir)
+ free(gbl_settings->last_sample_dir);
+
+ if (gbl_settings->last_bank_dir)
+ free(gbl_settings->last_bank_dir);
+
+ free(gbl_settings);
+
+ return;
+}
diff --git a/src/dish_file.h b/gui/global_settings.h
similarity index 50%
copy from src/dish_file.h
copy to gui/global_settings.h
index 5d875fd..38d8896 100644
--- a/src/dish_file.h
+++ b/gui/global_settings.h
@@ -1,6 +1,6 @@
/* Petri-Foo is a fork of the Specimen audio sampler.
- Copyright 2011 James W. Morris
+ Copyright 2011 Brendan Jones
This file is part of Petri-Foo.
@@ -18,18 +18,37 @@
*/
-#ifndef DISH_FILE_H
-#define DISH_FILE_H
+#ifndef SETTINGS_H
+#define SETTINGS_H
-/* recommended file extension for petri-foo data files:
- (includes dot)
+/* global settings
+
*/
-const char* dish_file_extension(void);
+#define DEFAULT_LOG_LINES 100
+#define DEFAULT_ABS_MAX_SAMPLE (1024 * 1024 * 1024)
+#define DEFAULT_MAX_SAMPLE (1024 * 1024 * 25)
-int dish_file_read(const char* name);
-int dish_file_write(const char* name);
+
+typedef struct global_settings_def
+{
+ char* filename;
+ char* last_sample_dir;
+ char* last_bank_dir;
+ int log_lines;
+/*
+ int abs_max_sample_size;
+ int max_sample_size;
+ */
+} global_settings;
+
+
+void settings_init(void);
+int settings_read(const char* path);
+int settings_write(void);
+global_settings* settings_get(void);
+void settings_free();
#endif
diff --git a/src/gui/gui.c b/gui/gui.c
similarity index 75%
rename from src/gui/gui.c
rename to gui/gui.c
index 5716943..dd46667 100644
--- a/src/gui/gui.c
+++ b/gui/gui.c
@@ -30,23 +30,28 @@
#include "instance.h"
#include "petri-foo.h"
+#include "pf_error.h"
+#include "phin.h"
+#include "audio-settings.h"
+#include "bank-ops.h"
+#include "channelsection.h"
+#include "config.h"
#include "driver.h"
-#include "mixer.h"
#include "gui.h"
-#include "patchsection.h"
+#include "log_display.h"
#include "mastersection.h"
-#include "channelsection.h"
#include "midisection.h"
-#include "patchlist.h"
-#include "waveform.h"
-#include "sample-editor.h"
-#include "sample-selector.h"
-#include "bank-ops.h"
-#include "audio-settings.h"
+#include "mixer.h"
#include "mod_src_gui.h"
+#include "msg_log.h"
+#include "patchlist.h"
+#include "patchsection.h"
#include "patch_set_and_get.h"
#include "patch_util.h"
+#include "sample-editor.h"
+#include "sample-selector.h"
+#include "waveform.h"
/* windows */
@@ -59,10 +64,23 @@ static GtkWidget* patch_list;
/* main menu */
+static GtkWidget* menubar = 0;
static GtkWidget* menu_file = 0;
static GtkWidget* menu_settings = 0;
static GtkWidget* menu_patch = 0;
static GtkWidget* menu_help = 0;
+static GtkWidget* menu_view = 0;
+static GtkWidget* menuitem_file_recent = 0;
+
+/* view menu */
+static GtkWidget* menu_view_log_display = 0;
+
+
+/* settings */
+static GtkWidget* menu_settings_fans = 0;
+
+/* current patch, makes passing patch id to sample editor easier */
+static int cur_patch = -1;
GtkWidget* gui_title_new(const char* msg)
@@ -264,8 +282,8 @@ void cb_menu_patch_add(GtkWidget* menu_item, gpointer data)
if (id < 0)
{
- errmsg("Failed to create a new patch (%s).\n",
- patch_strerror(id));
+ msg_log(MSG_ERROR, "Failed to create a new patch (%s).\n",
+ pf_error_str(pf_error_get()));
return;
}
@@ -289,8 +307,8 @@ void cb_menu_patch_add_default(GtkWidget* menu_item, gpointer data)
if (id < 0)
{
- errmsg("Failed to create a new patch (%s).\n",
- patch_strerror(id));
+ msg_log(MSG_ERROR, "Failed to create a new patch (%s).\n",
+ pf_error_str(pf_error_get()));
return;
}
@@ -310,14 +328,14 @@ void cb_menu_patch_duplicate(GtkWidget* menu_item, gpointer data)
if ((cp = patch_list_get_current_patch(PATCH_LIST(patch_list))) < 0)
{ /* let's be a little more polite here shall we? */
- debug ("Pardon, but exactly what am I to duplicate?\n");
+ msg_log(MSG_WARNING, "No patch to duplicate\n");
return;
}
if ((val = patch_duplicate(cp)) < 0)
{
- errmsg ("Failed to create a new patch (%s).\n",
- patch_strerror (val));
+ msg_log(MSG_ERROR, "Failed to duplicate patch (%s).\n",
+ pf_error_str(pf_error_get()));
return;
}
@@ -382,8 +400,8 @@ void cb_menu_patch_rename(GtkWidget* menu_item, gpointer data)
if (val < 0)
{
- errmsg ("Failed to rename patch (%s).\n",
- patch_strerror (val));
+ msg_log(MSG_ERROR, "Failed to rename patch (%s).\n",
+ pf_error_str(pf_error_get()));
return;
}
@@ -410,12 +428,7 @@ void cb_menu_patch_remove(GtkWidget* menu_item, gpointer data)
}
index = patch_list_get_current_index (PATCH_LIST(patch_list));
- if ((val = patch_destroy (cp)) < 0)
- {
- errmsg ("Error removing patch %d (%s).\n", cp,
- patch_strerror (val));
- return;
- }
+ patch_destroy(cp);
if (index == 0)
patch_list_update(PATCH_LIST(patch_list), index,
@@ -426,6 +439,25 @@ void cb_menu_patch_remove(GtkWidget* menu_item, gpointer data)
}
+void cb_menu_view_log_display_showing(gboolean active)
+{
+ gtk_check_menu_item_set_active(
+ GTK_CHECK_MENU_ITEM(menu_view_log_display), active);
+}
+
+
+static void cb_menu_view_log_display(GtkWidget* widget, gpointer data)
+{
+ if (gtk_check_menu_item_get_active(
+ GTK_CHECK_MENU_ITEM(menu_view_log_display)))
+ {
+ log_display_show();
+ }
+ else
+ log_display_hide();
+}
+
+
static void cb_menu_file_new_bank (GtkWidget * widget, gpointer data)
{
(void)widget;(void)data;
@@ -469,6 +501,15 @@ static void cb_menu_settings_audio (GtkWidget * widget, gpointer data)
}
+static void cb_menu_settings_fans(GtkWidget* widget, gpointer data)
+{
+ (void)widget;(void)data;
+ phin_fan_slider_set_fans_active(
+ gtk_check_menu_item_get_active(
+ GTK_CHECK_MENU_ITEM(menu_settings_fans)));
+}
+
+
static void cb_menu_help_stfu (GtkWidget* widget, gpointer data)
{
(void)widget;(void)data;
@@ -479,13 +520,13 @@ static void cb_menu_help_stfu (GtkWidget* widget, gpointer data)
static void cb_menu_help_about (GtkWidget* widget, gpointer data)
{
(void)widget;
- GdkPixbuf* logo;
- const char* authors[] = { "Pete Bessman (original author)",
- "See the AUTHORS file for others", 0 };
-
- /* should this be freed later on? */
- logo = gdk_pixbuf_new_from_file(PIXMAPSDIR "petri-foo.png", NULL);
+ GdkPixbuf* logo = 0;
+ const char* authors[] = { "Pete Bessman - original Specimen author",
+ "James Morris - Petri-Foo creator",
+ "See the AUTHORS file for others", 0 };
+/* should this be freed later on? */
+ logo = gdk_pixbuf_new_from_file(PIXMAPS_DIR "/petri-foo.png", NULL);
gtk_show_about_dialog(
GTK_WINDOW(data),
"name", "Petri-Foo",
@@ -502,21 +543,48 @@ static void cb_menu_help_about (GtkWidget* widget, gpointer data)
static void cb_patch_list_changed(PatchList* list, gpointer data)
{
(void)data;
- int patch = patch_list_get_current_patch(list);
+ cur_patch = patch_list_get_current_patch(list);
- debug("patch list changed!\n");
+ debug("patch list changed patch:%d!\n",cur_patch);
- patch_section_set_patch(PATCH_SECTION(patch_section), patch);
- midi_section_set_patch(MIDI_SECTION(midi_section), patch);
- channel_section_set_patch(CHANNEL_SECTION(channel_section), patch);
+ if (cur_patch < 0)
+ sample_editor_hide();
+ else if (sample_editor_get_visible())
+ sample_editor_show(cur_patch);
+
+ patch_section_set_patch(PATCH_SECTION(patch_section), cur_patch);
+ midi_section_set_patch(MIDI_SECTION(midi_section), cur_patch);
+ channel_section_set_patch(CHANNEL_SECTION(channel_section), cur_patch);
}
+static void cb_recent_chooser_item_activated (GtkRecentChooser *chooser
+ , gpointer *data)
+{
+ (void)data;
+ gchar *uri;
+ gchar *filename;
+ GtkRecentInfo *recentInfo;
+ debug("recent-menu item-activated");
+ uri = gtk_recent_chooser_get_current_uri (chooser);
+ filename = g_filename_from_uri(uri, NULL, NULL);
+ recentInfo = gtk_recent_chooser_get_current_item(chooser);
+ gtk_recent_manager_add_item(recent_manager, uri);
+ gtk_recent_info_unref(recentInfo);
+ if (bank_ops_open_recent(window, (char*) filename) == 0)
+ {
+ patch_list_update (PATCH_LIST(patch_list), 0, PATCH_LIST_INDEX);
+ master_section_update(MASTER_SECTION(master_section));
+ }
+
+ g_free(uri);
+ g_free(filename);
+}
+
int gui_init(void)
{
GtkWidget* window_vbox;
GtkWidget* master_hbox;
- GtkWidget* menubar;
GtkWidget* vbox;
debug ("Initializing GUI\n");
@@ -544,10 +612,14 @@ int gui_init(void)
G_CALLBACK(cb_menu_file_new_bank), window);
gui_menu_add(menu_file, "Open Bank...",
G_CALLBACK(cb_menu_file_open_bank), window);
+
+ menuitem_file_recent = gtk_menu_item_new_with_label("Open Recent");
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu_file), menuitem_file_recent);
gui_menu_add(menu_file, "Save Bank",
G_CALLBACK(cb_menu_file_save_bank), window);
gui_menu_add(menu_file, "Save Bank As...",
G_CALLBACK(cb_menu_file_save_bank_as), window);
+
/* seperator */
gui_menu_add(menu_file, NULL, NULL, NULL);
gui_menu_add(menu_file, "Quit", G_CALLBACK(cb_quit), NULL);
@@ -565,18 +637,42 @@ int gui_init(void)
gui_menu_add(menu_patch, "Remove",
G_CALLBACK(cb_menu_patch_remove), NULL);
+ /* view menu */
+ menu_view = gui_menu_add(menubar, "View", NULL, NULL);
+
+ menu_view_log_display =
+ gui_menu_check_add(menu_view, "Message Log", FALSE,
+ G_CALLBACK(cb_menu_view_log_display), window);
+
/* settings menu */
menu_settings = gui_menu_add(menubar, "Settings", NULL, NULL);
gui_menu_add(menu_settings, "Audio...",
G_CALLBACK(cb_menu_settings_audio), NULL);
+ menu_settings_fans =
+ gtk_check_menu_item_new_with_label("Use slider fans");
+
+ gtk_check_menu_item_set_active(
+ GTK_CHECK_MENU_ITEM(menu_settings_fans),
+ phin_fan_slider_get_fans_active());
+
+ g_signal_connect(GTK_OBJECT(menu_settings_fans), "toggled",
+ G_CALLBACK(cb_menu_settings_fans), NULL);
+
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu_settings),
+ menu_settings_fans);
+
+ gtk_widget_show(menu_settings_fans);
+
/* help menu */
menu_help = gui_menu_add(menubar, "Help", NULL, NULL);
- gui_menu_add(menu_help, "Stuff You!",
+ gui_menu_add(menu_help, "All Sound Off!",
G_CALLBACK(cb_menu_help_stfu), NULL);
gui_menu_add(menu_help, "About...",
G_CALLBACK(cb_menu_help_about), window);
+ gui_recent_files_load();
+
gtk_widget_show_all(menubar);
/* setup the main window's master hbox, and left and right boxes */
@@ -631,6 +727,7 @@ int gui_init(void)
/* intialize children */
sample_editor_init(window);
audio_settings_init(window);
+ log_display_init(window);
/* priming updates */
master_section_update(MASTER_SECTION(master_section));
@@ -646,6 +743,7 @@ void gui_refresh(void)
master_section_update(MASTER_SECTION(master_section));
patch_list_update(PATCH_LIST(patch_list), 0, PATCH_LIST_INDEX);
cb_patch_list_changed(PATCH_LIST(patch_list), NULL);
+ gui_recent_files_load();
}
@@ -697,3 +795,51 @@ GtkWidget* gui_menu_add(GtkWidget* menu, const char* label, GCallback cb,
return (submenu) ? submenu : item;
}
+
+
+GtkWidget*
+gui_menu_check_add(GtkWidget* menu, const char* label, gboolean active,
+ GCallback cb,
+ gpointer data)
+{
+ GtkWidget* item = 0;
+ GtkWidget* submenu = 0;
+
+ item = gtk_check_menu_item_new_with_label(label);
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), active);
+ g_signal_connect(item, "toggled", cb, data);
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+
+ return item;
+}
+
+/* recent items menu */
+void gui_recent_files_load(void)
+{
+ GtkWidget* menuitem_to_append_to = NULL;
+ GtkRecentFilter *recent_filter;
+ GtkWidget *menuitem_file_recent_items;
+ recent_manager = gtk_recent_manager_get_default();
+ recent_filter = gtk_recent_filter_new();
+ gtk_recent_filter_add_mime_type(recent_filter, "application/x-petri-foo");
+ menuitem_file_recent_items =
+ gtk_recent_chooser_menu_new_for_manager(recent_manager);
+ gtk_recent_chooser_add_filter(
+ GTK_RECENT_CHOOSER(menuitem_file_recent_items), recent_filter);
+ gtk_recent_chooser_set_show_tips(
+ GTK_RECENT_CHOOSER(menuitem_file_recent_items), TRUE);
+ gtk_recent_chooser_set_sort_type(
+ GTK_RECENT_CHOOSER(menuitem_file_recent_items),
+ GTK_RECENT_SORT_MRU);
+ gtk_recent_chooser_set_limit(
+ GTK_RECENT_CHOOSER(menuitem_file_recent_items), 10);
+ gtk_recent_chooser_set_local_only(
+ GTK_RECENT_CHOOSER(menuitem_file_recent_items), FALSE);
+ gtk_recent_chooser_menu_set_show_numbers(
+ GTK_RECENT_CHOOSER_MENU(menuitem_file_recent_items), TRUE);
+ g_signal_connect(GTK_OBJECT(menuitem_file_recent_items), "item-activated",
+ G_CALLBACK(cb_recent_chooser_item_activated), window);
+ gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem_file_recent),
+ menuitem_file_recent_items);
+
+}
diff --git a/src/gui/gui.h b/gui/gui.h
similarity index 84%
rename from src/gui/gui.h
rename to gui/gui.h
index 594899c..7bd15e3 100644
--- a/src/gui/gui.h
+++ b/gui/gui.h
@@ -38,9 +38,12 @@ enum
GUI_TEXTSPACE = 12, /* space between a label and its control */
GUI_BORDERSPACE = 12, /* space between a border and its guts */
GUI_THRESHOLD = 20, /* threshold used for sliderbuttons */
- GUI_REFRESH_TIMEOUT = 100 /* time in milliseconds between controller refreshes */
+ GUI_REFRESH_TIMEOUT = 100, /* time in milliseconds between controller refreshes */
+ GUI_MAX_RECENT_FILES = 5 /* maximum recent files in Open Recent Bank menu */
};
+/* Recent Manager */
+
/* returns a titlefied label */
GtkWidget* gui_title_new(const char* msg);
@@ -74,6 +77,9 @@ int gui_init(void);
/* refresh the gui's display */
void gui_refresh(void);
+/* update the recently used files */
+void gui_recent_files_load(void);
+
/* get the gui's PatchList widget */
PatchList* gui_get_patch_list(void);
@@ -87,8 +93,17 @@ void cb_menu_patch_duplicate( GtkWidget* menu_item, gpointer data);
void cb_menu_patch_rename( GtkWidget* menu_item, gpointer data);
void cb_menu_patch_remove( GtkWidget* menu_item, gpointer data);
+void cb_menu_view_log_display_showing(gboolean);
+
GtkWidget* gui_menu_add(GtkWidget* menu, const char* label, GCallback cb,
gpointer data);
+GtkWidget*
+ gui_menu_check_add(GtkWidget* menu, const char* label, gboolean active,
+ GCallback cb,
+ gpointer data);
+
+GtkRecentManager *recent_manager;
+
#endif /* __GUI_H__ */
diff --git a/src/gui/idselector.c b/gui/idselector.c
similarity index 100%
rename from src/gui/idselector.c
rename to gui/idselector.c
diff --git a/src/gui/idselector.h b/gui/idselector.h
similarity index 100%
rename from src/gui/idselector.h
rename to gui/idselector.h
diff --git a/src/gui/lfotab.c b/gui/lfotab.c
similarity index 85%
rename from src/gui/lfotab.c
rename to gui/lfotab.c
index cbf1ba3..50fb17d 100644
--- a/src/gui/lfotab.c
+++ b/gui/lfotab.c
@@ -23,7 +23,9 @@
#include <gtk/gtk.h>
-#include <phat/phat.h>
+
+#include "phin.h"
+
#include "lfotab.h"
#include "gui.h"
#include "idselector.h"
@@ -110,7 +112,7 @@ static void set_sensitive(LfoTabPrivate* p, gboolean val)
GTK_TOGGLE_BUTTON(p->sync_radio));
/* setting the table itself takes care of the labels,
- * but still need to set the phat widgets...
+ * but still need to set the phin widgets...
*/
gtk_widget_set_sensitive(p->lfo_table, val);
@@ -146,7 +148,7 @@ static void idsel_cb(IDSelector* ids, LfoTabPrivate* p)
static void on_cb(GtkToggleButton* button, LfoTabPrivate* p)
{
- patch_set_lfo_on(p->patch_id, p->lfo_id,
+ patch_set_lfo_active(p->patch_id, p->lfo_id,
gtk_toggle_button_get_active(button));
}
@@ -190,17 +192,17 @@ static void sync_cb2(GtkToggleButton* button, LfoTabPrivate* p)
}
-static void freq_cb(PhatFanSlider* fan, LfoTabPrivate* p)
+static void freq_cb(PhinFanSlider* fan, LfoTabPrivate* p)
{
patch_set_lfo_freq( p->patch_id, p->lfo_id,
- phat_fan_slider_get_value(fan));
+ phin_fan_slider_get_value(fan));
}
-static void beats_cb(PhatSliderButton* button, LfoTabPrivate* p)
+static void beats_cb(PhinSliderButton* button, LfoTabPrivate* p)
{
- patch_set_lfo_beats(p->patch_id, p->lfo_id,
- phat_slider_button_get_value(button));
+ patch_set_lfo_sync_beats(p->patch_id, p->lfo_id,
+ phin_slider_button_get_value(button));
}
static void positive_cb(GtkToggleButton* button, LfoTabPrivate* p)
@@ -210,17 +212,17 @@ static void positive_cb(GtkToggleButton* button, LfoTabPrivate* p)
}
-static void delay_cb(PhatFanSlider* fan, LfoTabPrivate* p)
+static void delay_cb(PhinFanSlider* fan, LfoTabPrivate* p)
{
patch_set_lfo_delay(p->patch_id, p->lfo_id,
- phat_fan_slider_get_value(fan));
+ phin_fan_slider_get_value(fan));
}
-static void attack_cb(PhatFanSlider* fan, LfoTabPrivate* p)
+static void attack_cb(PhinFanSlider* fan, LfoTabPrivate* p)
{
patch_set_lfo_attack(p->patch_id, p->lfo_id,
- phat_fan_slider_get_value(fan));
+ phin_fan_slider_get_value(fan));
}
static void mod_src_cb(GtkComboBox* combo, LfoTabPrivate* p)
@@ -246,7 +248,7 @@ static void mod_src_cb(GtkComboBox* combo, LfoTabPrivate* p)
static void mod_amount_cb(GtkWidget* w, LfoTabPrivate* p)
{
- float val = phat_fan_slider_get_value(PHAT_FAN_SLIDER(w));
+ float val = phin_fan_slider_get_value(PHIN_FAN_SLIDER(w));
if (w == p->fm1_amount)
patch_set_lfo_fm1_amt(p->patch_id, p->lfo_id, val);
@@ -405,7 +407,7 @@ static void lfo_tab_init(LfoTab* self)
/* freq */
gui_label_attach("Hrtz:", t, a1, a2, y, y + 1);
p->free_radio = gtk_radio_button_new(NULL);
- p->freq_fan = phat_hfan_slider_new_with_range(5.0, 0.0, 50.0, 0.1);
+ p->freq_fan = phin_hfan_slider_new_with_range(5.0, 0.0, 50.0, 0.1);
gui_attach(t, p->free_radio, b1, b2, y, y + 1);
gui_attach(t, p->freq_fan, c1, c2, y, y + 1);
++y;
@@ -413,10 +415,10 @@ static void lfo_tab_init(LfoTab* self)
/* sync */
p->sync_radio = gtk_radio_button_new_from_widget(
GTK_RADIO_BUTTON(p->free_radio));
- p->beats_sb = phat_slider_button_new_with_range(1.0, .25, 32.0, .25, 2);
- phat_slider_button_set_format(PHAT_SLIDER_BUTTON(p->beats_sb),
+ p->beats_sb = phin_slider_button_new_with_range(1.0, .25, 32.0, .25, 2);
+ phin_slider_button_set_format(PHIN_SLIDER_BUTTON(p->beats_sb),
-1, NULL, "Beats");
- phat_slider_button_set_threshold(PHAT_SLIDER_BUTTON(p->beats_sb),
+ phin_slider_button_set_threshold(PHIN_SLIDER_BUTTON(p->beats_sb),
GUI_THRESHOLD);
gui_attach(t, p->sync_radio, b1, b2, y, y + 1);
gui_attach(t, p->beats_sb, c1, c2, y, y + 1);
@@ -430,7 +432,7 @@ static void lfo_tab_init(LfoTab* self)
++y;
gui_label_attach("Amount:", t, a1, a2, y, y + 1);
- p->fm1_amount = phat_hfan_slider_new_with_range(0.0, -1.0, 1.0, 0.1);
+ p->fm1_amount = phin_hfan_slider_new_with_range(0.0, -1.0, 1.0, 0.1);
gui_attach(t, p->fm1_amount, c1, c2, y, y + 1);
++y;
@@ -441,7 +443,7 @@ static void lfo_tab_init(LfoTab* self)
++y;
gui_label_attach("Amount:", t, a1, a2, y, y + 1);
- p->fm2_amount = phat_hfan_slider_new_with_range(0.0, -1.0, 1.0, 0.1);
+ p->fm2_amount = phin_hfan_slider_new_with_range(0.0, -1.0, 1.0, 0.1);
gui_attach(t, p->fm2_amount, c1, c2, y, y + 1);
++y;
@@ -469,13 +471,13 @@ static void lfo_tab_init(LfoTab* self)
/* delay fan */
p->delay_label = label = gui_label_attach("Delay:", t, a1, a2, y, y+1);
- p->delay_fan = phat_hfan_slider_new_with_range(0.1, 0.0, 1.0, 0.01);
+ p->delay_fan = phin_hfan_slider_new_with_range(0.1, 0.0, 1.0, 0.01);
gui_attach(t, p->delay_fan, c1, c2, y, y + 1);
++y;
/* attack fan */
p->attack_label = label = gui_label_attach("Attack:", t, a1, a2, y,y+1);
- p->attack_fan = phat_hfan_slider_new_with_range(0.1, 0.0, 1.0, 0.01);
+ p->attack_fan = phin_hfan_slider_new_with_range(0.1, 0.0, 1.0, 0.01);
gui_attach(t, p->attack_fan, c1, c2, y, y + 1);
++y;
@@ -486,7 +488,7 @@ static void lfo_tab_init(LfoTab* self)
++y;
gui_label_attach("Amount:", t, a1, a2, y, y + 1);
- p->am1_amount = phat_hfan_slider_new_with_range(0.0, -1.0, 1.0, 0.1);
+ p->am1_amount = phin_hfan_slider_new_with_range(0.0, -1.0, 1.0, 0.1);
gui_attach(t, p->am1_amount, c1, c2, y, y + 1);
++y;
@@ -497,7 +499,7 @@ static void lfo_tab_init(LfoTab* self)
++y;
gui_label_attach("Amount:", t, a1, a2, y, y + 1);
- p->am2_amount = phat_hfan_slider_new_with_range(0.0, -1.0, 1.0, 0.1);
+ p->am2_amount = phin_hfan_slider_new_with_range(0.0, -1.0, 1.0, 0.1);
gui_attach(t, p->am2_amount, c1, c2, y, y + 1);
++y;
@@ -512,8 +514,7 @@ static void update_lfo(LfoTabPrivate* p)
LFOShape lfoshape;
int shape;
float freq, beats, delay, attack;
- bool sync, positive;
- bool on;
+ bool active, sync, positive;
GtkTreeIter iter;
int fm1src, fm2src;
@@ -542,31 +543,32 @@ static void update_lfo(LfoTabPrivate* p)
mod_src_combo_set_model(GTK_COMBO_BOX(p->am2_combo), mod_srcs);
unblock(p);
- debug("getting lfo (id:%d) data from patch\n", p->lfo_id);
+ debug("getting lfo (id:%d) data from patch:%d\n",
+ p->lfo_id,p->patch_id);
- patch_get_lfo_shape( p->patch_id, p->lfo_id, &lfoshape);
- patch_get_lfo_freq( p->patch_id, p->lfo_id, &freq);
- patch_get_lfo_beats( p->patch_id, p->lfo_id, &beats);
+ lfoshape = patch_get_lfo_shape( p->patch_id, p->lfo_id);
+ freq = patch_get_lfo_freq( p->patch_id, p->lfo_id);
+ beats = patch_get_lfo_sync_beats( p->patch_id, p->lfo_id);
if (!mod_src_is_global(p->lfo_id))
{
- patch_get_lfo_delay( p->patch_id, p->lfo_id, &delay);
- patch_get_lfo_attack( p->patch_id, p->lfo_id, &attack);
+ delay = patch_get_lfo_delay( p->patch_id, p->lfo_id);
+ attack = patch_get_lfo_attack( p->patch_id, p->lfo_id);
}
- patch_get_lfo_sync( p->patch_id, p->lfo_id, &sync);
- patch_get_lfo_positive( p->patch_id, p->lfo_id, &positive);
- patch_get_lfo_on( p->patch_id, p->lfo_id, &on);
+ sync = patch_get_lfo_sync( p->patch_id, p->lfo_id);
+ positive = patch_get_lfo_positive( p->patch_id, p->lfo_id);
+ active = patch_get_lfo_active( p->patch_id, p->lfo_id);
- patch_get_lfo_fm1_src( p->patch_id, p->lfo_id, &fm1src);
- patch_get_lfo_fm1_amt( p->patch_id, p->lfo_id, &fm1amt);
- patch_get_lfo_fm2_src( p->patch_id, p->lfo_id, &fm2src);
- patch_get_lfo_fm2_amt( p->patch_id, p->lfo_id, &fm2amt);
+ fm1src = patch_get_lfo_fm1_src( p->patch_id, p->lfo_id);
+ fm1amt = patch_get_lfo_fm1_amt( p->patch_id, p->lfo_id);
+ fm2src = patch_get_lfo_fm2_src( p->patch_id, p->lfo_id);
+ fm2amt = patch_get_lfo_fm2_amt( p->patch_id, p->lfo_id);
- patch_get_lfo_am1_src( p->patch_id, p->lfo_id, &am1src);
- patch_get_lfo_am1_amt( p->patch_id, p->lfo_id, &am1amt);
- patch_get_lfo_am2_src( p->patch_id, p->lfo_id, &am2src);
- patch_get_lfo_am2_amt( p->patch_id, p->lfo_id, &am2amt);
+ am1src = patch_get_lfo_am1_src( p->patch_id, p->lfo_id);
+ am1amt = patch_get_lfo_am1_amt( p->patch_id, p->lfo_id);
+ am2src = patch_get_lfo_am2_src( p->patch_id, p->lfo_id);
+ am2amt = patch_get_lfo_am2_amt( p->patch_id, p->lfo_id);
debug("getting mod src combo iter with id\n");
@@ -599,7 +601,7 @@ static void update_lfo(LfoTabPrivate* p)
block(p);
- phat_fan_slider_set_value(PHAT_FAN_SLIDER(p->freq_fan), freq);
+ phin_fan_slider_set_value(PHIN_FAN_SLIDER(p->freq_fan), freq);
if (mod_src_is_global(p->lfo_id))
@@ -611,15 +613,15 @@ static void update_lfo(LfoTabPrivate* p)
}
else
{
- phat_fan_slider_set_value(PHAT_FAN_SLIDER(p->delay_fan), delay);
- phat_fan_slider_set_value(PHAT_FAN_SLIDER(p->attack_fan), attack);
+ phin_fan_slider_set_value(PHIN_FAN_SLIDER(p->delay_fan), delay);
+ phin_fan_slider_set_value(PHIN_FAN_SLIDER(p->attack_fan), attack);
gtk_widget_show(p->delay_fan);
gtk_widget_show(p->delay_label);
gtk_widget_show(p->attack_fan);
gtk_widget_show(p->attack_label);
}
- phat_slider_button_set_value(PHAT_SLIDER_BUTTON(p->beats_sb), beats);
+ phin_slider_button_set_value(PHIN_SLIDER_BUTTON(p->beats_sb), beats);
if (sync)
gtk_toggle_button_set_active(
@@ -650,12 +652,12 @@ static void update_lfo(LfoTabPrivate* p)
gtk_combo_box_set_active_iter(GTK_COMBO_BOX(p->am1_combo), &am1iter);
gtk_combo_box_set_active_iter(GTK_COMBO_BOX(p->am2_combo), &am2iter);
- phat_fan_slider_set_value(PHAT_FAN_SLIDER(p->fm1_amount), fm1amt);
- phat_fan_slider_set_value(PHAT_FAN_SLIDER(p->fm2_amount), fm2amt);
- phat_fan_slider_set_value(PHAT_FAN_SLIDER(p->am1_amount), am1amt);
- phat_fan_slider_set_value(PHAT_FAN_SLIDER(p->am2_amount), am2amt);
+ phin_fan_slider_set_value(PHIN_FAN_SLIDER(p->fm1_amount), fm1amt);
+ phin_fan_slider_set_value(PHIN_FAN_SLIDER(p->fm2_amount), fm2amt);
+ phin_fan_slider_set_value(PHIN_FAN_SLIDER(p->am1_amount), am1amt);
+ phin_fan_slider_set_value(PHIN_FAN_SLIDER(p->am2_amount), am2amt);
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p->lfo_check), on);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p->lfo_check), active);
unblock(p);
}
diff --git a/src/gui/lfotab.h b/gui/lfotab.h
similarity index 100%
rename from src/gui/lfotab.h
rename to gui/lfotab.h
diff --git a/gui/log_display.c b/gui/log_display.c
new file mode 100644
index 0000000..6b41061
--- /dev/null
+++ b/gui/log_display.c
@@ -0,0 +1,154 @@
+/* Petri-Foo is a fork of the Specimen audio sampler.
+
+ Original Specimen author Pete Bessman
+ Copyright 2005 Pete Bessman
+ Copyright 2011 James W. Morris
+
+ This file is part of Petri-Foo.
+
+ Petri-Foo is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+
+ Petri-Foo is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Petri-Foo. If not, see <http://www.gnu.org/licenses/>.
+
+ This file is a derivative of a Specimen original, modified 2011
+*/
+
+
+#include <gtk/gtk.h>
+
+#include "log_display.h"
+#include "gui.h"
+#include "msg_log.h"
+#include "petri-foo.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+
+static GtkWidget* window;
+static GtkWidget* textview;
+
+
+
+static void cb_close (GtkWidget* widget, gpointer data)
+{
+ (void)widget; (void)data;
+ printf("\n\nclose\n\n");
+ gtk_widget_hide (window);
+ cb_menu_view_log_display_showing(false);
+}
+
+
+static void msg_log_callback(const char* msg, int msg_base_type)
+{
+ GtkTextBuffer* buffer;
+ GtkTextIter iter;
+ GtkTextMark* mark;
+ const char* tag = 0;
+
+if (GTK_IS_TEXT_VIEW(textview))
+{
+printf("%p ***IS*** textview\n", textview);
+}
+else
+{
+printf("%p ***IS NOT *** textview\n", textview);
+}
+
+ switch(msg_base_type)
+ {
+ case MSG_TYPE_DEBUG: tag = "debug"; break;
+ case MSG_TYPE_WARNING: tag = "warning"; break;
+ case MSG_TYPE_ERROR: tag = "error"; break;
+ case MSG_TYPE_CRITICAL: tag = "critical"; break;
+ default: tag = "message"; break;
+ }
+
+ buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview));
+ gtk_text_buffer_get_end_iter(buffer, &iter);
+
+ gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, msg, -1,
+ tag, NULL);
+
+ mark = gtk_text_buffer_get_mark (buffer, "scroll");
+ gtk_text_buffer_move_mark (buffer, mark, &iter);
+ gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(textview), mark);
+}
+
+
+void log_display_show(void)
+{
+ gtk_widget_show(window);
+}
+
+
+void log_display_hide(void)
+{
+ gtk_widget_hide(window);
+}
+
+
+void log_display_init(GtkWidget* parent)
+{
+ GtkWidget* swindow;
+ GtkWidget* vbox;
+
+ GtkTextBuffer* buffer;
+ GtkTextIter iter;
+
+ debug("Initializing audio settings window\n");
+
+ window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title(GTK_WINDOW (window), "Petri-Foo Message Log");
+ gtk_window_set_default_size(GTK_WINDOW(window), 700, 160);
+ gtk_window_set_modal (GTK_WINDOW (window), FALSE);
+
+ g_signal_connect(window, "delete-event",
+ G_CALLBACK(cb_close), NULL);
+
+ gtk_container_set_border_width(GTK_CONTAINER(window), GUI_SPACING);
+
+ vbox = gtk_vbox_new(FALSE, GUI_SPACING);
+ gtk_container_add(GTK_CONTAINER(window), vbox);
+ gtk_widget_show(vbox);
+
+ swindow = gtk_scrolled_window_new(NULL, NULL);
+ gtk_box_pack_start(GTK_BOX(vbox), swindow, TRUE, TRUE, 0);
+ gtk_widget_show(swindow);
+
+ textview = gtk_text_view_new();
+ gtk_container_add(GTK_CONTAINER(swindow), textview);
+ gtk_widget_show(textview);
+
+ buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview));
+
+ /* didn't need this scroll mark until colour tags were added. */
+ gtk_text_buffer_get_end_iter(buffer, &iter);
+ gtk_text_buffer_create_mark(buffer, "scroll", &iter, TRUE);
+
+ gtk_text_buffer_create_tag(buffer, "debug",
+ "foreground", "blue", NULL);
+
+ gtk_text_buffer_create_tag(buffer, "message", NULL);
+
+ gtk_text_buffer_create_tag(buffer, "warning",
+ "foreground", "purple", NULL);
+
+ gtk_text_buffer_create_tag(buffer, "error",
+ "foreground", "red", NULL);
+
+ gtk_text_buffer_create_tag(buffer, "critical",
+ "foreground", "red", NULL);
+
+
+ /* Tell msg log to use our callback which updates the text view */
+ msg_log_set_message_cb(msg_log_callback);
+}
diff --git a/src/dish_file.h b/gui/log_display.h
similarity index 74%
copy from src/dish_file.h
copy to gui/log_display.h
index 5d875fd..1bb519d 100644
--- a/src/dish_file.h
+++ b/gui/log_display.h
@@ -18,18 +18,16 @@
*/
-#ifndef DISH_FILE_H
-#define DISH_FILE_H
+#ifndef LOG_DISPLAY_H
+#define LOG_DISPLAY_H
-/* recommended file extension for petri-foo data files:
- (includes dot)
- */
+#include <gtk/gtk.h>
-const char* dish_file_extension(void);
-int dish_file_read(const char* name);
-int dish_file_write(const char* name);
+void log_display_init(GtkWidget* parent);
+void log_display_show(void);
+void log_display_hide(void);
#endif
diff --git a/src/gui/mastersection.c b/gui/mastersection.c
similarity index 91%
rename from src/gui/mastersection.c
rename to gui/mastersection.c
index d406603..9ebef13 100644
--- a/src/gui/mastersection.c
+++ b/gui/mastersection.c
@@ -23,7 +23,9 @@
#include <gtk/gtk.h>
-#include <phat/phat.h>
+
+#include "phin.h"
+
#include "mastersection.h"
#include "petri-foo.h"
#include "gui.h"
@@ -41,11 +43,11 @@ static void master_section_class_init(MasterSectionClass* klass)
}
-static void amplitude_changed_cb(PhatFanSlider* slider, gpointer data)
+static void amplitude_changed_cb(PhinFanSlider* slider, gpointer data)
{
(void)data;
float val;
- val = phat_fan_slider_get_value(slider);
+ val = phin_fan_slider_get_value(slider);
mixer_set_amplitude(val);
}
@@ -62,7 +64,7 @@ static void master_section_init(MasterSection* self)
/* amplitude */
label = gtk_label_new(NULL);
self->amplitude_fan =
- phat_hfan_slider_new_with_range(DEFAULT_AMPLITUDE, 0.0, 1.0, 0.1);
+ phin_hfan_slider_new_with_range(DEFAULT_AMPLITUDE, 0.0, 1.0, 0.1);
hbox = gtk_hbox_new(FALSE, GUI_TEXTSPACE);
gtk_label_set_markup(GTK_LABEL(label), "<b>Master</b>");
@@ -100,7 +102,7 @@ void master_section_update(MasterSection* self)
g_signal_handlers_block_by_func(self->amplitude_fan,
(gpointer)amplitude_changed_cb, NULL);
- phat_fan_slider_set_value(PHAT_FAN_SLIDER(self->amplitude_fan), amplitude);
+ phin_fan_slider_set_value(PHIN_FAN_SLIDER(self->amplitude_fan), amplitude);
g_signal_handlers_unblock_by_func(self->amplitude_fan, amplitude_changed_cb, NULL);
}
diff --git a/src/gui/mastersection.h b/gui/mastersection.h
similarity index 100%
rename from src/gui/mastersection.h
rename to gui/mastersection.h
diff --git a/src/gui/midisection.c b/gui/midisection.c
similarity index 89%
rename from src/gui/midisection.c
rename to gui/midisection.c
index 462ea70..ee435a6 100644
--- a/src/gui/midisection.c
+++ b/gui/midisection.c
@@ -23,8 +23,10 @@
#include <gtk/gtk.h>
-#include <phat/phat.h>
-#include <libgnomecanvas/libgnomecanvas.h>
+/*#include <libgnomecanvas/libgnomecanvas.h>*/
+
+#include "phin.h"
+
#include "midisection.h"
#include "petri-foo.h"
#include "gui.h"
@@ -120,8 +122,8 @@ static gboolean range_cb(GnomeCanvasItem* item, GdkEvent* event,
list = gui_get_patch_list();
- clicked = event->button.x / PHAT_KEYBOARD_KEY_WIDTH;
- note = patch_get_note(p->patch);
+ clicked = event->button.x / PHIN_KEYBOARD_KEY_WIDTH;
+ note = patch_get_root_note(p->patch);
lower = patch_get_lower_note(p->patch);
upper = patch_get_upper_note(p->patch);
@@ -156,20 +158,20 @@ static gboolean range_cb(GnomeCanvasItem* item, GdkEvent* event,
/* reposition note */
gnome_canvas_item_set(p->note, "x1",
- (gdouble)(note * PHAT_KEYBOARD_KEY_WIDTH - 1), NULL);
+ (gdouble)(note * PHIN_KEYBOARD_KEY_WIDTH - 1), NULL);
gnome_canvas_item_set(p->note, "x2",
- (gdouble) (note * PHAT_KEYBOARD_KEY_WIDTH
- + PHAT_KEYBOARD_KEY_WIDTH - 1), NULL);
+ (gdouble) (note * PHIN_KEYBOARD_KEY_WIDTH
+ + PHIN_KEYBOARD_KEY_WIDTH - 1), NULL);
/* reposition range */
gnome_canvas_item_set(p->range, "x1",
- (gdouble)(lower * PHAT_KEYBOARD_KEY_WIDTH - 1), NULL);
+ (gdouble)(lower * PHIN_KEYBOARD_KEY_WIDTH - 1), NULL);
gnome_canvas_item_set(p->range, "x2",
- (gdouble)(upper * PHAT_KEYBOARD_KEY_WIDTH
- + PHAT_KEYBOARD_KEY_WIDTH - 1), NULL);
+ (gdouble)(upper * PHIN_KEYBOARD_KEY_WIDTH
+ + PHIN_KEYBOARD_KEY_WIDTH - 1), NULL);
/* apply changes */
- patch_set_note(p->patch, note);
+ patch_set_root_note(p->patch, note);
patch_set_lower_note(p->patch, lower);
patch_set_upper_note(p->patch, upper);
@@ -234,7 +236,7 @@ static void midi_section_init(MidiSection* self)
p->ignore = FALSE;
x1 = 0;
y1 = 0;
- x2 = (PHAT_KEYBOARD_KEY_WIDTH * MIDI_NOTES);
+ x2 = (PHIN_KEYBOARD_KEY_WIDTH * MIDI_NOTES);
y2 = HEIGHT;
/* adjustment */
@@ -270,7 +272,7 @@ static void midi_section_init(MidiSection* self)
gnome_canvas_rect_get_type(),
"x1", (gdouble)x1,
"y1", (gdouble)y1,
- "x2", (gdouble)PHAT_KEYBOARD_KEY_WIDTH,
+ "x2", (gdouble)PHIN_KEYBOARD_KEY_WIDTH,
"y2", (gdouble)y2,
"fill-color-rgba", RANGE_COLOR,
"outline-color", "black",
@@ -282,7 +284,7 @@ static void midi_section_init(MidiSection* self)
gnome_canvas_rect_get_type(),
"x1", (gdouble)x1,
"y1", (gdouble)y1,
- "x2", (gdouble)PHAT_KEYBOARD_KEY_WIDTH,
+ "x2", (gdouble)PHIN_KEYBOARD_KEY_WIDTH,
"y2", (gdouble)y2,
"fill-color-rgba", NOTE_COLOR,
"outline-color", "black",
@@ -313,7 +315,7 @@ static void midi_section_init(MidiSection* self)
/* keyboard */
- p->keyboard = phat_hkeyboard_new(p->adj, MIDI_NOTES, TRUE);
+ p->keyboard = phin_hkeyboard_new(p->adj, MIDI_NOTES, TRUE);
gtk_box_pack_start(box, p->keyboard, FALSE, FALSE, 0);
gtk_widget_show(p->keyboard);
@@ -365,24 +367,24 @@ void midi_section_set_patch(MidiSection* self, int patch)
set_sensitive(p, TRUE);
- note = patch_get_note(patch);
+ note = patch_get_root_note(patch);
lower = patch_get_lower_note(patch);
upper = patch_get_upper_note(patch);
block(p);
gnome_canvas_item_set(p->note, "x1",
- (gdouble)(note * PHAT_KEYBOARD_KEY_WIDTH - 1), NULL);
+ (gdouble)(note * PHIN_KEYBOARD_KEY_WIDTH - 1), NULL);
gnome_canvas_item_set(p->note, "x2",
- (gdouble)(note * PHAT_KEYBOARD_KEY_WIDTH
- + PHAT_KEYBOARD_KEY_WIDTH - 1), NULL);
+ (gdouble)(note * PHIN_KEYBOARD_KEY_WIDTH
+ + PHIN_KEYBOARD_KEY_WIDTH - 1), NULL);
gnome_canvas_item_show(p->note);
gnome_canvas_item_set(p->range, "x1",
- (gdouble) (lower * PHAT_KEYBOARD_KEY_WIDTH - 1), NULL);
+ (gdouble) (lower * PHIN_KEYBOARD_KEY_WIDTH - 1), NULL);
gnome_canvas_item_set(p->range, "x2",
- (gdouble) (upper * PHAT_KEYBOARD_KEY_WIDTH
- + PHAT_KEYBOARD_KEY_WIDTH - 1), NULL);
+ (gdouble) (upper * PHIN_KEYBOARD_KEY_WIDTH
+ + PHIN_KEYBOARD_KEY_WIDTH - 1), NULL);
if (lower != upper)
gnome_canvas_item_show(p->range);
else
diff --git a/src/gui/midisection.h b/gui/midisection.h
similarity index 100%
rename from src/gui/midisection.h
rename to gui/midisection.h
diff --git a/src/gui/mod_section.c b/gui/mod_section.c
similarity index 78%
rename from src/gui/mod_section.c
rename to gui/mod_section.c
index fe04eab..f82ad69 100644
--- a/src/gui/mod_section.c
+++ b/gui/mod_section.c
@@ -17,9 +17,10 @@
along with Petri-Foo. If not, see <http://www.gnu.org/licenses/>.
*/
-
+#include <assert.h>
#include <gtk/gtk.h>
-#include <phat/phat.h>
+
+#include "phin.h"
#include "mod_section.h"
#include "gui.h"
@@ -64,7 +65,7 @@ static void mod_section_class_init(ModSectionClass* klass)
static void param1_cb(GtkWidget* w, ModSectionPrivate* p)
{
- float val = phat_fan_slider_get_value(PHAT_FAN_SLIDER(w));
+ float val = phin_fan_slider_get_value(PHIN_FAN_SLIDER(w));
patch_param_set_value(p->patch_id, p->param, val);
}
@@ -72,27 +73,28 @@ static void param2_cb(GtkWidget* w, ModSectionPrivate* p)
{
if (p->param == PATCH_PARAM_PITCH)
{
- float val = phat_slider_button_get_value(PHAT_SLIDER_BUTTON(w));
+ float val = phin_slider_button_get_value(PHIN_SLIDER_BUTTON(w));
patch_set_pitch_steps(p->patch_id, val);
}
}
static void vel_sens_cb(GtkWidget* w, ModSectionPrivate* p)
{
- float val = phat_fan_slider_get_value(PHAT_FAN_SLIDER(w));
- patch_set_vel_amount(p->patch_id, p->param, val);
+ float val = phin_fan_slider_get_value(PHIN_FAN_SLIDER(w));
+ patch_param_set_vel_amount(p->patch_id, p->param, val);
}
static void key_track_cb(GtkWidget* w, ModSectionPrivate* p)
{
- float val = phat_fan_slider_get_value(PHAT_FAN_SLIDER(w));
- patch_set_key_amount(p->patch_id, p->param, val);
+ float val = phin_fan_slider_get_value(PHIN_FAN_SLIDER(w));
+ patch_param_set_key_amount(p->patch_id, p->param, val);
}
static void mod_src_cb(GtkComboBox* combo, ModSectionPrivate* p)
{
int i;
+ gboolean active;
for (i = 0; i < MAX_MOD_SLOTS; ++i)
if (combo == GTK_COMBO_BOX(p->mod_combo[i]))
@@ -104,7 +106,8 @@ static void mod_src_cb(GtkComboBox* combo, ModSectionPrivate* p)
return;
}
- mod_src_callback_helper(p->patch_id, i, combo, p->param );
+ active = mod_src_callback_helper(p->patch_id, i, combo, p->param);
+ gtk_widget_set_sensitive(p->mod_amount[i], active);
}
static void mod_amount_cb(GtkWidget* w, ModSectionPrivate* p)
@@ -115,16 +118,12 @@ static void mod_amount_cb(GtkWidget* w, ModSectionPrivate* p)
if (p->param == PATCH_PARAM_AMPLITUDE)
--last_slot;
- else
- {
- if (p->param == PATCH_PARAM_PITCH)
- val = phat_slider_button_get_value(PHAT_SLIDER_BUTTON(w))
- / PATCH_MAX_PITCH_STEPS;
- else
- val = phat_fan_slider_get_value(PHAT_FAN_SLIDER(w));
- }
- debug("amount val:%f\n",val);
+ if (p->param == PATCH_PARAM_PITCH)
+ val = phin_slider_button_get_value(PHIN_SLIDER_BUTTON(w))
+ / PATCH_MAX_PITCH_STEPS;
+ else
+ val = phin_fan_slider_get_value(PHIN_FAN_SLIDER(w));
for (i = 0; i < last_slot; ++i)
if (w == p->mod_amount[i])
@@ -136,7 +135,7 @@ static void mod_amount_cb(GtkWidget* w, ModSectionPrivate* p)
return;
}
- patch_set_mod_amt(p->patch_id, p->param, i, val);
+ patch_param_set_mod_amt(p->patch_id, p->param, i, val);
}
@@ -246,25 +245,6 @@ unblock_mod_srcs:
}
-
-/* reflect certain midi cc changes of parameters in the gui
- no longer required
-
-static gboolean refresh(gpointer data)
-{
- ModSection* self = MOD_SECTION(data);
- ModSectionPrivate* p = MOD_SECTION_GET_PRIVATE(self);
-
- if (p->patch_id < 0)
- return TRUE;
-
- mod_section_set_patch(self, p->patch_id);
-
- return TRUE;
-}
- */
-
-
static void mod_section_init(ModSection* self)
{
ModSectionPrivate* p = MOD_SECTION_GET_PRIVATE(self);
@@ -291,10 +271,13 @@ void mod_section_set_param(ModSection* self, PatchParamType param)
float range_low = 0.0;
float range_hi = 1.0;
+ gboolean logscale = FALSE;
const char* lstr;
const char** param_names = names_params_get();
+ char buf[80];
+
int i;
int y = 0;
int env_slot = -1;
@@ -304,6 +287,8 @@ void mod_section_set_param(ModSection* self, PatchParamType param)
int b1 = 1, b2 = 2;
int c1 = 2, c2 = 3;
+debug("creating mod section...\n");
+
box = GTK_BOX(self);
p->param = param;
@@ -318,12 +303,8 @@ void mod_section_set_param(ModSection* self, PatchParamType param)
gui_attach(t, gui_title_new(param_names[param]), a1, c2, y, y + 1);
++y;
- /* indentation */
- gui_attach(t, gui_hpad_new(GUI_INDENT), a1, a2, y, y + 1);
- ++y;
-
/* title padding */
- gui_attach(t, gui_vpad_new(GUI_TITLESPACE), b1, b2, y, y + 1);
+ gui_attach(t, gui_vpad_new(GUI_TITLESPACE), a1, c2, y, y + 1);
++y;
/* label column spacing (of some description!?) */
@@ -337,24 +318,38 @@ void mod_section_set_param(ModSection* self, PatchParamType param)
{
case PATCH_PARAM_AMPLITUDE:
lstr = "Level:";
- env_slot = --last_mod_slot;
+ env_slot = EG_MOD_SLOT;
+ --last_mod_slot;
break;
- case PATCH_PARAM_PANNING: lstr = "Position:"; break;
- case PATCH_PARAM_PITCH: lstr = "Tuning:"; break;
- break;
- default:
- lstr = param_names[param];
+ case PATCH_PARAM_PANNING:
+ lstr = "Position:";
+ range_low = -1.0;
+ break;
+
+ case PATCH_PARAM_PITCH:
+ lstr = "Tuning:";
+ range_low = -1.0;
break;
+ case PATCH_PARAM_RESONANCE:
+ lstr = "Q:";
+ /* broken impl in Phat/Phin: logscale = TRUE; */
+ break;
+ case PATCH_PARAM_CUTOFF:
+ snprintf(buf, 80, "%s:", param_names[param]);
+ lstr = buf;
+ break;
+ default:
+ assert(0);
+ return;
}
gui_label_attach(lstr, t, a1, a2, y, y + 1);
- if (param == PATCH_PARAM_PANNING || param == PATCH_PARAM_PITCH)
- range_low = -1.0;
-
- p->param1 = phat_hfan_slider_new_with_range(0.0, range_low,
+ p->param1 = phin_hfan_slider_new_with_range(0.0, range_low,
range_hi, 0.1);
+ phin_fan_slider_set_log(PHIN_FAN_SLIDER(p->param1), logscale);
+
gui_attach(t, p->param1, b1, b2, y, y + 1);
if (param == PATCH_PARAM_PITCH)
@@ -366,13 +361,13 @@ void mod_section_set_param(ModSection* self, PatchParamType param)
/* velocity sensitivity */
gui_label_attach("Vel.Sens:", t, a1, a2, y, y + 1);
- p->vel_sens = phat_hfan_slider_new_with_range(0.0, 0.0, 1.0, 0.1);
+ p->vel_sens = phin_hfan_slider_new_with_range(0.0, -1.0, 1.0, 0.1);
gui_attach(t, p->vel_sens, b1, b2, y, y + 1);
++y;
/* key tracking */
gui_label_attach("Key Track:", t, a1, a2, y, y + 1);
- p->key_track = phat_hfan_slider_new_with_range(0.0, -1.0, 1.0, 0.1);
+ p->key_track = phin_hfan_slider_new_with_range(0.0, -1.0, 1.0, 0.1);
gui_attach(t, p->key_track, b1, b2, y, y + 1);
++y;
@@ -401,23 +396,13 @@ create_mod_srcs:
if (param == PATCH_PARAM_PITCH)
p->mod_amount[i] = mod_src_new_pitch_adjustment();
else
- p->mod_amount[i] = phat_hfan_slider_new_with_range(0.0, -1.0,
+ p->mod_amount[i] = phin_hfan_slider_new_with_range(0.0, -1.0,
1.0, 0.1);
gui_attach(t, p->mod_amount[i], c1, c2, y, y + 1);
++y;
}
- /* done */
connect(p);
-
- /* add a timeout to allow the gui to reflect changes in
- parameters which are changeable via midi cc mesages
-
- nb: no longer required...
-
- p->refresh = g_timeout_add(GUI_REFRESH_TIMEOUT, refresh,
- (gpointer)self);
- */
}
@@ -453,10 +438,10 @@ GtkWidget* mod_section_new(void)
void mod_section_set_patch(ModSection* self, int patch_id)
{
ModSectionPrivate* p = MOD_SECTION_GET_PRIVATE(self);
- float param1 = PATCH_PARAM_INVALID;
- float param2 = PATCH_PARAM_INVALID;
- float vsens;
- float ktrack;
+ float param1;
+ float param2 = 0;
+ float vel_amt;
+ float key_trk;
int i;
int last_slot = MAX_MOD_SLOTS;
@@ -473,24 +458,24 @@ void mod_section_set_patch(ModSection* self, int patch_id)
if (p->mod_only)
goto get_mod_srcs;
- patch_param_get_value(p->patch_id, p->param, ¶m1);
+ param1 = patch_param_get_value(p->patch_id, p->param);
if (p->param == PATCH_PARAM_PITCH)
param2 = patch_get_pitch_steps(p->patch_id);
else if (p->param == PATCH_PARAM_AMPLITUDE)
--last_slot;
- patch_get_vel_amount(patch_id, p->param, &vsens);
- patch_get_key_amount(patch_id, p->param, &ktrack);
+ vel_amt = patch_param_get_vel_amount(patch_id, p->param);
+ key_trk = patch_param_get_key_amount(patch_id, p->param);
get_mod_srcs:
for (i = 0; i < MAX_MOD_SLOTS; ++i)
{
- patch_get_mod_src(patch_id, p->param, i, &modsrc[i]);
+ modsrc[i] = patch_param_get_mod_src(patch_id, p->param, i);
if (i < last_slot)
- patch_get_mod_amt(patch_id, p->param, i, &modamt[i]);
+ modamt[i] = patch_param_get_mod_amt(patch_id, p->param, i);
if (!mod_src_combo_get_iter_with_id(GTK_COMBO_BOX(p->mod_combo[i]),
modsrc[i], &moditer[i]))
@@ -504,13 +489,13 @@ get_mod_srcs:
if (p->mod_only)
goto set_mod_srcs;
- phat_fan_slider_set_value(PHAT_FAN_SLIDER(p->param1), param1);
+ phin_fan_slider_set_value(PHIN_FAN_SLIDER(p->param1), param1);
if (p->param == PATCH_PARAM_PITCH)
- phat_slider_button_set_value(PHAT_SLIDER_BUTTON(p->param2), param2);
+ phin_slider_button_set_value(PHIN_SLIDER_BUTTON(p->param2), param2);
- phat_fan_slider_set_value(PHAT_FAN_SLIDER(p->key_track), ktrack);
- phat_fan_slider_set_value(PHAT_FAN_SLIDER(p->vel_sens), vsens);
+ phin_fan_slider_set_value(PHIN_FAN_SLIDER(p->key_track), key_trk);
+ phin_fan_slider_set_value(PHIN_FAN_SLIDER(p->vel_sens), vel_amt);
set_mod_srcs:
@@ -520,14 +505,18 @@ set_mod_srcs:
&moditer[i]);
if (p->param == PATCH_PARAM_PITCH)
{
- phat_slider_button_set_value(
- PHAT_SLIDER_BUTTON(p->mod_amount[i]),
+ phin_slider_button_set_value(
+ PHIN_SLIDER_BUTTON(p->mod_amount[i]),
modamt[i] * PATCH_MAX_PITCH_STEPS);
+ gtk_widget_set_sensitive(p->mod_amount[i],
+ modsrc[i] != MOD_SRC_NONE);
}
else if (i < last_slot)
{
- phat_fan_slider_set_value(PHAT_FAN_SLIDER(p->mod_amount[i]),
+ phin_fan_slider_set_value(PHIN_FAN_SLIDER(p->mod_amount[i]),
modamt[i]);
+ gtk_widget_set_sensitive(p->mod_amount[i],
+ modsrc[i] != MOD_SRC_NONE);
}
}
diff --git a/src/gui/mod_section.h b/gui/mod_section.h
similarity index 100%
rename from src/gui/mod_section.h
rename to gui/mod_section.h
diff --git a/src/gui/mod_src_gui.c b/gui/mod_src_gui.c
similarity index 90%
rename from src/gui/mod_src_gui.c
rename to gui/mod_src_gui.c
index e86bc29..5a6f187 100644
--- a/src/gui/mod_src_gui.c
+++ b/gui/mod_src_gui.c
@@ -23,7 +23,8 @@
#include "mod_src_gui.h"
-#include <phat/phat.h>
+
+#include "phin.h"
#include "gui.h"
#include "petri-foo.h"
@@ -106,19 +107,36 @@ GtkWidget* mod_src_new_pitch_adjustment(void)
{
GtkWidget* amt;
- amt = phat_slider_button_new_with_range(12, -PATCH_MAX_PITCH_STEPS,
+ amt = phin_slider_button_new_with_range(12, -PATCH_MAX_PITCH_STEPS,
PATCH_MAX_PITCH_STEPS,
0.1, 1.0);
-
- phat_slider_button_set_format(PHAT_SLIDER_BUTTON(amt),
+ phin_slider_button_set_format(PHIN_SLIDER_BUTTON(amt),
-1, NULL, NULL);
gtk_widget_set_tooltip_text(amt, "Semitones");
- phat_slider_button_set_threshold(PHAT_SLIDER_BUTTON(amt),
+ phin_slider_button_set_threshold(PHIN_SLIDER_BUTTON(amt),
GUI_THRESHOLD);
return amt;
}
+int mod_src_combo_get_mod_src_id(GtkComboBox* combo)
+{
+ GtkTreeIter iter;
+
+ if (gtk_combo_box_get_active_iter(combo, &iter))
+ {
+ int id;
+
+ gtk_tree_model_get( gtk_combo_box_get_model(combo),
+ &iter, COLUMN_INT, &id, -1);
+
+ return id;
+ }
+
+ return MOD_SRC_NONE;
+}
+
+
gboolean mod_src_callback_helper(int patch_id, int slot,
GtkComboBox* combo, PatchParamType par)
{
@@ -137,10 +155,12 @@ gboolean mod_src_callback_helper(int patch_id, int slot,
patch_id, slot, mod_src_name(id), id);
/* FIXME: probably should check return value */
- patch_set_mod_src(patch_id, par, slot, id);
+ patch_param_set_mod_src(patch_id, par, slot, id);
+
+ return id != MOD_SRC_NONE;
}
- return TRUE;
+ return FALSE;
}
@@ -170,9 +190,11 @@ gboolean mod_src_callback_helper_lfo(int patch_id,
input_no);
return FALSE;
}
+
+ return id != MOD_SRC_NONE;
}
- return TRUE;
+ return FALSE;
}
diff --git a/src/gui/mod_src_gui.h b/gui/mod_src_gui.h
similarity index 94%
rename from src/gui/mod_src_gui.h
rename to gui/mod_src_gui.h
index c92f274..694a5bb 100644
--- a/src/gui/mod_src_gui.h
+++ b/gui/mod_src_gui.h
@@ -35,11 +35,14 @@ enum {
GtkWidget* mod_src_new_combo_with_cell();
/* mod_src_new_pitch_adjustment
- creates a phat slider button with semitones label within.
+ creates a phin slider button with semitones label within.
*/
GtkWidget* mod_src_new_pitch_adjustment(void);
+int mod_src_combo_get_mod_src_id(GtkComboBox* combo);
+
+
/* mod_src_callback_helper
for use in the mod src combo box callback, it reads the
diff --git a/src/gui/paramtab.c b/gui/paramtab.c
similarity index 97%
rename from src/gui/paramtab.c
rename to gui/paramtab.c
index e734b3a..c845ddc 100644
--- a/src/gui/paramtab.c
+++ b/gui/paramtab.c
@@ -21,9 +21,10 @@
This file is a derivative of a Specimen original, modified 2011
*/
-
+#include <assert.h>
#include <gtk/gtk.h>
-#include <phat/phat.h>
+
+#include "phin.h"
#include "paramtab.h"
#include "gui.h"
@@ -104,7 +105,7 @@ void param_tab_set_param(ParamTab* self, PatchParamType param)
break;
default:
- debug ("unrecognised parameter for param tab\n");
+ assert(0);
return;
}
@@ -115,6 +116,7 @@ void param_tab_set_param(ParamTab* self, PatchParamType param)
gtk_box_pack_start(box, p->modsect1, FALSE, FALSE, 0);
gtk_widget_show(p->modsect1);
}
+ else {debug("param1 invalid\n");}
if (ms2 != PATCH_PARAM_INVALID)
{
diff --git a/src/gui/paramtab.h b/gui/paramtab.h
similarity index 100%
rename from src/gui/paramtab.h
rename to gui/paramtab.h
diff --git a/src/gui/patchlist.c b/gui/patchlist.c
similarity index 97%
rename from src/gui/patchlist.c
rename to gui/patchlist.c
index da59210..3f51759 100644
--- a/src/gui/patchlist.c
+++ b/gui/patchlist.c
@@ -140,7 +140,7 @@ void popup_menu(GdkEventButton *event, gboolean full_menu, gpointer data)
static gboolean
pressed_cb(GtkWidget *treeview, GdkEventButton *event, gpointer data)
{
- (void)data;
+ PatchListPrivate* p = (PatchListPrivate*)data;
if (event->type == GDK_BUTTON_PRESS && event->button == 3)
{
@@ -160,7 +160,10 @@ pressed_cb(GtkWidget *treeview, GdkEventButton *event, gpointer data)
&path,
NULL, NULL, NULL))
{
+ g_signal_handlers_block_by_func(p->select, select_cb, p);
gtk_tree_selection_unselect_all(selection);
+ g_signal_handlers_unblock_by_func(p->select, select_cb, p);
+
gtk_tree_selection_select_path(selection, path);
full_menu = TRUE;
}
diff --git a/src/gui/patchlist.h b/gui/patchlist.h
similarity index 100%
rename from src/gui/patchlist.h
rename to gui/patchlist.h
diff --git a/src/gui/patchsection.c b/gui/patchsection.c
similarity index 99%
rename from src/gui/patchsection.c
rename to gui/patchsection.c
index c820b85..efb2809 100644
--- a/src/gui/patchsection.c
+++ b/gui/patchsection.c
@@ -24,8 +24,10 @@
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
-#include <phat/phat.h>
#include <stdlib.h>
+
+#include "phin.h"
+
#include "patchsection.h"
#include "petri-foo.h"
#include "gui.h"
diff --git a/src/gui/patchsection.h b/gui/patchsection.h
similarity index 100%
rename from src/gui/patchsection.h
rename to gui/patchsection.h
diff --git a/src/petri-foo.c b/gui/petri-foo.c
similarity index 54%
rename from src/petri-foo.c
rename to gui/petri-foo.c
index 3bef391..d233bcd 100644
--- a/src/petri-foo.c
+++ b/gui/petri-foo.c
@@ -29,7 +29,7 @@
#include "instance.h"
#include "petri-foo.h"
-#include "gui/gui.h"
+#include "gui.h"
#include "midi.h"
#include "driver.h"
#include "lfo.h"
@@ -40,64 +40,73 @@
#include "names.h"
#include "dish_file.h"
#include "jackdriver.h"
+#include "global_settings.h"
+#include "msg_log.h"
+
void show_usage (void)
{
- printf ("Usage: petri-foo [options] [bankname]\n\n");
- printf ("Options:\n");
- printf(" -n, --name <name> Specify instance name, defaults to \"petri-foo\"\n" );
- printf(" -h, --help Display this help message\n\n");
- printf ("For more information, please see:\n");
- printf ("http://petri-foo.sourceforge.net/\n");
+ printf ("Usage: petri-foo [options] [bank]\n");
+ printf("(Bank files use .petri-foo extension)\n\n");
+
+ printf ("Options:\n");
+ printf(" -n, --name <name> Specify instance name, "
+ "defaults to \"petri-foo\"\n" );
+ printf(" -u, --unconnected Don't auto-connect to JACK\n");
+ printf(" -h, --help Display this help message\n\n");
+ printf ("For more information, please see:\n");
+ printf ("http://petri-foo.sourceforge.net/\n");
}
int main(int argc, char *argv[])
{
-#ifdef HAVE_LASH
- /*
- * Handle lash arguments here to prevent getopt_long() from
- * going bonkers over arguments it hasn't been told about.
- */
- lash_args_t *lash_args = lash_extract_args(&argc, &argv);
-#endif
-
- int opt;
- int longopt_index;
- static struct option long_options[] =
- {
- { "name", 1, 0, 'n'},
- { "uuid", 1, 0, 'U'},
- { "help", 0, 0, 'h'},
- { 0, 0, 0, 0}
- };
-
- /* command line argument processing */
- while((opt = getopt_long(argc, argv, "n:U:h", long_options,
- &longopt_index)) > 0)
- {
- switch (opt)
- {
- case 'n':
- set_instance_name(optarg);
- break;
- case 'U':
- jackdriver_set_uuid(strdup(optarg) );
- break;
- case 'h':
- show_usage();
- return 0;
- break;
- default:
- show_usage();
- return 1;
- break;
- }
- }
+ int opt;
+ int longopt_index;
+
+ static struct option long_options[] =
+ {
+ { "name", 1, 0, 'n'},
+ { "unconnected", 0, 0, 'u'},
+ { "uuid", 1, 0, 'U'},
+ { "help", 0, 0, 'h'},
+ { 0, 0, 0, 0}
+ };
+
+
+ while((opt = getopt_long(argc, argv, "n:u:U:h",
+ long_options, &longopt_index)) > 0)
+ {
+ switch (opt)
+ {
+ case 'n':
+ set_instance_name(optarg);
+ break;
+
+ case 'u':
+ jackdriver_set_unconnected();
+ break;
+
+ case 'U':
+ jackdriver_set_uuid(strdup(optarg) );
+ break;
+
+ case 'h':
+ show_usage();
+ return 0;
+
+ default:
+ show_usage();
+ return 1;
+ }
+ }
mod_src_create();
gtk_init(&argc, &argv);
+
+ settings_init();
gui_init();
+
driver_init();
lfo_tables_init();
mixer_init();
@@ -122,10 +131,11 @@ int main(int argc, char *argv[])
driver_stop();
patch_shutdown();
mixer_shutdown();
+ settings_write();
+ settings_free();
free_instance_name();
mod_src_destroy();
-
- debug("Goodbye.\n");
+ msg_log(MSG_MESSAGE, "Goodbye!\n");
return 0;
}
diff --git a/gui/sample-editor.c b/gui/sample-editor.c
new file mode 100644
index 0000000..457cf0b
--- /dev/null
+++ b/gui/sample-editor.c
@@ -0,0 +1,721 @@
+/* Petri-Foo is a fork of the Specimen audio sampler.
+
+ Original Specimen author Pete Bessman
+ Copyright 2005 Pete Bessman
+ Copyright 2011 James W. Morris
+
+ This file is part of Petri-Foo.
+
+ Petri-Foo is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+
+ Petri-Foo is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Petri-Foo. If not, see <http://www.gnu.org/licenses/>.
+
+ This file is a derivative of a Specimen original, modified 2011
+*/
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <gtk/gtk.h>
+#include "petri-foo.h"
+#include "patch_set_and_get.h"
+#include "waveform.h"
+#include "gui.h"
+#include "mixer.h"
+#include "sample-editor.h"
+
+#include "basic_combos.h"
+
+enum
+{
+ ZOOM_MIN = 1,
+ ZOOM_MAX = 100
+};
+
+typedef struct _SampleEditorPrivate SampleEditorPrivate;
+
+
+struct _SampleEditorPrivate
+{
+ GtkWidget* window;
+ GtkWidget* toolbar1;
+ GtkWidget* toolbar2;
+ GtkWidget* waveform;
+ GtkWidget* hscroll;
+ GtkObject* hscrolladj;
+ GtkWidget* fade_spin;
+ GtkWidget* xfade_spin;
+ GtkWidget* mark_combo;
+ GtkWidget* mark_spin;
+ GtkWidget* mark_val;
+ GtkWidget* reset;
+
+ gboolean ignore_callback;
+ gboolean ignore_mark_change;
+
+ float zoom_pc;
+ float range;
+
+ int old_play_start;
+ int old_play_stop;
+
+ int old_loop_start;
+ int old_loop_stop;
+ int old_fade;
+ int old_xfade;
+
+ int patch;
+};
+
+
+GtkWidget* wf_thumb = 0;
+
+
+SampleEditorPrivate* sample_editor_private_new()
+{
+ SampleEditorPrivate* p = malloc(sizeof(*p));
+
+ if (!p)
+ return 0;
+
+ p->window = 0;
+ p->toolbar1 = 0;
+ p->toolbar2 = 0;
+ p->waveform = 0;
+ p->hscroll = 0;
+ p->hscrolladj = 0;
+ p->fade_spin = 0;
+ p->xfade_spin = 0;
+ p->mark_combo = 0;
+ p->mark_spin = 0;
+ p->mark_val = 0;
+ p->reset = 0;
+
+ p->ignore_callback = FALSE;
+ p->ignore_mark_change = FALSE;
+
+ p->zoom_pc = 1.0;
+ p->range = 1.0;
+
+ p->old_play_start = 0;
+ p->old_play_stop = 0;
+
+ p->old_loop_start = 0;
+ p->old_loop_stop = 0;
+ p->old_fade = 0;
+ p->old_xfade = 0;
+
+ p->patch = -1;
+
+ return p;
+}
+
+
+static SampleEditorPrivate* se = 0;
+
+
+static void zoom_adj(void);
+static void update_mark_spin(void);
+static void update_fade_spins(void);
+static void cb_mark_combo_changed(GtkWidget* combo, gpointer data);
+
+static void cb_close(GtkWidget* widget, gpointer data)
+{
+ (void)widget;(void)data;
+ mixer_note_off_with_id(se->patch, patch_get_root_note(se->patch));
+ gtk_widget_hide(se->window);
+}
+
+static void cb_play(GtkWidget* widget, gpointer data)
+{
+ (void)widget;(void)data;
+ mixer_note_off_with_id(se->patch, patch_get_root_note(se->patch));
+ mixer_note_on_with_id(se->patch, patch_get_root_note(se->patch), 1.0);
+}
+
+static void cb_stop(GtkWidget* widget, gpointer data)
+{
+ (void)widget;(void)data;
+ mixer_note_off_with_id(se->patch, patch_get_root_note(se->patch));
+}
+
+static void cb_reset(GtkWidget* widget, gpointer data)
+{
+ (void)widget;(void)data;
+ patch_set_mark_frame(se->patch, WF_MARK_PLAY_START, se->old_play_start);
+ patch_set_mark_frame(se->patch, WF_MARK_PLAY_STOP, se->old_play_stop);
+ patch_set_mark_frame(se->patch, WF_MARK_LOOP_START, se->old_loop_start);
+ patch_set_mark_frame(se->patch, WF_MARK_LOOP_STOP, se->old_loop_stop);
+ cb_mark_combo_changed(se->mark_combo, 0);
+ gtk_widget_queue_draw(se->waveform);
+ gtk_widget_queue_draw(wf_thumb);
+}
+
+static void cb_clear(GtkWidget* widget, gpointer data)
+{
+ (void)widget;
+ char *op = data;
+
+ if (strcmp(op, "loop") == 0)
+ {
+ int play_start = patch_get_mark_frame(se->patch,WF_MARK_PLAY_START);
+ int play_stop = patch_get_mark_frame(se->patch, WF_MARK_PLAY_STOP);
+ patch_set_mark_frame(se->patch, WF_MARK_LOOP_START, play_start);
+ patch_set_mark_frame(se->patch, WF_MARK_LOOP_STOP, play_stop);
+ }
+ else if (strcmp(op, "play") == 0)
+ {
+ int frames = patch_get_mark_frame(se->patch, WF_MARK_STOP);
+ patch_set_mark_frame(se->patch, WF_MARK_PLAY_START, 0);
+ patch_set_mark_frame(se->patch, WF_MARK_PLAY_STOP, frames - 1);
+ }
+
+ cb_mark_combo_changed(se->mark_combo, 0);
+ gtk_widget_queue_draw(se->waveform);
+ gtk_widget_queue_draw(wf_thumb);
+}
+
+
+static void update_mark_val(int val)
+{
+ const float* wav = patch_get_sample(se->patch);
+ char buf[40];
+ snprintf(buf, 40, "%2.6f", wav[val * 2]);
+ gtk_label_set_label(GTK_LABEL(se->mark_val), buf);
+}
+
+
+static void cb_scroll(GtkWidget* scroll, gpointer data)
+{
+ (void)data;
+ float val = gtk_range_get_value(GTK_RANGE(scroll));
+ waveform_set_range(WAVEFORM(se->waveform), val, val + se->range);
+}
+
+
+static void cb_mark_spin_changed(GtkWidget* spin, gpointer data)
+{
+ (void)spin;(void)data;
+ int val;
+ int mark;
+
+ val = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(se->mark_spin));
+ mark = waveform_get_mark(WAVEFORM(se->waveform));
+
+ patch_set_mark_frame(se->patch, mark, val);
+ update_mark_val(val);
+ update_fade_spins(); /* so xfade spin button range is set correctly */
+ gtk_widget_queue_draw(se->waveform);
+ gtk_widget_queue_draw(wf_thumb);
+}
+
+
+static void cb_fade_spin_changed(GtkWidget* spin, gpointer data)
+{
+ (void)spin;(void)data;
+ int val = gtk_spin_button_get_value_as_int(
+ GTK_SPIN_BUTTON(se->fade_spin));
+ patch_set_fade_samples(se->patch, val);
+}
+
+
+static void cb_xfade_spin_changed(GtkWidget* spin, gpointer data)
+{
+ (void)spin;(void)data;
+ int val = gtk_spin_button_get_value_as_int(
+ GTK_SPIN_BUTTON(se->xfade_spin));
+ patch_set_xfade_samples(se->patch, val);
+ update_mark_spin(); /* so mark spin range is set correctly */
+}
+
+
+static void update_mark_spin(void)
+{
+ int min;
+ int max;
+
+ int mark = waveform_get_mark(WAVEFORM(se->waveform));
+ int val = patch_get_mark_frame_range(se->patch, mark, &min, &max);
+
+ if (val < 0)
+ {
+ val = patch_get_mark_frame(se->patch, mark);
+ gtk_widget_set_sensitive(se->mark_spin, FALSE);
+ }
+ else
+ gtk_widget_set_sensitive(se->mark_spin, TRUE);
+
+ g_signal_handlers_block_by_func(se->mark_spin, cb_mark_spin_changed, 0);
+ gtk_spin_button_set_range(GTK_SPIN_BUTTON(se->mark_spin), min, max);
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(se->mark_spin), val);
+ g_signal_handlers_unblock_by_func(se->mark_spin,cb_mark_spin_changed,0);
+
+ update_fade_spins(); /* ie set the range of xfade */
+ update_mark_val(val);
+}
+
+
+static void update_fade_spins(void)
+{
+ int fade = patch_get_fade_samples(se->patch);
+ int max_fade = patch_get_max_fade_samples(se->patch);
+ int xfade = patch_get_xfade_samples(se->patch);
+ int max_xfade = patch_get_max_xfade_samples(se->patch);
+
+ g_signal_handlers_block_by_func(se->fade_spin, cb_fade_spin_changed, 0);
+ gtk_spin_button_set_range(GTK_SPIN_BUTTON(se->fade_spin), 0, max_fade);
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(se->fade_spin), fade);
+ g_signal_handlers_unblock_by_func( se->fade_spin,
+ cb_fade_spin_changed,
+ 0);
+
+ g_signal_handlers_block_by_func(se->xfade_spin,
+ cb_xfade_spin_changed,
+ 0);
+
+ gtk_spin_button_set_range(GTK_SPIN_BUTTON(se->xfade_spin), 0,
+ max_xfade);
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(se->xfade_spin), xfade);
+ g_signal_handlers_unblock_by_func(se->xfade_spin,
+ cb_xfade_spin_changed, 0);
+}
+
+
+static void cb_mark_combo_changed(GtkWidget* combo, gpointer data)
+{
+ (void)combo;(void)data;
+ se->ignore_mark_change = TRUE;
+ waveform_set_mark(WAVEFORM(se->waveform),
+ gtk_combo_box_get_active(GTK_COMBO_BOX(se->mark_combo)));
+ update_mark_spin();
+}
+
+static void cb_wf_play_changed(void)
+{
+ /* there's some chance the play point that was changed is
+ selected and shown in the mark spin. */
+ update_mark_spin();
+ update_fade_spins();
+ gtk_widget_queue_draw(wf_thumb);
+}
+
+static void cb_wf_loop_changed(void)
+{
+ /* there's some chance the play point that was changed is
+ selected and shown in the mark spin. */
+ update_mark_spin();
+ update_fade_spins();
+ gtk_widget_queue_draw(wf_thumb);
+}
+
+static void cb_wf_mark_changed(void)
+{
+ /* ditto cb_wf_play_changed */
+ if (se->ignore_mark_change)
+ {
+ se->ignore_mark_change = FALSE;
+ return;
+ }
+ gtk_combo_box_set_active(GTK_COMBO_BOX(se->mark_combo),
+ waveform_get_mark(WAVEFORM(se->waveform)));
+}
+
+static void cb_wf_view_changed(void)
+{
+ float start, stop;
+ waveform_get_range(WAVEFORM(se->waveform), &start, &stop);
+
+ g_signal_handlers_block_by_func(se->hscroll, cb_scroll, 0);
+ zoom_adj();
+ g_signal_handlers_unblock_by_func(se->hscroll, cb_scroll, 0);
+
+}
+
+
+static void zoom_adj(void)
+{
+ float page_size=0;
+ float step_inc=0;
+ float page_inc=0;
+ float val=0;
+ float start=0;
+ float stop=0;
+
+ waveform_get_range(WAVEFORM(se->waveform), &start, &stop);
+ gtk_range_set_range(GTK_RANGE(se->hscroll), start, stop);
+
+ val = start;
+ se->range = page_size = stop - start;
+
+ step_inc = se->range / 100;
+ page_inc = step_inc / 10;
+ se->hscrolladj = gtk_adjustment_new(val, 0.0, 1.0,
+ step_inc,
+ page_inc,
+ page_size);
+
+ gtk_range_set_adjustment(GTK_RANGE(se->hscroll),
+ GTK_ADJUSTMENT(se->hscrolladj));
+
+ /* emit value-changed signal so waveform is redrawn with
+ * the new dimensions */
+ g_signal_emit_by_name(G_OBJECT(se->hscroll), "value-changed");
+
+ return;
+}
+
+static void cb_zoom_1to1(GtkWidget* widget, gpointer data)
+{
+ (void)widget;(void)data;
+ int frames;
+ int width;
+ float zoom_level;
+ float zoom_multiplier;
+
+ waveform_get_size(WAVEFORM(se->waveform), &width, NULL);
+ frames = patch_get_frames(se->patch);
+
+ zoom_level = width / (double)frames;
+
+ zoom_multiplier = se->range / zoom_level;
+
+ waveform_zoom(WAVEFORM(se->waveform), zoom_multiplier, 0.5);
+ zoom_adj();
+}
+
+static void cb_zoom_all(GtkWidget* widget, gpointer data)
+{
+ (void)widget;(void)data;
+ waveform_set_range(WAVEFORM(se->waveform), 0.0, 1.0);
+ zoom_adj();
+}
+
+
+static void cb_zoom_in(GtkWidget* widget, gpointer data)
+{
+ (void)widget;(void)data;
+ waveform_zoom(WAVEFORM(se->waveform), 2.0, 0.5);
+ zoom_adj();
+}
+
+static void cb_zoom_out(GtkWidget* widget, gpointer data)
+{
+ (void)widget;(void)data;
+ waveform_zoom(WAVEFORM(se->waveform), 0.5, 0.5);
+ zoom_adj();
+}
+
+
+static void sensitize_toolbars(gboolean tools_active)
+{
+ gtk_widget_set_sensitive(se->toolbar1, tools_active);
+ gtk_widget_set_sensitive(se->toolbar2, tools_active);
+ gtk_widget_set_sensitive(se->reset, tools_active);
+}
+
+
+void sample_editor_show(int id)
+{
+ se->patch = id;
+
+ waveform_set_patch(WAVEFORM(se->waveform), se->patch);
+
+ if (patch_get_sample(se->patch))
+ {
+ se->old_play_start = patch_get_mark_frame(se->patch,
+ WF_MARK_PLAY_START);
+ se->old_play_stop = patch_get_mark_frame(se->patch,
+ WF_MARK_PLAY_STOP);
+ se->old_loop_start = patch_get_mark_frame(se->patch,
+ WF_MARK_LOOP_START);
+ se->old_loop_stop = patch_get_mark_frame(se->patch,
+ WF_MARK_LOOP_STOP);
+ sensitize_toolbars(true);
+ }
+ else
+ sensitize_toolbars(false);
+
+ if (gtk_combo_box_get_active(GTK_COMBO_BOX(se->mark_combo))
+ == WF_MARK_START)
+ {
+ gtk_combo_box_set_active(GTK_COMBO_BOX(se->mark_combo),
+ WF_MARK_PLAY_START);
+ }
+
+ update_fade_spins();
+ gtk_widget_show(se->window);
+}
+
+
+void sample_editor_hide(void)
+{
+ gtk_widget_hide(se->window);
+}
+
+
+gboolean sample_editor_get_visible(void)
+{
+ return gtk_widget_get_visible(se->window);
+}
+
+
+
+void sample_editor_update(void)
+{
+ if (se->patch < 0)
+ return;
+
+ if (patch_get_sample(se->patch))
+ sensitize_toolbars(true);
+ else
+ sensitize_toolbars(false);
+
+ waveform_set_range(WAVEFORM(se->waveform), 0.0, 1.0);
+ gtk_widget_queue_draw(se->waveform);
+}
+
+
+
+void sample_editor_set_thumb(GtkWidget* thumb)
+{
+ wf_thumb = thumb;
+}
+
+
+void sample_editor_init(GtkWidget * parent)
+{
+ GtkWindow* w;
+ GtkWidget* master_vbox;
+ GtkWidget* hbox;
+ GtkWidget* brow;
+ GtkWidget* button;
+ GtkWidget* image;
+ GtkWidget* label;
+ GtkWidget* tmp;
+
+ assert(se == 0);
+
+ se = sample_editor_private_new();
+
+ /* main window */
+ se->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ w = GTK_WINDOW(se->window);
+ gtk_window_set_title(w, "Edit Sample");
+ gtk_window_set_resizable(w, TRUE);
+ gtk_window_set_transient_for(w, GTK_WINDOW(parent));
+ gtk_window_set_modal(w, FALSE);
+ g_signal_connect(G_OBJECT(w), "delete-event", G_CALLBACK(cb_close),
+ NULL);
+
+ /* master vbox */
+ master_vbox = gtk_vbox_new(FALSE, GUI_SPACING);
+ gtk_container_add(GTK_CONTAINER(se->window), master_vbox);
+ gtk_container_set_border_width(GTK_CONTAINER(se->window), GUI_SPACING);
+ gtk_widget_show(master_vbox);
+
+ /* top row hbox */
+ se->toolbar1 = hbox = gtk_hbox_new(FALSE, GUI_SPACING);
+ gtk_box_pack_start(GTK_BOX(master_vbox), hbox, FALSE, FALSE, 0);
+ gtk_widget_show(hbox);
+
+ /* play button */
+ image = gtk_image_new_from_stock(GTK_STOCK_MEDIA_PLAY,
+ GTK_ICON_SIZE_SMALL_TOOLBAR);
+ button = gtk_button_new();
+ gtk_container_add(GTK_CONTAINER(button), image);
+ gtk_box_pack_start(GTK_BOX (hbox), button, FALSE, FALSE, 0);
+ g_signal_connect_swapped(G_OBJECT (button), "clicked",
+ G_CALLBACK(cb_play), NULL);
+ gtk_widget_show(image);
+ gtk_widget_show(button);
+
+ /* stop button */
+ image = gtk_image_new_from_stock(GTK_STOCK_MEDIA_STOP,
+ GTK_ICON_SIZE_SMALL_TOOLBAR);
+ button = gtk_button_new ( );
+ gtk_container_add (GTK_CONTAINER (button), image);
+ gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
+ g_signal_connect_swapped (G_OBJECT (button), "clicked",
+ G_CALLBACK (cb_stop), NULL);
+ gtk_widget_show(image);
+ gtk_widget_show(button);
+
+ /* separator */
+ tmp = gtk_vseparator_new();
+ gtk_box_pack_start(GTK_BOX(hbox), tmp, FALSE, FALSE, 0);
+ gtk_widget_show(tmp);
+
+ /* fade spin button */
+ label = gtk_label_new("Fade:");
+ gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
+ gtk_widget_show(label);
+
+ se->fade_spin = gtk_spin_button_new_with_range(0, 1, 1);
+ gtk_box_pack_start(GTK_BOX(hbox), se->fade_spin, FALSE, FALSE, 0);
+ gtk_widget_show(se->fade_spin);
+ g_signal_connect(G_OBJECT(se->fade_spin), "value-changed",
+ G_CALLBACK(cb_fade_spin_changed), NULL);
+
+ /* X-fade spin button */
+ label = gtk_label_new("X-Fade:");
+ gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
+ gtk_widget_show(label);
+
+ se->xfade_spin = gtk_spin_button_new_with_range(0, 1, 1);
+ gtk_box_pack_start(GTK_BOX(hbox), se->xfade_spin, FALSE, FALSE, 0);
+ gtk_widget_show(se->xfade_spin);
+ g_signal_connect(G_OBJECT(se->xfade_spin), "value-changed",
+ G_CALLBACK(cb_xfade_spin_changed), NULL);
+
+ /* separator */
+ tmp = gtk_vseparator_new();
+ gtk_box_pack_start(GTK_BOX(hbox), tmp, FALSE, FALSE, 0);
+ gtk_widget_show(tmp);
+
+ /* mark combo */
+ se->mark_combo = basic_combo_create(waveform_get_mark_names());
+ gtk_box_pack_start(GTK_BOX(hbox), se->mark_combo, FALSE, FALSE, 0);
+ gtk_widget_show(se->mark_combo);
+ g_signal_connect(G_OBJECT(se->mark_combo), "changed",
+ G_CALLBACK(cb_mark_combo_changed), NULL);
+
+ se->mark_spin = gtk_spin_button_new_with_range(0, 1, 1);
+ gtk_box_pack_start(GTK_BOX(hbox), se->mark_spin, FALSE, FALSE, 0);
+ gtk_widget_show(se->mark_spin);
+ g_signal_connect(G_OBJECT(se->mark_spin), "value-changed",
+ G_CALLBACK(cb_mark_spin_changed), NULL);
+
+ /* mark spin value label */
+ se->mark_val = gtk_label_new("");
+ gtk_box_pack_start(GTK_BOX(hbox), se->mark_val, FALSE, FALSE, 0);
+ gtk_widget_show(se->mark_val);
+
+ /* separator */
+ tmp = gtk_vseparator_new();
+ gtk_box_pack_start(GTK_BOX(hbox), tmp, FALSE, FALSE, 0);
+ gtk_widget_show(tmp);
+
+ /* loop points clear button */
+ button = gtk_button_new_with_label ("Loop");
+ gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
+ g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (cb_clear),
+ (gpointer) "loop");
+ gtk_widget_show (button);
+
+ /* play points clear button */
+ button = gtk_button_new_with_label ("Play");
+ gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
+ g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (cb_clear),
+ (gpointer) "play");
+ gtk_widget_show (button);
+
+
+ /* clear label */
+ label = gtk_label_new ("Clear Points:");
+ gtk_box_pack_end (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+ gtk_widget_show (label);
+
+ /* waveform */
+ se->waveform = waveform_new();
+ waveform_set_patch( WAVEFORM(se->waveform), -1);
+ waveform_set_size( WAVEFORM(se->waveform), 512, 256);
+ waveform_set_interactive( WAVEFORM(se->waveform), TRUE);
+ gtk_box_pack_start(GTK_BOX(master_vbox), se->waveform, TRUE, TRUE, 0);
+ gtk_widget_show(se->waveform);
+ g_signal_connect(G_OBJECT(se->waveform), "play-changed",
+ G_CALLBACK(cb_wf_play_changed), NULL);
+ g_signal_connect(G_OBJECT(se->waveform), "loop-changed",
+ G_CALLBACK(cb_wf_loop_changed), NULL);
+ g_signal_connect(G_OBJECT(se->waveform), "mark-changed",
+ G_CALLBACK(cb_wf_mark_changed), NULL);
+ g_signal_connect(G_OBJECT(se->waveform), "view-changed",
+ G_CALLBACK(cb_wf_view_changed), NULL);
+
+ /* waveform scrollbar */
+ se->hscrolladj = gtk_adjustment_new(0.0, 0.0, 1.0, 0.0, 0.0, 1.0);
+ se->hscroll = gtk_hscrollbar_new(GTK_ADJUSTMENT(se->hscrolladj));
+ gtk_box_pack_start(GTK_BOX(master_vbox), se->hscroll, FALSE, FALSE, 0);
+ g_signal_connect(G_OBJECT(se->hscroll), "value-changed",
+ G_CALLBACK (cb_scroll), NULL);
+ gtk_widget_show (se->hscroll);
+
+ /* bottom row hbox */
+ brow = gtk_hbox_new(FALSE, 0);
+ gtk_box_pack_start (GTK_BOX(master_vbox), brow, FALSE, FALSE, 0);
+ gtk_widget_show(brow);
+
+ se->toolbar2 = hbox = gtk_hbox_new (FALSE, GUI_SPACING);
+ gtk_box_pack_start (GTK_BOX(brow), hbox, FALSE, FALSE, 0);
+ gtk_widget_show (hbox);
+
+ /* zoom-out button */
+ image = gtk_image_new_from_stock(GTK_STOCK_ZOOM_OUT,
+ GTK_ICON_SIZE_SMALL_TOOLBAR);
+ button = gtk_button_new();
+ gtk_container_add(GTK_CONTAINER(button), image);
+ gtk_box_pack_start(GTK_BOX (hbox), button, FALSE, FALSE, 0);
+ g_signal_connect_swapped(G_OBJECT (button), "clicked",
+ G_CALLBACK(cb_zoom_out), NULL);
+ gtk_widget_show(image);
+ gtk_widget_show(button);
+
+ /* zoom-in button */
+ image = gtk_image_new_from_stock(GTK_STOCK_ZOOM_IN,
+ GTK_ICON_SIZE_SMALL_TOOLBAR);
+ button = gtk_button_new();
+ gtk_container_add(GTK_CONTAINER(button), image);
+ gtk_box_pack_start(GTK_BOX (hbox), button, FALSE, FALSE, 0);
+ g_signal_connect_swapped(G_OBJECT (button), "clicked",
+ G_CALLBACK(cb_zoom_in), NULL);
+ gtk_widget_show(image);
+ gtk_widget_show(button);
+
+ /* zoom-1:1 button */
+ image = gtk_image_new_from_stock(GTK_STOCK_ZOOM_100,
+ GTK_ICON_SIZE_SMALL_TOOLBAR);
+ button = gtk_button_new();
+ gtk_container_add(GTK_CONTAINER(button), image);
+ gtk_box_pack_start(GTK_BOX (hbox), button, FALSE, FALSE, 0);
+ g_signal_connect_swapped(G_OBJECT (button), "clicked",
+ G_CALLBACK(cb_zoom_1to1), NULL);
+ gtk_widget_show(image);
+ gtk_widget_show(button);
+
+ /* zoom-all button */
+ image = gtk_image_new_from_stock(GTK_STOCK_ZOOM_FIT,
+ GTK_ICON_SIZE_SMALL_TOOLBAR);
+ button = gtk_button_new();
+ gtk_container_add(GTK_CONTAINER(button), image);
+ gtk_box_pack_start(GTK_BOX (hbox), button, FALSE, FALSE, 0);
+ g_signal_connect_swapped(G_OBJECT (button), "clicked",
+ G_CALLBACK(cb_zoom_all), NULL);
+ gtk_widget_show(image);
+ gtk_widget_show(button);
+
+ hbox = gtk_hbox_new (FALSE, GUI_SPACING);
+ gtk_box_pack_end(GTK_BOX(brow), hbox, FALSE, FALSE, 0);
+ gtk_widget_show (hbox);
+
+ /* close button */
+ button = gtk_button_new_from_stock (GTK_STOCK_CLOSE);
+ gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
+ g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(cb_close),
+ NULL);
+ gtk_widget_show (button);
+
+ /* reset button */
+ se->reset = button = gtk_button_new_with_label ("Reset");
+ gtk_box_pack_end(GTK_BOX (hbox), button, FALSE, FALSE, 0);
+ g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(cb_reset),
+ NULL);
+ gtk_widget_show (button);
+}
diff --git a/src/gui/sample-editor.h b/gui/sample-editor.h
similarity index 78%
rename from src/gui/sample-editor.h
rename to gui/sample-editor.h
index d2327de..ecada79 100644
--- a/src/gui/sample-editor.h
+++ b/gui/sample-editor.h
@@ -28,14 +28,15 @@
#include <gtk/gtk.h>
-void sample_editor_init(GtkWidget* parent);
+void sample_editor_init(GtkWidget* parent);
/* waveform thumb in sample tab */
-void sample_editor_set_thumb(GtkWidget* thumb);
+void sample_editor_set_thumb(GtkWidget* thumb);
-void sample_editor_show(int id);
-
-void sample_editor_update(void);
+void sample_editor_show(int id);
+void sample_editor_hide(void);
+gboolean sample_editor_get_visible(void);
+void sample_editor_update(void);
#endif /* __SAMPLE_EDITOR_H__ */
diff --git a/src/gui/sample-selector.c b/gui/sample-selector.c
similarity index 79%
rename from src/gui/sample-selector.c
rename to gui/sample-selector.c
index d7e725d..8c079f4 100644
--- a/src/gui/sample-selector.c
+++ b/gui/sample-selector.c
@@ -31,12 +31,15 @@
#include "basic_combos.h"
#include "gui.h"
#include "petri-foo.h"
+#include "pf_error.h"
#include "mixer.h"
+#include "msg_log.h"
#include "patch_set_and_get.h"
#include "patch_util.h"
#include "names.h"
#include "sample-selector.h"
#include "sample.h"
+#include "global_settings.h"
#include <sndfile.h>
@@ -54,7 +57,9 @@ typedef struct _raw_box
GtkWidget* box;
/* box contains: */
+ GtkWidget* toggle_box;
GtkWidget* check;
+ GtkWidget* auto_preview;
GtkWidget* table;
/* table contains: */
@@ -95,22 +100,23 @@ static void cb_load(raw_box* rb)
int err;
char *name = (char *)
gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(rb->dialog));
+ global_settings* settings = settings_get();
if (!name)
goto fail;
- debug("about to load sample...\n");
-
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(rb->check)))
{
int samplerate = gtk_spin_button_get_value_as_int(
GTK_SPIN_BUTTON(rb->samplerate));
- err = patch_sample_load(patch, name, samplerate,
+ if (patch_sample_load(patch, name, samplerate,
rb->channels,
- get_format(rb));
- if (err)
+ get_format(rb)) < 0)
+ {
+ err = pf_error_get();
goto fail;
+ }
}
else
{ /* don't repeat load sample */
@@ -119,16 +125,32 @@ static void cb_load(raw_box* rb)
if (s->filename && strcmp(name, s->filename) == 0)
return;
- if ((err = patch_sample_load(patch, name, 0, 0, 0)))
+ if (patch_sample_load(patch, name, 0, 0, 0))
+ {
+ err = pf_error_get();
goto fail;
+ }
+ }
+
+ if (name)
+ {
+ char* dirname = g_path_get_dirname(name);
+
+ if (dirname)
+ {
+ if (settings->last_sample_dir)
+ free(settings->last_sample_dir);
+
+ settings->last_sample_dir = strdup(dirname);
+ free(dirname);
+ }
}
- debug ("Successfully loaded sample %s\n", name);
return;
fail:
if (!name)
- {
+ { /* I don't really think this is possible, but hey. */
errmsg("no file selected\n");
msg = gtk_message_dialog_new(GTK_WINDOW(rb->dialog),
GTK_DIALOG_DESTROY_WITH_PARENT,
@@ -137,8 +159,12 @@ fail:
}
else
{
- errmsg ("Failed to load sample %s for patch %d (%s)\n", name,
- patch, patch_strerror(err));
+ msg_log(MSG_TYPE_ERROR, /* Unlike MSG_ERROR, MSG_TYPE_ERROR does
+ not set the log notification flag */
+ "Failed to load sample %s for patch %d (%s)\n",
+ name, patch, pf_error_str(err));
+
+ /* do our own notification here: */
msg = gtk_message_dialog_new(GTK_WINDOW(rb->dialog),
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
@@ -175,18 +201,17 @@ static void cb_preview(raw_box* rb)
static void cb_cancel(void)
{
- debug("cancelling sample load...\n");
-
if (!last_sample->filename)
{
- debug("no sample to restore, just unloading...\n");
patch_sample_unload(patch);
return;
}
if (strcmp(patch_get_sample_name(patch), last_sample->filename) != 0)
{
- debug("restoring sample:%s\n", last_sample->filename);
+ msg_log(MSG_MESSAGE, "Restoring sample:%s\n",
+ last_sample->filename);
+
patch_sample_load(patch, last_sample->filename,
last_sample->raw_samplerate,
last_sample->raw_channels,
@@ -204,34 +229,15 @@ static void raw_toggles_toggled_cb(GtkToggleButton* tog, gpointer data)
if (gtk_toggle_button_get_active(tog))
{
if (tog == GTK_TOGGLE_BUTTON(rb->stereo))
- {
- debug("setting raw channels to two\n");
rb->channels = 2;
- }
else if (tog == GTK_TOGGLE_BUTTON(rb->mono))
- {
- debug("setting raw channels to one\n");
rb->channels = 1;
- }
else if (tog == GTK_TOGGLE_BUTTON(rb->big_endian))
- {
- debug("setting raw endianness to big\n");
rb->endian = 2;
- }
else if (tog == GTK_TOGGLE_BUTTON(rb->little_endian))
- {
- debug("setting raw endianness to little\n");
rb->endian = 1;
- }
else if (tog == GTK_TOGGLE_BUTTON(rb->file_endian))
- {
- debug("setting raw endianness to file\n");
rb->endian = 0;
- }
- else
- {
- debug("unknown raw data toggle\n");
- }
}
}
@@ -246,6 +252,17 @@ static void raw_toggled_cb(GtkToggleButton* raw_toggle, gpointer data)
}
+static void selection_changed_cb(GtkFileChooser* dialog, gpointer data)
+{
+ (void)dialog;
+
+ raw_box* rb = (raw_box*)data;
+
+ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(rb->auto_preview)))
+ cb_preview(rb);
+}
+
+
static raw_box* raw_box_new(GtkWidget* dialog)
{
GtkTable* t;
@@ -264,13 +281,27 @@ static raw_box* raw_box_new(GtkWidget* dialog)
rb->endian = 0;
rb->box = gtk_vbox_new(FALSE, 0);
+ rb->toggle_box = gtk_hbox_new(FALSE,10);
rb->check = gtk_check_button_new_with_label("Raw/Headerless");
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rb->check), FALSE);
gtk_widget_show(rb->check);
- gtk_box_pack_start(GTK_BOX(rb->box), rb->check, TRUE, TRUE, 0);
+ gtk_box_pack_start(GTK_BOX(rb->toggle_box), rb->check, FALSE, FALSE, 0);
g_signal_connect(GTK_OBJECT(rb->check), "toggled",
G_CALLBACK(raw_toggled_cb), rb);
+
+ rb->auto_preview = gtk_check_button_new_with_label("Auto Preview");
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rb->auto_preview),
+ FALSE);
+ gtk_widget_show(rb->auto_preview);
+ gtk_box_pack_start(GTK_BOX(rb->toggle_box), rb->auto_preview, FALSE,
+ FALSE, 0);
+ g_signal_connect(dialog, "selection-changed",
+ G_CALLBACK(selection_changed_cb), rb);
+
+ gtk_box_pack_start(GTK_BOX(rb->box), rb->toggle_box, TRUE, TRUE, 0);
+ gtk_widget_show(rb->toggle_box);
+
rb->table = gtk_table_new(5, 2, FALSE);
gtk_box_pack_start(GTK_BOX(rb->box), rb->table, TRUE, TRUE, 0);
@@ -329,6 +360,7 @@ int sample_selector_show(int id, GtkWidget* parent_window,
{
GtkWidget* dialog;
raw_box* rawbox;
+ global_settings* settings = settings_get();
enum {
RESPONSE_LOAD = 1,
@@ -357,10 +389,17 @@ int sample_selector_show(int id, GtkWidget* parent_window,
{
gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog),
last_sample->filename);
+ gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),
+ g_path_get_dirname(last_sample->filename));
+ }
+ else {
+ if ( settings->last_sample_dir)
+ gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),
+ settings->last_sample_dir);
}
gtk_dialog_add_button(GTK_DIALOG(dialog),
- "Load", RESPONSE_LOAD);
+ "Loa_d", RESPONSE_LOAD);
gtk_dialog_add_button(GTK_DIALOG(dialog),
"Pre_view", RESPONSE_PREVIEW);
diff --git a/src/gui/sample-selector.h b/gui/sample-selector.h
similarity index 100%
rename from src/gui/sample-selector.h
rename to gui/sample-selector.h
diff --git a/src/gui/sampletab.c b/gui/sampletab.c
similarity index 98%
rename from src/gui/sampletab.c
rename to gui/sampletab.c
index 2ecaa51..c0944e7 100644
--- a/src/gui/sampletab.c
+++ b/gui/sampletab.c
@@ -148,8 +148,6 @@ static void set_mode(SampleTabPrivate* p)
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(p->reverse_check)))
mode |= PATCH_PLAY_REVERSE;
- else
- mode |= PATCH_PLAY_FORWARD;
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(p->to_end_check)))
mode |= PATCH_PLAY_TO_END;
@@ -244,7 +242,7 @@ static GtkWidget* file_button_new(SampleTabPrivate* p)
hbox = gtk_hbox_new(FALSE, 0);
p->file_label = gtk_label_new("Load File");
vsep = gtk_vseparator_new();
- image = gtk_image_new_from_file(PIXMAPSDIR "open.png");
+ image = gtk_image_new_from_stock(GTK_STOCK_OPEN, GTK_ICON_SIZE_BUTTON);
gtk_box_pack_start(GTK_BOX(hbox), p->file_label, TRUE, TRUE, 0);
gtk_box_pack_start(GTK_BOX(hbox), vsep, FALSE, FALSE, GUI_SPACING);
@@ -382,9 +380,10 @@ void sample_tab_set_patch(SampleTab* self, int patch)
gtk_combo_box_set_active_iter(GTK_COMBO_BOX(p->mode_opt),
&iter);
}
+
+ update_to_end_check(p);
}
- update_to_end_check(p);
unblock(p);
}
diff --git a/src/gui/sampletab.h b/gui/sampletab.h
similarity index 100%
rename from src/gui/sampletab.h
rename to gui/sampletab.h
diff --git a/gui/voicetab.c b/gui/voicetab.c
new file mode 100644
index 0000000..64abd34
--- /dev/null
+++ b/gui/voicetab.c
@@ -0,0 +1,249 @@
+/* Petri-Foo is a fork of the Specimen audio sampler.
+
+ Original Specimen author Pete Bessman
+ Copyright 2005 Pete Bessman
+ Copyright 2011 James W. Morris
+
+ This file is part of Petri-Foo.
+
+ Petri-Foo is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+
+ Petri-Foo is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Petri-Foo. If not, see <http://www.gnu.org/licenses/>.
+
+ This file is a derivative of a Specimen original, modified 2011
+*/
+
+
+#include <gtk/gtk.h>
+
+#include "phin.h"
+
+#include "voicetab.h"
+#include "gui.h"
+#include "patch_set_and_get.h"
+#include "bool_section.h"
+#include "float_section.h"
+
+
+typedef struct _VoiceTabPrivate VoiceTabPrivate;
+
+#define VOICE_TAB_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE((obj), \
+ VOICE_TAB_TYPE, VoiceTabPrivate))
+
+struct _VoiceTabPrivate
+{
+ int patch;
+ guint refresh;
+ GtkWidget* cut_sb;
+ GtkWidget* cutby_sb;
+
+ GtkWidget* mono_check;
+ GtkWidget* legato_sect;
+
+ GtkWidget* porta_sect;
+ GtkWidget* time_sect;
+};
+
+
+G_DEFINE_TYPE(VoiceTab, voice_tab, GTK_TYPE_VBOX);
+
+
+static void voice_tab_class_init(VoiceTabClass* klass)
+{
+ GtkObjectClass *object_class = GTK_OBJECT_CLASS(klass);
+ voice_tab_parent_class = g_type_class_peek_parent(klass);
+ g_type_class_add_private(object_class, sizeof(VoiceTabPrivate));
+}
+
+
+static void cut_cb(PhinSliderButton* button, VoiceTabPrivate* p)
+{
+ int val = phin_slider_button_get_value(button);
+ patch_set_cut(p->patch, val);
+}
+
+
+static void cutby_cb(PhinSliderButton* button, VoiceTabPrivate* p)
+{
+ int val = phin_slider_button_get_value(button);
+ patch_set_cut_by(p->patch, val);
+}
+
+
+static void porta_cb(BoolSection* b, VoiceTabPrivate* p)
+{
+ if (bool_section_get_active(b))
+ gtk_widget_set_sensitive(p->time_sect, TRUE);
+ else
+ gtk_widget_set_sensitive(p->time_sect, FALSE);
+}
+
+
+static void mono_cb(GtkToggleButton* button, VoiceTabPrivate* p)
+{
+ patch_set_monophonic(p->patch, gtk_toggle_button_get_active(button));
+ gtk_widget_set_sensitive(p->legato_sect,
+ gtk_toggle_button_get_active(button));
+}
+
+
+static void connect(VoiceTabPrivate* p)
+{
+ g_signal_connect(G_OBJECT(p->cut_sb), "value-changed",
+ G_CALLBACK(cut_cb), (gpointer)p);
+ g_signal_connect(G_OBJECT(p->cutby_sb), "value-changed",
+ G_CALLBACK(cutby_cb), (gpointer)p);
+
+ g_signal_connect(G_OBJECT(p->mono_check), "toggled",
+ G_CALLBACK(mono_cb), (gpointer)p);
+
+ g_signal_connect(G_OBJECT(p->porta_sect), "toggled",
+ G_CALLBACK(porta_cb), (gpointer)p);
+}
+
+
+static void block(VoiceTabPrivate* p)
+{
+ g_signal_handlers_block_by_func(p->cut_sb, cut_cb, p);
+ g_signal_handlers_block_by_func(p->cutby_sb, cutby_cb, p);
+ g_signal_handlers_block_by_func(p->mono_check, mono_cb, p);
+ g_signal_handlers_block_by_func(p->porta_sect, porta_cb, p);
+}
+
+
+static void unblock(VoiceTabPrivate* p)
+{
+ g_signal_handlers_unblock_by_func(p->cut_sb, cut_cb, p);
+ g_signal_handlers_unblock_by_func(p->cutby_sb, cutby_cb, p);
+ g_signal_handlers_unblock_by_func(p->mono_check, mono_cb, p);
+ g_signal_handlers_unblock_by_func(p->porta_sect, porta_cb, p);
+}
+
+
+static void voice_tab_init(VoiceTab* self)
+{
+ VoiceTabPrivate* p = VOICE_TAB_GET_PRIVATE(self);
+ GtkBox* box = GTK_BOX(self);
+ GtkWidget* table;
+ GtkTable* t;
+
+ int a1 = 0, a2 = 1;
+ int b1 = 1, b2 = 2;
+ int /*c1 = 2*/ c2 = 3;
+
+ int y = 0;
+
+ p->patch = -1;
+ p->refresh = -1;
+
+ gtk_container_set_border_width(GTK_CONTAINER(self), GUI_BORDERSPACE);
+
+ /* table */
+ table = gtk_table_new(8, 3, FALSE);
+ t = (GtkTable*) table;
+ gui_pack(box, table);
+
+ /* title */
+ gui_attach(t, gui_title_new("Voice"), a1, c2, y, y + 1);
+ ++y;
+
+ /* title padding */
+ gui_attach(t, gui_vpad_new(GUI_TITLESPACE), a1, c2, y, y + 1);
+ ++y;
+
+ /* cut sliderbutton */
+ p->cut_sb = phin_slider_button_new_with_range(0, 0, 99, 1, 0);
+ phin_slider_button_set_format(PHIN_SLIDER_BUTTON(p->cut_sb), 0,
+ "Cut:", NULL);
+ phin_slider_button_set_threshold(PHIN_SLIDER_BUTTON(p->cut_sb),
+ GUI_THRESHOLD);
+ gui_attach(t, p->cut_sb, a1, a2, y, y + 1);
+
+
+ /* cutby sliderbutton */
+ p->cutby_sb = phin_slider_button_new_with_range(0, 0, 99, 1, 0);
+ phin_slider_button_set_format(PHIN_SLIDER_BUTTON(p->cutby_sb), 0,
+ "Cut by:", NULL);
+ phin_slider_button_set_threshold(PHIN_SLIDER_BUTTON(p->cutby_sb),
+ GUI_THRESHOLD);
+ gui_attach(t, p->cutby_sb, b1, b2, y, y + 1);
+ ++y;
+
+ /* portamento control */
+ p->porta_sect = bool_section_new();
+ bool_section_set_bool( BOOL_SECTION(p->porta_sect),
+ PATCH_BOOL_PORTAMENTO);
+ gui_attach(t, p->porta_sect, a1, c2, y, y + 1);
+ ++y;
+
+ p->time_sect = float_section_new();
+ float_section_set_float(FLOAT_SECTION(p->time_sect),
+ PATCH_FLOAT_PORTAMENTO_TIME);
+ gui_attach(t, p->time_sect, a1, c2, y, y + 1);
+ ++y;
+
+ /* mono check button */
+ p->mono_check = gtk_check_button_new_with_label("Monophonic");
+ gui_attach(t, p->mono_check, a1, a2, y, y + 1);
+ ++y;
+
+ /* legato control */
+ p->legato_sect = bool_section_new();
+ bool_section_set_bool( BOOL_SECTION(p->legato_sect),
+ PATCH_BOOL_LEGATO);
+ gui_attach(t, p->legato_sect, a1, c2, y, y + 1);
+ ++y;
+
+ /* done! */
+ connect(p);
+}
+
+
+GtkWidget* voice_tab_new(void)
+{
+ return (GtkWidget*) g_object_new(VOICE_TAB_TYPE, NULL);
+}
+
+
+void voice_tab_set_patch(VoiceTab* self, int patch)
+{
+ VoiceTabPrivate* p = VOICE_TAB_GET_PRIVATE(self);
+ int cut, cutby;
+ gboolean porta, mono;
+
+ p->patch = patch;
+
+ if (patch < 0)
+ return;
+
+ cut = patch_get_cut(patch);
+ cutby = patch_get_cut_by(patch);
+ porta = patch_get_portamento(patch);
+ mono = patch_get_monophonic(patch);
+
+ block(p);
+
+ phin_slider_button_set_value(PHIN_SLIDER_BUTTON(p->cut_sb), cut);
+ phin_slider_button_set_value(PHIN_SLIDER_BUTTON(p->cutby_sb), cutby);
+
+ bool_section_set_patch(BOOL_SECTION(p->porta_sect), patch);
+
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p->mono_check), mono);
+
+ bool_section_set_patch(BOOL_SECTION(p->legato_sect), patch);
+ float_section_set_patch(FLOAT_SECTION(p->time_sect), patch);
+
+ gtk_widget_set_sensitive(p->legato_sect, mono);
+ gtk_widget_set_sensitive(p->time_sect, porta);
+
+ unblock(p);
+}
diff --git a/src/gui/voicetab.h b/gui/voicetab.h
similarity index 100%
rename from src/gui/voicetab.h
rename to gui/voicetab.h
diff --git a/src/gui/waveform.c b/gui/waveform.c
similarity index 91%
rename from src/gui/waveform.c
rename to gui/waveform.c
index faaaf9c..0c0d8df 100644
--- a/src/gui/waveform.c
+++ b/gui/waveform.c
@@ -100,7 +100,8 @@ static const char* mark_names[] = {
"Loop start",
"Loop end",
"Play end",
- "Sample end"
+ "Sample end",
+ 0
};
@@ -136,25 +137,20 @@ G_DEFINE_TYPE(Waveform, waveform, GTK_TYPE_DRAWING_AREA)
static void waveform_dispose(GObject * object);
-static void waveform_size_request (GtkWidget * widget,
- GtkRequisition * requisition);
+static void waveform_size_request( GtkWidget*, GtkRequisition*);
+static gboolean waveform_expose( GtkWidget*, GdkEventExpose*);
+static gboolean waveform_button_press( GtkWidget*, GdkEventButton*);
+static gboolean waveform_configure( GtkWidget*, GdkEventConfigure*);
+static gboolean waveform_scroll_event( GtkWidget*, GdkEventScroll*);
-static gboolean waveform_expose(GtkWidget * widget,
- GdkEventExpose * event);
-
-static gboolean waveform_button_press(GtkWidget * widget,
- GdkEventButton * event);
-
-static gboolean waveform_configure(GtkWidget * widget,
- GdkEventConfigure * event);
static void waveform_draw(Waveform * wf);
static void waveform_class_init (WaveformClass * klass)
{
- GObjectClass *object_class = G_OBJECT_CLASS(klass);
- GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
+ GObjectClass* object_class = G_OBJECT_CLASS(klass);
+ GtkWidgetClass* widget_class = GTK_WIDGET_CLASS(klass);
waveform_parent_class = g_type_class_peek_parent(klass);
@@ -163,6 +159,7 @@ static void waveform_class_init (WaveformClass * klass)
widget_class->configure_event = waveform_configure;
widget_class->size_request = waveform_size_request;
widget_class->button_press_event = waveform_button_press;
+ widget_class->scroll_event = waveform_scroll_event;
signals[PLAY_CHANGED] =
g_signal_new ("play-changed",
@@ -336,14 +333,14 @@ waveform_button_press (GtkWidget * widget, GdkEventButton * event)
{
if (event->button == 1)
mark = WF_MARK_PLAY_START;
- else if (event->button == 3)
+ else if (event->button == 3)
mark = WF_MARK_PLAY_STOP;
}
else
{
if (event->button == 1)
mark = WF_MARK_LOOP_START;
- else if (event->button == 3)
+ else if (event->button == 3)
mark = WF_MARK_LOOP_STOP;
}
}
@@ -388,6 +385,28 @@ waveform_button_press (GtkWidget * widget, GdkEventButton * event)
}
+static gboolean
+waveform_scroll_event(GtkWidget* widget, GdkEventScroll* event)
+{
+ Waveform* wf = WAVEFORM(widget);
+ WaveformPrivate* p = WAVEFORM_GET_PRIVATE(wf);
+ float center;
+
+ if (!p->interactive)
+ return FALSE;
+
+ center = event->x / p->width;
+
+ if (event->direction == GDK_SCROLL_DOWN)
+ waveform_zoom(wf, SCROLL_WHEEL_ZOOM_RATIO, center);
+ else
+ waveform_zoom(wf, 1 / SCROLL_WHEEL_ZOOM_RATIO, center);
+
+ g_signal_emit_by_name(G_OBJECT(wf), "view-changed");
+ return FALSE;
+}
+
+
inline static void
cr_rect(cairo_t* cr, double x1, double y1, double x2, double y2)
{
@@ -397,7 +416,7 @@ cr_rect(cairo_t* cr, double x1, double y1, double x2, double y2)
static void draw_back(WaveformPrivate* p, int w, int h, cairo_t* cr)
{
- int frames;
+ int frames = -1;
int start, stop;
int play_start, play_stop;
int loop_start, loop_stop;
@@ -407,10 +426,9 @@ static void draw_back(WaveformPrivate* p, int w, int h, cairo_t* cr)
cairo_pattern_t *bg_play;
cairo_pattern_t *bg_loop;
- frames = patch_get_frames(p->patch);
-
- if (frames > 0)
+ if (p->patch > -1 && patch_get_sample(p->patch))
{
+ frames = patch_get_frames(p->patch);
start = frames * p->range_start;
stop = frames * p->range_stop;
@@ -469,7 +487,8 @@ static void draw_back(WaveformPrivate* p, int w, int h, cairo_t* cr)
{ /* show left dead area if visible */
int w1 = (play_start < w - 1) ? play_start : w - 1;
cairo_rectangle (cr, 0, 0, w1, h);
- cairo_set_source (cr, bg_dead);
+ /*cairo_set_source (cr, bg_dead);*/
+ cairo_set_source_rgb(cr, BG_DEAD_R1, BG_DEAD_G1, BG_DEAD_B1);
cairo_fill (cr);
if (play_start > w - 1)
@@ -481,7 +500,8 @@ static void draw_back(WaveformPrivate* p, int w, int h, cairo_t* cr)
int x1 = (play_start > 0) ? play_start : 0;
int x2 = (loop_start < w - 1) ? loop_start : w - 1;
cr_rect(cr, x1, 0, x2, h);
- cairo_set_source (cr, bg_play);
+ /*cairo_set_source (cr, bg_play);*/
+ cairo_set_source_rgb(cr, BG_PLAY_R1, BG_PLAY_G1, BG_PLAY_B1);
cairo_fill (cr);
if (loop_start > w - 1)
@@ -494,7 +514,8 @@ static void draw_back(WaveformPrivate* p, int w, int h, cairo_t* cr)
int x1 = (loop_start > 0) ? loop_start: 0;
int x2 = (loop_stop < w - 1) ? loop_stop : w - 1;
cr_rect(cr, x1, 0, x2, h);
- cairo_set_source(cr, bg_loop);
+ /*cairo_set_source(cr, bg_loop);*/
+ cairo_set_source_rgb(cr, BG_LOOP_R1, BG_LOOP_G1, BG_LOOP_B1);
cairo_fill(cr);
if (loop_stop > w - 1)
@@ -506,7 +527,8 @@ static void draw_back(WaveformPrivate* p, int w, int h, cairo_t* cr)
int x1 = (loop_stop > 0) ? loop_stop : 0;
int x2 = (play_stop < w - 1) ? play_stop : w - 1;
cr_rect(cr, x1, 0, x2, h);
- cairo_set_source(cr, bg_play);
+ /*cairo_set_source(cr, bg_play);*/
+ cairo_set_source_rgb(cr, BG_PLAY_R1, BG_PLAY_G1, BG_PLAY_B1);
cairo_fill(cr);
if (play_stop > w - 1)
@@ -517,7 +539,8 @@ static void draw_back(WaveformPrivate* p, int w, int h, cairo_t* cr)
{ /* right dead area visible */
int x1 = (play_stop > 0) ? play_stop : 0;
cr_rect(cr, x1, 0, w, h);
- cairo_set_source(cr, bg_dead);
+ /*cairo_set_source(cr, bg_dead);*/
+ cairo_set_source_rgb(cr, BG_DEAD_R1, BG_DEAD_G1, BG_DEAD_B1);
cairo_fill(cr);
}
@@ -535,13 +558,15 @@ static void draw_grid(WaveformPrivate* p, int w, int h, cairo_t* cr)
int center = h / 2;
int step = h / GRID_Y;
+ /*
cairo_pattern_t *fg = cairo_pattern_create_linear (0, 0, 0, h);
-
cairo_pattern_add_color_stop_rgb(fg, 0.0, GRID_R1, GRID_G1, GRID_B1 );
cairo_pattern_add_color_stop_rgb(fg, 0.5, GRID_R2, GRID_G2, GRID_B2 );
cairo_pattern_add_color_stop_rgb(fg, 1.0, GRID_R1, GRID_G1, GRID_B1 );
cairo_set_source(cr, fg);
+ */
+ cairo_set_source_rgb(cr, GRID_R1, GRID_G1, GRID_B1);
cairo_set_line_width(cr, 1.0);
/* Massive improvement here using Cairo drawing with gradients
@@ -775,11 +800,11 @@ void draw_mark(WaveformPrivate* p, int w, int h, cairo_t* cr)
cairo_text_extents_t extents;
- frames = patch_get_frames (p->patch);
-
- if (frames <= 0)
+ if (p->patch < 0 || !patch_get_sample(p->patch))
return;
+ frames = patch_get_frames (p->patch);
+
start = frames * p->range_start;
stop = frames * p->range_stop;
play_start = patch_get_mark_frame(p->patch, WF_MARK_PLAY_START);
@@ -902,8 +927,6 @@ static void waveform_draw(Waveform * wf)
return;
#endif
- debug("drawing %p\n", p);
-
cr = gdk_cairo_create(p->pixmap);
cairo_rectangle(cr, 0, 0, p->width, p->height);
@@ -1007,6 +1030,47 @@ int waveform_detect_mark(Waveform* wf)
return small_mark;
}
+void waveform_zoom(Waveform* wf, gfloat zoom, gfloat center)
+{
+ WaveformPrivate* p = WAVEFORM_GET_PRIVATE(wf);
+
+ float dist;
+ float newstart;
+ float newstop;
+
+ float distl;
+ float distr;
+ float center_cp;
+
+ float newdistl;
+ float newdistr;
+
+ dist = p->range_stop - p->range_start;
+ distl = dist * center;
+ distr = dist * (1 - center);
+
+ center_cp = p->range_start + dist * center;
+
+ newdistl = distl / zoom;
+ newdistr = distr / zoom;
+
+ if (newdistl + newdistr >= 1.0)
+ {
+ waveform_set_range(wf, 0.0, 1.0);
+ return;
+ }
+
+ newstart = center_cp - newdistl;
+ newstop = center_cp + newdistr;
+
+ if (newstart < 0.0)
+ newstart = 0.0;
+
+ if (newstop > 1.0)
+ newstop = 1.0;
+
+ waveform_set_range(wf, newstart, newstop);
+}
void waveform_set_range (Waveform * wf, float start, float stop)
@@ -1018,7 +1082,7 @@ void waveform_set_range (Waveform * wf, float start, float stop)
? 0.0
: start;
- p->range_stop = (stop < 0.0 || start > 1.0 || start > stop)
+ p->range_stop = (stop < 0.0 || stop > 1.0 || start > stop)
? 1.0
: stop;
@@ -1078,8 +1142,13 @@ int waveform_get_patch (Waveform * wf)
void waveform_get_size (Waveform * wf, int *w, int *h)
{
WaveformPrivate* p = WAVEFORM_GET_PRIVATE(wf);
- *w = p->width;
- *h = p->height;
+
+ if (w)
+ *w = p->width;
+
+ if (h)
+ *h = p->height;
+
return;
}
diff --git a/src/gui/waveform.h b/gui/waveform.h
similarity index 96%
rename from src/gui/waveform.h
rename to gui/waveform.h
index 1482e10..c2c2a3d 100644
--- a/src/gui/waveform.h
+++ b/gui/waveform.h
@@ -45,7 +45,7 @@
WAVEFORM_TYPE, WaveformClass))
-
+#define SCROLL_WHEEL_ZOOM_RATIO 1.5
typedef struct _Waveform Waveform;
@@ -85,6 +85,8 @@ void waveform_get_size (Waveform* wf, int* w, int* h);
void waveform_get_range (Waveform* wf, float* start,
float* stop);
+void waveform_zoom(Waveform* wf, float zoom, float center);
+
void waveform_goto_mark_prev (Waveform* wf);
void waveform_goto_mark_next (Waveform* wf);
diff --git a/install-sh b/install-sh
deleted file mode 120000
index 205f21c..0000000
--- a/install-sh
+++ /dev/null
@@ -1 +0,0 @@
-/usr/share/automake-1.11/install-sh
\ No newline at end of file
diff --git a/install_manifest.txt b/install_manifest.txt
new file mode 100644
index 0000000..51e24ec
--- /dev/null
+++ b/install_manifest.txt
@@ -0,0 +1,6 @@
+/usr/local/share/petri-foo/pixmaps/petri-foo.png
+/usr/local/share/petri-foo/pixmaps/petri-foo_small.png
+/usr/local/share/mime/packages/petri-foo.xml
+/usr/local/share/pixmaps/petri-foo.png
+/usr/local/share/applications/petri-foo.desktop
+/usr/local/bin/petri-foo
diff --git a/libpetrifoo/CMakeLists.txt b/libpetrifoo/CMakeLists.txt
new file mode 100644
index 0000000..7f11d83
--- /dev/null
+++ b/libpetrifoo/CMakeLists.txt
@@ -0,0 +1,15 @@
+include_directories ( . )
+
+ADD_SUBDIRECTORY( patch_private )
+
+file (GLOB LIBPETRIFOO_SOURCES *.c)
+
+add_library( petrifoo ${LIBPETRIFOO_SOURCES})
+
+target_link_Libraries( petrifoo patch_private
+ ${JACK_LIBRARIES}
+ ${SNDFILE_LIBRARIES}
+ ${ALSA_LIBRARIES}
+ ${SAMPLERATE_LIBRARIES}
+ )
+
diff --git a/src/adsr.c b/libpetrifoo/adsr.c
similarity index 99%
rename from src/adsr.c
rename to libpetrifoo/adsr.c
index e2cb5b1..09396e5 100644
--- a/src/adsr.c
+++ b/libpetrifoo/adsr.c
@@ -64,7 +64,7 @@ struct _ADSR
void adsr_params_init(ADSRParams* params, float attack, float release)
{
- params->env_on = false;
+ params->active = false;
params->delay = 0.0;
params->attack = attack;
params->decay = 0.0;
diff --git a/src/adsr.h b/libpetrifoo/adsr.h
similarity index 99%
rename from src/adsr.h
rename to libpetrifoo/adsr.h
index 041a073..6519a73 100644
--- a/src/adsr.h
+++ b/libpetrifoo/adsr.h
@@ -49,7 +49,7 @@ typedef enum _ADSRState
/* envelope parameters */
typedef struct _ADSRParams
{
- bool env_on;
+ bool active;
float delay; /* delay length in seconds */
float attack; /* attack length in seconds */
float decay; /* decay length in seconds */
diff --git a/src/driver.c b/libpetrifoo/driver.c
similarity index 77%
rename from src/driver.c
rename to libpetrifoo/driver.c
index 1e9806a..b6cc6c1 100644
--- a/src/driver.c
+++ b/libpetrifoo/driver.c
@@ -30,7 +30,7 @@
#include "ticks.h"
#include "patch_util.h"
-
+#include <assert.h>
#include <strings.h> /* strcasecmp */
@@ -45,7 +45,7 @@ void driver_init(void)
{
int i;
- for (i = 0; drivers[i] != NULL; i++)
+ for (i = 0; drivers[i] != NULL; i++, ndrivers++)
drivers[i]->init();
if ((ndrivers = i) < 0)
@@ -60,8 +60,7 @@ int driver_restart(void)
int driver_start(void)
{
- if (ndrivers <= 0)
- return DRIVER_ERR_OTHER;
+ assert(ndrivers > 0);
if (curdriver >= 0)
drivers[curdriver]->stop();
@@ -103,32 +102,19 @@ const char* driver_get_name(void)
int driver_set_samplerate(int rate)
{
- if (rate <= 0)
- {
- debug ("can't accept samplerate %d\n", rate);
- return DRIVER_ERR_OTHER;
- }
-
- /* tell everybody our (potentially new) samplerate */
- lfo_set_samplerate (rate);
- patch_set_samplerate (rate);
- mixer_set_samplerate (rate);
- ticks_set_samplerate (rate);
+ assert(rate > 0);
+ lfo_set_samplerate(rate);
+ patch_set_samplerate(rate);
+ mixer_set_samplerate(rate);
+ ticks_set_samplerate(rate);
return 0;
}
int driver_set_buffersize(int nframes)
{
- if (nframes <= 0)
- {
- debug ("can't accept buffersize %d\n", nframes);
- return DRIVER_ERR_OTHER;
- }
-
- /* tell everybody our (potentially new) buffersize */
- patch_set_buffersize (nframes);
-
+ assert(nframes > 0);
+ patch_set_buffersize(nframes);
return 0;
}
diff --git a/src/driver.h b/libpetrifoo/driver.h
similarity index 97%
rename from src/driver.h
rename to libpetrifoo/driver.h
index 285b7e2..eed56c6 100644
--- a/src/driver.h
+++ b/libpetrifoo/driver.h
@@ -36,15 +36,6 @@
*/
-enum
-{
- DRIVER_ERR_ID = -1,
- DRIVER_ERR_OTHER = -2
-};
-
-
-
-
/* public class definition for drivers */
typedef struct _Driver
{
@@ -58,6 +49,7 @@ typedef struct _Driver
} Driver;
+
void driver_init (void);
int driver_restart (void);
int driver_start (void);
@@ -67,6 +59,7 @@ int driver_get_count (void);
const char* driver_get_name (void);
const char* driver_get_client_name(void);
+
/* this function should only be called by drivers when they start
* and/or their samplerate changes */
int driver_set_samplerate (int rate);
diff --git a/src/instance.c b/libpetrifoo/instance.c
similarity index 100%
rename from src/instance.c
rename to libpetrifoo/instance.c
diff --git a/src/instance.h b/libpetrifoo/instance.h
similarity index 100%
rename from src/instance.h
rename to libpetrifoo/instance.h
diff --git a/src/jackdriver.c b/libpetrifoo/jackdriver.c
similarity index 84%
rename from src/jackdriver.c
rename to libpetrifoo/jackdriver.c
index 47c09a3..00456d0 100644
--- a/src/jackdriver.c
+++ b/libpetrifoo/jackdriver.c
@@ -32,18 +32,17 @@
#include <jack/midiport.h>
#include <jack/transport.h>
-#ifdef HAVE_JACK_SESSION
+#ifdef HAVE_JACK_SESSION_H
#include <jack/session.h>
-#include "gui/audio-settings.h"
-#endif /* HAVE_JACK_SESSION */
+#endif /* HAVE_JACK_SESSION_H */
-#include <gtk/gtk.h>
#include <pthread.h>
#include "instance.h"
#include "petri-foo.h"
#include "driver.h"
#include "patch.h"
+#include "pf_error.h"
#include "mixer.h"
#include "sync.h"
#include "lfo.h"
@@ -63,8 +62,9 @@ static jack_port_t* lport;
static jack_port_t* rport;
static jack_port_t* midiport;
-#ifdef HAVE_JACK_SESSION
-static jack_session_event_t *session_event;
+#ifdef HAVE_JACK_SESSION_H
+/*static jack_session_event_t *session_event;*/
+JackSessionCallback session_cb = 0;
#endif
static jack_client_t* client;
@@ -75,9 +75,17 @@ static int running = 0;
static pthread_mutex_t running_mutex = PTHREAD_MUTEX_INITIALIZER;
static char* session_uuid = NULL;
+static bool autoconnect = true;
+
/* working together to stop CTS */
typedef jack_default_audio_sample_t jack_sample_t;
+#ifdef HAVE_JACK_SESSION_H
+void jackdriver_set_session_cb(JackSessionCallback jack_session_cb)
+{
+ session_cb = jack_session_cb;
+}
+#endif
static int process(jack_nframes_t frames, void* arg)
{
@@ -113,12 +121,12 @@ static int process(jack_nframes_t frames, void* arg)
if ((last_state == JackTransportStopped)
|| (last_state == JackTransportStarting))
{
- debug ("got transport start\n");
+ //debug ("got transport start\n");
sync_start_jack (new_tempo);
}
else if (new_tempo != last_tempo)
{
- debug ("got tempo change\n");
+ //debug ("got tempo change\n");
sync_start_jack (new_tempo);
}
last_tempo = new_tempo;
@@ -190,7 +198,7 @@ static int buffer_size_change(jack_nframes_t b, void* arg)
if ((new = malloc(sizeof(float) * b * 2)) == NULL)
{
- errmsg("Failed to change buffer size\n");
+ pf_error(PF_ERR_JACK_BUF_SIZE_CHANGE);
stop();
}
@@ -205,7 +213,7 @@ static int buffer_size_change(jack_nframes_t b, void* arg)
/* let the rest of the world know the good news */
driver_set_buffersize (b);
- return 0;
+ return 0;
}
@@ -229,11 +237,11 @@ static int start(void)
const char** ports;
char* instancename = strdup (get_instance_name());
- debug ("Initializing Jack Driver...\n");
+ debug("JACK initializing driver...\n");
pthread_mutex_lock (&running_mutex);
running = 0;
-#ifdef HAVE_JACK_SESSION
+#ifdef HAVE_JACK_SESSION_H
client = jack_client_open(instancename,
JackSessionID, NULL, session_uuid);
#else
@@ -242,7 +250,7 @@ static int start(void)
if (client == 0)
{
- errmsg ("Failed to open new jack client: %s\n", instancename);
+ pf_error(PF_ERR_JACK_OPEN_CLIENT);
pthread_mutex_unlock (&running_mutex);
return -1;
}
@@ -251,19 +259,14 @@ static int start(void)
jack_set_process_callback (client, process, 0);
-#ifdef HAVE_JACK_SESSION
- debug("HAVE JACK SESSION\n");
+#ifdef HAVE_JACK_SESSION_H
+
if (jack_set_session_callback)
{
- debug("setting session callback... ");
-
- if (jack_set_session_callback(client, audio_settings_session_cb, 0))
- {
- printf("fail\n");
- }
- else
+ if (jack_set_session_callback(client, session_cb, 0))
{
- printf("ok\n");
+ pf_error(PF_ERR_JACK_SESSION_CB);
+ return -1;
}
}
#endif
@@ -298,7 +301,7 @@ static int start(void)
if ((buffer = malloc (sizeof (float) * periodsize * 2)) == NULL)
{
- errmsg ("Failed to allocate space for buffer\n");
+ pf_error(PF_ERR_JACK_BUF_ALLOC);
jack_client_close (client);
pthread_mutex_unlock (&running_mutex);
return -1;
@@ -308,7 +311,7 @@ static int start(void)
if (jack_activate(client) != 0)
{
- errmsg ("Failed to activate client\n");
+ pf_error(PF_ERR_JACK_ACTIVATE);
jack_client_close(client);
pthread_mutex_unlock(&running_mutex);
return -1;
@@ -317,29 +320,28 @@ static int start(void)
ports = jack_get_ports(client, NULL, NULL,
JackPortIsInput | JackPortIsPhysical);
- if (ports[0] != NULL)
+ if (autoconnect)
{
- if (jack_connect(client, jack_port_name(lport), ports[0]) != 0)
- errmsg ("Cannot connect left output port\n");
-
- if (ports[1] != NULL)
+ if (ports[0] != NULL)
{
- if (jack_connect(client, jack_port_name (rport), ports[1]))
- errmsg ("Cannot connect right output port\n");
+ if (jack_connect(client, jack_port_name(lport), ports[0]) == 0)
+ debug("JACK failed to connect left output port\n");
+
+ if (ports[1] != NULL)
+ {
+ if (jack_connect(client, jack_port_name (rport), ports[1]))
+ debug("JACK failed to connect right output port\n");
+ }
+ else
+ debug("JACK failed to connect right output port\n");
+
+ free (ports);
}
else
- {
- errmsg ("Cannot connect right output port\n");
- }
-
- free (ports);
- }
- else
- {
- errmsg ("Cannot connect output ports\n");
+ debug("JACK failed to connect output ports\n");
}
- debug ("Initialization complete\n");
+ debug("JACK Initialization complete\n");
running = 1;
pthread_mutex_unlock (&running_mutex);
@@ -353,18 +355,12 @@ static int stop(void)
if (running)
{
- debug ("Shutting down...\n");
+ debug("JACK shutting down...\n");
jack_deactivate (client);
jack_client_close (client);
if (buffer != NULL)
free (buffer);
-
- debug ("Shutdown complete\n");
- }
- else
- {
- debug ("Not running, so not shutting down\n");
}
running = 0;
@@ -394,6 +390,13 @@ static void* getid(void)
return (void*)jack_get_client_name(client);
}
+
+void jackdriver_set_unconnected(void)
+{
+ autoconnect = false;
+}
+
+
void jackdriver_set_uuid (char *uuid)
{
session_uuid = uuid;
diff --git a/src/jackdriver.h b/libpetrifoo/jackdriver.h
similarity index 84%
rename from src/jackdriver.h
rename to libpetrifoo/jackdriver.h
index 03eb3ca..aef5c54 100644
--- a/src/jackdriver.h
+++ b/libpetrifoo/jackdriver.h
@@ -29,9 +29,16 @@
#include <jack/jack.h>
+#ifdef HAVE_JACK_SESSION_H
+#include <jack/session.h>
+void jackdriver_set_session_cb(JackSessionCallback jacksession_cb);
+#endif
+
+void jackdriver_set_unconnected(void);
void jackdriver_set_uuid(char *uuid);
jack_client_t* jackdriver_get_client(void);
+
#endif /* __JACKDRIVER_H__ */
diff --git a/src/lfo.c b/libpetrifoo/lfo.c
similarity index 98%
rename from src/lfo.c
rename to libpetrifoo/lfo.c
index bda6278..d40e9fc 100644
--- a/src/lfo.c
+++ b/libpetrifoo/lfo.c
@@ -86,7 +86,7 @@ inline static void lfo_phase_inc_from_beats (LFO* lfo, float beats)
void lfo_params_init(LFOParams* lfopar, float freq, LFOShape shape)
{
- lfopar->lfo_on = false;
+ lfopar->active = false;
lfopar->shape = shape;
lfopar->freq = freq;
lfopar->sync_beats = 1.0;
@@ -196,7 +196,7 @@ void lfo_set_tempo(float bpm)
}
-void lfo_rigger(LFO* lfo, LFOParams* params)
+void lfo_update_params(LFO* lfo, LFOParams* params)
{
lfo->positive = params->positive;
@@ -237,7 +237,7 @@ void lfo_rigger(LFO* lfo, LFOParams* params)
void lfo_trigger(LFO* lfo, LFOParams* params)
{
- lfo_rigger(lfo, params);
+ lfo_update_params(lfo, params);
lfo->phase = 0;
lfo->val = 0;
}
diff --git a/src/lfo.h b/libpetrifoo/lfo.h
similarity index 96%
rename from src/lfo.h
rename to libpetrifoo/lfo.h
index 8d9ab6a..867bac8 100644
--- a/src/lfo.h
+++ b/libpetrifoo/lfo.h
@@ -58,7 +58,7 @@ typedef enum
typedef struct _LFOParams
{
- bool lfo_on;
+ bool active;
LFOShape shape;
float freq; /* frequency in hz */
float sync_beats;
@@ -106,9 +106,7 @@ void lfo_init(LFO*);
* after the samplerate/tempo changes in order for those changes to
* take effect */
void lfo_trigger(LFO*, LFOParams*);
-
-/* like lfo_trigger except it don't reset phase */
-void lfo_rigger(LFO*, LFOParams*);
+void lfo_update_params(LFO*, LFOParams*);
/* advance an LFO and return its new value */
float lfo_tick(LFO*);
diff --git a/src/maths.c b/libpetrifoo/maths.c
similarity index 100%
rename from src/maths.c
rename to libpetrifoo/maths.c
diff --git a/src/maths.h b/libpetrifoo/maths.h
similarity index 100%
rename from src/maths.h
rename to libpetrifoo/maths.h
diff --git a/src/midi.c b/libpetrifoo/midi.c
similarity index 100%
rename from src/midi.c
rename to libpetrifoo/midi.c
diff --git a/src/midi.h b/libpetrifoo/midi.h
similarity index 100%
rename from src/midi.h
rename to libpetrifoo/midi.h
diff --git a/src/midi_control.h b/libpetrifoo/midi_control.h
similarity index 100%
rename from src/midi_control.h
rename to libpetrifoo/midi_control.h
diff --git a/src/mixer.c b/libpetrifoo/mixer.c
similarity index 99%
rename from src/mixer.c
rename to libpetrifoo/mixer.c
index b0600c5..0288a7e 100644
--- a/src/mixer.c
+++ b/libpetrifoo/mixer.c
@@ -198,7 +198,6 @@ void mixer_flush(void)
/* constructor */
void mixer_init(void)
{
- int p, c;
debug ("initializing...\n");
amplitude = DEFAULT_AMPLITUDE;
pthread_mutex_init (&preview.mutex, NULL);
diff --git a/src/mixer.h b/libpetrifoo/mixer.h
similarity index 100%
rename from src/mixer.h
rename to libpetrifoo/mixer.h
diff --git a/src/mod_src.c b/libpetrifoo/mod_src.c
similarity index 99%
rename from src/mod_src.c
rename to libpetrifoo/mod_src.c
index e09e94d..11d4db0 100644
--- a/src/mod_src.c
+++ b/libpetrifoo/mod_src.c
@@ -262,8 +262,6 @@ int mod_src_id(const char* name, int mask)
{
id_name* ids;
- debug("identifying %s\n", name);
-
if (strcmp(name, "OFF") == 0)
return MOD_SRC_NONE;
diff --git a/src/mod_src.h b/libpetrifoo/mod_src.h
similarity index 100%
copy from src/mod_src.h
copy to libpetrifoo/mod_src.h
diff --git a/src/names.c b/libpetrifoo/names.c
similarity index 99%
rename from src/names.c
rename to libpetrifoo/names.c
index 4f14a04..b7c8ba6 100644
--- a/src/names.c
+++ b/libpetrifoo/names.c
@@ -103,7 +103,6 @@ id_name* id_name_sequence(id_name* start, int first_id, int count,
int n;
const int blen = 40;
char buf[blen];
- id_name* idnames = start;
for (i = 0; i < count; ++i)
{
diff --git a/src/names.h b/libpetrifoo/names.h
similarity index 100%
rename from src/names.h
rename to libpetrifoo/names.h
diff --git a/src/patch.c b/libpetrifoo/patch.c
similarity index 88%
rename from src/patch.c
rename to libpetrifoo/patch.c
index 55cf361..b140e39 100644
--- a/src/patch.c
+++ b/libpetrifoo/patch.c
@@ -58,7 +58,7 @@ static float cc[16][CC_ARR_SIZE];
/* inline definitions shared by patch and patch_util:
* (see private/patch_data.h)
*/
-INLINE_ISOK_DEF
+INLINE_PATCHOK_DEF
INLINE_PATCH_LOCK_DEF
INLINE_PATCH_TRYLOCK_DEF
INLINE_PATCH_UNLOCK_DEF
@@ -158,7 +158,7 @@ inline static void patch_release_patch(Patch* p, int note, release_t mode)
/* we don't really release here, that's the job of
* advance( ); we just tell it *when* to release */
p->voices[i]->relmode = mode;
- p->voices[i]->relset = (p->mono && p->legato)
+ p->voices[i]->relset = (p->mono && p->voices[i]->legato)
? patch_legato_lag
: 0;
}
@@ -197,25 +197,27 @@ inline static void prepare_pitch(Patch* p, PatchVoice* v, int note)
/* this applies the tuning factor */
scale = pow(2, (p->pitch.val * p->pitch_steps) / 12.0);
- if (p->porta && (p->porta_secs > 0.0) && (p->last_note != note))
+ if (v->portamento
+ && (v->porta_secs > 0.0)
+ && (p->last_note != note))
{
/* we calculate the pitch here because we can't be certain
* what the current value of the last voice's pitch is */
v->pitch =
- pow(2, (p->last_note - p->note) * p->pitch.key_amt / 12.0);
+ pow(2, (p->last_note - p->root_note) * p->pitch.key_amt / 12.0);
v->pitch *= scale;
- v->porta_ticks = ticks_secs_to_ticks (p->porta_secs);
+ v->porta_ticks = ticks_secs_to_ticks(v->porta_secs);
/* calculate the value to be added to pitch each tick by
* subtracting the target pitch from the initial pitch and
* dividing by porta_ticks */
v->pitch_step =
- ((pow(2, (note - p->note) * p->pitch.key_amt / 12.0)
+ ((pow(2, (note - p->root_note) * p->pitch.key_amt / 12.0)
* scale) - v->pitch) / v->porta_ticks;
}
else
{
- v->pitch = pow(2, (note - p->note) * p->pitch.key_amt / 12.0);
+ v->pitch = pow(2, (note - p->root_note) * p->pitch.key_amt / 12.0);
v->pitch *= scale;
v->porta_ticks = 0;
}
@@ -232,6 +234,26 @@ inline static void prepare_pitch(Patch* p, PatchVoice* v, int note)
}
+inline static bool patch_bool_get(PatchBool* pb, Patch* p)
+{
+ const float* mod = patch_mod_id_to_pointer(pb->mod_id, p, NULL);
+ return (pb->active && pb->mod_id) ? (*mod > pb->thresh) : pb->active;
+}
+
+inline static float patch_float_get(PatchFloat* pf, Patch* p)
+{
+ float value = pf->val;
+
+ if (pf->mod_id)
+ {
+ const float* mod = patch_mod_id_to_pointer(pf->mod_id, p, NULL);
+ value += *mod * pf->mod_amt;
+ }
+
+ return value;
+}
+
+
/**************************************************************************
********************* PATCH TRIGGER PATCH ***********************
**************************************************************************/
@@ -244,6 +266,7 @@ patch_trigger_patch (Patch* p, int note, float vel, Tick ticks)
PatchVoice* v;
int index; /* the index we ended up settling on */
float key_track;
+ bool legato;
if (p->sample->sp == NULL)
return;
@@ -254,7 +277,9 @@ patch_trigger_patch (Patch* p, int note, float vel, Tick ticks)
key_track = (float)(note - p->lower_note)
/ (p->upper_note - p->lower_note);
- if (p->mono && p->legato)
+ legato = patch_bool_get(&p->legato, p);
+
+ if (p->mono && legato)
{
/* half of the previous logic operating here was ignored.
* removing it left only logic which could be simplified
@@ -268,6 +293,7 @@ patch_trigger_patch (Patch* p, int note, float vel, Tick ticks)
v->vel = vel;
else
{
+ /* don't trigger voice, do legato instead: */
v->ticks = ticks;
v->note = note;
v->vel = vel;
@@ -278,9 +304,9 @@ patch_trigger_patch (Patch* p, int note, float vel, Tick ticks)
v->xfade = false;
v->loop = p->play_mode & PATCH_PLAY_LOOP;
v->key_track = key_track;
-
+ v->portamento = patch_bool_get(&p->porta, p);
+ v->porta_secs = patch_float_get(&p->porta_secs, p);
prepare_pitch(p, v, note);
-
return;
}
}
@@ -323,8 +349,11 @@ patch_trigger_patch (Patch* p, int note, float vel, Tick ticks)
v->loop = p->play_mode & PATCH_PLAY_LOOP;
v->note = note;
v->key_track = key_track;
+ v->legato = legato;
+ v->portamento = patch_bool_get(&p->porta, p);
+ v->porta_secs = patch_float_get(&p->porta_secs, p);
- if (!(p->mono && p->legato))
+ if (!(p->mono && v->legato))
v->vel = vel;
if (!p->mono)
@@ -332,21 +361,21 @@ patch_trigger_patch (Patch* p, int note, float vel, Tick ticks)
for (i = 0; i < MAX_MOD_SLOTS; ++i)
{
- v->vol_mod[i] = patch_mod_id_to_pointer(p->vol.mod_id[i], p, v);
+ v->amp_mod[i] = patch_mod_id_to_pointer(p->amp.mod_id[i], p, v);
v->pan_mod[i] = patch_mod_id_to_pointer(p->pan.mod_id[i], p, v);
v->ffreq_mod[i] = patch_mod_id_to_pointer(p->ffreq.mod_id[i], p, v);
v->freso_mod[i] = patch_mod_id_to_pointer(p->freso.mod_id[i], p, v);
v->pitch_mod[i] = patch_mod_id_to_pointer(p->pitch.mod_id[i], p, v);
}
- if (!(p->mono && p->legato && v->active))
+ if (!(p->mono && v->legato && v->active))
playstate_init_fade_in(p, v);
prepare_pitch(p, v, note);
for (i = 0; i < VOICE_MAX_ENVS; i++)
{
- if (p->env_params[i].env_on)
+ if (p->env_params[i].active)
{
adsr_set_params(v->env[i], &p->env_params[i]);
adsr_trigger(v->env[i], key_track, vel);
@@ -355,7 +384,7 @@ patch_trigger_patch (Patch* p, int note, float vel, Tick ticks)
for (i = 0; i < VOICE_MAX_LFOS; i++)
{
- if (p->vlfo_params[i].lfo_on)
+ if (p->vlfo_params[i].active)
{
float const* src;
@@ -473,7 +502,10 @@ pan (Patch * p, PatchVoice * v, int index, float *l, float *r)
pan += *v->pan_mod[i] * p->pan.mod_amt[i];
/* scale for velocity tracking */
- pan = lerp(pan, pan * v->vel, p->pan.vel_amt);
+ if (p->pan.vel_amt < 0)
+ pan = lerp(pan, pan * (1.0 - v->vel), p->pan.vel_amt * -1);
+ else
+ pan = lerp(pan, pan * v->vel, p->pan.vel_amt);
/* scale for key tracking */
if (p->pan.key_amt < 0)
@@ -514,7 +546,11 @@ filter (Patch* p, PatchVoice* v, int index, float* l, float* r)
ffreq += *v->ffreq_mod[i] * p->ffreq.mod_amt[i];
/* scale to velocity */
- ffreq = lerp (ffreq, ffreq * v->vel, p->ffreq.vel_amt);
+ if (p->ffreq.vel_amt < 0)
+ ffreq = lerp(ffreq, ffreq * (1.0 - v->vel), p->ffreq.vel_amt * -1);
+ else
+ ffreq = lerp(ffreq, ffreq * v->vel, p->ffreq.vel_amt);
+
/* scale for key tracking */
if (p->ffreq.key_amt < 0)
@@ -538,7 +574,10 @@ filter (Patch* p, PatchVoice* v, int index, float* l, float* r)
freso += *v->freso_mod[i] * p->freso.mod_amt[i];
/* scale to velocity */
- freso = lerp(freso, freso * v->vel, p->freso.vel_amt);
+ if (p->freso.vel_amt < 0)
+ freso = lerp(freso, freso * (1.0 - v->vel), p->freso.vel_amt * -1);
+ else
+ freso = lerp(freso, freso * v->vel, p->freso.vel_amt);
/* scale for key tracking */
if (p->freso.key_amt < 0)
@@ -554,16 +593,16 @@ filter (Patch* p, PatchVoice* v, int index, float* l, float* r)
else if (freso < 0.0)
freso = 0.0;
- /* logify */
- logreso = log_amplitude(freso);
+ /* logify - seems better without this:
+ logreso = log_amplitude(freso); */
/* left */
- v->fbl = logreso * v->fbl + ffreq * (*l - v->fll);
+ v->fbl = freso * v->fbl + ffreq * (*l - v->fll);
v->fll += ffreq * v->fbl;
*l = v->fll;
/* right */
- v->fbr = logreso * v->fbr + ffreq * (*r - v->flr);
+ v->fbr = freso * v->fbr + ffreq * (*r - v->flr);
v->flr += ffreq * v->fbr;
*r = v->flr;
}
@@ -574,56 +613,60 @@ inline static int
gain (Patch* p, PatchVoice* v, int index, float* l, float* r)
{
int i;
- float vol = 0.0;
- float logvol = 0.0;
+ float amp = 0.0;
+ float logamp = 0.0;
/* first, we use our set value as a base */
- vol = p->vol.val;
+ amp = p->amp.val;
for (i = 0; i < EG_MOD_SLOT; ++i)
- if (v->vol_mod[i] != NULL)
- vol += *v->vol_mod[i] * p->vol.mod_amt[i];
+ if (v->amp_mod[i] != NULL)
+ amp += *v->amp_mod[i] * p->amp.mod_amt[i];
/* direct modulation source (ie no amount) */
- if (v->vol_mod[EG_MOD_SLOT])
- vol *= *v->vol_mod[EG_MOD_SLOT];
+ if (v->amp_mod[EG_MOD_SLOT])
+ amp *= *v->amp_mod[EG_MOD_SLOT];
/* scale for key tracking */
- if (p->vol.key_amt < 0)
- vol = lerp(vol, vol * (1.0 - v->key_track), p->vol.key_amt * -1);
+ if (p->amp.key_amt < 0)
+ amp = lerp(amp, amp * (1.0 - v->key_track), p->amp.key_amt * -1);
else
- vol = lerp(vol, vol * v->key_track, p->vol.key_amt);
+ amp = lerp(amp, amp * v->key_track, p->amp.key_amt);
/* velocity should be the last parameter considered because it
* has the most "importance" */
- vol = lerp(vol, vol * v->vel, p->vol.vel_amt);
+ if (p->amp.vel_amt < 0)
+ amp = lerp(amp, amp * (1.0 - v->vel), p->amp.vel_amt * -1);
+ else
+ amp = lerp(amp, amp * v->vel, p->amp.vel_amt);
+
/* apply fade in/out */
- vol *= v->fade_declick;
+ amp *= v->fade_declick;
/* clip */
- if (vol > 1.0)
- vol = 1.0;
- else if (vol < 0.0)
- vol = 0.0;
+ if (amp > 1.0)
+ amp = 1.0;
+ else if (amp < 0.0)
+ amp = 0.0;
/* as a last step, make logarithmic */
-/* logvol = log_amplitude(vol);
+/* logamp = log_amplitude(amp);
*/
/* adjust amplitude */
- *l *= vol;
- *r *= vol;
+ *l *= amp;
+ *r *= amp;
/*
- *l *= logvol;
- *r *= logvol;
+ *l *= logamp;
+ *r *= logamp;
*/
/* check to see if we've finished a release */
if (v->released && (v->fade_declick == 0.0f //< ALMOST_ZERO
- || (v->vol_mod[EG_MOD_SLOT]
- && *v->vol_mod[EG_MOD_SLOT] < ALMOST_ZERO)))
+ || (v->amp_mod[EG_MOD_SLOT]
+ && *v->amp_mod[EG_MOD_SLOT] < ALMOST_ZERO)))
{
return -1;
}
@@ -681,7 +724,7 @@ inline static int advance (Patch* p, PatchVoice* v, int index)
/* whether we need to recalculate our pos/step vars */
/* portamento */
- if (p->porta && v->porta_ticks)
+ if (v->portamento && v->porta_ticks)
{
recalc = true;
v->pitch += v->pitch_step;
@@ -723,6 +766,11 @@ inline static int advance (Patch* p, PatchVoice* v, int index)
recalc = true;
pitch = lerp (pitch, pitch * v->vel, p->pitch.vel_amt);
}
+ else if (p->pitch.vel_amt < -ALMOST_ZERO)
+ {
+ recalc = true;
+ pitch = lerp (pitch, pitch * (1.0 - v->vel), -p->pitch.vel_amt);
+ }
if (recalc)
{
@@ -855,7 +903,7 @@ inline static int advance (Patch* p, PatchVoice* v, int index)
if (!(p->play_mode & PATCH_PLAY_SINGLESHOT))
{
- if (!v->vol_mod[EG_MOD_SLOT]) /* direct mod source */
+ if (!v->amp_mod[EG_MOD_SLOT]) /* direct mod source */
{
playstate_init_fade_out(p, v);
}
@@ -915,7 +963,7 @@ inline static void patch_render_patch (Patch* p, float* buf, int nframes)
{
for (j = 0; j < PATCH_MAX_LFOS; ++j)
{
- if (p->glfo_params[j].lfo_on)
+ if (p->glfo_params[j].active)
p->glfo_table[j][i] = lfo_tick(p->glfo[j]);
}
}
@@ -944,15 +992,15 @@ inline static void patch_render_patch (Patch* p, float* buf, int nframes)
the correct value for the frame.
*/
for (k = 0; k < PATCH_MAX_LFOS; ++k)
- if (p->glfo_params[k].lfo_on)
+ if (p->glfo_params[k].active)
lfo_set_output(p->glfo[k], p->glfo_table[k][j]);
for (k = 0; k < VOICE_MAX_ENVS; ++k)
- if (p->env_params[k].env_on)
+ if (p->env_params[k].active)
adsr_tick(v->env[k]);
for (k = 0; k < VOICE_MAX_LFOS; ++k)
- if (p->vlfo_params[k].lfo_on)
+ if (p->vlfo_params[k].active)
lfo_tick(v->lfo[k]);
/* process samples */
@@ -1056,7 +1104,7 @@ void patch_render (float *buf, int nframes)
/* triggers all patches matching criteria */
void patch_trigger (int chan, int note, float vel, Tick ticks)
{
- static int idp[PATCH_COUNT]; /* holds all patches to be activated */
+ static int idp[PATCH_COUNT]; /* holds all patches to be activated */
int i, j;
/* We gather up all of the patches that need to be activated here
@@ -1066,14 +1114,16 @@ void patch_trigger (int chan, int note, float vel, Tick ticks)
* the same note and have the same cut/cut_by values will end up
* stepping over each other before they both are heard.
*/
-
+ int int_vel = (int)(vel * 127.0);
for (i = j = 0; i < PATCH_COUNT; i++)
{
if (patches[i]
&& patches[i]->active
&& patches[i]->channel == chan
&& (note >= patches[i]->lower_note
- && note <= patches[i]->upper_note))
+ && note <= patches[i]->upper_note)
+ && (int_vel >= patches[i]->lower_vel
+ && int_vel <= patches[i]->upper_vel))
{
idp[j++] = i;
}
@@ -1085,7 +1135,9 @@ void patch_trigger (int chan, int note, float vel, Tick ticks)
/* do triggers */
for (i = 0; i < j; i++)
+ {
patch_trigger_patch(patches[idp[i]], note, vel, ticks);
+ }
}
@@ -1107,47 +1159,6 @@ void patch_trigger_with_id (int id, int note, float vel, Tick ticks)
}
-static void patch_control_patch(Patch* p, int param, float value)
-{
-/*
- switch( param )
- {
- case CONTROL_PARAM_MODWHEEL:
- break;
- case CONTROL_PARAM_AMPLITUDE:
- p->vol.val = value;
- break;
- case CONTROL_PARAM_PANNING:
- p->pan.val = value;
- break;
- case CONTROL_PARAM_CUTOFF:
- p->ffreq.val = value;
- break;
- case CONTROL_PARAM_RESONANCE:
- p->freso.val = value;
- break;
- case CONTROL_PARAM_PITCH:
- p->pitch_bend = pow(2, value);
- break;
- case CONTROL_PARAM_PORTAMENTO:
- p->porta = (value < 0.5) ? 0 : 1;
- break;
- case CONTROL_PARAM_PORTAMENTO_TIME:
- p->porta_secs = value;
- break;
- case CONTROL_PARAM_CUTOFF_MOD1_AMT:
- p->ffreq.mod1_amt = value;
- break;
- case CONTROL_PARAM_RESO_MOD1_AMT:
- p->freso.mod1_amt = value;
- break;
- default:
- break;
- }
-*/
-}
-
-
void patch_control_init(void)
{
int c, p;
@@ -1168,20 +1179,9 @@ void patch_control_init(void)
void patch_control(int chan, int param, float value)
{
- int i;
-
+ /* FIXME: this could probably be put back into mixer and
+ a function call could be saved ?
+ */
cc[chan][1 + param] = value;
-
- for (i = 0; i < PATCH_COUNT; i++)
- {
- if (patches[i]
- && patches[i]->active
- && patches[i]->channel == chan)
- {
- patch_control_patch(patches[i], param, value);
- }
- }
-
- return;
}
diff --git a/src/patch.h b/libpetrifoo/patch.h
similarity index 80%
rename from src/patch.h
rename to libpetrifoo/patch.h
index fa965f6..6b9c4c4 100644
--- a/src/patch.h
+++ b/libpetrifoo/patch.h
@@ -111,52 +111,33 @@ typedef enum _MOD_SRC_ID_BITMASK
} mod_src_id_bitmask;
-/* error codes */
-enum
-{
-/* PATCH_PARAM_INVALID = -1, */
- PATCH_ID_INVALID = -2,
- PATCH_ALLOC_FAIL = -3,
- PATCH_NOTE_INVALID = -4,
- PATCH_PAN_INVALID = -5,
- PATCH_CHANNEL_INVALID = -6,
- PATCH_VOL_INVALID = -7,
- PATCH_PLAY_MODE_INVALID = -9,
- PATCH_LIMIT = -10,
- PATCH_SAMPLE_INDEX_INVALID = -11,
- PATCH_ENV_ID_INVALID = -12,
- PATCH_LFO_ID_INVALID = -13,
- PATCH_MOD_SRC_INVALID = -14,
- PATCH_MOD_AMOUNT_INVALID = -15,
- PATCH_MOD_SLOT_INVALID
-};
-
-
/* These are the bitfield constants for the different ways a patch can
be played. I've used comments to indicate mutual exclusion among
groups. */
+
+/* note: i dislike this setup, not the use of bitfields per se...
+ */
+
enum
{
/* direction */
- PATCH_PLAY_FORWARD = 1 << 0,
- PATCH_PLAY_REVERSE = 1 << 1,
- /************/
+ PATCH_PLAY_REVERSE = 0x0001, /* if not reverse then what!?!? */
/* duration */
- PATCH_PLAY_SINGLESHOT = 1 << 2,
- PATCH_PLAY_TRIM = 1 << 3,
- PATCH_PLAY_LOOP = 1 << 4,
- /***********/
+ PATCH_PLAY_SINGLESHOT = 0x0002,
+ PATCH_PLAY_TRIM = 0x0004,
+ PATCH_PLAY_LOOP = 0x0008,
/* ping pong mode can be set independently of all the other
- * params, but it should only be tested for if PATCH_PLAY_LOOP is set */
- PATCH_PLAY_PINGPONG = 1 << 5,
+ * params, but it should only be tested for if PATCH_PLAY_LOOP is set
+ */
+ PATCH_PLAY_PINGPONG = 0x0010,
/* patch play to end should only be tested for if PATCH_PLAY_LOOP is
set. if active, after note_off, playback continues past loop end
toward sample end
*/
- PATCH_PLAY_TO_END = 1 << 6,
+ PATCH_PLAY_TO_END = 0x0020,
};
@@ -178,8 +159,8 @@ typedef uint8_t PatchPlayMode;
/* code names for modulatable parameters */
typedef enum
{
- PATCH_PARAM_INVALID = -1,
- PATCH_PARAM_AMPLITUDE = 0,
+ PATCH_PARAM_INVALID = -1,
+ PATCH_PARAM_AMPLITUDE = 0,
PATCH_PARAM_PANNING,
PATCH_PARAM_PITCH,
PATCH_PARAM_CUTOFF,
@@ -188,6 +169,25 @@ typedef enum
} PatchParamType;
+typedef enum
+{
+ PATCH_BOOL_INVALID = -1,
+ PATCH_BOOL_PORTAMENTO = 0,
+ PATCH_BOOL_MONO,
+ PATCH_BOOL_LEGATO,
+
+} PatchBoolType;
+
+
+typedef enum
+{
+ PATCH_FLOAT_INVALID = -1,
+ PATCH_FLOAT_PORTAMENTO_TIME = 0
+
+} PatchFloatType;
+
+
+
void patch_control_init (void);
/* playback and rendering functions */
diff --git a/src/ticks.c b/libpetrifoo/patch_event.c
similarity index 65%
copy from src/ticks.c
copy to libpetrifoo/patch_event.c
index fdae58e..b6c27dc 100644
--- a/src/ticks.c
+++ b/libpetrifoo/patch_event.c
@@ -1,7 +1,5 @@
/* Petri-Foo is a fork of the Specimen audio sampler.
- Original Specimen author Pete Bessman
- Copyright 2005 Pete Bessman
Copyright 2011 James W. Morris
This file is part of Petri-Foo.
@@ -17,27 +15,40 @@
You should have received a copy of the GNU General Public License
along with Petri-Foo. If not, see <http://www.gnu.org/licenses/>.
-
- This file is a derivative of a Specimen original, modified 2011
*/
-#include <sys/time.h>
-#include "petri-foo.h"
-#include "driver.h"
-#include "ticks.h"
+#include "patch_event.h"
+#include "patch_private/patch_event_data.h"
-static int samplerate = -1;
-Tick ticks_secs_to_ticks (float secs)
+int patch_event_set(int patch_id, EvType evtype, ...)
{
- return samplerate * secs;
}
-void ticks_set_samplerate (int rate)
+BaseEvent* patch_event_get(int patch_id, EvType evtype, ...)
{
- samplerate = rate;
}
+
+
+
+/* assertions on these to make sure correct type used */
+bool base_event_get_bool(BaseEvent* ev)
+{
+}
+
+
+float base_event_get_float(BaseEvent* ev)
+{
+}
+
+
+int base_event_get_int(BaseEvent* ev)
+{
+}
+
+
+
diff --git a/libpetrifoo/patch_event.h b/libpetrifoo/patch_event.h
new file mode 100644
index 0000000..3a3b04e
--- /dev/null
+++ b/libpetrifoo/patch_event.h
@@ -0,0 +1,115 @@
+/* Petri-Foo is a fork of the Specimen audio sampler.
+
+ Copyright 2011 James W. Morris
+
+ This file is part of Petri-Foo.
+
+ Petri-Foo is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+
+ Petri-Foo is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Petri-Foo. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#ifndef PATCH_EVENT_H
+#define PATCH_EVENT_H
+
+
+#include <stdbool.h>
+
+
+typedef enum _EventType
+{
+ EV_TYPE_EG, /* patch_id, eg_id, var_id */
+ EV_TYPE_LFO, /* patch_id, lfo_id, var_id */
+ EV_TYPE_LFO_AM, /* patch_id, lfo_id, AM slot_id, var_id */
+ EV_TYPE_LFO_FM, /* patch_id, lfo_id, FM slot_id, var_id */
+ EV_TYPE_MAIN, /* patch_id, var_id */
+ EV_TYPE_MARK, /* patch_id, mark_id */
+
+} EvType;
+
+
+
+enum
+{
+ EV_INVALID_EVENT = -1,
+
+ /* bool settings */
+ EV__ACTIVE,
+ EV__LEGATO,
+ EV__MONO,
+ EV__ON,
+ EV__PORTAMENTO,
+ EV__POSITIVE,
+ EV__SYNC,
+
+ /* char settings */
+ EV__NAME,
+
+ /* float settings */
+ EV__AMPLITUDE,
+ EV__ASSIGN,
+ EV__ATTACK,
+ EV__CUTOFF,
+ EV__DECAY,
+ EV__DELAY,
+ EV__FREQ,
+ EV__HOLD,
+ EV__KEY_AMT,
+ EV__MOD_AMT,
+ EV__PAN,
+ EV__PORTAMENTO_TIME,
+ EV__PITCH,
+ EV__RELEASE,
+ EV__RESONANCE,
+ EV__SUSTAIN,
+ EV__SYNC_BEATS,
+ EV__THRESH,
+ EV__VALUE,
+ EV__VEL_AMT,
+
+ /* int settings */
+ EV__CHANNEL,
+ EV__CUT,
+ EV__CUT_BY,
+ EV__FADE_SAMPLES,
+ EV__LFO_SHAPE,
+ EV__LOOP_START,
+ EV__LOOP_STOP,
+ EV__LOWER_NOTE,
+ EV__LOWER_VEL,
+ EV__MOD_SRC,
+ EV__PITCH_STEPS,
+ EV__PLAY_MODE,
+ EV__PLAY_START,
+ EV__PLAY_STOP,
+ EV__ROOT_NOTE,
+ EV__UPPER_NOTE,
+ EV__UPPER_VEL,
+ EV__XFADE_SAMPLES,
+
+ EV_LAST_EVENT_XXX
+};
+
+
+
+typedef struct _BaseEvent BaseEvent;
+
+
+int patch_event_set( int patch_id, EvType, ...);
+BaseEvent* patch_event_get( int patch_id, EvType, ...);
+
+/* assertions on these to make sure correct type used */
+bool base_event_get_bool( BaseEvent*);
+float base_event_get_float( BaseEvent*);
+int base_event_get_int( BaseEvent*);
+
+#endif
diff --git a/libpetrifoo/patch_private/CMakeLists.txt b/libpetrifoo/patch_private/CMakeLists.txt
new file mode 100644
index 0000000..271952b
--- /dev/null
+++ b/libpetrifoo/patch_private/CMakeLists.txt
@@ -0,0 +1,2 @@
+file (GLOB LIBPATCHPRIVATE_SOURCES *.c)
+add_library( patch_private ${LIBPATCHPRIVATE_SOURCES})
diff --git a/src/patch_private/patch_data.c b/libpetrifoo/patch_private/patch_data.c
similarity index 85%
rename from src/patch_private/patch_data.c
rename to libpetrifoo/patch_private/patch_data.c
index 345757a..6b2e883 100644
--- a/src/patch_private/patch_data.c
+++ b/libpetrifoo/patch_private/patch_data.c
@@ -50,16 +50,22 @@ Patch* patch_new(void)
p->name[0] = '\0';
- p->active = true;
+ p->active = false;
p->sample = sample_new();
p->display_index = -1;
+
+ p->name[0] = '\0';
+
p->channel = 0;
- p->note = 60;
+ p->root_note = 60;
p->lower_note = 60;
p->upper_note = 60;
+ p->lower_vel = 0;
+ p->upper_vel = 127;
p->cut = 0;
p->cut_by = 0;
+
p->play_start = 0;
p->play_stop = 0;
p->loop_start = 0;
@@ -75,19 +81,30 @@ Patch* patch_new(void)
p->fade_samples = 0;
p->xfade_samples = 0;
- p->porta = false;
- p->porta_secs = 0.05;
+
+ p->porta.active = true; /* but only if PORTAMENTO */
+ p->porta.thresh = 0.5; /* controller says so... */
+ p->porta.mod_id = MOD_SRC_MIDI_CC + CC_PORTAMENTO;
+
+ p->porta_secs.val = 0.05;
+ p->porta_secs.mod_amt = 1.0;
+ p->porta_secs.mod_id = MOD_SRC_MIDI_CC + CC_PORTAMENTO_TIME;
+
p->pitch_steps = 2;
p->pitch_bend = 0;
- p->mono = false;
- p->legato = false;
- p->play_mode = PATCH_PLAY_SINGLESHOT | PATCH_PLAY_FORWARD;
+ p->mono = false;
+
+ p->legato.active = true; /* but only if mono is on, *AND* */
+ p->legato.thresh = 0.5; /* LEGATO controller says so... */
+ p->legato.mod_id = MOD_SRC_MIDI_CC + CC_LEGATO;
+
+ p->play_mode = PATCH_PLAY_SINGLESHOT;
for (i = 0; i < MAX_MOD_SLOTS; ++i)
{
- p->vol.mod_id[i] = MOD_SRC_NONE;
- p->vol.mod_amt[i] = 0.0;
+ p->amp.mod_id[i] = MOD_SRC_NONE;
+ p->amp.mod_amt[i] = 0.0;
p->pan.mod_id[i] = MOD_SRC_NONE;
p->pan.mod_amt[i] = 0.0;
@@ -105,9 +122,9 @@ Patch* patch_new(void)
p->mod_pitch_max[i] = 1.0;
}
- p->vol.val = DEFAULT_AMPLITUDE;
- p->vol.vel_amt = 1.0;
- p->vol.key_amt = 0.0;
+ p->amp.val = DEFAULT_AMPLITUDE;
+ p->amp.vel_amt = 1.0;
+ p->amp.key_amt = 0.0;
p->pan.val = 0.0;
p->pan.vel_amt = 0;
@@ -222,15 +239,15 @@ float const* patch_mod_id_to_pointer(int id, Patch* p, PatchVoice* v)
{
switch(id)
{
- case MOD_SRC_NONE: return 0;
+ case MOD_SRC_NONE: return NULL;
case MOD_SRC_ONE: return &one;
- case MOD_SRC_VELOCITY: return &v->vel;
- case MOD_SRC_KEY: return &v->key_track;
+ case MOD_SRC_VELOCITY: return (v) ? &v->vel : NULL;
+ case MOD_SRC_KEY: return (v) ? &v->key_track : NULL;
case MOD_SRC_PITCH_WHEEL:
return &((*cc_arr)[p->channel][0]);
}
- if (id & MOD_SRC_EG)
+ if (id & MOD_SRC_EG && v)
{
id &= ~MOD_SRC_EG;
@@ -238,7 +255,7 @@ float const* patch_mod_id_to_pointer(int id, Patch* p, PatchVoice* v)
return adsr_output(v->env[id]);
}
- if (id & MOD_SRC_VLFO)
+ if (id & MOD_SRC_VLFO && v)
{
id &= ~MOD_SRC_VLFO;
@@ -270,14 +287,14 @@ void patch_copy(Patch* dest, Patch* src)
{
int i;
- dest->active = true;
+ dest->active = false;
sample_deep_copy(dest->sample, src->sample);
strcpy(dest->name, src->name);
dest->channel = src->channel;
- dest->note = src->note;
+ dest->root_note = src->root_note;
dest->lower_note = src->lower_note;
dest->upper_note = src->upper_note;
dest->cut = src->cut;
@@ -298,7 +315,7 @@ void patch_copy(Patch* dest, Patch* src)
dest->legato = src->legato;
dest->play_mode = src->play_mode;
- dest->vol = src->vol;
+ dest->amp = src->amp;
dest->pan = src->pan;
dest->ffreq = src->ffreq;
dest->freso = src->freso;
diff --git a/src/patch_private/patch_data.h b/libpetrifoo/patch_private/patch_data.h
similarity index 55%
rename from src/patch_private/patch_data.h
rename to libpetrifoo/patch_private/patch_data.h
index 9ea5e44..cbb2bf8 100644
--- a/src/patch_private/patch_data.h
+++ b/libpetrifoo/patch_private/patch_data.h
@@ -28,15 +28,17 @@
#include "midi_control.h"
#include "patch.h"
-
#include "patch_voice.h"
-
#include "sample.h"
+/* PatchParam
+ a structure used for sound parameters which can be modulated
+ continually as the voice plays.
+ */
typedef struct _PatchParam
{
- float val; /* value of this parameter */
+ float val;
/* modulation sources */
int mod_id[MAX_MOD_SLOTS];
@@ -49,26 +51,58 @@ typedef struct _PatchParam
} PatchParam;
+typedef struct _PatchFloat
+{
+ float val;
+ int mod_id;
+ float mod_amt;
+
+} PatchFloat;
+
+
+/* PatchBool
+ a structure used for storing boolean settings which can be turned
+ on and off by a modulation source.
+
+ *usually* these settings will not be continually modified by the
+ modulation source; their value will usually only be taken each
+ time a voice is triggered.
+
+ modulation values below the threshold turn the feature off, while
+ those above turn it on.
+ */
+typedef struct _PatchBool
+{
+ bool active;
+ int mod_id;
+ float thresh;
+
+} PatchBool;
+
+
/* type for array of instruments (called patches) */
struct _Patch
{
- bool active; /* whether patch is in use or not */
- Sample* sample; /* sample data */
- int display_index; /* order in which this Patch to be displayed */
-
- char name[PATCH_MAX_NAME];
-
- int channel; /* midi channel to listen on */
- int note; /* midi note to listen on */
- int lower_note; /* lowest note in range */
- int upper_note; /* highest note in range */
- int cut; /* cut signal this patch emits */
- int cut_by; /* what cut signals stop this patch */
- int play_start; /* the first frame to play */
- int play_stop; /* the last frame to play */
- int loop_start; /* the first frame to loop at */
- int loop_stop; /* the last frame to loop at */
-
+ bool active; /* whether patch is in use or not */
+ Sample* sample; /* sample data */
+ int display_index; /* order in which this Patch to be displayed */
+
+ char name[PATCH_MAX_NAME];
+
+ int channel; /* midi channel to listen on */
+ int root_note; /* midi note to listen on */
+ int lower_note; /* lowest note in range */
+ int upper_note; /* highest note in range */
+ int lower_vel; /* lower velocity trigger */
+ int upper_vel; /* upper velocity trigger */
+
+ int cut; /* cut signal this patch emits */
+ int cut_by; /* what cut signals stop this patch */
+
+ int play_start; /* the first frame to play */
+ int play_stop; /* the last frame to play */
+ int loop_start; /* the first frame to loop at */
+ int loop_stop; /* the last frame to loop at */
int sample_stop; /* very last frame in sample */
int* marks[WF_MARK_STOP + 1];
@@ -76,19 +110,21 @@ struct _Patch
int fade_samples;
int xfade_samples;
- bool porta; /* whether portamento is being used or not */
- float porta_secs; /* length of portamento slides in seconds */
- int pitch_steps; /* range of pitch.val in halfsteps */
- float pitch_bend; /* pitch bending factor */
- bool mono; /* whether patch is monophonic or not */
- bool legato; /* whether patch is played legato or not */
+ PatchBool porta;
+ PatchFloat porta_secs;
+
+ int pitch_steps; /* range of pitch.val in halfsteps */
+ float pitch_bend; /* pitch bending factor */
+ bool mono; /* whether patch is monophonic or not */
+ PatchBool legato; /* whether patch is played legato or not */
PatchPlayMode play_mode; /* how this patch is to be played */
- PatchParam vol; /* volume: [0.0, 1.0] */
+
+ PatchParam amp; /* amplitude: [0.0, 1.0] */
PatchParam pan; /* panning: [-1.0, 1.0] */
PatchParam ffreq; /* filter cutoff frequency: [0.0, 1.0] */
PatchParam freso; /* filter resonance: [0.0, 1.0] */
- PatchParam pitch; /* pitch scaling: [0.0, 1.0] */
+ PatchParam pitch; /* pitch scaling: [-1.0, 1.0] */
double mod_pitch_min[MAX_MOD_SLOTS];
double mod_pitch_max[MAX_MOD_SLOTS];
@@ -97,33 +133,12 @@ struct _Patch
LFOParams glfo_params[PATCH_MAX_LFOS];
LFOParams vlfo_params[VOICE_MAX_LFOS];
- /* we need tables to store output values of global LFOs. there are
- good reasons for this, it's a necessity and, it's false to think
- this places any limitations on the modulation of the global LFOs
- (think: how would modulating a global LFO by a source from one of
- the (many) voices work? (we pretend it's impossible for simplicity's
- sake and therefor the right answer is it cannot work, and
- consequently there are no problems :-) ).
+ /* use tables to store output values of global LFOs
*/
float* glfo_table[PATCH_MAX_LFOS];
- /* NOTE: FIXME-ISH?
- above statement falls apart if the patch is monophonic - there
- would only ever be one voice and this makes it perfectly reasonable
- to allow modulation of the global LFOs by a source within the
- (one and only) voice.
-
- the over-arching logic would be something along the lines of
-
- if monophonic
- then
- don't use global lfo tables
- endif
- */
-
ADSRParams env_params[VOICE_MAX_ENVS];
-
/* each patch is responsible for its own voices */
PatchVoice* voices[PATCH_VOICE_COUNT];
int last_note; /* the last MIDI note value that played us */
diff --git a/src/patch_private/patch_defs.c b/libpetrifoo/patch_private/patch_defs.c
similarity index 100%
rename from src/patch_private/patch_defs.c
rename to libpetrifoo/patch_private/patch_defs.c
diff --git a/src/patch_private/patch_defs.h b/libpetrifoo/patch_private/patch_defs.h
similarity index 100%
rename from src/patch_private/patch_defs.h
rename to libpetrifoo/patch_private/patch_defs.h
diff --git a/src/mod_src.h b/libpetrifoo/patch_private/patch_event_data.h
similarity index 50%
rename from src/mod_src.h
rename to libpetrifoo/patch_private/patch_event_data.h
index be67eda..00ce040 100644
--- a/src/mod_src.h
+++ b/libpetrifoo/patch_private/patch_event_data.h
@@ -18,32 +18,65 @@
*/
-#ifndef MOD_SRC_H
-#define MOD_SRC_H
+#ifndef PATCH_EVENT_DATA_H
+#define PATCH_EVENT_DATA_H
+
#include <stdbool.h>
+#include <stdint.h>
+
+
+#define EV_MAX_IDS 4
+/* id[0] = patch_id*/
+
+struct _PatchEvent
+{
+ int id[EV_MAX_IDS];
+
+
+}/* typedef'd in patch_event.h */;
+
+
+typedef struct _EventSetVar
+{
+ uint16_t type;
+ uint16_t size;
+ int patch_id;
+
+ int var_id;
+
+ union {
+ bool b;
+ int i;
+ float f;
+ char* data;
+ };
+} EventSetVar;
-#include "names.h"
+typedef struct _EventSetParam
+{
+ uint16_t type;
+ uint16_t size;
+ int patch_id;
-/* construct/destruct */
-void mod_src_create(void);
-void mod_src_destroy(void);
+ int param;
+ float value;
-/* get a list of modulation sources satisfying mod_src_bitmask */
-id_name* mod_src_get(int mod_src_bitmask);
+} EventSetParam;
-/* free memory previously allocated by mod_src_get */
-void mod_src_free(id_name*);
-/* get id of named mod src as long as it satisfies mod_src_bitmask */
-int mod_src_id(const char*, int mod_src_bitmask);
+typedef struct _EventSetParMod
+{
+ uint16_t type;
+ uint16_t size;
+ int patch_id;
-const char* mod_src_name(int id);
+ int param;
+ int slot;
+ float value;
-bool mod_src_is_global(int id);
-bool mod_src_maybe_eg(const char*);
-bool mod_src_maybe_lfo(const char*);
+} EventSetParMod;
#endif
diff --git a/src/patch_private/patch_macros.h b/libpetrifoo/patch_private/patch_macros.h
similarity index 59%
rename from src/patch_private/patch_macros.h
rename to libpetrifoo/patch_private/patch_macros.h
index d0cfa86..87440c9 100644
--- a/src/patch_private/patch_macros.h
+++ b/libpetrifoo/patch_private/patch_macros.h
@@ -26,31 +26,30 @@
#define PATCH_MACROS_H
-#define INLINE_ISOK_DEF \
-inline static int isok(int id) \
-{ \
- if (id < 0 || id >= PATCH_COUNT \
- || !patches[id] || !patches[id]->active) \
- return 0; \
- return 1; \
+#define INLINE_PATCHOK_DEF \
+inline static bool patchok(int id) \
+{ \
+ return (id >= 0 && id < PATCH_COUNT \
+ && patches[id] != 0 \
+ && patches[id]->active);\
}
-#define INLINE_PATCH_TRIGGER_GLOBAL_LFO_DEF \
-inline static void \
-patch_trigger_global_lfo(int patch_id, LFO* lfo, LFOParams* lfopar) \
-{ \
- Patch* p = patches[patch_id]; \
- float const* src; \
- src = patch_mod_id_to_pointer(lfopar->fm1_id, p, NULL); \
- lfo_set_fm1(lfo, src); \
- src = patch_mod_id_to_pointer(lfopar->fm2_id, p, NULL); \
- lfo_set_fm2(lfo, src); \
- src = patch_mod_id_to_pointer(lfopar->am1_id, p, NULL); \
- lfo_set_am1(lfo, src); \
- src = patch_mod_id_to_pointer(lfopar->am2_id, p, NULL); \
- lfo_set_am2(lfo, src); \
- lfo_rigger(lfo, lfopar); \
+#define INLINE_PATCH_TRIGGER_GLOBAL_LFO_DEF \
+inline static void \
+patch_trigger_global_lfo(int patch_id, LFO* lfo, LFOParams* lfopar) \
+{ \
+ Patch* p = patches[patch_id]; \
+ float const* src; \
+ src = patch_mod_id_to_pointer(lfopar->fm1_id, p, NULL); \
+ lfo_set_fm1(lfo, src); \
+ src = patch_mod_id_to_pointer(lfopar->fm2_id, p, NULL); \
+ lfo_set_fm2(lfo, src); \
+ src = patch_mod_id_to_pointer(lfopar->am1_id, p, NULL); \
+ lfo_set_am1(lfo, src); \
+ src = patch_mod_id_to_pointer(lfopar->am2_id, p, NULL); \
+ lfo_set_am2(lfo, src); \
+ lfo_update_params(lfo, lfopar); \
}
diff --git a/src/patch_private/patch_voice.c b/libpetrifoo/patch_private/patch_voice.c
similarity index 98%
rename from src/patch_private/patch_voice.c
rename to libpetrifoo/patch_private/patch_voice.c
index f421355..d1555a8 100644
--- a/src/patch_private/patch_voice.c
+++ b/libpetrifoo/patch_private/patch_voice.c
@@ -37,24 +37,31 @@ PatchVoice* patch_voice_new(void)
pv->active = false;
pv->ticks = 0;
pv->relset = 0;
+
pv->relmode = RELEASE_NONE;
+
pv->released = false;
pv->to_end = false;
+
pv->dir = 0;
+
pv->note = 0;
pv->pitch = 0;
pv->pitch_step = 0;
+
pv->porta_ticks = 0;
+
pv->posi = 0;
pv->posf = 0;
pv->stepi = 0;
pv->stepf = 0;
+
pv->vel = 0;
pv->key_track = 0;
for (i = 0; i < MAX_MOD_SLOTS; ++i)
{
- pv->vol_mod[i] = NULL;
+ pv->amp_mod[i] = NULL;
pv->pan_mod[i] = NULL;
pv->ffreq_mod[i] = NULL;
pv->freso_mod[i] = NULL;
@@ -71,20 +78,24 @@ PatchVoice* patch_voice_new(void)
pv->fbl = 0;
pv->flr = 0;
pv->fbr = 0;
+
pv->playstate = PLAYSTATE_OFF;
pv->xfade = false;
pv->loop = false;
+
pv->fade_posi = -1;
pv->fade_posf = 0;
pv->fade_out_start_pos = 0;
+
pv->fade_declick = 0;
+
pv->xfade_point_posi = 0;
pv->xfade_point_posf = 0;
-
pv->xfade_posi = -1;
pv->xfade_posf = 0;
pv->xfade_dir = 0;
+
pv->xfade_declick = 0;
return pv;
diff --git a/src/patch_private/patch_voice.h b/libpetrifoo/patch_private/patch_voice.h
similarity index 97%
rename from src/patch_private/patch_voice.h
rename to libpetrifoo/patch_private/patch_voice.h
index 18659bb..dc76fbc 100644
--- a/src/patch_private/patch_voice.h
+++ b/libpetrifoo/patch_private/patch_voice.h
@@ -75,7 +75,11 @@ typedef struct _PatchVoice
double pitch; /* what pitch ratio to play at */
double pitch_step; /* how much to increment pitch by each
* porta_tick */
+ bool legato;
+ bool portamento;
+ float porta_secs;
int porta_ticks;/* how many ticks to increment pitch for */
+
int posi; /* integer sample index */
uint32_t posf; /* fractional sample index */
int stepi; /* integer step amount */
@@ -84,7 +88,7 @@ typedef struct _PatchVoice
float vel; /* velocity; volume of this voice */
float key_track; /* = (note - lower) / (upper - lower) */
- float const* vol_mod[MAX_MOD_SLOTS];
+ float const* amp_mod[MAX_MOD_SLOTS];
float const* pan_mod[MAX_MOD_SLOTS];
float const* ffreq_mod[MAX_MOD_SLOTS];
float const* freso_mod[MAX_MOD_SLOTS];
diff --git a/libpetrifoo/patch_set_and_get.c b/libpetrifoo/patch_set_and_get.c
new file mode 100644
index 0000000..708907c
--- /dev/null
+++ b/libpetrifoo/patch_set_and_get.c
@@ -0,0 +1,1341 @@
+/* Petri-Foo is a fork of the Specimen audio sampler.
+
+ Original Specimen author Pete Bessman
+ Copyright 2005 Pete Bessman
+ Copyright 2011 James W. Morris
+
+ This file is part of Petri-Foo.
+
+ Petri-Foo is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+
+ Petri-Foo is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Petri-Foo. If not, see <http://www.gnu.org/licenses/>.
+
+ This file is a derivative of a Specimen original, modified 2011
+*/
+
+
+#include "patch_set_and_get.h"
+
+#include <assert.h>
+#include <string.h>
+#include <math.h>
+
+
+#include "sample.h"
+#include "adsr.h"
+#include "lfo.h"
+#include "pf_error.h"
+
+
+#include "patch_private/patch_data.h"
+#include "patch_private/patch_defs.h"
+#include "patch_private/patch_macros.h"
+
+
+INLINE_PATCHOK_DEF
+
+inline static bool markok(int id)
+{
+ return (id >= WF_MARK_START && id <= WF_MARK_STOP);
+}
+
+
+inline static bool marksetok(int id)
+{
+ return (id >= WF_MARK_PLAY_START && id <= WF_MARK_PLAY_STOP);
+}
+
+
+static inline void set_mark_frame(int patch_id, int mark, int frame)
+{
+ *(patches[patch_id]->marks[mark]) = frame;
+}
+
+
+static inline int get_mark_frame(int patch_id, int mark)
+{
+ return *(patches[patch_id]->marks[mark]);
+}
+
+
+static int get_mark_frame_range(int patch_id, int mark, int* min, int* max)
+{
+ int xfade;
+
+ assert(patchok(patch_id));
+ assert(markok(mark));
+
+ xfade = patches[patch_id]->xfade_samples;
+
+ if (mark == WF_MARK_START || mark == WF_MARK_STOP)
+ {
+ *min = *max = get_mark_frame(patch_id, mark);
+ /* indicate non-editable! */
+ return -1;
+ }
+
+ /* potential range: */
+ *min = get_mark_frame(patch_id, mark - 1);
+ *max = get_mark_frame(patch_id, mark + 1);
+
+ /* tweak if necessary */
+ switch(mark)
+ {
+ case WF_MARK_PLAY_START:
+ *max -= xfade;
+ break;
+ case WF_MARK_PLAY_STOP:
+ *min += xfade;
+ break;
+ case WF_MARK_LOOP_START:
+ *min += xfade;
+ *max -= xfade;
+ break;
+ case WF_MARK_LOOP_STOP:
+ *min += xfade;
+ *max -= xfade;
+ break;
+ default:
+ assert(0);
+ }
+
+ return get_mark_frame(patch_id, mark);
+}
+
+
+static PatchParam* get_patch_param(int patch_id, PatchParamType param)
+{
+ switch(param)
+ {
+ case PATCH_PARAM_AMPLITUDE: return &patches[patch_id]->amp;
+ case PATCH_PARAM_PANNING: return &patches[patch_id]->pan;
+ case PATCH_PARAM_CUTOFF: return &patches[patch_id]->ffreq;
+ case PATCH_PARAM_RESONANCE: return &patches[patch_id]->freso;
+ case PATCH_PARAM_PITCH: return &patches[patch_id]->pitch;
+ default:
+ assert(0);
+ }
+ return 0;
+}
+
+
+static PatchBool* get_patch_bool(int patch_id, PatchBoolType booltype)
+{
+ assert(patchok(patch_id));
+ switch(booltype)
+ {
+ case PATCH_BOOL_PORTAMENTO: return &patches[patch_id]->porta;
+ case PATCH_BOOL_LEGATO: return &patches[patch_id]->legato;
+ default:
+ assert(0);
+ }
+ return 0;
+}
+
+
+static PatchFloat* get_patch_float(int patch_id, PatchFloatType floattype)
+{
+ assert(patchok(patch_id));
+ switch(floattype)
+ {
+ case PATCH_FLOAT_PORTAMENTO_TIME:
+ return &patches[patch_id]->porta_secs;
+ default:
+ assert(0);
+ }
+ return 0;
+}
+
+
+/* inline static function def macro, see private/patch_data.h */
+INLINE_PATCH_TRIGGER_GLOBAL_LFO_DEF
+
+
+
+/**************************************************************************/
+/************************* ENVELOPE SETTERS *******************************/
+/**************************************************************************/
+
+inline static int mod_src_to_eg_index(int id)
+{
+ assert(id >= MOD_SRC_EG);
+ id -= MOD_SRC_EG;
+ assert(id < VOICE_MAX_ENVS);
+ return id;
+}
+
+
+int patch_set_env_active(int patch_id, int eg, bool state)
+{
+ assert(patchok(patch_id));
+ eg = mod_src_to_eg_index(eg);
+ patches[patch_id]->env_params[eg].active = state;
+ return 0;
+}
+
+
+#define PATCH_SET_ENV_TIME( _EGPAR ) \
+int patch_set_env_##_EGPAR(int patch_id, int eg, float secs) \
+{ \
+ assert(patchok(patch_id)); \
+ if (secs < 0.0f) \
+ { \
+ pf_error(PF_ERR_PATCH_VALUE_NEGATIVE); \
+ return -1; \
+ } \
+ eg = mod_src_to_eg_index(eg); \
+ patches[patch_id]->env_params[eg]._EGPAR = secs; \
+ return 0; \
+}
+
+PATCH_SET_ENV_TIME( delay )
+PATCH_SET_ENV_TIME( attack )
+PATCH_SET_ENV_TIME( hold )
+PATCH_SET_ENV_TIME( decay )
+
+/* special cases: */
+
+int patch_set_env_sustain (int patch_id, int eg, float level)
+{
+ assert(patchok(patch_id));
+ if (level < 0.0 || level > 1.0)
+ {
+ pf_error(PF_ERR_PATCH_VALUE_LEVEL);
+ return -1;
+ }
+ eg = mod_src_to_eg_index(eg);
+ patches[patch_id]->env_params[eg].sustain = level;
+ return 0;
+}
+
+
+int patch_set_env_release (int patch_id, int eg, float secs)
+{
+ assert(patchok(patch_id));
+ if (secs < 0.0f)
+ {
+ pf_error(PF_ERR_PATCH_VALUE_NEGATIVE);
+ return -1;
+ }
+ eg = mod_src_to_eg_index(eg);
+ /* use of min release time should remain hidden */
+ if (secs < PATCH_MIN_RELEASE)
+ secs = PATCH_MIN_RELEASE;
+ patches[patch_id]->env_params[eg].release = secs;
+ return 0;
+}
+
+
+int patch_set_env_key_amt(int patch_id, int eg, float val)
+{
+ assert(patchok(patch_id));
+ if (val < 0.0 || val > 1.0)
+ {
+ pf_error(PF_ERR_PATCH_VALUE_LEVEL);
+ return -1;
+ }
+ eg = mod_src_to_eg_index(eg);
+ patches[patch_id]->env_params[eg].key_amt = val;
+ return 0;
+}
+
+
+/**************************************************************************/
+/************************* ENVELOPE GETTERS *******************************/
+/**************************************************************************/
+
+#define PATCH_GET_ENV_PARAM( _EGPAR, _EGPARTYPE) \
+_EGPARTYPE patch_get_env_##_EGPAR(int patch_id, int eg) \
+{ \
+ assert(patchok(patch_id)); \
+ eg = mod_src_to_eg_index(eg); \
+ return patches[patch_id]->env_params[eg]._EGPAR; \
+}
+
+PATCH_GET_ENV_PARAM( active, bool )
+PATCH_GET_ENV_PARAM( delay, float )
+PATCH_GET_ENV_PARAM( attack, float )
+PATCH_GET_ENV_PARAM( hold, float )
+PATCH_GET_ENV_PARAM( decay, float )
+PATCH_GET_ENV_PARAM( sustain, float )
+PATCH_GET_ENV_PARAM( key_amt, float )
+
+/* special cases: */
+float patch_get_env_release (int patch_id, int eg)
+{
+ float val;
+ assert(patchok(patch_id));
+ eg = mod_src_to_eg_index(eg);
+ val = patches[patch_id]->env_params[eg].release;
+ /* hide usage of min-release-value from outside world */
+ if (val <= PATCH_MIN_RELEASE)
+ val = 0;
+ return val;
+}
+
+
+/************************************************************************/
+/*************************** LFO SETTERS ********************************/
+/************************************************************************/
+
+static LFOParams* lfopar_from_id(int patch_id, int id, LFO** lfo)
+{
+ assert(patchok(patch_id));
+ assert( ((id & MOD_SRC_VLFO) && (id & MOD_SRC_GLFO)) == 0);
+ assert( ((id & MOD_SRC_VLFO) || (id & MOD_SRC_GLFO)) != 0);
+
+ if (lfo)
+ *lfo = 0;
+
+ if (id & MOD_SRC_VLFO)
+ {
+ assert ((id -= MOD_SRC_VLFO) < VOICE_MAX_LFOS);
+ return &patches[patch_id]->vlfo_params[id];
+ }
+
+ assert((id -= MOD_SRC_GLFO) < PATCH_MAX_LFOS);
+
+ if (lfo)
+ *lfo = patches[patch_id]->glfo[id];
+
+ return &patches[patch_id]->glfo_params[id];
+}
+
+
+#define PATCH_SET_LFO_VAR( _LFOVAR, _LFOVARTYPE ) \
+int patch_set_lfo_##_LFOVAR(int patch_id, int lfo_id, _LFOVARTYPE val) \
+{ \
+ LFO* lfo; \
+ LFOParams* lfopar; \
+ lfopar = lfopar_from_id(patch_id, lfo_id, &lfo);\
+ lfopar->_LFOVAR = val; \
+ if (lfo) \
+ lfo_update_params(lfo, lfopar); \
+ return 0; \
+}
+
+PATCH_SET_LFO_VAR( active, bool)
+PATCH_SET_LFO_VAR( positive, bool)
+PATCH_SET_LFO_VAR( shape, LFOShape)
+PATCH_SET_LFO_VAR( sync, bool)
+
+
+#define PATCH_SET_LFO_VAR_BOUNDED( _LFOVAR, _LFOVARTYPE ) \
+int patch_set_lfo_##_LFOVAR(int patch_id, int lfo_id, _LFOVARTYPE val) \
+{ \
+ LFO* lfo; \
+ LFOParams* lfopar; \
+ lfopar = lfopar_from_id(patch_id, lfo_id, &lfo);\
+ if (val < 0.0) \
+ { \
+ pf_error(PF_ERR_PATCH_VALUE_NEGATIVE); \
+ return -1; \
+ } \
+ lfopar->_LFOVAR = val; \
+ if (lfo) \
+ lfo_update_params(lfo, lfopar); \
+ return 0; \
+}
+
+PATCH_SET_LFO_VAR_BOUNDED( attack, float )
+PATCH_SET_LFO_VAR_BOUNDED( sync_beats, float )
+PATCH_SET_LFO_VAR_BOUNDED( delay, float )
+PATCH_SET_LFO_VAR_BOUNDED( freq, float )
+
+
+/************************************************************************/
+/*************************** LFO GETTERS ********************************/
+/************************************************************************/
+
+#define PATCH_GET_LFO_VAR( _LFOVAR, _LFOVARTYPE ) \
+_LFOVARTYPE patch_get_lfo_##_LFOVAR(int patch_id, int lfo_id) \
+{ \
+ return lfopar_from_id(patch_id, lfo_id, NULL)->_LFOVAR; \
+}
+
+PATCH_GET_LFO_VAR( active, bool )
+PATCH_GET_LFO_VAR( attack, float )
+PATCH_GET_LFO_VAR( sync_beats, float )
+PATCH_GET_LFO_VAR( delay, float )
+PATCH_GET_LFO_VAR( freq, float )
+PATCH_GET_LFO_VAR( positive, bool )
+PATCH_GET_LFO_VAR( shape, LFOShape )
+PATCH_GET_LFO_VAR( sync, bool )
+
+/**************************************************************************/
+/************************ PARAMETER SETTERS *******************************/
+/**************************************************************************/
+
+/* sets the cut signal this patch emits when activated */
+int patch_set_cut (int patch_id, int cut)
+{
+ assert(patchok(patch_id));
+ patches[patch_id]->cut = cut;
+ return 0;
+}
+
+/* sets the cut signal that terminates this patch if active */
+int patch_set_cut_by (int patch_id, int cut_by)
+{
+ assert(patchok(patch_id));
+ patches[patch_id]->cut_by = cut_by;
+ return 0;
+}
+
+/* set whether this patch should be played legato or not */
+int patch_set_legato(int patch_id, bool val)
+{
+ assert(patchok(patch_id));
+ patches[patch_id]->legato.active = val;
+ return 0;
+}
+
+
+int patch_set_fade_samples(int patch_id, int samples)
+{
+ assert(patchok(patch_id));
+
+ if (patches[patch_id]->sample->sp == NULL)
+ return 0;
+
+ if (samples < 0)
+ {
+ pf_error(PF_ERR_PATCH_PARAM_VALUE);
+ return -1;
+ }
+
+ if (patches[patch_id]->play_start + samples * 2
+ >= patches[patch_id]->play_stop)
+ {
+ pf_error(PF_ERR_PATCH_PARAM_VALUE);
+ return -1;
+ }
+
+ patches[patch_id]->fade_samples = samples;
+ return 0;
+}
+
+int patch_set_xfade_samples(int patch_id, int samples)
+{
+ assert(patchok(patch_id));
+
+ if (patches[patch_id]->sample->sp == NULL)
+ return 0;
+
+ if (samples < 0)
+ {
+ pf_error(PF_ERR_PATCH_PARAM_VALUE);
+ return -1;
+ }
+
+ if (patches[patch_id]->loop_start + samples
+ > patches[patch_id]->loop_stop)
+ {
+ pf_error(PF_ERR_PATCH_PARAM_VALUE);
+ return -1;
+ }
+
+ if (patches[patch_id]->loop_stop + samples
+ > patches[patch_id]->play_stop)
+ {
+ pf_error(PF_ERR_PATCH_PARAM_VALUE);
+ return -1;
+ }
+
+ patches[patch_id]->xfade_samples = samples;
+ return 0;
+}
+
+
+int patch_set_mark_frame(int patch_id, int mark, int frame)
+{
+ /* FIXME: perhaps this complexity better placed in libpetrifui? */
+ assert(patchok(patch_id));
+ assert(marksetok(mark));
+
+ if (patches[patch_id]->sample->sp == NULL)
+ { /* FIXME: assert here? */
+ errmsg("sample not set\n");
+ return -1;
+ }
+
+/* if (!mark_settable(mark))
+ {
+ debug("mark %d not settable\n", mark);
+ return -1;
+ }
+*/
+ int min;
+ int max;
+
+ get_mark_frame_range(patch_id, mark, &min, &max);
+
+ if (frame < min || frame > max)
+ return -1;
+
+ set_mark_frame(patch_id, mark, frame);
+ return mark;
+}
+
+
+int patch_set_mark_frame_expand(int patch_id, int mark, int frame,
+ int* also_changed)
+{
+ int also = 0;
+ int also_frame = -1;
+ int xfade = patches[patch_id]->xfade_samples;
+ int fade = patches[patch_id]->fade_samples;
+
+ assert(patchok(patch_id));
+
+ if (patches[patch_id]->sample->sp == NULL)
+ return -1;
+
+ /* if callee wishes not to be informed about which marks get changed
+ as a result of changing this one, also_changed will be NULL. It
+ needs to be a valid pointer.
+ */
+ if (!also_changed)
+ also_changed = &also;
+
+ *also_changed = -1;
+
+ switch(mark)
+ {
+ case WF_MARK_PLAY_START:
+ also_frame = frame + xfade; /* pot loop start pos */
+
+ if (frame + fade * 2 >= get_mark_frame(patch_id, WF_MARK_PLAY_STOP)
+ || also_frame >= get_mark_frame(patch_id, WF_MARK_LOOP_STOP))
+ {
+ mark = -1;
+ }
+ else if (also_frame > get_mark_frame(patch_id, WF_MARK_LOOP_START))
+ { /* moving play start along pushes loop start along... */
+ if (also_frame + xfade
+ < get_mark_frame(patch_id, WF_MARK_LOOP_STOP))
+ {
+ *also_changed = WF_MARK_LOOP_START;
+ }
+ else
+ mark = -1;
+ }
+ break;
+
+ case WF_MARK_PLAY_STOP:
+ also_frame = frame - xfade; /* pot loop stop pos */
+
+ if (frame - fade * 2<= get_mark_frame(patch_id, WF_MARK_PLAY_START)
+ || also_frame <= get_mark_frame(patch_id, WF_MARK_LOOP_START))
+ {
+ mark = -1;
+ }
+ else if (also_frame < get_mark_frame(patch_id, WF_MARK_LOOP_STOP))
+ {
+ if (also_frame - xfade
+ > get_mark_frame(patch_id, WF_MARK_LOOP_START))
+ {
+ *also_changed = WF_MARK_LOOP_STOP;
+ }
+ else
+ mark = -1;
+ }
+ break;
+
+ case WF_MARK_LOOP_START:
+ also_frame = frame - xfade; /* pot play start pos */
+
+ if (frame + xfade >= get_mark_frame(patch_id, WF_MARK_LOOP_STOP))
+ mark = -1;
+ else if (also_frame < get_mark_frame(patch_id, WF_MARK_PLAY_START))
+ {
+ if (also_frame > 0)
+ *also_changed = WF_MARK_PLAY_START;
+ else
+ mark = -1;
+ }
+ break;
+
+ case WF_MARK_LOOP_STOP:
+ also_frame = frame + xfade /* pot play stop pos */;
+
+ if (frame - xfade <= get_mark_frame(patch_id, WF_MARK_LOOP_START))
+ mark = -1;
+ else if (also_frame > get_mark_frame(patch_id, WF_MARK_PLAY_STOP))
+ {
+ if (also_frame < get_mark_frame(patch_id, WF_MARK_STOP))
+ *also_changed = WF_MARK_PLAY_STOP;
+ else
+ mark = -1;
+ }
+ break;
+
+ default:
+ mark = -1;
+ }
+
+ if (mark != -1)
+ {
+ set_mark_frame(patch_id, mark, frame);
+ }
+
+ if (*also_changed != -1)
+ {
+ set_mark_frame(patch_id, *also_changed, also_frame);
+ }
+
+ return mark;
+}
+
+
+/* sets the name */
+int patch_set_name (int patch_id, const char *name)
+{
+ assert(patchok(patch_id));
+ strncpy (patches[patch_id]->name, name, PATCH_MAX_NAME);
+ return 0;
+}
+
+
+#define PATCH_SET_VAR( _VAR, _VARMIN, _VARMAX ) \
+int patch_set_##_VAR(int patch_id, int val) \
+{ \
+ assert(patchok(patch_id)); \
+ if (val < _VARMIN || val > _VARMAX) \
+ { \
+ pf_error(PF_ERR_PATCH_PARAM_VALUE); \
+ return -1; \
+ } \
+ patches[patch_id]->_VAR = val; \
+ return 0; \
+}
+
+PATCH_SET_VAR( channel, 0, 15 )
+PATCH_SET_VAR( root_note, 0, 127 )
+PATCH_SET_VAR( lower_note, 0, 127 )
+PATCH_SET_VAR( upper_note, 0, 127 )
+PATCH_SET_VAR( lower_vel, 0, 127 )
+PATCH_SET_VAR( upper_vel, 0, 127 )
+
+PATCH_SET_VAR( pitch_steps, -PATCH_MAX_PITCH_STEPS, PATCH_MAX_PITCH_STEPS )
+
+/* set whether the patch is monophonic or not */
+int patch_set_monophonic(int patch_id, bool val)
+{
+ assert(patchok(patch_id));
+ patches[patch_id]->mono = val;
+ return 0;
+}
+
+
+#define PATCH_SET_PARAM( _PARAM, _PARMIN, _PARMAX ) \
+int patch_set_##_PARAM(int patch_id, float val) \
+{ \
+ assert(patchok(patch_id)); \
+ if (val < _PARMIN || val > _PARMAX) \
+ { \
+ pf_error(PF_ERR_PATCH_PARAM_VALUE); \
+ return -1; \
+ } \
+ patches[patch_id]->_PARAM.val = val; \
+ return 0; \
+}
+
+PATCH_SET_PARAM( amp, 0.0, 1.0 )
+PATCH_SET_PARAM( pan, -1.0, 1.0 )
+PATCH_SET_PARAM( ffreq, 0.0, 1.0 )
+PATCH_SET_PARAM( freso, 0.0, 1.0 )
+PATCH_SET_PARAM( pitch, -1.0, 1.0 )
+
+
+/* sets the play mode */
+int patch_set_play_mode (int patch_id, PatchPlayMode mode)
+{
+ assert(patchok(patch_id));
+
+ if (mode & PATCH_PLAY_SINGLESHOT)
+ {
+ assert( ((mode & PATCH_PLAY_TRIM)
+ | (mode & PATCH_PLAY_LOOP)) == 0);
+ }
+ else if (mode & PATCH_PLAY_TRIM)
+ {
+ assert( ((mode & PATCH_PLAY_SINGLESHOT)
+ | (mode & PATCH_PLAY_LOOP)) == 0);
+ }
+ else if (mode & PATCH_PLAY_LOOP)
+ {
+ assert( ((mode & PATCH_PLAY_SINGLESHOT)
+ | (mode & PATCH_PLAY_TRIM)) == 0);
+ }
+
+ if (!(mode & PATCH_PLAY_LOOP))
+ {
+ assert( ((mode & PATCH_PLAY_PINGPONG)
+ | (mode & PATCH_PLAY_TO_END)) == 0);
+ }
+
+ patches[patch_id]->play_mode = mode;
+ return 0;
+}
+
+/* set whether portamento is being used or not */
+int patch_set_portamento (int patch_id, bool val)
+{
+ assert(patchok(patch_id));
+ patches[patch_id]->porta.active = val;
+ return 0;
+}
+
+/* set length of portamento slides in seconds */
+int patch_set_portamento_time (int patch_id, float secs)
+{
+ assert(patchok(patch_id));
+ if (secs < 0.0)
+ {
+ pf_error(PF_ERR_PATCH_PARAM_VALUE);
+ return -1;
+ }
+ patches[patch_id]->porta_secs.val = secs;
+ return 0;
+}
+
+
+
+/**************************************************************************/
+/************************* PARAMETER GETTERS*******************************/
+/**************************************************************************/
+
+
+#define PATCH_GET_VAR( _VAR ) \
+int patch_get_##_VAR(int patch_id) \
+{ \
+ assert(patchok(patch_id)); \
+ return patches[patch_id]->_VAR; \
+}
+
+PATCH_GET_VAR( channel )
+PATCH_GET_VAR( cut )
+PATCH_GET_VAR( cut_by )
+PATCH_GET_VAR( display_index )
+PATCH_GET_VAR( root_note )
+PATCH_GET_VAR( lower_note )
+PATCH_GET_VAR( upper_note )
+PATCH_GET_VAR( lower_vel )
+PATCH_GET_VAR( upper_vel )
+PATCH_GET_VAR( pitch_steps )
+
+
+
+/* get the filter cutoff value */
+float patch_get_cutoff(int patch_id)
+{
+ assert(patchok(patch_id));
+ return patches[patch_id]->ffreq.val;
+}
+
+
+/* get the number of frame in the sample */
+int patch_get_frames(int patch_id)
+{
+ assert(patchok(patch_id));
+ if (patches[patch_id]->sample->sp == NULL)
+ return 0;
+ return patches[patch_id]->sample->frames;
+}
+
+/* get whether this patch is played legato or not */
+bool patch_get_legato(int patch_id)
+{
+ assert(patchok(patch_id));
+ return patches[patch_id]->legato.active;
+}
+
+
+int patch_get_mark_frame(int patch_id, int mark)
+{
+ assert(patchok(patch_id));
+ assert(markok(mark));
+
+ /* FIXME: should this be an assert or not ? */
+ assert(patches[patch_id]->sample->sp != NULL);
+
+ return get_mark_frame(patch_id, mark);
+}
+
+
+int patch_get_mark_frame_range(int patch_id, int mark, int* frame_min,
+ int* frame_max)
+{
+ assert(patchok(patch_id));
+ assert(markok(mark));
+
+ /* FIXME: should this be an assert or not ? */
+ assert(patches[patch_id]->sample->sp != NULL);
+
+ return get_mark_frame_range(patch_id, mark, frame_min, frame_max);
+}
+
+/* get whether this patch is monophonic or not */
+bool patch_get_monophonic(int patch_id)
+{
+ assert(patchok(patch_id));
+ return patches[patch_id]->mono;
+}
+
+/* get the name */
+char *patch_get_name(int patch_id)
+{
+ char *name;
+ assert(patchok(patch_id));
+ name = strdup (patches[patch_id]->name);
+ return name;
+}
+
+
+/* get the panorama */
+float patch_get_panning(int patch_id)
+{
+ assert(patchok(patch_id));
+ return patches[patch_id]->pan.val;
+}
+
+/* get the pitch */
+float patch_get_pitch(int patch_id)
+{
+ assert(patchok(patch_id));
+ return patches[patch_id]->pitch.val;
+}
+
+/* get the play mode */
+PatchPlayMode patch_get_play_mode(int patch_id)
+{
+ assert(patchok(patch_id));
+ return patches[patch_id]->play_mode;
+}
+
+/* get whether portamento is used or not */
+bool patch_get_portamento(int patch_id)
+{
+ assert(patchok(patch_id));
+ return patches[patch_id]->porta.active;
+}
+
+/* get length of portamento slides in seconds */
+float patch_get_portamento_time(int patch_id)
+{
+ assert(patchok(patch_id));
+ return patches[patch_id]->porta_secs.val;
+}
+
+
+/* get the filter's resonance amount */
+float patch_get_resonance(int patch_id)
+{
+ assert(patchok(patch_id));
+ return patches[patch_id]->freso.val;
+}
+
+/* get a pointer to the sample data */
+const float *patch_get_sample(int patch_id)
+{
+ assert(patchok(patch_id));
+ return patches[patch_id]->sample->sp;
+}
+
+/* get the name of the sample file */
+const char *patch_get_sample_name(int patch_id)
+{
+ assert(patchok(patch_id));
+ return patches[patch_id]->sample->filename;
+}
+
+
+/* get the amplitude */
+float patch_get_amplitude(int patch_id)
+{
+ assert(patchok(patch_id));
+ return patches[patch_id]->amp.val;
+}
+
+
+int patch_get_fade_samples(int patch_id)
+{
+ assert(patchok(patch_id));
+ return patches[patch_id]->fade_samples;
+}
+
+
+int patch_get_xfade_samples(int patch_id)
+{
+ assert(patchok(patch_id));
+ return patches[patch_id]->xfade_samples;
+}
+
+
+int patch_get_max_fade_samples(int patch_id)
+{
+ assert(patchok(patch_id));
+ return (patches[patch_id]->play_stop - patches[patch_id]->play_start) / 2;
+}
+
+
+int patch_get_max_xfade_samples(int patch_id)
+{
+ int min;
+ int tmp;
+
+ assert(patchok(patch_id));
+
+ min = patches[patch_id]->sample->frames;
+
+ tmp = patches[patch_id]->loop_stop - patches[patch_id]->loop_start;
+ min = (tmp < min) ? tmp : min;
+
+ tmp = patches[patch_id]->play_stop - patches[patch_id]->loop_stop;
+ min = (tmp < min) ? tmp : min;
+
+ tmp = patches[patch_id]->loop_start - patches[patch_id]->play_start;
+ min = (tmp < min) ? tmp : min;
+
+ return min;
+}
+
+
+/******************************************************************/
+/*************************** PARAM ********************************/
+/******************************************************************/
+
+float patch_param_get_value(int patch_id, PatchParamType param)
+{
+ assert(patchok(patch_id));
+
+ switch(param)
+ {
+ case PATCH_PARAM_AMPLITUDE: return patches[patch_id]->amp.val;
+ case PATCH_PARAM_PANNING: return patches[patch_id]->pan.val;
+ case PATCH_PARAM_CUTOFF: return patches[patch_id]->ffreq.val;
+ case PATCH_PARAM_RESONANCE: return patches[patch_id]->freso.val;
+ case PATCH_PARAM_PITCH: return patches[patch_id]->pitch.val;
+ default:
+ assert(0);
+ }
+}
+
+
+void patch_param_set_value(int patch_id, PatchParamType param, float v)
+{
+ assert(patchok(patch_id));
+
+ switch(param)
+ {
+ case PATCH_PARAM_AMPLITUDE: patches[patch_id]->amp.val = v; break;
+ case PATCH_PARAM_PANNING: patches[patch_id]->pan.val = v; break;
+ case PATCH_PARAM_CUTOFF: patches[patch_id]->ffreq.val = v; break;
+ case PATCH_PARAM_RESONANCE: patches[patch_id]->freso.val = v; break;
+ case PATCH_PARAM_PITCH: patches[patch_id]->pitch.val = v; break;
+ default:
+ assert(0);
+ }
+}
+
+
+/**************************************************************************/
+/*********************** MODULATION SETTERS *******************************/
+/**************************************************************************/
+
+#define PATCH_PARAM_CHECKS \
+ PatchParam* p; \
+ assert(patchok(patch_id)); \
+ p = get_patch_param(patch_id, param);
+
+int
+patch_param_set_mod_src(int patch_id, PatchParamType param, int slot,
+ int id)
+{
+ PATCH_PARAM_CHECKS
+ assert(slot >=0 && slot <= MAX_MOD_SLOTS);
+ p->mod_id[slot] = id;
+ return 0;
+}
+
+
+int
+patch_param_set_mod_amt(int patch_id, PatchParamType param, int slot,
+ float amt)
+{
+ PATCH_PARAM_CHECKS
+ assert(slot >=0 && slot <= MAX_MOD_SLOTS);
+
+ if (amt < -1.0 || amt > 1.0)
+ {
+ pf_error(PF_ERR_PATCH_PARAM_VALUE);
+ return -1;
+ }
+
+ p->mod_amt[slot] = amt;
+
+ if (param == PATCH_PARAM_PITCH)
+ {
+ patches[patch_id]->mod_pitch_max[slot] =
+ pow(2, (amt * PATCH_MAX_PITCH_STEPS) / 12.0);
+ patches[patch_id]->mod_pitch_min[slot] =
+ pow(2, -(amt * PATCH_MAX_PITCH_STEPS) / 12.0);
+ }
+
+ return 0;
+}
+
+
+#define PATCH_PARAM_SET_AMOUNT( _PARAM ) \
+int patch_param_set_##_PARAM##_amount \
+ (int patch_id, PatchParamType param, float amt) \
+{ \
+ PATCH_PARAM_CHECKS \
+ if (amt < -1.0 || amt > 1.0) \
+ { \
+ pf_error(PF_ERR_PATCH_PARAM_VALUE); \
+ return -1; \
+ } \
+ p->_PARAM##_amt = amt; \
+ return 0; \
+}
+
+PATCH_PARAM_SET_AMOUNT( vel )
+PATCH_PARAM_SET_AMOUNT( key )
+
+
+
+/**************************************************************************/
+/********************** MODULATION GETTERS ********************************/
+/**************************************************************************/
+
+int patch_param_get_mod_src(int patch_id, PatchParamType param, int slot)
+{
+ PATCH_PARAM_CHECKS
+ assert(slot >=0 && slot <= MAX_MOD_SLOTS);
+ return p->mod_id[slot];
+}
+
+
+float patch_param_get_mod_amt(int patch_id, PatchParamType param, int slot)
+{
+ PATCH_PARAM_CHECKS
+ assert(slot >=0 && slot <= MAX_MOD_SLOTS);
+ return p->mod_amt[slot];
+}
+
+
+float patch_param_get_vel_amount(int patch_id, PatchParamType param)
+{
+ PATCH_PARAM_CHECKS
+ return p->vel_amt;
+}
+
+
+float patch_param_get_key_amount(int patch_id, PatchParamType param)
+{
+ PATCH_PARAM_CHECKS
+ return p->key_amt;
+}
+
+
+#define PATCH_BOOL_GET \
+ PatchBool* b; \
+ assert(patchok(patch_id)); \
+ b = get_patch_bool(patch_id, booltype); \
+
+
+/* PatchBool set/get */
+void patch_bool_set_active(int patch_id, PatchBoolType booltype, bool val)
+{
+ PATCH_BOOL_GET
+ b->active = val;
+}
+
+
+void patch_bool_set_thresh(int patch_id, PatchBoolType booltype, float val)
+{
+ PATCH_BOOL_GET
+ b->thresh = val;
+}
+
+
+void patch_bool_set_mod_src(int patch_id, PatchBoolType booltype,int mod_id)
+{
+ PATCH_BOOL_GET
+ b->mod_id = mod_id;
+}
+
+
+void patch_bool_get_all(int patch_id, PatchBoolType booltype,
+ bool* active, float* thresh, int* mod_id)
+{
+ PATCH_BOOL_GET
+ *active = b->active;
+ *thresh = b->thresh;
+ *mod_id = b->mod_id;
+}
+
+
+bool patch_bool_get_active(int patch_id, PatchBoolType booltype)
+{
+ PATCH_BOOL_GET
+ return b->active;
+}
+
+
+float patch_bool_get_thresh(int patch_id, PatchBoolType booltype)
+{
+ PATCH_BOOL_GET
+ return b->thresh;
+}
+
+
+int patch_bool_get_mod_src(int patch_id, PatchBoolType booltype)
+{
+ PATCH_BOOL_GET
+ return b->mod_id;
+}
+
+#define PATCH_FLOAT_GET \
+ PatchFloat* f; \
+ assert(patchok(patch_id)); \
+ f = get_patch_float(patch_id, floattype);
+
+
+/* PatchFloat set/get */
+void
+patch_float_set_value(int patch_id, PatchFloatType floattype, float val)
+{
+ PATCH_FLOAT_GET
+ f->val = val;
+}
+
+
+void
+patch_float_set_mod_amt(int patch_id, PatchFloatType floattype, float val)
+{
+ PATCH_FLOAT_GET
+ f->mod_amt = val;
+}
+
+
+void
+patch_float_set_mod_src(int patch_id, PatchFloatType floattype, int mod_id)
+{
+ PATCH_FLOAT_GET
+ f->mod_id = mod_id;
+}
+
+
+void patch_float_get_all(int patch_id, PatchFloatType floattype,
+ float* value, float* mod_amt, int* mod_id)
+{
+ PATCH_FLOAT_GET
+ *value = f->val;
+ *mod_amt = f->mod_amt;
+ *mod_id = f->mod_id;
+}
+
+
+float patch_float_get_value(int patch_id, PatchFloatType floattype)
+{
+ PATCH_FLOAT_GET
+ return f->val;
+}
+
+
+float patch_float_get_mod_amt(int patch_id, PatchFloatType floattype)
+{
+ PATCH_FLOAT_GET
+ return f->mod_amt;
+}
+
+
+int patch_float_get_mod_src(int patch_id, PatchFloatType floattype)
+{
+ PATCH_FLOAT_GET
+ return f->mod_id;
+}
+
+
+
+/**************************************************************************/
+/****************** LFO FREQ MODULATION SETTERS ***************************/
+/**************************************************************************/
+
+#define PATCH_LFO_CHECKS \
+ LFO* lfo; \
+ LFOParams* lfopar; \
+ if (!(lfopar = lfopar_from_id(patch_id, lfo_id, &lfo))) \
+ return -1;
+
+#define PATCH_NULL_LFO_CHECKS \
+ LFOParams* lfopar; \
+ if (!(lfopar = lfopar_from_id(patch_id, lfo_id, NULL))) \
+ return -1;
+
+
+int patch_set_lfo_fm1_src(int patch_id, int lfo_id, int modsrc_id)
+{
+ PATCH_LFO_CHECKS
+ lfopar->fm1_id = modsrc_id;
+
+ if (lfo)
+ patch_trigger_global_lfo(patch_id, lfo, lfopar);
+
+ return 0;
+}
+
+int patch_set_lfo_fm2_src(int patch_id, int lfo_id, int modsrc_id)
+{
+ PATCH_LFO_CHECKS
+ lfopar->fm2_id = modsrc_id;
+
+ if (lfo)
+ patch_trigger_global_lfo(patch_id, lfo, lfopar);
+
+ return 0;
+}
+
+int patch_set_lfo_fm1_amt(int patch_id, int lfo_id, float amount)
+{
+ PATCH_LFO_CHECKS
+ lfopar->fm1_amt = amount;
+
+ if (lfo)
+ patch_trigger_global_lfo(patch_id, lfo, lfopar);
+
+ return 0;
+}
+
+int patch_set_lfo_fm2_amt(int patch_id, int lfo_id, float amount)
+{
+ PATCH_LFO_CHECKS
+ lfopar->fm2_amt = amount;
+
+ if (lfo)
+ patch_trigger_global_lfo(patch_id, lfo, lfopar);
+
+ return 0;
+}
+
+
+
+/**************************************************************************/
+/****************** LFO FREQ MODULATION GETTERS ***************************/
+/**************************************************************************/
+
+int patch_get_lfo_fm1_src(int patch_id, int lfo_id)
+{
+ PATCH_NULL_LFO_CHECKS
+ return lfopar->fm1_id;
+}
+
+int patch_get_lfo_fm2_src(int patch_id, int lfo_id)
+{
+ PATCH_NULL_LFO_CHECKS
+ return lfopar->fm2_id;
+}
+
+float patch_get_lfo_fm1_amt(int patch_id, int lfo_id)
+{
+ PATCH_NULL_LFO_CHECKS
+ return lfopar->fm1_amt;
+}
+
+float patch_get_lfo_fm2_amt(int patch_id, int lfo_id)
+{
+ PATCH_NULL_LFO_CHECKS
+ return lfopar->fm2_amt;
+}
+
+
+/**************************************************************************/
+/******************* LFO AMP MODULATION SETTERS ***************************/
+/**************************************************************************/
+
+int patch_set_lfo_am1_src(int patch_id, int lfo_id, int modsrc_id)
+{
+ PATCH_LFO_CHECKS
+ lfopar->am1_id = modsrc_id;
+
+ if (lfo)
+ patch_trigger_global_lfo(patch_id, lfo, lfopar);
+
+ return 0;
+}
+
+int patch_set_lfo_am2_src(int patch_id, int lfo_id, int modsrc_id)
+{
+ PATCH_LFO_CHECKS
+ lfopar->am2_id = modsrc_id;
+
+ if (lfo)
+ patch_trigger_global_lfo(patch_id, lfo, lfopar);
+
+ return 0;
+}
+
+int patch_set_lfo_am1_amt(int patch_id, int lfo_id, float amount)
+{
+ PATCH_LFO_CHECKS
+ lfopar->am1_amt = amount;
+
+ if (lfo)
+ patch_trigger_global_lfo(patch_id, lfo, lfopar);
+
+ return 0;
+}
+
+int patch_set_lfo_am2_amt(int patch_id, int lfo_id, float amount)
+{
+ PATCH_LFO_CHECKS
+ lfopar->am2_amt = amount;
+
+ if (lfo)
+ patch_trigger_global_lfo(patch_id, lfo, lfopar);
+
+ return 0;
+}
+
+
+
+/**************************************************************************/
+/******************* LFO AMP MODULATION GETTERS ***************************/
+/**************************************************************************/
+
+int patch_get_lfo_am1_src(int patch_id, int lfo_id)
+{
+ PATCH_NULL_LFO_CHECKS
+ return lfopar->am1_id;
+}
+
+int patch_get_lfo_am2_src(int patch_id, int lfo_id)
+{
+ PATCH_NULL_LFO_CHECKS
+ return lfopar->am2_id;
+}
+
+float patch_get_lfo_am1_amt(int patch_id, int lfo_id)
+{
+ PATCH_NULL_LFO_CHECKS
+ return lfopar->am1_amt;
+}
+
+float patch_get_lfo_am2_amt(int patch_id, int lfo_id)
+{
+ PATCH_NULL_LFO_CHECKS
+ return lfopar->am2_amt;
+}
+
+
diff --git a/libpetrifoo/patch_set_and_get.h b/libpetrifoo/patch_set_and_get.h
new file mode 100644
index 0000000..e480e3c
--- /dev/null
+++ b/libpetrifoo/patch_set_and_get.h
@@ -0,0 +1,245 @@
+/* Petri-Foo is a fork of the Specimen audio sampler.
+
+ Original Specimen author Pete Bessman
+ Copyright 2005 Pete Bessman
+ Copyright 2011 James W. Morris
+
+ This file is part of Petri-Foo.
+
+ Petri-Foo is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+
+ Petri-Foo is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Petri-Foo. If not, see <http://www.gnu.org/licenses/>.
+
+ This file is a derivative of a Specimen original, modified 2011
+*/
+
+
+#ifndef __PATCH_SET_AND_GET_H__
+#define __PATCH_SET_AND_GET_H__
+
+
+#include "patch.h"
+
+
+/* **ALL** IDs passed to these functions **MUST** be VALID.
+ * in debugging mode, this is ensured with assertions.
+ *
+ * patch_id: 0,1,2,3... <
+ * env_id: MOD_SRC_EG, +0, +1, +2, +3...
+ * lfo_id: MOD_SRC_LFO, +0, +1, +2, +3...
+ * slot: 0,1,2,3... < MAX_MOD_SLOTS
+ *
+ * ALL setter functions return 0 on success (value set was in
+ * range), and -1 on failure (value set was out of range) and
+ * additionally set an error code (retrievable via pf_error_get).
+ */
+
+
+
+
+
+/* envelope setters */
+int patch_set_env_active (int patch_id, int env_id, bool state);
+int patch_set_env_delay (int patch_id, int env_id, float secs);
+int patch_set_env_attack (int patch_id, int env_id, float secs);
+int patch_set_env_hold (int patch_id, int env_id, float secs);
+int patch_set_env_decay (int patch_id, int env_id, float secs);
+int patch_set_env_sustain (int patch_id, int env_id, float level);
+int patch_set_env_release (int patch_id, int env_id, float secs);
+int patch_set_env_key_amt (int patch_id, int env_id, float val);
+int patch_set_env_vel_amt (int patch_id, int env_id, float val);
+
+/* envelope getters */
+bool patch_get_env_active (int patch_id, int env_id);
+float patch_get_env_delay (int patch_id, int env_id);
+float patch_get_env_attack (int patch_id, int env_id);
+float patch_get_env_hold (int patch_id, int env_id);
+float patch_get_env_decay (int patch_id, int env_id);
+float patch_get_env_sustain (int patch_id, int env_id);
+float patch_get_env_release (int patch_id, int env_id);
+float patch_get_env_key_amt (int patch_id, int env_id);
+float patch_get_env_vel_amt (int patch_id, int env_id);
+
+/* lfo setters */
+int patch_set_lfo_active (int patch_id, int lfo_id, bool state);
+int patch_set_lfo_attack (int patch_id, int lfo_id, float secs);
+int patch_set_lfo_sync_beats(int patch_id, int lfo_id, float beats);
+int patch_set_lfo_delay (int patch_id, int lfo_id, float secs);
+int patch_set_lfo_freq (int patch_id, int lfo_id, float freq);
+int patch_set_lfo_positive (int patch_id, int lfo_id, bool state);
+int patch_set_lfo_shape (int patch_id, int lfo_id, LFOShape shape);
+int patch_set_lfo_sync (int patch_id, int lfo_id, bool state);
+
+/* lfo getters */
+bool patch_get_lfo_active (int patch_id, int lfo_id);
+float patch_get_lfo_attack (int patch_id, int lfo_id);
+float patch_get_lfo_sync_beats(int patch_id, int lfo_id);
+float patch_get_lfo_delay (int patch_id, int lfo_id);
+float patch_get_lfo_freq (int patch_id, int lfo_id);
+bool patch_get_lfo_positive (int patch_id, int lfo_id);
+LFOShape patch_get_lfo_shape (int patch_id, int lfo_id);
+bool patch_get_lfo_sync (int patch_id, int lfo_id);
+
+/* parameter setters */
+int patch_set_channel (int patch_id, int channel);
+int patch_set_cut (int patch_id, int cut);
+int patch_set_cut_by (int patch_id, int cut_by);
+int patch_set_cutoff (int patch_id, float freq);
+int patch_set_legato (int patch_id, bool val);
+int patch_set_lower_note(int patch_id, int note);
+int patch_set_lower_vel (int patch_id, int vel);
+int patch_set_upper_vel (int patch_id, int vel);
+
+/* both of these return mark_id on success */
+int patch_set_mark_frame (int patch_id, int mark_id, int frame);
+
+/* returns mark_id on sucessful setting, if another mark required
+ moving to accomodate the set mark, the id of the moved mark will
+ be set via also_changed which is otherwise -1.
+ */
+int patch_set_mark_frame_expand(int patch_id, int mark_id, int frame,
+ int* also_changed);
+
+int patch_set_monophonic (int id, bool val);
+int patch_set_name (int id, const char* name);
+int patch_set_root_note (int id, int note);
+int patch_set_panning (int id, float pan);
+int patch_set_pitch (int id, float pitch);
+int patch_set_pitch_steps (int id, int steps);
+int patch_set_play_mode (int id, PatchPlayMode mode);
+int patch_set_portamento (int id, bool val);
+int patch_set_portamento_time(int id, float secs);
+int patch_set_resonance (int id, float reso);
+
+int patch_set_upper_note (int id, int note);
+int patch_set_amplitude (int id, float vol);
+
+int patch_set_fade_samples (int id, int samples);
+int patch_set_xfade_samples(int id, int samples);
+
+/* parameter getters */
+int patch_get_channel (int id);
+int patch_get_cut (int id);
+int patch_get_cut_by (int id);
+float patch_get_cutoff (int id);
+int patch_get_display_index (int id);
+int patch_get_frames (int id);
+bool patch_get_legato (int id);
+int patch_get_lower_note (int id);
+int patch_get_lower_vel (int id);
+int patch_get_upper_vel (int id);
+
+int patch_get_mark_frame (int patch_id, int mark_id);
+int patch_get_mark_frame_range (int patch_id, int mark_id,
+ int* frame_min,
+ int* frame_max);
+
+bool patch_get_monophonic (int id);
+char* patch_get_name (int id);
+int patch_get_root_note (int id);
+float patch_get_panning (int id);
+float patch_get_pitch (int id);
+int patch_get_pitch_steps (int id);
+PatchPlayMode patch_get_play_mode (int id);
+bool patch_get_portamento (int id);
+float patch_get_portamento_time (int id);
+
+
+float patch_get_resonance (int id);
+const float* patch_get_sample (int id);
+const char* patch_get_sample_name (int id);
+int patch_get_upper_note (int id);
+float patch_get_amplitude (int id);
+int patch_get_fade_samples (int id);
+int patch_get_xfade_samples (int id);
+int patch_get_max_fade_samples (int id);
+int patch_get_max_xfade_samples (int id);
+
+
+/* returns 0 if non-raw sample loaded */
+int patch_get_raw_samplerate(int id);
+int patch_get_raw_channels(int id);
+int patch_get_raw_sndfile_format(int id);
+
+
+/* param */
+float patch_param_get_value(int patch_id, PatchParamType);
+void patch_param_set_value(int patch_id, PatchParamType, float val);
+
+/* modulation setters */
+int patch_param_set_mod_src(int patch_id, PatchParamType, int slot,
+ int src_id);
+int patch_param_set_mod_amt(int patch_id, PatchParamType, int slot,
+ float amt);
+int patch_param_set_vel_amount(int id, PatchParamType param,float amt);
+int patch_param_set_key_amount(int id, PatchParamType param,float amt);
+
+/* modulation getters */
+int patch_param_get_mod_src(int patch_id, PatchParamType, int slot);
+float patch_param_get_mod_amt(int patch_id, PatchParamType, int slot);
+float patch_param_get_vel_amount(int id, PatchParamType param);
+float patch_param_get_key_amount(int id, PatchParamType param);
+
+
+/* PatchBool set/get */
+void patch_bool_set_active( int patch_id, PatchBoolType, bool);
+void patch_bool_set_thresh( int patch_id, PatchBoolType, float);
+void patch_bool_set_mod_src( int patch_id, PatchBoolType, int mod_id);
+
+
+bool patch_bool_get_active( int patch_id, PatchBoolType);
+float patch_bool_get_thresh( int patch_id, PatchBoolType);
+int patch_bool_get_mod_src( int patch_id, PatchBoolType);
+void patch_bool_get_all( int patch_id, PatchBoolType,
+ bool* active,
+ float* thresh,
+ int* mod_id);
+
+/* PatchFloat set/get */
+void patch_float_set_value( int patch_id, PatchFloatType, float);
+void patch_float_set_mod_src(int patch_id, PatchFloatType, int mod_id);
+void patch_float_set_mod_amt(int patch_id, PatchFloatType, float);
+
+float patch_float_get_value( int patch_id, PatchFloatType);
+int patch_float_get_mod_src(int patch_id, PatchFloatType);
+float patch_float_get_mod_amt(int patch_id, PatchFloatType);
+void patch_float_get_all( int patch_id, PatchFloatType,
+ float* value,
+ float* mod_amt,
+ int* mod_id);
+
+/* lfo freq modulation setters */
+int patch_set_lfo_fm1_src(int patch_id, int lfo_id, int modsrc_id);
+int patch_set_lfo_fm2_src(int patch_id, int lfo_id, int modsrc_id);
+int patch_set_lfo_fm1_amt(int patch_id, int lfo_id, float amount);
+int patch_set_lfo_fm2_amt(int patch_id, int lfo_id, float amount);
+
+/* lfo amp modulation setters */
+int patch_set_lfo_am1_src(int patch_id, int lfo_id, int modsrc_id);
+int patch_set_lfo_am2_src(int patch_id, int lfo_id, int modsrc_id);
+int patch_set_lfo_am1_amt(int patch_id, int lfo_id, float amount);
+int patch_set_lfo_am2_amt(int patch_id, int lfo_id, float amount);
+
+/* lfo freq modulation getters */
+int patch_get_lfo_fm1_src(int patch_id, int lfo_id);
+int patch_get_lfo_fm2_src(int patch_id, int lfo_id);
+float patch_get_lfo_fm1_amt(int patch_id, int lfo_id);
+float patch_get_lfo_fm2_amt(int patch_id, int lfo_id);
+
+/* lfo amp modulation getters */
+int patch_get_lfo_am1_src(int patch_id, int lfo_id);
+int patch_get_lfo_am2_src(int patch_id, int lfo_id);
+float patch_get_lfo_am1_amt(int patch_id, int lfo_id);
+float patch_get_lfo_am2_amt(int patch_id, int lfo_id);
+
+
+
+#endif /* __PATCH_SET_AND_GET_H__ */
diff --git a/src/patch_util.c b/libpetrifoo/patch_util.c
similarity index 81%
rename from src/patch_util.c
rename to libpetrifoo/patch_util.c
index 4721917..5b43fd9 100644
--- a/src/patch_util.c
+++ b/libpetrifoo/patch_util.c
@@ -24,6 +24,7 @@
#include "patch_util.h"
+#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
@@ -34,6 +35,7 @@
#include "maths.h"
#include "ticks.h"
#include "patch.h"
+#include "pf_error.h"
#include "sample.h"
#include "adsr.h"
#include "lfo.h"
@@ -48,10 +50,6 @@
#include "patch_private/patch_macros.h"
-/*
-static int start_frame = 0;
-*/
-
/**************************************************************************/
/********************** PRIVATE GENERAL HELPER FUNCTIONS*******************/
/**************************************************************************/
@@ -60,7 +58,7 @@ static int start_frame = 0;
/* inline definitions shared by patch and patch_util:
* (see private/patch_data.h)
*/
-INLINE_ISOK_DEF
+INLINE_PATCHOK_DEF
INLINE_PATCH_LOCK_DEF
INLINE_PATCH_TRYLOCK_DEF
INLINE_PATCH_UNLOCK_DEF
@@ -117,16 +115,17 @@ int patch_create(void)
/* find unoccupied patch id */
for (id = 0; patches[id] && patches[id]->active; ++id)
if (id == PATCH_COUNT)
- return PATCH_LIMIT;
+ {
+ pf_error(PF_ERR_PATCH_COUNT);
+ return -1;
+ }
if (!(p = patch_new()))
{
- errmsg("Failed to create new patch\n");
- return PATCH_ALLOC_FAIL;
+ pf_error(PF_ERR_PATCH_ALLOC);
+ return -1;
}
- debug("Creating patch %d [%p]\n", id, p);
-
patches[id] = p;
patch_lock(id);
p->active = true;
@@ -149,13 +148,13 @@ int patch_create_default(void)
patch_lock(id);
- p->play_mode = PATCH_PLAY_LOOP | PATCH_PLAY_FORWARD;
+ p->play_mode = PATCH_PLAY_LOOP;
p->fade_samples = DEFAULT_FADE_SAMPLES;
p->xfade_samples = DEFAULT_FADE_SAMPLES;
/* adsr */
eg1 = &p->env_params[0];
- eg1->env_on = true;
+ eg1->active = true;
eg1->attack = 0.005;
eg1->release = 0.375;
eg1->key_amt = -0.99;
@@ -163,41 +162,41 @@ int patch_create_default(void)
/* controllers... */
/* pitch */
- patch_set_mod_src( id, PATCH_PARAM_PITCH, 0, MOD_SRC_PITCH_WHEEL);
- patch_set_mod_amt( id, PATCH_PARAM_PITCH, 0,
+ patch_param_set_mod_src(id, PATCH_PARAM_PITCH, 0, MOD_SRC_PITCH_WHEEL);
+ patch_param_set_mod_amt(id, PATCH_PARAM_PITCH, 0,
6.0f / PATCH_MAX_PITCH_STEPS);
- patch_set_mod_src( id, PATCH_PARAM_PITCH, 1, MOD_SRC_VLFO);
- patch_set_mod_amt( id, PATCH_PARAM_PITCH, 1,
+ patch_param_set_mod_src(id, PATCH_PARAM_PITCH, 1, MOD_SRC_VLFO);
+ patch_param_set_mod_amt(id, PATCH_PARAM_PITCH, 1,
2.0f / PATCH_MAX_PITCH_STEPS);
/* AMPLITUDE EG_MOD_SLOT has full effect, no need to set amount */
- patch_set_mod_src( id, PATCH_PARAM_AMPLITUDE, EG_MOD_SLOT,
+ patch_param_set_mod_src(id, PATCH_PARAM_AMPLITUDE, EG_MOD_SLOT,
MOD_SRC_EG);
- patch_set_mod_src( id, PATCH_PARAM_AMPLITUDE, 0,
+ patch_param_set_mod_src(id, PATCH_PARAM_AMPLITUDE, 0,
MOD_SRC_MIDI_CC | CC_CHANNEL_VOLUME);
- patch_set_mod_amt( id, PATCH_PARAM_AMPLITUDE, 0, 1.0f);
+ patch_param_set_mod_amt(id, PATCH_PARAM_AMPLITUDE, 0, 1.0f);
/* pan */
- patch_set_mod_src( id, PATCH_PARAM_PANNING, 0,
+ patch_param_set_mod_src(id, PATCH_PARAM_PANNING, 0,
MOD_SRC_MIDI_CC | CC_PAN);
- patch_set_mod_amt( id, PATCH_PARAM_PANNING, 0, 1.0f);
+ patch_param_set_mod_amt(id, PATCH_PARAM_PANNING, 0, 1.0f);
/* filter cutoff */
patch_param_set_value( id, PATCH_PARAM_CUTOFF, 0.5f);
- patch_set_mod_src( id, PATCH_PARAM_CUTOFF, 0,
+ patch_param_set_mod_src(id, PATCH_PARAM_CUTOFF, 0,
MOD_SRC_MIDI_CC | CC_SNDCTRL5_BRIGHTNESS);
- patch_set_mod_amt( id, PATCH_PARAM_CUTOFF, 0, 1.0f);
+ patch_param_set_mod_amt(id, PATCH_PARAM_CUTOFF, 0, 1.0f);
/* filter resonance */
patch_param_set_value( id, PATCH_PARAM_RESONANCE, 0.0f);
- patch_set_mod_src( id, PATCH_PARAM_RESONANCE, 0,
+ patch_param_set_mod_src(id, PATCH_PARAM_RESONANCE, 0,
MOD_SRC_MIDI_CC | CC_SNDCTRL2_TIMBRE);
- patch_set_mod_amt( id, PATCH_PARAM_RESONANCE, 0, 0.975f);
+ patch_param_set_mod_amt(id, PATCH_PARAM_RESONANCE, 0, 0.975f);
/* setup VLFO0 to provide the pitch modulation */
- patch_set_lfo_on( id, MOD_SRC_VLFO, true);
+ patch_set_lfo_active( id, MOD_SRC_VLFO, true);
patch_set_lfo_freq( id, MOD_SRC_VLFO, 9);
/* and the MOD WHEEL to modulate VLFO0 amplitude */
@@ -210,6 +209,8 @@ int patch_create_default(void)
patch_sample_load(id, "Default", 0, 0, 0);
p->lower_note = 36;
p->upper_note = 83;
+ p->lower_vel = 0;
+ p->upper_vel = 127;
patch_set_name(id, "Default");
@@ -217,13 +218,12 @@ int patch_create_default(void)
}
-int patch_destroy(int id)
+void patch_destroy(int id)
{
int index;
Patch* p;
- if (!isok(id))
- return PATCH_ID_INVALID;
+ assert(patchok(id));
debug ("Removing patch: %d\n", id);
@@ -250,8 +250,6 @@ int patch_destroy(int id)
--patches[id]->display_index;
}
}
-
- return 0;
}
@@ -262,7 +260,8 @@ void patch_destroy_all(void)
int id;
for (id = 0; id < PATCH_COUNT; id++)
- patch_destroy (id);
+ if (patches[id])
+ patch_destroy (id);
return;
}
@@ -285,7 +284,10 @@ int patch_dump(int **dump)
/* allocate dump */
*dump = malloc(sizeof(int) * count);
if (*dump == NULL)
- return PATCH_ALLOC_FAIL;
+ {
+ pf_error(PF_ERR_PATCH_DUMP_ALLOC);
+ return -1;
+ }
/* place active patches into dump array */
for (id = i = 0; id < PATCH_COUNT; id++)
@@ -321,8 +323,8 @@ int patch_dump(int **dump)
if (patches[(*dump)[k]]->channel != i)
continue;
- if (patches[(*dump)[k]]->note <
- patches[(*dump)[j]]->note)
+ if (patches[(*dump)[k]]->root_note <
+ patches[(*dump)[j]]->root_note)
{
tmp = (*dump)[j];
(*dump)[j] = (*dump)[k];
@@ -340,19 +342,13 @@ int patch_duplicate(int src_id)
int i;
int dest_id;
- if (!isok(src_id))
- return PATCH_ID_INVALID;
-
- if (!patches[src_id]->active)
- return PATCH_ID_INVALID;
+ assert(patchok(src_id));
+ assert(patches[src_id]->active);
dest_id = patch_create();
if (dest_id < 0)
- {
- debug("couldn't duplicate\n");
- return dest_id;
- }
+ return -1;
debug("Creating patch (%d) from patch %s (%d).\n", dest_id,
patches[src_id]->name, src_id);
@@ -387,11 +383,10 @@ int patch_duplicate(int src_id)
int patch_flush (int id)
{
int i;
-
- if (!isok(id))
- return PATCH_ID_INVALID;
-debug("flusing:%d\n",id);
+ assert(patchok(id));
+
+ debug("flusing:%d\n",id);
patch_lock (id);
@@ -409,7 +404,7 @@ debug("flusing:%d\n",id);
patch_unlock (id);
-debug("done\n");
+ debug("done\n");
return 0;
}
@@ -419,53 +414,11 @@ void patch_flush_all ( )
int i;
for (i = 0; i < PATCH_COUNT; i++)
- patch_flush (i);
+ if (patches[i])
+ patch_flush (i);
}
-/* returns error message associated with error code */
-const char *patch_strerror (int error)
-{
- switch (error)
- {
- case PATCH_PARAM_INVALID:
- return "patch parameter is invalid";
- break;
- case PATCH_ID_INVALID:
- return "patch id is invalid";
- break;
- case PATCH_ALLOC_FAIL:
- return "failed to allocate space for patch";
- break;
- case PATCH_NOTE_INVALID:
- return "specified note is invalid";
- break;
- case PATCH_PAN_INVALID:
- return "specified panning is invalid";
- break;
- case PATCH_CHANNEL_INVALID:
- return "specified channel is invalid";
- break;
- case PATCH_VOL_INVALID:
- return "specified amplitude is invalid";
- break;
- case PATCH_PLAY_MODE_INVALID:
- return "specified patch play mode is invalid";
- break;
- case PATCH_LIMIT:
- return "maximum patch count reached, can't create another";
- break;
- case PATCH_SAMPLE_INDEX_INVALID:
- return "specified sample is invalid";
- break;
- default:
- return "unknown error";
- break;
- }
-}
-
-
-
/* loads a sample file for a patch */
int patch_sample_load(int id, const char *name,
int raw_samplerate,
@@ -473,18 +426,17 @@ int patch_sample_load(int id, const char *name,
int sndfile_format)
{
int val;
+ double ratio = (patch_samplerate == 44100)
+ ? 1
+ : (patch_samplerate / 44100.0f);
+ int frames;
+
bool defsample = (strcmp(name, "Default") == 0);
- if (!isok (id))
- return PATCH_ID_INVALID;
+ assert(patchok(id));
+ assert(name != NULL);
- if (name == NULL)
- {
- debug ("Refusing to load null sample for patch %d\n", id);
- return PATCH_PARAM_INVALID;
- }
-
- debug ("Loading sample %s for patch %d\n", name, id);
+ debug("Loading sample %s for patch %d\n", name, id);
patch_flush (id);
/* we lock *after* we call patch_flush because patch_flush does
@@ -500,22 +452,27 @@ int patch_sample_load(int id, const char *name,
raw_channels,
sndfile_format);
- patches[id]->sample_stop = patches[id]->sample->frames - 1;
+ if (val < 0)
+ frames = 0;
+ else
+ frames = patches[id]->sample->frames - 1;
+
+ patches[id]->sample_stop = frames;
patches[id]->play_start = 0;
patches[id]->play_stop = patches[id]->sample_stop;
if (defsample)
{
- patches[id]->loop_start = 296;
- patches[id]->loop_stop = 5203;
- patches[id]->fade_samples = 100;
+ patches[id]->loop_start = 296 * ratio;
+ patches[id]->loop_stop = 5203 * ratio;
+ patches[id]->fade_samples = 100 * ratio;
patches[id]->xfade_samples = 0;
}
else
{
- patches[id]->fade_samples = 100;
- patches[id]->xfade_samples = 100;
+ patches[id]->fade_samples = (frames / 2 > 100) ? 100 * ratio : 0;
+ patches[id]->xfade_samples = (frames / 2 > 100) ? 100 * ratio : 0;
patches[id]->loop_start = patches[id]->xfade_samples;
patches[id]->loop_stop = patches[id]->sample_stop -
patches[id]->xfade_samples;
@@ -535,8 +492,8 @@ int patch_sample_load_from(int dest_id, int src_id)
const char* name;
bool defsample;
- if (!isok(dest_id) || !isok(src_id))
- return PATCH_ID_INVALID;
+ assert(patchok(dest_id));
+ assert(patchok(src_id));
name = patches[src_id]->sample->filename;
defsample = (strcmp(name, "Default") == 0);
@@ -576,9 +533,7 @@ int patch_sample_load_from(int dest_id, int src_id)
const Sample* patch_sample_data(int id)
{
- if (!isok(id))
- return 0;
-
+ assert(patchok(id));
return patches[id]->sample;
}
@@ -586,9 +541,8 @@ const Sample* patch_sample_data(int id)
/* unloads a patch's sample */
void patch_sample_unload (int id)
{
- if (!isok(id))
- return;
-
+ assert(patchok(id));
+
debug ("Unloading sample for patch %d\n", id);
patch_lock (id);
@@ -661,6 +615,13 @@ void patch_set_samplerate (int rate)
}
}
+
+int patch_get_samplerate(void)
+{
+ return patch_samplerate;
+}
+
+
/* destructor */
void patch_shutdown ( )
{
diff --git a/src/patch_util.h b/libpetrifoo/patch_util.h
similarity index 95%
rename from src/patch_util.h
rename to libpetrifoo/patch_util.h
index 6fbe3de..9ef82ac 100644
--- a/src/patch_util.h
+++ b/libpetrifoo/patch_util.h
@@ -37,7 +37,7 @@ enum { USER_PATCH, DEFAULT_PATCH };
int patch_create (void);
int patch_create_default (void);
-int patch_destroy (int id);
+void patch_destroy (int id);
void patch_destroy_all (void);
int patch_count (void);
@@ -57,8 +57,12 @@ int patch_sample_load_from(int dest_id, int src_id);
const Sample* patch_sample_data(int id);
void patch_sample_unload (int id);
+
+
void patch_set_buffersize (int nframes);
void patch_set_samplerate (int rate);
+int patch_get_samplerate (void);
+
void patch_shutdown (void);
void patch_sync (float bpm);
int patch_verify (int id);
diff --git a/src/petri-foo.h b/libpetrifoo/petri-foo.h
similarity index 53%
rename from src/petri-foo.h
rename to libpetrifoo/petri-foo.h
index 29eafdf..bf6975f 100644
--- a/src/petri-foo.h
+++ b/libpetrifoo/petri-foo.h
@@ -25,26 +25,47 @@
#ifndef __SPECIMEN_H__
#define __SPECIMEN_H__
-#include <config.h>
+#include "config.h"
#include <stdio.h>
#include <signal.h>
+
+#define DEFAULT_AMPLITUDE 0.7
+
+
+#define CHARBUFSIZE 256
+
+
#ifndef DEBUG
-# define DEBUG 0
+#define DEBUG 0
#endif
-enum
-{
- FUBAR = -69
-};
-
-#define DEFAULT_AMPLITUDE 0.7 /* default amplitude stuff is set to, from 0 to 1 */
+/*
+#define errmsg(fmt, ...) \
+{ \
+ msg_log(MSG_CRITICAL, \
+ "%20s:%5d\t%30s" fmt, \
+ __FILE__, __LINE__, __FUNCTION__ , ## __VA_ARGS__); \
+}
-#ifndef PIXMAPSDIR
-# define PIXMAPSDIR INSTALLDIR"/petri-foo/pixmaps/"
+#if DEBUG
+#define debug(fmt, ...) \
+{ \
+ msg_log(MSG_DEBUG, \
+ "%20s:%5d\t%30s" fmt, \
+ __FILE__, __LINE__, __FUNCTION__ , ## __VA_ARGS__); \
+}
+#else
+#define debug(...)
#endif
+*/
-#define errmsg(...) {fprintf(stderr, "%20s:%5d\t%30s", __FILE__, __LINE__, __FUNCTION__); fprintf(stderr, ": "); fprintf(stderr, __VA_ARGS__);}
+#define errmsg(...) \
+{ \
+ fprintf(stderr, "%20s:%5d\t%30s", __FILE__, __LINE__, __FUNCTION__); \
+ fprintf(stderr, ": "); \
+ fprintf(stderr, __VA_ARGS__); \
+}
#if DEBUG
# define debug(...) errmsg(__VA_ARGS__)
@@ -52,6 +73,8 @@ enum
# define debug(...)
#endif
+
typedef sig_atomic_t Atomic;
+
#endif /* __SPECIMEN_H__ */
diff --git a/libpetrifoo/pf_error.c b/libpetrifoo/pf_error.c
new file mode 100644
index 0000000..8472e17
--- /dev/null
+++ b/libpetrifoo/pf_error.c
@@ -0,0 +1,96 @@
+#include "pf_error.h"
+
+#include <assert.h>
+#include "petri-foo.h"
+
+static int last_error_no = PF_ERR_INVALID_ERROR;
+
+
+void pf_error(int pf_error_no)
+{
+ assert (last_error_no == PF_ERR_INVALID_ERROR);
+ last_error_no = pf_error_no;
+}
+
+
+int pf_error_get(void)
+{
+ int errno = last_error_no;
+ last_error_no = PF_ERR_INVALID_ERROR;
+}
+
+const char* pf_error_str(int pf_error_no)
+{
+ switch(pf_error_no)
+ {
+ /* JACK errors */
+ case PF_ERR_JACK_OPEN_CLIENT:
+ return "JACK failed to open client";
+ case PF_ERR_JACK_ACTIVATE:
+ return "JACK failed to activate client";
+ case PF_ERR_JACK_SESSION_CB:
+ return "JACK failed to set session callback";
+ case PF_ERR_JACK_BUF_ALLOC:
+ return "JACK failed to allocate buffer";
+ case PF_ERR_JACK_BUF_SIZE_CHANGE:
+ return "JACK failed buffer size change";
+
+ /* Patch errors */
+ case PF_ERR_PATCH_ID:
+ return "Invalid patch ID";
+ case PF_ERR_PATCH_COUNT:
+ return "Maximum patch count exceeded";
+ case PF_ERR_PATCH_ALLOC:
+ return "Patch allocation failed";
+ case PF_ERR_PATCH_DUMP_ALLOC:
+ return "Patch dump allocation failed";
+ case PF_ERR_PATCH_PARAM_ID:
+ return "Invalid param ID";
+ case PF_ERR_PATCH_BOOL_ID:
+ return "Invalid bool ID";
+ case PF_ERR_PATCH_FLOAT_ID:
+ return "Invalid float ID";
+ case PF_ERR_PATCH_ENV_ID:
+ return "Invalid ADSR ID";
+ case PF_ERR_PATCH_LFO_ID:
+ return "Invalid LFO ID";
+ case PF_ERR_PATCH_MOD_SRC_ID:
+ return "Invalid modulation-source ID";
+ case PF_ERR_PATCH_MOD_SLOT:
+ return "Invalid modulation-slot ID";
+ case PF_ERR_PATCH_CHANNEL:
+ return "Invalid channel number";
+ case PF_ERR_PATCH_NOTE:
+ return "Invalid note";
+ case PF_ERR_PATCH_PARAM_VALUE:
+ return "Invalud parameter value";
+
+ /* Sample errors */
+ case PF_ERR_SAMPLE_ALLOC:
+ return "Failed to allocate sample";
+ case PF_ERR_SAMPLE_DEFAULT_ALLOC:
+ return "Failed to allocate default sample";
+ case PF_ERR_SAMPLE_ALLOC_COPY:
+ return "Failed to allocate duplicate sample";
+ case PF_ERR_SAMPLE_MAX_FRAMES:
+ return "Sample is too long";
+ case PF_ERR_SAMPLE_RESAMPLE_MAX_FRAMES:
+ return "Sample (after resampling) is too long";
+ case PF_ERR_SAMPLE_RESAMPLE_ALLOC:
+ return "Failed to allocate resampling data";
+ case PF_ERR_SAMPLE_CHANNEL_COUNT:
+ return "Sample contains too many channels";
+ case PF_ERR_SAMPLE_CHANNEL_ALLOC:
+ return "Allocation for mono to stereo conversion failed";
+ case PF_ERR_SAMPLE_SNDFILE_FORMAT:
+ return "Sndfile format error";
+ case PF_ERR_SAMPLE_SNDFILE_OPEN:
+ return "Sndfile could not open sample";
+ case PF_ERR_SAMPLE_SNDFILE_READ:
+ return "Sndfile could not read sample";
+ case PF_ERR_SAMPLE_SRC_SIMPLE:
+ return "Secret Rabbit Code resample failed";
+ default:
+ return "uncategorized error";
+ }
+}
diff --git a/libpetrifoo/pf_error.h b/libpetrifoo/pf_error.h
new file mode 100644
index 0000000..efc3642
--- /dev/null
+++ b/libpetrifoo/pf_error.h
@@ -0,0 +1,57 @@
+#ifndef PF_ERROR_H
+#define PF_ERROR_H
+
+enum
+{
+ PF_ERR_INVALID_ERROR = -1,
+
+ /* JACK errors */
+ PF_ERR_JACK_OPEN_CLIENT,
+ PF_ERR_JACK_ACTIVATE,
+ PF_ERR_JACK_SESSION_CB,
+ PF_ERR_JACK_BUF_ALLOC,
+ PF_ERR_JACK_BUF_SIZE_CHANGE,
+
+ /* Patch errors */
+ /* (note: ID errors are only introducible via dish_file_read) */
+ PF_ERR_PATCH_ID,
+ PF_ERR_PATCH_COUNT,
+ PF_ERR_PATCH_ALLOC,
+ PF_ERR_PATCH_DUMP_ALLOC,
+ PF_ERR_PATCH_PARAM_ID,
+ PF_ERR_PATCH_BOOL_ID,
+ PF_ERR_PATCH_FLOAT_ID,
+ PF_ERR_PATCH_ENV_ID,
+ PF_ERR_PATCH_LFO_ID,
+ PF_ERR_PATCH_MOD_SRC_ID,
+ PF_ERR_PATCH_MOD_SLOT,
+ PF_ERR_PATCH_CHANNEL,
+ PF_ERR_PATCH_NOTE,
+
+ PF_ERR_PATCH_VALUE_NEGATIVE,
+ PF_ERR_PATCH_VALUE_LEVEL,
+
+ PF_ERR_PATCH_PARAM_VALUE,
+
+ /* Sample errors */
+ PF_ERR_SAMPLE_ALLOC,
+ PF_ERR_SAMPLE_DEFAULT_ALLOC,
+ PF_ERR_SAMPLE_ALLOC_COPY,
+ PF_ERR_SAMPLE_MAX_FRAMES,
+ PF_ERR_SAMPLE_RESAMPLE_MAX_FRAMES,
+ PF_ERR_SAMPLE_RESAMPLE_ALLOC,
+ PF_ERR_SAMPLE_CHANNEL_COUNT,
+ PF_ERR_SAMPLE_CHANNEL_ALLOC,
+ PF_ERR_SAMPLE_SNDFILE_FORMAT,
+ PF_ERR_SAMPLE_SNDFILE_OPEN,
+ PF_ERR_SAMPLE_SNDFILE_READ,
+ PF_ERR_SAMPLE_SRC_SIMPLE,
+};
+
+
+void pf_error(int pf_error_no);
+int pf_error_get(void);
+const char* pf_error_str(int pf_error_no);
+
+
+#endif
diff --git a/src/sample.c b/libpetrifoo/sample.c
similarity index 62%
rename from src/sample.c
rename to libpetrifoo/sample.c
index 8d54a25..001e375 100644
--- a/src/sample.c
+++ b/libpetrifoo/sample.c
@@ -27,10 +27,12 @@
#include <string.h>
#include <sndfile.h>
#include <samplerate.h>
+
+#include "lfo.h"
#include "petri-foo.h"
+#include "pf_error.h"
+#include "names.h"
#include "sample.h"
-#include "lfo.h"
-
#include <stdbool.h>
@@ -40,7 +42,10 @@ Sample* sample_new(void)
Sample* sample = malloc(sizeof(*sample));
if (!sample)
+ {
+ pf_error(PF_ERR_SAMPLE_ALLOC);
return 0;
+ }
sample->sp = 0;
sample->frames = 0;
@@ -55,6 +60,7 @@ Sample* sample_new(void)
return sample;
}
+
void sample_free (Sample* sample)
{
free(sample->filename);
@@ -85,12 +91,15 @@ int sample_default(Sample* sample, int rate)
LFO* lfo;
LFOParams lfopar;
int i;
+ double v;
float const* lfo_out;
+ debug("Creating default sample\n");
+
if (!(tmp = malloc(frames * 2 * sizeof(*tmp))))
{
- errmsg("Unable to allocate space for (default) samples!\n");
+ pf_error(PF_ERR_SAMPLE_DEFAULT_ALLOC);
return -1;
}
@@ -107,13 +116,11 @@ int sample_default(Sample* sample, int rate)
for (i = 0; i < frames; ++i)
{
lfo_tick(lfo);
- *tmp++ = *lfo_out;
- *tmp++ = *lfo_out;
- if (*lfo_out < -1.0 || *lfo_out > 1.0)
- {
- debug("lfo output %1.3f clips -1.0 || 1.0\n", *lfo_out);
- }
+ v = *lfo_out * 0.9;
+
+ *tmp++ = v;
+ *tmp++ = v;
}
lfo_free(lfo);
@@ -128,48 +135,44 @@ int sample_default(Sample* sample, int rate)
static float* resample(float* samples, int rate, SF_INFO* sfinfo)
{
double ratio;
- int frames;
+ int err;
+ SRC_DATA src;
+ float* tmp;
ratio = rate / (sfinfo->samplerate * 1.0);
- frames = (int)sfinfo->frames;
- debug("Resampling...\n");
-
- int err;
- SRC_DATA src;
- float* tmp = malloc(sizeof(float) * sfinfo->frames
- * sfinfo->channels
- * ratio);
- if (!tmp)
- {
- errmsg ("Out of memory for resampling\n");
- return 0;
- }
+ debug("Resampling from %d to %d\n", rate, sfinfo->samplerate);
src.src_ratio = ratio;
src.data_in = samples;
- src.data_out = tmp;
src.input_frames = sfinfo->frames;
src.output_frames = sfinfo->frames * ratio;
- frames = (int)src.output_frames;
+ if (src.output_frames >= MAX_SAMPLE_FRAMES)
+ {
+ pf_error(PF_ERR_SAMPLE_RESAMPLE_MAX_FRAMES);
+ return 0;
+ }
- if (frames != src.output_frames)
+ tmp = malloc(sizeof(float)
+ * sfinfo->frames * sfinfo->channels * ratio);
+ if (!tmp)
{
- errmsg("resampled sample would be too long\n");
- free(tmp);
+ pf_error(PF_ERR_SAMPLE_RESAMPLE_ALLOC);
return 0;
}
+ src.data_out = tmp;
+
err = src_simple(&src, SRC_SINC_BEST_QUALITY, sfinfo->channels);
if (err)
{
- errmsg("Failed to resample (%s)\n", src_strerror(err));
+ pf_error(PF_ERR_SAMPLE_SRC_SIMPLE);
free(tmp);
return 0;
}
- sfinfo->frames = frames;
+ sfinfo->frames = src.output_frames;
return tmp;
}
@@ -177,14 +180,14 @@ static float* resample(float* samples, int rate, SF_INFO* sfinfo)
static float* mono_to_stereo(float* samples, SF_INFO* sfinfo)
{
- debug ("Converting mono to stereo...\n");
+ debug("Converting mono to stereo...\n");
int i;
float* tmp = malloc(sizeof(float) * sfinfo->frames * 2);
if (!tmp)
{
- errmsg ("Out of memory for mono to stereo conversion.\n");
+ pf_error(PF_ERR_SAMPLE_CHANNEL_ALLOC);
return 0;
}
@@ -198,17 +201,16 @@ static float* mono_to_stereo(float* samples, SF_INFO* sfinfo)
static float* read_audio(SNDFILE* sfp, SF_INFO* sfinfo)
{
float* tmp;
- int frames = (int)sfinfo->frames;
- if (frames != sfinfo->frames)
+ if (sfinfo->frames >= MAX_SAMPLE_FRAMES)
{
- errmsg("sample is too long\n");
+ pf_error(PF_ERR_SAMPLE_MAX_FRAMES);
return 0;
}
if (sfinfo->channels > 2)
{
- errmsg ("Data can't have more than 2 channels\n");
+ pf_error(PF_ERR_SAMPLE_CHANNEL_COUNT);
sf_close (sfp);
return 0;
}
@@ -216,7 +218,7 @@ static float* read_audio(SNDFILE* sfp, SF_INFO* sfinfo)
/* set aside space for samples */
if (!(tmp = malloc(sfinfo->frames * sfinfo->channels * sizeof(*tmp))))
{
- errmsg ("Unable to allocate space for samples!\n");
+ pf_error(PF_ERR_SAMPLE_ALLOC);
sf_close (sfp);
return 0;
}
@@ -224,44 +226,115 @@ static float* read_audio(SNDFILE* sfp, SF_INFO* sfinfo)
/* load sample file into memory */
if (sf_readf_float(sfp, tmp, sfinfo->frames) != sfinfo->frames)
{
- errmsg("libsndfile had problems reading file, aborting\n");
+ pf_error(PF_ERR_SAMPLE_SNDFILE_READ);
free(tmp);
return 0;
}
- debug ("Read %d frames into memory.\n", (int) sfinfo->frames);
+ debug("Read %d frames into memory.\n", (int) sfinfo->frames);
return tmp;
}
-int sample_load_file(Sample* sample, const char* name,
- int rate,
+static SNDFILE* open_sample(SF_INFO* sfinfo, const char* name,
int raw_samplerate,
int raw_channels,
int sndfile_format)
{
- SNDFILE* sfp;
- SF_INFO sfinfo = { 0, 0, 0, 0, 0, 0 };
- float* tmp;
+ SNDFILE* sfp = NULL;
+
bool raw = (raw_samplerate || raw_channels || sndfile_format);
+ sfinfo->frames = 0;
+ sfinfo->samplerate = 0;
+ sfinfo->channels = 0;
+ sfinfo->format = 0;
+ sfinfo->sections = 0;
+ sfinfo->seekable = 0;
+
if (raw)
{
- sfinfo.samplerate = raw_samplerate;
- sfinfo.channels = raw_channels;
- sfinfo.format = sndfile_format;
+ id_name* idnames = names_sample_raw_format_get();
+ char* fmt_name = 0;
+ int i;
+
+ for (i = 0; idnames[i].name != 0; ++i)
+ if (idnames[i].id == sndfile_format)
+ fmt_name = idnames[i].name;
- if (!sf_format_check(&sfinfo))
+ sfinfo->samplerate = raw_samplerate;
+ sfinfo->channels = raw_channels;
+ sfinfo->format = sndfile_format;
+
+ debug("Reading raw sample %s as %d %s %s\n",
+ name, raw_samplerate,
+ (raw_channels == 2)? "stereo" : "mono",
+ fmt_name);
+
+ if (!sf_format_check(sfinfo))
{
- debug("LIBSNDFILE found error in format. aborting.\n");
- return -1;
+ pf_error(PF_ERR_SAMPLE_SNDFILE_FORMAT);
+ return 0;
}
}
+ else
+ debug("Reading sample %s\n", name);
- if ((sfp = sf_open(name, SFM_READ, &sfinfo)) == NULL)
+ if ((sfp = sf_open(name, SFM_READ, sfinfo)) == NULL)
+ {
+ pf_error(PF_ERR_SAMPLE_SNDFILE_OPEN);
+ return 0;
+ }
+
+ return sfp;
+}
+
+
+int sample_get_resampled_size(const char* name, int rate,
+ int raw_samplerate,
+ int raw_channels,
+ int sndfile_format)
+{
+ SF_INFO sfinfo;
+ SNDFILE* sfp;
+ sf_count_t frames;
+
+ if (!(sfp = open_sample(&sfinfo, name, raw_samplerate,
+ raw_channels,
+ sndfile_format)))
+ {
+ return -1;
+ }
+
+ sf_close(sfp);
+
+ if (sfinfo.samplerate == rate)
+ {
+ double ratio = rate / (sfinfo.samplerate * 1.0);
+ frames = sfinfo.frames * ratio;
+ }
+ else
+ frames = sfinfo.frames;
+
+ return frames < MAX_SAMPLE_FRAMES ? frames : 0;
+}
+
+
+int sample_load_file(Sample* sample, const char* name,
+ int rate,
+ int raw_samplerate,
+ int raw_channels,
+ int sndfile_format)
+{
+ float* tmp;
+ SF_INFO sfinfo;
+ SNDFILE* sfp;
+
+ if (!(sfp = open_sample(&sfinfo, name, raw_samplerate,
+ raw_channels,
+ sndfile_format)))
{
- debug ("libsndfile doesn't like %s\n", name);
return -1;
}
@@ -270,6 +343,19 @@ int sample_load_file(Sample* sample, const char* name,
sf_close(sfp);
+ if (raw_samplerate || raw_channels || sndfile_format)
+ {
+ sample->raw_samplerate = raw_samplerate;
+ sample->raw_channels = raw_channels;
+ sample->sndfile_format = sndfile_format;
+ }
+ else
+ {
+ sample->raw_samplerate = 0;
+ sample->raw_channels = 0;
+ sample->sndfile_format = 0;
+ }
+
if (sfinfo.samplerate != rate)
{
float* tmp2 = resample(tmp, rate, &sfinfo);
@@ -277,7 +363,6 @@ int sample_load_file(Sample* sample, const char* name,
if (!tmp2)
{
free(tmp);
- debug("failed to resample file\n");
return -1;
}
@@ -292,7 +377,6 @@ int sample_load_file(Sample* sample, const char* name,
if (!tmp2)
{
free(tmp);
- debug("failed to convert mono to stereo\n");
return -1;
}
@@ -300,35 +384,16 @@ int sample_load_file(Sample* sample, const char* name,
tmp = tmp2;
}
-debug("freeing old sample data\n");
-
free(sample->sp);
free(sample->filename);
-debug("setting new sample data\n");
-
sample->filename = strdup(name);
sample->sp = tmp;
sample->frames = sfinfo.frames;
- if (raw)
- {
- sample->raw_samplerate = raw_samplerate;
- sample->raw_channels = raw_channels;
- sample->sndfile_format = sndfile_format;
- }
- else
- {
- sample->raw_samplerate = 0;
- sample->raw_channels = 0;
- sample->sndfile_format = 0;
- }
-
sample->default_sample = false;
-debug("sample loaded\n");
-
return 0;
}
@@ -353,7 +418,7 @@ int sample_deep_copy(Sample* dest, const Sample* src)
if (!dest->sp)
{
- debug("Failed to allocate memory for sample data copy\n");
+ pf_error(PF_ERR_SAMPLE_ALLOC_COPY);
return -1;
}
diff --git a/src/sample.h b/libpetrifoo/sample.h
similarity index 83%
rename from src/sample.h
rename to libpetrifoo/sample.h
index 722d76e..da88045 100644
--- a/src/sample.h
+++ b/libpetrifoo/sample.h
@@ -27,6 +27,10 @@
#include <stdbool.h>
+#include <stdint.h>
+
+
+enum { MAX_SAMPLE_FRAMES = INT32_MAX };
typedef struct _RAW_FORMAT
@@ -44,11 +48,8 @@ struct _Sample
{
/* Public */
float* sp; /* samples pointer */
- int frames; /* number of frames (not samples).
- * samples whose length exceeds int on the
- * system they're to run on are disallowed.
- * (on 64bit, this still is OTT long).
- */
+ int frames; /* number of frames (not samples)
+ (frames < MAX_SAMPLE_FRAMES) == true */
int raw_samplerate; /* if the sample was a regular sound file ie */
int raw_channels; /* with a header, then these fields will be */
@@ -70,6 +71,12 @@ void sample_shallow_copy(Sample* dest, const Sample* src);
int sample_deep_copy(Sample* dest, const Sample* src);
+int sample_get_resampled_size(const char* name, int rate,
+ /* zero for non-raw data */ int raw_samplerate,
+ /* zero for non-raw data */ int raw_channels,
+ /* zero for non-raw data */ int sndfile_format);
+
+
int sample_load_file(Sample*, const char* name, int rate,
/* zero for non-raw data */ int raw_samplerate,
/* zero for non-raw data */ int raw_channels,
diff --git a/src/sync.c b/libpetrifoo/sync.c
similarity index 100%
rename from src/sync.c
rename to libpetrifoo/sync.c
diff --git a/src/sync.h b/libpetrifoo/sync.h
similarity index 100%
rename from src/sync.h
rename to libpetrifoo/sync.h
diff --git a/src/ticks.c b/libpetrifoo/ticks.c
similarity index 100%
rename from src/ticks.c
rename to libpetrifoo/ticks.c
diff --git a/src/ticks.h b/libpetrifoo/ticks.h
similarity index 100%
rename from src/ticks.h
rename to libpetrifoo/ticks.h
diff --git a/libpetrifui/CMakeLists.txt b/libpetrifui/CMakeLists.txt
new file mode 100644
index 0000000..84493d5
--- /dev/null
+++ b/libpetrifui/CMakeLists.txt
@@ -0,0 +1,22 @@
+
+file (GLOB LIBPETRIFUI_SOURCES *.c)
+
+include_directories (
+ ${Petri-Foo_SOURCE_DIR}/libpetrifoo
+ ${LIBXML2_INCLUDE_DIRS}
+ )
+
+link_directories (
+ ${LIBXML2_LIBRARY_DIRS}
+ )
+
+add_definitions (
+ ${LIBXML2_CFLAGS_OTHER}
+ )
+
+add_library( petrifui ${LIBPETRIFUI_SOURCES})
+
+target_link_Libraries( petrifui
+ petrifoo
+ ${LIBXML2_LIBRARIES}
+ )
diff --git a/src/dish_file.c b/libpetrifui/dish_file.c
similarity index 69%
rename from src/dish_file.c
rename to libpetrifui/dish_file.c
index 0a9fd15..08dcb3d 100644
--- a/src/dish_file.c
+++ b/libpetrifui/dish_file.c
@@ -29,16 +29,18 @@
#include "mixer.h"
#include "mod_src.h"
-#include "petri-foo.h"
+#include "msg_log.h"
#include "patch.h"
#include "patch_util.h"
#include "patch_set_and_get.h"
+#include "petri-foo.h"
+#include "pf_error.h"
#include "sample.h"
-#define BUFSIZE 256
static const char* dish_file_ext = ".petri-foo";
+static int dish_file_samplerate = 0;
const char* dish_file_extension(void)
@@ -76,20 +78,20 @@ static int dish_file_write_sample_raw(xmlNodePtr nodeparent, int patch_id)
{
xmlNodePtr node;
const Sample* s = patch_sample_data(patch_id);
- char buf[BUFSIZE];
+ char buf[CHARBUFSIZE];
if (!(s->raw_samplerate || s->raw_channels || s->sndfile_format))
return 0;
node = xmlNewTextChild(nodeparent, NULL, BAD_CAST "Raw", NULL);
- snprintf(buf, BUFSIZE, "%d", s->raw_samplerate);
+ snprintf(buf, CHARBUFSIZE, "%d", s->raw_samplerate);
xmlNewProp(node, BAD_CAST "samplerate", BAD_CAST buf);
- snprintf(buf, BUFSIZE, "%d", s->raw_channels);
+ snprintf(buf, CHARBUFSIZE, "%d", s->raw_channels);
xmlNewProp(node, BAD_CAST "channels", BAD_CAST buf);
- snprintf(buf, BUFSIZE, "%d", s->sndfile_format);
+ snprintf(buf, CHARBUFSIZE, "%d", s->sndfile_format);
xmlNewProp(node, BAD_CAST "sndfile_format", BAD_CAST buf);
return 0;
@@ -102,7 +104,7 @@ dish_file_write_param(xmlNodePtr nodeparent, int patch_id,
{
xmlNodePtr node1;
xmlNodePtr node2;
- char buf[BUFSIZE];
+ char buf[CHARBUFSIZE];
const char** param_names;
const char* prop1 = 0;
@@ -111,22 +113,17 @@ dish_file_write_param(xmlNodePtr nodeparent, int patch_id,
float val1;
float val2;
float vel_amt;
+ float key_trk;
int modsrc;
float modamt;
- float velsens;
- float keytrack;
int last_mod_slot = MAX_MOD_SLOTS;
int i;
- if (patch_param_get_value(patch_id, param, &val1)
- == PATCH_PARAM_INVALID)
- return -1;
+ val1 = patch_param_get_value(patch_id, param);
param_names = names_params_get();
- patch_get_vel_amount(patch_id, param, &vel_amt);
-
switch(param)
{
case PATCH_PARAM_AMPLITUDE: prop1 = "level"; prop2 = 0;
@@ -144,42 +141,42 @@ dish_file_write_param(xmlNodePtr nodeparent, int patch_id,
node1 = xmlNewTextChild(nodeparent, NULL,
BAD_CAST param_names[param], NULL);
- snprintf(buf, BUFSIZE, "%f", val1);
+ snprintf(buf, CHARBUFSIZE, "%f", val1);
xmlNewProp(node1, BAD_CAST prop1, BAD_CAST buf);
if (prop2)
{
- snprintf(buf, BUFSIZE, "%f", val2);
+ snprintf(buf, CHARBUFSIZE, "%f", val2);
xmlNewProp(node1, BAD_CAST prop2, BAD_CAST buf);
}
/* velocity sensing */
- patch_get_vel_amount(patch_id, param, &velsens);
- snprintf(buf, BUFSIZE, "%f", velsens);
+ vel_amt = patch_param_get_vel_amount(patch_id, param);
+ snprintf(buf, CHARBUFSIZE, "%f", vel_amt);
xmlNewProp(node1, BAD_CAST "velocity_sensing", BAD_CAST buf);
/* keyboard tracking */
- patch_get_key_amount(patch_id, param, &keytrack);
- snprintf(buf, BUFSIZE, "%f", keytrack);
+ key_trk = patch_param_get_key_amount(patch_id, param);
+ snprintf(buf, CHARBUFSIZE, "%f", key_trk);
xmlNewProp(node1, BAD_CAST "key_tracking", BAD_CAST buf);
for (i = 0; i < last_mod_slot; ++i)
{
- snprintf(buf, BUFSIZE, "Mod%d", i + 1);
+ snprintf(buf, CHARBUFSIZE, "Mod%d", i + 1);
- patch_get_mod_src(patch_id, param, i, &modsrc);
- patch_get_mod_amt(patch_id, param, i, &modamt);
+ modsrc = patch_param_get_mod_src(patch_id, param, i);
+ modamt = patch_param_get_mod_amt(patch_id, param, i);
node2 = xmlNewTextChild(node1, NULL, BAD_CAST buf, NULL);
xmlNewProp(node2, BAD_CAST "source", BAD_CAST mod_src_name(modsrc));
- snprintf(buf, BUFSIZE, "%f", modamt);
+ snprintf(buf, CHARBUFSIZE, "%f", modamt);
xmlNewProp(node2, BAD_CAST "amount", BAD_CAST buf);
}
if (param == PATCH_PARAM_AMPLITUDE)
{
- patch_get_mod_src(patch_id, PATCH_PARAM_AMPLITUDE,
- EG_MOD_SLOT, &modsrc);
+ modsrc = patch_param_get_mod_src(patch_id, PATCH_PARAM_AMPLITUDE,
+ EG_MOD_SLOT);
node2 = xmlNewTextChild(node1, NULL, BAD_CAST "Env", NULL);
xmlNewProp(node2, BAD_CAST "source", BAD_CAST mod_src_name(modsrc));
}
@@ -189,15 +186,100 @@ dish_file_write_param(xmlNodePtr nodeparent, int patch_id,
static int
+dish_file_write_bool(xmlNodePtr nodeparent, int patch_id,
+ PatchBoolType bool_type)
+{
+ xmlNodePtr node1;
+ xmlNodePtr node2;
+ char buf[CHARBUFSIZE];
+ const char* nodestr;
+
+ bool set;
+ float thresh;
+ int modsrc;
+
+ switch(bool_type)
+ {
+ case PATCH_BOOL_PORTAMENTO:
+ nodestr = "Portamento";
+ break;
+ case PATCH_BOOL_MONO:
+ nodestr = "Mono";
+ break;
+ case PATCH_BOOL_LEGATO:
+ nodestr = "Legato";
+ break;
+ default:
+ return -1;
+ }
+
+ patch_bool_get_all(patch_id, bool_type, &set, &thresh, &modsrc);
+
+ node1 = xmlNewTextChild(nodeparent, NULL, BAD_CAST nodestr, NULL);
+
+ xmlNewProp(node1, BAD_CAST "active",
+ BAD_CAST ((set) ? "true" : "false"));
+
+ node2 = xmlNewTextChild(node1, NULL, BAD_CAST "Mod", NULL);
+
+ xmlNewProp(node2, BAD_CAST "source", BAD_CAST mod_src_name(modsrc));
+
+ snprintf(buf, CHARBUFSIZE, "%f", thresh);
+ xmlNewProp(node2, BAD_CAST "threshold", BAD_CAST buf);
+
+ return 0;
+}
+
+
+static int
+dish_file_write_float(xmlNodePtr nodeparent, int patch_id,
+ PatchFloatType float_type)
+{
+ xmlNodePtr node1;
+ xmlNodePtr node2;
+ char buf[CHARBUFSIZE];
+ const char* nodestr;
+
+ float val;
+ float modamt;
+ int modsrc;
+
+ switch(float_type)
+ {
+ case PATCH_FLOAT_PORTAMENTO_TIME:
+ nodestr = "Portamento_time";
+ break;
+ default:
+ return -1;
+ }
+
+ patch_float_get_all(patch_id, float_type, &val, &modamt, &modsrc);
+
+ node1 = xmlNewTextChild(nodeparent, NULL, BAD_CAST nodestr, NULL);
+
+ snprintf(buf, CHARBUFSIZE, "%f", val);
+ xmlNewProp(node1, BAD_CAST "value", BAD_CAST buf);
+
+ node2 = xmlNewTextChild(node1, NULL, BAD_CAST "Mod", NULL);
+
+ xmlNewProp(node2, BAD_CAST "source", BAD_CAST mod_src_name(modsrc));
+
+ snprintf(buf, CHARBUFSIZE, "%f", modamt);
+ xmlNewProp(node2, BAD_CAST "amount", BAD_CAST buf);
+
+ return 0;
+}
+
+
+static int
dish_file_write_eg(xmlNodePtr nodeparent, int patch_id, int eg_id)
{
xmlNodePtr node1;
- char buf[BUFSIZE];
+ char buf[CHARBUFSIZE];
bool active;
float val;
- if (patch_get_env_on(patch_id, eg_id, &active) == -1)
- return -1;
+ active = patch_get_env_active(patch_id, eg_id);
node1 = xmlNewTextChild(nodeparent, NULL,
BAD_CAST mod_src_name(eg_id), NULL);
@@ -205,32 +287,32 @@ dish_file_write_eg(xmlNodePtr nodeparent, int patch_id, int eg_id)
xmlNewProp(node1, BAD_CAST "active",
BAD_CAST (active ? "true" : "false"));
- patch_get_env_delay(patch_id, eg_id, &val);
- snprintf(buf, BUFSIZE, "%f", val);
+ val = patch_get_env_delay(patch_id, eg_id);
+ snprintf(buf, CHARBUFSIZE, "%f", val);
xmlNewProp(node1, BAD_CAST "delay", BAD_CAST buf);
- patch_get_env_attack(patch_id, eg_id, &val);
- snprintf(buf, BUFSIZE, "%f", val);
+ val = patch_get_env_attack(patch_id, eg_id);
+ snprintf(buf, CHARBUFSIZE, "%f", val);
xmlNewProp(node1, BAD_CAST "attack", BAD_CAST buf);
- patch_get_env_hold(patch_id, eg_id, &val);
- snprintf(buf, BUFSIZE, "%f", val);
+ val = patch_get_env_hold(patch_id, eg_id);
+ snprintf(buf, CHARBUFSIZE, "%f", val);
xmlNewProp(node1, BAD_CAST "hold", BAD_CAST buf);
- patch_get_env_decay(patch_id, eg_id, &val);
- snprintf(buf, BUFSIZE, "%f", val);
+ val = patch_get_env_decay(patch_id, eg_id);
+ snprintf(buf, CHARBUFSIZE, "%f", val);
xmlNewProp(node1, BAD_CAST "decay", BAD_CAST buf);
- patch_get_env_sustain(patch_id, eg_id, &val);
- snprintf(buf, BUFSIZE, "%f", val);
+ val = patch_get_env_sustain(patch_id, eg_id);
+ snprintf(buf, CHARBUFSIZE, "%f", val);
xmlNewProp(node1, BAD_CAST "sustain", BAD_CAST buf);
- patch_get_env_release(patch_id, eg_id, &val);
- snprintf(buf, BUFSIZE, "%f", val);
+ val = patch_get_env_release(patch_id, eg_id);
+ snprintf(buf, CHARBUFSIZE, "%f", val);
xmlNewProp(node1, BAD_CAST "release", BAD_CAST buf);
- patch_get_env_key_amt(patch_id, eg_id, &val);
- snprintf(buf, BUFSIZE, "%f", val);
+ val = patch_get_env_key_amt(patch_id, eg_id);
+ snprintf(buf, CHARBUFSIZE, "%f", val);
xmlNewProp(node1, BAD_CAST "key_tracking", BAD_CAST buf);
return 0;
@@ -243,7 +325,7 @@ dish_file_write_lfo(xmlNodePtr nodeparent, int patch_id, int lfo_id)
xmlNodePtr node1;
xmlNodePtr node2;
xmlNodePtr node3;
- char buf[BUFSIZE];
+ char buf[CHARBUFSIZE];
bool state;
float val;
const char** shapes = names_lfo_shapes_get();
@@ -253,8 +335,7 @@ dish_file_write_lfo(xmlNodePtr nodeparent, int patch_id, int lfo_id)
float mod2amt;
LFOShape shape;
- if (patch_get_lfo_on(patch_id, lfo_id, &state) == -1)
- return -1;
+ state = patch_get_lfo_active(patch_id, lfo_id);
node1 = xmlNewTextChild(nodeparent, NULL,
BAD_CAST mod_src_name(lfo_id), NULL);
@@ -263,68 +344,68 @@ dish_file_write_lfo(xmlNodePtr nodeparent, int patch_id, int lfo_id)
BAD_CAST (state ? "true" : "false"));
node2 = xmlNewTextChild(node1, NULL, BAD_CAST "Frequency", NULL);
- patch_get_lfo_freq(patch_id, lfo_id, &val);
- snprintf(buf, BUFSIZE, "%f", val);
+ val = patch_get_lfo_freq(patch_id, lfo_id);
+ snprintf(buf, CHARBUFSIZE, "%f", val);
xmlNewProp(node2, BAD_CAST "hrtz", BAD_CAST buf);
- patch_get_lfo_beats(patch_id, lfo_id, &val);
- snprintf(buf, BUFSIZE, "%f", val);
+ val = patch_get_lfo_sync_beats(patch_id, lfo_id);
+ snprintf(buf, CHARBUFSIZE, "%f", val);
xmlNewProp(node2, BAD_CAST "beats", BAD_CAST buf);
- patch_get_lfo_sync(patch_id, lfo_id, &state);
+ val = patch_get_lfo_sync(patch_id, lfo_id);
xmlNewProp(node2, BAD_CAST "sync",
BAD_CAST (state ? "true" : "false"));
- patch_get_lfo_fm1_src(patch_id, lfo_id, &mod1src);
- patch_get_lfo_fm1_amt(patch_id, lfo_id, &mod1amt);
- patch_get_lfo_fm2_src(patch_id, lfo_id, &mod2src);
- patch_get_lfo_fm2_amt(patch_id, lfo_id, &mod2amt);
+ mod1src = patch_get_lfo_fm1_src(patch_id, lfo_id);
+ mod1amt = patch_get_lfo_fm1_amt(patch_id, lfo_id);
+ mod2src = patch_get_lfo_fm2_src(patch_id, lfo_id);
+ mod2amt = patch_get_lfo_fm2_amt(patch_id, lfo_id);
node3 = xmlNewTextChild(node2, NULL, BAD_CAST "Mod1", NULL);
xmlNewProp(node3, BAD_CAST "source", BAD_CAST mod_src_name(mod1src));
- snprintf(buf, BUFSIZE, "%f", mod1amt);
+ snprintf(buf, CHARBUFSIZE, "%f", mod1amt);
xmlNewProp(node3, BAD_CAST "amount", BAD_CAST buf);
node3 = xmlNewTextChild(node2, NULL, BAD_CAST "Mod2", NULL);
xmlNewProp(node3, BAD_CAST "source", BAD_CAST mod_src_name(mod2src));
- snprintf(buf, BUFSIZE, "%f", mod2amt);
+ snprintf(buf, CHARBUFSIZE, "%f", mod2amt);
xmlNewProp(node3, BAD_CAST "amount", BAD_CAST buf);
node2 = xmlNewTextChild(node1, NULL, BAD_CAST "Amplitude", NULL);
- patch_get_lfo_shape(patch_id, lfo_id, &shape);
+ shape = patch_get_lfo_shape(patch_id, lfo_id);
xmlNewProp(node2, BAD_CAST "shape", BAD_CAST shapes[shape]);
- patch_get_lfo_positive(patch_id, lfo_id, &state);
+ state = patch_get_lfo_positive(patch_id, lfo_id);
xmlNewProp(node2, BAD_CAST "positive",
BAD_CAST (state ? "true" : "false"));
/* assured by caller that lfo_id IS an lfo_id */
if (!mod_src_is_global(lfo_id))
{
- patch_get_lfo_delay(patch_id, lfo_id, &val);
- snprintf(buf, BUFSIZE, "%f", val);
+ val = patch_get_lfo_delay(patch_id, lfo_id);
+ snprintf(buf, CHARBUFSIZE, "%f", val);
xmlNewProp(node2, BAD_CAST "delay", BAD_CAST buf);
- patch_get_lfo_attack(patch_id, lfo_id, &val);
- snprintf(buf, BUFSIZE, "%f", val);
+ val = patch_get_lfo_attack(patch_id, lfo_id);
+ snprintf(buf, CHARBUFSIZE, "%f", val);
xmlNewProp(node2, BAD_CAST "attack", BAD_CAST buf);
}
- patch_get_lfo_am1_src(patch_id, lfo_id, &mod1src);
- patch_get_lfo_am1_amt(patch_id, lfo_id, &mod1amt);
- patch_get_lfo_am2_src(patch_id, lfo_id, &mod2src);
- patch_get_lfo_am2_amt(patch_id, lfo_id, &mod2amt);
+ mod1src = patch_get_lfo_am1_src(patch_id, lfo_id);
+ mod1amt = patch_get_lfo_am1_amt(patch_id, lfo_id);
+ mod2src = patch_get_lfo_am2_src(patch_id, lfo_id);
+ mod2amt = patch_get_lfo_am2_amt(patch_id, lfo_id);
node3 = xmlNewTextChild(node2, NULL, BAD_CAST "Mod1", NULL);
xmlNewProp(node3, BAD_CAST "source", BAD_CAST mod_src_name(mod1src));
- snprintf(buf, BUFSIZE, "%f", mod1amt);
+ snprintf(buf, CHARBUFSIZE, "%f", mod1amt);
xmlNewProp(node3, BAD_CAST "amount", BAD_CAST buf);
node3 = xmlNewTextChild(node2, NULL, BAD_CAST "Mod2", NULL);
xmlNewProp(node3, BAD_CAST "source", BAD_CAST mod_src_name(mod2src));
- snprintf(buf, BUFSIZE, "%f", mod2amt);
+ snprintf(buf, CHARBUFSIZE, "%f", mod2amt);
xmlNewProp(node3, BAD_CAST "amount", BAD_CAST buf);
return 0;
@@ -341,7 +422,7 @@ int dish_file_write(const char *name)
xmlNodePtr node1;
xmlNodePtr node2;
- char buf[BUFSIZE];
+ char buf[CHARBUFSIZE];
int i, j;
int* patch_id;
int patch_count;
@@ -361,9 +442,13 @@ int dish_file_write(const char *name)
*/
node1 = xmlNewTextChild(noderoot, NULL, BAD_CAST "Master", NULL);
- snprintf(buf, BUFSIZE, "%f", mixer_get_amplitude());
+ snprintf(buf, CHARBUFSIZE, "%f", mixer_get_amplitude());
xmlNewProp(node1, BAD_CAST "level", BAD_CAST buf);
+ snprintf(buf, CHARBUFSIZE, "%d", patch_get_samplerate());
+ xmlNewProp(node1, BAD_CAST "samplerate", BAD_CAST buf);
+
+
/* ------------------------
patches
*/
@@ -379,7 +464,7 @@ int dish_file_write(const char *name)
xmlNewProp(nodepatch, BAD_CAST "name",
BAD_CAST patch_get_name(patch_id[i]));
- snprintf(buf, BUFSIZE, "%d", patch_get_channel(patch_id[i]));
+ snprintf(buf, CHARBUFSIZE, "%d", patch_get_channel(patch_id[i]));
xmlNewProp(nodepatch, BAD_CAST "channel", BAD_CAST buf);
/* ------------------------
@@ -398,42 +483,51 @@ int dish_file_write(const char *name)
/* sample play */
node2 = xmlNewTextChild(node1, NULL, BAD_CAST "Play", NULL);
- snprintf(buf, BUFSIZE, "%d",
+ snprintf(buf, CHARBUFSIZE, "%d",
patch_get_mark_frame(patch_id[i], WF_MARK_PLAY_START));
xmlNewProp(node2, BAD_CAST "start", BAD_CAST buf);
- snprintf(buf, BUFSIZE, "%d",
+ snprintf(buf, CHARBUFSIZE, "%d",
patch_get_mark_frame(patch_id[i], WF_MARK_PLAY_STOP));
xmlNewProp(node2, BAD_CAST "stop", BAD_CAST buf);
- snprintf(buf, BUFSIZE, "%d", patch_get_fade_samples(patch_id[i]));
+ snprintf(buf, CHARBUFSIZE, "%d",
+ patch_get_fade_samples(patch_id[i]));
xmlNewProp(node2, BAD_CAST "fade_samples", BAD_CAST buf);
/* sample loop */
node2 = xmlNewTextChild(node1, NULL, BAD_CAST "Loop", NULL);
- snprintf(buf, BUFSIZE, "%d",
+ snprintf(buf, CHARBUFSIZE, "%d",
patch_get_mark_frame(patch_id[i], WF_MARK_LOOP_START));
xmlNewProp(node2, BAD_CAST "start", BAD_CAST buf);
- snprintf(buf, BUFSIZE, "%d",
+ snprintf(buf, CHARBUFSIZE, "%d",
patch_get_mark_frame(patch_id[i], WF_MARK_LOOP_STOP));
xmlNewProp(node2, BAD_CAST "stop", BAD_CAST buf);
- snprintf(buf, BUFSIZE, "%d", patch_get_xfade_samples(patch_id[i]));
+ snprintf(buf, CHARBUFSIZE, "%d",
+ patch_get_xfade_samples(patch_id[i]));
xmlNewProp(node2, BAD_CAST "xfade_samples", BAD_CAST buf);
/* sample note */
node2 = xmlNewTextChild(node1, NULL, BAD_CAST "Note", NULL);
- snprintf(buf, BUFSIZE, "%d", patch_get_note(patch_id[i]));
+ snprintf(buf, CHARBUFSIZE, "%d", patch_get_root_note(patch_id[i]));
xmlNewProp(node2, BAD_CAST "root", BAD_CAST buf);
- snprintf(buf, BUFSIZE, "%d", patch_get_lower_note(patch_id[i]));
+ snprintf(buf, CHARBUFSIZE, "%d", patch_get_lower_note(patch_id[i]));
xmlNewProp(node2, BAD_CAST "lower", BAD_CAST buf);
- snprintf(buf, BUFSIZE, "%d", patch_get_upper_note(patch_id[i]));
+ snprintf(buf, CHARBUFSIZE, "%d", patch_get_upper_note(patch_id[i]));
xmlNewProp(node2, BAD_CAST "upper", BAD_CAST buf);
+
+ snprintf(buf, CHARBUFSIZE, "%d", patch_get_lower_vel(patch_id[i]));
+ xmlNewProp(node2, BAD_CAST "velocity_lower", BAD_CAST buf);
+
+ snprintf(buf, CHARBUFSIZE, "%d", patch_get_upper_vel(patch_id[i]));
+ xmlNewProp(node2, BAD_CAST "velocity_upper", BAD_CAST buf);
+
/* ------------------------
amplitude
@@ -463,23 +557,19 @@ int dish_file_write(const char *name)
node1 = xmlNewTextChild(nodepatch, NULL, BAD_CAST "Voice", NULL);
/* voice cut */
- snprintf(buf, BUFSIZE, "%d", patch_get_cut(patch_id[i]));
+ snprintf(buf, CHARBUFSIZE, "%d", patch_get_cut(patch_id[i]));
xmlNewProp(node1, BAD_CAST "cut", BAD_CAST buf);
/* voice cut by */
- snprintf(buf, BUFSIZE, "%d", patch_get_cut_by(patch_id[i]));
+ snprintf(buf, CHARBUFSIZE, "%d", patch_get_cut_by(patch_id[i]));
xmlNewProp(node1, BAD_CAST "cut_by", BAD_CAST buf);
/* voice portamento */
- xmlNewProp(node1, BAD_CAST "portamento",
- BAD_CAST (patch_get_portamento(patch_id[i])
- ? "true"
- : "false"));
+ dish_file_write_bool(node1, patch_id[i], PATCH_BOOL_PORTAMENTO);
/* voice portamento_time */
- snprintf(buf, BUFSIZE, "%f",
- patch_get_portamento_time(patch_id[i]));
- xmlNewProp(node1, BAD_CAST "portamento_time", BAD_CAST buf);
+ dish_file_write_float(node1, patch_id[i],
+ PATCH_FLOAT_PORTAMENTO_TIME);
/* voice monophonic */
xmlNewProp(node1, BAD_CAST "monophonic",
@@ -488,10 +578,7 @@ int dish_file_write(const char *name)
: "false"));
/* voice legato */
- xmlNewProp(node1, BAD_CAST "legato",
- BAD_CAST (patch_get_legato(patch_id[i])
- ? "true"
- : "false"));
+ dish_file_write_bool(node1, patch_id[i], PATCH_BOOL_LEGATO);
/* ------------------------
envelopes
@@ -540,6 +627,14 @@ int dish_file_read_sample(xmlNodePtr node, int patch_id)
char* filename = 0;
bool sample_loaded = false;
+ double sr_ratio = 1.0;
+
+ if (dish_file_samplerate
+ && dish_file_samplerate != patch_get_samplerate())
+ sr_ratio = patch_get_samplerate() / (double)dish_file_samplerate;
+
+debug("sr_ratio:%f\n",sr_ratio);
+
int mode = PATCH_PLAY_SINGLESHOT;
if ((prop = xmlGetProp(node, BAD_CAST "file")))
@@ -557,15 +652,13 @@ int dish_file_read_sample(xmlNodePtr node, int patch_id)
mode = PATCH_PLAY_LOOP | PATCH_PLAY_PINGPONG;
else
{
- errmsg("invalid play mode:%s\n", prop);
+ msg_log(MSG_ERROR, "Invalid sample play mode:%s\n", prop);
}
}
if ((prop = xmlGetProp(node, BAD_CAST "reverse"))
&& xmlstr_to_bool(prop))
mode |= PATCH_PLAY_REVERSE;
- else
- mode |= PATCH_PLAY_FORWARD;
if ((prop = xmlGetProp(node, BAD_CAST "to_end"))
&& xmlstr_to_bool(prop))
@@ -586,7 +679,6 @@ int dish_file_read_sample(xmlNodePtr node, int patch_id)
int raw_samplerate = 0;
int raw_channels = 0;
int sndfile_format = 0;
- int err;
if (xmlStrcmp(node1->name, BAD_CAST "Raw") == 0)
{
@@ -603,14 +695,13 @@ int dish_file_read_sample(xmlNodePtr node, int patch_id)
sndfile_format = n;
}
- err = patch_sample_load(patch_id, filename,
+ if (patch_sample_load(patch_id, filename,
raw_samplerate,
raw_channels,
- sndfile_format);
- if (err)
+ sndfile_format) < 0)
{
- errmsg("failed to load sample:%s\n", (const char*)filename);
- return 0;
+ msg_log(MSG_ERROR, "failed to load sample: %s error (%s)\n",
+ filename, pf_error_str(pf_error_get()));
}
free(filename);
@@ -625,17 +716,17 @@ int dish_file_read_sample(xmlNodePtr node, int patch_id)
if (sscanf((const char*)prop, "%d", &s) == 1)
patch_set_mark_frame_expand(patch_id,
WF_MARK_PLAY_START,
- s, NULL);
+ s * sr_ratio, NULL);
}
if ((prop = xmlGetProp(node1, BAD_CAST "stop")))
if (sscanf((const char*)prop, "%d", &s) == 1)
patch_set_mark_frame_expand(patch_id,
WF_MARK_PLAY_STOP,
- s, NULL);
+ s * sr_ratio, NULL);
if ((prop = xmlGetProp(node1, BAD_CAST "fade_samples")))
if (sscanf((const char*)prop, "%d", &s) == 1)
- patch_set_fade_samples(patch_id, s);
+ patch_set_fade_samples(patch_id, s * sr_ratio);
}
else if (xmlStrcmp(node1->name, BAD_CAST "Loop") == 0)
{
@@ -643,25 +734,25 @@ int dish_file_read_sample(xmlNodePtr node, int patch_id)
if (sscanf((const char*)prop, "%d", &s) == 1)
patch_set_mark_frame_expand(patch_id,
WF_MARK_LOOP_START,
- s, NULL);
+ s * sr_ratio, NULL);
if ((prop = xmlGetProp(node1, BAD_CAST "stop")))
if (sscanf((const char*)prop, "%d", &s) == 1)
patch_set_mark_frame_expand(patch_id,
WF_MARK_LOOP_STOP,
- s, NULL);
+ s * sr_ratio, NULL);
if ((prop = xmlGetProp(node1, BAD_CAST "xfade_samples")))
if (sscanf((const char*)prop, "%d", &s) == 1)
- patch_set_xfade_samples(patch_id, s);
+ patch_set_xfade_samples(patch_id, s * sr_ratio);
}
else if (xmlStrcmp(node1->name, BAD_CAST "Note") == 0)
{
- int lower, root, upper;
+ int lower, root, upper, lower_vel, upper_vel;
if ((prop = xmlGetProp(node1, BAD_CAST "root")))
if (sscanf((const char*)prop, "%d", &root) == 1)
- patch_set_note(patch_id, root);
+ patch_set_root_note(patch_id, root);
if ((prop = xmlGetProp(node1, BAD_CAST "lower")))
if (sscanf((const char*)prop, "%d", &lower) == 1)
@@ -670,10 +761,19 @@ int dish_file_read_sample(xmlNodePtr node, int patch_id)
if ((prop = xmlGetProp(node1, BAD_CAST "upper")))
if (sscanf((const char*)prop, "%d", &upper) == 1)
patch_set_upper_note(patch_id, upper);
+
+ if ((prop = xmlGetProp(node1, BAD_CAST "velocity_lower")))
+ if (sscanf((const char*)prop, "%d", &lower_vel) == 1)
+ patch_set_lower_vel(patch_id, lower_vel);
+
+ if ((prop = xmlGetProp(node1, BAD_CAST "velocity_upper")))
+ if (sscanf((const char*)prop, "%d", &upper_vel) == 1)
+ patch_set_upper_vel(patch_id, upper_vel);
}
else
{
- errmsg("ignoring:%s\n", node1->name);
+ msg_log(MSG_WARNING, "ignoring XML NODE: %s\n",
+ (const char*)node1->name);
}
}
@@ -689,10 +789,8 @@ int dish_file_read_eg(xmlNodePtr node, int patch_id)
if ((eg_id = mod_src_id((const char*)node->name, MOD_SRC_EG)) < 0)
return -1;
-debug("loading eg with id:%d\n", eg_id);
-
if ((prop = xmlGetProp(node, BAD_CAST "active")))
- patch_set_env_on(patch_id, eg_id, xmlstr_to_bool(prop));
+ patch_set_env_active(patch_id, eg_id, xmlstr_to_bool(prop));
if ((prop = xmlGetProp(node, BAD_CAST "delay")))
if (sscanf((const char*)prop, "%f", &n) == 1)
@@ -737,7 +835,7 @@ int dish_file_read_lfo_freq_data(xmlNodePtr node, int patch_id, int lfo_id)
if ((prop = xmlGetProp(node, BAD_CAST "beats")))
if (sscanf((const char*)prop, "%f", &n) == 1)
- patch_set_lfo_beats(patch_id, lfo_id, n);
+ patch_set_lfo_sync_beats(patch_id, lfo_id, n);
if ((prop = xmlGetProp(node, BAD_CAST "sync")))
patch_set_lfo_sync(patch_id, lfo_id, xmlstr_to_bool(prop));
@@ -771,7 +869,8 @@ int dish_file_read_lfo_freq_data(xmlNodePtr node, int patch_id, int lfo_id)
}
else
{
- errmsg("ignoring:%s\n", (const char*)node1->name);
+ msg_log(MSG_WARNING, "ignoring XML NODE: %s\n",
+ (const char*)node1->name);
}
}
@@ -832,7 +931,8 @@ int dish_file_read_lfo_amp_data(xmlNodePtr node, int patch_id, int lfo_id)
}
else
{
- errmsg("ignoring:%s\n", (const char*)node1->name);
+ msg_log(MSG_WARNING, "ignoring XML NODE: %s\n",
+ (const char*)node1->name);
}
}
@@ -857,7 +957,7 @@ debug("lfo id:%d\n", lfo_id);
}
if ((prop = xmlGetProp(node, BAD_CAST "active")))
- patch_set_lfo_on(patch_id, lfo_id, xmlstr_to_bool(prop));
+ patch_set_lfo_active(patch_id, lfo_id, xmlstr_to_bool(prop));
for ( node1 = node->children;
node1 != NULL;
@@ -876,7 +976,8 @@ debug("lfo id:%d\n", lfo_id);
}
else
{
- errmsg("ignoring:%s\n", (const char*)node1->name);
+ msg_log(MSG_WARNING, "ignoring XML NODE: %s\n",
+ (const char*)node1->name);
}
}
@@ -918,11 +1019,11 @@ int dish_file_read_param(xmlNodePtr node, int patch_id,
if ((prop = xmlGetProp(node, BAD_CAST "velocity_sensing")))
if (sscanf((const char*)prop, "%f", &n) == 1)
- patch_set_vel_amount(patch_id, param, n);
+ patch_param_set_vel_amount(patch_id, param, n);
if ((prop = xmlGetProp(node, BAD_CAST "key_tracking")))
if (sscanf((const char*)prop, "%f", &n) == 1)
- patch_set_key_amount(patch_id, param, n);
+ patch_param_set_key_amount(patch_id, param, n);
for ( node1 = node->children;
node1 != NULL;
@@ -939,23 +1040,102 @@ int dish_file_read_param(xmlNodePtr node, int patch_id,
--slot; /* slot 0 is named as MOD1 */
if ((prop = xmlGetProp(node1, BAD_CAST "source")))
- patch_set_mod_src(patch_id, param, slot,
- mod_src_id((const char*)prop, MOD_SRC_ALL));
+ patch_param_set_mod_src(patch_id, param, slot,
+ mod_src_id((const char*)prop, MOD_SRC_ALL));
if ((prop = xmlGetProp(node1, BAD_CAST "amount")))
if (sscanf((const char*)prop, "%f", &n) == 1)
- patch_set_mod_amt(patch_id, param, slot, n);
+ patch_param_set_mod_amt(patch_id, param, slot, n);
}
else if ((param == PATCH_PARAM_AMPLITUDE
&& xmlStrcmp(node1->name, BAD_CAST "Env") == 0))
{
if ((prop = xmlGetProp(node1, BAD_CAST "source")))
- patch_set_mod_src(patch_id, param, EG_MOD_SLOT,
- mod_src_id((const char*)prop, MOD_SRC_ALL));
+ patch_param_set_mod_src(patch_id, param, EG_MOD_SLOT,
+ mod_src_id((const char*)prop, MOD_SRC_ALL));
}
else
{
- errmsg("ignoring:%s\n", (const char*)node1->name);
+ msg_log(MSG_WARNING, "ignoring XML NODE: %s\n",
+ (const char*)node1->name);
+ }
+ }
+
+ return 0;
+}
+
+
+int dish_file_read_bool(xmlNodePtr node, int patch_id,
+ PatchBoolType bool_type)
+{
+ float n;
+ xmlChar* prop;
+ xmlNodePtr node1;
+
+ if ((prop = xmlGetProp(node, BAD_CAST "active")))
+ patch_bool_set_active(patch_id, bool_type, xmlstr_to_bool(prop));
+
+ for ( node1 = node->children;
+ node1 != NULL;
+ node1 = node1->next)
+ {
+ if (node1->type != XML_ELEMENT_NODE)
+ continue;
+
+ if (xmlStrcmp(node1->name, BAD_CAST "Mod") == 0)
+ {
+ if ((prop = xmlGetProp(node1, BAD_CAST "source")))
+ patch_bool_set_mod_src(patch_id, bool_type,
+ mod_src_id((const char*)prop, MOD_SRC_GLOBALS));
+
+ if ((prop = xmlGetProp(node1, BAD_CAST "threshold")))
+ if (sscanf((const char*)prop, "%f", &n) == 1)
+ patch_bool_set_thresh(patch_id, bool_type, n);
+ }
+ else
+ {
+ msg_log(MSG_WARNING, "ignoring XML NODE: %s\n",
+ (const char*)node1->name);
+ }
+ }
+
+ return 0;
+}
+
+
+
+int dish_file_read_float(xmlNodePtr node, int patch_id,
+ PatchFloatType float_type)
+{
+ float n;
+ xmlChar* prop;
+ xmlNodePtr node1;
+
+ if ((prop = xmlGetProp(node, BAD_CAST "active")))
+ /* FIXME: needs value bounds testing */
+ patch_float_set_value(patch_id, float_type, xmlstr_to_bool(prop));
+
+ for ( node1 = node->children;
+ node1 != NULL;
+ node1 = node1->next)
+ {
+ if (node1->type != XML_ELEMENT_NODE)
+ continue;
+
+ if (xmlStrcmp(node1->name, BAD_CAST "Mod") == 0)
+ {
+ if ((prop = xmlGetProp(node1, BAD_CAST "source")))
+ patch_float_set_mod_src(patch_id, float_type,
+ mod_src_id((const char*)prop, MOD_SRC_GLOBALS));
+
+ if ((prop = xmlGetProp(node1, BAD_CAST "amount")))
+ if (sscanf((const char*)prop, "%f", &n) == 1)
+ patch_float_set_mod_amt(patch_id, float_type, n);
+ }
+ else
+ {
+ msg_log(MSG_WARNING, "ignoring XML NODE: %s\n",
+ (const char*)node1->name);
}
}
@@ -966,7 +1146,8 @@ int dish_file_read_param(xmlNodePtr node, int patch_id,
int dish_file_read_voice(xmlNodePtr node, int patch_id)
{
xmlChar* prop;
- float n;
+ xmlNodePtr node1;
+
int i;
if ((prop = xmlGetProp(node, BAD_CAST "cut")))
@@ -977,18 +1158,35 @@ int dish_file_read_voice(xmlNodePtr node, int patch_id)
if (sscanf((const char*)prop, "%d", &i))
patch_set_cut_by(patch_id, i);
- if ((prop = xmlGetProp(node, BAD_CAST "portamento")))
- patch_set_portamento(patch_id, xmlstr_to_bool(prop));
-
- if ((prop = xmlGetProp(node, BAD_CAST "portamento_time")))
- if (sscanf((const char*)prop, "%f", &n))
- patch_set_portamento_time(patch_id, n);
-
if ((prop = xmlGetProp(node, BAD_CAST "monophonic")))
patch_set_monophonic(patch_id, xmlstr_to_bool(prop));
- if ((prop = xmlGetProp(node, BAD_CAST "legato")))
- patch_set_legato(patch_id, xmlstr_to_bool(prop));
+ for ( node1 = node->children;
+ node1 != NULL;
+ node1 = node1->next)
+ {
+ if (node1->type != XML_ELEMENT_NODE)
+ continue;
+
+ if (xmlStrcmp(node1->name, BAD_CAST "Portamento") == 0)
+ {
+ dish_file_read_bool(node1, patch_id, PATCH_BOOL_PORTAMENTO);
+ }
+ else if (xmlStrcmp(node1->name, BAD_CAST "Portamento_time") == 0)
+ {
+ dish_file_read_float(node1, patch_id,
+ PATCH_FLOAT_PORTAMENTO_TIME);
+ }
+ else if (xmlStrcmp(node1->name, BAD_CAST "Legato") == 0)
+ {
+ dish_file_read_bool(node1, patch_id, PATCH_BOOL_LEGATO);
+ }
+ else
+ {
+ msg_log(MSG_WARNING, "ignoring XML NODE: %s\n",
+ (const char*)node1->name);
+ }
+ }
return 0;
}
@@ -1041,9 +1239,19 @@ int dish_file_read(const char *path)
if (xmlStrcmp(node1->name, BAD_CAST "Master") == 0)
{
+ int sr;
+
if ((prop = xmlGetProp(node1, BAD_CAST "level")))
if (sscanf((const char*)prop, "%f", &n) == 1)
mixer_set_amplitude(n);
+
+ if ((prop = xmlGetProp(node1, BAD_CAST "samplerate")))
+ {
+ if (sscanf((const char*)prop, "%d", &sr) == 1)
+ dish_file_samplerate = sr;
+ else
+ dish_file_samplerate = 0;
+ }
}
else if (xmlStrcmp(node1->name, BAD_CAST "Patch") == 0)
{
@@ -1125,14 +1333,16 @@ int dish_file_read(const char *path)
dish_file_read_lfo(node2, patch_id);
else
{
- errmsg("ignoring:%s\n", (const char*)node2->name);
+ msg_log(MSG_WARNING, "ignoring XML NODE: %s\n",
+ (const char*)node2->name);
}
}
}
}
else
{
- errmsg("ignoring:%s\n", (const char*)node1->name);
+ msg_log(MSG_WARNING, "ignoring XML NODE: %s\n",
+ (const char*)node1->name);
}
}
diff --git a/src/dish_file.h b/libpetrifui/dish_file.h
similarity index 100%
rename from src/dish_file.h
rename to libpetrifui/dish_file.h
diff --git a/libpetrifui/msg_log.c b/libpetrifui/msg_log.c
new file mode 100644
index 0000000..56d7885
--- /dev/null
+++ b/libpetrifui/msg_log.c
@@ -0,0 +1,170 @@
+/* Petri-Foo is a fork of the Specimen audio sampler.
+
+ Copyright 2011 James W. Morris
+
+ This file is part of Petri-Foo.
+
+ Petri-Foo is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+
+ Petri-Foo is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Petri-Foo. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <sys/time.h>
+#include <time.h>
+
+
+#include "petri-foo.h"
+#include "msg_log.h"
+
+
+static bool msg_log_notification_state = false;
+static msg_log_cb msg_log_callback = 0;
+
+
+void timestamp(char* buf, int buflen)
+{
+ time_t ltime;
+ struct tm *Tm;
+ struct timeval detail_time;
+ int n;
+
+ if (!buf)
+ return;
+
+ if (buflen < 13)
+ {
+ *buf = '\0';
+ return;
+ }
+
+ gettimeofday(&detail_time,NULL);
+ ltime = time(NULL);
+ Tm=localtime(<ime);
+
+ n = snprintf(buf, buflen, "%02d:%02d:%02d.%03d",
+ Tm->tm_hour, Tm->tm_min, Tm->tm_sec,
+ (int)(detail_time.tv_usec / 1000.0f));
+
+ if (n >= buflen)
+ snprintf(buf, buflen, "--:--:--.---");
+}
+
+
+char* strconcat(const char* str1, const char* str2)
+{
+ char* str = malloc(strlen(str1) + strlen(str2) + 1);
+
+ if (!str)
+ return 0;
+
+ strcpy(str, str1);
+ strcat(str, str2);
+
+ return str;
+}
+
+
+int msg_log(int type, const char* fmt, ...)
+{
+ const char* types[] = {
+ "Debug",
+ "Message",
+ "Warning",
+ "ERROR",
+ "CRITICAL!"
+ };
+
+ char msg[1024];
+ char tm[20];
+ char tmp[1024];
+
+ va_list ap;
+
+ int rc = 0;
+ int base_type = type & MSG_TYPE_MASK;
+ int out_type = type & MSG_FLAG_OUTPUT_MASK;
+
+ if (!out_type)
+ goto skip;
+
+ if (base_type <= MSG_INVALID || base_type >= MSG_TYPE_XXX)
+ {
+ char* newfmt;
+ newfmt = strconcat("Invalid log message: ", fmt);
+
+ va_start(ap, fmt);
+ msg_log(MSG_CRITICAL, newfmt, ap);
+ va_end(ap);
+
+ free(newfmt);
+
+ return -1;
+ }
+
+ timestamp(tm, 20);
+
+ va_start(ap, fmt);
+
+ if (vsnprintf(tmp, 1023, fmt, ap) >= 1023)
+ tmp[1023] = '\0';
+
+ va_end(ap);
+
+ rc = snprintf(msg, 1023, "%s %s: %s ", tm, types[base_type], tmp);
+
+ if (rc >= 1023)
+ {
+ rc = 1023;
+ msg[rc] = '\0';
+ }
+
+ if (out_type & MSG_FLAG_STDOUT)
+ fprintf(stdout, "%s", msg);
+
+ if (out_type & MSG_FLAG_STDERR)
+ fprintf(stderr, "%s", msg);
+
+ if ((out_type & MSG_FLAG_STDUI) && msg_log_callback)
+ msg_log_callback(msg, base_type);
+
+skip:
+
+ if (type & MSG_FLAG_NOTIFY)
+ msg_log_notification_state = true;
+
+ return rc;
+}
+
+
+/* were there any errors? */
+bool msg_log_get_notification_state(void)
+{
+ return msg_log_notification_state;
+}
+
+
+/* reset error status */
+void msg_log_reset_notification_state(void)
+{
+ msg_log_notification_state = false;
+}
+
+
+void msg_log_set_message_cb(msg_log_cb msgcb)
+{
+ msg_log_callback = msgcb;
+}
+
diff --git a/libpetrifui/msg_log.h b/libpetrifui/msg_log.h
new file mode 100644
index 0000000..83f0612
--- /dev/null
+++ b/libpetrifui/msg_log.h
@@ -0,0 +1,94 @@
+/* Petri-Foo is a fork of the Specimen audio sampler.
+
+ Copyright 2011 James W. Morris
+
+ This file is part of Petri-Foo.
+
+ Petri-Foo is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+
+ Petri-Foo is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Petri-Foo. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#ifndef MSG_LOG_H
+#define MSG_LOG_H
+
+/* MSG_LOG
+
+ Logging of messages useful to Petri-Foo user. Not to be confused with
+ messages useful to developers. Messages such as errors when user asks
+ Petri-Foo to load a bank or sample, etc.
+
+ *** NOT for usage by RT thread ***
+ */
+
+
+#include <stdbool.h>
+
+
+
+/* type of the callback that will handle the string formed by
+ logging a message:
+ */
+typedef void (*msg_log_cb)(const char* msg, int msg_base_type);
+
+
+enum
+{
+/* invalid message type */
+ MSG_INVALID = -1,
+
+/* base message types: */
+ MSG_TYPE_DEBUG = 0,
+ MSG_TYPE_MESSAGE,
+ MSG_TYPE_WARNING,
+ MSG_TYPE_ERROR,
+ MSG_TYPE_CRITICAL,
+
+/* used for checking valid base message types */
+ MSG_TYPE_XXX,
+
+/* message type mask */
+ MSG_TYPE_MASK = 0x000f,
+
+/* message flags: */
+ MSG_FLAG_NOTIFY = 0x0010, /* sets notification state */
+
+ MSG_FLAG_STDOUT = 0x0100, /* output to stdout */
+ MSG_FLAG_STDERR = 0x0200, /* output to stderr */
+ MSG_FLAG_STDUI = 0x0400, /* output to ie gui */
+
+ MSG_FLAG_OUTPUT_MASK = 0x0f00,
+
+/* the actual message types generally used */
+ MSG_DEBUG = MSG_TYPE_DEBUG | MSG_FLAG_STDOUT,
+ MSG_MESSAGE = MSG_TYPE_MESSAGE | MSG_FLAG_STDOUT | MSG_FLAG_STDUI,
+ MSG_WARNING = MSG_TYPE_WARNING | MSG_FLAG_STDOUT | MSG_FLAG_STDUI,
+
+ MSG_ERROR = MSG_TYPE_ERROR | MSG_FLAG_NOTIFY
+ | MSG_FLAG_STDERR | MSG_FLAG_STDUI,
+
+ MSG_CRITICAL = MSG_TYPE_CRITICAL | MSG_FLAG_NOTIFY
+ | MSG_FLAG_STDERR | MSG_FLAG_STDUI,
+};
+
+
+void timestamp(char* buf, int buflen);
+char* strconcat(const char*, const char*);
+
+
+int msg_log(int type, const char* format, ...);
+void msg_log_set_message_cb(msg_log_cb);
+
+bool msg_log_get_notification_state(void);
+void msg_log_reset_notification_state(void);
+
+#endif
diff --git a/libphin/AUTHORS b/libphin/AUTHORS
new file mode 100644
index 0000000..ac9116d
--- /dev/null
+++ b/libphin/AUTHORS
@@ -0,0 +1,12 @@
+-*- text -*-
+
+Thorsten Wilms <t_w_ at freenet.de>
+
+Pete Bessman <ninjadroid at gazuga.net>
+
+Loki Davison <loki.davison at gmail.com>
+
+Nedko Arnaudov <nedko at arnaudov.name>
+
+James W. Morris <james at jwm-art.net>
+
diff --git a/libphin/BUGS b/libphin/BUGS
new file mode 100644
index 0000000..35a960b
--- /dev/null
+++ b/libphin/BUGS
@@ -0,0 +1,4 @@
+-*- text -*-
+
+* Grab a fanslider and wiggle back and forth, sometimes the fan will
+ "lock up" and do funny things...
diff --git a/libphin/CMakeLists.txt b/libphin/CMakeLists.txt
new file mode 100644
index 0000000..1db196d
--- /dev/null
+++ b/libphin/CMakeLists.txt
@@ -0,0 +1,21 @@
+file (GLOB LIBPHIN_SOURCES *.c)
+
+include_directories (
+ ${GTK2_INCLUDE_DIRS}
+ ${LIBGNOMECANVAS2_INCLUDE_DIRS}
+ )
+
+link_directories (
+ ${GTK2_LIBRARY_DIRS}
+ ${LIBGNOMECANVAS2_LIBRARY_DIRS}
+ )
+
+add_definitions (
+ ${GTK2_CFLAGS_OTHER}
+ ${LIBGNOMECANVAS2_CFLAGS_OTHER}
+ )
+
+add_library( phin STATIC ${LIBPHIN_SOURCES})
+SET(CMAKE_INSTALL_LIBDIR lib CACHE PATH "Output directory for libraries")
+
+target_link_Libraries(phin ${GTK2_LIBRARIES} ${LIBGNOMECANVAS2_LIBRARIES})
diff --git a/COPYING b/libphin/COPYING
similarity index 100%
copy from COPYING
copy to libphin/COPYING
diff --git a/libphin/README b/libphin/README
new file mode 100644
index 0000000..fcb4cdb
--- /dev/null
+++ b/libphin/README
@@ -0,0 +1,6 @@
+PHIN is PHAT without the phatpad or phatknob
+and without deprecated GTK/GDK code
+so it won't die just yet
+and neither will petri-foo.
+ha.
+
diff --git a/libphin/TODO b/libphin/TODO
new file mode 100644
index 0000000..2903d4b
--- /dev/null
+++ b/libphin/TODO
@@ -0,0 +1,32 @@
+-*- text -*-
+
+---must---
+
+* format specifier thing for sliderbuttons is LAME ASS! Just use a
+ num digits arg.
+
+---gravy---
+
+* add escaping to fansliders
+
+* add ghosting to fansliders
+
+* add support for update policies
+
+* implement properties and style properties
+
+* add default context menu (copy, paste, revert, previous);
+ perhaps use interfaces?
+
+* use gconf to allow the user to set properties accross all
+ applications, create a config frontend
+
+* add option to turn off fan drawing and mouse hiding/warping for
+ fansliders
+
+* add fan threshold to fansliders
+
+---magic---
+
+* figure out how to make fanslider fans not flicker when pulled out to
+ the left or up (thresholds might help)
diff --git a/libphin/phin.h b/libphin/phin.h
new file mode 100644
index 0000000..29d7c2f
--- /dev/null
+++ b/libphin/phin.h
@@ -0,0 +1,35 @@
+/* Phin is a fork of the PHAT Audio Toolkit.
+ Phin is part of Petri-Foo. Petri-Foo is a fork of Specimen.
+
+ Original author Pete Bessman
+ Copyright 2005 Pete Bessman
+ Copyright 2011 James W. Morris
+
+ This file is part of Phin.
+
+ Phin is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+
+ Phin is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Phin. If not, see <http://www.gnu.org/licenses/>.
+
+ This file is a derivative of a PHAT original, modified 2011
+*/
+#ifndef __PHIN_H__
+#define __PHIN_H__
+
+#include <phinvfanslider.h>
+#include <phinhfanslider.h>
+#include <phinfanslider.h>
+#include <phinsliderbutton.h>
+#include <phinkeyboard.h>
+#include <phinvkeyboard.h>
+#include <phinhkeyboard.h>
+
+#endif /* __PHIN_H__ */
diff --git a/libphin/phinfanslider.c b/libphin/phinfanslider.c
new file mode 100644
index 0000000..3dfacbc
--- /dev/null
+++ b/libphin/phinfanslider.c
@@ -0,0 +1,2073 @@
+/* Phin is a fork of the PHAT Audio Toolkit.
+ Phin is part of Petri-Foo. Petri-Foo is a fork of Specimen.
+
+ Original author Pete Bessman
+ Copyright 2005 Pete Bessman
+ Copyright 2011 James W. Morris
+
+ This file is part of Phin.
+
+ Phin is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+
+ Phin is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Phin. If not, see <http://www.gnu.org/licenses/>.
+
+ This file is a derivative of a PHAT original, modified 2011
+*/
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+#include <math.h>
+#include "phinprivate.h"
+#include "phinfanslider.h"
+
+/* magic numbers */
+enum
+{
+ FAN_RISE = 3,
+ FAN_RUN = 1,
+ SLIDER_WIDTH = 16,
+ SLIDER_LENGTH = 32,
+ THRESHOLD = 4,
+};
+
+/* states */
+enum
+{
+ STATE_NORMAL,
+ STATE_CLICKED,
+ STATE_SCROLL,
+};
+
+#define VALUE_RATIO_NORMAL 1.00
+#define VALUE_RATIO_SHIFT 0.10
+#define VALUE_RATIO_CTRL 0.01
+
+
+
+/* signals */
+enum
+{
+ VALUE_CHANGED_SIGNAL,
+ CHANGED_SIGNAL,
+ LAST_SIGNAL,
+};
+
+static int signals[LAST_SIGNAL];
+
+
+typedef struct _PhinFanSliderPrivate PhinFanSliderPrivate;
+
+#define PHIN_FAN_SLIDER_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE((obj), PHIN_TYPE_FAN_SLIDER, \
+ PhinFanSliderPrivate))
+
+struct _PhinFanSliderPrivate
+{
+ GtkAdjustment* adjustment;
+ GtkAdjustment* adjustment_prv;
+ double val;
+ double center_val;
+ int xclick_root;
+ int yclick_root;
+ int xclick;
+ int yclick;
+ double value_update_ratio;
+ int fan_max_thickness;
+ int state;
+ gboolean inverted;
+ int direction;
+ gboolean is_log;
+ GtkOrientation orientation;
+ GtkWidget* fan_window;
+ GdkCursor* arrow_cursor;
+ GdkCursor* empty_cursor;
+ GdkWindow* event_window;
+ GtkWidget* hint_window0;
+ GtkWidget* hint_window1;
+ GdkRectangle cur_fan;
+ gboolean use_default_value;
+ gdouble default_value;
+};
+
+
+/* forward declarations */
+G_DEFINE_TYPE(PhinFanSlider, phin_fan_slider, GTK_TYPE_WIDGET);
+
+
+static gboolean fans_active = FALSE;
+static int fan_max_height = 0;
+static int fan_max_width = 0;
+
+
+static void phin_fan_slider_dispose (GObject* object);
+static void phin_fan_slider_realize (GtkWidget* widget);
+static void phin_fan_slider_unrealize (GtkWidget *widget);
+static void phin_fan_slider_map (GtkWidget *widget);
+static void phin_fan_slider_unmap (GtkWidget *widget);
+
+static void phin_fan_slider_draw_fan (PhinFanSlider* slider);
+static int phin_fan_slider_get_fan_length (PhinFanSlider* slider);
+static void phin_fan_slider_update_hints (PhinFanSlider* slider);
+
+static void phin_fan_slider_size_request (GtkWidget*widget,
+ GtkRequisition* requisition);
+
+static void phin_fan_slider_size_allocate (GtkWidget* widget,
+ GtkAllocation* allocation);
+
+static gboolean phin_fan_slider_expose (GtkWidget* widget,
+ GdkEventExpose* event);
+
+static gboolean phin_fan_slider_button_press(GtkWidget* widget,
+ GdkEventButton* event);
+
+static gboolean phin_fan_slider_button_release (GtkWidget* widget,
+ GdkEventButton* event);
+
+static gboolean phin_fan_slider_key_press (GtkWidget* widget,
+ GdkEventKey* event);
+
+static gboolean phin_fan_slider_scroll (GtkWidget* widget,
+ GdkEventScroll* event);
+
+static gboolean phin_fan_slider_motion_notify (GtkWidget* widget,
+ GdkEventMotion* event);
+
+static gboolean phin_fan_slider_enter_notify (GtkWidget* widget,
+ GdkEventCrossing* event);
+
+static gboolean phin_fan_slider_leave_notify (GtkWidget* widget,
+ GdkEventCrossing* event);
+
+static void phin_fan_slider_calc_layout (PhinFanSlider* slider,
+ int* x, int* y, int* w, int* h);
+
+static void phin_fan_slider_update_value (PhinFanSlider* slider,
+ int x_root, int y_root);
+
+static void phin_fan_slider_update_fan (PhinFanSlider* slider,
+ int x, int y);
+
+static gboolean phin_fan_slider_fan_expose (GtkWidget* widget,
+ GdkEventExpose* event,
+ PhinFanSlider* slider);
+
+static void phin_fan_slider_fan_show (GtkWidget* widget,
+ GtkWidget* slider);
+
+static gboolean phin_fan_slider_hint_expose (GtkWidget* widget,
+ GdkEventExpose* event,
+ GtkWidget* slider);
+
+static void phin_fan_slider_adjustment_changed (GtkAdjustment* adjustment,
+ PhinFanSlider* slider);
+
+static void phin_fan_slider_adjustment_value_changed( GtkAdjustment*,
+ PhinFanSlider*);
+
+
+void phin_fan_slider_set_fans_active(gboolean enable_fans)
+{
+ fans_active = enable_fans;
+}
+
+gboolean phin_fan_slider_get_fans_active(void)
+{
+ return fans_active;
+}
+
+
+/**
+ * phin_fan_slider_set_value:
+ * @slider: a #PhinFanSlider
+ * @value: a new value for the slider
+ *
+ * Sets the current value of the slider. If the value is outside the
+ * range of values allowed by @slider, it will be clamped to fit
+ * within them. The slider emits the "value-changed" signal if the
+ * value changes.
+ *
+ */
+void phin_fan_slider_set_value (PhinFanSlider* slider, double value)
+{
+ PhinFanSliderPrivate* p = PHIN_FAN_SLIDER_GET_PRIVATE(slider);
+
+ gdouble lower = gtk_adjustment_get_lower(p->adjustment);
+ gdouble upper = gtk_adjustment_get_upper(p->adjustment);
+
+ value = CLAMP (value, lower, upper);
+
+ gtk_adjustment_set_value (p->adjustment, value);
+
+ if(p->is_log)
+ {
+ gtk_adjustment_set_value(GTK_ADJUSTMENT(p->adjustment_prv),
+ log(value - lower) / log(upper - lower));
+ }
+ else
+ {
+ gtk_adjustment_set_value(GTK_ADJUSTMENT(p->adjustment_prv),
+ (value - lower) / (upper - lower));
+ }
+}
+
+
+void phin_fan_slider_set_log (PhinFanSlider* slider, gboolean is_log)
+{
+ PhinFanSliderPrivate* p = PHIN_FAN_SLIDER_GET_PRIVATE(slider);
+ p->is_log = is_log;
+}
+
+
+gboolean phin_fan_slider_is_log (PhinFanSlider* slider)
+{
+ PhinFanSliderPrivate* p = PHIN_FAN_SLIDER_GET_PRIVATE(slider);
+ return p->is_log;
+}
+
+
+/**
+ * phin_fan_slider_get_value:
+ * @slider: a #PhinFanSlider
+ *
+ * Retrieves the current value of the slider.
+ *
+ * Returns: current value of the slider.
+ *
+ */
+double phin_fan_slider_get_value (PhinFanSlider* slider)
+{
+ PhinFanSliderPrivate* p = PHIN_FAN_SLIDER_GET_PRIVATE(slider);
+
+ gdouble lower = gtk_adjustment_get_lower(p->adjustment);
+ gdouble upper = gtk_adjustment_get_upper(p->adjustment);
+ gdouble value = 0;
+ gdouble prv_value = gtk_adjustment_get_value(p->adjustment_prv);
+
+ if(p->is_log)
+ { /* FIXME: log scale */
+ value = exp(prv_value * log(upper - lower)) + lower;
+ }
+ else
+ {
+ value = prv_value * (upper - lower) + lower;
+ }
+
+ /* not sure what the purpose of this set value call is: */
+ gtk_adjustment_set_value(p->adjustment, value);
+
+ return value;
+}
+
+/*
+http://stackoverflow.com/questions/846221/logarithmic-slider/846249#846249
+ function logslider(value) {
+ // value will be between 0 and 100
+ var slidermin = 0;
+ var slidermax = 100;
+
+ // The result should be between 100 an 10000000
+ var minv = Math.log(100);
+ var maxv = Math.log(10000000);
+
+ // calculate adjustment factor
+ var scale = (maxv-minv) / (slidermax-slidermin);
+
+ return Math.exp(minv + scale*(value-slidermin));
+}
+
+*/
+/**
+ * phin_fan_slider_set_range:
+ * @slider: a #PhinFanSlider
+ * @lower: lowest allowable value
+ * @upper: highest allowable value
+ *
+ * Sets the range of allowable values for the slider, and clamps the slider's
+ * current value to be between @lower and @upper.
+ *
+ */
+void phin_fan_slider_set_range (PhinFanSlider* slider,
+ double lower, double upper)
+{
+ PhinFanSliderPrivate* p = PHIN_FAN_SLIDER_GET_PRIVATE(slider);
+ double value;
+
+ g_return_if_fail (lower <= upper);
+
+ gtk_adjustment_set_lower(p->adjustment, lower);
+ gtk_adjustment_set_upper(p->adjustment, upper);
+
+ value = CLAMP(gtk_adjustment_get_value(p->adjustment), lower, upper);
+
+ // XXX not sure about these
+ gtk_adjustment_changed(p->adjustment);
+ gtk_adjustment_set_value(p->adjustment, value);
+}
+
+/**
+ * phin_fan_slider_get_range:
+ * @slider: a #PhinFanSlider
+ * @lower: retrieves lowest allowable value
+ * @upper: retrieves highest allowable value
+ *
+ * Places the range of allowable values for @slider into @lower
+ * and @upper. Either variable may be set to %NULL if you are not
+ * interested in its value.
+ *
+ */
+void phin_fan_slider_get_range (PhinFanSlider* slider,
+ double* lower, double* upper)
+{
+ PhinFanSliderPrivate* p = PHIN_FAN_SLIDER_GET_PRIVATE(slider);
+
+ if (lower)
+ *lower = gtk_adjustment_get_lower(p->adjustment);
+ if (upper)
+ *upper = gtk_adjustment_get_upper(p->adjustment);
+}
+
+/**
+ * phin_fan_slider_set_adjustment:
+ * @slider: a #PhinFanSlider
+ * @adjustment: a #GtkAdjustment
+ *
+ * Sets the adjustment used by @slider. Every #PhinFanSlider uses an
+ * adjustment to store its current value and its range of allowable
+ * values. If @adjustment is %NULL, a new adjustment with a value of
+ * zero and a range of [-1.0, 1.0] will be created.
+ *
+ */
+void phin_fan_slider_set_adjustment (PhinFanSlider* slider,
+ GtkAdjustment* adjustment)
+{
+ PhinFanSliderPrivate* p = PHIN_FAN_SLIDER_GET_PRIVATE(slider);
+
+ g_return_if_fail (p->adjustment != adjustment);
+
+ if (!adjustment)
+ adjustment = (GtkAdjustment*)
+ gtk_adjustment_new (0.0, -1.0, 1.0, 1.0, 1.0, 0.0);
+ else
+ g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
+
+ if (p->adjustment)
+ {
+ g_signal_handlers_disconnect_by_func(
+ p->adjustment,
+ phin_fan_slider_adjustment_changed,
+ (gpointer)slider);
+
+ g_signal_handlers_disconnect_by_func(
+ p->adjustment,
+ phin_fan_slider_adjustment_value_changed,
+ (gpointer)slider);
+
+ g_object_unref (p->adjustment);
+ }
+
+ p->adjustment = adjustment;
+ g_object_ref (adjustment);
+ g_object_ref_sink (GTK_OBJECT (adjustment));
+
+ phin_fan_slider_adjustment_changed(p->adjustment, slider);
+
+ phin_fan_slider_set_value(PHIN_FAN_SLIDER (slider),
+ gtk_adjustment_get_value(adjustment));
+}
+
+/**
+ * phin_fan_slider_get_adjustment:
+ * @slider: a #PhinFanSlider
+ *
+ * Retrives the current adjustment in use by @slider.
+ *
+ * Returns: @slider's current #GtkAdjustment
+ *
+ */
+GtkAdjustment* phin_fan_slider_get_adjustment (PhinFanSlider* slider)
+{
+ PhinFanSliderPrivate* p = PHIN_FAN_SLIDER_GET_PRIVATE(slider);
+
+ /* I can't imagine this ever being true, but just to be
+ * "safe" ... */
+ if (!p->adjustment)
+ phin_fan_slider_set_adjustment (slider, NULL);
+
+ return p->adjustment;
+}
+
+/**
+ * phin_fan_slider_set_inverted:
+ * @slider: a #PhinFanSlider
+ * @inverted: %TRUE to invert the fanslider
+ *
+ * Sets in which direction the fanslider should draw increasing
+ * values. By default, horizontal fansliders draw low to high from
+ * left to right, and vertical fansliders draw from bottom to top.
+ * You can reverse this behavior by setting @inverted to %TRUE.
+ *
+ */
+void phin_fan_slider_set_inverted (PhinFanSlider* slider, gboolean inverted)
+{
+ PhinFanSliderPrivate* p = PHIN_FAN_SLIDER_GET_PRIVATE(slider);
+
+ p->inverted = inverted;
+ gtk_widget_queue_draw (GTK_WIDGET (slider));
+}
+
+/**
+ * phin_fan_slider_get_inverted:
+ * @slider: a #PhinFanSlider
+ *
+ * Determines whether @slider is inverted or not.
+ *
+ * Returns: %TRUE if @slider is inverted
+ *
+ */
+gboolean phin_fan_slider_get_inverted (PhinFanSlider* slider)
+{
+ PhinFanSliderPrivate* p = PHIN_FAN_SLIDER_GET_PRIVATE(slider);
+ return p->inverted;
+}
+
+/**
+ * phin_fan_slider_set_default_value:
+ * @slider: a #PhinFanSlider
+ * @value: the default value
+ *
+ * Set default value of the slider. Slider is reset to this value
+ * when middle mouse button is pressed.
+ */
+void phin_fan_slider_set_default_value(PhinFanSlider* slider, gdouble value)
+{
+ PhinFanSliderPrivate* p = PHIN_FAN_SLIDER_GET_PRIVATE(slider);
+
+ p->use_default_value = TRUE;
+ p->default_value = value;
+}
+
+void phin_fan_slider_set_orientation(PhinFanSlider* slider,
+ GtkOrientation o)
+{
+ PhinFanSliderPrivate* p = PHIN_FAN_SLIDER_GET_PRIVATE(slider);
+ p->orientation = o;
+}
+
+
+static void phin_fan_slider_class_init (PhinFanSliderClass* klass)
+{
+ GObjectClass* object_class = G_OBJECT_CLASS(klass);
+ GtkWidgetClass* widget_class = GTK_WIDGET_CLASS(klass);
+ phin_fan_slider_parent_class = g_type_class_peek_parent(klass);
+ GdkScreen* screen = gdk_screen_get_default();
+
+ debug ("class init\n");
+
+ phin_fan_slider_parent_class = g_type_class_peek(gtk_widget_get_type());
+
+ object_class->dispose = phin_fan_slider_dispose;
+ widget_class->realize = phin_fan_slider_realize;
+ widget_class->unrealize = phin_fan_slider_unrealize;
+ widget_class->map = phin_fan_slider_map;
+ widget_class->unmap = phin_fan_slider_unmap;
+ widget_class->expose_event = phin_fan_slider_expose;
+ widget_class->size_request = phin_fan_slider_size_request;
+ widget_class->size_allocate = phin_fan_slider_size_allocate;
+ widget_class->button_press_event = phin_fan_slider_button_press;
+ widget_class->button_release_event = phin_fan_slider_button_release;
+ widget_class->key_press_event = phin_fan_slider_key_press;
+ widget_class->scroll_event = phin_fan_slider_scroll;
+ widget_class->motion_notify_event = phin_fan_slider_motion_notify;
+ widget_class->enter_notify_event = phin_fan_slider_enter_notify;
+ widget_class->leave_notify_event = phin_fan_slider_leave_notify;
+
+ /**
+ * PhinFanSlider::value-changed:
+ * @slider: the object on which the signal was emitted
+ *
+ * The "value-changed" signal is emitted when the value of the
+ * slider's adjustment changes.
+ *
+ */
+ signals[VALUE_CHANGED_SIGNAL] =
+ g_signal_new ("value-changed",
+ G_TYPE_FROM_CLASS(klass),
+ G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET(PhinFanSliderClass, value_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
+
+ /**
+ * PhinFanSlider::changed:
+ * @slider: the object on which the signal was emitted
+ *
+ * The "changed" signal is emitted when any parameter of the
+ * slider's adjustment changes, except for the %value parameter.
+ *
+ */
+ signals[CHANGED_SIGNAL] =
+ g_signal_new ("changed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (PhinFanSliderClass, changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
+
+ klass->value_changed = NULL;
+ klass->changed = NULL;
+
+ if (screen)
+ fan_max_width = gdk_screen_get_width (screen);
+ else
+ fan_max_width = 1280;
+
+ if (screen)
+ fan_max_height = gdk_screen_get_height (screen);
+ else
+ fan_max_height = 1024;
+
+
+ g_type_class_add_private(object_class, sizeof(PhinFanSliderPrivate));
+}
+
+
+static void phin_fan_slider_init (PhinFanSlider* slider)
+{
+ PhinFanSliderPrivate* p = PHIN_FAN_SLIDER_GET_PRIVATE(slider);
+
+ gtk_widget_set_has_window(GTK_WIDGET(slider), FALSE);
+ gtk_widget_set_can_focus(GTK_WIDGET(slider), TRUE);
+
+ debug ("init\n");
+
+ p->adjustment = NULL;
+ p->adjustment_prv = (GtkAdjustment*)
+ gtk_adjustment_new (0.0, 0.0, 1.0, 0.1, 0.1, 0.0);
+ p->val = 0.69;
+ p->center_val = -1;
+ p->xclick_root = 0;
+ p->yclick_root = 0;
+ p->xclick = 0;
+ p->yclick = 0;
+ p->value_update_ratio = VALUE_RATIO_NORMAL;
+ p->fan_max_thickness = 1;
+ p->inverted = FALSE;
+ p->direction = 0;
+ p->state = STATE_NORMAL;
+ p->orientation = GTK_ORIENTATION_HORIZONTAL;
+ p->fan_window = NULL;
+ p->arrow_cursor = NULL;
+ p->empty_cursor = NULL;
+ p->event_window = NULL;
+ p->hint_window0 = NULL;
+ p->hint_window1 = NULL;
+ p->is_log = 0;
+ p->use_default_value = FALSE;
+
+ g_signal_connect (p->adjustment_prv, "changed",
+ G_CALLBACK (phin_fan_slider_adjustment_changed),
+ (gpointer) slider);
+ g_signal_connect (p->adjustment_prv, "value_changed",
+ G_CALLBACK (phin_fan_slider_adjustment_value_changed),
+ (gpointer) slider);
+
+ phin_fan_slider_adjustment_changed (p->adjustment_prv, slider);
+ phin_fan_slider_adjustment_value_changed (p->adjustment_prv, slider);
+
+}
+
+
+static void phin_fan_slider_dispose (GObject* object)
+{
+ PhinFanSlider* slider;
+ PhinFanSliderPrivate* p;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (PHIN_IS_FAN_SLIDER (object));
+
+ slider = PHIN_FAN_SLIDER(object);
+ p = PHIN_FAN_SLIDER_GET_PRIVATE(object);
+
+ debug ("dispose %p\n", object);
+
+ if (p->arrow_cursor != NULL)
+ {
+ gdk_cursor_unref (p->arrow_cursor);
+ p->arrow_cursor = NULL;
+ }
+
+ if (p->empty_cursor != NULL)
+ {
+ gdk_cursor_unref (p->empty_cursor);
+ p->empty_cursor = NULL;
+ }
+
+ if (p->event_window != NULL)
+ {
+ gdk_window_destroy (p->event_window);
+ p->event_window = NULL;
+ }
+
+ if (p->fan_window != NULL)
+ {
+ gtk_widget_destroy (p->fan_window);
+ p->fan_window = NULL;
+ }
+
+ if (p->hint_window0 != NULL)
+ {
+ gtk_widget_destroy (p->hint_window0);
+ p->hint_window0 = NULL;
+ }
+
+ if (p->hint_window1 != NULL)
+ {
+ gtk_widget_destroy (p->hint_window1);
+ p->hint_window1 = NULL;
+ }
+
+ if (p->adjustment)
+ {
+ g_signal_handlers_disconnect_by_func(
+ p->adjustment,
+ phin_fan_slider_adjustment_changed,
+ (gpointer)slider);
+
+ g_signal_handlers_disconnect_by_func(
+ p->adjustment,
+ phin_fan_slider_adjustment_value_changed,
+ (gpointer)slider);
+
+ /* called ref on it so we must call unref */
+ g_object_unref (p->adjustment);
+ p->adjustment = NULL;
+ }
+
+ if (p->adjustment_prv)
+ {
+ g_signal_handlers_disconnect_by_func(
+ p->adjustment_prv,
+ phin_fan_slider_adjustment_changed,
+ (gpointer)slider);
+
+ g_signal_handlers_disconnect_by_func(
+ p->adjustment_prv,
+ phin_fan_slider_adjustment_value_changed,
+ (gpointer)slider);
+ }
+}
+
+
+static void phin_fan_slider_realize (GtkWidget* widget)
+{
+ PhinFanSlider* slider;
+ PhinFanSliderPrivate* p;
+ GdkWindowAttr attributes;
+ gint attributes_mask;
+ GdkWindow* window;
+ GtkStyle* style;
+ debug ("realize\n");
+
+ g_return_if_fail (widget != NULL);
+ g_return_if_fail (PHIN_IS_FAN_SLIDER (widget));
+
+ gtk_widget_set_realized(GTK_WIDGET(widget), TRUE);
+
+ slider = PHIN_FAN_SLIDER(widget);
+ p = PHIN_FAN_SLIDER_GET_PRIVATE(widget);
+
+ if (p->orientation == GTK_ORIENTATION_VERTICAL)
+ {
+ p->arrow_cursor = gdk_cursor_new (GDK_SB_V_DOUBLE_ARROW);
+ }
+ else
+ {
+ p->arrow_cursor = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW);
+ }
+
+ p->empty_cursor = gdk_cursor_new(GDK_BLANK_CURSOR);
+
+ window = gtk_widget_get_parent_window (widget);
+ gtk_widget_set_window(widget, window);
+ g_object_ref (window);
+
+ style = gtk_widget_get_style(widget);
+ style = gtk_style_attach(style, window);
+ gtk_widget_set_style(widget, style);
+
+ attributes.window_type = GDK_WINDOW_CHILD;
+ attributes.wclass = GDK_INPUT_ONLY;
+ attributes.event_mask = gtk_widget_get_events (widget);
+ attributes.event_mask |= (GDK_BUTTON_PRESS_MASK
+ | GDK_BUTTON_RELEASE_MASK
+ | GDK_POINTER_MOTION_MASK
+ | GDK_POINTER_MOTION_HINT_MASK
+ | GDK_ENTER_NOTIFY_MASK
+ | GDK_LEAVE_NOTIFY_MASK
+ | GDK_SCROLL_MASK);
+ phin_fan_slider_calc_layout (slider,
+ &attributes.x,
+ &attributes.y,
+ &attributes.width,
+ &attributes.height);
+ attributes_mask = GDK_WA_X | GDK_WA_Y;
+
+ p->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
+ &attributes, attributes_mask);
+ gdk_window_set_user_data (p->event_window, widget);
+ gdk_window_set_cursor (p->event_window, p->arrow_cursor);
+
+ p->fan_window = gtk_window_new (GTK_WINDOW_POPUP);
+
+ gtk_window_resize(GTK_WINDOW(p->fan_window),
+ fan_max_width, fan_max_height);
+
+ gtk_widget_set_app_paintable (p->fan_window, TRUE);
+
+ g_signal_connect (G_OBJECT (p->fan_window),
+ "expose-event",
+ G_CALLBACK (phin_fan_slider_fan_expose),
+ (gpointer) slider);
+
+ g_signal_connect (G_OBJECT (p->fan_window),
+ "show",
+ G_CALLBACK (phin_fan_slider_fan_show),
+ (gpointer) slider);
+
+ g_signal_connect (G_OBJECT(p->fan_window),
+ "screen-changed",
+ G_CALLBACK (phin_screen_changed), NULL);
+
+ phin_screen_changed(p->fan_window, NULL, NULL);
+
+ p->hint_window0 = gtk_window_new (GTK_WINDOW_POPUP);
+ gtk_widget_realize (p->hint_window0);
+ g_signal_connect (G_OBJECT (p->hint_window0),
+ "expose-event",
+ G_CALLBACK (phin_fan_slider_hint_expose),
+ (gpointer) slider);
+
+ p->hint_window1 = gtk_window_new (GTK_WINDOW_POPUP);
+ gtk_widget_realize (p->hint_window1);
+ g_signal_connect (G_OBJECT (p->hint_window1),
+ "expose-event",
+ G_CALLBACK (phin_fan_slider_hint_expose),
+ (gpointer) slider);
+
+ /* a priming call */
+ phin_fan_slider_update_hints (slider);
+}
+
+static void phin_fan_slider_unrealize (GtkWidget *widget)
+{
+ PhinFanSliderPrivate* p = PHIN_FAN_SLIDER_GET_PRIVATE (widget);;
+ GtkWidgetClass* klass = GTK_WIDGET_CLASS(phin_fan_slider_parent_class);
+
+ debug ("unrealize\n");
+
+ gdk_cursor_unref (p->arrow_cursor);
+ p->arrow_cursor = NULL;
+
+ gdk_cursor_unref (p->empty_cursor);
+ p->empty_cursor = NULL;
+
+ gdk_window_set_user_data (p->event_window, NULL);
+ gdk_window_destroy (p->event_window);
+ p->event_window = NULL;
+
+ gtk_widget_destroy (p->fan_window);
+ p->fan_window = NULL;
+
+ gtk_widget_destroy (p->hint_window0);
+ p->hint_window0 = NULL;
+
+ gtk_widget_destroy (p->hint_window1);
+ p->hint_window1 = NULL;
+
+ if (klass->unrealize)
+ klass->unrealize (widget);
+}
+
+
+static void phin_fan_slider_map (GtkWidget *widget)
+{
+ PhinFanSliderPrivate* p = PHIN_FAN_SLIDER_GET_PRIVATE (widget);
+
+ debug ("map\n");
+
+ g_return_if_fail (PHIN_IS_FAN_SLIDER (widget));
+
+ gdk_window_show (p->event_window);
+
+ GTK_WIDGET_CLASS(phin_fan_slider_parent_class)->map(widget);
+}
+
+
+static void phin_fan_slider_unmap (GtkWidget *widget)
+{
+ PhinFanSliderPrivate* p = PHIN_FAN_SLIDER_GET_PRIVATE(widget);;
+
+ debug ("unmap\n");
+
+ g_return_if_fail (PHIN_IS_FAN_SLIDER (widget));
+
+ gdk_window_hide (p->event_window);
+
+ GTK_WIDGET_CLASS(phin_fan_slider_parent_class)->unmap(widget);
+}
+
+static void phin_fan_slider_size_request (GtkWidget* widget,
+ GtkRequisition* requisition)
+{
+ PhinFanSliderPrivate* p = PHIN_FAN_SLIDER_GET_PRIVATE (widget);;
+ int focus_width, focus_pad;
+ int pad;
+
+ debug ("size request\n");
+
+ g_return_if_fail (PHIN_IS_FAN_SLIDER (widget));
+
+ gtk_widget_style_get (widget,
+ "focus-line-width", &focus_width,
+ "focus-padding", &focus_pad,
+ NULL);
+
+ pad = 2 * (focus_width + focus_pad);
+
+ if (p->orientation == GTK_ORIENTATION_VERTICAL)
+ {
+ requisition->width = SLIDER_WIDTH + pad;
+ requisition->height = SLIDER_LENGTH + pad;
+ }
+ else
+ {
+ requisition->width = SLIDER_LENGTH + pad;
+ requisition->height = SLIDER_WIDTH + pad;
+ }
+}
+
+static void phin_fan_slider_size_allocate (GtkWidget* widget,
+ GtkAllocation* allocation)
+{
+ PhinFanSlider* slider = PHIN_FAN_SLIDER (widget);
+ PhinFanSliderPrivate* p = PHIN_FAN_SLIDER_GET_PRIVATE (widget);;
+ int x, y;
+ int w, h;
+
+ debug ("size allocate\n");
+
+ g_return_if_fail (widget != NULL);
+ g_return_if_fail (PHIN_IS_FAN_SLIDER (widget));
+ g_return_if_fail (allocation != NULL);
+
+ gtk_widget_set_allocation(widget, allocation);
+
+ phin_fan_slider_calc_layout (slider, &x, &y, &w, &h);
+
+ if (p->orientation == GTK_ORIENTATION_VERTICAL)
+ {
+ p->fan_max_thickness = ((fan_max_height - h)
+ / (2 * FAN_RISE / FAN_RUN));
+ }
+ else
+ {
+ p->fan_max_thickness = ((fan_max_width - w)
+ / (2 * FAN_RISE / FAN_RUN));
+ }
+
+ if (gtk_widget_get_realized(widget))
+ {
+ gdk_window_move_resize (p->event_window,
+ x, y, w, h);
+ }
+}
+
+
+static void draw_fan_rectangle(cairo_t* cr, double x, double y,
+ double w, double h,
+ GdkColor* col)
+{
+ gdk_cairo_set_source_color(cr, col);
+ cairo_set_line_width(cr, 1.0);
+ cairo_rectangle(cr, x, y, w, h);
+ cairo_stroke_preserve(cr);
+ cairo_fill(cr);
+}
+
+
+static gboolean phin_fan_slider_expose (GtkWidget* widget,
+ GdkEventExpose* event)
+{
+ PhinFanSliderPrivate* p = PHIN_FAN_SLIDER_GET_PRIVATE (widget);
+ PhinFanSlider* slider;
+ int x, y;
+ int w, h;
+ int fx, fy; /* "filled" coordinates */
+ int fw, fh;
+
+ GtkStyle* style;
+ cairo_t* cr;
+
+ g_return_val_if_fail (widget != NULL, FALSE);
+ g_return_val_if_fail (PHIN_IS_FAN_SLIDER (widget), FALSE);
+ g_return_val_if_fail (event != NULL, FALSE);
+
+ if (event->count > 0)
+ return FALSE;
+
+ slider = (PhinFanSlider*) widget;
+
+ style = gtk_widget_get_style(widget);
+ cr = gdk_cairo_create(gtk_widget_get_window(widget));
+
+ phin_fan_slider_calc_layout (slider, &x, &y, &w, &h);
+
+ if (p->orientation == GTK_ORIENTATION_VERTICAL)
+ {
+ if (p->center_val >= 0)
+ {
+ fw = w;
+ fh = ABS (p->val - p->center_val) * h;
+ fx = x;
+ fy = y + h - (p->center_val * h);
+
+ if ((p->val > p->center_val && !p->inverted)
+ || (p->val < p->center_val && p->inverted))
+ {
+ fy -= fh;
+ }
+
+ }
+ else
+ {
+ fw = w;
+ fh = p->val * h;
+ fx = x;
+ fy = (p->inverted)? y: y + h - fh;
+ }
+ }
+ else
+ {
+ if (p->center_val >= 0)
+ {
+ fw = ABS (p->val - p->center_val) * w;
+ fh = h;
+ fx = x + (p->center_val * w);
+ fy = y;
+
+ if ((p->val < p->center_val && !p->inverted)
+ || (p->val > p->center_val && p->inverted))
+ {
+ fx -= fw;
+ }
+ }
+ else
+ {
+ fw = p->val * w;
+ fh = h;
+ fx = (p->inverted)? x + w - fw: x;
+ fy = y;
+ }
+ }
+
+ if (!gtk_widget_is_sensitive(widget))
+ {
+ draw_fan_rectangle(cr, x, y, w, h,
+ &style->dark[GTK_STATE_INSENSITIVE]);
+ draw_fan_rectangle(cr, fx, fy, fw, fh,
+ &style->fg[GTK_STATE_INSENSITIVE]);
+ }
+ else
+ {
+ draw_fan_rectangle(cr, x, y, w, h,
+ &style->dark[GTK_STATE_NORMAL]);
+ draw_fan_rectangle(cr, fx, fy, fw, fh,
+ &style->base[GTK_STATE_SELECTED]);
+ }
+
+ cairo_destroy(cr);
+
+ if (gtk_widget_has_focus (widget))
+ {
+ int focus_width, focus_pad;
+ int pad;
+
+ gtk_widget_style_get (widget,
+ "focus-line-width", &focus_width,
+ "focus-padding", &focus_pad,
+ NULL);
+
+ pad = focus_width + focus_pad;
+
+ x -= pad;
+ y -= pad;
+ w += 2*pad;
+ h += 2*pad;
+
+ gtk_paint_focus (style, gtk_widget_get_window(widget),
+ gtk_widget_get_state (widget),
+ NULL, widget, NULL,
+ x, y, w, h);
+ }
+
+ if (gtk_widget_get_visible (p->fan_window))
+ gtk_widget_queue_draw (p->fan_window);
+
+ return FALSE;
+}
+
+
+static gboolean phin_fan_slider_button_press (GtkWidget* widget,
+ GdkEventButton* event)
+{
+ PhinFanSliderPrivate* p = PHIN_FAN_SLIDER_GET_PRIVATE (widget);
+ PhinFanSlider* slider;
+
+ g_return_val_if_fail (widget != NULL, FALSE);
+ g_return_val_if_fail (PHIN_IS_FAN_SLIDER (widget), FALSE);
+ g_return_val_if_fail (event != NULL, FALSE);
+
+ slider = (PhinFanSlider*) widget;
+
+ if(event->button == 1)
+ {
+ gtk_widget_grab_focus (widget);
+
+ if (p->state == STATE_SCROLL)
+ {
+ p->state = STATE_NORMAL;
+ gdk_window_set_cursor (p->event_window, p->arrow_cursor);
+ return FALSE;
+ }
+
+ gdk_window_set_cursor (p->event_window, p->empty_cursor);
+
+ p->xclick_root = event->x_root;
+ p->xclick = event->x;
+ p->yclick_root = event->y_root;
+ p->yclick = event->y;
+ p->state = STATE_CLICKED;
+ }
+ else if (event->button == 2 && p->use_default_value)
+ {
+ phin_fan_slider_set_value(slider, p->default_value);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+static gboolean phin_fan_slider_button_release (GtkWidget* widget,
+ GdkEventButton* event)
+{
+ PhinFanSliderPrivate* p = PHIN_FAN_SLIDER_GET_PRIVATE (widget);
+
+ g_return_val_if_fail (widget != NULL, FALSE);
+ g_return_val_if_fail (PHIN_IS_FAN_SLIDER (widget), FALSE);
+ g_return_val_if_fail (event != NULL, FALSE);
+
+ gdk_window_set_cursor (p->event_window, p->arrow_cursor);
+
+ if (p->state == STATE_CLICKED)
+ {
+ p->state = STATE_NORMAL;
+
+ phin_warp_pointer (event->x_root,
+ event->y_root,
+ p->xclick_root,
+ p->yclick_root);
+
+ if (gtk_widget_get_visible (p->fan_window))
+ gtk_widget_hide (p->fan_window);
+
+ if (gtk_widget_get_visible (p->hint_window0))
+ gtk_widget_hide (p->hint_window0);
+
+ if (gtk_widget_get_visible (p->hint_window1))
+ gtk_widget_hide (p->hint_window1);
+ }
+
+ return FALSE;
+}
+
+static gboolean phin_fan_slider_key_press (GtkWidget* widget,
+ GdkEventKey* event)
+{
+ PhinFanSliderPrivate* p = PHIN_FAN_SLIDER_GET_PRIVATE (widget);
+ GtkAdjustment* adj = p->adjustment_prv;
+ gdouble inc;
+
+ debug ("key press\n");
+
+ if (p->orientation == GTK_ORIENTATION_VERTICAL)
+ {
+ switch (event->keyval)
+ {
+ case GDK_Up:
+ inc = gtk_adjustment_get_step_increment(adj);
+ break;
+ case GDK_Down:
+ inc = -gtk_adjustment_get_step_increment(adj);
+ break;
+ case GDK_Page_Up:
+ inc = gtk_adjustment_get_page_increment(adj);
+ break;
+ case GDK_Page_Down:
+ inc = -gtk_adjustment_get_page_increment(adj);
+ break;
+ default:
+ return FALSE;
+ }
+ }
+ else
+ {
+ switch (event->keyval)
+ {
+ case GDK_Right:
+ inc = gtk_adjustment_get_step_increment(adj);
+ break;
+ case GDK_Left:
+ inc = -gtk_adjustment_get_step_increment(adj);
+ break;
+ case GDK_Page_Up:
+ inc = gtk_adjustment_get_page_increment(adj);
+ break;
+ case GDK_Page_Down:
+ inc = -gtk_adjustment_get_page_increment(adj);
+ break;
+ default:
+ return FALSE;
+ }
+ }
+
+ if (p->inverted)
+ inc = -inc;
+
+ gtk_adjustment_set_value (adj, gtk_adjustment_get_value(adj) + inc);
+
+ return TRUE;
+}
+
+static gboolean phin_fan_slider_scroll (GtkWidget* widget,
+ GdkEventScroll* event)
+{
+ PhinFanSliderPrivate* p = PHIN_FAN_SLIDER_GET_PRIVATE (widget);
+
+ gdouble val, pinc;
+
+ gtk_widget_grab_focus (widget);
+
+ p->state = STATE_SCROLL;
+
+ p->xclick_root = event->x_root;
+ p->yclick_root = event->y_root;
+ p->xclick = event->x;
+ p->yclick = event->y;
+
+ gdk_window_set_cursor (p->event_window, p->empty_cursor);
+
+ val = gtk_adjustment_get_value(p->adjustment_prv);
+ pinc = gtk_adjustment_get_page_increment(p->adjustment_prv);
+
+ if (((event->direction == GDK_SCROLL_UP
+ || event->direction == GDK_SCROLL_RIGHT) && !p->inverted)
+ || ((event->direction == GDK_SCROLL_DOWN
+ || event->direction == GDK_SCROLL_LEFT) && p->inverted))
+ {
+ gtk_adjustment_set_value (p->adjustment_prv, val + pinc);
+ }
+ else
+ {
+ gtk_adjustment_set_value (p->adjustment_prv, val - pinc);
+ }
+
+ return TRUE;
+}
+
+/* ctrl locks precision, xshiftxlocksxvaluex shift increases precision */
+static gboolean phin_fan_slider_motion_notify (GtkWidget* widget,
+ GdkEventMotion* event)
+{
+ PhinFanSliderPrivate* p = PHIN_FAN_SLIDER_GET_PRIVATE (widget);
+ PhinFanSlider* slider;
+
+ GtkAllocation fan_alloc;
+
+ g_return_val_if_fail (widget != NULL, FALSE);
+ g_return_val_if_fail (PHIN_IS_FAN_SLIDER (widget), FALSE);
+ g_return_val_if_fail (event != NULL, FALSE);
+
+ slider = (PhinFanSlider*) widget;
+ gtk_widget_get_allocation(p->fan_window, &fan_alloc);
+
+ switch (p->state)
+ {
+ case STATE_SCROLL:
+ if (ABS (event->x - p->xclick) >= THRESHOLD
+ || ABS (event->y - p->yclick) >= THRESHOLD)
+ {
+ gdk_window_set_cursor (p->event_window, p->arrow_cursor);
+ p->state = STATE_NORMAL;
+ }
+ case STATE_NORMAL:
+ goto skip;
+ }
+
+ if (fans_active && !(event->state & GDK_CONTROL_MASK))
+ phin_fan_slider_update_fan (slider, event->x, event->y);
+
+/*
+ if (!(event->state & GDK_SHIFT_MASK))
+ phin_fan_slider_update_value (slider, event->x_root, event->y_root);
+*/
+
+
+ /* shift no longer locks value */
+ if ((event->state & GDK_SHIFT_MASK))
+ p->value_update_ratio = VALUE_RATIO_SHIFT;
+ else if ((event->state & GDK_CONTROL_MASK))
+ p->value_update_ratio = VALUE_RATIO_CTRL;
+ else
+ p->value_update_ratio = VALUE_RATIO_NORMAL;
+
+ phin_fan_slider_update_value (slider, event->x_root, event->y_root);
+
+ if (p->orientation == GTK_ORIENTATION_VERTICAL)
+ {
+ int destx = event->x_root;
+ int width;
+
+ gdk_window_get_geometry (p->event_window,
+ NULL, NULL, &width, NULL, NULL);
+
+ if (gtk_widget_get_visible (p->fan_window))
+ {
+ if (event->x_root > p->xclick_root)
+ {
+ if (event->state & GDK_CONTROL_MASK)
+ {
+ destx = (p->xclick_root
+ + width
+ - p->xclick
+ + fan_alloc.width);
+ }
+ else
+ {
+ destx = MIN (event->x_root,
+ p->xclick_root
+ + width
+ - p->xclick
+ + fan_alloc.width);
+ }
+ }
+ else
+ {
+ if (event->state & GDK_CONTROL_MASK)
+ {
+ destx = (p->xclick_root
+ - p->xclick
+ - fan_alloc.width);
+ }
+ else
+ {
+ destx = MAX (event->x_root,
+ p->xclick_root
+ - p->xclick
+ - fan_alloc.width);
+ }
+ }
+ }
+ else if (event->state & GDK_CONTROL_MASK)
+ {
+ destx = p->xclick_root;
+ }
+
+ phin_warp_pointer (event->x_root,
+ event->y_root,
+ destx,
+ p->yclick_root);
+ }
+ else
+ {
+ int desty = event->y_root;
+ int height;
+
+ gdk_window_get_geometry (p->event_window,
+ NULL, NULL, NULL, &height, NULL);
+
+ if (gtk_widget_get_visible (p->fan_window))
+ {
+ if (event->y_root > p->yclick_root)
+ {
+ if (event->state & GDK_CONTROL_MASK)
+ {
+ desty = (p->yclick_root
+ + height
+ - p->yclick
+ + fan_alloc.height);
+ }
+ else
+ {
+ desty = MIN (event->y_root,
+ p->yclick_root
+ + height
+ - p->yclick
+ + fan_alloc.height);
+ }
+ }
+ else
+ {
+ if (event->state & GDK_CONTROL_MASK)
+ {
+ desty = (p->yclick_root
+ - p->yclick
+ - fan_alloc.height);
+ }
+ else
+ {
+ desty = MAX (event->y_root,
+ p->yclick_root
+ - p->yclick
+ - fan_alloc.height);
+ }
+ }
+ }
+ else if (event->state & GDK_CONTROL_MASK)
+ {
+ desty = p->yclick_root;
+ }
+
+ phin_warp_pointer (event->x_root,
+ event->y_root,
+ p->xclick_root,
+ desty);
+ }
+
+ gtk_widget_queue_draw (widget);
+
+ /* necessary in case update_fan() doesn't get called */
+ if (gtk_widget_get_visible(p->fan_window))
+ gtk_widget_queue_draw (p->fan_window);
+
+skip:
+ /* signal that we want more motion events */
+ gdk_window_get_pointer (NULL, NULL, NULL, NULL);
+
+ return FALSE;
+}
+
+
+static gboolean phin_fan_slider_enter_notify (GtkWidget* widget,
+ GdkEventCrossing* event)
+{
+ PhinFanSliderPrivate* p = PHIN_FAN_SLIDER_GET_PRIVATE (widget);
+ GtkAllocation win0_alloc;
+ GtkAllocation win1_alloc;
+
+ int width;
+ int height;
+ PhinFanSlider* slider = PHIN_FAN_SLIDER (widget);
+
+ if (p->state == STATE_NORMAL)
+ gdk_window_set_cursor (p->event_window, p->arrow_cursor);
+
+ phin_fan_slider_update_hints (slider);
+
+ gdk_window_get_geometry (p->event_window,
+ NULL, NULL, &width, &height, NULL);
+
+ gtk_widget_get_allocation(p->hint_window0, &win0_alloc);
+ gtk_widget_get_allocation(p->hint_window1, &win1_alloc);
+
+ if (p->orientation == GTK_ORIENTATION_VERTICAL)
+ {
+ gtk_window_move (GTK_WINDOW (p->hint_window0),
+ event->x_root - event->x - win0_alloc.width,
+ (event->y_root - event->y)
+ + (height - win0_alloc.height) / 2);
+
+ gtk_window_move (GTK_WINDOW (p->hint_window1),
+ event->x_root - event->x + width,
+ (event->y_root - event->y)
+ + (height - win1_alloc.height) / 2);
+ }
+ else
+ {
+ gtk_window_move (GTK_WINDOW (p->hint_window0),
+ (event->x_root - event->x)
+ + (width - win0_alloc.width) / 2,
+ event->y_root - event->y - win0_alloc.height);
+
+ gtk_window_move (GTK_WINDOW (p->hint_window1),
+ (event->x_root - event->x)
+ + (width - win1_alloc.width) / 2,
+ event->y_root - event->y + height);
+ }
+
+ return FALSE;
+}
+
+static gboolean phin_fan_slider_leave_notify (GtkWidget* widget,
+ GdkEventCrossing* event)
+{
+ (void)event;
+ PhinFanSliderPrivate* p = PHIN_FAN_SLIDER_GET_PRIVATE (widget);
+
+ if (p->state == STATE_SCROLL)
+ {
+ gdk_window_set_cursor (p->event_window, NULL);
+ p->state = STATE_NORMAL;
+ }
+
+ if (gtk_widget_get_visible (p->hint_window0))
+ gtk_widget_hide (p->hint_window0);
+
+ if (gtk_widget_get_visible (p->hint_window1))
+ gtk_widget_hide (p->hint_window1);
+
+ return FALSE;
+}
+
+
+/* helper to reduce copy & paste */
+static void
+fan_slider_draw(cairo_t* cr, GdkPixmap* bitmap, PhinFanSlider* slider,
+ int x, int y, int w, int h, int length, gdouble value)
+{
+ PhinFanSliderPrivate* p = PHIN_FAN_SLIDER_GET_PRIVATE (slider);
+ int offset;
+
+ GtkWidget* widget = GTK_WIDGET(slider);
+ GtkStyle* style = (bitmap) ? NULL : gtk_widget_get_style(widget);
+
+ double r1, g1, b1, a1; /* slider bg */
+ double r2, g2, b2, a2; /* slider fg */
+
+ /* length: (orientation dependent, orientation as slider length)
+ length = fan length, so dependant on size of fan */
+
+ /* p->center_val: dependant on range of slider and if zero is
+ within the range.
+ == ratio in range 0.0 to 1.0 of where zero in the value range
+ appears within the slider
+ or
+ == -1 if zero is not within the value range
+ */
+
+ if (bitmap)
+ {
+ r1 = g1 = b1 = a1 = 0.0;
+ r2 = g2 = b2 = a2 = 1.0;
+ }
+ else
+ {
+ gdk_col_to_double(&style->dark[GTK_STATE_NORMAL], &r1, &g1, &b1);
+ gdk_col_to_double(&style->base[GTK_STATE_SELECTED], &r2, &g2, &b2);
+ a1 = 0.35;
+ a2 = 0.75;
+ }
+
+ cairo_set_source_rgba (cr, 0, 0, 0, 0);
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+ cairo_paint (cr);
+
+ if (p->orientation == GTK_ORIENTATION_VERTICAL)
+ {
+ int sign_cur_fan_w;
+
+ float cv = (p->center_val >= 0.0f)
+ ? p->center_val
+ : 0.0f;
+
+ int fan_top_y = y - length / 2 + h / 2;
+ int fan_val_y = length * value;
+ int fan_cv_y = length * cv;
+
+ if (p->direction)
+ {
+ sign_cur_fan_w = 1 * p->cur_fan.width;
+ offset = w;
+ }
+ else
+ {
+ sign_cur_fan_w = -1 * p->cur_fan.width;
+ offset = 0;
+ }
+
+ /* fan background */
+ cairo_move_to( cr, x + offset, y);
+ /* bottom from slider */
+ cairo_line_to ( cr, x + offset + sign_cur_fan_w,
+ fan_top_y);
+ /* vertical fan line */
+ cairo_rel_line_to ( cr, 0, length);
+ /* top line back to slider */
+ cairo_line_to( cr, x + offset, y + h);
+
+ if (supports_alpha)
+ cairo_set_source_rgba( cr, r1, g1, b1, a1);
+ else
+ cairo_set_source_rgb( cr, r1, g1, b1);
+
+ cairo_fill( cr);
+
+ if (bitmap)
+ {
+ /* a bitmap is used as a mask so that when the fan slider is
+ drawn on a non-composited display it does not wipe out the
+ rest of the display for the duration of its showing */
+ return;
+ }
+
+ /* fan value foreground...
+ starting at slider */
+ cairo_move_to ( cr, x + offset, y + h - cv * h);
+ /* center line from slider */
+ cairo_line_to( cr, x + offset + sign_cur_fan_w,
+ fan_top_y + length - fan_cv_y);
+ /* vertical line from center value to value */
+ cairo_rel_line_to( cr, 0, (fan_cv_y - fan_val_y));
+ /* value line back to slider */
+ cairo_line_to( cr, x + offset, y + h - h * value);
+
+ if (supports_alpha)
+ cairo_set_source_rgba( cr, r2, g2, b2, a2);
+ else
+ cairo_set_source_rgb( cr, r2, g2, b2);
+
+ cairo_fill(cr);
+ }
+ else /* (p->orientation == GTK_ORIENTATION_HORIZONTAL) */
+ {
+ int sign_cur_fan_h;
+ float cv = (p->center_val >= 0.0f)
+ ? p->center_val
+ : 0.0f;
+
+ int fan_left_x = x - length / 2 + w / 2;
+ int fan_val_x = length * value;
+ int fan_cv_x = length * cv;
+
+ if (p->direction)
+ {
+ sign_cur_fan_h = 1 * p->cur_fan.height;
+ offset = h;
+ }
+ else
+ {
+ sign_cur_fan_h = -1 * p->cur_fan.height;
+ offset = 0;
+ }
+
+ /* fan background */
+ cairo_move_to ( cr, x, y + offset);
+ /* left-hand line from slider */
+ cairo_line_to ( cr, fan_left_x, y + offset + sign_cur_fan_h);
+ /* horizontal fan line */
+ cairo_rel_line_to ( cr, length, 0);
+ /* right-hand line back to slider */
+ cairo_line_to( cr, x + w, y + offset);
+
+ if (supports_alpha)
+ cairo_set_source_rgba( cr, r1, g1, b1, a1);
+ else
+ cairo_set_source_rgb( cr, r1, g1, b1);
+
+ cairo_fill(cr);
+
+ if (bitmap)
+ {
+ /* a bitmap is used as a mask so that when the fan slider is
+ drawn on a non-composited display it does not wipe out the
+ rest of the display for the duration of its showing */
+ return;
+ }
+
+ /* fan value foreground...
+ starting at slider */
+ cairo_move_to ( cr, x + cv * w, y + offset);
+ /* left-hand line from slider */
+ cairo_line_to ( cr, fan_left_x + fan_cv_x,
+ y + offset + sign_cur_fan_h);
+ /* horizontal line from center value to value */
+ cairo_rel_line_to ( cr, fan_val_x - fan_cv_x, 0);
+ /* value line back to slider */
+ cairo_line_to (cr, x + w * value, y + offset);
+
+ if (supports_alpha)
+ cairo_set_source_rgba( cr, r2, g2, b2, a2);
+ else
+ cairo_set_source_rgb( cr, r2, g2, b2);
+
+ cairo_fill(cr);
+
+ }
+}
+
+
+static void phin_fan_slider_draw_fan (PhinFanSlider* slider)
+{
+ PhinFanSliderPrivate* p = PHIN_FAN_SLIDER_GET_PRIVATE (slider);
+ GtkWidget* widget = GTK_WIDGET (slider);
+
+ int x, y, w, h;
+ int length;
+ double value;
+ cairo_t* cr;
+
+ if (!gtk_widget_is_drawable (p->fan_window))
+ return;
+
+ phin_fan_slider_calc_layout(slider, &x, &y, &w, &h);
+
+ {
+ int root_x, root_y;
+ gdk_window_get_origin(gtk_widget_get_window(widget),
+ &root_x, &root_y);
+ x += root_x;
+ y += root_y;
+ }
+
+ length = phin_fan_slider_get_fan_length (slider);
+
+ if (p->orientation == GTK_ORIENTATION_VERTICAL)
+ {
+ if (p->inverted)
+ value = 1.0 - gtk_adjustment_get_value(p->adjustment_prv);
+ else
+ value = gtk_adjustment_get_value(p->adjustment_prv);
+ }
+ else
+ {
+ if (p->inverted)
+ value = 1.0 - gtk_adjustment_get_value(p->adjustment_prv);
+ else
+ value = gtk_adjustment_get_value(p->adjustment_prv);
+ }
+
+ cr = gdk_cairo_create(gtk_widget_get_window(p->fan_window));
+
+ fan_slider_draw(cr, NULL, slider, x, y, w, h, length, value);
+
+ cairo_destroy(cr);
+}
+
+
+static void phin_fan_slider_calc_layout (PhinFanSlider* slider,
+ int* x, int* y, int* w, int* h)
+{
+ PhinFanSliderPrivate* p = PHIN_FAN_SLIDER_GET_PRIVATE (slider);
+ GtkWidget* widget = GTK_WIDGET (slider);
+ int focus_width, focus_pad;
+ int pad;
+ GtkAllocation widget_alloc;
+
+ gtk_widget_style_get (widget,
+ "focus-line-width", &focus_width,
+ "focus-padding", &focus_pad,
+ NULL);
+
+ pad = focus_width + focus_pad;
+
+ gtk_widget_get_allocation(widget, &widget_alloc);
+
+ if (p->orientation == GTK_ORIENTATION_VERTICAL)
+ {
+ *x = widget_alloc.x + (widget_alloc.width - SLIDER_WIDTH) / 2;
+ *y = widget_alloc.y + pad;
+ *w = SLIDER_WIDTH;
+ *h = widget_alloc.height - 2 * pad;
+ }
+ else
+ {
+ *x = widget_alloc.x + pad;
+ *y = widget_alloc.y + (widget_alloc.height - SLIDER_WIDTH) / 2;
+ *w = widget_alloc.width - 2 * pad;
+ *h = SLIDER_WIDTH;
+ }
+}
+
+
+static void phin_fan_slider_update_value (PhinFanSlider* slider,
+ int x_root, int y_root)
+{
+ PhinFanSliderPrivate* p = PHIN_FAN_SLIDER_GET_PRIVATE (slider);
+ int length;
+ double oldval;
+ double value;
+ double inc;
+ GtkAllocation slider_alloc;
+
+ if (p->state != STATE_CLICKED)
+ return;
+
+ gtk_widget_get_allocation(GTK_WIDGET(slider), &slider_alloc);
+
+ oldval = p->val;
+
+ if (p->orientation == GTK_ORIENTATION_VERTICAL)
+ {
+ if (gtk_widget_is_drawable (p->fan_window)
+ && (x_root != p->xclick_root))
+ {
+ length = phin_fan_slider_get_fan_length (slider);
+ inc = ((p->yclick_root - y_root)
+ * p->value_update_ratio / length);
+ }
+ else
+ {
+ inc = ((p->yclick_root - y_root)
+ * p->value_update_ratio / slider_alloc.height);
+ }
+ }
+ else
+ {
+ if (gtk_widget_is_drawable (p->fan_window)
+ && (y_root != p->yclick_root))
+ {
+ length = phin_fan_slider_get_fan_length (slider);
+ inc = ((x_root - p->xclick_root)
+ * p->value_update_ratio / length);
+ }
+ else
+ {
+ inc = ((x_root - p->xclick_root)
+ * p->value_update_ratio / slider_alloc.width);
+ }
+ }
+
+ if (p->inverted)
+ inc = -inc;
+
+ p->val += inc;
+ p->val = CLAMP (p->val, 0, 1);
+
+ if (p->val != oldval)
+ {
+ value =
+ (gtk_adjustment_get_lower(p->adjustment_prv) * (1.0 - p->val)
+ + gtk_adjustment_get_upper(p->adjustment_prv) * p->val);
+
+ g_signal_handlers_block_by_func(
+ G_OBJECT(slider),
+ phin_fan_slider_adjustment_value_changed,
+ (gpointer) slider);
+
+ gtk_adjustment_set_value(p->adjustment_prv, value);
+
+ g_signal_emit(G_OBJECT(slider), signals[VALUE_CHANGED_SIGNAL], 0);
+
+ g_signal_handlers_unblock_by_func
+ (G_OBJECT (slider),
+ phin_fan_slider_adjustment_value_changed,
+ (gpointer) slider);
+ }
+}
+
+
+static void phin_fan_slider_update_fan (PhinFanSlider* slider,
+ int x, int y)
+{
+ PhinFanSliderPrivate* p = PHIN_FAN_SLIDER_GET_PRIVATE (slider);
+ int width;
+ int height;
+ int w, h;
+ GtkAllocation fan_win_alloc;
+
+ if (p->state != STATE_CLICKED)
+ return;
+
+ gdk_window_get_geometry (p->event_window,
+ NULL, NULL, &w, &h, NULL);
+
+ gtk_widget_get_allocation(p->fan_window, &fan_win_alloc);
+
+ if (p->orientation == GTK_ORIENTATION_VERTICAL)
+ {
+ if (x > w)
+ {
+ width = x - w;
+ width = CLAMP (width, 0, p->fan_max_thickness);
+ p->cur_fan.width = width;
+ p->cur_fan.height = fan_max_height;
+ p->direction = 1;
+
+ if (!gtk_widget_get_visible (p->fan_window))
+ gtk_window_present (GTK_WINDOW (p->fan_window));
+
+ if (gtk_widget_get_visible (p->hint_window0))
+ gtk_widget_hide (p->hint_window0);
+
+ if (gtk_widget_get_visible (p->hint_window1))
+ gtk_widget_hide (p->hint_window1);
+ }
+ else if (x < 0)
+ {
+ width = -x;
+ width = CLAMP (width, 0, p->fan_max_thickness);
+ p->cur_fan.width = width;
+ p->cur_fan.height = fan_max_height;
+ p->direction = 0;
+
+ if (!gtk_widget_get_visible (p->fan_window))
+ gtk_window_present (GTK_WINDOW (p->fan_window));
+
+ if (gtk_widget_get_visible (p->hint_window0))
+ gtk_widget_hide (p->hint_window0);
+
+ if (gtk_widget_get_visible (p->hint_window1))
+ gtk_widget_hide (p->hint_window1);
+ }
+ else if (gtk_widget_get_visible (p->fan_window))
+ {
+ gtk_widget_hide (p->fan_window);
+ }
+ }
+ else
+ {
+ if (y > h)
+ {
+ height = y - h;
+ height = CLAMP (height, 0, p->fan_max_thickness);
+ p->cur_fan.width = fan_max_width;
+ p->cur_fan.height = height;
+ p->direction = 1;
+
+ if (!gtk_widget_get_visible (p->fan_window))
+ gtk_window_present (GTK_WINDOW (p->fan_window));
+
+ if (gtk_widget_get_visible (p->hint_window0))
+ gtk_widget_hide (p->hint_window0);
+
+ if (gtk_widget_get_visible (p->hint_window1))
+ gtk_widget_hide (p->hint_window1);
+ }
+ else if (y < 0)
+ {
+ height = -y;
+ height = CLAMP (height, 0, p->fan_max_thickness);
+ p->cur_fan.width = fan_max_width;
+ p->cur_fan.height = height;
+ p->direction = 0;
+
+ if (!gtk_widget_get_visible (p->fan_window))
+ gtk_window_present (GTK_WINDOW (p->fan_window));
+
+ if (gtk_widget_get_visible (p->hint_window0))
+ gtk_widget_hide (p->hint_window0);
+
+ if (gtk_widget_get_visible (p->hint_window1))
+ gtk_widget_hide (p->hint_window1);
+ }
+ else if (gtk_widget_get_visible (p->fan_window))
+ {
+ gtk_widget_hide (p->fan_window);
+ }
+ }
+}
+
+
+static int phin_fan_slider_get_fan_length (PhinFanSlider* slider)
+{
+ PhinFanSliderPrivate* p = PHIN_FAN_SLIDER_GET_PRIVATE (slider);
+ GtkAllocation fan_win_alloc;
+ GtkAllocation slider_alloc;
+
+ gtk_widget_get_allocation(p->fan_window, &fan_win_alloc);
+ gtk_widget_get_allocation(GTK_WIDGET(slider), &slider_alloc);
+
+ if (p->orientation == GTK_ORIENTATION_VERTICAL)
+ {
+ return 2 * (FAN_RISE / FAN_RUN)
+ * p->cur_fan.width
+ + slider_alloc.height;
+ }
+ else
+ {
+ return 2 * (FAN_RISE / FAN_RUN)
+ * p->cur_fan.height
+ + slider_alloc.width;
+ }
+}
+
+static gboolean phin_fan_slider_fan_expose (GtkWidget* widget,
+ GdkEventExpose* event,
+ PhinFanSlider* slider)
+{
+ (void)widget; (void)event;
+ phin_fan_slider_draw_fan (slider);
+
+ return TRUE;
+}
+
+static void phin_fan_slider_fan_show (GtkWidget* widget,
+ GtkWidget* slider)
+{
+ (void)widget; (void)slider;
+}
+
+static gboolean phin_fan_slider_hint_expose (GtkWidget* widget,
+ GdkEventExpose* event,
+ GtkWidget* slider)
+{
+ (void)widget; (void)slider; (void)event;
+ return TRUE;
+}
+
+
+/* setup the hint arrows. these should hint to the user to move the
+ * mouse in such a direction as to bring the fans out.
+ */
+
+static void phin_fan_slider_update_hints (PhinFanSlider* slider)
+{
+ (void)slider;
+/*
+ GdkRegion* oldclip0 = p->hint_clip0;
+ GdkRegion* oldclip1 = p->hint_clip1;
+
+ gtk_window_resize (GTK_WINDOW (p->hint_window0), 9, 9);
+ gtk_window_resize (GTK_WINDOW (p->hint_window1), 9, 9);
+
+ if (p->orientation == GTK_ORIENTATION_VERTICAL)
+ {
+ GdkPoint points0[7] = {
+ { 8, 3 },
+ { 4, 3 },
+ { 4, 0 },
+ { 0, 4 },
+ { 4, 8 },
+ { 4, 6 },
+ { 8, 6 }
+ };
+
+ GdkPoint points1[7] = {
+ { 0, 3 },
+ { 4, 3 },
+ { 4, 0 },
+ { 8, 4 },
+ { 4, 8 },
+ { 4, 6 },
+ { 0, 6 }
+ };
+
+ p->hint_clip0 = gdk_region_polygon (points0, 7, GDK_EVEN_ODD_RULE);
+ p->hint_clip1 = gdk_region_polygon (points1, 7, GDK_EVEN_ODD_RULE);
+
+ gdk_window_shape_combine_region (p->hint_window0->window,
+ p->hint_clip0, 0, 0);
+ gdk_window_shape_combine_region (p->hint_window1->window,
+ p->hint_clip1, 0, 0);
+ }
+ else
+ {
+ GdkPoint points0[7] = {
+ { 3, 8 },
+ { 3, 4 },
+ { 0, 4 },
+ { 4,-1 },
+ { 9, 4 },
+ { 6, 4 },
+ { 6, 8 }
+ };
+
+ GdkPoint points1[7] = {
+ { 3, 0 },
+ { 3, 4 },
+ { 0, 4 },
+ { 4, 9 },
+ { 9, 4 },
+ { 6, 4 },
+ { 6, 0 }
+ };
+
+ p->hint_clip0 = gdk_region_polygon (points0, 7, GDK_EVEN_ODD_RULE);
+ p->hint_clip1 = gdk_region_polygon (points1, 7, GDK_EVEN_ODD_RULE);
+
+ gdk_window_shape_combine_region (p->hint_window0->window,
+ p->hint_clip0, 0, 0);
+ gdk_window_shape_combine_region (p->hint_window1->window,
+ p->hint_clip1, 0, 0);
+ }
+
+ if (oldclip0 != NULL)
+ gdk_region_destroy (oldclip0);
+ if (oldclip1 != NULL)
+ gdk_region_destroy (oldclip1);
+*/
+}
+
+
+static void phin_fan_slider_adjustment_changed (GtkAdjustment* adj,
+ PhinFanSlider* slider)
+{
+ PhinFanSliderPrivate* p = PHIN_FAN_SLIDER_GET_PRIVATE (slider);
+ GtkWidget* widget;
+ double adj_lower, adj_upper, adj_value;
+
+ g_return_if_fail (PHIN_IS_FAN_SLIDER (slider));
+
+ widget = GTK_WIDGET (slider);
+
+ adj_lower = gtk_adjustment_get_lower(adj);
+ adj_upper = gtk_adjustment_get_upper(adj);
+ adj_value = gtk_adjustment_get_value(adj);
+
+ if (adj_lower < 0 && adj_upper > 0)
+ {
+ p->center_val = (-adj_lower / (adj_upper - adj_lower));
+ }
+ else
+ {
+ p->center_val = -1;
+ }
+
+ p->val = ((adj_value - adj_lower)
+ / (adj_upper - adj_lower));
+
+ gtk_widget_queue_draw (GTK_WIDGET (slider));
+
+ if (gtk_widget_get_realized (widget))
+ gdk_window_process_updates (gtk_widget_get_window(widget), FALSE);
+
+ g_signal_emit (G_OBJECT (slider), signals[CHANGED_SIGNAL], 0);
+}
+
+static void phin_fan_slider_adjustment_value_changed (GtkAdjustment* adj,
+ PhinFanSlider* slider)
+{
+ PhinFanSliderPrivate* p = PHIN_FAN_SLIDER_GET_PRIVATE (slider);
+ GtkWidget* widget;
+ double adj_lower, adj_upper, adj_value;
+
+ g_return_if_fail (PHIN_IS_FAN_SLIDER (slider));
+
+ widget = GTK_WIDGET (slider);
+ adj_lower = gtk_adjustment_get_lower(adj);
+ adj_upper = gtk_adjustment_get_upper(adj);
+ adj_value = gtk_adjustment_get_value(adj);
+
+ p->val = ((adj_value - adj_lower) / (adj_upper - adj_lower));
+
+ gtk_widget_queue_draw (widget);
+
+ if (gtk_widget_get_realized (widget))
+ gdk_window_process_updates (gtk_widget_get_window(widget), FALSE);
+
+ g_signal_emit (G_OBJECT (slider), signals[VALUE_CHANGED_SIGNAL], 0);
+
+ if (p->adjustment != NULL)
+ {
+ phin_fan_slider_get_value(slider);
+ /* update value of external adjustment */
+ }
+}
diff --git a/libphin/phinfanslider.h b/libphin/phinfanslider.h
new file mode 100644
index 0000000..93c2c0a
--- /dev/null
+++ b/libphin/phinfanslider.h
@@ -0,0 +1,118 @@
+/* Phin is a fork of the PHAT Audio Toolkit.
+ Phin is part of Petri-Foo. Petri-Foo is a fork of Specimen.
+
+ Original author Pete Bessman
+ Copyright 2005 Pete Bessman
+ Copyright 2011 James W. Morris
+
+ This file is part of Phin.
+
+ Phin is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+
+ Phin is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Phin. If not, see <http://www.gnu.org/licenses/>.
+
+ This file is a derivative of a PHAT original, modified 2011
+*/
+/* Phin is a fork of PHAT
+
+ Original Specimen author Pete Bessman
+ Copyright 2005 Pete Bessman
+ Copyright 2011 James W. Morris
+
+ This file is part of Phin
+
+ Phin is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+
+ Phin is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Phin. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __PHIN_FAN_SLIDER_H__
+#define __PHIN_FAN_SLIDER_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define PHIN_TYPE_FAN_SLIDER (phin_fan_slider_get_type())
+#define PHIN_FAN_SLIDER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), PHIN_TYPE_FAN_SLIDER, \
+ PhinFanSlider))
+
+#define PHIN_FAN_SLIDER_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), PHIN_TYPE_FAN_SLIDER, \
+ PhinFanSliderClass))
+
+#define PHIN_IS_FAN_SLIDER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), PHIN_TYPE_FAN_SLIDER))
+
+#define PHIN_IS_FAN_SLIDER_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), PHIN_TYPE_FAN_SLIDER))
+
+
+typedef struct _PhinFanSliderClass PhinFanSliderClass;
+typedef struct _PhinFanSlider PhinFanSlider;
+
+
+struct _PhinFanSlider
+{
+ GtkWidget parent;
+};
+
+
+struct _PhinFanSliderClass
+{
+ GtkWidgetClass parent_class;
+ /* private */
+ void (*value_changed) (PhinFanSlider* slider);
+ void (*changed) (PhinFanSlider* slider);
+};
+
+/* whether to use fans on the sliders or not (requires compositing).*/
+void phin_fan_slider_set_fans_active(gboolean enable_fans);
+gboolean phin_fan_slider_get_fans_active(void);
+
+
+GType phin_fan_slider_get_type( void );
+void phin_fan_slider_set_value( PhinFanSlider*, double );
+void phin_fan_slider_set_log( PhinFanSlider*, gboolean );
+gboolean phin_fan_slider_is_log( PhinFanSlider* );
+double phin_fan_slider_get_value( PhinFanSlider* );
+
+void phin_fan_slider_set_range( PhinFanSlider*, double lower,
+ double upper );
+void phin_fan_slider_get_range( PhinFanSlider*, double* lower,
+ double* upper );
+
+void phin_fan_slider_set_adjustment( PhinFanSlider*,
+ GtkAdjustment* );
+GtkAdjustment* phin_fan_slider_get_adjustment( PhinFanSlider* );
+
+void phin_fan_slider_set_inverted( PhinFanSlider*, gboolean);
+gboolean phin_fan_slider_get_inverted( PhinFanSlider*);
+
+void phin_fan_slider_set_default_value( PhinFanSlider*, gdouble );
+
+/* run once */
+void phin_fan_slider_set_orientation( PhinFanSlider*,
+ GtkOrientation );
+
+G_END_DECLS
+
+#endif /* __PHIN_FAN_SLIDER_H__ */
+
diff --git a/libphin/phinhfanslider.c b/libphin/phinhfanslider.c
new file mode 100644
index 0000000..671e4a7
--- /dev/null
+++ b/libphin/phinhfanslider.c
@@ -0,0 +1,79 @@
+/* Phin is a fork of the PHAT Audio Toolkit.
+ Phin is part of Petri-Foo. Petri-Foo is a fork of Specimen.
+
+ Original author Pete Bessman
+ Copyright 2005 Pete Bessman
+ Copyright 2011 James W. Morris
+
+ This file is part of Phin.
+
+ Phin is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+
+ Phin is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Phin. If not, see <http://www.gnu.org/licenses/>.
+
+ This file is a derivative of a PHAT original, modified 2011
+*/
+#include <gtk/gtk.h>
+
+
+#include "phinprivate.h"
+#include "phinfanslider.h"
+#include "phinhfanslider.h"
+
+
+G_DEFINE_TYPE(PhinHFanSlider, phin_hfan_slider, PHIN_TYPE_FAN_SLIDER);
+
+
+GtkWidget* phin_hfan_slider_new (GtkAdjustment* adjustment)
+{
+ PhinHFanSlider* slider;
+
+ gdouble adj_lower = gtk_adjustment_get_lower(adjustment);
+ gdouble adj_upper = gtk_adjustment_get_upper(adjustment);
+ gdouble adj_value = gtk_adjustment_get_value(adjustment);
+
+ g_assert (adj_lower < adj_upper);
+ g_assert((adj_value >= adj_lower)
+ && (adj_value <= adj_upper));
+
+ slider = g_object_new (PHIN_TYPE_HFAN_SLIDER, NULL);
+
+ phin_fan_slider_set_orientation(PHIN_FAN_SLIDER(slider),
+ GTK_ORIENTATION_HORIZONTAL);
+
+ phin_fan_slider_set_adjustment( PHIN_FAN_SLIDER (slider), adjustment);
+
+ return (GtkWidget*) slider;
+}
+
+
+GtkWidget* phin_hfan_slider_new_with_range (double value, double lower,
+ double upper, double step)
+{
+ GtkAdjustment* adj;
+
+ adj = (GtkAdjustment*)gtk_adjustment_new(value, lower, upper,
+ step, step, 0);
+ return phin_hfan_slider_new (adj);
+}
+
+
+static void phin_hfan_slider_class_init(PhinHFanSliderClass* klass)
+{
+ phin_hfan_slider_parent_class = g_type_class_peek_parent(klass);
+}
+
+
+static void phin_hfan_slider_init(PhinHFanSlider* slider)
+{
+ (void)slider;
+ return;
+}
diff --git a/libphin/phinhfanslider.h b/libphin/phinhfanslider.h
new file mode 100644
index 0000000..5d370e4
--- /dev/null
+++ b/libphin/phinhfanslider.h
@@ -0,0 +1,76 @@
+/* Phin is a fork of the PHAT Audio Toolkit.
+ Phin is part of Petri-Foo. Petri-Foo is a fork of Specimen.
+
+ Original author Pete Bessman
+ Copyright 2005 Pete Bessman
+ Copyright 2011 James W. Morris
+
+ This file is part of Phin.
+
+ Phin is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+
+ Phin is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Phin. If not, see <http://www.gnu.org/licenses/>.
+
+ This file is a derivative of a PHAT original, modified 2011
+*/
+#ifndef __PHIN_HFAN_SLIDER_H__
+#define __PHIN_HFAN_SLIDER_H__
+
+#include <gtk/gtk.h>
+
+#include "phinfanslider.h"
+
+
+G_BEGIN_DECLS
+
+#define PHIN_TYPE_HFAN_SLIDER \
+ (phin_hfan_slider_get_type())
+
+#define PHIN_HFAN_SLIDER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), PHIN_TYPE_HFAN_SLIDER, \
+ PhinHFanSlider))
+
+#define PHIN_IS_HFAN_SLIDER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), PHIN_TYPE_HFAN_SLIDER))
+
+
+#define PHIN_HFAN_SLIDER_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), PHIN_TYPE_HFAN_SLIDER, \
+ PhinHFanSliderClass))
+
+#define PHIN_IS_HFAN_SLIDER_CLASS(klass) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((klass), PHIN_TYPE_HFAN_SLIDER))
+
+
+typedef struct _PhinHFanSliderClass PhinHFanSliderClass;
+typedef struct _PhinHFanSlider PhinHFanSlider;
+
+struct _PhinHFanSlider
+{
+ PhinFanSlider parent;
+};
+
+struct _PhinHFanSliderClass
+{
+ PhinFanSliderClass parent_class;
+};
+
+GType phin_hfan_slider_get_type ( );
+
+GtkWidget* phin_hfan_slider_new (GtkAdjustment* adjustment);
+
+GtkWidget* phin_hfan_slider_new_with_range (double value,
+ double lower,
+ double upper,
+ double step);
+G_END_DECLS
+
+#endif /* __PHIN_HFAN_SLIDER_H__ */
diff --git a/libphin/phinhkeyboard.c b/libphin/phinhkeyboard.c
new file mode 100644
index 0000000..68422e0
--- /dev/null
+++ b/libphin/phinhkeyboard.c
@@ -0,0 +1,67 @@
+/* Phin is a fork of the PHAT Audio Toolkit.
+ Phin is part of Petri-Foo. Petri-Foo is a fork of Specimen.
+
+ Original author Pete Bessman
+ Copyright 2005 Pete Bessman
+ Copyright 2011 James W. Morris
+
+ This file is part of Phin.
+
+ Phin is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+
+ Phin is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Phin. If not, see <http://www.gnu.org/licenses/>.
+
+ This file is a derivative of a PHAT original, modified 2011
+*/
+#include <gtk/gtk.h>
+
+#include "phinhkeyboard.h"
+
+
+G_DEFINE_TYPE(PhinHKeyboard, phin_hkeyboard, PHIN_TYPE_KEYBOARD);
+
+
+static void phin_hkeyboard_class_init(PhinHKeyboardClass* klass)
+{
+ phin_hkeyboard_parent_class = g_type_class_peek_parent(klass);
+}
+
+
+static void phin_hkeyboard_init(PhinHKeyboard* self)
+{
+ (void)self;
+}
+
+/**
+ * phin_hkeyboard_new:
+ * @adjustment: the #GtkAdjustment that the new keyboard will use for scrolling
+ * @numkeys: number of keys to create
+ * @show_labels: whether to label the C keys
+ *
+ * Creates a new #PhinHKeyboard.
+ *
+ * Returns: a newly created #PhinHKeyboard
+ *
+ */
+GtkWidget* phin_hkeyboard_new(GtkAdjustment* adj, int numkeys,
+ gboolean show_labels)
+{
+ if (!adj)
+ adj = (GtkAdjustment*) gtk_adjustment_new(0, 0, 0, 0, 0, 0);
+
+ return g_object_new(PHIN_TYPE_HKEYBOARD,
+ "hadjustment", adj,
+ "shadow-type", GTK_SHADOW_NONE,
+ "orientation", GTK_ORIENTATION_HORIZONTAL,
+ "numkeys", numkeys,
+ "show-labels", show_labels,
+ NULL);
+}
diff --git a/libphin/phinhkeyboard.h b/libphin/phinhkeyboard.h
new file mode 100644
index 0000000..058af12
--- /dev/null
+++ b/libphin/phinhkeyboard.h
@@ -0,0 +1,76 @@
+/* Phin is a fork of the PHAT Audio Toolkit.
+ Phin is part of Petri-Foo. Petri-Foo is a fork of Specimen.
+
+ Original author Pete Bessman
+ Copyright 2005 Pete Bessman
+ Copyright 2011 James W. Morris
+
+ This file is part of Phin.
+
+ Phin is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+
+ Phin is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Phin. If not, see <http://www.gnu.org/licenses/>.
+
+ This file is a derivative of a PHAT original, modified 2011
+*/
+#ifndef __PHIN_HKEYBOARD__
+#define __PHIN_HKEYBOARD__
+
+#include <gtk/gtk.h>
+
+#include "phinkeyboard.h"
+
+
+G_BEGIN_DECLS
+
+
+#define PHIN_TYPE_HKEYBOARD (phin_hkeyboard_get_type())
+
+#define PHIN_HKEYBOARD(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
+ PHIN_TYPE_HKEYBOARD, PhinHKeyboard))
+
+#define PHIN_HKEYBOARD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), \
+ PHIN_TYPE_HKEYBOARD, \
+ PhinHKeyboardClass))
+
+#define PHIN_IS_HKEYBOARD(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), \
+ PHIN_TYPE_HKEYBOARD))
+
+#define PHIN_IS_HKEYBOARD_CLASS(klass) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((klass), PHIN_TYPE_HKEYBOARD))
+
+
+typedef struct _PhinHKeyboardClass PhinHKeyboardClass;
+typedef struct _PhinHKeyboard PhinHKeyboard;
+
+
+struct _PhinHKeyboard
+{
+ /*< private >*/
+ PhinKeyboard parent;
+};
+
+
+struct _PhinHKeyboardClass
+{
+ /*< private >*/
+ PhinKeyboardClass parent_class;
+};
+
+
+GType phin_hkeyboard_get_type(void);
+GtkWidget* phin_hkeyboard_new(GtkAdjustment*, int numkeys,
+ gboolean show_labels);
+
+
+G_END_DECLS
+
+#endif /* __PHIN_HKEYBOARD__ */
diff --git a/libphin/phinkeyboard.c b/libphin/phinkeyboard.c
new file mode 100644
index 0000000..ef53dd1
--- /dev/null
+++ b/libphin/phinkeyboard.c
@@ -0,0 +1,667 @@
+/* Phin is a fork of the PHAT Audio Toolkit.
+ Phin is part of Petri-Foo. Petri-Foo is a fork of Specimen.
+
+ Original author Pete Bessman
+ Copyright 2005 Pete Bessman
+ Copyright 2011 James W. Morris
+
+ This file is part of Phin.
+
+ Phin is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+
+ Phin is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Phin. If not, see <http://www.gnu.org/licenses/>.
+
+ This file is a derivative of a PHAT original, modified 2011
+*/
+#include <stdio.h>
+#include <gtk/gtk.h>
+#include <libgnomecanvas/libgnomecanvas.h>
+#include "phinkeyboard.h"
+
+
+/* properties */
+enum
+{
+ PROP_0,
+ PROP_ORIENTATION,
+ PROP_NUMKEYS,
+ PROP_SHOWLABELS,
+};
+
+/* signals */
+enum
+{
+ KEY_PRESSED,
+ KEY_RELEASED,
+ LAST_SIGNAL,
+};
+
+static int signals[LAST_SIGNAL];
+
+
+/* magic numbers */
+enum
+{
+ NUMKEYS = 128,
+ MINKEYS = 1,
+ MAXKEYS = 1000,
+ TEXT_POINTS = 7,
+};
+
+/* all colors are 32bits, RGBA, 8 bits (2 hex digits) per channel */
+
+/* natural (white) key colors */
+static const guint KEY_NAT_BG = 0xEEEEEEFF;
+static const guint KEY_NAT_HI = 0xFFFFFFFF;
+static const guint KEY_NAT_LOW = 0x000000FF;
+static const guint KEY_NAT_PRE = 0xFFFFFFFF;
+static const guint KEY_NAT_ON = 0xD7D7D7FF;
+static const guint KEY_NAT_SHAD = 0xAAAAAAFF;
+
+/* accidental (black) key colors */
+static const guint KEY_ACC_BG = 0x949494FF;
+static const guint KEY_ACC_HI = 0xC9C9C9FF;
+static const guint KEY_ACC_LOW = 0x000000FF;
+static const guint KEY_ACC_PRE = 0xA5A5A5FF;
+static const guint KEY_ACC_ON = 0x767676FF;
+static const guint KEY_ACC_SHAD = 0x4D4D4DFF;
+
+/* c text label color */
+static const guint KEY_TEXT_BG = 0x000000FF;
+
+
+typedef struct __Key _Key;
+
+struct __Key
+{
+ int index;
+ PhinKeyboard* keyboard; /* the keyboard we belong to */
+ GnomeCanvasGroup* group; /* the group this key belongs to */
+ GnomeCanvasItem* pre; /* prelight rectangle */
+ GnomeCanvasItem* on; /* active (depressed) rectangle */
+ GnomeCanvasItem* shad; /* active shadow */
+};
+
+
+typedef struct _PhinKeyboardPrivate PhinKeyboardPrivate;
+
+#define PHIN_KEYBOARD_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE((obj), PHIN_TYPE_KEYBOARD, \
+ PhinKeyboardPrivate))
+
+struct _PhinKeyboardPrivate
+{
+ _Key *keys;
+ int nkeys;
+ int label;
+
+ GnomeCanvas* canvas;
+ GtkOrientation orientation;
+};
+
+
+G_DEFINE_TYPE(PhinKeyboard, phin_keyboard, GTK_TYPE_VIEWPORT)
+
+
+static void phin_keyboard_class_init(PhinKeyboardClass* klass);
+static void phin_keyboard_init(PhinKeyboard* self);
+static void phin_keyboard_dispose(GObject* object);
+static void phin_keyboard_set_property(GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void phin_keyboard_get_property(GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+
+static void phin_keyboard_class_init(PhinKeyboardClass* klass)
+{
+ GObjectClass* object_class = G_OBJECT_CLASS(klass);
+
+ phin_keyboard_parent_class = g_type_class_peek_parent(klass);
+
+ object_class->dispose = phin_keyboard_dispose;
+
+ g_type_class_add_private(object_class, sizeof(PhinKeyboardPrivate));
+
+ object_class->set_property = phin_keyboard_set_property;
+ object_class->get_property = phin_keyboard_get_property;
+
+ g_object_class_install_property(object_class,
+ PROP_ORIENTATION,
+ g_param_spec_enum("orientation",
+ "Orientation",
+ "How the keyboard should be arranged on the screen",
+ GTK_TYPE_ORIENTATION,
+ GTK_ORIENTATION_VERTICAL,
+ G_PARAM_READWRITE
+ | G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property(object_class,
+ PROP_NUMKEYS,
+ g_param_spec_int("numkeys",
+ "Number of Keys",
+ "How many keys this keyboard should have",
+ MINKEYS,
+ MAXKEYS,
+ NUMKEYS,
+ G_PARAM_READWRITE
+ | G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property(object_class,
+ PROP_SHOWLABELS,
+ g_param_spec_boolean("show-labels",
+ "Show Labels",
+ "Whether C keys should be labeled or not",
+ TRUE,
+ G_PARAM_READWRITE
+ | G_PARAM_CONSTRUCT_ONLY));
+
+ /**
+ * PhinKeyboard::key-pressed
+ * @keyboard: the object on which the signal was emitted
+ * @key: the index of the key that was pressed
+ *
+ * The "key-pressed" signal is emitted whenever a key is pressed.
+ *
+ */
+ signals[KEY_PRESSED] =
+ g_signal_new ("key-pressed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (PhinKeyboardClass, key_pressed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__INT,
+ G_TYPE_NONE, 1, G_TYPE_INT);
+
+ /**
+ * PhinKeyboard::key-released
+ * @keyboard: the object on which the signal was emitted
+ * @key: the index of the key that was pressed
+ *
+ * The "key-released" signal is emitted whenever a key is released.
+ *
+ */
+ signals[KEY_RELEASED] =
+ g_signal_new ("key-released",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (PhinKeyboardClass, key_released),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__INT,
+ G_TYPE_NONE, 1, G_TYPE_INT);
+
+ klass->key_pressed = NULL;
+ klass->key_released = NULL;
+}
+
+
+static gboolean
+key_press_cb(GnomeCanvasItem* item, GdkEvent* event, _Key* key)
+{
+ (void)item;
+
+ switch (event->type)
+ {
+ case GDK_BUTTON_PRESS:
+ gnome_canvas_item_show(key->on);
+ gnome_canvas_item_show(key->shad);
+ g_signal_emit(key->keyboard, signals[KEY_PRESSED], 0, key->index);
+ break;
+
+ case GDK_BUTTON_RELEASE:
+ gnome_canvas_item_hide(key->on);
+ gnome_canvas_item_hide(key->shad);
+ g_signal_emit(key->keyboard, signals[KEY_RELEASED], 0, key->index);
+ break;
+
+ case GDK_ENTER_NOTIFY:
+ gnome_canvas_item_show(key->pre);
+ break;
+
+ case GDK_LEAVE_NOTIFY:
+ gnome_canvas_item_hide(key->pre);
+ break;
+
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+
+/* so much gayness in here, either I suck or gnome-canvas does; most
+ * likely, we both do */
+static void draw_key(PhinKeyboard* self, int index, int pos, guint bg,
+ guint hi, guint low, guint pre, guint on, guint shad)
+{
+ PhinKeyboardPrivate* p = PHIN_KEYBOARD_GET_PRIVATE(self);
+
+ _Key* key = &p->keys[index];
+ GnomeCanvasPoints* points;
+ int x1;
+ int y1;
+ int x2;
+ int y2;
+
+ if (p->orientation == GTK_ORIENTATION_VERTICAL)
+ {
+ x1 = 0;
+ y1 = pos + 1; /* teh gayz0r */
+ x2 = PHIN_KEYBOARD_KEY_LENGTH - 1;
+ y2 = pos - PHIN_KEYBOARD_KEY_WIDTH + 1;
+ }
+ else
+ {
+ x1 = pos + PHIN_KEYBOARD_KEY_WIDTH - 1;
+ y1 = 0;
+ x2 = pos;
+ y2 = PHIN_KEYBOARD_KEY_LENGTH - 1;
+ }
+
+ /* key group */
+ key->group = (GnomeCanvasGroup*)
+ gnome_canvas_item_new( gnome_canvas_root(p->canvas),
+ gnome_canvas_group_get_type(), NULL);
+
+ g_signal_connect(G_OBJECT(key->group), "event",
+ G_CALLBACK(key_press_cb), (gpointer)key);
+
+ key->index = index;
+ key->keyboard = self;
+
+ /* draw main key rect */
+ gnome_canvas_item_new(key->group,
+ gnome_canvas_rect_get_type(),
+ "x1", (gdouble)x1,
+ "y1", (gdouble)y1,
+ "x2", (gdouble)x2,
+ "y2", (gdouble)y2,
+ "fill-color-rgba", bg,
+ NULL);
+
+ /* draw prelight rect */
+ key->pre = gnome_canvas_item_new(key->group,
+ gnome_canvas_rect_get_type(),
+ "x1", (gdouble)x1,
+ "y1", (gdouble)y1,
+ "x2", (gdouble)x2,
+ "y2", (gdouble)y2,
+ "fill-color-rgba", pre,
+ NULL);
+
+ gnome_canvas_item_hide(key->pre);
+
+ /* draw key highlight */
+ points = gnome_canvas_points_new(3);
+
+ if (p->orientation == GTK_ORIENTATION_VERTICAL)
+ {
+ points->coords[0] = x1+1; points->coords[1] = y1;
+ points->coords[2] = x1+1; points->coords[3] = y2+1;
+ points->coords[4] = x2; points->coords[5] = y2+1;
+ }
+ else
+ {
+ points->coords[0] = x1; points->coords[1] = y1+1;
+ points->coords[2] = x2; points->coords[3] = y1+1;
+ points->coords[4] = x2; points->coords[5] = y2;
+ }
+
+ gnome_canvas_item_new(key->group,
+ gnome_canvas_line_get_type(),
+ "points", points,
+ "width-units", (gdouble)1,
+ "fill-color-rgba", hi,
+ NULL);
+
+ gnome_canvas_points_unref(points);
+
+ /* draw key border */
+ points = gnome_canvas_points_new(4);
+
+ if (p->orientation == GTK_ORIENTATION_VERTICAL)
+ {
+ points->coords[0] = x1; points->coords[1] = y1;
+ points->coords[2] = x1; points->coords[3] = y2;
+ points->coords[4] = x2; points->coords[5] = y2;
+ points->coords[6] = x2; points->coords[7] = y1;
+ }
+ else
+ {
+ points->coords[0] = x2; points->coords[1] = y1;
+ points->coords[2] = x1; points->coords[3] = y1;
+ points->coords[4] = x1; points->coords[5] = y2;
+ points->coords[6] = x2; points->coords[7] = y2;
+ }
+
+ gnome_canvas_item_new(key->group,
+ gnome_canvas_line_get_type(),
+ "points", points,
+ "width-units", (gdouble)1,
+ "fill-color-rgba", low,
+ NULL);
+
+ gnome_canvas_points_unref(points);
+
+ if (p->orientation == GTK_ORIENTATION_VERTICAL)
+ {
+ /* draw active rect */
+ key->on = gnome_canvas_item_new(key->group,
+ gnome_canvas_rect_get_type(),
+ "x1", (gdouble)x1+1,
+ "y1", (gdouble)y1,
+ "x2", (gdouble)x2,
+ "y2", (gdouble)y2+1,
+ "fill-color-rgba", on,
+ NULL);
+ }
+ else
+ {
+ /* draw active rect */
+ key->on = gnome_canvas_item_new(key->group,
+ gnome_canvas_rect_get_type(),
+ "x1", (gdouble)x1,
+ "y1", (gdouble)y1+1,
+ "x2", (gdouble)x2,
+ "y2", (gdouble)y2,
+ "fill-color-rgba", on,
+ NULL);
+ }
+
+ gnome_canvas_item_hide(key->on);
+
+ /* draw active shadow */
+ points = gnome_canvas_points_new(6);
+
+ if (p->orientation == GTK_ORIENTATION_VERTICAL)
+ {
+ points->coords[0] = x1+1; points->coords[1] = y1;
+ points->coords[2] = x1+1; points->coords[3] = y2+1;
+ points->coords[4] = x2; points->coords[5] = y2+1;
+ points->coords[6] = x2; points->coords[7] = y2 + 3;
+ points->coords[8] = x1 + 3; points->coords[9] = y2 + 3;
+ points->coords[10] = x1 + 3;points->coords[11] = y1;
+ }
+ else
+ {
+ points->coords[0] = x1; points->coords[1] = y1 + 1;
+ points->coords[2] = x2; points->coords[3] = y1 + 1;
+ points->coords[4] = x2; points->coords[5] = y2;
+ points->coords[6] = x2 + 2; points->coords[7] = y2;
+ points->coords[8] = x2 + 2; points->coords[9] = y1 + 3;
+ points->coords[10] = x1; points->coords[11] = y1 + 3;
+ }
+
+ key->shad = gnome_canvas_item_new(key->group,
+ gnome_canvas_polygon_get_type(),
+ "points", points,
+ "fill-color-rgba", shad,
+ NULL);
+ gnome_canvas_item_hide(key->shad);
+ gnome_canvas_points_unref(points);
+
+ /* draw label if applicable */
+ if (p->label && (index % 12) == 0)
+ {
+ char* s = g_strdup_printf("%d", index / 12);
+
+ if (p->orientation == GTK_ORIENTATION_VERTICAL)
+ {
+ gnome_canvas_item_new(key->group,
+ gnome_canvas_text_get_type(),
+ "text", s,
+ "x", (gdouble)(x2 - 2),
+ "y", (gdouble)(y1 - (PHIN_KEYBOARD_KEY_WIDTH / 2)),
+ "anchor", GTK_ANCHOR_EAST,
+ "fill-color-rgba", (gint)KEY_TEXT_BG,
+ "font", "sans",
+ "size-points", (gdouble)TEXT_POINTS, NULL);
+ }
+ else
+ {
+ gnome_canvas_item_new(key->group,
+ gnome_canvas_text_get_type(),
+ "text", s,
+ "x", (gdouble)(x1 - (PHIN_KEYBOARD_KEY_WIDTH / 2)),
+ "y", (gdouble)(y2 - 2),
+ "anchor", GTK_ANCHOR_SOUTH,
+ "fill-color-rgba", (gint)KEY_TEXT_BG,
+ "font", "sans",
+ "size-points", (gdouble)TEXT_POINTS,
+ "justification", GTK_JUSTIFY_CENTER, NULL);
+ }
+
+ g_free(s);
+ }
+}
+
+
+static void draw_keyboard(PhinKeyboard* self)
+{
+ PhinKeyboardPrivate* p = PHIN_KEYBOARD_GET_PRIVATE(self);
+ int i, pos, note;
+
+ /* make sure our construction properties are set (this is
+ * _lame_ass_) */
+ if (p->nkeys < 0 || p->label < 0)
+ return;
+
+ p->keys = g_new(_Key, p->nkeys);
+
+ /* orientation */
+ if (p->orientation == GTK_ORIENTATION_VERTICAL)
+ {
+ gtk_widget_set_size_request(GTK_WIDGET(self),
+ PHIN_KEYBOARD_KEY_LENGTH, 0);
+ gtk_widget_set_size_request(GTK_WIDGET(p->canvas),
+ PHIN_KEYBOARD_KEY_LENGTH,
+ (PHIN_KEYBOARD_KEY_WIDTH * p->nkeys));
+ gnome_canvas_set_scroll_region(p->canvas, 0, 0,
+ PHIN_KEYBOARD_KEY_LENGTH - 1,
+ (PHIN_KEYBOARD_KEY_WIDTH * p->nkeys)-1);
+ }
+ else
+ {
+ gtk_widget_set_size_request(GTK_WIDGET(self), 0,
+ PHIN_KEYBOARD_KEY_LENGTH);
+ gtk_widget_set_size_request(GTK_WIDGET(p->canvas),
+ (PHIN_KEYBOARD_KEY_WIDTH * p->nkeys),
+ PHIN_KEYBOARD_KEY_LENGTH);
+ gnome_canvas_set_scroll_region(p->canvas, 0, 0,
+ (PHIN_KEYBOARD_KEY_WIDTH * p->nkeys)-1,
+ PHIN_KEYBOARD_KEY_LENGTH - 1);
+ }
+
+ if (p->orientation == GTK_ORIENTATION_VERTICAL)
+ {
+ pos = (PHIN_KEYBOARD_KEY_WIDTH * p->nkeys) - 1;
+
+ for (i = note = 0; i < p->nkeys; ++i, ++note)
+ {
+ if (note > 11)
+ note = 0;
+
+ switch (note)
+ {
+ case 0: case 2: case 4: case 5: case 7: case 9: case 11:
+ draw_key(self, i, pos, KEY_NAT_BG, KEY_NAT_HI,
+ KEY_NAT_LOW, KEY_NAT_PRE,
+ KEY_NAT_ON, KEY_NAT_SHAD);
+ break;
+
+ default:
+ draw_key(self, i, pos, KEY_ACC_BG, KEY_ACC_HI,
+ KEY_ACC_LOW, KEY_ACC_PRE,
+ KEY_ACC_ON, KEY_ACC_SHAD);
+ break;
+ }
+ pos -= PHIN_KEYBOARD_KEY_WIDTH;
+ }
+ }
+ else
+ {
+ pos = 0;
+
+ for (i = note = 0; i < p->nkeys; ++i, ++note)
+ {
+ if (note > 11)
+ note = 0;
+
+ switch (note)
+ {
+ case 0: case 2: case 4: case 5: case 7: case 9: case 11:
+ draw_key(self, i, pos, KEY_NAT_BG, KEY_NAT_HI,
+ KEY_NAT_LOW, KEY_NAT_PRE,
+ KEY_NAT_ON, KEY_NAT_SHAD);
+ break;
+
+ default:
+ draw_key(self, i, pos, KEY_ACC_BG, KEY_ACC_HI,
+ KEY_ACC_LOW, KEY_ACC_PRE,
+ KEY_ACC_ON, KEY_ACC_SHAD);
+ break;
+ }
+
+ pos += PHIN_KEYBOARD_KEY_WIDTH;
+ }
+ }
+}
+
+
+
+static void phin_keyboard_init(PhinKeyboard* self)
+{
+ PhinKeyboardPrivate* p = PHIN_KEYBOARD_GET_PRIVATE(self);
+ p->keys = NULL;
+ p->nkeys = -1;
+ p->orientation = -1;
+ p->label = -1;
+
+ p->canvas = (GnomeCanvas*) gnome_canvas_new();
+ gtk_container_add(GTK_CONTAINER(self), GTK_WIDGET(p->canvas));
+ gtk_widget_show(GTK_WIDGET(p->canvas));
+}
+
+
+static void phin_keyboard_set_property(GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ PhinKeyboardPrivate* p = PHIN_KEYBOARD_GET_PRIVATE(object);
+
+ switch (prop_id)
+ {
+ case PROP_ORIENTATION:
+ p->orientation = g_value_get_enum(value);
+ break;
+
+ case PROP_NUMKEYS:
+ p->nkeys = g_value_get_int(value);
+ break;
+
+ case PROP_SHOWLABELS:
+ p->label = g_value_get_boolean(value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ return;
+ }
+
+ draw_keyboard(PHIN_KEYBOARD(object));
+}
+
+
+static void phin_keyboard_get_property(GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ PhinKeyboardPrivate* p = PHIN_KEYBOARD_GET_PRIVATE(object);
+
+ switch (prop_id)
+ {
+ case PROP_ORIENTATION:
+ g_value_set_enum (value, p->orientation);
+ break;
+
+ case PROP_NUMKEYS:
+ g_value_set_int(value, p->nkeys);
+ break;
+
+ case PROP_SHOWLABELS:
+ g_value_set_boolean(value, p->label);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+
+static void phin_keyboard_dispose(GObject* object)
+{
+ PhinKeyboardPrivate* p = PHIN_KEYBOARD_GET_PRIVATE(object);
+
+ g_free(p->keys);
+ p->keys = NULL;
+}
+
+
+/**
+ * phin_keyboard_get_adjustment:
+ * @keyboard: a #PhinKeyboard
+ *
+ * Retrives the current adjustment in use by @keyboard.
+ *
+ * Returns: @keyboard's current #GtkAdjustment
+ *
+ */
+GtkAdjustment* phin_keyboard_get_adjustment(PhinKeyboard* kb)
+{
+ PhinKeyboardPrivate* p = PHIN_KEYBOARD_GET_PRIVATE(kb);
+ GtkAdjustment* adj;
+
+ if (p->orientation == GTK_ORIENTATION_VERTICAL)
+ g_object_get(kb, "vadjustment", &adj, (char *)NULL);
+ else
+ g_object_get(kb, "hadjustment", &adj, (char *)NULL);
+
+ return adj;
+}
+
+
+/**
+ * phin_keyboard_set_adjustment:
+ * @keyboard: a #PhinKeyboard
+ * @adjustment: a #GtkAdjustment
+ *
+ * Sets the adjustment used by @keyboard.
+ *
+ */
+void phin_keyboard_set_adjustment(PhinKeyboard* kb, GtkAdjustment* adj)
+{
+ PhinKeyboardPrivate* p = PHIN_KEYBOARD_GET_PRIVATE(kb);
+
+ if (!adj)
+ return;
+
+ if (p->orientation == GTK_ORIENTATION_VERTICAL)
+ g_object_set(kb, "vadjustment", adj, (char *)NULL);
+ else
+ g_object_set(kb, "hadjustment", adj, (char *)NULL);
+}
diff --git a/libphin/phinkeyboard.h b/libphin/phinkeyboard.h
new file mode 100644
index 0000000..aa1704b
--- /dev/null
+++ b/libphin/phinkeyboard.h
@@ -0,0 +1,80 @@
+/* Phin is a fork of the PHAT Audio Toolkit.
+ Phin is part of Petri-Foo. Petri-Foo is a fork of Specimen.
+
+ Original author Pete Bessman
+ Copyright 2005 Pete Bessman
+ Copyright 2011 James W. Morris
+
+ This file is part of Phin.
+
+ Phin is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+
+ Phin is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Phin. If not, see <http://www.gnu.org/licenses/>.
+
+ This file is a derivative of a PHAT original, modified 2011
+*/
+#ifndef __PHIN_KEYBOARD__
+#define __PHIN_KEYBOARD__
+
+#include <gtk/gtk.h>
+#include <libgnomecanvas/libgnomecanvas.h>
+
+G_BEGIN_DECLS
+
+#define PHIN_TYPE_KEYBOARD (phin_keyboard_get_type())
+
+#define PHIN_KEYBOARD(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
+ PHIN_TYPE_KEYBOARD, PhinKeyboard))
+
+#define PHIN_KEYBOARD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), \
+ PHIN_TYPE_KEYBOARD, PhinKeyboardClass))
+
+#define PHIN_IS_KEYBOARD(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), \
+ PHIN_TYPE_KEYBOARD))
+
+#define PHIN_IS_KEYBOARD_CLASS(klass) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((klass), PHIN_TYPE_KEYBOARD))
+
+
+typedef struct _PhinKeyboard PhinKeyboard;
+typedef struct _PhinKeyboardClass PhinKeyboardClass;
+
+
+/* key dimensions */
+enum
+{
+ PHIN_KEYBOARD_KEY_WIDTH = 13,
+ PHIN_KEYBOARD_KEY_LENGTH = 33,
+};
+
+
+struct _PhinKeyboard
+{
+ GtkViewport parent;
+};
+
+
+struct _PhinKeyboardClass
+{
+ GtkViewportClass parent_class;
+ /*< private >*/
+ void (*key_pressed)(PhinKeyboard* keyboard, int key);
+ void (*key_released)(PhinKeyboard* keyboard, int key);
+};
+
+
+GType phin_keyboard_get_type (void);
+GtkAdjustment* phin_keyboard_get_adjustment(PhinKeyboard*);
+void phin_keyboard_set_adjustment(PhinKeyboard*, GtkAdjustment*);
+
+G_END_DECLS
+
+#endif /* __PHIN_KEYBOARD__ */
diff --git a/libphin/phinprivate.c b/libphin/phinprivate.c
new file mode 100644
index 0000000..9e9e4fd
--- /dev/null
+++ b/libphin/phinprivate.c
@@ -0,0 +1,93 @@
+/* Phin is a fork of the PHAT Audio Toolkit.
+ Phin is part of Petri-Foo. Petri-Foo is a fork of Specimen.
+
+ Original author Pete Bessman
+ Copyright 2005 Pete Bessman
+ Copyright 2011 James W. Morris
+
+ This file is part of Phin.
+
+ Phin is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+
+ Phin is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Phin. If not, see <http://www.gnu.org/licenses/>.
+
+ This file is a derivative of a PHAT original, modified 2011
+*/
+#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
+#include "phinprivate.h"
+
+void phin_warp_pointer (int xsrc, int ysrc,
+ int xdest, int ydest)
+{
+ (void)xsrc; (void)ysrc;
+/* this function used to use the Xlib function:
+ XWarpPointer (GDK_DISPLAY ( ), None, None, 0, 0, 0, 0, x, y);
+
+ where:
+ x = xdest - xsrc;
+ y = ydest - ysrc;
+*/
+ gdk_display_warp_pointer (gdk_display_get_default(),
+ gdk_screen_get_default(), xdest, ydest);
+}
+
+
+
+void set_cairo_rgba_from_gdk(cairo_t* cr, GdkColor* col, double a)
+{
+ double r = col->red / 65535.0f;
+ double g = col->green / 65535.0f;
+ double b = col->blue / 65535.0f;
+
+ if (supports_alpha)
+ cairo_set_source_rgba(cr, r, g, b, a);
+ else
+ cairo_set_source_rgb(cr, r, g, b);
+}
+
+
+void gdk_col_to_double(GdkColor* c, double* r, double* g, double* b)
+{
+ *r = c->red / 65535.0f;
+ *g = c->green / 65535.0f;
+ *b = c->blue / 65535.0f;
+}
+
+
+/* Only some X servers support alpha channels. Always have a fallback */
+gboolean supports_alpha = FALSE;
+
+
+/* Only some X servers support alpha channels. Always have a fallback */
+void phin_screen_changed(GtkWidget *widget, GdkScreen *old_screen,
+ gpointer userdata)
+{
+ (void)old_screen; (void)userdata;
+ /* To check if the display supports alpha channels, get the colormap */
+ GdkScreen *screen = gtk_widget_get_screen(widget);
+ GdkColormap *colormap = gdk_screen_get_rgba_colormap(screen);
+
+ if (!colormap)
+ {
+ debug("Your screen does not support alpha channels!\n");
+ colormap = gdk_screen_get_rgb_colormap(screen);
+ supports_alpha = FALSE;
+ }
+ else
+ {
+ debug("Your screen supports alpha channels!\n");
+ supports_alpha = TRUE;
+ }
+
+ /* Now we have a colormap appropriate for the screen, use it */
+ gtk_widget_set_colormap(widget, colormap);
+}
diff --git a/libphin/phinprivate.h b/libphin/phinprivate.h
new file mode 100644
index 0000000..bcd75aa
--- /dev/null
+++ b/libphin/phinprivate.h
@@ -0,0 +1,61 @@
+/* Phin is a fork of the PHAT Audio Toolkit.
+ Phin is part of Petri-Foo. Petri-Foo is a fork of Specimen.
+
+ Original author Pete Bessman
+ Copyright 2005 Pete Bessman
+ Copyright 2011 James W. Morris
+
+ This file is part of Phin.
+
+ Phin is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+
+ Phin is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Phin. If not, see <http://www.gnu.org/licenses/>.
+
+ This file is a derivative of a PHAT original, modified 2011
+*/
+#ifndef __PHIN_PRIVATE_H__
+#define __PHIN_PRIVATE_H__
+
+#include <gtk/gtk.h>
+#include <stdio.h>
+#include "config.h"
+
+
+#ifndef DEBUG
+#define DEBUG 0
+#endif
+
+
+/* no mechanism to set debug for petri-foo but not phin, so force no debug
+ here:
+ */
+
+#ifdef DEBUG
+#undef DEBUG
+#define DEBUG 0
+#endif
+
+
+#define debug(...) if (DEBUG) fprintf (stderr, __VA_ARGS__)
+
+
+extern gboolean supports_alpha;
+
+void phin_screen_changed(GtkWidget *widget, GdkScreen *old_screen,
+ gpointer userdata);
+
+void phin_warp_pointer (int xsrc, int ysrc, int xdest, int ydest);
+
+void set_cairo_rgba_from_gdk(cairo_t* cr, GdkColor* col, double a);
+void gdk_col_to_double(GdkColor* c, double* r, double* g, double* b);
+
+
+#endif /* __PHIN_PRIVATE_H__ */
diff --git a/libphin/phinsliderbutton.c b/libphin/phinsliderbutton.c
new file mode 100644
index 0000000..3976e6b
--- /dev/null
+++ b/libphin/phinsliderbutton.c
@@ -0,0 +1,1770 @@
+/* Phin is a fork of the PHAT Audio Toolkit.
+ Phin is part of Petri-Foo. Petri-Foo is a fork of Specimen.
+
+ Original author Pete Bessman
+ Copyright 2005 Pete Bessman
+ Copyright 2011 James W. Morris
+
+ This file is part of Phin.
+
+ Phin is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+
+ Phin is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Phin. If not, see <http://www.gnu.org/licenses/>.
+
+ This file is a derivative of a PHAT original, modified 2011
+*/
+#include <string.h>
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+#include "phinprivate.h"
+#include "phinsliderbutton.h"
+
+/* hilite states */
+enum
+{
+ LEFT_ARROW = 1,
+ RIGHT_ARROW,
+ LABEL,
+};
+
+/* action states */
+enum
+{
+ STATE_NORMAL,
+ STATE_PRESSED,
+ STATE_SLIDE,
+ STATE_ENTRY,
+ STATE_SCROLL,
+};
+
+/* magic numbers */
+enum
+{
+ SCROLL_THRESHOLD = 4,
+ DIGITS = 2,
+ MAXDIGITS = 20,
+};
+
+/* signals */
+enum
+{
+ CHANGED_SIGNAL,
+ VALUE_CHANGED_SIGNAL,
+ LAST_SIGNAL,
+};
+
+static int signals[LAST_SIGNAL];
+
+
+typedef struct _PhinSliderButtonPrivate PhinSliderButtonPrivate;
+
+#define PHIN_SLIDER_BUTTON_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE((obj), \
+ PHIN_TYPE_SLIDER_BUTTON, PhinSliderButtonPrivate))
+
+
+struct _PhinSliderButtonPrivate
+{
+ GtkAdjustment* adjustment;
+
+ GdkCursor* arrow_cursor;
+ GdkCursor* empty_cursor;
+ GdkWindow* event_window;
+ GtkWidget* left_arrow;
+ GtkWidget* right_arrow;
+ GtkWidget* label;
+ GtkWidget* prefix_label;
+ GtkWidget* postfix_label;
+ GtkWidget* entry;
+
+ char* prefix;
+ char* postfix;
+ int digits;
+ int hilite;
+ int state;
+ int xpress_root;
+ int ypress_root;
+ int xpress;
+ int ypress;
+ int firstrun;
+ guint threshold;
+ gboolean slid;
+};
+
+/* forward declarations */
+G_DEFINE_TYPE(PhinSliderButton, phin_slider_button, GTK_TYPE_HBOX)
+
+static void phin_slider_button_dispose( GObject* object);
+static void phin_slider_button_realize( GtkWidget* widget);
+static void phin_slider_button_unrealize( GtkWidget* widget);
+static void phin_slider_button_map( GtkWidget* widget);
+static void phin_slider_button_unmap( GtkWidget* widget);
+static void phin_slider_button_size_allocate( GtkWidget* widget,
+ GtkAllocation*);
+
+static gboolean phin_slider_button_expose( GtkWidget*,
+ GdkEventExpose*);
+
+static void phin_slider_button_adjustment_changed( GtkAdjustment*,
+ PhinSliderButton* );
+
+static void phin_slider_button_adjustment_value_changed(GtkAdjustment*,
+ PhinSliderButton*);
+
+static void phin_slider_button_entry_activate( GtkEntry*,
+ PhinSliderButton*);
+
+static gboolean phin_slider_button_entry_focus_out( GtkEntry*,
+ GdkEventFocus*,
+ PhinSliderButton*);
+
+static gboolean phin_slider_button_entry_key_press( GtkEntry* entry,
+ GdkEventKey* event,
+ PhinSliderButton*);
+
+static gboolean phin_slider_button_button_press( GtkWidget*,
+ GdkEventButton*);
+
+static gboolean phin_slider_button_button_release( GtkWidget*,
+ GdkEventButton*);
+
+static gboolean phin_slider_button_key_press( GtkWidget*,
+ GdkEventKey*);
+
+static gboolean phin_slider_button_scroll( GtkWidget*,
+ GdkEventScroll*);
+
+static gboolean phin_slider_button_enter_notify( GtkWidget*,
+ GdkEventCrossing*);
+
+static gboolean phin_slider_button_leave_notify( GtkWidget*,
+ GdkEventCrossing*);
+
+static gboolean phin_slider_button_motion_notify( GtkWidget*,
+ GdkEventMotion*);
+
+/* internal utility functions */
+static int check_pointer( PhinSliderButton*, int x, int y);
+static void update_cursor( PhinSliderButton*);
+static void update_label( PhinSliderButton*);
+static void entry_cancel( PhinSliderButton*);
+static void update_size( PhinSliderButton*);
+static char* value_to_string(PhinSliderButton*, double value);
+
+
+
+/**
+ * phin_slider_button_new:
+ * @adjustment: the #GtkAdjustment that the new button will use
+ * @digits: number of decimal digits to display
+ *
+ * Creates a new #PhinSliderButton.
+ *
+ * Returns: a newly created #PhinSliderButton
+ *
+ */
+GtkWidget* phin_slider_button_new(GtkAdjustment* adj, int digits)
+{
+ PhinSliderButton* button;
+ PhinSliderButtonPrivate* p;
+
+ debug ("new\n");
+
+ gdouble adj_lower = gtk_adjustment_get_lower(adj);
+ gdouble adj_upper = gtk_adjustment_get_upper(adj);
+ gdouble adj_value = gtk_adjustment_get_value(adj);
+
+ g_assert (adj_lower < adj_upper);
+ g_assert((adj_value >= adj_lower)
+ && (adj_value <= adj_upper));
+
+ button = g_object_new (PHIN_TYPE_SLIDER_BUTTON, NULL);
+ p = PHIN_SLIDER_BUTTON_GET_PRIVATE(button);
+
+ p->digits = (digits >= 0) ? digits : DIGITS;
+
+ if (p->digits > MAXDIGITS)
+ p->digits = MAXDIGITS;
+
+ phin_slider_button_set_adjustment(button, adj);
+
+ return (GtkWidget*) button;
+}
+
+
+/**
+ * phin_slider_button_new_with_range:
+ * @value: the initial value the new button should have
+ * @lower: the lowest value the new button will allow
+ * @upper: the highest value the new button will allow
+ * @step: increment added or subtracted when sliding
+ * @digits: number of decimal digits to display
+ *
+ * Creates a new #PhinSliderButton. The slider will create a new
+ * #GtkAdjustment from @value, @lower, @upper, and @step. If these
+ * parameters represent a bogus configuration, the program will
+ * terminate.
+ *
+ * Returns: a newly created #PhinSliderButton
+ *
+ */
+GtkWidget* phin_slider_button_new_with_range (double value, double lower,
+ double upper, double step,
+ int digits)
+{
+ GtkAdjustment* adj;
+
+ adj = (GtkAdjustment*)
+ gtk_adjustment_new (value, lower, upper, step, step, 0);
+
+ return phin_slider_button_new (adj, digits);
+}
+
+
+
+/**
+ * phin_slider_button_set_adjustment:
+ * @button: a #PhinSliderButton
+ * @adjustment: a #GtkAdjustment
+ *
+ * Sets the adjustment used by @button. If @adjustment is %NULL, a
+ * new adjustment with a value of zero and a range of [-1.0, 1.0] will
+ * be created.
+ *
+ */
+void phin_slider_button_set_adjustment (PhinSliderButton* button,
+ GtkAdjustment* adj)
+{
+ PhinSliderButtonPrivate* p = PHIN_SLIDER_BUTTON_GET_PRIVATE(button);
+
+ if (!adj)
+ adj = (GtkAdjustment*)
+ gtk_adjustment_new (0.0, -1.0, 1.0, 1.0, 1.0, 0.0);
+
+ if (p->adjustment)
+ {
+ g_signal_handlers_disconnect_by_func(p->adjustment,
+ phin_slider_button_adjustment_changed, (gpointer)button);
+ g_signal_handlers_disconnect_by_func(p->adjustment,
+ phin_slider_button_adjustment_value_changed, (gpointer)button);
+ g_object_unref(p->adjustment);
+ }
+
+ p->adjustment = adj;
+ g_object_ref (adj);
+ g_object_ref_sink (GTK_OBJECT(adj));
+
+ g_signal_connect (adj, "changed",
+ G_CALLBACK(phin_slider_button_adjustment_changed),
+ (gpointer) button);
+
+ g_signal_connect(adj, "value_changed",
+ G_CALLBACK(phin_slider_button_adjustment_value_changed),
+ (gpointer) button);
+
+ phin_slider_button_adjustment_changed (adj, button);
+ phin_slider_button_adjustment_value_changed (adj, button);
+}
+
+
+/**
+ * phin_slider_button_get_adjustment:
+ * @button: a #PhinSliderButton
+ *
+ * Retrives the current adjustment in use by @button.
+ *
+ * Returns: @button's current #GtkAdjustment
+ *
+ */
+GtkAdjustment* phin_slider_button_get_adjustment (PhinSliderButton* button)
+{
+ PhinSliderButtonPrivate* p = PHIN_SLIDER_BUTTON_GET_PRIVATE(button);
+
+ if (!p->adjustment)
+ phin_slider_button_set_adjustment (button, NULL);
+
+ return p->adjustment;
+}
+
+
+
+/**
+ * phin_slider_button_set_value:
+ * @button: a #PhinSliderButton
+ * @value: a new value for the button
+ *
+ * Sets the current value of the button. If the value is outside the
+ * range of values allowed by @button, it will be clamped. The button
+ * emits the "value-changed" signal if the value changes.
+ *
+ */
+void phin_slider_button_set_value (PhinSliderButton* button, double value)
+{
+ PhinSliderButtonPrivate* p = PHIN_SLIDER_BUTTON_GET_PRIVATE(button);
+
+ gdouble adj_lower = gtk_adjustment_get_lower(p->adjustment);
+ gdouble adj_upper = gtk_adjustment_get_upper(p->adjustment);
+
+ value = CLAMP (value, adj_lower, adj_upper);
+
+ gtk_adjustment_set_value (p->adjustment, value);
+}
+
+
+
+/**
+ * phin_slider_button_get_value:
+ * @button: a #PhinSliderButton
+ *
+ * Retrieves the current value of the button.
+ *
+ * Returns: current value of the button
+ *
+ */
+double phin_slider_button_get_value (PhinSliderButton* button)
+{
+ PhinSliderButtonPrivate* p = PHIN_SLIDER_BUTTON_GET_PRIVATE(button);
+ return gtk_adjustment_get_value(p->adjustment);
+}
+
+
+
+/**
+ * phin_slider_button_set_range:
+ * @button: a #PhinSliderButton
+ * @lower: lowest allowable value
+ * @upper: highest allowable value
+ *
+ * Sets the range of allowable values for the button, and clamps the
+ * button's current value to be between @lower and @upper.
+ */
+void phin_slider_button_set_range (PhinSliderButton* button,
+ double lower, double upper)
+{
+ PhinSliderButtonPrivate* p = PHIN_SLIDER_BUTTON_GET_PRIVATE(button);
+ double value;
+
+ g_return_if_fail (lower <= upper);
+
+ gtk_adjustment_set_lower(p->adjustment, lower);
+ gtk_adjustment_set_upper(p->adjustment, upper);
+
+ value = CLAMP (gtk_adjustment_get_value(p->adjustment),
+ gtk_adjustment_get_lower(p->adjustment), /* ott? */
+ gtk_adjustment_get_upper(p->adjustment));
+
+ gtk_adjustment_changed (p->adjustment);
+ gtk_adjustment_set_value (p->adjustment, value);
+}
+
+
+
+/**
+ * phin_slider_button_get_range:
+ * @button: a #PhinSliderButton
+ * @lower: retrieves lowest allowable value
+ * @upper: retrieves highest allowable value
+ *
+ * Places the range of allowable values for @button into @lower
+ * and @upper. Either variable may be set to %NULL if you are not
+ * interested in its value.
+ *
+ */
+void phin_slider_button_get_range (PhinSliderButton* button,
+ double* lower, double* upper)
+{
+ PhinSliderButtonPrivate* p = PHIN_SLIDER_BUTTON_GET_PRIVATE(button);
+
+ if (lower)
+ *lower = gtk_adjustment_get_lower(p->adjustment);
+ if (upper)
+ *upper = gtk_adjustment_get_upper(p->adjustment);
+}
+
+
+
+/**
+ * phin_slider_button_set_increment:
+ * @button: a #PhinSliderButton
+ * @step: step increment value
+ * @page: page increment value
+ *
+ * Sets the increments the button should use.
+ *
+ */
+void phin_slider_button_set_increment (PhinSliderButton* button,
+ double step, double page)
+{
+ PhinSliderButtonPrivate* p = PHIN_SLIDER_BUTTON_GET_PRIVATE(button);
+
+ gtk_adjustment_set_step_increment(p->adjustment, step);
+ gtk_adjustment_set_page_increment(p->adjustment, page);
+}
+
+
+
+/**
+ * phin_slider_button_get_increment:
+ * @button: a #PhinSliderButton
+ * @step: retrieves step increment value
+ * @page: retrieves page increment value
+ *
+ * Places the button's increment values into @step and @page. Either
+ * variable may be set to %NULL if you are not interested in its
+ * value.
+ *
+ */
+void phin_slider_button_get_increment (PhinSliderButton* button,
+ double* step, double* page)
+{
+ PhinSliderButtonPrivate* p = PHIN_SLIDER_BUTTON_GET_PRIVATE(button);
+
+ if (step)
+ *step = gtk_adjustment_get_step_increment(p->adjustment);
+ if (page)
+ *page = gtk_adjustment_get_page_increment(p->adjustment);
+}
+
+
+
+/**
+ * phin_slider_button_set_format:
+ * @button: a #PhinSliderButton
+ * @digits: number of decimal digits to display
+ * @prefix: text to prepend to number
+ * @postfix: text to append to number
+ *
+ * Sets the way @button renders it's label. If the first character in
+ * either @prefix or @postfix is '\0' the corresponding parameter will
+ * be unset. If you don't want to adjust @digits, set it to a
+ * negative value. If you don't want to adjust @prefix and/or
+ * @postfix, set them to %NULL.
+ *
+ */
+void phin_slider_button_set_format (PhinSliderButton* button,
+ int digits,
+ const char* prefix,
+ const char* postfix)
+{
+ PhinSliderButtonPrivate* p = PHIN_SLIDER_BUTTON_GET_PRIVATE(button);
+
+ if (digits >= 0)
+ {
+ p->digits = digits;
+
+ if (p->digits > MAXDIGITS)
+ p->digits = MAXDIGITS;
+ }
+
+ if (prefix)
+ {
+ g_free (p->prefix);
+
+ if (*prefix == '\0')
+ {
+ p->prefix = NULL;
+ }
+ else
+ {
+ p->prefix = g_strdup (prefix);
+ }
+ }
+
+ if (postfix)
+ {
+ g_free (p->postfix);
+
+ if (*postfix == '\0')
+ {
+ p->postfix = NULL;
+ }
+ else
+ {
+ p->postfix = g_strdup (postfix);
+ }
+ }
+
+ update_size (button);
+ update_label (button);
+}
+
+
+
+/**
+ * phin_slider_button_get_format:
+ * @button: a #PhinSliderButton
+ * @digits: retrieves the number of decimal digits to display
+ * @prefix: retrieves text prepended to number
+ * @postfix: retrieves text appended to number
+ *
+ * Retrieves the information @button uses to create its label. The
+ * value returned will point to the button's local copy, so don't
+ * write to it. Set the pointers for any value you aren't interested
+ * in to %NULL.
+ *
+ */
+void phin_slider_button_get_format (PhinSliderButton* button,
+ int* digits,
+ char** prefix,
+ char** postfix)
+{
+ PhinSliderButtonPrivate* p = PHIN_SLIDER_BUTTON_GET_PRIVATE(button);
+
+ if (digits)
+ *digits = p->digits;
+
+ if (prefix)
+ *prefix = p->prefix;
+
+ if (postfix)
+ *postfix = p->postfix;
+}
+
+
+/**
+ * phin_slider_button_set_threshold:
+ * @button: a #PhinSliderButton
+ * @threshold: an unsigned int >= 1
+ *
+ * Sets the threshold for @button. The threshold is how far the user
+ * has to move the mouse to effect a change when sliding.
+ *
+ */
+void phin_slider_button_set_threshold (PhinSliderButton* button,
+ guint threshold)
+{
+ PhinSliderButtonPrivate* p = PHIN_SLIDER_BUTTON_GET_PRIVATE(button);
+ g_return_if_fail (threshold != 0);
+
+ p->threshold = threshold;
+}
+
+
+/**
+ * phin_slider_button_get_threshold:
+ * @button: a #PhinSliderButton
+ *
+ * Retrieves the threshold for @button
+ *
+ * Returns: the threshold for @button, or -1 if @button is invalid
+ *
+ */
+int phin_slider_button_get_threshold (PhinSliderButton* button)
+{
+ PhinSliderButtonPrivate* p = PHIN_SLIDER_BUTTON_GET_PRIVATE(button);
+ return p->threshold;
+}
+
+
+static void phin_slider_button_class_init (PhinSliderButtonClass* klass)
+{
+ GObjectClass* object_class = G_OBJECT_CLASS(klass);
+ GtkWidgetClass* widget_class = GTK_WIDGET_CLASS(klass);
+
+ phin_slider_button_parent_class = g_type_class_peek_parent(klass);
+
+ g_type_class_add_private(object_class, sizeof(PhinSliderButtonPrivate));
+
+ object_class->dispose = phin_slider_button_dispose;
+
+ widget_class->realize = phin_slider_button_realize;
+ widget_class->unrealize = phin_slider_button_unrealize;
+ widget_class->map = phin_slider_button_map;
+ widget_class->unmap = phin_slider_button_unmap;
+ widget_class->size_allocate = phin_slider_button_size_allocate;
+ widget_class->expose_event = phin_slider_button_expose;
+ widget_class->button_press_event = phin_slider_button_button_press;
+ widget_class->button_release_event= phin_slider_button_button_release;
+ widget_class->key_press_event = phin_slider_button_key_press;
+ widget_class->scroll_event = phin_slider_button_scroll;
+ widget_class->enter_notify_event = phin_slider_button_enter_notify;
+ widget_class->leave_notify_event = phin_slider_button_leave_notify;
+ widget_class->motion_notify_event = phin_slider_button_motion_notify;
+
+ /**
+ * PhinSliderButton::value-changed:
+ * @button: the object on which the signal was emitted
+ *
+ * The "value-changed" signal is emitted when the value of the
+ * button's adjustment changes.
+ *
+ */
+ signals[VALUE_CHANGED_SIGNAL] =
+ g_signal_new ("value-changed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (PhinSliderButtonClass, value_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
+
+ /**
+ * PhinSliderButton::changed:
+ * @button: the object on which the signal was emitted
+ *
+ * The "changed" signal is emitted when any parameter of the
+ * slider's adjustment changes, except for the %value parameter.
+ *
+ */
+ signals[CHANGED_SIGNAL] =
+ g_signal_new ("changed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (PhinSliderButtonClass, changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
+
+ klass->value_changed = NULL;
+ klass->changed = NULL;
+}
+
+
+
+static void phin_slider_button_init (PhinSliderButton* button)
+{
+ PhinSliderButtonPrivate* p = PHIN_SLIDER_BUTTON_GET_PRIVATE(button);
+ GtkBox* box = GTK_BOX (button);
+ GtkWidget* widget = GTK_WIDGET (button);
+ GtkContainer* container = GTK_CONTAINER (button);
+ int focus_width, focus_pad;
+ GtkStyle* style;
+
+ gtk_widget_set_can_focus(widget, TRUE);
+
+ /* our parent class sets this to false; we need it to be true so
+ * that we are drawn without glitches when first shown
+ * (mapped) */
+ gtk_widget_set_redraw_on_allocate (GTK_WIDGET (box), TRUE);
+
+ p->arrow_cursor = NULL;
+ p->empty_cursor = NULL;
+ p->event_window = NULL;
+ p->left_arrow = gtk_arrow_new (GTK_ARROW_LEFT, GTK_SHADOW_NONE);
+ p->right_arrow = gtk_arrow_new (GTK_ARROW_RIGHT, GTK_SHADOW_NONE);
+ p->label = gtk_label_new (NULL);
+ p->prefix_label = NULL;
+ p->postfix_label = NULL;
+ p->entry = gtk_entry_new ( );
+ p->adjustment = NULL;
+ p->prefix = NULL;
+ p->postfix = NULL;
+ p->digits = DIGITS;
+ p->hilite = 0;
+ p->state = STATE_NORMAL;
+ p->xpress = 0;
+ p->ypress = 0;
+ p->xpress_root = 0;
+ p->ypress_root = 0;
+ p->threshold = 3;
+ p->slid = FALSE;
+ p->firstrun = 1;
+
+ gtk_box_pack_start (box, p->left_arrow, FALSE, FALSE, 0);
+ gtk_box_pack_start (box, p->label, TRUE, TRUE, 0);
+ gtk_box_pack_start (box, p->entry, TRUE, TRUE, 0);
+ gtk_box_pack_start (box, p->right_arrow, FALSE, FALSE, 0);
+
+ gtk_widget_style_get (widget,
+ "focus-line-width", &focus_width,
+ "focus-padding", &focus_pad,
+ NULL);
+
+ style = gtk_widget_get_style(widget);
+
+ gtk_container_set_border_width (container,
+ MAX( MAX(style->xthickness, style->ythickness),
+ focus_width + focus_pad));
+
+ gtk_entry_set_has_frame (GTK_ENTRY (p->entry), FALSE);
+
+ gtk_entry_set_alignment (GTK_ENTRY (p->entry), 0.5);
+
+ g_signal_connect (G_OBJECT (p->entry), "activate",
+ G_CALLBACK (phin_slider_button_entry_activate),
+ (gpointer) button);
+
+ g_signal_connect (G_OBJECT (p->entry), "focus-out-event",
+ G_CALLBACK (phin_slider_button_entry_focus_out),
+ (gpointer) button);
+
+ g_signal_connect (G_OBJECT (p->entry), "key-press-event",
+ G_CALLBACK (phin_slider_button_entry_key_press),
+ (gpointer) button);
+
+ gtk_misc_set_alignment (GTK_MISC (p->left_arrow), 0.5, 0.5);
+ gtk_misc_set_alignment (GTK_MISC (p->right_arrow), 0.5, 0.5);
+}
+
+
+
+static void phin_slider_button_dispose (GObject* object)
+{
+ PhinSliderButtonPrivate* p;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (PHIN_IS_SLIDER_BUTTON (object));
+
+ p = PHIN_SLIDER_BUTTON_GET_PRIVATE(object);
+
+ if (p->arrow_cursor)
+ {
+ gdk_cursor_unref (p->arrow_cursor);
+ p->arrow_cursor = NULL;
+ }
+
+ if (p->empty_cursor)
+ {
+ gdk_cursor_unref (p->empty_cursor);
+ p->empty_cursor = NULL;
+ }
+
+ if (p->event_window)
+ {
+ gdk_window_set_user_data (p->event_window, NULL);
+ gdk_window_destroy (p->event_window);
+ p->event_window = NULL;
+ }
+
+ if (p->left_arrow)
+ {
+ gtk_widget_destroy (p->left_arrow);
+ p->left_arrow = NULL;
+ }
+
+ if (p->right_arrow)
+ {
+ gtk_widget_destroy (p->right_arrow);
+ p->right_arrow = NULL;
+ }
+
+ if (p->label)
+ {
+ gtk_widget_destroy (p->label);
+ p->label = NULL;
+ }
+
+ if (p->prefix_label)
+ {
+ gtk_widget_destroy (p->prefix_label);
+ p->prefix_label = NULL;
+ }
+
+ if (p->postfix_label)
+ {
+ gtk_widget_destroy (p->postfix_label);
+ p->postfix_label = NULL;
+ }
+
+ if (p->entry)
+ {
+ gtk_widget_destroy (p->entry);
+ p->entry = NULL;
+ }
+
+ if (p->adjustment)
+ {
+ g_signal_handlers_disconnect_by_func(p->adjustment,
+ phin_slider_button_adjustment_changed,
+ (gpointer) PHIN_SLIDER_BUTTON(object));
+
+ g_signal_handlers_disconnect_by_func(p->adjustment,
+ phin_slider_button_adjustment_value_changed,
+ (gpointer) PHIN_SLIDER_BUTTON(object));
+
+ g_object_unref (p->adjustment);
+ p->adjustment = NULL;
+ }
+
+ if (p->prefix)
+ {
+ g_free (p->prefix);
+ p->prefix = NULL;
+ }
+
+ if (p->postfix)
+ {
+ g_free (p->postfix);
+ p->postfix = NULL;
+ }
+
+ G_OBJECT_CLASS(phin_slider_button_parent_class)->dispose(object);
+}
+
+
+
+static void phin_slider_button_realize (GtkWidget* widget)
+{
+ PhinSliderButton* button = PHIN_SLIDER_BUTTON(widget);
+ GtkWidgetClass* klass;
+ PhinSliderButtonPrivate* p;
+
+ GdkWindowAttr attributes;
+ GtkAllocation widget_alloc;
+ int attributes_mask;
+
+ debug ("realize\n");
+
+ g_return_if_fail (widget != NULL);
+ g_return_if_fail (PHIN_IS_SLIDER_BUTTON (widget));
+
+ klass = GTK_WIDGET_CLASS(phin_slider_button_parent_class);
+
+ if (klass->realize)
+ klass->realize (widget);
+
+ attributes.window_type = GDK_WINDOW_CHILD;
+ attributes.wclass = GDK_INPUT_ONLY;
+ attributes.event_mask = gtk_widget_get_events (widget);
+ attributes.event_mask |= (GDK_BUTTON_PRESS_MASK
+ | GDK_BUTTON_RELEASE_MASK
+ | GDK_POINTER_MOTION_MASK
+ | GDK_POINTER_MOTION_HINT_MASK
+ | GDK_ENTER_NOTIFY_MASK
+ | GDK_LEAVE_NOTIFY_MASK
+ | GDK_SCROLL_MASK
+ | GDK_KEY_PRESS_MASK);
+
+ gtk_widget_get_allocation(widget, &widget_alloc);
+
+ attributes.x = widget_alloc.x;
+ attributes.y = widget_alloc.y;
+ attributes.width = widget_alloc.width;
+ attributes.height = widget_alloc.height;
+ attributes_mask = GDK_WA_X | GDK_WA_Y;
+
+ p = PHIN_SLIDER_BUTTON_GET_PRIVATE(button);
+ p->event_window = gdk_window_new(gtk_widget_get_parent_window(widget),
+ &attributes, attributes_mask);
+ gdk_window_set_user_data (p->event_window, widget);
+
+ p->arrow_cursor = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW);
+ p->empty_cursor = gdk_cursor_new (GDK_BLANK_CURSOR);
+}
+
+
+
+static void phin_slider_button_unrealize (GtkWidget *widget)
+{
+ PhinSliderButton* button = PHIN_SLIDER_BUTTON(widget);
+ GtkWidgetClass* klass;
+ PhinSliderButtonPrivate* p;
+
+ debug ("unrealize\n");
+
+ p = PHIN_SLIDER_BUTTON_GET_PRIVATE(button);
+ gdk_cursor_unref (p->arrow_cursor);
+ p->arrow_cursor = NULL;
+
+ gdk_cursor_unref (p->empty_cursor);
+ p->empty_cursor = NULL;
+
+ gdk_window_set_user_data (p->event_window, NULL);
+ gdk_window_destroy (p->event_window);
+ p->event_window = NULL;
+
+ klass = GTK_WIDGET_CLASS(phin_slider_button_parent_class);
+
+ if (klass->unrealize)
+ klass->unrealize (widget);
+}
+
+
+static void phin_slider_button_map (GtkWidget *widget)
+{
+ PhinSliderButton* button;
+ PhinSliderButtonPrivate* p;
+
+ debug ("map\n");
+
+ g_return_if_fail (PHIN_IS_SLIDER_BUTTON (widget));
+ button = PHIN_SLIDER_BUTTON(widget);
+ p = PHIN_SLIDER_BUTTON_GET_PRIVATE(button);
+
+ gtk_widget_show (p->left_arrow);
+ gtk_widget_show (p->label);
+ gtk_widget_show (p->right_arrow);
+ gdk_window_show (p->event_window);
+
+ if (p->prefix_label)
+ gtk_widget_show (p->prefix_label);
+
+ if (p->postfix_label)
+ gtk_widget_show (p->postfix_label);
+
+ GTK_WIDGET_CLASS(phin_slider_button_parent_class)->map(widget);
+
+ gtk_widget_queue_draw(widget);
+}
+
+
+static void phin_slider_button_unmap (GtkWidget *widget)
+{
+ PhinSliderButton* button;
+ PhinSliderButtonPrivate* p;
+
+ debug ("unmap\n");
+
+ g_return_if_fail (PHIN_IS_SLIDER_BUTTON (widget));
+ button = PHIN_SLIDER_BUTTON(widget);
+ p = PHIN_SLIDER_BUTTON_GET_PRIVATE(button);
+
+ gtk_widget_hide (p->left_arrow);
+ gtk_widget_hide (p->label);
+ gtk_widget_hide (p->right_arrow);
+ gdk_window_hide (p->event_window);
+
+ if (p->prefix_label)
+ gtk_widget_hide (p->prefix_label);
+
+ if (p->postfix_label)
+ gtk_widget_hide (p->postfix_label);
+
+ GTK_WIDGET_CLASS(phin_slider_button_parent_class)->unmap(widget);
+}
+
+
+static void phin_slider_button_size_allocate (GtkWidget* widget,
+ GtkAllocation* allocation)
+{
+ PhinSliderButton* button;
+ PhinSliderButtonPrivate* p;
+
+ g_return_if_fail (widget != NULL);
+ g_return_if_fail (allocation != NULL);
+ g_return_if_fail (PHIN_IS_SLIDER_BUTTON (widget));
+
+ debug ("size allocate\n");
+
+ button = PHIN_SLIDER_BUTTON(widget);
+ p = PHIN_SLIDER_BUTTON_GET_PRIVATE(button);
+
+ GTK_WIDGET_CLASS(phin_slider_button_parent_class)
+ ->size_allocate (widget, allocation);
+
+ if (gtk_widget_get_realized (widget))
+ {
+ gdk_window_move_resize (p->event_window,
+ allocation->x,
+ allocation->y,
+ allocation->width,
+ allocation->height);
+ /* make sure entry is hidden at start */
+ if(p->firstrun)
+ {
+ gtk_widget_hide(p->entry);
+ p->firstrun = 0;
+ }
+ }
+}
+
+
+static gboolean phin_slider_button_expose (GtkWidget* widget,
+ GdkEventExpose* event)
+{
+ PhinSliderButton* button;
+ PhinSliderButtonPrivate* p;
+
+ /* <GRRRRRRRRRRRR> */
+ GtkAllocation a;
+ GtkAllocation arrow_a;
+ GtkAllocation label_a;
+ /* </GRRRRRRRRRRRR> */
+
+ GtkStyle* style;
+ GdkWindow* window;
+ int pad; /* pad */
+
+ g_return_val_if_fail (widget != NULL, FALSE);
+ g_return_val_if_fail (PHIN_IS_SLIDER_BUTTON (widget), FALSE);
+ g_return_val_if_fail (event != NULL, FALSE);
+ g_return_val_if_fail (gtk_widget_is_drawable (widget), FALSE);
+ g_return_val_if_fail (event->count == 0, FALSE);
+
+ //debug ("expose\n");
+
+ button = PHIN_SLIDER_BUTTON(widget);
+ p = PHIN_SLIDER_BUTTON_GET_PRIVATE(button);
+
+ gtk_widget_get_allocation(widget, &a);
+ gtk_widget_get_allocation(p->left_arrow, &arrow_a);
+ gtk_widget_get_allocation(p->label, &label_a);
+
+ style = gtk_widget_get_style(widget);
+ window = gtk_widget_get_window(widget);
+
+ pad = gtk_container_get_border_width (GTK_CONTAINER (widget));
+
+ /* clear the box */
+ gtk_paint_box (style, window,
+ GTK_STATE_NORMAL,
+ GTK_SHADOW_NONE,
+ NULL,
+ widget,
+ NULL, /* if this is "buttondefault" the
+ * smooth engine crashes */
+ a.x, a.y, a.width, a.height);
+
+ /* paint any applicable hilites */
+ if (p->state == STATE_NORMAL)
+ {
+ if (p->hilite == LEFT_ARROW)
+ {
+ gtk_paint_box (style, window,
+ GTK_STATE_PRELIGHT,
+ GTK_SHADOW_NONE,
+ NULL,
+ widget,
+ "button",
+ a.x, a.y,
+ arrow_a.width + pad,
+ a.height);
+ }
+ else if (p->hilite == RIGHT_ARROW)
+ {
+ int offset;
+ int width;
+
+ offset = (a.x + arrow_a.width + label_a.width + pad);
+
+ width = a.x + a.width - offset;
+
+ if (p->prefix_label)
+ {
+ GtkAllocation pre_a;
+ gtk_widget_get_allocation(p->prefix_label, &pre_a);
+ offset += pre_a.width;
+ }
+
+ if (p->postfix_label)
+ {
+ GtkAllocation post_a;
+ gtk_widget_get_allocation(p->postfix_label, &post_a);
+ offset += post_a.width;
+ }
+
+ gtk_paint_box (style, window,
+ GTK_STATE_PRELIGHT,
+ GTK_SHADOW_NONE,
+ NULL,
+ widget, "button",
+ offset, a.y, width, a.height);
+ }
+ else if (p->hilite == LABEL)
+ {
+ int offset;
+ int width;
+
+ offset = a.x + arrow_a.width + pad;
+
+ width = label_a.width;
+
+ if (p->prefix_label)
+ {
+ GtkAllocation pre_a;
+ gtk_widget_get_allocation(p->prefix_label, &pre_a);
+ width += pre_a.width;
+ }
+
+ if (p->postfix_label)
+ {
+ GtkAllocation post_a;
+ gtk_widget_get_allocation(p->prefix_label, &post_a);
+ width += post_a.width;
+ }
+
+ gtk_paint_box (style, window,
+ GTK_STATE_PRELIGHT,
+ GTK_SHADOW_NONE,
+ NULL,
+ widget, "button",
+ offset, a.y, width, a.height);
+ }
+ }
+
+ /* paint our border */
+ gtk_paint_shadow (style, window,
+ GTK_STATE_NORMAL,
+ GTK_SHADOW_OUT,
+ NULL,
+ widget,
+ "buttondefault",
+ a.x, a.y, a.width, a.height);
+
+ gtk_paint_shadow (style, window,
+ GTK_STATE_NORMAL,
+ GTK_SHADOW_OUT,
+ NULL,
+ widget,
+ "button",
+ a.x, a.y, a.width, a.height);
+
+ /* paint the focus if we have it */
+ if (gtk_widget_get_can_focus (widget))
+ {
+ int x, y;
+ int width, height;
+
+ x = a.x;
+ y = a.y;
+ width = a.width;
+ height = a.height;
+
+ x += pad;
+ y += pad;
+ width -= 2 * pad;
+ height -= 2 * pad;
+
+ gtk_paint_focus (style, window, gtk_widget_get_state (widget),
+ NULL, widget, "button",
+ x, y, width, height);
+ }
+
+ GTK_WIDGET_CLASS(phin_slider_button_parent_class)
+ ->expose_event (widget, event);
+
+ return FALSE;
+}
+
+
+
+static void phin_slider_button_adjustment_changed (GtkAdjustment* adj,
+ PhinSliderButton* button)
+{
+ (void)adj;
+ g_return_if_fail (PHIN_IS_SLIDER_BUTTON (button));
+ update_size (button);
+ update_label (button);
+ g_signal_emit (G_OBJECT (button), signals[CHANGED_SIGNAL], 0);
+}
+
+
+static void phin_slider_button_adjustment_value_changed (GtkAdjustment* adj,
+ PhinSliderButton* button)
+{
+ (void)adj;
+ g_return_if_fail (PHIN_IS_SLIDER_BUTTON (button));
+ update_label (button);
+ g_signal_emit (G_OBJECT (button), signals[VALUE_CHANGED_SIGNAL], 0);
+}
+
+
+static void phin_slider_button_entry_activate (GtkEntry* entry,
+ PhinSliderButton* button)
+{
+ PhinSliderButtonPrivate* p = PHIN_SLIDER_BUTTON_GET_PRIVATE(button);
+
+ double newval;
+
+ debug ("entry activate\n");
+
+ p->state = STATE_NORMAL;
+
+ newval = g_strtod (gtk_entry_get_text (GTK_ENTRY (entry)), NULL);
+
+ gtk_adjustment_set_value (p->adjustment, newval);
+
+ gtk_widget_hide (GTK_WIDGET (entry));
+ gtk_widget_show (p->label);
+ gtk_widget_queue_draw (GTK_WIDGET (button));
+}
+
+
+static gboolean phin_slider_button_entry_focus_out(GtkEntry* entry,
+ GdkEventFocus* event,
+ PhinSliderButton* button)
+{
+ (void)entry; (void)event;
+ PhinSliderButtonPrivate* p = PHIN_SLIDER_BUTTON_GET_PRIVATE(button);
+ GtkWidget* widget = GTK_WIDGET (button);
+
+ debug ("entry focus out\n");
+
+ entry_cancel (button);
+ p->hilite = 0;
+
+ /* check to see if the pointer wandered outside our toplevel; if
+ * it did, we grab the focus so that a widget has the focus when
+ * our toplevel gets the focus back */
+ if (gtk_widget_is_toplevel (widget))
+ {
+ GtkWidget* toplevel = gtk_widget_get_toplevel (widget);
+ GdkScreen* screen = gtk_window_get_screen (GTK_WINDOW (toplevel));
+ GdkDisplay* display = gdk_screen_get_display (screen);
+ GdkWindow* curwindow =
+ gdk_display_get_window_at_pointer (display, NULL, NULL);
+
+ if (curwindow)
+ {
+ curwindow = gdk_window_get_toplevel (curwindow);
+ GdkWindow* topwin = gtk_widget_get_window(toplevel);
+
+ if (curwindow != topwin)
+ {
+ debug ("%p, %p\n", curwindow, topwin);
+ gtk_widget_grab_focus (widget);
+ }
+ }
+ else
+ {
+ gtk_widget_grab_focus (widget);
+ }
+ }
+
+ return FALSE;
+}
+
+
+static gboolean phin_slider_button_entry_key_press(GtkEntry* entry,
+ GdkEventKey* event,
+ PhinSliderButton* button)
+{
+ (void)entry;
+ debug ("entry key press\n");
+
+ if (event->keyval == GDK_Escape)
+ {
+ entry_cancel (button);
+ gtk_widget_grab_focus (GTK_WIDGET (button));
+ }
+
+ return FALSE;
+}
+
+
+static gboolean phin_slider_button_button_press (GtkWidget* widget,
+ GdkEventButton* event)
+{
+ PhinSliderButton* button = PHIN_SLIDER_BUTTON (widget);
+ PhinSliderButtonPrivate* p = PHIN_SLIDER_BUTTON_GET_PRIVATE(button);
+
+ debug ("button press\n");
+
+ if (event->type != GDK_BUTTON_PRESS)
+ return FALSE;
+
+ if(event->button == 1)
+ {
+ double adj_value;
+ double step_inc;
+
+ switch (p->state)
+ {
+ case STATE_NORMAL:
+ p->xpress = event->x;
+ p->ypress = event->y;
+ p->xpress_root = event->x_root;
+ p->ypress_root = event->y_root;
+ p->slid = FALSE;
+ adj_value = gtk_adjustment_get_value(p->adjustment);
+ step_inc = gtk_adjustment_get_step_increment(p->adjustment);
+
+ if (p->hilite == LEFT_ARROW)
+ {
+ p->state = STATE_PRESSED;
+ gtk_adjustment_set_value(p->adjustment,
+ (adj_value - step_inc));
+ }
+ else if (p->hilite == RIGHT_ARROW)
+ {
+ p->state = STATE_PRESSED;
+ gtk_adjustment_set_value(p->adjustment,
+ (adj_value + step_inc));
+ }
+ else
+ {
+ p->state = STATE_SLIDE;
+ }
+ break;
+
+ case STATE_SCROLL:
+ p->state = STATE_NORMAL;
+ update_cursor (button);
+ break;
+
+ case STATE_ENTRY:
+ entry_cancel (button);
+ p->state = STATE_NORMAL;
+ update_cursor (button);
+ break;
+ }
+
+ update_cursor (button);
+ gtk_widget_grab_focus (widget);
+ gtk_widget_queue_draw (widget);
+ }
+ return FALSE;
+}
+
+
+static gboolean phin_slider_button_button_release (GtkWidget* widget,
+ GdkEventButton* event)
+{
+ PhinSliderButton* button = PHIN_SLIDER_BUTTON (widget);
+ PhinSliderButtonPrivate* p = PHIN_SLIDER_BUTTON_GET_PRIVATE(widget);
+
+ char* s;
+ char* t;
+
+ debug ("button release\n");
+ /* react to left button only */
+ if(event->button == 1)
+ {
+ switch (p->state)
+ {
+ case STATE_SLIDE:
+ if (!p->slid)
+ {
+ double adj_value = gtk_adjustment_get_value(p->adjustment);
+ p->state = STATE_ENTRY;
+ s = value_to_string(button, adj_value);
+
+ for (t = s; *t == ' '; t++);
+ gtk_entry_set_text (GTK_ENTRY (p->entry), t);
+ g_free (s);
+ s = t = NULL;
+
+ gtk_widget_hide (p->label);
+ if (p->prefix_label)
+ gtk_widget_hide (p->prefix_label);
+ if (p->postfix_label)
+ gtk_widget_hide (p->postfix_label);
+
+ gtk_widget_show (p->entry);
+
+ gtk_widget_grab_focus (p->entry);
+ }
+ else
+ {
+ p->state = STATE_NORMAL;
+ phin_warp_pointer (event->x_root, event->y_root,
+ p->xpress_root, p->ypress_root);
+ update_cursor (button);
+ }
+ break;
+ case STATE_PRESSED:
+ p->state = STATE_NORMAL;
+ update_cursor (button);
+ break;
+ }
+
+ gtk_widget_queue_draw (widget);
+ }
+ return FALSE;
+}
+
+
+static gboolean phin_slider_button_key_press (GtkWidget* widget,
+ GdkEventKey* event)
+{
+ PhinSliderButtonPrivate* p = PHIN_SLIDER_BUTTON_GET_PRIVATE(widget);
+ GtkAdjustment* adj = p->adjustment;
+ double val = gtk_adjustment_get_value(adj);
+
+ //debug ("key press\n");
+
+ switch (event->keyval)
+ {
+ case GDK_Up:
+ gtk_adjustment_set_value(adj,
+ val + gtk_adjustment_get_step_increment(adj));
+ break;
+ case GDK_Down:
+ gtk_adjustment_set_value (adj,
+ val - gtk_adjustment_get_step_increment(adj));
+ break;
+ case GDK_Page_Up:
+ gtk_adjustment_set_value (adj,
+ val + gtk_adjustment_get_page_increment(adj));
+ break;
+ case GDK_Page_Down:
+ gtk_adjustment_set_value (adj,
+ val - gtk_adjustment_get_page_increment(adj));
+ break;
+ default:
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+static gboolean phin_slider_button_scroll (GtkWidget* widget,
+ GdkEventScroll* event)
+{
+ PhinSliderButton* button = PHIN_SLIDER_BUTTON (widget);
+ PhinSliderButtonPrivate* p = PHIN_SLIDER_BUTTON_GET_PRIVATE(widget);
+ GtkAdjustment* adj;
+ double val, inc;
+
+ //debug ("scroll\n");
+
+ if (p->state != STATE_NORMAL
+ && p->state != STATE_SCROLL)
+ {
+ return FALSE;
+ }
+
+ p->state = STATE_SCROLL;
+ update_cursor (button);
+
+ p->xpress_root = event->x_root;
+ p->ypress_root = event->y_root;
+ p->xpress = event->x;
+ p->ypress = event->y;
+
+ adj = p->adjustment;
+ val = gtk_adjustment_get_value(adj);
+ inc = gtk_adjustment_get_page_increment(adj);
+
+ if (event->direction == GDK_SCROLL_UP
+ || event->direction == GDK_SCROLL_RIGHT)
+ {
+ gtk_adjustment_set_value (adj, val + inc);
+ }
+ else
+ gtk_adjustment_set_value (adj, val - inc);
+
+ gtk_widget_grab_focus (widget);
+ return FALSE;
+}
+
+
+static gboolean phin_slider_button_enter_notify (GtkWidget* widget,
+ GdkEventCrossing* event)
+{
+ PhinSliderButton* button = PHIN_SLIDER_BUTTON (widget);
+ PhinSliderButtonPrivate* p = PHIN_SLIDER_BUTTON_GET_PRIVATE(widget);
+
+ int old = p->hilite;
+
+ p->hilite = check_pointer(button, event->x, event->y);
+
+ if (p->hilite != old)
+ {
+ update_cursor (button);
+ gtk_widget_queue_draw (widget);
+ }
+
+ return FALSE;
+}
+
+
+static gboolean phin_slider_button_leave_notify (GtkWidget* widget,
+ GdkEventCrossing* event)
+{
+ (void)event;
+
+ PhinSliderButton* button = PHIN_SLIDER_BUTTON (widget);
+ PhinSliderButtonPrivate* p = PHIN_SLIDER_BUTTON_GET_PRIVATE(widget);
+
+ p->hilite = 0;
+
+ if (p->state == STATE_SCROLL)
+ p->state = STATE_NORMAL;
+
+ update_cursor (button);
+ gtk_widget_queue_draw (widget);
+
+ return FALSE;
+}
+
+
+static gboolean phin_slider_button_motion_notify (GtkWidget* widget,
+ GdkEventMotion* event)
+{
+ PhinSliderButton* button = PHIN_SLIDER_BUTTON (widget);
+ PhinSliderButtonPrivate* p = PHIN_SLIDER_BUTTON_GET_PRIVATE(widget);
+ int old = p->hilite;
+ int xdiff = 0;
+ double inc;
+
+ p->hilite = check_pointer (button, event->x, event->y);
+
+ if (p->hilite != old)
+ {
+ update_cursor (button);
+ gtk_widget_queue_draw (widget);
+ }
+
+ xdiff = (event->x - p->xpress) / p->threshold;
+ old = p->state;
+
+ if (ABS (xdiff) >= 1)
+ {
+ switch (p->state)
+ {
+ case STATE_SLIDE:
+ p->slid = TRUE;
+
+ inc = gtk_adjustment_get_step_increment(p->adjustment) * xdiff;
+
+ gtk_adjustment_set_value (p->adjustment,
+ gtk_adjustment_get_value(p->adjustment) + inc);
+
+ phin_warp_pointer (event->x_root, event->y_root,
+ p->xpress_root, p->ypress_root);
+ break;
+
+ case STATE_PRESSED:
+ p->state = STATE_SLIDE;
+ p->xpress_root = event->x_root;
+ p->ypress_root = event->y_root;
+ p->xpress = event->x;
+ p->ypress = event->y;
+ update_cursor (button);
+ break;
+
+ case STATE_SCROLL:
+ p->state = STATE_NORMAL;
+ update_cursor (button);
+ break;
+ }
+ }
+ else if (p->state == STATE_SCROLL
+ && (ABS (event->x - p->xpress) >= SCROLL_THRESHOLD
+ || ABS (event->y - p->ypress) >= SCROLL_THRESHOLD))
+ {
+ p->state = STATE_NORMAL;
+ update_cursor (button);
+ }
+
+ if (p->state != old)
+ gtk_widget_queue_draw (widget);
+
+ /* signal that we want more events */
+ gdk_window_get_pointer (NULL, NULL, NULL, NULL);
+
+ return FALSE;
+}
+
+
+static int check_pointer (PhinSliderButton* button, int x, int y)
+{
+ GtkWidget* widget = GTK_WIDGET (button);
+ PhinSliderButtonPrivate* p = PHIN_SLIDER_BUTTON_GET_PRIVATE(widget);
+
+ GtkAllocation a;
+ GtkAllocation la;
+ GtkAllocation ra;
+
+ int pad = gtk_container_get_border_width (GTK_CONTAINER (button));
+ int val;
+
+ gtk_widget_get_allocation(widget, &a);
+ gtk_widget_get_allocation(p->left_arrow, &la);
+ gtk_widget_get_allocation(p->right_arrow, &ra);
+
+ if ((y < 0 || y > a.height) || (x < 0 || x > a.width))
+ {
+ val = 0;
+ }
+ else if (x <= la.width + pad)
+ {
+ val = LEFT_ARROW;
+ }
+ else if (x >= (a.width - ra.width - pad))
+ {
+ val = RIGHT_ARROW;
+ }
+ else
+ {
+ val = LABEL;
+ }
+
+ return val;
+}
+
+
+static void entry_cancel (PhinSliderButton* button)
+{
+ PhinSliderButtonPrivate* p = PHIN_SLIDER_BUTTON_GET_PRIVATE(button);
+
+ p->state = STATE_NORMAL;
+
+ g_signal_handlers_block_by_func (p->entry,
+ phin_slider_button_entry_focus_out,
+ button);
+ gtk_widget_hide (p->entry);
+ g_signal_handlers_unblock_by_func (p->entry,
+ phin_slider_button_entry_focus_out,
+ button);
+ gtk_widget_show (p->label);
+
+ if (p->prefix_label)
+ gtk_widget_show (p->prefix_label);
+
+ if (p->postfix_label)
+ gtk_widget_show (p->postfix_label);
+
+ gtk_widget_queue_draw (GTK_WIDGET (button));
+}
+
+
+static void update_cursor (PhinSliderButton* button)
+{
+ PhinSliderButtonPrivate* p = PHIN_SLIDER_BUTTON_GET_PRIVATE(button);
+
+ switch (p->state)
+ {
+ case STATE_ENTRY:
+ case STATE_PRESSED:
+ gdk_window_set_cursor (p->event_window, NULL);
+ break;
+ case STATE_SLIDE:
+ case STATE_SCROLL:
+ gdk_window_set_cursor (p->event_window, p->empty_cursor);
+ break;
+ default:
+ if (p->hilite == LABEL)
+ {
+ gdk_window_set_cursor (p->event_window, p->arrow_cursor);
+ }
+ else
+ {
+ gdk_window_set_cursor (p->event_window, NULL);
+ }
+ break;
+ }
+}
+
+
+static void update_label (PhinSliderButton* button)
+{
+ PhinSliderButtonPrivate* p = PHIN_SLIDER_BUTTON_GET_PRIVATE(button);
+ char* s;
+
+ s = value_to_string (button, gtk_adjustment_get_value(p->adjustment));
+
+ gtk_label_set_text (GTK_LABEL (p->label), s);
+ gtk_widget_queue_draw (GTK_WIDGET (button)); /* just to be safe */
+
+ g_free (s);
+}
+
+
+/* Update the sizes and existence of the labels we use, depending on
+ * whether p->prefix and/or p->postfix are set.
+ */
+static void update_size (PhinSliderButton* button)
+{
+ PhinSliderButtonPrivate* p = PHIN_SLIDER_BUTTON_GET_PRIVATE(button);
+ GtkRequisition req;
+ GString* s = g_string_new (NULL);
+ GString* t = g_string_new (NULL);
+ char* u;
+ int label_len = 0;
+ int prefix_len = 0;
+ int postfix_len = 0;
+ double prefix_frac = 0;
+ double postfix_frac = 0;
+ int width = 0;
+ int width_avail = 0;
+ int width_alloc = 0;
+
+ u = value_to_string(button, gtk_adjustment_get_lower(p->adjustment));
+ s = g_string_new(u);
+ g_free(u);
+
+ u = value_to_string(button, gtk_adjustment_get_upper(p->adjustment));
+ t = g_string_new(u);
+ g_free(u);
+
+ label_len = MAX (s->len, t->len);
+
+ if (p->prefix)
+ prefix_len = strlen (p->prefix);
+
+ if (p->postfix)
+ postfix_len = strlen (p->postfix);
+
+ width = label_len + prefix_len + postfix_len;
+ gtk_entry_set_width_chars (GTK_ENTRY (p->entry), width);
+
+ gtk_widget_size_request (p->entry, &req);
+
+ prefix_frac = prefix_len * 1.0 / width;
+ postfix_frac = postfix_len * 1.0 / width;
+ width_avail = req.width;
+
+ if (p->prefix)
+ {
+ if (!p->prefix_label)
+ {
+ p->prefix_label = gtk_label_new (NULL);
+ gtk_misc_set_alignment(GTK_MISC(p->prefix_label), 0.0, 0.5);
+ gtk_box_pack_start (GTK_BOX (button), p->prefix_label,
+ TRUE, TRUE, 0);
+ gtk_box_reorder_child (GTK_BOX (button), p->prefix_label, 1);
+
+ if (gtk_widget_get_mapped (GTK_WIDGET (button)))
+ gtk_widget_show (p->prefix_label);
+ }
+
+ gtk_label_set_text (GTK_LABEL (p->prefix_label),
+ p->prefix);
+
+ width_alloc = req.width * prefix_frac;
+ gtk_widget_set_size_request (p->prefix_label,
+ width_alloc,
+ req.height);
+ width_avail -= width_alloc;
+ }
+ else if (p->prefix_label)
+ {
+ gtk_widget_destroy (p->prefix_label);
+ p->prefix_label = NULL;
+ }
+
+ if (p->postfix)
+ {
+ if (!p->postfix_label)
+ {
+ p->postfix_label = gtk_label_new (NULL);
+ gtk_misc_set_alignment(GTK_MISC(p->postfix_label), 1.0, 0.5);
+ gtk_box_pack_start (GTK_BOX (button), p->postfix_label,
+ TRUE, TRUE, 0);
+ gtk_box_reorder_child (GTK_BOX (button), p->postfix_label,
+ (p->prefix_label)? 3: 2);
+
+ if (gtk_widget_get_mapped (GTK_WIDGET (button)))
+ gtk_widget_show (p->postfix_label);
+ }
+
+ gtk_label_set_text (GTK_LABEL (p->postfix_label),
+ p->postfix);
+
+ width_alloc = req.width * postfix_frac;
+ gtk_widget_set_size_request (p->postfix_label,
+ width_alloc,
+ req.height);
+ width_avail -= width_alloc;
+ }
+ else if (p->postfix_label)
+ {
+ gtk_widget_destroy (p->postfix_label);
+ p->postfix_label = NULL;
+ }
+
+ /* we allocate the remainder to avoid floating point errors */
+ gtk_widget_set_size_request (p->label,
+ width_avail,
+ req.height);
+ gtk_widget_queue_draw (GTK_WIDGET (button));
+
+ g_string_free (s, TRUE);
+ g_string_free (t, TRUE);
+}
+
+
+static char* value_to_string(PhinSliderButton* button, double value)
+{
+ PhinSliderButtonPrivate* p = PHIN_SLIDER_BUTTON_GET_PRIVATE(button);
+ return g_strdup_printf ("%.*f", p->digits, value);
+}
diff --git a/libphin/phinsliderbutton.h b/libphin/phinsliderbutton.h
new file mode 100644
index 0000000..c6283cd
--- /dev/null
+++ b/libphin/phinsliderbutton.h
@@ -0,0 +1,105 @@
+/* Phin is a fork of the PHAT Audio Toolkit.
+ Phin is part of Petri-Foo. Petri-Foo is a fork of Specimen.
+
+ Original author Pete Bessman
+ Copyright 2005 Pete Bessman
+ Copyright 2011 James W. Morris
+
+ This file is part of Phin.
+
+ Phin is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+
+ Phin is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Phin. If not, see <http://www.gnu.org/licenses/>.
+
+ This file is a derivative of a PHAT original, modified 2011
+*/
+#ifndef __PHIN_SLIDER_BUTTON_H__
+#define __PHIN_SLIDER_BUTTON_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define PHIN_TYPE_SLIDER_BUTTON (phin_slider_button_get_type())
+
+#define PHIN_SLIDER_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
+ PHIN_TYPE_SLIDER_BUTTON, \
+ PhinSliderButton))
+
+#define PHIN_SLIDER_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), \
+ PHIN_TYPE_SLIDER_BUTTON, \
+ PhinSliderButtonClass))
+
+#define PHIN_IS_SLIDER_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), \
+ PHIN_TYPE_SLIDER_BUTTON))
+
+#define PHIN_IS_SLIDER_BUTTON_CLASS(klass)\
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), PHIN_TYPE_SLIDER_BUTTON))
+
+
+typedef struct _PhinSliderButtonClass PhinSliderButtonClass;
+typedef struct _PhinSliderButton PhinSliderButton;
+
+
+struct _PhinSliderButton
+{
+ GtkHBox parent;
+};
+
+struct _PhinSliderButtonClass
+{
+ GtkHBoxClass parent_class;
+
+ void (*value_changed) (PhinSliderButton* slider);
+ void (*changed) (PhinSliderButton* slider);
+};
+
+
+GType phin_slider_button_get_type ( );
+GtkWidget* phin_slider_button_new (GtkAdjustment*, int digits);
+GtkWidget* phin_slider_button_new_with_range ( double value,
+ double lower,
+ double upper,
+ double step,
+ int digits);
+
+void phin_slider_button_set_value( PhinSliderButton*, double );
+double phin_slider_button_get_value ( PhinSliderButton* );
+
+void phin_slider_button_set_range ( PhinSliderButton*,
+ double lower, double upper);
+void phin_slider_button_get_range ( PhinSliderButton*,
+ double* lower, double* upper);
+
+void phin_slider_button_set_adjustment( PhinSliderButton*,
+ GtkAdjustment* );
+GtkAdjustment* phin_slider_button_get_adjustment (PhinSliderButton* );
+
+void phin_slider_button_set_increment( PhinSliderButton*,
+ double step, double page);
+void phin_slider_button_get_increment( PhinSliderButton*,
+ double* step, double* page);
+
+void phin_slider_button_set_format( PhinSliderButton*, int digits,
+ const char* prefix,
+ const char* postfix);
+void phin_slider_button_get_format( PhinSliderButton*, int* digits,
+ char** prefix,
+ char** postfix);
+
+void phin_slider_button_set_threshold( PhinSliderButton*,
+ guint threshold);
+int phin_slider_button_get_threshold( PhinSliderButton*);
+
+
+G_END_DECLS
+
+#endif /* __PHIN_SLIDER_BUTTON_H__ */
diff --git a/libphin/phinvfanslider.c b/libphin/phinvfanslider.c
new file mode 100644
index 0000000..4ccfb5d
--- /dev/null
+++ b/libphin/phinvfanslider.c
@@ -0,0 +1,79 @@
+/* Phin is a fork of the PHAT Audio Toolkit.
+ Phin is part of Petri-Foo. Petri-Foo is a fork of Specimen.
+
+ Original author Pete Bessman
+ Copyright 2005 Pete Bessman
+ Copyright 2011 James W. Morris
+
+ This file is part of Phin.
+
+ Phin is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+
+ Phin is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Phin. If not, see <http://www.gnu.org/licenses/>.
+
+ This file is a derivative of a PHAT original, modified 2011
+*/
+#include <gtk/gtk.h>
+
+
+#include "phinprivate.h"
+#include "phinfanslider.h"
+#include "phinvfanslider.h"
+
+
+G_DEFINE_TYPE(PhinVFanSlider, phin_vfan_slider, PHIN_TYPE_FAN_SLIDER);
+
+
+GtkWidget* phin_vfan_slider_new (GtkAdjustment* adjustment)
+{
+ PhinVFanSlider* slider;
+
+ int adj_lower = gtk_adjustment_get_lower(adjustment);
+ int adj_upper = gtk_adjustment_get_upper(adjustment);
+ int adj_value = gtk_adjustment_get_value(adjustment);
+
+ g_assert (adj_lower < adj_upper);
+ g_assert((adj_value >= adj_lower)
+ && (adj_value <= adj_upper));
+
+ slider = g_object_new (PHIN_TYPE_VFAN_SLIDER, NULL);
+
+ phin_fan_slider_set_orientation(PHIN_FAN_SLIDER(slider),
+ GTK_ORIENTATION_VERTICAL);
+
+ phin_fan_slider_set_adjustment (PHIN_FAN_SLIDER (slider), adjustment);
+
+ return (GtkWidget*) slider;
+}
+
+
+GtkWidget* phin_vfan_slider_new_with_range (double value, double lower,
+ double upper, double step)
+{
+ GtkAdjustment* adj;
+
+ adj = (GtkAdjustment*)gtk_adjustment_new (value, lower, upper,
+ step, step, 0);
+ return phin_vfan_slider_new (adj);
+}
+
+
+static void phin_vfan_slider_class_init (PhinVFanSliderClass* klass)
+{
+ phin_vfan_slider_parent_class = g_type_class_peek_parent(klass);
+}
+
+
+static void phin_vfan_slider_init(PhinVFanSlider* slider)
+{
+ (void)slider;
+ return;
+}
diff --git a/libphin/phinvfanslider.h b/libphin/phinvfanslider.h
new file mode 100644
index 0000000..42f6d1c
--- /dev/null
+++ b/libphin/phinvfanslider.h
@@ -0,0 +1,75 @@
+/* Phin is a fork of the PHAT Audio Toolkit.
+ Phin is part of Petri-Foo. Petri-Foo is a fork of Specimen.
+
+ Original author Pete Bessman
+ Copyright 2005 Pete Bessman
+ Copyright 2011 James W. Morris
+
+ This file is part of Phin.
+
+ Phin is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+
+ Phin is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Phin. If not, see <http://www.gnu.org/licenses/>.
+
+ This file is a derivative of a PHAT original, modified 2011
+*/
+#ifndef __PHIN_VFAN_SLIDER_H__
+#define __PHIN_VFAN_SLIDER_H__
+
+#include <gtk/gtk.h>
+
+#include "phinfanslider.h"
+
+
+G_BEGIN_DECLS
+
+#define PHIN_TYPE_VFAN_SLIDER (phin_vfan_slider_get_type())
+
+#define PHIN_VFAN_SLIDER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
+ PHIN_TYPE_VFAN_SLIDER, \
+ PhinVFanSlider))
+
+#define PHIN_VFAN_SLIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), \
+ PHIN_TYPE_VFAN_SLIDER, \
+ PhinVFanSliderClass))
+
+#define PHIN_IS_VFAN_SLIDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), \
+ PHIN_TYPE_VFAN_SLIDER))
+
+#define PHIN_IS_VFAN_SLIDER_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), PHIN_TYPE_VFAN_SLIDER))
+
+
+typedef struct _PhinVFanSliderClass PhinVFanSliderClass;
+typedef struct _PhinVFanSlider PhinVFanSlider;
+
+
+struct _PhinVFanSlider
+{
+ PhinFanSlider parent;
+};
+
+struct _PhinVFanSliderClass
+{
+ PhinFanSliderClass parent_class;
+};
+
+
+GType phin_vfan_slider_get_type(void);
+GtkWidget* phin_vfan_slider_new (GtkAdjustment*);
+GtkWidget* phin_vfan_slider_new_with_range(double value,
+ double lower,
+ double upper,
+ double step);
+
+G_END_DECLS
+
+#endif /* __PHIN_VFAN_SLIDER_H__ */
diff --git a/libphin/phinvkeyboard.c b/libphin/phinvkeyboard.c
new file mode 100644
index 0000000..d7c7f11
--- /dev/null
+++ b/libphin/phinvkeyboard.c
@@ -0,0 +1,67 @@
+/* Phin is a fork of the PHAT Audio Toolkit.
+ Phin is part of Petri-Foo. Petri-Foo is a fork of Specimen.
+
+ Original author Pete Bessman
+ Copyright 2005 Pete Bessman
+ Copyright 2011 James W. Morris
+
+ This file is part of Phin.
+
+ Phin is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+
+ Phin is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Phin. If not, see <http://www.gnu.org/licenses/>.
+
+ This file is a derivative of a PHAT original, modified 2011
+*/
+#include <gtk/gtk.h>
+#include "phinvkeyboard.h"
+
+
+G_DEFINE_TYPE(PhinVKeyboard, phin_vkeyboard, PHIN_TYPE_KEYBOARD);
+
+
+static void phin_vkeyboard_class_init(PhinVKeyboardClass* klass)
+{
+ phin_vkeyboard_parent_class = g_type_class_peek_parent(klass);
+}
+
+
+static void phin_vkeyboard_init(PhinVKeyboard* self)
+{
+ (void)self;
+}
+
+
+/**
+ * phin_vkeyboard_new:
+ * @adjustment: the #GtkAdjustment that the new keyboard will use for scrolling
+ * @numkeys: number of keys to create
+ * @show_labels: whether to label the C keys
+ *
+ * Creates a new #PhinVKeyboard.
+ *
+ * Returns: a newly created #PhinVKeyboard
+ *
+ */
+GtkWidget* phin_vkeyboard_new(GtkAdjustment* adj, int numkeys,
+ gboolean show_labels)
+{
+ if (!adj)
+ adj = (GtkAdjustment*) gtk_adjustment_new(0, 0, 0, 0, 0, 0);
+
+ return g_object_new(PHIN_TYPE_VKEYBOARD,
+ "vadjustment", adj,
+ "shadow-type", GTK_SHADOW_NONE,
+ "orientation", GTK_ORIENTATION_VERTICAL,
+ "numkeys", numkeys,
+ "show-labels", show_labels,
+ NULL);
+}
diff --git a/libphin/phinvkeyboard.h b/libphin/phinvkeyboard.h
new file mode 100644
index 0000000..f2a0d63
--- /dev/null
+++ b/libphin/phinvkeyboard.h
@@ -0,0 +1,72 @@
+/* Phin is a fork of the PHAT Audio Toolkit.
+ Phin is part of Petri-Foo. Petri-Foo is a fork of Specimen.
+
+ Original author Pete Bessman
+ Copyright 2005 Pete Bessman
+ Copyright 2011 James W. Morris
+
+ This file is part of Phin.
+
+ Phin is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+
+ Phin is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Phin. If not, see <http://www.gnu.org/licenses/>.
+
+ This file is a derivative of a PHAT original, modified 2011
+*/
+#ifndef __PHIN_VKEYBOARD__
+#define __PHIN_VKEYBOARD__
+
+#include <gtk/gtk.h>
+
+#include "phinkeyboard.h"
+
+G_BEGIN_DECLS
+
+#define PHIN_TYPE_VKEYBOARD (phin_vkeyboard_get_type())
+
+#define PHIN_VKEYBOARD(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
+ PHIN_TYPE_VKEYBOARD, PhinVKeyboard))
+
+#define PHIN_VKEYBOARD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), \
+ PHIN_TYPE_VKEYBOARD, \
+ PhinVKeyboardClass))
+
+#define PHIN_IS_VKEYBOARD(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), \
+ PHIN_TYPE_VKEYBOARD))
+
+#define PHIN_IS_VKEYBOARD_CLASS(klass) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((klass), PHIN_TYPE_VKEYBOARD))
+
+
+typedef struct _PhinVKeyboardClass PhinVKeyboardClass;
+typedef struct _PhinVKeyboard PhinVKeyboard;
+
+struct _PhinVKeyboard
+{
+ PhinKeyboard parent;
+};
+
+
+struct _PhinVKeyboardClass
+{
+ PhinKeyboardClass parent_class;
+};
+
+
+GType phin_vkeyboard_get_type(void);
+GtkWidget* phin_vkeyboard_new(GtkAdjustment*, int numkeys,
+ gboolean show_labels);
+
+
+G_END_DECLS
+
+
+#endif /* __PHIN_VKEYBOARD__ */
diff --git a/petri-foo.desktop b/petri-foo.desktop
index aed78e3..eb002e3 100644
--- a/petri-foo.desktop
+++ b/petri-foo.desktop
@@ -4,8 +4,10 @@ Type=Application
Name=Petri-Foo
GenericName=Petri-Foo
Comment=Sound Sampler
-Icon=petri-foo-small.png
+Comment[ru]=Звуковой сэмплер Petri-Foo
+Icon=petri-foo
TryExec=petri-foo
Exec=petri-foo
Terminal=false
-Categories=Application;AudioVideo;AudioVideoEditing;Music;
+Categories=Application;Audio;AudioVideo;AudioVideoEditing;X-Jack;Midi;X-Alsa;
+MimeType=application/petri-foo;
diff --git a/petri-foo.xml b/petri-foo.xml
new file mode 100644
index 0000000..5cfe309
--- /dev/null
+++ b/petri-foo.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
+ <mime-type type="application/x-petri-foo">
+ <comment>Petri-Foo sample bank file</comment>
+ <glob pattern="*.petri-foo"/>
+ </mime-type>
+</mime-info>
diff --git a/pixmaps/Makefile.am b/pixmaps/Makefile.am
deleted file mode 100644
index 527b9cb..0000000
--- a/pixmaps/Makefile.am
+++ /dev/null
@@ -1,4 +0,0 @@
-pixmaps_DATA = open.png play.png stop.png panic.png \
- petri-foo.png petri-foo_small.png
-EXTRA_DIST = $(pixmaps_DATA)
-pixmapsdir = "$(pkgdatadir)/pixmaps"
diff --git a/pixmaps/open.png b/pixmaps/open.png
deleted file mode 100644
index fbf04f0..0000000
Binary files a/pixmaps/open.png and /dev/null differ
diff --git a/pixmaps/panic.png b/pixmaps/panic.png
deleted file mode 100644
index bc9bfde..0000000
Binary files a/pixmaps/panic.png and /dev/null differ
diff --git a/pixmaps/play.png b/pixmaps/play.png
deleted file mode 100644
index 73d5e5f..0000000
Binary files a/pixmaps/play.png and /dev/null differ
diff --git a/pixmaps/stop.png b/pixmaps/stop.png
deleted file mode 100644
index 83c9caa..0000000
Binary files a/pixmaps/stop.png and /dev/null differ
diff --git a/src/Makefile.am b/src/Makefile.am
deleted file mode 100644
index d75c63a..0000000
--- a/src/Makefile.am
+++ /dev/null
@@ -1,47 +0,0 @@
-SUBDIRS = gui patch_private
-
-bin_PROGRAMS = petri-foo
-
-petri_foo_SOURCES = \
- adsr.c adsr.h \
- config.h \
- dish_file.c dish_file.h \
- driver.c driver.h \
- instance.c instance.h \
- jackdriver.c jackdriver.h \
- lfo.c lfo.h \
- maths.c maths.h \
- midi.c midi.h \
- midi_control.h \
- mixer.c mixer.h \
- mod_src.c mod_src.h \
- names.c names.h \
- patch.c patch.h \
- patch_set_and_get.c patch_set_and_get.h \
- patch_util.c patch_util.h \
- petri-foo.c petri-foo.h \
- sample.c sample.h \
- sync.c sync.h \
- ticks.c ticks.h
-
-INCLUDES = \
- @ALSA_CFLAGS@ \
- @JACK_CFLAGS@ \
- @LIBSAMPLERATE_CFLAGS@ \
- @LIBSNDFILE_CFLAGS@ \
- @LIBXML_CFLAGS@ \
- @GTK_CFLAGS@
-
-petri_foo_LDADD = \
- patch_private/libpatch.a\
- gui/libgui.a \
- @PHAT_LIBS@ \
- @ALSA_LIBS@ \
- @JACK_LIBS@ \
- @LIBSAMPLERATE_LIBS@ \
- @LIBSNDFILE_LIBS@ \
- @LIBXML_LIBS@ \
- @GTK_LIBS@ \
- @LIBGNOMECANVAS_LIBS@
-
-EXTRA_DIST = gprof-helper.c
diff --git a/src/gprof-helper.c b/src/gprof-helper.c
deleted file mode 100644
index 031a108..0000000
--- a/src/gprof-helper.c
+++ /dev/null
@@ -1,139 +0,0 @@
-/* Petri-Foo is a fork of the Specimen audio sampler.
-
- Original Specimen author Pete Bessman
- Copyright 2005 Pete Bessman
- Copyright 2011 James W. Morris
-
- This file is part of Petri-Foo.
-
- Petri-Foo is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation.
-
- Petri-Foo is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Petri-Foo. If not, see <http://www.gnu.org/licenses/>.
-
- This file is a derivative of a Specimen original, modified 2011
-*/
-
-
-/* gprof-helper.c -- preload library to profile pthread-enabled programs
- *
- * Authors: Sam Hocevar <sam at zoy dot org>
- * Daniel Jönsson <danieljo at fagotten dot org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the Do What The Fuck You Want To
- * Public License as published by Banlu Kemiyatorn. See
- * http://sam.zoy.org/projects/COPYING.WTFPL for more details.
- *
- * Compilation example:
- * gcc -shared -nostdlib -fPIC gprof-helper.c -o gprof-helper.so -lpthread -ldl
- *
- * Usage example:
- * LD_PRELOAD=./gprof-helper.so your_program
- */
-
-#define _GNU_SOURCE
-#include <sys/time.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <dlfcn.h>
-#include <pthread.h>
-
-static void *wrapper_routine (void *);
-
-/* Original pthread function */
-static int (*pthread_create_orig) (pthread_t * __restrict,
- __const pthread_attr_t * __restrict,
- void *(*)(void *),
- void *__restrict) = NULL;
-
-/* Library initialization function */
-void _init (void)
-{
- pthread_create_orig = dlsym (RTLD_NEXT, "pthread_create");
- fprintf (stderr, "pthreads: using profiling hooks for gprof\n");
- if (pthread_create_orig == NULL)
- {
- char *error = dlerror ( );
-
- if (error == NULL)
- {
- error = "pthread_create is NULL";
- }
- fprintf (stderr, "%s", error);
- exit (EXIT_FAILURE);
- }
-}
-
-/* Our data structure passed to the wrapper */
-typedef struct wrapper_s
-{
- void *(*start_routine) (void *);
- void *arg;
-
- pthread_mutex_t lock;
- pthread_cond_t wait;
-
- struct itimerval itimer;
-
-} wrapper_t;
-
-/* The wrapper function in charge for setting the itimer value */
-static void *wrapper_routine (void *data)
-{
- /* Put user data in thread-local variables */
- void *(*start_routine) (void *) = ((wrapper_t *) data)->start_routine;
- void *arg = ((wrapper_t *) data)->arg;
-
- /* Set the profile timer value */
- setitimer (ITIMER_PROF, &((wrapper_t *) data)->itimer, NULL);
-
- /* Tell the calling thread that we don't need its data anymore */
- pthread_mutex_lock (&((wrapper_t *) data)->lock);
- pthread_cond_signal (&((wrapper_t *) data)->wait);
- pthread_mutex_unlock (&((wrapper_t *) data)->lock);
-
- /* Call the real function */
- return start_routine (arg);
-}
-
-/* Our wrapper function for the real pthread_create( ) */
-int pthread_create (pthread_t * __restrict thread,
- __const pthread_attr_t * __restrict attr,
- void *(*start_routine) (void *), void *__restrict arg)
-{
- wrapper_t wrapper_data;
- int i_return;
-
- /* Initialize the wrapper structure */
- wrapper_data.start_routine = start_routine;
- wrapper_data.arg = arg;
- getitimer (ITIMER_PROF, &wrapper_data.itimer);
- pthread_cond_init (&wrapper_data.wait, NULL);
- pthread_mutex_init (&wrapper_data.lock, NULL);
- pthread_mutex_lock (&wrapper_data.lock);
-
- /* The real pthread_create call */
- i_return = pthread_create_orig (thread,
- attr, &wrapper_routine, &wrapper_data);
-
- /* If the thread was successfully spawned, wait for the data
- * to be released */
- if (i_return == 0)
- {
- pthread_cond_wait (&wrapper_data.wait, &wrapper_data.lock);
- }
-
- pthread_mutex_unlock (&wrapper_data.lock);
- pthread_mutex_destroy (&wrapper_data.lock);
- pthread_cond_destroy (&wrapper_data.wait);
-
- return i_return;
-}
diff --git a/src/gui/Makefile.am b/src/gui/Makefile.am
deleted file mode 100644
index c6db4b7..0000000
--- a/src/gui/Makefile.am
+++ /dev/null
@@ -1,31 +0,0 @@
-noinst_LIBRARIES = libgui.a
-
-libgui_a_SOURCES = \
- audio-settings.c audio-settings.h \
- bank-ops.c bank-ops.h \
- basic_combos.c basic_combos.h \
- channelsection.c channelsection.h \
- envelopetab.c envelopetab.h \
- gui.c gui.h \
- idselector.c idselector.h \
- lfotab.c lfotab.h \
- mastersection.c mastersection.h \
- midisection.c midisection.h \
- mod_section.c mod_section.h \
- mod_src_gui.c mod_src_gui.h \
- paramtab.c paramtab.h \
- patchlist.c patchlist.h \
- patchsection.c patchsection.h \
- sample-editor.c sample-editor.h \
- sample-selector.c sample-selector.h \
- sampletab.c sampletab.h \
- voicetab.c voicetab.h \
- waveform.c waveform.h
-
-INCLUDES = \
- -l.. \
- @GTK_CFLAGS@ \
- @LIBGNOMECANVAS_CFLAGS@ \
- @PHAT_CFLAGS@
-
-libgui_a_CFLAGS = $(CFLAGS) -I.. -DINSTALLDIR=\"$(datadir)\"
diff --git a/src/gui/channelsection.c b/src/gui/channelsection.c
deleted file mode 100644
index d69ccc5..0000000
--- a/src/gui/channelsection.c
+++ /dev/null
@@ -1,132 +0,0 @@
-/* Petri-Foo is a fork of the Specimen audio sampler.
-
- Original Specimen author Pete Bessman
- Copyright 2005 Pete Bessman
- Copyright 2011 James W. Morris
-
- This file is part of Petri-Foo.
-
- Petri-Foo is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation.
-
- Petri-Foo is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Petri-Foo. If not, see <http://www.gnu.org/licenses/>.
-
- This file is a derivative of a Specimen original, modified 2011
-*/
-
-
-#include <gtk/gtk.h>
-#include <phat/phat.h>
-#include "channelsection.h"
-#include "gui.h"
-#include "patchlist.h"
-#include "midi.h"
-#include "patch_set_and_get.h"
-
-
-
-G_DEFINE_TYPE(ChannelSection, channel_section, GTK_TYPE_VBOX)
-
-
-static void channel_section_class_init(ChannelSectionClass* klass)
-{
- channel_section_parent_class = g_type_class_peek_parent(klass);
-}
-
-
-static void channel_cb(PhatSliderButton* button, ChannelSection* self)
-{
- int channel = (int)phat_slider_button_get_value(button);
- PatchList* list = gui_get_patch_list();
-
- patch_set_channel(self->patch, channel-1);
- patch_list_update(list, patch_list_get_current_patch(list),
- PATCH_LIST_PATCH);
-}
-
-
-static void connect(ChannelSection* self)
-{
- g_signal_connect(G_OBJECT(self->chan_sb), "value-changed",
- G_CALLBACK(channel_cb), (gpointer) self);
-}
-
-
-static void channel_section_init(ChannelSection* self)
-{
- GtkBox* box = GTK_BOX(self);
- GtkWidget* hbox = gtk_hbox_new(FALSE, 0);
- GtkBox* h = GTK_BOX(hbox);
-
- self->patch = -1;
-
- gui_pack(box, hbox);
- gui_label_pack("Channel:", h);
- gui_pack(h, gui_hpad_new(GUI_TEXTSPACE));
-
- /* channel sliderbutton */
- self->chan_sb = phat_slider_button_new_with_range(1, 1, MIDI_CHANS,1,0);
- phat_slider_button_set_threshold(PHAT_SLIDER_BUTTON(self->chan_sb),
- GUI_THRESHOLD);
- gui_pack(h, self->chan_sb);
-
- /* done */
- connect(self);
-}
-
-
-static void block(ChannelSection* self)
-{
- g_signal_handlers_block_by_func(self->chan_sb, channel_cb, self);
-}
-
-
-static void unblock(ChannelSection* self)
-{
- g_signal_handlers_unblock_by_func(self->chan_sb, channel_cb, self);
-}
-
-
-static void set_sensitive(ChannelSection* self, gboolean val)
-{
- gtk_widget_set_sensitive(self->chan_sb, val);
-}
-
-
-GtkWidget* channel_section_new(void)
-{
- return (GtkWidget*) g_object_new(CHANNEL_SECTION_TYPE, NULL);
-}
-
-
-void channel_section_set_patch(ChannelSection* self, int patch)
-{
- int channel;
-
- self->patch = patch;
-
- if (patch < 0)
- set_sensitive(self, FALSE);
- else
- {
- set_sensitive(self, TRUE);
- channel = patch_get_channel(patch);
- block(self);
- phat_slider_button_set_value(PHAT_SLIDER_BUTTON(self->chan_sb),
- channel+1);
- unblock(self);
- }
-}
-
-
-int channel_section_get_channel(ChannelSection* self)
-{
- return (self->patch < 0) ? 0 : patch_get_channel(self->patch);
-}
diff --git a/src/gui/sample-editor.c b/src/gui/sample-editor.c
deleted file mode 100644
index 1d1298d..0000000
--- a/src/gui/sample-editor.c
+++ /dev/null
@@ -1,568 +0,0 @@
-/* Petri-Foo is a fork of the Specimen audio sampler.
-
- Original Specimen author Pete Bessman
- Copyright 2005 Pete Bessman
- Copyright 2011 James W. Morris
-
- This file is part of Petri-Foo.
-
- Petri-Foo is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation.
-
- Petri-Foo is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Petri-Foo. If not, see <http://www.gnu.org/licenses/>.
-
- This file is a derivative of a Specimen original, modified 2011
-*/
-
-
-#include <stdio.h>
-#include <string.h>
-#include <gtk/gtk.h>
-#include "petri-foo.h"
-#include "patch_set_and_get.h"
-#include "waveform.h"
-#include "gui.h"
-#include "mixer.h"
-#include "sample-editor.h"
-
-#include "basic_combos.h"
-
-static GtkWidget* window;
-static GtkWidget* waveform;
-static GtkWidget* hscroll;
-
-static GtkObject* hscrolladj;
-
-static GtkWidget* wf_thumb = 0;
-
-static GtkWidget* fade_spin;
-static GtkWidget* xfade_spin;
-
-enum
-{
- ZOOM_MIN = 1,
- ZOOM_MAX = 100
-};
-
-
-static int ignore_callback = 0;
-
-static gboolean ignore_mark_change = FALSE; /* once upon a time*/
-
-static int zoom = ZOOM_MIN;
-static float range = 1.0;
-
-static int old_play_start, old_play_stop;
-static int old_loop_start, old_loop_stop;
-static int old_fade, old_xfade;
-static int patch;
-
-static GtkWidget* mark_combo;
-static GtkWidget* mark_spin;
-static GtkWidget* mark_val;
-
-
-static void update_mark_spin(void);
-static void update_fade_spins(void);
-static void cb_mark_combo_changed(GtkWidget* combo, gpointer data);
-
-static void cb_close (GtkWidget * widget, gpointer data)
-{
- (void)widget;(void)data;
- debug ("Hiding sample editor\n");
- mixer_note_off_with_id (patch, patch_get_note (patch));
- gtk_widget_hide (window);
-}
-
-static void cb_play (GtkWidget * widget, gpointer data)
-{
- (void)widget;(void)data;
- mixer_note_off_with_id (patch, patch_get_note (patch));
- mixer_note_on_with_id (patch, patch_get_note (patch), 1.0);
-}
-
-static void cb_stop (GtkWidget * widget, gpointer data)
-{
- (void)widget;(void)data;
- mixer_note_off_with_id (patch, patch_get_note (patch));
-}
-
-static void cb_reset (GtkWidget * widget, gpointer data)
-{
- (void)widget;(void)data;
- debug ("Restoring initial values\n");
-
- patch_set_mark_frame(patch, WF_MARK_PLAY_START, old_play_start);
- patch_set_mark_frame(patch, WF_MARK_PLAY_STOP, old_play_stop);
- patch_set_mark_frame(patch, WF_MARK_LOOP_START, old_loop_start);
- patch_set_mark_frame(patch, WF_MARK_LOOP_STOP, old_loop_stop);
- cb_mark_combo_changed(mark_combo, 0);
- gtk_widget_queue_draw(waveform);
- gtk_widget_queue_draw(wf_thumb);
-}
-
-static void cb_clear (GtkWidget * widget, gpointer data)
-{
- (void)widget;
- char *op = data;
-
- if (strcmp(op, "loop") == 0)
- {
- int play_start = patch_get_mark_frame(patch, WF_MARK_PLAY_START);
- int play_stop = patch_get_mark_frame(patch, WF_MARK_PLAY_STOP);
- patch_set_mark_frame(patch, WF_MARK_LOOP_START, play_start);
- patch_set_mark_frame(patch, WF_MARK_LOOP_STOP, play_stop);
- }
- else if (strcmp(op, "play") == 0)
- {
- int frames = patch_get_mark_frame(patch, WF_MARK_STOP);
- patch_set_mark_frame(patch, WF_MARK_PLAY_START, 0);
- patch_set_mark_frame(patch, WF_MARK_PLAY_STOP, frames - 1);
- }
-
- cb_mark_combo_changed(mark_combo, 0);
- gtk_widget_queue_draw(waveform);
- gtk_widget_queue_draw(wf_thumb);
-}
-
-
-static void update_mark_val(int val)
-{
- const float* wav = patch_get_sample(patch);
- char buf[40];
- snprintf(buf, 40, "%2.6f", wav[val * 2]);
- gtk_label_set_label(GTK_LABEL(mark_val), buf);
-}
-
-
-static void cb_scroll (GtkWidget * scroll, gpointer data)
-{
- (void)data;
- float val = gtk_range_get_value(GTK_RANGE(scroll));
- debug("scroll changing:%f\n",(float)val);
- waveform_set_range(WAVEFORM(waveform), val, val + range);
-}
-
-
-static void cb_mark_spin_changed(GtkWidget * spin, gpointer data)
-{
- debug("spin changing\n");
- int val = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(mark_spin));
- int mark = waveform_get_mark(WAVEFORM(waveform));
- patch_set_mark_frame(patch, mark, val);
- update_mark_val(val);
- update_fade_spins(); /* so xfade spin button range is set correctly */
- gtk_widget_queue_draw(waveform);
- gtk_widget_queue_draw(wf_thumb);
-}
-
-
-static void cb_fade_spin_changed(GtkWidget * spin, gpointer data)
-{
- debug("fade changed\n");
- int val = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(fade_spin));
- patch_set_fade_samples(patch, val);
-}
-
-
-static void cb_xfade_spin_changed(GtkWidget * spin, gpointer data)
-{
- debug("x-fade changed\n");
- int val = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(xfade_spin));
- patch_set_xfade_samples(patch, val);
- update_mark_spin(); /* so mark spin range is set correctly */
-}
-
-
-static void update_mark_spin(void)
-{
- int min;
- int max;
-
- int mark = waveform_get_mark(WAVEFORM(waveform));
- int val = patch_get_mark_frame_range(patch, mark, &min, &max);
-
- debug("updating mark spin\n");
-
- if (val < 0)
- {
- val = patch_get_mark_frame(patch, mark);
- gtk_widget_set_sensitive(mark_spin, FALSE);
- }
- else
- gtk_widget_set_sensitive(mark_spin, TRUE);
-
- g_signal_handlers_block_by_func(mark_spin, cb_mark_spin_changed, 0);
- gtk_spin_button_set_range(GTK_SPIN_BUTTON(mark_spin), min, max);
- gtk_spin_button_set_value(GTK_SPIN_BUTTON(mark_spin), val);
- g_signal_handlers_unblock_by_func(mark_spin, cb_mark_spin_changed, 0);
-
- update_fade_spins(); /* ie set the range of xfade */
- update_mark_val(val);
-}
-
-
-static void update_fade_spins(void)
-{
- int fade = patch_get_fade_samples(patch);
- int max_fade = patch_get_max_fade_samples(patch);
- int xfade = patch_get_xfade_samples(patch);
- int max_xfade = patch_get_max_xfade_samples(patch);
-
- g_signal_handlers_block_by_func(fade_spin, cb_fade_spin_changed, 0);
- gtk_spin_button_set_range(GTK_SPIN_BUTTON(fade_spin), 0, max_fade);
- gtk_spin_button_set_value(GTK_SPIN_BUTTON(fade_spin), fade);
- g_signal_handlers_unblock_by_func(fade_spin, cb_fade_spin_changed, 0);
-
- g_signal_handlers_block_by_func(xfade_spin, cb_xfade_spin_changed, 0);
- gtk_spin_button_set_range(GTK_SPIN_BUTTON(xfade_spin), 0, max_xfade);
- gtk_spin_button_set_value(GTK_SPIN_BUTTON(xfade_spin), xfade);
- g_signal_handlers_unblock_by_func(xfade_spin, cb_xfade_spin_changed, 0);
-}
-
-
-static void cb_mark_combo_changed(GtkWidget* combo, gpointer data)
-{
- debug("combo changing...\n");
- ignore_mark_change = TRUE;
- waveform_set_mark(WAVEFORM(waveform),
- gtk_combo_box_get_active(GTK_COMBO_BOX(mark_combo)));
- update_mark_spin();
-}
-
-static void cb_wf_play_changed(void)
-{
- /* there's some chance the play point that was changed is
- selected and shown in the mark spin. */
- debug("play changing...\n");
- update_mark_spin();
- update_fade_spins();
- gtk_widget_queue_draw(wf_thumb);
-}
-
-static void cb_wf_loop_changed(void)
-{
- /* there's some chance the play point that was changed is
- selected and shown in the mark spin. */
- debug("loop changing...\n");
- update_mark_spin();
- update_fade_spins();
- gtk_widget_queue_draw(wf_thumb);
-}
-
-static void cb_wf_mark_changed(void)
-{
- /* ditto cb_wf_play_changed */
- if (ignore_mark_change)
- {
- debug("ignoring mark change this time\n");
- ignore_mark_change = FALSE;
- return;
- }
- debug("mark changing...\n");
- gtk_combo_box_set_active(GTK_COMBO_BOX(mark_combo),
- waveform_get_mark(WAVEFORM(waveform)));
-}
-
-static void cb_wf_view_changed(void)
-{
- float start, stop;
- waveform_get_range(WAVEFORM(waveform), &start, &stop);
- debug("view changing...\n");
- g_signal_handlers_block_by_func(hscroll, cb_scroll, 0);
- gtk_adjustment_set_value(GTK_ADJUSTMENT(hscrolladj), start);
- g_signal_handlers_unblock_by_func(hscroll, cb_scroll, 0);
-}
-
-static void cb_zoom(GtkAdjustment* adj, GtkWidget* spinbutton)
-{
- (void)spinbutton;
- float max;
- float page_size;
- float step_inc;
- float page_inc;
- float val;
-
- float start;
- float stop;
- int frames = patch_get_frames(patch);
-
- waveform_get_range(WAVEFORM(waveform), &start, &stop);
-
- debug("zoom changing...\n");
-
- zoom = gtk_adjustment_get_value(adj);
-
- if (zoom < ZOOM_MIN)
- zoom = ZOOM_MIN;
- else if (zoom > ZOOM_MAX)
- zoom = ZOOM_MAX;
-
- max = 1.0 - (1.0 / zoom);
- page_size = 1.0 / zoom;
- page_inc = max / 1000;
- step_inc = max / 10;
-
- /* create new adjustment */
-
- val = start + (stop - start) / 2 - page_size / 2;
-
- /* range needs to be updated so that we can tell the waveform
- * object how much of itself it needs to draw when the scrollbar
- * changes */
-
- range = 1.0 - max;
-
- if (val + range > 1.0)
- val = 1.0 - range;
-
-
-debug("start:%f stop:%f hscroll range value:%f\n", start,stop,val);
-
- gtk_range_set_range(GTK_RANGE(hscroll), start, stop);
-
- hscrolladj = gtk_adjustment_new(val, 0.0, 1.0, step_inc,
- page_inc,
- page_size);
- gtk_range_set_adjustment(GTK_RANGE(hscroll),
- GTK_ADJUSTMENT(hscrolladj));
-
-
- /* emit value-changed signal so waveform is redrawn with
- * the new dimensions */
- g_signal_emit_by_name(G_OBJECT(hscroll), "value-changed");
-}
-
-
-
-void sample_editor_show(int id)
-{
- waveform_set_patch (WAVEFORM (waveform), id);
-
- patch = id;
-
- old_play_start = patch_get_mark_frame(patch, WF_MARK_PLAY_START);
- old_play_stop = patch_get_mark_frame(patch, WF_MARK_PLAY_STOP);
- old_loop_start = patch_get_mark_frame(patch, WF_MARK_LOOP_START);
- old_loop_stop = patch_get_mark_frame(patch, WF_MARK_LOOP_STOP);
-
- gtk_combo_box_set_active(GTK_COMBO_BOX(mark_combo), WF_MARK_PLAY_START);
-
- update_fade_spins();
-
- gtk_widget_show (window);
-}
-
-
-void sample_editor_update(void)
-{
- gtk_widget_queue_draw(waveform);
-}
-
-
-
-void sample_editor_set_thumb(GtkWidget* thumb)
-{
- wf_thumb = thumb;
-}
-
-
-void sample_editor_init(GtkWidget * parent)
-{
- GtkWindow *w;
- GtkWidget *master_vbox;
- GtkWidget *hbox;
- GtkWidget *button;
- GtkWidget *image;
- GtkWidget *label;
- GtkWidget *spinbutton;
- GtkAdjustment *zoom_adj;
- GtkWidget* tmp;
-
- debug ("Initializing sample editor window\n");
-
- /* main window */
- window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
- w = GTK_WINDOW (window);
- gtk_window_set_title (w, "Edit Sample");
- gtk_window_set_resizable (w, TRUE);
- gtk_window_set_transient_for (w, GTK_WINDOW (parent));
- gtk_window_set_modal (w, FALSE);
- g_signal_connect (G_OBJECT(w), "delete-event", G_CALLBACK(cb_close),
- NULL);
-
- /* master vbox */
- master_vbox = gtk_vbox_new (FALSE, GUI_SPACING);
- gtk_container_add (GTK_CONTAINER (window), master_vbox);
- gtk_container_set_border_width (GTK_CONTAINER (window), GUI_SPACING);
- gtk_widget_show (master_vbox);
-
-
- /* top row hbox */
- hbox = gtk_hbox_new (FALSE, GUI_SPACING);
- gtk_box_pack_start (GTK_BOX (master_vbox), hbox, FALSE, FALSE, 0);
- gtk_widget_show (hbox);
-
- /* play button */
- image = gtk_image_new_from_stock(GTK_STOCK_MEDIA_PLAY,
- GTK_ICON_SIZE_SMALL_TOOLBAR);
- button = gtk_button_new();
- gtk_container_add(GTK_CONTAINER(button), image);
- gtk_box_pack_start(GTK_BOX (hbox), button, FALSE, FALSE, 0);
- g_signal_connect_swapped(G_OBJECT (button), "clicked",
- G_CALLBACK(cb_play), NULL);
- gtk_widget_show(image);
- gtk_widget_show(button);
-
- /* stop button */
- image = gtk_image_new_from_stock(GTK_STOCK_MEDIA_STOP,
- GTK_ICON_SIZE_SMALL_TOOLBAR);
- button = gtk_button_new ( );
- gtk_container_add (GTK_CONTAINER (button), image);
- gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
- g_signal_connect_swapped (G_OBJECT (button), "clicked",
- G_CALLBACK (cb_stop), NULL);
- gtk_widget_show(image);
- gtk_widget_show(button);
-
- /* separator */
- tmp = gtk_vseparator_new();
- gtk_box_pack_start(GTK_BOX(hbox), tmp, FALSE, FALSE, 0);
- gtk_widget_show(tmp);
-
- /* fade spin button */
- label = gtk_label_new("Fade:");
- gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
- gtk_widget_show(label);
-
- fade_spin = gtk_spin_button_new_with_range(0, 1, 1);
- gtk_box_pack_start(GTK_BOX(hbox), fade_spin, FALSE, FALSE, 0);
- gtk_widget_show(fade_spin);
- g_signal_connect(G_OBJECT(fade_spin), "value-changed",
- G_CALLBACK(cb_fade_spin_changed), NULL);
-
- /* X-fade spin button */
- label = gtk_label_new("X-Fade:");
- gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
- gtk_widget_show(label);
-
- xfade_spin = gtk_spin_button_new_with_range(0, 1, 1);
- gtk_box_pack_start(GTK_BOX(hbox), xfade_spin, FALSE, FALSE, 0);
- gtk_widget_show(xfade_spin);
- g_signal_connect(G_OBJECT(xfade_spin), "value-changed",
- G_CALLBACK(cb_xfade_spin_changed), NULL);
-
- /* separator */
- tmp = gtk_vseparator_new();
- gtk_box_pack_start(GTK_BOX(hbox), tmp, FALSE, FALSE, 0);
- gtk_widget_show(tmp);
-
-
- /* mark combo */
- mark_combo = basic_combo_create(waveform_get_mark_names());
- gtk_box_pack_start(GTK_BOX (hbox), mark_combo, FALSE, FALSE, 0);
- gtk_widget_show(mark_combo);
- g_signal_connect(G_OBJECT(mark_combo), "changed",
- G_CALLBACK(cb_mark_combo_changed), NULL);
-
- mark_spin = gtk_spin_button_new_with_range(0, 1, 1);
- gtk_box_pack_start(GTK_BOX (hbox), mark_spin, FALSE, FALSE, 0);
- gtk_widget_show(mark_spin);
- g_signal_connect(G_OBJECT(mark_spin), "value-changed",
- G_CALLBACK(cb_mark_spin_changed), NULL);
-
- /* mark spin value label */
- mark_val = gtk_label_new("");
- gtk_box_pack_start(GTK_BOX (hbox), mark_val, FALSE, FALSE, 0);
- gtk_widget_show(mark_val);
-
- /* separator */
- tmp = gtk_vseparator_new();
- gtk_box_pack_start(GTK_BOX(hbox), tmp, FALSE, FALSE, 0);
- gtk_widget_show(tmp);
-
- /* loop points clear button */
- button = gtk_button_new_with_label ("Loop");
- gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
- g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (cb_clear),
- (gpointer) "loop");
- gtk_widget_show (button);
-
- /* play points clear button */
- button = gtk_button_new_with_label ("Play");
- gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
- g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (cb_clear),
- (gpointer) "play");
- gtk_widget_show (button);
-
-
- /* clear label */
- label = gtk_label_new ("Clear Points:");
- gtk_box_pack_end (GTK_BOX (hbox), label, FALSE, FALSE, 0);
- gtk_widget_show (label);
-
- /* waveform */
- waveform = waveform_new();
- waveform_set_patch( WAVEFORM(waveform), -1);
- waveform_set_size( WAVEFORM(waveform), 512, 256);
- waveform_set_interactive( WAVEFORM(waveform), TRUE);
- gtk_box_pack_start (GTK_BOX (master_vbox), waveform, TRUE, TRUE, 0);
- gtk_widget_show (waveform);
- g_signal_connect(G_OBJECT (waveform), "play-changed",
- G_CALLBACK(cb_wf_play_changed), NULL);
- g_signal_connect(G_OBJECT (waveform), "loop-changed",
- G_CALLBACK(cb_wf_loop_changed), NULL);
- g_signal_connect(G_OBJECT (waveform), "mark-changed",
- G_CALLBACK(cb_wf_mark_changed), NULL);
- g_signal_connect(G_OBJECT (waveform), "view-changed",
- G_CALLBACK(cb_wf_view_changed), NULL);
-
- /* waveform scrollbar */
- hscrolladj = gtk_adjustment_new (0.0, 0.0, 1.0, 0.0, 0.0, 1.0);
- hscroll = gtk_hscrollbar_new (GTK_ADJUSTMENT (hscrolladj));
- gtk_box_pack_start (GTK_BOX (master_vbox), hscroll, FALSE, FALSE, 0);
- g_signal_connect (G_OBJECT (hscroll), "value-changed",
- G_CALLBACK (cb_scroll), NULL);
- gtk_widget_show (hscroll);
-
- /* hbox */
- hbox = gtk_hbox_new (FALSE, GUI_SPACING);
- gtk_box_pack_start (GTK_BOX (master_vbox), hbox, FALSE, FALSE, 0);
- gtk_widget_show (hbox);
-
- /* zoom spinbutton */
- label = gtk_label_new ("Zoom:");
- gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
- gtk_widget_show (label);
-
- zoom_adj =
- (GtkAdjustment *) gtk_adjustment_new (1.0, ZOOM_MIN, ZOOM_MAX, 1,
- 5, 0.0);
- spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (zoom_adj), 1, 2);
- gtk_box_pack_start (GTK_BOX (hbox), spinbutton, FALSE, FALSE, 0);
- g_signal_connect (G_OBJECT (zoom_adj), "value_changed",
- G_CALLBACK (cb_zoom), (gpointer) spinbutton);
- gtk_widget_show (spinbutton);
-
-
- /* close button */
- button = gtk_button_new_from_stock (GTK_STOCK_CLOSE);
- gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
- g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (cb_close),
- NULL);
- gtk_widget_show (button);
-
- /* reset button */
- button = gtk_button_new_with_label ("Reset");
- gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
- g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (cb_reset),
- NULL);
- gtk_widget_show (button);
-}
diff --git a/src/gui/voicetab.c b/src/gui/voicetab.c
deleted file mode 100644
index d6b49fe..0000000
--- a/src/gui/voicetab.c
+++ /dev/null
@@ -1,333 +0,0 @@
-/* Petri-Foo is a fork of the Specimen audio sampler.
-
- Original Specimen author Pete Bessman
- Copyright 2005 Pete Bessman
- Copyright 2011 James W. Morris
-
- This file is part of Petri-Foo.
-
- Petri-Foo is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation.
-
- Petri-Foo is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Petri-Foo. If not, see <http://www.gnu.org/licenses/>.
-
- This file is a derivative of a Specimen original, modified 2011
-*/
-
-
-#include <gtk/gtk.h>
-#include <phat/phat.h>
-#include "voicetab.h"
-#include "gui.h"
-#include "patch_set_and_get.h"
-
-
-typedef struct _VoiceTabPrivate VoiceTabPrivate;
-
-#define VOICE_TAB_GET_PRIVATE(obj) \
- (G_TYPE_INSTANCE_GET_PRIVATE((obj), \
- VOICE_TAB_TYPE, VoiceTabPrivate))
-
-struct _VoiceTabPrivate
-{
- int patch;
- guint refresh;
- GtkWidget* cut_sb;
- GtkWidget* cutby_sb;
- GtkWidget* time_fan;
- GtkWidget* mono_check;
- GtkWidget* legato_check;
- GtkWidget* porta_check;
-};
-
-
-G_DEFINE_TYPE(VoiceTab, voice_tab, GTK_TYPE_VBOX);
-
-
-static void voice_tab_class_init(VoiceTabClass* klass)
-{
- GtkObjectClass *object_class = GTK_OBJECT_CLASS(klass);
- voice_tab_parent_class = g_type_class_peek_parent(klass);
- g_type_class_add_private(object_class, sizeof(VoiceTabPrivate));
-}
-
-
-static void cut_cb(PhatSliderButton* button, VoiceTabPrivate* p)
-{
- int val = phat_slider_button_get_value(button);
- patch_set_cut(p->patch, val);
-}
-
-
-static void cutby_cb(PhatSliderButton* button, VoiceTabPrivate* p)
-{
- int val = phat_slider_button_get_value(button);
- patch_set_cut_by(p->patch, val);
-}
-
-
-static void porta_cb(GtkToggleButton* button, VoiceTabPrivate* p)
-{
- patch_set_portamento(p->patch, gtk_toggle_button_get_active(button));
-}
-
-
-static void porta_cb2(GtkToggleButton* button, VoiceTabPrivate* p)
-{
- if (gtk_toggle_button_get_active(button))
- gtk_widget_set_sensitive(p->time_fan, TRUE);
- else
- gtk_widget_set_sensitive(p->time_fan, FALSE);
-}
-
-
-static void time_cb(PhatFanSlider* fan, VoiceTabPrivate* p)
-{
- float val = phat_fan_slider_get_value(fan);
- patch_set_portamento_time(p->patch, val);
-}
-
-
-static void mono_cb(GtkToggleButton* button, VoiceTabPrivate* p)
-{
- patch_set_monophonic(p->patch, gtk_toggle_button_get_active(button));
-}
-
-
-static void mono_cb2(GtkToggleButton* button, VoiceTabPrivate* p)
-{
- gtk_widget_set_sensitive(p->legato_check,
- gtk_toggle_button_get_active(button));
-}
-
-
-static void legato_cb(GtkToggleButton* button, VoiceTabPrivate* p)
-{
- patch_set_legato(p->patch, gtk_toggle_button_get_active(button));
-}
-
-
-static void connect(VoiceTabPrivate* p)
-{
- g_signal_connect(G_OBJECT(p->cut_sb), "value-changed",
- G_CALLBACK(cut_cb), (gpointer)p);
- g_signal_connect(G_OBJECT(p->cutby_sb), "value-changed",
- G_CALLBACK(cutby_cb), (gpointer)p);
- g_signal_connect(G_OBJECT(p->mono_check), "toggled",
- G_CALLBACK(mono_cb), (gpointer)p);
- g_signal_connect(G_OBJECT(p->mono_check), "toggled",
- G_CALLBACK(mono_cb2), (gpointer)p);
- g_signal_connect(G_OBJECT(p->legato_check), "toggled",
- G_CALLBACK(legato_cb), (gpointer)p);
- g_signal_connect(G_OBJECT(p->porta_check), "toggled",
- G_CALLBACK(porta_cb), (gpointer)p);
- g_signal_connect(G_OBJECT(p->porta_check), "toggled",
- G_CALLBACK(porta_cb2), (gpointer)p);
- g_signal_connect(G_OBJECT(p->time_fan), "value-changed",
- G_CALLBACK(time_cb), (gpointer)p);
-}
-
-
-static void block(VoiceTabPrivate* p)
-{
- g_signal_handlers_block_by_func(p->cut_sb, cut_cb, p);
- g_signal_handlers_block_by_func(p->cutby_sb, cutby_cb, p);
- g_signal_handlers_block_by_func(p->mono_check, mono_cb, p);
- g_signal_handlers_block_by_func(p->legato_check,legato_cb, p);
- g_signal_handlers_block_by_func(p->porta_check, porta_cb, p);
- g_signal_handlers_block_by_func(p->time_fan, time_cb, p);
- /* *_cb2 intentionally omitted */
-}
-
-
-static void unblock(VoiceTabPrivate* p)
-{
- g_signal_handlers_unblock_by_func(p->cut_sb, cut_cb, p);
- g_signal_handlers_unblock_by_func(p->cutby_sb, cutby_cb, p);
- g_signal_handlers_unblock_by_func(p->mono_check, mono_cb, p);
- g_signal_handlers_unblock_by_func(p->legato_check, legato_cb, p);
- g_signal_handlers_unblock_by_func(p->porta_check, porta_cb, p);
- g_signal_handlers_unblock_by_func(p->time_fan, time_cb, p);
- /* *_cb2 intentionally omitted */
-}
-
-
-static gboolean refresh(gpointer data)
-{
- VoiceTabPrivate* p = data;
- gboolean porta;
- float time;
-
- if (p->patch < 0)
- return TRUE;
-
- porta = patch_get_portamento(p->patch);
- time = patch_get_portamento_time(p->patch);
-
- block(p);
-
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p->porta_check), porta);
- phat_fan_slider_set_value(PHAT_FAN_SLIDER(p->time_fan), time);
-
- unblock(p);
-
- return TRUE;
-}
-
-
-static void voice_tab_init(VoiceTab* self)
-{
- VoiceTabPrivate* p = VOICE_TAB_GET_PRIVATE(self);
- GtkBox* box = GTK_BOX(self);
- GtkWidget* title;
- GtkWidget* table;
- GtkTable* t;
- GtkWidget* pad;
- GtkWidget* label;
-
- p->patch = -1;
- p->refresh = -1;
-
- gtk_container_set_border_width(GTK_CONTAINER(self), GUI_BORDERSPACE);
-
- /* table */
- table = gtk_table_new(8, 6, FALSE);
- t = (GtkTable*) table;
- gtk_box_pack_start(box, table, FALSE, FALSE, 0);
- gtk_widget_show(table);
-
- /* voice title */
- title = gui_title_new("Voice");
- gtk_table_attach_defaults(t, title, 0, 6, 0, 1);
- gtk_widget_show(title);
-
- /* indentation */
- pad = gui_hpad_new(GUI_INDENT);
- gtk_table_attach(t, pad, 0, 1, 1, 2, 0, 0, 0, 0);
- gtk_widget_show(pad);
-
- /* voice title padding */
- pad = gui_vpad_new(GUI_TITLESPACE);
- gtk_table_attach(t, pad, 1, 2, 1, 2, 0, 0, 0, 0);
- gtk_widget_show(pad);
-
- /* portamento title padding */
- pad = gui_vpad_new(GUI_TITLESPACE);
- gtk_table_attach(t, pad, 1, 2, 6, 7, 0, 0, 0, 0);
- gtk_widget_show(pad);
-
- /* cut-mono column spacing */
- pad = gui_hpad_new(GUI_SECSPACE);
- gtk_table_attach(t, pad, 4, 5, 1, 2, 0, 0, 0, 0);
- gtk_widget_show(pad);
-
- /* time-fan column spacing */
- pad = gui_hpad_new(GUI_TEXTSPACE);
- gtk_table_attach(t, pad, 2, 3, 1, 2, 0, 0, 0, 0);
- gtk_widget_show(pad);
-
- /* section spacing */
- pad = gui_vpad_new(GUI_SECSPACE);
- gtk_table_attach(t, pad, 0, 1, 4, 5, 0, 0, 0, 0);
- gtk_widget_show(pad);
-
- /* cut sliderbutton */
- p->cut_sb = phat_slider_button_new_with_range(0, 0, 99, 1, 0);
- phat_slider_button_set_format(PHAT_SLIDER_BUTTON(p->cut_sb), 0,
- "Cut:", NULL);
- phat_slider_button_set_threshold(PHAT_SLIDER_BUTTON(p->cut_sb),
- GUI_THRESHOLD);
- gtk_table_attach_defaults(t, p->cut_sb, 1, 4, 2, 3);
- gtk_widget_show(p->cut_sb);
-
- gtk_table_set_row_spacing(t, 2, GUI_SPACING);
-
- /* cutby sliderbutton */
- p->cutby_sb = phat_slider_button_new_with_range(0, 0, 99, 1, 0);
- phat_slider_button_set_format(PHAT_SLIDER_BUTTON(p->cutby_sb), 0,
- "Cut by:", NULL);
- phat_slider_button_set_threshold(PHAT_SLIDER_BUTTON(p->cutby_sb),
- GUI_THRESHOLD);
- gtk_table_attach_defaults(t, p->cutby_sb, 1, 4, 3, 4);
- gtk_widget_show(p->cutby_sb);
-
- /* mono sliderbutton */
- p->mono_check = gtk_check_button_new_with_label("Monophonic");
- gtk_table_attach_defaults(t, p->mono_check, 5, 6, 2, 3);
- gtk_widget_show(p->mono_check);
-
- /* legato sliderbutton */
- p->legato_check = gtk_check_button_new_with_label("Legato");
- gtk_table_attach_defaults(t, p->legato_check, 5, 6, 3, 4);
- gtk_widget_show(p->legato_check);
- gtk_widget_set_sensitive(p->legato_check, FALSE);
-
- /* portamento checkbox */
- title = gui_title_new("Portamento");
- p->porta_check = gtk_check_button_new();
- gtk_container_add(GTK_CONTAINER(p->porta_check), title);
- gtk_table_attach_defaults(t, p->porta_check, 0, 6, 5, 6);
- gtk_widget_show(title);
- gtk_widget_show(p->porta_check);
-
- /* time fan */
- label = gtk_label_new("Time:");
- p->time_fan = phat_hfan_slider_new_with_range(0.05, 0.0, 1.0, 0.01);
- gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
- gtk_table_attach(t, label, 1, 2, 7, 8, GTK_FILL, 0, 0, 0);
- gtk_table_attach_defaults(t, p->time_fan, 3, 4, 7, 8);
- gtk_widget_show(label);
- gtk_widget_show(p->time_fan);
- gtk_widget_set_sensitive(p->time_fan, FALSE);
-
- /* done */
- connect(p);
- p->refresh = g_timeout_add(GUI_REFRESH_TIMEOUT, refresh, (gpointer)p);
-}
-
-
-GtkWidget* voice_tab_new(void)
-{
- return (GtkWidget*) g_object_new(VOICE_TAB_TYPE, NULL);
-}
-
-
-void voice_tab_set_patch(VoiceTab* self, int patch)
-{
- VoiceTabPrivate* p = VOICE_TAB_GET_PRIVATE(self);
- int cut, cutby;
- gboolean porta, mono, legato;
- float time;
-
- p->patch = patch;
-
- if (patch < 0)
- return;
-
- cut = patch_get_cut(patch);
- cutby = patch_get_cut_by(patch);
- porta = patch_get_portamento(patch);
- mono = patch_get_monophonic(patch);
- legato = patch_get_legato(patch);
- time = patch_get_portamento_time(patch);
-
- block(p);
-
- phat_slider_button_set_value(PHAT_SLIDER_BUTTON(p->cut_sb), cut);
- phat_slider_button_set_value(PHAT_SLIDER_BUTTON(p->cutby_sb), cutby);
-
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p->porta_check), porta);
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p->mono_check), mono);
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p->legato_check),legato);
-
- phat_fan_slider_set_value(PHAT_FAN_SLIDER(p->time_fan), time);
-
- unblock(p);
-}
diff --git a/src/patch_private/Makefile.am b/src/patch_private/Makefile.am
deleted file mode 100644
index 6eb708a..0000000
--- a/src/patch_private/Makefile.am
+++ /dev/null
@@ -1,18 +0,0 @@
-
-noinst_LIBRARIES = libpatch.a
-
-libpatch_a_SOURCES = \
- patch_data.c patch_data.h \
- patch_defs.c patch_defs.h \
- patch_macros.h \
- patch_voice.c patch_voice.h
-
-
-
-
-INCLUDES = \
- -l..
-
-
-libpatch_a_CFLAGS = $(CFLAGS) -I.. -DINSTALLDIR=\"$(datadir)\"
-
diff --git a/src/patch_set_and_get.c b/src/patch_set_and_get.c
deleted file mode 100644
index 7e24473..0000000
--- a/src/patch_set_and_get.c
+++ /dev/null
@@ -1,1891 +0,0 @@
-/* Petri-Foo is a fork of the Specimen audio sampler.
-
- Original Specimen author Pete Bessman
- Copyright 2005 Pete Bessman
- Copyright 2011 James W. Morris
-
- This file is part of Petri-Foo.
-
- Petri-Foo is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation.
-
- Petri-Foo is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Petri-Foo. If not, see <http://www.gnu.org/licenses/>.
-
- This file is a derivative of a Specimen original, modified 2011
-*/
-
-
-#include "patch_set_and_get.h"
-
-
-#include <string.h>
-#include <math.h>
-
-
-#include "sample.h"
-#include "adsr.h"
-#include "lfo.h"
-
-
-#include "patch_private/patch_data.h"
-#include "patch_private/patch_defs.h"
-#include "patch_private/patch_macros.h"
-
-
-INLINE_ISOK_DEF
-
-
-inline static int mod_src_to_eg_index(int patch_id, int id)
-{
- if (!isok(patch_id))
- return PATCH_ID_INVALID;
-
- id -= MOD_SRC_EG;
-
- return (id >= 0 && id < VOICE_MAX_ENVS)
- ? id
- : PATCH_ENV_ID_INVALID;
-}
-
-
-static int mod_src_ok(int id)
-{
- return (id & MOD_SRC_ALL || id == MOD_SRC_NONE)
- ? 0
- : PATCH_MOD_SRC_INVALID;
-}
-
-
-inline static bool mark_ok(int id)
-{
- if (id < WF_MARK_START || id > WF_MARK_STOP)
- return false;
-
- return true;
-}
-
-inline static bool mark_settable(int id)
-{
- if (id < WF_MARK_PLAY_START || id > WF_MARK_PLAY_STOP)
- return false;
-
- return true;
-}
-
-
-static inline void set_mark_frame(int patch, int mark, int frame)
-{
- *(patches[patch]->marks[mark]) = frame;
-}
-
-
-static inline int get_mark_frame(int patch, int mark)
-{
- return *(patches[patch]->marks[mark]);
-}
-
-
-static int get_mark_frame_range(int patch, int mark, int* min, int* max)
-{
- int xfade = patches[patch]->xfade_samples;
-
- if (mark == WF_MARK_START || mark == WF_MARK_STOP)
- {
- *min = *max = get_mark_frame(patch, mark);
- /* indicate non-editable! */
- return -1;
- }
-
- /* potential range: */
- *min = get_mark_frame(patch, mark - 1);
- *max = get_mark_frame(patch, mark + 1);
-
- /* tweak if necessary */
- switch(mark)
- {
- case WF_MARK_PLAY_START:
- *max -= xfade;
- break;
- case WF_MARK_PLAY_STOP:
- *min += xfade;
- break;
- case WF_MARK_LOOP_START:
- *min += xfade;
- *max -= xfade;
- break;
- case WF_MARK_LOOP_STOP:
- *min += xfade;
- *max -= xfade;
- break;
- }
-
- return get_mark_frame(patch, mark);
-}
-
-
-static int get_patch_param(int patch_id, PatchParamType param,
- PatchParam** p)
-{
- if (!isok(patch_id))
- return PATCH_ID_INVALID;
-
- switch(param)
- {
- case PATCH_PARAM_AMPLITUDE: *p = &patches[patch_id]->vol; break;
- case PATCH_PARAM_PANNING: *p = &patches[patch_id]->pan; break;
- case PATCH_PARAM_CUTOFF: *p = &patches[patch_id]->ffreq; break;
- case PATCH_PARAM_RESONANCE: *p = &patches[patch_id]->freso; break;
- case PATCH_PARAM_PITCH: *p = &patches[patch_id]->pitch; break;
- default:
- debug ("Invalid request for address of param\n");
- return PATCH_PARAM_INVALID;
- }
-
- return 0;
-}
-
-
-/* inline static function def macro, see private/patch_data.h */
-INLINE_PATCH_TRIGGER_GLOBAL_LFO_DEF
-
-
-
-/**************************************************************************/
-/************************* ENVELOPE SETTERS *******************************/
-/**************************************************************************/
-
-
-int patch_set_env_on (int patch_id, int eg, bool state)
-{
- eg = mod_src_to_eg_index(patch_id, eg);
-
- if (eg < 0)
- return eg; /* as error code */
-
- patches[patch_id]->env_params[eg].env_on = state;
- return 0;
-}
-
-
-/* sets the delay length in seconds */
-int patch_set_env_delay (int patch_id, int eg, float secs)
-{
- eg = mod_src_to_eg_index(patch_id, eg);
-
- if (eg < 0)
- return eg; /* as error code */
-
- if (secs < 0.0)
- return PATCH_PARAM_INVALID;
-
- patches[patch_id]->env_params[eg].delay = secs;
- return 0;
-}
-
-/* sets the attack length in seconds */
-int patch_set_env_attack (int patch_id, int eg, float secs)
-{
- eg = mod_src_to_eg_index(patch_id, eg);
-
- if (eg < 0)
- return eg; /* as error code */
-
- if (secs < 0.0)
- return PATCH_PARAM_INVALID;
-
- patches[patch_id]->env_params[eg].attack = secs;
- return 0;
-}
-
-/* sets the hold length in seconds */
-int patch_set_env_hold (int patch_id, int eg, float secs)
-{
- eg = mod_src_to_eg_index(patch_id, eg);
-
- if (eg < 0)
- return eg; /* as error code */
-
- if (secs < 0.0)
- return PATCH_PARAM_INVALID;
-
- patches[patch_id]->env_params[eg].hold = secs;
- return 0;
-}
-
-/* sets the decay length in seconds */
-int patch_set_env_decay (int patch_id, int eg, float secs)
-{
- eg = mod_src_to_eg_index(patch_id, eg);
-
- if (eg < 0)
- return eg; /* as error code */
-
- if (secs < 0.0)
- return PATCH_PARAM_INVALID;
-
- patches[patch_id]->env_params[eg].decay = secs;
- return 0;
-}
-
-/* sets the sustain level */
-int patch_set_env_sustain (int patch_id, int eg, float level)
-{
- eg = mod_src_to_eg_index(patch_id, eg);
-
- if (eg < 0)
- return eg; /* as error code */
-
- if (level < 0.0 || level > 1.0)
- return PATCH_PARAM_INVALID;
-
- patches[patch_id]->env_params[eg].sustain = level;
- return 0;
-}
-
-/* sets the release length in seconds */
-int patch_set_env_release (int patch_id, int eg, float secs)
-{
- eg = mod_src_to_eg_index(patch_id, eg);
-
- if (eg < 0)
- return eg; /* as error code */
-
- if (secs < 0.0)
- return PATCH_PARAM_INVALID;
-
- if (secs < PATCH_MIN_RELEASE)
- secs = PATCH_MIN_RELEASE;
-
- patches[patch_id]->env_params[eg].release = secs;
- return 0;
-}
-
-/* sets key tracking amount */
-int patch_set_env_key_amt(int patch_id, int eg, float val)
-{
- eg = mod_src_to_eg_index(patch_id, eg);
-
- if (eg < 0)
- return eg; /* as error code */
-
- if (val < -1.0 || val > 1.0)
- return PATCH_PARAM_INVALID;
-
- patches[patch_id]->env_params[eg].key_amt = val;
- return 0;
-}
-
-/*
-int patch_set_env_vel_amt(int patch_id, int eg, float val)
-{
- eg = mod_src_to_eg_index(patch_id, eg);
-
- if (eg < 0)
- return eg;
-
- if (val < -1.0 || val > 1.0)
- return PATCH_PARAM_INVALID;
-
- patches[patch_id]->env_params[eg].vel_amt = val;
- return 0;
-}
-*/
-
-/**************************************************************************/
-/************************* ENVELOPE GETTERS *******************************/
-/**************************************************************************/
-
-/* places the delay length in seconds into val */
-int patch_get_env_on(int patch_id, int eg, bool* val)
-{
- eg = mod_src_to_eg_index(patch_id, eg);
-
- if (eg < 0)
- return eg; /* as error code */
-
- *val = patches[patch_id]->env_params[eg].env_on;
- return 0;
-}
-
-
-
-/* places the delay length in seconds into val */
-int patch_get_env_delay (int patch_id, int eg, float* val)
-{
- eg = mod_src_to_eg_index(patch_id, eg);
-
- if (eg < 0)
- return eg; /* as error code */
-
- *val = patches[patch_id]->env_params[eg].delay;
- return 0;
-}
-
-
-/* places the attack length in seconds into val */
-int patch_get_env_attack (int patch_id, int eg, float* val)
-{
- eg = mod_src_to_eg_index(patch_id, eg);
-
- if (eg < 0)
- return eg; /* as error code */
-
- *val = patches[patch_id]->env_params[eg].attack;
- return 0;
-}
-
-
-/* places the hold length in seconds into val */
-int patch_get_env_hold (int patch_id, int eg, float* val)
-{
- eg = mod_src_to_eg_index(patch_id, eg);
-
- if (eg < 0)
- return eg; /* as error code */
-
- *val = patches[patch_id]->env_params[eg].hold;
- return 0;
-}
-
-
-/* places the decay length in seconds into val */
-int patch_get_env_decay (int patch_id, int eg, float* val)
-{
- eg = mod_src_to_eg_index(patch_id, eg);
-
- if (eg < 0)
- return eg; /* as error code */
-
- *val = patches[patch_id]->env_params[eg].decay;
- return 0;
-}
-
-
-/* places the sustain level into val */
-int patch_get_env_sustain (int patch_id, int eg, float* val)
-{
- eg = mod_src_to_eg_index(patch_id, eg);
-
- if (eg < 0)
- return eg; /* as error code */
-
- *val = patches[patch_id]->env_params[eg].sustain;
- return 0;
-}
-
-/* places the release length in seconds into val */
-int patch_get_env_release (int patch_id, int eg, float* val)
-{
- eg = mod_src_to_eg_index(patch_id, eg);
-
- if (eg < 0)
- return eg; /* as error code */
-
- *val = patches[patch_id]->env_params[eg].release;
-
- /* we hide the fact that we have a min release value from the
- * outside world (they're on a need-to-know basis) */
- if (*val <= PATCH_MIN_RELEASE)
- *val = 0;
- return 0;
-}
-
-
-int patch_get_env_key_amt (int patch_id, int eg, float* val)
-{
- eg = mod_src_to_eg_index(patch_id, eg);
-
- if (eg < 0)
- return eg; /* as error code */
-
- *val = patches[patch_id]->env_params[eg].key_amt;
- return 0;
-}
-
-/*
-int patch_get_env_vel_amt (int patch_id, int eg, float* val)
-{
- eg = mod_src_to_eg_index(patch_id, eg);
-
- if (eg < 0)
- return eg;
-
- *val = patches[patch_id]->env_params[eg].vel_amt;
- return 0;
-}
-*/
-/************************************************************************/
-/*************************** LFO SETTERS ********************************/
-/************************************************************************/
-
-static int lfo_from_id(int patch_id, int id, LFO** lfo, LFOParams** lfopar)
-{
- if (lfo)
- *lfo = 0;
-
- *lfopar = 0;
-
- if (!isok(patch_id))
- return PATCH_ID_INVALID;
-
- if ((id & MOD_SRC_VLFO) && (id & MOD_SRC_GLFO))
- return PATCH_LFO_ID_INVALID;
-
- if (id & MOD_SRC_VLFO)
- {
- id -= MOD_SRC_VLFO;
-
- if (id < VOICE_MAX_LFOS)
- *lfopar = &patches[patch_id]->vlfo_params[id];
-
- return 0;
- }
-
- if (id & MOD_SRC_GLFO)
- {
- id -= MOD_SRC_GLFO;
-
- if (id < PATCH_MAX_LFOS)
- {
- if (lfo)
- *lfo = patches[patch_id]->glfo[id];
-
- *lfopar = &patches[patch_id]->glfo_params[id];
- }
-
- return 0;
- }
-
- return PATCH_LFO_ID_INVALID;
-}
-
-int patch_set_lfo_on (int patch_id, int lfo_id, bool state)
-{
- LFO* lfo;
- LFOParams* lfopar;
- int err;
-
- if ((err = lfo_from_id(patch_id, lfo_id, &lfo, &lfopar)))
- return err;
-
- lfopar->lfo_on = state;
-
- if (lfo)
- lfo_trigger(lfo, lfopar);
-
- return 0;
-}
-
-/* set the attack time of the param's LFO */
-int patch_set_lfo_attack (int patch_id, int lfo_id, float secs)
-{
- LFO* lfo;
- LFOParams* lfopar;
- int err;
-
- if ((err = lfo_from_id(patch_id, lfo_id, &lfo, &lfopar)))
- return err;
-
- if (secs < 0.0)
- return PATCH_PARAM_INVALID;
-
- lfopar->attack = secs;
-
- if (lfo)
- lfo_rigger(lfo, lfopar);
-
- return 0;
-}
-
-/* set the period length of the param's lfo in beats */
-int patch_set_lfo_beats (int patch_id, int lfo_id, float beats)
-{
- LFO* lfo;
- LFOParams* lfopar;
- int err;
-
- if ((err = lfo_from_id(patch_id, lfo_id, &lfo, &lfopar)))
- return err;
-
- if (beats < 0.0)
- return PATCH_PARAM_INVALID;
-
- lfopar->sync_beats = beats;
-
- if (lfo)
- lfo_rigger(lfo, lfopar);
-
- return 0;
-}
-
-/* set the delay time of the param's LFO */
-int patch_set_lfo_delay (int patch_id, int lfo_id, float secs)
-{
- LFO* lfo;
- LFOParams* lfopar;
- int err;
-
- if ((err = lfo_from_id(patch_id, lfo_id, &lfo, &lfopar)))
- return err;
-
- if (secs < 0.0)
- return PATCH_PARAM_INVALID;
-
- lfopar->delay = secs;
-
- if (lfo)
- lfo_rigger(lfo, lfopar);
-
- return 0;
-}
-
-/* set the frequency of the param's lfo */
-int patch_set_lfo_freq (int patch_id, int lfo_id, float freq)
-{
- LFO* lfo;
- LFOParams* lfopar;
- int err;
-
- if ((err = lfo_from_id(patch_id, lfo_id, &lfo, &lfopar)))
- return err;
-
- if (freq < 0.0)
- return PATCH_PARAM_INVALID;
-
- lfopar->freq = freq;
-
- if (lfo)
- lfo_rigger(lfo, lfopar);
-
- return 0;
-}
-
-
-/* set whether to constrain the param's LFOs to positive values or not */
-int patch_set_lfo_positive (int patch_id, int lfo_id, bool state)
-{
- LFO* lfo;
- LFOParams* lfopar;
- int err;
-
- if ((err = lfo_from_id(patch_id, lfo_id, &lfo, &lfopar)))
- return err;
-
- lfopar->positive = state;
-
- if (lfo)
- lfo_rigger(lfo, lfopar);
-
- return 0;
-}
-
-
-/* set the param's lfo shape */
-int patch_set_lfo_shape (int patch_id, int lfo_id, LFOShape shape)
-{
- LFO* lfo;
- LFOParams* lfopar;
- int err;
-
- if ((err = lfo_from_id(patch_id, lfo_id, &lfo, &lfopar)))
- return err;
-
- lfopar->shape = shape;
-
- if (lfo)
- lfo_rigger(lfo, lfopar);
-
- return 0;
-}
-
-/* set whether to the param's lfo should sync to tempo or not */
-int patch_set_lfo_sync (int patch_id, int lfo_id, bool state)
-{
- LFO* lfo;
- LFOParams* lfopar;
- int err;
-
- if ((err = lfo_from_id(patch_id, lfo_id, &lfo, &lfopar)))
- return err;
-
- lfopar->sync = state;
-
- if (lfo)
- lfo_rigger(lfo, lfopar);
-
- return 0;
-}
-
-/************************************************************************/
-/*************************** LFO GETTERS ********************************/
-/************************************************************************/
-
-int patch_get_lfo_on(int patch_id, int lfo_id, bool* val)
-{
- LFOParams* lfopar;
- int err;
- if ((err = lfo_from_id(patch_id, lfo_id, NULL, &lfopar)))
- return err;
- *val = lfopar->lfo_on;
- return 0;
-}
-
-
-/* get the attack time of the param's LFO */
-int patch_get_lfo_attack (int patch_id, int lfo_id, float* val)
-{
- LFOParams* lfopar;
- int err;
- if ((err = lfo_from_id(patch_id, lfo_id, NULL, &lfopar)))
- return err;
- *val = lfopar->attack;
- return 0;
-}
-
-/* get the param's lfo period length in beats */
-int patch_get_lfo_beats (int patch_id, int lfo_id, float* val)
-{
- LFOParams* lfopar;
- int err;
- if ((err = lfo_from_id(patch_id, lfo_id, NULL, &lfopar)))
- return err;
- *val = lfopar->sync_beats;
- return 0;
-}
-
-/* get the delay time of the param's LFO */
-int patch_get_lfo_delay (int patch_id, int lfo_id, float* val)
-{
- LFOParams* lfopar;
- int err;
- if ((err = lfo_from_id(patch_id, lfo_id, NULL, &lfopar)))
- return err;
- *val = lfopar->delay;
- return 0;
-}
-
-/* get the param's lfo frequency */
-int patch_get_lfo_freq (int patch_id, int lfo_id, float* val)
-{
- LFOParams* lfopar;
- int err;
- if ((err = lfo_from_id(patch_id, lfo_id, NULL, &lfopar)))
- return err;
- *val = lfopar->freq;
- return 0;
-}
-
-int patch_get_lfo_positive (int patch_id, int lfo_id, bool* val)
-{
- LFOParams* lfopar;
- int err;
- if ((err = lfo_from_id(patch_id, lfo_id, NULL, &lfopar)))
- return err;
- *val = lfopar->positive;
- return 0;
-}
-
-/* get param's lfo shape */
-int patch_get_lfo_shape (int patch_id, int lfo_id, LFOShape* val)
-{
- LFOParams* lfopar;
- int err;
- if ((err = lfo_from_id(patch_id, lfo_id, NULL, &lfopar)))
- return err;
- *val = lfopar->shape;
- return 0;
-}
-
-/* get whether param's lfo is tempo synced or not */
-int patch_get_lfo_sync (int patch_id, int lfo_id, bool* val)
-{
- LFOParams* lfopar;
- int err;
- if ((err = lfo_from_id(patch_id, lfo_id, NULL, &lfopar)))
- return err;
- *val = lfopar->sync;
- return 0;
-}
-
-
-/**************************************************************************/
-/************************ PARAMETER SETTERS *******************************/
-/**************************************************************************/
-
-/* sets channel patch listens on */
-int patch_set_channel (int id, int channel)
-{
- if (!isok (id))
- return PATCH_ID_INVALID;
-
- if (channel < 0 || channel > 15)
- return PATCH_CHANNEL_INVALID;
-
- patches[id]->channel = channel;
- return 0;
-}
-
-/* sets the cut signal this patch emits when activated */
-int patch_set_cut (int id, int cut)
-{
- if (!isok (id))
- return PATCH_ID_INVALID;
- patches[id]->cut = cut;
- return 0;
-}
-
-/* sets the cut signal that terminates this patch if active */
-int patch_set_cut_by (int id, int cut_by)
-{
- if (!isok (id))
- return PATCH_ID_INVALID;
- patches[id]->cut_by = cut_by;
- return 0;
-}
-
-/* sets filter cutoff frequency */
-int patch_set_cutoff (int id, float freq)
-{
- if (!isok (id))
- return PATCH_ID_INVALID;
-
- if (freq < 0.0 || freq > 1.0)
- return PATCH_PARAM_INVALID;
-
- patches[id]->ffreq.val = freq;
- return 0;
-}
-
-/* set whether this patch should be played legato or not */
-int patch_set_legato(int id, bool val)
-{
- if (!isok (id))
- return PATCH_ID_INVALID;
- patches[id]->legato = val;
- return 0;
-}
-
-
-int patch_set_fade_samples(int id, int samples)
-{
-debug("set fade samples id:%d samples:%d\n",id,samples);
- if (!isok (id))
- return PATCH_ID_INVALID;
-
- if (patches[id]->sample->sp == NULL)
- return 0;
-
- if (samples < 0)
- {
- debug ("refusing to set negative fade length\n");
- return PATCH_PARAM_INVALID;
- }
-
- if (patches[id]->play_start + samples * 2 >= patches[id]->play_stop)
- {
- debug ("refusing to set fade length greater than half the "
- " number of samples between play start and play stop\n");
- return PATCH_PARAM_INVALID;
- }
-
- patches[id]->fade_samples = samples;
- return 0;
-}
-
-int patch_set_xfade_samples(int id, int samples)
-{
- if (!isok (id))
- return PATCH_ID_INVALID;
-
- if (patches[id]->sample->sp == NULL)
- return 0;
-
- if (samples < 0)
- {
- debug ("refusing to set negative xfade length\n");
- return PATCH_PARAM_INVALID;
- }
-
- if (patches[id]->loop_start + samples > patches[id]->loop_stop)
- {
- debug ("refusing to set xfade length greater than samples"
- " between play start and play stop\n");
- return PATCH_PARAM_INVALID;
- }
-
- if (patches[id]->loop_stop + samples > patches[id]->play_stop)
- {
- debug ("refusing to set xfade length greater than samples"
- " between loop stop and play stop\n");
- return PATCH_PARAM_INVALID;
- }
-
-debug("setting xfade to %d\n",samples);
- patches[id]->xfade_samples = samples;
- return 0;
-}
-
-
-/* sets the lower note of a patch's range */
-int patch_set_lower_note (int id, int note)
-{
- if (!isok (id))
- return PATCH_ID_INVALID;
-
- if (note < 0 || note > 127)
- return PATCH_NOTE_INVALID;
-
- patches[id]->lower_note = note;
- return 0;
-}
-
-
-int patch_set_mark_frame(int patch, int mark, int frame)
-{
- if (!isok(patch))
- return -1;
-
- if (patches[patch]->sample->sp == NULL)
- return -1;
-
- if (!mark_settable(mark))
- return -1;
-
- int min;
- int max;
-
- get_mark_frame_range(patch, mark, &min, &max);
-
- if (frame < min || frame > max)
- return -1;
-
- set_mark_frame(patch, mark, frame);
- return mark;
-}
-
-
-int patch_set_mark_frame_expand(int patch, int mark, int frame,
- int* also_changed)
-{
- int also = 0;
- int also_frame = -1;
- int xfade = patches[patch]->xfade_samples;
- int fade = patches[patch]->fade_samples;
-
- if (!isok(patch))
- return -1;
-
- if (patches[patch]->sample->sp == NULL)
- return -1;
-
- /* if callee wishes not to be informed about which marks get changed
- as a result of changing this one, also_changed will be NULL. It
- needs to be a valid pointer.
- */
- if (!also_changed)
- also_changed = &also;
-
- *also_changed = -1;
-
- switch(mark)
- {
- case WF_MARK_PLAY_START:
- also_frame = frame + xfade; /* pot loop start pos */
-
- if (frame + fade * 2 >= get_mark_frame(patch, WF_MARK_PLAY_STOP)
- || also_frame >= get_mark_frame(patch, WF_MARK_LOOP_STOP))
- {
- mark = -1;
- }
- else if (also_frame > get_mark_frame(patch, WF_MARK_LOOP_START))
- { /* moving play start along pushes loop start along... */
- if (also_frame + xfade
- < get_mark_frame(patch, WF_MARK_LOOP_STOP))
- {
- *also_changed = WF_MARK_LOOP_START;
- }
- else
- mark = -1;
- }
- break;
-
- case WF_MARK_PLAY_STOP:
- also_frame = frame - xfade; /* pot loop stop pos */
-
- if (frame - fade * 2<= get_mark_frame(patch, WF_MARK_PLAY_START)
- || also_frame <= get_mark_frame(patch, WF_MARK_LOOP_START))
- {
- mark = -1;
- }
- else if (also_frame < get_mark_frame(patch, WF_MARK_LOOP_STOP))
- {
- if (also_frame - xfade
- > get_mark_frame(patch, WF_MARK_LOOP_START))
- {
- *also_changed = WF_MARK_LOOP_STOP;
- }
- else
- mark = -1;
- }
- break;
-
- case WF_MARK_LOOP_START:
- also_frame = frame - xfade; /* pot play start pos */
-
- if (frame + xfade >= get_mark_frame(patch, WF_MARK_LOOP_STOP))
- mark = -1;
- else if (also_frame < get_mark_frame(patch, WF_MARK_PLAY_START))
- {
- if (also_frame > 0)
- *also_changed = WF_MARK_PLAY_START;
- else
- mark = -1;
- }
- break;
-
- case WF_MARK_LOOP_STOP:
- also_frame = frame + xfade /* pot play stop pos */;
-
- if (frame - xfade <= get_mark_frame(patch, WF_MARK_LOOP_START))
- mark = -1;
- else if (also_frame > get_mark_frame(patch, WF_MARK_PLAY_STOP))
- {
- if (also_frame < get_mark_frame(patch, WF_MARK_STOP))
- *also_changed = WF_MARK_PLAY_STOP;
- else
- mark = -1;
- }
- break;
-
- default:
- mark = -1;
- }
-
- if (mark != -1)
- {
- set_mark_frame(patch, mark, frame);
- }
-
- if (*also_changed != -1)
- {
- set_mark_frame(patch, *also_changed, also_frame);
- }
-
- return mark;
-}
-
-
-/* set whether the patch is monophonic or not */
-int patch_set_monophonic(int id, bool val)
-{
- if (!isok (id))
- return PATCH_ID_INVALID;
-
- patches[id]->mono = val;
- return 0;
-}
-
-/* sets the name */
-int patch_set_name (int id, const char *name)
-{
- if (!isok (id))
- return PATCH_ID_INVALID;
- strncpy (patches[id]->name, name, PATCH_MAX_NAME);
- return 0;
-}
-
-/* sets the root note */
-int patch_set_note (int id, int note)
-{
- if (!isok (id))
- return PATCH_ID_INVALID;
-
- if (note < 0 || note > 127)
- return PATCH_NOTE_INVALID;
-
- patches[id]->note = note;
- return 0;
-}
-
-/* sets the panorama */
-int patch_set_panning (int id, float pan)
-{
- if (!isok (id))
- return PATCH_ID_INVALID;
-
- if (pan < -1.0 || pan > 1.0)
- return PATCH_PAN_INVALID;
-
- patches[id]->pan.val = pan;
- return 0;
-}
-
-/* set the pitch */
-int patch_set_pitch (int id, float pitch)
-{
- if (!isok (id))
- return PATCH_ID_INVALID;
-
- if (pitch < -1.0 || pitch > 1.0)
- return PATCH_PARAM_INVALID;
-
- patches[id]->pitch.val = pitch;
- return 0;
-}
-
-/* set the pitch range */
-int patch_set_pitch_steps (int id, int steps)
-{
- if (!isok (id))
- return PATCH_ID_INVALID;
-
- if (steps < -PATCH_MAX_PITCH_STEPS
- || steps > PATCH_MAX_PITCH_STEPS)
- return PATCH_PARAM_INVALID;
-
- patches[id]->pitch_steps = steps;
- return 0;
-}
-
-/* sets the play mode */
-int patch_set_play_mode (int id, PatchPlayMode mode)
-{
- if (!isok (id))
- return PATCH_ID_INVALID;
-
- /* verify direction */
- if (mode & PATCH_PLAY_FORWARD)
- {
- if (mode & PATCH_PLAY_REVERSE)
- {
- return PATCH_PLAY_MODE_INVALID;
- }
- }
- else if (mode & PATCH_PLAY_REVERSE)
- {
- if (mode & PATCH_PLAY_FORWARD)
- {
- return PATCH_PLAY_MODE_INVALID;
- }
- }
- else
- {
- return PATCH_PLAY_MODE_INVALID;
- }
-
- /* verify duration */
- if (mode & PATCH_PLAY_SINGLESHOT)
- {
- if ((mode & PATCH_PLAY_TRIM) || (mode & PATCH_PLAY_LOOP))
- {
- return PATCH_PLAY_MODE_INVALID;
- }
- }
- else if (mode & PATCH_PLAY_TRIM)
- {
- if ((mode & PATCH_PLAY_SINGLESHOT) || (mode & PATCH_PLAY_LOOP))
- {
- return PATCH_PLAY_MODE_INVALID;
- }
- }
- else if (mode & PATCH_PLAY_LOOP)
- {
- if ((mode & PATCH_PLAY_SINGLESHOT) || (mode & PATCH_PLAY_TRIM))
- {
- return PATCH_PLAY_MODE_INVALID;
- }
- }
-
- /* make sure pingpong isn't frivolously set (just for style
- * points) */
- if ((mode & PATCH_PLAY_PINGPONG) && !(mode && PATCH_PLAY_LOOP))
- {
- return PATCH_PLAY_MODE_INVALID;
- }
-
- patches[id]->play_mode = mode;
- return 0;
-}
-
-/* set whether portamento is being used or not */
-int patch_set_portamento (int id, bool val)
-{
- if (!isok (id))
- return PATCH_ID_INVALID;
-
- patches[id]->porta = val;
- return 0;
-}
-
-/* set length of portamento slides in seconds */
-int patch_set_portamento_time (int id, float secs)
-{
- if (!isok (id))
- return PATCH_ID_INVALID;
-
- if (secs < 0.0)
- return PATCH_PARAM_INVALID;
-
- patches[id]->porta_secs = secs;
- return 0;
-}
-
-
-/* set the filter's resonance */
-int patch_set_resonance (int id, float reso)
-{
- if (!isok (id))
- return PATCH_ID_INVALID;
-
- if (reso < 0.0 || reso > 1.0)
- return PATCH_PARAM_INVALID;
-
- patches[id]->freso.val = reso;
- return 0;
-}
-
-
-/* set the upper note of a patch's range */
-int patch_set_upper_note (int id, int note)
-{
- if (!isok (id))
- return PATCH_ID_INVALID;
-
- if (note < 0 || note > 127)
- return PATCH_NOTE_INVALID;
-
- patches[id]->upper_note = note;
- return 0;
-}
-
-/* set the amplitude */
-int patch_set_amplitude (int id, float vol)
-{
-
- if (!isok (id))
- return PATCH_ID_INVALID;
-
- if (vol < 0 || vol > 1.0)
- return PATCH_VOL_INVALID;
-
- patches[id]->vol.val = vol;
- return 0;
-}
-
-/**************************************************************************/
-/************************* PARAMETER GETTERS*******************************/
-/**************************************************************************/
-
-/* get the channel the patch listens on */
-int patch_get_channel (int id)
-{
- if (!isok (id))
- return PATCH_ID_INVALID;
-
- return patches[id]->channel;
-}
-
-/* get the cut signal */
-int patch_get_cut (int id)
-{
- if (!isok (id))
- return PATCH_ID_INVALID;
-
- return patches[id]->cut;
-}
-
-/* get the cut-by signal */
-int patch_get_cut_by (int id)
-{
- if (!isok (id))
- return PATCH_ID_INVALID;
-
- return patches[id]->cut_by;
-}
-
-/* get the filter cutoff value */
-float patch_get_cutoff (int id)
-{
- if (!isok (id))
- return PATCH_ID_INVALID;
-
- return patches[id]->ffreq.val;
-}
-
-/* get the display index */
-int patch_get_display_index (int id)
-{
- if (!isok (id))
- return PATCH_ID_INVALID;
-
- return patches[id]->display_index;
-}
-
-/* get the number of frame in the sample */
-int patch_get_frames (int id)
-{
- if (!isok (id))
- return PATCH_ID_INVALID;
-
- if (patches[id]->sample->sp == NULL)
- return 0;
-
- debug("patches[%d].sample->frames:%d\n", id, patches[id]->sample->frames);
-
- return patches[id]->sample->frames;
-}
-
-/* get whether this patch is played legato or not */
-bool patch_get_legato(int id)
-{
- if (!isok (id))
- return PATCH_ID_INVALID;
-
- return patches[id]->legato;
-}
-
-
-/* get the lower note */
-int patch_get_lower_note (int id)
-{
- if (!isok (id))
- return PATCH_ID_INVALID;
-
- return patches[id]->lower_note;
-}
-
-
-int patch_get_mark_frame(int patch, int mark)
-{
- if (!isok(patch))
- return -1;
-
- if (patches[patch]->sample->sp == NULL)
- return -1;
-
- if (!mark_ok(mark))
- return -1;
-
- return get_mark_frame(patch, mark);
-}
-
-
-int patch_get_mark_frame_range(int patch, int mark, int* frame_min,
- int* frame_max)
-{
- if (!isok(patch) || !mark_ok(mark))
- return -1;
-
- return get_mark_frame_range(patch, mark, frame_min, frame_max);
-}
-
-/* get whether this patch is monophonic or not */
-bool patch_get_monophonic(int id)
-{
- if (!isok(id))
- return PATCH_ID_INVALID;
-
- return patches[id]->mono;
-}
-
-/* get the name */
-char *patch_get_name (int id)
-{
- char *name;
-
- if (!isok(id))
- name = strdup ("\0");
- else
- name = strdup (patches[id]->name);
-
- return name;
-}
-
-/* get the root note */
-int patch_get_note (int id)
-{
- if (!isok(id))
- return PATCH_ID_INVALID;
-
- return patches[id]->note;
-}
-
-/* get the panorama */
-float patch_get_panning (int id)
-{
- if (!isok(id))
- return PATCH_ID_INVALID;
-
- return patches[id]->pan.val;
-}
-
-/* get the pitch */
-float patch_get_pitch (int id)
-{
- if (!isok(id))
- return PATCH_ID_INVALID;
-
- return patches[id]->pitch.val;
-}
-
-/* get the pitch range */
-int patch_get_pitch_steps (int id)
-{
- if (!isok(id))
- return PATCH_ID_INVALID;
-
- return patches[id]->pitch_steps;
-}
-
-/* get the play mode */
-PatchPlayMode patch_get_play_mode (int id)
-{
- if (!isok(id))
- return PATCH_ID_INVALID;
-
- return patches[id]->play_mode;
-}
-
-/* get whether portamento is used or not */
-bool patch_get_portamento (int id)
-{
- if (!isok(id))
- return PATCH_ID_INVALID;
-
- return patches[id]->porta;
-}
-
-/* get length of portamento slides in seconds */
-float patch_get_portamento_time (int id)
-{
- if (!isok(id))
- return PATCH_ID_INVALID;
-
- return patches[id]->porta_secs;
-}
-
-
-/* get the filter's resonance amount */
-float patch_get_resonance (int id)
-{
- if (!isok(id))
- return PATCH_ID_INVALID;
-
- return patches[id]->freso.val;
-}
-
-/* get a pointer to the sample data */
-const float *patch_get_sample (int id)
-{
- if (!isok(id))
- return NULL;
-
- return patches[id]->sample->sp;
-}
-
-/* get the name of the sample file */
-const char *patch_get_sample_name (int id)
-{
- if (!isok(id))
- return 0;
-
- return patches[id]->sample->filename;
-}
-
-/* get the upper note */
-int patch_get_upper_note (int id)
-{
- if (!isok(id))
- return PATCH_ID_INVALID;
-
- return patches[id]->upper_note;
-}
-
-/* get the amplitude */
-float patch_get_amplitude (int id)
-{
- if (!isok(id))
- return PATCH_ID_INVALID;
-
- return patches[id]->vol.val;
-}
-
-
-int patch_get_fade_samples(int id)
-{
- if (!isok (id))
- return PATCH_ID_INVALID;
-
- return patches[id]->fade_samples;
-}
-
-
-int patch_get_xfade_samples(int id)
-{
- if (!isok(id))
- return PATCH_ID_INVALID;
-
- return patches[id]->xfade_samples;
-}
-
-
-int patch_get_max_fade_samples(int id)
-{
- return (patches[id]->play_stop - patches[id]->play_start) / 2;
-}
-
-
-int patch_get_max_xfade_samples(int id)
-{
- int min = patches[id]->sample->frames;
- int tmp;
-
- tmp = patches[id]->loop_stop - patches[id]->loop_start;
- min = (tmp < min) ? tmp : min;
-
- tmp = patches[id]->play_stop - patches[id]->loop_stop;
- min = (tmp < min) ? tmp : min;
-
- tmp = patches[id]->loop_start - patches[id]->play_start;
- min = (tmp < min) ? tmp : min;
-
-debug("max xfade samples:%d\n", min);
-
- return min;
-}
-
-
-/******************************************************************/
-/*************************** PARAM ********************************/
-/******************************************************************/
-
-int patch_param_get_value(int patch_id, PatchParamType param, float* v)
-{
- if (!isok(patch_id))
- return PATCH_ID_INVALID;
-
- switch(param)
- {
- case PATCH_PARAM_AMPLITUDE: *v = patches[patch_id]->vol.val; break;
- case PATCH_PARAM_PANNING: *v = patches[patch_id]->pan.val; break;
- case PATCH_PARAM_CUTOFF: *v = patches[patch_id]->ffreq.val; break;
- case PATCH_PARAM_RESONANCE: *v = patches[patch_id]->freso.val; break;
- case PATCH_PARAM_PITCH: *v = patches[patch_id]->pitch.val; break;
- default:
- return PATCH_PARAM_INVALID;
- }
-
- return 0;
-}
-
-
-int patch_param_set_value(int patch_id, PatchParamType param, float v)
-{
- if (!isok(patch_id))
- return PATCH_ID_INVALID;
-
- switch(param)
- {
- case PATCH_PARAM_AMPLITUDE: patches[patch_id]->vol.val = v; break;
- case PATCH_PARAM_PANNING: patches[patch_id]->pan.val = v; break;
- case PATCH_PARAM_CUTOFF: patches[patch_id]->ffreq.val = v; break;
- case PATCH_PARAM_RESONANCE: patches[patch_id]->freso.val = v; break;
- case PATCH_PARAM_PITCH: patches[patch_id]->pitch.val = v; break;
- default:
- return PATCH_PARAM_INVALID;
- }
-
- return 0;
-}
-
-
-/**************************************************************************/
-/*********************** MODULATION SETTERS *******************************/
-/**************************************************************************/
-
-int patch_set_mod_src(int patch_id, PatchParamType param, int slot, int id)
-{
- PatchParam* p;
- int err;
-
- if ((err = get_patch_param(patch_id, param, &p)) != 0)
- return err;
-
- if (slot < 0 || slot > MAX_MOD_SLOTS)
- return PATCH_MOD_SLOT_INVALID;
-
- if ((err = mod_src_ok(id)) != 0)
- return err;
-
- p->mod_id[slot] = id;
- return 0;
-}
-
-
-int
-patch_set_mod_amt(int patch_id, PatchParamType param, int slot, float amt)
-{
- PatchParam* p;
- int err;
-
- if ((err = get_patch_param(patch_id, param, &p)) != 0)
- return err;
-
- if (slot < 0 || slot > MAX_MOD_SLOTS)
- return PATCH_MOD_SLOT_INVALID;
-
- if (amt < -1.0 || amt > 1.0)
- return PATCH_MOD_AMOUNT_INVALID;
-
- p->mod_amt[slot] = amt;
-
- if (param == PATCH_PARAM_PITCH)
- {
- patches[patch_id]->mod_pitch_max[slot] =
- pow(2, (amt * PATCH_MAX_PITCH_STEPS) / 12.0);
- patches[patch_id]->mod_pitch_min[slot] =
- pow(2, -(amt * PATCH_MAX_PITCH_STEPS) / 12.0);
- }
-
- return 0;
-}
-
-
-int patch_set_vel_amount(int patch_id, PatchParamType param, float amt)
-{
- PatchParam* p;
- int err;
-
- if (!isok (patch_id))
- return PATCH_ID_INVALID;
-
- if ((err = get_patch_param(patch_id, param, &p)) < 0)
- return err;
-
- if (amt < 0.0 || amt > 1.0)
- return PATCH_PARAM_INVALID;
-
- p->vel_amt = amt;
- return 0;
-}
-
-
-int patch_set_key_amount(int patch_id, PatchParamType param, float amt)
-{
- PatchParam* p;
- int err;
-
- if (!isok (patch_id))
- return PATCH_ID_INVALID;
-
- if ((err = get_patch_param(patch_id, param, &p)) < 0)
- return err;
-
- if (amt < -1.0 || amt > 1.0)
- return PATCH_PARAM_INVALID;
-
- p->key_amt = amt;
- return 0;
-}
-
-
-/**************************************************************************/
-/********************** MODULATION GETTERS ********************************/
-/**************************************************************************/
-
-int
-patch_get_mod_src(int patch_id, PatchParamType param, int slot, int* src_id)
-{
- PatchParam* p;
- int err;
-
- if ((err = get_patch_param(patch_id, param, &p)) != 0)
- return err;
-
- if (slot < 0 || slot > MAX_MOD_SLOTS)
- return PATCH_MOD_SLOT_INVALID;
-
- *src_id = p->mod_id[slot];
-
- return 0;
-}
-
-
-int
-patch_get_mod_amt(int patch_id, PatchParamType param, int slot, float* amt)
-{
- PatchParam* p;
- int err;
-
- if ((err = get_patch_param(patch_id, param, &p)) != 0)
- return err;
-
- if (slot < 0 || slot > MAX_MOD_SLOTS)
- return PATCH_MOD_SLOT_INVALID;
-
- *amt = p->mod_amt[slot];
- return 0;
-}
-
-
-int patch_get_vel_amount (int patch_id, PatchParamType param, float* val)
-{
- PatchParam* p;
- int err;
-
- if (!isok (patch_id))
- return PATCH_ID_INVALID;
-
- if ((err = get_patch_param(patch_id, param, &p)) < 0)
- return err;
-
- *val = p->vel_amt;
- return 0;
-}
-
-
-int patch_get_key_amount (int patch_id, PatchParamType param, float* val)
-{
- PatchParam* p;
- int err;
-
- if (!isok (patch_id))
- return PATCH_ID_INVALID;
-
- if ((err = get_patch_param(patch_id, param, &p)) < 0)
- return err;
-
- *val = p->key_amt;
- return 0;
-}
-
-
-/**************************************************************************/
-/****************** LFO FREQ MODULATION SETTERS ***************************/
-/**************************************************************************/
-
-int patch_set_lfo_fm1_src(int patch_id, int lfo_id, int modsrc_id)
-{
- LFO* lfo;
- LFOParams* lfopar;
- int err;
- if ((err = lfo_from_id(patch_id, lfo_id, &lfo, &lfopar)))
- return err;
- lfopar->fm1_id = modsrc_id;
-
- if (lfo)
- patch_trigger_global_lfo(patch_id, lfo, lfopar);
-
- return 0;
-}
-
-int patch_set_lfo_fm2_src(int patch_id, int lfo_id, int modsrc_id)
-{
- LFO* lfo;
- LFOParams* lfopar;
- int err;
- if ((err = lfo_from_id(patch_id, lfo_id, &lfo, &lfopar)))
- return err;
- lfopar->fm2_id = modsrc_id;
-
- if (lfo)
- patch_trigger_global_lfo(patch_id, lfo, lfopar);
-
- return 0;
-}
-
-int patch_set_lfo_fm1_amt(int patch_id, int lfo_id, float amount)
-{
- LFO* lfo;
- LFOParams* lfopar;
- int err;
- if ((err = lfo_from_id(patch_id, lfo_id, &lfo, &lfopar)))
- return err;
- lfopar->fm1_amt = amount;
-
- if (lfo)
- patch_trigger_global_lfo(patch_id, lfo, lfopar);
-
- return 0;
-}
-
-int patch_set_lfo_fm2_amt(int patch_id, int lfo_id, float amount)
-{
- LFO* lfo;
- LFOParams* lfopar;
- int err;
- if ((err = lfo_from_id(patch_id, lfo_id, &lfo, &lfopar)))
- return err;
- lfopar->fm2_amt = amount;
-
- if (lfo)
- patch_trigger_global_lfo(patch_id, lfo, lfopar);
-
- return 0;
-}
-
-
-
-/**************************************************************************/
-/****************** LFO FREQ MODULATION GETTERS ***************************/
-/**************************************************************************/
-
-int patch_get_lfo_fm1_src(int patch_id, int lfo_id, int* modsrc_id)
-{
- LFOParams* lfopar;
- int err;
- if ((err = lfo_from_id(patch_id, lfo_id, NULL, &lfopar)))
- return err;
- *modsrc_id = lfopar->fm1_id;
- return 0;
-}
-
-int patch_get_lfo_fm2_src(int patch_id, int lfo_id, int* modsrc_id)
-{
- LFOParams* lfopar;
- int err;
- if ((err = lfo_from_id(patch_id, lfo_id, NULL, &lfopar)))
- return err;
- *modsrc_id = lfopar->fm2_id;
- return 0;
-}
-
-int patch_get_lfo_fm1_amt(int patch_id, int lfo_id, float* amount)
-{
- LFOParams* lfopar;
- int err;
- if ((err = lfo_from_id(patch_id, lfo_id, NULL, &lfopar)))
- return err;
- *amount = lfopar->fm1_amt;
- return 0;
-}
-
-int patch_get_lfo_fm2_amt(int patch_id, int lfo_id, float* amount)
-{
- LFOParams* lfopar;
- int err;
- if ((err = lfo_from_id(patch_id, lfo_id, NULL, &lfopar)))
- return err;
- *amount = lfopar->fm2_amt;
- return 0;
-}
-
-
-/**************************************************************************/
-/******************* LFO AMP MODULATION SETTERS ***************************/
-/**************************************************************************/
-
-int patch_set_lfo_am1_src(int patch_id, int lfo_id, int modsrc_id)
-{
- LFO* lfo;
- LFOParams* lfopar;
- int err;
- if ((err = lfo_from_id(patch_id, lfo_id, &lfo, &lfopar)))
- return err;
- lfopar->am1_id = modsrc_id;
-
- if (lfo)
- patch_trigger_global_lfo(patch_id, lfo, lfopar);
-
- return 0;
-}
-
-int patch_set_lfo_am2_src(int patch_id, int lfo_id, int modsrc_id)
-{
- LFO* lfo;
- LFOParams* lfopar;
- int err;
- if ((err = lfo_from_id(patch_id, lfo_id, &lfo, &lfopar)))
- return err;
- lfopar->am2_id = modsrc_id;
-
- if (lfo)
- patch_trigger_global_lfo(patch_id, lfo, lfopar);
-
- return 0;
-}
-
-int patch_set_lfo_am1_amt(int patch_id, int lfo_id, float amount)
-{
- LFO* lfo;
- LFOParams* lfopar;
- int err;
- if ((err = lfo_from_id(patch_id, lfo_id, &lfo, &lfopar)))
- return err;
- lfopar->am1_amt = amount;
-
- if (lfo)
- patch_trigger_global_lfo(patch_id, lfo, lfopar);
-
- return 0;
-}
-
-int patch_set_lfo_am2_amt(int patch_id, int lfo_id, float amount)
-{
- LFO* lfo;
- LFOParams* lfopar;
- int err;
- if ((err = lfo_from_id(patch_id, lfo_id, &lfo, &lfopar)))
- return err;
- lfopar->am2_amt = amount;
-
- if (lfo)
- patch_trigger_global_lfo(patch_id, lfo, lfopar);
-
- return 0;
-}
-
-
-
-/**************************************************************************/
-/******************* LFO AMP MODULATION GETTERS ***************************/
-/**************************************************************************/
-
-int patch_get_lfo_am1_src(int patch_id, int lfo_id, int* modsrc_id)
-{
- LFOParams* lfopar;
- int err;
- if ((err = lfo_from_id(patch_id, lfo_id, NULL, &lfopar)))
- return err;
- *modsrc_id = lfopar->am1_id;
- return 0;
-}
-
-int patch_get_lfo_am2_src(int patch_id, int lfo_id, int* modsrc_id)
-{
- LFOParams* lfopar;
- int err;
- if ((err = lfo_from_id(patch_id, lfo_id, NULL, &lfopar)))
- return err;
- *modsrc_id = lfopar->am2_id;
- return 0;
-}
-
-int patch_get_lfo_am1_amt(int patch_id, int lfo_id, float* amount)
-{
- LFOParams* lfopar;
- int err;
- if ((err = lfo_from_id(patch_id, lfo_id, NULL, &lfopar)))
- return err;
- *amount = lfopar->am1_amt;
- return 0;
-}
-
-int patch_get_lfo_am2_amt(int patch_id, int lfo_id, float* amount)
-{
- LFOParams* lfopar;
- int err;
- if ((err = lfo_from_id(patch_id, lfo_id, NULL, &lfopar)))
- return err;
- *amount = lfopar->am2_amt;
- return 0;
-}
-
-
diff --git a/src/patch_set_and_get.h b/src/patch_set_and_get.h
deleted file mode 100644
index 6fd5ae5..0000000
--- a/src/patch_set_and_get.h
+++ /dev/null
@@ -1,205 +0,0 @@
-/* Petri-Foo is a fork of the Specimen audio sampler.
-
- Original Specimen author Pete Bessman
- Copyright 2005 Pete Bessman
- Copyright 2011 James W. Morris
-
- This file is part of Petri-Foo.
-
- Petri-Foo is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation.
-
- Petri-Foo is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Petri-Foo. If not, see <http://www.gnu.org/licenses/>.
-
- This file is a derivative of a Specimen original, modified 2011
-*/
-
-
-#ifndef __PATCH_SET_AND_GET_H__
-#define __PATCH_SET_AND_GET_H__
-
-
-#include "patch.h"
-
-
-/* values to use as env_id and lfo_id are found in patch.h
- under _MOD_SRC_ID_BITMASK.
-
- to set the third envelope: env_id = MOD_SRC_EG + 3
- */
-
-/* envelope setters */
-int patch_set_env_on (int patch_id, int env_id, bool state);
-int patch_set_env_delay (int patch_id, int env_id, float secs);
-int patch_set_env_attack (int patch_id, int env_id, float secs);
-int patch_set_env_hold (int patch_id, int env_id, float secs);
-int patch_set_env_decay (int patch_id, int env_id, float secs);
-int patch_set_env_sustain (int patch_id, int env_id, float level);
-int patch_set_env_release (int patch_id, int env_id, float secs);
-int patch_set_env_key_amt (int patch_id, int env_id, float val);
-int patch_set_env_vel_amt (int patch_id, int env_id, float val);
-
-/* envelope getters */
-int patch_get_env_on (int patch_id, int env_id, bool* val);
-int patch_get_env_delay (int patch_id, int env_id, float* val);
-int patch_get_env_attack (int patch_id, int env_id, float* val);
-int patch_get_env_hold (int patch_id, int env_id, float* val);
-int patch_get_env_decay (int patch_id, int env_id, float* val);
-int patch_get_env_sustain (int patch_id, int env_id, float* val);
-int patch_get_env_release (int patch_id, int env_id, float* val);
-int patch_get_env_key_amt (int patch_id, int env_id, float* val);
-int patch_get_env_vel_amt (int patch_id, int env_id, float* val);
-
-/* lfo setters */
-int patch_set_lfo_on (int patch_id, int lfo_id, bool state);
-int patch_set_lfo_attack (int patch_id, int lfo_id, float secs);
-int patch_set_lfo_beats (int patch_id, int lfo_id, float beats);
-int patch_set_lfo_delay (int patch_id, int lfo_id, float secs);
-int patch_set_lfo_freq (int patch_id, int lfo_id, float freq);
-int patch_set_lfo_positive (int patch_id, int lfo_id, bool state);
-int patch_set_lfo_shape (int patch_id, int lfo_id, LFOShape shape);
-int patch_set_lfo_sync (int patch_id, int lfo_id, bool state);
-
-/* lfo getters */
-int patch_get_lfo_on (int patch_id, int lfo_id, bool* val);
-int patch_get_lfo_attack (int patch_id, int lfo_id, float* secs);
-int patch_get_lfo_beats (int patch_id, int lfo_id, float* val);
-int patch_get_lfo_delay (int patch_id, int lfo_id, float* secs);
-int patch_get_lfo_freq (int patch_id, int lfo_id, float* val);
-int patch_get_lfo_positive (int patch_id, int lfo_id, bool* val);
-int patch_get_lfo_shape (int patch_id, int lfo_id, LFOShape* val);
-int patch_get_lfo_sync (int patch_id, int lfo_id, bool* val);
-
-/* parameter setters */
-int patch_set_channel (int id, int channel);
-int patch_set_cut (int id, int cut);
-int patch_set_cut_by (int id, int cut_by);
-int patch_set_cutoff (int id, float freq);
-int patch_set_legato (int id, bool val);
-int patch_set_lower_note (int id, int note);
-
-/* both of these return mark_id on success */
-int patch_set_mark_frame (int patch_id, int mark_id, int frame);
-
-/* returns mark_id on sucessful setting, if another mark required
- moving to accomodate the set mark, the id of the moved mark will
- be set via also_changed which is otherwise -1.
- */
-int patch_set_mark_frame_expand(int patch_id, int mark_id, int frame,
- int* also_changed);
-
-int patch_set_monophonic (int id, bool val);
-int patch_set_name (int id, const char* name);
-int patch_set_note (int id, int note);
-int patch_set_panning (int id, float pan);
-int patch_set_pitch (int id, float pitch);
-int patch_set_pitch_steps (int id, int steps);
-int patch_set_play_mode (int id, PatchPlayMode mode);
-int patch_set_portamento (int id, bool val);
-int patch_set_portamento_time(int id, float secs);
-int patch_set_range (int id, bool range);
-int patch_set_resonance (int id, float reso);
-
-int patch_set_upper_note (int id, int note);
-int patch_set_amplitude (int id, float vol);
-
-int patch_set_fade_samples (int id, int samples);
-int patch_set_xfade_samples(int id, int samples);
-
-/* parameter getters */
-int patch_get_channel (int id);
-int patch_get_cut (int id);
-int patch_get_cut_by (int id);
-float patch_get_cutoff (int id);
-int patch_get_display_index (int id);
-int patch_get_frames (int id);
-bool patch_get_legato (int id);
-int patch_get_lower_note (int id);
-
-int patch_get_mark_frame (int patch_id, int mark_id);
-int patch_get_mark_frame_range(int patch_id, int mark_id,
- int* frame_min,
- int* frame_max);
-
-bool patch_get_monophonic (int id);
-char* patch_get_name (int id);
-int patch_get_note (int id);
-float patch_get_panning (int id);
-float patch_get_pitch (int id);
-int patch_get_pitch_steps (int id);
-PatchPlayMode patch_get_play_mode (int id);
-bool patch_get_portamento (int id);
-float patch_get_portamento_time(int id);
-
-/* still don't get the point of this:
-bool patch_get_range (int id);
- seems to be TRUE when lower != upper.
- */
-
-float patch_get_resonance (int id);
-const float* patch_get_sample (int id);
-const char* patch_get_sample_name (int id);
-int patch_get_upper_note (int id);
-float patch_get_amplitude (int id);
-int patch_get_fade_samples (int id);
-int patch_get_xfade_samples (int id);
-int patch_get_max_fade_samples(int id);
-int patch_get_max_xfade_samples(int id);
-
-
-/* returns 0 if non-raw sample loaded */
-int patch_get_raw_samplerate(int id);
-int patch_get_raw_channels(int id);
-int patch_get_raw_sndfile_format(int id);
-
-
-/* param */
-int patch_param_get_value(int patch_id, PatchParamType, float* val);
-int patch_param_set_value(int patch_id, PatchParamType, float val);
-
-/* modulation setters */
-int patch_set_mod_src(int patch_id, PatchParamType, int slot, int src_id);
-int patch_set_mod_amt(int patch_id, PatchParamType, int slot, float amt);
-int patch_set_vel_amount(int id, PatchParamType param, float amt);
-int patch_set_key_amount(int id, PatchParamType param, float amt);
-
-/* modulation getters */
-int patch_get_mod_src(int patch_id, PatchParamType, int slot, int* src_id);
-int patch_get_mod_amt(int patch_id, PatchParamType, int slot, float* amt);
-int patch_get_vel_amount(int id, PatchParamType param, float* val);
-int patch_get_key_amount(int id, PatchParamType param, float* val);
-
-/* lfo freq modulation setters */
-int patch_set_lfo_fm1_src(int patch_id, int lfo_id, int modsrc_id);
-int patch_set_lfo_fm2_src(int patch_id, int lfo_id, int modsrc_id);
-int patch_set_lfo_fm1_amt(int patch_id, int lfo_id, float amount);
-int patch_set_lfo_fm2_amt(int patch_id, int lfo_id, float amount);
-
-/* lfo freq modulation getters */
-int patch_get_lfo_fm1_src(int patch_id, int lfo_id, int* modsrc_id);
-int patch_get_lfo_fm2_src(int patch_id, int lfo_id, int* modsrc_id);
-int patch_get_lfo_fm1_amt(int patch_id, int lfo_id, float* amount);
-int patch_get_lfo_fm2_amt(int patch_id, int lfo_id, float* amount);
-
-/* lfo amp modulation setters */
-int patch_set_lfo_am1_src(int patch_id, int lfo_id, int modsrc_id);
-int patch_set_lfo_am2_src(int patch_id, int lfo_id, int modsrc_id);
-int patch_set_lfo_am1_amt(int patch_id, int lfo_id, float amount);
-int patch_set_lfo_am2_amt(int patch_id, int lfo_id, float amount);
-
-/* lfo amp modulation getters */
-int patch_get_lfo_am1_src(int patch_id, int lfo_id, int* modsrc_id);
-int patch_get_lfo_am2_src(int patch_id, int lfo_id, int* modsrc_id);
-int patch_get_lfo_am1_amt(int patch_id, int lfo_id, float* amount);
-int patch_get_lfo_am2_amt(int patch_id, int lfo_id, float* amount);
-
-
-
-#endif /* __PATCH_SET_AND_GET_H__ */
--
petri-foo packaging
More information about the pkg-multimedia-commits
mailing list