pax_global_header00006660000000000000000000000064131576541610014523gustar00rootroot0000000000000052 comment=53337c388f326352bf8293a5cf0df56891dea2fb wildmidi-wildmidi-0.4.2/000077500000000000000000000000001315765416100151305ustar00rootroot00000000000000wildmidi-wildmidi-0.4.2/.chklist000066400000000000000000000004141315765416100165710ustar00rootroot00000000000000Edit files for version number (and possibly other changes) : - djgpp/config.h - os2/config.h - amiga/config.h - android/jni/config.h Edit files for possibly other changes: - djgpp/Makefile - os2/makefile - amiga/Makefile* - amiga/*.cfg - android/* - android/jni/*.mk wildmidi-wildmidi-0.4.2/.gitignore000066400000000000000000000004411315765416100171170ustar00rootroot00000000000000# compiled objects # *.o *.so *.dll # logs and other texts # *.log # OS generated files # .DS_Store .DS_Store? ._* .Spotlight-V100 .Trashes Icon? ehthumbs.db Thumbs.db # Eclipse .cproject .preferences.xml .project .settings/ # CLion .idea/ # config files include/config.h wildmidi.pc wildmidi-wildmidi-0.4.2/.travis.yml000066400000000000000000000016021315765416100172400ustar00rootroot00000000000000os: - linux - osx osx_image: xcode8.3 dist: trusty sudo: required language: c env: - BUILD_TYPE=Debug - BUILD_TYPE=Release matrix: include: - os: linux env: ANALYZE="scan-build-3.6 --use-cc clang-3.6 --use-c++ clang++-3.6 " compiler: clang branches: only: - master - coverity_scan - /wildmidi-.*$/ before_install: - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./CI/before_install.linux.sh; fi - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then ./CI/before_install.osx.sh; fi before_script: - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./CI/before_script.linux.sh; fi - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then ./CI/before_script.osx.sh; fi script: - cd ./build - if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then ${ANALYZE}make -j3; fi notifications: irc: channels: - "chat.freenode.net#wildmidi" on_success: change on_failure: always wildmidi-wildmidi-0.4.2/CI/000077500000000000000000000000001315765416100154235ustar00rootroot00000000000000wildmidi-wildmidi-0.4.2/CI/before_install.linux.sh000077500000000000000000000015061315765416100221120ustar00rootroot00000000000000#!/bin/sh if [ "${ANALYZE}" ]; then echo "yes" | sudo add-apt-repository "deb http://llvm.org/apt/`lsb_release -sc`/ llvm-toolchain-`lsb_release -sc`-3.6 main" wget -O - http://llvm.org/apt/llvm-snapshot.gpg.key|sudo apt-key add - fi echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse" echo "yes" | sudo apt-add-repository ppa:psi29a/`lsb_release -sc` sudo apt-get update -qq sudo apt-get install -qq libgtest-dev google-mock sudo apt-get install -qq libopenal-dev if [ "${ANALYZE}" ]; then sudo apt-get install -qq clang-3.6; fi sudo mkdir /usr/src/gtest/build cd /usr/src/gtest/build sudo cmake .. sudo make -j4 sudo ln -s /usr/src/gtest/build/libgtest.so /usr/lib/libgtest.so sudo ln -s /usr/src/gtest/build/libgtest_main.so /usr/lib/libgtest_main.so wildmidi-wildmidi-0.4.2/CI/before_install.osx.sh000077500000000000000000000001631315765416100215620ustar00rootroot00000000000000#!/bin/sh brew update brew outdated cmake || brew upgrade cmake brew outdated pkgconfig || brew upgrade pkgconfig wildmidi-wildmidi-0.4.2/CI/before_script.linux.sh000077500000000000000000000004251315765416100217470ustar00rootroot00000000000000#!/bin/sh free -m mkdir build cd build export CODE_COVERAGE=1 if [ "${CC}" = "clang" ]; then export CODE_COVERAGE=0; fi ${ANALYZE}cmake .. -DBUILD_WITH_CODE_COVERAGE=${CODE_COVERAGE} -DBUILD_UNITTESTS=1 -DCMAKE_INSTALL_PREFIX=/usr -DBINDIR=/usr/bin -DCMAKE_BUILD_TYPE="None" wildmidi-wildmidi-0.4.2/CI/before_script.msvc.sh000066400000000000000000000126321315765416100215600ustar00rootroot00000000000000#!/bin/bash while [ $# -gt 0 ]; do ARGSTR=$1 shift if [ ${ARGSTR:0:1} != "-" ]; then echo "Unknown argument $ARGSTR" echo "Try '$0 -h'" exit 1 fi for (( i=1; i<${#ARGSTR}; i++ )); do ARG=${ARGSTR:$i:1} case $ARG in V ) VERBOSE=true ;; v ) VS_VERSION=$1 shift ;; d ) SKIP_DOWNLOAD=true ;; e ) SKIP_EXTRACT=true ;; k ) KEEP=true ;; u ) UNITY_BUILD=true ;; p ) PLATFORM=$1 shift ;; c ) CONFIGURATION=$1 shift ;; h ) cat < Set the configuration, can also be set with environment variable CONFIGURATION. -d Skip checking the downloads. -e Skip extracting dependencies. -h Show this message. -k Keep the old build directory, default is to delete it. -p Set the build platform, can also be set with environment variable PLATFORM. -u Configure for unity builds. -v <2013/2015> Choose the Visual Studio version to use. -V Run verbosely EOF exit 0 ;; * ) echo "Unknown argument $ARG." echo "Try '$0 -h'" exit 1 ;; esac done done if [ -z $VERBOSE ]; then STRIP="> /dev/null 2>&1" fi if [ -z $VS_VERSION ]; then VS_VERSION="2013" fi if [ -z $APPVEYOR ]; then echo "Running prebuild outside of Appveyor." DIR=$(echo "$0" | sed "s,\\\\,/,g" | sed "s,\(.\):,/\\1,") cd $(dirname "$DIR")/.. else echo "Running prebuild in Appveyor." cd $APPVEYOR_BUILD_FOLDER VERSION="$(cat README.md | grep Version: | awk '{ print $3; }')-$(git rev-parse --short HEAD)" appveyor UpdateBuild -Version "$VERSION" > /dev/null & fi run_cmd() { CMD="$1" shift if [ -z $VERBOSE ]; then eval $CMD $@ > output.log 2>&1 RET=$? if [ $RET -ne 0 ]; then if [ -z $APPVEYOR ]; then echo "Command $CMD failed, output can be found in `real_pwd`/output.log" else echo echo "Command $CMD failed;" cat output.log fi else rm output.log fi return $RET else eval $CMD $@ return $? fi } download() { if [ $# -lt 3 ]; then echo "Invalid parameters to download." return 1 fi NAME=$1 shift echo "$NAME..." while [ $# -gt 1 ]; do URL=$1 FILE=$2 shift shift if ! [ -f $FILE ]; then printf " Downloading $FILE... " if [ -z $VERBOSE ]; then curl --silent --retry 10 -kLy 5 -o $FILE $URL RET=$? else curl --retry 10 -kLy 5 -o $FILE $URL RET=$? fi if [ $RET -ne 0 ]; then echo "Failed!" else echo "Done." fi else echo " $FILE exists, skipping." fi done if [ $# -ne 0 ]; then echo "Missing parameter." fi } real_pwd() { pwd | sed "s,/\(.\),\1:," } CMAKE_OPTS="" add_cmake_opts() { CMAKE_OPTS="$CMAKE_OPTS $@" } RUNTIME_DLLS="" add_runtime_dlls() { RUNTIME_DLLS="$RUNTIME_DLLS $@" } OSG_PLUGINS="" add_osg_dlls() { OSG_PLUGINS="$OSG_PLUGINS $@" } if [ -z $PLATFORM ]; then PLATFORM=`uname -m` fi if [ -z $CONFIGURATION ]; then CONFIGURATION="Debug" fi case $VS_VERSION in 14|2015 ) GENERATOR="Visual Studio 14 2015" XP_TOOLSET="v140_xp" ;; # 12|2013| * ) GENERATOR="Visual Studio 12 2013" XP_TOOLSET="v120_xp" ;; esac case $PLATFORM in x64|x86_64|x86-64|win64|Win64 ) ARCHNAME=x86-64 ARCHSUFFIX=64 BITS=64 BASE_OPTS="-G\"$GENERATOR Win64\"" add_cmake_opts "-G\"$GENERATOR Win64\"" ;; x32|x86|i686|i386|win32|Win32 ) ARCHNAME=x86 ARCHSUFFIX=86 BITS=32 BASE_OPTS="-G\"$GENERATOR\" -T$XP_TOOLSET" add_cmake_opts "-G\"$GENERATOR\"" -T$XP_TOOLSET ;; * ) echo "Unknown platform $PLATFORM." exit 1 ;; esac case $CONFIGURATION in debug|Debug|DEBUG ) CONFIGURATION=Debug ;; release|Release|RELEASE ) CONFIGURATION=Release ;; relwithdebinfo|RelWithDebInfo|RELWITHDEBINFO ) CONFIGURATION=RelWithDebInfo ;; esac echo echo "==========================" echo "Starting prebuild on win$BITS" echo "==========================" echo mkdir -p deps cd deps DEPS="`pwd`" if [ -z $SKIP_DOWNLOAD ]; then echo "Downloading dependency packages." echo # OpenAL download "OpenAL-Soft 1.16.0" \ http://kcat.strangesoft.net/openal-binaries/openal-soft-1.16.0-bin.zip \ OpenAL-Soft-1.16.0.zip fi cd .. #/.. # Set up dependencies if [ -z $KEEP ]; then echo printf "Preparing build directory... " rm -rf Build_$BITS mkdir -p Build_$BITS/deps echo Done. fi mkdir -p Build_$BITS/deps cd Build_$BITS/deps DEPS_INSTALL=`pwd` cd $DEPS echo echo "Extracting dependencies..." # OpenAL printf "OpenAL-Soft 1.16.0... " { if [ -d openal-soft-1.16.0-bin ]; then printf "Exists. " elif [ -z $SKIP_EXTRACT ]; then rm -rf openal-soft-1.16.0-bin eval 7z x -y OpenAL-Soft-1.16.0.zip $STRIP fi OPENAL_SDK="`real_pwd`/openal-soft-1.16.0-bin" add_cmake_opts -DOPENAL_INCLUDE_DIR="$OPENAL_SDK/include/AL" \ -DOPENAL_LIBRARY="$OPENAL_SDK/libs/Win$BITS/OpenAL32.lib" echo Done. } cd $DEPS_INSTALL/.. echo echo "Setting up WildMIDI build..." if [ -z $VERBOSE ]; then printf " Configuring... " else echo " cmake .. $CMAKE_OPTS" fi run_cmd cmake .. $CMAKE_OPTS RET=$? if [ -z $VERBOSE ]; then if [ $RET -eq 0 ]; then echo Done. else echo Failed.; fi fi echo # NOTE: Disable this when/if we want to run test cases if [ -z $CI ]; then echo "Copying Runtime DLLs..." mkdir -p $CONFIGURATION for DLL in $RUNTIME_DLLS; do echo " `basename $DLL`." cp "$DLL" $CONFIGURATION/ done echo "Copying Runtime Resources/Config Files" echo " wildmidi.cfg" cp $CONFIGURATION/../cfg/wildmidi.cfg $CONFIGURATION/wildmidi.cfg fi exit $RET wildmidi-wildmidi-0.4.2/CI/before_script.osx.sh000077500000000000000000000005721315765416100214240ustar00rootroot00000000000000#!/bin/sh export CXX=clang++ export CC=clang DEPENDENCIES_ROOT="/private/tmp/wildmidi-deps/wildmidi-deps" mkdir build cd build cmake \ -D CMAKE_EXE_LINKER_FLAGS="-lz" \ -D CMAKE_PREFIX_PATH="$DEPENDENCIES_ROOT" \ -D CMAKE_OSX_DEPLOYMENT_TARGET="10.9" \ -D CMAKE_OSX_SYSROOT="macosx10.12" \ -D CMAKE_BUILD_TYPE=Release \ -D WANT_OSX_DEPLOYMENT=TRUE \ -G"Unix Makefiles" \ .. wildmidi-wildmidi-0.4.2/CI/build.msvc.sh000066400000000000000000000020371315765416100200270ustar00rootroot00000000000000#!/bin/bash if [ -z $PLATFORM ]; then PLATFORM=`uname -m` fi if [ -z $CONFIGURATION ]; then CONFIGURATION="Debug" fi case $PLATFORM in x32|x86|i686|i386|win32|Win32 ) BITS=32 PLATFORM=Win32 ;; x64|x86_64|x86-64|win64|Win64 ) BITS=64 PLATFORM=x64 ;; * ) echo "Unknown platform $PLATFORM." exit 1 ;; esac if [ -z $APPVEYOR ]; then echo "Running $BITS-bit $CONFIGURATION build outside of Appveyor." DIR=$(echo "$0" | sed "s,\\\\,/,g" | sed "s,\(.\):,/\\1,") cd $(dirname "$DIR")/.. else echo "Running $BITS-bit $CONFIGURATION build in Appveyor." cd $APPVEYOR_BUILD_FOLDER fi cd build_$BITS which msbuild > /dev/null if [ $? -ne 0 ]; then msbuild() { /c/Program\ Files\ \(x86\)/MSBuild/12.0/Bin/MSBuild.exe "$@" } fi if [ -z $APPVEYOR ]; then msbuild WildMIDI.sln //t:Build //m:8 else msbuild WildMIDI.sln //t:Build //m:8 //logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" fi RET=$? if [ $RET -eq 0 ] && [ ! -z $PACKAGE ]; then msbuild PACKAGE.vcxproj //t:Build //m:8 RET=$? fi exit $RET wildmidi-wildmidi-0.4.2/CMakeLists.txt000066400000000000000000000217111315765416100176720ustar00rootroot00000000000000# ########## Project setup ########## PROJECT(wildmidi C) CMAKE_MINIMUM_REQUIRED(VERSION 2.8.11) # WildMIDI Version SET(VERSION_MAJOR 0) SET(VERSION_MINOR 4) SET(VERSION_RELEASE 2) SET(WILDMIDI_VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_RELEASE}") # Lib Versions SET(SOVERSION 2) SET(VERSION 2.0.1) # Find Macros SET(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake) INCLUDE(CMakeDependentOption) INCLUDE(CheckCCompilerFlag) INCLUDE(CheckCSourceCompiles) INCLUDE(CheckIncludeFile) INCLUDE(TestBigEndian) # Set a default build type if none was specified IF (NOT DEFINED CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE STREQUAL "") MESSAGE(STATUS "Setting build type to 'Debug' as none was specified.") SET(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build." FORCE) # Set the possible values of build type for cmake-gui SET_PROPERTY(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") ENDIF () SET(CMAKE_CONFIGURATION_TYPES "${CMAKE_BUILD_TYPE}") MESSAGE(STATUS "Build Type: ${CMAKE_BUILD_TYPE}") # Set our optoins OPTION(BUILD_SHARED_LIBS "Build a dynamic wildmidi library" ON) OPTION(WANT_PLAYER "Build WildMIDI player in addition to the libraries" ON) OPTION(WANT_STATIC "Build static library in addition to dynamic library" OFF) CMAKE_DEPENDENT_OPTION(WANT_PLAYERSTATIC "Build a statically linked WildMIDI player" ON "WANT_STATIC;WANT_PLAYER" OFF) OPTION(WANT_ALSA "Include ALSA (Advanced Linux Sound Architecture) support" OFF) OPTION(WANT_OSS "Include OSS (Open Sound System) support" OFF) OPTION(WANT_OPENAL "Include OpenAL suport (Cross Platform) support" OFF) OPTION(WANT_DEVTEST "Build WildMIDI DevTest file to check files" OFF) OPTION(WANT_OSX_DEPLOYMENT "OSX Deployment" OFF) IF (WIN32 AND MSVC) OPTION(WANT_MP_BUILD "Build with Multiple Processes (/MP)" OFF) ENDIF () IF (UNIX AND NOT APPLE) SET(WILDMIDI_CFG "/etc/wildmidi/wildmidi.cfg" CACHE STRING "default config location") ELSE () SET(WILDMIDI_CFG "wildmidi.cfg" CACHE STRING "default config location") ENDIF () IF ((NOT BUILD_SHARED_LIBS) AND (NOT WANT_STATIC)) MESSAGE(FATAL_ERROR "Neither dynamic nor static library build is selected.") ENDIF () # Platform specific defines IF (UNIX) # allow 'large' files in 32 bit builds ADD_DEFINITIONS( -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGE_FILES ) ENDIF (UNIX) IF (OPENBSD) # Set RPATH for OpenBSD so WildMIDI can find libWildMidi.so # use, i.e. don't skip the full RPATH for the build tree SET(CMAKE_SKIP_BUILD_RPATH FALSE) # when building, don't use the install RPATH already # (but later on when installing) SET(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") # add the automatically determined parts of the RPATH # which point to directories outside the build tree to the install RPATH SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) # the RPATH to be used when installing, but only if it's not a system directory LIST(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/lib" isSystemDir) IF ("${isSystemDir}" STREQUAL "-1") SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") ENDIF () ENDIF (OPENBSD) IF (WIN32) ADD_DEFINITIONS( -DNOMINMAX -DWIN32_LEAN_AND_MEAN -D_CRT_SECURE_NO_WARNINGS ) ENDIF (WIN32) # Compiler specific settings IF (CMAKE_COMPILER_IS_GNUCC OR (CMAKE_C_COMPILER_ID MATCHES "Clang")) ADD_DEFINITIONS( -Wall -W -fno-common ) IF (NOT WIN32 AND NOT CYGWIN) SET(OLD_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}") SET(CMAKE_REQUIRED_FLAGS "${OLD_REQUIRED_FLAGS} -Werror") CHECK_C_SOURCE_COMPILES("int foo(void) __attribute__((visibility(\"default\"))); int main(void) {return 0;}" HAVE_VISIBILITY_DEFAULT) IF (HAVE_VISIBILITY_DEFAULT) CHECK_C_COMPILER_FLAG(-fvisibility=hidden HAVE_VISIBILITY_HIDDEN) ENDIF () SET(CMAKE_REQUIRED_FLAGS "${OLD_REQUIRED_FLAGS}") ENDIF () IF (CMAKE_BUILD_TYPE STREQUAL "Debug") ADD_DEFINITIONS(-ggdb3 -O0) ELSEIF (CMAKE_BUILD_TYPE STREQUAL "Release") ADD_DEFINITIONS(-O3) ENDIF (CMAKE_BUILD_TYPE STREQUAL "Debug") ENDIF () IF (CMAKE_C_COMPILER_ID MATCHES "SunPro") SET(OLD_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}") SET(CMAKE_REQUIRED_FLAGS "${OLD_REQUIRED_FLAGS} -xldscope=hidden") # __SUNPRO_C >= 0x590 # CHECK_C_SOURCE_COMPILES("int foo(void) __attribute__((visibility(\"default\"))); # int main(void) {return 0;}" HAVE_VISIBILITY_DEFAULT) # __SUNPRO_C >= 0x550 CHECK_C_SOURCE_COMPILES("__global int foo(void); int main(void) {return 0;}" HAVE_LDSCOPE_GLOBAL) IF (HAVE_LDSCOPE_GLOBAL)# OR HAVE_VISIBILITY_DEFAULT SET(HAVE_LDSCOPE_HIDDEN 1) ENDIF () SET(CMAKE_REQUIRED_FLAGS "${OLD_REQUIRED_FLAGS}") ENDIF () CHECK_C_SOURCE_COMPILES("int main(void) {__builtin_expect(0,0); return 0;}" HAVE___BUILTIN_EXPECT) CHECK_C_SOURCE_COMPILES("static inline int static_foo() {return 0;} int main(void) {return 0;}" HAVE_C_INLINE) CHECK_C_SOURCE_COMPILES("static __inline__ int static_foo() {return 0;} int main(void) {return 0;}" HAVE_C___INLINE__) CHECK_C_SOURCE_COMPILES("static __inline int static_foo() {return 0;} int main(void) {return 0;}" HAVE_C___INLINE) CHECK_INCLUDE_FILE(stdint.h HAVE_STDINT_H) CHECK_INCLUDE_FILE(inttypes.h HAVE_INTTYPES_H) TEST_BIG_ENDIAN(WORDS_BIGENDIAN) SET(AUDIODRV_ALSA) SET(AUDIODRV_OSS) SET(AUDIODRV_OPENAL) # UNIX-like environments IF (UNIX AND NOT APPLE) # Go looking for available sound packages for WildMIDI player IF (WANT_PLAYER) FIND_PACKAGE(ALSA) FIND_PACKAGE(OpenAL) FIND_PACKAGE(OSS) # Set preferred output IF (WANT_ALSA) IF (NOT ALSA_FOUND) MESSAGE(FATAL_ERROR "ALSA required but not found.") ENDIF () SET(AUDIODRV_ALSA 1) SET(AUDIO_LIBRARY ${ALSA_LIBRARY}) ELSEIF (WANT_OSS) IF (NOT OSS_FOUND) MESSAGE(FATAL_ERROR "OSS required but not found.") ENDIF () # no special header paths SET(AUDIODRV_OSS 1) SET(AUDIO_LIBRARY ${OSS_LIBRARY}) ELSEIF (WANT_OPENAL) IF (NOT OPENAL_FOUND) MESSAGE(FATAL_ERROR "OpenAL required but not found.") ENDIF () SET(AUDIODRV_OPENAL 1) SET(AUDIO_LIBRARY ${OPENAL_LIBRARY}) ELSE () # Try to auto-detect IF (ALSA_FOUND) SET(AUDIO_LIBRARY ${ALSA_LIBRARY}) SET(AUDIODRV_ALSA 1) ELSEIF (OSS_FOUND) # no special header paths SET(AUDIO_LIBRARY ${OSS_LIBRARY}) SET(AUDIODRV_OSS 1) ELSEIF (OPENAL_FOUND) SET(AUDIO_LIBRARY ${OPENAL_LIBRARY}) SET(AUDIODRV_OPENAL 1) ELSE () MESSAGE(WARNING "Could not find an audio sub-system!") SET(AUDIO_LIBRARY "") ENDIF () ENDIF () ENDIF () # find our math lib FIND_LIBRARY(M_LIBRARY m REQUIRED) ## Debian and non debian Linux building IF (DPKG_PROGRAM) ## Debian specific ELSE () ## Non debian specific ENDIF () ENDIF (UNIX AND NOT APPLE) IF (APPLE AND WANT_PLAYER) FIND_PACKAGE(OpenAL) IF (WANT_OPENAL) IF (NOT OPENAL_FOUND) MESSAGE(FATAL_ERROR "OpenAL required but not found.") ENDIF () SET(AUDIO_LIBRARY ${OPENAL_LIBRARY}) ELSE () IF (OPENAL_FOUND) SET(AUDIO_LIBRARY ${OPENAL_LIBRARY}) SET(AUDIODRV_OPENAL 1) ELSE () MESSAGE(WARNING "Could not find an audio sub-system!") SET(AUDIO_LIBRARY "") ENDIF () ENDIF () ENDIF () IF (WIN32) IF (WANT_PLAYER) LINK_LIBRARIES(winmm) ENDIF () ENDIF (WIN32) # ######### General setup ########## INCLUDE_DIRECTORIES(BEFORE "${CMAKE_SOURCE_DIR}/include") FILE(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/include") INCLUDE_DIRECTORIES(BEFORE "${CMAKE_BINARY_DIR}/include") IF (NOT HAVE_STDINT_H) # AND NOT HAVE_INTTYPES_H INCLUDE_DIRECTORIES(BEFORE "${CMAKE_SOURCE_DIR}/include/stdint") ENDIF () IF (AMIGA OR AROS) SET(WILDMIDI_AMIGA 1) ENDIF () IF (APPLE) SET(APP_BUNDLE_NAME "${CMAKE_PROJECT_NAME}.app") SET(APP_BUNDLE_DIR "${wildmidi_BINARY_DIR}/${APP_BUNDLE_NAME}") IF (WANT_OSX_DEPLOYMENT) SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) ENDIF () ENDIF (APPLE) IF (APPLE) SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${APP_BUNDLE_DIR}/Contents/MacOS") ELSE (APPLE) SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${wildmidi_BINARY_DIR}") ENDIF (APPLE) # Setup up our config file CONFIGURE_FILE("${CMAKE_SOURCE_DIR}/include/config.h.cmake" "${CMAKE_BINARY_DIR}/include/config.h") ADD_SUBDIRECTORY(src) wildmidi-wildmidi-0.4.2/COPYING000066400000000000000000000001341315765416100161610ustar00rootroot00000000000000For the player see docs/license/GPLv3.txt For the library see docs/license/LGPLv3.txt wildmidi-wildmidi-0.4.2/README.md000066400000000000000000000141761315765416100164200ustar00rootroot00000000000000WildMIDI is a simple software midi player which has a core softsynth library that can be use with other applications. The WildMIDI library uses Gravis Ultrasound patch files to convert MIDI files into audio which is then passed back to the calling application. The library API is designed so that it is easy to include WildMIDI into applications that wish to include MIDI file playback. Version: 0.4.2 Licenses: GPLv3+ and LGPLv3 Website: http://www.mindwerks.net/projects/wildmidi PLATFORMS: * Linux: Arch, Debian, Fedora, Ubuntu (player: ALSA, OSS, OpenAL output) * Windows: x86 and x64 * OSX: x86, x64 and powerpc (in Xterm. player: OpenAL output) * BSD: Debian, FreeBSD, NetBSD, OpenBSD. (player: OSS output) * kFreeBSD: Debian (player: OSS output) * Hurd: Debian * DOS (player: sound blaster or compatibles output.) * OS/2 (player: Dart output.) * AmigaOS & variants like MorphOS, AROS. (player: AHI output) BUILD FROM SOURCE: Requirements: * git * cmake * GCC or clang / Xcode / VisualStudio / MinGW or MinGW-w64 * DOS port: DJGPP / GNU make * OS/2 port: OpenWatcom (tested with version 1.9) * Nintendo 3DS port: devkitARM * Nintendo Wii port: devkitPPC CHANGELOG 0.4.2 * Fixed CVE-2017-11661, CVE-2017-11662, CVE-2017-11663, CVE-2017-11664 (Bug #175). * Fixed WildMidi_Open() might read beyond buffer with too short inputs (Bug #178). * Fixed a buffer overflow during playback with malformed midi files (Bug #180). * GUS patch processing changes to meet users expectations (Bug #132). * Worked around a build failure with newer FreeBSD versions failing to retrieve the ONLCR constant (Bug #171). * Fixed a minor Windows unicode issue (PR #170). * A few other fixes / clean-ups. 0.4.1 * Fixed bug in handling of the "source" directive in config files. * Fixed a nasty bug in dBm_pan_volume. Other fixes and clean-ups. * Build system updates. Install a pkg-config file on supported platforms such as Linux. New android ndk makefile. * File i/o updates. * Support for OS/2. * Support for Nintendo 3DS * Support for Nintendo Wii * Support for AmigaOS and its variants like MorphOS and AROS. 0.4.0 * API change: The library now returns audio data in host-endian format, not little-endian. * API change: WildMidi_GetVersion() added to the api, along with new numeric version macros in the wildmidi_lib.h header. the dso version is changed from 1 to 2. * API change: All long or unsigned long type _WM_Info fields changed into strictly 32bit fields (int32_t or uint32_t.) * API change: WildMidi_OpenBuffer() and WildMidi_GetOutput() changed to accept strictly 32bit size parameters, i.e. uint32_t, instead of unsigned long. * API change: WildMidi_ConvertToMidi() and WildMidi_ConvertBufferToMidi() added for MIDI-like files to be converted to MIDI. * API change: WildMidi_SetCvtOption() added to support conversion options. * API change: WildMidi_SongSeek() added to support Type 2 MIDI files. * API change: WildMidi_GetLyric() added to support embedded text, such as KAR files. * API change: WildMidi_GetError() and WildMidi_ClearError() added to cleanly check for, retrieve and clear error messages. They no longer go to stderr. * Support for loading XMI (XMIDI format) and XFM files, such as from Arena. Thanks Ryan Nunn for releasing his code under the LGPL. * Support for loading MUS (MUS Id format) files, such as from Doom. * Support for loading HMP/HMI files, such as from Daggerfall. * Support for loading KAR (MIDI with Lyrics) and Type 2 MIDI files. * Build requires cmake-2.8.11 or newer now. 0.3.9 * Library: Fixed a segmentation fault with bad midi files. 0.3.8 * Library: Fixed a seek-to-0 bug in order to cure an issue of truncated start (bug #100, gnome/gstreamer bug #694811.) * Player, OpenAL: reduced buffers from 8 to 4 so as to cure some output delay issues (bug #85.) 0.3.7 * Plug a memory leak in case of broken midis. * Properly reset global state upon library shutdown. * Support for type-2 midi files. * Fix a possible crash in WildMidi_SetOption. * DOS port: Support for Sound Blaster output in player. * Uglify the library's private global variable and function names. * Build: Add option for a statically linked player. * Build: Add headers to project files. Use -fno-common flag. * Other small fixes/clean-ups. 0.3.6 * Fix some portability issues. * Fix a double-free issue during library shutdown when several midis were alive. * Fix the invalid option checking in WildMidi_Init(). * Fix the roundtempo option which had been broken since its invention in 0.2.3.5 (WM_MO_ROUNDTEMPO: was 0xA000 instead of 0x2000.) * Fix cfg files without a newline at the end weren't parsed correctly. * Handle cfg files with mac line-endings. * Refuse loading suspiciously long files. 0.3.5 * Greatly reduced the heap usage (was a regression introduced in 0.2.3) * OpenAL support: Fixed audio output on big-endian systems. Fixed audio skips at song start. * OSS support: No longer uses mmap mode for better compatibility. This gains us NetBSD and OpenBSD support. * Worked around an invalid memory read found by valgrind when playing Beethoven's Fur Elise.rmi at 44100 Hz using the old MIDIA patch-set from 1994. * Build fixes for MSVC. Revised visibility attributes usage. 0.3.4 * OpenAL support: This gains us OSX and other platforms that OpenAL supports for sound output! * DOS (DJGPP) support: This goes a long way to helping other DOS based applications. * MinGW support: This gains us win32 and win64 support using this toolchain. * OSS fixes. * Add missing parts of the absolute paths fix in config parsing. * New portable file and path-name system to handle cross-platform support. * Support for Debian/kFreeBSD, Debian/Hurd and other Debian archs. * Many bug fixes, code clean-ups and cosmetic fixes. 0.3.3 * default to hidden visibility and only export our API functions * windows lean and mean to help compile times on Windows * cli and xcode work now on OSX * better FreeBSD support * Supported platforms are Debian, FreeBSD, Windows and OSX (but only for WAV output) 0.3.1 - 0.3.2 * Cmake updates/fixes/cleanups. 0.3.0 * initial CMake support. * process non-registered params. fix issue of notes ending before attack envelope completed. (sf.net svn r149/r151.) wildmidi-wildmidi-0.4.2/amiga/000077500000000000000000000000001315765416100162065ustar00rootroot00000000000000wildmidi-wildmidi-0.4.2/amiga/Makefile000066400000000000000000000031371315765416100176520ustar00rootroot00000000000000# GNU Makefile to build for AmigaOS variants using gcc # # make aros : build for i386-aros # make morphos : build for ppc-morphos # make amigaos : build for m68k-amigaos # make amigaos4 : build for ppc-amigaos4 # Set to 1 for debug build DEBUG = 0 # The tools ifeq ($(CROSS),) CC=gcc AS=as AR=ar RANLIB=ranlib else CC=$(CROSS)-gcc AS=$(CROSS)-as AR=$(CROSS)-ar RANLIB=$(CROSS)-ranlib endif INCLUDE = -I. -I../include CFLAGS = $(INCLUDE) -Wall -W -fno-common ARFLAGS = cr LD = $(CC) LDFLAGS = -L. -lWildMidi ifeq ($(DEBUG),1) CFLAGS += -g else CFLAGS += -O2 endif ifeq ($(AROS),1) include gcc_aros.cfg endif ifeq ($(MORPHOS),1) include gcc_morphos.cfg endif ifeq ($(AOS3),1) include gcc_aos3.cfg endif ifeq ($(AOS4),1) include gcc_aos4.cfg endif # Build rules %.o: %.c $(CC) -c $(CFLAGS) -o $@ $< %.o: ../src/%.c $(CC) -c $(CFLAGS) -o $@ $< # Objects LIB_OBJ= wm_error.o file_io.o lock.o wildmidi_lib.o reverb.o gus_pat.o f_xmidi.o f_mus.o f_hmp.o f_midi.o f_hmi.o mus2mid.o xmi2mid.o internal_midi.o patches.o sample.o PLAYER_OBJ= getopt_long.o wm_tty.o amiga.o wildmidi.o # Build targets .PHONY: clean distclean all: libWildMidi.a wildmidi libWildMidi.a: $(LIB_OBJ) $(AR) $(ARFLAGS) $@ $^ $(RANLIB) $@ wildmidi: libWildMidi.a $(PLAYER_OBJ) $(LD) -o $@ $(PLAYER_OBJ) $(LDFLAGS) aros: @echo Building for i386-aros $(MAKE) AROS=1 morphos: @echo Building for ppc-morphos $(MAKE) MORPHOS=1 amigaos: @echo Building for m68k-amigaos $(MAKE) AOS3=1 amigaos4: @echo Building for ppc-amigaos4 $(MAKE) AOS4=1 clean: rm -rf $(LIB_OBJ) $(PLAYER_OBJ) distclean: clean rm -rf libWildMidi.a WildMidi.lib wildmidi wildmidi-wildmidi-0.4.2/amiga/Makefile.vbcc000066400000000000000000000024621315765416100205660ustar00rootroot00000000000000# GNU Makefile to build for AmigaOS variants using VBCC # # make amigaos : build for m68k-amigaos # for now, only tested for m68k-amigaos: AOS3 := 1 # The tools CC=vc #MKLIB=join $(LIB_OBJ) as WildMidi.lib MKLIB=cat $(LIB_OBJ) > WildMidi.lib INCLUDE = -I. -I../include CFLAGS = -O1 -speed -c99 CFLAGS += $(INCLUDE) LDFLAGS = -L. -lWildMidi ifeq ($(MORPHOS),1) include vbcc_morphos.cfg endif ifeq ($(AOS3),1) include vbcc_aos3.cfg endif ifeq ($(AOS4),1) include vbcc_aos4.cfg endif # Build rules %.o: %.c $(CC) -c $(CFLAGS) -o $@ $< %.o: ../src/%.c $(CC) -c $(CFLAGS) -o $@ $< # Objects LIB_OBJ= wm_error.o file_io.o lock.o wildmidi_lib.o reverb.o gus_pat.o f_xmidi.o f_mus.o f_hmp.o f_midi.o f_hmi.o mus2mid.o xmi2mid.o internal_midi.o patches.o sample.o PLAYER_OBJ= getopt_long.o wm_tty.o amiga.o wildmidi.o # Build targets .PHONY: clean distclean all: WildMidi.lib wildmidi WildMidi.lib: $(LIB_OBJ) $(MKLIB) wildmidi: WildMidi.lib $(PLAYER_OBJ) $(CC) -o $@ $(PLAYER_OBJ) $(LDFLAGS) amigaos: @echo Building for m68k-amigaos $(MAKE) -f Makefile.vbcc AOS3=1 amigaos4: @echo Building for ppc-amigaos4 $(MAKE) -f Makefile.vbcc AOS4=1 morphos: @echo Building for ppc-morphos $(MAKE) -f Makefile.vbcc MORPHOS=1 clean: rm -rf $(LIB_OBJ) $(PLAYER_OBJ) distclean: clean rm -rf libWildMidi.a WildMidi.lib wildmidi wildmidi-wildmidi-0.4.2/amiga/config.h000066400000000000000000000010431315765416100176220ustar00rootroot00000000000000/* wildmidi config for amigaos variants */ #define WILDMIDI_AMIGA 1 #define WILDMIDI_CFG "wildmidi.cfg" #define PACKAGE_URL "http://www.mindwerks.net/projects/wildmidi/" #define PACKAGE_BUGREPORT "https://github.com/Mindwerks/wildmidi/issues" #define PACKAGE_VERSION "0.4.2" #define HAVE_C_INLINE #if defined(__GNUC__) && ((__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR >= 96)) #define HAVE___BUILTIN_EXPECT #endif #ifndef HAVE___BUILTIN_EXPECT #define __builtin_expect(x,c) x #endif #define AUDIODRV_AHI 1 /* AHI output for player app */ wildmidi-wildmidi-0.4.2/amiga/gcc_aos3.cfg000066400000000000000000000003651315765416100203540ustar00rootroot00000000000000# makefile fragment for m68k-amigaos / gcc INCLUDE+= -I../include/stdint LDFLAGS+= -noixemul LDFLAGS+= -lm CFLAGS += -noixemul CFLAGS += -DWORDS_BIGENDIAN=1 # avoid conflicts between our stdint.h and ixemul sys/types.h CFLAGS += -D_ANSI_SOURCE wildmidi-wildmidi-0.4.2/amiga/gcc_aos4.cfg000066400000000000000000000002741315765416100203540ustar00rootroot00000000000000# makefile fragment for ppc-amigaos4 / gcc LDFLAGS+= -noixemul LDFLAGS+= -lm CFLAGS += -noixemul CFLAGS += -DWORDS_BIGENDIAN=1 CFLAGS += -D__USE_INLINE__ CFLAGS += -D__USE_OLD_TIMEVAL__ wildmidi-wildmidi-0.4.2/amiga/gcc_aros.cfg000066400000000000000000000000511315765416100204430ustar00rootroot00000000000000# makefile fragment for i386-aros / gcc wildmidi-wildmidi-0.4.2/amiga/gcc_morphos.cfg000066400000000000000000000001611315765416100211700ustar00rootroot00000000000000# makefile fragment for ppc-morphos / gcc LDFLAGS+= -noixemul CFLAGS += -noixemul CFLAGS += -DWORDS_BIGENDIAN=1 wildmidi-wildmidi-0.4.2/amiga/vbcc_aos3.cfg000066400000000000000000000003351315765416100205320ustar00rootroot00000000000000# makefile fragment for m68k-amigaos / vbcc LDFLAGS+= -lm881 CFLAGS += -cpu=68020 -fpu=68881 CFLAGS += -D__AMIGA__ CFLAGS += -DWORDS_BIGENDIAN=1 # bullshit -- until the code is adjusted CFLAGS += -D__FUNCTION__=__func__ wildmidi-wildmidi-0.4.2/android/000077500000000000000000000000001315765416100165505ustar00rootroot00000000000000wildmidi-wildmidi-0.4.2/android/.gitignore000066400000000000000000000000051315765416100205330ustar00rootroot00000000000000obj/ wildmidi-wildmidi-0.4.2/android/Android.mk000066400000000000000000000004251315765416100204620ustar00rootroot00000000000000LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := WildMidi_shared LOCAL_SRC_FILES := libs/$(TARGET_ARCH_ABI)/libWildMidi.so LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/jni $(LOCAL_PATH)/../include TARGET_PLATFORM = android-10 include $(PREBUILT_SHARED_LIBRARY) wildmidi-wildmidi-0.4.2/android/jni/000077500000000000000000000000001315765416100173305ustar00rootroot00000000000000wildmidi-wildmidi-0.4.2/android/jni/Android.mk000066400000000000000000000011261315765416100212410ustar00rootroot00000000000000LOCAL_PATH := $(call my-dir)/../.. include $(CLEAR_VARS) LOCAL_MODULE := WildMidi LOCAL_C_INCLUDES := $(LOCAL_PATH)/android/jni $(LOCAL_PATH)/include LOCAL_ARM_MODE := arm LOCAL_CFLAGS += -DWILDMIDI_BUILD LOCAL_CFLAGS += -fvisibility=hidden -DSYM_VISIBILITY LOCAL_SRC_FILES := \ src/f_hmi.c \ src/f_hmp.c \ src/f_midi.c \ src/f_mus.c \ src/f_xmidi.c \ src/file_io.c \ src/gus_pat.c \ src/internal_midi.c \ src/lock.c \ src/mus2mid.c \ src/patches.c \ src/reverb.c \ src/sample.c \ src/wildmidi_lib.c \ src/wm_error.c \ src/xmi2mid.c include $(BUILD_SHARED_LIBRARY) wildmidi-wildmidi-0.4.2/android/jni/Application.mk000066400000000000000000000002551315765416100221260ustar00rootroot00000000000000APP_ABI := armeabi-v7a x86 APP_MODULES := WildMidi APP_PLATFORM := android-10 APP_OPTIM := release NDK_TOOLCHAIN_VERSION := 4.9 wildmidi-wildmidi-0.4.2/android/jni/config.h000066400000000000000000000041621315765416100207510ustar00rootroot00000000000000/* config.h -- generated from config.h.cmake */ /* Name of package */ #define PACKAGE "wildmidi" /* Define to the home page for this package. */ #define PACKAGE_URL "http://www.mindwerks.net/projects/wildmidi/" /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "https://github.com/Mindwerks/wildmidi/issues" /* Define to the full name of this package. */ #define PACKAGE_NAME "WildMidi" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "WildMidi 0.4.2" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "wildmidi" /* Define to the version of this package. */ #define PACKAGE_VERSION "0.4.2" /* Version number of package */ #define VERSION "0.4.2" /* Define this to the location of the wildmidi config file */ /* #undef WILDMIDI_CFG "/etc/wildmidi/wildmidi.cfg" */ /* Define if the C compiler supports the `inline' keyword. */ #define HAVE_C_INLINE /* Define if the C compiler supports the `__inline__' keyword. */ #define HAVE_C___INLINE__ /* Define if the C compiler supports the `__inline' keyword. */ #define HAVE_C___INLINE #if !defined(HAVE_C_INLINE) && !defined(__cplusplus) # ifdef HAVE_C___INLINE__ # define inline __inline__ # elif defined(HAVE_C___INLINE) # define inline __inline # else # define inline # endif #endif /* Define if the compiler has the `__builtin_expect' built-in function */ #define HAVE___BUILTIN_EXPECT #ifndef HAVE___BUILTIN_EXPECT #define __builtin_expect(x,c) x #endif /* define this if you are running a bigendian system (motorola, sparc, etc) */ /* #undef WORDS_BIGENDIAN */ /* define this if building for AmigaOS variants */ /* #undef WILDMIDI_AMIGA */ /* Define if you have the header file. */ #define HAVE_STDINT_H /* Define if you have the header file. */ #define HAVE_INTTYPES_H /* Define our audio drivers */ /* #undef HAVE_LINUX_SOUNDCARD_H */ /* #undef HAVE_SYS_SOUNDCARD_H */ /* #undef HAVE_MACHINE_SOUNDCARD_H */ /* #undef HAVE_SOUNDCARD_H */ /* #undef AUDIODRV_ALSA */ /* #undef AUDIODRV_OSS */ /* #undef AUDIODRV_OPENAL */ /* #undef AUDIODRV_AHI */ wildmidi-wildmidi-0.4.2/android/project.properties000066400000000000000000000005511315765416100223350ustar00rootroot00000000000000# This file is automatically generated by Android Tools. # Do not modify this file -- YOUR CHANGES WILL BE ERASED! # # This file must be checked in Version Control Systems. # # To customize properties used by the Ant build system use, # "ant.properties", and override values to adapt the script to your # project structure. # Project target. target=android-10 wildmidi-wildmidi-0.4.2/appveyor.yml000066400000000000000000000026231315765416100175230ustar00rootroot00000000000000version: "{build}" branches: only: - master - /wildmidi-.*$/ - appveyor platform: - Win32 - x64 configuration: Debug matrix: fast_finish: true # For the Qt, Boost, CMake, etc installs os: unstable # We want the git revision for versioning, # so shallow clones don't work. clone_depth: 1 #cache: # - C:\projects\wildmidi\deps\ffmpeg32-2.5.2.7z # - C:\projects\wildmidi\deps\ffmpeg32-2.5.2-dev.7z # - C:\projects\wildmidi\deps\ffmpeg64-2.5.2.7z # - C:\projects\wildmidi\deps\ffmpeg64-2.5.2-dev.7z clone_folder: C:\projects\wildmidi before_build: - cmd: sh %APPVEYOR_BUILD_FOLDER%\CI\before_script.msvc.sh -u -p %PLATFORM% build_script: - cmd: if %PLATFORM%==Win32 set build=Build_32 - cmd: if %PLATFORM%==x64 set build=Build_64 - cmd: msbuild %build%\WildMIDI.sln /t:Build /p:Configuration=%configuration% /m:2 /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" after_build: - cmd: if %PLATFORM%==Win32 7z a WildMIDI_x32.zip %APPVEYOR_BUILD_FOLDER%\Build_32\Debug\wildmidi* - cmd: if %PLATFORM%==x64 7z a WildMIDI_x64.zip %APPVEYOR_BUILD_FOLDER%\Build_64\Debug\wildmidi* test: off #notifications: # - provider: Email # to: # - # on_build_failure: true # on_build_status_changed: true artifacts: - path: WildMIDI_x32.zip name: WildMIDI_x32 - path: WildMIDI_x64.zip name: WildMIDI_x64 wildmidi-wildmidi-0.4.2/cfg/000077500000000000000000000000001315765416100156675ustar00rootroot00000000000000wildmidi-wildmidi-0.4.2/cfg/wildmidi.cfg000066400000000000000000000110571315765416100201560ustar00rootroot00000000000000dir /usr/share/midi/freepats # Automatically generated on Sun Feb 19 19:22:39 EST 2006 # by http://freepats.opensrc.org/mkcfg.sh.txt drumset 0 25 Drum_000/025_Snare_Roll.pat 26 Drum_000/026_Snap.pat 27 Drum_000/027_High_Q.pat 31 Drum_000/031_Sticks.pat 32 Drum_000/032_Square_Click.pat 33 Drum_000/033_Metronome_Click.pat 34 Drum_000/034_Metronome_Bell.pat 35 Drum_000/035_Kick_1.pat amp=100 36 Drum_000/036_Kick_2.pat amp=100 37 Drum_000/037_Stick_Rim.pat 38 Drum_000/038_Snare_1.pat 39 Drum_000/039_Clap_Hand.pat amp=100 40 Drum_000/040_Snare_2.pat 41 Drum_000/041_Tom_Low_2.pat amp=100 42 Drum_000/042_Hi-Hat_Closed.pat 43 Drum_000/043_Tom_Low_1.pat amp=100 44 Drum_000/044_Hi-Hat_Pedal.pat 45 Drum_000/045_Tom_Mid_2.pat amp=100 46 Drum_000/046_Hi-Hat_Open.pat 47 Drum_000/047_Tom_Mid_1.pat amp=100 48 Drum_000/048_Tom_High_2.pat amp=100 49 Drum_000/049_Cymbal_Crash_1.pat 50 Drum_000/050_Tom_High_1.pat amp=100 51 Drum_000/051_Cymbal_Ride_1.pat 52 Drum_000/052_Cymbal_Chinese.pat 53 Drum_000/053_Cymbal_Ride_Bell.pat amp=100 54 Drum_000/054_Tombourine.pat 55 Drum_000/055_Cymbal_Splash.pat 56 Drum_000/056_Cow_Bell.pat 57 Drum_000/057_Cymbal_Crash_2.pat 58 Drum_000/058_Vibra-Slap.pat 59 Drum_000/059_Cymbal_Ride_2.pat 60 Drum_000/060_Bongo_High.pat 61 Drum_000/061_Bongo_Low.pat 62 Drum_000/062_Conga_High_1_Mute.pat 63 Drum_000/063_Conga_High_2_Open.pat 64 Drum_000/064_Conga_Low.pat 65 Drum_000/065_Timbale_High.pat 66 Drum_000/066_Timbale_Low.pat 67 Drum_000/067_Agogo_High.pat 68 Drum_000/068_Agogo_Low.pat 69 Drum_000/069_Cabasa.pat amp=100 70 Drum_000/070_Maracas.pat 71 Drum_000/071_Whistle_1_High_Short.pat 72 Drum_000/072_Whistle_2_Low_Long.pat 73 Drum_000/073_Guiro_1_Short.pat 74 Drum_000/074_Guiro_2_Long.pat 75 Drum_000/075_Claves.pat amp=100 76 Drum_000/076_Wood_Block_1_High.pat 77 Drum_000/077_Wood_Block_2_Low.pat 78 Drum_000/078_Cuica_1_Mute.pat amp=100 79 Drum_000/079_Cuica_2_Open.pat amp=100 80 Drum_000/080_Triangle_1_Mute.pat 81 Drum_000/081_Triangle_2_Open.pat 82 Drum_000/082_Shaker.pat 84 Drum_000/084_Belltree.pat bank 0 0 Tone_000/000_Acoustic_Grand_Piano.pat amp=120 pan=center 1 Tone_000/001_Acoustic_Brite_Piano.pat 2 Tone_000/002_Electric_Grand_Piano.pat 4 Tone_000/004_Electric_Piano_1_Rhodes.pat 5 Tone_000/005_Electric_Piano_2_Chorused_Yamaha_DX.pat 6 Tone_000/006_Harpsichord.pat 7 Tone_000/007_Clavinet.pat 8 Tone_000/008_Celesta.pat 9 Tone_000/009_Glockenspiel.pat 13 Tone_000/013_Xylophone.pat 14 Tone_000/014_Tubular_Bells.pat 15 Tone_000/015_Dulcimer.pat 16 Tone_000/016_Hammond_Organ.pat 19 Tone_000/019_Church_Organ.pat 21 Tone_000/021_Accordion.pat 23 Tone_000/023_Tango_Accordion.pat 24 Tone_000/024_Nylon_Guitar.pat 25 Tone_000/025_Steel_Guitar.pat 26 Tone_000/026_Jazz_Guitar.pat 27 Tone_000/027_Clean_Electric_Guitar.pat 28 Tone_000/028_Muted_Electric_Guitar.pat 29 Tone_000/029_Overdriven_Guitar.pat 30 Tone_000/030_Distortion_Guitar.pat 32 Tone_000/032_Acoustic_Bass.pat 33 Tone_000/033_Finger_Bass.pat 34 Tone_000/034_Pick_Bass.pat 35 Tone_000/035_Fretless_Bass.pat 36 Tone_000/036_Slap_Bass_1.pat 37 Tone_000/037_Slap_Bass_2.pat 38 Tone_000/038_Synth_Bass_1.pat 40 Tone_000/040_Violin.pat 42 Tone_000/042_Cello.pat 44 Tone_000/044_Tremolo_Strings.pat 45 Tone_000/045_Pizzicato_Strings.pat 46 Tone_000/046_Harp.pat 47 Tone_000/047_Timpani.pat 48 Tone_000/048_String_Ensemble_1_Marcato.pat 53 Tone_000/053_Voice_Oohs.pat 56 Tone_000/056_Trumpet.pat 57 Tone_000/057_Trombone.pat 58 Tone_000/058_Tuba.pat 59 Tone_000/059_Muted_Trumpet.pat 60 Tone_000/060_French_Horn.pat 61 Tone_000/061_Brass_Section.pat 64 Tone_000/064_Soprano_Sax.pat 65 Tone_000/065_Alto_Sax.pat 66 Tone_000/066_Tenor_Sax.pat 67 Tone_000/067_Baritone_Sax.pat 68 Tone_000/068_Oboe.pat 69 Tone_000/069_English_Horn.pat 70 Tone_000/070_Bassoon.pat 71 Tone_000/071_Clarinet.pat 72 Tone_000/072_Piccolo.pat 73 Tone_000/073_Flute.pat 74 Tone_000/074_Recorder.pat 75 Tone_000/075_Pan_Flute.pat 76 Tone_000/076_Bottle_Blow.pat 79 Tone_000/079_Ocarina.pat 80 Tone_000/080_Square_Wave.pat 84 Tone_000/084_Charang.pat 88 Tone_000/088_New_Age.pat 94 Tone_000/094_Halo_Pad.pat 95 Tone_000/095_Sweep_Pad.pat 98 Tone_000/098_Crystal.pat 101 Tone_000/101_Goblins--Unicorn.pat 102 Tone_000/102_Echo_Voice.pat 104 Tone_000/104_Sitar.pat 114 Tone_000/114_Steel_Drums.pat 115 Tone_000/115_Wood_Block.pat 120 Tone_000/120_Guitar_Fret_Noise.pat 122 Tone_000/122_Seashore.pat 125 Tone_000/125_Helicopter.pat wildmidi-wildmidi-0.4.2/cmake/000077500000000000000000000000001315765416100162105ustar00rootroot00000000000000wildmidi-wildmidi-0.4.2/cmake/FindOSS.cmake000066400000000000000000000042421315765416100204610ustar00rootroot00000000000000# - Find OSS # Find OSS headers and libraries. # # OSS_INCLUDE_DIR - where to find soundcard.h, etc. # OSS_LIBRARY - link library, if any, needed for OSS. # OSS_FOUND - True if OSS found. INCLUDE(CheckIncludeFiles) INCLUDE(CheckCSourceCompiles) SET(OSS_LIBRARY "") SET(OSS_INCLUDE_DIR) # system header must suffice SET(OSS_FOUND) MESSAGE(STATUS "Looking for OSS...") #CHECK_INCLUDE_FILES(linux/soundcard.h HAVE_LINUX_SOUNDCARD_H) # Linux does provide CHECK_INCLUDE_FILES(sys/soundcard.h HAVE_SYS_SOUNDCARD_H) CHECK_INCLUDE_FILES(machine/soundcard.h HAVE_MACHINE_SOUNDCARD_H) CHECK_INCLUDE_FILES(soundcard.h HAVE_SOUNDCARD_H) # less common, but exists. # NetBSD and OpenBSD uses ossaudio emulation layer, # otherwise no link library is needed. IF(CMAKE_SYSTEM_NAME MATCHES "kNetBSD.*|NetBSD.*|kOpenBSD.*|OpenBSD.*") # AND HAVE_SOUNDCARD_H ??? FIND_LIBRARY(OSSAUDIO_LIBRARIES "ossaudio") IF(OSSAUDIO_LIBRARIES STREQUAL "OSSAUDIO_LIBRARIES-NOTFOUND") SET(OSSAUDIO_LIBRARIES) ELSE() MESSAGE(STATUS "Found libossaudio: ${OSSAUDIO_LIBRARIES}") SET(OSS_LIBRARY ${OSSAUDIO_LIBRARIES}) ENDIF() ELSE() SET(OSSAUDIO_LIBRARIES) ENDIF() SET(OLD_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES}") IF(OSSAUDIO_LIBRARIES) SET(CMAKE_REQUIRED_LIBRARIES ${OSSAUDIO_LIBRARIES}) ENDIF() IF(HAVE_SYS_SOUNDCARD_H) CHECK_C_SOURCE_COMPILES("#include #include int main() {return SNDCTL_DSP_RESET;}" OSS_FOUND) ELSEIF(HAVE_MACHINE_SOUNDCARD_H) CHECK_C_SOURCE_COMPILES("#include #include int main() {return SNDCTL_DSP_RESET;}" OSS_FOUND) ELSEIF(HAVE_SOUNDCARD_H) CHECK_C_SOURCE_COMPILES("#include #include int main() {return SNDCTL_DSP_RESET;}" OSS_FOUND) ENDIF() SET(CMAKE_REQUIRED_LIBRARIES "${OLD_REQUIRED_LIBRARIES}") MARK_AS_ADVANCED ( OSS_FOUND OSS_INCLUDE_DIR OSS_LIBRARY ) IF(OSS_FOUND) MESSAGE(STATUS "Found OSS.") ELSE() MESSAGE(STATUS "Could not find OSS.") ENDIF() wildmidi-wildmidi-0.4.2/cmake/Toolchain-MinGW32.cmake000066400000000000000000000014211315765416100222540ustar00rootroot00000000000000# toolchain file I use to cross compile on Linux # targetting Windows (x86/mingw). running: # cmake -DCMAKE_TOOLCHAIN_FILE=/path/to/Toolchain-MinGW32.cmake .... SET(CMAKE_SYSTEM_NAME Windows) SET(CMAKE_C_COMPILER /usr/local/cross-win32/bin/i686-pc-mingw32-gcc) SET(CMAKE_CXX_COMPILER /usr/local/cross-win32/bin/i686-pc-mingw32-g++) SET(CMAKE_RC_COMPILER /usr/local/cross-win32/bin/i686-pc-mingw32-windres) # where is the target environment SET(CMAKE_FIND_ROOT_PATH /usr/local/cross-win32) # adjust the default behaviour of the FIND_XXX() commands: # search headers and libraries in the target environment, search # programs in the host environment SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) wildmidi-wildmidi-0.4.2/cmake/Toolchain-MinGW64.cmake000066400000000000000000000014521315765416100222650ustar00rootroot00000000000000# toolchain file I use to cross compile on Linux # targetting Windows (x64/mingw-w64). running: # cmake -DCMAKE_TOOLCHAIN_FILE=/path/to/Toolchain-MinGW64.cmake .... SET(CMAKE_SYSTEM_NAME Windows) SET(CMAKE_C_COMPILER /opt/cross_win64/bin/x86_64-w64-mingw32-gcc) SET(CMAKE_CXX_COMPILER /opt/cross_win64/bin/x86_64-w64-mingw32-g++) SET(CMAKE_RC_COMPILER /opt/cross_win64/bin/x86_64-w64-mingw32-windres) # where is the target environment SET(CMAKE_FIND_ROOT_PATH /opt/cross_win64 /opt/cross_win64/x86_64-w64-mingw32) # adjust the default behaviour of the FIND_XXX() commands: # search headers and libraries in the target environment, search # programs in the host environment SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) wildmidi-wildmidi-0.4.2/cmake/Toolchain-OSX-ppc.cmake000066400000000000000000000013071315765416100223620ustar00rootroot00000000000000# toolchain file I use to cross compile on Linux # targetting OSX/Darwin (powerpc). running: # cmake -DCMAKE_TOOLCHAIN_FILE=/path/to/Toolchain-OSX-ppc.cmake .... SET(CMAKE_SYSTEM_NAME Darwin) SET(CMAKE_C_COMPILER /opt/cross_osx-ppc/bin/powerpc-apple-darwin9-gcc) SET(CMAKE_CXX_COMPILER /opt/cross_osx-ppc/bin/powerpc-apple-darwin9-g++) # where is the target environment SET(CMAKE_FIND_ROOT_PATH /opt/cross_osx-ppc) # adjust the default behaviour of the FIND_XXX() commands: # search headers and libraries in the target environment, search # programs in the host environment SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) wildmidi-wildmidi-0.4.2/cmake/Toolchain-OSX-x86.cmake000066400000000000000000000012751315765416100222310ustar00rootroot00000000000000# toolchain file I use to cross compile on Linux # targetting OSX/Darwin (x86). running: # cmake -DCMAKE_TOOLCHAIN_FILE=/path/to/Toolchain-OSX-x86.cmake .... SET(CMAKE_SYSTEM_NAME Darwin) SET(CMAKE_C_COMPILER /opt/cross_osx-x86/bin/i686-apple-darwin9-gcc) SET(CMAKE_CXX_COMPILER /opt/cross_osx-x86/bin/i686-apple-darwin9-g++) # where is the target environment SET(CMAKE_FIND_ROOT_PATH /opt/cross_osx-x86) # adjust the default behaviour of the FIND_XXX() commands: # search headers and libraries in the target environment, search # programs in the host environment SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) wildmidi-wildmidi-0.4.2/cmake/Toolchain-OSX-x86_64.cmake000066400000000000000000000013301315765416100225320ustar00rootroot00000000000000# toolchain file I use to cross compile on Linux # targetting OSX/Darwin (x86_64). running: # cmake -DCMAKE_TOOLCHAIN_FILE=/path/to/Toolchain-OSX-x86_64.cmake .... SET(CMAKE_SYSTEM_NAME Darwin) SET(CMAKE_C_COMPILER /opt/cross_osx-x86_64/usr/bin/x86_64-apple-darwin9-gcc) SET(CMAKE_CXX_COMPILER /opt/cross_osx-x86_64/usr/bin/x86_64-apple-darwin9-g++) # where is the target environment SET(CMAKE_FIND_ROOT_PATH /opt/cross_osx-x86_64) # adjust the default behaviour of the FIND_XXX() commands: # search headers and libraries in the target environment, search # programs in the host environment SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) wildmidi-wildmidi-0.4.2/djgpp/000077500000000000000000000000001315765416100162345ustar00rootroot00000000000000wildmidi-wildmidi-0.4.2/djgpp/Makefile000066400000000000000000000037371315765416100177060ustar00rootroot00000000000000#------------------------------------------------------------------------------# # Makefile for building WildMidi library and player for DOS. # You will need a DJGPP build environment and GNU make to do it painlessly. # To build natively on DOS, you need long file names support (e.g. doslfn.) #------------------------------------------------------------------------------# # Set to 1 for debug build DEBUG = 0 # DXE3 version of the library requires DJGPP-2.05 or newer. # Set to 0 if dont want to build / use a DXE3 version of the library. USE_DXE = 1 # The tools ifeq ($(CROSS),) CC=gcc AS=as AR=ar RANLIB=ranlib else CC=$(CROSS)-gcc AS=$(CROSS)-as AR=$(CROSS)-ar RANLIB=$(CROSS)-ranlib endif DXE3GEN=dxe3gen INCLUDE = -I. -I../include/stdint -I../include CFLAGS = $(INCLUDE) -Wall -W -fno-common ARFLAGS = cr # SB output support (comment out if not wanted) CFLAGS+= -DAUDIODRV_DOSSB SB_OBJ = dosirq.o dosdma.o dossb.o LD = $(CC) ifneq ($(USE_DXE),1) WM_LINK = WildMidi else WM_LINK = WildMidi_dxe endif LDFLAGS = -L. -l$(WM_LINK) # build for pentium and newer (comment out if not wanted) CFLAGS += -march=i586 ifeq ($(DEBUG),1) CFLAGS += -g else CFLAGS += -O2 -fomit-frame-pointer -ffast-math endif # Build rules %.o: %.c $(CC) -c $(CFLAGS) -o $@ $< %.o: ../src/%.c $(CC) -c $(CFLAGS) -o $@ $< # Objects LIB_OBJ= wm_error.o file_io.o lock.o wildmidi_lib.o reverb.o gus_pat.o f_xmidi.o f_mus.o f_hmp.o f_midi.o f_hmi.o mus2mid.o xmi2mid.o internal_midi.o patches.o sample.o PLAYER_OBJ= $(SB_OBJ) getopt_long.o wm_tty.o wildmidi.o # Build targets TARGETS = libWildMidi.a wildmidi.exe libWildMidi_dxe.a wildmidi.dxe .PHONY: clean distclean all: $(TARGETS) libWildMidi.a: $(LIB_OBJ) $(AR) $(ARFLAGS) $@ $^ $(RANLIB) $@ libWildMidi_dxe.a: wildmidi.dxe wildmidi.dxe: $(LIB_OBJ) -$(DXE3GEN) -Y libWildMidi_dxe.a -o $@ -E _WildMidi_ -U $^ wildmidi.exe: lib$(WM_LINK).a $(PLAYER_OBJ) $(LD) -o $@ $(PLAYER_OBJ) $(LDFLAGS) clean: rm -rf $(LIB_OBJ) $(PLAYER_OBJ) distclean: clean rm -rf $(TARGETS) wildmidi-wildmidi-0.4.2/djgpp/README000066400000000000000000000017071315765416100171210ustar00rootroot00000000000000This directory contains the Makefile and config.h needed to compile libWilMidi library and wildmidi player for DOS using DJGPP. To compile, you need DJGPP library and its associated compiler suite. Both djgpp-v2.03 and v2.05 should work. DJGPP is available from its official site at Cd in to the djgpp directory and run 'make', i.e.: cd djgpp make .. which will generate libWildMidi.a and wildmidi.exe. If necessary, edit the Makefile to meet your needs/environment. The player (wildmidi.exe) can either output to a Sound Blaster (SB1, SB2, SBPro, SB16, or compatible) hardware: wildmidi mymidi.mid ... or, it can generate a wav file: wildmidi -o output.wav mymidi.mid Use -r to specify a sample rate, use -c to point to your wildmidi.cfg config file: wildmidi -c c:\wildmidi.cfg -r 22050 mymidi.mid Run "wildmidi -h" to see other command line switches. wildmidi-wildmidi-0.4.2/djgpp/config.h000066400000000000000000000007071315765416100176560ustar00rootroot00000000000000#define WILDMIDI_CFG "wildmidi.cfg" #define PACKAGE_URL "http://www.mindwerks.net/projects/wildmidi/" #define PACKAGE_BUGREPORT "https://github.com/Mindwerks/wildmidi/issues" #define PACKAGE_VERSION "0.4.2" #define HAVE_C_INLINE #if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR >= 96) #define HAVE___BUILTIN_EXPECT #endif #ifndef HAVE___BUILTIN_EXPECT #define __builtin_expect(x,c) x #endif #define WM_NO_LOCK 1 /* don't need locking in MSDOS */ wildmidi-wildmidi-0.4.2/djgpp/dosdma.c000066400000000000000000000140141315765416100176470ustar00rootroot00000000000000/* Implementation of DMA routines on DOS - from libMikMod. Copyright (C) 1999 by Andrew Zabolotny, This file is part of WildMIDI. WildMIDI is free software: you can redistribute and/or modify the player under the terms of the GNU General Public License and you can redistribute and/or modify the library under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the licenses, or(at your option) any later version. WildMIDI 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 and the GNU Lesser General Public License for more details. You should have received a copy of the GNU General Public License and the GNU Lesser General Public License along with WildMIDI. If not, see . */ #include "dosdma.h" #include /* includes sys/version.h (djgpp >= 2.02) */ #include #include #include #include /* BUG WARNING: there is an error in DJGPP libraries <= 2.01: * src/libc/dpmi/api/d0102.s loads the selector and allocsize * arguments in the wrong order. DJGPP >= 2.02 have it fixed. */ #if !defined(__DJGPP_MINOR__) || (__DJGPP_MINOR__-0 < 2) #warning __dpmi_resize_dos_memory() from DJGPP <= 2.01 is broken! #endif __dma_regs dma[8] = { /* *INDENT-OFF* */ {DMA_ADDR_0, DMA_PAGE_0, DMA_SIZE_0, DMA1_MASK_REG, DMA1_CLEAR_FF_REG, DMA1_MODE_REG}, {DMA_ADDR_1, DMA_PAGE_1, DMA_SIZE_1, DMA1_MASK_REG, DMA1_CLEAR_FF_REG, DMA1_MODE_REG}, {DMA_ADDR_2, DMA_PAGE_2, DMA_SIZE_2, DMA1_MASK_REG, DMA1_CLEAR_FF_REG, DMA1_MODE_REG}, {DMA_ADDR_3, DMA_PAGE_3, DMA_SIZE_3, DMA1_MASK_REG, DMA1_CLEAR_FF_REG, DMA1_MODE_REG}, {DMA_ADDR_4, 0, DMA_SIZE_4, DMA2_MASK_REG, DMA2_CLEAR_FF_REG, DMA2_MODE_REG}, {DMA_ADDR_5, DMA_PAGE_5, DMA_SIZE_5, DMA2_MASK_REG, DMA2_CLEAR_FF_REG, DMA2_MODE_REG}, {DMA_ADDR_6, DMA_PAGE_6, DMA_SIZE_6, DMA2_MASK_REG, DMA2_CLEAR_FF_REG, DMA2_MODE_REG}, {DMA_ADDR_7, DMA_PAGE_7, DMA_SIZE_7, DMA2_MASK_REG, DMA2_CLEAR_FF_REG, DMA2_MODE_REG} /* *INDENT-ON* */ }; static int __initialized = 0; static int __buffer_count = 0; static __dpmi_meminfo __locked_data; int dma_initialize() { if (!__djgpp_nearptr_enable()) return 0; /* Trick: Avoid re-setting DS selector limit on each memory allocation call */ __djgpp_selector_limit = 0xffffffff; __locked_data.address = __djgpp_base_address + (unsigned long)&dma; __locked_data.size = sizeof(dma); if (__dpmi_lock_linear_region(&__locked_data)) return 0; return (__initialized = 1); } void dma_finalize() { if (!__initialized) return; __dpmi_unlock_linear_region(&__locked_data); __djgpp_nearptr_disable(); } dma_buffer *dma_allocate(unsigned int channel, unsigned int size) { int parsize = (size + 15) >> 4; /* size in paragraphs */ int par = 0; /* Real-mode paragraph */ int selector = 0; /* Protected-mode selector */ int mask = channel <= 3 ? 0xfff : 0x1fff; /* Alignment mask in para. */ int allocsize = parsize; /* Allocated size in paragraphs */ int count; /* Try count */ int bound = 0; /* Nearest bound address */ int maxsize; /* Maximal possible block size */ dma_buffer *buffer = NULL; __dpmi_meminfo buff_info, struct_info; if (!dma_initialize()) return NULL; /* Loop until we'll get a properly aligned memory block */ for (count = 8; count; count--) { int resize = (selector != 0); /* Try first to resize (possibly previously) allocated block */ if (resize) { maxsize = (bound + parsize) - par; if (maxsize > parsize * 2) maxsize = parsize * 2; if (maxsize == allocsize) resize = 0; else { allocsize = maxsize; if (__dpmi_resize_dos_memory(selector, allocsize, &maxsize) != 0) resize = 0; } } if (!resize) { if (selector) __dpmi_free_dos_memory(selector), selector = 0; par = __dpmi_allocate_dos_memory(allocsize, &selector); } if ((par == 0) || (par == -1)) goto exit; /* If memory block contains a properly aligned portion, quit loop */ bound = (par + mask + 1) & ~mask; if (par + parsize <= bound) break; if (bound + parsize <= par + allocsize) { par = bound; break; } } if (!count) { __dpmi_free_dos_memory(selector); goto exit; } buffer = (dma_buffer *) malloc(sizeof(dma_buffer)); buffer->linear = (unsigned char *)(__djgpp_conventional_base + bound * 16); buffer->physical = bound * 16; buffer->size = parsize * 16; buffer->selector = selector; buffer->channel = channel; buff_info.address = buffer->physical; buff_info.size = buffer->size; /* Don't pay attention to return code since under plain DOS it often returns error (at least under HIMEM/CWSDPMI and EMM386/DPMI) */ __dpmi_lock_linear_region(&buff_info); /* Lock the DMA buffer control structure as well */ struct_info.address = __djgpp_base_address + (unsigned long)buffer; struct_info.size = sizeof(dma_buffer); if (__dpmi_lock_linear_region(&struct_info)) { __dpmi_unlock_linear_region(&buff_info); __dpmi_free_dos_memory(selector); free(buffer); buffer = NULL; goto exit; } exit: if (buffer) __buffer_count++; else if (--__buffer_count == 0) dma_finalize(); return buffer; } void dma_free(dma_buffer * buffer) { __dpmi_meminfo buff_info; if (!buffer) return; buff_info.address = buffer->physical; buff_info.size = buffer->size; __dpmi_unlock_linear_region(&buff_info); __dpmi_free_dos_memory(buffer->selector); free(buffer); if (--__buffer_count == 0) dma_finalize(); } void dma_start(dma_buffer * buffer, unsigned long count, unsigned char mode) { /* Disable interrupts */ int old_ints = disable(); dma_disable(buffer->channel); dma_set_mode(buffer->channel, mode); dma_clear_ff(buffer->channel); dma_set_addr(buffer->channel, buffer->physical); dma_clear_ff(buffer->channel); dma_set_count(buffer->channel, count); dma_enable(buffer->channel); /* Re-enable interrupts */ if (old_ints) enable(); } wildmidi-wildmidi-0.4.2/djgpp/dosdma.h000066400000000000000000000143761315765416100176670ustar00rootroot00000000000000/* Interface for DMA routines on DOS -- from libMikMod. Copyright (C) 1999 by Andrew Zabolotny, This file is part of WildMIDI. WildMIDI is free software: you can redistribute and/or modify the player under the terms of the GNU General Public License and you can redistribute and/or modify the library under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the licenses, or(at your option) any later version. WildMIDI 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 and the GNU Lesser General Public License for more details. You should have received a copy of the GNU General Public License and the GNU Lesser General Public License along with WildMIDI. If not, see . */ #ifndef __DOSDMA_H__ #define __DOSDMA_H__ #include #define DMA1_BASE 0x00 /* 8 bit slave DMA, channels 0..3 */ #define DMA2_BASE 0xC0 /* 16 bit master DMA, ch 4(=slave input)..7 */ #define DMA1_CMD_REG 0x08 /* command register (w) */ #define DMA1_STAT_REG 0x08 /* status register (r) */ #define DMA1_REQ_REG 0x09 /* request register (w) */ #define DMA1_MASK_REG 0x0A /* single-channel mask (w) */ #define DMA1_MODE_REG 0x0B /* mode register (w) */ #define DMA1_CLEAR_FF_REG 0x0C /* clear pointer flip-flop (w) */ #define DMA1_TEMP_REG 0x0D /* Temporary Register (r) */ #define DMA1_RESET_REG 0x0D /* Master Clear (w) */ #define DMA1_CLR_MASK_REG 0x0E /* Clear Mask */ #define DMA1_MASK_ALL_REG 0x0F /* all-channels mask (w) */ #define DMA2_CMD_REG 0xD0 /* command register (w) */ #define DMA2_STAT_REG 0xD0 /* status register (r) */ #define DMA2_REQ_REG 0xD2 /* request register (w) */ #define DMA2_MASK_REG 0xD4 /* single-channel mask (w) */ #define DMA2_MODE_REG 0xD6 /* mode register (w) */ #define DMA2_CLEAR_FF_REG 0xD8 /* clear pointer flip-flop (w) */ #define DMA2_TEMP_REG 0xDA /* Temporary Register (r) */ #define DMA2_RESET_REG 0xDA /* Master Clear (w) */ #define DMA2_CLR_MASK_REG 0xDC /* Clear Mask */ #define DMA2_MASK_ALL_REG 0xDE /* all-channels mask (w) */ #define DMA_ADDR_0 0x00 /* DMA address registers */ #define DMA_ADDR_1 0x02 #define DMA_ADDR_2 0x04 #define DMA_ADDR_3 0x06 #define DMA_ADDR_4 0xC0 #define DMA_ADDR_5 0xC4 #define DMA_ADDR_6 0xC8 #define DMA_ADDR_7 0xCC #define DMA_SIZE_0 0x01 /* DMA transfer size registers */ #define DMA_SIZE_1 0x03 #define DMA_SIZE_2 0x05 #define DMA_SIZE_3 0x07 #define DMA_SIZE_4 0xC2 #define DMA_SIZE_5 0xC6 #define DMA_SIZE_6 0xCA #define DMA_SIZE_7 0xCE #define DMA_PAGE_0 0x87 /* DMA page registers */ #define DMA_PAGE_1 0x83 #define DMA_PAGE_2 0x81 #define DMA_PAGE_3 0x82 #define DMA_PAGE_5 0x8B #define DMA_PAGE_6 0x89 #define DMA_PAGE_7 0x8A #define DMA_MODE_AUTOINIT 0x10 /* Auto-init mode bit */ #define DMA_MODE_READ 0x44 /* I/O to memory, no autoinit, increment, single mode */ #define DMA_MODE_WRITE 0x48 /* memory to I/O, no autoinit, increment, single mode */ #define DMA_MODE_CASCADE 0xC0 /* pass thru DREQ->HRQ, DACK<-HLDA only */ /* Indexable specific DMA registers */ typedef struct __dma_regs_s { unsigned char addr; /* DMA transfer address register */ unsigned char page; /* DMA page register */ unsigned char size; /* DMA transfer size register */ unsigned char mask; /* DMA mask/unmask register */ unsigned char flip; /* DMA flip-flop reset register */ unsigned char mode; /* DMA mode register */ } __dma_regs; extern __dma_regs dma[8]; /* Enable a specific DMA channel */ static inline void dma_enable(unsigned int channel) { outportb(dma[channel].mask, channel & 3); } /* Disable a specific DMA channel */ static inline void dma_disable(unsigned int channel) { outportb(dma[channel].mask, (channel & 3) | 0x04); } /* Clear the 'DMA Flip Flop' flag */ static inline void dma_clear_ff(unsigned int channel) { outportb(dma[channel].flip, 0); } /* Set mode for a specific DMA channel */ static inline void dma_set_mode(unsigned int channel, char mode) { outportb(dma[channel].mode, mode | (channel & 3)); } /* Set DMA page register */ static inline void dma_set_page(unsigned int channel, char page) { if (channel > 3) page &= 0xfe; outportb(dma[channel].page, page); } /* Set transfer address & page bits for specific DMA channel. Assumes dma flipflop is clear. */ static inline void dma_set_addr(unsigned int channel, unsigned int address) { unsigned char dma_reg = dma[channel].addr; dma_set_page(channel, address >> 16); if (channel <= 3) { outportb(dma_reg, (address) & 0xff); outportb(dma_reg, (address >> 8) & 0xff); } else { outportb(dma_reg, (address >> 1) & 0xff); outportb(dma_reg, (address >> 9) & 0xff); } } /* Set transfer size for a specific DMA channel. Assumes dma flip-flop is clear. */ static inline void dma_set_count(unsigned int channel, unsigned int count) { unsigned char dma_reg = dma[channel].size; count--; /* number of DMA transfers is bigger by one */ if (channel > 3) count >>= 1; outportb(dma_reg, (count) & 0xff); outportb(dma_reg, (count >> 8) & 0xff); } /* Query the number of bytes left to transfer. Assumes DMA flip-flop is clear. */ static inline int dma_get_count(unsigned int channel) { unsigned char dma_reg = dma[channel].size; /* using short to get 16-bit wrap around */ unsigned short count; count = inportb(dma_reg); count |= inportb(dma_reg) << 8; count++; return (channel <= 3) ? count : (count << 1); } typedef struct dma_buffer_s { unsigned char *linear; /* Linear address */ unsigned long physical; /* Physical address */ unsigned long size; /* Buffer size */ unsigned short selector; /* The selector assigned to this memory */ unsigned char channel; /* The DMA channel */ } dma_buffer; /* Allocate a block of memory suitable for using as a DMA buffer */ extern dma_buffer *dma_allocate(unsigned int channel, unsigned int size); /* Deallocate a DMA buffer */ extern void dma_free(dma_buffer * buffer); /* Start DMA transfer to or from given buffer */ extern void dma_start(dma_buffer * buffer, unsigned long count, unsigned char mode); #endif /* __DOSDMA_H__ */ wildmidi-wildmidi-0.4.2/djgpp/dosirq.c000066400000000000000000000210631315765416100177030ustar00rootroot00000000000000/* Implementation of IRQ routines on DOS -- from libMikMod. Copyright (C) 1999 by Andrew Zabolotny, This file is part of WildMIDI. WildMIDI is free software: you can redistribute and/or modify the player under the terms of the GNU General Public License and you can redistribute and/or modify the library under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the licenses, or(at your option) any later version. WildMIDI 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 and the GNU Lesser General Public License for more details. You should have received a copy of the GNU General Public License and the GNU Lesser General Public License along with WildMIDI. If not, see . */ #include "dosirq.h" #include #include #include #include #include #include unsigned int __irq_stack_size = 0x4000; unsigned int __irq_stack_count = 1; static void __int_stub_template (void) { /* *INDENT-OFF* */ asm(" pushal\n" " pushl %ds\n" " pushl %es\n" " pushl %fs\n" " pushl %gs\n" " movw $0x1234,%ax\n" /* Get DPMI data selector */ " movw %ax,%ds\n" /* Set DS and ES to data selector */ " movw %ax,%es\n" " movl $0x12345678,%ebx\n" /* Interrupt stack top */ " movl (%ebx),%ecx\n" " movl %ecx,%edx\n" " subl $0x12345678,%ecx\n" /* Subtract irq_stack_count */ " movl %ecx,(%ebx)\n" " movw %ss,%si\n" /* Save old SS:ESP */ " movl %esp,%edi\n" " movl %edx,%esp\n" /* Set SS:ESP to interrupt stack */ " movw %ax,%ss\n" " pushl %esi\n" " pushl %edi\n" " pushl %ebx\n" " pushl %edx\n" " call 1f\n" /* Call user interrupt handler */ "1: popl %edx\n" " popl %ebx\n" " movl %edx,(%ebx)\n" " popl %edi\n" " popl %esi\n" " movl %edi,%esp\n" /* Restore old SS:ESP */ " movw %si,%ss\n" " popl %gs\n" " popl %fs\n" " popl %es\n" " popl %ds\n" " popal\n" " iret\n"); /* *INDENT-ON* */ } #include static int _allocate_iret_wrapper(_go32_dpmi_seginfo * info) { unsigned char *irqtpl = (unsigned char *)__int_stub_template; unsigned char *irqend, *irqwrapper, *tmp; __dpmi_meminfo handler_info; unsigned int wrappersize; /* First, skip until pushal */ while (*irqtpl != 0x60) irqtpl++; /* Now find the iret */ irqend = irqtpl; while (*irqend++ != 0xcf); wrappersize = 4 + __irq_stack_size * __irq_stack_count + 4 + ((long)irqend - (long)irqtpl); irqwrapper = (unsigned char *) malloc(wrappersize); /* Lock the wrapper */ handler_info.address = __djgpp_base_address + (unsigned long)irqwrapper; handler_info.size = wrappersize; if (__dpmi_lock_linear_region(&handler_info)) { free(irqwrapper); return -1; } /* First comes the interrupt wrapper size */ *(unsigned long *)irqwrapper = wrappersize; /* Next comes the interrupt stack */ tmp = irqwrapper + 4 + __irq_stack_size * __irq_stack_count; /* The following dword is interrupt stack pointer */ *((void **)tmp) = tmp; tmp += 4; /* Now comes the interrupt wrapper itself */ memcpy(tmp, irqtpl, irqend - irqtpl); *(unsigned short *)(tmp + 9) = _my_ds(); *(unsigned long *)(tmp + 16) = (unsigned long)tmp - 4; *(unsigned long *)(tmp + 26) = __irq_stack_size; *(unsigned long *)(tmp + 46) = info->pm_offset - (unsigned long)(tmp + 50); info->pm_offset = (unsigned long)tmp; info->pm_selector = _my_cs(); return 0; } static void _free_iret_wrapper(_go32_dpmi_seginfo * info) { __dpmi_meminfo handler_info; info->pm_offset -= 4 + __irq_stack_size * __irq_stack_count + 4; handler_info.address = __djgpp_base_address + info->pm_offset; handler_info.size = *(unsigned long *)info->pm_offset; __dpmi_unlock_linear_region(&handler_info); free((void *)info->pm_offset); } struct irq_handle *irq_hook(int irqno, void (*handler)(), unsigned long size) { int interrupt; struct irq_handle *irq; __dpmi_version_ret version; __dpmi_meminfo handler_info, struct_info; _go32_dpmi_seginfo info; unsigned long old_sel, old_ofs; __dpmi_get_version(&version); if (irqno < 8) interrupt = version.master_pic + irqno; else interrupt = version.slave_pic + (irqno - 8); if (_go32_dpmi_get_protected_mode_interrupt_vector(interrupt, &info)) return NULL; old_sel = info.pm_selector; old_ofs = info.pm_offset; info.pm_offset = (unsigned long)handler; if (_allocate_iret_wrapper(&info)) return NULL; /* Lock the interrupt handler in memory */ handler_info.address = __djgpp_base_address + (unsigned long)handler; handler_info.size = size; if (__dpmi_lock_linear_region(&handler_info)) { _free_iret_wrapper(&info); return NULL; } irq = (struct irq_handle *) malloc(sizeof(struct irq_handle)); irq->c_handler = handler; irq->handler_size = size; irq->handler = info.pm_offset; irq->prev_selector = old_sel; irq->prev_offset = old_ofs; irq->int_num = interrupt; irq->irq_num = irqno; irq->pic_base = irqno < 8 ? PIC1_BASE : PIC2_BASE; struct_info.address = __djgpp_base_address + (unsigned long)irq; struct_info.size = sizeof(struct irq_handle); if (__dpmi_lock_linear_region(&struct_info)) { free(irq); __dpmi_unlock_linear_region(&handler_info); _free_iret_wrapper(&info); return NULL; } _go32_dpmi_set_protected_mode_interrupt_vector(interrupt, &info); irq->pic_mask = irq_state(irq); return irq; } void irq_unhook(struct irq_handle *irq) { _go32_dpmi_seginfo info; __dpmi_meminfo mem_info; if (!irq) return; /* Restore the interrupt vector */ irq_disable(irq); info.pm_offset = irq->prev_offset; info.pm_selector = irq->prev_selector; _go32_dpmi_set_protected_mode_interrupt_vector(irq->int_num, &info); /* Unlock the interrupt handler */ mem_info.address = __djgpp_base_address + (unsigned long)irq->c_handler; mem_info.size = irq->handler_size; __dpmi_unlock_linear_region(&mem_info); /* Unlock the irq_handle structure */ mem_info.address = __djgpp_base_address + (unsigned long)irq; mem_info.size = sizeof(struct irq_handle); __dpmi_unlock_linear_region(&mem_info); info.pm_offset = irq->handler; _free_iret_wrapper(&info); /* If IRQ was enabled before we hooked, restore enabled state */ if (irq->pic_mask) irq_enable(irq); else irq_disable(irq); free(irq); } /*---------------------------------------------- IRQ detection mechanism -----*/ static struct irq_handle *__irqs[16]; static int (*__irq_confirm) (int irqno); static volatile unsigned int __irq_mask; static volatile unsigned int __irq_count[16]; #define DECLARE_IRQ_HANDLER(irqno) \ static void __irq##irqno##_handler () \ { \ if (irq_check (__irqs [irqno]) && __irq_confirm (irqno)) \ { \ __irq_count [irqno]++; \ __irq_mask |= (1 << irqno); \ } \ irq_ack (__irqs [irqno]); \ } /* *INDENT-OFF* */ DECLARE_IRQ_HANDLER(0) DECLARE_IRQ_HANDLER(1) DECLARE_IRQ_HANDLER(2) DECLARE_IRQ_HANDLER(3) DECLARE_IRQ_HANDLER(4) DECLARE_IRQ_HANDLER(5) DECLARE_IRQ_HANDLER(6) DECLARE_IRQ_HANDLER(7) DECLARE_IRQ_HANDLER(8) DECLARE_IRQ_HANDLER(9) DECLARE_IRQ_HANDLER(10) DECLARE_IRQ_HANDLER(11) DECLARE_IRQ_HANDLER(12) DECLARE_IRQ_HANDLER(13) DECLARE_IRQ_HANDLER(14) DECLARE_IRQ_HANDLER(15) /* *INDENT-ON* */ static void (*__irq_handlers[16]) () = { __irq0_handler, __irq1_handler, __irq2_handler, __irq3_handler, __irq4_handler, __irq5_handler, __irq6_handler, __irq7_handler, __irq8_handler, __irq9_handler, __irq10_handler, __irq11_handler, __irq12_handler, __irq13_handler, __irq14_handler, __irq15_handler}; void irq_detect_start(unsigned int irqs, int (*irq_confirm) (int irqno)) { int i; __irq_mask = 0; __irq_confirm = irq_confirm; memset(&__irqs, 0, sizeof(__irqs)); memset((void *) &__irq_count, 0, sizeof(__irq_count)); /* Hook all specified IRQs */ for (i = 1; i <= 15; i++) if (irqs & (1 << i)) { __irqs[i] = irq_hook(i, __irq_handlers[i], 200); /* Enable the interrupt */ irq_enable(__irqs[i]); } /* Enable IRQ2 if we need at least one IRQ above 7 */ if (irqs & 0xff00) _irq_enable(2); } void irq_detect_end() { int i; for (i = 15; i >= 1; i--) if (__irqs[i]) irq_unhook(__irqs[i]); } int irq_detect_get(int irqno, unsigned int *irqmask) { int oldirq = disable(); int count = __irq_count[irqno]; *irqmask = __irq_mask; __irq_mask = 0; if (oldirq) enable(); return count; } void irq_detect_clear() { int oldirq = disable(); memset((void *) &__irq_count, 0, sizeof(__irq_count)); __irq_mask = 0; if (oldirq) enable(); } wildmidi-wildmidi-0.4.2/djgpp/dosirq.h000066400000000000000000000107241315765416100177120ustar00rootroot00000000000000/* Interface for IRQ routines on DOS -- from libMikMod. Copyright (C) 1999 by Andrew Zabolotny, This file is part of WildMIDI. WildMIDI is free software: you can redistribute and/or modify the player under the terms of the GNU General Public License and you can redistribute and/or modify the library under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the licenses, or(at your option) any later version. WildMIDI 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 and the GNU Lesser General Public License for more details. You should have received a copy of the GNU General Public License and the GNU Lesser General Public License along with WildMIDI. If not, see . */ #ifndef __DOSIRQ_H__ #define __DOSIRQ_H__ #include #define PIC1_BASE 0x20 /* PIC1 base */ #define PIC2_BASE 0xA0 /* PIC2 base */ struct irq_handle { void (*c_handler) (); /* The real interrupt handler */ unsigned long handler_size; /* The size of interrupt handler */ unsigned long handler; /* Interrupt wrapper address */ unsigned long prev_selector; /* Selector of previous handler */ unsigned long prev_offset; /* Offset of previous handler */ unsigned char irq_num; /* IRQ number */ unsigned char int_num; /* Interrupt number */ unsigned char pic_base; /* PIC base (0x20 or 0xA0) */ unsigned char pic_mask; /* Old PIC mask state */ }; /* Return the enabled state for specific IRQ */ static inline unsigned char irq_state(struct irq_handle * irq) { return ((~inportb(irq->pic_base + 1)) & (0x01 << (irq->irq_num & 7))); } /* Acknowledge the end of interrupt */ static inline void _irq_ack(int irqno) { outportb(irqno > 7 ? PIC2_BASE : PIC1_BASE, 0x60 | (irqno & 7)); /* For second controller we also should acknowledge first controller */ if (irqno > 7) outportb(PIC1_BASE, 0x20); /* 0x20, 0x62? */ } /* Acknowledge the end of interrupt */ static inline void irq_ack(struct irq_handle * irq) { outportb(irq->pic_base, 0x60 | (irq->irq_num & 7)); /* For second controller we also should acknowledge first controller */ if (irq->pic_base != PIC1_BASE) outportb(PIC1_BASE, 0x20); /* 0x20, 0x62? */ } /* Mask (disable) the particular IRQ given his ordinal */ static inline void _irq_disable(int irqno) { unsigned int port_no = (irqno < 8 ? PIC1_BASE : PIC2_BASE) + 1; outportb(port_no, inportb(port_no) | (1 << (irqno & 7))); } /* Unmask (enable) the particular IRQ given its ordinal */ static inline void _irq_enable(int irqno) { unsigned int port_no = (irqno < 8 ? PIC1_BASE : PIC2_BASE) + 1; outportb(port_no, inportb(port_no) & ~(1 << (irqno & 7))); } /* Mask (disable) the particular IRQ given its irq_handle structure */ static inline void irq_disable(struct irq_handle * irq) { outportb(irq->pic_base + 1, inportb(irq->pic_base + 1) | (1 << (irq->irq_num & 7))); } /* Unmask (enable) the particular IRQ given its irq_handle structure */ static inline void irq_enable(struct irq_handle * irq) { outportb(irq->pic_base + 1, inportb(irq->pic_base + 1) & ~(1 << (irq->irq_num & 7))); } /* Check if a specific IRQ is pending: return 0 is no */ static inline int irq_check(struct irq_handle * irq) { outportb(irq->pic_base, 0x0B); /* Read IRR vector */ return (inportb(irq->pic_base) & (1 << (irq->irq_num & 7))); } /* Hook a specific IRQ; NOTE: IRQ is disabled upon return, irq_enable() it */ extern struct irq_handle *irq_hook(int irqno, void (*handler)(), unsigned long size); /* Unhook a previously hooked IRQ */ extern void irq_unhook(struct irq_handle * irq); /* Start IRQ detection process (IRQ list is given with irq mask) */ /* irq_confirm should return "1" if the IRQ really comes from the device */ extern void irq_detect_start(unsigned int irqs, int (*irq_confirm) (int irqno)); /* Finish IRQ detection process */ extern void irq_detect_end(); /* Get the count of specific irqno that happened */ extern int irq_detect_get(int irqno, unsigned int *irqmask); /* Clear IRQ counters */ extern void irq_detect_clear(); /* The size of interrupt stack */ extern unsigned int __irq_stack_size; /* The number of nested interrupts that can be handled */ extern unsigned int __irq_stack_count; #endif /* __DOSIRQ_H__ */ wildmidi-wildmidi-0.4.2/djgpp/dossb.c000066400000000000000000000313021315765416100175110ustar00rootroot00000000000000/* Sound Blaster I/O routines, common for SB8, SBPro and SB16 -- from libMikMod. Written by Andrew Zabolotny Further bug fixes by O. Sezer This file is part of WildMIDI. WildMIDI is free software: you can redistribute and/or modify the player under the terms of the GNU General Public License and you can redistribute and/or modify the library under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the licenses, or(at your option) any later version. WildMIDI 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 and the GNU Lesser General Public License for more details. You should have received a copy of the GNU General Public License and the GNU Lesser General Public License along with WildMIDI. If not, see . */ #include #include #include #include #include #include #include #include "dossb.h" /********************************************* Private variables/routines *****/ __sb_state sb; /* Wait for SoundBlaster for some time */ #if (__GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ == 0) # define _func_noinline volatile /* match original code */ # define _func_noclone #else /* avoid warnings from newer gcc: * "function definition has qualified void return type" and * function return types not compatible due to 'volatile' */ # define _func_noinline __attribute__((__noinline__)) # if (__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ < 5) # define _func_noclone # else # define _func_noclone __attribute__((__noclone__)) # endif #endif _func_noinline _func_noclone void __sb_wait() { inportb(SB_DSP_RESET); inportb(SB_DSP_RESET); inportb(SB_DSP_RESET); inportb(SB_DSP_RESET); inportb(SB_DSP_RESET); inportb(SB_DSP_RESET); } static void sb_irq() { /* Make sure its not a spurious IRQ */ if (!irq_check(sb.irq_handle)) return; sb.irqcount++; /* Acknowledge DMA transfer is complete */ if (sb.mode & SBMODE_16BITS) __sb_dsp_ack_dma16(); else __sb_dsp_ack_dma8(); /* SoundBlaster 1.x cannot do autoinit ... */ if (sb.dspver < SBVER_20) __sb_dspreg_outwlh(SBDSP_DMA_PCM8, (sb.dma_buff->size >> 1) - 1); /* Send EOI */ irq_ack(sb.irq_handle); enable(); if (sb.timer_callback) sb.timer_callback(); } static void sb_irq_end() { } static boolean __sb_reset() { /* Disable the output */ sb_output(FALSE); /* Clear pending ints if any */ __sb_dsp_ack_dma8(); __sb_dsp_ack_dma16(); /* Reset the DSP */ outportb(SB_DSP_RESET, SBM_DSP_RESET); __sb_wait(); __sb_wait(); outportb(SB_DSP_RESET, 0); /* Now wait for AA coming from datain port */ if (__sb_dsp_in() != 0xaa) return FALSE; /* Finally, get the DSP version */ if ((sb.dspver = __sb_dsp_version()) == 0xffff) return FALSE; /* Check again */ if (sb.dspver != __sb_dsp_version()) return FALSE; return TRUE; } /***************************************************** SB detection stuff *****/ static int __sb_irq_irqdetect(int irqno) { (void)irqno; __sb_dsp_ack_dma8(); return 1; } static void __sb_irq_dmadetect() { /* Make sure its not a spurious IRQ */ if (!irq_check(sb.irq_handle)) return; sb.irqcount++; /* Acknowledge DMA transfer is complete */ if (sb.mode & SBMODE_16BITS) __sb_dsp_ack_dma16(); else __sb_dsp_ack_dma8(); /* Send EOI */ irq_ack(sb.irq_handle); } static boolean __sb_detect() { /* First find the port number */ if (!sb.port) { int i; for (i = 5; i >= 0; i--) { sb.port = 0x210 + i * 0x10; if (__sb_reset()) break; } if (i < 0) { sb.port = 0; return FALSE; } } /* Now detect the IRQ and DMA numbers */ if (!sb.irq) { unsigned int irqmask, sbirqmask, sbirqcount; unsigned long timer; /* IRQ can be one of 2,3,5,7,10 */ irq_detect_start(0x04ac, __sb_irq_irqdetect); /* Prepare timeout counter */ _farsetsel(_dos_ds); timer = _farnspeekl(0x46c); sbirqmask = 0; sbirqcount = 10; /* Emit 10 SB irqs */ /* Tell SoundBlaster to emit IRQ for 8-bit transfers */ __sb_dsp_out(SBDSP_GEN_IRQ8); __sb_wait(); for (;;) { irq_detect_get(0, &irqmask); if (irqmask) { sbirqmask |= irqmask; if (!--sbirqcount) break; __sb_dsp_out(SBDSP_GEN_IRQ8); } if (_farnspeekl(0x46c) - timer >= 9) /* Wait ~1/2 secs */ break; } if (sbirqmask) for (sb.irq = 15; sb.irq > 0; sb.irq--) if (irq_detect_get(sb.irq, &irqmask) == 10) break; irq_detect_end(); if (!sb.irq) return FALSE; } /* Detect the 8-bit and 16-bit DMAs */ if (!sb.dma8 || ((sb.dspver >= SBVER_16) && !sb.dma16)) { static int __dma8[] = { 0, 1, 3 }; static int __dma16[] = { 5, 6, 7 }; int *dma; sb_output(FALSE); /* Temporary hook SB IRQ */ sb.irq_handle = irq_hook(sb.irq, __sb_irq_dmadetect, 200); irq_enable(sb.irq_handle); if (sb.irq > 7) _irq_enable(2); /* Start a short DMA transfer and check if IRQ happened */ for (;;) { int i, oldcount; unsigned int timer; if (!sb.dma8) dma = &sb.dma8; else if ((sb.dspver >= SBVER_16) && !sb.dma16) dma = &sb.dma16; else break; for (i = 0; i < 3; i++) { boolean success = 1; *dma = (dma == &sb.dma8) ? __dma8[i] : __dma16[i]; oldcount = sb.irqcount; dma_disable(*dma); dma_set_mode(*dma, DMA_MODE_WRITE); dma_clear_ff(*dma); dma_set_count(*dma, 2); dma_enable(*dma); __sb_dspreg_out(SBDSP_SET_TIMING, 206); /* 20KHz */ if (dma == &sb.dma8) { sb.mode = 0; __sb_dspreg_outwlh(SBDSP_DMA_PCM8, 1); } else { sb.mode = SBMODE_16BITS; __sb_dspreg_out(SBDSP_DMA_GENERIC16, 0); __sb_dsp_out(0); __sb_dsp_out(1); } _farsetsel(_dos_ds); timer = _farnspeekl(0x46c); while (oldcount == sb.irqcount) if (_farnspeekl(0x46c) - timer >= 2) { success = 0; break; } dma_disable(*dma); if (success) break; *dma = 0; } if (!*dma) break; } irq_unhook(sb.irq_handle); sb.irq_handle = NULL; if (!sb.dma8 || ((sb.dspver >= SBVER_16) && !sb.dma16)) return FALSE; } return TRUE; } /*************************************************** High-level interface *****/ /* Detect whenever SoundBlaster is present and fill "sb" structure */ boolean sb_detect() { char *env; /* Try to find the port and DMA from environment */ env = getenv("BLASTER"); while (env && *env) { /* Skip whitespace */ while ((*env == ' ') || (*env == '\t')) env++; if (!*env) break; switch (*env++) { case 'A': case 'a': if (!sb.port) sb.port = strtol(env, &env, 16); break; case 'E': case 'e': if (!sb.aweport) sb.aweport = strtol(env, &env, 16); break; case 'I': case 'i': if (!sb.irq) sb.irq = strtol(env, &env, 10); break; case 'D': case 'd': if (!sb.dma8) sb.dma8 = strtol(env, &env, 10); break; case 'H': case 'h': if (!sb.dma16) sb.dma16 = strtol(env, &env, 10); break; default: /* Skip other values (H == MIDI, T == model, any other?) */ while (*env && (*env != ' ') && (*env != '\t')) env++; break; } } /* Try to detect missing sound card parameters */ __sb_detect(); if (!sb.port || !sb.irq || !sb.dma8) return FALSE; if (!__sb_reset()) return FALSE; if ((sb.dspver >= SBVER_16) && !sb.dma16) return FALSE; if (sb.dspver >= SBVER_PRO) sb.caps |= SBMODE_STEREO; if (sb.dspver >= SBVER_16 && sb.dma16) sb.caps |= SBMODE_16BITS; if (sb.dspver < SBVER_20) sb.maxfreq_mono = 22222; else sb.maxfreq_mono = 45454; if (sb.dspver <= SBVER_16) sb.maxfreq_stereo = 22727; else sb.maxfreq_stereo = 45454; sb.ok = 1; return TRUE; } /* Reset SoundBlaster */ void sb_reset() { sb_stop_dma(); __sb_reset(); } /* Start working with SoundBlaster */ boolean sb_open() { __dpmi_meminfo struct_info; if (!sb.ok) if (!sb_detect()) return FALSE; if (sb.open) return FALSE; /* Now lock the sb structure in memory */ struct_info.address = __djgpp_base_address + (unsigned long)&sb; struct_info.size = sizeof(sb); if (__dpmi_lock_linear_region(&struct_info)) return FALSE; /* Hook the SB IRQ */ sb.irq_handle = irq_hook(sb.irq, sb_irq, (long)sb_irq_end - (long)sb_irq); if (!sb.irq_handle) { __dpmi_unlock_linear_region(&struct_info); return FALSE; } /* Enable the interrupt */ irq_enable(sb.irq_handle); if (sb.irq > 7) _irq_enable(2); sb.open++; return TRUE; } /* Finish working with SoundBlaster */ boolean sb_close() { __dpmi_meminfo struct_info; if (!sb.open) return FALSE; sb.open--; /* Stop/free DMA buffer */ sb_stop_dma(); /* Unhook IRQ */ irq_unhook(sb.irq_handle); sb.irq_handle = NULL; /* Unlock the sb structure */ struct_info.address = __djgpp_base_address + (unsigned long)&sb; struct_info.size = sizeof(sb); __dpmi_unlock_linear_region(&struct_info); return TRUE; } /* Enable/disable stereo DSP mode */ /* Enable/disable speaker output */ void sb_output(boolean enable) { __sb_dsp_out(enable ? SBDSP_SPEAKER_ENA : SBDSP_SPEAKER_DIS); } /* Start playing from DMA buffer */ boolean sb_start_dma(unsigned char mode, unsigned int freq) { int dmachannel = (mode & SBMODE_16BITS) ? sb.dma16 : sb.dma8; int dmabuffsize; unsigned int tc = 0; /* timing constant (<=sbpro only) */ /* Stop DMA transfer if it is enabled */ sb_stop_dma(); /* Sanity check */ if ((mode & SBMODE_MASK & sb.caps) != (mode & SBMODE_MASK)) return FALSE; /* Check this SB can perform at requested frequency */ if (((mode & SBMODE_STEREO) && (freq > sb.maxfreq_stereo)) || (!(mode & SBMODE_STEREO) && (freq > sb.maxfreq_mono))) return FALSE; /* Check the timing constant here to avoid failing later */ if (sb.dspver < SBVER_16) { /* SBpro cannot do signed transfer */ if (mode & SBMODE_SIGNED) return FALSE; /* Old SBs have a different way on setting DMA timing constant */ tc = freq; if (mode & SBMODE_STEREO) tc *= 2; tc = 1000000 / tc; if (tc > 255) return FALSE; } sb.mode = mode; /* Get a DMA buffer enough for a 1/4sec interval... 4K <= dmasize <= 32K */ dmabuffsize = freq; if (mode & SBMODE_STEREO) dmabuffsize *= 2; if (mode & SBMODE_16BITS) dmabuffsize *= 2; dmabuffsize >>= 2; if (dmabuffsize < 4096) dmabuffsize = 4096; if (dmabuffsize > 32768) dmabuffsize = 32768; dmabuffsize = (dmabuffsize + 255) & 0xffffff00; sb.dma_buff = dma_allocate(dmachannel, dmabuffsize); if (!sb.dma_buff) return FALSE; /* Fill DMA buffer with silence */ dmabuffsize = sb.dma_buff->size; if (mode & SBMODE_SIGNED) memset(sb.dma_buff->linear, 0, dmabuffsize); else memset(sb.dma_buff->linear, 0x80, dmabuffsize); /* Prime DMA for transfer */ dma_start(sb.dma_buff, dmabuffsize, DMA_MODE_WRITE | DMA_MODE_AUTOINIT); /* Tell SoundBlaster to start transfer */ if (sb.dspver >= SBVER_16) { /* SB16 */ __sb_dspreg_outwhl(SBDSP_SET_RATE, freq); /* Start DMA->DAC transfer */ __sb_dspreg_out(SBM_GENDAC_AUTOINIT | SBM_GENDAC_FIFO | ((mode & SBMODE_16BITS) ? SBDSP_DMA_GENERIC16 : SBDSP_DMA_GENERIC8), ((mode & SBMODE_SIGNED) ? SBM_GENDAC_SIGNED : 0) | ((mode & SBMODE_STEREO) ? SBM_GENDAC_STEREO : 0)); /* Write the length of transfer */ dmabuffsize = (dmabuffsize >> 2) - 1; __sb_dsp_out(dmabuffsize); __sb_dsp_out(dmabuffsize >> 8); } else { __sb_dspreg_out(SBDSP_SET_TIMING, 256 - tc); dmabuffsize = (dmabuffsize >> 1) - 1; if (sb.dspver >= SBVER_20) { /* SB 2.0/Pro */ /* Set stereo mode */ __sb_stereo((mode & SBMODE_STEREO) ? TRUE : FALSE); __sb_dspreg_outwlh(SBDSP_SET_DMA_BLOCK, dmabuffsize); if (sb.dspver >= SBVER_PRO) __sb_dsp_out(SBDSP_HS_DMA_DAC8_AUTO); else __sb_dsp_out(SBDSP_DMA_PCM8_AUTO); } else { /* Original SB */ /* Start DMA->DAC transfer */ __sb_dspreg_outwlh(SBDSP_DMA_PCM8, dmabuffsize); } } return TRUE; } /* Stop playing from DMA buffer */ void sb_stop_dma() { if (!sb.dma_buff) return; if (sb.mode & SBMODE_16BITS) __sb_dsp_out(SBDSP_DMA_HALT16); else __sb_dsp_out(SBDSP_DMA_HALT8); dma_disable(sb.dma_buff->channel); dma_free(sb.dma_buff); sb.dma_buff = NULL; } /* Query current position/total size of the DMA buffer */ void sb_query_dma(unsigned int *dma_size, unsigned int *dma_pos) { unsigned int dma_left; *dma_size = sb.dma_buff->size; /* It can happen we try to read DMA count when HI/LO bytes will be inconsistent */ for (;;) { unsigned int dma_left_test; dma_clear_ff(sb.dma_buff->channel); dma_left_test = dma_get_count(sb.dma_buff->channel); dma_left = dma_get_count(sb.dma_buff->channel); if ((dma_left >= dma_left_test) && (dma_left - dma_left_test < 10)) break; } *dma_pos = *dma_size - dma_left; } wildmidi-wildmidi-0.4.2/djgpp/dossb.h000066400000000000000000000353041315765416100175240ustar00rootroot00000000000000/* SoundBlaster and compatible soundcards definitions -- from libMikMod. Written by Andrew Zabolotny Further bug fixes by O.Sezer This file is part of WildMIDI. WildMIDI is free software: you can redistribute and/or modify the player under the terms of the GNU General Public License and you can redistribute and/or modify the library under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the licenses, or(at your option) any later version. WildMIDI 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 and the GNU Lesser General Public License for more details. You should have received a copy of the GNU General Public License and the GNU Lesser General Public License along with WildMIDI. If not, see . */ #ifndef __DOSSB_H__ #define __DOSSB_H__ #include "dosdma.h" #include "dosirq.h" #define SB_FM_LEFT_STATUS (sb.port + 0x00) /* (r) Left FM status */ #define SB_FM_LEFT_REGSEL (sb.port + 0x00) /* (w) Left FM register select */ #define SB_FM_LEFT_DATA (sb.port + 0x01) /* (w) Left FM data */ #define SB_FM_RIGHT_STATUS (sb.port + 0x02) /* (r) Right FM status */ #define SB_FM_RIGHT_REGSEL (sb.port + 0x02) /* (w) Right FM register select */ #define SB_FM_RIGHT_DATA (sb.port + 0x03) /* (w) Right FM data */ #define SB_MIXER_REGSEL (sb.port + 0x04) /* (w) Mixer register select */ #define SB_MIXER_DATA (sb.port + 0x05) /* (rw)Mixer data */ #define SB_DSP_RESET (sb.port + 0x06) /* (w) DSP reset */ #define SB_FM_STATUS (sb.port + 0x08) /* (r) FM status */ #define SB_FM_REGSEL (sb.port + 0x08) /* (w) FM register select */ #define SB_FM_DATA (sb.port + 0x09) /* (w) FM data */ #define SB_DSP_DATA_IN (sb.port + 0x0a) /* (r) DSP data input */ #define SB_DSP_DATA_OUT (sb.port + 0x0c) /* (w) DSP data output */ #define SB_DSP_DATA_OUT_STATUS (sb.port + 0x0c) /* (r) DSP data output status */ #define SB_DSP_TIMER_IRQ (sb.port + 0x0d) /* (r) clear timer IRQ? */ #define SB_DSP_DATA_IN_STATUS (sb.port + 0x0e) /* (r) DSP data input status */ #define SB_DSP_DMA8_IRQ (sb.port + 0x0e) /* (r) Acknowledge 8-bit DMA transfer */ #define SB_DSP_DMA16_IRQ (sb.port + 0x0f) /* (r) Acknowledge 16-bit DMA transfer */ /* DSP commands */ #define SBDSP_ASP_STATUS 0x03 /* ASP Status (SB16ASP) */ #define SBDSP_STATUS_OLD 0x04 /* DSP Status (Obsolete) (SB2.0-Pro2) */ #define SBDSP_DIRECT_DAC 0x10 /* Direct DAC, 8-bit (SB) */ #define SBDSP_DMA_PCM8 0x14 /* DMA DAC, 8-bit (SB) */ #define SBDSP_DMA_ADPCM2 0x16 /* DMA DAC, 2-bit ADPCM (SB) */ #define SBDSP_DMA_ADPCM2R 0x17 /* DMA DAC, 2-bit ADPCM Reference (SB) */ #define SBDSP_DMA_PCM8_AUTO 0x1C /* Auto-Initialize DMA DAC, 8-bit (SB2.0) */ #define SBDSP_DMA_ADPCM2R_AUTO 0x1F /* Auto-Initialize DMA DAC, 2-bit ADPCM Reference (SB2.0) */ #define SBDSP_DIRECT_ADC 0x20 /* Direct ADC, 8-bit (SB) */ #define SBDSP_DMA_ADC8 0x24 /* DMA ADC, 8-bit (SB) */ #define SBDSP_DIRECT_ADC8_BURST 0x28 /* Direct ADC, 8-bit (Burst) (SB-Pro2) */ #define SBDSP_DMA_ADC8_AUTO 0x2C /* Auto-Initialize DMA ADC, 8-bit (SB2.0) */ #define SBDSP_MIDI_READ_POLL 0x30 /* MIDI Read Poll (SB) */ #define SBDSP_MIDI_READ_IRQ 0x31 /* MIDI Read Interrupt (SB) */ #define SBDSP_MIDI_READ_TIME 0x32 /* MIDI Read Timestamp Poll (SB???) */ #define SBDSP_MIDI_READ_TIME_IRQ 0x33 /* MIDI Read Timestamp Interrupt (SB???) */ #define SBDSP_MIDI_RW_POLL 0x34 /* MIDI Read Poll + Write Poll (UART) (SB2.0) */ #define SBDSP_MIDI_RW_IRQ 0x35 /* MIDI Read Interrupt + Write Poll (UART) (SB2.0???) */ #define SBDSP_MIDI_RW_TIME_IRQ 0x37 /* MIDI Read Timestamp Interrupt + Write Poll (UART) (SB2.0???) */ #define SBDSP_MIDI_WRITE_POLL 0x38 /* MIDI Write Poll (SB) */ #define SBDSP_SET_TIMING 0x40 /* Set Time Constant (SB) */ #define SBDSP_SET_RATE 0x41 /* Set Sample Rate, Hz (SB16) */ #define SBDSP_DMA_CONT8_AUTO 0x45 /* Continue Auto-Initialize DMA, 8-bit (SB16) */ #define SBDSP_DMA_CONT16_AUTO 0x47 /* Continue Auto-Initialize DMA, 16-bit (SB16) */ #define SBDSP_SET_DMA_BLOCK 0x48 /* Set DMA Block Size (SB2.0) */ #define SBDSP_DMA_ADPCM4 0x74 /* DMA DAC, 4-bit ADPCM (SB) */ #define SBDSP_DMA_ADPCM4_REF 0x75 /* DMA DAC, 4-bit ADPCM Reference (SB) */ #define SBDSP_DMA_ADPCM26 0x76 /* DMA DAC, 2.6-bit ADPCM (SB) */ #define SBDSP_DMA_ADPCM26_REF 0x77 /* DMA DAC, 2.6-bit ADPCM Reference (SB) */ #define SBDSP_DMA_ADPCM4R_AUTO 0x7D /* Auto-Initialize DMA DAC, 4-bit ADPCM Reference (SB2.0) */ #define SBDSP_DMA_ADPCM26R_AUTO 0x7F /* Auto-Initialize DMA DAC, 2.6-bit ADPCM Reference (SB2.0) */ #define SBDSP_DISABLE_DAC 0x80 /* Silence DAC (SB) */ #define SBDSP_HS_DMA_DAC8_AUTO 0x90 /* Auto-Initialize DMA DAC, 8-bit (High Speed) (SB2.0-Pro2) */ #define SBDSP_HS_DMA_ADC8_AUTO 0x98 /* Auto-Initialize DMA ADC, 8-bit (High Speed) (SB2.0-Pro2) */ #define SBDSP_STEREO_ADC_DIS 0xA0 /* Disable Stereo Input Mode (SBPro Only) */ #define SBDSP_STEREO_ADC_ENA 0xA8 /* Enable Stereo Input Mode (SBPro Only) */ #define SBDSP_DMA_GENERIC16 0xB0 /* Generic DAC/ADC DMA (16-bit) (SB16) */ #define SBDSP_DMA_GENERIC8 0xC0 /* Generic DAC/ADC DMA (8-bit) (SB16) */ #define SBDSP_DMA_HALT8 0xD0 /* Halt DMA Operation, 8-bit (SB) */ #define SBDSP_SPEAKER_ENA 0xD1 /* Enable Speaker (SB) */ #define SBDSP_SPEAKER_DIS 0xD3 /* Disable Speaker (SB) */ #define SBDSP_DMA_CONT8 0xD4 /* Continue DMA Operation, 8-bit (SB) */ #define SBDSP_DMA_HALT16 0xD5 /* Halt DMA Operation, 16-bit (SB16) */ #define SBDSP_DMA_CONT16 0xD6 /* Continue DMA Operation, 16-bit (SB16) */ #define SBDSP_SPEAKER_STATUS 0xD8 /* Speaker Status (SB) */ #define SBDSP_DMA_EXIT16_AUTO 0xD9 /* Exit Auto-Initialize DMA Operation, 16-bit (SB16) */ #define SBDSP_DMA_EXIT8_AUTO 0xDA /* Exit Auto-Initialize DMA Operation, 8-bit (SB2.0) */ #define SBDSP_IDENTIFY 0xE0 /* DSP Identification (SB2.0) */ #define SBDSP_VERSION 0xE1 /* DSP Version (SB) */ #define SBDSP_COPYRIGHT 0xE3 /* DSP Copyright (SBPro2???) */ #define SBDSP_WRITE_TEST 0xE4 /* Write Test Register (SB2.0) */ #define SBDSP_READ_TEST 0xE8 /* Read Test Register (SB2.0) */ #define SBDSP_SINE_GEN 0xF0 /* Sine Generator (SB) */ #define SBDSP_AUX_STATUS_PRO 0xF1 /* DSP Auxiliary Status (Obsolete) (SB-Pro2) */ #define SBDSP_GEN_IRQ8 0xF2 /* IRQ Request, 8-bit (SB) */ #define SBDSP_GEN_IRQ16 0xF3 /* IRQ Request, 16-bit (SB16) */ #define SBDSP_STATUS 0xFB /* DSP Status (SB16) */ #define SBDSP_AUX_STATUS_16 0xFC /* DSP Auxiliary Status (SB16) */ #define SBDSP_CMD_STATUS 0xFD /* DSP Command Status (SB16) */ /* Mixer commands */ #define SBMIX_RESET 0x00 /* Reset Write SBPro */ #define SBMIX_STATUS 0x01 /* Status Read SBPro */ #define SBMIX_MASTER_LEVEL1 0x02 /* Master Volume Read/Write SBPro Only */ #define SBMIX_DAC_LEVEL 0x04 /* DAC Level Read/Write SBPro */ #define SBMIX_FM_OUTPUT 0x06 /* FM Output Control Read/Write SBPro Only */ #define SBMIX_MIC_LEVEL 0x0A /* Microphone Level Read/Write SBPro */ #define SBMIX_INPUT_SELECT 0x0C /* Input/Filter Select Read/Write SBPro Only */ #define SBMIX_OUTPUT_SELECT 0x0E /* Output/Stereo Select Read/Write SBPro Only */ #define SBMIX_FM_LEVEL 0x22 /* Master Volume Read/Write SBPro */ #define SBMIX_MASTER_LEVEL 0x26 /* FM Level Read/Write SBPro */ #define SBMIX_CD_LEVEL 0x28 /* CD Audio Level Read/Write SBPro */ #define SBMIX_LINEIN_LEVEL 0x2E /* Line In Level Read/Write SBPro */ #define SBMIX_MASTER_LEVEL_L 0x30 /* Master Volume Left Read/Write SB16 */ #define SBMIX_MASTER_LEVEL_R 0x31 /* Master Volume Right Read/Write SB16 */ #define SBMIX_DAC_LEVEL_L 0x32 /* DAC Level Left Read/Write SB16 */ #define SBMIX_DAC_LEVEL_R 0x33 /* DAC Level Right Read/Write SB16 */ #define SBMIX_FM_LEVEL_L 0x34 /* FM Level Left Read/Write SB16 */ #define SBMIX_FM_LEVEL_R 0x35 /* FM Level Right Read/Write SB16 */ #define SBMIX_CD_LEVEL_L 0x36 /* CD Audio Level Left Read/Write SB16 */ #define SBMIX_CD_LEVEL_R 0x37 /* CD Audio Level Right Read/Write SB16 */ #define SBMIX_LINEIN_LEVEL_L 0x38 /* Line In Level Left Read/Write SB16 */ #define SBMIX_LINEIN_LEVEL_R 0x39 /* Line In Level Right Read/Write SB16 */ #define SBMIX_MIC_LEVEL_16 0x3A /* Microphone Level Read/Write SB16 */ #define SBMIX_PCSPK_LEVEL 0x3B /* PC Speaker Level Read/Write SB16 */ #define SBMIX_OUTPUT_CONTROL 0x3C /* Output Control Read/Write SB16 */ #define SBMIX_INPUT_CONTROL_L 0x3D /* Input Control Left Read/Write SB16 */ #define SBMIX_INPUT_CONTROL_R 0x3E /* Input Control Right Read/Write SB16 */ #define SBMIX_INPUT_GAIN_L 0x3F /* Input Gain Control Left Read/Write SB16 */ #define SBMIX_INPUT_GAIN_R 0x40 /* Input Gain Control Right Read/Write SB16 */ #define SBMIX_OUTPUT_GAIN_L 0x41 /* Output Gain Control Left Read/Write SB16 */ #define SBMIX_OUTPUT_GAIN_R 0x42 /* Output Gain Control Right Read/Write SB16 */ #define SBMIX_AGC_CONTROL 0x43 /* Automatic Gain Control (AGC) Read/Write SB16 */ #define SBMIX_TREBLE_L 0x44 /* Treble Left Read/Write SB16 */ #define SBMIX_TREBLE_R 0x45 /* Treble Right Read/Write SB16 */ #define SBMIX_BASS_L 0x46 /* Bass Left Read/Write SB16 */ #define SBMIX_BASS_R 0x47 /* Bass Right Read/Write SB16 */ #define SBMIX_IRQ_SELECT 0x80 /* IRQ Select Read/Write SB16 */ #define SBMIX_DMA_SELECT 0x81 /* DMA Select Read/Write SB16 */ #define SBMIX_IRQ_STATUS 0x82 /* IRQ Status Read SB16 */ /* SB_DSP_DATA_OUT_STATUS and SB_DSP_DATA_IN_STATUS bits */ #define SBM_DSP_READY 0x80 /* SB_DSP_RESET / SBMIX_RESET */ #define SBM_DSP_RESET 0x01 /* SBMIX_OUTPUT_SELECT */ #define SBM_MIX_STEREO 0x02 #define SBM_MIX_FILTER 0x20 /* SBDSP_DMA_GENERIC16/SBDSP_DMA_GENERIC8 */ #define SBM_GENDAC_FIFO 0x02 #define SBM_GENDAC_AUTOINIT 0x04 #define SBM_GENDAC_ADC 0x08 /* Second (mode) byte */ #define SBM_GENDAC_SIGNED 0x10 #define SBM_GENDAC_STEREO 0x20 /* DSP version masks */ #define SBVER_10 0x0100 /* Original SoundBlaster */ #define SBVER_15 0x0105 /* SoundBlaster 1.5 */ #define SBVER_20 0x0200 /* SoundBlaster 2.0 */ #define SBVER_PRO 0x0300 /* SoundBlaster Pro */ #define SBVER_PRO2 0x0301 /* SoundBlaster Pro 2 */ #define SBVER_16 0x0400 /* SoundBlaster 16 */ #define SBVER_AWE32 0x040c /* SoundBlaster AWE32 */ typedef unsigned char boolean; #ifndef FALSE #define FALSE 0 #define TRUE 1 #endif /* Play mode bits */ #define SBMODE_16BITS 0x0001 #define SBMODE_STEREO 0x0002 #define SBMODE_SIGNED 0x0004 /* Mask for capabilities that never change */ #define SBMODE_MASK (SBMODE_16BITS | SBMODE_STEREO) /* You can fill some members of this struct (i.e. port,irq,dma) before * calling sb_detect() or sb_open()... this will ignore environment settings. */ typedef struct __sb_state_s { boolean ok; /* Are structure contents valid? */ int port, aweport; /* sb/awe32 base port */ int irq; /* SoundBlaster IRQ */ int dma8, dma16; /* 8-bit and 16-bit DMAs */ unsigned maxfreq_mono; /* Maximum discretization frequency / mono mode */ unsigned maxfreq_stereo; /* Maximum discretization frequency / stereo mode */ unsigned short dspver; /* DSP version number */ struct irq_handle *irq_handle; /* The interrupt handler */ dma_buffer *dma_buff; /* Pre-allocated DMA buffer */ unsigned char caps; /* SoundBlaster capabilities (SBMODE_XXX) */ unsigned char mode; /* Current SB mode (SBMODE_XXX) */ boolean open; /* Whenever the card has been opened */ volatile int irqcount; /* Incremented on each IRQ... for diagnostics */ void (*timer_callback) (); /* Called TWICE per buffer play */ } __sb_state; extern __sb_state sb; extern void __sb_wait(); static inline boolean __sb_dsp_ready_in() { int count; for (count = 10000; count >= 0; count--) if (inportb(SB_DSP_DATA_IN_STATUS) & SBM_DSP_READY) return TRUE; return FALSE; } static inline boolean __sb_dsp_ready_out() { int count; for (count = 10000; count >= 0; count--) if ((inportb(SB_DSP_DATA_OUT_STATUS) & SBM_DSP_READY) == 0) return TRUE; return FALSE; } static inline void __sb_dsp_out(unsigned char reg) { __sb_dsp_ready_out(); outportb(SB_DSP_DATA_OUT, reg); } static inline unsigned char __sb_dsp_in() { __sb_dsp_ready_in(); return inportb(SB_DSP_DATA_IN); } static inline void __sb_dspreg_out(unsigned char reg, unsigned char val) { __sb_dsp_out(reg); __sb_dsp_out(val); } static inline void __sb_dspreg_outwlh(unsigned char reg, unsigned short val) { __sb_dsp_out(reg); __sb_dsp_out(val); __sb_dsp_out(val >> 8); } static inline void __sb_dspreg_outwhl(unsigned char reg, unsigned short val) { __sb_dsp_out(reg); __sb_dsp_out(val >> 8); __sb_dsp_out(val); } static inline unsigned char __sb_dspreg_in(unsigned char reg) { __sb_dsp_out(reg); return __sb_dsp_in(); } static inline void __sb_dsp_ack_dma8() { inportb(SB_DSP_DMA8_IRQ); } static inline void __sb_dsp_ack_dma16() { inportb(SB_DSP_DMA16_IRQ); } static inline unsigned short __sb_dsp_version() { unsigned short ver; __sb_dsp_out(SBDSP_VERSION); __sb_dsp_ready_in(); ver = ((unsigned short)__sb_dsp_in()) << 8; ver |= __sb_dsp_in(); return ver; } static inline void __sb_mixer_out(unsigned char reg, unsigned char val) { outportb(SB_MIXER_REGSEL, reg); outportb(SB_MIXER_DATA, val); } static inline unsigned char __sb_mixer_in(unsigned char reg) { outportb(SB_MIXER_REGSEL, reg); return inportb(SB_MIXER_DATA); } /* Enable stereo transfers: sbpro mode only */ static inline void __sb_stereo(boolean stereo) { unsigned char val = __sb_mixer_in(SBMIX_OUTPUT_SELECT); if (stereo) val |= SBM_MIX_STEREO; else val &= ~SBM_MIX_STEREO; __sb_mixer_out(SBMIX_OUTPUT_SELECT, val); } /* Detect whenever SoundBlaster is present and fill "sb" structure */ extern boolean sb_detect(); /* Reset SoundBlaster */ extern void sb_reset(); /* Start working with SoundBlaster */ extern boolean sb_open(); /* Finish working with SoundBlaster */ extern boolean sb_close(); /* Enable/disable speaker output */ extern void sb_output(boolean enable); /* Start playing from DMA buffer in either 8/16 bit mono/stereo */ extern boolean sb_start_dma(unsigned char mode, unsigned int freq); /* Stop playing from DMA buffer */ extern void sb_stop_dma(); /* Query current position/total size of the DMA buffer */ extern void sb_query_dma(unsigned int *dma_size, unsigned int *dma_pos); #endif /* __DOSSB_H__ */ wildmidi-wildmidi-0.4.2/docs/000077500000000000000000000000001315765416100160605ustar00rootroot00000000000000wildmidi-wildmidi-0.4.2/docs/formats/000077500000000000000000000000001315765416100175335ustar00rootroot00000000000000wildmidi-wildmidi-0.4.2/docs/formats/HmiFileFormat.txt000066400000000000000000000110311315765416100227560ustar00rootroot00000000000000HMP File Format (Incomplete - Under Construction) Document version 1 Authored by Chris Ison chrisisonwildcode@gmail.com Last Edited 24 May 2014 Copyright (C) 2014 WildMidi Developers This document is licensed under the Creative Commons Attribution-ShareAlike 4.0 International License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/4.0/ Introduction This document describes the HMI format as used by the WildMIDI project. It is not a complete description of the HMI file format and only those parts that have been decyphered and are relevant to the WildMidi project are described here. Unfortunately we cannot answer questions about the format that are not described within this document. If you feel there is an error in this document please feel free to report it as a bug at https://github.com/Mindwerks/wildmidi/issues/ Description // Header { char header[18] = "HMI-MIDISONG061595"; char no_idea_1[196]; char beats_per_minute; char no_idea_2[15]; char track_count; char no_idea_3[141]; { // Repeat for number of tracks in track_count char track_offset[4]; // Stored as little endian; } char no_idea_4[??]; // this is the remaining amout up to the first // track chunk marked by the first track offset. } // Track Chunk { char track_header[] = "HMI-MIDITRACK"; char no_idea_4[74]; char track_header_size[4]; char no_idea_5[(track_header_size - 91]; { // Repeat until end of track detected // ** NOTE ** Since track chunk has no length details, // you need to scan for end of track marker. char midi_delta[] = ???; // See MIDI Delta char midi_event[] = ???; // See MIDI Events // ** NOTE ** Note On event is slightly different to the // normal MIDI note on event. See MIDI Events below. // Last event in track chunk is end of track meta event, // defined as 0xff 0x2f 0x00. } { // Extra Data { // Some HMI files have data after the tracks. // Details are unknown about these bytes of data. char no_idea_6[] = ???; } MIDI Delta This is a variable length value that determins how time (in MIDI ticks) is to pass before the following MIDI event is to be processed. Just like MIDI's variable length values, HMI files have bit 7 set on the each value in the variable length value except the last one. A value of 255 would be stored as 0x81 0x7f, or a value of 1 would be stored as 0x01 in the HMI variable length format. Examples: Delta of 255: < midi event > 0x81 0x7f < midi event> Delta of 127: < midi event > 0x7f < midi event > Delta of 65537: < midi event > 0x82 0x80 0x71 < midi event > MIDI Events The first byte of a midi events is split into 2 x 4bits. Bits 7-4 is the command while bits 3-0 is the MIDI channel the command is to occur on. For example 0x94 means do command 9 on channel 4. The only exception to this is where bits 7-4 = F in hexidecimal as these are a special group of commands. The following commands are detailed in this document with the channel information (bits 3 - 0) set to 0, example 0x80. However the channel information could have a value anywhere from 0 to F in hexidecimal. // Note On Event { char cmd = 0x90; char note = 32; // Could be a value of 0 - 127 char velocity = 100; // Could be a value of 0 - 127. // If this value is 0 then it // is treated as a note off char length[] = < variable length value >; // See MIDI Delta for example } // Aftertouch Event { // See "Aftertouch Event" in MidFileFormat.txt } // Controller Events { // See "Controller Events" in MidFileFormat.txt } // Patch Event { // See "Patch Event" in MidFileFormat.txt } // Preasure Event { // See "Pressure Event" in MidFileFormat.txt } // Pitch Event { // See "Patch Event" in MidFileFormat.txt } // Sysexs Events { // See "Sysex Events" in MidFileFormat.txt } // HMI Events { // This is undocumented in specifications others have put together // so nothing other than the following is known about it. char cmd = 0xfe; { char type = 0x10; char data_1[2]; char size; // Could be anything from 0x00 to 0xff char data_2[size]; char data_3[5]; } // *** OR *** { char type = 0x15; char data[6]; } // *** OR *** { char type; char data[2]; } } // Meta Events { // See "Meta Events" MidFileFormat.txt } wildmidi-wildmidi-0.4.2/docs/formats/HmpFileFormat.txt000066400000000000000000000134641315765416100230010ustar00rootroot00000000000000HMP File Format (Incomplete - Under Construction) Document version 1 Written by Chris Ison Last Edited 24 May 2014 Copyright (C) 2014 WildMidi Developers This document is licensed under the Creative Commons Attribution-ShareAlike 4.0 International License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/4.0/ Introduction This document describes the HMP format as used by the WildMIDI project. It is not a complete description of the HMP file format and only those parts that are relevant to the WildMidi project are described here. Unfortunately we cannot answer questions about the format that are not described within this document. If you feel there is an error in this document please feel free to report it as a bug at https://github.com/Mindwerks/wildmidi/issues/ The HMP format comes in 2 versions. Apart from the file header there is no difference between the 2 versions as far WildMIDI is concerned. Description // First version of hmp files { char header[] = "HMIMIDIP"; char no_idea_1[24]; // All zeros } // *** OR *** // Second version of hmp files { char header[] = "HMIMIDIP013195"; char no_idea_1[18]; // All zeros } // The remaining header section of hmp files { char file_length[4]; // File size minus header[] stored as little-endian char no_idea_2[16]; // All zeros char number_of_chunks[4]; // Number of chunks stored as little-endian char no_idea_3[4]; // Unknown char beats_per_minute[4]; // beats per minute stored as little-endian // *** NOTE: Using a division of 60 *** char song_length_s[4]; // length of song in seconds as little-endian } // First version of hmp files { char no_idea4[712]; // Unknown // chunks start here } // *** OR *** // Second version of hmp files { char no_idea4[840]; // Unknown // chunks start here } // Chunk information { char chunk_number[4]; // Stored as little-endian char chunk_length[4]; // Size of entire chunk stored as little-endian char track_number[4]; // Track numbe stored as little endian { // Repeat until end of chunk char midi_delta[] = ???; // See MIDI Delta char midi_event[] = ???; // See MIDI Events } } MIDI Delta This is a variable length value that determins how time (in MIDI ticks) is to pass before the following MIDI event is to be processed. Opposite to MIDI variable length values. In HMP files the variable length value is stored in LSB with bit 7 set off for all except the last 7 bit value. A value of 255 would be stored as 0x7f 0x81, or a value of 1 would be stored as 0x81 in the HMP variable length format. Examples: Delta of 255: < midi event > 0x7f 0x81 < midi event> Delta of 127: < midi event > 0xff < midi event > Delta of 65537: < midi event > 0x7f 0x00 0x82 < midi event > MIDI Events The first byte of a midi events is split into 2 x 4bits. Bits 7-4 is the command while bits 3-0 is the MIDI channel the command is to occur on. For example 0x94 means do command 9 on channel 4. The only exception to this is where bits 7-4 = F in hexidecimal as these are a special group of commands. The following commands are detailed in this document with the channel information (bits 3 - 0) set to 0, example 0x80. However the channel information could have a value anywhere from 0x0 to 0xf. For more detail about the folling MIDI command information please see MidiFileFormat.txt within the WildMIDI project source code. // Note Off { char cmd = 0x80; char note = 27; // Could be a value of 0 - 127 char velocity = 0; // Could be a value of 0 - 127. Ignored by WildMIDI } // Note On { char cmd = 0x90; char note = 32; // Could be a value of 0 - 127 char velocity = 100; // Could be a value of 0 - 127. // If this value is 0 then it is treated as a note of } // Aftertouch { // Adjust the velocity of a note as if adjusting the preasure you // are placing on the key of a preasure sensitive keyboard after // you started playing it. char cmd = 0xa0; char note = 32; // Could be a value of 0 - 127 char velocity = 100; // Could be a value of 0 - 127. } // Controller { char cmd = 0xb0; char controller = 32; // Could be a value of 0 - 127 char setting = 100; // Could be a value of 0 - 127 /* In track 1 of HMP files controller 110 is set to 255 to mark the start of the looped events of tracks 2 & 3. Controller 111 in track 1 set to 128 to mark the end of the looped events of track 2 & 3. */ } // Patch { /* Change the patch (or sound) used to play notes on the channel */ char cmd = 0xc0; char change_patch = 32; // Could be a value of 0 - 127 } // Preasure { /* Adjust the velocity of all active notes on the channel as if adjusting the preasure you are placing on the keys of a preasure sensitive keyboard after you started playing them. */ char cmd = 0xd0; char velocity = 32; // Could be a value of 0 - 127 } // Pitch { /* Adjust the pitch of a channel just like a pitch bend wheel does. */ char cmd = 0xe0; char data_1 = 32; // Could be a value of 0 - 127 char data_2 = 100; // Could be a value of 0 - 127. } // Sysex { ** It is uncertain if sysex events will apepar in a HMP file ** ** but they have been included because it is possible ** char cmd = 0xf0; // *** OR *** char cmd = 0xf7; char sysex_size[] = < variable length in MIDI file format >; char sysex_data[sysex_size] = ...; // Ending with 0xf7 } // Meta Events { char cmd = 0xff; char instruction = 0x02; // Could be 0 - 127 char data_size[] = < variable length in MIDI file format >; char data[data_size]; } wildmidi-wildmidi-0.4.2/docs/formats/MUSFileFormat.txt000066400000000000000000000414301315765416100227130ustar00rootroot00000000000000 MUS File Format â•â•â•â•â•â•â•â•â•â•â•â•â•â•â• Written by: Vladimir Arnost, QA-Software Updated: March 9, 1996 Version: 1.31 Internet: xarnos00@dcse.fee.vutbr.cz FIDO: 2:423/36.2 1. General Description ────────────────────── A .MUS file is a simple clone of .MID file. It uses the same instruments, similar commands and the same principle: a list of sound events. It consists of two parts: header and body. NOTE: All numerical values mentioned in this document are zero-based. If not specified otherwise, all numbers are given in decimal. Hexadecimal numbers are suffixed by 'h' (e.g. 5Ch). Bits are numbered in this fashion: LSB (right-most) = 0, MSB (left-most) = 7. 2. MUS File Header ────────────────── The MUS header has the following structure: struct MUSheader { char ID[4]; // identifier "MUS" 0x1A WORD scoreLen; WORD scoreStart; WORD channels; // count of primary channels WORD sec_channels; // count of secondary channels WORD instrCnt; WORD dummy; // variable-length part starts here WORD instruments[]; }; NOTE: WORD is a 16-bit unsigned integer (little-endian) The header has two parts: the fixed-length and the variable-length part. The former contains file identifier, score start and length, number of channels and number of used instruments. The latter part is actually a list of used instruments. The instruments are stored as numbers which are arranged in this fashion: Instrument Number Meaning 0 - 127 standard MIDI instruments 135 - 181 standard MIDI percussions (notes 35 - 81) `scoreStart' is the absolute file position of the score and `scoreLen' is its length in bytes. Usage of a 16-bit number as length limits .MUS file size to 64KB. `channels' tells you how many channels are utilized in the song. The channel number 15 (percussions) is not included in the sum. 3. MUS File Body ──────────────── Unlike MID files, MUS body contains only one track. File body is a sequence of sound events and time records. A sound event consists of one or more bytes encoded as follows: 1st byte -- event descriptor: ╓──7─┬──6─┬──5─┬──4─┬──3─┬──2─┬──1─┬──0─╖ â•‘Last│ Event type │ Channel number â•‘ ╙────┴────┴────┴────┴────┴────┴────┴────╜ `Event type' is one of these: 0 - release note 1 - play note 2 - pitch wheel (bender) 3 - system event (valueless controller) 4 - change controller 5 - ??? 6 - score end 7 - ??? `Channel number' determines which channel this event refers to. Channels provide only logical score division. Every channel carries its own settings (instrument #, panning, volume) and the channel number specifies only which settings to use. In general, the channel number itself is almost irrelevant and may be chosen arbitrarily within the interval 0 to 14. The only exception is the channel number 15, which is dedicated ONLY to percussions. `Last' - if set, the event is followed by time information. This means that this is the last event in a group of events which occur at the same time. The time information is a number of ticks to wait before processing next event. One tick is usually 1/140 sec (in Doom I, II and Heretic; Raptor uses 1/70 sec). Time information can be read in this way: 1. time = 0 2. READ a byte 3. time = time * 128 + byte AND 127 4. IF (byte AND 128) GO TO 2 5. RETURN time The time info is a series of 7-bit chunks. The bit #7 is set until the last byte whose bit 7 is zero. This scheme allows small numbers occupy less space than large ones. Event Type ──────────────────── 0 Release note ╓─7─┬─6─┬─5─┬─4─┬─3─┬─2─┬─1─┬─0─╖ â•‘ 0 │ Note number 0 - 127 â•‘ ╙───┴───┴───┴───┴───┴───┴───┴───╜ 1 Play note ╓─7─┬─6─┬─5─┬─4─┬─3─┬─2─┬─1─┬─0─╖ ╓─7─┬─6─┬─5─┬─4─┬─3─┬─2─┬─1─┬─0─╖ â•‘Vol│ Note number 0 - 127 â•‘ â•‘ 0 │ Note volume 0 - 127 â•‘ ╙───┴───┴───┴───┴───┴───┴───┴───╜ ╙───┴───┴───┴───┴───┴───┴───┴───╜ `Note volume' is present only if `Vol' bit is set. Otherwise the previous value is used and the second byte is not present. NOTE: Each channel keeps track of its own last volume value. More than one note can be played at once in one channel. Channel 15 is dedicated to drums and percussions. `Note number' acts as an instrument selector there. See Appendix C 2 Pitch wheel ╓─7─┬─6─┬─5─┬─4─┬─3─┬─2─┬─1─┬─0─╖ â•‘ Pitch wheel value â•‘ ╙───┴───┴───┴───┴───┴───┴───┴───╜ Sets pitch wheel (bender) value of a channel. Some handy values are shown in the table (all values in the range 0-255 can be used): ┌───────┬───────────────────────┠│ Value │ Pitch change │ ├───────┼───────────────────────┤ │ 0 │ two half-tones down │ │ 64 │ one half-tone down │ │ 128 │ normal (default) │ │ 192 │ one half-tone up │ │ 255 │ two half-tones up │ └───────┴───────────────────────┘ 3 System event (Valueless controller) ╓─7─┬─6─┬─5─┬─4─┬─3─┬─2─┬─1─┬─0─╖ â•‘ 0 │ Number â•‘ ╙───┴───┴───┴───┴───┴───┴───┴───╜ Number MIDI ctrl Description 10 120 (78h) All sounds off 11 123 (7Bh) All notes off 12 126 (7Eh) Mono 13 127 (7Fh) Poly 14 121 (79h) Reset all controllers NOTE: The second column (MIDI ctrl) lists the corresponding MIDI controller number. It is not needed unless you want to convert MUS file data to MIDI. 4 Change controller ╓─7─┬─6─┬─5─┬─4─┬─3─┬─2─┬─1─┬─0─╖ ╓─7─┬─6─┬─5─┬─4─┬─3─┬─2─┬─1─┬─0─╖ â•‘ 0 │ Controller number â•‘ â•‘ 0 │ Controller value â•‘ ╙───┴───┴───┴───┴───┴───┴───┴───╜ ╙───┴───┴───┴───┴───┴───┴───┴───╜ Number MIDI ctrl Description 0 N/A Instrument (patch, program) number 1 0 or 32 Bank select: 0 by default 2 1 (01h) Modulation pot (frequency vibrato depth) 3 7 (07h) Volume: 0-silent, ~100-normal, 127-loud 4 10 (0Ah) Pan (balance) pot: 0-left, 64-center (default), 127-right 5 11 (0Bh) Expression pot 6 91 (5Bh) Reverb depth 7 93 (5Dh) Chorus depth 8 64 (40h) Sustain pedal (hold) 9 67 (43h) Soft pedal NOTE: MUS controller 0 has no equivalent MIDI controller, but is encoded as MIDI event 0Cxh--patch change (`x' is the channel number) 5 Unknown Not known what data (if any) this command takes. 6 Score end No data. Marks the end of score. Must be present at the end, otherwise the player may go off the rails. In DOOM this command restarts playing. 7 Unknown Not known what data (if any) this command takes. APPENDIX A - Note numbers ───────────────────────── â•”â•â•â•â•â•â•â•â•╦â•â•â•â•â•╤â•â•â•â•╤â•â•â•â•╤â•â•â•â•╤â•â•â•â•╤â•â•â•â•╤â•â•â•â•╤â•â•â•â•╤â•â•â•â•╤â•â•â•â•╤â•â•â•â•╤â•â•â•â•â•— â•‘ Octave â•‘ C │ C# │ D │ D# │ E │ F │ F# │ G │ G# │ A │ A# │ B â•‘ â• â•â•â•â•â•â•â•â•╬â•â•â•â•â•╪â•â•â•â•╪â•â•â•â•╪â•â•â•â•╪â•â•â•â•╪â•â•â•â•╪â•â•â•â•╪â•â•â•â•╪â•â•â•â•╪â•â•â•â•╪â•â•â•â•╪â•â•â•â•â•£ â•‘ 0 â•‘ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 10 │ 11 â•‘ â•‘ 1 â•‘ 12 │ 13 │ 14 │ 15 │ 16 │ 17 │ 18 │ 19 │ 20 │ 21 │ 22 │ 23 â•‘ â•‘ 2 â•‘ 24 │ 25 │ 26 │ 27 │ 28 │ 29 │ 30 │ 31 │ 32 │ 33 │ 34 │ 35 â•‘ â•‘ 3 â•‘ 36 │ 37 │ 38 │ 39 │ 40 │ 41 │ 42 │ 43 │ 44 │ 45 │ 46 │ 47 â•‘ â•‘ 4 â•‘ 48 │ 49 │ 50 │ 51 │ 52 │ 53 │ 54 │ 55 │ 56 │ 57 │ 58 │ 59 â•‘ â•‘ 5 â•‘ 60 │ 61 │ 62 │ 63 │ 64 │ 65 │ 66 │ 67 │ 68 │ 69 │ 70 │ 71 â•‘ â•‘ 6 â•‘ 72 │ 73 │ 74 │ 75 │ 76 │ 77 │ 78 │ 79 │ 80 │ 81 │ 82 │ 83 â•‘ â•‘ 7 â•‘ 84 │ 85 │ 86 │ 87 │ 88 │ 89 │ 90 │ 91 │ 92 │ 93 │ 94 │ 95 â•‘ â•‘ 8 â•‘ 96 │ 97 │ 98 │ 99 │100 │101 │102 │103 │104 │105 │106 │107 â•‘ â•‘ 9 â•‘ 108 │109 │110 │111 │112 │113 │114 │115 │116 │117 │118 │119 â•‘ â•‘ 10 â•‘ 120 │121 │122 │123 │124 │125 │126 │127 │ │ │ │ â•‘ ╚â•â•â•â•â•â•â•â•â•©â•â•â•â•â•â•§â•â•â•â•â•§â•â•â•â•â•§â•â•â•â•â•§â•â•â•â•â•§â•â•â•â•â•§â•â•â•â•â•§â•â•â•â•â•§â•â•â•â•â•§â•â•â•â•â•§â•â•â•â•â•§â•â•â•â•â• APPENDIX B - Instrument Patch Map ───────────────────────────────── Block 0-7 PIANO Block 8-15 CHROM PERCUSSION 0 Acoustic Grand Piano 8 Celesta 1 Bright Acoustic Piano 9 Glockenspiel 2 Electric Grand Piano 10 Music Box 3 Honky-tonk Piano 11 Vibraphone 4 Rhodes Paino 12 Marimba 5 Chorused Piano 13 Xylophone 6 Harpsichord 14 Tubular-bell 7 Clavinet 15 Dulcimer Block 16-23 ORGAN Block 24-31 GUITAR 16 Hammond Organ 24 Acoustic Guitar (nylon) 17 Percussive Organ 25 Acoustic Guitar (steel) 18 Rock Organ 26 Electric Guitar (jazz) 19 Church Organ 27 Electric Guitar (clean) 20 Reed Organ 28 Electric Guitar (muted) 21 Accordion 29 Overdriven Guitar 22 Harmonica 30 Distortion Guitar 23 Tango Accordion 31 Guitar Harmonics Block 32-39 BASS Block 40-47 STRINGS 32 Acoustic Bass 40 Violin 33 Electric Bass (finger) 41 Viola 34 Electric Bass (pick) 42 Cello 35 Fretless Bass 43 Contrabass 36 Slap Bass 1 44 Tremolo Strings 37 Slap Bass 2 45 Pizzicato Strings 38 Synth Bass 1 46 Orchestral Harp 39 Synth Bass 2 47 Timpani Block 48-55 ENSEMBLE Block 56-63 BRASS 48 String Ensemble 1 56 Trumpet 49 String Ensemble 2 57 Trombone 50 Synth Strings 1 58 Tuba 51 Synth Strings 2 59 Muted Trumpet 52 Choir Aahs 60 French Horn 53 Voice Oohs 61 Brass Section 54 Synth Voice 62 Synth Brass 1 55 Orchestra Hit 63 Synth Bass 2 Block 64-71 REED Block 72-79 PIPE 64 Soprano Sax 72 Piccolo 65 Alto Sax 73 Flute 66 Tenor Sax 74 Recorder 67 Baritone Sax 75 Pan Flute 68 Oboe 76 Bottle Blow 69 English Horn 77 Shakuhachi 70 Bassoon 78 Whistle 71 Clarinet 79 Ocarina Block 80-87 SYNTH LEAD Block 88-95 SYNTH PAD 80 Lead 1 (square) 88 Pad 1 (new age) 81 Lead 2 (sawtooth) 89 Pad 2 (warm) 82 Lead 3 (calliope) 90 Pad 3 (polysynth) 83 Lead 4 (chiffer) 91 Pad 4 (choir) 84 Lead 5 (charang) 92 Pad 5 (bowed glass) 85 Lead 6 (voice) 93 Pad 6 (metal) 86 Lead 7 (5th sawtooth) 94 Pad 7 (halo) 87 Lead 8 (bass & lead) 95 Pad 8 (sweep) Block 96-103 SYNTH EFFECTS Block 104-111 ETHNIC 96 FX 1 (rain) 104 Sitar 97 FX 2 (soundtrack) 105 Banjo 98 FX 3 (crystal) 106 Shamisen 99 FX 4 (atmosphere) 107 Koto 100 FX 5 (brightness) 108 Kalimba 101 FX 6 (goblin) 109 Bag Pipe 102 FX 7 (echo drops) 110 Fiddle 103 FX 8 (star-theme) 111 Shanai Block 112-119 PERCUSSIVE Block 120-127 SOUND EFFECTS 112 Tinkle Bell 120 Guitar Fret Noise 113 Agogo 121 Breath Noise 114 Steel Drums 122 Seashore 115 Woodblock 123 Bird Tweet 116 Taiko Drum 124 Telephone Ring 117 Melodic Tom 125 Helicopter 118 Synth Drum 126 Applause 119 Reverse Cymbal 127 Gun Shot APPENDIX C - Percussion Key Map ─────────────────────────────── In channel #15, the note number does not affect the pitch but the instrument type. The default pitch for percussions is 60 (C-5). Note Instrument Note Instrument 35 Acoustic Bass Drum 59 Ride Cymbal 2 36 Bass Drum 60 High Bongo 37 Slide Stick 61 Low Bango 38 Acoustic Snare 62 Mute High Conga 39 Hand Clap 63 Open High Conga 40 Electric Snare 64 Low Conga 41 Low Floor Tom 65 High Timbale 42 Closed High-Hat 66 Low Timbale 43 High Floor Tom 67 High Agogo 44 Pedal High Hat 68 Low Agogo 45 Low Tom 69 Cabasa 46 Open High Hat 70 Maracas 47 Low-Mid Tom 71 Short Whistle 48 High-Mid Tom 72 Long Whistle 49 Crash Cymbal 1 73 Short Guiro 50 High Tom 74 Long Guiro 51 Ride Cymbal 1 75 Claves 52 Chinses Cymbal 76 High Wood Block 53 Ride Bell 77 Low Wood Block 54 Tambourine 78 Mute Cuica 55 Splash Cymbal 79 Open Cuica 56 Cowbell 80 Mute Triangle 57 Crash Cymbal 2 81 Open Triangle 58 Vibraslap wildmidi-wildmidi-0.4.2/docs/formats/XMIFileFormat-AIL.txt000066400000000000000000000711621315765416100233140ustar00rootroot00000000000000 IBM Audio Interface Library Extended MIDI (XMIDI) Specification Release 1.02 of 17 August 1992 Contents Overview ........................................................... 3 Extended MIDI Controller Reference ................................. 4 Extended MIDI IFF (.XMI) Structure ................................. 11 Extended MIDI Global Timbre Library File Format .................... 13 Glossary of Audio Interface Library Terms .......................... 14 Overview The term 'Extended MIDI,' or 'XMIDI,' refers to the set of features added to the base Musical Instrument Digital Interface (MIDI) data specification by the drivers and utility programs included with the Audio Interface Library's Version 2.00 release. The XMIDI standard brings many powerful features to the Audio Interface Library which would otherwise be absent in a system conforming to the original MIDI standard. Composers who are interested in getting started with XMIDI should pay particular attention to the descriptions of the utility programs MIDIFORM, GLIB, MIDIECHO, and CAKEPORT in the Tools Reference section of this manual, before moving on to the specific discussions of the Extended MIDI controllers below. It is strongly recommended that musicians with even the slightest programming knowledge (or interest) examine the Application Program Interface Reference section as well, in order to gain the best possible understanding of the Audio Interface Library's capabilities. Programmers seeking to master effective Audio Interface Library application design are also advised to familiarize themselves with the Tools Reference section, followed by a thorough perusal of the Application Program Interface Reference and Technical Notes. Special attention should be given to the Programming Examples section as well. The chapters in this section on the two primary XMIDI file formats are provided for reference only. Users planning to upgrade Audio Interface Library Version 1 MIDI applications to the XMIDI standard should begin with an understanding of the MIDIFORM and GLIB programs and how they create and manage the new system's data file formats. Virtually all of the Version 1 API functions have been retained, but many have undergone revision or syntactic changes as part of the Version 2.0 release. A careful review of the Application Program Interface Reference and Programming Examples sections will ease the transition to the new API. Extended MIDI Controller Reference XMIDI provides a number of additional MIDI-style Control Change messages which greatly extend the range of composition and arrangement options available to the musician and application programmer. Below is a list of Extended MIDI Control Change messages available in the current Audio Interface Library release, together with explanations of their uses in XMIDI sequences. ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ Controller ³ Description ³ ÆÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍØÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͵ ³ 110 (6eh) ³ Channel Lock ³ ³ 111 (6fh) ³ Channel Lock Protect ³ ³ 112 (70h) ³ Voice Protect ³ ³ 113 (71h) ³ Timbre Protect ³ ³ 114 (72h) ³ Patch Bank Select ³ ³ 115 (73h) ³ Indirect Controller Prefix ³ ³ 116 (74h) ³ For Loop Controller ³ ³ 117 (75h) ³ Next/Break Loop Controller ³ ³ 118 (76h) ³ Clear Beat/Bar Count ³ ³ 119 (77h) ³ Callback Trigger ³ ³ 120 (78h) ³ Sequence Branch Index ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ Channel Lock (110) < 64: Release previously locked channel and restore default channel number mapping >= 64: Seize ("lock") an unlocked, unprotected physical MIDI channel (2-9) for assignment to this logical channel # (11-16) The Channel Lock controller is one of the more powerful Extended MIDI controllers. Channel locking allows the XMIDI drivers to play multiple XMIDI sequences simultaneously, which in turn permits the creation of impressive sound effects and musical "mixes." When used with a value greater than or equal to 64, the Channel Lock controller attempts to seize, or "lock," the highest MIDI channel number recognized by the driver's supported synthesizer which has the fewest actively playing notes. Channels which are already locked, or which have been "protected" against locking by use of the XMIDI Channel Lock Protect controller (111), are immune to seizure. If no available MIDI channels are eligible for locking under these criteria, the controller will have no effect. (This will occur only if all unprotected channels are already locked.) After a MIDI channel has been successfully locked, the driver maps the locked channel onto the MIDI channel in which the Channel Lock controller itself appeared. This means that all subsequent MIDI events sent on the same channel as the Channel Lock controller (the "logical" channel) will instead be transmitted on the newly locked (or "physical") channel. This concept is perhaps best illustrated with a typical application of channel locking. Below is a list of events comprising a short XMIDI sequence to create a "machine gun" sound effect. (Timing and note velocity information has been omitted for simplicity.) Ch 02 Controller 114 = 1 ;XMIDI Patch Bank Select = 1 Ch 02 Patch = 5 ;MIDI Program Change to patch 5 ("gunshot") Ch 02 Pitch Wheel 0 ;Pitch bend centered (no bend) Ch 02 Controller 1 = 0 ;Modulation = 0 Ch 02 Controller 7 = 127 ;Volume = 127 Ch 02 Controller 10 = 64 ;Panpot = 64 (center of stereo field) Ch 02 Controller 116 = 5 ;FOR loop = 1 to 5... Ch 02 Note C 5 on ;...sound a brief "gunshot" note... Ch 02 Note C 5 off Ch 02 Controller 116 = 127 ;...NEXT loop This "machine gun" sequence would be ideal for use as part of an arcade game's sound-effects arsenal, except for one serious drawback: what happens if MIDI channel 2 is already being used by a background music sequence, or perhaps another sound effect? The controller values and patch change in the sequence above would certainly have an unfavorable effect on a romantic violin solo playing on channel 2. The problem could be solved by setting aside a block of active MIDI channels for use with overlaid sound-effects sequences, but this might be an unacceptable compromise for applications requiring playback of any but the simplest XMIDI sequences. Channel locking and remapping is a much more satisfactory solution. When composing sequences for the XMIDI standard, the composer could assign all tracks in sound effects and other overlaid sequences to MIDI channels in the range 11 through 16. MIDI channels in this range are not normally recognized by synthesizers supported by the AIL. But if an XMIDI Channel Lock controller is then inserted before the first Channel Voice event in the channel, the AIL driver can temporarily reassign a physical MIDI channel to the out-of-range logical channel number, preventing the channel's use by any other sequence being played for as long as it is needed by the sequence which "locked" the channel. A not-so-obvious benefit of this scheme is that all sound-effects sequences can safely share the same logical channel numbers between 11 and 16, since only the physical channel numbers recognized by the synthesizer are vulnerable to usage conflicts. With channel locking installed, the machine gun sound-effect sequence might look like this: Ch 11 Controller 110 = 127 ;XMIDI Channel Lock (seize channel) Ch 11 Controller 114 = 1 ;XMIDI Patch Bank Select = 1 Ch 11 Patch = 5 ;MIDI Program Change to patch 5 ("gunshot") Ch 11 Pitch Wheel 0 ;Pitch bend centered (no bend) Ch 11 Controller 1 = 0 ;Modulation = 0 Ch 11 Controller 7 = 127 ;Volume = 127 Ch 11 Controller 10 = 64 ;Panpot = 64 (center of stereo field) Ch 11 Controller 116 = 5 ;FOR loop = 1 to 5... Ch 11 Note C 5 on ;...sound a brief "gunshot" note... Ch 11 Note C 5 off Ch 11 Controller 116 = 127 ;...NEXT loop Ch 11 Controller 110 = 0 ;XMIDI Channel Lock (release channel) The sequence's new final event, a Channel Lock controller with the value 0, is actually unnecessary since all channels locked by a sequence are released automatically as soon as the sequence ends or playback is stopped. However, in sequences with multiple tracks, it is a good idea to explicitly release each locked channel as soon as it is no longer needed by the sequence, instead of waiting for all tracks to expire. This allows the XMIDI driver to restore the channel to the sequence from which it was "stolen," minimizing the disruption to the background music. When a locked channel is released, either through a Channel Lock controller with a value below 64 or through a C call to the analogous AIL_release_channel() function, the timbre bank, patch number, pitch wheel, and MIDI controllers in the channel are updated to their correct values before being returned to the service of the original sequence. This relieves the application of the responsibility of keeping track of these values while a channel is locked. Conversely, when a channel is locked by a Channel Lock controller or its complementary AIL_lock_channel() function, the MIDI Sustain (Hold1) controller (64) in the channel is forced to its "off" condition and all notes playing in the channel are silenced. No other controller values or MIDI messages are initialized! It is essential for a sequence (or an application) which has just received a locked channel to initialize all MIDI parameters, including MIDI controllers likely to contain undesirable values, the XMIDI Patch Bank Select controller and MIDI Program Change number, and the MIDI pitch wheel, to appropriate values. (Avoid the temptation to accomplish this with MIDI Channel Mode messages such as All Notes Off or Reset All Controllers. Channel Mode messages may be interpreted differently by various synthesizers, and the XMIDI driver code which maintains sequence state tables and other data structures makes no attempt to interpret them at all.) Channel Lock Protect (111) < 64: Channel is eligible for temporary reassignment by AIL_lock_channel() or Channel Lock controllers >= 64: Channel may not be locked (seized for reassignment) Occasionally it may be desirable to prevent any sequence or application process from interrupting traffic on a given MIDI channel. Depending on its value, the XMIDI Channel Lock Protect controller will either render the physical MIDI channel in which it appears immune to seizure, or allow it to be considered for seizure when a Channel Lock controller message or AIL_lock_channel() call is issued. Voice Protect (112) < 64: Voices playing in channel assume normal priority (release voice protection) >= 64: Voices playing in channel assume highest possible priority (assert voice protection) Available on some synthesizers, voice protection is an XMIDI feature which allows a sequence to discourage the polyphonic voice assignment algorithm from "stealing" synthesizer voices from notes played in a given MIDI channel when no free voices are available. If the Voice Protect controller's value is less than 64, voices assigned to notes playing in the channel will be considered for reassignment to play incoming note events. This is the default condition for each channel. Otherwise, the "voice priority" of notes in the channel will constantly assume its maximum value, preventing the channel's notes from being robbed of their voices. Voice protection should be used conservatively and released as soon as possible, since the synthesizer emulation code works best when allowed to make its own decisions regarding voice allocation. Timbre Protect (113) < 64: Timbre currently assigned to this channel's patch may be "discarded" (if least-recently-used) to make room in local timbre cache or synthesizer memory >= 64: Timbre may not be discarded from cache or synthesizer memory For information on timbre protection, refer to the descriptions of the AIL_protect_timbre() / AIL_unprotect_timbre() functions in the Application Program Interface Reference section of this manual. Patch Bank Select (114) This controller may be used to "extend" the scope of MIDI Program Change (or Cakewalk "Patch") messages. Normally, any of 128 synthesizer patches may be selected with a Program Change message; however, the Patch Bank Select controller instructs the AIL XMIDI driver to associate custom timbres in any of 127 banks with synthesizer patches which are subsequently selected in a channel. By convention, patch bank 0 is reserved for the Roland MT-32's built-in patch/timbre combinations, and for the Ad Lib-style instruments intended to emulate those patches. Custom Roland timbres (and their Ad Lib counterparts) should be placed in patch banks 1 through 126. Timbre bank 127 is reserved for custom "drum kit" timbres to be used when playing note events on MIDI channel 10. When a MIDI Program Change (or "patch") event is encountered, the XMIDI synthesizer driver looks in its collection of timbres from the Global Timbre Library for a custom timbre whose "patch number" is the specified Program Change number and whose "bank" is equal to the current Patch Bank Select controller value. If the timbre is found, the synthesizer is automatically instructed to associate the timbre with the patch which was just selected by the Program Change event. Under normal circumstances, the search for the requested timbre should not fail, since the application should have been informed in advance of the need for the timbre via the AIL_timbre_request() function. (See the Application Program Interface Reference section of this manual for more information on XMIDI timbre management.) The default Patch Bank Select controller value is 0. Therefore, AIL applications which do not require custom Roland MT-32 timbres may disregard this controller altogether. Otherwise, care must be taken to explicitly specify the Timbre Bank Select controller value to be used in each channel of every sequence and sound effect used by the application, since the default value of 0 is asserted only upon driver initialization -- not when a channel is locked or when a sequence stops. Indirect Controller Prefix (115) This controller specifies that the next Control Change message encountered in this channel should obtain its value from the Indirect Controller Array's nth byte entry, where n is the indirect controller prefix's own value. For more information on the Indirect Controller Array, see the AIL_register_sequence() function description in the Application Program Interface Reference section of this manual. For Loop Controller (116) 1-127: Define beginning of MIDI data block to be played a total of v times, where v is the For loop controller's value 0: Define beginning of MIDI data block to be played indefinitely This controller allows the creation of a loop within an XMIDI sequence. Its use is almost self- explanatory, especially for those familiar with BASIC or C's "for...next" construct. A loop value of 1 causes the block of MIDI/XMIDI events between the For controller and its corresponding Next/Break controller to be executed precisely once -- as if the controllers did not exist. Values from 2 to 127 cause the event block to be executed from 2 to 127 times. A value of 0, on the other hand, causes the event block to loop indefinitely, interruptable only at the application's request. There are four rules to bear in mind when using For...Next/Break loops: * At least one XMIDI 'quantization interval' must separate the For and Next/Break loop controllers. In practice, this means that more than 1/120 second (8.4 milliseconds) of real time must elapse between these two events during playback. Otherwise, the application will "hang" forever with interrupts disabled, since neither the For nor the Next/Break controller automatically terminates the current interval. * The branching effect caused by a Next/Break controller does not result in the note queue being flushed, unlike the operation of the AIL_branch_index() function. Only the sequence pointer is adjusted by the Next/Break controller. Refer to the AIL_branch_index() function description in the Application Program Interface Reference for additional notes about sequence branching in general. * Multi-track MIDI Format 1 files are converted to MIDI Format 0 during the MIDIFORM program's XMIDI compilation process. This implies that loops placed on a single track will actually cause events in all other tracks to be repeated as well. In situations where it is desired to loop tracks independently of each other, a possible solution is to split the tracks into multiple XMIDI sequences and have the application play each sequence simultaneously. * For...Next/Break controller loops may be nested up to 4 levels deep. Next/Break Loop Controller (117) < 64: (Break) Loop iteration stops, regardless of the current For loop count >= 64: (Next) Decrement innermost For loop count and, if nonzero, branch immediately to the innermost For controller event One application of the Indirect Controller Prefix controller (q.v.) would be to turn a Next controller into a Break controller by providing a dynamic controller value as specified above. This feature may be used to introduce elements of application program control into sound-effect sequences. Otherwise, the Next controller should have a value greater than or equal to 64, in order to function in the manner detailed in the preceding For Loop Controller description. Clear Beat/Bar Count (118) (Value unused, 0-127) This controller resets the current beat and measure counters to 0:0. See the AIL_beat_count() / AIL_measure_count() function description in the Application Program Interface Reference section for information on the beat and measure counters. Callback Trigger (119) (Value = trigger_value parameter passed to callback function, 0-127) See the AIL_install_callback() function description in the Application Program Interface Reference section for information on callback functions. Sequence Branch Index (120) (Value = marker_number parameter passed to AIL_branch_index() function, 0-127) See the AIL_branch_index() function description in the Application Program Interface Reference section for information on sequence branching. * * * In addition to the controllers listed here, some synthesizer drivers (such as the Roland MT-32 family) provide several other XMIDI Control Change message types. These controllers allow the musician to access the synthesizer's set of memory-addressable features, without the need to deal directly with MIDI System Exclusive messages. For more information about synthesizer- specific XMIDI controllers, as well as a list of general XMIDI controllers supported by each driver, refer to the Technical Notes section of this manual. Extended MIDI IFF (.XMI) Structure XMIDI sequence files are "preprocessed" MIDI sequence files. Created by the MIDIFORM program described in the Tools Reference section of this manual, XMIDI files are stored in accordance with Electronic Arts' Interchange File Format (EA IFF 85) standard. Below is a summary of the XMIDI format's technical details, which is presented as an aid to application developers with specialized needs not supported directly by the Audio Interface Library. The XMIDI file format preserves all of the information needed to faithfully reproduce the MIDI sequence's original sound, while discarding elements of the MIDI storage format that are redundant, inefficient, or otherwise unnecessary for real-time playback. An XMIDI file containing a single translated MIDI sequence often requires from 10% to 30% less storage space, and can be performed with substantially less background processing time. Each XMIDI file created by the MIDIFORM program contains a single IFF "CAT " chunk of type XMID. The CAT chunk contains at least one XMIDI sequence, whose local chunks are stored within a "FORM" chunk of type XMID. As created by MIDIFORM, the XMIDI file may contain a chunk of type FORM XDIR which contains information about the file's collection of XMIDI sequences. The XDIR chunk is for the application's benefit, and is not currently required by the XMIDI drivers. In the expression below, signifies a 32-bit "big endian" (or Motorola 680XX-style, MSB first) chunk length, which includes neither itself nor its preceding 4-character CAT , FORM, or local chunk name. Square brackets enclose optional chunks; ellipses are placed after the closing braces of chunks or data items which may be repeated. [ FORMXDIR { INFO UWORD # of FORMs XMID in file, 1-65535 } ] CAT XMID { FORMXMID { [ TIMB UWORD # of timbre list entries, 0-16384 { UBYTE patch number 0-127 UBYTE timbre bank 0-127 } ... ] [ RBRN UWORD # of branch point offsets, 0-127 { UWORD Sequence Branch Index controller value 0-127 ULONG controller offset from start of EVNT chunk } ... ] EVNT { UBYTE interval count (if < 128) UBYTE (if > 127) } ... } ... } TIMB and RBRN are optional chunks. RBRN is included only if XMIDI Sequence Branch Index (120) controllers appear in the original MIDI sequence. The mandatory EVNT chunk contains the quantized sequence events. EVNT must appear as the last local chunk in FORM XMID, while the other local chunks may appear in any order. consists of any MIDI Channel Voice, System Exclusive, or Meta-event except Note Off. The MIDI 'running status' convention is not used. Note On events are followed by their duration in intervals, expressed as a MIDI variable-length quantity (i.e., a string of 7-bit bytes stored most significant byte first, with the high bit set in all bytes except the last). Extended MIDI Global Timbre Library File Format For information about Global Timbre Library data in general, review the discussion of the GLIB program in the Tools Reference section of this manual, as well as the descriptions of timbre-related functions in the Application Program Interface Reference. A 'boilerplate' example of C code to fetch a desired timbre from any Global Timbre Library file can be found in the sample program listing XPLAY.C. In the expression below, ellipses are placed after the closing braces of data items which may be repeated. File header, one entry for each timbre in file { BYTE timbre patch number BYTE timbre bank number ULONG offset of timbre length word from start of file } ... Structure of each timbre as stored in file { UWORD timbre length word (size of timbre in bytes + 2) { UBYTE timbre data byte } ... } ... Glossary of Audio Interface Library Terms ADV: Abbreviation for Audio Driver, the standard MS-DOS filename suffix for AIL device drivers. The .ADV files are actually small assembly-language programs which contain the "intelligence" needed to support a given PC audio device. API: Application Program Interface. The AIL API module is linked directly with the application. It contains the Process Services (described in the API Reference section), as well as the actual C or Pascal-callable routines which link the application to its installed audio drivers. Bank: A collection of timbres, or software instrument definitions. Think of a bank as a "virtual orchestra" which contains a number of different instruments available for use by a given driver. See also Bankfile. Bankfile: An MS-DOS file containing a bank. Bankfiles are typically generated by a synthesizer's "instrument editor" program. The Audio Interface Library includes a program called GLIB which converts these device-specific bankfiles into an efficient, standardized runtime file format known as the Global Timbre Library, or GTL. See the description of the GLIB program in the Tools Reference section for details. Channel: Most MIDI events can be associated with one of sixteen possible channels. Although MIDI is a serial data standard at heart, it is often required to convey information which exists as a series of events in a number of parallel, synchronous dimensions. For instance, a single MIDI data stream may be expected to "play" an ensemble consisting of a piano, two guitars, a drum set, and a brass section. By associating events intended for a given instrument with the instrument's unique channel number, the composer of the MIDI sequence can prevent acoustically unfortunate conflicts between the pianos, drums, guitars, and horns. Controller: MIDI defines a number of control change events which affect the performance characteristics of instruments playing in a particular channel. Each MIDI synthesizer responds to a portion of the defined MIDI controller set. For example, the Roland MT-32 recognizes the standard MIDI controllers for Volume (controller 7), Panpot (controller 10), Sustain (controller 64), and Modulation (controller 1), among others. Global Timbre Library: See Bankfile. GTL: See Bankfile. MIDI Channel: See Channel. MIDI Channel Voice Message: A short representation (2-3 bytes) of a single MIDI event. Channel Voice messages include the Note Off, Note On, Polyphonic Key Pressure, Control Change, Program Change, Channel Pressure, and Pitch Wheel Change message types. MIDI Controller: See Controller. MIDI System Exclusive Message: A device-specific data packet sent to a MIDI synthesizer. Often, system exclusive messages are used to control aspects of synthesis not otherwise covered by the MIDI standard, such as custom instrument data, reverb control, and channel response configuration. Most MIDI synthesizers are accompanied by literature describing what system exclusive messages they recognize, if any. Multi-Timbral: Refers to a synthesizer's ability to play notes with more than one type of musical instrument at a time. Operator: See Partial. Partial: Also called an operator, a partial is a component of an FM or additive voice (q.v.). On the Roland MT-32/LAPC-1 synthesizer, each voice may use from 1 to 4 of 32 available partials. On the Ad Lib, Sound Blaster, and other YM3812-based cards, each voice requires 2 of 18 available partials. The Yamaha YMF262 (OPL3) device, used in some newer FM sound cards, provides 36 partials which may be assigned in groups of 2 or 4 per voice. Patch: A patch associates a timbre with a given MIDI channel. In general, the details of patch manipulation are handled automatically by the AIL drivers. For information on a given synthesizer's patch format, consult the programming manual for the device in question. Patch Bank: See Bank PCM: Abbreviation for Pulse Code Modulation, the technique used for most sampled sound playback on the PC. A common variation which implements rudimentary data compression is known as ADPCM, or ADaptive Pulse Code Modulation. Polyphonic: Refers to a synthesizer's ability to play more than one voice at a time. Sequence: Simply put, a musical work expressed as a series (sequence) of MIDI events. Sysex: See MIDI System Exclusive Message. System Exclusive Message: See MIDI System Exclusive Message. Timbre: In the Audio Interface Library's parlance, a timbre (pronounced tim'-ber, or tam'-ber) is a software definition of a musical instrument. See also Bank and Bankfile. Timbre Cache: Some AIL XMIDI drivers require the application to set aside a small area of memory to store instrument definitions. This area is known as the timbre cache. See the API Reference's discussion of the AIL_default_timbre_cache_size() function for more information. Track: A logical division of a MIDI sequence. Often, the composer associates a single MIDI channel with each track, placing all performance data for each instrument on its own track. Voice: As used in the Audio Interface Library, the term voice refers to the minimum synthesizer resources needed to play a single note with a given instrument. The Ad Lib and similar devices provide a total of 9 simultaneous voices, while the Roland MT-32/LAPC-1 synthesizer can generate from 8 to 32 voices at once, depending on the number of partials (q.v.) used by each voice. XMIDI: Abbreviation for eXtended MIDI. See the preceding parts of this section for details. wildmidi-wildmidi-0.4.2/docs/formats/XmiFileFormat.txt000066400000000000000000000052201315765416100230010ustar00rootroot00000000000000XMI File Format (Incomplete - Under Construction) Document version 1 Authored by Chris Ison chrisisonwildcode@gmail.com Last Edited 24 May 2014 Copyright (C) 2014 WildMidi Developers This document is licensed under the Creative Commons Attribution-ShareAlike 4.0 International License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/4.0/ Introduction This document describes the XMI format as used by the WildMIDI project. It is not a complete description of the XMI file format and only those parts that have been decyphered and are relevant to the WildMidi project are described here. Unfortunately we cannot answer questions about the format that are not described within this document. If you feel there is an error in this document please feel free to report it as a bug at https://github.com/Mindwerks/wildmidi/issues/ Description // FORM DATA { uint8_t text[4] = "FORM"; uint32_t size_of_data_before_chunks; uint8_t text[8] = "XDIRINFO"; uint8_t unknown[4] = { 0x00, 0x00, 0x00, 0x02 }; uint8_t form_count; uint8_t unknown_data[size_of_data_before_chunks - 13] uint8_t text[4] = "CAT "; uint32_t size_of_CAT; uint8_t text[4] = "XMID"; { // XMID Chunks uint8_t text[4] = "FORM"; uint32_t size_of_form; uint8_t text[4] = "XMID"; { { uint8_t text[4] = "TIMB"; uint32_t TIMB_size; uint8_t TIMB_data[TIMB_size] = { 8bit patch, 8bit bank, ... } } // OR { uint8_t text[4] = "RBRN" uint32_t RBRN_size; uint8_t unknown[RBRN_size]; } // OR { uint8_t text[4] = "EVNT" uint32_t EVNT_size; uint8_t MIDI_data[EVNT_size] { // All events and delta values stored as with standard MIDI, // EXCEPT for there is no "Note Off" and "Note On" extra data // after the velocity that states the length of the note // in delta ticks stored in MIDI variable length format. // ALSO NOTE that only the first TEMPO event is used, // all others are ignored. // Example Note on may be stored like // uint8_t event_data[] = { 0x90, 0x24, 0x64, 0xA3 } // uint8_t delta_ticks[] = { 0xA3 } // uint8_t event_data[] = { 0x90, 0x48, 0x64, 0x23, 0xA3 } // See the MIDI file format for more information ... } } ... } } } wildmidi-wildmidi-0.4.2/docs/license/000077500000000000000000000000001315765416100175025ustar00rootroot00000000000000wildmidi-wildmidi-0.4.2/docs/license/GPLv3.txt000066400000000000000000001045131315765416100211420ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . wildmidi-wildmidi-0.4.2/docs/license/LGPLv3.txt000066400000000000000000000167271315765416100212670ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. wildmidi-wildmidi-0.4.2/docs/man/000077500000000000000000000000001315765416100166335ustar00rootroot00000000000000wildmidi-wildmidi-0.4.2/docs/man/man1/000077500000000000000000000000001315765416100174675ustar00rootroot00000000000000wildmidi-wildmidi-0.4.2/docs/man/man1/wildmidi.1000066400000000000000000000126201315765416100213540ustar00rootroot00000000000000.TH wildmidi 1 "10 March 2016" "" "WildMidi Player" .SH NAME wildmidi \- example player for libWildMidi .PP .SH LIBRARY .B libWildMidi .PP .SH FILES .B /etc/wildmidi/wildmidi.cfg .PP .SH SYNOPSIS .B wildmidi [\-bhlvwnst] [\-c \fIconfig\-file\fB] [\-d \fIaudiodev\fB] [\-m \fIvolume\-level\fB] [\-o \fIwav\-file\fB] [\-f \fIfrequency\-Hz(MUS)\fB] [\-r \fIsample-rate\fB] [\-g \fIconvert-xmi-type\fB] \fImidifile ... .PP .SH DESCRIPTION This is a demonstration program to show the capabilities of libWildMidi. .PP \fImidifile\fP can be a MIDI type file in the HMI, HMP, MIDI, MUS or XMI formats and is processed by libWildMidi and the resulting audio is output by the player. .PP You can have more than one \fImidifile\fP on the command line and \fBwildmidi\fP will pass them to libWildMidi for processing, one after the other. You can also use wildcards, for example: \fBwildmidi *.mid\fP .PP .SH OPTIONS .IP "\fB\-b\fP | \fB\-\-reverb\fP" Turns on an 8 point reverb engine that adds depth to the final mix. .P .IP "\fB\-c\fP \fIconfig\-file\fP | \fB\-\-config\fP \fIconfig\-file\fP" Uses the configuration file stated by \fIconfig\-file\fP instead of /etc/wildmidi/wildmidi.cfg .PP .IP "\fB\-d\fP \fIaudiodev\fP | \fB\-\-device=\fIaudiodev\fP" Send the audio to \fIaudiodev\fP instead of the default. ALSA defaults to the system "default" while OSS defaults to "/dev/dsp". Other environments do not support this option. .PP .IP "\fB\-h\fP | \fB\-\-help\fP" Displays command line options. .PP .IP "\fB\-f\fP | \fB\-\-frequency\fP" Use frequency F Hz for playback (MUS). .PP .IP "\fB\-g\fP | \fB\-\-convert\fP" Convert XMI: 0 - No Conversion (default) 1 - MT32 to GM 2 - MT32 to GS .PP .IP "\fB\-l\fP | \fB\-\-log_vol\fP" Some MIDI files have been recorded on hardware that uses a volume curve, making them sound really badly mixed on other MIDI devices. Use this option to use volume curves. .PP .IP "\fB\-m\fP \fIvolume\-level\fP | \fB\-\-mastervol=\fIvolume\-level\fP" Set the overall volume level to \fIvolume\-level\fP. The minimum is 0 and the maximum is 127, with the default being 100. .PP .IP "\fB\-o\fP \fIwav\-file\fP | \fB\-\-wavout=\fIwav\-file\fP" Records the audio in wav format to \fIwav-file\fP. .PP .IP "\fB\-r\fP \fIsndrate\fP | \fB\-\-rate=\fIsndrate\fP" Set the audio output rate to \fIsndrate\fP. The default rate is 32072. .PP .IP "\fB\-n\fP | \fB\-\-roundtempo\fP" Round tempo to nearest whole number. .PP .IP "\fB\-s\fP | \fB\-\-skipsilentstart\fP" Skips any silence at the start of playback. .PP .IP "\fB\-v\fP | \fB\-\-version\fP" Display version and copyright information. .PP .IP "\fB\-x\fP | \fB\-\-tomidi\fP" Convert a MUS or an XMI file to midi and save to file. .PP .SH TEST OPTIONS These options are not designed for general use. Instead these options are designed to make it easier to listen to specific sound samples. .PP Note: These options are not displayed by \fB\-h\fP | \fB\-\-help\fP .PP .IP "\fB-k\fP \fIN\fP | \fB\-\-test_bank=\fIN\fP" Set the test bank to \fIN\fP. Range is 0 to 127. .PP .IP "\fB\-p\fP \fIN\fP | \fB\-\-test_patch=\fIN\fP" Set the test patch to \fIN\fP. Range is 0 to 127. .PP .IP "\fB\-t\fP | \fB\-\-test_midi\fP" Plays the built in test midi which plays all 127 notes. .PP .SH USER INTERFACE The player accepts limited user input that allows some interaction while playing midi files. .PP .IP \fB\+\fP Turns the master volume up. .PP .IP \fB\-\fP Turns the master volume down. .PP .IP \fBe\fP Turns enhanced resampling on and off. .PP .IP \fBl\fP Turns volume curves on and off. .PP .IP \fBr\fP Turns the final mix reverb on and off. .PP .IP \fBn\fP Play the next midi on the command line. .PP .IP \fBm\fP Save the currently playing file to a midi file. NOTE: This saves to the current directory. .PP .IP \fBp\fP Pause the playback. Note: since the audio is buffered it will stop when the audio buffer is empty. .PP .IP \fB.\fP Seek forward 1 second. Note: Clears active midi events and will only play midi events from after the new position. .PP .IP \fB,\fP Seek backwards 1 second. Note: Clears active midi events and will only play midi events from after the new position. .PP .IP \fBq\fP Quit wildmidi. .PP .SH SEE ALSO .BR wildmidi.cfg (5) .PP .SH AUTHOR Chris Ison Bret Curtis .PP .SH COPYRIGHT Copyright (C) WildMidi Developers 2001\-2016 .PP This file is part of WildMIDI. .PP WildMIDI is free software: you can redistribute and/or modify the player under the terms of the GNU General Public License and you can redistribute and/or modify the library under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the licenses, or(at your option) any later version. .PP WildMIDI 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 and the GNU Lesser General Public License for more details. .PP You should have received a copy of the GNU General Public License and the GNU Lesser General Public License along with WildMIDI. If not, see . .PP This manpage is licensed under the Creative Commons AttributionShare Alike 3.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. .PP wildmidi-wildmidi-0.4.2/docs/man/man3/000077500000000000000000000000001315765416100174715ustar00rootroot00000000000000wildmidi-wildmidi-0.4.2/docs/man/man3/WildMidi_ClearError.3000066400000000000000000000036171315765416100234060ustar00rootroot00000000000000.TH WildMidi_ClearError 3 "10 March 2016" "" "WildMidi Programmer's Manual" .SH NAME WildMidi_ClearError \- Clear errors .PP .SH LIBRARY .B libWildMidi .PP .SH SYNOPSIS .B #include .PP .B void WildMidi_ClearError(\fIvoid\fP) .PP .SH DESCRIPTION Clears errors in wildmidi library. .PP .SH SEE ALSO .BR WildMidi_GetVersion (3) , .BR WildMidi_Init (3) , .BR WildMidi_MasterVolume (3) , .BR WildMidi_Open (3) , .BR WildMidi_OpenBuffer (3) , .BR WildMidi_SetOption (3) , .BR WildMidi_GetOutput (3) , .BR WildMidi_GetMidiOutput (3) , .BR WildMidi_GetInfo (3) , .BR WildMidi_FastSeek (3) , .BR WildMidi_Close (3) , .BR wildmidi.cfg (5) .PP .SH AUTHOR Chris Ison Bret Curtis .PP .SH COPYRIGHT Copyright (C) WildMidi Developers 2001\-2016 .PP This file is part of WildMIDI. .PP WildMIDI is free software: you can redistribute and/or modify the player under the terms of the GNU General Public License and you can redistribute and/or modify the library under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the licenses, or(at your option) any later version. .PP WildMIDI 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 and the GNU Lesser General Public License for more details. .PP You should have received a copy of the GNU General Public License and the GNU Lesser General Public License along with WildMIDI. If not, see . .PP This manpage is licensed under the Creative Commons Attribution\-Share Alike 3.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. .PP wildmidi-wildmidi-0.4.2/docs/man/man3/WildMidi_Close.3000066400000000000000000000041271315765416100224100ustar00rootroot00000000000000.TH WildMidi_Close 3 "10 March 2016" "" "WildMidi Programmer's Manual" .SH NAME WildMidi_Close \- Close an open midi handle .SH LIBRARY .B libWildMidi .SH SYNOPSIS .B #include .PP .B int WildMidi_Close (midi *\fIhandle\fB) .PP .SH DESCRIPTION Finish processing MIDI data or file. .PP .IP \fIhandle\fP The identifier obtained from opening a midi file with \fBWildMidi_Open\fR(3)\fP or \fBWildMidi_OpenBuffer\fR(3)\fP .PP .SH "RETURN VALUE" returns \-1 on error, otherwise returns 0 .PP .SH SEE ALSO .BR WildMidi_GetVersion (3) , .BR WildMidi_Init (3) , .BR WildMidi_MasterVolume (3) , .BR WildMidi_Open (3) , .BR WildMidi_OpenBuffer (3) , .BR WildMidi_SetOption (3) , .BR WildMidi_GetOutput (3) , .BR WildMidi_GetMidiOutput (3) , .BR WildMidi_GetInfo (3) , .BR WildMidi_FastSeek (3) , .BR WildMidi_Shutdown (3) , .BR wildmidi.cfg (5) .PP .SH AUTHOR Chris Ison Bret Curtis .SH COPYRIGHT Copyright (C) WildMidi Developers 2001\-2016 .PP This file is part of WildMIDI. .PP WildMIDI is free software: you can redistribute and/or modify the player under the terms of the GNU General Public License and you can redistribute and/or modify the library under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the licenses, or(at your option) any later version. .PP WildMIDI 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 and the GNU Lesser General Public License for more details. .PP You should have received a copy of the GNU General Public License and the GNU Lesser General Public License along with WildMIDI. If not, see . .PP This manpage is licensed under the Creative Commons Attribution\-Share Alike 3.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. .PP wildmidi-wildmidi-0.4.2/docs/man/man3/WildMidi_ConvertBufferToMidi.3000066400000000000000000000046721315765416100252300ustar00rootroot00000000000000.TH WildMidi_ConvertBufferToMidi 3 "10 March 2016" "" "WildMidi Programmer's Manual" .SH NAME WildMidi_ConvertBufferToMidi \- Convert a MIDI-like buffer into a new MIDI buffer. .PP .SH LIBRARY .B libWildMidi .PP .SH SYNOPSIS .B #include .PP .B WildMidi_ConvertBufferToMidi (uint8_t *\fIin\fP, uint8_t \fIinsize\fP, uint8_t **\fIout\fP, uint32_t *\fIoutsize\fP) .PP .SH DESCRIPTION Takes a MIDI-like memory buffer as input and tries to detect, convert and write to a memory buffer in MIDI format. .PP .IP \fIin\fP The input buffer that contains MIDI-like content: XMI or MUS. .PP .IP \fIinsize\fP The size of the input buffer. .PP .IP \fIout\fP The output buffer. It will be allocated with \fBmalloc\fP() and must be \fBfree\fP()d by the caller when it is no longer needed. .PP .IP \fIoutsize\fP The size of the output buffer. .RS .PP .SH SEE ALSO .BR WildMidi_GetVersion (3) , .BR WildMidi_MasterVolume (3) , .BR WildMidi_Open (3) , .BR WildMidi_OpenBuffer (3) , .BR WildMidi_SetOption (3) , .BR WildMidi_GetOutput (3) , .BR WildMidi_GetMidiOutput (3) , .BR WildMidi_GetInfo (3) , .BR WildMidi_FastSeek (3) , .BR WildMidi_Close (3) , .BR WildMidi_Shutdown (3) , .BR wildmidi.cfg (5) .PP .SH AUTHOR Chris Ison Bret Curtis .PP .SH COPYRIGHT Copyright (C) WildMidi Developers 2001\-2016 .PP This file is part of WildMIDI. .PP WildMIDI is free software: you can redistribute and/or modify the player under the terms of the GNU General Public License and you can redistribute and/or modify the library under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the licenses, or(at your option) any later version. .PP WildMIDI 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 and the GNU Lesser General Public License for more details. .PP You should have received a copy of the GNU General Public License and the GNU Lesser General Public License along with WildMIDI. If not, see . .PP This manpage is licensed under the Creative Commons Attribution\-Share Alike 3.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. .PP wildmidi-wildmidi-0.4.2/docs/man/man3/WildMidi_ConvertToMidi.3000066400000000000000000000045211315765416100240670ustar00rootroot00000000000000.TH WildMidi_ConvertToMidi 3 "10 March 2016" "" "WildMidi Programmer's Manual" .SH NAME WildMidi_ConvertToMidi \- Convert a MIDI-like file into a new MIDI file. .PP .SH LIBRARY .B libWildMidi .PP .SH SYNOPSIS .B #include .PP .B WildMidi_ConvertToMidi (const char *\fIfile\fP, uint8_t **\fIout\fP, uint32_t *\fIsize\fP) .PP .SH DESCRIPTION Takes a MIDI-like file as input and tries to detect, convert and write to a memory buffer in MIDI format. .PP .IP \fIfile\fP The input file that contains MIDI-like content: XMI or MUS. .PP .IP \fIout\fP The output buffer. It will be allocated with \fBmalloc\fP() and must be \fBfree\fP()d by the caller when it is no longer needed. .PP .IP \fIsize\fP The size of the output buffer. .RS .PP .SH SEE ALSO .BR WildMidi_GetVersion (3) , .BR WildMidi_MasterVolume (3) , .BR WildMidi_Open (3) , .BR WildMidi_OpenBuffer (3) , .BR WildMidi_SetOption (3) , .BR WildMidi_GetOutput (3) , .BR WildMidi_GetMidiOutput (3) , .BR WildMidi_GetInfo (3) , .BR WildMidi_FastSeek (3) , .BR WildMidi_Close (3) , .BR WildMidi_Shutdown (3) , .BR wildmidi.cfg (5) .PP .SH AUTHOR Chris Ison Bret Curtis .PP .SH COPYRIGHT Copyright (C) WildMidi Developers 2001\-2016 .PP This file is part of WildMIDI. .PP WildMIDI is free software: you can redistribute and/or modify the player under the terms of the GNU General Public License and you can redistribute and/or modify the library under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the licenses, or(at your option) any later version. .PP WildMIDI 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 and the GNU Lesser General Public License for more details. .PP You should have received a copy of the GNU General Public License and the GNU Lesser General Public License along with WildMIDI. If not, see . .PP This manpage is licensed under the Creative Commons Attribution\-Share Alike 3.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. .PP wildmidi-wildmidi-0.4.2/docs/man/man3/WildMidi_FastSeek.3000066400000000000000000000051661315765416100230540ustar00rootroot00000000000000.TH WildMidi_FastSeek 3 "10 March 2016" "" "WildMidi Programmer's Manual" .SH NAME WildMidi_FastSeek \- Move to a position in a midi file .PP .SH LIBRARY .B libWildMidi .PP .SH SYNOPSIS .B #include .PP .B int WildMidi_FastSeek (midi *\fIhandle\fB, unsigned long int *\fIsample_pos\fB); .PP .SH DESCRIPTION Resets all note specific midi states and active notes before scanning to \fIsample_pos\fP samples from the beginning taking note of any changes to midi channel states. The next call to \fIWildMidi_GetOutput\fP\fR(3)\fP will behave as if you started to play the midi from that position. .PP .IP \fIhandle\fP The identifier obtained from opening a midi file with \fBWildMidi_Open\fR(3)\fP or \fBWildMidi_OpenBuffer\fR(3)\fP .PP .IP \fIsample_pos\fP The number of samples from the beginning you want libWildMidi to seek to. .PP NOTE: significant delay can occur when using this function. You can expect even more delay if you select a position that's already been passed forcing the library to start from the beginning. .PP .SH SEE ALSO .BR WildMidi_GetVersion (3) , .BR WildMidi_Init (3) , .BR WildMidi_MasterVolume (3) , .BR WildMidi_Open (3) , .BR WildMidi_OpenBuffer (3) , .BR WildMidi_SetOption (3) , .BR WildMidi_GetOutput (3) , .BR WildMidi_GetMidiOutput (3) , .BR WildMidi_GetInfo (3) , .BR WildMidi_Close (3) , .BR WildMidi_Shutdown (3) , .BR wildmidi.cfg (5) .PP .SH AUTHOR Chris Ison Bret Curtis .PP .SH COPYRIGHT Copyright (C) WildMidi Developers 2001\-2016 .PP This file is part of WildMIDI. .PP WildMIDI is free software: you can redistribute and/or modify the player under the terms of the GNU General Public License and you can redistribute and/or modify the library under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the licenses, or(at your option) any later version. .PP WildMIDI 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 and the GNU Lesser General Public License for more details. .PP You should have received a copy of the GNU General Public License and the GNU Lesser General Public License along with WildMIDI. If not, see . .PP This manpage is licensed under the Creative Commons Attribution\-Share Alike 3.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. .PP wildmidi-wildmidi-0.4.2/docs/man/man3/WildMidi_GetError.3000066400000000000000000000036411315765416100230740ustar00rootroot00000000000000.TH WildMidi_GetError 3 "10 March 2016" "" "WildMidi Programmer's Manual" .SH NAME WildMidi_GetError \- Return the last error message .PP .SH LIBRARY .B libWildMidi .PP .SH SYNOPSIS .B #include .PP .B char * WildMidi_GetError(\fIvoid\fP) .PP .SH DESCRIPTION Returns the last error message, if any. .PP .SH SEE ALSO .BR WildMidi_GetVersion (3) , .BR WildMidi_Init (3) , .BR WildMidi_MasterVolume (3) , .BR WildMidi_Open (3) , .BR WildMidi_OpenBuffer (3) , .BR WildMidi_SetOption (3) , .BR WildMidi_GetOutput (3) , .BR WildMidi_GetMidiOutput (3) , .BR WildMidi_GetInfo (3) , .BR WildMidi_FastSeek (3) , .BR WildMidi_Close (3) , .BR wildmidi.cfg (5) .PP .SH AUTHOR Chris Ison Bret Curtis .PP .SH COPYRIGHT Copyright (C) WildMidi Developers 2001\-2016 .PP This file is part of WildMIDI. .PP WildMIDI is free software: you can redistribute and/or modify the player under the terms of the GNU General Public License and you can redistribute and/or modify the library under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the licenses, or(at your option) any later version. .PP WildMIDI 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 and the GNU Lesser General Public License for more details. .PP You should have received a copy of the GNU General Public License and the GNU Lesser General Public License along with WildMIDI. If not, see . .PP This manpage is licensed under the Creative Commons Attribution\-Share Alike 3.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. .PP wildmidi-wildmidi-0.4.2/docs/man/man3/WildMidi_GetInfo.3000066400000000000000000000100051315765416100226660ustar00rootroot00000000000000.TH WildMidi_GetInfo 3 "10 March 2016" "" "WildMidi Programmer's Manual" .SH NAME WildMidi_GetInfo \- get information on a midi .SH LIBRARY .B libWildMidi .SH SYNOPSIS .B #include .PP .B struct _WM_Info *WildMidi_GetInfo (midi *\fIhandle\fP); .PP .SH DESCRIPTION Obtains information allowing you to determine song position, current options, and any copyright information. .PP .IP \fIhandle\fP The identifier obtained from opening a midi file with \fBWildMidi_Open\fR(3)\fP or \fBWildMidi_OpenBuffer\fR(3)\fP .PP .SH RETURN VALUE On error returns NULL with an error message displayed to stderr. .PP Otherwise returns a pointer to a struct containing the information. .PP .nf struct _WM_Info { char *\fIcopyright\fP; uint32_t \fIcurrent_sample\fP; uint32_t \fIapprox_total_samples\fP; uint32_t \fItotal_midi_time\fP; uint16_t \fImixer_options\fP; uint32_t \fItotal_midi_time\fP; }; .fi .PP .IP \fIcopyright\fP A pointer to a \\0 terminated string containing any copyright MIDI events found while processing the MIDI file \fIhandle\fP refers to. If more than one copyright event was found then each one is separated by \\n .PP If \fIcopyright\fP is NULL then no copyright MIDI events were found. .PP .IP \fIcurrent_sample\fP This is the number of stereo samples libWildMidi has processed for the MIDI file referred to by \fIhandle\fP. You can use this value to determine the current playing time by dividing this value by the \fIrate\fP given when libWildMidi was initialized by \fBWildMidi_Init\fR(3)\fP. .PP .IP \fIapprox_total_samples\fP This is the total number of stereo samples libWildMidi expects to process. This can be used to obtain the total playing time by dividing this value by the \fIrate\fP given when libWildMidi was initialized by \fBWildMidi_Init\fP\fR(3).\fP Also when you divide \fIcurrent_sample\fP by this value and multiplying by 100, you have the percentage currently processed. .PP .IP \fItotal_midi_time\fP This is the total time of MIDI events in 1/1000's of a second. It differs from \fIapprox_total_samples\fP in that it only states the total time within the MIDI file and does not take into account the extra bit of time to finish playing sampling smoothly. .PP .IP \fImixer_options\fP .RS .IP WM_MO_LOG_VOLUME Using curved volume settings instead of linear ones. .PP .IP WM_MO_ENHANCED_RESAMPLING The enhanced resampler is active .PP .IP WM_MO_REVERB Reverb is being added to the final output. .RE .PP .SH SEE ALSO .BR WildMidi_GetVersion (3) , .BR WildMidi_Init (3) , .BR WildMidi_MasterVolume (3) , .BR WildMidi_Open (3) , .BR WildMidi_OpenBuffer (3) , .BR WildMidi_SetOption (3) , .BR WildMidi_GetOutput (3) , .BR WildMidi_GetMidiOutput (3) , .BR WildMidi_FastSeek (3) , .BR WildMidi_Close (3) , .BR WildMidi_Shutdown (3) , .BR wildmidi.cfg (5) .PP .SH AUTHOR Chris Ison Bret Curtis .PP .SH COPYRIGHT Copyright (C) WildMidi Developers 2001\-2016 .PP This file is part of WildMIDI. .PP WildMIDI is free software: you can redistribute and/or modify the player under the terms of the GNU General Public License and you can redistribute and/or modify the library under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the licenses, or(at your option) any later version. .PP WildMIDI 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 and the GNU Lesser General Public License for more details. .PP You should have received a copy of the GNU General Public License and the GNU Lesser General Public License along with WildMIDI. If not, see . .PP This manpage is licensed under the Creative Commons Attribution\-Share Alike 3.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. .PP wildmidi-wildmidi-0.4.2/docs/man/man3/WildMidi_GetLyric.3000066400000000000000000000045021315765416100230620ustar00rootroot00000000000000.TH WildMidi_GetLyric 3 "10 March 2016" "" "WildMidi Programmer's Manual" .SH NAME WildMidi_GetLyric \- get lyrics of a midi .SH LIBRARY .B libWildMidi .SH SYNOPSIS .B #include .PP .B char *WildMidi_GetLyric (midi *\fIhandle\fP); .PP .SH DESCRIPTION Returns a pointer to a nul terminated string that contains the data contained in the last read lyric or text meta event. Or returns NULL if no lyric is waiting to be read. .PP .IP \fIhandle\fP The identifier obtained from opening a midi file with \fBWildMidi_Open\fR(3)\fP or \fBWildMidi_OpenBuffer\fR(3)\fP .PP .SH RETURN VALUE On error returns NULL with an error message displayed to stderr. .PP Otherwise returns a pointer to a *char containing the lyric data. .PP .SH SEE ALSO .BR WildMidi_GetVersion (3) , .BR WildMidi_Init (3) , .BR WildMidi_MasterVolume (3) , .BR WildMidi_Open (3) , .BR WildMidi_OpenBuffer (3) , .BR WildMidi_SetOption (3) , .BR WildMidi_GetOutput (3) , .BR WildMidi_GetMidiOutput (3) , .BR WildMidi_FastSeek (3) , .BR WildMidi_Close (3) , .BR WildMidi_Shutdown (3) , .BR wildmidi.cfg (5) .PP .SH AUTHOR Chris Ison Bret Curtis .PP .SH COPYRIGHT Copyright (C) WildMidi Developers 2001\-2016 .PP This file is part of WildMIDI. .PP WildMIDI is free software: you can redistribute and/or modify the player under the terms of the GNU General Public License and you can redistribute and/or modify the library under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the licenses, or(at your option) any later version. .PP WildMIDI 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 and the GNU Lesser General Public License for more details. .PP You should have received a copy of the GNU General Public License and the GNU Lesser General Public License along with WildMIDI. If not, see . .PP This manpage is licensed under the Creative Commons Attribution\-Share Alike 3.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. .PP wildmidi-wildmidi-0.4.2/docs/man/man3/WildMidi_GetMidiOutput.3000066400000000000000000000053461315765416100241120ustar00rootroot00000000000000.TH WildMidi_GetMidiOutput 3 "10 March 2016" "" "WildMidi Programmer's Manual" .SH NAME WildMidi_GetMidiOutput \- get a midi file of a file being processed. .SH LIBRARY .B libWildMidi .PP .SH SYNOPSIS .B #include .PP .B int WildMidi_GetMidiOutput (midi *\fIhandle\fP, int8_t **\fIbuffer\fP, uint32_t *\fIsize\fP) .PP .SH DESCRIPTION Writes the midi\-format data from the file being processed to the memory location pointed to by \fIbuffer\fP. The data will be in type-0 format for type-0 and type-1 files. For type-2 files, the data will be in type-2 format unless the WM_MO_SAVEASTYPE0 option is set. .PP .IP \fIhandle\fP The identifier obtained from opening a file with \fBWildMidi_Open\fR(3)\fP or \fBWildMidi_OpenBuffer\fR(3)\fP .PP .IP \fIbuffer\fP The memory location where libWildMidi is to store the midi data from the \fIhandle\fP. The \fIbuffer\fP will be allocated with \fBmalloc\fP() and must be \fBfree\fP()d by the caller when it is no longer needed. .PP .IP \fIsize\fP The location where libWildMidi is to store the size of the midi data stored in \fIbuffer\fP. .PP .SH "RETURN VALUE" Returns \-1 on error otherwise returns 0 .PP .SH SEE ALSO .BR WildMidi_GetVersion (3) , .BR WildMidi_Init (3) , .BR WildMidi_MasterVolume (3), .BR WildMidi_Open (3) , .BR WildMidi_OpenBuffer (3) , .BR WildMidi_SetOption (3) , .BR WildMidi_GetOutput (3) , .BR WildMidi_GetInfo (3) , .BR WildMidi_FastSeek (3) , .BR WildMidi_Close (3) , .BR WildMidi_Shutdown (3), .BR wildmidi.cfg (5) .PP .SH AUTHOR Chris Ison Bret Curtis .PP .SH COPYRIGHT Copyright (C) WildMidi Developers 2001\-2016 .PP This file is part of WildMIDI. .PP WildMIDI is free software: you can redistribute and/or modify the player under the terms of the GNU General Public License and you can redistribute and/or modify the library under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the licenses, or(at your option) any later version. .PP WildMIDI 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 and the GNU Lesser General Public License for more details. .PP You should have received a copy of the GNU General Public License and the GNU Lesser General Public License along with WildMIDI. If not, see . .PP This manpage is licensed under the Creative Commons Attribution\-Share Alike 3.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. .PP wildmidi-wildmidi-0.4.2/docs/man/man3/WildMidi_GetOutput.3000066400000000000000000000061511315765416100233020ustar00rootroot00000000000000.TH WildMidi_GetOutput 3 "10 March 2016" "" "WildMidi Programmer's Manual" .SH NAME WildMidi_GetOutput \- retrieve raw audio data .PP .SH LIBRARY .B libWildMidi .PP .SH SYNOPSIS .B #include .PP .B int WildMidi_GetOutput (midi *\fIhandle\fP, int8_t *\fIbuffer\fP, uint32_t \fIsize\fP); .PP .SH DESCRIPTION Places \fIsize\fP bytes of audio data from a \fIhandle\fP, previously opened by \fBWildMidi_Open\fP\fR(3)\fP or \fBWildMidi_OpenBuffer\fP\fR(3)\fP, into a buffer pointer to by \fIbuffer\fP. .PP \fIbuffer\fP must be at least \fIsize\fP bytes, with \fIsize\fP being a multiple of 4 as the data is stored in 16bit interleaved stereo format. .PP .IP \fIhandle\fP The identifier obtained from opening a midi file with \fBWildMidi_Open\fR(3)\fP or \fBWildMidi_OpenBuffer\fR(3)\fP .PP .IP \fIbuffer\fP The location supplied by the calling program where libWildMidi is to store the audio data. The audio data will be stored as signed 16bit interleaved stereo in native\-endian byte order. .PP .IP \fIsize\fP The size of the buffer in bytes. Since libWildMidi processes the audio in 16bit interleaved stereo format, this value needs to be a multiple of 4. .PP .SH "RETURN VALUE" Returns \-1 on error along with an error message sent to stderr, 0 when there is no more audio data, otherwise the number of bytes of audio data written to \fIbuffer\fP. .PP NOTE: if the return value is less than the size you gave, this does not denote an error, it simply means the lib reached the end of the midi before it could fill the buffer. .PP .SH SEE ALSO .BR WildMidi_GetVersion (3) , .BR WildMidi_Init (3) , .BR WildMidi_MasterVolume (3) , .BR WildMidi_Open (3) , .BR WildMidi_OpenBuffer (3) , .BR WildMidi_SetOption (3) , .BR WildMidi_GetMidiOutput (3) , .BR WildMidi_GetInfo (3) , .BR WildMidi_FastSeek (3) , .BR WildMidi_Close (3) , .BR WildMidi_Shutdown (3) , .BR wildmidi.cfg (5) .PP .SH AUTHOR Chris Ison Bret Curtis .PP .SH COPYRIGHT Copyright (C) WildMidi Developers 2001\-2016 .PP This file is part of WildMIDI. .PP WildMIDI is free software: you can redistribute and/or modify the player under the terms of the GNU General Public License and you can redistribute and/or modify the library under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the licenses, or(at your option) any later version. .PP WildMIDI 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 and the GNU Lesser General Public License for more details. .PP You should have received a copy of the GNU General Public License and the GNU Lesser General Public License along with WildMIDI. If not, see . .PP This manpage is licensed under the Creative Commons Attribution\-Share Alike 3.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. .PP wildmidi-wildmidi-0.4.2/docs/man/man3/WildMidi_GetString.3000066400000000000000000000043241315765416100232500ustar00rootroot00000000000000.TH WildMidi_GetString 3 "10 March 2016" "" "WildMidi Programmer's Manual" .SH NAME WildMidi_GetString \- Get string from library .SH LIBRARY .B libWildMidi .SH SYNOPSIS .B #include .PP .B const char *WildMidi_GetString (uint16_t \fIinfo\fP); .PP .SH DESCRIPTION Returns a pointer to a string depending on what \fIinfo\fP is set to. .PP At this stage WM_GS_VERSION is the only setting for \fIinfo\fP which returns a pointer to a string containing libWildMidi version information. .PP .SH "RETURN VALUE" Returns a const char pointer to a string containing the string requested. .PP .SH SEE ALSO .BR WildMidi_GetVersion (3) , .BR WildMidi_Init (3) , .BR WildMidi_MasterVolume (3) , .BR WildMidi_Open (3) , .BR WildMidi_OpenBuffer (3) , .BR WildMidi_SetOption (3) , .BR WildMidi_GetOutput (3) , .BR WildMidi_GetMidiOutput (3) , .BR WildMidi_GetInfo (3) , .BR WildMidi_FastSeek (3) , .BR WildMidi_Close (3) , .BR WildMidi_Shutdown (3) , .BR wildmidi.cfg (5) .PP .SH AUTHOR Chris Ison Bret Curtis .PP .SH COPYRIGHT Copyright (C) WildMidi Developers 2001\-2016 .PP This file is part of WildMIDI. .PP WildMIDI is free software: you can redistribute and/or modify the player under the terms of the GNU General Public License and you can redistribute and/or modify the library under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the licenses, or(at your option) any later version. .PP WildMIDI 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 and the GNU Lesser General Public License for more details. .PP You should have received a copy of the GNU General Public License and the GNU Lesser General Public License along with WildMIDI. If not, see . .PP This manpage is licensed under the Creative Commons Attribution\-Share Alike 3.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. .PP wildmidi-wildmidi-0.4.2/docs/man/man3/WildMidi_GetVersion.3000066400000000000000000000042111315765416100234220ustar00rootroot00000000000000.TH WildMidi_GetVersion 3 "10 March 2016" "" "WildMidi Programmer's Manual" .SH NAME WildMidi_GetVersion \- Get the library version .SH LIBRARY .B libWildMidi .SH SYNOPSIS .B #include .PP .B long WildMidi_GetVersion (void); .PP .SH DESCRIPTION Retrieve the library version. Does not require library initialization. .PP .SH "RETURN VALUE" Returns the library version .PP .SH "EXAMPLES" .PP .nf \f(CWlong ver = WildMidi_GetVersion(); printf("libWildMidi\-%ld.%ld.%ld\\n", (ver>>16) & 255, (ver>>8) & 255, (ver) & 255);\fR .fi .PP .SH SEE ALSO .BR WildMidi_Init (3) , .BR WildMidi_MasterVolume (3) , .BR WildMidi_Open (3) , .BR WildMidi_OpenBuffer (3) , .BR WildMidi_SetOption (3) , .BR WildMidi_GetOutput (3) , .BR WildMidi_GetMidiOutput (3) , .BR WildMidi_GetInfo (3) , .BR WildMidi_FastSeek (3) , .BR WildMidi_Close (3) , .BR WildMidi_Shutdown (3) , .BR wildmidi.cfg (5) .PP .SH AUTHOR Chris Ison Bret Curtis .PP .SH COPYRIGHT Copyright (C) WildMidi Developers 2001\-2016 .PP This file is part of WildMIDI. .PP WildMIDI is free software: you can redistribute and/or modify the player under the terms of the GNU General Public License and you can redistribute and/or modify the library under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the licenses, or(at your option) any later version. .PP WildMIDI 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 and the GNU Lesser General Public License for more details. .PP You should have received a copy of the GNU General Public License and the GNU Lesser General Public License along with WildMIDI. If not, see . .PP This manpage is licensed under the Creative Commons Attribution\-Share Alike 3.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. .PP wildmidi-wildmidi-0.4.2/docs/man/man3/WildMidi_Init.3000066400000000000000000000070541315765416100222500ustar00rootroot00000000000000.TH WildMidi_Init 3 "10 March 2016" "" "WildMidi Programmer's Manual" .SH NAME WildMidi_Init \- Initialize the library .PP .SH LIBRARY .B libWildMidi .PP .SH SYNOPSIS .B #include .PP .B WildMidi_Init (const char *\fIconfig_file\fP, uint16_t \fIrate\fP, uint16_t \fIoptions\fP) .PP .SH DESCRIPTION Initializes libWildMidi in preparation for playback. This function only needs to be called once by the program using libWildMidi. .PP .IP \fIconfig-file\fP The file that contains the instrument configuration for the library. .PP .IP \fIrate\fP The sound rate you want the the audio data output at. Rates accepted by libWildMidi are 11025 \- 65000. .PP .IP \fIoptions\fP The initial options to set for the library. see below. .RS .PP .IP WM_MO_LOG_VOLUME By default the library uses linear volume levels typically used in computer MIDI players. These can differ somewhat to volume levels found on some midi hardware which may use a volume curve based on decibels. This option sets the volume levels to what you'd expect on such devices. .PP .IP WM_MO_ENHANCED_RESAMPLING By default libWildMidi uses linear interpolation for the resampling of the sound samples. Setting this option enables the library to use a resampling method that attempts to fill in the gaps giving richer sound. .PP .IP WM_MO_REVERB libWildMidi has an 8 reflection reverb engine. Use this option to give more depth to the output. .PP .IP WM_MO_WHOLETEMPO Ignores the fractional or decimal part of a tempo setting. If you are having timing issues try \fIWM_MO_ROUNDTEMPO\fP before trying this option. This option added due to some software not supporting fractional tempos allowable in the MIDI specification. .PP .IP WM_MO_ROUNDTEMPO Rounds the fractional or decimal part of a tempo setting. Try this option is you are having timing issues, if this fails then try \fIWM_MO_WHOLETEMPO\fP. This option added due to some software not supporting fractional tempos allowable in the MIDI specification. .RE .PP .SH SEE ALSO .BR WildMidi_GetVersion (3) , .BR WildMidi_MasterVolume (3) , .BR WildMidi_Open (3) , .BR WildMidi_OpenBuffer (3) , .BR WildMidi_SetOption (3) , .BR WildMidi_GetOutput (3) , .BR WildMidi_GetMidiOutput (3) , .BR WildMidi_GetInfo (3) , .BR WildMidi_FastSeek (3) , .BR WildMidi_Close (3) , .BR WildMidi_Shutdown (3) , .BR wildmidi.cfg (5) .PP .SH AUTHOR Chris Ison Bret Curtis .PP .SH COPYRIGHT Copyright (C) WildMidi Developers 2001\-2016 .PP This file is part of WildMIDI. .PP WildMIDI is free software: you can redistribute and/or modify the player under the terms of the GNU General Public License and you can redistribute and/or modify the library under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the licenses, or(at your option) any later version. .PP WildMIDI 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 and the GNU Lesser General Public License for more details. .PP You should have received a copy of the GNU General Public License and the GNU Lesser General Public License along with WildMIDI. If not, see . .PP This manpage is licensed under the Creative Commons Attribution\-Share Alike 3.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. .PP wildmidi-wildmidi-0.4.2/docs/man/man3/WildMidi_MasterVolume.3000066400000000000000000000041541315765416100237660ustar00rootroot00000000000000.TH WildMidi_MasterVolume 3 "10 March 2016" "" "WildMidi Programmer's Manual" .SH NAME WildMidi_MasterVolume \- sets the overall audio level of the library. .SH LIBRARY .B libWildMidi .PP .SH SYNOPSIS .B #include .PP .B int WildMidi_MasterVolume (uint8_t \fImaster_volume\fP) .PP .SH DESCRIPTION Sets the overall library volume level to \fImaster_volume\fP. The range of \fImaster_volume\fP is between 0 and 127 with 100 being the default. .PP .SH "RETURN VALUE" Returns \-1 on error, otherwise returns 0. .PP .SH SEE ALSO .BR WildMidi_GetVersion (3) , .BR WildMidi_Init (3) , .BR WildMidi_Open (3) , .BR WildMidi_OpenBuffer (3) , .BR WildMidi_SetOption (3) , .BR WildMidi_GetOutput (3) , .BR WildMidi_GetMidiOutput (3) , .BR WildMidi_GetInfo (3) , .BR WildMidi_FastSeek (3) , .BR WildMidi_Close (3) , .BR WildMidi_Shutdown (3), .BR wildmidi.cfg (5) .PP .SH AUTHOR Chris Ison Bret Curtis .PP .SH COPYRIGHT Copyright (C) WildMidi Developers 2001\-2016 .PP This file is part of WildMIDI. .PP WildMIDI is free software: you can redistribute and/or modify the player under the terms of the GNU General Public License and you can redistribute and/or modify the library under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the licenses, or(at your option) any later version. .PP WildMIDI 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 and the GNU Lesser General Public License for more details. .PP You should have received a copy of the GNU General Public License and the GNU Lesser General Public License along with WildMIDI. If not, see . .PP This manpage is licensed under the Creative Commons Attribution\-Share Alike 3.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. .PP wildmidi-wildmidi-0.4.2/docs/man/man3/WildMidi_Open.3000066400000000000000000000043371315765416100222470ustar00rootroot00000000000000.TH WildMidi_Open 3 "10 March 2016" "" "WildMidi Programmer's Manual" .SH NAME WildMidi_Open \- Open a midi file for processing .SH LIBRARY .B libWildMidi .PP .SH SYNOPSIS .B #include .PP .B midi *WildMidi_Open (const char *\fImidifile\fP) .PP .SH DESCRIPTION Open a MIDI type file pointed to by \fImidifile\fP for processing. This file must be in HMP, HMI, MIDI, or XMIDI format. .PP .SH "RETURN VALUE" Returns NULL on error and sends a message to stderr, otherwise returns a handle for the midi file opened. This handle is used by most functions in libWildMidi to identify which midi file we are referring to. .PP .SH SEE ALSO .BR WildMidi_GetVersion (3) , .BR WildMidi_Init (3) , .BR WildMidi_MasterVolume (3) , .BR WildMidi_OpenBuffer (3) , .BR WildMidi_SetOption (3) , .BR WildMidi_GetOutput (3) , .BR WildMidi_GetMidiOutput (3) , .BR WildMidi_GetInfo (3) , .BR WildMidi_FastSeek (3) , .BR WildMidi_Close (3) , .BR WildMidi_Shutdown (3) , .BR wildmidi.cfg (5) .PP .SH AUTHOR Chris Ison Bret Curtis .PP .SH COPYRIGHT Copyright (C) WildMidi Developers 2001\-2016 .PP This file is part of WildMIDI. .PP WildMIDI is free software: you can redistribute and/or modify the player under the terms of the GNU General Public License and you can redistribute and/or modify the library under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the licenses, or(at your option) any later version. .PP WildMIDI 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 and the GNU Lesser General Public License for more details. .PP You should have received a copy of the GNU General Public License and the GNU Lesser General Public License along with WildMIDI. If not, see . .PP This manpage is licensed under the Creative Commons Attribution\-Share Alike 3.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. .PP wildmidi-wildmidi-0.4.2/docs/man/man3/WildMidi_OpenBuffer.3000066400000000000000000000045761315765416100234060ustar00rootroot00000000000000.TH WildMidi_OpenBuffer 3 "10 March 2016" "" "WildMidi Programmer's Manual" .SH NAME WildMidi_OpenBuffer \- Open a midi file buffer for processing .PP .SH LIBRARY .B libWildMidi .PP .SH SYNOPSIS .B #include .PP .B midi *WildMidi_OpenBuffer (uint8_t *\fImidibuffer\fP, uint32_t \fIsize\fP) .PP .SH DESCRIPTION Open a file, that you have buffered in memory, for processing. .PP .IP \fImidibuffer\fP The memory location of the buffered file. This buffer needs to be in either HMP, HMI, MIDI, or XMIDI file format. Once this function is called, any changes to the buffer will have no effect. .PP .IP \fIsize\fP This is the size of the midi file in bytes that is stored in memory. .PP .SH "RETURN VALUE" Returns NULL on error, otherwise returns a handle for the midi buffer opened. .PP .SH SEE ALSO .BR WildMidi_GetVersion (3) , .BR WildMidi_Init (3) , .BR WildMidi_MasterVolume (3) , .BR WildMidi_Open (3) , .BR WildMidi_SetOption (3) , .BR WildMidi_GetOutput (3) , .BR WildMidi_GetMidiOutput (3) , .BR WildMidi_GetInfo (3) , .BR WildMidi_FastSeek (3) , .BR WildMidi_Close (3) , .BR WildMidi_Shutdown (3) , .BR wildmidi.cfg (5) .PP .SH AUTHOR Chris Ison Bret Curtis .PP .SH COPYRIGHT Copyright (C) WildMidi Developers 2001\-2016 .PP This file is part of WildMIDI. .PP WildMIDI is free software: you can redistribute and/or modify the player under the terms of the GNU General Public License and you can redistribute and/or modify the library under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the licenses, or(at your option) any later version. .PP WildMIDI 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 and the GNU Lesser General Public License for more details. .PP You should have received a copy of the GNU General Public License and the GNU Lesser General Public License along with WildMIDI. If not, see . .PP This manpage is licensed under the Creative Commons Attribution\-Share Alike 3.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. .PP wildmidi-wildmidi-0.4.2/docs/man/man3/WildMidi_SetCvtOption.3000066400000000000000000000044631315765416100237470ustar00rootroot00000000000000.TH WildMidi_SetCvtOption 3 "10 March 2016" "" "WildMidi Programmer's Manual" .SH NAME WildMidi_SetCvtOption \- Set a conversion option for a specific midi .PP .SH LIBRARY .B libWildMidi .PP .SH SYNOPSIS .B #include .PP .B int WildMidi_SetCvtOption (uint16_t *\fItag\fP, uint16_t \fIsetting\fP) .PP .SH DESCRIPTION Set a conversion option for a specific midi. .PP .B \fItag\fP The type of option you wish to change. .PP .RS .IP WM_CO_XMI_TYPE The the conversion type of an XMI to MIDI. .PP .IP WM_CO_FREQUENCY The frequency to be used for a MUS file. .PP .RE .IP \fIsetting\fP Value for the particular tag. .PP .SH "RETURN VALUE" Returns \-1 on error, otherwise returns 0. .SH SEE ALSO .BR WildMidi_GetVersion (3) , .BR WildMidi_Init (3) , .BR WildMidi_MasterVolume (3) , .BR WildMidi_Open (3) , .BR WildMidi_OpenBuffer (3) , .BR WildMidi_SetCvtOption (3) , .BR WildMidi_GetOutput (3) , .BR WildMidi_GetMidiOutput (3) , .BR WildMidi_GetInfo (3) , .BR WildMidi_FastSeek (3) , .BR WildMidi_Close (3) , .BR WildMidi_Shutdown (3) , .BR wildmidi.cfg (5) .PP .SH AUTHOR Chris Ison Bret Curtis .PP .SH COPYRIGHT Copyright (C) WildMidi Developers 2001\-2016 .PP This file is part of WildMIDI. .PP WildMIDI is free software: you can redistribute and/or modify the player under the terms of the GNU General Public License and you can redistribute and/or modify the library under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the licenses, or(at your option) any later version. .PP WildMIDI 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 and the GNU Lesser General Public License for more details. .PP You should have received a copy of the GNU General Public License and the GNU Lesser General Public License along with WildMIDI. If not, see . .PP This manpage is licensed under the Creative Commons Attribution\-Share Alike 3.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. .PP wildmidi-wildmidi-0.4.2/docs/man/man3/WildMidi_SetOption.3000066400000000000000000000074511315765416100232720ustar00rootroot00000000000000.TH WildMidi_SetOption 3 "10 March 2016" "" "WildMidi Programmer's Manual" .SH NAME WildMidi_SetOption \- Set a library option for a specific midi .PP .SH LIBRARY .B libWildMidi .PP .SH SYNOPSIS .B #include .PP .B int WildMidi_SetOption (midi *\fIhandle\fP, uint16_t \fIoptions\fP, uint16_t \fIsetting\fP) .PP .SH DESCRIPTION Set a library option for a specific midi. .PP .IP \fIhandle\fP The identifier obtained from opening a midi file with \fBWildMidi_Open\fR(3)\fP or \fBWildMidi_OpenBuffer\fR(3)\fP .PP .B \fIoptions\fP The option or options you wish to change. .PP .RS .IP WM_MO_LOG_VOLUME By default the library uses linear volume levels typically used in computer MIDI players. These can differ somewhat to volume levels found on some midi hardware which may use a volume curve based on decibels. This option sets the volume levels to what you'd expect on such devices. .PP .IP WM_MO_ENHANCED_RESAMPLING By default libWildMidi uses linear interpolation for the resampling of the sound samples. Setting this option enables the library to use a resampling method that attempts to fill in the gaps giving richer sound. .PP .IP WM_MO_REVERB libWildMidi has an 8 reflection reverb engine. Use this option to give more depth to the output. .PP .IP WM_MO_LOOP Makes libWildMidi to automatically rewind when it reaches the end, so the file would play in continuous loop. .PP .IP WM_MO_STRIPSILENCE Strips silence at song start. .PP .IP WM_MO_SAVEASTYPE0 This option tells \fBWildMidi_GetMidiOutput\fP(3) to output type-0 format data for type-2 files. .PP .IP WM_MO_TEXTASLYRIC Some files have the lyrics in the text meta event. This option reads lyrics from there instead. .PP .RE .IP setting To turn on an option, repeat that option here. To turn off an option, do not put the option here. .PP .IP "Example: To turn on Reverb" WildMidi_SetOption(handle, WM_MO_REVERB, WM_MO_REVERB); .IP "Example: To turn off Reverb" WildMidi_SetOption(handle, WM_MO_REVERB, 0); .IP "Example: To turn on Reverb and Enhanced Resampling" WildMidi_SetOption(handle, (WM_MO_REVERB | WM_MO_ENHANCED_RESAMPLING), (WM_MO_REVERB | WM_MO_ENHANCED_RESAMPLING)); .PP .SH "RETURN VALUE" Returns \-1 on error, otherwise returns 0. .SH SEE ALSO .BR WildMidi_GetVersion (3) , .BR WildMidi_Init (3) , .BR WildMidi_MasterVolume (3) , .BR WildMidi_Open (3) , .BR WildMidi_OpenBuffer (3) , .BR WildMidi_SetOption (3) , .BR WildMidi_GetOutput (3) , .BR WildMidi_GetMidiOutput (3) , .BR WildMidi_GetInfo (3) , .BR WildMidi_FastSeek (3) , .BR WildMidi_Close (3) , .BR WildMidi_Shutdown (3) , .BR wildmidi.cfg (5) .PP .SH AUTHOR Chris Ison Bret Curtis .PP .SH COPYRIGHT Copyright (C) WildMidi Developers 2001\-2016 .PP This file is part of WildMIDI. .PP WildMIDI is free software: you can redistribute and/or modify the player under the terms of the GNU General Public License and you can redistribute and/or modify the library under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the licenses, or(at your option) any later version. .PP WildMIDI 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 and the GNU Lesser General Public License for more details. .PP You should have received a copy of the GNU General Public License and the GNU Lesser General Public License along with WildMIDI. If not, see . .PP This manpage is licensed under the Creative Commons Attribution\-Share Alike 3.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. .PP wildmidi-wildmidi-0.4.2/docs/man/man3/WildMidi_Shutdown.3000066400000000000000000000041061315765416100231530ustar00rootroot00000000000000.TH WildMidi_Shutdown 3 "10 March 2016" "" "WildMidi Programmer's Manual" .SH NAME WildMidi_Shutdown \- Shutdown the library .PP .SH LIBRARY .B libWildMidi .PP .SH SYNOPSIS .B #include .PP .B void WildMidi_Shutdown(\fIvoid\fP) .PP .SH DESCRIPTION Shuts down the wildmidi library, resetting data and freeing up memory used by the library. .PP Once this is called, the library is no longer initialized and \fBWildMidi_Init\fP\fR(3)\fP will need to be called again. .PP .SH SEE ALSO .BR WildMidi_GetVersion (3) , .BR WildMidi_Init (3) , .BR WildMidi_MasterVolume (3) , .BR WildMidi_Open (3) , .BR WildMidi_OpenBuffer (3) , .BR WildMidi_SetOption (3) , .BR WildMidi_GetOutput (3) , .BR WildMidi_GetMidiOutput (3) , .BR WildMidi_GetInfo (3) , .BR WildMidi_FastSeek (3) , .BR WildMidi_Close (3) , .BR wildmidi.cfg (5) .PP .SH AUTHOR Chris Ison Bret Curtis .PP .SH COPYRIGHT Copyright (C) WildMidi Developers 2001\-2016 .PP This file is part of WildMIDI. .PP WildMIDI is free software: you can redistribute and/or modify the player under the terms of the GNU General Public License and you can redistribute and/or modify the library under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the licenses, or(at your option) any later version. .PP WildMIDI 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 and the GNU Lesser General Public License for more details. .PP You should have received a copy of the GNU General Public License and the GNU Lesser General Public License along with WildMIDI. If not, see . .PP This manpage is licensed under the Creative Commons Attribution\-Share Alike 3.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. .PP wildmidi-wildmidi-0.4.2/docs/man/man3/WildMidi_SongSeek.3000066400000000000000000000044571315765416100230670ustar00rootroot00000000000000.TH WildMidi_SongSeek 3 "10 March 2016" "" "WildMidi Programmer's Manual" .SH NAME WildMidi_SongSeek \- Move to next song. .PP .SH LIBRARY .B libWildMidi .PP .SH SYNOPSIS .B #include .PP .B int WildMidi_SongSeek (midi *\fIhandle\fB, int8_t *\fInextsong\fB); .PP .SH DESCRIPTION Stops and flushes currently playing midi and then begins playing the next, previous or the same song contained in a type-2 midi. .PP .IP \fIhandle\fP The identifier obtained from opening a midi file with \fBWildMidi_Open\fR(3)\fP or \fBWildMidi_OpenBuffer\fR(3)\fP .PP .IP \fInextsong\fP Whether to go to previous song (-1), beginning of current song (0), next song (1). Only 0 is accepted for type-0 or type-1 midis. .PP .SH SEE ALSO .BR WildMidi_GetVersion (3) , .BR WildMidi_Init (3) , .BR WildMidi_MasterVolume (3) , .BR WildMidi_Open (3) , .BR WildMidi_OpenBuffer (3) , .BR WildMidi_SetOption (3) , .BR WildMidi_GetOutput (3) , .BR WildMidi_GetMidiOutput (3) , .BR WildMidi_GetInfo (3) , .BR WildMidi_Close (3) , .BR WildMidi_Shutdown (3) , .BR wildmidi.cfg (5) .PP .SH AUTHOR Chris Ison Bret Curtis .PP .SH COPYRIGHT Copyright (C) WildMidi Developers 2001\-2016 .PP This file is part of WildMIDI. .PP WildMIDI is free software: you can redistribute and/or modify the player under the terms of the GNU General Public License and you can redistribute and/or modify the library under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the licenses, or(at your option) any later version. .PP WildMIDI 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 and the GNU Lesser General Public License for more details. .PP You should have received a copy of the GNU General Public License and the GNU Lesser General Public License along with WildMIDI. If not, see . .PP This manpage is licensed under the Creative Commons Attribution\-Share Alike 3.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. .PP wildmidi-wildmidi-0.4.2/docs/man/man5/000077500000000000000000000000001315765416100174735ustar00rootroot00000000000000wildmidi-wildmidi-0.4.2/docs/man/man5/wildmidi.cfg.5000066400000000000000000000133741315765416100221310ustar00rootroot00000000000000.TH wildmidi.cfg 5 "10 March 2016" "" "WildMidi Config File" .SH NAME wildmidi.cfg \- Config file for libWildMidi .PP .SH LIBRARY .B libWildMidi .PP .SH DESCRIPTION Contains the patch configuration for libWildMidi and location of Gravis Ultrasound compatible patch files. .PP .nf dir ~/guspats/ source /etc/wildmidi.cfg bank 0 0 acpiano.pat amp=110 env_time4=300 1 brpiano.pat amp=100 drumset 0 25 snarerol keep=env amp=225 note=60 26 snap note=65 .fi .PP .SH SYNTAX .IP "\fBguspat_editor_author_cant_read_so_fix_release_time_for_me\fP" Some patch file editors switch the 4th and 5th envelopes around making the sound play much longer than intended in players that stuck to the Gravis Ultrasound patch standard. Including this option in the config enables a fix that detects this oversight, playing the sound samples as if they were correct. .IP NOTE: This is a global setting. If it is found to affect good patch samples it will be moved to a per patch setting in a future version. .PP .IP "\fBauto_amp\fP" Forces WildMIDI to amplify samples to their maximum level ignoring the amp=% in the patch lines of the config. .PP .IP "\fBauto_amp_with_amp\fP" Forces WildMIDI to amplify samples to their maximum level then apply the amp=% in the patch lines of the config. .PP .IP "\fBdir\fP \fIdir\-name\fP" Change the search path for config and patch files to \fIdir\-name\fP. This is specific to the current config file and carried to any included config file unless they have their own \fBdir\fP setting. Any included file that has its own \fBdir\fP setting does not effect the \fBdir\fP setting of the current config file. .PP .IP "\fBsource\fP \fIinclude\-confg\fP" Include the settings from \fIinclude\-config\fP. Any patch already set will be over\-ridden by the included config file. .PP .IP "\fBbank\fP \fIN\fP" The patches following this setting belong to MIDI instrument bank \fIN\fP. .PP .IP "\fBdrumset\fP \fIN\fP" The patches following this setting belong to MIDI drum bank \fIN\fP. .PP .IP "\fIpatchno\fP \fIpatchfile\fP [\fBamp=\fP\fIvolume\fP] [\fBnote=\fP\fImiodinte\fP] [\fBkeep=loop\fP] [\fBkeep=env\fP] [\fBremove=sustain\fP] [\fBremove=clamped\fP] [\fBenv_level\fP[\fI0\-5\fP]\fB=\fP\fIlevel\fP] [\fBenv_time\fP[\fI0\-5\fP]\fB=\fP\fItime\fP]" .PP Example: 0 acpiano.pat amp=110 .PP .RS .IP "\fIpatchno\fP" This is the MIDI patch number the instrument belongs to. .PP .IP "\fIpatchfile\fP" The filename of the Gravis Ultrasound compatible patch file. If the filename is missing the .pat extension, libWildMidi will add .pat when attempting to load the file. .PP .IP "\fBamp=\fP\fIvolume\fP" Force the volume of the samples in this patch to \fIvolume\fP% prior to using it. .PP .IP "\fBnote=\fP\fImidinote\fP" Use note \fImidinote\fP when playing the samples in this patch. NOTE: this is for instruments listed under drumset. .PP .IP "\fBkeep=loop\fP" Play the samples in this patch with the loop, when normally we would not for this instrument. .PP .IP "\fBkeep=env\fP" Use the envelope data in this patch, when normally we wouldn't for this instrument. .PP .IP "\fBremove=sustain\fP" Do note hold the note after the 3rd envelope until note off, which is what happens if the sustain bit is set in the patch file. .PP .IP "\fBremove=clamped\fP" Do not jump to 6th envelope on note off, which is what happens if the clamped bit is set in the patch file. .PP .IP "\fBenv_level\fP[\fI0\-5\fP]\fB=\fP\fIlevel\fP" Set the envelope level to \fIlevel\fP with 1.0 being maximum, and 0.0 being minimum. .IP Example: set 5th envelope level to 10% \- \fBenv_level[0\-5]=\fP0.1 .PP .IP "\fBenv_time\fP[\fI0\-5\fP]\fB=\fP\fItime\fP" Set the envelope time to \fItime\fP with a resolution of 1/1000th of a second. This setting is the time it should take for the envelope to reach maximum level. .IP Example: set 1st envelope time to 1sec \- \fBenv_time0=\fP1000 .IP Example: set 3rd envelope time to 0.5secs \- \fBenv_time2=\fP500 .RE .PP .IP "\fBreverb_room_width\fP \fIfval\fP" Set the room width for the reverb engine in meters. \fIfval\fP is a float value in meters. Minimum setting is 1.0 meter, maximum setting is 100.0 meters, and default is 15.0 meters. .IP Example: set room width to 30 meters \- \fBreverb_room_width 30\fP .PP .IP "\fBreverb_room_length\fP \fIfval\fP" Set the room length for the reverb engine in meters. \fIfval\fP is a float value in meters. Minimum setting is 1.0 meter, maximum setting is 100.0 meters, and default is 20.0 meters. .IP Example: set room length to 40 meters \- \fBreverb_room_length 40\fP .PP .SH SEE ALSO .BR wildmidi (1) .PP .SH AUTHOR Chris Ison Bret Curtis .PP .SH COPYRIGHT Copyright (C) Chris Ison 2001\-2010 Copyright (C) Bret Curtis 2013\-2016 .PP This file is part of WildMIDI. .PP WildMIDI is free software: you can redistribute and/or modify the player under the terms of the GNU General Public License and you can redistribute and/or modify the library under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the licenses, or(at your option) any later version. .PP WildMIDI 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 and the GNU Lesser General Public License for more details. .PP You should have received a copy of the GNU General Public License and the GNU Lesser General Public License along with WildMIDI. If not, see . .PP This manpage is licensed under the Creative Commons Attribution\-Share Alike 3.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. .PP wildmidi-wildmidi-0.4.2/include/000077500000000000000000000000001315765416100165535ustar00rootroot00000000000000wildmidi-wildmidi-0.4.2/include/common.h000066400000000000000000000033331315765416100202160ustar00rootroot00000000000000/* * common.h -- Midi Wavetable Processing library * * Copyright (C) WildMIDI Developers 2001-2016 * * This file is part of WildMIDI. * * WildMIDI is free software: you can redistribute and/or modify the player * under the terms of the GNU General Public License and you can redistribute * and/or modify the library under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either version 3 of * the licenses, or(at your option) any later version. * * WildMIDI 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 and * the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License and the * GNU Lesser General Public License along with WildMIDI. If not, see * . */ #ifndef __COMMON_H #define __COMMON_H #ifndef __VBCC__ #define UNUSED(x) (void)(x) #else #define UNUSED(x) /* vbcc emits an annoying warning for (void)(x) */ #endif #define MEM_CHUNK 8192 extern int16_t _WM_MasterVolume; extern uint16_t _WM_SampleRate; extern uint16_t _WM_MixerOptions; extern float _WM_reverb_room_width; /* = 16.875f; */ extern float _WM_reverb_room_length; /* = 22.5f; */ extern float _WM_reverb_listen_posx; /* = 8.4375f; */ extern float _WM_reverb_listen_posy; /* = 16.875f; */ extern void _cvt_reset_options (void); extern uint16_t _cvt_get_option (uint16_t tag); /* Set our global defines here */ #ifndef M_PI #define M_PI 3.14159265358979323846 #endif #ifndef M_LN2 #define M_LN2 0.69314718055994530942 #endif #endif /* __COMMON_H */ wildmidi-wildmidi-0.4.2/include/config.h.cmake000066400000000000000000000042521315765416100212530ustar00rootroot00000000000000/* config.h -- generated from config.h.cmake */ /* Name of package */ #define PACKAGE "wildmidi" /* Define to the home page for this package. */ #define PACKAGE_URL "http://www.mindwerks.net/projects/wildmidi/" /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "https://github.com/Mindwerks/wildmidi/issues" /* Define to the full name of this package. */ #define PACKAGE_NAME "WildMidi" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "WildMidi @WILDMIDI_VERSION@" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "wildmidi" /* Define to the version of this package. */ #define PACKAGE_VERSION "@WILDMIDI_VERSION@" /* Version number of package */ #define VERSION "@WILDMIDI_VERSION@" /* Define this to the location of the wildmidi config file */ #define WILDMIDI_CFG "@WILDMIDI_CFG@" /* Define if the C compiler supports the `inline' keyword. */ #cmakedefine HAVE_C_INLINE /* Define if the C compiler supports the `__inline__' keyword. */ #cmakedefine HAVE_C___INLINE__ /* Define if the C compiler supports the `__inline' keyword. */ #cmakedefine HAVE_C___INLINE #if !defined(HAVE_C_INLINE) && !defined(__cplusplus) # ifdef HAVE_C___INLINE__ # define inline __inline__ # elif defined(HAVE_C___INLINE) # define inline __inline # else # define inline # endif #endif /* Define if the compiler has the `__builtin_expect' built-in function */ #cmakedefine HAVE___BUILTIN_EXPECT #ifndef HAVE___BUILTIN_EXPECT #define __builtin_expect(x,c) x #endif /* define this if you are running a bigendian system (motorola, sparc, etc) */ #cmakedefine WORDS_BIGENDIAN 1 /* define this if building for AmigaOS variants */ #cmakedefine WILDMIDI_AMIGA 1 /* Define if you have the header file. */ #cmakedefine HAVE_STDINT_H /* Define if you have the header file. */ #cmakedefine HAVE_INTTYPES_H /* Define our audio drivers */ #cmakedefine HAVE_LINUX_SOUNDCARD_H #cmakedefine HAVE_SYS_SOUNDCARD_H #cmakedefine HAVE_MACHINE_SOUNDCARD_H #cmakedefine HAVE_SOUNDCARD_H #cmakedefine AUDIODRV_ALSA #cmakedefine AUDIODRV_OSS #cmakedefine AUDIODRV_OPENAL #cmakedefine AUDIODRV_AHI wildmidi-wildmidi-0.4.2/include/f_hmi.h000066400000000000000000000021271315765416100200100ustar00rootroot00000000000000/* * hmi.h -- Midi Wavetable Processing library * * Copyright (C) WildMIDI Developers 2001-2016 * * This file is part of WildMIDI. * * WildMIDI is free software: you can redistribute and/or modify the player * under the terms of the GNU General Public License and you can redistribute * and/or modify the library under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either version 3 of * the licenses, or(at your option) any later version. * * WildMIDI 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 and * the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License and the * GNU Lesser General Public License along with WildMIDI. If not, see * . */ #ifndef __HMI_H #define __HMI_H extern struct _mdi *_WM_ParseNewHmi(uint8_t *hmi_data, uint32_t hmi_size); #endif /* __HMI_H */ wildmidi-wildmidi-0.4.2/include/f_hmp.h000066400000000000000000000021271315765416100200170ustar00rootroot00000000000000/* * hmp.h -- Midi Wavetable Processing library * * Copyright (C) WildMIDI Developers 2001-2016 * * This file is part of WildMIDI. * * WildMIDI is free software: you can redistribute and/or modify the player * under the terms of the GNU General Public License and you can redistribute * and/or modify the library under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either version 3 of * the licenses, or(at your option) any later version. * * WildMIDI 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 and * the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License and the * GNU Lesser General Public License along with WildMIDI. If not, see * . */ #ifndef __HMP_H #define __HMP_H extern struct _mdi *_WM_ParseNewHmp(uint8_t *hmp_data, uint32_t hmp_size); #endif /* __HMP_H */ wildmidi-wildmidi-0.4.2/include/f_midi.h000066400000000000000000000022551315765416100201570ustar00rootroot00000000000000/* * midi.h -- Midi Wavetable Processing library * * Copyright (C) WildMIDI Developers 2001-2016 * * This file is part of WildMIDI. * * WildMIDI is free software: you can redistribute and/or modify the player * under the terms of the GNU General Public License and you can redistribute * and/or modify the library under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either version 3 of * the licenses, or(at your option) any later version. * * WildMIDI 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 and * the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License and the * GNU Lesser General Public License along with WildMIDI. If not, see * . */ #ifndef __MIDI_H #define __MIDI_H extern struct _mdi *_WM_ParseNewMidi(uint8_t *midi_data, uint32_t midi_size); extern int _WM_Event2Midi(struct _mdi *mdi, uint8_t **out, uint32_t *outsize); #endif /* __MIDI_H */ wildmidi-wildmidi-0.4.2/include/f_mus.h000066400000000000000000000021431315765416100200350ustar00rootroot00000000000000/* * mus_wm.h -- Midi Wavetable Processing library * * Copyright (C) WildMIDI Developers 2001-2016 * * This file is part of WildMIDI. * * WildMIDI is free software: you can redistribute and/or modify the player * under the terms of the GNU General Public License and you can redistribute * and/or modify the library under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either version 3 of * the licenses, or(at your option) any later version. * * WildMIDI 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 and * the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License and the * GNU Lesser General Public License along with WildMIDI. If not, see * . */ #ifndef __MUS_WM_H #define __MUS_WM_H extern struct _mdi *_WM_ParseNewMus(uint8_t *mus_data, uint32_t mus_size); #endif /* __MUS_WM_H */ wildmidi-wildmidi-0.4.2/include/f_xmidi.h000066400000000000000000000021271315765416100203450ustar00rootroot00000000000000/* * xmi.h -- Midi Wavetable Processing library * * Copyright (C) WildMIDI Developers 2001-2016 * * This file is part of WildMIDI. * * WildMIDI is free software: you can redistribute and/or modify the player * under the terms of the GNU General Public License and you can redistribute * and/or modify the library under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either version 3 of * the licenses, or(at your option) any later version. * * WildMIDI 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 and * the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License and the * GNU Lesser General Public License along with WildMIDI. If not, see * . */ #ifndef __XMI_H #define __XMI_H extern struct _mdi *_WM_ParseNewXmi(uint8_t *xmi_data, uint32_t xmi_size); #endif /* __XMI_H */ wildmidi-wildmidi-0.4.2/include/file_io.h000066400000000000000000000022141315765416100203310ustar00rootroot00000000000000/* * file_io.c -- file handling * * Copyright (C) Chris Ison 2001-2011 * Copyright (C) Bret Curtis 2013-2016 * * This file is part of WildMIDI. * * WildMIDI is free software: you can redistribute and/or modify the player * under the terms of the GNU General Public License and you can redistribute * and/or modify the library under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either version 3 of * the licenses, or(at your option) any later version. * * WildMIDI 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 and * the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License and the * GNU Lesser General Public License along with WildMIDI. If not, see * . */ #ifndef __FILE_IO_H #define __FILE_IO_H #define WM_MAXFILESIZE 0x1fffffff extern void *_WM_BufferFile (const char *filename, uint32_t *size); #endif /* __FILE_IO_H */ wildmidi-wildmidi-0.4.2/include/filenames.h000066400000000000000000000160431315765416100206730ustar00rootroot00000000000000/* Macros for taking apart, interpreting and processing file names. * * These are here because some non-Posix (a.k.a. DOSish) systems have * drive letter brain-damage at the beginning of an absolute file name, * use forward- and back-slash in path names interchangeably, and * some of them have case-insensitive file names. * * This was based on filenames.h from BFD, the Binary File Descriptor * library, Copyright (C) 2000-2016 Free Software Foundation, Inc., * and changed by O. Sezer for our needs. * The original version of this header in binutils/gcc is GPL licensed, * this modified version was authorized to be LGPL in our LGPL projects: * http://gcc.gnu.org/ml/gcc-patches/2016-09/msg02007.html * http://gcc.gnu.org/ml/gcc-patches/2016-09/msg02179.html * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser * General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef FILENAMES_H #define FILENAMES_H #include /* ---------------------- Windows, DOS, OS2: ---------------------- */ #if defined(__MSDOS__) || defined(MSDOS) || defined(__DOS__) || \ defined(__DJGPP__) || defined(__OS2__) || defined(__EMX__) || \ defined(_WIN32) || defined(__CYGWIN__) #define HAVE_DOS_BASED_FILE_SYSTEM 1 #define HAVE_CASE_INSENSITIVE_FILE_SYSTEM 1 #define HAS_DRIVE_SPEC(f) ((f)[0] && ((f)[1] == ':')) #define STRIP_DRIVE_SPEC(f) ((f) + 2) #define IS_DIR_SEPARATOR(c) ((c) == '/' || (c) == '\\') /* both '/' and '\\' work as dir separator. djgpp likes changing * '\\' into '/', so I define DIR_SEPARATOR_CHAR as '/' for djgpp, * '\\' otherwise. */ #ifdef __DJGPP__ #define DIR_SEPARATOR_CHAR '/' #define DIR_SEPARATOR_STR "/" #else #define DIR_SEPARATOR_CHAR '\\' #define DIR_SEPARATOR_STR "\\" #endif /* Note that IS_ABSOLUTE_PATH accepts d:foo as well, although it is only semi-absolute. This is because the users of IS_ABSOLUTE_PATH want to know whether to prepend the current working directory to a file name, which should not be done with a name like d:foo. */ #define IS_ABSOLUTE_PATH(f) (IS_DIR_SEPARATOR((f)[0]) || HAS_DRIVE_SPEC((f))) #ifdef __cplusplus static inline char *FIND_FIRST_DIRSEP(char *_the_path) { /* FIXME: What about C:FOO ? */ char *p1 = strchr(_the_path, '/'); char *p2 = strchr(_the_path, '\\'); if (p1 == NULL) return p2; if (p2 == NULL) return p1; return (p1 < p2)? p1 : p2; } static inline char *FIND_LAST_DIRSEP (char *_the_path) { /* FIXME: What about C:FOO ? */ char *p1 = strrchr(_the_path, '/'); char *p2 = strrchr(_the_path, '\\'); if (p1 == NULL) return p2; if (p2 == NULL) return p1; return (p1 > p2)? p1 : p2; } static inline const char *FIND_FIRST_DIRSEP(const char *_the_path) { /* FIXME: What about C:FOO ? */ const char *p1 = strchr(_the_path, '/'); const char *p2 = strchr(_the_path, '\\'); if (p1 == NULL) return p2; if (p2 == NULL) return p1; return (p1 < p2)? p1 : p2; } static inline const char *FIND_LAST_DIRSEP (const char *_the_path) { /* FIXME: What about C:FOO ? */ const char *p1 = strrchr(_the_path, '/'); const char *p2 = strrchr(_the_path, '\\'); if (p1 == NULL) return p2; if (p2 == NULL) return p1; return (p1 > p2)? p1 : p2; } #else static inline char *FIND_FIRST_DIRSEP(const char *_the_path) { /* FIXME: What about C:FOO ? */ char *p1 = strchr(_the_path, '/'); char *p2 = strchr(_the_path, '\\'); if (p1 == NULL) return p2; if (p2 == NULL) return p1; return (p1 < p2)? p1 : p2; } static inline char *FIND_LAST_DIRSEP (const char *_the_path) { /* FIXME: What about C:FOO ? */ char *p1 = strrchr(_the_path, '/'); char *p2 = strrchr(_the_path, '\\'); if (p1 == NULL) return p2; if (p2 == NULL) return p1; return (p1 > p2)? p1 : p2; } #endif /* C++ */ /* ----------------- AmigaOS, MorphOS, AROS, etc: ----------------- */ #elif defined(__MORPHOS__) || defined(__AROS__) || defined(AMIGAOS) || \ defined(__amigaos__) || defined(__amigaos4__) || defined(__amigados__) || \ defined(AMIGA) || defined(_AMIGA) || defined(__AMIGA__) #define HAS_DRIVE_SPEC(f) (0) /* */ #define STRIP_DRIVE_SPEC(f) (f) /* */ #define IS_DIR_SEPARATOR(c) ((c) == '/' || (c) == ':') #define DIR_SEPARATOR_CHAR '/' #define DIR_SEPARATOR_STR "/" #define IS_ABSOLUTE_PATH(f) (IS_DIR_SEPARATOR((f)[0]) || (strchr((f), ':'))) #define HAVE_CASE_INSENSITIVE_FILE_SYSTEM 1 #ifdef __cplusplus static inline char *FIND_FIRST_DIRSEP(char *_the_path) { char *p = strchr(_the_path, ':'); if (p != NULL) return p; return strchr(_the_path, '/'); } static inline char *FIND_LAST_DIRSEP (char *_the_path) { char *p = strrchr(_the_path, '/'); if (p != NULL) return p; return strchr(_the_path, ':'); } static inline const char *FIND_FIRST_DIRSEP(const char *_the_path) { const char *p = strchr(_the_path, ':'); if (p != NULL) return p; return strchr(_the_path, '/'); } static inline const char *FIND_LAST_DIRSEP (const char *_the_path) { const char *p = strrchr(_the_path, '/'); if (p != NULL) return p; return strchr(_the_path, ':'); } #else static inline char *FIND_FIRST_DIRSEP(const char *_the_path) { char *p = strchr(_the_path, ':'); if (p != NULL) return p; return strchr(_the_path, '/'); } static inline char *FIND_LAST_DIRSEP (const char *_the_path) { char *p = strrchr(_the_path, '/'); if (p != NULL) return p; return strchr(_the_path, ':'); } #endif /* C++ */ /* ---------------------- assumed UNIX-ish : ---------------------- */ #else /* */ #define IS_DIR_SEPARATOR(c) ((c) == '/') #define DIR_SEPARATOR_CHAR '/' #define DIR_SEPARATOR_STR "/" #define IS_ABSOLUTE_PATH(f) (IS_DIR_SEPARATOR((f)[0])) #define HAS_DRIVE_SPEC(f) (0) #define STRIP_DRIVE_SPEC(f) (f) #ifdef __cplusplus static inline char *FIND_FIRST_DIRSEP(char *_the_path) { return strchr(_the_path, '/'); } static inline char *FIND_LAST_DIRSEP (char *_the_path) { return strrchr(_the_path, '/'); } static inline const char *FIND_FIRST_DIRSEP(const char *_the_path) { return strchr(_the_path, '/'); } static inline const char *FIND_LAST_DIRSEP (const char *_the_path) { return strrchr(_the_path, '/'); } #else static inline char *FIND_FIRST_DIRSEP(const char *_the_path) { return strchr(_the_path, '/'); } static inline char *FIND_LAST_DIRSEP (const char *_the_path) { return strrchr(_the_path, '/'); } #endif /* C++ */ #endif #endif /* FILENAMES_H */ wildmidi-wildmidi-0.4.2/include/getopt_long.h000066400000000000000000000051721315765416100212520ustar00rootroot00000000000000/* $OpenBSD: getopt.h,v 1.3 2013/11/22 21:32:49 millert Exp $ */ /* $NetBSD: getopt.h,v 1.4 2000/07/07 10:43:54 ad Exp $ */ /*- * Copyright (c) 2000 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Dieter Baron and Thomas Klausner. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef _GETOPT_H_ #define _GETOPT_H_ /* * GNU-like getopt_long() */ #define no_argument 0 #define required_argument 1 #define optional_argument 2 struct option { /* name of long option */ const char *name; /* * one of no_argument, required_argument, and optional_argument: * whether option takes an argument */ int has_arg; /* if not NULL, set *flag to val when option found */ int *flag; /* if flag not NULL, value to set *flag to; else return value */ int val; }; #if defined(__cplusplus) extern "C" { #endif int getopt_long(int, char * const *, const char *, const struct option *, int *); int getopt_long_only(int, char * const *, const char *, const struct option *, int *); #ifndef _GETOPT_DEFINED_ #define _GETOPT_DEFINED_ int getopt(int, char * const *, const char *); extern char *optarg; /* getopt(3) external variables */ extern int opterr; extern int optind; extern int optopt; extern int optreset; #endif #if defined(__cplusplus) } #endif #endif /* !_GETOPT_H_ */ wildmidi-wildmidi-0.4.2/include/gus_pat.h000066400000000000000000000122311315765416100203650ustar00rootroot00000000000000/* * gus_pat.h -- Midi Wavetable Processing library * * Copyright (C) WildMIDI Developers 2001-2016 * * This file is part of WildMIDI. * * WildMIDI is free software: you can redistribute and/or modify the player * under the terms of the GNU General Public License and you can redistribute * and/or modify the library under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either version 3 of * the licenses, or(at your option) any later version. * * WildMIDI 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 and * the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License and the * GNU Lesser General Public License along with WildMIDI. If not, see * . */ #ifndef __GUS_PAT_H #define __GUS_PAT_H /* Guspat Envelope Rate Timings */ #ifndef _WILDMIDI_LIB_C static float env_time_table[] = { /* Row 1 = (4095.0 / (x * ( 1.0 / (1.6 * 14.0) ))) / 1000000.0 */ 0.0f, 0.091728000f, 0.045864000f, 0.030576000f, 0.022932000f, 0.018345600f, 0.015288000f, 0.013104000f, 0.011466000f, 0.010192000f, 0.009172800f, 0.008338909f, 0.007644000f, 0.007056000f, 0.006552000f, 0.006115200f, 0.005733000f, 0.005395765f, 0.005096000f, 0.004827789f, 0.004586400f, 0.004368000f, 0.004169455f, 0.003988174f, 0.003822000f, 0.003669120f, 0.003528000f, 0.003397333f, 0.003276000f, 0.003163034f, 0.003057600f, 0.002958968f, 0.002866500f, 0.002779636f, 0.002697882f, 0.002620800f, 0.002548000f, 0.002479135f, 0.002413895f, 0.002352000f, 0.002293200f, 0.002237268f, 0.002184000f, 0.002133209f, 0.002084727f, 0.002038400f, 0.001994087f, 0.001951660f, 0.001911000f, 0.001872000f, 0.001834560f, 0.001798588f, 0.001764000f, 0.001730717f, 0.001698667f, 0.001667782f, 0.001638000f, 0.001609263f, 0.001581517f, 0.001554712f, 0.001528800f, 0.001503738f, 0.001479484f, 0.001456000f, /* Row 2 = (4095.0 / (x * ((1.0 / (1.6 * 14.0)) / 8.0 ))) / 1000000.0 */ 0.0f, 0.733824000f, 0.366912000f, 0.244608000f, 0.183456000f, 0.146764800f, 0.122304000f, 0.104832000f, 0.091728000f, 0.081536000f, 0.073382400f, 0.066711273f, 0.061152000f, 0.056448000f, 0.052416000f, 0.048921600f, 0.045864000f, 0.043166118f, 0.040768000f, 0.038622316f, 0.036691200f, 0.034944000f, 0.033355636f, 0.031905391f, 0.030576000f, 0.029352960f, 0.028224000f, 0.027178667f, 0.026208000f, 0.025304276f, 0.024460800f, 0.023671742f, 0.022932000f, 0.022237091f, 0.021583059f, 0.020966400f, 0.020384000f, 0.019833081f, 0.019311158f, 0.018816000f, 0.018345600f, 0.017898146f, 0.017472000f, 0.017065674f, 0.016677818f, 0.016307200f, 0.015952696f, 0.015613277f, 0.015288000f, 0.014976000f, 0.014676480f, 0.014388706f, 0.014112000f, 0.013845736f, 0.013589333f, 0.013342255f, 0.013104000f, 0.012874105f, 0.012652138f, 0.012437695f, 0.012230400f, 0.012029902f, 0.011835871f, 0.011648000f, /* Row 3 = (4095.0 / (x * ((1.0 / (1.6 * 14.0)) / 64.0 ))) / 1000000.0 */ 0.0f, 5.870592000f, 2.935296000f, 1.956864000f, 1.467648000f, 1.174118400f, 0.978432000f, 0.838656000f, 0.733824000f, 0.652288000f, 0.587059200f, 0.533690182f, 0.489216000f, 0.451584000f, 0.419328000f, 0.391372800f, 0.366912000f, 0.345328941f, 0.326144000f, 0.308978526f, 0.293529600f, 0.279552000f, 0.266845091f, 0.255243130f, 0.244608000f, 0.234823680f, 0.225792000f, 0.217429333f, 0.209664000f, 0.202434207f, 0.195686400f, 0.189373935f, 0.183456000f, 0.177896727f, 0.172664471f, 0.167731200f, 0.163072000f, 0.158664649f, 0.154489263f, 0.150528000f, 0.146764800f, 0.143185171f, 0.139776000f, 0.136525395f, 0.133422545f, 0.130457600f, 0.127621565f, 0.124906213f, 0.122304000f, 0.119808000f, 0.117411840f, 0.115109647f, 0.112896000f, 0.110765887f, 0.108714667f, 0.106738036f, 0.104832000f, 0.102992842f, 0.101217103f, 0.099501559f, 0.097843200f, 0.096239213f, 0.094686968f, 0.093184000f, /* Row 4 = (4095.0 / (x * ((1.0 / (1.6 * 14.0)) / 512.0))) / 1000000.0 */ 0.0f, 46.964736000f,23.482368000f,15.654912000f,11.741184000f, 9.392947200f, 7.827456000f, 6.709248000f, 5.870592000f, 5.218304000f, 4.696473600f, 4.269521455f, 3.913728000f, 3.612672000f, 3.354624000f, 3.130982400f, 2.935296000f, 2.762631529f, 2.609152000f, 2.471828211f, 2.348236800f, 2.236416000f, 2.134760727f, 2.041945043f, 1.956864000f, 1.878589440f, 1.806336000f, 1.739434667f, 1.677312000f, 1.619473655f, 1.565491200f, 1.514991484f, 1.467648000f, 1.423173818f, 1.381315765f, 1.341849600f, 1.304576000f, 1.269317189f, 1.235914105f, 1.204224000f, 1.174118400f, 1.145481366f, 1.118208000f, 1.092203163f, 1.067380364f, 1.043660800f, 1.020972522f, 0.999249702f, 0.978432000f, 0.958464000f, 0.939294720f, 0.920877176f, 0.903168000f, 0.886127094f, 0.869717333f, 0.853904291f, 0.838656000f, 0.823942737f, 0.809736828f, 0.796012475f, 0.782745600f, 0.769913705f, 0.757495742f, 0.745472000f }; #endif /* !_WILDMIDI_LIB_C */ extern struct _sample * _WM_load_gus_pat (const char *filename, int _fix_release); #endif /* __GUS_PAT_H */ wildmidi-wildmidi-0.4.2/include/internal_midi.h000066400000000000000000000175051315765416100215520ustar00rootroot00000000000000/* * internal_midi.h -- Midi Wavetable Processing library * * Copyright (C) WildMIDI Developers 2001-2016 * * This file is part of WildMIDI. * * WildMIDI is free software: you can redistribute and/or modify the player * under the terms of the GNU General Public License and you can redistribute * and/or modify the library under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either version 3 of * the licenses, or(at your option) any later version. * * WildMIDI 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 and * the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License and the * GNU Lesser General Public License along with WildMIDI. If not, see * . */ #ifndef __INTERNAL_MIDI_H #define __INTERNAL_MIDI_H struct _channel { uint8_t bank; struct _patch *patch; uint8_t hold; uint8_t volume; uint8_t pressure; uint8_t expression; int8_t balance; int8_t pan; int16_t left_adjust; int16_t right_adjust; int16_t pitch; int16_t pitch_range; int32_t pitch_adjust; uint16_t reg_data; uint8_t reg_non; uint8_t isdrum; }; struct _event_data { uint8_t channel; union Data { uint32_t value; char * string; } data; }; struct _note { uint16_t noteid; uint8_t velocity; struct _patch *patch; struct _sample *sample; uint32_t sample_pos; uint32_t sample_inc; int32_t env_inc; uint8_t env; int32_t env_level; uint8_t modes; uint8_t hold; uint8_t active; struct _note *replay; struct _note *next; uint32_t left_mix_volume; uint32_t right_mix_volume; uint8_t is_off; uint8_t ignore_chan_events; }; struct _mdi; struct _event { void (*do_event)(struct _mdi *mdi, struct _event_data *data); struct _event_data event_data; uint32_t samples_to_next; uint32_t samples_to_next_fixed; }; struct _mdi { int lock; uint32_t samples_to_mix; struct _event *events; struct _event *current_event; uint32_t event_count; uint32_t events_size; /* try to stay optimally ahead to prevent reallocs */ struct _WM_Info extra_info; struct _WM_Info *tmp_info; uint16_t midi_master_vol; struct _channel channel[16]; struct _note *note; struct _note note_table[2][16][128]; struct _patch **patches; uint32_t patch_count; int16_t amp; int32_t *mix_buffer; uint32_t mix_buffer_size; struct _rvb *reverb; int32_t dyn_vol_peak; double dyn_vol_adjust; double dyn_vol; double dyn_vol_to_reach; uint8_t is_type2; char *lyric; }; extern int16_t _WM_lin_volume[]; extern uint32_t _WM_freq_table[]; /* ===================== */ /* * All "do" functions need to be "extern" for playback */ extern void _WM_do_midi_divisions(struct _mdi *mdi, struct _event_data *data); extern void _WM_do_note_off(struct _mdi *mdi, struct _event_data *data); extern void _WM_do_note_on(struct _mdi *mdi, struct _event_data *data); extern void _WM_do_aftertouch(struct _mdi *mdi, struct _event_data *data); extern void _WM_do_control_bank_select(struct _mdi *mdi, struct _event_data *data); extern void _WM_do_control_data_entry_course(struct _mdi *mdi, struct _event_data *data); extern void _WM_do_control_channel_volume(struct _mdi *mdi, struct _event_data *data); extern void _WM_do_control_channel_balance(struct _mdi *mdi, struct _event_data *data); extern void _WM_do_control_channel_pan(struct _mdi *mdi, struct _event_data *data); extern void _WM_do_control_channel_expression(struct _mdi *mdi, struct _event_data *data); extern void _WM_do_control_data_entry_fine(struct _mdi *mdi, struct _event_data *data); extern void _WM_do_control_channel_hold(struct _mdi *mdi, struct _event_data *data); extern void _WM_do_control_data_increment(struct _mdi *mdi, struct _event_data *data); extern void _WM_do_control_data_decrement(struct _mdi *mdi, struct _event_data *data); extern void _WM_do_control_non_registered_param_fine(struct _mdi *mdi, struct _event_data *data); extern void _WM_do_control_non_registered_param_course(struct _mdi *mdi, struct _event_data *data); extern void _WM_do_control_registered_param_fine(struct _mdi *mdi, struct _event_data *data); extern void _WM_do_control_registered_param_course(struct _mdi *mdi, struct _event_data *data); extern void _WM_do_control_channel_sound_off(struct _mdi *mdi, struct _event_data *data); extern void _WM_do_control_channel_controllers_off(struct _mdi *mdi, struct _event_data *data); extern void _WM_do_control_channel_notes_off(struct _mdi *mdi, struct _event_data *data); extern void _WM_do_control_dummy(struct _mdi *mdi, struct _event_data *data); extern void _WM_do_patch(struct _mdi *mdi, struct _event_data *data); extern void _WM_do_channel_pressure(struct _mdi *mdi, struct _event_data *data); extern void _WM_do_pitch(struct _mdi *mdi, struct _event_data *data); extern void _WM_do_sysex_roland_drum_track(struct _mdi *mdi, struct _event_data *data); extern void _WM_do_sysex_gm_reset(struct _mdi *mdi, struct _event_data *data); extern void _WM_do_sysex_roland_reset(struct _mdi *mdi, struct _event_data *data); extern void _WM_do_sysex_yamaha_reset(struct _mdi *mdi, struct _event_data *data); extern void _WM_do_meta_endoftrack(struct _mdi *mdi, struct _event_data *data); extern void _WM_do_meta_tempo(struct _mdi *mdi, struct _event_data *data); extern void _WM_do_meta_timesignature(struct _mdi *mdi, struct _event_data *data); extern void _WM_do_meta_keysignature(struct _mdi *mdi, struct _event_data *data); extern void _WM_do_meta_sequenceno(struct _mdi *mdi, struct _event_data *data); extern void _WM_do_meta_channelprefix(struct _mdi *mdi, struct _event_data *data); extern void _WM_do_meta_portprefix(struct _mdi *mdi, struct _event_data *data); extern void _WM_do_meta_smpteoffset(struct _mdi *mdi, struct _event_data *data); extern void _WM_do_meta_text(struct _mdi *mdi, struct _event_data *data); extern void _WM_do_meta_copyright(struct _mdi *mdi, struct _event_data *data); extern void _WM_do_meta_trackname(struct _mdi *mdi, struct _event_data *data); extern void _WM_do_meta_instrumentname(struct _mdi *mdi, struct _event_data *data); extern void _WM_do_meta_lyric(struct _mdi *mdi, struct _event_data *data); extern void _WM_do_meta_marker(struct _mdi *mdi, struct _event_data *data); extern void _WM_do_meta_cuepoint(struct _mdi *mdi, struct _event_data *data); /* * We need to expose these fuctions for use on some or the parsers due to some * formats not being able to trigger these events via _WM_Setup_Midi_Event. */ extern int _WM_midi_setup_noteoff(struct _mdi *mdi, uint8_t channel, uint8_t note, uint8_t velocity); extern int _WM_midi_setup_endoftrack(struct _mdi *mdi); extern int _WM_midi_setup_tempo(struct _mdi *mdi, uint32_t setting); /* ===================== */ /* * Only non-standard midi event or non-track event setup functions need to be here */ extern int _WM_midi_setup_divisions(struct _mdi *mdi, uint32_t divisions); /* ===================== */ /* * All other declarations */ extern struct _mdi * _WM_initMDI(void); extern void _WM_freeMDI(struct _mdi *mdi); extern uint32_t _WM_SetupMidiEvent(struct _mdi *mdi, uint8_t *event_data, uint32_t inlen, uint8_t running_event); extern void _WM_ResetToStart(struct _mdi *mdi); extern void _WM_do_pan_adjust(struct _mdi *mdi, uint8_t ch); extern void _WM_do_note_off_extra(struct _note *nte); /* extern void _WM_DynamicVolumeAdjust(struct _mdi *mdi, int32_t *tmp_buffer, uint32_t buffer_used);*/ extern void _WM_AdjustChannelVolumes(struct _mdi *mdi, uint8_t ch); extern float _WM_GetSamplesPerTick(uint32_t divisions, uint32_t tempo); #endif /* __INTERNAL_MIDI_H */ wildmidi-wildmidi-0.4.2/include/lock.h000066400000000000000000000023311315765416100176530ustar00rootroot00000000000000/* * lock.h - data locking code for lib * * Copyright (C) Chris Ison 2001-2011 * Copyright (C) Bret Curtis 2013-2016 * * This file is part of WildMIDI. * * WildMIDI is free software: you can redistribute and/or modify the player * under the terms of the GNU General Public License and you can redistribute * and/or modify the library under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either version 3 of * the licenses, or(at your option) any later version. * * WildMIDI 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 and * the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License and the * GNU Lesser General Public License along with WildMIDI. If not, see * . */ #ifndef __LOCK_H #define __LOCK_H extern void _WM_Lock (int * wmlock); extern void _WM_Unlock (int *wmlock); #if defined WM_NO_LOCK #define _WM_Lock(p) do {} while (0) #define _WM_Unlock(p) do {} while (0) #endif #endif /* __LOCK_H */ wildmidi-wildmidi-0.4.2/include/mus2mid.h000066400000000000000000000020571315765416100203100ustar00rootroot00000000000000/* * MUS2MIDI: DMX (DOOM) MUS to MIDI Library Header * * Copyright (C) 2014-2016 Bret Curtis * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef MUSLIB_H #define MUSLIB_H #include int _WM_mus2midi (const uint8_t *in, uint32_t insize, uint8_t **out, uint32_t *outsize, uint16_t frequency); #endif /* MUSLIB_H */ wildmidi-wildmidi-0.4.2/include/patches.h000066400000000000000000000031301315765416100203500ustar00rootroot00000000000000/* * patches.h -- Midi Wavetable Processing library * * Copyright (C) WildMIDI Developers 2001-2016 * * This file is part of WildMIDI. * * WildMIDI is free software: you can redistribute and/or modify the player * under the terms of the GNU General Public License and you can redistribute * and/or modify the library under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either version 3 of * the licenses, or(at your option) any later version. * * WildMIDI 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 and * the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License and the * GNU Lesser General Public License along with WildMIDI. If not, see * . */ #ifndef __PATCHES_H #define __PATCHES_H struct _env { float time; float level; uint8_t set; }; struct _sample; struct _mdi; struct _patch { uint16_t patchid; uint8_t loaded; char *filename; int16_t amp; uint8_t keep; uint8_t remove; struct _env env[6]; uint8_t note; uint32_t inuse_count; struct _sample *first_sample; struct _patch *next; }; extern struct _patch *_WM_patch[128]; extern int _WM_patch_lock; extern struct _patch *_WM_get_patch_data(struct _mdi *mdi, uint16_t patchid); extern void _WM_load_patch(struct _mdi *mdi, uint16_t patchid); #endif /* __PATCHES_H */ wildmidi-wildmidi-0.4.2/include/reverb.h000066400000000000000000000034271315765416100202170ustar00rootroot00000000000000/* * reverb.h -- Midi Wavetable Processing library * * Copyright (C) Chris Ison 2001-2011 * Copyright (C) Bret Curtis 2013-2016 * * This file is part of WildMIDI. * * WildMIDI is free software: you can redistribute and/or modify the player * under the terms of the GNU General Public License and you can redistribute * and/or modify the library under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either version 3 of * the licenses, or(at your option) any later version. * * WildMIDI 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 and * the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License and the * GNU Lesser General Public License along with WildMIDI. If not, see * . */ #ifndef __REVERB_H #define __REVERB_H struct _rvb { /* filter data */ int32_t l_buf_flt_in[8][6][2]; int32_t l_buf_flt_out[8][6][2]; int32_t r_buf_flt_in[8][6][2]; int32_t r_buf_flt_out[8][6][2]; int32_t coeff[8][6][5]; /* buffer data */ int32_t *l_buf; int32_t *r_buf; int l_buf_size; int r_buf_size; int l_out; int r_out; int l_sp_in[8]; int r_sp_in[8]; int l_in[4]; int r_in[4]; int gain; uint32_t max_reverb_time; }; extern void _WM_reset_reverb (struct _rvb *rvb); extern struct _rvb *_WM_init_reverb(int rate, float room_x, float room_y, float listen_x, float listen_y); extern void _WM_free_reverb (struct _rvb *rvb); extern void _WM_do_reverb (struct _rvb *rvb, int32_t *buffer, int size); #endif /* __REVERB_H */ wildmidi-wildmidi-0.4.2/include/sample.h000066400000000000000000000041671315765416100202150ustar00rootroot00000000000000/* * sample.h -- Midi Wavetable Processing library * * Copyright (C) WildMIDI Developers 2001-2016 * * This file is part of WildMIDI. * * WildMIDI is free software: you can redistribute and/or modify the player * under the terms of the GNU General Public License and you can redistribute * and/or modify the library under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either version 3 of * the licenses, or(at your option) any later version. * * WildMIDI 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 and * the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License and the * GNU Lesser General Public License along with WildMIDI. If not, see * . */ #ifndef __SAMPLE_H #define __SAMPLE_H #define SAMPLE_16BIT 0x01 #define SAMPLE_UNSIGNED 0x02 #define SAMPLE_LOOP 0x04 #define SAMPLE_PINGPONG 0x08 #define SAMPLE_REVERSE 0x10 #define SAMPLE_SUSTAIN 0x20 #define SAMPLE_ENVELOPE 0x40 #define SAMPLE_CLAMPED 0x80 #ifdef DEBUG_SAMPLES #define SAMPLE_CONVERT_DEBUG(dx) printf("\r%s\n",dx) #else #define SAMPLE_CONVERT_DEBUG(dx) #endif struct _patch; struct _mdi; struct _sample { uint32_t data_length; uint32_t loop_start; uint32_t loop_end; uint32_t loop_size; uint8_t loop_fraction; uint16_t rate; uint32_t freq_low; uint32_t freq_high; uint32_t freq_root; uint8_t modes; int32_t env_rate[7]; int32_t env_target[7]; uint32_t inc_div; int16_t *data; struct _sample *next; uint32_t note_off_decay; }; extern int _WM_fix_release; extern int _WM_auto_amp; extern int _WM_auto_amp_with_amp; extern struct _sample *_WM_get_sample_data(struct _patch *sample_patch, uint32_t freq); extern int _WM_load_sample(struct _patch *sample_patch); extern uint32_t _WM_get_decay_samples(struct _mdi * mdi, uint8_t channel, uint8_t note); #endif /* __SAMPLE_H */ wildmidi-wildmidi-0.4.2/include/stdint/000077500000000000000000000000001315765416100200605ustar00rootroot00000000000000wildmidi-wildmidi-0.4.2/include/stdint/stdint.h000066400000000000000000000012511315765416100215350ustar00rootroot00000000000000#ifndef WM_STDINT_H #define WM_STDINT_H #include typedef signed char int8_t; typedef unsigned char uint8_t; typedef signed short int int16_t; typedef unsigned short int uint16_t; #if (INT_MAX == 2147483647) typedef signed int int32_t; typedef unsigned int uint32_t; #elif (LONG_MAX == 2147483647) typedef signed long int int32_t; typedef unsigned long int uint32_t; #else #error define a 32bit integral type #endif /* int32_t */ /* make sure of type sizes */ typedef int _wm_int8_test [(sizeof(int8_t ) == 1) * 2 - 1]; typedef int _wm_int16_test[(sizeof(int16_t) == 2) * 2 - 1]; typedef int _wm_int32_test[(sizeof(int32_t) == 4) * 2 - 1]; #endif /* WM_STDINT_H */ wildmidi-wildmidi-0.4.2/include/wildmidi_lib.h000066400000000000000000000131671315765416100213640ustar00rootroot00000000000000/* * wildmidi_lib.h -- Midi Wavetable Processing library * * Copyright (C) WildMIDI Developers 2001-2016 * * This file is part of WildMIDI. * * WildMIDI is free software: you can redistribute and/or modify the player * under the terms of the GNU General Public License and you can redistribute * and/or modify the library under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either version 3 of * the licenses, or(at your option) any later version. * * WildMIDI 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 and * the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License and the * GNU Lesser General Public License along with WildMIDI. If not, see * . */ #ifndef WILDMIDI_LIB_H #define WILDMIDI_LIB_H /* library version number */ #define LIBWILDMIDI_VER_MAJOR 0L #define LIBWILDMIDI_VER_MINOR 4L #define LIBWILDMIDI_VER_MICRO 2L #define LIBWILDMIDI_VERSION \ ((LIBWILDMIDI_VER_MAJOR << 16) | \ (LIBWILDMIDI_VER_MINOR << 8) | \ (LIBWILDMIDI_VER_MICRO )) /* public constants */ #define WM_MO_LOG_VOLUME 0x0001 #define WM_MO_ENHANCED_RESAMPLING 0x0002 #define WM_MO_REVERB 0x0004 #define WM_MO_LOOP 0x0008 #define WM_MO_SAVEASTYPE0 0x1000 #define WM_MO_ROUNDTEMPO 0x2000 #define WM_MO_STRIPSILENCE 0x4000 #define WM_MO_TEXTASLYRIC 0x8000 /* conversion options */ #define WM_CO_XMI_TYPE 0x0010 #define WM_CO_FREQUENCY 0x0020 /* for WildMidi_GetString */ #define WM_GS_VERSION 0x0001 /* set our symbol export visiblity */ #if defined _WIN32 || defined __CYGWIN__ /* ========== NOTE TO WINDOWS DEVELOPERS: * If you are compiling for Windows and will link to the static library * (libWildMidi.a with MinGW, or wildmidi_static.lib with MSVC, etc), * you must define WILDMIDI_STATIC in your project. Otherwise dllimport * will be assumed. */ # if defined(WILDMIDI_BUILD) && defined(DLL_EXPORT) /* building libWildMidi as a dll for windows */ # define WM_SYMBOL __declspec(dllexport) # elif defined(WILDMIDI_BUILD) || defined(WILDMIDI_STATIC) /* building or using static libWildMidi for windows */ # define WM_SYMBOL # else /* using libWildMidi dll for windows */ # define WM_SYMBOL __declspec(dllimport) # endif #elif defined(WILDMIDI_BUILD) # if defined(SYM_VISIBILITY) /* __GNUC__ >= 4, or older gcc with backported feature */ # define WM_SYMBOL __attribute__ ((visibility ("default"))) /* # elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590) # define WM_SYMBOL __attribute__ ((visibility ("default"))) */ # elif defined(SYM_LDSCOPE) /* __SUNPRO_C >= 0x550 */ # define WM_SYMBOL __global # elif defined(__OS2__) && defined(__WATCOMC__) && defined(__SW_BD) # define WM_SYMBOL __declspec(dllexport) # else # define WM_SYMBOL # endif #else # define WM_SYMBOL #endif #include #if defined(__cplusplus) extern "C" { #endif struct _WM_Info { char *copyright; uint32_t current_sample; uint32_t approx_total_samples; uint16_t mixer_options; uint32_t total_midi_time; }; typedef void midi; WM_SYMBOL const char * WildMidi_GetString (uint16_t info); WM_SYMBOL long WildMidi_GetVersion (void); WM_SYMBOL int WildMidi_Init (const char *config_file, uint16_t rate, uint16_t mixer_options); WM_SYMBOL int WildMidi_MasterVolume (uint8_t master_volume); WM_SYMBOL midi * WildMidi_Open (const char *midifile); WM_SYMBOL midi * WildMidi_OpenBuffer (uint8_t *midibuffer, uint32_t size); WM_SYMBOL int WildMidi_GetMidiOutput (midi *handle, int8_t **buffer, uint32_t *size); WM_SYMBOL int WildMidi_GetOutput (midi *handle, int8_t *buffer, uint32_t size); WM_SYMBOL int WildMidi_SetOption (midi *handle, uint16_t options, uint16_t setting); WM_SYMBOL int WildMidi_SetCvtOption (uint16_t tag, uint16_t setting); WM_SYMBOL int WildMidi_ConvertToMidi (const char *file, uint8_t **out, uint32_t *size); WM_SYMBOL int WildMidi_ConvertBufferToMidi (uint8_t *in, uint32_t insize, uint8_t **out, uint32_t *size); WM_SYMBOL struct _WM_Info * WildMidi_GetInfo (midi * handle); WM_SYMBOL int WildMidi_FastSeek (midi * handle, unsigned long int *sample_pos); WM_SYMBOL int WildMidi_SongSeek (midi * handle, int8_t nextsong); WM_SYMBOL int WildMidi_Close (midi * handle); WM_SYMBOL int WildMidi_Shutdown (void); WM_SYMBOL char * WildMidi_GetLyric (midi * handle); WM_SYMBOL char * WildMidi_GetError (void); WM_SYMBOL void WildMidi_ClearError (void); /* NOTE: Not Yet Implemented Or Tested Properly */ /* Due to delay in audio output in the player, this is not being developed futher at the moment. Further Development will occur when output latency has been reduced enough to "appear" instant. WM_SYMBOL int WildMidi_Live (midi * handle, uint32_t midi_event); */ /* reserved for future coding * need to change these to use a time for cmd_pos and new_cmd_pos WM_SYMBOL int WildMidi_InsertMidiEvent (midi * handle, uint8_t char midi_cmd, *char midi_cmd_data, unsigned long int midi_cmd_data_size, unsigned long int *cmd_pos); WM_SYMBOL int WildMidi_DeleteMidiEvent (midi * handle, uint8_t char midi_cmd, unsigned long int *cmd_pos); WM_SYMBOL int WildMidi_MoveMidiEvent (midi * handle, , uint8_t char midi_cmd, unsigned long int *cmd_pos, unsigned long int *new_cmd_pos); */ #if defined(__cplusplus) } #endif #endif /* WILDMIDI_LIB_H */ wildmidi-wildmidi-0.4.2/include/wm_error.h000066400000000000000000000036141315765416100205640ustar00rootroot00000000000000/* * wm_error.h -- error reporting * * Copyright (C) WildMIDI Developers 2001-2016 * * This file is part of WildMIDI. * * WildMIDI is free software: you can redistribute and/or modify the player * under the terms of the GNU General Public License and you can redistribute * and/or modify the library under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either version 3 of * the licenses, or(at your option) any later version. * * WildMIDI 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 and * the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License and the * GNU Lesser General Public License along with WildMIDI. If not, see * . */ #ifndef __WM_ERROR_H #define __WM_ERROR_H enum { WM_ERR_NONE = 0, WM_ERR_MEM, WM_ERR_STAT, WM_ERR_LOAD, WM_ERR_OPEN, WM_ERR_READ, WM_ERR_INVALID, WM_ERR_CORUPT, WM_ERR_NOT_INIT, WM_ERR_INVALID_ARG, WM_ERR_ALR_INIT, WM_ERR_NOT_MIDI, WM_ERR_LONGFIL, WM_ERR_NOT_HMP, WM_ERR_NOT_HMI, WM_ERR_CONVERT, WM_ERR_NOT_MUS, WM_ERR_NOT_XMI, WM_ERR_MAX }; extern char * _WM_Global_ErrorS; extern int _WM_Global_ErrorI; extern void _WM_GLOBAL_ERROR(const char *func, int lne, int wmerno, const char * wmfor, int error); /* sets the global error string to a custom msg */ extern void _WM_ERROR_NEW(const char * wmfmt, ...) #ifdef __GNUC__ __attribute__((format(printf, 1, 2))) #endif ; /* prints a debug message to stderr */ extern void _WM_DEBUG_MSG(const char * wmfmt, ...) #ifdef __GNUC__ __attribute__((format(printf, 1, 2))) #endif ; #endif /* __WM_ERROR_H */ wildmidi-wildmidi-0.4.2/include/wm_tty.h000066400000000000000000000024551315765416100202550ustar00rootroot00000000000000/* wm_tty.h - unix termios code for player * * Copyright (C) Chris Ison 2001-2011 * Copyright (C) Bret Curtis 2013-2016 * * This file is part of WildMIDI. * * WildMIDI is free software: you can redistribute and/or modify the player * under the terms of the GNU General Public License and you can redistribute * and/or modify the library under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either version 3 of * the licenses, or(at your option) any later version. * * WildMIDI 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 and * the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License and the * GNU Lesser General Public License along with WildMIDI. If not, see * . */ #ifndef wm_tty_h #define wm_tty_h void wm_inittty(void); void wm_resetty(void); #if defined(_WIN32)||defined(__DJGPP__)||defined(WILDMIDI_AMIGA)||defined(__OS2__)||defined(__EMX__) #define wm_inittty() do {} while (0) #define wm_resetty() do {} while (0) #endif /* _WIN32, __DJGPP__, __OS2__ */ #endif /* wm_tty_h */ wildmidi-wildmidi-0.4.2/include/xmi2mid.h000066400000000000000000000027431315765416100203030ustar00rootroot00000000000000/* * XMIDI: Miles XMIDI to MID Library Header * * Copyright (C) 2001 Ryan Nunn * Copyright (C) 2014-2016 Bret Curtis * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ /* XMIDI Converter */ #ifndef XMIDILIB_H #define XMIDILIB_H #include /* Conversion types for Midi files */ #define XMIDI_CONVERT_NOCONVERSION 0x00 #define XMIDI_CONVERT_MT32_TO_GM 0x01 #define XMIDI_CONVERT_MT32_TO_GS 0x02 #define XMIDI_CONVERT_MT32_TO_GS127 0x03 /* This one is broken, don't use */ #define XMIDI_CONVERT_MT32_TO_GS127DRUM 0x04 /* This one is broken, don't use */ #define XMIDI_CONVERT_GS127_TO_GS 0x05 int _WM_xmi2midi(const uint8_t *in, uint32_t insize, uint8_t **out, uint32_t *outsize, uint32_t convert_type); #endif /* XMIDILIB_H */ wildmidi-wildmidi-0.4.2/os2/000077500000000000000000000000001315765416100156335ustar00rootroot00000000000000wildmidi-wildmidi-0.4.2/os2/config.h000066400000000000000000000007021315765416100172500ustar00rootroot00000000000000#define WILDMIDI_CFG "wildmidi.cfg" #define PACKAGE_URL "http://www.mindwerks.net/projects/wildmidi/" #define PACKAGE_BUGREPORT "https://github.com/Mindwerks/wildmidi/issues" #define PACKAGE_VERSION "0.4.2" #define HAVE_C_INLINE #if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR >= 96) #define HAVE___BUILTIN_EXPECT #endif #ifndef HAVE___BUILTIN_EXPECT #define __builtin_expect(x,c) x #endif #define AUDIODRV_OS2DART 1 /* OS/2 DART output */ wildmidi-wildmidi-0.4.2/os2/makefile000066400000000000000000000047001315765416100173340ustar00rootroot00000000000000# Makefile for OS/2 using Watcom compiler. # # wmake # - builds wildmidi.dll and its import lib (wildmidi.lib) # # wmake target=static # - builds the static library wildmidi_static.lib !ifndef target target = dll !endif CFLAGS = -bt=os2 -bm -fp5 -fpi87 -mf -oeatxh -w4 -ei -j -zp8 -zq # -5s : Pentium stack calling conventions. # -5r : Pentium register calling conventions. CFLAGS+= -5s DLLFLAGS=-bd .SUFFIXES: .SUFFIXES: .obj .c DLLNAME=wildmidi.dll EXPNAME=wildmidi.exp LIBNAME=wildmidi.lib LIBSTATIC=wildmidi_static.lib PLAYER=wildmidi.exe PLAYER_STATIC=wildmidi_static.exe PLAYER_LIBS=mmpm2.lib CFLAGS_LIB= $(CFLAGS) -DWILDMIDI_BUILD CFLAGS_EXE= $(CFLAGS) !ifeq target static BLD_TARGET=$(LIBSTATIC) $(PLAYER_STATIC) !else CFLAGS_LIB+= $(DLLFLAGS) BLD_TARGET=$(DLLNAME) $(PLAYER) !endif OBJ=wm_error.obj file_io.obj lock.obj wildmidi_lib.obj reverb.obj gus_pat.obj f_xmidi.obj f_mus.obj f_hmp.obj f_midi.obj f_hmi.obj mus2mid.obj xmi2mid.obj internal_midi.obj patches.obj sample.obj PLAYER_OBJ=getopt_long.obj wm_tty.obj wildmidi.obj all: $(BLD_TARGET) # rely on symbol name, not ordinal: -irn switch of wlib is default, but -inn is not. $(DLLNAME): $(OBJ) wlink NAM $@ SYSTEM os2v2_dll INITINSTANCE TERMINSTANCE OPTION MANYAUTODATA FIL {$(OBJ)} OPTION IMPF=$(EXPNAME) wlib -q -b -n -inn -pa -s -t -zld -ii -io $(LIBNAME) +$(DLLNAME) $(LIBSTATIC): $(OBJ) wlib -q -b -n $@ $(OBJ) $(PLAYER): $(DLLNAME) $(PLAYER_OBJ) wlink N $@ SYS OS2V2 LIBR {$(LIBNAME) $(PLAYER_LIBS)} F {$(PLAYER_OBJ)} $(PLAYER_STATIC): $(LIBSTATIC) $(PLAYER_OBJ) wlink N $@ SYS OS2V2 LIBR {$(LIBSTATIC) $(PLAYER_LIBS)} F {$(PLAYER_OBJ)} # rules for library objs: .c.obj: wcc386 $(CFLAGS_LIB) $(INCLUDES) -fo=$^@ $< # rules for player objs: getopt_long.obj: getopt_long.c wcc386 $(CFLAGS_EXE) $(INCLUDES) -fo=$^@ $< wm_tty.obj: wm_tty.c wcc386 $(CFLAGS_EXE) $(INCLUDES) -fo=$^@ $< wildmidi.obj: wildmidi.c wcc386 $(CFLAGS_EXE) $(INCLUDES) -fo=$^@ $< !ifndef __UNIX__ INCLUDES=-I. -I..\include .c: ..\src distclean: clean .symbolic @if exist $(LIBSTATIC) del $(LIBSTATIC) @if exist $(DLLNAME) del $(DLLNAME) @if exist $(EXPNAME) del $(EXPNAME) @if exist $(LIBNAME) del $(LIBNAME) @if exist $(PLAYER) del $(PLAYER) @if exist $(PLAYER_STATIC) del $(PLAYER_STATIC) clean: .symbolic @if exist *.obj del *.obj !else INCLUDES=-I. -I../include .c: ../src distclean: clean .symbolic rm -f $(DLLNAME) $(EXPNAME) $(LIBNAME) $(LIBSTATIC) $(PLAYER) $(PLAYER_STATIC) clean: .symbolic rm -f *.obj !endif wildmidi-wildmidi-0.4.2/os2/makefile.emx000066400000000000000000000024121315765416100201220ustar00rootroot00000000000000# Makefile for OS/2 using EMX environment. # builds static wildmidi.a library and wildmidi.exe player CC=gcc AS=as AR=ar RANLIB=ranlib LD=$(CC) INCLUDES=-I. -I../include/stdint -I../include CFLAGS = $(INCLUDES) -Wall -W -Zmt LDFLAGS = -Zmt ARFLAGS = cr ifeq ($(DEBUG),1) CFLAGS += -g else CFLAGS += -O2 -ffast-math LDFLAGS+= -s endif LIBSTATIC=wildmidi.a PLAYER_STATIC=wildmidi.exe PLAYER_LIBS=-L. -lwildmidi #PLAYER_LIBS+=-lmmpm2 PLAYER_LIBS+=-los2me CFLAGS_LIB= $(CFLAGS) -DWILDMIDI_BUILD CFLAGS_EXE= $(CFLAGS) OBJ=wm_error.o file_io.o lock.o wildmidi_lib.o reverb.o gus_pat.o f_xmidi.o f_mus.o f_hmp.o f_midi.o f_hmi.o mus2mid.o xmi2mid.o internal_midi.o patches.o sample.o PLAYER_OBJ=wildmidi.o getopt_long.o wm_tty.o all: $(LIBSTATIC) $(PLAYER_STATIC) $(LIBSTATIC): $(OBJ) $(AR) $(ARFLAGS) $@ $^ -$(RANLIB) $@ $(PLAYER_STATIC): $(LIBSTATIC) $(PLAYER_OBJ) $(LD) -o $@ $(PLAYER_OBJ) $(PLAYER_LIBS) $(LDFLAGS) # rules for library objs: %.o: ../src/%.c $(CC) -c $(CFLAGS_LIB) -o $@ $< # rules for player objs: getopt_long.o: ../src/getopt_long.c $(CC) -c $(CFLAGS_EXE) -o $@ $< wm_tty.o: ../src/wm_tty.c $(CC) -c $(CFLAGS_EXE) -o $@ $< wildmidi.o: ../src/wildmidi.c $(CC) -c $(CFLAGS_EXE) -o $@ $< clean: $(RM) *.o distclean: clean $(RM) $(LIBSTATIC) $(PLAYER_STATIC) wildmidi-wildmidi-0.4.2/src/000077500000000000000000000000001315765416100157175ustar00rootroot00000000000000wildmidi-wildmidi-0.4.2/src/CMakeLists.txt000066400000000000000000000337441315765416100204720ustar00rootroot00000000000000# Setup our wildmidi library that we link to SET(wildmidi_library_SRCS wm_error.c file_io.c lock.c wildmidi_lib.c reverb.c gus_pat.c internal_midi.c patches.c f_xmidi.c f_mus.c f_hmp.c f_midi.c f_hmi.c sample.c mus2mid.c xmi2mid.c ) SET(wildmidi_library_HDRS ../include/wm_error.h ../include/file_io.h ../include/lock.h ../include/wildmidi_lib.h ../include/reverb.h ../include/gus_pat.h ../include/f_xmidi.h ../include/f_mus.h ../include/f_hmp.h ../include/f_midi.h ../include/f_hmi.h ../include/internal_midi.h ../include/patches.h ../include/sample.h ../include/common.h ../include/filenames.h ../include/mus2mid.h ../include/xmi2mid.h ) IF (MSVC) SET(GETOPT getopt_long.c) ELSE () SET(GETOPT) ENDIF () IF (AMIGA OR AROS) SET(SYS_OTHER amiga.c) ELSE () SET(SYS_OTHER) ENDIF () SET(wildmidi_executable_SRCS ${GETOPT} ${SYS_OTHER} wm_tty.c wildmidi.c ) SET(wildmidi_executable_HDRS ../include/wm_tty.h ../include/getopt_long.h ) # set our target paths SET(EXECUTABLE_OUTPUT_PATH "${CMAKE_BINARY_DIR}") SET(LIBRARY_OUTPUT_PATH "${CMAKE_BINARY_DIR}") # set our library names IF (WIN32 AND NOT CMAKE_COMPILER_IS_MINGW) # windows uses *.lib for both static and dynamic, workaround SET(LIBRARY_DYN_NAME "wildmidi_dynamic") SET(LIBRARY_STATIC_NAME "wildmidi_static") ELSE () # everyone else uses .a and .so SET(LIBRARY_DYN_NAME "WildMidi") SET(LIBRARY_STATIC_NAME "WildMidi") ENDIF () # do we want a static library? IF (WANT_STATIC) ADD_LIBRARY(libwildmidi_static STATIC ${wildmidi_library_SRCS} ${wildmidi_library_HDRS} ) TARGET_LINK_LIBRARIES(libwildmidi_static ${M_LIBRARY} ) SET_TARGET_PROPERTIES(libwildmidi_static PROPERTIES OUTPUT_NAME ${LIBRARY_STATIC_NAME} CLEAN_DIRECT_OUTPUT 1 COMPILE_DEFINITIONS WILDMIDI_BUILD ) ENDIF (WANT_STATIC) IF (BUILD_SHARED_LIBS) # dynamic library ADD_LIBRARY(libwildmidi_dynamic SHARED ${wildmidi_library_SRCS} ${wildmidi_library_HDRS} ) TARGET_LINK_LIBRARIES(libwildmidi_dynamic ${M_LIBRARY} ) SET_TARGET_PROPERTIES(libwildmidi_dynamic PROPERTIES SOVERSION ${SOVERSION} VERSION ${VERSION} OUTPUT_NAME ${LIBRARY_DYN_NAME} CLEAN_DIRECT_OUTPUT 1 ) IF (WIN32) SET_TARGET_PROPERTIES(libwildmidi_dynamic PROPERTIES DEFINE_SYMBOL DLL_EXPORT COMPILE_DEFINITIONS WILDMIDI_BUILD ) ELSEIF (HAVE_VISIBILITY_HIDDEN AND HAVE_VISIBILITY_DEFAULT) # GCC, Clang SET_TARGET_PROPERTIES(libwildmidi_dynamic PROPERTIES COMPILE_DEFINITIONS "WILDMIDI_BUILD;SYM_VISIBILITY" COMPILE_FLAGS "-fvisibility=hidden" ) #ELSEIF (HAVE_LDSCOPE_HIDDEN AND HAVE_VISIBILITY_DEFAULT) # SunPro (__SUNPRO_C >= 0x590) # SET_TARGET_PROPERTIES(libwildmidi_dynamic PROPERTIES # COMPILE_DEFINITIONS "WILDMIDI_BUILD;SYM_VISIBILITY" # COMPILE_FLAGS "-xldscope=hidden" # ) ELSEIF (HAVE_LDSCOPE_HIDDEN AND HAVE_LDSCOPE_GLOBAL) # SunPro (__SUNPRO_C >= 0x550) SET_TARGET_PROPERTIES(libwildmidi_dynamic PROPERTIES COMPILE_DEFINITIONS "WILDMIDI_BUILD;SYM_LDSCOPE" COMPILE_FLAGS "-xldscope=hidden" ) ELSE () SET_TARGET_PROPERTIES(libwildmidi_dynamic PROPERTIES COMPILE_DEFINITIONS WILDMIDI_BUILD ) ENDIF () ENDIF (BUILD_SHARED_LIBS) # Set our default and then look at the possible locations SET(WILDMIDILIB "${CMAKE_BINARY_DIR}/lib${LIBRARY_DYN_NAME}.so") SET(WILDMIDILIBSTATIC "${CMAKE_BINARY_DIR}/lib${LIBRARY_STATIC_NAME}.a") # MS Visual Studio IF (MSVC) SET(WILDMIDILIB "${CMAKE_BINARY_DIR}\\${CMAKE_BUILD_TYPE}\\${LIBRARY_DYN_NAME}.lib") SET(WILDMIDILIBSTATIC "${CMAKE_BINARY_DIR}\\${CMAKE_BUILD_TYPE}\\${LIBRARY_STATIC_NAME}.lib") ENDIF (MSVC) # MinGW or MinGW-w64 IF (CMAKE_COMPILER_IS_MINGW) SET(WILDMIDILIB "${CMAKE_BINARY_DIR}/lib${LIBRARY_DYN_NAME}.dll.a") SET(WILDMIDIDLL "${CMAKE_BINARY_DIR}/lib${LIBRARY_DYN_NAME}.dll") SET(WILDMIDILIBSTATIC "${CMAKE_BINARY_DIR}/lib${LIBRARY_STATIC_NAME}.a") ENDIF (CMAKE_COMPILER_IS_MINGW) # Apple's Xcode IF (CMAKE_GENERATOR STREQUAL "Xcode") SET(WILDMIDILIB "${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}/lib${LIBRARY_DYN_NAME}.dylib") SET(WILDMIDILIBSTATIC "${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}/lib${LIBRARY_STATIC_NAME}.a") ELSEIF (APPLE) # Apple's CLI default SET(WILDMIDILIB "${CMAKE_BINARY_DIR}/lib${LIBRARY_DYN_NAME}.dylib") SET(WILDMIDILIBSTATIC "${CMAKE_BINARY_DIR}/lib${LIBRARY_STATIC_NAME}.a") ENDIF (CMAKE_GENERATOR STREQUAL "Xcode") # do we want the wildmidi player? IF (WANT_PLAYER AND BUILD_SHARED_LIBS) ADD_EXECUTABLE(wildmidi ${wildmidi_executable_SRCS} ${wildmidi_executable_HDRS} ) ADD_DEPENDENCIES(wildmidi libwildmidi_dynamic) IF (AUDIODRV_OPENAL) TARGET_INCLUDE_DIRECTORIES(wildmidi PRIVATE ${OPENAL_INCLUDE_DIR} ) ELSEIF (AUDIODRV_ALSA) TARGET_INCLUDE_DIRECTORIES(wildmidi PRIVATE ${ALSA_INCLUDE_DIR} ) ELSEIF (AUDIODRV_OSS) # no special header paths ENDIF () TARGET_LINK_LIBRARIES(wildmidi ${WILDMIDILIB} ${M_LIBRARY} ${AUDIO_LIBRARY} ) ENDIF () IF (WANT_PLAYERSTATIC) ADD_EXECUTABLE(wildmidi-static ${wildmidi_executable_SRCS} ${wildmidi_executable_HDRS} ) ADD_DEPENDENCIES(wildmidi-static libwildmidi_static) SET_TARGET_PROPERTIES(wildmidi-static PROPERTIES COMPILE_DEFINITIONS WILDMIDI_STATIC ) IF (AUDIODRV_OPENAL) TARGET_INCLUDE_DIRECTORIES(wildmidi-static PRIVATE ${OPENAL_INCLUDE_DIR} ) ELSEIF (AUDIODRV_ALSA) TARGET_INCLUDE_DIRECTORIES(wildmidi-static PRIVATE ${ALSA_INCLUDE_DIR} ) ELSEIF (AUDIODRV_OSS) # no special header paths ENDIF () TARGET_LINK_LIBRARIES(wildmidi-static ${WILDMIDILIBSTATIC} ${M_LIBRARY} ${AUDIO_LIBRARY} ) ENDIF (WANT_PLAYERSTATIC) IF (WANT_DEVTEST) SET(wildmidi-devtest_executable_SRCS ${GETOPT} DevTest.c ) ADD_EXECUTABLE(wildmidi-devtest ${wildmidi-devtest_executable_SRCS} ) ENDIF (WANT_DEVTEST) # convenience variables SET(WILDMIDILIB_INSTALLDIR "lib${LIB_SUFFIX}") SET(WILDMIDIDLL_INSTALLDIR "bin${LIB_SUFFIX}") # add multiarch folder, if needed IF (CMAKE_LIBRARY_ARCHITECTURE) SET(WILDMIDILIB_INSTALLDIR "${WILDMIDILIB_INSTALLDIR}/${CMAKE_LIBRARY_ARCHITECTURE}") SET(WILDMIDIDLL_INSTALLDIR "${WILDMIDIDLL_INSTALLDIR}/${CMAKE_LIBRARY_ARCHITECTURE}") ENDIF () # prepare pkg-config file SET(WILDMIDILIB_PREFIX "${CMAKE_INSTALL_PREFIX}") SET(WILDMIDILIB_LIBDIR "${WILDMIDILIB_INSTALLDIR}") CONFIGURE_FILE("wildmidi.pc.in" "${CMAKE_BINARY_DIR}/wildmidi.pc" @ONLY) # install target (*nix OSes) IF (UNIX AND NOT APPLE) # install our libraries IF (WANT_STATIC) INSTALL(TARGETS libwildmidi_static DESTINATION ${WILDMIDILIB_INSTALLDIR}) IF (WANT_PLAYERSTATIC) INSTALL(TARGETS wildmidi-static DESTINATION bin) ENDIF () ENDIF (WANT_STATIC) IF (BUILD_SHARED_LIBS) INSTALL(TARGETS libwildmidi_dynamic DESTINATION ${WILDMIDILIB_INSTALLDIR}) IF (WANT_PLAYER) INSTALL(TARGETS wildmidi DESTINATION bin) ENDIF () ENDIF () # install our devtest if asked for IF (WANT_DEVTEST) INSTALL(TARGETS wildmidi-devtest DESTINATION bin) ENDIF (WANT_DEVTEST) # install pkg-config file INSTALL(FILES ${CMAKE_BINARY_DIR}/wildmidi.pc DESTINATION "${WILDMIDILIB_INSTALLDIR}/pkgconfig") # install supporting man pages and headers INSTALL(FILES ${CMAKE_SOURCE_DIR}/include/wildmidi_lib.h DESTINATION include) INSTALL(DIRECTORY ${CMAKE_SOURCE_DIR}/docs/man/ DESTINATION share/man) ENDIF (UNIX AND NOT APPLE) # install target (Windows: MinGW or MinGW-w64) IF (WIN32 AND CMAKE_COMPILER_IS_MINGW) IF ("${CMAKE_INSTALL_PREFIX}" STREQUAL "") MESSAGE("INSTALL PREFIX IS EMPTY") SET(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/wildmidi_lib" CACHE STRING "Install Prefix" FORCE) MESSAGE("INSTALL PREFIX NOW: ${CMAKE_INSTALL_PREFIX}") ENDIF ("${CMAKE_INSTALL_PREFIX}" STREQUAL "") # install our libraries IF (WANT_STATIC) INSTALL(TARGETS libwildmidi_static DESTINATION ${WILDMIDILIB_INSTALLDIR}) IF (WANT_PLAYERSTATIC) INSTALL(TARGETS wildmidi-static DESTINATION bin) ENDIF () ENDIF (WANT_STATIC) IF (BUILD_SHARED_LIBS) INSTALL(FILES ${WILDMIDILIB} DESTINATION ${WILDMIDILIB_INSTALLDIR}) INSTALL(FILES ${WILDMIDIDLL} DESTINATION ${WILDMIDIDLL_INSTALLDIR}) IF (WANT_PLAYER) INSTALL(TARGETS wildmidi DESTINATION bin) ENDIF () ENDIF () # install our devtest if asked for IF (WANT_DEVTEST) INSTALL(TARGETS wildmidi-devtest DESTINATION bin) ENDIF (WANT_DEVTEST) # install pkg-config file INSTALL(FILES ${CMAKE_BINARY_DIR}/wildmidi.pc DESTINATION "${WILDMIDILIB_INSTALLDIR}/pkgconfig") # install supporting man pages and headers INSTALL(FILES ${CMAKE_SOURCE_DIR}/include/wildmidi_lib.h DESTINATION include) INSTALL(DIRECTORY ${CMAKE_SOURCE_DIR}/docs/man/ DESTINATION share/man) ENDIF (WIN32 AND CMAKE_COMPILER_IS_MINGW) IF (WIN32 AND MSVC) IF (WANT_MP_BUILD) SET(MT_BUILD "/MP") ENDIF () foreach (OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES}) STRING(TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG) SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} "$(SolutionDir)$(Configuration)") SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY_${OUTPUTCONFIG} "$(ProjectDir)$(Configuration)") endforeach (OUTPUTCONFIG) IF (WANT_PLAYER) # Release builds use the debug console SET_TARGET_PROPERTIES(wildmidi PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:CONSOLE") SET_TARGET_PROPERTIES(wildmidi PROPERTIES LINK_FLAGS_MINSIZEREL "/SUBSYSTEM:CONSOLE") TARGET_COMPILE_DEFINITIONS(wildmidi PRIVATE $<$:_CONSOLE>) TARGET_COMPILE_DEFINITIONS(wildmidi PRIVATE $<$:_CONSOLE>) ENDIF () IF (WANT_PLAYERSTATIC) # Release builds use the debug console SET_TARGET_PROPERTIES(wildmidi-static PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:CONSOLE") SET_TARGET_PROPERTIES(wildmidi-static PROPERTIES LINK_FLAGS_MINSIZEREL "/SUBSYSTEM:CONSOLE") TARGET_COMPILE_DEFINITIONS(wildmidi-static PRIVATE $<$:_CONSOLE>) TARGET_COMPILE_DEFINITIONS(wildmidi-static PRIVATE $<$:_CONSOLE>) ENDIF () # Play a bit with the warning levels SET(WARNINGS "/Wall") # Since windows can only disable specific warnings, not enable them SET(WARNINGS_DISABLE # Warnings that aren't enabled normally and don't need to be enabled # They're unneeded and sometimes completely retarded warnings that /Wall enables # Not going to bother commenting them as they tend to warn on every standard library file 4061 4263 4264 4266 4350 4371 4435 4514 4548 4571 4610 4619 4623 4625 4626 4628 4640 4668 4710 4711 4820 4826 4917 4946 # Warnings that are thrown on standard libraries 4347 # Non-template function with same name and parameter count as template function 4365 # Variable signed/unsigned mismatch 4510 4512 # Unable to generate copy constructor/assignment operator as it's not public in the base 4706 # Assignment in conditional expression 4738 # Storing 32-bit float result in memory, possible loss of performance 4986 # Undocumented warning that occurs in the crtdbg.h file 4987 # nonstandard extension used (triggered by setjmp.h) 4996 # Function was declared deprecated # caused by boost 4191 # 'type cast' : unsafe conversion (1.56, thread_primitives.hpp, normally off) # project specific warnings 4099 # Type mismatch, declared class or struct is defined with other type 4100 # Unreferenced formal parameter (-Wunused-parameter) 4101 # Unreferenced local variable (-Wunused-variable) 4127 # Conditional expression is constant 4242 # Storing value in a variable of a smaller type, possible loss of data 4244 # Storing value of one type in variable of another (size_t in int, for example) 4245 # Signed/unsigned mismatch 4267 # Conversion from 'size_t' to 'int', possible loss of data 4305 # Truncating value (double to float, for example) 4309 # Variable overflow, trying to store 128 in a signed char for example 4351 # New behavior: elements of array 'array' will be default initialized (desired behavior) 4355 # Using 'this' in member initialization list 4505 # Unreferenced local function has been removed 4701 # Potentially uninitialized local variable used 4702 # Unreachable code 4800 # Boolean optimization warning, e.g. myBool = (myInt != 0) instead of myBool = myInt ) foreach (d ${WARNINGS_DISABLE}) SET(WARNINGS "${WARNINGS} /wd${d}") endforeach (d) IF (WANT_PLAYER) SET_TARGET_PROPERTIES(wildmidi PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") ENDIF () IF (WANT_PLAYERSTATIC) SET_TARGET_PROPERTIES(wildmidi-static PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") ENDIF () ENDIF () wildmidi-wildmidi-0.4.2/src/DevTest.c000066400000000000000000002174311315765416100174510ustar00rootroot00000000000000/* * DevTest.c: Display Information about the following file formats * * .pat Gravis Ultrasound patch file. * .mid MIDI file. * .xmi Xmidi file. * .hmp "HMIMIDIP" file * .hmi "HMIMIDIP013195" file. * .mus http://www.vgmpf.com/Wiki/index.php?title=MUS * * NOTE: This file is intended for developer use to aide in * feature development, and bug hunting. * COMPILING: gcc -Wall -W -O2 -o devtest DevTest.c * * Copyright (C) WildMIDI Developers 2001-2016 * * This file is part of WildMIDI. * * WildMIDI is free software: you can redistribute and/or modify the library * under the terms of the GNU Lesser General Public License and you can * redistribute the player and DevTest under the terms of the GNU General * Public License as published by the Free Software Foundation, either * version 3 of the licenses, or(at your option) any later version. * * WildMIDI 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 and * the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License and the * GNU Lesser General Public License along with WildMIDI. If not, see * . */ /*#include "config.h"*/ #include #include #include #include #include #include #include #include #ifdef _WIN32 #include #include #undef close #define close _close #undef open #define open _open #undef read #define read _read #else /* unixish: */ #include #include #include #endif #define UNUSED(x) (void)(x) static struct option const long_options[] = { { "debug-level", 1, 0, 'd' }, { "version", 0, 0, 'v' }, { "help", 0, 0, 'h' }, { NULL, 0, NULL, 0 } }; #define EVENT_DATA_8BIT 1 static float env_time_table[] = { 0.0f, 0.091728000f, 0.045864000f, 0.030576000f, 0.022932000f, 0.018345600f, 0.015288000f, 0.013104000f, 0.011466000f, 0.010192000f, 0.009172800f, 0.008338909f, 0.007644000f, 0.007056000f, 0.006552000f, 0.006115200f, 0.005733000f, 0.005395765f, 0.005096000f, 0.004827789f, 0.004586400f, 0.004368000f, 0.004169455f, 0.003988174f, 0.003822000f, 0.003669120f, 0.003528000f, 0.003397333f, 0.003276000f, 0.003163034f, 0.003057600f, 0.002958968f, 0.002866500f, 0.002779636f, 0.002697882f, 0.002620800f, 0.002548000f, 0.002479135f, 0.002413895f, 0.002352000f, 0.002293200f, 0.002237268f, 0.002184000f, 0.002133209f, 0.002084727f, 0.002038400f, 0.001994087f, 0.001951660f, 0.001911000f, 0.001872000f, 0.001834560f, 0.001798588f, 0.001764000f, 0.001730717f, 0.001698667f, 0.001667782f, 0.001638000f, 0.001609263f, 0.001581517f, 0.001554712f, 0.001528800f, 0.001503738f, 0.001479484f, 0.001456000f, 0.0f, 0.733824000f, 0.366912000f, 0.244608000f, 0.183456000f, 0.146764800f, 0.122304000f, 0.104832000f, 0.091728000f, 0.081536000f, 0.073382400f, 0.066711273f, 0.061152000f, 0.056448000f, 0.052416000f, 0.048921600f, 0.045864000f, 0.043166118f, 0.040768000f, 0.038622316f, 0.036691200f, 0.034944000f, 0.033355636f, 0.031905391f, 0.030576000f, 0.029352960f, 0.028224000f, 0.027178667f, 0.026208000f, 0.025304276f, 0.024460800f, 0.023671742f, 0.022932000f, 0.022237091f, 0.021583059f, 0.020966400f, 0.020384000f, 0.019833081f, 0.019311158f, 0.018816000f, 0.018345600f, 0.017898146f, 0.017472000f, 0.017065674f, 0.016677818f, 0.016307200f, 0.015952696f, 0.015613277f, 0.015288000f, 0.014976000f, 0.014676480f, 0.014388706f, 0.014112000f, 0.013845736f, 0.013589333f, 0.013342255f, 0.013104000f, 0.012874105f, 0.012652138f, 0.012437695f, 0.012230400f, 0.012029902f, 0.011835871f, 0.011648000f, 0.0f, 5.870592000f, 2.935296000f, 1.956864000f, 1.467648000f, 1.174118400f, 0.978432000f, 0.838656000f, 0.733824000f, 0.652288000f, 0.587059200f, 0.533690182f, 0.489216000f, 0.451584000f, 0.419328000f, 0.391372800f, 0.366912000f, 0.345328941f, 0.326144000f, 0.308978526f, 0.293529600f, 0.279552000f, 0.266845091f, 0.255243130f, 0.244608000f, 0.234823680f, 0.225792000f, 0.217429333f, 0.209664000f, 0.202434207f, 0.195686400f, 0.189373935f, 0.183456000f, 0.177896727f, 0.172664471f, 0.167731200f, 0.163072000f, 0.158664649f, 0.154489263f, 0.150528000f, 0.146764800f, 0.143185171f, 0.139776000f, 0.136525395f, 0.133422545f, 0.130457600f, 0.127621565f, 0.124906213f, 0.122304000f, 0.119808000f, 0.117411840f, 0.115109647f, 0.112896000f, 0.110765887f, 0.108714667f, 0.106738036f, 0.104832000f, 0.102992842f, 0.101217103f, 0.099501559f, 0.097843200f, 0.096239213f, 0.094686968f, 0.093184000f, 0.0f, 46.964736000f,23.482368000f,15.654912000f,11.741184000f, 9.392947200f, 7.827456000f, 6.709248000f, 5.870592000f, 5.218304000f, 4.696473600f, 4.269521455f, 3.913728000f, 3.612672000f, 3.354624000f, 3.130982400f, 2.935296000f, 2.762631529f, 2.609152000f, 2.471828211f, 2.348236800f, 2.236416000f, 2.134760727f, 2.041945043f, 1.956864000f, 1.878589440f, 1.806336000f, 1.739434667f, 1.677312000f, 1.619473655f, 1.565491200f, 1.514991484f, 1.467648000f, 1.423173818f, 1.381315765f, 1.341849600f, 1.304576000f, 1.269317189f, 1.235914105f, 1.204224000f, 1.174118400f, 1.145481366f, 1.118208000f, 1.092203163f, 1.067380364f, 1.043660800f, 1.020972522f, 0.999249702f, 0.978432000f, 0.958464000f, 0.939294720f, 0.920877176f, 0.903168000f, 0.886127094f, 0.869717333f, 0.853904291f, 0.838656000f, 0.823942737f, 0.809736828f, 0.796012475f, 0.782745600f, 0.769913705f, 0.757495742f, 0.745472000f }; /* the following hardcoded to avoid the need for a config.h : */ static const char *PACKAGE_URL = "http://www.mindwerks.net/projects/wildmidi/"; static const char *PACKAGE_BUGREPORT = "https://github.com/Mindwerks/wildmidi/issues"; static const char *PACKAGE_VERSION = "0.4"; static void do_version(void) { printf("DevTest for WildMIDI %s - For testing purposes only\n", PACKAGE_VERSION); printf("Copyright (C) WildMIDI Developers 2001-2014\n"); printf("DevTest comes with ABSOLUTELY NO WARRANTY\n"); printf("This is free software, and you are welcome to redistribute it\n"); printf("under the terms and conditions of the GNU Lesser General Public License version 3.\n"); printf("For more information see COPYING\n\n"); printf("Report bugs to %s\n", PACKAGE_BUGREPORT); printf("WildMIDI homepage at %s\n", PACKAGE_URL); printf("\n"); } static void do_help(void) { do_version(); printf(" -d N --debug-level N Verbose output\n"); printf(" -h --help Display this information\n"); printf(" -v --version Display version information\n\n"); } static unsigned char * DT_BufferFile(const char *filename, unsigned long int *size) { int buffer_fd; unsigned char *data; char *ret_data = NULL; struct stat buffer_stat; #ifndef _WIN32 const char *home = NULL; struct passwd *pwd_ent; char buffer_dir[1024]; #endif char *buffer_file = NULL; #ifndef _WIN32 if (strncmp(filename, "~/", 2) == 0) { if ((pwd_ent = getpwuid(getuid()))) { home = pwd_ent->pw_dir; } else { home = getenv("HOME"); } if (home) { buffer_file = malloc(strlen(filename) + strlen(home) + 1); if (buffer_file == NULL) { printf("Unable to get ram to expand %s: %s\n", filename, strerror(errno)); return NULL; } strcpy(buffer_file, home); strcat(buffer_file, filename + 1); } } else if (filename[0] != '/') { ret_data = getcwd(buffer_dir, 1024); if (ret_data != NULL) buffer_file = malloc(strlen(filename) + strlen(buffer_dir) + 2); if (buffer_file == NULL || ret_data == NULL) { printf("Unable to get ram to expand %s: %s\n", filename, strerror(errno)); return NULL; } strcpy(buffer_file, buffer_dir); if (buffer_dir[strlen(buffer_dir) - 1] != '/') strcat(buffer_file, "/"); strcat(buffer_file, filename); } #endif if (buffer_file == NULL) { buffer_file = malloc(strlen(filename) + 1); if (buffer_file == NULL) { printf("Unable to get ram to expand %s: %s\n", filename, strerror(errno)); return NULL; } strcpy(buffer_file, filename); } if (stat(buffer_file, &buffer_stat)) { printf("Unable to stat %s: %s\n", filename, strerror(errno)); free(buffer_file); return NULL; } *size = buffer_stat.st_size; data = malloc(*size); if (data == NULL) { printf("Unable to get ram for %s: %s\n", filename, strerror(errno)); free(buffer_file); return NULL; } #ifdef _WIN32 if ((buffer_fd = open(buffer_file,(O_RDONLY | O_BINARY))) == -1) { #else if ((buffer_fd = open(buffer_file, O_RDONLY)) == -1) { #endif printf("Unable to open %s: %s\n", filename, strerror(errno)); free(buffer_file); free(data); return NULL; } if (read(buffer_fd, data, *size) != buffer_stat.st_size) { printf("Unable to read %s: %s\n", filename, strerror(errno)); free(buffer_file); free(data); close(buffer_fd); return NULL; } close(buffer_fd); free(buffer_file); return data; } static char check_notes[16][128]; static void zero_check_notes(void) { } static int count_check_notes(void) { int ch = 0; int nt = 0; int notes_still_on = 0; for (ch = 0; ch < 16; ch++) { for (nt = 0; nt < 128; nt++) { if (check_notes[ch][nt] == 1) { notes_still_on++; } } } return notes_still_on; } static int check_midi_event (unsigned char *midi_data, unsigned long int midi_size, unsigned char running_event, int verbose, int options) { unsigned int rtn_cnt = 0; unsigned char event = 0; unsigned int meta_length = 0; unsigned int i = 0; /* printf("Midi Data: "); for (i = 0; i < ((midi_size >= 32)? 32 : midi_size); i++) { printf("0x%.2x ",midi_data[i]); if (i == 15) printf("\n "); } printf("\n"); printf("Midi Size: %lu\n", midi_size); */ if (*midi_data < 0x80) { if (running_event != 0) { event = running_event; } else { printf("Expected MIDI event\n"); return -1; } // printf("Unsing running event 0x%2x\n", running_event); } else { event = *midi_data++; midi_size--; rtn_cnt++; } switch (event >> 4) { case 0x8: if ((midi_size < 2) || (midi_data[0] > 0x7F) || (midi_data[1] > 0x7F)) { printf("Note off: Missing or Corrupt MIDI Data\n"); return -1; } if (verbose) printf("Note Off: chan(%i) note(%i) vel(%i)\n", (event & 0x0F), midi_data[0], midi_data[1]); rtn_cnt += 2; check_notes[(event & 0x0F)][midi_data[0]] = 0; break; case 0x9: if ((midi_size < 2) || (midi_data[0] > 0x7F) || (midi_data[1] > 0x7F)) { printf("Note On: Missing or Corrupt MIDI Data\n"); return -1; } if (verbose) printf("Note On: chan(%i) note(%i) vel(%i)\n", (event & 0x0F), midi_data[0], midi_data[1]); rtn_cnt += 2; if (midi_data[1] == 0) { check_notes[(event & 0x0F)][midi_data[0]] = 0; } else { check_notes[(event & 0x0F)][midi_data[0]] = 1; } break; case 0xA: if ((midi_size < 2) || (midi_data[0] > 0x7F) || (midi_data[1] > 0x7F)) { printf("Aftertouch: Missing or Corrupt MIDI Data\n"); return -1; } if (verbose) printf("Aftertouch: chan(%i) note(%i) vel(%i)\n", (event & 0x0F), midi_data[0], midi_data[1]); rtn_cnt += 2; break; case 0xB: if (!(options & EVENT_DATA_8BIT)) { if ((midi_size < 2) || (midi_data[0] > 0x7F) || (midi_data[1] > 0x7F)) { printf("Controller: Missing or Corrupt MIDI Data\n"); return -1; } } else { if ((midi_size < 2) || (midi_data[0] > 0x7F)) { printf("Controller: Missing or Corrupt MIDI Data\n"); return -1; } } if (verbose) { printf("Controller "); switch(midi_data[0]) { case 0: printf("Bank Select: "); break; case 6: printf("Data Entry Course: "); break; case 7: printf("Channel Volume: "); break; case 8: printf("Channel Balance: "); break; case 10: printf("Pan: "); break; case 11: printf("Channel Expression: "); break; case 38: printf("Data Entry Fine: "); break; case 64: printf("Channel Hold: "); break; case 96: printf("Data Increment: "); break; case 97: printf("Data Decrement: "); break; case 98: printf("Non-registered Param Fine: "); break; case 99: printf("Non-registered Param Course: "); break; case 100: printf("Registered Param Fine: "); break; case 101: printf("Registered Param Course: "); break; case 120: printf("Channel Sound Off: "); break; case 121: printf("Channel Controllers Off: "); break; case 123: printf("Channel Notes Off: "); break; default: printf(" Unknown(%i): ", midi_data[0]); } printf("chan(%i) set(%i)\n", (event & 0x0F), midi_data[1]); } rtn_cnt += 2; break; case 0xC: if ((midi_size == 0) || (*midi_data > 0x7F)) { printf("Set Patch: Missing or Corrupt MIDI Data\n"); return -1; } if (verbose) printf("Set Patch: chan(%i) patch(%i)\n", (event & 0x0F), *midi_data); rtn_cnt++; break; case 0xD: if ((midi_size == 0) || (*midi_data > 0x7F)) { printf("Channel Pressure: Missing or Corrupt MIDI Data\n"); return -1; } if (verbose) printf("Channel Pressure: chan(%i) pres(%i)\n", (event & 0x0F), *midi_data); rtn_cnt++; break; case 0xE: if ((midi_size < 2) || (midi_data[0] > 0x7F) || (midi_data[1] > 0x7F)) { printf("Set Pitch: Missing or Corrupt MIDI Data\n"); return -1; } if (verbose) printf("Set Pitch: chan(%i) pitch(%i)\n", (event & 0x0F), ((midi_data[0] << 7) | midi_data[1])); rtn_cnt += 2; break; case 0xF: if ((event == 0xF0) || (event == 0xF7)) { unsigned long int sysex_size = 0; unsigned char *sysex_store = NULL; unsigned long int sysex_store_ofs = 0; if (verbose) printf("Sysex Event which we mostly ignore\n"); while (*midi_data > 0x7F) { sysex_size = (sysex_size << 7) | (*midi_data & 0x7F); midi_data++; midi_size--; rtn_cnt++; } sysex_size = (sysex_size << 7) | (*midi_data & 0x7F); midi_data++; midi_size--; rtn_cnt++; if (!sysex_size) { if (verbose) printf("Zero Sysex size\n"); break; } if (sysex_size > midi_size) { printf("Bad Sysex size %lu\n", sysex_size); return -1; } sysex_store = realloc(sysex_store, (sysex_store_ofs + sysex_size)); memcpy(&sysex_store[sysex_store_ofs], midi_data, sysex_size); sysex_store_ofs += sysex_size; if (sysex_store[sysex_store_ofs - 1] == 0xF7) { unsigned long int sysex_ofs = 0; unsigned char tmpsysexdata[] = { 0x41, 0x10, 0x42, 0x12 }; if (strncmp((const char *) tmpsysexdata, (const char *) sysex_store, 4) == 0) { /* Roland Sysex Checksum */ unsigned char sysex_cs = 0; sysex_ofs = 4; do { sysex_cs += sysex_store[sysex_ofs]; if (sysex_cs > 0x7F) { sysex_cs -= 0x80; } sysex_ofs++; } while (sysex_store[sysex_ofs + 1] != 0xF7); sysex_cs = 0x80 - sysex_cs; if (sysex_cs != sysex_store[sysex_ofs]) { printf("Roland Sysex Checksum Error: "); sysex_ofs = 0; do { printf("%02x ", sysex_store[sysex_ofs]); sysex_ofs++; } while (sysex_ofs != sysex_store_ofs); printf("\n"); free(sysex_store); return -1; } else { if (sysex_store[4] == 0x40) { if (((sysex_store[5] & 0xF0) == 0x10) && (sysex_store[6] == 0x15)) { /* Roland Drum Track Setting */ unsigned char sysex_ch = 0x0F & sysex_store[5]; if (sysex_ch == 0x00) { sysex_ch = 0x09; } else if (sysex_ch <= 0x09) { sysex_ch -= 1; } if (verbose) printf("Additional Drum Channel(0x%02x) Setting: 0x%02x\n", sysex_ch, sysex_store[7]); } else if ((sysex_store[5] == 0x00) && (sysex_store[6] == 0x7F) && (sysex_store[7] == 0x00)) { /* Roland GS Reset */ if (verbose) printf("GS Reset\n"); } else { goto UNKNOWNSYSEX; } } else { goto UNKNOWNSYSEX; } } } else { UNKNOWNSYSEX: if (verbose) { printf("Unknown Sysex: "); sysex_ofs = 0; do { printf("%02x ", sysex_store[sysex_ofs]); sysex_ofs++; } while (sysex_ofs != sysex_store_ofs); printf("\n"); } } } free(sysex_store); sysex_store = NULL; rtn_cnt += sysex_size; } else if ((event <= 0xFE) && (event >= 0xF1)) { // Added just in case printf("Realtime Event: 0x%.2x ** NOTE: Not expected in midi file type data\n",event); } else if (event == 0xFF) { /* * Only including meta events that are supported by wildmidi */ if (*midi_data == 0x00) { if (midi_size < 4) { printf("Data too short: Missing MIDI Data\n"); return -1; } if (midi_data[1] != 0x02) { printf("Corrupt MIDI Data, Bad Sequence Number Prefix\n"); return -1; } if (verbose) { printf("Meta Event: Sequence Number: %.2x %.2x\n", midi_data[2], midi_data[3]); } } else if (*midi_data == 0x01) { if (verbose) printf("Meta Event: Text\n"); } else if (*midi_data == 0x02) { if (verbose) printf("Meta Event: Copyright\n"); } else if (*midi_data == 0x03) { if (verbose) printf("Meta Event: Trackname\n"); } else if (*midi_data == 0x04) { if (verbose) printf("Meta Event: Instrument Name\n"); } else if (*midi_data == 0x05) { if (verbose) printf("Meta Event: Lyric\n"); } else if (*midi_data == 0x06) { if (verbose) printf("Meta Event: Marker\n"); } else if (*midi_data == 0x07) { if (verbose) printf("Meta Event: Cue Point\n"); } else if (*midi_data == 0x2F) { if (verbose) { printf("Meta Event: End Of Track\n"); printf("========================\n\n"); } if (midi_size < 2) { printf("Data too short: Missing MIDI Data\n"); return -1; } if (midi_data[1] != 0x00) { printf("Missing or Corrupt MIDI Data\n"); return -1; } } else if (*midi_data == 0x20) { if (verbose) printf("Meta Event: Channel Prefix: "); if (midi_size < 3) { printf("Data too short: Missing MIDI Data\n"); return -1; } if (midi_data[1] != 0x01) { printf("Corrupt MIDI Data, Bad Channel Prefix\n"); return -1; } if (verbose) printf("%i\n", (int) midi_data[2]); } else if (*midi_data == 0x21) { if (verbose) printf("Meta Event: Port Prefix: "); if (midi_size < 3) { printf("Data too short: Missing MIDI Data\n"); return -1; } if (midi_data[1] != 0x01) { printf("Corrupt MIDI Data, Bad Port Prefix\n"); return -1; } if (verbose) printf("%i\n", (int) midi_data[2]); } else if (*midi_data == 0x51) { if (verbose) printf("Meta Event: Tempo\n"); if (midi_size < 5) { printf("Data too short: Missing MIDI Data\n"); return -1; } if (midi_data[1] != 0x03) { printf("Corrupt MIDI Data, Bad Tempo\n"); return -1; } } else if (*midi_data == 0x54) { if (midi_size < 7) { printf("Data too short: Missing MIDI Data\n"); return -1; } if (midi_data[1] != 0x05) { printf("Corrupt MIDI Data, Bad SMPTE Offset Prefix\n"); return -1; } if (verbose) { printf("Meta Event: SMPTE Offset: %.2x %.2x %.2x %.2x %2.x\n", midi_data[2], midi_data[3], midi_data[4], midi_data[5], midi_data[6]); } } else if (*midi_data == 0x58) { if (midi_size < 6) { printf("Data too short: Missing MIDI Data\n"); return -1; } if (midi_data[1] != 0x04) { printf("Corrupt MIDI Data, Bad Time Signature Prefix\n"); return -1; } if (verbose) { printf("Meta Event: Time Signature: %.2x %.2x %.2x %.2x\n", midi_data[2], midi_data[3], midi_data[4], midi_data[5]); } } else if (*midi_data == 0x59) { if (midi_size < 4) { printf("Data too short: Missing MIDI Data\n"); return -1; } if (midi_data[1] != 0x02) { printf("Corrupt MIDI Data, Bad Key Signature Prefix\n"); return -1; } if (verbose) { printf("Meta Event: Key Signature: %.2x %.2x\n", midi_data[2], midi_data[3]); } } else { if (verbose) printf("Meta Event: Unsupported (%i)\n", *midi_data); } midi_data++; midi_size--; rtn_cnt++; meta_length = 0; while (*midi_data > 0x7F) { meta_length = (meta_length << 7) | (*midi_data & 0x7F); midi_data++; rtn_cnt++; if (midi_size == 0) { printf("Data too short: Missing MIDI Data\n"); return -1; } midi_size--; } meta_length = (meta_length << 7) | (*midi_data & 0x7F); midi_data++; midi_size--; rtn_cnt++; if (midi_size < meta_length) { printf("Data too short: Missing MIDI Data\n"); return -1; } if ((verbose) && (meta_length != 0)) { printf ("Meta data (%u bytes):", meta_length); for (i = 0; i < meta_length; i++) { if ((i % 4) == 0) printf(" "); if ((i % 8) == 0) printf("\n"); printf ("0x%.2x ", *midi_data); if (*midi_data > 32) printf("%c ", *midi_data); midi_data++; } printf("\n"); } rtn_cnt += meta_length; } else { printf("Corrupt Midi, Unknown Event Data\n"); return -1; } break; } // printf("Return Count: %i\n", rtn_cnt); return rtn_cnt; } static uint32_t time_mins = 0; static float time_secs = 0.0f; static float secs_per_tick = 0.0f; static float frequency = 0.0f; static void set_secs_per_tick (uint32_t divisions, uint32_t tempo) { float microseconds_per_tick; /* Slow but needed for accuracy */ microseconds_per_tick = (float) tempo / (float) divisions; secs_per_tick = microseconds_per_tick / 1000000.0f; return; } static void add_time (int add_ticks) { uint32_t add_mins = 0; time_secs += (add_ticks * secs_per_tick); if (time_secs > 60.0f) { add_mins = (uint32_t)(time_secs / 60.0f); time_secs -= (float)(add_mins * 60); time_mins += add_mins; } return; } static void display_time(void) { printf("Time %.2i:%02.05f ", time_mins, time_secs); return; } static void add_and_display_time(int add_ticks) { add_time(add_ticks); display_time(); return; } static int8_t test_mus(uint8_t * mus_data, uint32_t mus_size, uint32_t verbose) { uint32_t mus_data_ofs = 0; uint32_t mus_song_ofs = 0; uint32_t mus_song_len = 0; // uint16_t mus_ch_cnt1 = 0; // uint16_t mus_ch_cnt2 = 0; uint16_t mus_no_instr = 0; uint16_t mus_instr_cnt = 0; uint8_t mus_event_size = 0; uint8_t mus_hdr[] = { 'M', 'U', 'S', 0x1A }; uint8_t mus_prev_vol[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; uint32_t mus_ticks = 0; // Check that we have enough data to check the header if (mus_size < 17) { printf("Not a valid MUS file: File too short\n"); return -1; } // Check Header if (strncmp((char *) mus_data, (char *) mus_hdr, 4) != 0) { printf("Not a valid MUS file: expected MUS followed by 0x1A\n"); return -1; } // Get Song Length mus_song_len = (mus_data[5] << 8) | mus_data[4]; // Get Song Offset mus_song_ofs = (mus_data[7] << 8) | mus_data[6]; if (verbose) printf("Song Offset: %i, Length: %i\n", mus_song_ofs, mus_song_len); // Have yet to determine what this actually is. // mus_ch_cnt1 = (mus_data[9] << 8) | mus_data[8]; // mus_ch_cnt2 = (mus_data[11] << 8) | mus_data[10]; // Number of instruments defined mus_no_instr = (mus_data[13] << 8) | mus_data[12]; if (verbose) printf("Number of Instruments: %i\n", mus_no_instr); // Skip next 2 data bytes mus_data_ofs = 16; // Check that we have enough data to check the rest if (mus_size < (mus_data_ofs + (mus_no_instr << 1) + mus_song_len)) { printf("Not a valid MUS file: File too short\n"); return -1; } if (verbose) { do { printf("(%i) %i\n",mus_instr_cnt, ((mus_data[mus_data_ofs + 1] << 8) | mus_data[mus_data_ofs])); mus_data_ofs += 2; mus_instr_cnt++; } while (mus_instr_cnt != mus_no_instr); } // make sure we are at song offset mus_data_ofs = mus_song_ofs; if (verbose) { // Setup secs_per_tick if (frequency == 0.0) frequency = 140.0; set_secs_per_tick (60, (uint32_t)(60000000.0f / frequency)); add_and_display_time(0); } do { // Read Event _WM_READ_MUS_EVENT: if (verbose) { display_time(); } switch ((mus_data[mus_data_ofs] >> 4) & 0x07) { case 0: // note off mus_event_size = 2; if (verbose) printf("Note Off 0x%.2x\n", mus_data[mus_data_ofs + 1]); break; case 1: // note on if (mus_data[mus_data_ofs + 1] & 0x80) { mus_event_size = 3; if (verbose) printf("Note On (0x%.2x): 0x%.2x\n", (mus_data[mus_data_ofs + 1] & 0x7f), mus_data[mus_data_ofs + 2]); mus_prev_vol[mus_data[mus_data_ofs] & 0x0f] = mus_data[mus_data_ofs + 2]; } else { mus_event_size = 2; if (verbose) printf("Note On (0x%.2x): [0x%.2x]\n", mus_data[mus_data_ofs + 1], mus_prev_vol[mus_data[mus_data_ofs] & 0x0f]); } break; case 2: // pitch bend mus_event_size = 2; if (verbose) printf("Pitch Bend 0x%.2x\n", mus_data[mus_data_ofs + 1]); break; case 3: // system controller mus_event_size = 2; if (verbose) { printf("System Controller: "); switch (mus_data[mus_data_ofs + 1]) { case 10: printf("All Sounds Off\n"); break; case 11: printf("All Notes Off\n"); break; case 12: // Not supported by WildMidi. Parsed for compatability printf("Mono\n"); break; case 13: // Not supported by WildMidi. Parsed for compatability printf("Poly\n"); break; case 14: printf("Reset All Controllers\n"); break; default: printf("Unsupported %i\n", mus_data[mus_data_ofs + 1]); } } break; case 4: // controller mus_event_size = 3; if (verbose) { printf("Controller: "); switch (mus_data[mus_data_ofs + 1]) { case 0: printf("Patch 0x%.2x\n", mus_data[mus_data_ofs + 2]); break; case 1: printf("Bank 0x%.2x\n", mus_data[mus_data_ofs + 2]); break; case 2: printf("Modulation 0x%.2x\n", mus_data[mus_data_ofs + 2]); break; case 3: printf("Volume 0x%.2x\n", mus_data[mus_data_ofs + 2]); break; case 4: printf("Pan 0x%.2x\n", (mus_data[mus_data_ofs + 2] - 64)); break; case 5: printf("Expression 0x%.2x\n", mus_data[mus_data_ofs + 2]); break; case 6: printf("Reverb 0x%.2x\n", mus_data[mus_data_ofs + 2]); break; case 7: printf("Chorus 0x%.2x\n", mus_data[mus_data_ofs + 2]); break; case 8: printf("Sustain 0x%.2x\n", mus_data[mus_data_ofs + 2]); break; case 9: printf("Soft Pedal 0x%.2x\n", mus_data[mus_data_ofs + 2]); break; default: printf("Unsupported 0x%.2x 0x%.2x\n", mus_data[mus_data_ofs + 1], mus_data[mus_data_ofs + 2]); } } break; case 5: // ?? mus_event_size = 1; if (verbose) printf("0x%.2x\n", mus_data[mus_data_ofs]); break; case 6: // End Of Song //mus_event_size = 1; if (verbose) printf("End Of Song\n"); goto _WM_MUS_EOS; break; case 7: // ?? mus_event_size = 1; if (verbose) printf("0x%.2x\n", mus_data[mus_data_ofs]); break; } #if 0 // DEBUG if (verbose) { uint8_t i = 0; for (i = 0; i < mus_event_size; i++) { printf("0x%.2x ", mus_data[mus_data_ofs + i]); } printf("\n"); } #endif if (!(mus_data[mus_data_ofs] & 0x80)) { mus_data_ofs += mus_event_size; goto _WM_READ_MUS_EVENT; } mus_data_ofs += mus_event_size; // Read Time (140 ticks per minute) mus_ticks = 0; do { mus_ticks = (mus_ticks << 7) | (mus_data[mus_data_ofs] & 0x7f); mus_data_ofs++; } while (mus_data[mus_data_ofs - 1] > 0x7f); if (verbose) { add_time(mus_ticks); } } while (mus_data_ofs < mus_size); // Song End _WM_MUS_EOS: return 0; } static int test_hmi(unsigned char * hmi_data, unsigned long int hmi_size, int verbose) { uint16_t hmi_division = 0; //uint32_t hmi_duration_secs = 0; uint32_t hmi_track_cnt = 0; uint32_t i = 0; uint32_t *hmi_track_offset = NULL; uint32_t hmi_dbg = 0; uint32_t hmi_delta = 0; uint32_t hmi_track_end = 0; int32_t check_ret = 0; uint8_t hmi_running_event = 0; uint32_t hmi_track_header_length = 0; uint32_t hmi_file_end = hmi_size; // Check header if (strncmp((char *) hmi_data,"HMI-MIDISONG061595", 18) != 0) { printf("Not a valid HMI file: expected HMI-MIDISONG061595\n"); return -1; } hmi_data += 212; hmi_size -= 212; hmi_dbg += 212; hmi_division = *hmi_data++; if (verbose) { printf("Beats per minute: %u\n",hmi_division); set_secs_per_tick (60, (uint32_t)(60000000.0f / (float)hmi_division)); } hmi_data += 15; hmi_size -= 16; hmi_dbg += 16; hmi_track_cnt = *hmi_data++; hmi_size--; if (verbose) printf("Track count: %i\n", hmi_track_cnt); hmi_track_offset = malloc(sizeof(uint32_t) * hmi_track_cnt); hmi_dbg++; hmi_data += 141; hmi_size -= 141; hmi_dbg += 141; hmi_track_offset[0] = *hmi_data; // To keep Xcode happy for (i = 0; i < hmi_track_cnt; i++) { // printf("DEBUG @ %.8x\n",hmi_dbg); hmi_track_offset[i] = *hmi_data++; hmi_track_offset[i] += (*hmi_data++ << 8); hmi_track_offset[i] += (*hmi_data++ << 16); hmi_track_offset[i] += (*hmi_data++ << 24); hmi_size -= 4; //FIXME: These are absolute data offsets? if (verbose) printf("Track %i offset: %.8x\n",i,hmi_track_offset[i]); hmi_dbg += 4; } hmi_size -= (hmi_track_offset[0] - hmi_dbg); hmi_data += (hmi_track_offset[0] - hmi_dbg); hmi_dbg += (hmi_track_offset[0] - hmi_dbg); for (i = 0; i < hmi_track_cnt; i++) { /* printf("DEBUG @ %.8x: ",hmi_dbg); for (j = 0; j < 16; j++) { printf("%.2x ",hmi_data[j]); } printf("\n"); */ if (strncmp((char *) hmi_data,"HMI-MIDITRACK", 13) != 0) { printf("Not a valid HMI file: expected HMI-MIDITRACK\n"); free (hmi_track_offset); return -1; } if (verbose) printf("Start of track %u\n",i); hmi_track_header_length = hmi_data[0x57]; hmi_track_header_length += (hmi_data[0x58] << 8); hmi_track_header_length += (hmi_data[0x59] << 16); hmi_track_header_length += (hmi_data[0x5a] << 24); if (verbose) printf("Track header length: %u\n",hmi_track_header_length); hmi_data += hmi_track_header_length; hmi_size -= hmi_track_header_length; hmi_dbg += hmi_track_header_length; if (i < (hmi_track_cnt -1)) { hmi_track_end = hmi_track_offset[i+1]; } else { hmi_track_end = hmi_file_end; } // printf("DEBUG: 0x%.8x\n",hmi_track_end); while (hmi_dbg < hmi_track_end) { /* printf("DEBUG @ 0x%.8x: ",hmi_dbg); for (j = 0; j < 16; j++) { printf("%.2x ",hmi_data[j]); } printf("\n"); */ hmi_delta = 0; if (*hmi_data > 0x7f) { while (*hmi_data > 0x7F) { hmi_delta = (hmi_delta << 7) | (*hmi_data & 0x7F); hmi_data++; hmi_size--; hmi_dbg++; } } hmi_delta = (hmi_delta << 7) | (*hmi_data & 0x7F); if (verbose) { add_and_display_time(hmi_delta); } hmi_data++; hmi_size--; hmi_dbg++; if (hmi_data[0] == 0xfe) { if (verbose) printf("Skipping HMI event\n"); if (hmi_data[1] == 0x10) { hmi_size -= (hmi_data[4] + 5); hmi_dbg += (hmi_data[4] + 5); hmi_data += (hmi_data[4] + 5); } else if (hmi_data[1] == 0x15) { hmi_size -= 4; hmi_dbg += 4; hmi_data += 4; } hmi_data += 4; hmi_size -= 4; hmi_dbg += 4; } else { if ((check_ret = check_midi_event(hmi_data, hmi_size, hmi_running_event, verbose, 0)) == -1) { printf("Missing or Corrupt MIDI Data\n"); free (hmi_track_offset); return -1; } // Running event // 0xff does not alter running event if ((*hmi_data == 0xF0) || (*hmi_data == 0xF7)) { // Sysex resets running event data hmi_running_event = 0; } else if (*hmi_data < 0xF0) { // MIDI events 0x80 to 0xEF set running event if (*hmi_data >= 0x80) { hmi_running_event = *hmi_data; } } // if (verbose) printf("Running Event: 0x%.2x\n",hmi_running_event); if ((hmi_data[0] == 0xff) && (hmi_data[1] == 0x2f) && (hmi_data[2] == 0x00)) { hmi_data += check_ret; hmi_size -= check_ret; hmi_dbg += check_ret; break; } if ((hmi_running_event & 0xf0) == 0x90) { // note on has extra data to specify how long the note is. hmi_data += check_ret; hmi_size -= check_ret; hmi_dbg += check_ret; hmi_delta = 0; if (*hmi_data > 0x7f) { while (*hmi_data > 0x7F) { hmi_delta = (hmi_delta << 7) | (*hmi_data & 0x7F); hmi_data++; hmi_size--; hmi_dbg++; } } hmi_delta = (hmi_delta << 7) | (*hmi_data & 0x7F); if (verbose) printf("Note Length: %f secs\n", ((float)hmi_delta * secs_per_tick)); hmi_data++; hmi_size--; hmi_dbg++; } else { hmi_data += check_ret; hmi_size -= check_ret; hmi_dbg += check_ret; } } } } free (hmi_track_offset); return 0; } static int test_hmp(unsigned char * hmp_data, unsigned long int hmp_size, int verbose) { uint8_t is_hmq = 0; uint32_t zero_cnt = 0; uint32_t i = 0; uint32_t j = 0; uint32_t hmp_file_length = 0; uint32_t hmp_chunks = 0; uint32_t hmp_chunk_num = 0; uint32_t hmp_chunk_length = 0; uint32_t hmp_division = 0; uint32_t hmp_song_time = 0; uint32_t hmp_track = 0; uint32_t hmp_var_len_val = 0; int32_t check_ret = 0; // check the header if (strncmp((char *) hmp_data,"HMIMIDIP", 8) != 0) { printf("Not a valid HMP file: expected HMIMIDIP\n"); return -1; } hmp_data += 8; hmp_size -= 8; if (strncmp((char *) hmp_data,"013195", 6) == 0) { is_hmq = 1; hmp_data += 6; hmp_size -= 6; if (verbose) printf("HMPv2 format detected\n"); } // should be a bunch of \0's if (is_hmq) { zero_cnt = 18; } else { zero_cnt = 24; } for (i = 0; i < zero_cnt; i++) { // printf("DEBUG (%.2x): %.2x\n",i, hmp_data[i]); if (hmp_data[i] != 0) { printf("Not a valid HMP file\n"); return -1; } } hmp_data += zero_cnt; hmp_size -= zero_cnt; hmp_file_length = *hmp_data++; hmp_file_length += (*hmp_data++ << 8); hmp_file_length += (*hmp_data++ << 16); hmp_file_length += (*hmp_data++ << 24); if (verbose) printf("File length: %u\n", hmp_file_length); // Next 12 bytes are normally \0 so skipping over them hmp_data += 12; hmp_size -= 16; hmp_chunks = *hmp_data++; hmp_chunks += (*hmp_data++ << 8); hmp_chunks += (*hmp_data++ << 16); hmp_chunks += (*hmp_data++ << 24); if (verbose) printf("Number of chunks: %u\n", hmp_chunks); // Unsure of what next 4 bytes are so skip over them hmp_data += 4; hmp_size -= 8; hmp_division = *hmp_data++; hmp_division += (*hmp_data++ << 8); hmp_division += (*hmp_data++ << 16); hmp_division += (*hmp_data++ << 24); if (verbose) { printf("Beats per minute: %u\n", hmp_division); set_secs_per_tick(60,(uint32_t)(60000000.0f / (float)hmp_division)); } hmp_song_time = *hmp_data++; hmp_song_time += (*hmp_data++ << 8); hmp_song_time += (*hmp_data++ << 16); hmp_song_time += (*hmp_data++ << 24); hmp_size -= 8; if (verbose) printf("Song Time: %u\n", hmp_song_time); if (is_hmq) { hmp_data += 840; hmp_size -= 840; } else { hmp_data += 712; hmp_size -= 712; } for (i = 0; i < hmp_chunks; i++) { hmp_chunk_num = *hmp_data++; hmp_chunk_num += (*hmp_data++ << 8); hmp_chunk_num += (*hmp_data++ << 16); hmp_chunk_num += (*hmp_data++ << 24); hmp_size -= 4; if (verbose) printf("Chunk number: %u\n", hmp_chunk_num); hmp_chunk_length = *hmp_data++; hmp_chunk_length += (*hmp_data++ << 8); hmp_chunk_length += (*hmp_data++ << 16); hmp_chunk_length += (*hmp_data++ << 24); hmp_size -= 4; if (verbose) printf("Chunk length: %u\n", hmp_chunk_length); if (hmp_chunk_length > hmp_size) { printf("File too short\n"); return -1; } hmp_track = *hmp_data++; hmp_track += (*hmp_data++ << 8); hmp_track += (*hmp_data++ << 16); hmp_track += (*hmp_data++ << 24); hmp_size -= 4; if (verbose) printf("Track Number: %u\n", hmp_track); // Start of Midi Data // because chunk length includes chunk header // remove header length from chunk length hmp_chunk_length -= 12; // Start of Midi Data for (j = 0; j < hmp_chunk_length; j++) { uint32_t var_len_shift = 0; hmp_var_len_val = 0; if (*hmp_data < 0x80) { do { hmp_var_len_val = hmp_var_len_val | ((*hmp_data++ & 0x7F) << var_len_shift); var_len_shift += 7; hmp_size--; j++; } while (*hmp_data < 0x80); } hmp_var_len_val = hmp_var_len_val | ((*hmp_data++ & 0x7F) << var_len_shift); hmp_size--; if (verbose) { add_and_display_time(hmp_var_len_val); } if ((check_ret = check_midi_event(hmp_data, hmp_size, 0, verbose, EVENT_DATA_8BIT)) == -1) { printf("Missing or Corrupt MIDI Data\n"); return -1; } // Display loop start/end if ((hmp_chunk_num == 1) && ((hmp_data[0] & 0xf0) == 0xb0)) { if ((hmp_data[1] == 110) && (hmp_data[2] == 255) && (verbose)) printf("HMP Loop Start\n"); if ((hmp_data[1] == 111) && (hmp_data[2] == 128) && (verbose)) printf("HMP Loop End\n"); } j += check_ret; hmp_data += check_ret; hmp_size -= check_ret; } } return 0; } static int test_xmidi(unsigned char * xmidi_data, unsigned long int xmidi_size, int verbose) { unsigned int tmp_val = 0; unsigned int i = 0; unsigned int j = 0; unsigned int form_cnt = 0; unsigned int cat_len = 0; unsigned int subform_len = 0; unsigned int event_len = 0; unsigned int divisions = 60; unsigned int tempo = 500000; uint32_t tempo_set = 0; if (strncmp((char *) xmidi_data,"FORM", 4) != 0) { printf("Not a valid xmidi file: expected FORM\n"); return -1; } if (verbose) printf("First FORM found\n"); xmidi_data += 4; xmidi_size -= 4; // bytes until next entry tmp_val = *xmidi_data++ << 24; tmp_val |= *xmidi_data++ << 16; tmp_val |= *xmidi_data++ << 8; tmp_val |= *xmidi_data++; xmidi_size -= 4; if (strncmp((char *) xmidi_data,"XDIRINFO", 8) != 0) { printf("Not a valid xmidi file: expected XDIRINFO\n"); return -1; } xmidi_data += 8; xmidi_size -= 8; /* 0x00 0x00 0x00 0x02 at this point are unknown so skip over them */ xmidi_data += 4; xmidi_size -= 4; // number of forms contained after this point form_cnt = *xmidi_data++; if (verbose) printf("Contains %u forms\n", form_cnt); /* at this stage unsure if remaining data in this section means anything */ tmp_val -= 13; xmidi_data += tmp_val; xmidi_size -= tmp_val; if (strncmp((char *) xmidi_data,"CAT ", 4) != 0) { printf("Not a valid xmidi file: expected CAT\n"); return -1; } xmidi_data += 4; xmidi_size -= 4; // stored just in case it means something cat_len = *xmidi_data++ << 24; cat_len |= *xmidi_data++ << 16; cat_len |= *xmidi_data++ << 8; cat_len |= *xmidi_data++; xmidi_size -= 4; if (verbose) printf("CAT length = %u",cat_len); if (strncmp((char *) xmidi_data,"XMID", 4) != 0) { printf("Not a valid xmidi file: expected XMID\n"); return -1; } xmidi_data += 4; xmidi_size -= 4; // Start of FORM data which contains the songs for (i = 0; i < form_cnt; i++) { if (strncmp((char *) xmidi_data,"FORM", 4) != 0) { printf("Not a valid xmidi file: expected FORM\n"); return -1; } if (verbose) printf("\nNew FORM\n"); xmidi_data += 4; xmidi_size -= 4; // stored just in case it means something subform_len = *xmidi_data++ << 24; subform_len |= *xmidi_data++ << 16; subform_len |= *xmidi_data++ << 8; subform_len |= *xmidi_data++; xmidi_size -= 4; if (verbose) printf("FORM length: %u\n",subform_len); if (strncmp((char *) xmidi_data,"XMID", 4) != 0) { printf("Not a valid xmidi file: expected XMID\n"); return -1; } if (verbose) printf("XMID Data\n"); xmidi_data += 4; xmidi_size -= 4; subform_len -= 4; if (verbose) { set_secs_per_tick (divisions, tempo); } do { if (strncmp((char *) xmidi_data,"TIMB", 4) == 0) { /* TODO: Do we need to explore this further */ xmidi_data += 4; xmidi_size -= 4; tmp_val = *xmidi_data++ << 24; tmp_val |= *xmidi_data++ << 16; tmp_val |= *xmidi_data++ << 8; tmp_val |= *xmidi_data++; xmidi_size -= 4; subform_len -= 8; if (verbose) printf("TIMB length: %u\n", tmp_val); /* patch information */ tmp_val /= 2; for (j=0; j < tmp_val; j++) { if (verbose) printf ("Patch:%i, Bank:%i\n", xmidi_data[0], xmidi_data[1]); xmidi_data += 2; xmidi_size -= 2; subform_len -= 2; } if (verbose) printf("\n"); } else if (strncmp((char *) xmidi_data,"RBRN", 4) == 0) { xmidi_data += 4; xmidi_size -= 4; event_len = *xmidi_data++ << 24; event_len |= *xmidi_data++ << 16; event_len |= *xmidi_data++ << 8; event_len |= *xmidi_data++; xmidi_size -= 4; subform_len -= 8; if (verbose) printf("RBRN length: %u\n",event_len); // TODO: still have to work out what this is. // Does not seem to be needed for midi playback. xmidi_data += event_len; subform_len -= event_len; } else if (strncmp((char *) xmidi_data,"EVNT", 4) == 0) { int check_ret = 0; xmidi_data += 4; xmidi_size -= 4; event_len = *xmidi_data++ << 24; event_len |= *xmidi_data++ << 16; event_len |= *xmidi_data++ << 8; event_len |= *xmidi_data++; xmidi_size -= 4; subform_len -= 8; if (verbose) printf("EVENT length: %u\n",event_len); do { if (*xmidi_data < 0x80) { // Delta until next event? tmp_val = 0; tmp_val = (tmp_val << 7) | (*xmidi_data++ & 0x7F); xmidi_size--; event_len--; subform_len--; if (verbose) { // printf ("Intervals: %u\n", tmp_val); add_time(tmp_val); } } else { if (verbose) display_time(); if ((check_ret = check_midi_event(xmidi_data, xmidi_size, 0, verbose, 0)) == -1) { printf("Missing or Corrupt MIDI Data\n"); return -1; } if ((*xmidi_data & 0xf0) == 0x90) { xmidi_data += check_ret; xmidi_size -= check_ret; event_len -= check_ret; subform_len -= check_ret; tmp_val = 0; if (*xmidi_data > 0x7f) { while (*xmidi_data > 0x7f) { tmp_val = (tmp_val << 7) | (*xmidi_data++ & 0x7f); xmidi_size--; event_len--; subform_len--; } } tmp_val = (tmp_val << 7) | (*xmidi_data++ & 0x7f); xmidi_size--; event_len--; subform_len--; if (verbose) printf("Note Length: %f secs\n", ((float)tmp_val * secs_per_tick)); } else { if ((xmidi_data[0] == 0xff) && (xmidi_data[1] == 0x51) && (xmidi_data[2] == 0x03)) { if (!tempo_set) { tempo_set = 1; /* Tempo */ tempo = (xmidi_data[3] << 16) + (xmidi_data[4] << 8)+ xmidi_data[5]; if (!tempo) tempo = 500000; if (verbose) { set_secs_per_tick (divisions, tempo); } } } xmidi_data += check_ret; xmidi_size -= check_ret; event_len -= check_ret; subform_len -= check_ret; } } } while (event_len); if (verbose) printf("\n"); } else { printf("Not a valid xmidi file: unknown XMID entry\n"); return -1; } } while (subform_len); if (verbose) printf("=============\n\n"); } return 0; } static int test_midi(unsigned char * midi_data, unsigned long int midi_size, int verbose) { unsigned int tmp_val; unsigned int track_size; unsigned char *next_track; unsigned int delta; unsigned long int delta_accum; unsigned int no_tracks; unsigned int i; unsigned int divisions = 96; unsigned char running_event = 0; unsigned long int tempo = 500000; int check_ret = 0; unsigned int total_count = 0; if (strncmp((char *) midi_data, "RIFF", 4) == 0) { midi_data += 20; midi_size -= 20; total_count += 20; } if (strncmp((char *) midi_data, "MThd", 4) != 0) { printf("Not a compatible file\n"); return -1; } midi_data += 4; midi_size -= 4; total_count += 4; if (midi_size < 10) { printf("Midi File Too Short\n"); return -1; } /* * Get Midi Header Size - must always be 6 */ tmp_val = *midi_data++ << 24; tmp_val |= *midi_data++ << 16; tmp_val |= *midi_data++ << 8; tmp_val |= *midi_data++; midi_size -= 4; total_count += 4; if (verbose) printf("Header Size: %i\n", tmp_val); if (tmp_val != 6) { printf("Corrupt Midi Header\n"); return -1; } /* * Get Midi Format - we only support 0, 1 and 2 */ tmp_val = *midi_data++ << 8; tmp_val |= *midi_data++; midi_size -= 2; total_count += 2; if (verbose) printf("Format: %i\n", tmp_val); if (tmp_val > 2) { printf("Midi Format Not Supported\n"); return -1; } /* * Get No. of Tracks */ tmp_val = *midi_data++ << 8; tmp_val |= *midi_data++; midi_size -= 2; total_count += 2; if (verbose) printf("Number of Tracks: %i\n", tmp_val); if (tmp_val < 1) { printf("Midi Contains No Tracks\n"); return -1; } no_tracks = tmp_val; /* * Get Divisions */ divisions = *midi_data++ << 8; divisions |= *midi_data++; midi_size -= 2; total_count += 2; if (verbose) { printf("Divisions: %i\n", divisions); if (divisions & 0x00008000) { printf("Division Type Not Supported\n"); return -1; } set_secs_per_tick (divisions, tempo); } for (i = 0; i < no_tracks; i++) { time_mins = 0; time_secs = 0.0; if (midi_size < 8) { printf("Midi File Too Short\n"); return -1; } if (strncmp((char *) midi_data, "MTrk", 4) != 0) { printf("Expected Track Header\n"); return -1; } if (verbose) printf("Start of Track\n"); midi_data += 4; midi_size -= 4; total_count += 4; track_size = *midi_data++ << 24; track_size |= *midi_data++ << 16; track_size |= *midi_data++ << 8; track_size |= *midi_data++; midi_size -= 4; total_count += 4; if (verbose) printf("Track Size: %i\n", track_size); if (midi_size < track_size) { printf("Midi File Too Short: Missing Track Data\n"); return -1; } if ((midi_data[track_size - 3] != 0xFF) || (midi_data[track_size - 2] != 0x2F) || (midi_data[track_size - 1] != 0x00)) { printf("Corrupt Midi, Expected EOT\n"); return -1; } next_track = midi_data + track_size; delta_accum = 0; while (midi_data < next_track) { delta = 0; // printf("Get Delta: "); while (*midi_data > 0x7F) { delta = (delta << 7) | (*midi_data & 0x7F); // printf("0x%.2x ",*midi_data); midi_data++; midi_size--; total_count++; if (midi_size == 0) { printf("Corrupt Midi, Missing or Corrupt Track Data\n"); return -1; } } delta = (delta << 7) | (*midi_data & 0x7F); if (verbose) add_and_display_time(delta); midi_data++; if (midi_size == 0) { printf("Corrupt Midi, Missing or Corrupt Track Data\n"); return -1; } midi_size--; total_count++; delta_accum += delta; /* tempo microseconds per quarter note * divisions pulses per quarter note */ /*if (verbose) printf("Est Seconds: %f\n",(((float)tempo/(float)divisions*(float)delta_accum)/1000000.0));*/ /* if (verbose) printf("Delta: %i, Accumilated Delta: %ld\n", delta, delta_accum); */ if (*midi_data < 0x80) { if (running_event == 0) { printf("Currupt Midi: expected event, got data\n"); return -1; } } // printf("Event Offset: 0x%.8x\n", total_count); if ((check_ret = check_midi_event(midi_data, midi_size, running_event, verbose, 0)) == -1) { printf("Missing or Corrupt MIDI Data 0x%.8x\n",total_count); return -1; } if ((*midi_data == 0xF0) || (*midi_data == 0xF7)) { /* Sysex resets running event data */ running_event = 0; } else if (*midi_data < 0xF0) { /* MIDI events 0x80 to 0xEF set running event */ if (*midi_data >= 0x80) { running_event = *midi_data; // printf("Set running_event 0x%2x\n", running_event); } } if ((midi_data[0] == 0xff) && (midi_data[1] == 0x51) && (midi_data[2] == 0x03)) { /* Tempo */ tempo = (midi_data[3] << 16) + (midi_data[4] << 8)+ midi_data[5]; if (!tempo) tempo = 500000; if (verbose) { /* Slow but needed for accuracy */ set_secs_per_tick (divisions, tempo); } } midi_size -= check_ret; total_count += check_ret; // printf("Midi data remaining: %lu\n", midi_size); if (midi_size == 0) { /* check for end of track being at end */ if ((midi_data[0] == 0xff) && (midi_data[1] == 0x2f) && (midi_data[2] == 0x0)) { return 0; } else { printf("Corrupt Midi, Missing or Corrupt Track Data\n"); return -1; } } midi_data += check_ret; if (midi_data > next_track) { printf("Corrupt Midi, Track Data went beyond track boundries.\n"); return -1; } } } return 0; } static int test_guspat(unsigned char * gus_patch, unsigned long int filesize, int verbose) { unsigned long int gus_ptr = 0; unsigned char no_of_samples = 0; if (filesize < 239) { printf("File too short\n"); return -1; } if (memcmp(gus_patch, "GF1PATCH110\0ID#000002", 22) && memcmp(gus_patch, "GF1PATCH100\0ID#000002", 22)) { printf("Unsupported format\n"); return -1; } if ((gus_patch[82] > 1) || (gus_patch[151] > 1)) { printf("Unsupported format\n"); return -1; } no_of_samples = gus_patch[198]; if (verbose) printf("Number of samples: %i\n", no_of_samples); gus_ptr = 239; do { if ((gus_ptr + 96) > filesize) { printf("File too short\n"); return -1; } if (verbose) { printf("Sample Start\n"); printf("Loop Fraction: 0x%x, ", gus_patch[gus_ptr + 7]); printf("Data Length: %i, ", ((gus_patch[gus_ptr + 11] << 24) | (gus_patch[gus_ptr + 10] << 16) | (gus_patch[gus_ptr + 9] << 8) | gus_patch[gus_ptr + 8])); printf("Loop Start: %i, ", ((gus_patch[gus_ptr + 15] << 24) | (gus_patch[gus_ptr + 14] << 16) | (gus_patch[gus_ptr + 13] << 8) | gus_patch[gus_ptr + 12])); printf("Loop End: %i\n", ((gus_patch[gus_ptr + 19] << 24) | (gus_patch[gus_ptr + 18] << 16) | (gus_patch[gus_ptr + 17] << 8) | gus_patch[gus_ptr + 16])); printf("Rate: %i, ", ((gus_patch[gus_ptr + 21] << 8) | gus_patch[gus_ptr + 20])); printf("Low Freq: %fHz, ", (float) ((gus_patch[gus_ptr + 25] << 24) | (gus_patch[gus_ptr + 24] << 16) | (gus_patch[gus_ptr + 23] << 8) | gus_patch[gus_ptr + 22]) / 1000.0); printf("High Freq: %fHz, ", (float) ((gus_patch[gus_ptr + 29] << 24) | (gus_patch[gus_ptr + 28] << 16) | (gus_patch[gus_ptr + 27] << 8) | gus_patch[gus_ptr + 26]) / 1000.0); printf("Root Freq: %fHz\n", (float) ((gus_patch[gus_ptr + 33] << 24) | (gus_patch[gus_ptr + 32] << 16) | (gus_patch[gus_ptr + 31] << 8) | gus_patch[gus_ptr + 30]) / 1000.0); printf("Attack Level: %i, Attack Time: %fsecs\n", gus_patch[gus_ptr + 43], env_time_table[gus_patch[gus_ptr + 37]]); printf("Decay Level: %i, Decay Time: %fsecs\n", gus_patch[gus_ptr + 44], env_time_table[gus_patch[gus_ptr + 38]]); printf("Sustain Level: %i, Sustain Time: %fsecs\n", gus_patch[gus_ptr + 45], env_time_table[gus_patch[gus_ptr + 39]]); printf("Sustained Release Level: %i, Sustained Release Time: %fsecs\n", gus_patch[gus_ptr + 46], env_time_table[gus_patch[gus_ptr + 40]]); printf("Normal Release Level: %i, Normal Release Time: %fsecs\n", gus_patch[gus_ptr + 47], env_time_table[gus_patch[gus_ptr + 41]]); printf("Clamped Release Level: %i, Clamped Release Time: %fsecs\n", gus_patch[gus_ptr + 48], env_time_table[gus_patch[gus_ptr + 42]]); } if (env_time_table[gus_patch[gus_ptr + 40]] < env_time_table[gus_patch[gus_ptr + 41]]) { printf("WARNING!! Normal release envelope longer than sustained release envelope\n"); printf(" Caused by patch editor not following the file format set by Gravis\n"); printf(" WildMIDI will attempt to compensate for it on playback\n"); } if (env_time_table[gus_patch[gus_ptr + 41]] < env_time_table[gus_patch[gus_ptr + 42]]) { printf("WARNING!! Clamped release envelope longer than normal release envelope\n"); printf(" Caused by patch editor not following the file format set by Gravis\n"); printf(" WildMIDI will attempt to compensate for it on playback\n"); } if (verbose) { printf("Modes: "); if (gus_patch[gus_ptr + 55] & 0x01) printf("16 Bit "); if (gus_patch[gus_ptr + 55] & 0x02) printf("Unsigned "); if (gus_patch[gus_ptr + 55] & 0x04) printf("Loop "); if (gus_patch[gus_ptr + 55] & 0x08) printf("Ping Pong "); if (gus_patch[gus_ptr + 55] & 0x10) printf("Reverse "); if (gus_patch[gus_ptr + 55] & 0x20) printf("Sustain "); if (gus_patch[gus_ptr + 55] & 0x40) printf("Envelope "); if (gus_patch[gus_ptr + 55] & 0x80) printf("Clamped Release "); printf("\n"); printf("Sample End\n\n"); } gus_ptr += 96 + ((gus_patch[gus_ptr + 11] << 24) | (gus_patch[gus_ptr + 10] << 16) | (gus_patch[gus_ptr + 9] << 8) | gus_patch[gus_ptr + 8]); } while (--no_of_samples); return 0; } int main(int argc, char ** argv) { int i; int option_index = 0; int verbose = 0; int testret = 0; uint8_t mus_hdr[] = { 'M', 'U', 'S', 0x1A }; uint8_t xmi_hdr[] = { 'F', 'O', 'R', 'M' }; int notes_still_on = 0; unsigned char *filebuffer = NULL; unsigned long int filesize = 0; do_version(); while (1) { i = getopt_long(argc, argv, "d:f:vh", long_options, &option_index); if (i == -1) break; switch (i) { case 'd': /* Verbose */ verbose = atoi(optarg); break; case 'f': /* Frequency */ frequency = atof(optarg); break; case 'v': /* Version */ return 0; case 'h': /* help */ do_help(); return 0; default: printf("Unknown Option -%o ??\n", i); return 0; } } if (optind >= argc) { return 0; } while (optind < argc) { printf("Testing: %s\n", argv[optind]); zero_check_notes(); if ((filebuffer = DT_BufferFile(argv[optind], &filesize)) != NULL) { if (memcmp(filebuffer,"HMIMIDIP", 8) == 0) { testret = test_hmp(filebuffer, filesize, verbose); notes_still_on = count_check_notes(); } else if (memcmp(filebuffer, "HMI-MIDISONG061595", 18) == 0) { testret = test_hmi(filebuffer, filesize, verbose); notes_still_on = count_check_notes(); } else if (memcmp(filebuffer, mus_hdr, 4) == 0) { testret = test_mus(filebuffer, filesize, verbose); notes_still_on = count_check_notes(); } else if (memcmp(filebuffer, xmi_hdr, 4) == 0) { testret = test_xmidi(filebuffer, filesize, verbose); notes_still_on = count_check_notes(); } else if ((memcmp(filebuffer, "GF1PATCH110\0ID#000002", 22) == 0) || (memcmp(filebuffer, "GF1PATCH100\0ID#000002", 22) == 0)) { testret = test_guspat(filebuffer, filesize, verbose); } else { testret = test_midi(filebuffer, filesize, verbose); notes_still_on = count_check_notes(); } free(filebuffer); if (notes_still_on) { printf("%i notes still on after end of file\n",notes_still_on); } if (testret != 0) { printf("FAILED: %s will not work correctly with WildMIDI\n\n", argv[optind]); } else { printf("Success\n\n"); } } optind++; } return 0; } wildmidi-wildmidi-0.4.2/src/amiga.c000066400000000000000000000062301315765416100171420ustar00rootroot00000000000000/* amiga-specific stuff for WildMIDI player * Copyright (C) WildMIDI Developers 2016 * * WildMIDI is free software: you can redistribute and/or modify the player * under the terms of the GNU General Public License and you can redistribute * and/or modify the library under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either version 3 of * the licenses, or(at your option) any later version. * * WildMIDI 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 and * the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License and the * GNU Lesser General Public License along with WildMIDI. If not, see * . */ #include #include #include #include #include struct timerequest *timerio; struct MsgPort *timerport; #if defined(__MORPHOS__) || defined(__VBCC__) struct Library *TimerBase; #else struct Device *TimerBase; #endif static BPTR amiga_stdin, amiga_stdout; #define MODE_RAW 1 #define MODE_NORMAL 0 static void amiga_atexit (void) { if (amiga_stdin) SetMode(amiga_stdin, MODE_NORMAL); if (TimerBase) { WaitIO((struct IORequest *) timerio); CloseDevice((struct IORequest *) timerio); DeleteIORequest((struct IORequest *) timerio); DeleteMsgPort(timerport); TimerBase = NULL; } } void amiga_sysinit (void) { if ((timerport = CreateMsgPort())) { if ((timerio = (struct timerequest *)CreateIORequest(timerport, sizeof(struct timerequest)))) { if (OpenDevice((STRPTR) TIMERNAME, UNIT_MICROHZ, (struct IORequest *) timerio, 0) == 0) { #if defined(__MORPHOS__) || defined(__VBCC__) TimerBase = (struct Library *)timerio->tr_node.io_Device; #else TimerBase = timerio->tr_node.io_Device; #endif } else { DeleteIORequest((struct IORequest *)timerio); DeleteMsgPort(timerport); } } else { DeleteMsgPort(timerport); } } if (!TimerBase) { fprintf(stderr, "Can't open timer.device\n"); exit (-1); } /* 1us wait, for timer cleanup success */ timerio->tr_node.io_Command = TR_ADDREQUEST; timerio->tr_time.tv_secs = 0; timerio->tr_time.tv_micro = 1; SendIO((struct IORequest *) timerio); WaitIO((struct IORequest *) timerio); amiga_stdout = Output(); amiga_stdin = Input(); SetMode(amiga_stdin, MODE_RAW); atexit (amiga_atexit); } int amiga_getch (unsigned char *c) { if (WaitForChar(amiga_stdin,10)) { return Read (amiga_stdin, c, 1); } return 0; } void amiga_usleep(unsigned long timeout) { timerio->tr_node.io_Command = TR_ADDREQUEST; timerio->tr_time.tv_secs = timeout / 1000000; timerio->tr_time.tv_micro = timeout % 1000000; SendIO((struct IORequest *) timerio); WaitIO((struct IORequest *) timerio); } wildmidi-wildmidi-0.4.2/src/f_hmi.c000066400000000000000000000336761315765416100171640ustar00rootroot00000000000000/* * hmi.c -- Midi Wavetable Processing library * * Copyright (C) WildMIDI Developers 2001-2016 * * This file is part of WildMIDI. * * WildMIDI is free software: you can redistribute and/or modify the player * under the terms of the GNU General Public License and you can redistribute * and/or modify the library under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either version 3 of * the licenses, or(at your option) any later version. * * WildMIDI 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 and * the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License and the * GNU Lesser General Public License along with WildMIDI. If not, see * . */ #include "config.h" #include #include #include #include #include "common.h" #include "wm_error.h" #include "wildmidi_lib.h" #include "internal_midi.h" #include "reverb.h" #include "f_hmi.h" /* Turns hmp file data into an event stream */ struct _mdi * _WM_ParseNewHmi(uint8_t *hmi_data, uint32_t hmi_size) { uint32_t hmi_tmp = 0; uint8_t *hmi_base = hmi_data; uint32_t data_size; uint16_t hmi_bpm = 0; uint16_t hmi_division = 0; uint32_t hmi_track_cnt = 0; uint32_t *hmi_track_offset = NULL; uint32_t i = 0; uint32_t j = 0; uint8_t *hmi_addr = NULL; uint32_t *hmi_track_header_length = NULL; struct _mdi *hmi_mdi = NULL; float tempo_f = 5000000.0f; uint32_t *hmi_track_end = NULL; uint8_t hmi_tracks_ended = 0; uint8_t *hmi_running_event = NULL; uint32_t setup_ret = 0; uint32_t *hmi_delta = NULL; uint32_t smallest_delta = 0; uint32_t subtract_delta = 0; uint32_t sample_count = 0; float sample_count_f = 0; float sample_remainder = 0; float samples_per_delta_f = 0; struct _note { uint32_t length; uint8_t channel; } *note; if (memcmp(hmi_data, "HMI-MIDISONG061595", 18)) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_HMI, NULL, 0); return NULL; } //FIXME: Unsure if this is correct but it seems to be the only offset that plays the files at what appears to be the right speed. hmi_bpm = hmi_data[212]; hmi_division = 60; hmi_track_cnt = hmi_data[228]; hmi_mdi = _WM_initMDI(); _WM_midi_setup_divisions(hmi_mdi, hmi_division); if ((_WM_MixerOptions & WM_MO_ROUNDTEMPO)) { tempo_f = (float) (60000000 / hmi_bpm) + 0.5f; } else { tempo_f = (float) (60000000 / hmi_bpm); } samples_per_delta_f = _WM_GetSamplesPerTick(hmi_division, (uint32_t)tempo_f); _WM_midi_setup_tempo(hmi_mdi, (uint32_t)tempo_f); hmi_track_offset = (uint32_t *) malloc(sizeof(uint32_t) * hmi_track_cnt); hmi_track_header_length = (uint32_t *) malloc(sizeof(uint32_t) * hmi_track_cnt); hmi_track_end = (uint32_t *) malloc(sizeof(uint32_t) * hmi_track_cnt); hmi_delta = (uint32_t *) malloc(sizeof(uint32_t) * hmi_track_cnt); note = (struct _note *) malloc(sizeof(struct _note) * 128 * hmi_track_cnt); hmi_running_event = (uint8_t *) malloc(sizeof(uint8_t) * 128 * hmi_track_cnt); hmi_data += 370; smallest_delta = 0xffffffff; if (hmi_size < (370 + (hmi_track_cnt * 17))) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_HMI, "file too short", 0); goto _hmi_end; } hmi_track_offset[0] = *hmi_data; // To keep Xcode happy for (i = 0; i < hmi_track_cnt; i++) { hmi_track_offset[i] = *hmi_data++; hmi_track_offset[i] += (*hmi_data++ << 8); hmi_track_offset[i] += (*hmi_data++ << 16); hmi_track_offset[i] += (*hmi_data++ << 24); if (hmi_size < (hmi_track_offset[i] + 0x5a + 4)) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_HMI, "file too short", 0); goto _hmi_end; } hmi_addr = hmi_base + hmi_track_offset[i]; if (memcmp(hmi_addr, "HMI-MIDITRACK", 13)) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_HMI, NULL, 0); goto _hmi_end; } hmi_track_header_length[i] = hmi_addr[0x57]; hmi_track_header_length[i] += (hmi_addr[0x58] << 8); hmi_track_header_length[i] += (hmi_addr[0x59] << 16); hmi_track_header_length[i] += (hmi_addr[0x5a] << 24); hmi_addr += hmi_track_header_length[i]; hmi_track_offset[i] += hmi_track_header_length[i]; // Get tracks initial delta and set its samples_till_next; hmi_delta[i] = 0; if (*hmi_addr > 0x7f) { do { hmi_delta[i] = (hmi_delta[i] << 7) + (*hmi_addr & 0x7f); hmi_addr++; hmi_track_offset[i]++; } while (*hmi_addr > 0x7f); } hmi_delta[i] = (hmi_delta[i] << 7) + (*hmi_addr & 0x7f); hmi_track_offset[i]++; hmi_addr++; // Find smallest delta to work with if (hmi_delta[i] < smallest_delta) { smallest_delta = hmi_delta[i]; } hmi_track_end[i] = 0; hmi_running_event[i] = 0; for (j = 0; j < 128; j++) { hmi_tmp = (128 * i) + j; note[hmi_tmp].length = 0; note[hmi_tmp].channel = 0; } } subtract_delta = smallest_delta; sample_count_f= (((float) smallest_delta * samples_per_delta_f) + sample_remainder); sample_count = (uint32_t) sample_count_f; sample_remainder = sample_count_f - (float) sample_count; hmi_mdi->events[hmi_mdi->event_count - 1].samples_to_next += sample_count; hmi_mdi->extra_info.approx_total_samples += sample_count; while (hmi_tracks_ended < hmi_track_cnt) { smallest_delta = 0; for (i = 0; i < hmi_track_cnt; i++) { if (hmi_track_end[i]) continue; // first check to see if any active notes need turning off. for (j = 0; j < 128; j++) { hmi_tmp = (128 * i) + j; if (note[hmi_tmp].length) { note[hmi_tmp].length -= subtract_delta; if (note[hmi_tmp].length) { if ((!smallest_delta) || (smallest_delta > note[hmi_tmp].length)) { smallest_delta = note[hmi_tmp].length; } } else { _WM_midi_setup_noteoff(hmi_mdi, note[hmi_tmp].channel, j, 0); } } } if (hmi_delta[i]) { hmi_delta[i] -= subtract_delta; if (hmi_delta[i]) { if ((!smallest_delta) || (smallest_delta > hmi_delta[i])) { smallest_delta = hmi_delta[i]; } continue; } } do { hmi_data = hmi_base + hmi_track_offset[i]; hmi_delta[i] = 0; if (hmi_track_offset[i] >= hmi_size) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_HMI, "file too short", 0); goto _hmi_end; } data_size = hmi_size - hmi_track_offset[i]; if (hmi_data[0] == 0xfe) { // HMI only event of some sort. if (hmi_data[1] == 0x10) { hmi_tmp = (hmi_data[4] + 5); hmi_data += hmi_tmp; hmi_track_offset[i] += hmi_tmp; hmi_tmp += 4; } else if (hmi_data[1] == 0x15) { hmi_data += 4; hmi_track_offset[i] += 4; hmi_tmp = 8; } else { hmi_tmp = 4; } hmi_data += 4; hmi_track_offset[i] += 4; if (hmi_tmp > data_size) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_HMI, "file too short", 0); goto _hmi_end; } data_size -= hmi_tmp; } else { if ((setup_ret = _WM_SetupMidiEvent(hmi_mdi,hmi_data,data_size,hmi_running_event[i])) == 0) { goto _hmi_end; } if ((hmi_data[0] == 0xff) && (hmi_data[1] == 0x2f) && (hmi_data[2] == 0x00)) { hmi_track_end[i] = 1; hmi_tracks_ended++; for(j = 0; j < 128; j++) { hmi_tmp = (128 * i) + j; if (note[hmi_tmp].length) { _WM_midi_setup_noteoff(hmi_mdi, note[hmi_tmp].channel, j, 0); note[hmi_tmp].length = 0; } } goto _hmi_next_track; } // Running event // 0xff does not alter running event if ((*hmi_data == 0xF0) || (*hmi_data == 0xF7)) { // Sysex resets running event data hmi_running_event[i] = 0; } else if (*hmi_data < 0xF0) { // MIDI events 0x80 to 0xEF set running event if (*hmi_data >= 0x80) { hmi_running_event[i] = *hmi_data; } } if ((hmi_running_event[i] & 0xf0) == 0x90) { // note on has extra data to specify how long the note is. if (*hmi_data > 127) { hmi_tmp = hmi_data[1]; } else { hmi_tmp = *hmi_data; } hmi_tmp += (i * 128); note[hmi_tmp].channel = hmi_running_event[i] & 0xf; hmi_data += setup_ret; hmi_track_offset[i] += setup_ret; data_size -= setup_ret; note[hmi_tmp].length = 0; if (data_size && *hmi_data > 0x7f) { do { if (!data_size) break; note[hmi_tmp].length = (note[hmi_tmp].length << 7) | (*hmi_data & 0x7F); hmi_data++; data_size--; hmi_track_offset[i]++; } while (*hmi_data > 0x7F); } if (!data_size) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_HMI, "file too short", 0); goto _hmi_end; } note[hmi_tmp].length = (note[hmi_tmp].length << 7) | (*hmi_data & 0x7F); hmi_data++; data_size--; hmi_track_offset[i]++; if (note[hmi_tmp].length) { if ((!smallest_delta) || (smallest_delta > note[hmi_tmp].length)) { smallest_delta = note[hmi_tmp].length; } } else { _WM_midi_setup_noteoff(hmi_mdi, note[hmi_tmp].channel, j, 0); } } else { hmi_data += setup_ret; hmi_track_offset[i] += setup_ret; data_size -= setup_ret; } } // get track delta // hmi_delta[i] = 0; // set at start of loop if (data_size && *hmi_data > 0x7f) { do { if (!data_size) break; hmi_delta[i] = (hmi_delta[i] << 7) | (*hmi_data & 0x7F); hmi_data++; data_size--; hmi_track_offset[i]++; } while (*hmi_data > 0x7F); } if (!data_size) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_HMI, "file too short", 0); goto _hmi_end; } hmi_delta[i] = (hmi_delta[i] << 7) | (*hmi_data & 0x7F); hmi_data++; data_size--; hmi_track_offset[i]++; } while (!hmi_delta[i]); if ((!smallest_delta) || (smallest_delta > hmi_delta[i])) { smallest_delta = hmi_delta[i]; } _hmi_next_track: hmi_tmp = 0; UNUSED(hmi_tmp); } // convert smallest delta to samples till next subtract_delta = smallest_delta; sample_count_f= (((float) smallest_delta * samples_per_delta_f) + sample_remainder); sample_count = (uint32_t) sample_count_f; sample_remainder = sample_count_f - (float) sample_count; hmi_mdi->events[hmi_mdi->event_count - 1].samples_to_next += sample_count; hmi_mdi->extra_info.approx_total_samples += sample_count; } if ((hmi_mdi->reverb = _WM_init_reverb(_WM_SampleRate, _WM_reverb_room_width, _WM_reverb_room_length, _WM_reverb_listen_posx, _WM_reverb_listen_posy)) == NULL) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to init reverb", 0); goto _hmi_end; } hmi_mdi->extra_info.current_sample = 0; hmi_mdi->current_event = &hmi_mdi->events[0]; hmi_mdi->samples_to_mix = 0; hmi_mdi->note = NULL; _WM_ResetToStart(hmi_mdi); _hmi_end: free(hmi_track_offset); free(hmi_track_header_length); free(hmi_track_end); free(hmi_delta); free(note); free(hmi_running_event); if (hmi_mdi->reverb) return (hmi_mdi); _WM_freeMDI(hmi_mdi); return 0; } wildmidi-wildmidi-0.4.2/src/f_hmp.c000066400000000000000000000270211315765416100171560ustar00rootroot00000000000000/* * hmp.c -- Midi Wavetable Processing library * * Copyright (C) WildMIDI Developers 2001-2016 * * This file is part of WildMIDI. * * WildMIDI is free software: you can redistribute and/or modify the player * under the terms of the GNU General Public License and you can redistribute * and/or modify the library under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either version 3 of * the licenses, or(at your option) any later version. * * WildMIDI 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 and * the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License and the * GNU Lesser General Public License along with WildMIDI. If not, see * . */ #include "config.h" #include #include #include #include #include "common.h" #include "wm_error.h" #include "wildmidi_lib.h" #include "internal_midi.h" #include "reverb.h" #include "f_hmp.h" /* Turns hmp file data into an event stream */ struct _mdi * _WM_ParseNewHmp(uint8_t *hmp_data, uint32_t hmp_size) { uint8_t is_hmp2 = 0; uint32_t zero_cnt = 0; uint32_t i = 0; uint32_t hmp_file_length = 0; uint32_t hmp_chunks = 0; uint32_t hmp_divisions = 0; uint32_t hmp_unknown = 0; uint32_t hmp_bpm = 0; uint32_t hmp_song_time = 0; struct _mdi *hmp_mdi; uint8_t **hmp_chunk; uint32_t *chunk_length; uint32_t *chunk_ofs; uint32_t *chunk_delta; uint8_t *chunk_end; uint32_t chunk_num = 0; uint32_t hmp_track = 0; uint32_t smallest_delta = 0; uint32_t subtract_delta = 0; uint32_t end_of_chunks = 0; uint32_t var_len_shift = 0; float tempo_f = 500000.0f; float samples_per_delta_f = 0; uint32_t sample_count = 0; float sample_count_f = 0; float sample_remainder = 0; if (memcmp(hmp_data, "HMIMIDIP", 8)) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_HMP, NULL, 0); return NULL; } hmp_data += 8; hmp_size -= 8; if (!memcmp(hmp_data, "013195", 6)) { hmp_data += 6; hmp_size -= 6; is_hmp2 = 1; } // should be a bunch of \0's if (is_hmp2) { zero_cnt = 18; } else { zero_cnt = 24; } for (i = 0; i < zero_cnt; i++) { if (hmp_data[i] != 0) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_HMP, NULL, 0); return NULL; } } hmp_data += zero_cnt; hmp_size -= zero_cnt; hmp_file_length = *hmp_data++; hmp_file_length += (*hmp_data++ << 8); hmp_file_length += (*hmp_data++ << 16); hmp_file_length += (*hmp_data++ << 24); hmp_size -= 4; UNUSED(hmp_file_length); // Next 12 bytes are normally \0 so skipping over them hmp_data += 12; hmp_size -= 12; hmp_chunks = *hmp_data++; hmp_chunks += (*hmp_data++ << 8); hmp_chunks += (*hmp_data++ << 16); hmp_chunks += (*hmp_data++ << 24); hmp_size -= 4; // Still decyphering what this is hmp_unknown = *hmp_data++; hmp_unknown += (*hmp_data++ << 8); hmp_unknown += (*hmp_data++ << 16); hmp_unknown += (*hmp_data++ << 24); hmp_size -= 4; UNUSED(hmp_unknown); // Defaulting: experimenting has found this to be the ideal value hmp_divisions = 60; // Beats per minute hmp_bpm = *hmp_data++; hmp_bpm += (*hmp_data++ << 8); hmp_bpm += (*hmp_data++ << 16); hmp_bpm += (*hmp_data++ << 24); hmp_size -= 4; /* Slow but needed for accuracy */ if ((_WM_MixerOptions & WM_MO_ROUNDTEMPO)) { tempo_f = (float) (60000000 / hmp_bpm) + 0.5f; } else { tempo_f = (float) (60000000 / hmp_bpm); } samples_per_delta_f = _WM_GetSamplesPerTick(hmp_divisions, (uint32_t) tempo_f); //DEBUG //fprintf(stderr, "DEBUG: Samples Per Delta Tick: %f\r\n",samples_per_delta_f); // FIXME: This value is incorrect hmp_song_time = *hmp_data++; hmp_song_time += (*hmp_data++ << 8); hmp_song_time += (*hmp_data++ << 16); hmp_song_time += (*hmp_data++ << 24); hmp_size -= 4; // DEBUG //fprintf(stderr,"DEBUG: ??DIVISIONS??: %u, BPM: %u, ??SONG TIME??: %u:%.2u\r\n",hmp_divisions, hmp_bpm, (hmp_song_time / 60), (hmp_song_time % 60)); UNUSED(hmp_song_time); if (is_hmp2) { hmp_data += 840; hmp_size -= 840; } else { hmp_data += 712; hmp_size -= 712; } hmp_mdi = _WM_initMDI(); _WM_midi_setup_divisions(hmp_mdi, hmp_divisions); _WM_midi_setup_tempo(hmp_mdi, (uint32_t)tempo_f); hmp_chunk = (uint8_t **) malloc(sizeof(uint8_t *) * hmp_chunks); chunk_length = (uint32_t *) malloc(sizeof(uint32_t) * hmp_chunks); chunk_delta = (uint32_t *) malloc(sizeof(uint32_t) * hmp_chunks); chunk_ofs = (uint32_t *) malloc(sizeof(uint32_t) * hmp_chunks); chunk_end = (uint8_t *) malloc(sizeof(uint8_t) * hmp_chunks); smallest_delta = 0xffffffff; // store chunk info for use, and check chunk lengths for (i = 0; i < hmp_chunks; i++) { hmp_chunk[i] = hmp_data; chunk_ofs[i] = 0; chunk_num = *hmp_data++; chunk_num += (*hmp_data++ << 8); chunk_num += (*hmp_data++ << 16); chunk_num += (*hmp_data++ << 24); chunk_ofs[i] += 4; UNUSED(chunk_num); chunk_length[i] = *hmp_data++; chunk_length[i] += (*hmp_data++ << 8); chunk_length[i] += (*hmp_data++ << 16); chunk_length[i] += (*hmp_data++ << 24); chunk_ofs[i] += 4; if (chunk_length[i] > hmp_size) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_HMP, "file too short", 0); goto _hmp_end; } hmp_size -= chunk_length[i]; hmp_track = *hmp_data++; hmp_track += (*hmp_data++ << 8); hmp_track += (*hmp_data++ << 16); hmp_track += (*hmp_data++ << 24); chunk_ofs[i] += 4; UNUSED(hmp_track); // Start of Midi Data chunk_delta[i] = 0; var_len_shift = 0; if (*hmp_data < 0x80) { do { chunk_delta[i] = chunk_delta[i] | ((*hmp_data++ & 0x7F) << var_len_shift); var_len_shift += 7; chunk_ofs[i]++; } while (*hmp_data < 0x80); } chunk_delta[i] = chunk_delta[i] | ((*hmp_data++ & 0x7F) << var_len_shift); chunk_ofs[i]++; if (chunk_delta[i] < smallest_delta) { smallest_delta = chunk_delta[i]; } // goto start of next chunk hmp_data = hmp_chunk[i] + chunk_length[i]; chunk_length[i] -= chunk_ofs[i]; hmp_chunk[i] += chunk_ofs[i]++; chunk_end[i] = 0; } subtract_delta = smallest_delta; sample_count_f = (((float) smallest_delta * samples_per_delta_f) + sample_remainder); sample_count = (uint32_t) sample_count_f; sample_remainder = sample_count_f - (float) sample_count; hmp_mdi->events[hmp_mdi->event_count - 1].samples_to_next += sample_count; hmp_mdi->extra_info.approx_total_samples += sample_count; while (end_of_chunks < hmp_chunks) { smallest_delta = 0; // DEBUG // fprintf(stderr,"DEBUG: Delta Ticks: %u\r\n",subtract_delta); for (i = 0; i < hmp_chunks; i++) { if (chunk_end[i]) continue; if (chunk_delta[i]) { chunk_delta[i] -= subtract_delta; if (chunk_delta[i]) { if ((!smallest_delta) || (smallest_delta > chunk_delta[i])) { smallest_delta = chunk_delta[i]; } continue; } } do { if (((hmp_chunk[i][0] & 0xf0) == 0xb0 ) && ((hmp_chunk[i][1] == 110) || (hmp_chunk[i][1] == 111)) && (hmp_chunk[i][2] > 0x7f)) { // Reserved for loop markers // TODO: still deciding what to do about these hmp_chunk[i] += 3; chunk_length[i] -= 3; } else { uint32_t setup_ret = 0; if ((setup_ret = _WM_SetupMidiEvent(hmp_mdi, hmp_chunk[i], chunk_length[i], 0)) == 0) { goto _hmp_end; } if ((hmp_chunk[i][0] == 0xff) && (hmp_chunk[i][1] == 0x2f) && (hmp_chunk[i][2] == 0x00)) { /* End of Chunk */ end_of_chunks++; chunk_end[i] = 1; chunk_length[i] -= 3; hmp_chunk[i] += 3; goto NEXT_CHUNK; } else if ((hmp_chunk[i][0] == 0xff) && (hmp_chunk[i][1] == 0x51) && (hmp_chunk[i][2] == 0x03)) { /* Tempo */ tempo_f = (float)((hmp_chunk[i][3] << 16) + (hmp_chunk[i][4] << 8)+ hmp_chunk[i][5]); if (tempo_f == 0.0f) tempo_f = 500000.0f; // DEBUG fprintf(stderr,"DEBUG: Tempo change %f\r\n", tempo_f); } hmp_chunk[i] += setup_ret; chunk_length[i] -= setup_ret; } var_len_shift = 0; chunk_delta[i] = 0; if (chunk_length[i] && *hmp_chunk[i] < 0x80) { do { if (! chunk_length[i]) break; chunk_delta[i] = chunk_delta[i] + ((*hmp_chunk[i] & 0x7F) << var_len_shift); var_len_shift += 7; hmp_chunk[i]++; chunk_length[i]--; } while (*hmp_chunk[i] < 0x80); } if (! chunk_length[i]) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_HMP, "file too short", 0); goto _hmp_end; } chunk_delta[i] = chunk_delta[i] + ((*hmp_chunk[i] & 0x7F) << var_len_shift); hmp_chunk[i]++; chunk_length[i]--; } while (!chunk_delta[i]); if ((!smallest_delta) || (smallest_delta > chunk_delta[i])) { smallest_delta = chunk_delta[i]; } NEXT_CHUNK: continue; } subtract_delta = smallest_delta; sample_count_f= (((float) smallest_delta * samples_per_delta_f) + sample_remainder); sample_count = (uint32_t) sample_count_f; sample_remainder = sample_count_f - (float) sample_count; hmp_mdi->events[hmp_mdi->event_count - 1].samples_to_next += sample_count; hmp_mdi->extra_info.approx_total_samples += sample_count; // DEBUG // fprintf(stderr,"DEBUG: Sample Count %u\r\n",sample_count); } if ((hmp_mdi->reverb = _WM_init_reverb(_WM_SampleRate, _WM_reverb_room_width, _WM_reverb_room_length, _WM_reverb_listen_posx, _WM_reverb_listen_posy)) == NULL) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to init reverb", 0); goto _hmp_end; } hmp_mdi->extra_info.current_sample = 0; hmp_mdi->current_event = &hmp_mdi->events[0]; hmp_mdi->samples_to_mix = 0; hmp_mdi->note = NULL; _WM_ResetToStart(hmp_mdi); _hmp_end: free(hmp_chunk); free(chunk_length); free(chunk_delta); free(chunk_ofs); free(chunk_end); if (hmp_mdi->reverb) return (hmp_mdi); _WM_freeMDI(hmp_mdi); return NULL; } wildmidi-wildmidi-0.4.2/src/f_midi.c000066400000000000000000001150121315765416100173120ustar00rootroot00000000000000/* * midi.c -- Midi Wavetable Processing library * * Copyright (C) WildMIDI Developers 2001-2016 * * This file is part of WildMIDI. * * WildMIDI is free software: you can redistribute and/or modify the player * under the terms of the GNU General Public License and you can redistribute * and/or modify the library under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either version 3 of * the licenses, or(at your option) any later version. * * WildMIDI 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 and * the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License and the * GNU Lesser General Public License along with WildMIDI. If not, see * . */ #include "config.h" #include #include #include #include #include "common.h" #include "wm_error.h" #include "f_midi.h" #include "wildmidi_lib.h" #include "internal_midi.h" #include "reverb.h" #include "sample.h" struct _mdi * _WM_ParseNewMidi(uint8_t *midi_data, uint32_t midi_size) { struct _mdi *mdi; uint32_t tmp_val; uint32_t midi_type; uint8_t **tracks; uint32_t *track_size; uint32_t end_of_tracks = 0; uint32_t no_tracks; uint32_t i; uint32_t divisions = 96; uint32_t tempo = 500000; float samples_per_delta_f = 0; uint32_t sample_count = 0; float sample_count_f = 0; float sample_remainder = 0; uint8_t *sysex_store = NULL; uint32_t *track_delta; uint8_t *track_end; uint32_t smallest_delta = 0; uint32_t subtract_delta = 0; uint8_t *running_event; uint32_t setup_ret = 0; if (midi_size < 14) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(too short)", 0); return (NULL); } if (!memcmp(midi_data, "RIFF", 4)) { if (midi_size < 34) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(too short)", 0); return (NULL); } midi_data += 20; midi_size -= 20; } if (memcmp(midi_data, "MThd", 4)) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_MIDI, NULL, 0); return (NULL); } midi_data += 4; midi_size -= 4; /* * Get Midi Header Size - must always be 6 */ tmp_val = *midi_data++ << 24; tmp_val |= *midi_data++ << 16; tmp_val |= *midi_data++ << 8; tmp_val |= *midi_data++; midi_size -= 4; if (tmp_val != 6) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, NULL, 0); return (NULL); } /* * Get Midi Format - we only support 0, 1 & 2 */ tmp_val = *midi_data++ << 8; tmp_val |= *midi_data++; midi_size -= 2; if (tmp_val > 2) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, NULL, 0); return (NULL); } midi_type = tmp_val; /* * Get No. of Tracks */ tmp_val = *midi_data++ << 8; tmp_val |= *midi_data++; midi_size -= 2; if (tmp_val < 1) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(no tracks)", 0); return (NULL); } no_tracks = tmp_val; /* * Check that type 0 midi file has only 1 track */ if ((midi_type == 0) && (no_tracks > 1)) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(expected 1 track for type 0 midi file, found more)", 0); return (NULL); } /* * Get Divisions */ divisions = *midi_data++ << 8; divisions |= *midi_data++; midi_size -= 2; if (divisions & 0x00008000) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, NULL, 0); return (NULL); } samples_per_delta_f = _WM_GetSamplesPerTick(divisions, tempo); mdi = _WM_initMDI(); _WM_midi_setup_divisions(mdi,divisions); tracks = (uint8_t **) malloc(sizeof(uint8_t *) * no_tracks); track_size = (uint32_t *) malloc(sizeof(uint32_t) * no_tracks); track_delta = (uint32_t *) malloc(sizeof(uint32_t) * no_tracks); track_end = (uint8_t *) malloc(sizeof(uint8_t) * no_tracks); running_event = (uint8_t *) malloc(sizeof(uint8_t) * no_tracks); smallest_delta = 0xffffffff; for (i = 0; i < no_tracks; i++) { if (midi_size < 8) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(too short)", 0); goto _end; } if (memcmp(midi_data, "MTrk", 4) != 0) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(missing track header)", 0); goto _end; } midi_data += 4; midi_size -= 4; /* track size */ tmp_val = *midi_data++ << 24; tmp_val |= *midi_data++ << 16; tmp_val |= *midi_data++ << 8; tmp_val |= *midi_data++; midi_size -= 4; if (midi_size < tmp_val) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(too short)", 0); goto _end; } if (tmp_val < 3) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(bad track size)", 0); goto _end; } if ((midi_data[tmp_val - 3] != 0xFF) || (midi_data[tmp_val - 2] != 0x2F) || (midi_data[tmp_val - 1] != 0x00)) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(missing EOT)", 0); goto _end; } tracks[i] = midi_data; track_size[i] = tmp_val; midi_data += tmp_val; midi_size -= tmp_val; track_end[i] = 0; running_event[i] = 0; track_delta[i] = 0; while (*tracks[i] > 0x7F) { track_delta[i] = (track_delta[i] << 7) + (*tracks[i] & 0x7F); tracks[i]++; track_size[i]--; } track_delta[i] = (track_delta[i] << 7) + (*tracks[i] & 0x7F); tracks[i]++; track_size[i]--; if (midi_type == 1 ) { if (track_delta[i] < smallest_delta) { smallest_delta = track_delta[i]; } } else { /* * Type 0 & 2 midi only needs delta from 1st track * for initial sample calculations. */ if (i == 0) smallest_delta = track_delta[i]; } } subtract_delta = smallest_delta; sample_count_f = (((float) smallest_delta * samples_per_delta_f) + sample_remainder); sample_count = (uint32_t) sample_count_f; sample_remainder = sample_count_f - (float) sample_count; mdi->events[mdi->event_count - 1].samples_to_next += sample_count; mdi->extra_info.approx_total_samples += sample_count; /* * Handle type 0 & 2 the same, but type 1 differently */ if (midi_type == 1) { /* Type 1 */ while (end_of_tracks != no_tracks) { smallest_delta = 0; for (i = 0; i < no_tracks; i++) { if (track_end[i]) continue; if (track_delta[i]) { track_delta[i] -= subtract_delta; if (track_delta[i]) { if ((!smallest_delta) || (smallest_delta > track_delta[i])) { smallest_delta = track_delta[i]; } continue; } } do { setup_ret = _WM_SetupMidiEvent(mdi, tracks[i], track_size[i], running_event[i]); if (setup_ret == 0) { goto _end; } if (tracks[i][0] > 0x7f) { if (tracks[i][0] < 0xf0) { /* Events 0x80 - 0xef set running event */ running_event[i] = tracks[i][0]; } else if ((tracks[i][0] == 0xf0) || (tracks[i][0] == 0xf7)) { /* Sysex resets running event */ running_event[i] = 0; } else if ((tracks[i][0] == 0xff) && (tracks[i][1] == 0x2f) && (tracks[i][2] == 0x00)) { /* End of Track */ end_of_tracks++; track_end[i] = 1; tracks[i] += 3; track_size[i] -= 3; goto NEXT_TRACK; } else if ((tracks[i][0] == 0xff) && (tracks[i][1] == 0x51) && (tracks[i][2] == 0x03)) { /* Tempo */ tempo = (tracks[i][3] << 16) + (tracks[i][4] << 8)+ tracks[i][5]; if (!tempo) tempo = 500000; samples_per_delta_f = _WM_GetSamplesPerTick(divisions, tempo); } } tracks[i] += setup_ret; track_size[i] -= setup_ret; if (*tracks[i] > 0x7f) { do { if (!track_size[i]) break; track_delta[i] = (track_delta[i] << 7) + (*tracks[i] & 0x7F); tracks[i]++; track_size[i]--; } while (*tracks[i] > 0x7f); } if (!track_size[i]) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(too short)", 0); goto _end; } track_delta[i] = (track_delta[i] << 7) + (*tracks[i] & 0x7F); tracks[i]++; track_size[i]--; } while (!track_delta[i]); if ((!smallest_delta) || (smallest_delta > track_delta[i])) { smallest_delta = track_delta[i]; } NEXT_TRACK: continue; } subtract_delta = smallest_delta; sample_count_f = (((float) smallest_delta * samples_per_delta_f) + sample_remainder); sample_count = (uint32_t) sample_count_f; sample_remainder = sample_count_f - (float) sample_count; mdi->events[mdi->event_count - 1].samples_to_next += sample_count; mdi->extra_info.approx_total_samples += sample_count; } } else { /* Type 0 & 2 */ if (midi_type == 2) { mdi->is_type2 = 1; } sample_remainder = 0; for (i = 0; i < no_tracks; i++) { running_event[i] = 0; do { setup_ret = _WM_SetupMidiEvent(mdi, tracks[i], track_size[i], running_event[i]); if (setup_ret == 0) { goto _end; } if (tracks[i][0] > 0x7f) { if (tracks[i][0] < 0xf0) { /* Events 0x80 - 0xef set running event */ running_event[i] = tracks[i][0]; } else if ((tracks[i][0] == 0xf0) || (tracks[i][0] == 0xf7)) { /* Sysex resets running event */ running_event[i] = 0; } else if ((tracks[i][0] == 0xff) && (tracks[i][1] == 0x2f) && (tracks[i][2] == 0x00)) { /* End of Track */ track_end[i] = 1; goto NEXT_TRACK2; } else if ((tracks[i][0] == 0xff) && (tracks[i][1] == 0x51) && (tracks[i][2] == 0x03)) { /* Tempo */ tempo = (tracks[i][3] << 16) + (tracks[i][4] << 8)+ tracks[i][5]; if (!tempo) tempo = 500000; samples_per_delta_f = _WM_GetSamplesPerTick(divisions, tempo); } } tracks[i] += setup_ret; track_size[i] -= setup_ret; track_delta[i] = 0; if (*tracks[i] > 0x7f) { do { if (!track_size[i]) break; track_delta[i] = (track_delta[i] << 7) + (*tracks[i] & 0x7F); tracks[i]++; track_size[i]--; } while (*tracks[i] > 0x7f); } if (!track_size[i]) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(too short)", 0); goto _end; } track_delta[i] = (track_delta[i] << 7) + (*tracks[i] & 0x7F); tracks[i]++; track_size[i]--; sample_count_f = (((float) track_delta[i] * samples_per_delta_f) + sample_remainder); sample_count = (uint32_t) sample_count_f; sample_remainder = sample_count_f - (float) sample_count; mdi->events[mdi->event_count - 1].samples_to_next += sample_count; mdi->extra_info.approx_total_samples += sample_count; NEXT_TRACK2: smallest_delta = track_delta[i]; /* Added just to keep Xcode happy */ UNUSED(smallest_delta); /* Added to just keep clang happy */ } while (track_end[i] == 0); } } if ((mdi->reverb = _WM_init_reverb(_WM_SampleRate, _WM_reverb_room_width, _WM_reverb_room_length, _WM_reverb_listen_posx, _WM_reverb_listen_posy)) == NULL) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to init reverb", 0); goto _end; } mdi->extra_info.current_sample = 0; mdi->current_event = &mdi->events[0]; mdi->samples_to_mix = 0; mdi->note = NULL; _WM_ResetToStart(mdi); _end: free(sysex_store); free(track_end); free(track_delta); free(running_event); free(tracks); free(track_size); if (mdi->reverb) return (mdi); _WM_freeMDI(mdi); return (NULL); } /* Convert WildMIDI's MDI events into a type 0 MIDI file. returns 0 = successful -1 = failed **out points to place to store stuff *outsize points to where to store byte counts NOTE: This will only write out events that we do support. *** CAUTION *** This will output type 0 midi file reguardless of the original file type. Type 2 midi files will have each original track play on the same track one after the other in the type 0 file. */ int _WM_Event2Midi(struct _mdi *mdi, uint8_t **out, uint32_t *outsize) { uint32_t out_ofs = 0; uint8_t running_event = 0; uint32_t divisions = 96; uint32_t tempo = 500000; float samples_per_tick = 0; uint32_t value = 0; float value_f = 0; struct _event *event = mdi->events; uint32_t track_size = 0; uint32_t track_start = 0; uint32_t track_count = 0; if (!mdi->event_count) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_CONVERT, "(No events to convert)", 0); return -1; } samples_per_tick = _WM_GetSamplesPerTick(divisions, tempo); /* Note: This isn't accurate but will allow enough space for events plus delta values. */ (*out) = (uint8_t *) malloc (sizeof(uint8_t) * (mdi->event_count * 12)); /* Midi Header */ (*out)[0] = 'M'; (*out)[1] = 'T'; (*out)[2] = 'h'; (*out)[3] = 'd'; (*out)[4] = 0x00; (*out)[5] = 0x00; (*out)[6] = 0x00; (*out)[7] = 0x06; if ((!(_WM_MixerOptions & WM_MO_SAVEASTYPE0)) && (mdi->is_type2)) { /* Type 2 */ (*out)[8] = 0x00; (*out)[9] = 0x02; } else { /* Type 0 */ (*out)[8] = 0x00; (*out)[9] = 0x00; } /* No. of tracks stored in 10-11 *** See below */ /* Division stored in 12-13 *** See below */ /* Track Header */ (*out)[14] = 'M'; (*out)[15] = 'T'; (*out)[16] = 'r'; (*out)[17] = 'k'; /* Track size stored in 18-21 *** see below */ out_ofs = 22; track_start = out_ofs; track_count++; do { /* TODO Is there a better way? */ if (event->do_event == _WM_do_midi_divisions) { // DEBUG // fprintf(stderr,"Division: %u\r\n",event->event_data.data); divisions = event->event_data.data.value; (*out)[12] = (divisions >> 8) & 0xff; (*out)[13] = divisions & 0xff; samples_per_tick = _WM_GetSamplesPerTick(divisions, tempo); } else if (event->do_event == _WM_do_note_off) { // DEBUG // fprintf(stderr,"Note Off: %u %.4x\r\n",event->event_data.channel, event->event_data.data); if (running_event != (0x80 | event->event_data.channel)) { (*out)[out_ofs++] = 0x80 | event->event_data.channel; running_event = (*out)[out_ofs - 1]; } (*out)[out_ofs++] = (event->event_data.data.value >> 8) & 0xff; (*out)[out_ofs++] = event->event_data.data.value & 0xff; } else if (event->do_event == _WM_do_note_on) { // DEBUG // fprintf(stderr,"Note On: %u %.4x\r\n",event->event_data.channel, event->event_data.data); if (running_event != (0x90 | event->event_data.channel)) { (*out)[out_ofs++] = 0x90 | event->event_data.channel; running_event = (*out)[out_ofs - 1]; } (*out)[out_ofs++] = (event->event_data.data.value >> 8) & 0xff; (*out)[out_ofs++] = event->event_data.data.value & 0xff; } else if (event->do_event == _WM_do_aftertouch) { // DEBUG // fprintf(stderr,"Aftertouch: %u %.4x\r\n",event->event_data.channel, event->event_data.data); if (running_event != (0xa0 | event->event_data.channel)) { (*out)[out_ofs++] = 0xa0 | event->event_data.channel; running_event = (*out)[out_ofs - 1]; } (*out)[out_ofs++] = (event->event_data.data.value >> 8) & 0xff; (*out)[out_ofs++] = event->event_data.data.value & 0xff; } else if (event->do_event == _WM_do_control_bank_select) { // DEBUG // fprintf(stderr,"Control Bank Select: %u %.4x\r\n",event->event_data.channel, event->event_data.data); if (running_event != (0xb0 | event->event_data.channel)) { (*out)[out_ofs++] = 0xb0 | event->event_data.channel; running_event = (*out)[out_ofs - 1]; } (*out)[out_ofs++] = 0; (*out)[out_ofs++] = event->event_data.data.value & 0xff; } else if (event->do_event == _WM_do_control_data_entry_course) { // DEBUG // fprintf(stderr,"Control Data Entry Course: %u %.4x\r\n",event->event_data.channel, event->event_data.data); if (running_event != (0xb0 | event->event_data.channel)) { (*out)[out_ofs++] = 0xb0 | event->event_data.channel; running_event = (*out)[out_ofs - 1]; } (*out)[out_ofs++] = 6; (*out)[out_ofs++] = event->event_data.data.value & 0xff; } else if (event->do_event == _WM_do_control_channel_volume) { // DEBUG // fprintf(stderr,"Control Channel Volume: %u %.4x\r\n",event->event_data.channel, event->event_data.data); if (running_event != (0xb0 | event->event_data.channel)) { (*out)[out_ofs++] = 0xb0 | event->event_data.channel; running_event = (*out)[out_ofs - 1]; } (*out)[out_ofs++] = 7; (*out)[out_ofs++] = event->event_data.data.value & 0xff; } else if (event->do_event == _WM_do_control_channel_balance) { // DEBUG // fprintf(stderr,"Control Channel Balance: %u %.4x\r\n",event->event_data.channel, event->event_data.data); if (running_event != (0xb0 | event->event_data.channel)) { (*out)[out_ofs++] = 0xb0 | event->event_data.channel; running_event = (*out)[out_ofs - 1]; } (*out)[out_ofs++] = 8; (*out)[out_ofs++] = event->event_data.data.value & 0xff; } else if (event->do_event == _WM_do_control_channel_pan) { // DEBUG // fprintf(stderr,"Control Channel Pan: %u %.4x\r\n",event->event_data.channel, event->event_data.data); if (running_event != (0xb0 | event->event_data.channel)) { (*out)[out_ofs++] = 0xb0 | event->event_data.channel; running_event = (*out)[out_ofs - 1]; } (*out)[out_ofs++] = 10; (*out)[out_ofs++] = event->event_data.data.value & 0xff; } else if (event->do_event == _WM_do_control_channel_expression) { // DEBUG // fprintf(stderr,"Control Channel Expression: %u %.4x\r\n",event->event_data.channel, event->event_data.data); if (running_event != (0xb0 | event->event_data.channel)) { (*out)[out_ofs++] = 0xb0 | event->event_data.channel; running_event = (*out)[out_ofs - 1]; } (*out)[out_ofs++] = 11; (*out)[out_ofs++] = event->event_data.data.value & 0xff; } else if (event->do_event == _WM_do_control_data_entry_fine) { // DEBUG // fprintf(stderr,"Control Data Entry Fine: %u %.4x\r\n",event->event_data.channel, event->event_data.data); if (running_event != (0xb0 | event->event_data.channel)) { (*out)[out_ofs++] = 0xb0 | event->event_data.channel; running_event = (*out)[out_ofs - 1]; } (*out)[out_ofs++] = 38; (*out)[out_ofs++] = event->event_data.data.value & 0xff; } else if (event->do_event == _WM_do_control_channel_hold) { // DEBUG // fprintf(stderr,"Control Channel Hold: %u %.4x\r\n",event->event_data.channel, event->event_data.data); if (running_event != (0xb0 | event->event_data.channel)) { (*out)[out_ofs++] = 0xb0 | event->event_data.channel; running_event = (*out)[out_ofs - 1]; } (*out)[out_ofs++] = 64; (*out)[out_ofs++] = event->event_data.data.value & 0xff; } else if (event->do_event == _WM_do_control_data_increment) { // DEBUG // fprintf(stderr,"Control Data Increment: %u %.4x\r\n",event->event_data.channel, event->event_data.data); if (running_event != (0xb0 | event->event_data.channel)) { (*out)[out_ofs++] = 0xb0 | event->event_data.channel; running_event = (*out)[out_ofs - 1]; } (*out)[out_ofs++] = 96; (*out)[out_ofs++] = event->event_data.data.value & 0xff; } else if (event->do_event == _WM_do_control_data_decrement) { // DEBUG //fprintf(stderr,"Control Data Decrement: %u %.4x\r\n",event->event_data.channel, event->event_data.data); if (running_event != (0xb0 | event->event_data.channel)) { (*out)[out_ofs++] = 0xb0 | event->event_data.channel; running_event = (*out)[out_ofs - 1]; } (*out)[out_ofs++] = 97; (*out)[out_ofs++] = event->event_data.data.value & 0xff; } else if (event->do_event == _WM_do_control_non_registered_param_fine) { // DEBUG // fprintf(stderr,"Control Non Registered Param: %u %.4x\r\n",event->event_data.channel, event->event_data.data); if (running_event != (0xb0 | event->event_data.channel)) { (*out)[out_ofs++] = 0xb0 | event->event_data.channel; running_event = (*out)[out_ofs - 1]; } (*out)[out_ofs++] = 98; (*out)[out_ofs++] = event->event_data.data.value & 0x7f; } else if (event->do_event == _WM_do_control_non_registered_param_course) { // DEBUG // fprintf(stderr,"Control Non Registered Param: %u %.4x\r\n",event->event_data.channel, event->event_data.data); if (running_event != (0xb0 | event->event_data.channel)) { (*out)[out_ofs++] = 0xb0 | event->event_data.channel; running_event = (*out)[out_ofs - 1]; } (*out)[out_ofs++] = 99; (*out)[out_ofs++] = (event->event_data.data.value >> 7) & 0x7f; } else if (event->do_event == _WM_do_control_registered_param_fine) { // DEBUG // fprintf(stderr,"Control Registered Param Fine: %u %.4x\r\n",event->event_data.channel, event->event_data.data); if (running_event != (0xb0 | event->event_data.channel)) { (*out)[out_ofs++] = 0xb0 | event->event_data.channel; running_event = (*out)[out_ofs - 1]; } (*out)[out_ofs++] = 100; (*out)[out_ofs++] = event->event_data.data.value & 0x7f; } else if (event->do_event == _WM_do_control_registered_param_course) { // DEBUG // fprintf(stderr,"Control Registered Param Course: %u %.4x\r\n",event->event_data.channel, event->event_data.data); if (running_event != (0xb0 | event->event_data.channel)) { (*out)[out_ofs++] = 0xb0 | event->event_data.channel; running_event = (*out)[out_ofs - 1]; } (*out)[out_ofs++] = 101; (*out)[out_ofs++] = (event->event_data.data.value >> 7) & 0x7f; } else if (event->do_event == _WM_do_control_channel_sound_off) { // DEBUG // fprintf(stderr,"Control Channel Sound Off: %u %.4x\r\n",event->event_data.channel, event->event_data.data); if (running_event != (0xb0 | event->event_data.channel)) { (*out)[out_ofs++] = 0xb0 | event->event_data.channel; running_event = (*out)[out_ofs - 1]; } (*out)[out_ofs++] = 120; (*out)[out_ofs++] = event->event_data.data.value & 0xff; } else if (event->do_event == _WM_do_control_channel_controllers_off) { // DEBUG // fprintf(stderr,"Control Channel Controllers Off: %u %.4x\r\n",event->event_data.channel, event->event_data.data); if (running_event != (0xb0 | event->event_data.channel)) { (*out)[out_ofs++] = 0xb0 | event->event_data.channel; running_event = (*out)[out_ofs - 1]; } (*out)[out_ofs++] = 121; (*out)[out_ofs++] = event->event_data.data.value & 0xff; } else if (event->do_event == _WM_do_control_channel_notes_off) { // DEBUG // fprintf(stderr,"Control Channel Notes Off: %u %.4x\r\n",event->event_data.channel, event->event_data.data); if (running_event != (0xb0 | event->event_data.channel)) { (*out)[out_ofs++] = 0xb0 | event->event_data.channel; running_event = (*out)[out_ofs - 1]; } (*out)[out_ofs++] = 123; (*out)[out_ofs++] = event->event_data.data.value & 0xff; } else if (event->do_event == _WM_do_control_dummy) { // DEBUG // fprintf(stderr,"Control Dummy Event: %u %.4x\r\n",event->event_data.channel, event->event_data.data); if (running_event != (0xb0 | event->event_data.channel)) { (*out)[out_ofs++] = 0xb0 | event->event_data.channel; running_event = (*out)[out_ofs - 1]; } (*out)[out_ofs++] = (event->event_data.data.value >> 8) & 0xff; (*out)[out_ofs++] = event->event_data.data.value & 0xff; } else if (event->do_event == _WM_do_patch) { // DEBUG // fprintf(stderr,"Patch: %u %.4x\r\n",event->event_data.channel, event->event_data.data); if (running_event != (0xc0 | event->event_data.channel)) { (*out)[out_ofs++] = 0xc0 | event->event_data.channel; running_event = (*out)[out_ofs - 1]; } (*out)[out_ofs++] = event->event_data.data.value & 0xff; } else if (event->do_event == _WM_do_channel_pressure) { // DEBUG // fprintf(stderr,"Channel Pressure: %u %.4x\r\n",event->event_data.channel, event->event_data.data); if (running_event != (0xd0 | event->event_data.channel)) { (*out)[out_ofs++] = 0xd0 | event->event_data.channel; running_event = (*out)[out_ofs - 1]; } (*out)[out_ofs++] = event->event_data.data.value & 0xff; } else if (event->do_event == _WM_do_pitch) { // DEBUG // fprintf(stderr,"Pitch: %u %.4x\r\n",event->event_data.channel, event->event_data.data); if (running_event != (0xe0 | event->event_data.channel)) { (*out)[out_ofs++] = 0xe0 | event->event_data.channel; running_event = (*out)[out_ofs - 1]; } (*out)[out_ofs++] = event->event_data.data.value & 0x7f; (*out)[out_ofs++] = (event->event_data.data.value >> 7) & 0x7f; } else if (event->do_event == _WM_do_sysex_roland_drum_track) { // DEBUG // fprintf(stderr,"Sysex Roland Drum Track: %u %.4x\r\n",event->event_data.channel, event->event_data.data); uint8_t foo[] = {0xf0, 0x09, 0x41, 0x10, 0x42, 0x12, 0x40, 0x00, 0x15, 0x00, 0xf7}; uint8_t foo_ch = event->event_data.channel; if (foo_ch == 9) { foo_ch = 0; } else if (foo_ch < 9) { foo_ch++; } foo[7] = 0x10 | foo_ch; foo[9] = event->event_data.data.value; memcpy(&((*out)[out_ofs]),foo,11); out_ofs += 11; running_event = 0; } else if (event->do_event == _WM_do_sysex_gm_reset) { // DEBUG // fprintf(stderr,"Sysex GM Reset\r\n"); uint8_t foo[] = {0xf0, 0x05, 0x7e, 0x7f, 0x09, 0x01, 0xf7}; memcpy(&((*out)[out_ofs]),foo,7); out_ofs += 7; running_event = 0; } else if (event->do_event == _WM_do_sysex_roland_reset) { // DEBUG // fprintf(stderr,"Sysex Roland Reset\r\n"); uint8_t foo[] = {0xf0, 0x0a, 0x41, 0x10, 0x42, 0x12, 0x40, 0x00, 0x7f, 0x00, 0x41, 0xf7}; memcpy(&((*out)[out_ofs]),foo,12); out_ofs += 12; running_event = 0; } else if (event->do_event == _WM_do_sysex_yamaha_reset) { // DEBUG // fprintf(stderr,"Sysex Yamaha Reset\r\n"); uint8_t foo[] = {0xf0, 0x08, 0x43, 0x10, 0x4c, 0x00, 0x00, 0x7e, 0x00, 0xf7}; memcpy(&((*out)[out_ofs]),foo,10); out_ofs += 10; running_event = 0; } else if (event->do_event == _WM_do_meta_endoftrack) { // DEBUG // fprintf(stderr,"End Of Track\r\n"); if ((!(_WM_MixerOptions & WM_MO_SAVEASTYPE0)) && (mdi->is_type2)) { /* Write end of track marker */ (*out)[out_ofs++] = 0xff; (*out)[out_ofs++] = 0x2f; (*out)[out_ofs++] = 0x00; track_size = out_ofs - track_start; (*out)[track_start - 4] = (track_size >> 24) & 0xff; (*out)[track_start - 3] = (track_size >> 16) & 0xff; (*out)[track_start - 2] = (track_size >> 8) & 0xff; (*out)[track_start - 1] = track_size & 0xff; if (event[1].do_event != NULL) { (*out)[out_ofs++] = 'M'; (*out)[out_ofs++] = 'T'; (*out)[out_ofs++] = 'r'; (*out)[out_ofs++] = 'k'; track_count++; out_ofs += 4; track_start = out_ofs; /* write out a 0 delta */ (*out)[out_ofs++] = 0; running_event = 0; } } goto NEXT_EVENT; } else if (event->do_event == _WM_do_meta_tempo) { // DEBUG // fprintf(stderr,"Tempo: %u\r\n",event->event_data.data); tempo = event->event_data.data.value & 0xffffff; samples_per_tick = _WM_GetSamplesPerTick(divisions, tempo); //DEBUG //fprintf(stderr,"\rDEBUG: div %i, tempo %i, bpm %f, pps %f, spd %f\r\n", divisions, tempo, bpm_f, pulses_per_second_f, samples_per_delta_f); (*out)[out_ofs++] = 0xff; (*out)[out_ofs++] = 0x51; (*out)[out_ofs++] = 0x03; (*out)[out_ofs++] = (tempo & 0xff0000) >> 16; (*out)[out_ofs++] = (tempo & 0xff00) >> 8; (*out)[out_ofs++] = (tempo & 0xff); } else if (event->do_event == _WM_do_meta_timesignature) { // DEBUG // fprintf(stderr,"Time Signature: %x\r\n",event->event_data.data); (*out)[out_ofs++] = 0xff; (*out)[out_ofs++] = 0x58; (*out)[out_ofs++] = 0x04; (*out)[out_ofs++] = (event->event_data.data.value & 0xff000000) >> 24; (*out)[out_ofs++] = (event->event_data.data.value & 0xff0000) >> 16; (*out)[out_ofs++] = (event->event_data.data.value & 0xff00) >> 8; (*out)[out_ofs++] = (event->event_data.data.value & 0xff); } else if (event->do_event == _WM_do_meta_keysignature) { // DEBUG // fprintf(stderr,"Key Signature: %x\r\n",event->event_data.data); (*out)[out_ofs++] = 0xff; (*out)[out_ofs++] = 0x59; (*out)[out_ofs++] = 0x02; (*out)[out_ofs++] = (event->event_data.data.value & 0xff00) >> 8; (*out)[out_ofs++] = (event->event_data.data.value & 0xff); } else if (event->do_event == _WM_do_meta_sequenceno) { // DEBUG // fprintf(stderr,"Sequence Number: %x\r\n",event->event_data.data); (*out)[out_ofs++] = 0xff; (*out)[out_ofs++] = 0x00; (*out)[out_ofs++] = 0x02; (*out)[out_ofs++] = (event->event_data.data.value & 0xff00) >> 8; (*out)[out_ofs++] = (event->event_data.data.value & 0xff); } else if (event->do_event == _WM_do_meta_channelprefix) { // DEBUG // fprintf(stderr,"Channel Prefix: %x\r\n",event->event_data.data); (*out)[out_ofs++] = 0xff; (*out)[out_ofs++] = 0x20; (*out)[out_ofs++] = 0x01; (*out)[out_ofs++] = (event->event_data.data.value & 0xff); } else if (event->do_event == _WM_do_meta_portprefix) { // DEBUG // fprintf(stderr,"Port Prefix: %x\r\n",event->event_data.data); (*out)[out_ofs++] = 0xff; (*out)[out_ofs++] = 0x21; (*out)[out_ofs++] = 0x01; (*out)[out_ofs++] = (event->event_data.data.value & 0xff); } else if (event->do_event == _WM_do_meta_smpteoffset) { // DEBUG // fprintf(stderr,"SMPTE Offset: %x\r\n",event->event_data.data); (*out)[out_ofs++] = 0xff; (*out)[out_ofs++] = 0x54; (*out)[out_ofs++] = 0x05; /* Remember because of the 5 bytes we stored it a little hacky. */ (*out)[out_ofs++] = (event->event_data.channel & 0xff); (*out)[out_ofs++] = (event->event_data.data.value & 0xff000000) >> 24; (*out)[out_ofs++] = (event->event_data.data.value & 0xff0000) >> 16; (*out)[out_ofs++] = (event->event_data.data.value & 0xff00) >> 8; (*out)[out_ofs++] = (event->event_data.data.value & 0xff); } else if (event->do_event == _WM_do_meta_text) { (*out)[out_ofs++] = 0xff; (*out)[out_ofs++] = 0x01; goto _WRITE_TEXT; } else if (event->do_event == _WM_do_meta_copyright) { (*out)[out_ofs++] = 0xff; (*out)[out_ofs++] = 0x02; goto _WRITE_TEXT; } else if (event->do_event == _WM_do_meta_trackname) { (*out)[out_ofs++] = 0xff; (*out)[out_ofs++] = 0x03; goto _WRITE_TEXT; } else if (event->do_event == _WM_do_meta_instrumentname) { (*out)[out_ofs++] = 0xff; (*out)[out_ofs++] = 0x04; goto _WRITE_TEXT; } else if (event->do_event == _WM_do_meta_lyric) { (*out)[out_ofs++] = 0xff; (*out)[out_ofs++] = 0x05; goto _WRITE_TEXT; } else if (event->do_event == _WM_do_meta_marker) { (*out)[out_ofs++] = 0xff; (*out)[out_ofs++] = 0x06; goto _WRITE_TEXT; } else if (event->do_event == _WM_do_meta_cuepoint) { (*out)[out_ofs++] = 0xff; (*out)[out_ofs++] = 0x07; _WRITE_TEXT: value = strlen(event->event_data.data.string); if (value > 0x0fffffff) (*out)[out_ofs++] = (((value >> 28) &0x7f) | 0x80); if (value > 0x1fffff) (*out)[out_ofs++] = (((value >> 21) &0x7f) | 0x80); if (value > 0x3fff) (*out)[out_ofs++] = (((value >> 14) & 0x7f) | 0x80); if (value > 0x7f) (*out)[out_ofs++] = (((value >> 7) & 0x7f) | 0x80); (*out)[out_ofs++] = (value & 0x7f); memcpy(&(*out)[out_ofs], event->event_data.data.string, value); out_ofs += value; } else { // DEBUG fprintf(stderr,"Unknown Event %.2x %.4x\n",event->event_data.channel, event->event_data.data.value); event++; continue; } value_f = (float)event->samples_to_next / samples_per_tick; value = (uint32_t) (value_f + 0.5f); //DEBUG //fprintf(stderr,"\rDEBUG: STN %i, SPD %f, Delta %i\r\n", event->samples_to_next, samples_per_delta_f, value); if (value > 0x0fffffff) (*out)[out_ofs++] = (((value >> 28) &0x7f) | 0x80); if (value > 0x1fffff) (*out)[out_ofs++] = (((value >> 21) &0x7f) | 0x80); if (value > 0x3fff) (*out)[out_ofs++] = (((value >> 14) & 0x7f) | 0x80); if (value > 0x7f) (*out)[out_ofs++] = (((value >> 7) & 0x7f) | 0x80); (*out)[out_ofs++] = (value & 0x7f); NEXT_EVENT: event++; } while (event->do_event != NULL); if ((_WM_MixerOptions & WM_MO_SAVEASTYPE0) || (!mdi->is_type2)) { /* Write end of track marker */ (*out)[out_ofs++] = 0xff; (*out)[out_ofs++] = 0x2f; (*out)[out_ofs++] = 0x00; /* Write last track size */ track_size = out_ofs - track_start; (*out)[track_start - 4] = (track_size >> 24) & 0xff; (*out)[track_start - 3] = (track_size >> 16) & 0xff; (*out)[track_start - 2] = (track_size >> 8) & 0xff; (*out)[track_start - 1] = track_size & 0xff; } /* write track count */ (*out)[10] = (track_count >> 8) & 0xff; (*out)[11] = track_count & 0xff; (*out) = (uint8_t *) realloc((*out), out_ofs); (*outsize) = out_ofs; return 0; } wildmidi-wildmidi-0.4.2/src/f_mus.c000066400000000000000000000333371315765416100172050ustar00rootroot00000000000000/* * mus_wm.c -- Midi Wavetable Processing library * * Copyright (C) WildMIDI Developers 2001-2016 * * This file is part of WildMIDI. * * WildMIDI is free software: you can redistribute and/or modify the player * under the terms of the GNU General Public License and you can redistribute * and/or modify the library under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either version 3 of * the licenses, or(at your option) any later version. * * WildMIDI 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 and * the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License and the * GNU Lesser General Public License along with WildMIDI. If not, see * . */ #include "config.h" #include #include #include #include #include "common.h" #include "wm_error.h" #include "wildmidi_lib.h" #include "internal_midi.h" #include "reverb.h" #include "f_mus.h" #ifdef DEBUG_MUS #define MUS_EVENT_DEBUG(dx,dy,dz) fprintf(stderr,"\r%s, 0x%.2x, 0x%.8x\n",dx,dy,dz) #else #define MUS_EVENT_DEBUG(dx,dy,dz) #endif /* Turns mus file data into an event stream. */ struct _mdi * _WM_ParseNewMus(uint8_t *mus_data, uint32_t mus_size) { uint8_t mus_hdr[] = { 'M', 'U', 'S', 0x1A }; uint32_t mus_song_ofs = 0; uint32_t mus_song_len = 0; uint16_t mus_ch_cnt1 = 0; uint16_t mus_ch_cnt2 = 0; uint16_t mus_no_instr = 0; uint32_t mus_data_ofs = 0; uint16_t * mus_mid_instr = NULL; uint16_t mus_instr_cnt = 0; struct _mdi *mus_mdi; uint32_t mus_divisions = 60; float tempo_f = 0; uint16_t mus_freq = 0; float samples_per_tick_f = 0; #define MUS_SZ 4 uint8_t mus_event[MUS_SZ] = { 0, 0, 0, 0 }; uint8_t mus_event_size = 0; uint8_t mus_prev_vol[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; uint32_t setup_ret = 0; uint32_t mus_ticks = 0; uint32_t sample_count = 0; float sample_count_f = 0; float sample_remainder = 0; uint16_t pitchbend_tmp = 0; if (mus_size < 17) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_MUS, "File too short", 0); return NULL; } if (memcmp(mus_data, mus_hdr, 4)) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_MUS, NULL, 0); return NULL; } // Get Song Length mus_song_len = (mus_data[5] << 8) | mus_data[4]; // Get Song Offset mus_song_ofs = (mus_data[7] << 8) | mus_data[6]; // Have yet to determine what this actually is. mus_ch_cnt1 = (mus_data[9] << 8) | mus_data[8]; mus_ch_cnt2 = (mus_data[11] << 8) | mus_data[10]; UNUSED(mus_ch_cnt1); UNUSED(mus_ch_cnt2); // Number of instruments defined mus_no_instr = (mus_data[13] << 8) | mus_data[12]; // Skip next 2 data bytes mus_data_ofs = 16; // Check that we have enough data to check the rest if (mus_size < (mus_data_ofs + (mus_no_instr << 1) + mus_song_len)) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_MUS, "File too short", 0); return NULL; } // Instrument definition mus_mid_instr = (uint16_t *) malloc(mus_no_instr * sizeof(uint16_t)); for (mus_instr_cnt = 0; mus_instr_cnt < mus_no_instr; mus_instr_cnt++) { mus_mid_instr[mus_instr_cnt] = (mus_data[mus_data_ofs + 1] << 8) | mus_data[mus_data_ofs]; mus_data_ofs += 2; } // make sure we are at song offset mus_data_ofs = mus_song_ofs; // do some calculations so we know how many samples per mus tick mus_freq = _cvt_get_option(WM_CO_FREQUENCY); if (mus_freq == 0) mus_freq = 140; if ((_WM_MixerOptions & WM_MO_ROUNDTEMPO)) { tempo_f = (float) (60000000 / mus_freq) + 0.5f; } else { tempo_f = (float) (60000000 / mus_freq); } samples_per_tick_f = _WM_GetSamplesPerTick(mus_divisions, (uint32_t)tempo_f); // initialise the mdi structure mus_mdi = _WM_initMDI(); _WM_midi_setup_divisions(mus_mdi, mus_divisions); _WM_midi_setup_tempo(mus_mdi, (uint32_t)tempo_f); // lets do this do { // Build the event _mus_build_event: #if 1 // Mus drums happen on channel 15, swap channel 9 & 15 // DEBUG MUS_EVENT_DEBUG("Before", mus_data[mus_data_ofs], 0); if ((mus_data[mus_data_ofs] & 0x0f) == 0x0f) { mus_data[mus_data_ofs] = (mus_data[mus_data_ofs] & 0xf0) | 0x09; } else if ((mus_data[mus_data_ofs] & 0x0f) == 0x09) { mus_data[mus_data_ofs] = (mus_data[mus_data_ofs] & 0xf0) | 0x0f; } // DEBUG MUS_EVENT_DEBUG("After", mus_data[mus_data_ofs], 0); #endif switch ((mus_data[mus_data_ofs] >> 4) & 0x07) { case 0: // Note Off mus_event_size = 2; mus_event[0] = 0x80 | (mus_data[mus_data_ofs] & 0x0f); mus_event[1] = mus_data[mus_data_ofs + 1]; mus_event[2] = 0; mus_event[3] = 0; break; case 1: // Note On if (mus_data[mus_data_ofs + 1] & 0x80) { mus_event_size = 3; mus_event[0] = 0x90 | (mus_data[mus_data_ofs] & 0x0f); mus_event[1] = mus_data[mus_data_ofs + 1] & 0x7f; mus_event[2] = mus_data[mus_data_ofs + 2]; mus_event[3] = 0; mus_prev_vol[mus_data[mus_data_ofs] & 0x0f] = mus_event[2]; } else { mus_event_size = 2; mus_event[0] = 0x90 | (mus_data[mus_data_ofs] & 0x0f); mus_event[1] = mus_data[mus_data_ofs + 1]; mus_event[2] = mus_prev_vol[mus_data[mus_data_ofs] & 0x0f]; mus_event[3] = 0; } break; case 2: // Pitch Bend mus_event_size = 2; mus_event[0] = 0xe0 | (mus_data[mus_data_ofs] & 0x0f); pitchbend_tmp = mus_data[mus_data_ofs + 1] << 6; mus_event[1] = pitchbend_tmp & 0x7f; mus_event[2] = (pitchbend_tmp >> 7) & 0x7f; mus_event[3] = 0; break; case 3: mus_event_size = 2; switch (mus_data[mus_data_ofs + 1]) { case 10: // All Sounds Off mus_event[0] = 0xb0 | (mus_data[mus_data_ofs] & 0x0f); mus_event[1] = 120; mus_event[2] = 0; mus_event[3] = 0; break; case 11: // All Notes Off mus_event[0] = 0xb0 | (mus_data[mus_data_ofs] & 0x0f); mus_event[1] = 123; mus_event[2] = 0; mus_event[3] = 0; break; case 12: // Mono (Not supported by WildMIDI) /* ************************** FIXME: Add dummy mdi event ************************** */ mus_event[0] = 0xb0 | (mus_data[mus_data_ofs] & 0x0f); mus_event[1] = 126; mus_event[2] = 0; mus_event[3] = 0; break; case 13: // Poly (Not supported by WildMIDI) /* ************************** FIXME: Add dummy mdi event ************************** */ mus_event[0] = 0xb0 | (mus_data[mus_data_ofs] & 0x0f); mus_event[1] = 127; mus_event[2] = 0; mus_event[3] = 0; break; case 14: // Reset All Controllers mus_event[0] = 0xb0 | (mus_data[mus_data_ofs] & 0x0f); mus_event[1] = 121; mus_event[2] = 0; mus_event[3] = 0; break; default: // Unsupported goto _mus_next_data; } break; case 4: mus_event_size = 3; switch (mus_data[mus_data_ofs + 1]) { case 0: // Patch /* ************************************************* FIXME: Check if setting is MIDI or MUS instrument ************************************************* */ mus_event[0] = 0xc0 | (mus_data[mus_data_ofs] & 0x0f); mus_event[1] = mus_data[mus_data_ofs + 2]; mus_event[2] = 0; mus_event[3] = 0; break; case 1: // Bank Select mus_event[0] = 0xb0 | (mus_data[mus_data_ofs] & 0x0f); mus_event[1] = 0; mus_event[2] = mus_data[mus_data_ofs + 2]; mus_event[3] = 0; break; case 2: // Modulation (Not supported by WildMidi) mus_event[0] = 0xb0 | (mus_data[mus_data_ofs] & 0x0f); mus_event[1] = 1; mus_event[2] = mus_data[mus_data_ofs + 2]; mus_event[3] = 0; break; case 3: // Volume mus_event[0] = 0xb0 | (mus_data[mus_data_ofs] & 0x0f); mus_event[1] = 7; mus_event[2] = mus_data[mus_data_ofs + 2]; mus_event[3] = 0; break; case 4: // Pan mus_event[0] = 0xb0 | (mus_data[mus_data_ofs] & 0x0f); mus_event[1] = 10; mus_event[2] = mus_data[mus_data_ofs + 2]; mus_event[3] = 0; break; case 5: // Expression mus_event[0] = 0xb0 | (mus_data[mus_data_ofs] & 0x0f); mus_event[1] = 11; mus_event[2] = mus_data[mus_data_ofs + 2]; mus_event[3] = 0; break; case 6: // Reverb (Not supported by WildMidi) mus_event[0] = 0xb0 | (mus_data[mus_data_ofs] & 0x0f); mus_event[1] = 91; mus_event[2] = mus_data[mus_data_ofs + 2]; mus_event[3] = 0; break; case 7: // Chorus (Not supported by WildMidi) mus_event[0] = 0xb0 | (mus_data[mus_data_ofs] & 0x0f); mus_event[1] = 93; mus_event[2] = mus_data[mus_data_ofs + 2]; mus_event[3] = 0; break; case 8: // Sustain mus_event[0] = 0xb0 | (mus_data[mus_data_ofs] & 0x0f); mus_event[1] = 64; mus_event[2] = mus_data[mus_data_ofs + 2]; mus_event[3] = 0; break; case 9: // Soft Peddle (Not supported by WildMidi) mus_event[0] = 0xb0 | (mus_data[mus_data_ofs] & 0x0f); mus_event[1] = 67; mus_event[2] = mus_data[mus_data_ofs + 2]; mus_event[3] = 0; break; default: // Unsupported goto _mus_next_data; } break; case 5: mus_event_size = 1; goto _mus_next_data; case 6: goto _mus_end_of_song; case 7: mus_event_size = 1; goto _mus_next_data; } setup_ret = _WM_SetupMidiEvent(mus_mdi, (uint8_t *)mus_event, MUS_SZ, 0); if (setup_ret == 0) { goto _mus_end; } _mus_next_data: if (!(mus_data[mus_data_ofs] & 0x80)) { mus_data_ofs += mus_event_size; goto _mus_build_event; } mus_data_ofs += mus_event_size; mus_ticks = 0; do { mus_ticks = (mus_ticks << 7) | (mus_data[mus_data_ofs++] & 0x7f); } while (mus_data[mus_data_ofs - 1] & 0x80); sample_count_f = ((float)mus_ticks * samples_per_tick_f) + sample_remainder; sample_count = (uint32_t)sample_count_f; sample_remainder = sample_count_f - (float)sample_count; mus_mdi->events[mus_mdi->event_count - 1].samples_to_next = sample_count; mus_mdi->extra_info.approx_total_samples += sample_count; } while (mus_data_ofs < mus_size); _mus_end_of_song: // Finalise mdi structure if ((mus_mdi->reverb = _WM_init_reverb(_WM_SampleRate, _WM_reverb_room_width, _WM_reverb_room_length, _WM_reverb_listen_posx, _WM_reverb_listen_posy)) == NULL) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to init reverb", 0); goto _mus_end; } _WM_midi_setup_endoftrack(mus_mdi); mus_mdi->extra_info.current_sample = 0; mus_mdi->current_event = &mus_mdi->events[0]; mus_mdi->samples_to_mix = 0; mus_mdi->note = NULL; _WM_ResetToStart(mus_mdi); _mus_end: free(mus_mid_instr); if (mus_mdi->reverb) return (mus_mdi); _WM_freeMDI(mus_mdi); return NULL; } wildmidi-wildmidi-0.4.2/src/f_xmidi.c000066400000000000000000000300321315765416100175000ustar00rootroot00000000000000/* * xmi.c -- Midi Wavetable Processing library * * Copyright (C) WildMIDI Developers 2001-2016 * * This file is part of WildMIDI. * * WildMIDI is free software: you can redistribute and/or modify the player * under the terms of the GNU General Public License and you can redistribute * and/or modify the library under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either version 3 of * the licenses, or(at your option) any later version. * * WildMIDI 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 and * the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License and the * GNU Lesser General Public License along with WildMIDI. If not, see * . */ #include "config.h" #include #include #include #include #include "common.h" #include "wm_error.h" #include "wildmidi_lib.h" #include "internal_midi.h" #include "reverb.h" #include "f_xmidi.h" struct _mdi *_WM_ParseNewXmi(uint8_t *xmi_data, uint32_t xmi_size) { struct _mdi *xmi_mdi = NULL; uint32_t xmi_tmpdata = 0; uint8_t xmi_formcnt = 0; uint32_t xmi_catlen = 0; uint32_t xmi_subformlen = 0; uint32_t i = 0; uint32_t j = 0; uint32_t xmi_evntlen = 0; uint32_t xmi_divisions = 60; uint32_t xmi_tempo = 500000; uint32_t xmi_sample_count = 0; float xmi_sample_count_f = 0; float xmi_sample_remainder = 0; float xmi_samples_per_delta_f = 0; uint8_t xmi_ch = 0; uint8_t xmi_note = 0; uint32_t *xmi_notelen = NULL; uint32_t setup_ret = 0; uint32_t xmi_delta = 0; uint32_t xmi_lowestdelta = 0; uint32_t xmi_evnt_cnt = 0; if (memcmp(xmi_data,"FORM",4)) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_XMI, NULL, 0); return NULL; } xmi_data += 4; xmi_size -= 4; // bytes until next entry xmi_tmpdata = *xmi_data++ << 24; xmi_tmpdata |= *xmi_data++ << 16; xmi_tmpdata |= *xmi_data++ << 8; xmi_tmpdata |= *xmi_data++; xmi_size -= 4; if (memcmp(xmi_data,"XDIRINFO",8)) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_XMI, NULL, 0); return NULL; } xmi_data += 8; xmi_size -= 8; /* 0x00 0x00 0x00 0x02 at this point are unknown so skip over them */ xmi_data += 4; xmi_size -= 4; // number of forms contained after this point xmi_formcnt = *xmi_data++; if (xmi_formcnt == 0) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_XMI, NULL, 0); return NULL; } xmi_size--; /* at this stage unsure if remaining data in this section means anything */ xmi_tmpdata -= 13; xmi_data += xmi_tmpdata; xmi_size -= xmi_tmpdata; /* FIXME: Check: may not even need to process CAT information */ if (memcmp(xmi_data,"CAT ",4)) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_XMI, NULL, 0); return NULL; } xmi_data += 4; xmi_size -= 4; xmi_catlen = *xmi_data++ << 24; xmi_catlen |= *xmi_data++ << 16; xmi_catlen |= *xmi_data++ << 8; xmi_catlen |= *xmi_data++; xmi_size -= 4; UNUSED(xmi_catlen); if (memcmp(xmi_data,"XMID",4)) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_XMI, NULL, 0); return NULL; } xmi_data += 4; xmi_size -= 4; xmi_mdi = _WM_initMDI(); _WM_midi_setup_divisions(xmi_mdi, xmi_divisions); _WM_midi_setup_tempo(xmi_mdi, xmi_tempo); xmi_samples_per_delta_f = _WM_GetSamplesPerTick(xmi_divisions, xmi_tempo); xmi_notelen = (uint32_t *) malloc(sizeof(uint32_t) * 16 * 128); memset(xmi_notelen, 0, (sizeof(uint32_t) * 16 * 128)); for (i = 0; i < xmi_formcnt; i++) { if (memcmp(xmi_data,"FORM",4)) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_XMI, NULL, 0); goto _xmi_end; } xmi_data += 4; xmi_size -= 4; xmi_subformlen = *xmi_data++ << 24; xmi_subformlen |= *xmi_data++ << 16; xmi_subformlen |= *xmi_data++ << 8; xmi_subformlen |= *xmi_data++; xmi_size -= 4; if (memcmp(xmi_data,"XMID",4)) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_XMI, NULL, 0); goto _xmi_end; } xmi_data += 4; xmi_size -= 4; xmi_subformlen -= 4; // Process Subform do { if (!memcmp(xmi_data,"TIMB",4)) { // Holds patch information // FIXME: May not be needed for playback as EVNT seems to // hold patch events xmi_data += 4; xmi_tmpdata = *xmi_data++ << 24; xmi_tmpdata |= *xmi_data++ << 16; xmi_tmpdata |= *xmi_data++ << 8; xmi_tmpdata |= *xmi_data++; xmi_data += xmi_tmpdata; xmi_size -= (8 + xmi_tmpdata); xmi_subformlen -= (8 + xmi_tmpdata); } else if (!memcmp(xmi_data,"RBRN",4)) { // Unknown what this is // FIXME: May not be needed for playback xmi_data += 4; xmi_tmpdata = *xmi_data++ << 24; xmi_tmpdata |= *xmi_data++ << 16; xmi_tmpdata |= *xmi_data++ << 8; xmi_tmpdata |= *xmi_data++; xmi_data += xmi_tmpdata; xmi_size -= (8 + xmi_tmpdata); xmi_subformlen -= (8 + xmi_tmpdata); } else if (!memcmp(xmi_data,"EVNT",4)) { // EVNT is where all the MIDI music information is stored xmi_data += 4; xmi_evnt_cnt++; xmi_evntlen = *xmi_data++ << 24; xmi_evntlen |= *xmi_data++ << 16; xmi_evntlen |= *xmi_data++ << 8; xmi_evntlen |= *xmi_data++; xmi_size -= 8; xmi_subformlen -= 8; do { if (*xmi_data < 0x80) { xmi_delta = 0; if (*xmi_data > 0x7f) { while (*xmi_data > 0x7f) { xmi_delta = (xmi_delta << 7) | (*xmi_data++ & 0x7f); xmi_size--; xmi_evntlen--; xmi_subformlen--; } } xmi_delta = (xmi_delta << 7) | (*xmi_data++ & 0x7f); xmi_size--; xmi_evntlen--; xmi_subformlen--; do { // determine delta till next event if ((xmi_lowestdelta != 0) && (xmi_lowestdelta <= xmi_delta)) { xmi_tmpdata = xmi_lowestdelta; } else { xmi_tmpdata = xmi_delta; } xmi_sample_count_f= (((float) xmi_tmpdata * xmi_samples_per_delta_f) + xmi_sample_remainder); xmi_sample_count = (uint32_t) xmi_sample_count_f; xmi_sample_remainder = xmi_sample_count_f - (float) xmi_sample_count; xmi_mdi->events[xmi_mdi->event_count - 1].samples_to_next += xmi_sample_count; xmi_mdi->extra_info.approx_total_samples += xmi_sample_count; xmi_lowestdelta = 0; // scan through on notes for (j = 0; j < (16*128); j++) { // only want notes that are on if (xmi_notelen[j] == 0) continue; // remove delta to next event from on notes xmi_notelen[j] -= xmi_tmpdata; // Check if we need to turn note off if (xmi_notelen[j] == 0) { xmi_ch = j / 128; xmi_note = j - (xmi_ch * 128); _WM_midi_setup_noteoff(xmi_mdi, xmi_ch, xmi_note, 0); } else { // otherwise work out new lowest delta if ((xmi_lowestdelta == 0) || (xmi_lowestdelta > xmi_notelen[j])) { xmi_lowestdelta = xmi_notelen[j]; } } } xmi_delta -= xmi_tmpdata; } while (xmi_delta); } else { if ((xmi_data[0] == 0xff) && (xmi_data[1] == 0x51) && (xmi_data[2] == 0x03)) { // Ignore tempo events setup_ret = 6; goto _XMI_Next_Event; } if ((setup_ret = _WM_SetupMidiEvent(xmi_mdi,xmi_data, xmi_size, 0)) == 0) { goto _xmi_end; } if ((*xmi_data & 0xf0) == 0x90) { // Note on has extra data stating note length xmi_ch = *xmi_data & 0x0f; xmi_note = xmi_data[1]; xmi_data += setup_ret; xmi_size -= setup_ret; xmi_evntlen -= setup_ret; xmi_subformlen -= setup_ret; xmi_tmpdata = 0; if (*xmi_data > 0x7f) { while (*xmi_data > 0x7f) { xmi_tmpdata = (xmi_tmpdata << 7) | (*xmi_data++ & 0x7f); xmi_size--; xmi_evntlen--; xmi_subformlen--; } } xmi_tmpdata = (xmi_tmpdata << 7) | (*xmi_data++ & 0x7f); xmi_size--; xmi_evntlen--; xmi_subformlen--; // store length xmi_notelen[128 * xmi_ch + xmi_note] = xmi_tmpdata; if ((xmi_tmpdata > 0) && ((xmi_lowestdelta == 0) || (xmi_tmpdata < xmi_lowestdelta))) { xmi_lowestdelta = xmi_tmpdata; } } else { _XMI_Next_Event: xmi_data += setup_ret; xmi_size -= setup_ret; xmi_evntlen -= setup_ret; xmi_subformlen -= setup_ret; } } } while (xmi_evntlen); } else { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_XMI, NULL, 0); goto _xmi_end; } } while (xmi_subformlen); } // Finalise mdi structure if ((xmi_mdi->reverb = _WM_init_reverb(_WM_SampleRate, _WM_reverb_room_width, _WM_reverb_room_length, _WM_reverb_listen_posx, _WM_reverb_listen_posy)) == NULL) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to init reverb", 0); goto _xmi_end; } xmi_mdi->extra_info.current_sample = 0; xmi_mdi->current_event = &xmi_mdi->events[0]; xmi_mdi->samples_to_mix = 0; xmi_mdi->note = NULL; /* More than 1 event form in XMI means treat as type 2 */ if (xmi_evnt_cnt > 1) { xmi_mdi->is_type2 = 1; } _WM_ResetToStart(xmi_mdi); _xmi_end: if (xmi_notelen) free(xmi_notelen); if (xmi_mdi->reverb) return (xmi_mdi); _WM_freeMDI(xmi_mdi); return NULL; } wildmidi-wildmidi-0.4.2/src/file_io.c000066400000000000000000000177331315765416100175040ustar00rootroot00000000000000/* * file_io.c -- file handling * * Copyright (C) WildMIDI Developers 2001-2016 * * This file is part of WildMIDI. * * WildMIDI is free software: you can redistribute and/or modify the player * under the terms of the GNU General Public License and you can redistribute * and/or modify the library under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either version 3 of * the licenses, or(at your option) any later version. * * WildMIDI 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 and * the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License and the * GNU Lesser General Public License along with WildMIDI. If not, see * . */ #include "config.h" #include #include #include #include #ifndef WILDMIDI_AMIGA #include #include #include #endif #ifdef _WIN32 #include #include #undef close #define close _close #undef open #define open _open #undef read #define read _read #elif defined(__DJGPP__) #include #include #include #elif defined(__OS2__) || defined(__EMX__) #define INCL_DOS #define INCL_DOSERRORS #include #include #include #elif defined(WILDMIDI_AMIGA) #include #include #else #include #include #include #endif #if !defined(O_BINARY) # if defined(_O_BINARY) # define O_BINARY _O_BINARY # else # define O_BINARY 0 # endif #endif #include "wm_error.h" #include "file_io.h" #ifdef WILDMIDI_AMIGA static long AMIGA_filesize (const char *path) { long size = -1; BPTR fh = Open((const STRPTR) path, MODE_OLDFILE); if (fh) { struct FileInfoBlock *fib = (struct FileInfoBlock*) AllocDosObject(DOS_FIB, NULL); if (fib != NULL) { if (ExamineFH(fh, fib)) size = fib->fib_Size; FreeDosObject(DOS_FIB, fib); } Close(fh); } return size; } static long AMIGA_read (BPTR fd, unsigned char *buf, long size) { long bytes_read = 0, result; while (bytes_read < size) { result = Read(fd, buf + bytes_read, size - bytes_read); if (result < 0) return result; if (result == 0) break; bytes_read += result; } return bytes_read; } static BPTR AMIGA_open (const char *path) { return Open((const STRPTR) path, MODE_OLDFILE); } static void AMIGA_close (BPTR fd) { Close(fd); } #endif void *_WM_BufferFile(const char *filename, uint32_t *size) { char *buffer_file = NULL; uint8_t *data; #ifdef __DJGPP__ int buffer_fd; struct ffblk f; #elif defined(_WIN32) int buffer_fd; HANDLE h; WIN32_FIND_DATAA wfd; #elif defined(__OS2__) || defined(__EMX__) int buffer_fd; HDIR h = HDIR_CREATE; FILEFINDBUF3 fb = {0}; ULONG cnt = 1; #elif defined(WILDMIDI_AMIGA) BPTR buffer_fd; long filsize; #elif defined(_3DS) || defined(GEKKO) int buffer_fd; struct stat buffer_stat; #else /* unix builds */ int buffer_fd; struct stat buffer_stat; /* for basedir of filename: */ const char *home = NULL; struct passwd *pwd_ent; char buffer_dir[1024]; if (strncmp(filename, "~/", 2) == 0) { pwd_ent = getpwuid(getuid()); if (pwd_ent) { home = pwd_ent->pw_dir; } else { home = getenv("HOME"); } if (home) { buffer_file = (char *) malloc(strlen(filename) + strlen(home) + 1); if (buffer_file == NULL) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, filename, errno); return NULL; } strcpy(buffer_file, home); strcat(buffer_file, filename + 1); } } else if (filename[0] != '/') { char* cwdresult = getcwd(buffer_dir, 1024); if (cwdresult != NULL) buffer_file = (char *) malloc(strlen(filename) + strlen(buffer_dir) + 2); if (buffer_file == NULL || cwdresult == NULL) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, filename, errno); return NULL; } strcpy(buffer_file, buffer_dir); if (buffer_dir[strlen(buffer_dir) - 1] != '/') strcat(buffer_file, "/"); strcat(buffer_file, filename); } #endif /* unix builds */ if (buffer_file == NULL) { buffer_file = (char *) malloc(strlen(filename) + 1); if (buffer_file == NULL) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, filename, errno); return NULL; } strcpy(buffer_file, filename); } #ifdef __DJGPP__ if (findfirst(buffer_file, &f, FA_ARCH | FA_RDONLY) != 0) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_STAT, filename, errno); free(buffer_file); return NULL; } *size = f.ff_fsize; #elif defined(_WIN32) if ((h = FindFirstFileA(buffer_file, &wfd)) == INVALID_HANDLE_VALUE) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_STAT, filename, ENOENT); free(buffer_file); return NULL; } FindClose(h); if (wfd.nFileSizeHigh != 0) /* too big */ *size = 0xffffffff; else *size = wfd.nFileSizeLow; #elif defined(__OS2__) || defined(__EMX__) if (DosFindFirst(buffer_file, &h, FILE_NORMAL, &fb, sizeof(fb), &cnt, FIL_STANDARD) != NO_ERROR) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_STAT, filename, ENOENT); free(buffer_file); return NULL; } DosFindClose(h); *size = fb.cbFile; #elif defined(WILDMIDI_AMIGA) if ((filsize = AMIGA_filesize(buffer_file)) < 0) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_STAT, filename, ENOENT /* do better!! */); free(buffer_file); return NULL; } *size = filsize; #else if (stat(buffer_file, &buffer_stat)) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_STAT, filename, errno); free(buffer_file); return NULL; } /* st_size can be sint32 or int64. */ if (buffer_stat.st_size > WM_MAXFILESIZE) /* too big */ *size = 0xffffffff; else *size = buffer_stat.st_size; #endif if (__builtin_expect((*size > WM_MAXFILESIZE), 0)) { /* don't bother loading suspiciously long files */ _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_LONGFIL, filename, 0); free(buffer_file); return NULL; } /* +1 needed for parsing text files without a newline at the end */ data = (uint8_t *) malloc(*size + 1); if (data == NULL) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, filename, errno); free(buffer_file); return NULL; } #if defined(WILDMIDI_AMIGA) if (!(buffer_fd = AMIGA_open(buffer_file))) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_OPEN, filename, ENOENT /* do better!! */); free(buffer_file); free(data); return NULL; } if (AMIGA_read(buffer_fd, data, filsize) != filsize) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_READ, filename, EIO /* do better!! */); free(buffer_file); free(data); AMIGA_close(buffer_fd); return NULL; } AMIGA_close(buffer_fd); free(buffer_file); #else if ((buffer_fd = open(buffer_file,(O_RDONLY | O_BINARY))) == -1) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_OPEN, filename, errno); free(buffer_file); free(data); return NULL; } if (read(buffer_fd, data, *size) != (long) *size) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_READ, filename, errno); free(buffer_file); free(data); close(buffer_fd); return NULL; } close(buffer_fd); free(buffer_file); #endif data[*size] = '\0'; return data; } wildmidi-wildmidi-0.4.2/src/getopt_long.c000066400000000000000000000347331315765416100204160ustar00rootroot00000000000000/* $OpenBSD: getopt_long.c,v 1.26 2013/06/08 22:47:56 millert Exp $ */ /* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */ /* * Copyright (c) 2002 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Sponsored in part by the Defense Advanced Research Projects * Agency (DARPA) and Air Force Research Laboratory, Air Force * Materiel Command, USAF, under agreement number F39502-99-1-0512. */ /*- * Copyright (c) 2000 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Dieter Baron and Thomas Klausner. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include "getopt_long.h" int opterr = 1; /* if error message should be printed */ int optind = 1; /* index into parent argv vector */ int optopt = '?'; /* character checked for validity */ int optreset; /* reset getopt */ char *optarg; /* argument associated with option */ #define PRINT_ERROR ((opterr) && (*options != ':')) #define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */ #define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */ #define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */ /* return values */ #define BADCH (int)'?' #define BADARG ((*options == ':') ? (int)':' : (int)'?') #define INORDER (int)1 #define EMSG "" static int getopt_internal(int, char * const *, const char *, const struct option *, int *, int); static int parse_long_options(char * const *, const char *, const struct option *, int *, int, int); static int gcd(int, int); static void permute_args(int, int, int, char * const *); static char *place = EMSG; /* option letter processing */ /* XXX: set optreset to 1 rather than these two */ static int nonopt_start = -1; /* first non option argument (for permute) */ static int nonopt_end = -1; /* first option after non options (for permute) */ /* Error messages */ static const char recargchar[] = "option requires an argument -- %c"; static const char recargstring[] = "option requires an argument -- %s"; static const char ambig[] = "ambiguous option -- %.*s"; static const char noarg[] = "option doesn't take an argument -- %.*s"; static const char illoptchar[] = "unknown option -- %c"; static const char illoptstring[] = "unknown option -- %s"; /* * Compute the greatest common divisor of a and b. */ static int gcd(int a, int b) { int c; c = a % b; while (c != 0) { a = b; b = c; c = a % b; } return (b); } /* * Exchange the block from nonopt_start to nonopt_end with the block * from nonopt_end to opt_end (keeping the same order of arguments * in each block). */ static void permute_args(int panonopt_start, int panonopt_end, int opt_end, char * const *nargv) { int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; char *swap; /* * compute lengths of blocks and number and size of cycles */ nnonopts = panonopt_end - panonopt_start; nopts = opt_end - panonopt_end; ncycle = gcd(nnonopts, nopts); cyclelen = (opt_end - panonopt_start) / ncycle; for (i = 0; i < ncycle; i++) { cstart = panonopt_end+i; pos = cstart; for (j = 0; j < cyclelen; j++) { if (pos >= panonopt_end) pos -= nnonopts; else pos += nopts; swap = nargv[pos]; /* LINTED const cast */ ((char **) nargv)[pos] = nargv[cstart]; /* LINTED const cast */ ((char **)nargv)[cstart] = swap; } } } /* * parse_long_options -- * Parse long options in argc/argv argument vector. * Returns -1 if short_too is set and the option does not match long_options. */ static int parse_long_options(char * const *nargv, const char *options, const struct option *long_options, int *idx, int short_too, int flags) { char *current_argv, *has_equal; size_t current_argv_len; int i, match, exact_match, second_partial_match; current_argv = place; match = -1; exact_match = 0; second_partial_match = 0; optind++; if ((has_equal = strchr(current_argv, '=')) != NULL) { /* argument found (--option=arg) */ current_argv_len = has_equal - current_argv; has_equal++; } else current_argv_len = strlen(current_argv); for (i = 0; long_options[i].name; i++) { /* find matching long option */ if (strncmp(current_argv, long_options[i].name, current_argv_len)) continue; if (strlen(long_options[i].name) == current_argv_len) { /* exact match */ match = i; exact_match = 1; break; } /* * If this is a known short option, don't allow * a partial match of a single character. */ if (short_too && current_argv_len == 1) continue; if (match == -1) /* first partial match */ match = i; else if ((flags & FLAG_LONGONLY) || long_options[i].has_arg != long_options[match].has_arg || long_options[i].flag != long_options[match].flag || long_options[i].val != long_options[match].val) second_partial_match = 1; } if (!exact_match && second_partial_match) { /* ambiguous abbreviation */ if (PRINT_ERROR) fprintf(stderr, ambig, (int)current_argv_len, current_argv); optopt = 0; return (BADCH); } if (match != -1) { /* option found */ if (long_options[match].has_arg == no_argument && has_equal) { if (PRINT_ERROR) fprintf(stderr, noarg, (int)current_argv_len, current_argv); /* * XXX: GNU sets optopt to val regardless of flag */ if (long_options[match].flag == NULL) optopt = long_options[match].val; else optopt = 0; return (BADARG); } if (long_options[match].has_arg == required_argument || long_options[match].has_arg == optional_argument) { if (has_equal) optarg = has_equal; else if (long_options[match].has_arg == required_argument) { /* * optional argument doesn't use next nargv */ optarg = nargv[optind++]; } } if ((long_options[match].has_arg == required_argument) && (optarg == NULL)) { /* * Missing argument; leading ':' indicates no error * should be generated. */ if (PRINT_ERROR) fprintf(stderr, recargstring, current_argv); /* * XXX: GNU sets optopt to val regardless of flag */ if (long_options[match].flag == NULL) optopt = long_options[match].val; else optopt = 0; --optind; return (BADARG); } } else { /* unknown option */ if (short_too) { --optind; return (-1); } if (PRINT_ERROR) fprintf(stderr, illoptstring, current_argv); optopt = 0; return (BADCH); } if (idx) *idx = match; if (long_options[match].flag) { *long_options[match].flag = long_options[match].val; return (0); } else return (long_options[match].val); } /* * getopt_internal -- * Parse argc/argv argument vector. Called by user level routines. */ static int getopt_internal(int nargc, char * const *nargv, const char *options, const struct option *long_options, int *idx, int flags) { char *oli; /* option letter list index */ int optchar, short_too; static int posixly_correct = -1; if (options == NULL) return (-1); /* * XXX Some GNU programs (like cvs) set optind to 0 instead of * XXX using optreset. Work around this braindamage. */ if (optind == 0) optind = optreset = 1; /* * Disable GNU extensions if POSIXLY_CORRECT is set or options * string begins with a '+'. */ if (posixly_correct == -1 || optreset) posixly_correct = (getenv("POSIXLY_CORRECT") != NULL); if (*options == '-') flags |= FLAG_ALLARGS; else if (posixly_correct || *options == '+') flags &= ~FLAG_PERMUTE; if (*options == '+' || *options == '-') options++; optarg = NULL; if (optreset) nonopt_start = nonopt_end = -1; start: if (optreset || !*place) { /* update scanning pointer */ optreset = 0; if (optind >= nargc) { /* end of argument vector */ place = EMSG; if (nonopt_end != -1) { /* do permutation, if we have to */ permute_args(nonopt_start, nonopt_end, optind, nargv); optind -= nonopt_end - nonopt_start; } else if (nonopt_start != -1) { /* * If we skipped non-options, set optind * to the first of them. */ optind = nonopt_start; } nonopt_start = nonopt_end = -1; return (-1); } if (*(place = nargv[optind]) != '-' || (place[1] == '\0' && strchr(options, '-') == NULL)) { place = EMSG; /* found non-option */ if (flags & FLAG_ALLARGS) { /* * GNU extension: * return non-option as argument to option 1 */ optarg = nargv[optind++]; return (INORDER); } if (!(flags & FLAG_PERMUTE)) { /* * If no permutation wanted, stop parsing * at first non-option. */ return (-1); } /* do permutation */ if (nonopt_start == -1) nonopt_start = optind; else if (nonopt_end != -1) { permute_args(nonopt_start, nonopt_end, optind, nargv); nonopt_start = optind - (nonopt_end - nonopt_start); nonopt_end = -1; } optind++; /* process next argument */ goto start; } if (nonopt_start != -1 && nonopt_end == -1) nonopt_end = optind; /* * If we have "-" do nothing, if "--" we are done. */ if (place[1] != '\0' && *++place == '-' && place[1] == '\0') { optind++; place = EMSG; /* * We found an option (--), so if we skipped * non-options, we have to permute. */ if (nonopt_end != -1) { permute_args(nonopt_start, nonopt_end, optind, nargv); optind -= nonopt_end - nonopt_start; } nonopt_start = nonopt_end = -1; return (-1); } } /* * Check long options if: * 1) we were passed some * 2) the arg is not just "-" * 3) either the arg starts with -- we are getopt_long_only() */ if (long_options != NULL && place != nargv[optind] && (*place == '-' || (flags & FLAG_LONGONLY))) { short_too = 0; if (*place == '-') place++; /* --foo long option */ else if (*place != ':' && strchr(options, *place) != NULL) short_too = 1; /* could be short option too */ optchar = parse_long_options(nargv, options, long_options, idx, short_too, flags); if (optchar != -1) { place = EMSG; return (optchar); } } if ((optchar = (int)*place++) == (int)':' || (optchar == (int)'-' && *place != '\0') || (oli = strchr(options, optchar)) == NULL) { /* * If the user specified "-" and '-' isn't listed in * options, return -1 (non-option) as per POSIX. * Otherwise, it is an unknown option character (or ':'). */ if (optchar == (int)'-' && *place == '\0') return (-1); if (!*place) ++optind; if (PRINT_ERROR) fprintf(stderr, illoptchar, optchar); optopt = optchar; return (BADCH); } if (long_options != NULL && optchar == 'W' && oli[1] == ';') { /* -W long-option */ if (*place) /* no space */ /* NOTHING */; else if (++optind >= nargc) { /* no arg */ place = EMSG; if (PRINT_ERROR) fprintf(stderr, recargchar, optchar); optopt = optchar; return (BADARG); } else /* white space */ place = nargv[optind]; optchar = parse_long_options(nargv, options, long_options, idx, 0, flags); place = EMSG; return (optchar); } if (*++oli != ':') { /* doesn't take argument */ if (!*place) ++optind; } else { /* takes (optional) argument */ optarg = NULL; if (*place) /* no white space */ optarg = place; else if (oli[1] != ':') { /* arg not optional */ if (++optind >= nargc) { /* no arg */ place = EMSG; if (PRINT_ERROR) fprintf(stderr, recargchar, optchar); optopt = optchar; return (BADARG); } else optarg = nargv[optind]; } place = EMSG; ++optind; } /* dump back option letter */ return (optchar); } /* * getopt -- * Parse argc/argv argument vector. * * [eventually this will replace the BSD getopt] */ int getopt(int nargc, char * const *nargv, const char *options) { /* * We don't pass FLAG_PERMUTE to getopt_internal() since * the BSD getopt(3) (unlike GNU) has never done this. * * Furthermore, since many privileged programs call getopt() * before dropping privileges it makes sense to keep things * as simple (and bug-free) as possible. */ return (getopt_internal(nargc, nargv, options, NULL, NULL, 0)); } /* * getopt_long -- * Parse argc/argv argument vector. */ int getopt_long(int nargc, char * const *nargv, const char *options, const struct option *long_options, int *idx) { return (getopt_internal(nargc, nargv, options, long_options, idx, FLAG_PERMUTE)); } /* * getopt_long_only -- * Parse argc/argv argument vector. */ int getopt_long_only(int nargc, char * const *nargv, const char *options, const struct option *long_options, int *idx) { return (getopt_internal(nargc, nargv, options, long_options, idx, FLAG_PERMUTE|FLAG_LONGONLY)); } wildmidi-wildmidi-0.4.2/src/gus_pat.c000066400000000000000000001063101315765416100175260ustar00rootroot00000000000000/* * gus_pat.c -- Midi Wavetable Processing library * * Copyright (C) WildMIDI Developers 2001-2016 * * This file is part of WildMIDI. * * WildMIDI is free software: you can redistribute and/or modify the player * under the terms of the GNU General Public License and you can redistribute * and/or modify the library under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either version 3 of * the licenses, or(at your option) any later version. * * WildMIDI 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 and * the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License and the * GNU Lesser General Public License along with WildMIDI. If not, see * . */ #include "config.h" #include #include #include #include #include #include "gus_pat.h" #include "common.h" #include "wm_error.h" #include "file_io.h" #include "sample.h" //#define DEBUG_GUSPAT #ifdef DEBUG_GUSPAT #define GUSPAT_FILENAME_DEBUG(dx) fprintf(stderr,"\r%s\n",dx) #define GUSPAT_INT_DEBUG(dx,dy) fprintf(stderr,"\r%s: %i\n",dx,dy) #define GUSPAT_FLOAT_DEBUG(dx,dy) fprintf(stderr,"\r%s: %f\n",dx,dy) #define GUSPAT_START_DEBUG() fprintf(stderr,"\r") #define GUSPAT_MODE_DEBUG(dx,dy,dz) if (dx & dy) fprintf(stderr,"%s",dz) #define GUSPAT_END_DEBUG() fprintf(stderr,"\n") #else #define GUSPAT_FILENAME_DEBUG(dx) #define GUSPAT_INT_DEBUG(dx,dy) #define GUSPAT_FLOAT_DEBUG(dx,dy) #define GUSPAT_START_DEBUG() #define GUSPAT_MODE_DEBUG(dx,dy,dz) #define GUSPAT_END_DEBUG() #endif /* sample data conversion functions * convert data to signed shorts */ /* 8bit signed */ static int convert_8s(uint8_t *data, struct _sample *gus_sample) { uint8_t *read_data = data; uint8_t *read_end = data + gus_sample->data_length; int16_t *write_data = NULL; SAMPLE_CONVERT_DEBUG(__FUNCTION__); gus_sample->data = (int16_t *) calloc((gus_sample->data_length + 2), sizeof(int16_t)); if (__builtin_expect((gus_sample->data != NULL), 1)) { write_data = gus_sample->data; do { *write_data++ = (*read_data++) << 8; } while (read_data != read_end); return 0; } _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, 0, "calloc failed", errno); return -1; } /* 8bit signed ping pong */ static int convert_8sp(uint8_t *data, struct _sample *gus_sample) { uint32_t loop_length = gus_sample->loop_end - gus_sample->loop_start; uint32_t dloop_length = loop_length * 2; uint32_t new_length = gus_sample->data_length + dloop_length; uint8_t *read_data = data; uint8_t *read_end = data + gus_sample->loop_start; int16_t *write_data = NULL; int16_t *write_data_a = NULL; int16_t *write_data_b = NULL; SAMPLE_CONVERT_DEBUG(__FUNCTION__); gus_sample->data = (int16_t *) calloc((new_length + 2), sizeof(int16_t)); if (__builtin_expect((gus_sample->data != NULL), 1)) { write_data = gus_sample->data; do { *write_data++ = (*read_data++) << 8; } while (read_data != read_end); *write_data = (*read_data++ << 8); write_data_a = write_data + dloop_length; *write_data_a-- = *write_data; write_data++; write_data_b = write_data + dloop_length; read_end = data + gus_sample->loop_end; do { *write_data = (*read_data++) << 8; *write_data_a-- = *write_data; *write_data_b++ = *write_data; write_data++; } while (read_data != read_end); *write_data = (*read_data++ << 8); *write_data_b++ = *write_data; read_end = data + gus_sample->data_length; if (__builtin_expect((read_data != read_end), 1)) { do { *write_data_b++ = (*read_data++) << 8; } while (read_data != read_end); } gus_sample->loop_start += loop_length; gus_sample->loop_end += dloop_length; gus_sample->data_length = new_length; gus_sample->modes ^= SAMPLE_PINGPONG; return 0; } _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); return -1; } /* 8bit signed reverse */ static int convert_8sr(uint8_t *data, struct _sample *gus_sample) { uint8_t *read_data = data; uint8_t *read_end = data + gus_sample->data_length; int16_t *write_data = NULL; uint32_t tmp_loop = 0; SAMPLE_CONVERT_DEBUG(__FUNCTION__); gus_sample->data = (int16_t *) calloc((gus_sample->data_length + 2), sizeof(int16_t)); if (__builtin_expect((gus_sample->data != NULL), 1)) { write_data = gus_sample->data + gus_sample->data_length - 1; do { *write_data-- = (*read_data++) << 8; } while (read_data != read_end); tmp_loop = gus_sample->loop_end; gus_sample->loop_end = gus_sample->data_length - gus_sample->loop_start; gus_sample->loop_start = gus_sample->data_length - tmp_loop; gus_sample->loop_fraction = ((gus_sample->loop_fraction & 0x0f) << 4) | ((gus_sample->loop_fraction & 0xf0) >> 4); gus_sample->modes ^= SAMPLE_REVERSE; return 0; } _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); return -1; } /* 8bit signed reverse ping pong */ static int convert_8srp(uint8_t *data, struct _sample *gus_sample) { uint32_t loop_length = gus_sample->loop_end - gus_sample->loop_start; uint32_t dloop_length = loop_length * 2; uint32_t new_length = gus_sample->data_length + dloop_length; uint8_t *read_data = data + gus_sample->data_length - 1; uint8_t *read_end = data + gus_sample->loop_end; int16_t *write_data = NULL; int16_t *write_data_a = NULL; int16_t *write_data_b = NULL; SAMPLE_CONVERT_DEBUG(__FUNCTION__); gus_sample->data = (int16_t *) calloc((new_length + 2), sizeof(int16_t)); if (__builtin_expect((gus_sample->data != NULL), 1)) { write_data = gus_sample->data; do { *write_data++ = (*read_data--) << 8; } while (read_data != read_end); *write_data = (*read_data-- << 8); write_data_a = write_data + dloop_length; *write_data_a-- = *write_data; write_data++; write_data_b = write_data + dloop_length; read_end = data + gus_sample->loop_start; do { *write_data = (*read_data--) << 8; *write_data_a-- = *write_data; *write_data_b++ = *write_data; write_data++; } while (read_data != read_end); *write_data = (*read_data-- << 8); *write_data_b++ = *write_data; read_end = data - 1; do { *write_data_b++ = (*read_data--) << 8; write_data_b++; } while (read_data != read_end); gus_sample->loop_start += loop_length; gus_sample->loop_end += dloop_length; gus_sample->data_length = new_length; gus_sample->modes ^= SAMPLE_PINGPONG | SAMPLE_REVERSE; return 0; } _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); return -1; } /* 8bit unsigned */ static int convert_8u(uint8_t *data, struct _sample *gus_sample) { uint8_t *read_data = data; uint8_t *read_end = data + gus_sample->data_length; int16_t *write_data = NULL; SAMPLE_CONVERT_DEBUG(__FUNCTION__); gus_sample->data = (int16_t *) calloc((gus_sample->data_length + 2), sizeof(int16_t)); if (__builtin_expect((gus_sample->data != NULL), 1)) { write_data = gus_sample->data; do { *write_data++ = ((*read_data++) ^ 0x80) << 8; } while (read_data != read_end); gus_sample->modes ^= SAMPLE_UNSIGNED; return 0; } _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); return -1; } /* 8bit unsigned ping pong */ static int convert_8up(uint8_t *data, struct _sample *gus_sample) { uint32_t loop_length = gus_sample->loop_end - gus_sample->loop_start; uint32_t dloop_length = loop_length * 2; uint32_t new_length = gus_sample->data_length + dloop_length; uint8_t *read_data = data; uint8_t *read_end = data + gus_sample->loop_start; int16_t *write_data = NULL; int16_t *write_data_a = NULL; int16_t *write_data_b = NULL; SAMPLE_CONVERT_DEBUG(__FUNCTION__); gus_sample->data = (int16_t *) calloc((new_length + 2), sizeof(int16_t)); if (__builtin_expect((gus_sample->data != NULL), 1)) { write_data = gus_sample->data; do { *write_data++ = ((*read_data++) ^ 0x80) << 8; } while (read_data != read_end); *write_data = ((*read_data++) ^ 0x80) << 8; write_data_a = write_data + dloop_length; *write_data_a-- = *write_data; write_data++; write_data_b = write_data + dloop_length; read_end = data + gus_sample->loop_end; do { *write_data = ((*read_data++) ^ 0x80) << 8; *write_data_a-- = *write_data; *write_data_b++ = *write_data; write_data++; } while (read_data != read_end); *write_data = ((*read_data++) ^ 0x80) << 8; *write_data_b++ = *write_data; read_end = data + gus_sample->data_length; if (__builtin_expect((read_data != read_end), 1)) { do { *write_data_b++ = ((*read_data++) ^ 0x80) << 8; } while (read_data != read_end); } gus_sample->loop_start += loop_length; gus_sample->loop_end += dloop_length; gus_sample->data_length = new_length; gus_sample->modes ^= SAMPLE_PINGPONG | SAMPLE_UNSIGNED; return 0; } _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); return -1; } /* 8bit unsigned reverse */ static int convert_8ur(uint8_t *data, struct _sample *gus_sample) { uint8_t *read_data = data; uint8_t *read_end = data + gus_sample->data_length; int16_t *write_data = NULL; uint32_t tmp_loop = 0; SAMPLE_CONVERT_DEBUG(__FUNCTION__); gus_sample->data = (int16_t *) calloc((gus_sample->data_length + 2), sizeof(int16_t)); if (__builtin_expect((gus_sample->data != NULL), 1)) { write_data = gus_sample->data + gus_sample->data_length - 1; do { *write_data-- = ((*read_data++) ^ 0x80) << 8; } while (read_data != read_end); tmp_loop = gus_sample->loop_end; gus_sample->loop_end = gus_sample->data_length - gus_sample->loop_start; gus_sample->loop_start = gus_sample->data_length - tmp_loop; gus_sample->loop_fraction = ((gus_sample->loop_fraction & 0x0f) << 4) | ((gus_sample->loop_fraction & 0xf0) >> 4); gus_sample->modes ^= SAMPLE_REVERSE | SAMPLE_UNSIGNED; return 0; } _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); return -1; } /* 8bit unsigned reverse ping pong */ static int convert_8urp(uint8_t *data, struct _sample *gus_sample) { uint32_t loop_length = gus_sample->loop_end - gus_sample->loop_start; uint32_t dloop_length = loop_length * 2; uint32_t new_length = gus_sample->data_length + dloop_length; uint8_t *read_data = data + gus_sample->data_length - 1; uint8_t *read_end = data + gus_sample->loop_end; int16_t *write_data = NULL; int16_t *write_data_a = NULL; int16_t *write_data_b = NULL; SAMPLE_CONVERT_DEBUG(__FUNCTION__); gus_sample->data = (int16_t *) calloc((new_length + 2), sizeof(int16_t)); if (__builtin_expect((gus_sample->data != NULL), 1)) { write_data = gus_sample->data; do { *write_data++ = ((*read_data--) ^ 0x80) << 8; } while (read_data != read_end); *write_data = ((*read_data--) ^ 0x80) << 8; write_data_a = write_data + dloop_length; *write_data_a-- = *write_data; write_data++; write_data_b = write_data + dloop_length; read_end = data + gus_sample->loop_start; do { *write_data = ((*read_data--) ^ 0x80) << 8; *write_data_a-- = *write_data; *write_data_b++ = *write_data; write_data++; } while (read_data != read_end); *write_data = ((*read_data--) ^ 0x80) << 8; *write_data_b++ = *write_data; read_end = data - 1; do { *write_data_b++ = ((*read_data--) ^ 0x80) << 8; } while (read_data != read_end); gus_sample->loop_start += loop_length; gus_sample->loop_end += dloop_length; gus_sample->data_length = new_length; gus_sample->modes ^= SAMPLE_PINGPONG | SAMPLE_REVERSE | SAMPLE_UNSIGNED; return 0; } _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); return -1; } /* 16bit signed */ static int convert_16s(uint8_t *data, struct _sample *gus_sample) { uint8_t *read_data = data; uint8_t *read_end = data + gus_sample->data_length; int16_t *write_data = NULL; SAMPLE_CONVERT_DEBUG(__FUNCTION__); gus_sample->data = (int16_t *) calloc(((gus_sample->data_length >> 1) + 2), sizeof(int16_t)); if (__builtin_expect((gus_sample->data != NULL), 1)) { write_data = gus_sample->data; do { *write_data = *read_data++; *write_data++ |= (*read_data++) << 8; } while (read_data < read_end); gus_sample->loop_start >>= 1; gus_sample->loop_end >>= 1; gus_sample->data_length >>= 1; return 0; } _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); return -1; } /* 16bit signed ping pong */ static int convert_16sp(uint8_t *data, struct _sample *gus_sample) { uint32_t loop_length = gus_sample->loop_end - gus_sample->loop_start; uint32_t dloop_length = loop_length * 2; uint32_t new_length = gus_sample->data_length + dloop_length; uint8_t *read_data = data; uint8_t *read_end = data + gus_sample->loop_start; int16_t *write_data = NULL; int16_t *write_data_a = NULL; int16_t *write_data_b = NULL; SAMPLE_CONVERT_DEBUG(__FUNCTION__); gus_sample->data = (int16_t *) calloc(((new_length >> 1) + 2), sizeof(int16_t)); if (__builtin_expect((gus_sample->data != NULL), 1)) { write_data = gus_sample->data; do { *write_data = (*read_data++); *write_data++ |= (*read_data++) << 8; } while (read_data < read_end); *write_data = (*read_data++); *write_data |= (*read_data++) << 8; write_data_a = write_data + (dloop_length >> 1); *write_data_a-- = *write_data; write_data++; write_data_b = write_data + (dloop_length >> 1); read_end = data + gus_sample->loop_end; do { *write_data = (*read_data++); *write_data |= (*read_data++) << 8; *write_data_a-- = *write_data; *write_data_b++ = *write_data; write_data++; } while (read_data < read_end); *write_data = *(read_data++); *write_data |= (*read_data++) << 8; *write_data_b++ = *write_data; read_end = data + gus_sample->data_length; if (__builtin_expect((read_data != read_end), 1)) { do { *write_data_b = *(read_data++); *write_data_b++ |= (*read_data++) << 8; } while (read_data < read_end); } gus_sample->loop_start += loop_length; gus_sample->loop_end += dloop_length; gus_sample->data_length = new_length; gus_sample->modes ^= SAMPLE_PINGPONG; gus_sample->loop_start >>= 1; gus_sample->loop_end >>= 1; gus_sample->data_length >>= 1; return 0; } _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); return -1; } /* 16bit signed reverse */ static int convert_16sr(uint8_t *data, struct _sample *gus_sample) { uint8_t *read_data = data; uint8_t *read_end = data + gus_sample->data_length; int16_t *write_data = NULL; uint32_t tmp_loop = 0; SAMPLE_CONVERT_DEBUG(__FUNCTION__); gus_sample->data = (int16_t *) calloc(((gus_sample->data_length >> 1) + 2), sizeof(int16_t)); if (__builtin_expect((gus_sample->data != NULL), 1)) { write_data = gus_sample->data + (gus_sample->data_length >> 1) - 1; do { *write_data = *read_data++; *write_data-- |= (*read_data++) << 8; } while (read_data < read_end); tmp_loop = gus_sample->loop_end; gus_sample->loop_end = gus_sample->data_length - gus_sample->loop_start; gus_sample->loop_start = gus_sample->data_length - tmp_loop; gus_sample->loop_fraction = ((gus_sample->loop_fraction & 0x0f) << 4) | ((gus_sample->loop_fraction & 0xf0) >> 4); gus_sample->loop_start >>= 1; gus_sample->loop_end >>= 1; gus_sample->data_length >>= 1; gus_sample->modes ^= SAMPLE_REVERSE; return 0; } _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); return -1; } /* 16bit signed reverse ping pong */ static int convert_16srp(uint8_t *data, struct _sample *gus_sample) { uint32_t loop_length = gus_sample->loop_end - gus_sample->loop_start; uint32_t dloop_length = loop_length * 2; uint32_t new_length = gus_sample->data_length + dloop_length; uint8_t *read_data = data + gus_sample->data_length - 1; uint8_t *read_end = data + gus_sample->loop_end; int16_t *write_data = NULL; int16_t *write_data_a = NULL; int16_t *write_data_b = NULL; SAMPLE_CONVERT_DEBUG(__FUNCTION__); gus_sample->data = (int16_t *) calloc(((new_length >> 1) + 2), sizeof(int16_t)); if (__builtin_expect((gus_sample->data != NULL), 1)) { write_data = gus_sample->data; do { *write_data = (*read_data--) << 8; *write_data++ |= *read_data--; } while (read_data < read_end); *write_data = (*read_data-- << 8); *write_data |= *read_data--; write_data_a = write_data + (dloop_length >> 1); *write_data_a-- = *write_data; write_data++; write_data_b = write_data + (dloop_length >> 1); read_end = data + gus_sample->loop_start; do { *write_data = (*read_data--) << 8; *write_data |= *read_data--; *write_data_a-- = *write_data; *write_data_b++ = *write_data; write_data++; } while (read_data < read_end); *write_data = ((*read_data--) << 8); *write_data |= *read_data--; *write_data_b++ = *write_data; read_end = data - 1; do { *write_data_b = (*read_data--) << 8; *write_data_b++ |= *read_data--; } while (read_data < read_end); gus_sample->loop_start += loop_length; gus_sample->loop_end += dloop_length; gus_sample->data_length = new_length; gus_sample->modes ^= SAMPLE_PINGPONG | SAMPLE_REVERSE; return 0; } _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); return -1; } /* 16bit unsigned */ static int convert_16u(uint8_t *data, struct _sample *gus_sample) { uint8_t *read_data = data; uint8_t *read_end = data + gus_sample->data_length; int16_t *write_data = NULL; SAMPLE_CONVERT_DEBUG(__FUNCTION__); gus_sample->data = (int16_t *) calloc(((gus_sample->data_length >> 1) + 2), sizeof(int16_t)); if (__builtin_expect((gus_sample->data != NULL), 1)) { write_data = gus_sample->data; do { *write_data = *read_data++; *write_data++ |= ((*read_data++) ^ 0x80) << 8; } while (read_data < read_end); gus_sample->loop_start >>= 1; gus_sample->loop_end >>= 1; gus_sample->data_length >>= 1; gus_sample->modes ^= SAMPLE_UNSIGNED; return 0; } _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); return -1; } /* 16bit unsigned ping pong */ static int convert_16up(uint8_t *data, struct _sample *gus_sample) { uint32_t loop_length = gus_sample->loop_end - gus_sample->loop_start; uint32_t dloop_length = loop_length * 2; uint32_t new_length = gus_sample->data_length + dloop_length; uint8_t *read_data = data; uint8_t *read_end = data + gus_sample->loop_start; int16_t *write_data = NULL; int16_t *write_data_a = NULL; int16_t *write_data_b = NULL; SAMPLE_CONVERT_DEBUG(__FUNCTION__); gus_sample->data = (int16_t *) calloc(((new_length >> 1) + 2), sizeof(int16_t)); if (__builtin_expect((gus_sample->data != NULL), 1)) { write_data = gus_sample->data; do { *write_data = (*read_data++); *write_data++ |= ((*read_data++) ^ 0x80) << 8; } while (read_data < read_end); *write_data = (*read_data++); *write_data |= ((*read_data++) ^ 0x80) << 8; write_data_a = write_data + (dloop_length >> 1); *write_data_a-- = *write_data; write_data++; write_data_b = write_data + (dloop_length >> 1); read_end = data + gus_sample->loop_end; do { *write_data = (*read_data++); *write_data |= ((*read_data++) ^ 0x80) << 8; *write_data_a-- = *write_data; *write_data_b++ = *write_data; write_data++; } while (read_data < read_end); *write_data = (*read_data++); *write_data |= ((*read_data++) ^ 0x80) << 8; *write_data_b++ = *write_data; read_end = data + gus_sample->data_length; if (__builtin_expect((read_data != read_end), 1)) { do { *write_data_b = (*read_data++); *write_data_b++ |= ((*read_data++) ^ 0x80) << 8; } while (read_data < read_end); } gus_sample->loop_start += loop_length; gus_sample->loop_end += dloop_length; gus_sample->data_length = new_length; gus_sample->modes ^= SAMPLE_PINGPONG; gus_sample->loop_start >>= 1; gus_sample->loop_end >>= 1; gus_sample->data_length >>= 1; return 0; } _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); return -1; } /* 16bit unsigned reverse */ static int convert_16ur(uint8_t *data, struct _sample *gus_sample) { uint8_t *read_data = data; uint8_t *read_end = data + gus_sample->data_length; int16_t *write_data = NULL; uint32_t tmp_loop = 0; SAMPLE_CONVERT_DEBUG(__FUNCTION__); gus_sample->data = (int16_t *) calloc(((gus_sample->data_length >> 1) + 2), sizeof(int16_t)); if (__builtin_expect((gus_sample->data != NULL), 1)) { write_data = gus_sample->data + (gus_sample->data_length >> 1) - 1; do { *write_data = *read_data++; *write_data-- |= ((*read_data++) ^ 0x80) << 8; } while (read_data < read_end); tmp_loop = gus_sample->loop_end; gus_sample->loop_end = gus_sample->data_length - gus_sample->loop_start; gus_sample->loop_start = gus_sample->data_length - tmp_loop; gus_sample->loop_fraction = ((gus_sample->loop_fraction & 0x0f) << 4) | ((gus_sample->loop_fraction & 0xf0) >> 4); gus_sample->loop_start >>= 1; gus_sample->loop_end >>= 1; gus_sample->data_length >>= 1; gus_sample->modes ^= SAMPLE_REVERSE | SAMPLE_UNSIGNED; return 0; } _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); return -1; } /* 16bit unsigned reverse ping pong */ static int convert_16urp(uint8_t *data, struct _sample *gus_sample) { uint32_t loop_length = gus_sample->loop_end - gus_sample->loop_start; uint32_t dloop_length = loop_length * 2; uint32_t new_length = gus_sample->data_length + dloop_length; uint8_t *read_data = data + gus_sample->data_length - 1; uint8_t *read_end = data + gus_sample->loop_end; int16_t *write_data = NULL; int16_t *write_data_a = NULL; int16_t *write_data_b = NULL; SAMPLE_CONVERT_DEBUG(__FUNCTION__); gus_sample->data = (int16_t *) calloc(((new_length >> 1) + 2), sizeof(int16_t)); if (__builtin_expect((gus_sample->data != NULL), 1)) { write_data = gus_sample->data; do { *write_data = ((*read_data--) ^ 0x80) << 8; *write_data++ |= *read_data--; } while (read_data < read_end); *write_data = ((*read_data--) ^ 0x80) << 8; *write_data |= *read_data--; write_data_a = write_data + (dloop_length >> 1); *write_data_a-- = *write_data; write_data++; write_data_b = write_data + (dloop_length >> 1); read_end = data + gus_sample->loop_start; do { *write_data = ((*read_data--) ^ 0x80) << 8; *write_data |= *read_data--; *write_data_a-- = *write_data; *write_data_b++ = *write_data; write_data++; } while (read_data < read_end); *write_data = ((*read_data--) ^ 0x80) << 8; *write_data |= *read_data--; *write_data_b++ = *write_data; read_end = data - 1; do { *write_data_b = ((*read_data--) ^ 0x80) << 8; *write_data_b++ |= *read_data--; } while (read_data < read_end); gus_sample->loop_start += loop_length; gus_sample->loop_end += dloop_length; gus_sample->data_length = new_length; gus_sample->modes ^= SAMPLE_PINGPONG | SAMPLE_REVERSE | SAMPLE_UNSIGNED; return 0; } _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); return -1; } /* sample loading */ struct _sample * _WM_load_gus_pat(const char *filename, int fix_release) { uint8_t *gus_patch; uint32_t gus_size; uint32_t gus_ptr; uint8_t no_of_samples; struct _sample *gus_sample = NULL; struct _sample *first_gus_sample = NULL; uint32_t i = 0; int (*do_convert[])(uint8_t *data, struct _sample *gus_sample) = { convert_8s, convert_16s, convert_8u, convert_16u, convert_8sp, convert_16sp, convert_8up, convert_16up, convert_8sr, convert_16sr, convert_8ur, convert_16ur, convert_8srp, convert_16srp, convert_8urp, convert_16urp }; uint32_t tmp_loop; UNUSED(fix_release); SAMPLE_CONVERT_DEBUG(__FUNCTION__); SAMPLE_CONVERT_DEBUG(filename); if ((gus_patch = (uint8_t *) _WM_BufferFile(filename, &gus_size)) == NULL) { return NULL; } if (gus_size < 239) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, filename, 0); free(gus_patch); return NULL; } if (memcmp(gus_patch, "GF1PATCH110\0ID#000002", 22) && memcmp(gus_patch, "GF1PATCH100\0ID#000002", 22)) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, filename, 0); free(gus_patch); return NULL; } if (gus_patch[82] > 1) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, filename, 0); free(gus_patch); return NULL; } if (gus_patch[151] > 1) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, filename, 0); free(gus_patch); return NULL; } GUSPAT_FILENAME_DEBUG(filename); GUSPAT_INT_DEBUG("voices",gus_patch[83]); no_of_samples = gus_patch[198]; gus_ptr = 239; while (no_of_samples) { uint32_t tmp_cnt; if (first_gus_sample == NULL) { first_gus_sample = (struct _sample *) malloc(sizeof(struct _sample)); gus_sample = first_gus_sample; } else { gus_sample->next = (struct _sample *) malloc(sizeof(struct _sample)); gus_sample = gus_sample->next; } if (gus_sample == NULL) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, filename, 0); free(gus_patch); return NULL; } gus_sample->next = NULL; gus_sample->loop_fraction = gus_patch[gus_ptr + 7]; gus_sample->data_length = (gus_patch[gus_ptr + 11] << 24) | (gus_patch[gus_ptr + 10] << 16) | (gus_patch[gus_ptr + 9] << 8) | gus_patch[gus_ptr + 8]; gus_sample->loop_start = (gus_patch[gus_ptr + 15] << 24) | (gus_patch[gus_ptr + 14] << 16) | (gus_patch[gus_ptr + 13] << 8) | gus_patch[gus_ptr + 12]; gus_sample->loop_end = (gus_patch[gus_ptr + 19] << 24) | (gus_patch[gus_ptr + 18] << 16) | (gus_patch[gus_ptr + 17] << 8) | gus_patch[gus_ptr + 16]; gus_sample->rate = (gus_patch[gus_ptr + 21] << 8) | gus_patch[gus_ptr + 20]; gus_sample->freq_low = (gus_patch[gus_ptr + 25] << 24) | (gus_patch[gus_ptr + 24] << 16) | (gus_patch[gus_ptr + 23] << 8) | gus_patch[gus_ptr + 22]; gus_sample->freq_high = (gus_patch[gus_ptr + 29] << 24) | (gus_patch[gus_ptr + 28] << 16) | (gus_patch[gus_ptr + 27] << 8) | gus_patch[gus_ptr + 26]; gus_sample->freq_root = (gus_patch[gus_ptr + 33] << 24) | (gus_patch[gus_ptr + 32] << 16) | (gus_patch[gus_ptr + 31] << 8) | gus_patch[gus_ptr + 30]; /* This is done this way instead of ((freq * 1024) / rate) to avoid 32bit overflow. */ /* Result is 0.001% inacurate */ gus_sample->inc_div = ((gus_sample->freq_root * 512) / gus_sample->rate) * 2; #if 0 /* We dont use this info at this time, kept in here for info */ printf("\rTremolo Sweep: %i, Rate: %i, Depth %i\n", gus_patch[gus_ptr+49], gus_patch[gus_ptr+50], gus_patch[gus_ptr+51]); printf("\rVibrato Sweep: %i, Rate: %i, Depth %i\n", gus_patch[gus_ptr+52], gus_patch[gus_ptr+53], gus_patch[gus_ptr+54]); #endif gus_sample->modes = gus_patch[gus_ptr + 55]; GUSPAT_START_DEBUG(); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_16BIT, "16bit "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_UNSIGNED, "Unsigned "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_LOOP, "Loop "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_PINGPONG, "PingPong "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_REVERSE, "Reverse "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_SUSTAIN, "Sustain "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_ENVELOPE, "Envelope "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_CLAMPED, "Clamped "); GUSPAT_END_DEBUG(); if (gus_sample->loop_start > gus_sample->loop_end) { tmp_loop = gus_sample->loop_end; gus_sample->loop_end = gus_sample->loop_start; gus_sample->loop_start = tmp_loop; gus_sample->loop_fraction = ((gus_sample->loop_fraction & 0x0f) << 4) | ((gus_sample->loop_fraction & 0xf0) >> 4); } // kill "echo" envelopes because users dont want/like them // and this is what timidity does which is why we sounded different // NOTE: This may cause some pats to sound different to what their authers intended gus_patch[gus_ptr + 41] = 0x3f; gus_patch[gus_ptr + 42] = 0x3f; // lets set up the envelope data for (i = 0; i < 6; i++) { GUSPAT_INT_DEBUG("Envelope #",i); if (gus_sample->modes & SAMPLE_ENVELOPE) { uint8_t env_rate = gus_patch[gus_ptr + 37 + i]; gus_sample->env_target[i] = 16448 * gus_patch[gus_ptr + 43 + i]; GUSPAT_INT_DEBUG("Envelope Level",gus_patch[gus_ptr+43+i]); GUSPAT_FLOAT_DEBUG("Envelope Time",env_time_table[env_rate]); gus_sample->env_rate[i] = (int32_t) (4194303.0f / ((float) _WM_SampleRate * env_time_table[env_rate])); GUSPAT_INT_DEBUG("Envelope Rate",gus_sample->env_rate[i]); GUSPAT_INT_DEBUG("GUSPAT Rate",env_rate); if (gus_sample->env_rate[i] == 0) { _WM_DEBUG_MSG("%s: Warning: found invalid envelope(%u) rate setting in %s. Using %f instead.", __FUNCTION__, i, filename, env_time_table[63]); gus_sample->env_rate[i] = (int32_t) (4194303.0f / ((float) _WM_SampleRate * env_time_table[63])); GUSPAT_FLOAT_DEBUG("Envelope Time",env_time_table[63]); } } else { gus_sample->env_target[i] = 4194303; gus_sample->env_rate[i] = (int32_t) (4194303.0f / ((float) _WM_SampleRate * env_time_table[63])); GUSPAT_FLOAT_DEBUG("Envelope Time",env_time_table[63]); } } gus_sample->env_target[6] = 0; gus_sample->env_rate[6] = (int32_t) (4194303.0f / ((float) _WM_SampleRate * env_time_table[63])); gus_ptr += 96; tmp_cnt = gus_sample->data_length; if (do_convert[(((gus_sample->modes & 0x18) >> 1) | (gus_sample->modes & 0x03))](&gus_patch[gus_ptr], gus_sample) == -1) { free(gus_patch); return NULL; } /* Test and set decay expected decay time after a note off NOTE: This sets samples for full range decay */ if (gus_sample->modes & SAMPLE_ENVELOPE) { float samples_f = 0; if (gus_sample->modes & SAMPLE_CLAMPED) { samples_f = (4194301.0f - (float)gus_sample->env_target[5]) / gus_sample->env_rate[5]; } else { if (gus_sample->modes & SAMPLE_SUSTAIN) { samples_f = (4194301.0f - (float)gus_sample->env_target[3]) / gus_sample->env_rate[3]; samples_f += (float)(gus_sample->env_target[3] - gus_sample->env_target[4]) / gus_sample->env_rate[4]; } else { samples_f = (4194301.0f - (float)gus_sample->env_target[4]) / gus_sample->env_rate[4]; } samples_f += (float)(gus_sample->env_target[4] - gus_sample->env_target[5]) / gus_sample->env_rate[5]; } samples_f += (float)gus_sample->env_target[5] / gus_sample->env_rate[6]; gus_sample->note_off_decay = (uint32_t)samples_f; } else { gus_sample->note_off_decay = gus_sample->data_length * _WM_SampleRate / gus_sample->rate; } gus_ptr += tmp_cnt; gus_sample->loop_start = (gus_sample->loop_start << 10) | (((gus_sample->loop_fraction & 0x0f) << 10) / 16); gus_sample->loop_end = (gus_sample->loop_end << 10) | (((gus_sample->loop_fraction & 0xf0) << 6) / 16); gus_sample->loop_size = gus_sample->loop_end - gus_sample->loop_start; gus_sample->data_length = gus_sample->data_length << 10; no_of_samples--; } free(gus_patch); return first_gus_sample; } wildmidi-wildmidi-0.4.2/src/internal_midi.c000066400000000000000000003022321315765416100207030ustar00rootroot00000000000000/* * internal_midi.c -- Midi Wavetable Processing library * * Copyright (C) WildMIDI Developers 2001-2016 * * This file is part of WildMIDI. * * WildMIDI is free software: you can redistribute and/or modify the player * under the terms of the GNU General Public License and you can redistribute * and/or modify the library under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either version 3 of * the licenses, or(at your option) any later version. * * WildMIDI 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 and * the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License and the * GNU Lesser General Public License along with WildMIDI. If not, see * . */ #include "config.h" #include #include #include #include #include #include "common.h" #include "lock.h" #include "wm_error.h" #include "reverb.h" #include "sample.h" #include "wildmidi_lib.h" #include "patches.h" #include "internal_midi.h" #ifdef __DJGPP__ #define powf pow /* prefer C89 pow() from libc.a instead of powf() from libm. */ #endif #ifdef WILDMIDI_AMIGA #define powf pow #endif #if defined(__WATCOMC__) || defined(__EMX__) #define powf pow #endif #define HOLD_OFF 0x02 //#define DEBUG_MIDI #ifdef DEBUG_MIDI #define MIDI_EVENT_DEBUG(dx,dy,dz) fprintf(stderr,"\r%s, 0x%.2x, 0x%.8x\n",dx,dy,dz) #define MIDI_EVENT_SDEBUG(dx,dy,dz) fprintf(stderr,"\r%s, 0x%.2x, %s\n",dx,dy,dz) #else #define MIDI_EVENT_DEBUG(dx,dy,dz) #define MIDI_EVENT_SDEBUG(dx,dy,dz) #endif /* f: ( VOLUME / 127.0 ) * 1024.0 */ int16_t _WM_lin_volume[] = { 0, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120, 129, 137, 145, 153, 161, 169, 177, 185, 193, 201, 209, 217, 225, 233, 241, 249, 258, 266, 274, 282, 290, 298, 306, 314, 322, 330, 338, 346, 354, 362, 370, 378, 387, 395, 403, 411, 419, 427, 435, 443, 451, 459, 467, 475, 483, 491, 499, 507, 516, 524, 532, 540, 548, 556, 564, 572, 580, 588, 596, 604, 612, 620, 628, 636, 645, 653, 661, 669, 677, 685, 693, 701, 709, 717, 725, 733, 741, 749, 757, 765, 774, 782, 790, 798, 806, 814, 822, 830, 838, 846, 854, 862, 870, 878, 886, 894, 903, 911, 919, 927, 935, 943, 951, 959, 967, 975, 983, 991, 999, 1007, 1015, 1024 }; /* f: As per midi 2 standard */ static float dBm_volume[] = { -999999.999999f, -84.15214884f, -72.11094901f, -65.06729865f, -60.06974919f, -56.19334866f, -53.02609882f, -50.34822724f, -48.02854936f, -45.98244846f, -44.15214884f, -42.49644143f, -40.984899f, -39.59441475f, -38.30702741f, -37.10849848f, -35.98734953f, -34.93419198f, -33.94124863f, -33.0020048f, -32.11094901f, -31.26337705f, -30.45524161f, -29.6830354f, -28.94369917f, -28.23454849f, -27.55321492f, -26.89759827f, -26.26582758f, -25.65622892f, -25.06729865f, -24.49768108f, -23.94614971f, -23.41159124f, -22.89299216f, -22.38942706f, -21.90004881f, -21.42407988f, -20.96080497f, -20.50956456f, -20.06974919f, -19.64079457f, -19.22217722f, -18.81341062f, -18.41404178f, -18.02364829f, -17.64183557f, -17.26823452f, -16.90249934f, -16.54430564f, -16.19334866f, -15.84934179f, -15.51201509f, -15.18111405f, -14.85639845f, -14.53764126f, -14.22462776f, -13.91715461f, -13.6150291f, -13.31806837f, -13.02609882f, -12.73895544f, -12.45648126f, -12.17852686f, -11.90494988f, -11.63561457f, -11.37039142f, -11.10915673f, -10.85179233f, -10.59818521f, -10.34822724f, -10.10181489f, -9.858848981f, -9.619234433f, -9.382880049f, -9.149698303f, -8.919605147f, -8.692519831f, -8.468364731f, -8.247065187f, -8.028549359f, -7.812748083f, -7.599594743f, -7.389025143f, -7.180977396f, -6.97539181f, -6.772210788f, -6.571378733f, -6.372841952f, -6.176548572f, -5.982448461f, -5.790493145f, -5.600635744f, -5.412830896f, -5.227034694f, -5.043204627f, -4.861299517f, -4.681279468f, -4.503105811f, -4.326741054f, -4.152148838f, -3.979293887f, -3.808141968f, -3.63865985f, -3.470815266f, -3.304576875f, -3.139914228f, -2.976797731f, -2.815198619f, -2.655088921f, -2.496441432f, -2.339229687f, -2.183427931f, -2.029011099f, -1.875954785f, -1.724235224f, -1.573829269f, -1.424714368f, -1.276868546f, -1.130270383f, -0.9848989963f, -0.8407340256f, -0.6977556112f, -0.5559443807f, -0.4152814317f, -0.2757483179f, -0.1373270335f, 0.0f }; /* f: As per midi 2 standard */ static float dBm_pan_volume[] = { -999999.999999f, -38.15389834f, -32.13396282f, -28.61324502f, -26.1160207f, -24.179814f, -22.5986259f, -21.26257033f, -20.10605521f, -19.08677237f, -18.17583419f, -17.35263639f, -16.60196565f, -15.91226889f, -15.2745658f, -14.6817375f, -14.12804519f, -13.60879499f, -13.12009875f, -12.65869962f, -12.22184237f, -11.80717543f, -11.41267571f, -11.03659017f, -10.67738981f, -10.33373306f, -10.00443638f, -9.6884504f, -9.384840381f, -9.092770127f, -8.811488624f, -8.540318866f, -8.278648457f, -8.025921658f, -7.781632628f, -7.545319633f, -7.316560087f, -7.094966257f, -6.880181552f, -6.671877289f, -6.46974987f, -6.273518306f, -6.082922045f, -5.897719045f, -5.717684082f, -5.542607236f, -5.372292553f, -5.206556845f, -5.045228616f, -4.888147106f, -4.735161423f, -4.586129765f, -4.44091872f, -4.299402626f, -4.161462998f, -4.026988004f, -3.895871989f, -3.76801504f, -3.643322591f, -3.52170506f, -3.403077519f, -3.287359388f, -3.174474158f, -3.064349129f, -2.956915181f, -2.852106549f, -2.749860626f, -2.650117773f, -2.55282115f, -2.457916557f, -2.36535228f, -2.27507896f, -2.187049463f, -2.101218759f, -2.017543814f, -1.935983486f,-1.856498429f, -1.779051001f, -1.703605184f, -1.630126502f, -1.558581949f, -1.48893992f, -1.421170148f, -1.35524364f, -1.291132623f, -1.228810491f, -1.168251755f, -1.109431992f, -1.052327808f, -0.9969167902f, -0.9431774708f, -0.8910892898f, -0.8406325604f, -0.7917884361f, -0.7445388804f, -0.6988666373f, -0.6547552046f, -0.612188808f, -0.5711523768f, -0.5316315211f, -0.4936125107f, -0.4570822543f, -0.4220282808f, -0.3884387214f, -0.3563022927f, -0.3256082808f, -0.2963465264f, -0.2685074109f, -0.2420818435f, -0.2170612483f, -0.1934375538f, -0.1712031815f, -0.1503510361f, -0.1308744964f, -0.1127674066f, -0.09602406855f, -0.08063923423f, -0.06660809932f, -0.05392629701f, -0.04258989258f, -0.03259537844f, -0.02393966977f, -0.01662010072f, -0.01063442111f, -0.005980793601f, -0.002657791522f, -0.000664397052f, 0.0f }; uint32_t _WM_freq_table[] = { 837201792, 837685632, 838169728, 838653568, 839138240, 839623232, 840108480, 840593984, 841079680, 841565184, 842051648, 842538240, 843025152, 843512320, 843999232, 844486976, 844975040, 845463360, 845951936, 846440320, 846929536, 847418944, 847908608, 848398656, 848888960, 849378944, 849869824, 850361024, 850852416, 851344192, 851835584, 852327872, 852820480, 853313280, 853806464, 854299328, 854793024, 855287040, 855781312, 856275904, 856770752, 857265344, 857760704, 858256448, 858752448, 859248704, 859744768, 860241600, 860738752, 861236160, 861733888, 862231360, 862729600, 863228160, 863727104, 864226176, 864725696, 865224896, 865724864, 866225152, 866725760, 867226688, 867727296, 868228736, 868730496, 869232576, 869734912, 870236928, 870739904, 871243072, 871746560, 872250368, 872754496, 873258240, 873762880, 874267840, 874773184, 875278720, 875783936, 876290112, 876796480, 877303232, 877810176, 878317504, 878824512, 879332416, 879840576, 880349056, 880857792, 881366272, 881875712, 882385280, 882895296, 883405440, 883915456, 884426304, 884937408, 885448832, 885960512, 886472512, 886984192, 887496768, 888009728, 888522944, 889036352, 889549632, 890063680, 890578048, 891092736, 891607680, 892122368, 892637952, 893153792, 893670016, 894186496, 894703232, 895219648, 895737024, 896254720, 896772672, 897290880, 897808896, 898327744, 898846912, 899366336, 899886144, 900405568, 900925952, 901446592, 901967552, 902488768, 903010368, 903531584, 904053760, 904576256, 905099008, 905622016, 906144896, 906668480, 907192512, 907716800, 908241408, 908765632, 909290816, 909816256, 910342144, 910868160, 911394624, 911920768, 912447680, 912975104, 913502720, 914030592, 914558208, 915086784, 915615552, 916144768, 916674176, 917203968, 917733440, 918263744, 918794496, 919325440, 919856704, 920387712, 920919616, 921451840, 921984320, 922517184, 923049728, 923583168, 924116928, 924651008, 925185344, 925720000, 926254336, 926789696, 927325312, 927861120, 928397440, 928933376, 929470208, 930007296, 930544768, 931082560, 931619968, 932158464, 932697152, 933236160, 933775488, 934315072, 934854464, 935394688, 935935296, 936476224, 937017344, 937558208, 938100160, 938642304, 939184640, 939727488, 940269888, 940813312, 941357056, 941900992, 942445440, 942990016, 943534400, 944079680, 944625280, 945171200, 945717440, 946263360, 946810176, 947357376, 947904832, 948452672, 949000192, 949548608, 950097280, 950646400, 951195776, 951745472, 952294912, 952845184, 953395904, 953946880, 954498176, 955049216, 955601088, 956153408, 956705920, 957258816, 957812032, 958364928, 958918848, 959472960, 960027456, 960582272, 961136768, 961692224, 962248000, 962804032, 963360448, 963916608, 964473600, 965031040, 965588736, 966146816, 966705152, 967263168, 967822144, 968381440, 968941120, 969501056, 970060736, 970621376, 971182272, 971743488, 972305088, 972866368, 973428608, 973991104, 974554048, 975117312, 975680768, 976243968, 976808192, 977372736, 977937536, 978502656, 979067584, 979633344, 980199488, 980765888, 981332736, 981899200, 982466688, 983034432, 983602624, 984171008, 984739776, 985308160, 985877632, 986447360, 987017472, 987587904, 988157952, 988729088, 989300416, 989872192, 990444224, 991016000, 991588672, 992161728, 992735168, 993308864, 993882880, 994456576, 995031296, 995606336, 996181696, 996757440, 997332800, 997909184, 998485888, 999062912, 999640256, 1000217984, 1000795392, 1001373696, 1001952448, 1002531520, 1003110848, 1003689920, 1004270016, 1004850304, 1005431040, 1006012160, 1006592832, 1007174592, 1007756608, 1008339008, 1008921792, 1009504768, 1010087552, 1010671296, 1011255360, 1011839808, 1012424576, 1013009024, 1013594368, 1014180160, 1014766272, 1015352768, 1015938880, 1016526016, 1017113472, 1017701248, 1018289408, 1018877824, 1019465984, 1020055104, 1020644672, 1021234496, 1021824768, 1022414528, 1023005440, 1023596608, 1024188160, 1024780096, 1025371584, 1025964160, 1026557120, 1027150336, 1027744000, 1028337920, 1028931520, 1029526144, 1030121152, 1030716480, 1031312128, 1031907456, 1032503808, 1033100480, 1033697536, 1034294912, 1034892032, 1035490048, 1036088512, 1036687232, 1037286336, 1037885824, 1038484928, 1039085056, 1039685632, 1040286464, 1040887680, 1041488448, 1042090368, 1042692608, 1043295168, 1043898176, 1044501440, 1045104384, 1045708288, 1046312640, 1046917376, 1047522368, 1048127040, 1048732800, 1049338816, 1049945280, 1050552128, 1051158528, 1051765952, 1052373824, 1052982016, 1053590592, 1054199424, 1054807936, 1055417600, 1056027456, 1056637760, 1057248448, 1057858752, 1058470016, 1059081728, 1059693824, 1060306304, 1060918336, 1061531392, 1062144896, 1062758656, 1063372928, 1063987392, 1064601664, 1065216896, 1065832448, 1066448448, 1067064704, 1067680704, 1068297728, 1068915136, 1069532864, 1070150976, 1070768640, 1071387520, 1072006720, 1072626240, 1073246080, 1073866368, 1074486272, 1075107200, 1075728512, 1076350208, 1076972160, 1077593856, 1078216704, 1078839680, 1079463296, 1080087040, 1080710528, 1081335168, 1081960064, 1082585344, 1083211008, 1083836928, 1084462592, 1085089280, 1085716352, 1086343936, 1086971648, 1087599104, 1088227712, 1088856576, 1089485824, 1090115456, 1090745472, 1091375104, 1092005760, 1092636928, 1093268352, 1093900160, 1094531584, 1095164160, 1095796992, 1096430336, 1097064064, 1097697280, 1098331648, 1098966400, 1099601536, 1100237056, 1100872832, 1101508224, 1102144768, 1102781824, 1103419136, 1104056832, 1104694144, 1105332608, 1105971328, 1106610432, 1107249920, 1107889152, 1108529408, 1109170048, 1109811072, 1110452352, 1111094144, 1111735552, 1112377984, 1113020928, 1113664128, 1114307712, 1114950912, 1115595264, 1116240000, 1116885120, 1117530624, 1118175744, 1118821888, 1119468416, 1120115456, 1120762752, 1121410432, 1122057856, 1122706176, 1123355136, 1124004224, 1124653824, 1125303040, 1125953408, 1126604160, 1127255168, 1127906560, 1128557696, 1129209984, 1129862528, 1130515456, 1131168768, 1131822592, 1132475904, 1133130368, 1133785216, 1134440448, 1135096064, 1135751296, 1136407680, 1137064448, 1137721472, 1138379008, 1139036800, 1139694336, 1140353024, 1141012096, 1141671424, 1142331264, 1142990592, 1143651200, 1144312192, 1144973440, 1145635200, 1146296448, 1146958976, 1147621760, 1148285056, 1148948608, 1149612672, 1150276224, 1150940928, 1151606144, 1152271616, 1152937600, 1153603072, 1154269824, 1154936832, 1155604352, 1156272128, 1156939648, 1157608192, 1158277248, 1158946560, 1159616384, 1160286464, 1160956288, 1161627264, 1162298624, 1162970240, 1163642368, 1164314112, 1164987008, 1165660160, 1166333824, 1167007872, 1167681536, 1168356352, 1169031552, 1169707136, 1170383104, 1171059584, 1171735552, 1172412672, 1173090304, 1173768192, 1174446592, 1175124480, 1175803648, 1176483072, 1177163008, 1177843328, 1178523264, 1179204352, 1179885824, 1180567680, 1181249920, 1181932544, 1182614912, 1183298304, 1183982208, 1184666368, 1185351040, 1186035328, 1186720640, 1187406464, 1188092672, 1188779264, 1189466368, 1190152960, 1190840832, 1191528960, 1192217600, 1192906624, 1193595136, 1194285056, 1194975232, 1195665792, 1196356736, 1197047296, 1197739136, 1198431360, 1199123968, 1199816960, 1200510336, 1201203328, 1201897600, 1202592128, 1203287040, 1203982464, 1204677504, 1205373696, 1206070272, 1206767232, 1207464704, 1208161664, 1208859904, 1209558528, 1210257536, 1210956928, 1211656832, 1212356224, 1213056768, 1213757952, 1214459392, 1215161216, 1215862656, 1216565376, 1217268352, 1217971840, 1218675712, 1219379200, 1220083840, 1220788992, 1221494528, 1222200448, 1222906752, 1223612672, 1224319872, 1225027456, 1225735424, 1226443648, 1227151616, 1227860864, 1228570496, 1229280512, 1229990912, 1230700928, 1231412096, 1232123776, 1232835840, 1233548288, 1234261248, 1234973696, 1235687424, 1236401536, 1237116032, 1237831040, 1238545536, 1239261312, 1239977472, 1240694144, 1241411072, 1242128512, 1242845568, 1243563776, 1244282496, 1245001600, 1245721088, 1246440192, 1247160448, 1247881216, 1248602368, 1249324032, 1250045184, 1250767616, 1251490432, 1252213632, 1252937344, 1253661440, 1254385152, 1255110016, 1255835392, 1256561152, 1257287424, 1258013184, 1258740096, 1259467648, 1260195456, 1260923648, 1261651584, 1262380800, 1263110272, 1263840256, 1264570624, 1265301504, 1266031872, 1266763520, 1267495552, 1268227968, 1268961024, 1269693440, 1270427264, 1271161472, 1271896064, 1272631168, 1273365760, 1274101632, 1274838016, 1275574784, 1276311808, 1277049472, 1277786624, 1278525056, 1279264000, 1280003328, 1280743040, 1281482368, 1282222976, 1282963968, 1283705344, 1284447232, 1285188736, 1285931392, 1286674560, 1287418240, 1288162176, 1288906624, 1289650688, 1290395904, 1291141760, 1291887872, 1292634496, 1293380608, 1294128128, 1294875904, 1295624320, 1296373120, 1297122304, 1297870976, 1298621056, 1299371520, 1300122496, 1300873856, 1301624832, 1302376960, 1303129600, 1303882752, 1304636288, 1305389312, 1306143872, 1306898688, 1307654016, 1308409600, 1309165696, 1309921536, 1310678528, 1311435904, 1312193920, 1312952192, 1313710080, 1314469248, 1315228928, 1315988992, 1316749568, 1317509632, 1318271104, 1319032960, 1319795200, 1320557952, 1321321088, 1322083840, 1322847872, 1323612416, 1324377216, 1325142656, 1325907584, 1326673920, 1327440512, 1328207744, 1328975360, 1329742464, 1330510976, 1331279872, 1332049152, 1332819072, 1333589248, 1334359168, 1335130240, 1335901824, 1336673920, 1337446400, 1338218368, 1338991744, 1339765632, 1340539904, 1341314560, 1342088832, 1342864512, 1343640576, 1344417024, 1345193984, 1345971456, 1346748416, 1347526656, 1348305408, 1349084672, 1349864320, 1350643456, 1351424000, 1352205056, 1352986496, 1353768448, 1354550784, 1355332608, 1356115968, 1356899712, 1357683840, 1358468480, 1359252608, 1360038144, 1360824192, 1361610624, 1362397440, 1363183872, 1363971712, 1364760064, 1365548672, 1366337792, 1367127424, 1367916672, 1368707200, 1369498240, 1370289664, 1371081472, 1371873024, 1372665856, 1373459072, 1374252800, 1375047040, 1375840768, 1376635904, 1377431552, 1378227584, 1379024000, 1379820928, 1380617472, 1381415296, 1382213760, 1383012480, 1383811840, 1384610560, 1385410816, 1386211456, 1387012480, 1387814144, 1388615168, 1389417728, 1390220672, 1391024128, 1391827968, 1392632320, 1393436288, 1394241536, 1395047296, 1395853568, 1396660224, 1397466368, 1398274048, 1399082112, 1399890688, 1400699648, 1401508224, 1402318080, 1403128576, 1403939456, 1404750848, 1405562624, 1406374016, 1407186816, 1408000000, 1408813696, 1409627904, 1410441728, 1411256704, 1412072320, 1412888320, 1413704960, 1414521856, 1415338368, 1416156288, 1416974720, 1417793664, 1418612992, 1419431808, 1420252160, 1421072896, 1421894144, 1422715904, 1423537280, 1424359808, 1425183104, 1426006784, 1426830848, 1427655296, 1428479488, 1429305088, 1430131072, 1430957568, 1431784576, 1432611072, 1433438976, 1434267392, 1435096192, 1435925632, 1436754432, 1437584768, 1438415616, 1439246848, 1440078720, 1440910848, 1441742720, 1442575872, 1443409664, 1444243584, 1445078400, 1445912576, 1446748032, 1447584256, 1448420864, 1449257856, 1450094464, 1450932480, 1451771008, 1452609920, 1453449472, 1454289408, 1455128960, 1455969920, 1456811264, 1457653248, 1458495616, 1459337600, 1460180864, 1461024768, 1461869056, 1462713984, 1463558272, 1464404096, 1465250304, 1466097152, 1466944384, 1467792128, 1468639488, 1469488256, 1470337408, 1471187200, 1472037376, 1472887168, 1473738368, 1474589952, 1475442304, 1476294912, 1477148160, 1478000768, 1478854912, 1479709696, 1480564608, 1481420288, 1482275456, 1483132160, 1483989248, 1484846976, 1485704960, 1486562688, 1487421696, 1488281344, 1489141504, 1490002048, 1490863104, 1491723776, 1492585856, 1493448448, 1494311424, 1495175040, 1496038144, 1496902656, 1497767808, 1498633344, 1499499392, 1500365056, 1501232128, 1502099712, 1502967808, 1503836416, 1504705536, 1505574016, 1506444032, 1507314688, 1508185856, 1509057408, 1509928576, 1510801280, 1511674240, 1512547840, 1513421952, 1514295680, 1515170816, 1516046464, 1516922624, 1517799296, 1518676224, 1519552896, 1520431104, 1521309824, 1522188928, 1523068800, 1523948032, 1524828672, 1525709824, 1526591616, 1527473792, 1528355456, 1529238784, 1530122496, 1531006720, 1531891712, 1532776832, 1533661824, 1534547968, 1535434880, 1536322304, 1537210112, 1538097408, 1538986368, 1539875840, 1540765696, 1541656192, 1542547072, 1543437440, 1544329472, 1545221888, 1546114944, 1547008384, 1547901440, 1548796032, 1549691136, 1550586624, 1551482752, 1552378368, 1553275520, 1554173184, 1555071232, 1555970048, 1556869248, 1557767936, 1558668288, 1559568896, 1560470272, 1561372032, 1562273408, 1563176320, 1564079616, 1564983424, 1565888000, 1566791808, 1567697408, 1568603392, 1569509760, 1570416896, 1571324416, 1572231424, 1573140096, 1574049152, 1574958976, 1575869184, 1576778752, 1577689984, 1578601728, 1579514112, 1580426880, 1581339264, 1582253056, 1583167488, 1584082432, 1584997888, 1585913984, 1586829440, 1587746304, 1588663936, 1589582080, 1590500736, 1591418880, 1592338560, 1593258752, 1594179584, 1595100928, 1596021632, 1596944000, 1597866880, 1598790272, 1599714304, 1600638848, 1601562752, 1602488320, 1603414272, 1604340992, 1605268224, 1606194816, 1607123072, 1608051968, 1608981120, 1609911040, 1610841344, 1611771264, 1612702848, 1613634688, 1614567168, 1615500288, 1616432896, 1617367040, 1618301824, 1619237120, 1620172800, 1621108096, 1622044928, 1622982272, 1623920128, 1624858752, 1625797632, 1626736256, 1627676416, 1628616960, 1629558272, 1630499968, 1631441152, 1632384000, 1633327232, 1634271232, 1635215744, 1636159744, 1637105152, 1638051328, 1638998016, 1639945088, 1640892928, 1641840128, 1642788992, 1643738368, 1644688384, 1645638784, 1646588672, 1647540352, 1648492416, 1649445120, 1650398464, 1651351168, 1652305408, 1653260288, 1654215808, 1655171712, 1656128256, 1657084288, 1658041856, 1659000064, 1659958784, 1660918272, 1661876992, 1662837376, 1663798400, 1664759936, 1665721984, 1666683520, 1667646720, 1668610560, 1669574784, 1670539776, 1671505024, 1672470016, 1673436544 }; #if 0 /* NOT NEEDED USES TOO MUCH CPU */ void _WM_DynamicVolumeAdjust(struct _mdi *mdi, int32_t *tmp_buffer, uint32_t buffer_used) { uint32_t i = 0; uint32_t j = 0; int8_t peak_set = 0; int32_t prev_val = 0; uint32_t peak_ofs = 0; int32_t peak = mdi->dyn_vol_peak; double volume_to_reach = mdi->dyn_vol_to_reach; double volume = mdi->dyn_vol; double volume_adjust = mdi->dyn_vol_adjust; double tmp_output = 0.0; #define MAX_DYN_VOL 1.0 for (i = 0; i < buffer_used; i++) { if ((i == 0) || (i > peak_ofs)) { // Find Next Peak/Troff peak_set = 0; prev_val = peak; peak_ofs = 0; for (j = i; j < buffer_used; j++) { if (peak_set == 0) { // find what direction the data is going if (prev_val > tmp_buffer[j]) { // Going Down peak_set = -1; } else if (prev_val < tmp_buffer[j]) { // Doing Up peak_set = 1; } else { // No direction, keep looking prev_val = tmp_buffer[j]; continue; } } if (peak_set == 1) { // Data is going up if (peak < tmp_buffer[j]) { peak = tmp_buffer[j]; peak_ofs = j; } else if (peak > tmp_buffer[j]) { // Data is starting to go down, we found the peak break; } } else { // assume peak_set == -1 // Data is going down if (peak > tmp_buffer[j]) { peak = tmp_buffer[j]; peak_ofs = j; } else if (peak < tmp_buffer[j]) { // Data is starting to go up, we found the troff break; } } prev_val = tmp_buffer[j]; } if (peak_set != 0) { if (peak_set == 1) { if (peak > 32767) { volume_to_reach = 32767.0 / (double)peak; } else { volume_to_reach = MAX_DYN_VOL; } } else { // assume peak_set == -1 if (peak < -32768) { volume_to_reach = -32768.0 / (double)peak; } else { volume_to_reach = MAX_DYN_VOL; } } } else { // No peak found, set volume we want to normal volume_to_reach = MAX_DYN_VOL; } if (volume != volume_to_reach) { if (volume_to_reach == MAX_DYN_VOL) { // if we want normal volume then adjust to it slower volume_adjust = (volume_to_reach - volume) / ((double)_WM_SampleRate * 0.1); } else { // if we want to clamp the volume then adjust quickly volume_adjust = (volume_to_reach - volume) / ((double)_WM_SampleRate * 0.0001); } } } // First do we need to do volume adjustments if ((volume_adjust != 0.0) && (volume != volume_to_reach)) { volume += volume_adjust; if (volume_adjust > 0.0) { // if increasing the volume if (volume >= MAX_DYN_VOL) { // we dont boost volume volume = MAX_DYN_VOL; volume_adjust = 0.0; } else if (volume > volume_to_reach) { // we dont want to go above the level we wanted volume = volume_to_reach; volume_adjust = 0.0; } } else { // decreasing the volume if (volume < volume_to_reach) { // we dont want to go below the level we wanted volume = volume_to_reach; volume_adjust = 0.0; } } } // adjust buffer volume tmp_output = (double)tmp_buffer[i] * volume; tmp_buffer[i] = (int32_t)tmp_output; } // store required values mdi->dyn_vol_adjust = volume_adjust; mdi->dyn_vol_peak = peak; mdi->dyn_vol = volume; mdi->dyn_vol_to_reach = volume_to_reach; } #endif /* Should be called in any function that effects note volumes */ void _WM_AdjustNoteVolumes(struct _mdi *mdi, uint8_t ch, struct _note *nte) { float premix_dBm; float premix_lin; uint8_t pan_ofs; float premix_dBm_left; float premix_dBm_right; float premix_left; float premix_right; float volume_adj; uint32_t vol_ofs; /* Pointless CPU heating checks to shoosh up a compiler */ if (ch > 0x0f) ch = 0x0f; if (nte->ignore_chan_events) return; pan_ofs = mdi->channel[ch].balance + mdi->channel[ch].pan - 64; vol_ofs = (nte->velocity * ((mdi->channel[ch].expression * mdi->channel[ch].volume) / 127)) / 127; /* This value is to reduce the chance of clipping. Higher value means lower overall volume, Lower value means higher overall volume. NOTE: The lower the value the higher the chance of clipping. FIXME: Still needs tuning. Clipping heard at a value of 3.75 */ #define VOL_DIVISOR 4.0f volume_adj = ((float)_WM_MasterVolume / 1024.0f) / VOL_DIVISOR; MIDI_EVENT_DEBUG(__FUNCTION__,ch, 0); if (pan_ofs > 127) pan_ofs = 127; premix_dBm_left = dBm_pan_volume[(127-pan_ofs)]; premix_dBm_right = dBm_pan_volume[pan_ofs]; if (mdi->extra_info.mixer_options & WM_MO_LOG_VOLUME) { premix_dBm = dBm_volume[vol_ofs]; premix_dBm_left += premix_dBm; premix_dBm_right += premix_dBm; premix_left = (powf(10.0f, (premix_dBm_left / 20.0f))) * volume_adj; premix_right = (powf(10.0f, (premix_dBm_right / 20.0f))) * volume_adj; } else { premix_lin = (float)(_WM_lin_volume[vol_ofs]) / 1024.0f; premix_left = premix_lin * powf(10.0f, (premix_dBm_left / 20)) * volume_adj; premix_right = premix_lin * powf(10.0f, (premix_dBm_right / 20)) * volume_adj; } nte->left_mix_volume = (int32_t)(premix_left * 1024.0f); nte->right_mix_volume = (int32_t)(premix_right * 1024.0f); } /* Should be called in any function that effects channel volumes */ /* Calling this function with a value > 15 will make it adjust notes on all channels */ void _WM_AdjustChannelVolumes(struct _mdi *mdi, uint8_t ch) { struct _note *nte = mdi->note; if (nte != NULL) { do { if (ch <= 15) { if ((nte->noteid >> 8) == ch) { goto _DO_ADJUST; } } else { _DO_ADJUST: if (!nte->ignore_chan_events) { _WM_AdjustNoteVolumes(mdi, ch, nte); if (nte->replay) _WM_AdjustNoteVolumes(mdi, ch, nte->replay); } } nte = nte->next; } while (nte != NULL); } } float _WM_GetSamplesPerTick(uint32_t divisions, uint32_t tempo) { float microseconds_per_tick; float secs_per_tick; float samples_per_tick; /* Slow but needed for accuracy */ microseconds_per_tick = (float) tempo / (float) divisions; secs_per_tick = microseconds_per_tick / 1000000.0f; samples_per_tick = _WM_SampleRate * secs_per_tick; return (samples_per_tick); } static void _WM_CheckEventMemoryPool(struct _mdi *mdi) { if ((mdi->event_count + 1) >= mdi->events_size) { mdi->events_size += MEM_CHUNK; mdi->events = (struct _event *) realloc(mdi->events, (mdi->events_size * sizeof(struct _event))); } } void _WM_do_note_off_extra(struct _note *nte) { MIDI_EVENT_DEBUG(__FUNCTION__,0, 0); nte->is_off = 0; { if (!(nte->modes & SAMPLE_ENVELOPE)) { if (nte->modes & SAMPLE_LOOP) { nte->modes ^= SAMPLE_LOOP; } nte->env_inc = 0; } else if (nte->hold) { nte->hold |= HOLD_OFF; /* } else if (nte->modes & SAMPLE_SUSTAIN) { if (nte->env < 3) { nte->env = 3; if (nte->env_level > nte->sample->env_target[3]) { nte->env_inc = -nte->sample->env_rate[3]; } else { nte->env_inc = nte->sample->env_rate[3]; } } */ } else if (nte->modes & SAMPLE_CLAMPED) { if (nte->env < 5) { nte->env = 5; if (nte->env_level > nte->sample->env_target[5]) { nte->env_inc = -nte->sample->env_rate[5]; } else { nte->env_inc = nte->sample->env_rate[5]; } } } else if (nte->env < 3) { nte->env = 3; if (nte->env_level > nte->sample->env_target[3]) { nte->env_inc = -nte->sample->env_rate[3]; } else { nte->env_inc = nte->sample->env_rate[3]; } } } } void _WM_do_midi_divisions(struct _mdi *mdi, struct _event_data *data) { // placeholder function so we can record divisions in the event stream // for conversion function _WM_Event2Midi() UNUSED(mdi); UNUSED(data); return; } void _WM_do_note_off(struct _mdi *mdi, struct _event_data *data) { struct _note *nte; uint8_t ch = data->channel; MIDI_EVENT_DEBUG(__FUNCTION__,ch, data->data.value); nte = &mdi->note_table[0][ch][(data->data.value >> 8)]; if (!nte->active) { nte = &mdi->note_table[1][ch][(data->data.value >> 8)]; if (!nte->active) { return; } } if ((mdi->channel[ch].isdrum) && (!(nte->modes & SAMPLE_LOOP))) { return; } if ((nte->modes & SAMPLE_ENVELOPE) && (nte->env == 0)) { // This is a fix for notes that end before the // initial step of the envelope has completed // making it impossible to hear them at times. nte->is_off = 1; } else { _WM_do_note_off_extra(nte); } } static inline uint32_t get_inc(struct _mdi *mdi, struct _note *nte) { int ch = nte->noteid >> 8; int32_t note_f; uint32_t freq; if (__builtin_expect((nte->patch->note != 0), 0)) { note_f = nte->patch->note * 100; } else { note_f = (nte->noteid & 0x7f) * 100; } note_f += mdi->channel[ch].pitch_adjust; if (__builtin_expect((note_f < 0), 0)) { note_f = 0; } else if (__builtin_expect((note_f > 12700), 0)) { note_f = 12700; } freq = _WM_freq_table[(note_f % 1200)] >> (10 - (note_f / 1200)); return (((freq / ((_WM_SampleRate * 100) / 1024)) * 1024 / nte->sample->inc_div)); } void _WM_do_note_on(struct _mdi *mdi, struct _event_data *data) { struct _note *nte; struct _note *prev_nte; struct _note *nte_array; uint32_t freq = 0; struct _patch *patch; struct _sample *sample; uint8_t ch = data->channel; uint8_t note = (data->data.value >> 8); uint8_t velocity = (data->data.value & 0xFF); if (velocity == 0x00) { _WM_do_note_off(mdi, data); return; } MIDI_EVENT_DEBUG(__FUNCTION__,ch, data->data.value); if (!mdi->channel[ch].isdrum) { patch = mdi->channel[ch].patch; if (patch == NULL) { return; } freq = _WM_freq_table[(note % 12) * 100] >> (10 - (note / 12)); } else { patch = _WM_get_patch_data(mdi, ((mdi->channel[ch].bank << 8) | note | 0x80)); if (patch == NULL) { return; } if (patch->note) { freq = _WM_freq_table[(patch->note % 12) * 100] >> (10 - (patch->note / 12)); } else { freq = _WM_freq_table[(note % 12) * 100] >> (10 - (note / 12)); } } sample = _WM_get_sample_data(patch, (freq / 100)); if (sample == NULL) { return; } nte = &mdi->note_table[0][ch][note]; if (nte->active) { if ((nte->modes & SAMPLE_ENVELOPE) && (nte->env < 3) && (!(nte->hold & HOLD_OFF))) return; nte->replay = &mdi->note_table[1][ch][note]; nte->env = 6; nte->env_inc = -nte->sample->env_rate[6]; nte = nte->replay; } else { if (mdi->note_table[1][ch][note].active) { if ((nte->modes & SAMPLE_ENVELOPE) && (nte->env < 3) && (!(nte->hold & HOLD_OFF))) return; mdi->note_table[1][ch][note].replay = nte; mdi->note_table[1][ch][note].env = 6; mdi->note_table[1][ch][note].env_inc = -mdi->note_table[1][ch][note].sample->env_rate[6]; } else { nte_array = mdi->note; if (nte_array == NULL) { mdi->note = nte; } else { do { prev_nte = nte_array; nte_array = nte_array->next; } while (nte_array); prev_nte->next = nte; } nte->active = 1; nte->next = NULL; } } nte->noteid = (ch << 8) | note; nte->patch = patch; nte->sample = sample; nte->sample_pos = 0; nte->sample_inc = get_inc(mdi, nte); nte->velocity = velocity; nte->env = 0; nte->env_inc = nte->sample->env_rate[0]; nte->env_level = 0; nte->modes = sample->modes; nte->hold = mdi->channel[ch].hold; nte->replay = NULL; nte->is_off = 0; nte->ignore_chan_events = 0; _WM_AdjustNoteVolumes(mdi, ch, nte); } void _WM_do_aftertouch(struct _mdi *mdi, struct _event_data *data) { struct _note *nte; uint8_t ch = data->channel; MIDI_EVENT_DEBUG(__FUNCTION__,ch, data->data.value); nte = &mdi->note_table[0][ch][(data->data.value >> 8)]; if (!nte->active) { nte = &mdi->note_table[1][ch][(data->data.value >> 8)]; if (!nte->active) { return; } } nte->velocity = data->data.value & 0xff; _WM_AdjustNoteVolumes(mdi, ch, nte); if (nte->replay) { nte->replay->velocity = data->data.value & 0xff; _WM_AdjustNoteVolumes(mdi, ch, nte->replay); } } void _WM_do_control_bank_select(struct _mdi *mdi, struct _event_data *data) { uint8_t ch = data->channel; MIDI_EVENT_DEBUG(__FUNCTION__,ch, data->data.value); mdi->channel[ch].bank = data->data.value; } void _WM_do_control_data_entry_course(struct _mdi *mdi, struct _event_data *data) { uint8_t ch = data->channel; int data_tmp; MIDI_EVENT_DEBUG(__FUNCTION__,ch, data->data.value); if ((mdi->channel[ch].reg_non == 0) && (mdi->channel[ch].reg_data == 0x0000)) { /* Pitch Bend Range */ data_tmp = mdi->channel[ch].pitch_range % 100; mdi->channel[ch].pitch_range = data->data.value * 100 + data_tmp; /* printf("Data Entry Course: pitch_range: %i\n\r",mdi->channel[ch].pitch_range);*/ /* printf("Data Entry Course: data %li\n\r",data->data.value);*/ } } void _WM_do_control_channel_volume(struct _mdi *mdi, struct _event_data *data) { uint8_t ch = data->channel; MIDI_EVENT_DEBUG(__FUNCTION__,ch, data->data.value); mdi->channel[ch].volume = data->data.value; _WM_AdjustChannelVolumes(mdi, ch); } void _WM_do_control_channel_balance(struct _mdi *mdi, struct _event_data *data) { uint8_t ch = data->channel; MIDI_EVENT_DEBUG(__FUNCTION__,ch, data->data.value); mdi->channel[ch].balance = data->data.value; _WM_AdjustChannelVolumes(mdi, ch); } void _WM_do_control_channel_pan(struct _mdi *mdi, struct _event_data *data) { uint8_t ch = data->channel; MIDI_EVENT_DEBUG(__FUNCTION__,ch, data->data.value); mdi->channel[ch].pan = data->data.value; _WM_AdjustChannelVolumes(mdi, ch); } void _WM_do_control_channel_expression(struct _mdi *mdi, struct _event_data *data) { uint8_t ch = data->channel; MIDI_EVENT_DEBUG(__FUNCTION__,ch, data->data.value); mdi->channel[ch].expression = data->data.value; _WM_AdjustChannelVolumes(mdi, ch); } void _WM_do_control_data_entry_fine(struct _mdi *mdi, struct _event_data *data) { uint8_t ch = data->channel; int data_tmp; MIDI_EVENT_DEBUG(__FUNCTION__,ch, data->data.value); if ((mdi->channel[ch].reg_non == 0) && (mdi->channel[ch].reg_data == 0x0000)) { /* Pitch Bend Range */ data_tmp = mdi->channel[ch].pitch_range / 100; mdi->channel[ch].pitch_range = (data_tmp * 100) + data->data.value; /* printf("Data Entry Fine: pitch_range: %i\n\r",mdi->channel[ch].pitch_range);*/ /* printf("Data Entry Fine: data: %li\n\r", data->data.value);*/ } } void _WM_do_control_channel_hold(struct _mdi *mdi, struct _event_data *data) { struct _note *note_data = mdi->note; uint8_t ch = data->channel; MIDI_EVENT_DEBUG(__FUNCTION__,ch, data->data.value); if (data->data.value > 63) { mdi->channel[ch].hold = 1; } else { mdi->channel[ch].hold = 0; if (note_data) { do { if ((note_data->noteid >> 8) == ch) { if (note_data->hold & HOLD_OFF) { if (note_data->modes & SAMPLE_ENVELOPE) { if (note_data->modes & SAMPLE_CLAMPED) { if (note_data->env < 5) { note_data->env = 5; if (note_data->env_level > note_data->sample->env_target[5]) { note_data->env_inc = -note_data->sample->env_rate[5]; } else { note_data->env_inc = note_data->sample->env_rate[5]; } } /* } else if (note_data->modes & SAMPLE_SUSTAIN) { if (note_data->env < 3) { note_data->env = 3; if (note_data->env_level > note_data->sample->env_target[3]) { note_data->env_inc = -note_data->sample->env_rate[3]; } else { note_data->env_inc = note_data->sample->env_rate[3]; } } */ } else if (note_data->env < 3) { note_data->env = 3; if (note_data->env_level > note_data->sample->env_target[3]) { note_data->env_inc = -note_data->sample->env_rate[3]; } else { note_data->env_inc = note_data->sample->env_rate[3]; } } } else { if (note_data->modes & SAMPLE_LOOP) { note_data->modes ^= SAMPLE_LOOP; } note_data->env_inc = 0; } } note_data->hold = 0x00; } note_data = note_data->next; } while (note_data); } } } void _WM_do_control_data_increment(struct _mdi *mdi, struct _event_data *data) { uint8_t ch = data->channel; MIDI_EVENT_DEBUG(__FUNCTION__,ch, data->data.value); if ((mdi->channel[ch].reg_non == 0) && (mdi->channel[ch].reg_data == 0x0000)) { /* Pitch Bend Range */ if (mdi->channel[ch].pitch_range < 0x3FFF) mdi->channel[ch].pitch_range++; } } void _WM_do_control_data_decrement(struct _mdi *mdi, struct _event_data *data) { uint8_t ch = data->channel; MIDI_EVENT_DEBUG(__FUNCTION__,ch, data->data.value); if ((mdi->channel[ch].reg_non == 0) && (mdi->channel[ch].reg_data == 0x0000)) { /* Pitch Bend Range */ if (mdi->channel[ch].pitch_range > 0) mdi->channel[ch].pitch_range--; } } void _WM_do_control_non_registered_param_fine(struct _mdi *mdi, struct _event_data *data) { uint8_t ch = data->channel; MIDI_EVENT_DEBUG(__FUNCTION__,ch, data->data.value); mdi->channel[ch].reg_data = (mdi->channel[ch].reg_data & 0x3F80) | data->data.value; mdi->channel[ch].reg_non = 1; } void _WM_do_control_non_registered_param_course(struct _mdi *mdi, struct _event_data *data) { uint8_t ch = data->channel; MIDI_EVENT_DEBUG(__FUNCTION__,ch, data->data.value); mdi->channel[ch].reg_data = (mdi->channel[ch].reg_data & 0x7F) | (data->data.value << 7); mdi->channel[ch].reg_non = 1; } void _WM_do_control_registered_param_fine(struct _mdi *mdi, struct _event_data *data) { uint8_t ch = data->channel; MIDI_EVENT_DEBUG(__FUNCTION__,ch, data->data.value); mdi->channel[ch].reg_data = (mdi->channel[ch].reg_data & 0x3F80) | data->data.value; mdi->channel[ch].reg_non = 0; } void _WM_do_control_registered_param_course(struct _mdi *mdi, struct _event_data *data) { uint8_t ch = data->channel; MIDI_EVENT_DEBUG(__FUNCTION__,ch, data->data.value); mdi->channel[ch].reg_data = (mdi->channel[ch].reg_data & 0x7F) | (data->data.value << 7); mdi->channel[ch].reg_non = 0; } void _WM_do_control_channel_sound_off(struct _mdi *mdi, struct _event_data *data) { struct _note *note_data = mdi->note; uint8_t ch = data->channel; MIDI_EVENT_DEBUG(__FUNCTION__,ch, data->data.value); if (note_data) { do { if ((note_data->noteid >> 8) == ch) { note_data->active = 0; if (note_data->replay) { note_data->replay = NULL; } } note_data = note_data->next; } while (note_data); } } void _WM_do_control_channel_controllers_off(struct _mdi *mdi, struct _event_data *data) { uint8_t ch = data->channel; MIDI_EVENT_DEBUG(__FUNCTION__,ch, data->data.value); mdi->channel[ch].expression = 127; mdi->channel[ch].pressure = 127; mdi->channel[ch].reg_data = 0xffff; mdi->channel[ch].pitch_range = 200; mdi->channel[ch].pitch = 0; mdi->channel[ch].pitch_adjust = 0; mdi->channel[ch].hold = 0; _WM_AdjustChannelVolumes(mdi, ch); } void _WM_do_control_channel_notes_off(struct _mdi *mdi, struct _event_data *data) { struct _note *note_data = mdi->note; uint8_t ch = data->channel; MIDI_EVENT_DEBUG(__FUNCTION__,ch, data->data.value); if (mdi->channel[ch].isdrum) return; if (note_data) { do { if ((note_data->noteid >> 8) == ch) { if (!note_data->hold) { if (note_data->modes & SAMPLE_ENVELOPE) { if (note_data->env < 5) { if (note_data->env_level > note_data->sample->env_target[5]) { note_data->env_inc = -note_data->sample->env_rate[5]; } else { note_data->env_inc = note_data->sample->env_rate[5]; } note_data->env = 5; } } } else { note_data->hold |= HOLD_OFF; } } note_data = note_data->next; } while (note_data); } } void _WM_do_control_dummy(struct _mdi *mdi, struct _event_data *data) { #ifdef DEBUG_MIDI uint8_t ch = data->channel; MIDI_EVENT_DEBUG(__FUNCTION__, ch, data->data.value); #else UNUSED(data); #endif UNUSED(mdi); } void _WM_do_patch(struct _mdi *mdi, struct _event_data *data) { uint8_t ch = data->channel; MIDI_EVENT_DEBUG(__FUNCTION__,ch, data->data.value); if (!mdi->channel[ch].isdrum) { mdi->channel[ch].patch = _WM_get_patch_data(mdi, ((mdi->channel[ch].bank << 8) | data->data.value)); } else { mdi->channel[ch].bank = data->data.value; } } void _WM_do_channel_pressure(struct _mdi *mdi, struct _event_data *data) { uint8_t ch = data->channel; struct _note *note_data = mdi->note; MIDI_EVENT_DEBUG(__FUNCTION__,ch, data->data.value); mdi->channel[ch].pressure = data->data.value; while (note_data) { if (!note_data->ignore_chan_events) { if ((note_data->noteid >> 8) == ch) { note_data->velocity = data->data.value & 0xff; _WM_AdjustNoteVolumes(mdi, ch, note_data); if (note_data->replay) { note_data->replay->velocity = data->data.value & 0xff; _WM_AdjustNoteVolumes(mdi, ch, note_data->replay); } } } note_data = note_data->next; } } void _WM_do_pitch(struct _mdi *mdi, struct _event_data *data) { struct _note *note_data = mdi->note; uint8_t ch = data->channel; MIDI_EVENT_DEBUG(__FUNCTION__,ch, data->data.value); mdi->channel[ch].pitch = data->data.value - 0x2000; if (mdi->channel[ch].pitch < 0) { mdi->channel[ch].pitch_adjust = mdi->channel[ch].pitch_range * mdi->channel[ch].pitch / 8192; } else { mdi->channel[ch].pitch_adjust = mdi->channel[ch].pitch_range * mdi->channel[ch].pitch / 8191; } if (note_data) { do { if ((note_data->noteid >> 8) == ch) { note_data->sample_inc = get_inc(mdi, note_data); } note_data = note_data->next; } while (note_data); } } void _WM_do_sysex_roland_drum_track(struct _mdi *mdi, struct _event_data *data) { uint8_t ch = data->channel; MIDI_EVENT_DEBUG(__FUNCTION__,ch, data->data.value); if (data->data.value > 0) { mdi->channel[ch].isdrum = 1; mdi->channel[ch].patch = NULL; } else { mdi->channel[ch].isdrum = 0; mdi->channel[ch].patch = _WM_get_patch_data(mdi, 0); } } void _WM_do_sysex_gm_reset(struct _mdi *mdi, struct _event_data *data) { int i; if (data != NULL) { MIDI_EVENT_DEBUG(__FUNCTION__,data->channel, data->data.value); } else { MIDI_EVENT_DEBUG(__FUNCTION__,0, 0); } for (i = 0; i < 16; i++) { mdi->channel[i].bank = 0; if (i != 9) { mdi->channel[i].patch = _WM_get_patch_data(mdi, 0); } else { mdi->channel[i].patch = NULL; } mdi->channel[i].hold = 0; mdi->channel[i].volume = 100; mdi->channel[i].pressure = 127; mdi->channel[i].expression = 127; mdi->channel[i].balance = 64; mdi->channel[i].pan = 64; mdi->channel[i].pitch = 0; mdi->channel[i].pitch_range = 200; mdi->channel[i].reg_data = 0xFFFF; mdi->channel[i].isdrum = 0; } /* I would not expect notes to be active when this event triggers but we'll adjust active notes as well just in case */ _WM_AdjustChannelVolumes(mdi,16); // A setting > 15 adjusts all channels mdi->channel[9].isdrum = 1; } void _WM_do_sysex_roland_reset(struct _mdi *mdi, struct _event_data *data) { #ifdef DEBUG_MIDI uint8_t ch = data->channel; MIDI_EVENT_DEBUG(__FUNCTION__, ch, data->data.value); #else UNUSED(data); #endif _WM_do_sysex_gm_reset(mdi,data); } void _WM_do_sysex_yamaha_reset(struct _mdi *mdi, struct _event_data *data) { #ifdef DEBUG_MIDI uint8_t ch = data->channel; MIDI_EVENT_DEBUG(__FUNCTION__, ch, data->data.value); #else UNUSED(data); #endif _WM_do_sysex_gm_reset(mdi,data); } void _WM_Release_Allowance(struct _mdi *mdi) { uint32_t release = 0; uint32_t longest_release = 0; struct _note *note = mdi->note; while (note != NULL) { if (note->modes & SAMPLE_ENVELOPE) { //ensure envelope isin a release state if (note->env < 4) { note->env = 4; } // make sure this is set note->env_inc = -note->sample->env_rate[note->env]; release = note->env_level / -note->env_inc; } else { // Sample release if (note->modes & SAMPLE_LOOP) { note->modes ^= SAMPLE_LOOP; } release = note->sample->data_length - note->sample_pos; } if (release > longest_release) longest_release = release; note->replay = NULL; note = note->next; } mdi->samples_to_mix = longest_release; return; } void _WM_do_meta_endoftrack(struct _mdi *mdi, struct _event_data *data) { /* placeholder function so we can record eot in the event stream * for conversion function _WM_Event2Midi */ #ifdef DEBUG_MIDI uint8_t ch = data->channel; MIDI_EVENT_DEBUG(__FUNCTION__, ch, data->data.value); #else UNUSED(data); #endif _WM_Release_Allowance(mdi); return; } void _WM_do_meta_tempo(struct _mdi *mdi, struct _event_data *data) { /* placeholder function so we can record tempo in the event stream * for conversion function _WM_Event2Midi */ #ifdef DEBUG_MIDI uint8_t ch = data->channel; MIDI_EVENT_DEBUG(__FUNCTION__, ch, data->data.value); #else UNUSED(data); #endif UNUSED(mdi); return; } void _WM_do_meta_timesignature(struct _mdi *mdi, struct _event_data *data) { /* placeholder function so we can record tempo in the event stream * for conversion function _WM_Event2Midi */ #ifdef DEBUG_MIDI uint8_t ch = data->channel; MIDI_EVENT_DEBUG(__FUNCTION__, ch, data->data.value); #else UNUSED(data); #endif UNUSED(mdi); return; } void _WM_do_meta_keysignature(struct _mdi *mdi, struct _event_data *data) { /* placeholder function so we can record tempo in the event stream * for conversion function _WM_Event2Midi */ #ifdef DEBUG_MIDI uint8_t ch = data->channel; MIDI_EVENT_DEBUG(__FUNCTION__, ch, data->data.value); #else UNUSED(data); #endif UNUSED(mdi); return; } void _WM_do_meta_sequenceno(struct _mdi *mdi, struct _event_data *data) { /* placeholder function so we can record tempo in the event stream * for conversion function _WM_Event2Midi */ #ifdef DEBUG_MIDI uint8_t ch = data->channel; MIDI_EVENT_DEBUG(__FUNCTION__, ch, data->data.value); #else UNUSED(data); #endif UNUSED(mdi); return; } void _WM_do_meta_channelprefix(struct _mdi *mdi, struct _event_data *data) { /* placeholder function so we can record tempo in the event stream * for conversion function _WM_Event2Midi */ #ifdef DEBUG_MIDI uint8_t ch = data->channel; MIDI_EVENT_DEBUG(__FUNCTION__, ch, data->data.value); #else UNUSED(data); #endif UNUSED(mdi); return; } void _WM_do_meta_portprefix(struct _mdi *mdi, struct _event_data *data) { /* placeholder function so we can record tempo in the event stream * for conversion function _WM_Event2Midi */ #ifdef DEBUG_MIDI uint8_t ch = data->channel; MIDI_EVENT_DEBUG(__FUNCTION__, ch, data->data.value); #else UNUSED(data); #endif UNUSED(mdi); return; } void _WM_do_meta_smpteoffset(struct _mdi *mdi, struct _event_data *data) { /* placeholder function so we can record tempo in the event stream * for conversion function _WM_Event2Midi */ #ifdef DEBUG_MIDI uint8_t ch = data->channel; MIDI_EVENT_DEBUG(__FUNCTION__, ch, data->data.value); #else UNUSED(data); #endif UNUSED(mdi); return; } void _WM_do_meta_text(struct _mdi *mdi, struct _event_data *data) { /* placeholder function so we can record tempo in the event stream * for conversion function _WM_Event2Midi */ #ifdef DEBUG_MIDI uint8_t ch = data->channel; MIDI_EVENT_SDEBUG(__FUNCTION__, ch, data->data.string); #endif if (mdi->extra_info.mixer_options & WM_MO_TEXTASLYRIC) { mdi->lyric = data->data.string; } return; } void _WM_do_meta_copyright(struct _mdi *mdi, struct _event_data *data) { /* placeholder function so we can record tempo in the event stream * for conversion function _WM_Event2Midi */ #ifdef DEBUG_MIDI uint8_t ch = data->channel; MIDI_EVENT_SDEBUG(__FUNCTION__, ch, data->data.string); #else UNUSED(data); #endif UNUSED(mdi); return; } void _WM_do_meta_trackname(struct _mdi *mdi, struct _event_data *data) { /* placeholder function so we can record tempo in the event stream * for conversion function _WM_Event2Midi */ #ifdef DEBUG_MIDI uint8_t ch = data->channel; MIDI_EVENT_SDEBUG(__FUNCTION__, ch, data->data.string); #else UNUSED(data); #endif UNUSED(mdi); return; } void _WM_do_meta_instrumentname(struct _mdi *mdi, struct _event_data *data) { /* placeholder function so we can record tempo in the event stream * for conversion function _WM_Event2Midi */ #ifdef DEBUG_MIDI uint8_t ch = data->channel; MIDI_EVENT_SDEBUG(__FUNCTION__, ch, data->data.string); #else UNUSED(data); #endif UNUSED(mdi); return; } void _WM_do_meta_lyric(struct _mdi *mdi, struct _event_data *data) { /* placeholder function so we can record tempo in the event stream * for conversion function _WM_Event2Midi */ #ifdef DEBUG_MIDI uint8_t ch = data->channel; MIDI_EVENT_SDEBUG(__FUNCTION__, ch, data->data.string); #endif if (!(mdi->extra_info.mixer_options & WM_MO_TEXTASLYRIC)) { mdi->lyric = data->data.string; } return; } void _WM_do_meta_marker(struct _mdi *mdi, struct _event_data *data) { /* placeholder function so we can record tempo in the event stream * for conversion function _WM_Event2Midi */ #ifdef DEBUG_MIDI uint8_t ch = data->channel; MIDI_EVENT_SDEBUG(__FUNCTION__, ch, data->data.string); #else UNUSED(data); #endif UNUSED(mdi); return; } void _WM_do_meta_cuepoint(struct _mdi *mdi, struct _event_data *data) { /* placeholder function so we can record tempo in the event stream * for conversion function _WM_Event2Midi */ #ifdef DEBUG_MIDI uint8_t ch = data->channel; MIDI_EVENT_SDEBUG(__FUNCTION__, ch, data->data.string); #else UNUSED(data); #endif UNUSED(mdi); return; } void _WM_ResetToStart(struct _mdi *mdi) { struct _event * event = NULL; mdi->current_event = mdi->events; mdi->samples_to_mix = 0; mdi->extra_info.current_sample = 0; _WM_do_sysex_gm_reset(mdi, NULL); /* Ensure last event is NULL */ _WM_CheckEventMemoryPool(mdi); mdi->events[mdi->event_count].do_event = NULL; mdi->events[mdi->event_count].event_data.channel = 0; mdi->events[mdi->event_count].event_data.data.value = 0; mdi->events[mdi->event_count].samples_to_next = 0; if (_WM_MixerOptions & WM_MO_STRIPSILENCE) { event = mdi->events; /* Scan for first note on removing any samples as we go */ if (event->do_event != *_WM_do_note_on) { do { if (event->samples_to_next != 0) { mdi->extra_info.approx_total_samples -= event->samples_to_next; event->samples_to_next = 0; } event++; if (event == NULL) break; } while (event->do_event != *_WM_do_note_on); } /* Reverse scan for last note off removing any samples as we go */ event = &mdi->events[mdi->event_count - 1]; if (event->do_event != *_WM_do_note_off) { do { mdi->extra_info.approx_total_samples -= event->samples_to_next; event->samples_to_next = 0; if (event == mdi->events) break; /* just to be safe */ event--; } while (event->do_event != *_WM_do_note_off); } mdi->extra_info.approx_total_samples -= event->samples_to_next; event->samples_to_next = 0; } } int _WM_midi_setup_divisions(struct _mdi *mdi, uint32_t divisions) { MIDI_EVENT_DEBUG(__FUNCTION__,0,0); _WM_CheckEventMemoryPool(mdi); mdi->events[mdi->event_count].do_event = *_WM_do_midi_divisions; mdi->events[mdi->event_count].event_data.channel = 0; mdi->events[mdi->event_count].event_data.data.value = divisions; mdi->events[mdi->event_count].samples_to_next = 0; mdi->event_count++; return (0); } int _WM_midi_setup_noteoff(struct _mdi *mdi, uint8_t channel, uint8_t note, uint8_t velocity) { MIDI_EVENT_DEBUG(__FUNCTION__,channel, note); _WM_CheckEventMemoryPool(mdi); note &= 0x7f; /* silently bound note to 0..127 (github bug #180) */ mdi->events[mdi->event_count].do_event = *_WM_do_note_off; mdi->events[mdi->event_count].event_data.channel = channel; mdi->events[mdi->event_count].event_data.data.value = (note << 8) | velocity; mdi->events[mdi->event_count].samples_to_next = 0; mdi->event_count++; return (0); } static int midi_setup_noteon(struct _mdi *mdi, uint8_t channel, uint8_t note, uint8_t velocity) { MIDI_EVENT_DEBUG(__FUNCTION__,channel, note); _WM_CheckEventMemoryPool(mdi); note &= 0x7f; /* silently bound note to 0..127 (github bug #180) */ mdi->events[mdi->event_count].do_event = *_WM_do_note_on; mdi->events[mdi->event_count].event_data.channel = channel; mdi->events[mdi->event_count].event_data.data.value = (note << 8) | velocity; mdi->events[mdi->event_count].samples_to_next = 0; mdi->event_count++; if (mdi->channel[channel].isdrum) _WM_load_patch(mdi, ((mdi->channel[channel].bank << 8) | (note | 0x80))); return (0); } static int midi_setup_aftertouch(struct _mdi *mdi, uint8_t channel, uint8_t note, uint8_t pressure) { MIDI_EVENT_DEBUG(__FUNCTION__,channel, note); _WM_CheckEventMemoryPool(mdi); note &= 0x7f; /* silently bound note to 0..127 (github bug #180) */ mdi->events[mdi->event_count].do_event = *_WM_do_aftertouch; mdi->events[mdi->event_count].event_data.channel = channel; mdi->events[mdi->event_count].event_data.data.value = (note << 8) | pressure; mdi->events[mdi->event_count].samples_to_next = 0; mdi->event_count++; return (0); } static int midi_setup_control(struct _mdi *mdi, uint8_t channel, uint8_t controller, uint8_t setting) { void (*tmp_event)(struct _mdi *mdi, struct _event_data *data) = NULL; MIDI_EVENT_DEBUG(__FUNCTION__,channel, controller); switch (controller) { /* ********************************************************************** FIXME: Need to add dummy events for MIDI events we don't support. There is no reason not to store unsupported events in light of our out to midi option. ********************************************************************** */ case 0: tmp_event = *_WM_do_control_bank_select; mdi->channel[channel].bank = setting; break; case 6: tmp_event = *_WM_do_control_data_entry_course; break; case 7: tmp_event = *_WM_do_control_channel_volume; mdi->channel[channel].volume = setting; break; case 8: tmp_event = *_WM_do_control_channel_balance; break; case 10: tmp_event = *_WM_do_control_channel_pan; break; case 11: tmp_event = *_WM_do_control_channel_expression; break; case 38: tmp_event = *_WM_do_control_data_entry_fine; break; case 64: tmp_event = *_WM_do_control_channel_hold; break; case 96: tmp_event = *_WM_do_control_data_increment; break; case 97: tmp_event = *_WM_do_control_data_decrement; break; case 98: tmp_event = *_WM_do_control_non_registered_param_fine; break; case 99: tmp_event = *_WM_do_control_non_registered_param_course; break; case 100: tmp_event = *_WM_do_control_registered_param_fine; break; case 101: tmp_event = *_WM_do_control_registered_param_course; break; case 120: tmp_event = *_WM_do_control_channel_sound_off; break; case 121: tmp_event = *_WM_do_control_channel_controllers_off; break; case 123: tmp_event = *_WM_do_control_channel_notes_off; break; default: tmp_event = *_WM_do_control_dummy; break; } _WM_CheckEventMemoryPool(mdi); mdi->events[mdi->event_count].do_event = tmp_event; mdi->events[mdi->event_count].event_data.channel = channel; if (tmp_event != *_WM_do_control_dummy) { mdi->events[mdi->event_count].event_data.data.value = setting; } else { mdi->events[mdi->event_count].event_data.data.value = (controller << 8) | setting; } mdi->events[mdi->event_count].samples_to_next = 0; mdi->event_count++; return (0); } static int midi_setup_patch(struct _mdi *mdi, uint8_t channel, uint8_t patch) { MIDI_EVENT_DEBUG(__FUNCTION__,channel, patch); _WM_CheckEventMemoryPool(mdi); mdi->events[mdi->event_count].do_event = *_WM_do_patch; mdi->events[mdi->event_count].event_data.channel = channel; mdi->events[mdi->event_count].event_data.data.value = patch; mdi->events[mdi->event_count].samples_to_next = 0; mdi->event_count++; if (mdi->channel[channel].isdrum) { mdi->channel[channel].bank = patch; } else { _WM_load_patch(mdi, ((mdi->channel[channel].bank << 8) | patch)); mdi->channel[channel].patch = _WM_get_patch_data(mdi, ((mdi->channel[channel].bank << 8) | patch)); } return (0); } static int midi_setup_channel_pressure(struct _mdi *mdi, uint8_t channel, uint8_t pressure) { MIDI_EVENT_DEBUG(__FUNCTION__,channel, pressure); _WM_CheckEventMemoryPool(mdi); mdi->events[mdi->event_count].do_event = *_WM_do_channel_pressure; mdi->events[mdi->event_count].event_data.channel = channel; mdi->events[mdi->event_count].event_data.data.value = pressure; mdi->events[mdi->event_count].samples_to_next = 0; mdi->event_count++; return (0); } static int midi_setup_pitch(struct _mdi *mdi, uint8_t channel, uint16_t pitch) { MIDI_EVENT_DEBUG(__FUNCTION__,channel, pitch); _WM_CheckEventMemoryPool(mdi); mdi->events[mdi->event_count].do_event = *_WM_do_pitch; mdi->events[mdi->event_count].event_data.channel = channel; mdi->events[mdi->event_count].event_data.data.value = pitch; mdi->events[mdi->event_count].samples_to_next = 0; mdi->event_count++; return (0); } static int midi_setup_sysex_roland_drum_track(struct _mdi *mdi, uint8_t channel, uint16_t setting) { MIDI_EVENT_DEBUG(__FUNCTION__,channel, setting); _WM_CheckEventMemoryPool(mdi); mdi->events[mdi->event_count].do_event = _WM_do_sysex_roland_drum_track; mdi->events[mdi->event_count].event_data.channel = channel; mdi->events[mdi->event_count].event_data.data.value = setting; mdi->events[mdi->event_count].samples_to_next = 0; mdi->event_count++; if (setting > 0) { mdi->channel[channel].isdrum = 1; } else { mdi->channel[channel].isdrum = 0; } return (0); } static int midi_setup_sysex_gm_reset(struct _mdi *mdi) { MIDI_EVENT_DEBUG(__FUNCTION__,0,0); _WM_CheckEventMemoryPool(mdi); mdi->events[mdi->event_count].do_event = *_WM_do_sysex_roland_reset; mdi->events[mdi->event_count].event_data.channel = 0; mdi->events[mdi->event_count].event_data.data.value = 0; mdi->events[mdi->event_count].samples_to_next = 0; mdi->event_count++; return (0); } static int midi_setup_sysex_roland_reset(struct _mdi *mdi) { MIDI_EVENT_DEBUG(__FUNCTION__,0,0); _WM_CheckEventMemoryPool(mdi); mdi->events[mdi->event_count].do_event = *_WM_do_sysex_roland_reset; mdi->events[mdi->event_count].event_data.channel = 0; mdi->events[mdi->event_count].event_data.data.value = 0; mdi->events[mdi->event_count].samples_to_next = 0; mdi->event_count++; return (0); } static int midi_setup_sysex_yamaha_reset(struct _mdi *mdi) { MIDI_EVENT_DEBUG(__FUNCTION__,0,0); _WM_CheckEventMemoryPool(mdi); mdi->events[mdi->event_count].do_event = *_WM_do_sysex_roland_reset; mdi->events[mdi->event_count].event_data.channel = 0; mdi->events[mdi->event_count].event_data.data.value = 0; mdi->events[mdi->event_count].samples_to_next = 0; mdi->event_count++; return (0); } int _WM_midi_setup_endoftrack(struct _mdi *mdi) { MIDI_EVENT_DEBUG(__FUNCTION__,0,0); _WM_CheckEventMemoryPool(mdi); mdi->events[mdi->event_count].do_event = *_WM_do_meta_endoftrack; mdi->events[mdi->event_count].event_data.channel = 0; mdi->events[mdi->event_count].event_data.data.value = 0; mdi->events[mdi->event_count].samples_to_next = 0; mdi->event_count++; return (0); } int _WM_midi_setup_tempo(struct _mdi *mdi, uint32_t setting) { MIDI_EVENT_DEBUG(__FUNCTION__,0,setting); _WM_CheckEventMemoryPool(mdi); mdi->events[mdi->event_count].do_event = *_WM_do_meta_tempo; mdi->events[mdi->event_count].event_data.channel = 0; mdi->events[mdi->event_count].event_data.data.value = setting; mdi->events[mdi->event_count].samples_to_next = 0; mdi->event_count++; return (0); } static int midi_setup_timesignature(struct _mdi *mdi, uint32_t setting) { MIDI_EVENT_DEBUG(__FUNCTION__,0, setting); _WM_CheckEventMemoryPool(mdi); mdi->events[mdi->event_count].do_event = *_WM_do_meta_timesignature; mdi->events[mdi->event_count].event_data.channel = 0; mdi->events[mdi->event_count].event_data.data.value = setting; mdi->events[mdi->event_count].samples_to_next = 0; mdi->event_count++; return (0); } static int midi_setup_keysignature(struct _mdi *mdi, uint32_t setting) { MIDI_EVENT_DEBUG(__FUNCTION__,0, setting); _WM_CheckEventMemoryPool(mdi); mdi->events[mdi->event_count].do_event = *_WM_do_meta_keysignature; mdi->events[mdi->event_count].event_data.channel = 0; mdi->events[mdi->event_count].event_data.data.value = setting; mdi->events[mdi->event_count].samples_to_next = 0; mdi->event_count++; return (0); } static int midi_setup_sequenceno(struct _mdi *mdi, uint32_t setting) { MIDI_EVENT_DEBUG(__FUNCTION__,0, setting); _WM_CheckEventMemoryPool(mdi); mdi->events[mdi->event_count].do_event = *_WM_do_meta_sequenceno; mdi->events[mdi->event_count].event_data.channel = 0; mdi->events[mdi->event_count].event_data.data.value = setting; mdi->events[mdi->event_count].samples_to_next = 0; mdi->event_count++; return (0); } static int midi_setup_channelprefix(struct _mdi *mdi, uint32_t setting) { MIDI_EVENT_DEBUG(__FUNCTION__,0, setting); _WM_CheckEventMemoryPool(mdi); mdi->events[mdi->event_count].do_event = *_WM_do_meta_channelprefix; mdi->events[mdi->event_count].event_data.channel = 0; mdi->events[mdi->event_count].event_data.data.value = setting; mdi->events[mdi->event_count].samples_to_next = 0; mdi->event_count++; return (0); } static int midi_setup_portprefix(struct _mdi *mdi, uint32_t setting) { MIDI_EVENT_DEBUG(__FUNCTION__,0, setting); _WM_CheckEventMemoryPool(mdi); mdi->events[mdi->event_count].do_event = *_WM_do_meta_portprefix; mdi->events[mdi->event_count].event_data.channel = 0; mdi->events[mdi->event_count].event_data.data.value = setting; mdi->events[mdi->event_count].samples_to_next = 0; mdi->event_count++; return (0); } static int midi_setup_smpteoffset(struct _mdi *mdi, uint32_t setting) { MIDI_EVENT_DEBUG(__FUNCTION__,0, setting); _WM_CheckEventMemoryPool(mdi); mdi->events[mdi->event_count].do_event = *_WM_do_meta_smpteoffset; mdi->events[mdi->event_count].event_data.channel = 0; mdi->events[mdi->event_count].event_data.data.value = setting; mdi->events[mdi->event_count].samples_to_next = 0; mdi->event_count++; return (0); } static void strip_text(char * text) { char * ch_loc = NULL; ch_loc = strrchr(text, '\n'); while (ch_loc != NULL) { *ch_loc = ' '; ch_loc = strrchr(text, '\n'); } ch_loc = strrchr(text, '\r'); while (ch_loc != NULL) { *ch_loc = ' '; ch_loc = strrchr(text, '\r'); } } static int midi_setup_text(struct _mdi *mdi, char * text) { MIDI_EVENT_SDEBUG(__FUNCTION__,0, text); strip_text(text); _WM_CheckEventMemoryPool(mdi); mdi->events[mdi->event_count].do_event = *_WM_do_meta_text; mdi->events[mdi->event_count].event_data.channel = 0; mdi->events[mdi->event_count].event_data.data.string = text; mdi->events[mdi->event_count].samples_to_next = 0; mdi->event_count++; return (0); } static int midi_setup_copyright(struct _mdi *mdi, char * text) { MIDI_EVENT_SDEBUG(__FUNCTION__,0, text); strip_text(text); _WM_CheckEventMemoryPool(mdi); mdi->events[mdi->event_count].do_event = *_WM_do_meta_copyright; mdi->events[mdi->event_count].event_data.channel = 0; mdi->events[mdi->event_count].event_data.data.string = text; mdi->events[mdi->event_count].samples_to_next = 0; mdi->event_count++; return (0); } static int midi_setup_trackname(struct _mdi *mdi, char * text) { MIDI_EVENT_SDEBUG(__FUNCTION__,0, text); strip_text(text); _WM_CheckEventMemoryPool(mdi); mdi->events[mdi->event_count].do_event = *_WM_do_meta_trackname; mdi->events[mdi->event_count].event_data.channel = 0; mdi->events[mdi->event_count].event_data.data.string = text; mdi->events[mdi->event_count].samples_to_next = 0; mdi->event_count++; return (0); } static int midi_setup_instrumentname(struct _mdi *mdi, char * text) { MIDI_EVENT_SDEBUG(__FUNCTION__,0, text); strip_text(text); _WM_CheckEventMemoryPool(mdi); mdi->events[mdi->event_count].do_event = *_WM_do_meta_instrumentname; mdi->events[mdi->event_count].event_data.channel = 0; mdi->events[mdi->event_count].event_data.data.string = text; mdi->events[mdi->event_count].samples_to_next = 0; mdi->event_count++; return (0); } static int midi_setup_lyric(struct _mdi *mdi, char * text) { MIDI_EVENT_SDEBUG(__FUNCTION__,0, text); strip_text(text); _WM_CheckEventMemoryPool(mdi); mdi->events[mdi->event_count].do_event = *_WM_do_meta_lyric; mdi->events[mdi->event_count].event_data.channel = 0; mdi->events[mdi->event_count].event_data.data.string = text; mdi->events[mdi->event_count].samples_to_next = 0; mdi->event_count++; return (0); } static int midi_setup_marker(struct _mdi *mdi, char * text) { MIDI_EVENT_SDEBUG(__FUNCTION__,0, text); strip_text(text); _WM_CheckEventMemoryPool(mdi); mdi->events[mdi->event_count].do_event = *_WM_do_meta_marker; mdi->events[mdi->event_count].event_data.channel = 0; mdi->events[mdi->event_count].event_data.data.string = text; mdi->events[mdi->event_count].samples_to_next = 0; mdi->event_count++; return (0); } static int midi_setup_cuepoint(struct _mdi *mdi, char * text) { MIDI_EVENT_SDEBUG(__FUNCTION__,0, text); strip_text(text); _WM_CheckEventMemoryPool(mdi); mdi->events[mdi->event_count].do_event = *_WM_do_meta_cuepoint; mdi->events[mdi->event_count].event_data.channel = 0; mdi->events[mdi->event_count].event_data.data.string = text; mdi->events[mdi->event_count].samples_to_next = 0; mdi->event_count++; return (0); } struct _mdi * _WM_initMDI(void) { struct _mdi *mdi; mdi = (struct _mdi *) malloc(sizeof(struct _mdi)); memset(mdi, 0, (sizeof(struct _mdi))); mdi->extra_info.copyright = NULL; mdi->extra_info.mixer_options = _WM_MixerOptions; _WM_load_patch(mdi, 0x0000); mdi->events_size = MEM_CHUNK; mdi->events = (struct _event *) malloc(mdi->events_size * sizeof(struct _event)); mdi->event_count = 0; mdi->current_event = mdi->events; mdi->samples_to_mix = 0; mdi->extra_info.current_sample = 0; mdi->extra_info.total_midi_time = 0; mdi->extra_info.approx_total_samples = 0; mdi->dyn_vol = 1.0; mdi->dyn_vol_adjust = 0.0; mdi->dyn_vol_peak = 0; mdi->dyn_vol_to_reach = 1.0; mdi->is_type2 = 0; mdi->lyric = NULL; _WM_do_sysex_gm_reset(mdi, NULL); return (mdi); } void _WM_freeMDI(struct _mdi *mdi) { struct _sample *tmp_sample; uint32_t i; if (mdi->patch_count != 0) { _WM_Lock(&_WM_patch_lock); for (i = 0; i < mdi->patch_count; i++) { mdi->patches[i]->inuse_count--; if (mdi->patches[i]->inuse_count == 0) { /* free samples here */ while (mdi->patches[i]->first_sample) { tmp_sample = mdi->patches[i]->first_sample->next; free(mdi->patches[i]->first_sample->data); free(mdi->patches[i]->first_sample); mdi->patches[i]->first_sample = tmp_sample; } mdi->patches[i]->loaded = 0; } } _WM_Unlock(&_WM_patch_lock); free(mdi->patches); } if (mdi->event_count != 0) { for (i = 0; i < mdi->event_count; i++) { /* Free up the string event storage */ if (mdi->events[i].do_event == _WM_do_meta_text) { free(mdi->events[i].event_data.data.string); } else if (mdi->events[i].do_event == _WM_do_meta_text) { free(mdi->events[i].event_data.data.string); } else if (mdi->events[i].do_event == _WM_do_meta_copyright) { free(mdi->events[i].event_data.data.string); } else if (mdi->events[i].do_event == _WM_do_meta_trackname) { free(mdi->events[i].event_data.data.string); } else if (mdi->events[i].do_event == _WM_do_meta_instrumentname) { free(mdi->events[i].event_data.data.string); } else if (mdi->events[i].do_event == _WM_do_meta_lyric) { free(mdi->events[i].event_data.data.string); } else if (mdi->events[i].do_event == _WM_do_meta_marker) { free(mdi->events[i].event_data.data.string); } else if (mdi->events[i].do_event == _WM_do_meta_cuepoint) { free(mdi->events[i].event_data.data.string); } } } free(mdi->events); _WM_free_reverb(mdi->reverb); free(mdi->mix_buffer); free(mdi); } uint32_t _WM_SetupMidiEvent(struct _mdi *mdi, uint8_t * event_data, uint32_t input_length, uint8_t running_event) { /* Only add standard MIDI and Sysex events in here. Non-standard events need to be handled by calling function to avoid compatibility issues. TODO: Add value limit checks */ uint32_t ret_cnt = 0; uint8_t command = 0; uint8_t channel = 0; uint8_t data_1 = 0; uint8_t data_2 = 0; char *text = NULL; if (!input_length) goto shortbuf; if (event_data[0] >= 0x80) { command = *event_data & 0xf0; channel = *event_data++ & 0x0f; ret_cnt++; if (--input_length == 0) goto shortbuf; } else { command = running_event & 0xf0; channel = running_event & 0x0f; } switch(command) { case 0x80: _SETUP_NOTEOFF: if (input_length < 2) goto shortbuf; data_1 = *event_data++; data_2 = *event_data++; _WM_midi_setup_noteoff(mdi, channel, data_1, data_2); ret_cnt += 2; break; case 0x90: if (event_data[1] == 0) goto _SETUP_NOTEOFF; /* A velocity of 0 in a note on is actually a note off */ if (input_length < 2) goto shortbuf; data_1 = *event_data++; data_2 = *event_data++; midi_setup_noteon(mdi, channel, data_1, data_2); ret_cnt += 2; break; case 0xa0: if (input_length < 2) goto shortbuf; data_1 = *event_data++; data_2 = *event_data++; midi_setup_aftertouch(mdi, channel, data_1, data_2); ret_cnt += 2; break; case 0xb0: if (input_length < 2) goto shortbuf; data_1 = *event_data++; data_2 = *event_data++; midi_setup_control(mdi, channel, data_1, data_2); ret_cnt += 2; break; case 0xc0: data_1 = *event_data++; midi_setup_patch(mdi, channel, data_1); ret_cnt++; break; case 0xd0: data_1 = *event_data++; midi_setup_channel_pressure(mdi, channel, data_1); ret_cnt++; break; case 0xe0: if (input_length < 2) goto shortbuf; data_1 = *event_data++; data_2 = *event_data++; midi_setup_pitch(mdi, channel, ((data_2 << 7) | (data_1 & 0x7f))); ret_cnt += 2; break; case 0xf0: if (channel == 0x0f) { /* MIDI Meta Events */ uint32_t tmp_length = 0; if ((event_data[0] == 0x00) && (event_data[1] == 0x02)) { /* Sequence Number We only setting this up here for WM_Event2Midi function */ if (input_length < 4) goto shortbuf; midi_setup_sequenceno(mdi, ((event_data[2] << 8) + event_data[3])); ret_cnt += 4; } else if (event_data[0] == 0x01) { /* Text Event */ /* Get Length */ event_data++; ret_cnt++; if (--input_length && *event_data > 0x7f) { do { if (!input_length) break; tmp_length = (tmp_length << 7) + (*event_data & 0x7f); event_data++; input_length--; ret_cnt++; } while (*event_data > 0x7f); } if (!input_length) goto shortbuf; tmp_length = (tmp_length << 7) + (*event_data & 0x7f); event_data++; ret_cnt++; if (--input_length < tmp_length) goto shortbuf; if (!tmp_length) break;/* broken file? */ text = (char *) malloc(tmp_length + 1); memcpy(text, event_data, tmp_length); text[tmp_length] = '\0'; midi_setup_text(mdi, text); ret_cnt += tmp_length; } else if (event_data[0] == 0x02) { /* Copyright Event */ /* Get Length */ event_data++; ret_cnt++; if (--input_length && *event_data > 0x7f) { do { if (!input_length) break; tmp_length = (tmp_length << 7) + (*event_data & 0x7f); event_data++; input_length--; ret_cnt++; } while (*event_data > 0x7f); } if (!input_length) goto shortbuf; tmp_length = (tmp_length << 7) + (*event_data & 0x7f); event_data++; ret_cnt++; if (--input_length < tmp_length) goto shortbuf; if (!tmp_length) break;/* broken file? */ /* Copy copyright info in the getinfo struct */ if (mdi->extra_info.copyright) { mdi->extra_info.copyright = (char *) realloc(mdi->extra_info.copyright,(strlen(mdi->extra_info.copyright) + 1 + tmp_length + 1)); memcpy(&mdi->extra_info.copyright[strlen(mdi->extra_info.copyright) + 1], event_data, tmp_length); mdi->extra_info.copyright[strlen(mdi->extra_info.copyright) + 1 + tmp_length] = '\0'; mdi->extra_info.copyright[strlen(mdi->extra_info.copyright)] = '\n'; } else { mdi->extra_info.copyright = (char *) malloc(tmp_length + 1); memcpy(mdi->extra_info.copyright, event_data, tmp_length); mdi->extra_info.copyright[tmp_length] = '\0'; } /* NOTE: free'd when events are cleared during closure of mdi */ text = (char *) malloc(tmp_length + 1); memcpy(text, event_data, tmp_length); text[tmp_length] = '\0'; midi_setup_copyright(mdi, text); ret_cnt += tmp_length; } else if (event_data[0] == 0x03) { /* Track Name Event */ /* Get Length */ event_data++; ret_cnt++; if (--input_length && *event_data > 0x7f) { do { if (!input_length) break; tmp_length = (tmp_length << 7) + (*event_data & 0x7f); event_data++; input_length--; ret_cnt++; } while (*event_data > 0x7f); } if (!input_length) goto shortbuf; tmp_length = (tmp_length << 7) + (*event_data & 0x7f); event_data++; ret_cnt++; if (--input_length < tmp_length) goto shortbuf; if (!tmp_length) break;/* broken file? */ text = (char *) malloc(tmp_length + 1); memcpy(text, event_data, tmp_length); text[tmp_length] = '\0'; midi_setup_trackname(mdi, text); ret_cnt += tmp_length; } else if (event_data[0] == 0x04) { /* Instrument Name Event */ /* Get Length */ event_data++; ret_cnt++; if (--input_length && *event_data > 0x7f) { do { if (!input_length) break; tmp_length = (tmp_length << 7) + (*event_data & 0x7f); event_data++; input_length--; ret_cnt++; } while (*event_data > 0x7f); } if (!input_length) goto shortbuf; tmp_length = (tmp_length << 7) + (*event_data & 0x7f); event_data++; ret_cnt++; if (--input_length < tmp_length) goto shortbuf; if (!tmp_length) break;/* broken file? */ text = (char *) malloc(tmp_length + 1); memcpy(text, event_data, tmp_length); text[tmp_length] = '\0'; midi_setup_instrumentname(mdi, text); ret_cnt += tmp_length; } else if (event_data[0] == 0x05) { /* Lyric Event */ /* Get Length */ event_data++; ret_cnt++; if (--input_length && *event_data > 0x7f) { do { if (!input_length) break; tmp_length = (tmp_length << 7) + (*event_data & 0x7f); event_data++; input_length--; ret_cnt++; } while (*event_data > 0x7f); } if (!input_length) goto shortbuf; tmp_length = (tmp_length << 7) + (*event_data & 0x7f); event_data++; ret_cnt++; if (--input_length < tmp_length) goto shortbuf; if (!tmp_length) break;/* broken file? */ text = (char *) malloc(tmp_length + 1); memcpy(text, event_data, tmp_length); text[tmp_length] = '\0'; midi_setup_lyric(mdi, text); ret_cnt += tmp_length; } else if (event_data[0] == 0x06) { /* Marker Event */ /* Get Length */ event_data++; ret_cnt++; if (--input_length && *event_data > 0x7f) { do { if (!input_length) break; tmp_length = (tmp_length << 7) + (*event_data & 0x7f); event_data++; input_length--; ret_cnt++; } while (*event_data > 0x7f); } if (!input_length) goto shortbuf; tmp_length = (tmp_length << 7) + (*event_data & 0x7f); event_data++; ret_cnt++; if (--input_length < tmp_length) goto shortbuf; if (!tmp_length) break;/* broken file? */ text = (char *) malloc(tmp_length + 1); memcpy(text, event_data, tmp_length); text[tmp_length] = '\0'; midi_setup_marker(mdi, text); ret_cnt += tmp_length; } else if (event_data[0] == 0x07) { /* Cue Point Event */ /* Get Length */ event_data++; ret_cnt++; if (--input_length && *event_data > 0x7f) { do { if (!input_length) break; tmp_length = (tmp_length << 7) + (*event_data & 0x7f); event_data++; input_length--; ret_cnt++; } while (*event_data > 0x7f); } if (!input_length) goto shortbuf; tmp_length = (tmp_length << 7) + (*event_data & 0x7f); event_data++; ret_cnt++; if (--input_length < tmp_length) goto shortbuf; if (!tmp_length) break;/* broken file? */ text = (char *) malloc(tmp_length + 1); memcpy(text, event_data, tmp_length); text[tmp_length] = '\0'; midi_setup_cuepoint(mdi, text); ret_cnt += tmp_length; } else if ((event_data[0] == 0x20) && (event_data[1] == 0x01)) { /* Channel Prefix We only setting this up here for WM_Event2Midi function */ if (input_length < 3) goto shortbuf; midi_setup_channelprefix(mdi, event_data[2]); ret_cnt += 3; } else if ((event_data[0] == 0x21) && (event_data[1] == 0x01)) { /* Port Prefix We only setting this up here for WM_Event2Midi function */ if (input_length < 3) goto shortbuf; midi_setup_portprefix(mdi, event_data[2]); ret_cnt += 3; } else if ((event_data[0] == 0x2F) && (event_data[1] == 0x00)) { /* End of Track Deal with this inside calling function We only setting this up here for _WM_Event2Midi function */ if (input_length < 2) goto shortbuf; _WM_midi_setup_endoftrack(mdi); ret_cnt += 2; } else if ((event_data[0] == 0x51) && (event_data[1] == 0x03)) { /* Tempo Deal with this inside calling function. We only setting this up here for _WM_Event2Midi function */ if (input_length < 5) goto shortbuf; _WM_midi_setup_tempo(mdi, ((event_data[2] << 16) + (event_data[3] << 8) + event_data[4])); ret_cnt += 5; } else if ((event_data[0] == 0x54) && (event_data[1] == 0x05)) { if (input_length < 7) goto shortbuf; /* SMPTE Offset We only setting this up here for WM_Event2Midi function */ midi_setup_smpteoffset(mdi, ((event_data[3] << 24) + (event_data[4] << 16) + (event_data[5] << 8) + event_data[6])); /* Because this has 5 bytes of data we gonna "hack" it a little */ mdi->events[mdi->events_size - 1].event_data.channel = event_data[2]; ret_cnt += 7; } else if ((event_data[0] == 0x58) && (event_data[1] == 0x04)) { /* Time Signature We only setting this up here for WM_Event2Midi function */ if (input_length < 6) goto shortbuf; midi_setup_timesignature(mdi, ((event_data[2] << 24) + (event_data[3] << 16) + (event_data[4] << 8) + event_data[5])); ret_cnt += 6; } else if ((event_data[0] == 0x59) && (event_data[1] == 0x02)) { /* Key Signature We only setting this up here for WM_Event2Midi function */ if (input_length < 4) goto shortbuf; midi_setup_keysignature(mdi, ((event_data[2] << 8) + event_data[3])); ret_cnt += 4; } else { /* Unsupported Meta Event */ event_data++; ret_cnt++; if (--input_length && *event_data > 0x7f) { do { if (!input_length) break; tmp_length = (tmp_length << 7) + (*event_data & 0x7f); event_data++; input_length--; ret_cnt++; } while (*event_data > 0x7f); } if (!input_length) goto shortbuf; tmp_length = (tmp_length << 7) + (*event_data & 0x7f); ret_cnt++; ret_cnt += tmp_length; if (--input_length < tmp_length) goto shortbuf; } } else if ((channel == 0) || (channel == 7)) { /* Sysex Events */ uint32_t sysex_len = 0; uint8_t *sysex_store = NULL; if (*event_data > 0x7f) { do { if (!input_length) break; sysex_len = (sysex_len << 7) + (*event_data & 0x7F); event_data++; input_length--; ret_cnt++; } while (*event_data > 0x7f); } if (!input_length) goto shortbuf; sysex_len = (sysex_len << 7) + (*event_data & 0x7F); event_data++; ret_cnt++; if (--input_length < sysex_len) goto shortbuf; if (!sysex_len) break;/* broken file? */ sysex_store = (uint8_t *) malloc(sizeof(uint8_t) * sysex_len); memcpy(sysex_store, event_data, sysex_len); if (sysex_store[sysex_len - 1] == 0xF7) { uint8_t rolandsysexid[] = { 0x41, 0x10, 0x42, 0x12 }; if (memcmp(rolandsysexid, sysex_store, 4) == 0) { /* For Roland Sysex Messages */ /* checksum */ uint8_t sysex_cs = 0; uint32_t sysex_ofs = 4; do { sysex_cs += sysex_store[sysex_ofs]; if (sysex_cs > 0x7F) { sysex_cs -= 0x80; } sysex_ofs++; } while (sysex_store[sysex_ofs + 1] != 0xf7); sysex_cs = 128 - sysex_cs; /* is roland sysex message valid */ if (sysex_cs == sysex_store[sysex_ofs]) { /* process roland sysex event */ if (sysex_store[4] == 0x40) { if (((sysex_store[5] & 0xf0) == 0x10) && (sysex_store[6] == 0x15)) { /* Roland Drum Track Setting */ uint8_t sysex_ch = 0x0f & sysex_store[5]; if (sysex_ch == 0x00) { sysex_ch = 0x09; } else if (sysex_ch <= 0x09) { sysex_ch -= 1; } midi_setup_sysex_roland_drum_track(mdi, sysex_ch, sysex_store[7]); } else if ((sysex_store[5] == 0x00) && (sysex_store[6] == 0x7F) && (sysex_store[7] == 0x00)) { /* Roland GS Reset */ midi_setup_sysex_roland_reset(mdi); } } } } else { /* For non-Roland Sysex Messages */ uint8_t gm_reset[] = {0x7e, 0x7f, 0x09, 0x01, 0xf7}; uint8_t yamaha_reset[] = {0x43, 0x10, 0x4c, 0x00, 0x00, 0x7e, 0x00, 0xf7}; if (memcmp(gm_reset, sysex_store, 5) == 0) { /* GM Reset */ midi_setup_sysex_gm_reset(mdi); } else if (memcmp(yamaha_reset,sysex_store,8) == 0) { /* Yamaha Reset */ midi_setup_sysex_yamaha_reset(mdi); } } } free(sysex_store); sysex_store = NULL; /* event_data += sysex_len; */ ret_cnt += sysex_len; } else { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(unrecognized meta type event)", 0); return 0; } break; default: /* Should NEVER get here */ ret_cnt = 0; break; } if (ret_cnt == 0) _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(missing event)", 0); return ret_cnt; shortbuf: _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(input too short)", 0); return 0; } wildmidi-wildmidi-0.4.2/src/lock.c000066400000000000000000000046611315765416100170220ustar00rootroot00000000000000/* * lock.c - data locking code for lib * * Copyright (C) Chris Ison 2001-2011 * Copyright (C) Bret Curtis 2013-2016 * * This file is part of WildMIDI. * * WildMIDI is free software: you can redistribute and/or modify the player * under the terms of the GNU General Public License and you can redistribute * and/or modify the library under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either version 3 of * the licenses, or(at your option) any later version. * * WildMIDI 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 and * the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License and the * GNU Lesser General Public License along with WildMIDI. If not, see * . */ #include "config.h" #if !defined(WM_NO_LOCK) #ifdef _WIN32 #include #elif defined(__OS2__) || defined(__EMX__) #define INCL_DOS #include #elif defined(WILDMIDI_AMIGA) #include #else /* unixish ... */ #define _GNU_SOURCE #include /* usleep() */ #endif #include "lock.h" /* _WM_Lock(wmlock) wmlock = a pointer to a value returns nothing Attempts to set a lock on the MDI tree so that only 1 library command may access it at any time. If lock fails the process retries until successful. */ void _WM_Lock(int * wmlock) { LOCK_START: /* Check if lock is clear, if so set it */ if (__builtin_expect(((*wmlock) == 0), 1)) { (*wmlock)++; /* Now that the lock is set, make sure we * don't have a race condition. If so, * decrement the lock by one and retry. */ if (__builtin_expect(((*wmlock) == 1), 1)) { return; /* Lock cleanly set */ } (*wmlock)--; } #ifdef _WIN32 Sleep(10); #elif defined(__OS2__) || defined(__EMX__) DosSleep(10); #elif defined(WILDMIDI_AMIGA) Delay(1); #else usleep(500); #endif goto LOCK_START; } /* _WM_Unlock(wmlock) wmlock = a pointer to a value returns nothing Removes a lock previously placed on the MDI tree. */ void _WM_Unlock(int *wmlock) { /* We don't want a -1 lock, so just to make sure */ if ((*wmlock) != 0) { (*wmlock)--; } } #endif /* !WM_NO_LOCK */ wildmidi-wildmidi-0.4.2/src/mus2mid.c000066400000000000000000000334271315765416100174540ustar00rootroot00000000000000/* * MUS2MIDI: MUS to MIDI Library * * Copyright (C) 2014 Bret Curtis * Copyright (C) WildMIDI Developers 2015-2016 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "config.h" #include #include #include #include "mus2mid.h" #include "wm_error.h" #define FREQUENCY 140 /* default Hz or BPM */ #if 0 /* older units: */ #define TEMPO 0x001aa309 /* MPQN: 60000000 / 34.37Hz = 1745673 */ #define DIVISION 0x0059 /* 89 -- used by many mus2midi converters */ #endif #define TEMPO 0x00068A1B /* MPQN: 60000000 / 140BPM (140Hz) = 428571 */ /* 0x000D1436 -> MPQN: 60000000 / 70BPM (70Hz) = 857142 */ #define DIVISION 0x0101 /* 257 for 140Hz files with a 140MPQN */ /* 0x0088 -> 136 for 70Hz files with a 140MPQN */ /* 0x010B -> 267 for 70hz files with a 70MPQN */ /* 0x01F9 -> 505 for 140hz files with a 70MPQN */ /* New * QLS: MPQN/1000000 = 0.428571 * TDPS: QLS/PPQN = 0.428571/136 = 0.003151257 * PPQN: 136 * * QLS: MPQN/1000000 = 0.428571 * TDPS: QLS/PPQN = 0.428571/257 = 0.001667591 * PPQN: 257 * * QLS: MPQN/1000000 = 0.857142 * TDPS: QLS/PPQN = 0.857142/267 = 0.00321027 * PPQN: 267 * * QLS: MPQN/1000000 = 0.857142 * TDPS: QLS/PPQN = 0.857142/505 = 0.001697311 * PPQN: 505 * * Old * QLS: MPQN/1000000 = 1.745673 * TDPS: QLS/PPQN = 1.745673 / 89 = 0.019614303 (seconds per tick) * PPQN: (TDPS = QLS/PPQN) (0.019614303 = 1.745673/PPQN) (0.019614303*PPQN = 1.745673) (PPQN = 89.000001682) * */ #define MUSEVENT_KEYOFF 0 #define MUSEVENT_KEYON 1 #define MUSEVENT_PITCHWHEEL 2 #define MUSEVENT_CHANNELMODE 3 #define MUSEVENT_CONTROLLERCHANGE 4 #define MUSEVENT_END 6 #define MIDI_MAXCHANNELS 16 static const char MUS_ID[] = { 'M', 'U', 'S', 0x1A }; static const uint8_t midimap[] = {/* MIDI Number Description */ 0, /* 0 program change */ 0, /* 1 bank selection */ 0x01, /* 2 Modulation pot (frequency vibrato depth) */ 0x07, /* 3 Volume: 0-silent, ~100-normal, 127-loud */ 0x0A, /* 4 Pan (balance) pot: 0-left, 64-center (default), 127-right */ 0x0B, /* 5 Expression pot */ 0x5B, /* 6 Reverb depth */ 0x5D, /* 7 Chorus depth */ 0x40, /* 8 Sustain pedal */ 0x43, /* 9 Soft pedal */ 0x78, /* 10 All sounds off */ 0x7B, /* 11 All notes off */ 0x7E, /* 12 Mono (use numchannels + 1) */ 0x7F, /* 13 Poly */ 0x79, /* 14 reset all controllers */ }; typedef struct MUSHeader { char ID[4]; /* identifier: "MUS" 0x1A */ uint16_t scoreLen; uint16_t scoreStart; uint16_t channels; /* count of primary channels */ uint16_t sec_channels; /* count of secondary channels */ uint16_t instrCnt; } MUSHeader ; #define MUS_HEADERSIZE 14 typedef struct MidiHeaderChunk { char name[4]; int32_t length; int16_t format; /* make 0 */ int16_t ntracks;/* make 1 */ int16_t division; /* 0xe250 ?? */ } MidiHeaderChunk; #define MIDI_HEADERSIZE 14 typedef struct MidiTrackChunk { char name[4]; int32_t length; } MidiTrackChunk; #define TRK_CHUNKSIZE 8 struct mus_ctx { const uint8_t *src, *src_ptr; uint32_t srcsize; uint32_t datastart; uint8_t *dst, *dst_ptr; uint32_t dstsize, dstrem; }; #define DST_CHUNK 8192 static void resize_dst(struct mus_ctx *ctx) { uint32_t pos = ctx->dst_ptr - ctx->dst; ctx->dst = (uint8_t *) realloc(ctx->dst, ctx->dstsize + DST_CHUNK); ctx->dstsize += DST_CHUNK; ctx->dstrem += DST_CHUNK; ctx->dst_ptr = ctx->dst + pos; } static void write1(struct mus_ctx *ctx, uint32_t val) { if (ctx->dstrem < 1) resize_dst(ctx); *ctx->dst_ptr++ = val & 0xff; ctx->dstrem--; } static void write2(struct mus_ctx *ctx, uint32_t val) { if (ctx->dstrem < 2) resize_dst(ctx); *ctx->dst_ptr++ = (val>>8) & 0xff; *ctx->dst_ptr++ = val & 0xff; ctx->dstrem -= 2; } static void write4(struct mus_ctx *ctx, uint32_t val) { if (ctx->dstrem < 4) resize_dst(ctx); *ctx->dst_ptr++ = (val>>24)&0xff; *ctx->dst_ptr++ = (val>>16)&0xff; *ctx->dst_ptr++ = (val>>8) & 0xff; *ctx->dst_ptr++ = val & 0xff; ctx->dstrem -= 4; } static void seekdst(struct mus_ctx *ctx, uint32_t pos) { ctx->dst_ptr = ctx->dst + pos; while (ctx->dstsize < pos) resize_dst(ctx); ctx->dstrem = ctx->dstsize - pos; } static void skipdst(struct mus_ctx *ctx, int32_t pos) { size_t newpos; ctx->dst_ptr += pos; newpos = ctx->dst_ptr - ctx->dst; while (ctx->dstsize < newpos) resize_dst(ctx); ctx->dstrem = ctx->dstsize - newpos; } static uint32_t getdstpos(struct mus_ctx *ctx) { return (ctx->dst_ptr - ctx->dst); } /* writes a variable length integer to a buffer, and returns bytes written */ static int32_t writevarlen(int32_t value, uint8_t *out) { int32_t buffer, count = 0; buffer = value & 0x7f; while ((value >>= 7) > 0) { buffer <<= 8; buffer += 0x80; buffer += (value & 0x7f); } while (1) { ++count; *out = (uint8_t)buffer; ++out; if (buffer & 0x80) buffer >>= 8; else break; } return (count); } #define READ_INT16(b) ((b)[0] | ((b)[1] << 8)) #define READ_INT32(b) ((b)[0] | ((b)[1] << 8) | ((b)[2] << 16) | ((b)[3] << 24)) int _WM_mus2midi(const uint8_t *in, uint32_t insize, uint8_t **out, uint32_t *outsize, uint16_t frequency) { struct mus_ctx ctx; MUSHeader header; const uint8_t *cur, *end; uint32_t track_size_pos, begin_track_pos, current_pos; int32_t delta_time;/* Delta time for midi event */ int temp, ret = -1; int channel_volume[MIDI_MAXCHANNELS]; int channelMap[MIDI_MAXCHANNELS], currentChannel; if (insize < MUS_HEADERSIZE) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(too short)", 0); return (-1); } if (!frequency) frequency = FREQUENCY; /* read the MUS header and set our location */ memcpy(header.ID, in, 4); header.scoreLen = READ_INT16(&in[4]); header.scoreStart = READ_INT16(&in[6]); header.channels = READ_INT16(&in[8]); header.sec_channels = READ_INT16(&in[10]); header.instrCnt = READ_INT16(&in[12]); if (memcmp(header.ID, MUS_ID, 4)) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_MUS, NULL, 0); return (-1); } if (insize < (uint32_t)header.scoreLen + (uint32_t)header.scoreStart) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(too short)", 0); return (-1); } /* channel #15 should be excluded in the numchannels field: */ if (header.channels > MIDI_MAXCHANNELS - 1) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, NULL, 0); return (-1); } memset(&ctx, 0, sizeof(struct mus_ctx)); ctx.src = ctx.src_ptr = in; ctx.srcsize = insize; ctx.dst = (uint8_t *) calloc(DST_CHUNK, sizeof(uint8_t)); ctx.dst_ptr = ctx.dst; ctx.dstsize = DST_CHUNK; ctx.dstrem = DST_CHUNK; /* Map channel 15 to 9 (percussions) */ for (temp = 0; temp < MIDI_MAXCHANNELS; ++temp) { channelMap[temp] = -1; channel_volume[temp] = 0x40; } channelMap[15] = 9; /* Header is 14 bytes long and add the rest as well */ write1(&ctx, 'M'); write1(&ctx, 'T'); write1(&ctx, 'h'); write1(&ctx, 'd'); write4(&ctx, 6); /* length of header */ write2(&ctx, 0); /* MIDI type (always 0) */ write2(&ctx, 1); /* MUS files only have 1 track */ write2(&ctx, DIVISION); /* division */ /* Write out track header and track length position for later */ begin_track_pos = getdstpos(&ctx); write1(&ctx, 'M'); write1(&ctx, 'T'); write1(&ctx, 'r'); write1(&ctx, 'k'); track_size_pos = getdstpos(&ctx); skipdst(&ctx, 4); /* write tempo: microseconds per quarter note */ write1(&ctx, 0x00); /* delta time */ write1(&ctx, 0xff); /* sys command */ write2(&ctx, 0x5103); /* command - set tempo */ write1(&ctx, TEMPO & 0x000000ff); write1(&ctx, (TEMPO & 0x0000ff00) >> 8); write1(&ctx, (TEMPO & 0x00ff0000) >> 16); /* Percussions channel starts out at full volume */ write1(&ctx, 0x00); write1(&ctx, 0xB9); write1(&ctx, 0x07); write1(&ctx, 127); /* get current position in source, and end of position */ cur = in + header.scoreStart; end = cur + header.scoreLen; currentChannel = 0; delta_time = 0; /* main loop */ while(cur < end){ /*printf("LOOP DEBUG: %d\r\n",iterator++);*/ uint8_t channel; uint8_t event; uint8_t temp_buffer[32]; /* temp buffer for current iterator */ uint8_t *out_local = temp_buffer; uint8_t status, bit1, bit2, bitc = 2; /* read in current bit */ event = *cur++; channel = (event & 15); /* current channel */ /* write variable length delta time */ out_local += writevarlen(delta_time, out_local); /* set all channels to 127 (max) volume */ if (channelMap[channel] < 0) { *out_local++ = 0xB0 + currentChannel; *out_local++ = 0x07; *out_local++ = 127; *out_local++ = 0x00; channelMap[channel] = currentChannel++; if (currentChannel == 9) ++currentChannel; } status = channelMap[channel]; /* handle events */ switch ((event & 122) >> 4){ case MUSEVENT_KEYOFF: status |= 0x80; bit1 = *cur++; bit2 = 0x40; break; case MUSEVENT_KEYON: status |= 0x90; bit1 = *cur & 127; if (*cur++ & 128) /* volume bit? */ channel_volume[channelMap[channel]] = *cur++; bit2 = channel_volume[channelMap[channel]]; break; case MUSEVENT_PITCHWHEEL: status |= 0xE0; bit1 = (*cur & 1) >> 6; bit2 = (*cur++ >> 1) & 127; break; case MUSEVENT_CHANNELMODE: status |= 0xB0; if (*cur >= sizeof(midimap) / sizeof(midimap[0])) { _WM_ERROR_NEW("%s:%i: can't map %u to midi", __FUNCTION__, __LINE__, *cur); goto _end; } bit1 = midimap[*cur++]; bit2 = (*cur++ == 12) ? header.channels + 1 : 0x00; break; case MUSEVENT_CONTROLLERCHANGE: if (*cur == 0) { cur++; status |= 0xC0; bit1 = *cur++; bit2 = 0;/* silence bogus warnings */ bitc = 1; } else { status |= 0xB0; if (*cur >= sizeof(midimap) / sizeof(midimap[0])) { _WM_ERROR_NEW("%s:%i: can't map %u to midi", __FUNCTION__, __LINE__, *cur); goto _end; } bit1 = midimap[*cur++]; bit2 = *cur++; } break; case MUSEVENT_END: /* End */ status = 0xff; bit1 = 0x2f; bit2 = 0x00; if (cur != end) { /* should we error here or report-only? */ _WM_DEBUG_MSG("%s:%i: MUS buffer off by %ld bytes", __FUNCTION__, __LINE__, (long)(cur - end)); } break; case 5:/* Unknown */ case 7:/* Unknown */ default:/* shouldn't happen */ _WM_ERROR_NEW("%s:%i: unrecognized event (%u)", __FUNCTION__, __LINE__, event); goto _end; } /* write it out */ *out_local++ = status; *out_local++ = bit1; if (bitc == 2) *out_local++ = bit2; /* write out our temp buffer */ if (out_local != temp_buffer) { if (ctx.dstrem < sizeof(temp_buffer)) resize_dst(&ctx); memcpy(ctx.dst_ptr, temp_buffer, out_local - temp_buffer); ctx.dst_ptr += out_local - temp_buffer; ctx.dstrem -= out_local - temp_buffer; } if (event & 128) { delta_time = 0; do { delta_time = (int32_t) ((delta_time * 128 + (*cur & 127)) * (140.0f / frequency)); } while ((*cur++ & 128)); } else { delta_time = 0; } } /* write out track length */ current_pos = getdstpos(&ctx); seekdst(&ctx, track_size_pos); write4(&ctx, current_pos - begin_track_pos - TRK_CHUNKSIZE); seekdst(&ctx, current_pos); /* reseek to end position */ *out = ctx.dst; *outsize = ctx.dstsize - ctx.dstrem; ret = 0; _end: /* cleanup */ if (ret < 0) { free(ctx.dst); *out = NULL; *outsize = 0; } return (ret); } wildmidi-wildmidi-0.4.2/src/patches.c000066400000000000000000000054201315765416100175130ustar00rootroot00000000000000/* * patches.c -- Midi Wavetable Processing library * * Copyright (C) WildMIDI Developers 2001-2016 * * This file is part of WildMIDI. * * WildMIDI is free software: you can redistribute and/or modify the player * under the terms of the GNU General Public License and you can redistribute * and/or modify the library under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either version 3 of * the licenses, or(at your option) any later version. * * WildMIDI 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 and * the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License and the * GNU Lesser General Public License along with WildMIDI. If not, see * . */ #include "config.h" #include #include #include #include "wildmidi_lib.h" #include "internal_midi.h" #include "lock.h" #include "patches.h" #include "sample.h" struct _patch *_WM_patch[128]; int _WM_patch_lock = 0; struct _patch * _WM_get_patch_data(struct _mdi *mdi, uint16_t patchid) { struct _patch *search_patch; _WM_Lock(&_WM_patch_lock); search_patch = _WM_patch[patchid & 0x007F]; if (search_patch == NULL) { _WM_Unlock(&_WM_patch_lock); return (NULL); } while (search_patch) { if (search_patch->patchid == patchid) { _WM_Unlock(&_WM_patch_lock); return (search_patch); } search_patch = search_patch->next; } if ((patchid >> 8) != 0) { _WM_Unlock(&_WM_patch_lock); return (_WM_get_patch_data(mdi, patchid & 0x00FF)); } _WM_Unlock(&_WM_patch_lock); return (NULL); } void _WM_load_patch(struct _mdi *mdi, uint16_t patchid) { uint32_t i; struct _patch *tmp_patch = NULL; for (i = 0; i < mdi->patch_count; i++) { if (mdi->patches[i]->patchid == patchid) { return; } } tmp_patch = _WM_get_patch_data(mdi, patchid); if (tmp_patch == NULL) { return; } _WM_Lock(&_WM_patch_lock); if (!tmp_patch->loaded) { if (_WM_load_sample(tmp_patch) == -1) { _WM_Unlock(&_WM_patch_lock); return; } } if (tmp_patch->first_sample == NULL) { _WM_Unlock(&_WM_patch_lock); return; } mdi->patch_count++; mdi->patches = (struct _patch **) realloc(mdi->patches, (sizeof(struct _patch*) * mdi->patch_count)); mdi->patches[mdi->patch_count - 1] = tmp_patch; tmp_patch->inuse_count++; _WM_Unlock(&_WM_patch_lock); } wildmidi-wildmidi-0.4.2/src/reverb.c000066400000000000000000000307101315765416100173510ustar00rootroot00000000000000/* * reverb.c -- Midi Wavetable Processing library * * Copyright (C) WildMIDI Developers 2001-2016 * * This file is part of WildMIDI. * * WildMIDI is free software: you can redistribute and/or modify the player * under the terms of the GNU General Public License and you can redistribute * and/or modify the library under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either version 3 of * the licenses, or(at your option) any later version. * * WildMIDI 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 and * the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License and the * GNU Lesser General Public License along with WildMIDI. If not, see * . */ #include "config.h" #include #include #include #include "common.h" #include "reverb.h" /* reverb function */ void _WM_reset_reverb(struct _rvb *rvb) { int i, j, k; for (i = 0; i < rvb->l_buf_size; i++) { rvb->l_buf[i] = 0; } for (i = 0; i < rvb->r_buf_size; i++) { rvb->r_buf[i] = 0; } for (k = 0; k < 8; k++) { for (i = 0; i < 6; i++) { for (j = 0; j < 2; j++) { rvb->l_buf_flt_in[k][i][j] = 0; rvb->l_buf_flt_out[k][i][j] = 0; rvb->r_buf_flt_in[k][i][j] = 0; rvb->r_buf_flt_out[k][i][j] = 0; } } } } /* _WM_init_reverb ========================= Engine Description 8 reflective points around the room 2 speaker positions 1 listener position Sounds come from the speakers to all points and to the listener. Sound comes from the reflective points to the listener. These sounds are combined, put through a filter that mimics surface absorbtion. The combined sounds are also sent to the reflective points on the opposite side. */ struct _rvb * _WM_init_reverb(int rate, float room_x, float room_y, float listen_x, float listen_y) { /* filters set at 125Hz, 250Hz, 500Hz, 1000Hz, 2000Hz, 4000Hz */ double Freq[] = {125.0, 250.0, 500.0, 1000.0, 2000.0, 4000.0}; /* numbers calculated from * 101.325 kPa, 20 deg C, 50% relative humidity */ double dbAirAbs[] = {-0.00044, -0.00131, -0.002728, -0.004665, -0.009887, -0.029665}; /* modify these to adjust the absorption qualities of the surface. * Remember that lower frequencies are less effected by surfaces * Note: I am currently playing with the values and finding the ideal surfaces * for nice default reverb. */ double dbAttn[8][6] = { {-1.839, -6.205, -8.891, -12.059, -15.935, -20.942}, {-0.131, -6.205, -12.059, -20.933, -20.933, -15.944}, {-0.131, -6.205, -12.059, -20.933, -20.933, -15.944}, {-1.839, -6.205, -8.891, -12.059, -15.935, -20.942}, {-1.839, -6.205, -8.891, -12.059, -15.935, -20.942}, {-0.131, -6.205, -12.059, -20.933, -20.933, -15.944}, {-0.131, -6.205, -12.059, -20.933, -20.933, -15.944}, {-1.839, -6.205, -8.891, -12.059, -15.935, -20.942} }; /* double dbAttn[6] = { // concrete covered in carpet // -0.175, -0.537, -1.412, -4.437, -7.959, -7.959 // pleated drapes -0.630, -3.223, -5.849, -12.041, -10.458, -7.959 }; */ /* distance */ double SPL_DST[8] = {0.0}; double SPR_DST[8] = {0.0}; double RFN_DST[8] = {0.0}; double MAXL_DST = 0.0; double MAXR_DST = 0.0; double SPL_LSN_XOFS = 0.0; double SPL_LSN_YOFS = 0.0; double SPL_LSN_DST = 0.0; double SPR_LSN_XOFS = 0.0; double SPR_LSN_YOFS = 0.0; double SPR_LSN_DST = 0.0; struct _rvb *rtn_rvb = (struct _rvb *) malloc(sizeof(struct _rvb)); int j = 0; int i = 0; struct _coord { double x; double y; }; struct _coord SPL; /* Left Speaker Position */ struct _coord SPR; /* Right Speaker Position */ /* position of the reflective points */ struct _coord RFN[8]; SPL.x = room_x / 4.0; SPR.x = room_x / 4.0 * 3.0; SPL.y = room_y / 10.0; SPR.y = room_y / 10.0; RFN[0].x = room_x / 3.0; RFN[0].y = 0.0; RFN[1].x = 0.0; RFN[1].y = room_y / 3.0; RFN[2].x = 0.0; RFN[2].y = room_y / 3.0 * 2.0; RFN[3].x = room_x / 3.0; RFN[3].y = room_y; RFN[4].x = room_x / 3.0 * 2.0; RFN[4].y = room_y; RFN[5].x = room_x; RFN[5].y = room_y / 3.0 * 2.0; RFN[6].x = room_x; RFN[6].y = room_y / 3.0; RFN[7].x = room_x / 3.0 * 2.0; RFN[7].y = 0.0; SPL_LSN_XOFS = SPL.x - listen_x; SPL_LSN_YOFS = SPL.y - listen_y; SPL_LSN_DST = sqrt((SPL_LSN_XOFS * SPL_LSN_XOFS) + (SPL_LSN_YOFS * SPL_LSN_YOFS)); if (SPL_LSN_DST > MAXL_DST) MAXL_DST = SPL_LSN_DST; SPR_LSN_XOFS = SPR.x - listen_x; SPR_LSN_YOFS = SPR.y - listen_y; SPR_LSN_DST = sqrt((SPR_LSN_XOFS * SPR_LSN_XOFS) + (SPR_LSN_YOFS * SPR_LSN_YOFS)); if (SPR_LSN_DST > MAXR_DST) MAXR_DST = SPR_LSN_DST; if (rtn_rvb == NULL) { return NULL; } for (j = 0; j < 8; j++) { double SPL_RFL_XOFS = 0; double SPL_RFL_YOFS = 0; double SPR_RFL_XOFS = 0; double SPR_RFL_YOFS = 0; double RFN_XOFS = listen_x - RFN[j].x; double RFN_YOFS = listen_y - RFN[j].y; RFN_DST[j] = sqrt((RFN_XOFS * RFN_XOFS) + (RFN_YOFS * RFN_YOFS)); SPL_RFL_XOFS = SPL.x - RFN[i].x; SPL_RFL_YOFS = SPL.y - RFN[i].y; SPR_RFL_XOFS = SPR.x - RFN[i].x; SPR_RFL_YOFS = SPR.y - RFN[i].y; SPL_DST[i] = sqrt( (SPL_RFL_XOFS * SPL_RFL_XOFS) + (SPL_RFL_YOFS * SPL_RFL_YOFS)); SPR_DST[i] = sqrt( (SPR_RFL_XOFS * SPR_RFL_XOFS) + (SPR_RFL_YOFS * SPR_RFL_YOFS)); /* add the 2 distances together and remove the speaker to listener distance so we dont have to delay the initial output */ SPL_DST[i] += RFN_DST[i]; /* so i dont have to delay speaker output */ SPL_DST[i] -= SPL_LSN_DST; if (i < 4) { if (SPL_DST[i] > MAXL_DST) MAXL_DST = SPL_DST[i]; } else { if (SPL_DST[i] > MAXR_DST) MAXR_DST = SPL_DST[i]; } SPR_DST[i] += RFN_DST[i]; /* so i dont have to delay speaker output */ SPR_DST[i] -= SPR_LSN_DST; if (i < 4) { if (SPR_DST[i] > MAXL_DST) MAXL_DST = SPR_DST[i]; } else { if (SPR_DST[i] > MAXR_DST) MAXR_DST = SPR_DST[i]; } RFN_DST[j] *= 2.0; if (j < 4) { if (RFN_DST[j] > MAXL_DST) MAXL_DST = RFN_DST[j]; } else { if (RFN_DST[j] > MAXR_DST) MAXR_DST = RFN_DST[j]; } for (i = 0; i < 6; i++) { double srate = (double) rate; double bandwidth = 2.0; double omega = 2.0 * M_PI * Freq[i] / srate; double sn = sin(omega); double cs = cos(omega); double alpha = sn * sinh(M_LN2 / 2 * bandwidth * omega / sn); double A = pow(10.0, ((dbAttn[j][i] + (dbAirAbs[i] * RFN_DST[j])) / 40.0) ); /* Peaking band EQ filter */ double b0 = 1 + (alpha * A); double b1 = -2 * cs; double b2 = 1 - (alpha * A); double a0 = 1 + (alpha / A); double a1 = -2 * cs; double a2 = 1 - (alpha / A); rtn_rvb->coeff[j][i][0] = (int32_t) ((b0 / a0) * 1024.0); rtn_rvb->coeff[j][i][1] = (int32_t) ((b1 / a0) * 1024.0); rtn_rvb->coeff[j][i][2] = (int32_t) ((b2 / a0) * 1024.0); rtn_rvb->coeff[j][i][3] = (int32_t) ((a1 / a0) * 1024.0); rtn_rvb->coeff[j][i][4] = (int32_t) ((a2 / a0) * 1024.0); } } /* init the reverb buffers */ rtn_rvb->l_buf_size = (int) ((float) rate * (MAXL_DST / 340.29)); rtn_rvb->l_buf = (int32_t *) malloc(sizeof(int32_t) * (rtn_rvb->l_buf_size + 1)); rtn_rvb->l_out = 0; rtn_rvb->r_buf_size = (int) ((float) rate * (MAXR_DST / 340.29)); rtn_rvb->r_buf = (int32_t *) malloc(sizeof(int32_t) * (rtn_rvb->r_buf_size + 1)); rtn_rvb->r_out = 0; for (i = 0; i < 4; i++) { rtn_rvb->l_sp_in[i] = (int) ((float) rate * (SPL_DST[i] / 340.29)); rtn_rvb->l_sp_in[i + 4] = (int) ((float) rate * (SPL_DST[i + 4] / 340.29)); rtn_rvb->r_sp_in[i] = (int) ((float) rate * (SPR_DST[i] / 340.29)); rtn_rvb->r_sp_in[i + 4] = (int) ((float) rate * (SPR_DST[i + 4] / 340.29)); rtn_rvb->l_in[i] = (int) ((float) rate * (RFN_DST[i] / 340.29)); rtn_rvb->r_in[i] = (int) ((float) rate * (RFN_DST[i + 4] / 340.29)); } rtn_rvb->gain = 4; _WM_reset_reverb(rtn_rvb); return rtn_rvb; } /* _WM_free_reverb - free up memory used for reverb */ void _WM_free_reverb(struct _rvb *rvb) { if (!rvb) return; free(rvb->l_buf); free(rvb->r_buf); free(rvb); } void _WM_do_reverb(struct _rvb *rvb, int32_t *buffer, int size) { int i, j, k; int32_t l_buf_flt = 0; int32_t r_buf_flt = 0; int32_t l_rfl = 0; int32_t r_rfl = 0; int vol_div = 64; for (i = 0; i < size; i += 2) { int32_t tmp_l_val = 0; int32_t tmp_r_val = 0; /* add the initial reflections from each speaker, 4 to go the left, 4 go to the right buffers */ tmp_l_val = buffer[i] / vol_div; tmp_r_val = buffer[i + 1] / vol_div; for (j = 0; j < 4; j++) { rvb->l_buf[rvb->l_sp_in[j]] += tmp_l_val; rvb->l_sp_in[j] = (rvb->l_sp_in[j] + 1) % rvb->l_buf_size; rvb->l_buf[rvb->r_sp_in[j]] += tmp_r_val; rvb->r_sp_in[j] = (rvb->r_sp_in[j] + 1) % rvb->l_buf_size; rvb->r_buf[rvb->l_sp_in[j + 4]] += tmp_l_val; rvb->l_sp_in[j + 4] = (rvb->l_sp_in[j + 4] + 1) % rvb->r_buf_size; rvb->r_buf[rvb->r_sp_in[j + 4]] += tmp_r_val; rvb->r_sp_in[j + 4] = (rvb->r_sp_in[j + 4] + 1) % rvb->r_buf_size; } /* filter the reverb output and add to buffer */ l_rfl = rvb->l_buf[rvb->l_out]; rvb->l_buf[rvb->l_out] = 0; rvb->l_out = (rvb->l_out + 1) % rvb->l_buf_size; r_rfl = rvb->r_buf[rvb->r_out]; rvb->r_buf[rvb->r_out] = 0; rvb->r_out = (rvb->r_out + 1) % rvb->r_buf_size; for (k = 0; k < 8; k++) { for (j = 0; j < 6; j++) { l_buf_flt = ((l_rfl * rvb->coeff[k][j][0]) + (rvb->l_buf_flt_in[k][j][0] * rvb->coeff[k][j][1]) + (rvb->l_buf_flt_in[k][j][1] * rvb->coeff[k][j][2]) - (rvb->l_buf_flt_out[k][j][0] * rvb->coeff[k][j][3]) - (rvb->l_buf_flt_out[k][j][1] * rvb->coeff[k][j][4])) / 1024; rvb->l_buf_flt_in[k][j][1] = rvb->l_buf_flt_in[k][j][0]; rvb->l_buf_flt_in[k][j][0] = l_rfl; rvb->l_buf_flt_out[k][j][1] = rvb->l_buf_flt_out[k][j][0]; rvb->l_buf_flt_out[k][j][0] = l_buf_flt; buffer[i] += l_buf_flt / 8; r_buf_flt = ((r_rfl * rvb->coeff[k][j][0]) + (rvb->r_buf_flt_in[k][j][0] * rvb->coeff[k][j][1]) + (rvb->r_buf_flt_in[k][j][1] * rvb->coeff[k][j][2]) - (rvb->r_buf_flt_out[k][j][0] * rvb->coeff[k][j][3]) - (rvb->r_buf_flt_out[k][j][1] * rvb->coeff[k][j][4])) / 1024; rvb->r_buf_flt_in[k][j][1] = rvb->r_buf_flt_in[k][j][0]; rvb->r_buf_flt_in[k][j][0] = r_rfl; rvb->r_buf_flt_out[k][j][1] = rvb->r_buf_flt_out[k][j][0]; rvb->r_buf_flt_out[k][j][0] = r_buf_flt; buffer[i + 1] += r_buf_flt / 8; } } /* add filtered result back into the buffers but on the opposite side */ tmp_l_val = buffer[i + 1] / vol_div; tmp_r_val = buffer[i] / vol_div; for (j = 0; j < 4; j++) { rvb->l_buf[rvb->l_in[j]] += tmp_l_val; rvb->l_in[j] = (rvb->l_in[j] + 1) % rvb->l_buf_size; rvb->r_buf[rvb->r_in[j]] += tmp_r_val; rvb->r_in[j] = (rvb->r_in[j] + 1) % rvb->r_buf_size; } } } wildmidi-wildmidi-0.4.2/src/sample.c000066400000000000000000000166171315765416100173570ustar00rootroot00000000000000/* * sample.c -- Midi Wavetable Processing library * * Copyright (C) WildMIDI Developers 2001-2016 * * This file is part of WildMIDI. * * WildMIDI is free software: you can redistribute and/or modify the player * under the terms of the GNU General Public License and you can redistribute * and/or modify the library under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either version 3 of * the licenses, or(at your option) any later version. * * WildMIDI 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 and * the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License and the * GNU Lesser General Public License along with WildMIDI. If not, see * . */ #include "config.h" #include #include #include "lock.h" #include "common.h" #include "patches.h" #include "gus_pat.h" #include "wildmidi_lib.h" #include "internal_midi.h" #include "sample.h" /* FIXME: Need to decide if this stuff needs to be broken up for different formats. */ uint32_t _WM_get_decay_samples(struct _mdi * mdi, uint8_t channel, uint8_t note) { struct _patch *patch = NULL; struct _sample *sample = NULL; uint32_t freq = 0; uint32_t decay_samples = 0; if (mdi->channel[channel].isdrum) { patch = _WM_get_patch_data(mdi, ((mdi->channel[channel].bank << 8) | note | 0x80)); } else { patch = mdi->channel[channel].patch; } if (patch == NULL) return (0); /* first get the freq we need so we can check the right sample */ if (patch->patchid & 0x80) { /* is a drum patch */ if (patch->note) { freq = _WM_freq_table[(patch->note % 12) * 100] >> (10 - (patch->note / 12)); } else { freq = _WM_freq_table[(note % 12) * 100] >> (10 - (note / 12)); } } else { freq = _WM_freq_table[(note % 12) * 100] >> (10 - (note / 12)); } /* get the sample */ sample = _WM_get_sample_data(patch, (freq / 100)); if (sample == NULL) return (0); decay_samples = sample->note_off_decay; return (decay_samples); } struct _sample *_WM_get_sample_data(struct _patch *sample_patch, uint32_t freq) { struct _sample *last_sample = NULL; struct _sample *return_sample = NULL; _WM_Lock(&_WM_patch_lock); if (sample_patch == NULL) { _WM_Unlock(&_WM_patch_lock); return (NULL); } if (sample_patch->first_sample == NULL) { _WM_Unlock(&_WM_patch_lock); return (NULL); } if (freq == 0) { _WM_Unlock(&_WM_patch_lock); return (sample_patch->first_sample); } return_sample = sample_patch->first_sample; last_sample = sample_patch->first_sample; while (last_sample) { if (freq > last_sample->freq_low) { if (freq < last_sample->freq_high) { _WM_Unlock(&_WM_patch_lock); return (last_sample); } else { return_sample = last_sample; } } last_sample = last_sample->next; } _WM_Unlock(&_WM_patch_lock); return (return_sample); } /* sample loading */ int _WM_load_sample(struct _patch *sample_patch) { struct _sample *guspat = NULL; struct _sample *tmp_sample = NULL; uint32_t i = 0; /* we only want to try loading the guspat once. */ sample_patch->loaded = 1; if ((guspat = _WM_load_gus_pat(sample_patch->filename, _WM_fix_release)) == NULL) { return (-1); } if (_WM_auto_amp) { int16_t tmp_max = 0; int16_t tmp_min = 0; int16_t samp_max = 0; int16_t samp_min = 0; tmp_sample = guspat; do { samp_max = 0; samp_min = 0; for (i = 0; i < (tmp_sample->data_length >> 10); i++) { if (tmp_sample->data[i] > samp_max) samp_max = tmp_sample->data[i]; if (tmp_sample->data[i] < samp_min) samp_min = tmp_sample->data[i]; } if (samp_max > tmp_max) tmp_max = samp_max; if (samp_min < tmp_min) tmp_min = samp_min; tmp_sample = tmp_sample->next; } while (tmp_sample); if (_WM_auto_amp_with_amp) { if (tmp_max >= -tmp_min) { sample_patch->amp = (sample_patch->amp * ((32767 << 10) / tmp_max)) >> 10; } else { sample_patch->amp = (sample_patch->amp * ((32768 << 10) / -tmp_min)) >> 10; } } else { if (tmp_max >= -tmp_min) { sample_patch->amp = (32767 << 10) / tmp_max; } else { sample_patch->amp = (32768 << 10) / -tmp_min; } } } sample_patch->first_sample = guspat; if (sample_patch->patchid & 0x0080) { if (!(sample_patch->keep & SAMPLE_LOOP)) { do { guspat->modes &= 0xFB; guspat = guspat->next; } while (guspat); } guspat = sample_patch->first_sample; if (!(sample_patch->keep & SAMPLE_ENVELOPE)) { do { guspat->modes &= 0xBF; guspat = guspat->next; } while (guspat); } guspat = sample_patch->first_sample; } if (sample_patch->patchid == 47) { do { if (!(guspat->modes & SAMPLE_LOOP)) { for (i = 3; i < 6; i++) { guspat->env_target[i] = guspat->env_target[2]; guspat->env_rate[i] = guspat->env_rate[2]; } } guspat = guspat->next; } while (guspat); guspat = sample_patch->first_sample; } do { if ((sample_patch->remove & SAMPLE_SUSTAIN) && (guspat->modes & SAMPLE_SUSTAIN)) { guspat->modes ^= SAMPLE_SUSTAIN; } if ((sample_patch->remove & SAMPLE_CLAMPED) && (guspat->modes & SAMPLE_CLAMPED)) { guspat->modes ^= SAMPLE_CLAMPED; } if (sample_patch->keep & SAMPLE_ENVELOPE) { guspat->modes |= SAMPLE_ENVELOPE; } for (i = 0; i < 6; i++) { if (guspat->modes & SAMPLE_ENVELOPE) { if (sample_patch->env[i].set & 0x02) { guspat->env_target[i] = 16448 * (int32_t) (255.0f * sample_patch->env[i].level); } if (sample_patch->env[i].set & 0x01) { guspat->env_rate[i] = (int32_t) (4194303.0f / ((float) _WM_SampleRate * (sample_patch->env[i].time / 1000.0f))); } } else { guspat->env_target[i] = 4194303; guspat->env_rate[i] = (int32_t) (4194303.0f / ((float) _WM_SampleRate * env_time_table[63])); } } guspat = guspat->next; } while (guspat); return (0); } wildmidi-wildmidi-0.4.2/src/wildmidi.c000066400000000000000000002070121315765416100176670ustar00rootroot00000000000000/* * wildmidi.c -- Midi Player using the WildMidi Midi Processing Library * * Copyright (C) WildMidi Developers 2001-2016 * * This file is part of WildMIDI. * * WildMIDI is free software: you can redistribute and/or modify the player * under the terms of the GNU General Public License and you can redistribute * and/or modify the library under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either version 3 of * the licenses, or(at your option) any later version. * * WildMIDI 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 and * the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License and the * GNU Lesser General Public License along with WildMIDI. If not, see * . */ #include "config.h" #include #include #include #include #include #if defined(__DJGPP__) #include #include #include #include "getopt_long.h" #include #define getopt dj_getopt /* hack */ #include #undef getopt #define msleep(s) usleep((s)*1000) #include #include #ifdef AUDIODRV_DOSSB #include "dossb.h" #endif #elif (defined _WIN32) || (defined __CYGWIN__) #include #include #include #include #include #include #define msleep(s) Sleep((s)) #include #include "getopt_long.h" #ifdef __WATCOMC__ #define _putch putch #endif #elif defined(__OS2__) || defined(__EMX__) #define INCL_DOS #define INCL_DOSERRORS #define INCL_OS2MM #ifdef __EMX__ #define INCL_KBD #define INCL_VIO #endif #include #include #include #define msleep(s) DosSleep((s)) #include #include #include "getopt_long.h" #ifdef __EMX__ #include /* for off_t typedef */ int putch (int c) { char ch = c; VioWrtTTY(&ch, 1, 0); return c; } int kbhit (void) { KBDKEYINFO k; if (KbdPeek(&k, 0)) return 0; return (k.fbStatus & KBDTRF_FINAL_CHAR_IN); } #endif #elif defined(WILDMIDI_AMIGA) extern void amiga_sysinit (void); extern int amiga_usleep(unsigned long millisec); #define msleep(s) amiga_usleep((s)*1000) extern int amiga_getch (unsigned char *ch); #include #include #include "getopt_long.h" #ifdef AUDIODRV_AHI #include #endif #else /* unix build */ static int msleep(unsigned long millisec); #include #include #include #include #include #include #include #ifdef AUDIODRV_ALSA # include #elif defined AUDIODRV_OSS # if defined HAVE_SYS_SOUNDCARD_H # include # elif defined HAVE_MACHINE_SOUNDCARD_H # include # elif defined HAVE_SOUNDCARD_H # include /* less common, but exists. */ # endif #elif defined AUDIODRV_OPENAL # include # include #endif #endif /* !_WIN32, !__DJGPP__ (unix build) */ #include "wildmidi_lib.h" #include "wm_tty.h" #include "filenames.h" struct _midi_test { uint8_t *data; uint32_t size; }; /* scale test from 0 to 127 * test a * offset 18-21 (0x12-0x15) - track size * offset 25 (0x1A) = bank number * offset 28 (0x1D) = patch number */ static uint8_t midi_test_c_scale[] = { 0x4d, 0x54, 0x68, 0x64, 0x00, 0x00, 0x00, 0x06, /* 0x00 */ 0x00, 0x00, 0x00, 0x01, 0x00, 0x06, 0x4d, 0x54, /* 0x08 */ 0x72, 0x6b, 0x00, 0x00, 0x02, 0x63, 0x00, 0xb0, /* 0x10 */ 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x90, 0x00, /* 0x18 C */ 0x64, 0x08, 0x80, 0x00, 0x00, 0x08, 0x90, 0x02, /* 0x20 D */ 0x64, 0x08, 0x80, 0x02, 0x00, 0x08, 0x90, 0x04, /* 0x28 E */ 0x64, 0x08, 0x80, 0x04, 0x00, 0x08, 0x90, 0x05, /* 0x30 F */ 0x64, 0x08, 0x80, 0x05, 0x00, 0x08, 0x90, 0x07, /* 0x38 G */ 0x64, 0x08, 0x80, 0x07, 0x00, 0x08, 0x90, 0x09, /* 0x40 A */ 0x64, 0x08, 0x80, 0x09, 0x00, 0x08, 0x90, 0x0b, /* 0x48 B */ 0x64, 0x08, 0x80, 0x0b, 0x00, 0x08, 0x90, 0x0c, /* 0x50 C */ 0x64, 0x08, 0x80, 0x0c, 0x00, 0x08, 0x90, 0x0e, /* 0x58 D */ 0x64, 0x08, 0x80, 0x0e, 0x00, 0x08, 0x90, 0x10, /* 0x60 E */ 0x64, 0x08, 0x80, 0x10, 0x00, 0x08, 0x90, 0x11, /* 0x68 F */ 0x64, 0x08, 0x80, 0x11, 0x00, 0x08, 0x90, 0x13, /* 0x70 G */ 0x64, 0x08, 0x80, 0x13, 0x00, 0x08, 0x90, 0x15, /* 0x78 A */ 0x64, 0x08, 0x80, 0x15, 0x00, 0x08, 0x90, 0x17, /* 0x80 B */ 0x64, 0x08, 0x80, 0x17, 0x00, 0x08, 0x90, 0x18, /* 0x88 C */ 0x64, 0x08, 0x80, 0x18, 0x00, 0x08, 0x90, 0x1a, /* 0x90 D */ 0x64, 0x08, 0x80, 0x1a, 0x00, 0x08, 0x90, 0x1c, /* 0x98 E */ 0x64, 0x08, 0x80, 0x1c, 0x00, 0x08, 0x90, 0x1d, /* 0xA0 F */ 0x64, 0x08, 0x80, 0x1d, 0x00, 0x08, 0x90, 0x1f, /* 0xA8 G */ 0x64, 0x08, 0x80, 0x1f, 0x00, 0x08, 0x90, 0x21, /* 0xB0 A */ 0x64, 0x08, 0x80, 0x21, 0x00, 0x08, 0x90, 0x23, /* 0xB8 B */ 0x64, 0x08, 0x80, 0x23, 0x00, 0x08, 0x90, 0x24, /* 0xC0 C */ 0x64, 0x08, 0x80, 0x24, 0x00, 0x08, 0x90, 0x26, /* 0xC8 D */ 0x64, 0x08, 0x80, 0x26, 0x00, 0x08, 0x90, 0x28, /* 0xD0 E */ 0x64, 0x08, 0x80, 0x28, 0x00, 0x08, 0x90, 0x29, /* 0xD8 F */ 0x64, 0x08, 0x80, 0x29, 0x00, 0x08, 0x90, 0x2b, /* 0xE0 G */ 0x64, 0x08, 0x80, 0x2b, 0x00, 0x08, 0x90, 0x2d, /* 0xE8 A */ 0x64, 0x08, 0x80, 0x2d, 0x00, 0x08, 0x90, 0x2f, /* 0xF0 B */ 0x64, 0x08, 0x80, 0x2f, 0x00, 0x08, 0x90, 0x30, /* 0xF8 C */ 0x64, 0x08, 0x80, 0x30, 0x00, 0x08, 0x90, 0x32, /* 0x100 D */ 0x64, 0x08, 0x80, 0x32, 0x00, 0x08, 0x90, 0x34, /* 0x108 E */ 0x64, 0x08, 0x80, 0x34, 0x00, 0x08, 0x90, 0x35, /* 0x110 F */ 0x64, 0x08, 0x80, 0x35, 0x00, 0x08, 0x90, 0x37, /* 0x118 G */ 0x64, 0x08, 0x80, 0x37, 0x00, 0x08, 0x90, 0x39, /* 0x120 A */ 0x64, 0x08, 0x80, 0x39, 0x00, 0x08, 0x90, 0x3b, /* 0X128 B */ 0x64, 0x08, 0x80, 0x3b, 0x00, 0x08, 0x90, 0x3c, /* 0x130 C */ 0x64, 0x08, 0x80, 0x3c, 0x00, 0x08, 0x90, 0x3e, /* 0x138 D */ 0x64, 0x08, 0x80, 0x3e, 0x00, 0x08, 0x90, 0x40, /* 0X140 E */ 0x64, 0x08, 0x80, 0x40, 0x00, 0x08, 0x90, 0x41, /* 0x148 F */ 0x64, 0x08, 0x80, 0x41, 0x00, 0x08, 0x90, 0x43, /* 0x150 G */ 0x64, 0x08, 0x80, 0x43, 0x00, 0x08, 0x90, 0x45, /* 0x158 A */ 0x64, 0x08, 0x80, 0x45, 0x00, 0x08, 0x90, 0x47, /* 0x160 B */ 0x64, 0x08, 0x80, 0x47, 0x00, 0x08, 0x90, 0x48, /* 0x168 C */ 0x64, 0x08, 0x80, 0x48, 0x00, 0x08, 0x90, 0x4a, /* 0x170 D */ 0x64, 0x08, 0x80, 0x4a, 0x00, 0x08, 0x90, 0x4c, /* 0x178 E */ 0x64, 0x08, 0x80, 0x4c, 0x00, 0x08, 0x90, 0x4d, /* 0x180 F */ 0x64, 0x08, 0x80, 0x4d, 0x00, 0x08, 0x90, 0x4f, /* 0x188 G */ 0x64, 0x08, 0x80, 0x4f, 0x00, 0x08, 0x90, 0x51, /* 0x190 A */ 0x64, 0x08, 0x80, 0x51, 0x00, 0x08, 0x90, 0x53, /* 0x198 B */ 0x64, 0x08, 0x80, 0x53, 0x00, 0x08, 0x90, 0x54, /* 0x1A0 C */ 0x64, 0x08, 0x80, 0x54, 0x00, 0x08, 0x90, 0x56, /* 0x1A8 D */ 0x64, 0x08, 0x80, 0x56, 0x00, 0x08, 0x90, 0x58, /* 0x1B0 E */ 0x64, 0x08, 0x80, 0x58, 0x00, 0x08, 0x90, 0x59, /* 0x1B8 F */ 0x64, 0x08, 0x80, 0x59, 0x00, 0x08, 0x90, 0x5b, /* 0x1C0 G */ 0x64, 0x08, 0x80, 0x5b, 0x00, 0x08, 0x90, 0x5d, /* 0x1C8 A */ 0x64, 0x08, 0x80, 0x5d, 0x00, 0x08, 0x90, 0x5f, /* 0x1D0 B */ 0x64, 0x08, 0x80, 0x5f, 0x00, 0x08, 0x90, 0x60, /* 0x1D8 C */ 0x64, 0x08, 0x80, 0x60, 0x00, 0x08, 0x90, 0x62, /* 0x1E0 D */ 0x64, 0x08, 0x80, 0x62, 0x00, 0x08, 0x90, 0x64, /* 0x1E8 E */ 0x64, 0x08, 0x80, 0x64, 0x00, 0x08, 0x90, 0x65, /* 0x1F0 F */ 0x64, 0x08, 0x80, 0x65, 0x00, 0x08, 0x90, 0x67, /* 0x1F8 G */ 0x64, 0x08, 0x80, 0x67, 0x00, 0x08, 0x90, 0x69, /* 0x200 A */ 0x64, 0x08, 0x80, 0x69, 0x00, 0x08, 0x90, 0x6b, /* 0x208 B */ 0x64, 0x08, 0x80, 0x6b, 0x00, 0x08, 0x90, 0x6c, /* 0x210 C */ 0x64, 0x08, 0x80, 0x6c, 0x00, 0x08, 0x90, 0x6e, /* 0x218 D */ 0x64, 0x08, 0x80, 0x6e, 0x00, 0x08, 0x90, 0x70, /* 0x220 E */ 0x64, 0x08, 0x80, 0x70, 0x00, 0x08, 0x90, 0x71, /* 0x228 F */ 0x64, 0x08, 0x80, 0x71, 0x00, 0x08, 0x90, 0x73, /* 0x230 G */ 0x64, 0x08, 0x80, 0x73, 0x00, 0x08, 0x90, 0x75, /* 0x238 A */ 0x64, 0x08, 0x80, 0x75, 0x00, 0x08, 0x90, 0x77, /* 0x240 B */ 0x64, 0x08, 0x80, 0x77, 0x00, 0x08, 0x90, 0x78, /* 0x248 C */ 0x64, 0x08, 0x80, 0x78, 0x00, 0x08, 0x90, 0x7a, /* 0x250 D */ 0x64, 0x08, 0x80, 0x7a, 0x00, 0x08, 0x90, 0x7c, /* 0x258 E */ 0x64, 0x08, 0x80, 0x7c, 0x00, 0x08, 0x90, 0x7d, /* 0x260 F */ 0x64, 0x08, 0x80, 0x7d, 0x00, 0x08, 0x90, 0x7f, /* 0x268 G */ 0x64, 0x08, 0x80, 0x7f, 0x00, 0x08, 0xff, 0x2f, /* 0x270 */ 0x00 /* 0x278 */ }; static struct _midi_test midi_test[] = { { midi_test_c_scale, 663 }, { NULL, 0 } }; static int midi_test_max = 1; /* ============================== Audio Output Functions We have two 'drivers': first is the wav file writer which is always available. the second, if it is really compiled in, is the system audio output driver. only _one of the two_ can be active, not both. ============================== */ static unsigned int rate = 32072; static int (*send_output)(int8_t *output_data, int output_size); static void (*close_output)(void); static void (*pause_output)(void); static void (*resume_output)(void); #define wmidi_geterrno() errno /* generic case */ #if defined(_WIN32) static int audio_fd = -1; #define WM_IS_BADF(_fd) ((_fd)<0) #define WM_BADF -1 static inline int wmidi_fileexists (const char *path) { return (GetFileAttributes(path) != INVALID_FILE_ATTRIBUTES); } static inline int wmidi_open_write (const char *path) { return _open(path, (O_RDWR | O_CREAT | O_TRUNC | O_BINARY), 0664); } static inline void wmidi_close (int fd) { _close(fd); } static inline long wmidi_seekset (int fd, long ofs) { return _lseek(fd, ofs, SEEK_SET); } static inline int wmidi_write (int fd, const void *buf, size_t size) { return _write(fd, buf, size); } #elif defined(__DJGPP__) static int audio_fd = -1; #define WM_IS_BADF(_fd) ((_fd)<0) #define WM_BADF -1 static inline int wmidi_fileexists (const char *path) { struct ffblk f; return (findfirst(path, &f, FA_ARCH | FA_RDONLY) == 0); } static inline int wmidi_open_write (const char *path) { return open(path, (O_RDWR | O_CREAT | O_TRUNC | O_BINARY), 0664); } static inline void wmidi_close (int fd) { close(fd); } static inline off_t wmidi_seekset (int fd, off_t ofs) { return lseek(fd, ofs, SEEK_SET); } static inline int wmidi_write (int fd, const void *buf, size_t size) { return write(fd, buf, size); } #elif defined(__OS2__) || defined(__EMX__) static int audio_fd = -1; #define WM_IS_BADF(_fd) ((_fd)<0) #define WM_BADF -1 static inline int wmidi_fileexists (const char *path) { int f = open(path, (O_RDONLY | O_BINARY)); if (f != -1) { close(f); return 1; } else return 0; } static inline int wmidi_open_write (const char *path) { return open(path, (O_RDWR | O_CREAT | O_TRUNC | O_BINARY), 0664); } static inline void wmidi_close (int fd) { close(fd); } static inline off_t wmidi_seekset (int fd, off_t ofs) { return lseek(fd, ofs, SEEK_SET); } static inline int wmidi_write (int fd, const void *buf, size_t size) { return write(fd, buf, size); } #elif defined(WILDMIDI_AMIGA) static BPTR audio_fd = 0; #define WM_IS_BADF(_fd) ((_fd)==0) #define WM_BADF 0 #undef wmidi_geterrno static int wmidi_geterrno (void) { switch (IoErr()) { case ERROR_OBJECT_NOT_FOUND: return ENOENT; case ERROR_DISK_FULL: return ENOSPC; } return EIO; /* better ?? */ } static inline int wmidi_fileexists (const char *path) { BPTR fd = Open((const STRPTR)path, MODE_OLDFILE); if (!fd) return 0; Close(fd); return 1; } static inline BPTR wmidi_open_write (const char *path) { return Open((const STRPTR) path, MODE_NEWFILE); } static inline LONG wmidi_close (BPTR fd) { return Close(fd); } static inline LONG wmidi_seekset (BPTR fd, LONG ofs) { return Seek(fd, ofs, OFFSET_BEGINNING); } static LONG wmidi_write (BPTR fd, /*const*/ void *buf, LONG size) { LONG written = 0, result; unsigned char *p = (unsigned char *)buf; while (written < size) { result = Write(fd, p + written, size - written); if (result < 0) return result; written += result; } return written; } #else /* common posix case */ static int audio_fd = -1; #define WM_IS_BADF(_fd) ((_fd)<0) #define WM_BADF -1 static inline int wmidi_fileexists (const char *path) { struct stat st; return (stat(path, &st) == 0); } static inline int wmidi_open_write (const char *path) { return open(path, (O_RDWR | O_CREAT | O_TRUNC), (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH)); } static inline int wmidi_close (int fd) { return close(fd); } static inline off_t wmidi_seekset (int fd, off_t ofs) { return lseek(fd, ofs, SEEK_SET); } static inline ssize_t wmidi_write (int fd, const void *buf, size_t size) { return write(fd, buf, size); } #endif static void pause_output_nop(void) { } static void resume_output_nop(void) { } /* MIDI Output Functions */ static char midi_file[1024]; static int write_midi_output(void *output_data, int output_size) { if (midi_file[0] == '\0') return (-1); /* * Test if file already exists */ if (wmidi_fileexists(midi_file)) { fprintf(stderr, "\rError: %s already exists\r\n", midi_file); return (-1); } audio_fd = wmidi_open_write(midi_file); if (WM_IS_BADF(audio_fd)) { fprintf(stderr, "Error: unable to open file for writing (%s)\r\n", strerror(wmidi_geterrno())); return (-1); } if (wmidi_write(audio_fd, output_data, output_size) < 0) { fprintf(stderr, "\nERROR: failed writing midi (%s)\r\n", strerror(wmidi_geterrno())); wmidi_close(audio_fd); audio_fd = WM_BADF; return (-1); } wmidi_close(audio_fd); audio_fd = WM_BADF; return (0); } /* Wav Output Functions */ static char wav_file[1024]; static uint32_t wav_size; static int write_wav_output(int8_t *output_data, int output_size); static void close_wav_output(void); static int open_wav_output(void) { uint8_t wav_hdr[] = { 0x52, 0x49, 0x46, 0x46, /* "RIFF" */ 0x00, 0x00, 0x00, 0x00, /* riffsize: pcm size + 36 (filled when closing.) */ 0x57, 0x41, 0x56, 0x45, /* "WAVE" */ 0x66, 0x6D, 0x74, 0x20, /* "fmt " */ 0x10, 0x00, 0x00, 0x00, /* length of this RIFF block: 16 */ 0x01, 0x00, /* wave format == 1 (WAVE_FORMAT_PCM) */ 0x02, 0x00, /* channels == 2 */ 0x00, 0x00, 0x00, 0x00, /* sample rate (filled below) */ 0x00, 0x00, 0x00, 0x00, /* bytes_per_sec: rate * channels * format bytes */ 0x04, 0x00, /* block alignment: channels * format bytes == 4 */ 0x10, 0x00, /* format bits == 16 */ 0x64, 0x61, 0x74, 0x61, /* "data" */ 0x00, 0x00, 0x00, 0x00 /* datasize: the pcm size (filled when closing.) */ }; if (wav_file[0] == '\0') return (-1); audio_fd = wmidi_open_write(wav_file); if (WM_IS_BADF(audio_fd)) { fprintf(stderr, "Error: unable to open file for writing (%s)\r\n", strerror(wmidi_geterrno())); return (-1); } else { uint32_t bytes_per_sec; wav_hdr[24] = (rate) & 0xFF; wav_hdr[25] = (rate >> 8) & 0xFF; bytes_per_sec = rate * 4; wav_hdr[28] = (bytes_per_sec) & 0xFF; wav_hdr[29] = (bytes_per_sec >> 8) & 0xFF; wav_hdr[30] = (bytes_per_sec >> 16) & 0xFF; wav_hdr[31] = (bytes_per_sec >> 24) & 0xFF; } if (wmidi_write(audio_fd, wav_hdr, 44) < 0) { fprintf(stderr, "ERROR: failed writing wav header (%s)\r\n", strerror(wmidi_geterrno())); wmidi_close(audio_fd); audio_fd = WM_BADF; return (-1); } wav_size = 0; send_output = write_wav_output; close_output = close_wav_output; pause_output = pause_output_nop; resume_output = resume_output_nop; return (0); } static int write_wav_output(int8_t *output_data, int output_size) { #ifdef WORDS_BIGENDIAN /* libWildMidi outputs host-endian, *.wav must have little-endian. */ uint16_t *swp = (uint16_t *) output_data; int i = (output_size / 2) - 1; for (; i >= 0; --i) { swp[i] = (swp[i] << 8) | (swp[i] >> 8); } #endif if (wmidi_write(audio_fd, output_data, output_size) < 0) { fprintf(stderr, "\nERROR: failed writing wav (%s)\r\n", strerror(wmidi_geterrno())); wmidi_close(audio_fd); audio_fd = WM_BADF; return (-1); } wav_size += output_size; return (0); } static void close_wav_output(void) { uint8_t wav_count[4]; if (WM_IS_BADF(audio_fd)) return; printf("Finishing and closing wav output\r"); wav_count[0] = (wav_size) & 0xFF; wav_count[1] = (wav_size >> 8) & 0xFF; wav_count[2] = (wav_size >> 16) & 0xFF; wav_count[3] = (wav_size >> 24) & 0xFF; wmidi_seekset(audio_fd, 40); if (wmidi_write(audio_fd, wav_count, 4) < 0) { fprintf(stderr, "\nERROR: failed writing wav (%s)\r\n", strerror(wmidi_geterrno())); goto end; } wav_size += 36; wav_count[0] = (wav_size) & 0xFF; wav_count[1] = (wav_size >> 8) & 0xFF; wav_count[2] = (wav_size >> 16) & 0xFF; wav_count[3] = (wav_size >> 24) & 0xFF; wmidi_seekset(audio_fd, 4); if (wmidi_write(audio_fd, wav_count, 4) < 0) { fprintf(stderr, "\nERROR: failed writing wav (%s)\r\n", strerror(wmidi_geterrno())); goto end; } end: printf("\n"); if (!WM_IS_BADF(audio_fd)) wmidi_close(audio_fd); audio_fd = WM_BADF; } #if (defined _WIN32) || (defined __CYGWIN__) static HWAVEOUT hWaveOut = NULL; static CRITICAL_SECTION waveCriticalSection; #define open_audio_output open_mm_output static int write_mm_output (int8_t *output_data, int output_size); static void close_mm_output (void); static WAVEHDR *mm_blocks = NULL; #define MM_BLOCK_SIZE 16384 #define MM_BLOCK_COUNT 3 static DWORD mm_free_blocks = MM_BLOCK_COUNT; static DWORD mm_current_block = 0; #if defined(_MSC_VER) && (_MSC_VER < 1300) typedef DWORD DWORD_PTR; #endif static void CALLBACK mmOutProc (HWAVEOUT hWaveOut, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) { /* unused params */ (void)hWaveOut; (void)dwParam1; (void)dwParam2; if(uMsg != WOM_DONE) return; /* increment mm_free_blocks */ EnterCriticalSection(&waveCriticalSection); (*(DWORD *)dwInstance)++; LeaveCriticalSection(&waveCriticalSection); } static int open_mm_output (void) { WAVEFORMATEX wfx; char *mm_buffer; int i; InitializeCriticalSection(&waveCriticalSection); if((mm_buffer = (char *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ((MM_BLOCK_SIZE + sizeof(WAVEHDR)) * MM_BLOCK_COUNT))) == NULL) { fprintf(stderr, "Memory allocation error\r\n"); return -1; } mm_blocks = (WAVEHDR*)mm_buffer; mm_buffer += sizeof(WAVEHDR) * MM_BLOCK_COUNT; for(i = 0; i < MM_BLOCK_COUNT; i++) { mm_blocks[i].dwBufferLength = MM_BLOCK_SIZE; mm_blocks[i].lpData = mm_buffer; mm_buffer += MM_BLOCK_SIZE; } wfx.nSamplesPerSec = rate; wfx.wBitsPerSample = 16; wfx.nChannels = 2; wfx.cbSize = 0; wfx.wFormatTag = WAVE_FORMAT_PCM; wfx.nBlockAlign = (wfx.wBitsPerSample >> 3) * wfx.nChannels; wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec; if(waveOutOpen(&hWaveOut, WAVE_MAPPER, &wfx, (DWORD_PTR)mmOutProc, (DWORD_PTR)&mm_free_blocks, CALLBACK_FUNCTION) != MMSYSERR_NOERROR) { fprintf(stderr, "unable to open WAVE_MAPPER device\r\n"); HeapFree(GetProcessHeap(), 0, mm_blocks); hWaveOut = NULL; mm_blocks = NULL; return -1; } send_output = write_mm_output; close_output = close_mm_output; pause_output = pause_output_nop; resume_output = resume_output_nop; return (0); } static int write_mm_output (int8_t *output_data, int output_size) { WAVEHDR* current; int free_size = 0; int data_read = 0; current = &mm_blocks[mm_current_block]; while (output_size) { if(current->dwFlags & WHDR_PREPARED) waveOutUnprepareHeader(hWaveOut, current, sizeof(WAVEHDR)); free_size = MM_BLOCK_SIZE - current->dwUser; if (free_size > output_size) free_size = output_size; memcpy(current->lpData + current->dwUser, &output_data[data_read], free_size); current->dwUser += free_size; output_size -= free_size; data_read += free_size; if (current->dwUser < MM_BLOCK_SIZE) { return (0); } current->dwBufferLength = MM_BLOCK_SIZE; waveOutPrepareHeader(hWaveOut, current, sizeof(WAVEHDR)); waveOutWrite(hWaveOut, current, sizeof(WAVEHDR)); EnterCriticalSection(&waveCriticalSection); mm_free_blocks--; LeaveCriticalSection(&waveCriticalSection); while(!mm_free_blocks) Sleep(10); mm_current_block++; mm_current_block %= MM_BLOCK_COUNT; current = &mm_blocks[mm_current_block]; current->dwUser = 0; } return (0); } static void close_mm_output (void) { int i; if (!hWaveOut) return; printf("Shutting down sound output\r\n"); for (i = 0; i < MM_BLOCK_COUNT; i++) { while (waveOutUnprepareHeader(hWaveOut, &mm_blocks[i], sizeof(WAVEHDR)) == WAVERR_STILLPLAYING) { Sleep(10); } } waveOutClose (hWaveOut); HeapFree(GetProcessHeap(), 0, mm_blocks); hWaveOut = NULL; mm_blocks = NULL; } #elif (defined(__OS2__) || defined(__EMX__)) && defined(AUDIODRV_OS2DART) /* based on Dart code originally written by Kevin Langman for XMP */ #define open_audio_output open_dart_output static int write_dart_output (int8_t *output_data, int output_size); static void close_dart_output (void); #define BUFFERCOUNT 4 static MCI_MIX_BUFFER MixBuffers[BUFFERCOUNT]; static MCI_MIXSETUP_PARMS MixSetupParms; static MCI_BUFFER_PARMS BufferParms; static MCI_GENERIC_PARMS GenericParms; static ULONG DeviceID = 0; static ULONG bsize = 16; static short next = 2; static short ready = 1; static HMTX dart_mutex; /* Buffer update thread (created and called by DART) */ static LONG APIENTRY OS2_Dart_UpdateBuffers (ULONG ulStatus, PMCI_MIX_BUFFER pBuffer, ULONG ulFlags) { (void) pBuffer;/* unused param */ if ((ulFlags == MIX_WRITE_COMPLETE) || ((ulFlags == (MIX_WRITE_COMPLETE | MIX_STREAM_ERROR)) && (ulStatus == ERROR_DEVICE_UNDERRUN))) { DosRequestMutexSem(dart_mutex, SEM_INDEFINITE_WAIT); ready++; DosReleaseMutexSem(dart_mutex); } return (TRUE); } static int open_dart_output(void) { int i; MCI_AMP_OPEN_PARMS AmpOpenParms; if (DosCreateMutexSem(NULL, &dart_mutex, 0, 0) != NO_ERROR) { fprintf(stderr, "Failed creating a MutexSem.\r\n"); return (-1); } /* compute a size for circa 1/4" of playback. */ bsize = rate >> 2; bsize <<= 1; /* stereo */ bsize <<= 1; /* 16 bit */ for (i = 15; i >= 12; i--) { if (bsize & (1 << i)) break; } bsize = (1 << i); /* make sure buffer is not greater than 64 Kb: DART can't handle it. */ if (bsize > 65536) bsize = 65536; MixBuffers[0].pBuffer = NULL; /* marker */ memset(&GenericParms, 0, sizeof(MCI_GENERIC_PARMS)); /* open AMP device */ memset(&AmpOpenParms, 0, sizeof(MCI_AMP_OPEN_PARMS)); AmpOpenParms.usDeviceID = 0; AmpOpenParms.pszDeviceType = (PSZ) MAKEULONG(MCI_DEVTYPE_AUDIO_AMPMIX, 0); /* 0: default waveaudio device */ if(mciSendCommand(0, MCI_OPEN, MCI_WAIT|MCI_OPEN_TYPE_ID|MCI_OPEN_SHAREABLE, (PVOID) &AmpOpenParms, 0) != MCIERR_SUCCESS) { fprintf(stderr, "Failed opening DART audio device\r\n"); return (-1); } DeviceID = AmpOpenParms.usDeviceID; /* setup playback parameters */ memset(&MixSetupParms, 0, sizeof(MCI_MIXSETUP_PARMS)); MixSetupParms.ulBitsPerSample = 16; MixSetupParms.ulFormatTag = MCI_WAVE_FORMAT_PCM; MixSetupParms.ulSamplesPerSec = rate; MixSetupParms.ulChannels = 2; MixSetupParms.ulFormatMode = MCI_PLAY; MixSetupParms.ulDeviceType = MCI_DEVTYPE_WAVEFORM_AUDIO; MixSetupParms.pmixEvent = OS2_Dart_UpdateBuffers; if (mciSendCommand(DeviceID, MCI_MIXSETUP, MCI_WAIT | MCI_MIXSETUP_INIT, (PVOID) & MixSetupParms, 0) != MCIERR_SUCCESS) { mciSendCommand(DeviceID, MCI_CLOSE, MCI_WAIT, (PVOID) & GenericParms, 0); fprintf(stderr, "Failed DART mixer setup\r\n"); return (-1); } /*bsize = MixSetupParms.ulBufferSize;*/ /*printf("Dart Buffer Size = %lu\n", bsize);*/ BufferParms.ulNumBuffers = BUFFERCOUNT; BufferParms.ulBufferSize = bsize; BufferParms.pBufList = MixBuffers; if (mciSendCommand(DeviceID, MCI_BUFFER, MCI_WAIT | MCI_ALLOCATE_MEMORY, (PVOID) & BufferParms, 0) != MCIERR_SUCCESS) { fprintf(stderr, "DART Memory allocation error\r\n"); mciSendCommand(DeviceID, MCI_CLOSE, MCI_WAIT, (PVOID) & GenericParms, 0); return (-1); } for (i = 0; i < BUFFERCOUNT; i++) { MixBuffers[i].ulBufferLength = bsize; } /* Start Playback */ memset(MixBuffers[0].pBuffer, /*32767 */ 0, bsize); memset(MixBuffers[1].pBuffer, /*32767 */ 0, bsize); MixSetupParms.pmixWrite(MixSetupParms.ulMixHandle, MixBuffers, 2); send_output = write_dart_output; close_output = close_dart_output; pause_output = pause_output_nop; resume_output = resume_output_nop; return (0); } static int write_dart_output (int8_t *output_data, int output_size) { static int idx = 0; if (idx + output_size > bsize) { do { DosRequestMutexSem(dart_mutex, SEM_INDEFINITE_WAIT); if (ready != 0) { DosReleaseMutexSem(dart_mutex); break; } DosReleaseMutexSem(dart_mutex); DosSleep(20); } while (TRUE); MixBuffers[next].ulBufferLength = idx; MixSetupParms.pmixWrite(MixSetupParms.ulMixHandle, &(MixBuffers[next]), 1); ready--; next++; idx = 0; if (next == BUFFERCOUNT) { next = 0; } } memcpy(&((char *)MixBuffers[next].pBuffer)[idx], output_data, output_size); idx += output_size; return (0); } static void close_dart_output (void) { printf("Shutting down sound output\r\n"); if (MixBuffers[0].pBuffer) { mciSendCommand(DeviceID, MCI_BUFFER, MCI_WAIT | MCI_DEALLOCATE_MEMORY, &BufferParms, 0); MixBuffers[0].pBuffer = NULL; } if (DeviceID) { mciSendCommand(DeviceID, MCI_CLOSE, MCI_WAIT, (PVOID) &GenericParms, 0); DeviceID = 0; } } #elif defined(__DJGPP__) && defined(AUDIODRV_DOSSB) /* SoundBlaster/Pro/16/AWE32 driver for DOS -- adapted from * libMikMod, written by Andrew Zabolotny , * further fixes by O.Sezer . * Timer callback functionality replaced by a push mechanism * to keep the wildmidi player changes to a minimum, for now. */ /* The last buffer byte filled with sound */ static unsigned int buff_tail = 0; static int write_sb_output(int8_t *data, unsigned int siz) { unsigned int dma_size, dma_pos; unsigned int cnt; sb_query_dma(&dma_size, &dma_pos); /* There isn't much sense in filling less than 256 bytes */ dma_pos &= ~255; /* If nothing to mix, quit */ if (buff_tail == dma_pos) return 0; /* If DMA pointer still didn't wrapped around ... */ if (dma_pos > buff_tail) { if ((cnt = dma_pos - buff_tail) > siz) cnt = siz; memcpy(sb.dma_buff->linear + buff_tail, data, cnt); buff_tail += cnt; /* If we arrived right to the DMA buffer end, jump to the beginning */ if (buff_tail >= dma_size) buff_tail = 0; } else { /* If wrapped around, fill first to the end of buffer */ if ((cnt = dma_size - buff_tail) > siz) cnt = siz; memcpy(sb.dma_buff->linear + buff_tail, data, cnt); buff_tail += cnt; siz -= cnt; if (!siz) return cnt; /* Now fill from buffer beginning to current DMA pointer */ if (dma_pos > siz) dma_pos = siz; data += cnt; cnt += dma_pos; memcpy(sb.dma_buff->linear, data, dma_pos); buff_tail = dma_pos; } return cnt; } static int write_sb_s16stereo(int8_t *data, int siz) { /* libWildMidi sint16 stereo -> SB16 sint16 stereo */ int i; while (1) { i = write_sb_output(data, siz); if ((siz -= i) <= 0) return 0; data += i; /*usleep(100);*/ } } static int write_sb_u8stereo(int8_t *data, int siz) { /* libWildMidi sint16 stereo -> SB uint8 stereo */ int16_t *src = (int16_t *) data; uint8_t *dst = (uint8_t *) data; int i = (siz /= 2); for (; i >= 0; --i) { *dst++ = (*src++ >> 8) + 128; } while (1) { i = write_sb_output(data, siz); if ((siz -= i) <= 0) return 0; data += i; /*usleep(100);*/ } } static int write_sb_u8mono(int8_t *data, int siz) { /* libWildMidi sint16 stereo -> SB uint8 mono */ int16_t *src = (int16_t *) data; uint8_t *dst = (uint8_t *) data; int i = (siz /= 4); int val; for (; i >= 0; --i) { /* do a cheap (left+right)/2 */ val = *src++; val += *src++; *dst++ = (val >> 9) + 128; } while (1) { i = write_sb_output(data, siz); if ((siz -= i) <= 0) return 0; data += i; /*usleep(100);*/ } } static void sb_silence_s16(void) { memset(sb.dma_buff->linear, 0, sb.dma_buff->size); } static void sb_silence_u8(void) { memset(sb.dma_buff->linear, 0x80, sb.dma_buff->size); } static void close_sb_output(void) { sb.timer_callback = NULL; sb_output(FALSE); sb_stop_dma(); sb_close(); } #define open_audio_output open_sb_output static int open_sb_output(void) { if (!sb_open()) { fprintf(stderr, "Sound Blaster initialization failed.\n"); return -1; } if (rate < 4000) rate = 4000; if (sb.caps & SBMODE_STEREO) { if (rate > sb.maxfreq_stereo) rate = sb.maxfreq_stereo; } else { if (rate > sb.maxfreq_mono) rate = sb.maxfreq_mono; } /* Enable speaker output */ sb_output(TRUE); /* Set our routine to be called during SB IRQs */ buff_tail = 0; sb.timer_callback = NULL;/* see above */ /* Start cyclic DMA transfer */ if (!sb_start_dma(((sb.caps & SBMODE_16BITS) ? SBMODE_16BITS | SBMODE_SIGNED : 0) | (sb.caps & SBMODE_STEREO), rate)) { sb_output(FALSE); sb_close(); fprintf(stderr, "Sound Blaster: DMA start failed.\n"); return -1; } if (sb.caps & SBMODE_16BITS) { /* can do stereo, too */ send_output = write_sb_s16stereo; pause_output = sb_silence_s16; resume_output = resume_output_nop; printf("Sound Blaster 16 or compatible (16 bit, stereo, %u Hz)\n", rate); } else if (sb.caps & SBMODE_STEREO) { send_output = write_sb_u8stereo; pause_output = sb_silence_u8; resume_output = resume_output_nop; printf("Sound Blaster Pro or compatible (8 bit, stereo, %u Hz)\n", rate); } else { send_output = write_sb_u8mono; pause_output = sb_silence_u8; resume_output = resume_output_nop; printf("Sound Blaster %c or compatible (8 bit, mono, %u Hz)\n", (sb.dspver < SBVER_20)? '1' : '2', rate); } close_output = close_sb_output; return 0; } #elif defined(WILDMIDI_AMIGA) && defined(AUDIODRV_AHI) /* Driver for output to native Amiga AHI device: * Written by Szilárd Biró , loosely based * on an old AOS4 version by Fredrik Wikstrom */ #define BUFFERSIZE (4 << 10) static struct MsgPort *AHImp = NULL; static struct AHIRequest *AHIReq[2] = { NULL, NULL }; static int active = 0; static int8_t *AHIBuf[2] = { NULL, NULL }; #define open_audio_output open_ahi_output static int write_ahi_output(int8_t *output_data, int output_size); static void close_ahi_output(void); static int open_ahi_output(void) { AHImp = CreateMsgPort(); if (AHImp) { AHIReq[0] = (struct AHIRequest *) CreateIORequest(AHImp, sizeof(struct AHIRequest)); if (AHIReq[0]) { AHIReq[0]->ahir_Version = 4; AHIReq[1] = (struct AHIRequest *) AllocVec(sizeof(struct AHIRequest), MEMF_PUBLIC); if (AHIReq[1]) { if (!OpenDevice(AHINAME, AHI_DEFAULT_UNIT, (struct IORequest *)AHIReq[0], 0)) { /*AHIReq[0]->ahir_Std.io_Message.mn_Node.ln_Pri = 0;*/ AHIReq[0]->ahir_Std.io_Command = CMD_WRITE; AHIReq[0]->ahir_Std.io_Data = NULL; AHIReq[0]->ahir_Std.io_Offset = 0; AHIReq[0]->ahir_Frequency = rate; AHIReq[0]->ahir_Type = AHIST_S16S;/* 16 bit stereo */ AHIReq[0]->ahir_Volume = 0x10000; AHIReq[0]->ahir_Position = 0x8000; CopyMem(AHIReq[0], AHIReq[1], sizeof(struct AHIRequest)); AHIBuf[0] = (int8_t *) AllocVec(BUFFERSIZE, MEMF_PUBLIC | MEMF_CLEAR); if (AHIBuf[0]) { AHIBuf[1] = (int8_t *) AllocVec(BUFFERSIZE, MEMF_PUBLIC | MEMF_CLEAR); if (AHIBuf[1]) { send_output = write_ahi_output; close_output = close_ahi_output; pause_output = pause_output_nop; resume_output = resume_output_nop; return (0); } } } } } } close_ahi_output(); fprintf(stderr, "ERROR: Unable to open AHI output\r\n"); return (-1); } static int write_ahi_output(int8_t *output_data, int output_size) { int chunk; while (output_size > 0) { if (AHIReq[active]->ahir_Std.io_Data) { WaitIO((struct IORequest *) AHIReq[active]); } chunk = (output_size < BUFFERSIZE)? output_size : BUFFERSIZE; memcpy(AHIBuf[active], output_data, chunk); output_size -= chunk; output_data += chunk; AHIReq[active]->ahir_Std.io_Data = AHIBuf[active]; AHIReq[active]->ahir_Std.io_Length = chunk; AHIReq[active]->ahir_Link = !CheckIO((struct IORequest *) AHIReq[active ^ 1]) ? AHIReq[active ^ 1] : NULL; SendIO((struct IORequest *)AHIReq[active]); active ^= 1; } return (0); } static void close_ahi_output(void) { if (AHIReq[1]) { AHIReq[0]->ahir_Link = NULL; /* in case we are linked to req[0] */ if (!CheckIO((struct IORequest *) AHIReq[1])) { AbortIO((struct IORequest *) AHIReq[1]); WaitIO((struct IORequest *) AHIReq[1]); } FreeVec(AHIReq[1]); AHIReq[1] = NULL; } if (AHIReq[0]) { if (!CheckIO((struct IORequest *) AHIReq[0])) { AbortIO((struct IORequest *) AHIReq[0]); WaitIO((struct IORequest *) AHIReq[0]); } if (AHIReq[0]->ahir_Std.io_Device) { CloseDevice((struct IORequest *) AHIReq[0]); AHIReq[0]->ahir_Std.io_Device = NULL; } DeleteIORequest((struct IORequest *) AHIReq[0]); AHIReq[0] = NULL; } if (AHImp) { DeleteMsgPort(AHImp); AHImp = NULL; } if (AHIBuf[0]) { FreeVec(AHIBuf[0]); AHIBuf[0] = NULL; } if (AHIBuf[1]) { FreeVec(AHIBuf[1]); AHIBuf[1] = NULL; } } #else #ifdef AUDIODRV_ALSA static int alsa_first_time = 1; static snd_pcm_t *pcm = NULL; static char pcmname[64]; #define open_audio_output open_alsa_output static int write_alsa_output(int8_t *output_data, int output_size); static void close_alsa_output(void); static int open_alsa_output(void) { snd_pcm_hw_params_t *hw; snd_pcm_sw_params_t *sw; int err; unsigned int alsa_buffer_time; unsigned int alsa_period_time; unsigned int r; if (!pcmname[0]) { strcpy(pcmname, "default"); } if ((err = snd_pcm_open(&pcm, pcmname, SND_PCM_STREAM_PLAYBACK, 0)) < 0) { fprintf(stderr, "Error: audio open error: %s\r\n", snd_strerror(err)); return -1; } snd_pcm_hw_params_alloca(&hw); if ((err = snd_pcm_hw_params_any(pcm, hw)) < 0) { fprintf(stderr, "ERROR: No configuration available for playback: %s\r\n", snd_strerror(err)); goto fail; } if ((err = snd_pcm_hw_params_set_access(pcm, hw, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { fprintf(stderr, "Cannot set access mode: %s.\r\n", snd_strerror(err)); goto fail; } if (snd_pcm_hw_params_set_format(pcm, hw, SND_PCM_FORMAT_S16) < 0) { fprintf(stderr, "ALSA does not support 16bit signed audio for your soundcard\r\n"); goto fail; } if (snd_pcm_hw_params_set_channels(pcm, hw, 2) < 0) { fprintf(stderr, "ALSA does not support stereo for your soundcard\r\n"); goto fail; } r = rate; if (snd_pcm_hw_params_set_rate_near(pcm, hw, &rate, 0) < 0) { fprintf(stderr, "ALSA does not support %uHz for your soundcard\r\n", rate); goto fail; } if (r != rate) { fprintf(stderr, "ALSA: sample rate set to %uHz instead of %u\r\n", rate, r); } alsa_buffer_time = 500000; alsa_period_time = 50000; if ((err = snd_pcm_hw_params_set_buffer_time_near(pcm, hw, &alsa_buffer_time, 0)) < 0) { fprintf(stderr, "Set buffer time failed: %s.\r\n", snd_strerror(err)); goto fail; } if ((err = snd_pcm_hw_params_set_period_time_near(pcm, hw, &alsa_period_time, 0)) < 0) { fprintf(stderr, "Set period time failed: %s.\r\n", snd_strerror(err)); goto fail; } if (snd_pcm_hw_params(pcm, hw) < 0) { fprintf(stderr, "Unable to install hw params\r\n"); goto fail; } snd_pcm_sw_params_alloca(&sw); snd_pcm_sw_params_current(pcm, sw); if (snd_pcm_sw_params(pcm, sw) < 0) { fprintf(stderr, "Unable to install sw params\r\n"); goto fail; } send_output = write_alsa_output; close_output = close_alsa_output; pause_output = pause_output_nop; resume_output = resume_output_nop; return (0); fail: close_alsa_output(); return -1; } static int write_alsa_output(int8_t *output_data, int output_size) { int err; snd_pcm_uframes_t frames; while (output_size > 0) { frames = snd_pcm_bytes_to_frames(pcm, output_size); if ((err = snd_pcm_writei(pcm, output_data, frames)) < 0) { if (snd_pcm_state(pcm) == SND_PCM_STATE_XRUN) { if ((err = snd_pcm_prepare(pcm)) < 0) fprintf(stderr, "\nsnd_pcm_prepare() failed.\r\n"); alsa_first_time = 1; continue; } return err; } output_size -= snd_pcm_frames_to_bytes(pcm, err); output_data += snd_pcm_frames_to_bytes(pcm, err); if (alsa_first_time) { alsa_first_time = 0; snd_pcm_start(pcm); } } return (0); } static void close_alsa_output(void) { if (!pcm) return; printf("Shutting down sound output\r\n"); snd_pcm_close(pcm); pcm = NULL; } #elif defined AUDIODRV_OSS #if !defined(AFMT_S16_NE) #ifdef WORDS_BIGENDIAN #define AFMT_S16_NE AFMT_S16_BE #else #define AFMT_S16_NE AFMT_S16_LE #endif #endif #define DEFAULT_FRAGSIZE 14 #define DEFAULT_NUMFRAGS 16 static char pcmname[64]; #define open_audio_output open_oss_output static int write_oss_output(int8_t *output_data, int output_size); static void close_oss_output(void); static void pause_output_oss(void) { ioctl(audio_fd, SNDCTL_DSP_POST, 0); } static int open_oss_output(void) { int tmp; unsigned int r; if (!pcmname[0]) { strcpy(pcmname, "/dev/dsp"); } if ((audio_fd = open(pcmname, O_WRONLY)) < 0) { fprintf(stderr, "ERROR: Unable to open dsp (%s)\r\n", strerror(errno)); return (-1); } if (ioctl(audio_fd, SNDCTL_DSP_RESET, 0) < 0) { fprintf(stderr, "ERROR: Unable to reset dsp\r\n"); goto fail; } tmp = AFMT_S16_NE; if (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &tmp) < 0) { fprintf(stderr, "ERROR: Unable to set 16bit sound format\r\n"); goto fail; } tmp = 2; if (ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &tmp) < 0) { fprintf(stderr, "ERROR: Unable to set stereo\r\n"); goto fail; } r = rate; if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &rate) < 0) { fprintf(stderr, "ERROR: Unable to set %uHz sample rate\r\n", rate); goto fail; } if (r != rate) { fprintf(stderr, "OSS: sample rate set to %uHz instead of %u\r\n", rate, r); } tmp = (DEFAULT_NUMFRAGS<<16)|DEFAULT_FRAGSIZE; if (ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &tmp) < 0) { fprintf(stderr, "ERROR: Unable to set fragment size\r\n"); goto fail; } send_output = write_oss_output; close_output = close_oss_output; pause_output = pause_output_oss; resume_output = resume_output_nop; return (0); fail: close_oss_output(); return (-1); } static int write_oss_output(int8_t *output_data, int output_size) { int res = 0; while (output_size > 0) { res = write(audio_fd, output_data, output_size); if (res > 0) { output_size -= res; output_data += res; } else { fprintf(stderr, "\nOSS: write failure to dsp: %s.\r\n", strerror(errno)); return (-1); } } return (0); } static void close_oss_output(void) { if (audio_fd < 0) return; printf("Shutting down sound output\r\n"); ioctl(audio_fd, SNDCTL_DSP_RESET, 0); close(audio_fd); audio_fd = -1; } #elif defined AUDIODRV_OPENAL #define NUM_BUFFERS 4 static ALCdevice *device; static ALCcontext *context; static ALuint sourceId = 0; static ALuint buffers[NUM_BUFFERS]; static ALuint frames = 0; #define open_audio_output open_openal_output static void pause_output_openal(void) { alSourcePause(sourceId); } static int write_openal_output(int8_t *output_data, int output_size) { ALint processed, state; ALuint bufid; if (frames < NUM_BUFFERS) { /* initial state: fill the buffers */ alBufferData(buffers[frames], AL_FORMAT_STEREO16, output_data, output_size, rate); /* Now queue and start playback! */ if (++frames == NUM_BUFFERS) { alSourceQueueBuffers(sourceId, frames, buffers); alSourcePlay(sourceId); } return 0; } /* Get relevant source info */ alGetSourcei(sourceId, AL_SOURCE_STATE, &state); if (state == AL_PAUSED) { /* resume it, then.. */ alSourcePlay(sourceId); if (alGetError() != AL_NO_ERROR) { fprintf(stderr, "\nError restarting playback\r\n"); return (-1); } } processed = 0; while (processed == 0) { /* Wait until we have a processed buffer */ alGetSourcei(sourceId, AL_BUFFERS_PROCESSED, &processed); } /* Unqueue and handle each processed buffer */ alSourceUnqueueBuffers(sourceId, 1, &bufid); /* Read the next chunk of data, refill the buffer, and queue it * back on the source */ alBufferData(bufid, AL_FORMAT_STEREO16, output_data, output_size, rate); alSourceQueueBuffers(sourceId, 1, &bufid); if (alGetError() != AL_NO_ERROR) { fprintf(stderr, "\nError buffering data\r\n"); return (-1); } /* Make sure the source hasn't underrun */ alGetSourcei(sourceId, AL_SOURCE_STATE, &state); /*printf("STATE: %#08x - %d\n", state, queued);*/ if (state != AL_PLAYING) { ALint queued; /* If no buffers are queued, playback is finished */ alGetSourcei(sourceId, AL_BUFFERS_QUEUED, &queued); if (queued == 0) { fprintf(stderr, "\nNo buffers queued for playback\r\n"); return (-1); } alSourcePlay(sourceId); } return (0); } static void close_openal_output(void) { if (!context) return; printf("Shutting down sound output\r\n"); alSourceStop(sourceId); /* stop playing */ alSourcei(sourceId, AL_BUFFER, 0); /* unload buffer from source */ alDeleteBuffers(NUM_BUFFERS, buffers); alDeleteSources(1, &sourceId); alcDestroyContext(context); alcCloseDevice(device); context = NULL; device = NULL; frames = 0; } static int open_openal_output(void) { /* setup our audio devices and contexts */ device = alcOpenDevice(NULL); if (!device) { fprintf(stderr, "OpenAL: Unable to open default device.\r\n"); return (-1); } context = alcCreateContext(device, NULL); if (context == NULL || alcMakeContextCurrent(context) == ALC_FALSE) { if (context != NULL) alcDestroyContext(context); alcCloseDevice(device); context = NULL; device = NULL; fprintf(stderr, "OpenAL: Failed to create the default context.\r\n"); return (-1); } /* setup our sources and buffers */ alGenSources(1, &sourceId); alGenBuffers(NUM_BUFFERS, buffers); send_output = write_openal_output; close_output = close_openal_output; pause_output = pause_output_openal; resume_output = resume_output_nop; return (0); } #else /* no audio output driver compiled in: */ #define open_audio_output open_noaudio_output static int open_noaudio_output(void) { fprintf(stderr, "No audio output driver was selected at compile time.\r\n"); return -1; } #endif /* AUDIODRV_ALSA */ #endif /* _WIN32 || __CYGWIN__ */ static struct option const long_options[] = { { "version", 0, 0, 'v' }, { "help", 0, 0, 'h' }, { "rate", 1, 0, 'r' }, { "mastervol", 1, 0, 'm' }, { "config", 1, 0, 'c' }, { "wavout", 1, 0, 'o' }, { "tomidi", 1, 0, 'x' }, { "convert", 1, 0, 'g' }, { "frequency", 1, 0, 'f' }, { "log_vol", 0, 0, 'l' }, { "reverb", 0, 0, 'b' }, { "test_midi", 0, 0, 't' }, { "test_bank", 1, 0, 'k' }, { "test_patch", 1, 0, 'p' }, { "enhanced", 0, 0, 'e' }, #if defined(AUDIODRV_OSS) || defined(AUDIODRV_ALSA) { "device", 1, 0, 'd' }, #endif { "roundtempo", 0, 0, 'n' }, { "skipsilentstart", 0, 0, 's' }, { "textaslyric", 0, 0, 'a' }, { "playfrom", 1, 0, 'i'}, { "playto", 1, 0, 'j'}, { NULL, 0, NULL, 0 } }; static void do_help(void) { printf(" -v --version Display version info and exit\n"); printf(" -h --help Display this help and exit\n"); #if defined(AUDIODRV_OSS) || defined(AUDIODRV_ALSA) printf(" -d D --device=D Use device D for audio output instead of default\n"); #endif printf("MIDI Options:\n"); printf(" -n --roundtempo Round tempo to nearest whole number\n"); printf(" -s --skipsilentstart Skips any silence at the start of playback\n"); printf(" -t --test_midi Listen to test MIDI\n"); printf("Non-MIDI Options:\n"); printf(" -x --tomidi Convert file to midi and save to file\n"); printf(" -g --convert Convert XMI: 0 - No Conversion (default)\n"); printf(" 1 - MT32 to GM\n"); printf(" 2 - MT32 to GS\n"); printf(" -f F --frequency=F Use frequency F Hz for playback (MUS)\n"); printf("Software Wavetable Options:\n"); printf(" -o W --wavout=W Save output to W in 16bit stereo format wav file\n"); printf(" -l --log_vol Use log volume adjustments\n"); printf(" -r N --rate=N Set sample rate to N samples per second (Hz)\n"); printf(" -c P --config=P Point to your wildmidi.cfg config file name/path\n"); printf(" defaults to: %s\n", WILDMIDI_CFG); printf(" -m V --mastervol=V Set the master volume (0..127), default is 100\n"); printf(" -b --reverb Enable final output reverb engine\n"); } static void do_version(void) { printf("\nWildMidi %s Open Source Midi Sequencer\n", PACKAGE_VERSION); printf("Copyright (C) WildMIDI Developers 2001-2016\n\n"); printf("WildMidi comes with ABSOLUTELY NO WARRANTY\n"); printf("This is free software, and you are welcome to redistribute it under\n"); printf("the terms and conditions of the GNU General Public License version 3.\n"); printf("For more information see COPYING\n\n"); printf("Report bugs to %s\n", PACKAGE_BUGREPORT); printf("WildMIDI homepage is at %s\n\n", PACKAGE_URL); } static void do_syntax(void) { printf("Usage: wildmidi [options] filename.mid\n\n"); } static char config_file[1024]; int main(int argc, char **argv) { struct _WM_Info *wm_info; int i, res; int option_index = 0; uint16_t mixer_options = 0; void *midi_ptr; uint8_t master_volume = 100; int8_t *output_buffer; uint32_t perc_play; uint32_t pro_mins; uint32_t pro_secs; uint32_t apr_mins; uint32_t apr_secs; char modes[5]; uint8_t ch; int test_midi = 0; int test_count = 0; uint8_t *test_data; uint8_t test_bank = 0; uint8_t test_patch = 0; static char spinner[] = "|/-\\"; static int spinpoint = 0; unsigned long int seek_to_sample; uint32_t samples = 0; int inpause = 0; char * ret_err = NULL; long libraryver; char * lyric = NULL; char *last_lyric = NULL; size_t last_lyric_length = 0; int8_t kareoke = 0; #define MAX_LYRIC_CHAR 128 char lyrics[MAX_LYRIC_CHAR + 1]; #define MAX_DISPLAY_LYRICS 29 char display_lyrics[MAX_DISPLAY_LYRICS + 1]; unsigned long int play_from = 0; unsigned long int play_to = 0; memset(lyrics,' ',MAX_LYRIC_CHAR); memset(display_lyrics,' ',MAX_DISPLAY_LYRICS); #if defined(AUDIODRV_OSS) || defined(AUDIODRV_ALSA) pcmname[0] = 0; #endif config_file[0] = 0; wav_file[0] = 0; midi_file[0] = 0; do_version(); while (1) { i = getopt_long(argc, argv, "0vho:tx:g:f:lr:c:m:btak:p:ed:nsi:j:", long_options, &option_index); if (i == -1) break; switch (i) { case 'v': /* Version */ return (0); case 'h': /* help */ do_syntax(); do_help(); return (0); case 'r': /* Sample Rate */ res = atoi(optarg); if (res < 0 || res > 65535) { fprintf(stderr, "Error: bad rate %i.\n", res); return (1); } rate = (uint32_t) res; break; case 'b': /* Reverb */ mixer_options |= WM_MO_REVERB; break; case 'm': /* Master Volume */ master_volume = (uint8_t) atoi(optarg); break; case 'o': /* Wav Output */ if (!*optarg) { fprintf(stderr, "Error: empty wavfile name.\n"); return (1); } strncpy(wav_file, optarg, sizeof(wav_file)); wav_file[sizeof(wav_file) - 1] = 0; break; case 'g': /* XMIDI Conversion */ WildMidi_SetCvtOption(WM_CO_XMI_TYPE, (uint16_t) atoi(optarg)); break; case 'f': /* MIDI-like Conversion */ WildMidi_SetCvtOption(WM_CO_FREQUENCY, (uint16_t) atoi(optarg)); break; case 'x': /* MIDI Output */ if (!*optarg) { fprintf(stderr, "Error: empty midi name.\n"); return (1); } strncpy(midi_file, optarg, sizeof(midi_file)); midi_file[sizeof(midi_file) - 1] = 0; break; case 'c': /* Config File */ if (!*optarg) { fprintf(stderr, "Error: empty config name.\n"); return (1); } strncpy(config_file, optarg, sizeof(config_file)); config_file[sizeof(config_file) - 1] = 0; break; #if defined(AUDIODRV_OSS) || defined(AUDIODRV_ALSA) case 'd': /* Output device */ if (!*optarg) { fprintf(stderr, "Error: empty device name.\n"); return (1); } strncpy(pcmname, optarg, sizeof(pcmname)); pcmname[sizeof(pcmname) - 1] = 0; break; #endif case 'e': /* Enhanced Resampling */ mixer_options |= WM_MO_ENHANCED_RESAMPLING; break; case 'l': /* log volume */ mixer_options |= WM_MO_LOG_VOLUME; break; case 't': /* play test midis */ test_midi = 1; break; case 'k': /* set test bank */ test_bank = (uint8_t) atoi(optarg); break; case 'p': /* set test patch */ test_patch = (uint8_t) atoi(optarg); break; case 'n': /* whole number tempo */ mixer_options |= WM_MO_ROUNDTEMPO; break; case 'a': /* Some files have the lyrics in the text meta event. * This option reads lyrics from there instead. */ mixer_options |= WM_MO_TEXTASLYRIC; break; case 's': /* strip silence at start */ mixer_options |= WM_MO_STRIPSILENCE; break; case '0': /* treat as type 2 midi when writing to file */ mixer_options |= WM_MO_SAVEASTYPE0; break; case 'i': play_from = (unsigned long int)(atof(optarg) * (double)rate); break; case 'j': play_to = (unsigned long int)(atof(optarg) * (double)rate); break; default: do_syntax(); return (1); } } if (optind >= argc && !test_midi) { fprintf(stderr, "ERROR: No midi file given\r\n"); do_syntax(); return (1); } if (test_midi) { if (midi_file[0] != '\0') { fprintf(stderr, "--test_midi and --convert cannot be used together.\n"); return (1); } } /* check if we only need to convert a file to midi */ if (midi_file[0] != '\0') { const char *real_file = FIND_LAST_DIRSEP(argv[optind]); uint32_t size; uint8_t *data; if (!real_file) real_file = argv[optind]; else real_file++; printf("Converting %s\r\n", real_file); if (WildMidi_ConvertToMidi(argv[optind], &data, &size) < 0) { fprintf(stderr, "Conversion failed: %s.\r\n", WildMidi_GetError()); WildMidi_ClearError(); return (1); } printf("Writing %s: %u bytes.\r\n", midi_file, size); write_midi_output(data, size); free(data); return (0); } if (!config_file[0]) { strncpy(config_file, WILDMIDI_CFG, sizeof(config_file)); config_file[sizeof(config_file) - 1] = 0; } printf("Initializing Sound System\n"); if (wav_file[0] != '\0') { if (open_wav_output() == -1) { return (1); } } else { if (open_audio_output() == -1) { return (1); } } libraryver = WildMidi_GetVersion(); printf("Initializing libWildMidi %ld.%ld.%ld\n\n", (libraryver>>16) & 255, (libraryver>> 8) & 255, (libraryver ) & 255); if (WildMidi_Init(config_file, rate, mixer_options) == -1) { fprintf(stderr, "%s\r\n", WildMidi_GetError()); WildMidi_ClearError(); return (1); } printf(" + Volume up e Better resampling n Next Midi\n"); printf(" - Volume down l Log volume q Quit\n"); printf(" , 1sec Seek Back r Reverb . 1sec Seek Forward\n"); printf(" m save as midi p Pause On/Off\n\n"); output_buffer = (int8_t *) malloc(16384); if (output_buffer == NULL) { fprintf(stderr, "Not enough memory, exiting\n"); WildMidi_Shutdown(); return (1); } wm_inittty(); #ifdef WILDMIDI_AMIGA amiga_sysinit(); #endif WildMidi_MasterVolume(master_volume); while (optind < argc || test_midi) { WildMidi_ClearError(); if (!test_midi) { const char *real_file = FIND_LAST_DIRSEP(argv[optind]); if (!real_file) real_file = argv[optind]; else real_file++; printf("\rPlaying %s ", real_file); midi_ptr = WildMidi_Open(argv[optind]); optind++; if (midi_ptr == NULL) { ret_err = WildMidi_GetError(); printf(" Skipping: %s\r\n",ret_err); continue; } } else { if (test_count == midi_test_max) { break; } test_data = (uint8_t *) malloc(midi_test[test_count].size); memcpy(test_data, midi_test[test_count].data, midi_test[test_count].size); test_data[25] = test_bank; test_data[28] = test_patch; midi_ptr = WildMidi_OpenBuffer(test_data, 633); test_count++; if (midi_ptr == NULL) { fprintf(stderr, "\rFailed loading test midi no. %i\r\n", test_count); continue; } printf("\rPlaying test midi no. %i ", test_count); } wm_info = WildMidi_GetInfo(midi_ptr); apr_mins = wm_info->approx_total_samples / (rate * 60); apr_secs = (wm_info->approx_total_samples % (rate * 60)) / rate; mixer_options = wm_info->mixer_options; modes[0] = (mixer_options & WM_MO_LOG_VOLUME)? 'l' : ' '; modes[1] = (mixer_options & WM_MO_REVERB)? 'r' : ' '; modes[2] = (mixer_options & WM_MO_ENHANCED_RESAMPLING)? 'e' : ' '; modes[3] = ' '; modes[4] = '\0'; printf("\r\n[Approx %2um %2us Total]\r\n", apr_mins, apr_secs); fprintf(stderr, "\r"); memset(lyrics,' ',MAX_LYRIC_CHAR); memset(display_lyrics,' ',MAX_DISPLAY_LYRICS); if (play_from != 0) { WildMidi_FastSeek(midi_ptr, &play_from); if (play_to < play_from) { // Ignore --playto if set less than --playfrom play_to = 0; } } while (1) { ch = 0; #ifdef _WIN32 if (_kbhit()) { ch = _getch(); _putch(ch); } #elif defined(__DJGPP__) || defined(__OS2__) || defined(__EMX__) if (kbhit()) { ch = getch(); putch(ch); } #elif defined(WILDMIDI_AMIGA) amiga_getch (&ch); #else if (read(STDIN_FILENO, &ch, 1) != 1) ch = 0; #endif if (ch) { switch (ch) { case 'l': WildMidi_SetOption(midi_ptr, WM_MO_LOG_VOLUME, ((mixer_options & WM_MO_LOG_VOLUME) ^ WM_MO_LOG_VOLUME)); mixer_options ^= WM_MO_LOG_VOLUME; modes[0] = (mixer_options & WM_MO_LOG_VOLUME)? 'l' : ' '; break; case 'r': WildMidi_SetOption(midi_ptr, WM_MO_REVERB, ((mixer_options & WM_MO_REVERB) ^ WM_MO_REVERB)); mixer_options ^= WM_MO_REVERB; modes[1] = (mixer_options & WM_MO_REVERB)? 'r' : ' '; break; case 'e': WildMidi_SetOption(midi_ptr, WM_MO_ENHANCED_RESAMPLING, ((mixer_options & WM_MO_ENHANCED_RESAMPLING) ^ WM_MO_ENHANCED_RESAMPLING)); mixer_options ^= WM_MO_ENHANCED_RESAMPLING; modes[2] = (mixer_options & WM_MO_ENHANCED_RESAMPLING)? 'e' : ' '; break; case 'a': WildMidi_SetOption(midi_ptr, WM_MO_TEXTASLYRIC, ((mixer_options & WM_MO_TEXTASLYRIC) ^ WM_MO_TEXTASLYRIC)); mixer_options ^= WM_MO_TEXTASLYRIC; break; case 'n': goto NEXTMIDI; case 'p': if (inpause) { inpause = 0; fprintf(stderr, " \r"); resume_output(); } else { inpause = 1; fprintf(stderr, "Paused \r"); pause_output(); continue; } break; case 'q': printf("\r\n"); if (inpause) goto end2; goto end1; case '-': if (master_volume > 0) { master_volume--; WildMidi_MasterVolume(master_volume); } break; case '+': if (master_volume < 127) { master_volume++; WildMidi_MasterVolume(master_volume); } break; case ',': /* fast seek backwards */ if (wm_info->current_sample < rate) { seek_to_sample = 0; } else { seek_to_sample = wm_info->current_sample - rate; } WildMidi_FastSeek(midi_ptr, &seek_to_sample); break; case '.': /* fast seek forwards */ if ((wm_info->approx_total_samples - wm_info->current_sample) < rate) { seek_to_sample = wm_info->approx_total_samples; } else { seek_to_sample = wm_info->current_sample + rate; } WildMidi_FastSeek(midi_ptr, &seek_to_sample); break; case '<': WildMidi_SongSeek (midi_ptr, -1); break; case '>': WildMidi_SongSeek (midi_ptr, 1); break; case '/': WildMidi_SongSeek (midi_ptr, 0); break; case 'm': /* save as midi */ { int8_t *getmidibuffer = NULL; uint32_t getmidisize = 0; int32_t getmidiret = 0; getmidiret = WildMidi_GetMidiOutput(midi_ptr, &getmidibuffer, &getmidisize); if (getmidiret == -1) { fprintf(stderr, "\r\n\nFAILED to convert events to midi\r\n"); ret_err = WildMidi_GetError(); fprintf(stderr, "%s\r\n",ret_err); WildMidi_ClearError(); } else { char *real_file = FIND_LAST_DIRSEP(argv[optind-1]); if (!real_file) real_file = argv[optind]; else real_file++; strncpy(midi_file, real_file, strlen(real_file)); midi_file[strlen(real_file)-4] = '.'; midi_file[strlen(real_file)-3] = 'm'; midi_file[strlen(real_file)-2] = 'i'; midi_file[strlen(real_file)-1] = 'd'; printf("\rWriting %s: %u bytes.\r\n", midi_file, getmidisize); write_midi_output(getmidibuffer,getmidisize); free(getmidibuffer); } } break; case 'k': /* Kareoke */ /* Enables/Disables the display of lyrics */ kareoke ^= 1; break; default: break; } } if (inpause) { wm_info = WildMidi_GetInfo(midi_ptr); perc_play = (wm_info->current_sample * 100) / wm_info->approx_total_samples; pro_mins = wm_info->current_sample / (rate * 60); pro_secs = (wm_info->current_sample % (rate * 60)) / rate; fprintf(stderr, "%s [%s] [%3i] [%2um %2us Processed] [%2u%%] P \r", display_lyrics, modes, (int)master_volume, pro_mins, pro_secs, perc_play); msleep(5); continue; } if (play_to != 0) { if ((wm_info->current_sample + 4096) <= play_to) { samples = 16384; } else { samples = (play_to - wm_info->current_sample) << 2; if (!samples) { // We are at or past where we wanted to play to break; } } } else { samples = 16384; } res = WildMidi_GetOutput(midi_ptr, output_buffer, samples); if (res <= 0) break; wm_info = WildMidi_GetInfo(midi_ptr); lyric = WildMidi_GetLyric(midi_ptr); memmove(lyrics, &lyrics[1], MAX_LYRIC_CHAR - 1); lyrics[MAX_LYRIC_CHAR - 1] = ' '; if ((lyric != NULL) && (lyric != last_lyric) && (kareoke)) { last_lyric = lyric; if (last_lyric_length != 0) { memcpy(lyrics, &lyrics[last_lyric_length], MAX_LYRIC_CHAR - last_lyric_length); } memcpy(&lyrics[MAX_DISPLAY_LYRICS], lyric, strlen(lyric)); last_lyric_length = strlen(lyric); } else { if (last_lyric_length != 0) last_lyric_length--; } memcpy(display_lyrics,lyrics,MAX_DISPLAY_LYRICS); display_lyrics[MAX_DISPLAY_LYRICS] = '\0'; perc_play = (wm_info->current_sample * 100) / wm_info->approx_total_samples; pro_mins = wm_info->current_sample / (rate * 60); pro_secs = (wm_info->current_sample % (rate * 60)) / rate; fprintf(stderr, "%s [%s] [%3i] [%2um %2us Processed] [%2u%%] %c \r", display_lyrics, modes, (int)master_volume, pro_mins, pro_secs, perc_play, spinner[spinpoint++ % 4]); if (send_output(output_buffer, res) < 0) { /* driver prints an error message already. */ printf("\r"); goto end2; } } NEXTMIDI: fprintf(stderr, "\r\n"); if (WildMidi_Close(midi_ptr) == -1) { ret_err = WildMidi_GetError(); fprintf(stderr, "OOPS: failed closing midi handle!\r\n%s\r\n",ret_err); } memset(output_buffer, 0, 16384); send_output(output_buffer, 16384); } end1: memset(output_buffer, 0, 16384); send_output(output_buffer, 16384); msleep(5); end2: close_output(); free(output_buffer); if (WildMidi_Shutdown() == -1) { ret_err = WildMidi_GetError(); fprintf(stderr, "OOPS: failure shutting down libWildMidi\r\n%s\r\n", ret_err); WildMidi_ClearError(); } wm_resetty(); printf("\r\n"); return (0); } /* helper / replacement functions: */ #if !(defined(_WIN32) || defined(__DJGPP__) || defined(WILDMIDI_AMIGA) || defined(__OS2__) || defined(__EMX__)) static int msleep(unsigned long milisec) { struct timespec req = { 0, 0 }; time_t sec = (int) (milisec / 1000); milisec = milisec - (sec * 1000); req.tv_sec = sec; req.tv_nsec = milisec * 1000000L; while (nanosleep(&req, &req) == -1) continue; return (1); } #endif wildmidi-wildmidi-0.4.2/src/wildmidi.pc.in000066400000000000000000000005541315765416100204560ustar00rootroot00000000000000# WildMIDI pkg-config file prefix=@WILDMIDILIB_PREFIX@ exec_prefix=${prefix} libdir=${exec_prefix}/@WILDMIDILIB_LIBDIR@ includedir=${exec_prefix}/include Name: WildMIDI Description: software synthesizer library Version: @WILDMIDI_VERSION@ URL: https://www.mindwerks.net/projects/wildmidi/ Libs: -L${libdir} -lWildMidi Libs.private: -lm Cflags: -I${includedir} wildmidi-wildmidi-0.4.2/src/wildmidi_lib.c000066400000000000000000002451511315765416100205230ustar00rootroot00000000000000/* * wildmidi_lib.c -- Midi Wavetable Processing library * * Copyright (C) WildMIDI Developers 2001-2016 * * This file is part of WildMIDI. * * WildMIDI is free software: you can redistribute and/or modify the player * under the terms of the GNU General Public License and you can redistribute * and/or modify the library under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either version 3 of * the licenses, or(at your option) any later version. * * WildMIDI 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 and * the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License and the * GNU Lesser General Public License along with WildMIDI. If not, see * . */ #define _WILDMIDI_LIB_C #include "config.h" #include #include #include #include #include #include #include #include "wm_error.h" #include "file_io.h" #include "lock.h" #include "reverb.h" #include "gus_pat.h" #include "common.h" #include "wildmidi_lib.h" #include "filenames.h" #include "internal_midi.h" #include "f_hmi.h" #include "f_hmp.h" #include "f_midi.h" #include "f_mus.h" #include "f_xmidi.h" #include "patches.h" #include "sample.h" #include "mus2mid.h" #include "xmi2mid.h" /* * ========================= * Global Data and Data Structs * ========================= */ static int WM_Initialized = 0; uint16_t _WM_MixerOptions = 0; uint16_t _WM_SampleRate; int16_t _WM_MasterVolume; /* when converting files to midi */ typedef struct _cvt_options { int lock; uint16_t xmi_convert_type; uint16_t frequency; } _cvt_options; static _cvt_options WM_ConvertOptions = {0, 0, 0}; float _WM_reverb_room_width = 16.875f; float _WM_reverb_room_length = 22.5f; float _WM_reverb_listen_posx = 8.4375f; float _WM_reverb_listen_posy = 16.875f; int _WM_fix_release = 0; int _WM_auto_amp = 0; int _WM_auto_amp_with_amp = 0; struct _miditrack { uint32_t length; uint32_t ptr; uint32_t delta; uint8_t running_event; uint8_t EOT; }; struct _mdi_patches { struct _patch *patch; struct _mdi_patch *next; }; #define FPBITS 10 #define FPMASK ((1L<> 1); int j; int sign; double ck; double x, x_inc, xz; double z[35]; double *gptr, *t; _WM_Lock(&gauss_lock); if (gauss_table) { _WM_Unlock(&gauss_lock); return; } newt_coeffs[0][0] = 1; for (i = 0; i <= n; i++) { newt_coeffs[i][0] = 1; newt_coeffs[i][i] = 1; if (i > 1) { newt_coeffs[i][0] = newt_coeffs[i - 1][0] / i; newt_coeffs[i][i] = newt_coeffs[i - 1][0] / i; } for (j = 1; j < i; j++) { newt_coeffs[i][j] = newt_coeffs[i - 1][j - 1] + newt_coeffs[i - 1][j]; if (i > 1) newt_coeffs[i][j] /= i; } z[i] = i / (4 * M_PI); } for (i = 0; i <= n; i++) for (j = 0, sign = (int) pow(-1, i); j <= i; j++, sign *= -1) newt_coeffs[i][j] *= sign; t = (double *) malloc((1<first_sample) { tmp_sample = _WM_patch[i]->first_sample->next; free(_WM_patch[i]->first_sample->data); free(_WM_patch[i]->first_sample); _WM_patch[i]->first_sample = tmp_sample; } free(_WM_patch[i]->filename); tmp_patch = _WM_patch[i]->next; free(_WM_patch[i]); _WM_patch[i] = tmp_patch; } } _WM_Unlock(&_WM_patch_lock); } /* wm_strdup -- adds extra space for appending up to 4 chars */ static char *wm_strdup (const char *str) { size_t l = strlen(str) + 5; char *d = (char *) malloc(l * sizeof(char)); if (d) { strcpy(d, str); return (d); } return (NULL); } static inline int wm_isdigit(int c) { return (c >= '0' && c <= '9'); } static inline int wm_isupper(int c) { return (c >= 'A' && c <= 'Z'); } static inline int wm_tolower(int c) { return ((wm_isupper(c)) ? (c | ('a' - 'A')) : c); } #if 0 /* clang whines that these aren't used. */ static inline int wm_islower(int c) { return (c >= 'a' && c <= 'z'); } static inline int wm_toupper(int c) { return ((wm_islower(c)) ? (c & ~('a' - 'A')) : c); } #endif static int wm_strcasecmp(const char *s1, const char * s2) { const char * p1 = s1; const char * p2 = s2; char c1, c2; if (p1 == p2) return 0; do { c1 = wm_tolower (*p1++); c2 = wm_tolower (*p2++); if (c1 == '\0') break; } while (c1 == c2); return (int)(c1 - c2); } static int wm_strncasecmp(const char *s1, const char *s2, size_t n) { const char * p1 = s1; const char * p2 = s2; char c1, c2; if (p1 == p2 || n == 0) return 0; do { c1 = wm_tolower (*p1++); c2 = wm_tolower (*p2++); if (c1 == '\0' || c1 != c2) break; } while (--n > 0); return (int)(c1 - c2); } #define TOKEN_CNT_INC 8 static char** WM_LC_Tokenize_Line(char *line_data) { int line_length = (int) strlen(line_data); int token_data_length = 0; int line_ofs = 0; int token_start = 0; char **token_data = NULL; int token_count = 0; if (!line_length) return (NULL); do { /* ignore everything after # */ if (line_data[line_ofs] == '#') { break; } if ((line_data[line_ofs] == ' ') || (line_data[line_ofs] == '\t')) { /* whitespace means we aren't in a token */ if (token_start) { token_start = 0; line_data[line_ofs] = '\0'; } } else { if (!token_start) { /* the start of a token in the line */ token_start = 1; if (token_count >= token_data_length) { token_data_length += TOKEN_CNT_INC; token_data = (char **) realloc(token_data, token_data_length * sizeof(char *)); if (token_data == NULL) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM,"to parse config", errno); return (NULL); } } token_data[token_count] = &line_data[line_ofs]; token_count++; } } line_ofs++; } while (line_ofs != line_length); /* if we have found some tokens then add a null token to the end */ if (token_count) { if (token_count >= token_data_length) { token_data = (char **) realloc(token_data, ((token_count + 1) * sizeof(char *))); } token_data[token_count] = NULL; } return (token_data); } static int load_config(const char *config_file, const char *conf_dir) { uint32_t config_size = 0; char *config_buffer = NULL; const char *dir_end = NULL; char *config_dir = NULL; uint32_t config_ptr = 0; uint32_t line_start_ptr = 0; uint16_t patchid = 0; struct _patch * tmp_patch; char **line_tokens = NULL; int token_count = 0; config_buffer = (char *) _WM_BufferFile(config_file, &config_size); if (!config_buffer) { WM_FreePatches(); return (-1); } if (conf_dir) { if (!(config_dir = wm_strdup(conf_dir))) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, config_file, errno); WM_FreePatches(); free(config_buffer); return (-1); } } else { dir_end = FIND_LAST_DIRSEP(config_file); if (dir_end) { config_dir = (char *) malloc((dir_end - config_file + 2)); if (config_dir == NULL) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, config_file, errno); WM_FreePatches(); free(config_buffer); return (-1); } strncpy(config_dir, config_file, (dir_end - config_file + 1)); config_dir[dir_end - config_file + 1] = '\0'; } } config_ptr = 0; line_start_ptr = 0; /* handle files without a newline at the end: this relies on * _WM_BufferFile() allocating the buffer with one extra byte */ config_buffer[config_size] = '\n'; while (config_ptr <= config_size) { if (config_buffer[config_ptr] == '\r' || config_buffer[config_ptr] == '\n') { config_buffer[config_ptr] = '\0'; if (config_ptr != line_start_ptr) { _WM_Global_ErrorI = 0; /* because WM_LC_Tokenize_Line() can legitimately return NULL */ line_tokens = WM_LC_Tokenize_Line(&config_buffer[line_start_ptr]); if (line_tokens) { if (wm_strcasecmp(line_tokens[0], "dir") == 0) { free(config_dir); if (!line_tokens[1]) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(missing name in dir line)", 0); WM_FreePatches(); free(line_tokens); free(config_buffer); return (-1); } else if (!(config_dir = wm_strdup(line_tokens[1]))) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, config_file, errno); WM_FreePatches(); free(line_tokens); free(config_buffer); return (-1); } if (!IS_DIR_SEPARATOR(config_dir[strlen(config_dir) - 1])) { config_dir[strlen(config_dir) + 1] = '\0'; config_dir[strlen(config_dir)] = DIR_SEPARATOR_CHAR; } } else if (wm_strcasecmp(line_tokens[0], "source") == 0) { char *new_config = NULL; if (!line_tokens[1]) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(missing name in source line)", 0); WM_FreePatches(); free(line_tokens); free(config_buffer); return (-1); } else if (!IS_ABSOLUTE_PATH(line_tokens[1]) && config_dir) { new_config = (char *) malloc(strlen(config_dir) + strlen(line_tokens[1]) + 1); if (new_config == NULL) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, config_file, errno); WM_FreePatches(); free(config_dir); free(line_tokens); free(config_buffer); return (-1); } strcpy(new_config, config_dir); strcpy(&new_config[strlen(config_dir)], line_tokens[1]); } else { if (!(new_config = wm_strdup(line_tokens[1]))) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, config_file, errno); WM_FreePatches(); free(line_tokens); free(config_buffer); return (-1); } } if (load_config(new_config, config_dir) == -1) { free(new_config); free(line_tokens); free(config_buffer); free(config_dir); return (-1); } free(new_config); } else if (wm_strcasecmp(line_tokens[0], "bank") == 0) { if (!line_tokens[1] || !wm_isdigit(line_tokens[1][0])) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(syntax error in bank line)", 0); WM_FreePatches(); free(config_dir); free(line_tokens); free(config_buffer); return (-1); } patchid = (atoi(line_tokens[1]) & 0xFF) << 8; } else if (wm_strcasecmp(line_tokens[0], "drumset") == 0) { if (!line_tokens[1] || !wm_isdigit(line_tokens[1][0])) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(syntax error in drumset line)", 0); WM_FreePatches(); free(config_dir); free(line_tokens); free(config_buffer); return (-1); } patchid = ((atoi(line_tokens[1]) & 0xFF) << 8) | 0x80; } else if (wm_strcasecmp(line_tokens[0], "reverb_room_width") == 0) { if (!line_tokens[1] || !wm_isdigit(line_tokens[1][0])) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(syntax error in reverb_room_width line)", 0); WM_FreePatches(); free(config_dir); free(line_tokens); free(config_buffer); return (-1); } _WM_reverb_room_width = (float) atof(line_tokens[1]); if (_WM_reverb_room_width < 1.0f) { _WM_DEBUG_MSG("%s: reverb_room_width < 1 meter, setting to minimum of 1 meter", config_file); _WM_reverb_room_width = 1.0f; } else if (_WM_reverb_room_width > 100.0f) { _WM_DEBUG_MSG("%s: reverb_room_width > 100 meters, setting to maximum of 100 meters", config_file); _WM_reverb_room_width = 100.0f; } } else if (wm_strcasecmp(line_tokens[0], "reverb_room_length") == 0) { if (!line_tokens[1] || !wm_isdigit(line_tokens[1][0])) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(syntax error in reverb_room_length line)", 0); WM_FreePatches(); free(config_dir); free(line_tokens); free(config_buffer); return (-1); } _WM_reverb_room_length = (float) atof(line_tokens[1]); if (_WM_reverb_room_length < 1.0f) { _WM_DEBUG_MSG("%s: reverb_room_length < 1 meter, setting to minimum of 1 meter", config_file); _WM_reverb_room_length = 1.0f; } else if (_WM_reverb_room_length > 100.0f) { _WM_DEBUG_MSG("%s: reverb_room_length > 100 meters, setting to maximum of 100 meters", config_file); _WM_reverb_room_length = 100.0f; } } else if (wm_strcasecmp(line_tokens[0], "reverb_listener_posx") == 0) { if (!line_tokens[1] || !wm_isdigit(line_tokens[1][0])) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(syntax error in reverb_listen_posx line)", 0); WM_FreePatches(); free(config_dir); free(line_tokens); free(config_buffer); return (-1); } _WM_reverb_listen_posx = (float) atof(line_tokens[1]); if ((_WM_reverb_listen_posx > _WM_reverb_room_width) || (_WM_reverb_listen_posx < 0.0f)) { _WM_DEBUG_MSG("%s: reverb_listen_posx set outside of room", config_file); _WM_reverb_listen_posx = _WM_reverb_room_width / 2.0f; } } else if (wm_strcasecmp(line_tokens[0], "reverb_listener_posy") == 0) { if (!line_tokens[1] || !wm_isdigit(line_tokens[1][0])) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(syntax error in reverb_listen_posy line)", 0); WM_FreePatches(); free(config_dir); free(line_tokens); free(config_buffer); return (-1); } _WM_reverb_listen_posy = (float) atof(line_tokens[1]); if ((_WM_reverb_listen_posy > _WM_reverb_room_width) || (_WM_reverb_listen_posy < 0.0f)) { _WM_DEBUG_MSG("%s: reverb_listen_posy set outside of room", config_file); _WM_reverb_listen_posy = _WM_reverb_room_length * 0.75f; } } else if (wm_strcasecmp(line_tokens[0], "guspat_editor_author_cant_read_so_fix_release_time_for_me") == 0) { _WM_fix_release = 1; } else if (wm_strcasecmp(line_tokens[0], "auto_amp") == 0) { _WM_auto_amp = 1; } else if (wm_strcasecmp(line_tokens[0], "auto_amp_with_amp") == 0) { _WM_auto_amp = 1; _WM_auto_amp_with_amp = 1; } else if (wm_isdigit(line_tokens[0][0])) { patchid = (patchid & 0xFF80) | (atoi(line_tokens[0]) & 0x7F); if (_WM_patch[(patchid & 0x7F)] == NULL) { _WM_patch[(patchid & 0x7F)] = (struct _patch *) malloc(sizeof(struct _patch)); if (_WM_patch[(patchid & 0x7F)] == NULL) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, config_file, errno); WM_FreePatches(); free(config_dir); free(line_tokens); free(config_buffer); return (-1); } tmp_patch = _WM_patch[(patchid & 0x7F)]; tmp_patch->patchid = patchid; tmp_patch->filename = NULL; tmp_patch->amp = 1024; tmp_patch->note = 0; tmp_patch->next = NULL; tmp_patch->first_sample = NULL; tmp_patch->loaded = 0; tmp_patch->inuse_count = 0; } else { tmp_patch = _WM_patch[(patchid & 0x7F)]; if (tmp_patch->patchid == patchid) { free(tmp_patch->filename); tmp_patch->filename = NULL; tmp_patch->amp = 1024; tmp_patch->note = 0; } else { if (tmp_patch->next) { while (tmp_patch->next) { if (tmp_patch->next->patchid == patchid) break; tmp_patch = tmp_patch->next; } if (tmp_patch->next == NULL) { if ((tmp_patch->next = (struct _patch *) malloc(sizeof(struct _patch))) == NULL) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, config_file, 0); WM_FreePatches(); free(config_dir); free(line_tokens); free(config_buffer); return (-1); } tmp_patch = tmp_patch->next; tmp_patch->patchid = patchid; tmp_patch->filename = NULL; tmp_patch->amp = 1024; tmp_patch->note = 0; tmp_patch->next = NULL; tmp_patch->first_sample = NULL; tmp_patch->loaded = 0; tmp_patch->inuse_count = 0; } else { tmp_patch = tmp_patch->next; free(tmp_patch->filename); tmp_patch->filename = NULL; tmp_patch->amp = 1024; tmp_patch->note = 0; } } else { tmp_patch->next = (struct _patch *) malloc(sizeof(struct _patch)); if (tmp_patch->next == NULL) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, config_file, errno); WM_FreePatches(); free(config_dir); free(line_tokens); free(config_buffer); return (-1); } tmp_patch = tmp_patch->next; tmp_patch->patchid = patchid; tmp_patch->filename = NULL; tmp_patch->amp = 1024; tmp_patch->note = 0; tmp_patch->next = NULL; tmp_patch->first_sample = NULL; tmp_patch->loaded = 0; tmp_patch->inuse_count = 0; } } } if (!line_tokens[1]) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(missing name in patch line)", 0); WM_FreePatches(); free(config_dir); free(line_tokens); free(config_buffer); return (-1); } else if (!IS_ABSOLUTE_PATH(line_tokens[1]) && config_dir) { tmp_patch->filename = (char *) malloc(strlen(config_dir) + strlen(line_tokens[1]) + 5); if (tmp_patch->filename == NULL) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, config_file, 0); WM_FreePatches(); free(config_dir); free(line_tokens); free(config_buffer); return (-1); } strcpy(tmp_patch->filename, config_dir); strcat(tmp_patch->filename, line_tokens[1]); } else { if (!(tmp_patch->filename = wm_strdup(line_tokens[1]))) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, config_file, 0); WM_FreePatches(); free(config_dir); free(line_tokens); free(config_buffer); return (-1); } } if (wm_strncasecmp(&tmp_patch->filename[strlen(tmp_patch->filename) - 4], ".pat", 4) != 0) { strcat(tmp_patch->filename, ".pat"); } tmp_patch->env[0].set = 0x00; tmp_patch->env[1].set = 0x00; tmp_patch->env[2].set = 0x00; tmp_patch->env[3].set = 0x00; tmp_patch->env[4].set = 0x00; tmp_patch->env[5].set = 0x00; tmp_patch->keep = 0; tmp_patch->remove = 0; token_count = 0; while (line_tokens[token_count]) { if (wm_strncasecmp(line_tokens[token_count], "amp=", 4) == 0) { if (!wm_isdigit(line_tokens[token_count][4])) { _WM_DEBUG_MSG("%s: syntax error in patch line for %s", config_file, "amp="); } else { tmp_patch->amp = (atoi(&line_tokens[token_count][4]) << 10) / 100; } } else if (wm_strncasecmp(line_tokens[token_count], "note=", 5) == 0) { if (!wm_isdigit(line_tokens[token_count][5])) { _WM_DEBUG_MSG("%s: syntax error in patch line for %s", config_file, "note="); } else { tmp_patch->note = atoi(&line_tokens[token_count][5]); } } else if (wm_strncasecmp(line_tokens[token_count], "env_time", 8) == 0) { if ((!wm_isdigit(line_tokens[token_count][8])) || (!wm_isdigit(line_tokens[token_count][10])) || (line_tokens[token_count][9] != '=')) { _WM_DEBUG_MSG("%s: syntax error in patch line for %s", config_file, "env_time"); } else { uint32_t env_no = atoi(&line_tokens[token_count][8]); if (env_no > 5) { _WM_DEBUG_MSG("%s: syntax error in patch line for %s", config_file, "env_time"); } else { tmp_patch->env[env_no].time = (float) atof(&line_tokens[token_count][10]); if ((tmp_patch->env[env_no].time > 45000.0f) || (tmp_patch->env[env_no].time < 1.47f)) { _WM_DEBUG_MSG("%s: range error in patch line %s", config_file, "env_time"); tmp_patch->env[env_no].set &= 0xFE; } else { tmp_patch->env[env_no].set |= 0x01; } } } } else if (wm_strncasecmp(line_tokens[token_count], "env_level", 9) == 0) { if ((!wm_isdigit(line_tokens[token_count][9])) || (!wm_isdigit(line_tokens[token_count][11])) || (line_tokens[token_count][10] != '=')) { _WM_DEBUG_MSG("%s: syntax error in patch line for %s", config_file, "env_level"); } else { uint32_t env_no = atoi(&line_tokens[token_count][9]); if (env_no > 5) { _WM_DEBUG_MSG("%s: syntax error in patch line for %s", config_file, "env_level"); } else { tmp_patch->env[env_no].level = (float) atof(&line_tokens[token_count][11]); if ((tmp_patch->env[env_no].level > 1.0f) || (tmp_patch->env[env_no].level < 0.0f)) { _WM_DEBUG_MSG("%s: range error in patch line for %s", config_file, "env_level"); tmp_patch->env[env_no].set &= 0xFD; } else { tmp_patch->env[env_no].set |= 0x02; } } } } else if (wm_strcasecmp(line_tokens[token_count], "keep=loop") == 0) { tmp_patch->keep |= SAMPLE_LOOP; } else if (wm_strcasecmp(line_tokens[token_count], "keep=env") == 0) { tmp_patch->keep |= SAMPLE_ENVELOPE; } else if (wm_strcasecmp(line_tokens[token_count], "remove=sustain") == 0) { tmp_patch->remove |= SAMPLE_SUSTAIN; } else if (wm_strcasecmp(line_tokens[token_count], "remove=clamped") == 0) { tmp_patch->remove |= SAMPLE_CLAMPED; } token_count++; } } } else if (_WM_Global_ErrorI) { /* malloc() failure in WM_LC_Tokenize_Line() */ WM_FreePatches(); free(line_tokens); free(config_buffer); return (-1); } /* free up tokens */ free(line_tokens); } line_start_ptr = config_ptr + 1; } config_ptr++; } free(config_buffer); free(config_dir); return (0); } static int WM_LoadConfig(const char *config_file) { return load_config(config_file, NULL); } static int add_handle(void * handle) { struct _hndl *tmp_handle = NULL; if (first_handle == NULL) { first_handle = (struct _hndl *) malloc(sizeof(struct _hndl)); if (first_handle == NULL) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, " to get ram", errno); return (-1); } first_handle->handle = handle; first_handle->prev = NULL; first_handle->next = NULL; } else { tmp_handle = first_handle; if (tmp_handle->next) { while (tmp_handle->next) tmp_handle = tmp_handle->next; } tmp_handle->next = (struct _hndl *) malloc(sizeof(struct _hndl)); if (tmp_handle->next == NULL) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, " to get ram", errno); return (-1); } tmp_handle->next->prev = tmp_handle; tmp_handle = tmp_handle->next; tmp_handle->next = NULL; tmp_handle->handle = handle; } return (0); } //#define DEBUG_RESAMPLE #ifdef DEBUG_RESAMPLE #define RESAMPLE_DEBUGI(dx,dy) fprintf(stderr,"\r%s, %i\n",dx,dy) #define RESAMPLE_DEBUGS(dx) fprintf(stderr,"\r%s\n",dx) #else #define RESAMPLE_DEBUGI(dx,dy) #define RESAMPLE_DEBUGS(dx) #endif static int WM_GetOutput_Linear(midi * handle, int8_t *buffer, uint32_t size) { uint32_t buffer_used = 0; uint32_t i; struct _mdi *mdi = (struct _mdi *) handle; uint32_t real_samples_to_mix = 0; uint32_t data_pos; int32_t premix, left_mix, right_mix; // int32_t vol_mul; struct _note *note_data = NULL; uint32_t count; struct _event *event = mdi->current_event; int32_t *tmp_buffer; int32_t *out_buffer; _WM_Lock(&mdi->lock); buffer_used = 0; memset(buffer, 0, size); if ( (size / 2) > mdi->mix_buffer_size) { if ( (size / 2) <= ( mdi->mix_buffer_size * 2 )) { mdi->mix_buffer_size += MEM_CHUNK; } else { mdi->mix_buffer_size = size / 2; } mdi->mix_buffer = (int32_t *) realloc(mdi->mix_buffer, mdi->mix_buffer_size * sizeof(int32_t)); } tmp_buffer = mdi->mix_buffer; memset(tmp_buffer, 0, ((size / 2) * sizeof(int32_t))); out_buffer = tmp_buffer; do { if (__builtin_expect((!mdi->samples_to_mix), 0)) { while ((!mdi->samples_to_mix) && (event->do_event)) { event->do_event(mdi, &event->event_data); if ((mdi->extra_info.mixer_options & WM_MO_LOOP) && (event[0].do_event == *_WM_do_meta_endoftrack)) { _WM_ResetToStart(mdi); event = mdi->current_event; } else { mdi->samples_to_mix = event->samples_to_next; event++; mdi->current_event = event; } } if (__builtin_expect((!mdi->samples_to_mix), 0)) { if (mdi->extra_info.current_sample >= mdi->extra_info.approx_total_samples) { break; } else if ((mdi->extra_info.approx_total_samples - mdi->extra_info.current_sample) > (size >> 2)) { mdi->samples_to_mix = size >> 2; } else { mdi->samples_to_mix = mdi->extra_info.approx_total_samples - mdi->extra_info.current_sample; } } } if (__builtin_expect((mdi->samples_to_mix > (size >> 2)), 1)) { real_samples_to_mix = size >> 2; } else { real_samples_to_mix = mdi->samples_to_mix; if (real_samples_to_mix == 0) { continue; } } /* do mixing here */ count = real_samples_to_mix; do { note_data = mdi->note; left_mix = right_mix = 0; RESAMPLE_DEBUGI("SAMPLES_TO_MIX",count); if (__builtin_expect((note_data != NULL), 1)) { RESAMPLE_DEBUGS("Processing Notes"); while (note_data) { /* * =================== * resample the sample * =================== */ data_pos = note_data->sample_pos >> FPBITS; premix = ((note_data->sample->data[data_pos] + (((note_data->sample->data[data_pos + 1] - note_data->sample->data[data_pos]) * (int32_t)(note_data->sample_pos & FPMASK)) / 1024)) * (note_data->env_level >> 12)) / 1024; left_mix += (premix * (int32_t)note_data->left_mix_volume) / 1024; right_mix += (premix * (int32_t)note_data->right_mix_volume) / 1024; /* * ======================== * sample position checking * ======================== */ #ifdef DEBUG_RESAMPLE fprintf(stderr,"\r\n%d -> INC %i, ENV %i, LEVEL %i, TARGET %d, RATE %i, SAMPLE POS %i, SAMPLE LENGTH %i, PREMIX %i (%i:%i)", (uint32_t)note_data, note_data->env_inc, note_data->env, note_data->env_level, note_data->sample->env_target[note_data->env], note_data->sample->env_rate[note_data->env], note_data->sample_pos, note_data->sample->data_length, premix, left_mix, right_mix); if (note_data->modes & SAMPLE_LOOP) fprintf(stderr,", LOOP %i + %i", note_data->sample->loop_start, note_data->sample->loop_size); fprintf(stderr,"\r\n"); #endif note_data->sample_pos += note_data->sample_inc; if (__builtin_expect((note_data->modes & SAMPLE_LOOP), 1)) { if (__builtin_expect( (note_data->sample_pos > note_data->sample->loop_end), 0)) { note_data->sample_pos = note_data->sample->loop_start + ((note_data->sample_pos - note_data->sample->loop_start) % note_data->sample->loop_size); } } else if (__builtin_expect( (note_data->sample_pos >= note_data->sample->data_length), 0)) { goto _END_THIS_NOTE; } if (__builtin_expect((note_data->env_inc == 0), 0)) { note_data = note_data->next; RESAMPLE_DEBUGS("Next Note: 0 env_inc"); continue; } note_data->env_level += note_data->env_inc; if (note_data->env_inc < 0) { if (__builtin_expect((note_data->env_level > note_data->sample->env_target[note_data->env]), 0)) { note_data = note_data->next; RESAMPLE_DEBUGS("Next Note: env_lvl > env_target"); continue; } } else if (note_data->env_inc > 0) { if (__builtin_expect((note_data->env_level < note_data->sample->env_target[note_data->env]), 0)) { note_data = note_data->next; RESAMPLE_DEBUGS("Next Note: env_lvl < env_target"); continue; } } // Yes could have a condition here but // it would crete another bottleneck note_data->env_level = note_data->sample->env_target[note_data->env]; switch (note_data->env) { case 0: if (!(note_data->modes & SAMPLE_ENVELOPE)) { note_data->env_inc = 0; note_data = note_data->next; RESAMPLE_DEBUGS("Next Note: No Envelope"); continue; } break; case 2: if (note_data->modes & SAMPLE_SUSTAIN /*|| note_data->hold*/) { note_data->env_inc = 0; note_data = note_data->next; RESAMPLE_DEBUGS("Next Note: SAMPLE_SUSTAIN"); continue; } else if (note_data->modes & SAMPLE_CLAMPED) { note_data->env = 5; if (note_data->env_level > note_data->sample->env_target[5]) { note_data->env_inc = -note_data->sample->env_rate[5]; } else { note_data->env_inc = note_data->sample->env_rate[5]; } continue; } break; case 5: if (__builtin_expect((note_data->env_level == 0), 1)) { goto _END_THIS_NOTE; } /* sample release */ if (note_data->modes & SAMPLE_LOOP) note_data->modes ^= SAMPLE_LOOP; note_data->env_inc = 0; note_data = note_data->next; RESAMPLE_DEBUGS("Next Note: Sample Release"); continue; case 6: _END_THIS_NOTE: if (__builtin_expect((note_data->replay != NULL), 1)) { note_data->active = 0; { struct _note *prev_note = NULL; struct _note *nte_array = mdi->note; if (nte_array != note_data) { do { prev_note = nte_array; nte_array = nte_array->next; } while (nte_array != note_data); } if (prev_note) { prev_note->next = note_data->replay; } else { mdi->note = note_data->replay; } note_data->replay->next = note_data->next; note_data = note_data->replay; note_data->active = 1; } } else { note_data->active = 0; { struct _note *prev_note = NULL; struct _note *nte_array = mdi->note; if (nte_array != note_data) { do { prev_note = nte_array; nte_array = nte_array->next; } while ((nte_array != note_data) && (nte_array)); } if (prev_note) { prev_note->next = note_data->next; } else { mdi->note = note_data->next; } note_data = note_data->next; } } RESAMPLE_DEBUGS("Next Note: Killed Off Note"); continue; } note_data->env++; if (note_data->is_off == 1) { _WM_do_note_off_extra(note_data); } else { if (note_data->env_level >= note_data->sample->env_target[note_data->env]) { note_data->env_inc = -note_data->sample->env_rate[note_data->env]; } else { note_data->env_inc = note_data->sample->env_rate[note_data->env]; } } note_data = note_data->next; #ifdef DEBUG_RESAMPLE if (note_data != NULL) RESAMPLE_DEBUGI("Next Note: Next ENV ", note_data->env); else RESAMPLE_DEBUGS("Next Note: Next ENV"); #endif continue; } } *tmp_buffer++ = left_mix; *tmp_buffer++ = right_mix; } while (--count); buffer_used += real_samples_to_mix * 4; size -= (real_samples_to_mix << 2); mdi->extra_info.current_sample += real_samples_to_mix; mdi->samples_to_mix -= real_samples_to_mix; } while (size); tmp_buffer = out_buffer; if (mdi->extra_info.mixer_options & WM_MO_REVERB) { _WM_do_reverb(mdi->reverb, tmp_buffer, (buffer_used / 2)); } //_WM_DynamicVolumeAdjust(mdi, tmp_buffer, (buffer_used/2)); for (i = 0; i < buffer_used; i += 4) { left_mix = *tmp_buffer++; right_mix = *tmp_buffer++; /* * =================== * Write to the buffer * =================== */ #ifdef WORDS_BIGENDIAN (*buffer++) = ((left_mix >> 8) & 0x7f) | ((left_mix >> 24) & 0x80); (*buffer++) = left_mix & 0xff; (*buffer++) = ((right_mix >> 8) & 0x7f) | ((right_mix >> 24) & 0x80); (*buffer++) = right_mix & 0xff; #else (*buffer++) = left_mix & 0xff; (*buffer++) = ((left_mix >> 8) & 0x7f) | ((left_mix >> 24) & 0x80); (*buffer++) = right_mix & 0xff; (*buffer++) = ((right_mix >> 8) & 0x7f) | ((right_mix >> 24) & 0x80); #endif } _WM_Unlock(&mdi->lock); return (buffer_used); } static int WM_GetOutput_Gauss(midi * handle, int8_t *buffer, uint32_t size) { uint32_t buffer_used = 0; uint32_t i; struct _mdi *mdi = (struct _mdi *) handle; uint32_t real_samples_to_mix = 0; uint32_t data_pos; int32_t premix, left_mix, right_mix; struct _note *note_data = NULL; uint32_t count; int16_t *sptr; double y, xd; double *gptr, *gend; int left, right, temp_n; int ii, jj; struct _event *event = mdi->current_event; int32_t *tmp_buffer; int32_t *out_buffer; _WM_Lock(&mdi->lock); buffer_used = 0; memset(buffer, 0, size); if ( (size / 2) > mdi->mix_buffer_size) { if ( (size / 2) <= ( mdi->mix_buffer_size * 2 )) { mdi->mix_buffer_size += MEM_CHUNK; } else { mdi->mix_buffer_size = size / 2; } mdi->mix_buffer = (int32_t *) realloc(mdi->mix_buffer, mdi->mix_buffer_size * sizeof(int32_t)); } tmp_buffer = mdi->mix_buffer; memset(tmp_buffer, 0, ((size / 2) * sizeof(int32_t))); out_buffer = tmp_buffer; do { if (__builtin_expect((!mdi->samples_to_mix), 0)) { while ((!mdi->samples_to_mix) && (event->do_event)) { event->do_event(mdi, &event->event_data); if ((mdi->extra_info.mixer_options & WM_MO_LOOP) && (event[0].do_event == *_WM_do_meta_endoftrack)) { _WM_ResetToStart(mdi); event = mdi->current_event; } else { mdi->samples_to_mix = event->samples_to_next; event++; mdi->current_event = event; } } if (!mdi->samples_to_mix) { if (mdi->extra_info.current_sample >= mdi->extra_info.approx_total_samples) { break; } else if ((mdi->extra_info.approx_total_samples - mdi->extra_info.current_sample) > (size >> 2)) { mdi->samples_to_mix = size >> 2; } else { mdi->samples_to_mix = mdi->extra_info.approx_total_samples - mdi->extra_info.current_sample; } } } if (__builtin_expect((mdi->samples_to_mix > (size >> 2)), 1)) { real_samples_to_mix = size >> 2; } else { real_samples_to_mix = mdi->samples_to_mix; if (real_samples_to_mix == 0) { continue; } } /* do mixing here */ count = real_samples_to_mix; do { note_data = mdi->note; left_mix = right_mix = 0; if (__builtin_expect((note_data != NULL), 1)) { while (note_data) { /* * =================== * resample the sample * =================== */ data_pos = note_data->sample_pos >> FPBITS; /* check to see if we're near one of the ends */ left = data_pos; right = (note_data->sample->data_length >> FPBITS) - left - 1; temp_n = (right << 1) - 1; if (temp_n <= 0) temp_n = 1; if (temp_n > (left << 1) + 1) temp_n = (left << 1) + 1; /* use Newton if we can't fill the window */ if (temp_n < gauss_n) { xd = note_data->sample_pos & FPMASK; xd /= (1L << FPBITS); xd += temp_n >> 1; y = 0; sptr = note_data->sample->data + (note_data->sample_pos >> FPBITS) - (temp_n >> 1); for (ii = temp_n; ii;) { for (jj = 0; jj <= ii; jj++) y += sptr[jj] * newt_coeffs[ii][jj]; y *= xd - --ii; } y += *sptr; } else { /* otherwise, use Gauss as usual */ y = 0; gptr = &gauss_table[(note_data->sample_pos & FPMASK) * (gauss_n + 1)]; gend = gptr + gauss_n; sptr = note_data->sample->data + (note_data->sample_pos >> FPBITS) - (gauss_n >> 1); do { y += *(sptr++) * *(gptr++); } while (gptr <= gend); } premix = (int32_t)((y * (note_data->env_level >> 12)) / 1024); left_mix += (premix * (int32_t)note_data->left_mix_volume) / 1024; right_mix += (premix * (int32_t)note_data->right_mix_volume) / 1024; /* * ======================== * sample position checking * ======================== */ note_data->sample_pos += note_data->sample_inc; if (__builtin_expect( (note_data->sample_pos > note_data->sample->loop_end), 0)) { if (note_data->modes & SAMPLE_LOOP) { note_data->sample_pos = note_data->sample->loop_start + ((note_data->sample_pos - note_data->sample->loop_start) % note_data->sample->loop_size); } else if (__builtin_expect( (note_data->sample_pos >= note_data->sample->data_length), 0)) { goto _END_THIS_NOTE; } } if (__builtin_expect((note_data->env_inc == 0), 0)) { /* fprintf(stderr,"\r\nINC = 0, ENV %i, LEVEL %i, TARGET %d, RATE %i\r\n", note_data->env, note_data->env_level, note_data->sample->env_target[note_data->env], note_data->sample->env_rate[note_data->env]); */ note_data = note_data->next; continue; } note_data->env_level += note_data->env_inc; /* fprintf(stderr,"\r\nENV %i, LEVEL %i, TARGET %d, RATE %i, INC %i\r\n", note_data->env, note_data->env_level, note_data->sample->env_target[note_data->env], note_data->sample->env_rate[note_data->env], note_data->env_inc); */ if (note_data->env_inc < 0) { if (note_data->env_level > note_data->sample->env_target[note_data->env]) { note_data = note_data->next; continue; } } else if (note_data->env_inc > 0) { if (note_data->env_level < note_data->sample->env_target[note_data->env]) { note_data = note_data->next; continue; } } // Yes could have a condition here but // it would crete another bottleneck note_data->env_level = note_data->sample->env_target[note_data->env]; switch (note_data->env) { case 0: if (!(note_data->modes & SAMPLE_ENVELOPE)) { note_data->env_inc = 0; note_data = note_data->next; continue; } break; case 2: if (note_data->modes & SAMPLE_SUSTAIN /*|| note_data->hold*/) { note_data->env_inc = 0; note_data = note_data->next; continue; } else if (note_data->modes & SAMPLE_CLAMPED) { note_data->env = 5; if (note_data->env_level > note_data->sample->env_target[5]) { note_data->env_inc = -note_data->sample->env_rate[5]; } else { note_data->env_inc = note_data->sample->env_rate[5]; } continue; } break; case 5: if (__builtin_expect((note_data->env_level == 0), 1)) { goto _END_THIS_NOTE; } /* sample release */ if (note_data->modes & SAMPLE_LOOP) note_data->modes ^= SAMPLE_LOOP; note_data->env_inc = 0; note_data = note_data->next; continue; case 6: _END_THIS_NOTE: if (__builtin_expect((note_data->replay != NULL), 1)) { note_data->active = 0; { struct _note *prev_note = NULL; struct _note *nte_array = mdi->note; if (nte_array != note_data) { do { prev_note = nte_array; nte_array = nte_array->next; } while (nte_array != note_data); } if (prev_note) { prev_note->next = note_data->replay; } else { mdi->note = note_data->replay; } note_data->replay->next = note_data->next; note_data = note_data->replay; note_data->active = 1; } } else { note_data->active = 0; { struct _note *prev_note = NULL; struct _note *nte_array = mdi->note; if (nte_array != note_data) { do { prev_note = nte_array; nte_array = nte_array->next; } while ((nte_array != note_data) && (nte_array)); } if (prev_note) { prev_note->next = note_data->next; } else { mdi->note = note_data->next; } note_data = note_data->next; } } continue; } note_data->env++; if (note_data->is_off == 1) { _WM_do_note_off_extra(note_data); } else { if (note_data->env_level >= note_data->sample->env_target[note_data->env]) { note_data->env_inc = -note_data->sample->env_rate[note_data->env]; } else { note_data->env_inc = note_data->sample->env_rate[note_data->env]; } } note_data = note_data->next; continue; } } *tmp_buffer++ = left_mix; *tmp_buffer++ = right_mix; } while (--count); buffer_used += real_samples_to_mix * 4; size -= (real_samples_to_mix << 2); mdi->extra_info.current_sample += real_samples_to_mix; mdi->samples_to_mix -= real_samples_to_mix; } while (size); tmp_buffer = out_buffer; if (mdi->extra_info.mixer_options & WM_MO_REVERB) { _WM_do_reverb(mdi->reverb, tmp_buffer, (buffer_used / 2)); } // _WM_DynamicVolumeAdjust(mdi, tmp_buffer, (buffer_used/2)); for (i = 0; i < buffer_used; i += 4) { left_mix = *tmp_buffer++; right_mix = *tmp_buffer++; /* * =================== * Write to the buffer * =================== */ #ifdef WORDS_BIGENDIAN (*buffer++) = ((left_mix >> 8) & 0x7f) | ((left_mix >> 24) & 0x80); (*buffer++) = left_mix & 0xff; (*buffer++) = ((right_mix >> 8) & 0x7f) | ((right_mix >> 24) & 0x80); (*buffer++) = right_mix & 0xff; #else (*buffer++) = left_mix & 0xff; (*buffer++) = ((left_mix >> 8) & 0x7f) | ((left_mix >> 24) & 0x80); (*buffer++) = right_mix & 0xff; (*buffer++) = ((right_mix >> 8) & 0x7f) | ((right_mix >> 24) & 0x80); #endif } _WM_Unlock(&mdi->lock); return (buffer_used); } /* * ========================= * External Functions * ========================= */ WM_SYMBOL int WildMidi_ConvertToMidi (const char *file, uint8_t **out, uint32_t *size) { uint8_t *buf; int ret; if (!file) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL filename)", 0); return (-1); } if ((buf = (uint8_t *) _WM_BufferFile(file, size)) == NULL) { return (-1); } ret = WildMidi_ConvertBufferToMidi(buf, *size, out, size); free(buf); return ret; } WM_SYMBOL int WildMidi_ConvertBufferToMidi (uint8_t *in, uint32_t insize, uint8_t **out, uint32_t *outsize) { if (!in || !out || !outsize) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL params)", 0); return (-1); } if (!memcmp(in, "FORM", 4)) { if (_WM_xmi2midi(in, insize, out, outsize, _cvt_get_option(WM_CO_XMI_TYPE)) < 0) { return (-1); } } else if (!memcmp(in, "MUS", 3)) { if (_WM_mus2midi(in, insize, out, outsize, _cvt_get_option(WM_CO_FREQUENCY)) < 0) { return (-1); } } else if (!memcmp(in, "MThd", 4)) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, 0, "Already a midi file", 0); return (-1); } else { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, NULL, 0); return (-1); } return (0); } WM_SYMBOL const char *WildMidi_GetString(uint16_t info) { static char WM_Version[] = "WildMidi Processing Library " PACKAGE_VERSION; switch (info) { case WM_GS_VERSION: return WM_Version; } return NULL; } WM_SYMBOL long WildMidi_GetVersion (void) { return (LIBWILDMIDI_VERSION); } WM_SYMBOL int WildMidi_Init(const char *config_file, uint16_t rate, uint16_t mixer_options) { if (WM_Initialized) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_ALR_INIT, NULL, 0); return (-1); } if (config_file == NULL) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL config file pointer)", 0); return (-1); } WM_InitPatches(); if (WM_LoadConfig(config_file) == -1) { return (-1); } if (mixer_options & 0x0FF0) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(invalid option)", 0); WM_FreePatches(); return (-1); } _WM_MixerOptions = mixer_options; if (rate < 11025) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(rate out of bounds, range is 11025 - 65535)", 0); WM_FreePatches(); return (-1); } _WM_SampleRate = rate; gauss_lock = 0; _WM_patch_lock = 0; _WM_MasterVolume = 948; WM_Initialized = 1; return (0); } WM_SYMBOL int WildMidi_MasterVolume(uint8_t master_volume) { if (!WM_Initialized) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0); return (-1); } if (master_volume > 127) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(master volume out of range, range is 0-127)", 0); return (-1); } _WM_MasterVolume = _WM_lin_volume[master_volume]; return (0); } WM_SYMBOL int WildMidi_Close(midi * handle) { struct _mdi *mdi = (struct _mdi *) handle; struct _hndl * tmp_handle; if (!WM_Initialized) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0); return (-1); } if (handle == NULL) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL handle)", 0); return (-1); } if (first_handle == NULL) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(no midi's open)", 0); return (-1); } _WM_Lock(&mdi->lock); if (first_handle->handle == handle) { tmp_handle = first_handle->next; free(first_handle); first_handle = tmp_handle; if (first_handle) first_handle->prev = NULL; } else { tmp_handle = first_handle; while (tmp_handle->handle != handle) { tmp_handle = tmp_handle->next; if (tmp_handle == NULL) { break; } } if (tmp_handle) { tmp_handle->prev->next = tmp_handle->next; if (tmp_handle->next) { tmp_handle->next->prev = tmp_handle->prev; } free(tmp_handle); } } _WM_freeMDI(mdi); return (0); } WM_SYMBOL midi *WildMidi_Open(const char *midifile) { uint8_t *mididata = NULL; uint32_t midisize = 0; uint8_t mus_hdr[] = { 'M', 'U', 'S', 0x1A }; uint8_t xmi_hdr[] = { 'F', 'O', 'R', 'M' }; midi * ret = NULL; if (!WM_Initialized) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0); return (NULL); } if (midifile == NULL) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL filename)", 0); return (NULL); } if ((mididata = (uint8_t *) _WM_BufferFile(midifile, &midisize)) == NULL) { return (NULL); } if (midisize < 18) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(too short)", 0); return (NULL); } if (memcmp(mididata,"HMIMIDIP", 8) == 0) { ret = (void *) _WM_ParseNewHmp(mididata, midisize); } else if (memcmp(mididata, "HMI-MIDISONG061595", 18) == 0) { ret = (void *) _WM_ParseNewHmi(mididata, midisize); } else if (memcmp(mididata, mus_hdr, 4) == 0) { ret = (void *) _WM_ParseNewMus(mididata, midisize); } else if (memcmp(mididata, xmi_hdr, 4) == 0) { ret = (void *) _WM_ParseNewXmi(mididata, midisize); } else { ret = (void *) _WM_ParseNewMidi(mididata, midisize); } free(mididata); if (ret) { if (add_handle(ret) != 0) { WildMidi_Close(ret); ret = NULL; } } return (ret); } WM_SYMBOL midi *WildMidi_OpenBuffer(uint8_t *midibuffer, uint32_t size) { uint8_t mus_hdr[] = { 'M', 'U', 'S', 0x1A }; uint8_t xmi_hdr[] = { 'F', 'O', 'R', 'M' }; midi * ret = NULL; if (!WM_Initialized) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0); return (NULL); } if (midibuffer == NULL) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL midi data buffer)", 0); return (NULL); } if (size > WM_MAXFILESIZE) { /* don't bother loading suspiciously long files */ _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_LONGFIL, NULL, 0); return (NULL); } if (size < 18) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(too short)", 0); return (NULL); } if (memcmp(midibuffer,"HMIMIDIP", 8) == 0) { ret = (void *) _WM_ParseNewHmp(midibuffer, size); } else if (memcmp(midibuffer, "HMI-MIDISONG061595", 18) == 0) { ret = (void *) _WM_ParseNewHmi(midibuffer, size); } else if (memcmp(midibuffer, mus_hdr, 4) == 0) { ret = (void *) _WM_ParseNewMus(midibuffer, size); } else if (memcmp(midibuffer, xmi_hdr, 4) == 0) { ret = (void *) _WM_ParseNewXmi(midibuffer, size); } else { ret = (void *) _WM_ParseNewMidi(midibuffer, size); } if (ret) { if (add_handle(ret) != 0) { WildMidi_Close(ret); ret = NULL; } } return (ret); } WM_SYMBOL int WildMidi_FastSeek(midi * handle, unsigned long int *sample_pos) { struct _mdi *mdi; struct _event *event; struct _note *note_data; if (!WM_Initialized) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0); return (-1); } if (handle == NULL) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL handle)", 0); return (-1); } if (sample_pos == NULL) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL seek position pointer)", 0); return (-1); } mdi = (struct _mdi *) handle; _WM_Lock(&mdi->lock); event = mdi->current_event; /* make sure we havent asked for a positions beyond the end of the song. */ if (*sample_pos > mdi->extra_info.approx_total_samples) { /* if so set the position to the end of the song */ *sample_pos = mdi->extra_info.approx_total_samples; } /* was end of song requested and are we are there? */ if (*sample_pos == mdi->extra_info.approx_total_samples) { /* yes */ _WM_Unlock(&mdi->lock); return (0); } /* did we want to fast forward? */ if (mdi->extra_info.current_sample > *sample_pos) { /* no - reset some stuff */ event = mdi->events; _WM_ResetToStart((struct _mdi *) handle); mdi->extra_info.current_sample = 0; mdi->samples_to_mix = 0; } if ((mdi->extra_info.current_sample + mdi->samples_to_mix) > *sample_pos) { mdi->samples_to_mix = (mdi->extra_info.current_sample + mdi->samples_to_mix) - *sample_pos; mdi->extra_info.current_sample = *sample_pos; } else { mdi->extra_info.current_sample += mdi->samples_to_mix; mdi->samples_to_mix = 0; while ((!mdi->samples_to_mix) && (event->do_event)) { event->do_event(mdi, &event->event_data); mdi->samples_to_mix = event->samples_to_next; if ((mdi->extra_info.current_sample + mdi->samples_to_mix) > *sample_pos) { mdi->samples_to_mix = (mdi->extra_info.current_sample + mdi->samples_to_mix) - *sample_pos; mdi->extra_info.current_sample = *sample_pos; } else { mdi->extra_info.current_sample += mdi->samples_to_mix; mdi->samples_to_mix = 0; } event++; } mdi->current_event = event; } /* * Clear notes as this is a fast seek so we only care * about new notes. * * NOTE: This function is for performance only. * Might need a WildMidi_SlowSeek if we need better accuracy. */ note_data = mdi->note; if (note_data) { do { note_data->active = 0; if (note_data->replay) { note_data->replay = NULL; } note_data = note_data->next; } while (note_data); } mdi->note = NULL; /* clear the reverb buffers since we not gonna be using them here */ _WM_reset_reverb(mdi->reverb); _WM_Unlock(&mdi->lock); return (0); } WM_SYMBOL int WildMidi_SongSeek (midi * handle, int8_t nextsong) { struct _mdi *mdi; struct _event *event; struct _event *event_new; struct _note *note_data; if (!WM_Initialized) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0); return (-1); } if (handle == NULL) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL handle)", 0); return (-1); } mdi = (struct _mdi *) handle; _WM_Lock(&mdi->lock); if ((!mdi->is_type2) && (nextsong != 0)) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(Illegal use. Only usable with files detected to be type 2 compatible.", 0); _WM_Unlock(&mdi->lock); return (-1); } if ((nextsong > 1) || (nextsong < -1)) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(Invalid nextsong setting. -1 is previous song, 0 start of current song, 1 is next song)", 0); _WM_Unlock(&mdi->lock); return (-1); } event = mdi->current_event; if (nextsong == -1) { /* goto start of previous song */ /* * So with this one we have to go back 2 eof's * then forward 1 event to get to the start of * the previous song. * NOTE: We will automatically stop at the start * of the data. */ uint8_t eof_cnt = 1; while (event != mdi->events) { if (event[-1].do_event == _WM_do_meta_endoftrack) { if (eof_cnt == 0) { break; } eof_cnt = 0; } event--; } event_new = event; event = mdi->events; _WM_ResetToStart((struct _mdi *) handle); } else if (nextsong == 1) { /* goto start of next song */ while (event->do_event != NULL) { if (event->do_event == _WM_do_meta_endoftrack) { event++; if (event->do_event == NULL) { event--; goto START_THIS_SONG; } else { break; } } event++; } event_new = event; event = mdi->current_event; } else { START_THIS_SONG: /* goto start of this song */ /* first find the offset */ while (event != mdi->events) { if (event[-1].do_event == _WM_do_meta_endoftrack) { break; } event--; } event_new = event; event = mdi->events; _WM_ResetToStart((struct _mdi *) handle); } while (event != event_new) { event->do_event(mdi, &event->event_data); mdi->extra_info.current_sample += event->samples_to_next; event++; } mdi->current_event = event; note_data = mdi->note; if (note_data) { do { note_data->active = 0; if (note_data->replay) { note_data->replay = NULL; } note_data = note_data->next; } while (note_data); } mdi->note = NULL; _WM_Unlock(&mdi->lock); return (0); } WM_SYMBOL int WildMidi_GetOutput(midi * handle, int8_t *buffer, uint32_t size) { if (__builtin_expect((!WM_Initialized), 0)) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0); return (-1); } if (__builtin_expect((handle == NULL), 0)) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL handle)", 0); return (-1); } if (__builtin_expect((buffer == NULL), 0)) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL buffer pointer)", 0); return (-1); } if (__builtin_expect((size == 0), 0)) { return (0); } if (__builtin_expect((!!(size % 4)), 0)) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(size not a multiple of 4)", 0); return (-1); } if (((struct _mdi *) handle)->extra_info.mixer_options & WM_MO_ENHANCED_RESAMPLING) { if (!gauss_table) init_gauss(); return (WM_GetOutput_Gauss(handle, buffer, size)); } return (WM_GetOutput_Linear(handle, buffer, size)); } WM_SYMBOL int WildMidi_GetMidiOutput(midi * handle, int8_t **buffer, uint32_t *size) { if (__builtin_expect((!WM_Initialized), 0)) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0); return (-1); } if (__builtin_expect((handle == NULL), 0)) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL handle)", 0); return (-1); } if (__builtin_expect((buffer == NULL), 0)) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL buffer pointer)", 0); return (-1); } return _WM_Event2Midi((struct _mdi *)handle, (uint8_t **)buffer, size); } WM_SYMBOL int WildMidi_SetOption(midi * handle, uint16_t options, uint16_t setting) { struct _mdi *mdi; if (!WM_Initialized) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0); return (-1); } if (handle == NULL) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL handle)", 0); return (-1); } mdi = (struct _mdi *) handle; _WM_Lock(&mdi->lock); if ((!(options & 0x800F)) || (options & 0x7FF0)) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(invalid option)", 0); _WM_Unlock(&mdi->lock); return (-1); } if (setting & 0x7FF0) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(invalid setting)", 0); _WM_Unlock(&mdi->lock); return (-1); } mdi->extra_info.mixer_options = ((mdi->extra_info.mixer_options & (0x80FF ^ options)) | (options & setting)); if (options & WM_MO_LOG_VOLUME) { _WM_AdjustChannelVolumes(mdi, 16); // Settings greater than 15 // adjusts all channels } else if (options & WM_MO_REVERB) { _WM_reset_reverb(mdi->reverb); } _WM_Unlock(&mdi->lock); return (0); } WM_SYMBOL int WildMidi_SetCvtOption(uint16_t tag, uint16_t setting) { _WM_Lock(&WM_ConvertOptions.lock); switch (tag) { case WM_CO_XMI_TYPE: /* validation happens in xmidi.c */ WM_ConvertOptions.xmi_convert_type = setting; break; case WM_CO_FREQUENCY: /* validation happens in format */ WM_ConvertOptions.frequency = setting; break; default: _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(invalid setting)", 0); _WM_Unlock(&WM_ConvertOptions.lock); return (-1); } _WM_Unlock(&WM_ConvertOptions.lock); return (0); } WM_SYMBOL struct _WM_Info * WildMidi_GetInfo(midi * handle) { struct _mdi *mdi = (struct _mdi *) handle; if (!WM_Initialized) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0); return (NULL); } if (handle == NULL) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL handle)", 0); return (NULL); } _WM_Lock(&mdi->lock); if (mdi->tmp_info == NULL) { mdi->tmp_info = (struct _WM_Info *) malloc(sizeof(struct _WM_Info)); if (mdi->tmp_info == NULL) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to set info", 0); _WM_Unlock(&mdi->lock); return (NULL); } mdi->tmp_info->copyright = NULL; } mdi->tmp_info->current_sample = mdi->extra_info.current_sample; mdi->tmp_info->approx_total_samples = mdi->extra_info.approx_total_samples; mdi->tmp_info->mixer_options = mdi->extra_info.mixer_options; mdi->tmp_info->total_midi_time = (mdi->tmp_info->approx_total_samples * 1000) / _WM_SampleRate; if (mdi->extra_info.copyright) { free(mdi->tmp_info->copyright); mdi->tmp_info->copyright = (char *) malloc(strlen(mdi->extra_info.copyright) + 1); if (mdi->tmp_info->copyright == NULL) { free(mdi->tmp_info); mdi->tmp_info = NULL; _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to set copyright", 0); _WM_Unlock(&mdi->lock); return (NULL); } else { strcpy(mdi->tmp_info->copyright, mdi->extra_info.copyright); } } else { mdi->tmp_info->copyright = NULL; } _WM_Unlock(&mdi->lock); return ((struct _WM_Info *)mdi->tmp_info); } WM_SYMBOL int WildMidi_Shutdown(void) { if (!WM_Initialized) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0); return (-1); } while (first_handle) { /* closes open handle and rotates the handles list. */ WildMidi_Close((struct _mdi *) first_handle->handle); } WM_FreePatches(); free_gauss(); /* reset the globals */ _cvt_reset_options (); _WM_MasterVolume = 948; _WM_MixerOptions = 0; _WM_fix_release = 0; _WM_auto_amp = 0; _WM_auto_amp_with_amp = 0; _WM_reverb_room_width = 16.875f; _WM_reverb_room_length = 22.5f; _WM_reverb_listen_posx = 8.4375f; _WM_reverb_listen_posy = 16.875f; WM_Initialized = 0; if (_WM_Global_ErrorS != NULL) free(_WM_Global_ErrorS); return (0); } /* char * WildMidi_GetLyric(midi * handle) Returns points to a \0 terminated string that contains the data contained in the last read lyric or text meta event. Or returns NULL if no lyric is waiting to be read. Force read from text meta event by including WM_MO_TEXTASLYRIC in the options in WildMidi_Init. Programs calling this only need to read the pointer. Cleanup is done by the lib. Once WildMidi_GetLyric is called it will return NULL on subsiquent calls until the next lyric event is processed during a WildMidi_GetOutput call. */ WM_SYMBOL char * WildMidi_GetLyric (midi * handle) { struct _mdi *mdi = (struct _mdi *) handle; char * lyric = NULL; if (!WM_Initialized) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0); return (NULL); } if (handle == NULL) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL handle)", 0); return (NULL); } _WM_Lock(&mdi->lock); lyric = mdi->lyric; mdi->lyric = NULL; _WM_Unlock(&mdi->lock); return (lyric); } /* * Return Last Error Message */ WM_SYMBOL char * WildMidi_GetError (void) { return (_WM_Global_ErrorS); } /* * Clear any error message */ WM_SYMBOL void WildMidi_ClearError (void) { _WM_Global_ErrorI = 0; if (_WM_Global_ErrorS != NULL) { free(_WM_Global_ErrorS); _WM_Global_ErrorS = NULL; } return; } wildmidi-wildmidi-0.4.2/src/wm_error.c000066400000000000000000000064711315765416100177270ustar00rootroot00000000000000/* * wm_error.c -- error reporting * * Copyright (C) WildMIDI Developers 2001-2016 * * This file is part of WildMIDI. * * WildMIDI is free software: you can redistribute and/or modify the player * under the terms of the GNU General Public License and you can redistribute * and/or modify the library under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either version 3 of * the licenses, or(at your option) any later version. * * WildMIDI 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 and * the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License and the * GNU Lesser General Public License along with WildMIDI. If not, see * . */ #include "config.h" #include #include #include #include #include "wm_error.h" void _WM_DEBUG_MSG(const char * wmfmt, ...) { va_list args; fprintf(stderr, "\r"); va_start(args, wmfmt); vfprintf(stderr, wmfmt, args); va_end(args); fprintf(stderr, "\n"); } static const char *errors[WM_ERR_MAX+1] = { "No Error", "Unable to obtain memory", "Unable to stat", "Unable to load", "Unable to open", "Unable to read", "Invalid or Unsupported file format", "File corrupt", "Library not Initialized", "Invalid argument", "Library Already Initialized", "Not a midi file", "Refusing to load unusually long file", "Not an hmp file", "Not an hmi file", "Unable to convert", "Not a mus file", "Not an xmi file", "Invalid error code" }; #define MAX_ERROR_LEN 255 char * _WM_Global_ErrorS = NULL; int _WM_Global_ErrorI = 0; void _WM_GLOBAL_ERROR(const char *func, int lne, int wmerno, const char *wmfor, int error) { char *errorstring; if (wmerno < 0 || wmerno >= WM_ERR_MAX) wmerno = WM_ERR_MAX; /* set to invalid error code. */ _WM_Global_ErrorI = wmerno; if (_WM_Global_ErrorS != NULL) free(_WM_Global_ErrorS); errorstring = (char *) malloc(MAX_ERROR_LEN+1); if (error == 0) { if (wmfor == NULL) { sprintf(errorstring,"Error (%s:%i) %s", func, lne, errors[wmerno]); } else { sprintf(errorstring,"Error (%s:%i) %s (%s)", func, lne, wmfor, errors[wmerno]); } } else { if (wmfor == NULL) { sprintf(errorstring,"System Error (%s:%i) %s : %s", func, lne, errors[wmerno], strerror(error)); } else { sprintf(errorstring,"System Error (%s:%i) %s (%s) : %s", func, lne, wmfor, errors[wmerno], strerror(error)); } } errorstring[MAX_ERROR_LEN] = 0; _WM_Global_ErrorS = errorstring; } void _WM_ERROR_NEW(const char * wmfmt, ...) { char *errorstring; va_list args; va_start(args, wmfmt); errorstring = (char *) malloc(MAX_ERROR_LEN+1); vsprintf(errorstring, wmfmt, args); va_end(args); errorstring[MAX_ERROR_LEN] = 0; _WM_Global_ErrorS = errorstring; _WM_Global_ErrorI = WM_ERR_MAX;/* well, it's a custom error message */ } wildmidi-wildmidi-0.4.2/src/wm_tty.c000066400000000000000000000040041315765416100174040ustar00rootroot00000000000000/* * wm_tty.c - unix termios code for player * * Copyright (C) Chris Ison 2001-2011 * Copyright (C) Bret Curtis 2013-2016 * * This file is part of WildMIDI. * * WildMIDI is free software: you can redistribute and/or modify the player * under the terms of the GNU General Public License and you can redistribute * and/or modify the library under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either version 3 of * the licenses, or(at your option) any later version. * * WildMIDI 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 and * the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License and the * GNU Lesser General Public License along with WildMIDI. If not, see * . */ #include "config.h" #if !(defined(_WIN32) || defined(__DJGPP__) || defined(WILDMIDI_AMIGA) || defined(__OS2__) || defined(__EMX__)) #define _XOPEN_SOURCE 600 /* for ONLCR */ #define __BSD_VISIBLE 1 /* for ONLCR in *BSD */ #include #include #include #ifndef FNONBLOCK #define FNONBLOCK O_NONBLOCK #endif struct termios _tty; static tcflag_t _res_oflg = 0; static tcflag_t _res_lflg = 0; void wm_inittty(void) { if (!isatty(STDIN_FILENO)) return; /* save tty: */ tcgetattr(STDIN_FILENO, &_tty); _res_oflg = _tty.c_oflag; _res_lflg = _tty.c_lflag; /* set raw: */ _tty.c_lflag &= ~(ICANON | ICRNL | ISIG); _tty.c_oflag &= ~ONLCR; tcsetattr(STDIN_FILENO, TCSANOW, &_tty); fcntl(STDIN_FILENO, F_SETFL, FNONBLOCK); } void wm_resetty(void) { if (!isatty(STDIN_FILENO)) return; /* reset tty: */ _tty.c_oflag = _res_oflg; _tty.c_lflag = _res_lflg; tcsetattr(STDIN_FILENO, TCSADRAIN, &_tty); } #endif /* !(_WIN32,__DJGPP__,__OS2__) */ wildmidi-wildmidi-0.4.2/src/xmi2mid.c000066400000000000000000000772341315765416100174510ustar00rootroot00000000000000/* * XMIDI: Miles XMIDI to MID Library * * Copyright (C) 2001 Ryan Nunn * Copyright (C) 2014 Bret Curtis * Copyright (C) WildMIDI Developers 2015-2016 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ /* XMIDI Converter */ #include "config.h" #include #include #include #include #include "xmi2mid.h" #include "wm_error.h" /* Midi Status Bytes */ #define MIDI_STATUS_NOTE_OFF 0x8 #define MIDI_STATUS_NOTE_ON 0x9 #define MIDI_STATUS_AFTERTOUCH 0xA #define MIDI_STATUS_CONTROLLER 0xB #define MIDI_STATUS_PROG_CHANGE 0xC #define MIDI_STATUS_PRESSURE 0xD #define MIDI_STATUS_PITCH_WHEEL 0xE #define MIDI_STATUS_SYSEX 0xF typedef struct _midi_event { int32_t time; uint8_t status; uint8_t data[2]; uint32_t len; uint8_t *buffer; struct _midi_event *next; } midi_event; typedef struct { uint16_t type; uint16_t tracks; } midi_descriptor; struct xmi_ctx { const uint8_t *src, *src_ptr; uint32_t srcsize; uint32_t datastart; uint8_t *dst, *dst_ptr; uint32_t dstsize, dstrem; uint32_t convert_type; midi_descriptor info; int bank127[16]; midi_event **events; signed short *timing; midi_event *list; midi_event *current; }; /* forward declarations of private functions */ static void DeleteEventList(midi_event *mlist); static void CreateNewEvent(struct xmi_ctx *ctx, int32_t time); /* List manipulation */ static int GetVLQ(struct xmi_ctx *ctx, uint32_t *quant); /* Variable length quantity */ static int GetVLQ2(struct xmi_ctx *ctx, uint32_t *quant);/* Variable length quantity */ static int PutVLQ(struct xmi_ctx *ctx, uint32_t value); /* Variable length quantity */ static int ConvertEvent(struct xmi_ctx *ctx, const int32_t time, const uint8_t status, const int size); static int32_t ConvertSystemMessage(struct xmi_ctx *ctx, const int32_t time, const uint8_t status); static int32_t ConvertFiletoList(struct xmi_ctx *ctx); static uint32_t ConvertListToMTrk(struct xmi_ctx *ctx, midi_event *mlist); static int ParseXMI(struct xmi_ctx *ctx); static int ExtractTracks(struct xmi_ctx *ctx); static uint32_t ExtractTracksFromXmi(struct xmi_ctx *ctx); static uint32_t read1(struct xmi_ctx *ctx) { uint8_t b0; b0 = *ctx->src_ptr++; return (b0); } static uint32_t read2(struct xmi_ctx *ctx) { uint8_t b0, b1; b0 = *ctx->src_ptr++; b1 = *ctx->src_ptr++; return (b0 + (b1 << 8)); } static uint32_t read4(struct xmi_ctx *ctx) { uint8_t b0, b1, b2, b3; b3 = *ctx->src_ptr++; b2 = *ctx->src_ptr++; b1 = *ctx->src_ptr++; b0 = *ctx->src_ptr++; return (b0 + (b1<<8) + (b2<<16) + (b3<<24)); } static void copy(struct xmi_ctx *ctx, char *b, uint32_t len) { memcpy(b, ctx->src_ptr, len); ctx->src_ptr += len; } #define DST_CHUNK 8192 static void resize_dst(struct xmi_ctx *ctx) { uint32_t pos = ctx->dst_ptr - ctx->dst; ctx->dst = (uint8_t *) realloc(ctx->dst, ctx->dstsize + DST_CHUNK); ctx->dstsize += DST_CHUNK; ctx->dstrem += DST_CHUNK; ctx->dst_ptr = ctx->dst + pos; } static void write1(struct xmi_ctx *ctx, uint32_t val) { if (ctx->dstrem < 1) resize_dst(ctx); *ctx->dst_ptr++ = val & 0xff; ctx->dstrem--; } static void write2(struct xmi_ctx *ctx, uint32_t val) { if (ctx->dstrem < 2) resize_dst(ctx); *ctx->dst_ptr++ = (val>>8) & 0xff; *ctx->dst_ptr++ = val & 0xff; ctx->dstrem -= 2; } static void write4(struct xmi_ctx *ctx, uint32_t val) { if (ctx->dstrem < 4) resize_dst(ctx); *ctx->dst_ptr++ = (val>>24)&0xff; *ctx->dst_ptr++ = (val>>16)&0xff; *ctx->dst_ptr++ = (val>>8) & 0xff; *ctx->dst_ptr++ = val & 0xff; ctx->dstrem -= 4; } static void seeksrc(struct xmi_ctx *ctx, uint32_t pos) { ctx->src_ptr = ctx->src + pos; } static void seekdst(struct xmi_ctx *ctx, uint32_t pos) { ctx->dst_ptr = ctx->dst + pos; while (ctx->dstsize < pos) resize_dst(ctx); ctx->dstrem = ctx->dstsize - pos; } static void skipsrc(struct xmi_ctx *ctx, int32_t pos) { ctx->src_ptr += pos; } static void skipdst(struct xmi_ctx *ctx, int32_t pos) { size_t newpos; ctx->dst_ptr += pos; newpos = ctx->dst_ptr - ctx->dst; while (ctx->dstsize < newpos) resize_dst(ctx); ctx->dstrem = ctx->dstsize - newpos; } static uint32_t getsrcsize(struct xmi_ctx *ctx) { return (ctx->srcsize); } static uint32_t getsrcpos(struct xmi_ctx *ctx) { return (ctx->src_ptr - ctx->src); } static uint32_t getdstpos(struct xmi_ctx *ctx) { return (ctx->dst_ptr - ctx->dst); } /* This is a default set of patches to convert from MT32 to GM * The index is the MT32 Patch number and the value is the GM Patch * This is only suitable for music that doesn't do timbre changes * XMIDIs that contain Timbre changes will not convert properly. */ static const char mt32asgm[128] = { 0, /* 0 Piano 1 */ 1, /* 1 Piano 2 */ 2, /* 2 Piano 3 (synth) */ 4, /* 3 EPiano 1 */ 4, /* 4 EPiano 2 */ 5, /* 5 EPiano 3 */ 5, /* 6 EPiano 4 */ 3, /* 7 Honkytonk */ 16, /* 8 Organ 1 */ 17, /* 9 Organ 2 */ 18, /* 10 Organ 3 */ 16, /* 11 Organ 4 */ 19, /* 12 Pipe Organ 1 */ 19, /* 13 Pipe Organ 2 */ 19, /* 14 Pipe Organ 3 */ 21, /* 15 Accordion */ 6, /* 16 Harpsichord 1 */ 6, /* 17 Harpsichord 2 */ 6, /* 18 Harpsichord 3 */ 7, /* 19 Clavinet 1 */ 7, /* 20 Clavinet 2 */ 7, /* 21 Clavinet 3 */ 8, /* 22 Celesta 1 */ 8, /* 23 Celesta 2 */ 62, /* 24 Synthbrass 1 (62) */ 63, /* 25 Synthbrass 2 (63) */ 62, /* 26 Synthbrass 3 Bank 8 */ 63, /* 27 Synthbrass 4 Bank 8 */ 38, /* 28 Synthbass 1 */ 39, /* 29 Synthbass 2 */ 38, /* 30 Synthbass 3 Bank 8 */ 39, /* 31 Synthbass 4 Bank 8 */ 88, /* 32 Fantasy */ 90, /* 33 Harmonic Pan - No equiv closest is polysynth(90) :( */ 52, /* 34 Choral ?? Currently set to SynthVox(54). Should it be ChoirAhhs(52)??? */ 92, /* 35 Glass */ 97, /* 36 Soundtrack */ 99, /* 37 Atmosphere */ 14, /* 38 Warmbell, sounds kind of like crystal(98) perhaps Tubular Bells(14) would be better. It is! */ 54, /* 39 FunnyVox, sounds alot like Bagpipe(109) and Shania(111) */ 98, /* 40 EchoBell, no real equiv, sounds like Crystal(98) */ 96, /* 41 IceRain */ 68, /* 42 Oboe 2001, no equiv, just patching it to normal oboe(68) */ 95, /* 43 EchoPans, no equiv, setting to SweepPad */ 81, /* 44 DoctorSolo Bank 8 */ 87, /* 45 SchoolDaze, no real equiv */ 112,/* 46 Bell Singer */ 80, /* 47 SquareWave */ 48, /* 48 Strings 1 */ 48, /* 49 Strings 2 - should be 49 */ 44, /* 50 Strings 3 (Synth) - Experimental set to Tremollo Strings - should be 50 */ 45, /* 51 Pizzicato Strings */ 40, /* 52 Violin 1 */ 40, /* 53 Violin 2 ? Viola */ 42, /* 54 Cello 1 */ 42, /* 55 Cello 2 */ 43, /* 56 Contrabass */ 46, /* 57 Harp 1 */ 46, /* 58 Harp 2 */ 24, /* 59 Guitar 1 (Nylon) */ 25, /* 60 Guitar 2 (Steel) */ 26, /* 61 Elec Guitar 1 */ 27, /* 62 Elec Guitar 2 */ 104,/* 63 Sitar */ 32, /* 64 Acou Bass 1 */ 32, /* 65 Acou Bass 2 */ 33, /* 66 Elec Bass 1 */ 34, /* 67 Elec Bass 2 */ 36, /* 68 Slap Bass 1 */ 37, /* 69 Slap Bass 2 */ 35, /* 70 Fretless Bass 1 */ 35, /* 71 Fretless Bass 2 */ 73, /* 72 Flute 1 */ 73, /* 73 Flute 2 */ 72, /* 74 Piccolo 1 */ 72, /* 75 Piccolo 2 */ 74, /* 76 Recorder */ 75, /* 77 Pan Pipes */ 64, /* 78 Sax 1 */ 65, /* 79 Sax 2 */ 66, /* 80 Sax 3 */ 67, /* 81 Sax 4 */ 71, /* 82 Clarinet 1 */ 71, /* 83 Clarinet 2 */ 68, /* 84 Oboe */ 69, /* 85 English Horn (Cor Anglais) */ 70, /* 86 Bassoon */ 22, /* 87 Harmonica */ 56, /* 88 Trumpet 1 */ 56, /* 89 Trumpet 2 */ 57, /* 90 Trombone 1 */ 57, /* 91 Trombone 2 */ 60, /* 92 French Horn 1 */ 60, /* 93 French Horn 2 */ 58, /* 94 Tuba */ 61, /* 95 Brass Section 1 */ 61, /* 96 Brass Section 2 */ 11, /* 97 Vibes 1 */ 11, /* 98 Vibes 2 */ 99, /* 99 Syn Mallet Bank 1 */ 112,/* 100 WindBell no real equiv Set to TinkleBell(112) */ 9, /* 101 Glockenspiel */ 14, /* 102 Tubular Bells */ 13, /* 103 Xylophone */ 12, /* 104 Marimba */ 107,/* 105 Koto */ 111,/* 106 Sho?? set to Shanai(111) */ 77, /* 107 Shakauhachi */ 78, /* 108 Whistle 1 */ 78, /* 109 Whistle 2 */ 76, /* 110 Bottle Blow */ 76, /* 111 Breathpipe no real equiv set to bottle blow(76) */ 47, /* 112 Timpani */ 117,/* 113 Melodic Tom */ 116,/* 114 Deap Snare no equiv, set to Taiko(116) */ 118,/* 115 Electric Perc 1 */ 118,/* 116 Electric Perc 2 */ 116,/* 117 Taiko */ 115,/* 118 Taiko Rim, no real equiv, set to Woodblock(115) */ 119,/* 119 Cymbal, no real equiv, set to reverse cymbal(119) */ 115,/* 120 Castanets, no real equiv, in GM set to Woodblock(115) */ 112,/* 121 Triangle, no real equiv, set to TinkleBell(112) */ 55, /* 122 Orchestral Hit */ 124,/* 123 Telephone */ 123,/* 124 BirdTweet */ 94, /* 125 Big Notes Pad no equiv, set to halo pad (94) */ 98, /* 126 Water Bell set to Crystal Pad(98) */ 121 /* 127 Jungle Tune set to Breath Noise */ }; /* Same as above, except include patch changes * so GS instruments can be used */ static const char mt32asgs[256] = { 0, 0, /* 0 Piano 1 */ 1, 0, /* 1 Piano 2 */ 2, 0, /* 2 Piano 3 (synth) */ 4, 0, /* 3 EPiano 1 */ 4, 0, /* 4 EPiano 2 */ 5, 0, /* 5 EPiano 3 */ 5, 0, /* 6 EPiano 4 */ 3, 0, /* 7 Honkytonk */ 16, 0, /* 8 Organ 1 */ 17, 0, /* 9 Organ 2 */ 18, 0, /* 10 Organ 3 */ 16, 0, /* 11 Organ 4 */ 19, 0, /* 12 Pipe Organ 1 */ 19, 0, /* 13 Pipe Organ 2 */ 19, 0, /* 14 Pipe Organ 3 */ 21, 0, /* 15 Accordion */ 6, 0, /* 16 Harpsichord 1 */ 6, 0, /* 17 Harpsichord 2 */ 6, 0, /* 18 Harpsichord 3 */ 7, 0, /* 19 Clavinet 1 */ 7, 0, /* 20 Clavinet 2 */ 7, 0, /* 21 Clavinet 3 */ 8, 0, /* 22 Celesta 1 */ 8, 0, /* 23 Celesta 2 */ 62, 0, /* 24 Synthbrass 1 (62) */ 63, 0, /* 25 Synthbrass 2 (63) */ 62, 0, /* 26 Synthbrass 3 Bank 8 */ 63, 0, /* 27 Synthbrass 4 Bank 8 */ 38, 0, /* 28 Synthbass 1 */ 39, 0, /* 29 Synthbass 2 */ 38, 0, /* 30 Synthbass 3 Bank 8 */ 39, 0, /* 31 Synthbass 4 Bank 8 */ 88, 0, /* 32 Fantasy */ 90, 0, /* 33 Harmonic Pan - No equiv closest is polysynth(90) :( */ 52, 0, /* 34 Choral ?? Currently set to SynthVox(54). Should it be ChoirAhhs(52)??? */ 92, 0, /* 35 Glass */ 97, 0, /* 36 Soundtrack */ 99, 0, /* 37 Atmosphere */ 14, 0, /* 38 Warmbell, sounds kind of like crystal(98) perhaps Tubular Bells(14) would be better. It is! */ 54, 0, /* 39 FunnyVox, sounds alot like Bagpipe(109) and Shania(111) */ 98, 0, /* 40 EchoBell, no real equiv, sounds like Crystal(98) */ 96, 0, /* 41 IceRain */ 68, 0, /* 42 Oboe 2001, no equiv, just patching it to normal oboe(68) */ 95, 0, /* 43 EchoPans, no equiv, setting to SweepPad */ 81, 0, /* 44 DoctorSolo Bank 8 */ 87, 0, /* 45 SchoolDaze, no real equiv */ 112, 0, /* 46 Bell Singer */ 80, 0, /* 47 SquareWave */ 48, 0, /* 48 Strings 1 */ 48, 0, /* 49 Strings 2 - should be 49 */ 44, 0, /* 50 Strings 3 (Synth) - Experimental set to Tremollo Strings - should be 50 */ 45, 0, /* 51 Pizzicato Strings */ 40, 0, /* 52 Violin 1 */ 40, 0, /* 53 Violin 2 ? Viola */ 42, 0, /* 54 Cello 1 */ 42, 0, /* 55 Cello 2 */ 43, 0, /* 56 Contrabass */ 46, 0, /* 57 Harp 1 */ 46, 0, /* 58 Harp 2 */ 24, 0, /* 59 Guitar 1 (Nylon) */ 25, 0, /* 60 Guitar 2 (Steel) */ 26, 0, /* 61 Elec Guitar 1 */ 27, 0, /* 62 Elec Guitar 2 */ 104, 0, /* 63 Sitar */ 32, 0, /* 64 Acou Bass 1 */ 32, 0, /* 65 Acou Bass 2 */ 33, 0, /* 66 Elec Bass 1 */ 34, 0, /* 67 Elec Bass 2 */ 36, 0, /* 68 Slap Bass 1 */ 37, 0, /* 69 Slap Bass 2 */ 35, 0, /* 70 Fretless Bass 1 */ 35, 0, /* 71 Fretless Bass 2 */ 73, 0, /* 72 Flute 1 */ 73, 0, /* 73 Flute 2 */ 72, 0, /* 74 Piccolo 1 */ 72, 0, /* 75 Piccolo 2 */ 74, 0, /* 76 Recorder */ 75, 0, /* 77 Pan Pipes */ 64, 0, /* 78 Sax 1 */ 65, 0, /* 79 Sax 2 */ 66, 0, /* 80 Sax 3 */ 67, 0, /* 81 Sax 4 */ 71, 0, /* 82 Clarinet 1 */ 71, 0, /* 83 Clarinet 2 */ 68, 0, /* 84 Oboe */ 69, 0, /* 85 English Horn (Cor Anglais) */ 70, 0, /* 86 Bassoon */ 22, 0, /* 87 Harmonica */ 56, 0, /* 88 Trumpet 1 */ 56, 0, /* 89 Trumpet 2 */ 57, 0, /* 90 Trombone 1 */ 57, 0, /* 91 Trombone 2 */ 60, 0, /* 92 French Horn 1 */ 60, 0, /* 93 French Horn 2 */ 58, 0, /* 94 Tuba */ 61, 0, /* 95 Brass Section 1 */ 61, 0, /* 96 Brass Section 2 */ 11, 0, /* 97 Vibes 1 */ 11, 0, /* 98 Vibes 2 */ 99, 0, /* 99 Syn Mallet Bank 1 */ 112, 0, /* 100 WindBell no real equiv Set to TinkleBell(112) */ 9, 0, /* 101 Glockenspiel */ 14, 0, /* 102 Tubular Bells */ 13, 0, /* 103 Xylophone */ 12, 0, /* 104 Marimba */ 107, 0, /* 105 Koto */ 111, 0, /* 106 Sho?? set to Shanai(111) */ 77, 0, /* 107 Shakauhachi */ 78, 0, /* 108 Whistle 1 */ 78, 0, /* 109 Whistle 2 */ 76, 0, /* 110 Bottle Blow */ 76, 0, /* 111 Breathpipe no real equiv set to bottle blow(76) */ 47, 0, /* 112 Timpani */ 117, 0, /* 113 Melodic Tom */ 116, 0, /* 114 Deap Snare no equiv, set to Taiko(116) */ 118, 0, /* 115 Electric Perc 1 */ 118, 0, /* 116 Electric Perc 2 */ 116, 0, /* 117 Taiko */ 115, 0, /* 118 Taiko Rim, no real equiv, set to Woodblock(115) */ 119, 0, /* 119 Cymbal, no real equiv, set to reverse cymbal(119) */ 115, 0, /* 120 Castanets, no real equiv, in GM set to Woodblock(115) */ 112, 0, /* 121 Triangle, no real equiv, set to TinkleBell(112) */ 55, 0, /* 122 Orchestral Hit */ 124, 0, /* 123 Telephone */ 123, 0, /* 124 BirdTweet */ 94, 0, /* 125 Big Notes Pad no equiv, set to halo pad (94) */ 98, 0, /* 126 Water Bell set to Crystal Pad(98) */ 121, 0 /* 127 Jungle Tune set to Breath Noise */ }; int _WM_xmi2midi(const uint8_t *in, uint32_t insize, uint8_t **out, uint32_t *outsize, uint32_t convert_type) { struct xmi_ctx ctx; unsigned int i; int ret = -1; if (convert_type > XMIDI_CONVERT_MT32_TO_GS) { _WM_ERROR_NEW("%s:%i: %d is an invalid conversion type.", __FUNCTION__, __LINE__, convert_type); return (ret); } memset(&ctx, 0, sizeof(struct xmi_ctx)); ctx.src = ctx.src_ptr = in; ctx.srcsize = insize; ctx.convert_type = convert_type; if (ParseXMI(&ctx) < 0) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_XMI, NULL, 0); goto _end; } if (ExtractTracks(&ctx) < 0) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_MIDI, NULL, 0); goto _end; } ctx.dst = (uint8_t *) malloc(DST_CHUNK); ctx.dst_ptr = ctx.dst; ctx.dstsize = DST_CHUNK; ctx.dstrem = DST_CHUNK; /* Header is 14 bytes long and add the rest as well */ write1(&ctx, 'M'); write1(&ctx, 'T'); write1(&ctx, 'h'); write1(&ctx, 'd'); write4(&ctx, 6); write2(&ctx, ctx.info.type); write2(&ctx, ctx.info.tracks); write2(&ctx, ctx.timing[0]);/* write divisions from track0 */ for (i = 0; i < ctx.info.tracks; i++) ConvertListToMTrk(&ctx, ctx.events[i]); *out = ctx.dst; *outsize = ctx.dstsize - ctx.dstrem; ret = 0; _end: /* cleanup */ if (ret < 0) { free(ctx.dst); *out = NULL; *outsize = 0; } if (ctx.events) { for (i = 0; i < ctx.info.tracks; i++) DeleteEventList(ctx.events[i]); free(ctx.events); } free(ctx.timing); return (ret); } static void DeleteEventList(midi_event *mlist) { midi_event *event; midi_event *next; next = mlist; while ((event = next) != NULL) { next = event->next; free(event->buffer); free(event); } } /* Sets current to the new event and updates list */ static void CreateNewEvent(struct xmi_ctx *ctx, int32_t time) { if (!ctx->list) { ctx->list = ctx->current = (midi_event *) calloc(1, sizeof(midi_event)); ctx->current->time = (time < 0)? 0 : time; return; } if (time < 0) { midi_event *event = (midi_event *) calloc(1, sizeof(midi_event)); event->next = ctx->list; ctx->list = ctx->current = event; return; } if (ctx->current->time > time) ctx->current = ctx->list; while (ctx->current->next) { if (ctx->current->next->time > time) { midi_event *event = (midi_event *) calloc(1, sizeof(midi_event)); event->next = ctx->current->next; ctx->current->next = event; ctx->current = event; ctx->current->time = time; return; } ctx->current = ctx->current->next; } ctx->current->next = (midi_event *) calloc(1, sizeof(midi_event)); ctx->current = ctx->current->next; ctx->current->time = time; } /* Conventional Variable Length Quantity */ static int GetVLQ(struct xmi_ctx *ctx, uint32_t *quant) { int i; uint32_t data; *quant = 0; for (i = 0; i < 4; i++) { data = read1(ctx); *quant <<= 7; *quant |= data & 0x7F; if (!(data & 0x80)) { i++; break; } } return (i); } /* XMIDI Delta Variable Length Quantity */ static int GetVLQ2(struct xmi_ctx *ctx, uint32_t *quant) { int i; int32_t data; *quant = 0; for (i = 0; i < 4; i++) { data = read1(ctx); if (data & 0x80) { skipsrc(ctx, -1); break; } *quant += data; } return (i); } static int PutVLQ(struct xmi_ctx *ctx, uint32_t value) { int32_t buffer; int i = 1, j; buffer = value & 0x7F; while (value >>= 7) { buffer <<= 8; buffer |= ((value & 0x7F) | 0x80); i++; } for (j = 0; j < i; j++) { write1(ctx, buffer & 0xFF); buffer >>= 8; } return (i); } /* Converts Events * * Source is at the first data byte * size 1 is single data byte * size 2 is dual data byte * size 3 is XMI Note on * Returns bytes converted */ static int ConvertEvent(struct xmi_ctx *ctx, const int32_t time, const uint8_t status, const int size) { uint32_t delta = 0; int32_t data; midi_event *prev; int i; data = read1(ctx); /* Bank changes are handled here */ if ((status >> 4) == 0xB && data == 0) { data = read1(ctx); ctx->bank127[status & 0xF] = 0; if ( ctx->convert_type == XMIDI_CONVERT_MT32_TO_GM || ctx->convert_type == XMIDI_CONVERT_MT32_TO_GS || ctx->convert_type == XMIDI_CONVERT_MT32_TO_GS127 || (ctx->convert_type == XMIDI_CONVERT_MT32_TO_GS127DRUM && (status & 0xF) == 9) ) return (2); CreateNewEvent(ctx, time); ctx->current->status = status; ctx->current->data[0] = 0; ctx->current->data[1] = data; if (ctx->convert_type == XMIDI_CONVERT_GS127_TO_GS && data == 127) ctx->bank127[status & 0xF] = 1; return (2); } /* Handling for patch change mt32 conversion, probably should go elsewhere */ if ((status >> 4) == 0xC && (status&0xF) != 9 && ctx->convert_type != XMIDI_CONVERT_NOCONVERSION) { if (ctx->convert_type == XMIDI_CONVERT_MT32_TO_GM) { data = mt32asgm[data]; } else if ((ctx->convert_type == XMIDI_CONVERT_GS127_TO_GS && ctx->bank127[status&0xF]) || ctx->convert_type == XMIDI_CONVERT_MT32_TO_GS || ctx->convert_type == XMIDI_CONVERT_MT32_TO_GS127DRUM) { CreateNewEvent (ctx, time); ctx->current->status = 0xB0 | (status&0xF); ctx->current->data[0] = 0; ctx->current->data[1] = mt32asgs[data*2+1]; data = mt32asgs[data*2]; } else if (ctx->convert_type == XMIDI_CONVERT_MT32_TO_GS127) { CreateNewEvent (ctx, time); ctx->current->status = 0xB0 | (status&0xF); ctx->current->data[0] = 0; ctx->current->data[1] = 127; } } /* Drum track handling */ else if ((status >> 4) == 0xC && (status&0xF) == 9 && (ctx->convert_type == XMIDI_CONVERT_MT32_TO_GS127DRUM || ctx->convert_type == XMIDI_CONVERT_MT32_TO_GS127)) { CreateNewEvent (ctx, time); ctx->current->status = 0xB9; ctx->current->data[0] = 0; ctx->current->data[1] = 127; } CreateNewEvent(ctx, time); ctx->current->status = status; ctx->current->data[0] = data; if (size == 1) return (1); ctx->current->data[1] = read1(ctx); if (size == 2) return (2); /* XMI Note On handling */ prev = ctx->current; i = GetVLQ(ctx, &delta); CreateNewEvent(ctx, time + delta * 3); ctx->current->status = status; ctx->current->data[0] = data; ctx->current->data[1] = 0; ctx->current = prev; return (i + 2); } /* Simple routine to convert system messages */ static int32_t ConvertSystemMessage(struct xmi_ctx *ctx, const int32_t time, const uint8_t status) { int32_t i = 0; CreateNewEvent(ctx, time); ctx->current->status = status; /* Handling of Meta events */ if (status == 0xFF) { ctx->current->data[0] = read1(ctx); i++; } i += GetVLQ(ctx, &ctx->current->len); if (!ctx->current->len) return (i); ctx->current->buffer = (uint8_t *) malloc(sizeof(uint8_t)*ctx->current->len); copy(ctx, (char *) ctx->current->buffer, ctx->current->len); return (i + ctx->current->len); } /* XMIDI and Midi to List * Returns XMIDI PPQN */ static int32_t ConvertFiletoList(struct xmi_ctx *ctx) { int32_t time = 0; uint32_t data; int32_t end = 0; int32_t tempo = 500000; int32_t tempo_set = 0; uint32_t status = 0; uint32_t file_size = getsrcsize(ctx); /* Set Drum track to correct setting if required */ if (ctx->convert_type == XMIDI_CONVERT_MT32_TO_GS127) { CreateNewEvent(ctx, 0); ctx->current->status = 0xB9; ctx->current->data[0] = 0; ctx->current->data[1] = 127; } while (!end && getsrcpos(ctx) < file_size) { GetVLQ2(ctx, &data); time += data * 3; status = read1(ctx); switch (status >> 4) { case MIDI_STATUS_NOTE_ON: ConvertEvent(ctx, time, status, 3); break; /* 2 byte data */ case MIDI_STATUS_NOTE_OFF: case MIDI_STATUS_AFTERTOUCH: case MIDI_STATUS_CONTROLLER: case MIDI_STATUS_PITCH_WHEEL: ConvertEvent(ctx, time, status, 2); break; /* 1 byte data */ case MIDI_STATUS_PROG_CHANGE: case MIDI_STATUS_PRESSURE: ConvertEvent(ctx, time, status, 1); break; case MIDI_STATUS_SYSEX: if (status == 0xFF) { int32_t pos = getsrcpos(ctx); uint32_t dat = read1(ctx); if (dat == 0x2F) /* End */ end = 1; else if (dat == 0x51 && !tempo_set) /* Tempo. Need it for PPQN */ { skipsrc(ctx, 1); tempo = read1(ctx) << 16; tempo += read1(ctx) << 8; tempo += read1(ctx); tempo *= 3; tempo_set = 1; } else if (dat == 0x51 && tempo_set) /* Skip any other tempo changes */ { GetVLQ(ctx, &dat); skipsrc(ctx, dat); break; } seeksrc(ctx, pos); } ConvertSystemMessage(ctx, time, status); break; default: break; } } return ((tempo * 3) / 25000); } /* Converts and event list to a MTrk * Returns bytes of the array * buf can be NULL */ static uint32_t ConvertListToMTrk(struct xmi_ctx *ctx, midi_event *mlist) { int32_t time = 0; midi_event *event; uint32_t delta; uint8_t last_status = 0; uint32_t i = 8; uint32_t j; uint32_t size_pos, cur_pos; int end = 0; write1(ctx, 'M'); write1(ctx, 'T'); write1(ctx, 'r'); write1(ctx, 'k'); size_pos = getdstpos(ctx); skipdst(ctx, 4); for (event = mlist; event && !end; event = event->next) { delta = (event->time - time); time = event->time; i += PutVLQ(ctx, delta); if ((event->status != last_status) || (event->status >= 0xF0)) { write1(ctx, event->status); i++; } last_status = event->status; switch (event->status >> 4) { /* 2 bytes data * Note off, Note on, Aftertouch, Controller and Pitch Wheel */ case 0x8: case 0x9: case 0xA: case 0xB: case 0xE: write1(ctx, event->data[0]); write1(ctx, event->data[1]); i += 2; break; /* 1 bytes data * Program Change and Channel Pressure */ case 0xC: case 0xD: write1(ctx, event->data[0]); i++; break; /* Variable length * SysEx */ case 0xF: if (event->status == 0xFF) { if (event->data[0] == 0x2f) end = 1; write1(ctx, event->data[0]); i++; } i += PutVLQ(ctx, event->len); if (event->len) { for (j = 0; j < event->len; j++) { write1(ctx, event->buffer[j]); i++; } } break; /* Never occur */ default: _WM_DEBUG_MSG("%s: unrecognized event", __FUNCTION__); break; } } cur_pos = getdstpos(ctx); seekdst(ctx, size_pos); write4(ctx, i - 8); seekdst(ctx, cur_pos); return (i); } /* Assumes correct xmidi */ static uint32_t ExtractTracksFromXmi(struct xmi_ctx *ctx) { uint32_t num = 0; signed short ppqn; uint32_t len = 0; int32_t begin; char buf[32]; while (getsrcpos(ctx) < getsrcsize(ctx) && num != ctx->info.tracks) { /* Read first 4 bytes of name */ copy(ctx, buf, 4); len = read4(ctx); /* Skip the FORM entries */ if (!memcmp(buf, "FORM", 4)) { skipsrc(ctx, 4); copy(ctx, buf, 4); len = read4(ctx); } if (memcmp(buf, "EVNT", 4)) { skipsrc(ctx, (len + 1) & ~1); continue; } ctx->list = NULL; begin = getsrcpos(ctx); /* Convert it */ if (!(ppqn = ConvertFiletoList(ctx))) { _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, NULL, 0); break; } ctx->timing[num] = ppqn; ctx->events[num] = ctx->list; /* Increment Counter */ num++; /* go to start of next track */ seeksrc(ctx, begin + ((len + 1) & ~1)); } /* Return how many were converted */ return (num); } static int ParseXMI(struct xmi_ctx *ctx) { uint32_t i; uint32_t start; uint32_t len; uint32_t chunk_len; uint32_t file_size; char buf[32]; file_size = getsrcsize(ctx); if (getsrcpos(ctx) + 8 > file_size) { badfile: _WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(too short)", 0); return (-1); } /* Read first 4 bytes of header */ copy(ctx, buf, 4); /* Could be XMIDI */ if (!memcmp(buf, "FORM", 4)) { /* Read length of */ len = read4(ctx); start = getsrcpos(ctx); if (start + 4 > file_size) goto badfile; /* Read 4 bytes of type */ copy(ctx, buf, 4); /* XDIRless XMIDI, we can handle them here. */ if (!memcmp(buf, "XMID", 4)) { _WM_DEBUG_MSG("Warning: XMIDI without XDIR"); ctx->info.tracks = 1; } /* Not an XMIDI that we recognise */ else if (memcmp(buf, "XDIR", 4)) { goto badfile; } else { /* Seems Valid */ ctx->info.tracks = 0; for (i = 4; i < len; i++) { /* check too short files */ if (getsrcpos(ctx) + 10 > file_size) break; /* Read 4 bytes of type */ copy(ctx, buf, 4); /* Read length of chunk */ chunk_len = read4(ctx); /* Add eight bytes */ i += 8; if (memcmp(buf, "INFO", 4)) { /* Must align */ skipsrc(ctx, (chunk_len + 1) & ~1); i += (chunk_len + 1) & ~1; continue; } /* Must be at least 2 bytes long */ if (chunk_len < 2) break; ctx->info.tracks = read2(ctx); break; } /* Didn't get to fill the header */ if (ctx->info.tracks == 0) { goto badfile; } /* Ok now to start part 2 * Goto the right place */ seeksrc(ctx, start + ((len + 1) & ~1)); if (getsrcpos(ctx) + 12 > file_size) goto badfile; /* Read 4 bytes of type */ copy(ctx, buf, 4); if (memcmp(buf, "CAT ", 4)) { _WM_ERROR_NEW("XMI error: expected \"CAT \", found \"%c%c%c%c\".", buf[0], buf[1], buf[2], buf[3]); return (-1); } /* Now read length of this track */ read4(ctx); /* Read 4 bytes of type */ copy(ctx, buf, 4); if (memcmp(buf, "XMID", 4)) { _WM_ERROR_NEW("XMI error: expected \"XMID\", found \"%c%c%c%c\".", buf[0], buf[1], buf[2], buf[3]); return (-1); } /* Valid XMID */ ctx->datastart = getsrcpos(ctx); return (0); } } return (-1); } static int ExtractTracks(struct xmi_ctx *ctx) { uint32_t i; ctx->events = (midi_event **) calloc(ctx->info.tracks, sizeof(midi_event*)); ctx->timing = (int16_t *) calloc(ctx->info.tracks, sizeof(int16_t)); /* type-2 for multi-tracks, type-0 otherwise */ ctx->info.type = (ctx->info.tracks > 1)? 2 : 0; seeksrc(ctx, ctx->datastart); i = ExtractTracksFromXmi(ctx); if (i != ctx->info.tracks) { _WM_ERROR_NEW("XMI error: extracted only %u out of %u tracks from XMIDI", ctx->info.tracks, i); return (-1); } return (0); } wildmidi-wildmidi-0.4.2/test/000077500000000000000000000000001315765416100161075ustar00rootroot00000000000000wildmidi-wildmidi-0.4.2/test/test.c000066400000000000000000000010541315765416100172320ustar00rootroot00000000000000/* tiny, minimal C source for testing, e.g. running under valgrind. */ #include #include midi *song; int main (int argc, char **argv) { if (argc != 2) return 1; if (WildMidi_Init("wildmidi.cfg", 44100, 0) != 0) return 1; song = WildMidi_Open (argv[1]); #if defined(LIBWILDMIDI_VERSION) && (LIBWILDMIDI_VERSION-0 >= 0x000400L) if (!song) fprintf(stderr, "%s\n", WildMidi_GetError()); #endif WildMidi_MasterVolume (100); if (song) WildMidi_Close(song); WildMidi_Shutdown(); return (song == NULL); }