mirror of
https://github.com/ZDoom/raze-gles.git
synced 2024-12-24 10:40:46 +00:00
Move midi stuff to audiolib
# Conflicts: # platform/Windows/eduke32.vcxproj # platform/Windows/nblood.vcxproj.filters # source/audiolib/include/al_midi.h # source/audiolib/include/opl3.h # source/audiolib/include/oplmidi.h # source/audiolib/src/_al_midi.h # source/audiolib/src/_oplmidi.h # source/audiolib/src/al_midi.cpp # source/audiolib/src/opl3.cpp # source/audiolib/src/oplmidi.cpp # source/duke3d/Dependencies.mak # source/duke3d/src/sdlmusic.cpp
This commit is contained in:
parent
9b63ab5279
commit
75d2e81e98
33 changed files with 79 additions and 4839 deletions
31
GNUmakefile
31
GNUmakefile
|
@ -369,6 +369,9 @@ audiolib_objs := \
|
|||
xa.cpp \
|
||||
xmp.cpp \
|
||||
driver_nosound.cpp \
|
||||
al_midi.cpp \
|
||||
gmtimbre.cpp \
|
||||
opl3.cpp \
|
||||
|
||||
audiolib_root := $(source)/$(audiolib)
|
||||
audiolib_src := $(audiolib_root)/src
|
||||
|
@ -381,7 +384,7 @@ audiolib_deps :=
|
|||
|
||||
ifeq ($(PLATFORM),WINDOWS)
|
||||
ifeq ($(MIXERTYPE),WIN)
|
||||
audiolib_objs += driver_directsound.cpp
|
||||
audiolib_objs += driver_directsound.cpp music.cpp midi.cpp mpu401.cpp
|
||||
endif
|
||||
endif
|
||||
|
||||
|
@ -389,7 +392,7 @@ ifeq ($(MIXERTYPE),SDL)
|
|||
ifeq (,$(filter $(PLATFORM),DARWIN WINDOWS WII))
|
||||
audiolib_cflags += `$(PKG_CONFIG) --cflags vorbis`
|
||||
endif
|
||||
audiolib_objs += driver_sdl.cpp
|
||||
audiolib_objs += driver_sdl.cpp sdlmusic.cpp
|
||||
endif
|
||||
|
||||
ifneq (0,$(HAVE_XMP))
|
||||
|
@ -519,7 +522,7 @@ duke3d_cflags := -I$(duke3d_src)
|
|||
|
||||
common_editor_deps := duke3d_common_editor engine_editor
|
||||
|
||||
duke3d_game_deps := duke3d_common_midi audiolib mact
|
||||
duke3d_game_deps := audiolib mact
|
||||
duke3d_editor_deps := audiolib
|
||||
|
||||
ifneq (0,$(NETCODE))
|
||||
|
@ -703,7 +706,6 @@ ifeq ($(PLATFORM),WINDOWS)
|
|||
endif
|
||||
ifeq ($(MIXERTYPE),WIN)
|
||||
LIBS += -ldsound
|
||||
duke3d_common_midi_objs := music.cpp midi.cpp mpu401.cpp
|
||||
endif
|
||||
endif
|
||||
|
||||
|
@ -720,9 +722,6 @@ ifeq ($(RENDERTYPE),SDL)
|
|||
duke3d_game_rsrc_objs += game_icon.c
|
||||
duke3d_editor_rsrc_objs += build_icon.c
|
||||
endif
|
||||
ifeq ($(MIXERTYPE),SDL)
|
||||
duke3d_common_midi_objs := sdlmusic.cpp
|
||||
endif
|
||||
|
||||
|
||||
#### Blood
|
||||
|
@ -740,7 +739,7 @@ blood_obj := $(obj)/$(blood)
|
|||
|
||||
blood_cflags := -I$(blood_src)
|
||||
|
||||
blood_game_deps := blood_common_midi audiolib mact libsmackerdec
|
||||
blood_game_deps := audiolib mact libsmackerdec
|
||||
|
||||
ifneq (0,$(NETCODE))
|
||||
blood_game_deps += enet
|
||||
|
@ -844,9 +843,6 @@ ifeq ($(PLATFORM),WINDOWS)
|
|||
ifeq ($(STARTUP_WINDOW),1)
|
||||
blood_game_objs += startwin.game.cpp
|
||||
endif
|
||||
ifeq ($(MIXERTYPE),WIN)
|
||||
blood_common_midi_objs := music.cpp midi.cpp mpu401.cpp al_midi.cpp gmtimbre.cpp opl3.cpp
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq (11,$(HAVE_GTK2)$(STARTUP_WINDOW))
|
||||
|
@ -856,9 +852,6 @@ endif
|
|||
ifeq ($(RENDERTYPE),SDL)
|
||||
blood_game_rsrc_objs += game_icon.c
|
||||
endif
|
||||
ifeq ($(MIXERTYPE),SDL)
|
||||
blood_common_midi_objs := sdlmusic.cpp oplmidi.cpp al_midi.cpp gmtimbre.cpp opl3.cpp
|
||||
endif
|
||||
|
||||
#### Redneck Rampage
|
||||
|
||||
|
@ -879,7 +872,7 @@ rr_cflags := -I$(rr_src)
|
|||
|
||||
common_editor_deps := rr_common_editor engine_editor
|
||||
|
||||
rr_game_deps := rr_common_midi audiolib mact
|
||||
rr_game_deps := audiolib mact
|
||||
rr_editor_deps := audiolib
|
||||
|
||||
ifneq (0,$(NETCODE))
|
||||
|
@ -967,9 +960,6 @@ ifeq ($(PLATFORM),WINDOWS)
|
|||
ifeq ($(STARTUP_WINDOW),1)
|
||||
rr_game_objs += startwin.game.cpp
|
||||
endif
|
||||
ifeq ($(MIXERTYPE),WIN)
|
||||
rr_common_midi_objs := music.cpp midi.cpp mpu401.cpp
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(PLATFORM),WII)
|
||||
|
@ -985,9 +975,6 @@ ifeq ($(RENDERTYPE),SDL)
|
|||
rr_game_rsrc_objs += game_icon.c
|
||||
rr_editor_rsrc_objs += build_icon.c
|
||||
endif
|
||||
ifeq ($(MIXERTYPE),SDL)
|
||||
rr_common_midi_objs := sdlmusic.cpp
|
||||
endif
|
||||
|
||||
#### Shadow Warrior
|
||||
|
||||
|
@ -1000,7 +987,7 @@ sw_obj := $(obj)/$(sw)
|
|||
|
||||
sw_cflags := -I$(sw_src)
|
||||
|
||||
sw_game_deps := duke3d_common_midi audiolib mact
|
||||
sw_game_deps := audiolib mact
|
||||
sw_editor_deps := audiolib
|
||||
|
||||
sw_game := voidsw
|
||||
|
|
|
@ -189,6 +189,7 @@
|
|||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\source\audiolib\src\al_midi.cpp" />
|
||||
<ClCompile Include="..\..\source\audiolib\src\drivers.cpp" />
|
||||
<ClCompile Include="..\..\source\audiolib\src\driver_directsound.cpp" />
|
||||
<ClCompile Include="..\..\source\audiolib\src\driver_nosound.cpp" />
|
||||
|
@ -201,25 +202,45 @@
|
|||
<ClCompile Include="..\..\source\audiolib\src\flac.cpp" />
|
||||
<ClCompile Include="..\..\source\audiolib\src\formats.cpp" />
|
||||
<ClCompile Include="..\..\source\audiolib\src\fx_man.cpp" />
|
||||
<ClCompile Include="..\..\source\audiolib\src\gmtimbre.cpp" />
|
||||
<ClCompile Include="..\..\source\audiolib\src\midi.cpp" />
|
||||
<ClCompile Include="..\..\source\audiolib\src\mix.cpp" />
|
||||
<ClCompile Include="..\..\source\audiolib\src\mixst.cpp" />
|
||||
<ClCompile Include="..\..\source\audiolib\src\mpu401.cpp" />
|
||||
<ClCompile Include="..\..\source\audiolib\src\multivoc.cpp" />
|
||||
<ClCompile Include="..\..\source\audiolib\src\music.cpp" />
|
||||
<ClCompile Include="..\..\source\audiolib\src\opl3.cpp" />
|
||||
<ClCompile Include="..\..\source\audiolib\src\oplmidi.cpp" />
|
||||
<ClCompile Include="..\..\source\audiolib\src\pitch.cpp" />
|
||||
<ClCompile Include="..\..\source\audiolib\src\sdlmusic.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\source\audiolib\src\vorbis.cpp" />
|
||||
<ClCompile Include="..\..\source\audiolib\src\xa.cpp" />
|
||||
<ClCompile Include="..\..\source\audiolib\src\xmp.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\source\audiolib\include\al_midi.h" />
|
||||
<ClInclude Include="..\..\source\audiolib\include\drivers.h" />
|
||||
<ClInclude Include="..\..\source\audiolib\include\fx_man.h" />
|
||||
<ClInclude Include="..\..\source\audiolib\include\midi.h" />
|
||||
<ClInclude Include="..\..\source\audiolib\include\mpu401.h" />
|
||||
<ClInclude Include="..\..\source\audiolib\include\multivoc.h" />
|
||||
<ClInclude Include="..\..\source\audiolib\include\music.h" />
|
||||
<ClInclude Include="..\..\source\audiolib\include\opl3.h" />
|
||||
<ClInclude Include="..\..\source\audiolib\include\oplmidi.h" />
|
||||
<ClInclude Include="..\..\source\audiolib\src\driver_directsound.h" />
|
||||
<ClInclude Include="..\..\source\audiolib\src\driver_nosound.h" />
|
||||
<ClInclude Include="..\..\source\audiolib\src\driver_sdl.h" />
|
||||
<ClInclude Include="..\..\source\audiolib\src\linklist.h" />
|
||||
<ClInclude Include="..\..\source\audiolib\src\pitch.h" />
|
||||
<ClInclude Include="..\..\source\audiolib\src\_al_midi.h" />
|
||||
<ClInclude Include="..\..\source\audiolib\src\_midi.h" />
|
||||
<ClInclude Include="..\..\source\audiolib\src\_multivc.h" />
|
||||
<ClInclude Include="..\..\source\audiolib\src\_oplmidi.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
|
|
|
@ -53,6 +53,30 @@
|
|||
<ClCompile Include="..\..\source\audiolib\src\xmp.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\source\audiolib\src\sdlmusic.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\source\audiolib\src\al_midi.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\source\audiolib\src\gmtimbre.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\source\audiolib\src\midi.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\source\audiolib\src\mpu401.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\source\audiolib\src\music.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\source\audiolib\src\opl3.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\source\audiolib\src\oplmidi.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\source\audiolib\src\pitch.h">
|
||||
|
@ -85,5 +109,29 @@
|
|||
<ClInclude Include="..\..\source\audiolib\include\music.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\source\audiolib\src\_al_midi.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\source\audiolib\src\_midi.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\source\audiolib\src\_oplmidi.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\source\audiolib\include\al_midi.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\source\audiolib\include\midi.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\source\audiolib\include\mpu401.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\source\audiolib\include\opl3.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\source\audiolib\include\oplmidi.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -184,7 +184,6 @@
|
|||
<ClInclude Include="..\..\source\duke3d\src\input.h" />
|
||||
<ClInclude Include="..\..\source\duke3d\src\inv.h" />
|
||||
<ClInclude Include="..\..\source\duke3d\src\menus.h" />
|
||||
<ClInclude Include="..\..\source\duke3d\src\mpu401.h" />
|
||||
<ClInclude Include="..\..\source\duke3d\src\network.h" />
|
||||
<ClInclude Include="..\..\source\duke3d\src\player.h" />
|
||||
<ClInclude Include="..\..\source\duke3d\src\premap.h" />
|
||||
|
@ -195,7 +194,6 @@
|
|||
<ClInclude Include="..\..\source\duke3d\src\screentext.h" />
|
||||
<ClInclude Include="..\..\source\duke3d\src\sector.h" />
|
||||
<ClInclude Include="..\..\source\duke3d\src\_functio.h" />
|
||||
<ClInclude Include="..\..\source\duke3d\src\_midi.h" />
|
||||
<ClInclude Include="..\..\source\duke3d\src\_rts.h" />
|
||||
<ClInclude Include="..\..\source\duke3d\src\config.h" />
|
||||
<ClInclude Include="..\..\source\duke3d\src\duke3d.h" />
|
||||
|
@ -240,9 +238,6 @@
|
|||
<ClCompile Include="..\..\source\duke3d\src\input.cpp" />
|
||||
<ClCompile Include="..\..\source\duke3d\src\mdump.cpp" />
|
||||
<ClCompile Include="..\..\source\duke3d\src\menus.cpp" />
|
||||
<ClCompile Include="..\..\source\duke3d\src\midi.cpp" />
|
||||
<ClCompile Include="..\..\source\duke3d\src\mpu401.cpp" />
|
||||
<ClCompile Include="..\..\source\duke3d\src\music.cpp" />
|
||||
<ClCompile Include="..\..\source\duke3d\src\namesdyn.cpp" />
|
||||
<ClCompile Include="..\..\source\duke3d\src\network.cpp" />
|
||||
<ClCompile Include="..\..\source\duke3d\src\osdcmds.cpp" />
|
||||
|
@ -254,12 +249,6 @@
|
|||
<ClCompile Include="..\..\source\duke3d\src\sbar.cpp" />
|
||||
<ClCompile Include="..\..\source\duke3d\src\screens.cpp" />
|
||||
<ClCompile Include="..\..\source\duke3d\src\screentext.cpp" />
|
||||
<ClCompile Include="..\..\source\duke3d\src\sdlmusic.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\source\duke3d\src\sector.cpp" />
|
||||
<ClCompile Include="..\..\source\duke3d\src\sounds.cpp" />
|
||||
<ClCompile Include="..\..\source\duke3d\src\soundsdyn.cpp" />
|
||||
|
|
|
@ -132,12 +132,6 @@
|
|||
<ClInclude Include="..\..\source\duke3d\src\android.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\source\duke3d\src\mpu401.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\source\duke3d\src\_midi.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\source\duke3d\src\cheats.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
|
@ -194,15 +188,6 @@
|
|||
<ClCompile Include="..\..\source\duke3d\src\menus.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\source\duke3d\src\midi.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\source\duke3d\src\mpu401.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\source\duke3d\src\music.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\source\duke3d\src\namesdyn.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
@ -224,9 +209,6 @@
|
|||
<ClCompile Include="..\..\source\duke3d\src\savegame.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\source\duke3d\src\sdlmusic.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\source\duke3d\src\sector.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
|
|
@ -214,7 +214,6 @@
|
|||
<ClCompile Include="..\..\source\blood\src\getopt.cpp" />
|
||||
<ClCompile Include="..\..\source\blood\src\gib.cpp" />
|
||||
<ClCompile Include="..\..\source\blood\src\globals.cpp" />
|
||||
<ClCompile Include="..\..\source\blood\src\gmtimbre.cpp" />
|
||||
<ClCompile Include="..\..\source\blood\src\inifile.cpp" />
|
||||
<ClCompile Include="..\..\source\blood\src\iob.cpp" />
|
||||
<ClCompile Include="..\..\source\blood\src\levels.cpp" />
|
||||
|
@ -222,11 +221,8 @@
|
|||
<ClCompile Include="..\..\source\blood\src\map2d.cpp" />
|
||||
<ClCompile Include="..\..\source\blood\src\menu.cpp" />
|
||||
<ClCompile Include="..\..\source\blood\src\messages.cpp" />
|
||||
<ClCompile Include="..\..\source\blood\src\midi.cpp" />
|
||||
<ClCompile Include="..\..\source\blood\src\mirrors.cpp" />
|
||||
<ClCompile Include="..\..\source\blood\src\misc.cpp" />
|
||||
<ClCompile Include="..\..\source\blood\src\mpu401.cpp" />
|
||||
<ClCompile Include="..\..\source\blood\src\music.cpp" />
|
||||
<ClCompile Include="..\..\source\blood\src\network.cpp" />
|
||||
<ClCompile Include="..\..\source\blood\src\osdcmd.cpp" />
|
||||
<ClCompile Include="..\..\source\blood\src\player.cpp" />
|
||||
|
@ -334,9 +330,7 @@
|
|||
<ClInclude Include="..\..\source\blood\src\iob.h" />
|
||||
<ClInclude Include="..\..\source\blood\src\levels.h" />
|
||||
<ClInclude Include="..\..\source\blood\src\loadsave.h" />
|
||||
<ClInclude Include="..\..\source\blood\src\midi.h" />
|
||||
<ClInclude Include="..\..\source\blood\src\misc.h" />
|
||||
<ClInclude Include="..\..\source\blood\src\mpu401.h" />
|
||||
<ClInclude Include="..\..\source\blood\src\network.h" />
|
||||
<ClInclude Include="..\..\source\blood\src\osdcmds.h" />
|
||||
<ClInclude Include="..\..\source\blood\src\player.h" />
|
||||
|
@ -357,7 +351,6 @@
|
|||
<ClInclude Include="..\..\source\blood\src\view.h" />
|
||||
<ClInclude Include="..\..\source\blood\src\weapon.h" />
|
||||
<ClInclude Include="..\..\source\blood\src\_functio.h" />
|
||||
<ClInclude Include="..\..\source\blood\src\_midi.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
|
|
|
@ -93,15 +93,6 @@
|
|||
<ClCompile Include="..\..\source\blood\src\sound.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\source\blood\src\mpu401.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\source\blood\src\music.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\source\blood\src\midi.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\source\blood\src\gameutil.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
@ -234,9 +225,6 @@
|
|||
<ClCompile Include="..\..\source\blood\src\loadsave.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\source\blood\src\gmtimbre.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\source\blood\src\common.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
@ -337,15 +325,6 @@
|
|||
<ClInclude Include="..\..\source\blood\src\sound.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\source\blood\src\midi.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\source\blood\src\mpu401.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\source\blood\src\_midi.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\source\blood\src\loadsave.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
|
|
|
@ -184,7 +184,6 @@
|
|||
<ClInclude Include="..\..\source\rr\src\input.h" />
|
||||
<ClInclude Include="..\..\source\rr\src\inv.h" />
|
||||
<ClInclude Include="..\..\source\rr\src\menus.h" />
|
||||
<ClInclude Include="..\..\source\rr\src\mpu401.h" />
|
||||
<ClInclude Include="..\..\source\rr\src\net.h" />
|
||||
<ClInclude Include="..\..\source\rr\src\player.h" />
|
||||
<ClInclude Include="..\..\source\rr\src\premap.h" />
|
||||
|
@ -195,7 +194,6 @@
|
|||
<ClInclude Include="..\..\source\rr\src\screentext.h" />
|
||||
<ClInclude Include="..\..\source\rr\src\sector.h" />
|
||||
<ClInclude Include="..\..\source\rr\src\_functio.h" />
|
||||
<ClInclude Include="..\..\source\rr\src\_midi.h" />
|
||||
<ClInclude Include="..\..\source\rr\src\_rts.h" />
|
||||
<ClInclude Include="..\..\source\rr\src\config.h" />
|
||||
<ClInclude Include="..\..\source\rr\src\duke3d.h" />
|
||||
|
@ -240,9 +238,6 @@
|
|||
<ClCompile Include="..\..\source\rr\src\input.cpp" />
|
||||
<ClCompile Include="..\..\source\rr\src\mdump.cpp" />
|
||||
<ClCompile Include="..\..\source\rr\src\menus.cpp" />
|
||||
<ClCompile Include="..\..\source\rr\src\midi.cpp" />
|
||||
<ClCompile Include="..\..\source\rr\src\mpu401.cpp" />
|
||||
<ClCompile Include="..\..\source\rr\src\music.cpp" />
|
||||
<ClCompile Include="..\..\source\rr\src\namesdyn.cpp" />
|
||||
<ClCompile Include="..\..\source\rr\src\net.cpp" />
|
||||
<ClCompile Include="..\..\source\rr\src\osdcmds.cpp" />
|
||||
|
@ -254,12 +249,6 @@
|
|||
<ClCompile Include="..\..\source\rr\src\sbar.cpp" />
|
||||
<ClCompile Include="..\..\source\rr\src\screens.cpp" />
|
||||
<ClCompile Include="..\..\source\rr\src\screentext.cpp" />
|
||||
<ClCompile Include="..\..\source\rr\src\sdlmusic.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\source\rr\src\sector.cpp" />
|
||||
<ClCompile Include="..\..\source\rr\src\sounds.cpp" />
|
||||
<ClCompile Include="..\..\source\rr\src\soundsdyn.cpp" />
|
||||
|
|
|
@ -132,12 +132,6 @@
|
|||
<ClInclude Include="..\..\source\rr\src\android.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\source\rr\src\mpu401.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\source\rr\src\_midi.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\source\rr\src\cheats.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
|
@ -194,15 +188,6 @@
|
|||
<ClCompile Include="..\..\source\rr\src\menus.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\source\rr\src\midi.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\source\rr\src\mpu401.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\source\rr\src\music.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\source\rr\src\namesdyn.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
@ -224,9 +209,6 @@
|
|||
<ClCompile Include="..\..\source\rr\src\savegame.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\source\rr\src\sdlmusic.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\source\rr\src\sector.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
|
|
@ -41,8 +41,7 @@ common_h=\
|
|||
$(blood_src)/common_game.h \
|
||||
$(blood_src)/blood.h \
|
||||
$(blood_src)/actor.h \
|
||||
$(blood_src)/ai.h \
|
||||
$(blood_src)/al_midi.h \
|
||||
$(blood_src)/ai.h \
|
||||
$(blood_src)/asound.h \
|
||||
$(blood_src)/callback.h \
|
||||
$(blood_src)/choke.h \
|
||||
|
@ -69,12 +68,9 @@ common_h=\
|
|||
$(blood_src)/map2d.h \
|
||||
$(blood_src)/menu.h \
|
||||
$(blood_src)/messages.h \
|
||||
$(blood_src)/midi.h \
|
||||
$(blood_src)/mirrors.h \
|
||||
$(blood_src)/misc.h \
|
||||
$(blood_src)/mpu401.h \
|
||||
$(blood_src)/network.h \
|
||||
$(blood_src)/opl3.h \
|
||||
$(blood_src)/osdcmds.h \
|
||||
$(blood_src)/player.h \
|
||||
$(blood_src)/pqueue.h \
|
||||
|
@ -181,11 +177,3 @@ $(mact_obj)/control.$o: $(mact_src)/control.cpp $(mact_inc)/control.h $(mact_inc
|
|||
$(mact_obj)/keyboard.$o: $(mact_src)/keyboard.cpp $(mact_inc)/keyboard.h $(engine_inc)/compat.h $(engine_inc)/baselayer.h
|
||||
$(mact_obj)/joystick.$o: $(mact_src)/joystick.cpp $(mact_inc)/joystick.h $(engine_inc)/baselayer.h
|
||||
$(mact_obj)/scriplib.$o: $(mact_src)/scriplib.cpp $(mact_inc)/scriplib.h $(mact_src)/_scrplib.h $(engine_inc)/compat.h
|
||||
|
||||
$(blood_obj)/al_midi.$o: $(blood_src)/al_midi.cpp $(engine_inc)/compat.h $(blood_src)/al_midi.h $(blood_src)/_al_midi.h $(blood_src)/opl3.h
|
||||
$(blood_obj)/gmtimbre.$o: $(blood_src)/gmtimbre.cpp
|
||||
$(blood_obj)/opl3.$o: $(blood_src)/opl3.cpp
|
||||
$(blood_obj)/midi.$o: $(blood_src)/midi.cpp $(blood_src)/_midi.h $(blood_src)/midi.h $(blood_src)/al_midi.h $(audiolib_inc)/music.h
|
||||
$(blood_obj)/oplmidi.$o: $(blood_src)/oplmidi.cpp $(blood_src)/_oplmidi.h $(blood_src)/oplmidi.h $(blood_src)/al_midi.h $(audiolib_inc)/music.h
|
||||
$(blood_obj)/mpu401.$o: $(blood_src)/mpu401.cpp $(blood_src)/mpu401.h $(audiolib_inc)/music.h
|
||||
$(blood_obj)/music.$o: $(blood_src)/music.cpp $(blood_src)/midi.h $(blood_src)/mpu401.h $(blood_src)/al_midi.h $(audiolib_inc)/music.h
|
||||
|
|
|
@ -1,147 +0,0 @@
|
|||
//-------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (C) 2016 EDuke32 developers and contributors
|
||||
|
||||
This file is part of EDuke32.
|
||||
|
||||
EDuke32 is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License version 2
|
||||
as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
#ifndef ___MIDI_H
|
||||
#define ___MIDI_H
|
||||
#include "compat.h"
|
||||
|
||||
#define RELATIVE_BEAT( measure, beat, tick ) \
|
||||
( ( tick ) + ( ( beat ) << 9 ) + ( ( measure ) << 16 ) )
|
||||
|
||||
//Bobby Prince thinks this may be 100
|
||||
//#define GENMIDI_DefaultVolume 100
|
||||
#define GENMIDI_DefaultVolume 90
|
||||
|
||||
#define MAX_FORMAT 1
|
||||
|
||||
#define NUM_MIDI_CHANNELS 16
|
||||
|
||||
#define TIME_PRECISION 16
|
||||
|
||||
#define MIDI_HEADER_SIGNATURE 0x6468544d // "MThd"
|
||||
#define MIDI_TRACK_SIGNATURE 0x6b72544d // "MTrk"
|
||||
|
||||
#define MIDI_VOLUME 7
|
||||
#define MIDI_PAN 10
|
||||
#define MIDI_DETUNE 94
|
||||
#define MIDI_RHYTHM_CHANNEL 9
|
||||
#define MIDI_RPN_MSB 100
|
||||
#define MIDI_RPN_LSB 101
|
||||
#define MIDI_DATAENTRY_MSB 6
|
||||
#define MIDI_DATAENTRY_LSB 38
|
||||
#define MIDI_PITCHBEND_MSB 0
|
||||
#define MIDI_PITCHBEND_LSB 0
|
||||
#define MIDI_RUNNING_STATUS 0x80
|
||||
#define MIDI_NOTE_OFF 0x8
|
||||
#define MIDI_NOTE_ON 0x9
|
||||
#define MIDI_POLY_AFTER_TCH 0xA
|
||||
#define MIDI_CONTROL_CHANGE 0xB
|
||||
#define MIDI_PROGRAM_CHANGE 0xC
|
||||
#define MIDI_AFTER_TOUCH 0xD
|
||||
#define MIDI_PITCH_BEND 0xE
|
||||
#define MIDI_SPECIAL 0xF
|
||||
#define MIDI_SYSEX 0xF0
|
||||
#define MIDI_SYSEX_CONTINUE 0xF7
|
||||
#define MIDI_META_EVENT 0xFF
|
||||
#define MIDI_END_OF_TRACK 0x2F
|
||||
#define MIDI_TEMPO_CHANGE 0x51
|
||||
#define MIDI_TIME_SIGNATURE 0x58
|
||||
#define MIDI_RESET_ALL_CONTROLLERS 0x79
|
||||
#define MIDI_ALL_NOTES_OFF 0x7b
|
||||
#define MIDI_MONO_MODE_ON 0x7E
|
||||
#define MIDI_SYSTEM_RESET 0xFF
|
||||
|
||||
#define GET_NEXT_EVENT( track, data ) do { \
|
||||
( data ) = *( track )->pos; \
|
||||
( track )->pos += 1; \
|
||||
} while (0)
|
||||
|
||||
#define GET_MIDI_CHANNEL( event ) ( ( event ) & 0xf )
|
||||
#define GET_MIDI_COMMAND( event ) ( ( event ) >> 4 )
|
||||
|
||||
#define EMIDI_INFINITE -1
|
||||
#define EMIDI_END_LOOP_VALUE 127
|
||||
#define EMIDI_ALL_CARDS 127
|
||||
#define EMIDI_INCLUDE_TRACK 110
|
||||
#define EMIDI_EXCLUDE_TRACK 111
|
||||
#define EMIDI_PROGRAM_CHANGE 112
|
||||
#define EMIDI_VOLUME_CHANGE 113
|
||||
#define EMIDI_CONTEXT_START 114
|
||||
#define EMIDI_CONTEXT_END 115
|
||||
#define EMIDI_LOOP_START 116
|
||||
#define EMIDI_LOOP_END 117
|
||||
#define EMIDI_SONG_LOOP_START 118
|
||||
#define EMIDI_SONG_LOOP_END 119
|
||||
|
||||
#define EMIDI_GeneralMIDI 0
|
||||
|
||||
#define EMIDI_AffectsCurrentCard(c, type) (((c) == EMIDI_ALL_CARDS) || ((c) == (type)))
|
||||
#define EMIDI_NUM_CONTEXTS 7
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *pos;
|
||||
char *loopstart;
|
||||
int16_t loopcount;
|
||||
int16_t RunningStatus;
|
||||
unsigned time;
|
||||
int32_t FPSecondsPerTick;
|
||||
int16_t tick;
|
||||
int16_t beat;
|
||||
int16_t measure;
|
||||
int16_t BeatsPerMeasure;
|
||||
int16_t TicksPerBeat;
|
||||
int16_t TimeBase;
|
||||
int32_t delay;
|
||||
int16_t active;
|
||||
} songcontext;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *start;
|
||||
char *pos;
|
||||
|
||||
int32_t delay;
|
||||
int16_t active;
|
||||
int16_t RunningStatus;
|
||||
|
||||
int16_t currentcontext;
|
||||
songcontext context[EMIDI_NUM_CONTEXTS];
|
||||
|
||||
char EMIDI_IncludeTrack;
|
||||
char EMIDI_ProgramChange;
|
||||
char EMIDI_VolumeChange;
|
||||
} track;
|
||||
|
||||
static int32_t _MIDI_ReadNumber(void *from, size_t size);
|
||||
static int32_t _MIDI_ReadDelta(track *ptr);
|
||||
static void _MIDI_ResetTracks(void);
|
||||
static void _MIDI_AdvanceTick(void);
|
||||
static void _MIDI_MetaEvent(track *Track);
|
||||
static void _MIDI_SysEx(track *Track);
|
||||
static int32_t _MIDI_InterpretControllerInfo(track *Track, int32_t TimeSet, int32_t channel, int32_t c1, int32_t c2);
|
||||
static int32_t _MIDI_SendControlChange(int32_t channel, int32_t c1, int32_t c2);
|
||||
static void _MIDI_SetChannelVolume(int32_t channel, int32_t volume);
|
||||
static void _MIDI_SendChannelVolumes(void);
|
||||
static void _MIDI_InitEMIDI(void);
|
||||
|
||||
#endif
|
|
@ -1,952 +0,0 @@
|
|||
//-------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (C) 2010 EDuke32 developers and contributors
|
||||
|
||||
This file is part of EDuke32.
|
||||
|
||||
EDuke32 is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License version 2
|
||||
as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/**********************************************************************
|
||||
module: MIDI.C
|
||||
|
||||
author: James R. Dose
|
||||
date: May 25, 1994
|
||||
|
||||
Midi song file playback routines.
|
||||
|
||||
(c) Copyright 1994 James R. Dose. All Rights Reserved.
|
||||
**********************************************************************/
|
||||
|
||||
// This object is shared by all Build games with MIDI playback!
|
||||
|
||||
#include "compat.h"
|
||||
#include "music.h"
|
||||
#include "_midi.h"
|
||||
#include "midi.h"
|
||||
#include "mpu401.h"
|
||||
#include "compat.h"
|
||||
#include "pragmas.h"
|
||||
|
||||
#include "windows_inc.h"
|
||||
|
||||
extern int32_t MUSIC_SoundDevice;
|
||||
|
||||
static const int32_t _MIDI_CommandLengths[ NUM_MIDI_CHANNELS ] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 1, 1, 2, 0
|
||||
};
|
||||
|
||||
static track *_MIDI_TrackPtr = NULL;
|
||||
static int32_t _MIDI_TrackMemSize;
|
||||
static int32_t _MIDI_NumTracks;
|
||||
|
||||
static int32_t _MIDI_SongActive = FALSE;
|
||||
static int32_t _MIDI_SongLoaded = FALSE;
|
||||
static int32_t _MIDI_Loop = FALSE;
|
||||
|
||||
static int32_t _MIDI_Division;
|
||||
static int32_t _MIDI_Tick = 0;
|
||||
static int32_t _MIDI_Beat = 1;
|
||||
static int32_t _MIDI_Measure = 1;
|
||||
static uint32_t _MIDI_Time;
|
||||
static int32_t _MIDI_BeatsPerMeasure;
|
||||
static int32_t _MIDI_TicksPerBeat;
|
||||
static int32_t _MIDI_TimeBase;
|
||||
static int32_t _MIDI_FPSecondsPerTick;
|
||||
static uint32_t _MIDI_TotalTime;
|
||||
static int32_t _MIDI_TotalTicks;
|
||||
static int32_t _MIDI_TotalBeats;
|
||||
static int32_t _MIDI_TotalMeasures;
|
||||
|
||||
uint32_t _MIDI_PositionInTicks;
|
||||
uint32_t _MIDI_GlobalPositionInTicks;
|
||||
|
||||
static int32_t _MIDI_Context;
|
||||
|
||||
static int32_t _MIDI_ActiveTracks;
|
||||
static int32_t _MIDI_TotalVolume = MIDI_MaxVolume;
|
||||
|
||||
static int32_t _MIDI_ChannelVolume[ NUM_MIDI_CHANNELS ];
|
||||
|
||||
static midifuncs *_MIDI_Funcs = NULL;
|
||||
|
||||
static int32_t Reset = FALSE;
|
||||
|
||||
int32_t MIDI_Tempo = 120;
|
||||
|
||||
static int32_t _MIDI_ReadNumber(void *from, size_t size)
|
||||
{
|
||||
if (size > 4)
|
||||
size = 4;
|
||||
|
||||
char *FromPtr = (char *)from;
|
||||
int32_t value = 0;
|
||||
|
||||
while (size--)
|
||||
{
|
||||
value <<= 8;
|
||||
value += *FromPtr++;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static int32_t _MIDI_ReadDelta(track *ptr)
|
||||
{
|
||||
int32_t value;
|
||||
|
||||
GET_NEXT_EVENT(ptr, value);
|
||||
|
||||
if (value & 0x80)
|
||||
{
|
||||
value &= 0x7f;
|
||||
char c;
|
||||
|
||||
do
|
||||
{
|
||||
GET_NEXT_EVENT(ptr, c);
|
||||
value = (value << 7) + (c & 0x7f);
|
||||
}
|
||||
while (c & 0x80);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static void _MIDI_ResetTracks(void)
|
||||
{
|
||||
_MIDI_Tick = 0;
|
||||
_MIDI_Beat = 1;
|
||||
_MIDI_Measure = 1;
|
||||
_MIDI_Time = 0;
|
||||
_MIDI_BeatsPerMeasure = 4;
|
||||
_MIDI_TicksPerBeat = _MIDI_Division;
|
||||
_MIDI_TimeBase = 4;
|
||||
_MIDI_PositionInTicks = 0;
|
||||
_MIDI_ActiveTracks = 0;
|
||||
_MIDI_Context = 0;
|
||||
|
||||
track *ptr = _MIDI_TrackPtr;
|
||||
for (bssize_t i = 0; i < _MIDI_NumTracks; ++i)
|
||||
{
|
||||
ptr->pos = ptr->start;
|
||||
ptr->delay = _MIDI_ReadDelta(ptr);
|
||||
ptr->active = ptr->EMIDI_IncludeTrack;
|
||||
ptr->RunningStatus = 0;
|
||||
ptr->currentcontext = 0;
|
||||
ptr->context[ 0 ].loopstart = ptr->start;
|
||||
ptr->context[ 0 ].loopcount = 0;
|
||||
|
||||
if (ptr->active)
|
||||
_MIDI_ActiveTracks++;
|
||||
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
static void _MIDI_AdvanceTick(void)
|
||||
{
|
||||
_MIDI_PositionInTicks++;
|
||||
_MIDI_Time += _MIDI_FPSecondsPerTick;
|
||||
|
||||
_MIDI_Tick++;
|
||||
while (_MIDI_Tick > _MIDI_TicksPerBeat)
|
||||
{
|
||||
_MIDI_Tick -= _MIDI_TicksPerBeat;
|
||||
_MIDI_Beat++;
|
||||
}
|
||||
while (_MIDI_Beat > _MIDI_BeatsPerMeasure)
|
||||
{
|
||||
_MIDI_Beat -= _MIDI_BeatsPerMeasure;
|
||||
_MIDI_Measure++;
|
||||
}
|
||||
}
|
||||
|
||||
static void _MIDI_SysEx(track *Track)
|
||||
{
|
||||
int32_t length = _MIDI_ReadDelta(Track);
|
||||
Track->pos += length;
|
||||
}
|
||||
|
||||
|
||||
static void _MIDI_MetaEvent(track *Track)
|
||||
{
|
||||
int32_t command;
|
||||
int32_t length;
|
||||
|
||||
GET_NEXT_EVENT(Track, command);
|
||||
GET_NEXT_EVENT(Track, length);
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case MIDI_END_OF_TRACK:
|
||||
Track->active = FALSE;
|
||||
|
||||
_MIDI_ActiveTracks--;
|
||||
break;
|
||||
|
||||
case MIDI_TEMPO_CHANGE:
|
||||
{
|
||||
int32_t tempo = tabledivide32_noinline(60000000L, _MIDI_ReadNumber(Track->pos, 3));
|
||||
MIDI_SetTempo(tempo);
|
||||
break;
|
||||
}
|
||||
|
||||
case MIDI_TIME_SIGNATURE:
|
||||
{
|
||||
if ((_MIDI_Tick > 0) || (_MIDI_Beat > 1))
|
||||
_MIDI_Measure++;
|
||||
|
||||
_MIDI_Tick = 0;
|
||||
_MIDI_Beat = 1;
|
||||
_MIDI_TimeBase = 1;
|
||||
_MIDI_BeatsPerMeasure = (int32_t)*Track->pos;
|
||||
int32_t denominator = (int32_t) * (Track->pos + 1);
|
||||
|
||||
while (denominator > 0)
|
||||
{
|
||||
_MIDI_TimeBase += _MIDI_TimeBase;
|
||||
denominator--;
|
||||
}
|
||||
|
||||
_MIDI_TicksPerBeat = tabledivide32_noinline(_MIDI_Division * 4, _MIDI_TimeBase);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Track->pos += length;
|
||||
}
|
||||
|
||||
static int32_t _MIDI_InterpretControllerInfo(track *Track, int32_t TimeSet, int32_t channel, int32_t c1, int32_t c2)
|
||||
{
|
||||
track *trackptr;
|
||||
int32_t tracknum;
|
||||
int32_t loopcount;
|
||||
|
||||
switch (c1)
|
||||
{
|
||||
case MIDI_MONO_MODE_ON :
|
||||
Track->pos++;
|
||||
break;
|
||||
|
||||
case MIDI_VOLUME :
|
||||
if (!Track->EMIDI_VolumeChange)
|
||||
_MIDI_SetChannelVolume(channel, c2);
|
||||
break;
|
||||
|
||||
case EMIDI_INCLUDE_TRACK :
|
||||
case EMIDI_EXCLUDE_TRACK :
|
||||
break;
|
||||
|
||||
case EMIDI_PROGRAM_CHANGE :
|
||||
if (Track->EMIDI_ProgramChange)
|
||||
_MIDI_Funcs->ProgramChange(channel, c2 & 0x7f);
|
||||
break;
|
||||
|
||||
case EMIDI_VOLUME_CHANGE :
|
||||
if (Track->EMIDI_VolumeChange)
|
||||
_MIDI_SetChannelVolume(channel, c2);
|
||||
break;
|
||||
|
||||
case EMIDI_CONTEXT_START :
|
||||
break;
|
||||
|
||||
case EMIDI_CONTEXT_END :
|
||||
if ((Track->currentcontext == _MIDI_Context) || (_MIDI_Context < 0) ||
|
||||
(Track->context[_MIDI_Context].pos == NULL))
|
||||
break;
|
||||
|
||||
Track->currentcontext = _MIDI_Context;
|
||||
Track->context[ 0 ].loopstart = Track->context[ _MIDI_Context ].loopstart;
|
||||
Track->context[ 0 ].loopcount = Track->context[ _MIDI_Context ].loopcount;
|
||||
Track->pos = Track->context[ _MIDI_Context ].pos;
|
||||
Track->RunningStatus = Track->context[ _MIDI_Context ].RunningStatus;
|
||||
|
||||
if (TimeSet)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
_MIDI_Time = Track->context[ _MIDI_Context ].time;
|
||||
_MIDI_FPSecondsPerTick = Track->context[ _MIDI_Context ].FPSecondsPerTick;
|
||||
_MIDI_Tick = Track->context[ _MIDI_Context ].tick;
|
||||
_MIDI_Beat = Track->context[ _MIDI_Context ].beat;
|
||||
_MIDI_Measure = Track->context[ _MIDI_Context ].measure;
|
||||
_MIDI_BeatsPerMeasure = Track->context[ _MIDI_Context ].BeatsPerMeasure;
|
||||
_MIDI_TicksPerBeat = Track->context[ _MIDI_Context ].TicksPerBeat;
|
||||
_MIDI_TimeBase = Track->context[ _MIDI_Context ].TimeBase;
|
||||
TimeSet = TRUE;
|
||||
break;
|
||||
|
||||
case EMIDI_LOOP_START :
|
||||
case EMIDI_SONG_LOOP_START :
|
||||
loopcount = (c2 == 0) ? EMIDI_INFINITE : c2;
|
||||
|
||||
if (c1 == EMIDI_SONG_LOOP_START)
|
||||
{
|
||||
trackptr = _MIDI_TrackPtr;
|
||||
tracknum = _MIDI_NumTracks;
|
||||
}
|
||||
else
|
||||
{
|
||||
trackptr = Track;
|
||||
tracknum = 1;
|
||||
}
|
||||
|
||||
while (tracknum > 0)
|
||||
{
|
||||
trackptr->context[ 0 ].loopcount = loopcount;
|
||||
trackptr->context[ 0 ].pos = trackptr->pos;
|
||||
trackptr->context[ 0 ].loopstart = trackptr->pos;
|
||||
trackptr->context[ 0 ].RunningStatus = trackptr->RunningStatus;
|
||||
trackptr->context[ 0 ].active = trackptr->active;
|
||||
trackptr->context[ 0 ].delay = trackptr->delay;
|
||||
trackptr->context[ 0 ].time = _MIDI_Time;
|
||||
trackptr->context[ 0 ].FPSecondsPerTick = _MIDI_FPSecondsPerTick;
|
||||
trackptr->context[ 0 ].tick = _MIDI_Tick;
|
||||
trackptr->context[ 0 ].beat = _MIDI_Beat;
|
||||
trackptr->context[ 0 ].measure = _MIDI_Measure;
|
||||
trackptr->context[ 0 ].BeatsPerMeasure = _MIDI_BeatsPerMeasure;
|
||||
trackptr->context[ 0 ].TicksPerBeat = _MIDI_TicksPerBeat;
|
||||
trackptr->context[ 0 ].TimeBase = _MIDI_TimeBase;
|
||||
trackptr++;
|
||||
tracknum--;
|
||||
}
|
||||
break;
|
||||
|
||||
case EMIDI_LOOP_END :
|
||||
case EMIDI_SONG_LOOP_END :
|
||||
if ((c2 != EMIDI_END_LOOP_VALUE) || (Track->context[0].loopstart == NULL) || (Track->context[0].loopcount == 0))
|
||||
break;
|
||||
|
||||
if (c1 == EMIDI_SONG_LOOP_END)
|
||||
{
|
||||
trackptr = _MIDI_TrackPtr;
|
||||
tracknum = _MIDI_NumTracks;
|
||||
_MIDI_ActiveTracks = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
trackptr = Track;
|
||||
tracknum = 1;
|
||||
_MIDI_ActiveTracks--;
|
||||
}
|
||||
|
||||
while (tracknum > 0)
|
||||
{
|
||||
if (trackptr->context[ 0 ].loopcount != EMIDI_INFINITE)
|
||||
{
|
||||
trackptr->context[ 0 ].loopcount--;
|
||||
}
|
||||
|
||||
trackptr->pos = trackptr->context[ 0 ].loopstart;
|
||||
trackptr->RunningStatus = trackptr->context[ 0 ].RunningStatus;
|
||||
trackptr->delay = trackptr->context[ 0 ].delay;
|
||||
trackptr->active = trackptr->context[ 0 ].active;
|
||||
if (trackptr->active)
|
||||
{
|
||||
_MIDI_ActiveTracks++;
|
||||
}
|
||||
|
||||
if (!TimeSet)
|
||||
{
|
||||
_MIDI_Time = trackptr->context[ 0 ].time;
|
||||
_MIDI_FPSecondsPerTick = trackptr->context[ 0 ].FPSecondsPerTick;
|
||||
_MIDI_Tick = trackptr->context[ 0 ].tick;
|
||||
_MIDI_Beat = trackptr->context[ 0 ].beat;
|
||||
_MIDI_Measure = trackptr->context[ 0 ].measure;
|
||||
_MIDI_BeatsPerMeasure = trackptr->context[ 0 ].BeatsPerMeasure;
|
||||
_MIDI_TicksPerBeat = trackptr->context[ 0 ].TicksPerBeat;
|
||||
_MIDI_TimeBase = trackptr->context[ 0 ].TimeBase;
|
||||
TimeSet = TRUE;
|
||||
}
|
||||
|
||||
trackptr++;
|
||||
tracknum--;
|
||||
}
|
||||
break;
|
||||
|
||||
default :
|
||||
if (_MIDI_Funcs->ControlChange)
|
||||
_MIDI_Funcs->ControlChange(channel, c1, c2);
|
||||
}
|
||||
|
||||
return TimeSet;
|
||||
}
|
||||
|
||||
static void _MIDI_ServiceRoutine(void)
|
||||
{
|
||||
if (!_MIDI_SongActive)
|
||||
return;
|
||||
|
||||
track *Track = _MIDI_TrackPtr;
|
||||
int32_t tracknum = 0;
|
||||
int32_t TimeSet = FALSE;
|
||||
int32_t c1 = 0;
|
||||
int32_t c2 = 0;
|
||||
|
||||
while (tracknum < _MIDI_NumTracks)
|
||||
{
|
||||
while ((Track->active) && (Track->delay == 0))
|
||||
{
|
||||
int32_t event;
|
||||
GET_NEXT_EVENT(Track, event);
|
||||
|
||||
if (GET_MIDI_COMMAND(event) == MIDI_SPECIAL)
|
||||
{
|
||||
switch (event)
|
||||
{
|
||||
case MIDI_SYSEX:
|
||||
case MIDI_SYSEX_CONTINUE: _MIDI_SysEx(Track); break;
|
||||
case MIDI_META_EVENT: _MIDI_MetaEvent(Track); break;
|
||||
}
|
||||
|
||||
if (Track->active)
|
||||
Track->delay = _MIDI_ReadDelta(Track);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (event & MIDI_RUNNING_STATUS)
|
||||
Track->RunningStatus = event;
|
||||
else
|
||||
{
|
||||
event = Track->RunningStatus;
|
||||
Track->pos--;
|
||||
}
|
||||
|
||||
int const channel = GET_MIDI_CHANNEL(event);
|
||||
int const command = GET_MIDI_COMMAND(event);
|
||||
|
||||
if (_MIDI_CommandLengths[ command ] > 0)
|
||||
{
|
||||
GET_NEXT_EVENT(Track, c1);
|
||||
if (_MIDI_CommandLengths[ command ] > 1)
|
||||
GET_NEXT_EVENT(Track, c2);
|
||||
}
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case MIDI_NOTE_OFF:
|
||||
if (_MIDI_Funcs->NoteOff)
|
||||
_MIDI_Funcs->NoteOff(channel, c1, c2);
|
||||
break;
|
||||
|
||||
case MIDI_NOTE_ON:
|
||||
if (_MIDI_Funcs->NoteOn)
|
||||
_MIDI_Funcs->NoteOn(channel, c1, c2);
|
||||
break;
|
||||
|
||||
case MIDI_POLY_AFTER_TCH:
|
||||
if (_MIDI_Funcs->PolyAftertouch)
|
||||
_MIDI_Funcs->PolyAftertouch(channel, c1, c2);
|
||||
break;
|
||||
|
||||
case MIDI_CONTROL_CHANGE:
|
||||
TimeSet = _MIDI_InterpretControllerInfo(Track, TimeSet, channel, c1, c2);
|
||||
break;
|
||||
|
||||
case MIDI_PROGRAM_CHANGE:
|
||||
if ((_MIDI_Funcs->ProgramChange) && (!Track->EMIDI_ProgramChange))
|
||||
_MIDI_Funcs->ProgramChange(channel, c1 & 0x7f);
|
||||
break;
|
||||
|
||||
case MIDI_AFTER_TOUCH:
|
||||
if (_MIDI_Funcs->ChannelAftertouch)
|
||||
_MIDI_Funcs->ChannelAftertouch(channel, c1);
|
||||
break;
|
||||
|
||||
case MIDI_PITCH_BEND:
|
||||
if (_MIDI_Funcs->PitchBend)
|
||||
_MIDI_Funcs->PitchBend(channel, c1, c2);
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
Track->delay = _MIDI_ReadDelta(Track);
|
||||
}
|
||||
|
||||
Track->delay--;
|
||||
Track++;
|
||||
tracknum++;
|
||||
|
||||
if (_MIDI_ActiveTracks == 0)
|
||||
{
|
||||
_MIDI_ResetTracks();
|
||||
if (_MIDI_Loop)
|
||||
{
|
||||
tracknum = 0;
|
||||
Track = _MIDI_TrackPtr;
|
||||
}
|
||||
else
|
||||
{
|
||||
_MIDI_SongActive = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_MIDI_AdvanceTick();
|
||||
_MIDI_GlobalPositionInTicks++;
|
||||
}
|
||||
|
||||
static int32_t _MIDI_SendControlChange(int32_t channel, int32_t c1, int32_t c2)
|
||||
{
|
||||
if (_MIDI_Funcs == NULL || _MIDI_Funcs->ControlChange == NULL)
|
||||
return MIDI_Error;
|
||||
|
||||
_MIDI_Funcs->ControlChange(channel, c1, c2);
|
||||
|
||||
return MIDI_Ok;
|
||||
}
|
||||
|
||||
int32_t MIDI_AllNotesOff(void)
|
||||
{
|
||||
for (bssize_t channel = 0; channel < NUM_MIDI_CHANNELS; channel++)
|
||||
{
|
||||
_MIDI_SendControlChange(channel, 0x40, 0);
|
||||
_MIDI_SendControlChange(channel, MIDI_ALL_NOTES_OFF, 0);
|
||||
_MIDI_SendControlChange(channel, 0x78, 0);
|
||||
}
|
||||
|
||||
return MIDI_Ok;
|
||||
}
|
||||
|
||||
static void _MIDI_SetChannelVolume(int32_t channel, int32_t volume)
|
||||
{
|
||||
_MIDI_ChannelVolume[ channel ] = volume;
|
||||
|
||||
if (_MIDI_Funcs == NULL || _MIDI_Funcs->ControlChange == NULL)
|
||||
return;
|
||||
|
||||
volume *= _MIDI_TotalVolume;
|
||||
volume = tabledivide32_noinline(volume, MIDI_MaxVolume);
|
||||
|
||||
_MIDI_Funcs->ControlChange(channel, MIDI_VOLUME, volume);
|
||||
}
|
||||
|
||||
static void _MIDI_SendChannelVolumes(void)
|
||||
{
|
||||
for (bssize_t channel = 0; channel < NUM_MIDI_CHANNELS; channel++)
|
||||
_MIDI_SetChannelVolume(channel, _MIDI_ChannelVolume[channel]);
|
||||
}
|
||||
|
||||
int32_t MIDI_Reset(void)
|
||||
{
|
||||
MIDI_AllNotesOff();
|
||||
|
||||
for (bssize_t channel = 0; channel < NUM_MIDI_CHANNELS; channel++)
|
||||
{
|
||||
_MIDI_SendControlChange(channel, MIDI_RESET_ALL_CONTROLLERS, 0);
|
||||
_MIDI_SendControlChange(channel, MIDI_RPN_MSB, MIDI_PITCHBEND_MSB);
|
||||
_MIDI_SendControlChange(channel, MIDI_RPN_LSB, MIDI_PITCHBEND_LSB);
|
||||
_MIDI_SendControlChange(channel, MIDI_DATAENTRY_MSB, 2); /* Pitch Bend Sensitivity MSB */
|
||||
_MIDI_SendControlChange(channel, MIDI_DATAENTRY_LSB, 0); /* Pitch Bend Sensitivity LSB */
|
||||
_MIDI_ChannelVolume[ channel ] = GENMIDI_DefaultVolume;
|
||||
}
|
||||
|
||||
_MIDI_SendChannelVolumes();
|
||||
|
||||
Reset = TRUE;
|
||||
|
||||
return MIDI_Ok;
|
||||
}
|
||||
|
||||
int32_t MIDI_SetVolume(int32_t volume)
|
||||
{
|
||||
if (_MIDI_Funcs == NULL)
|
||||
return MIDI_NullMidiModule;
|
||||
|
||||
_MIDI_TotalVolume = max(0, min(MIDI_MaxVolume, volume));
|
||||
_MIDI_SendChannelVolumes();
|
||||
|
||||
return MIDI_Ok;
|
||||
}
|
||||
|
||||
int32_t MIDI_GetVolume(void) { return (_MIDI_Funcs == NULL) ? MIDI_NullMidiModule : _MIDI_TotalVolume; }
|
||||
|
||||
void MIDI_SetLoopFlag(int32_t loopflag) { _MIDI_Loop = loopflag; }
|
||||
|
||||
void MIDI_ContinueSong(void)
|
||||
{
|
||||
if (!_MIDI_SongLoaded)
|
||||
return;
|
||||
|
||||
_MIDI_SongActive = TRUE;
|
||||
MPU_Unpause();
|
||||
}
|
||||
|
||||
void MIDI_PauseSong(void)
|
||||
{
|
||||
if (!_MIDI_SongLoaded)
|
||||
return;
|
||||
|
||||
_MIDI_SongActive = FALSE;
|
||||
MIDI_AllNotesOff();
|
||||
MPU_Pause();
|
||||
}
|
||||
|
||||
void MIDI_SetMidiFuncs(midifuncs *funcs) { _MIDI_Funcs = funcs; }
|
||||
|
||||
void MIDI_StopSong(void)
|
||||
{
|
||||
if (!_MIDI_SongLoaded)
|
||||
return;
|
||||
|
||||
_MIDI_SongActive = FALSE;
|
||||
_MIDI_SongLoaded = FALSE;
|
||||
|
||||
MPU_Reset();
|
||||
MPU_Init(MUSIC_SoundDevice);
|
||||
|
||||
MIDI_Reset();
|
||||
_MIDI_ResetTracks();
|
||||
|
||||
DO_FREE_AND_NULL(_MIDI_TrackPtr);
|
||||
|
||||
_MIDI_NumTracks = 0;
|
||||
_MIDI_TrackMemSize = 0;
|
||||
|
||||
_MIDI_TotalTime = 0;
|
||||
_MIDI_TotalTicks = 0;
|
||||
_MIDI_TotalBeats = 0;
|
||||
_MIDI_TotalMeasures = 0;
|
||||
|
||||
}
|
||||
|
||||
int32_t MIDI_PlaySong(char *song, int32_t loopflag)
|
||||
{
|
||||
int32_t numtracks;
|
||||
int32_t format;
|
||||
int32_t headersize;
|
||||
int32_t tracklength;
|
||||
track *CurrentTrack;
|
||||
char *ptr;
|
||||
|
||||
if (_MIDI_Funcs == NULL)
|
||||
return MIDI_NullMidiModule;
|
||||
|
||||
if (B_UNBUF32(song) != MIDI_HEADER_SIGNATURE)
|
||||
return MIDI_InvalidMidiFile;
|
||||
|
||||
song += 4;
|
||||
headersize = _MIDI_ReadNumber(song, 4);
|
||||
song += 4;
|
||||
format = _MIDI_ReadNumber(song, 2);
|
||||
int32_t My_MIDI_NumTracks = _MIDI_ReadNumber(song + 2, 2);
|
||||
int32_t My_MIDI_Division = _MIDI_ReadNumber(song + 4, 2);
|
||||
if (My_MIDI_Division < 0)
|
||||
{
|
||||
// If a SMPTE time division is given, just set to 96 so no errors occur
|
||||
My_MIDI_Division = 96;
|
||||
}
|
||||
|
||||
if (format > MAX_FORMAT)
|
||||
return MIDI_UnknownMidiFormat;
|
||||
|
||||
ptr = song + headersize;
|
||||
|
||||
if (My_MIDI_NumTracks == 0)
|
||||
return MIDI_NoTracks;
|
||||
|
||||
int32_t My_MIDI_TrackMemSize = My_MIDI_NumTracks * sizeof(track);
|
||||
track * My_MIDI_TrackPtr = (track *)Xmalloc(My_MIDI_TrackMemSize);
|
||||
|
||||
CurrentTrack = My_MIDI_TrackPtr;
|
||||
numtracks = My_MIDI_NumTracks;
|
||||
|
||||
while (numtracks--)
|
||||
{
|
||||
if (B_UNBUF32(ptr) != MIDI_TRACK_SIGNATURE)
|
||||
{
|
||||
DO_FREE_AND_NULL(My_MIDI_TrackPtr);
|
||||
|
||||
My_MIDI_TrackMemSize = 0;
|
||||
|
||||
return MIDI_InvalidTrack;
|
||||
}
|
||||
|
||||
tracklength = _MIDI_ReadNumber(ptr + 4, 4);
|
||||
ptr += 8;
|
||||
CurrentTrack->start = ptr;
|
||||
ptr += tracklength;
|
||||
CurrentTrack++;
|
||||
}
|
||||
|
||||
// at this point we know song load is successful
|
||||
|
||||
if (_MIDI_SongLoaded)
|
||||
MIDI_StopSong();
|
||||
|
||||
MPU_Init(MUSIC_SoundDevice);
|
||||
|
||||
_MIDI_Loop = loopflag;
|
||||
_MIDI_NumTracks = My_MIDI_NumTracks;
|
||||
_MIDI_Division = My_MIDI_Division;
|
||||
_MIDI_TrackMemSize = My_MIDI_TrackMemSize;
|
||||
_MIDI_TrackPtr = My_MIDI_TrackPtr;
|
||||
|
||||
_MIDI_InitEMIDI();
|
||||
_MIDI_ResetTracks();
|
||||
|
||||
if (!Reset)
|
||||
MIDI_Reset();
|
||||
|
||||
Reset = FALSE;
|
||||
|
||||
MIDI_SetDivision(_MIDI_Division);
|
||||
//MIDI_SetTempo( 120 );
|
||||
|
||||
_MIDI_SongLoaded = TRUE;
|
||||
_MIDI_SongActive = TRUE;
|
||||
|
||||
while (_MPU_BuffersWaiting < 4) _MIDI_ServiceRoutine();
|
||||
MPU_BeginPlayback();
|
||||
|
||||
return MIDI_Ok;
|
||||
}
|
||||
|
||||
void MIDI_SetTempo(int32_t tempo)
|
||||
{
|
||||
int32_t tickspersecond;
|
||||
|
||||
MIDI_Tempo = tempo;
|
||||
tickspersecond = ((tempo) * _MIDI_Division)/60;
|
||||
_MIDI_FPSecondsPerTick = tabledivide32_noinline(1 << TIME_PRECISION, tickspersecond);
|
||||
MPU_SetTempo(tempo);
|
||||
}
|
||||
|
||||
void MIDI_SetDivision(int32_t division)
|
||||
{
|
||||
MPU_SetDivision(division);
|
||||
}
|
||||
|
||||
int32_t MIDI_GetTempo(void) { return MIDI_Tempo; }
|
||||
|
||||
static void _MIDI_InitEMIDI(void)
|
||||
{
|
||||
int32_t type = EMIDI_GeneralMIDI;
|
||||
|
||||
_MIDI_ResetTracks();
|
||||
|
||||
_MIDI_TotalTime = 0;
|
||||
_MIDI_TotalTicks = 0;
|
||||
_MIDI_TotalBeats = 0;
|
||||
_MIDI_TotalMeasures = 0;
|
||||
|
||||
track *Track = _MIDI_TrackPtr;
|
||||
int32_t tracknum = 0;
|
||||
|
||||
while ((tracknum < _MIDI_NumTracks) && (Track != NULL))
|
||||
{
|
||||
_MIDI_Tick = 0;
|
||||
_MIDI_Beat = 1;
|
||||
_MIDI_Measure = 1;
|
||||
_MIDI_Time = 0;
|
||||
_MIDI_BeatsPerMeasure = 4;
|
||||
_MIDI_TicksPerBeat = _MIDI_Division;
|
||||
_MIDI_TimeBase = 4;
|
||||
|
||||
_MIDI_PositionInTicks = 0;
|
||||
_MIDI_ActiveTracks = 0;
|
||||
_MIDI_Context = -1;
|
||||
|
||||
Track->RunningStatus = 0;
|
||||
Track->active = TRUE;
|
||||
|
||||
Track->EMIDI_ProgramChange = FALSE;
|
||||
Track->EMIDI_VolumeChange = FALSE;
|
||||
Track->EMIDI_IncludeTrack = TRUE;
|
||||
|
||||
memset(Track->context, 0, sizeof(Track->context));
|
||||
|
||||
while (Track->delay > 0)
|
||||
{
|
||||
_MIDI_AdvanceTick();
|
||||
Track->delay--;
|
||||
}
|
||||
|
||||
int32_t IncludeFound = FALSE;
|
||||
|
||||
while (Track->active)
|
||||
{
|
||||
int32_t event;
|
||||
|
||||
GET_NEXT_EVENT(Track, event);
|
||||
|
||||
if (GET_MIDI_COMMAND(event) == MIDI_SPECIAL)
|
||||
{
|
||||
switch (event)
|
||||
{
|
||||
case MIDI_SYSEX:
|
||||
case MIDI_SYSEX_CONTINUE: _MIDI_SysEx(Track); break;
|
||||
case MIDI_META_EVENT: _MIDI_MetaEvent(Track); break;
|
||||
}
|
||||
|
||||
if (Track->active)
|
||||
{
|
||||
Track->delay = _MIDI_ReadDelta(Track);
|
||||
while (Track->delay > 0)
|
||||
{
|
||||
_MIDI_AdvanceTick();
|
||||
Track->delay--;
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (event & MIDI_RUNNING_STATUS)
|
||||
Track->RunningStatus = event;
|
||||
else
|
||||
{
|
||||
event = Track->RunningStatus;
|
||||
Track->pos--;
|
||||
}
|
||||
|
||||
// channel = GET_MIDI_CHANNEL(event);
|
||||
int const command = GET_MIDI_COMMAND(event);
|
||||
int length = _MIDI_CommandLengths[ command ];
|
||||
|
||||
if (command == MIDI_CONTROL_CHANGE)
|
||||
{
|
||||
if (*Track->pos == MIDI_MONO_MODE_ON)
|
||||
length++;
|
||||
|
||||
int32_t c1, c2;
|
||||
GET_NEXT_EVENT(Track, c1);
|
||||
GET_NEXT_EVENT(Track, c2);
|
||||
length -= 2;
|
||||
|
||||
switch (c1)
|
||||
{
|
||||
case EMIDI_LOOP_START :
|
||||
case EMIDI_SONG_LOOP_START :
|
||||
Track->context[ 0 ].loopcount = (c2 == 0) ? EMIDI_INFINITE : c2;
|
||||
Track->context[ 0 ].pos = Track->pos;
|
||||
Track->context[ 0 ].loopstart = Track->pos;
|
||||
Track->context[ 0 ].RunningStatus = Track->RunningStatus;
|
||||
Track->context[ 0 ].time = _MIDI_Time;
|
||||
Track->context[ 0 ].FPSecondsPerTick = _MIDI_FPSecondsPerTick;
|
||||
Track->context[ 0 ].tick = _MIDI_Tick;
|
||||
Track->context[ 0 ].beat = _MIDI_Beat;
|
||||
Track->context[ 0 ].measure = _MIDI_Measure;
|
||||
Track->context[ 0 ].BeatsPerMeasure = _MIDI_BeatsPerMeasure;
|
||||
Track->context[ 0 ].TicksPerBeat = _MIDI_TicksPerBeat;
|
||||
Track->context[ 0 ].TimeBase = _MIDI_TimeBase;
|
||||
break;
|
||||
|
||||
case EMIDI_LOOP_END :
|
||||
case EMIDI_SONG_LOOP_END :
|
||||
if (c2 == EMIDI_END_LOOP_VALUE)
|
||||
{
|
||||
Track->context[ 0 ].loopstart = NULL;
|
||||
Track->context[ 0 ].loopcount = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case EMIDI_INCLUDE_TRACK :
|
||||
if (EMIDI_AffectsCurrentCard(c2, type))
|
||||
{
|
||||
//printf( "Include track %d on card %d\n", tracknum, c2 );
|
||||
IncludeFound = TRUE;
|
||||
Track->EMIDI_IncludeTrack = TRUE;
|
||||
}
|
||||
else if (!IncludeFound)
|
||||
{
|
||||
//printf( "Track excluded %d on card %d\n", tracknum, c2 );
|
||||
IncludeFound = TRUE;
|
||||
Track->EMIDI_IncludeTrack = FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case EMIDI_EXCLUDE_TRACK :
|
||||
if (EMIDI_AffectsCurrentCard(c2, type))
|
||||
{
|
||||
//printf( "Exclude track %d on card %d\n", tracknum, c2 );
|
||||
Track->EMIDI_IncludeTrack = FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case EMIDI_PROGRAM_CHANGE :
|
||||
if (!Track->EMIDI_ProgramChange)
|
||||
//printf( "Program change on track %d\n", tracknum );
|
||||
Track->EMIDI_ProgramChange = TRUE;
|
||||
break;
|
||||
|
||||
case EMIDI_VOLUME_CHANGE :
|
||||
if (!Track->EMIDI_VolumeChange)
|
||||
//printf( "Volume change on track %d\n", tracknum );
|
||||
Track->EMIDI_VolumeChange = TRUE;
|
||||
break;
|
||||
|
||||
case EMIDI_CONTEXT_START :
|
||||
if ((c2 > 0) && (c2 < EMIDI_NUM_CONTEXTS))
|
||||
{
|
||||
Track->context[ c2 ].pos = Track->pos;
|
||||
Track->context[ c2 ].loopstart = Track->context[ 0 ].loopstart;
|
||||
Track->context[ c2 ].loopcount = Track->context[ 0 ].loopcount;
|
||||
Track->context[ c2 ].RunningStatus = Track->RunningStatus;
|
||||
Track->context[ c2 ].time = _MIDI_Time;
|
||||
Track->context[ c2 ].FPSecondsPerTick = _MIDI_FPSecondsPerTick;
|
||||
Track->context[ c2 ].tick = _MIDI_Tick;
|
||||
Track->context[ c2 ].beat = _MIDI_Beat;
|
||||
Track->context[ c2 ].measure = _MIDI_Measure;
|
||||
Track->context[ c2 ].BeatsPerMeasure = _MIDI_BeatsPerMeasure;
|
||||
Track->context[ c2 ].TicksPerBeat = _MIDI_TicksPerBeat;
|
||||
Track->context[ c2 ].TimeBase = _MIDI_TimeBase;
|
||||
}
|
||||
break;
|
||||
|
||||
case EMIDI_CONTEXT_END :
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Track->pos += length;
|
||||
Track->delay = _MIDI_ReadDelta(Track);
|
||||
|
||||
while (Track->delay > 0)
|
||||
{
|
||||
_MIDI_AdvanceTick();
|
||||
Track->delay--;
|
||||
}
|
||||
}
|
||||
|
||||
_MIDI_TotalTime = max(_MIDI_TotalTime, _MIDI_Time);
|
||||
if (RELATIVE_BEAT(_MIDI_Measure, _MIDI_Beat, _MIDI_Tick) >
|
||||
RELATIVE_BEAT(_MIDI_TotalMeasures, _MIDI_TotalBeats, _MIDI_TotalTicks))
|
||||
{
|
||||
_MIDI_TotalTicks = _MIDI_Tick;
|
||||
_MIDI_TotalBeats = _MIDI_Beat;
|
||||
_MIDI_TotalMeasures = _MIDI_Measure;
|
||||
}
|
||||
|
||||
Track++;
|
||||
tracknum++;
|
||||
}
|
||||
|
||||
_MIDI_ResetTracks();
|
||||
}
|
||||
|
||||
|
||||
void MIDI_UpdateMusic(void)
|
||||
{
|
||||
if (!_MIDI_SongLoaded || !_MIDI_SongActive) return;
|
||||
while (_MPU_BuffersWaiting < 4) _MIDI_ServiceRoutine();
|
||||
}
|
||||
|
|
@ -1,87 +0,0 @@
|
|||
//-------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (C) 2016 EDuke32 developers and contributors
|
||||
|
||||
This file is part of EDuke32.
|
||||
|
||||
EDuke32 is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License version 2
|
||||
as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
#ifndef __MIDI_H
|
||||
#define __MIDI_H
|
||||
|
||||
enum MIDI_Errors
|
||||
{
|
||||
MIDI_Warning = -2,
|
||||
MIDI_Error = -1,
|
||||
MIDI_Ok = 0,
|
||||
MIDI_NullMidiModule,
|
||||
MIDI_InvalidMidiFile,
|
||||
MIDI_UnknownMidiFormat,
|
||||
MIDI_NoTracks,
|
||||
MIDI_InvalidTrack,
|
||||
MIDI_NoMemory,
|
||||
MIDI_DPMI_Error
|
||||
};
|
||||
|
||||
|
||||
#define MIDI_PASS_THROUGH 1
|
||||
#define MIDI_DONT_PLAY 0
|
||||
|
||||
#define MIDI_MaxVolume 255
|
||||
|
||||
extern char MIDI_PatchMap[ 128 ];
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void (*NoteOff)(int32_t channel, int32_t key, int32_t velocity);
|
||||
void (*NoteOn)(int32_t channel, int32_t key, int32_t velocity);
|
||||
void (*PolyAftertouch)(int32_t channel, int32_t key, int32_t pressure);
|
||||
void (*ControlChange)(int32_t channel, int32_t number, int32_t value);
|
||||
void (*ProgramChange)(int32_t channel, int32_t program);
|
||||
void (*ChannelAftertouch)(int32_t channel, int32_t pressure);
|
||||
void (*PitchBend)(int32_t channel, int32_t lsb, int32_t msb);
|
||||
void (*FinishBuffer)(void);
|
||||
} midifuncs;
|
||||
|
||||
void MIDI_RerouteMidiChannel( int32_t channel, int32_t ( *function )( int32_t event, int32_t c1, int32_t c2 ) );
|
||||
int32_t MIDI_AllNotesOff( void );
|
||||
void MIDI_SetUserChannelVolume( int32_t channel, int32_t volume );
|
||||
void MIDI_ResetUserChannelVolume( void );
|
||||
int32_t MIDI_Reset( void );
|
||||
int32_t MIDI_SetVolume( int32_t volume );
|
||||
int32_t MIDI_GetVolume( void );
|
||||
void MIDI_SetMidiFuncs( midifuncs *funcs );
|
||||
void MIDI_SetContext( int32_t context );
|
||||
int32_t MIDI_GetContext( void );
|
||||
void MIDI_SetLoopFlag( int32_t loopflag );
|
||||
void MIDI_ContinueSong( void );
|
||||
void MIDI_PauseSong( void );
|
||||
int32_t MIDI_SongPlaying( void );
|
||||
void MIDI_StopSong( void );
|
||||
int32_t MIDI_PlaySong( char *song, int32_t loopflag );
|
||||
void MIDI_SetTempo( int32_t tempo );
|
||||
int32_t MIDI_GetTempo( void );
|
||||
void MIDI_SetSongTick( uint32_t PositionInTicks );
|
||||
void MIDI_SetSongTime( uint32_t milliseconds );
|
||||
void MIDI_SetSongPosition( int32_t measure, int32_t beat, int32_t tick );
|
||||
void MIDI_GetSongPosition( songposition *pos );
|
||||
void MIDI_GetSongLength( songposition *pos );
|
||||
void MIDI_LoadTimbres( void );
|
||||
void MIDI_UpdateMusic(void);
|
||||
void MIDI_SetDivision( int32_t division );
|
||||
|
||||
#endif
|
|
@ -1,496 +0,0 @@
|
|||
//-------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (C) 2010 EDuke32 developers and contributors
|
||||
|
||||
This file is part of EDuke32.
|
||||
|
||||
EDuke32 is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License version 2
|
||||
as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/**********************************************************************
|
||||
module: MPU401.C
|
||||
|
||||
author: James R. Dose
|
||||
date: January 1, 1994
|
||||
|
||||
Low level routines to support sending of MIDI data to MPU401
|
||||
compatible MIDI interfaces.
|
||||
|
||||
(c) Copyright 1994 James R. Dose. All Rights Reserved.
|
||||
**********************************************************************/
|
||||
|
||||
// This object is shared by all Build games with MIDI playback!
|
||||
|
||||
#include "mpu401.h"
|
||||
#include "compat.h"
|
||||
#include "pragmas.h"
|
||||
|
||||
#define NEED_MMSYSTEM_H
|
||||
#include "windows_inc.h"
|
||||
|
||||
static HMIDISTRM hmido = (HMIDISTRM)-1;
|
||||
static MIDIOUTCAPS midicaps;
|
||||
static DWORD mididevice = -1;
|
||||
|
||||
#define PAD(x) ((((x)+3)&(~3)))
|
||||
|
||||
#define BUFFERLEN (32*4*4)
|
||||
#define NUMBUFFERS 6
|
||||
static char eventbuf[NUMBUFFERS][BUFFERLEN];
|
||||
static int32_t eventcnt[NUMBUFFERS];
|
||||
static MIDIHDR bufferheaders[NUMBUFFERS];
|
||||
int32_t _MPU_CurrentBuffer = 0;
|
||||
int32_t _MPU_BuffersWaiting = 0;
|
||||
|
||||
extern uint32_t _MIDI_GlobalPositionInTicks;
|
||||
uint32_t _MPU_LastEvent=0;
|
||||
|
||||
#define MIDI_NOTE_OFF 0x80
|
||||
#define MIDI_NOTE_ON 0x90
|
||||
#define MIDI_POLY_AFTER_TCH 0xA0
|
||||
#define MIDI_CONTROL_CHANGE 0xB0
|
||||
#define MIDI_PROGRAM_CHANGE 0xC0
|
||||
#define MIDI_AFTER_TOUCH 0xD0
|
||||
#define MIDI_PITCH_BEND 0xE0
|
||||
#define MIDI_META_EVENT 0xFF
|
||||
#define MIDI_END_OF_TRACK 0x2F
|
||||
#define MIDI_TEMPO_CHANGE 0x51
|
||||
#define MIDI_MONO_MODE_ON 0x7E
|
||||
#define MIDI_ALL_NOTES_OFF 0x7B
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
|
||||
Memory locked functions:
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
void MPU_FinishBuffer(int32_t buffer)
|
||||
{
|
||||
if (!eventcnt[buffer]) return;
|
||||
ZeroMemory(&bufferheaders[buffer], sizeof(MIDIHDR));
|
||||
bufferheaders[buffer].lpData = eventbuf[buffer];
|
||||
bufferheaders[buffer].dwBufferLength =
|
||||
bufferheaders[buffer].dwBytesRecorded = eventcnt[buffer];
|
||||
midiOutPrepareHeader((HMIDIOUT)hmido, &bufferheaders[buffer], sizeof(MIDIHDR));
|
||||
midiStreamOut(hmido, &bufferheaders[buffer], sizeof(MIDIHDR));
|
||||
// printf("Sending %d bytes (buffer %d)\n",eventcnt[buffer],buffer);
|
||||
_MPU_BuffersWaiting++;
|
||||
}
|
||||
|
||||
void MPU_BeginPlayback(void)
|
||||
{
|
||||
_MPU_LastEvent = _MIDI_GlobalPositionInTicks;
|
||||
if (hmido != (HMIDISTRM)-1) midiStreamRestart(hmido);
|
||||
}
|
||||
|
||||
void MPU_Pause(void)
|
||||
{
|
||||
if (hmido != (HMIDISTRM)-1) midiStreamPause(hmido);
|
||||
}
|
||||
|
||||
void MPU_Unpause(void)
|
||||
{
|
||||
if (hmido != (HMIDISTRM)-1) midiStreamRestart(hmido);
|
||||
}
|
||||
|
||||
|
||||
void CALLBACK MPU_MIDICallback(HMIDIOUT handle, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
|
||||
{
|
||||
int32_t i;
|
||||
|
||||
UNREFERENCED_PARAMETER(dwInstance);
|
||||
UNREFERENCED_PARAMETER(dwParam2);
|
||||
|
||||
switch (uMsg)
|
||||
{
|
||||
case MOM_DONE:
|
||||
midiOutUnprepareHeader((HMIDIOUT)handle, (MIDIHDR *)dwParam1, sizeof(MIDIHDR));
|
||||
for (i=0; i<NUMBUFFERS; i++)
|
||||
{
|
||||
if ((MIDIHDR *)dwParam1 == &bufferheaders[i])
|
||||
{
|
||||
eventcnt[i] = 0; // marks the buffer as free
|
||||
// printf("Finished buffer %d\n",i);
|
||||
_MPU_BuffersWaiting--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
Function: MPU_SendMidi
|
||||
|
||||
Queues a MIDI message to the music device.
|
||||
---------------------------------------------------------------------*/
|
||||
|
||||
int32_t MPU_GetNextBuffer(void)
|
||||
{
|
||||
int32_t i;
|
||||
for (i=0; i<NUMBUFFERS; i++)
|
||||
{
|
||||
if (eventcnt[i] == 0) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void MPU_SendMidi(char *data, int32_t count)
|
||||
{
|
||||
char *p;
|
||||
int32_t padded, nextbuffer;
|
||||
static int32_t masks[3] = { 0x000000ffl, 0x0000ffffl, 0x00ffffffl };
|
||||
|
||||
if (count <= 0) return;
|
||||
if (count <= 3)
|
||||
{
|
||||
if (eventcnt[_MPU_CurrentBuffer] + 12 > BUFFERLEN)
|
||||
{
|
||||
// buffer over-full
|
||||
nextbuffer = MPU_GetNextBuffer();
|
||||
if (nextbuffer < 0)
|
||||
{
|
||||
// printf("All buffers full!\n");
|
||||
return;
|
||||
}
|
||||
MPU_FinishBuffer(_MPU_CurrentBuffer);
|
||||
_MPU_CurrentBuffer = nextbuffer;
|
||||
}
|
||||
|
||||
p = eventbuf[_MPU_CurrentBuffer] + eventcnt[_MPU_CurrentBuffer];
|
||||
((int32_t *)p)[0] = _MIDI_GlobalPositionInTicks - _MPU_LastEvent;
|
||||
((int32_t *)p)[1] = 0;
|
||||
((int32_t *)p)[2] = (MEVT_SHORTMSG << 24) | ((*((int32_t *)data)) & masks[count-1]);
|
||||
eventcnt[_MPU_CurrentBuffer] += 12;
|
||||
}
|
||||
else
|
||||
{
|
||||
padded = PAD(count);
|
||||
if (eventcnt[_MPU_CurrentBuffer] + 12 + padded > BUFFERLEN)
|
||||
{
|
||||
// buffer over-full
|
||||
nextbuffer = MPU_GetNextBuffer();
|
||||
if (nextbuffer < 0)
|
||||
{
|
||||
// printf("All buffers full!\n");
|
||||
return;
|
||||
}
|
||||
MPU_FinishBuffer(_MPU_CurrentBuffer);
|
||||
_MPU_CurrentBuffer = nextbuffer;
|
||||
}
|
||||
|
||||
p = eventbuf[_MPU_CurrentBuffer] + eventcnt[_MPU_CurrentBuffer];
|
||||
((int32_t *)p)[0] = _MIDI_GlobalPositionInTicks - _MPU_LastEvent;
|
||||
((int32_t *)p)[1] = 0;
|
||||
((int32_t *)p)[2] = (MEVT_LONGMSG<<24) | (count & 0xffffffl);
|
||||
p+=12; eventcnt[_MPU_CurrentBuffer] += 12;
|
||||
for (; count>0; count--, padded--, eventcnt[_MPU_CurrentBuffer]++)
|
||||
*(p++) = *(data++);
|
||||
for (; padded>0; padded--, eventcnt[_MPU_CurrentBuffer]++)
|
||||
*(p++) = 0;
|
||||
}
|
||||
_MPU_LastEvent = _MIDI_GlobalPositionInTicks;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
Function: MPU_SendMidiImmediate
|
||||
|
||||
Sends a MIDI message immediately to the the music device.
|
||||
---------------------------------------------------------------------*/
|
||||
void MPU_SendMidiImmediate(char *data, int32_t count)
|
||||
{
|
||||
MIDIHDR mhdr;
|
||||
static int32_t masks[3] = { 0x00ffffffl, 0x0000ffffl, 0x000000ffl };
|
||||
|
||||
if (!count) return;
|
||||
if (count<=3) midiOutShortMsg((HMIDIOUT)hmido, (*((int32_t *)data)) & masks[count-1]);
|
||||
else
|
||||
{
|
||||
ZeroMemory(&mhdr, sizeof(mhdr));
|
||||
mhdr.lpData = data;
|
||||
mhdr.dwBufferLength = count;
|
||||
midiOutPrepareHeader((HMIDIOUT)hmido, &mhdr, sizeof(MIDIHDR));
|
||||
midiOutLongMsg((HMIDIOUT)hmido, &mhdr, sizeof(MIDIHDR));
|
||||
while (!(mhdr.dwFlags & MHDR_DONE)) ;
|
||||
midiOutUnprepareHeader((HMIDIOUT)hmido, &mhdr, sizeof(MIDIHDR));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
Function: MPU_Reset
|
||||
|
||||
Resets the MPU401 card.
|
||||
---------------------------------------------------------------------*/
|
||||
|
||||
int32_t MPU_Reset
|
||||
(
|
||||
void
|
||||
)
|
||||
|
||||
{
|
||||
midiStreamStop(hmido);
|
||||
midiStreamClose(hmido);
|
||||
hmido = (HMIDISTRM)-1;
|
||||
|
||||
return MPU_Ok;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
Function: MPU_Init
|
||||
|
||||
Detects and initializes the MPU401 card.
|
||||
---------------------------------------------------------------------*/
|
||||
|
||||
int32_t MPU_Init
|
||||
(
|
||||
int32_t addr
|
||||
)
|
||||
|
||||
{
|
||||
if (hmido != (HMIDISTRM)-1)
|
||||
return MPU_Ok;
|
||||
|
||||
int32_t i;
|
||||
|
||||
for (i=0; i<NUMBUFFERS; i++) eventcnt[i]=0;
|
||||
|
||||
mididevice = addr;
|
||||
|
||||
if (midiOutGetDevCaps(mididevice, &midicaps, sizeof(MIDIOUTCAPS)) != MMSYSERR_NOERROR) return MPU_Error;
|
||||
|
||||
if (midiStreamOpen(&hmido,(LPUINT)&mididevice,1,(DWORD_PTR)MPU_MIDICallback,0L,CALLBACK_FUNCTION) != MMSYSERR_NOERROR) return MPU_Error;
|
||||
|
||||
return MPU_Ok;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
Function: MPU_NoteOff
|
||||
|
||||
Sends a full MIDI note off event out to the music device.
|
||||
---------------------------------------------------------------------*/
|
||||
|
||||
void MPU_NoteOff
|
||||
(
|
||||
int32_t channel,
|
||||
int32_t key,
|
||||
int32_t velocity
|
||||
)
|
||||
|
||||
{
|
||||
char msg[3];
|
||||
msg[0] = (MIDI_NOTE_OFF | channel);
|
||||
msg[1] = (key);
|
||||
msg[2] = (velocity);
|
||||
MPU_SendMidi(msg, 3);
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
Function: MPU_NoteOn
|
||||
|
||||
Sends a full MIDI note on event out to the music device.
|
||||
---------------------------------------------------------------------*/
|
||||
|
||||
void MPU_NoteOn
|
||||
(
|
||||
int32_t channel,
|
||||
int32_t key,
|
||||
int32_t velocity
|
||||
)
|
||||
|
||||
{
|
||||
char msg[3];
|
||||
msg[0] = (MIDI_NOTE_ON | channel);
|
||||
msg[1] = (key);
|
||||
msg[2] = (velocity);
|
||||
MPU_SendMidi(msg, 3);
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
Function: MPU_PolyAftertouch
|
||||
|
||||
Sends a full MIDI polyphonic aftertouch event out to the music device.
|
||||
---------------------------------------------------------------------*/
|
||||
|
||||
void MPU_PolyAftertouch
|
||||
(
|
||||
int32_t channel,
|
||||
int32_t key,
|
||||
int32_t pressure
|
||||
)
|
||||
|
||||
{
|
||||
char msg[3];
|
||||
msg[0] = (MIDI_POLY_AFTER_TCH | channel);
|
||||
msg[1] = (key);
|
||||
msg[2] = (pressure);
|
||||
MPU_SendMidi(msg, 3);
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
Function: MPU_ControlChange
|
||||
|
||||
Sends a full MIDI control change event out to the music device.
|
||||
---------------------------------------------------------------------*/
|
||||
|
||||
void MPU_ControlChange
|
||||
(
|
||||
int32_t channel,
|
||||
int32_t number,
|
||||
int32_t value
|
||||
)
|
||||
|
||||
{
|
||||
char msg[3];
|
||||
msg[0] = (MIDI_CONTROL_CHANGE | channel);
|
||||
msg[1] = (number);
|
||||
msg[2] = (value);
|
||||
MPU_SendMidi(msg, 3);
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
Function: MPU_ProgramChange
|
||||
|
||||
Sends a full MIDI program change event out to the music device.
|
||||
---------------------------------------------------------------------*/
|
||||
|
||||
void MPU_ProgramChange
|
||||
(
|
||||
int32_t channel,
|
||||
int32_t program
|
||||
)
|
||||
|
||||
{
|
||||
char msg[2];
|
||||
msg[0] = (MIDI_PROGRAM_CHANGE | channel);
|
||||
msg[1] = (program);
|
||||
MPU_SendMidi(msg, 2);
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
Function: MPU_ChannelAftertouch
|
||||
|
||||
Sends a full MIDI channel aftertouch event out to the music device.
|
||||
---------------------------------------------------------------------*/
|
||||
|
||||
void MPU_ChannelAftertouch
|
||||
(
|
||||
int32_t channel,
|
||||
int32_t pressure
|
||||
)
|
||||
|
||||
{
|
||||
char msg[2];
|
||||
msg[0] = (MIDI_AFTER_TOUCH | channel);
|
||||
msg[1] = (pressure);
|
||||
MPU_SendMidi(msg, 2);
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
Function: MPU_PitchBend
|
||||
|
||||
Sends a full MIDI pitch bend event out to the music device.
|
||||
---------------------------------------------------------------------*/
|
||||
|
||||
void MPU_PitchBend
|
||||
(
|
||||
int32_t channel,
|
||||
int32_t lsb,
|
||||
int32_t msb
|
||||
)
|
||||
|
||||
{
|
||||
char msg[3];
|
||||
msg[0] = (MIDI_PITCH_BEND | channel);
|
||||
msg[1] = (lsb);
|
||||
msg[2] = (msb);
|
||||
MPU_SendMidi(msg, 3);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void MPU_SetTempo(int32_t tempo)
|
||||
{
|
||||
MIDIPROPTEMPO prop;
|
||||
prop.cbStruct = sizeof(MIDIPROPTEMPO);
|
||||
prop.dwTempo = tabledivide32_noinline(60000000l, tempo);
|
||||
midiStreamProperty(hmido, (LPBYTE)&prop, MIDIPROP_SET|MIDIPROP_TEMPO);
|
||||
}
|
||||
|
||||
void MPU_SetDivision(int32_t division)
|
||||
{
|
||||
MIDIPROPTIMEDIV prop;
|
||||
prop.cbStruct = sizeof(MIDIPROPTIMEDIV);
|
||||
prop.dwTimeDiv = division;
|
||||
midiStreamProperty(hmido, (LPBYTE)&prop, MIDIPROP_SET|MIDIPROP_TIMEDIV);
|
||||
}
|
||||
|
||||
void MPU_SetVolume(int32_t volume)
|
||||
{
|
||||
/*
|
||||
HMIXER hmixer;
|
||||
int32_t mixerid;
|
||||
MIXERCONTROLDETAILS mxcd;
|
||||
MIXERCONTROLDETAILS_UNSIGNED mxcdu;
|
||||
MMRESULT mme;
|
||||
|
||||
if (mididevice < 0) return;
|
||||
|
||||
mme = mixerOpen(&hmixer, mididevice, 0,0, MIXER_OBJECTF_MIDIOUT);
|
||||
if (mme) {
|
||||
puts("Failed opening mixer");
|
||||
return;
|
||||
}
|
||||
|
||||
mixerGetID(hmixer, &mixerid, MIXER_OBJECTF_HMIXER);
|
||||
printf("mixerid=%d\n",mixerid);
|
||||
|
||||
ZeroMemory(&mxcd,sizeof(mxcd));
|
||||
mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
|
||||
mxcd.dwControlID = MIXERCONTROL_CONTROLTYPE_VOLUME;
|
||||
mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
|
||||
mxcd.paDetails = (LPVOID)&mxcdu;
|
||||
mxcdu.dwValue = (volume << 8) & 0xffff;
|
||||
|
||||
printf("set %d\n",mixerSetControlDetails((HMIXEROBJ)mididevice, &mxcd,
|
||||
MIXER_OBJECTF_MIDIOUT|MIXER_SETCONTROLDETAILSF_VALUE));
|
||||
|
||||
mixerClose(hmixer);
|
||||
*/
|
||||
UNREFERENCED_PARAMETER(volume);
|
||||
}
|
||||
|
||||
int32_t MPU_GetVolume(void)
|
||||
{
|
||||
// if (mididevice < 0) return 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 1994-1995 Apogee Software, Ltd.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
Modifications for JonoF's port by Jonathon Fowler (jf@jonof.id.au)
|
||||
*/
|
||||
#ifndef __MPU401_H
|
||||
#define __MPU401_H
|
||||
|
||||
#include "compat.h"
|
||||
|
||||
#define MPU_DefaultAddress 0x330
|
||||
|
||||
enum MPU_ERRORS
|
||||
{
|
||||
MPU_Warning = -2,
|
||||
MPU_Error = -1,
|
||||
MPU_Ok = 0
|
||||
};
|
||||
|
||||
#define MPU_NotFound -1
|
||||
#define MPU_UARTFailed -2
|
||||
|
||||
#define MPU_ReadyToWrite 0x40
|
||||
#define MPU_ReadyToRead 0x80
|
||||
#define MPU_CmdEnterUART 0x3f
|
||||
#define MPU_CmdReset 0xff
|
||||
#define MPU_CmdAcknowledge 0xfe
|
||||
|
||||
extern int32_t _MPU_CurrentBuffer;
|
||||
extern int32_t _MPU_BuffersWaiting;
|
||||
|
||||
void MPU_SendMidi( char *data, int32_t count );
|
||||
void MPU_SendMidiImmediate( char *data, int32_t count );
|
||||
int32_t MPU_Reset( void );
|
||||
int32_t MPU_Init( int32_t addr );
|
||||
void MPU_NoteOff( int32_t channel, int32_t key, int32_t velocity );
|
||||
void MPU_NoteOn( int32_t channel, int32_t key, int32_t velocity );
|
||||
void MPU_PolyAftertouch( int32_t channel, int32_t key, int32_t pressure );
|
||||
void MPU_ControlChange( int32_t channel, int32_t number, int32_t value );
|
||||
void MPU_ProgramChange( int32_t channel, int32_t program );
|
||||
void MPU_ChannelAftertouch( int32_t channel, int32_t pressure );
|
||||
void MPU_PitchBend( int32_t channel, int32_t lsb, int32_t msb );
|
||||
|
||||
void MPU_SetTempo(int32_t tempo);
|
||||
void MPU_SetDivision(int32_t division);
|
||||
void MPU_SetVolume(int32_t volume);
|
||||
int32_t MPU_GetVolume(void);
|
||||
|
||||
void MPU_BeginPlayback( void );
|
||||
void MPU_Pause(void);
|
||||
void MPU_Unpause(void);
|
||||
|
||||
#endif
|
|
@ -1,125 +0,0 @@
|
|||
//-------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (C) 2016 EDuke32 developers and contributors
|
||||
|
||||
This file is part of EDuke32.
|
||||
|
||||
EDuke32 is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License version 2
|
||||
as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
// This object is shared by all Build games with MIDI playback!
|
||||
|
||||
#include "compat.h"
|
||||
#include "music.h"
|
||||
#include "midi.h"
|
||||
#include "mpu401.h"
|
||||
|
||||
int32_t MUSIC_SoundDevice = -1;
|
||||
int32_t MUSIC_ErrorCode = MUSIC_Ok;
|
||||
|
||||
static midifuncs MUSIC_MidiFunctions;
|
||||
|
||||
int32_t MUSIC_InitMidi(int32_t card, midifuncs *Funcs, int32_t Address);
|
||||
|
||||
#define MUSIC_SetErrorCode(status) MUSIC_ErrorCode = (status);
|
||||
|
||||
const char *MUSIC_ErrorString(int32_t ErrorNumber)
|
||||
{
|
||||
const char *ErrorString;
|
||||
|
||||
switch (ErrorNumber)
|
||||
{
|
||||
case MUSIC_Warning:
|
||||
case MUSIC_Error: ErrorString = MUSIC_ErrorString(MUSIC_ErrorCode); break;
|
||||
case MUSIC_Ok: ErrorString = "Music ok."; break;
|
||||
case MUSIC_MidiError: ErrorString = "Error playing MIDI file."; break;
|
||||
default: ErrorString = "Unknown Music error code."; break;
|
||||
}
|
||||
|
||||
return ErrorString;
|
||||
}
|
||||
|
||||
|
||||
int32_t MUSIC_Init(int32_t SoundCard, int32_t Address)
|
||||
{
|
||||
MUSIC_SoundDevice = SoundCard;
|
||||
|
||||
return MUSIC_InitMidi(SoundCard, &MUSIC_MidiFunctions, Address);
|
||||
}
|
||||
|
||||
|
||||
int32_t MUSIC_Shutdown(void)
|
||||
{
|
||||
MIDI_StopSong();
|
||||
|
||||
return MUSIC_Ok;
|
||||
}
|
||||
|
||||
|
||||
void MUSIC_SetVolume(int32_t volume)
|
||||
{
|
||||
if (MUSIC_SoundDevice != -1)
|
||||
MIDI_SetVolume(min(max(0, volume), 255));
|
||||
}
|
||||
|
||||
|
||||
int32_t MUSIC_GetVolume(void) { return MUSIC_SoundDevice == -1 ? 0 : MIDI_GetVolume(); }
|
||||
void MUSIC_SetLoopFlag(int32_t loopflag) { MIDI_SetLoopFlag(loopflag); }
|
||||
void MUSIC_Continue(void) { MIDI_ContinueSong(); }
|
||||
void MUSIC_Pause(void) { MIDI_PauseSong(); }
|
||||
|
||||
int32_t MUSIC_StopSong(void)
|
||||
{
|
||||
MIDI_StopSong();
|
||||
MUSIC_SetErrorCode(MUSIC_Ok);
|
||||
return MUSIC_Ok;
|
||||
}
|
||||
|
||||
|
||||
int32_t MUSIC_PlaySong(char *song, int32_t songsize, int32_t loopflag)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(songsize);
|
||||
|
||||
MUSIC_SetErrorCode(MUSIC_Ok)
|
||||
|
||||
if (MIDI_PlaySong(song, loopflag) != MIDI_Ok)
|
||||
{
|
||||
MUSIC_SetErrorCode(MUSIC_MidiError);
|
||||
return MUSIC_Warning;
|
||||
}
|
||||
|
||||
return MUSIC_Ok;
|
||||
}
|
||||
|
||||
|
||||
int32_t MUSIC_InitMidi(int32_t card, midifuncs *Funcs, int32_t Address)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(card);
|
||||
UNREFERENCED_PARAMETER(Address);
|
||||
Funcs->NoteOff = MPU_NoteOff;
|
||||
Funcs->NoteOn = MPU_NoteOn;
|
||||
Funcs->PolyAftertouch = MPU_PolyAftertouch;
|
||||
Funcs->ControlChange = MPU_ControlChange;
|
||||
Funcs->ProgramChange = MPU_ProgramChange;
|
||||
Funcs->ChannelAftertouch = MPU_ChannelAftertouch;
|
||||
Funcs->PitchBend = MPU_PitchBend;
|
||||
|
||||
MIDI_SetMidiFuncs(Funcs);
|
||||
|
||||
return MIDI_Ok;
|
||||
}
|
||||
|
||||
void MUSIC_Update(void) { MIDI_UpdateMusic(); }
|
|
@ -1,483 +0,0 @@
|
|||
//-------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (C) 2010 EDuke32 developers and contributors
|
||||
|
||||
This file is part of EDuke32.
|
||||
|
||||
EDuke32 is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License version 2
|
||||
as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* A reimplementation of Jim Dose's FX_MAN routines, using SDL_mixer 1.2.
|
||||
* Whee. FX_MAN is also known as the "Apogee Sound System", or "ASS" for
|
||||
* short. How strangely appropriate that seems.
|
||||
*/
|
||||
|
||||
// This object is shared by all Build games with MIDI playback!
|
||||
|
||||
#define NEED_SDL_MIXER
|
||||
|
||||
#include "compat.h"
|
||||
|
||||
#include "duke3d.h"
|
||||
#include "cache1d.h"
|
||||
|
||||
#include "sdlayer.h"
|
||||
#include "music.h"
|
||||
|
||||
#include "vfs.h"
|
||||
|
||||
#if !defined _WIN32 && !defined(GEKKO)
|
||||
//# define FORK_EXEC_MIDI 1
|
||||
#endif
|
||||
|
||||
#if defined FORK_EXEC_MIDI // fork/exec based external midi player
|
||||
#include <signal.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/wait.h>
|
||||
static char **external_midi_argv;
|
||||
static pid_t external_midi_pid=-1;
|
||||
static int8_t external_midi_restart=0;
|
||||
#endif
|
||||
|
||||
#ifdef __ANDROID__ //TODO fix
|
||||
static char const *external_midi_tempfn = APPBASENAME "-music.mid";
|
||||
#else
|
||||
static char const *external_midi_tempfn = "/tmp/" APPBASENAME "-music.mid";
|
||||
#endif
|
||||
|
||||
static int32_t external_midi = 0;
|
||||
|
||||
int32_t MUSIC_ErrorCode = MUSIC_Ok;
|
||||
|
||||
static char warningMessage[80];
|
||||
static char errorMessage[80];
|
||||
|
||||
static int32_t music_initialized = 0;
|
||||
static int32_t music_context = 0;
|
||||
static int32_t music_loopflag = MUSIC_PlayOnce;
|
||||
static Mix_Music *music_musicchunk = NULL;
|
||||
|
||||
static void setErrorMessage(const char *msg)
|
||||
{
|
||||
Bstrncpyz(errorMessage, msg, sizeof(errorMessage));
|
||||
}
|
||||
|
||||
// The music functions...
|
||||
|
||||
const char *MUSIC_ErrorString(int32_t ErrorNumber)
|
||||
{
|
||||
switch (ErrorNumber)
|
||||
{
|
||||
case MUSIC_Warning:
|
||||
return warningMessage;
|
||||
|
||||
case MUSIC_Error:
|
||||
return errorMessage;
|
||||
|
||||
case MUSIC_Ok:
|
||||
return "OK; no error.";
|
||||
|
||||
case MUSIC_MidiError:
|
||||
return "MIDI error.";
|
||||
|
||||
default:
|
||||
return "Unknown error.";
|
||||
} // switch
|
||||
|
||||
return NULL;
|
||||
} // MUSIC_ErrorString
|
||||
|
||||
int32_t MUSIC_Init(int32_t SoundCard, int32_t Address)
|
||||
{
|
||||
#ifdef __ANDROID__
|
||||
music_initialized = 1;
|
||||
return MUSIC_Ok;
|
||||
#endif
|
||||
// Use an external MIDI player if the user has specified to do so
|
||||
char *command = getenv("EDUKE32_MUSIC_CMD");
|
||||
const SDL_version *linked = Mix_Linked_Version();
|
||||
|
||||
UNREFERENCED_PARAMETER(SoundCard);
|
||||
UNREFERENCED_PARAMETER(Address);
|
||||
|
||||
if (music_initialized)
|
||||
{
|
||||
setErrorMessage("Music system is already initialized.");
|
||||
return MUSIC_Error;
|
||||
} // if
|
||||
|
||||
if (SDL_VERSIONNUM(linked->major,linked->minor,linked->patch) < MIX_REQUIREDVERSION)
|
||||
{
|
||||
// reject running with SDL_Mixer versions older than what is stated in sdl_inc.h
|
||||
initprintf("You need at least v%d.%d.%d of SDL_mixer for music\n",SDL_MIXER_MIN_X,SDL_MIXER_MIN_Y,SDL_MIXER_MIN_Z);
|
||||
return MUSIC_Error;
|
||||
}
|
||||
|
||||
external_midi = (command != NULL && command[0] != 0);
|
||||
|
||||
if (external_midi)
|
||||
{
|
||||
#if defined FORK_EXEC_MIDI
|
||||
int32_t ws=1, numargs=0, pagesize=sysconf(_SC_PAGE_SIZE);
|
||||
char *c, *cmd;
|
||||
size_t sz;
|
||||
#endif
|
||||
|
||||
initprintf("Setting music command to \"%s\".\n", command);
|
||||
|
||||
#if !defined FORK_EXEC_MIDI
|
||||
if (Mix_SetMusicCMD(command)==-1)
|
||||
{
|
||||
perror("Mix_SetMusicCMD");
|
||||
goto fallback;
|
||||
}
|
||||
#else
|
||||
|
||||
if (pagesize==-1)
|
||||
goto fallback;
|
||||
|
||||
for (c=command; *c; c++)
|
||||
{
|
||||
if (isspace(*c))
|
||||
ws = 1;
|
||||
else if (ws)
|
||||
{
|
||||
ws = 0;
|
||||
numargs++;
|
||||
}
|
||||
}
|
||||
|
||||
if (numargs==0)
|
||||
goto fallback;
|
||||
|
||||
sz = (numargs+2)*sizeof(char *) + (c-command+1);
|
||||
sz = ((sz+pagesize-1)/pagesize)*pagesize;
|
||||
#if defined(__APPLE__) || defined(__ANDROID__)
|
||||
external_midi_argv = Xcalloc(1,sz+pagesize);
|
||||
external_midi_argv = (char **)((intptr_t)external_midi_argv + (pagesize-(((intptr_t)external_midi_argv)&(pagesize-1))));
|
||||
#else
|
||||
if (posix_memalign((void **)&external_midi_argv, pagesize, sz))
|
||||
goto fallback;
|
||||
#endif
|
||||
cmd = (char *)external_midi_argv + (numargs+2)*sizeof(char *);
|
||||
Bmemcpy(cmd, command, c-command+1);
|
||||
|
||||
ws = 1;
|
||||
numargs = 0;
|
||||
for (c=cmd; *c; c++)
|
||||
{
|
||||
if (isspace(*c))
|
||||
{
|
||||
ws = 1;
|
||||
*c = 0;
|
||||
}
|
||||
else if (ws)
|
||||
{
|
||||
ws = 0;
|
||||
external_midi_argv[numargs++] = c;
|
||||
}
|
||||
}
|
||||
external_midi_argv[numargs] = external_midi_tempfn;
|
||||
external_midi_argv[numargs+1] = NULL;
|
||||
|
||||
if (mprotect(external_midi_argv, sz, PROT_READ)==-1) // make argv and command string read-only
|
||||
{
|
||||
perror("MUSIC_Init: mprotect");
|
||||
goto fallback;
|
||||
}
|
||||
# if 0
|
||||
{
|
||||
int i;
|
||||
initprintf("----Music argv:\n");
|
||||
for (i=0; i<numargs+1; i++)
|
||||
initprintf(" %s\n", external_midi_argv[i]);
|
||||
initprintf("----\n");
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
music_initialized = 1;
|
||||
return MUSIC_Ok;
|
||||
|
||||
fallback:
|
||||
initprintf("Error setting music command, falling back to timidity.\n");
|
||||
}
|
||||
|
||||
{
|
||||
static const char *s[] = { "/etc/timidity.cfg", "/etc/timidity/timidity.cfg", "/etc/timidity/freepats.cfg" };
|
||||
buildvfs_FILE fp;
|
||||
int32_t i;
|
||||
|
||||
for (i = ARRAY_SIZE(s)-1; i>=0; i--)
|
||||
{
|
||||
fp = buildvfs_fopen_read(s[i]);
|
||||
if (fp == NULL)
|
||||
{
|
||||
if (i == 0)
|
||||
{
|
||||
initprintf("Error: couldn't open any of the following files:\n");
|
||||
for (i = ARRAY_SIZE(s)-1; i>=0; i--)
|
||||
initprintf("%s\n",s[i]);
|
||||
return MUSIC_Error;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else break;
|
||||
}
|
||||
buildvfs_fclose(fp);
|
||||
}
|
||||
|
||||
music_initialized = 1;
|
||||
return MUSIC_Ok;
|
||||
} // MUSIC_Init
|
||||
|
||||
|
||||
int32_t MUSIC_Shutdown(void)
|
||||
{
|
||||
// TODO - make sure this is being called from the menu -- SA
|
||||
#if !defined FORK_EXEC_MIDI
|
||||
if (external_midi)
|
||||
Mix_SetMusicCMD(NULL);
|
||||
#endif
|
||||
|
||||
MUSIC_StopSong();
|
||||
music_context = 0;
|
||||
music_initialized = 0;
|
||||
music_loopflag = MUSIC_PlayOnce;
|
||||
|
||||
return MUSIC_Ok;
|
||||
} // MUSIC_Shutdown
|
||||
|
||||
|
||||
void MUSIC_SetMaxFMMidiChannel(int32_t channel)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(channel);
|
||||
} // MUSIC_SetMaxFMMidiChannel
|
||||
|
||||
|
||||
void MUSIC_SetVolume(int32_t volume)
|
||||
{
|
||||
volume = max(0, volume);
|
||||
volume = min(volume, 255);
|
||||
|
||||
Mix_VolumeMusic(volume >> 1); // convert 0-255 to 0-128.
|
||||
} // MUSIC_SetVolume
|
||||
|
||||
|
||||
int32_t MUSIC_GetVolume(void)
|
||||
{
|
||||
return (Mix_VolumeMusic(-1) << 1); // convert 0-128 to 0-255.
|
||||
} // MUSIC_GetVolume
|
||||
|
||||
|
||||
void MUSIC_SetLoopFlag(int32_t loopflag)
|
||||
{
|
||||
music_loopflag = loopflag;
|
||||
} // MUSIC_SetLoopFlag
|
||||
|
||||
|
||||
void MUSIC_Continue(void)
|
||||
{
|
||||
if (Mix_PausedMusic())
|
||||
Mix_ResumeMusic();
|
||||
} // MUSIC_Continue
|
||||
|
||||
|
||||
void MUSIC_Pause(void)
|
||||
{
|
||||
Mix_PauseMusic();
|
||||
} // MUSIC_Pause
|
||||
|
||||
int32_t MUSIC_StopSong(void)
|
||||
{
|
||||
#if defined FORK_EXEC_MIDI
|
||||
if (external_midi)
|
||||
{
|
||||
if (external_midi_pid > 0)
|
||||
{
|
||||
int32_t ret;
|
||||
struct timespec ts;
|
||||
|
||||
external_midi_restart = 0; // make SIGCHLD handler a no-op
|
||||
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 5000000; // sleep 5ms at most
|
||||
|
||||
kill(external_midi_pid, SIGTERM);
|
||||
nanosleep(&ts, NULL);
|
||||
ret = waitpid(external_midi_pid, NULL, WNOHANG|WUNTRACED);
|
||||
// printf("(%d)", ret);
|
||||
|
||||
if (ret != external_midi_pid)
|
||||
{
|
||||
if (ret==-1)
|
||||
perror("waitpid");
|
||||
else
|
||||
{
|
||||
// we tried to be nice, but no...
|
||||
kill(external_midi_pid, SIGKILL);
|
||||
initprintf("%s: wait for SIGTERM timed out.\n", __func__);
|
||||
if (waitpid(external_midi_pid, NULL, WUNTRACED)==-1)
|
||||
perror("waitpid (2)");
|
||||
}
|
||||
}
|
||||
|
||||
external_midi_pid = -1;
|
||||
}
|
||||
|
||||
return MUSIC_Ok;
|
||||
}
|
||||
#endif
|
||||
|
||||
//if (!fx_initialized)
|
||||
if (!Mix_QuerySpec(NULL, NULL, NULL))
|
||||
{
|
||||
setErrorMessage("Need FX system initialized, too. Sorry.");
|
||||
return MUSIC_Error;
|
||||
} // if
|
||||
|
||||
if ((Mix_PlayingMusic()) || (Mix_PausedMusic()))
|
||||
Mix_HaltMusic();
|
||||
|
||||
if (music_musicchunk)
|
||||
Mix_FreeMusic(music_musicchunk);
|
||||
|
||||
music_musicchunk = NULL;
|
||||
|
||||
return MUSIC_Ok;
|
||||
} // MUSIC_StopSong
|
||||
|
||||
#if defined FORK_EXEC_MIDI
|
||||
static int32_t playmusic()
|
||||
{
|
||||
pid_t pid = vfork();
|
||||
|
||||
if (pid==-1) // error
|
||||
{
|
||||
initprintf("%s: vfork: %s\n", __func__, strerror(errno));
|
||||
return MUSIC_Error;
|
||||
}
|
||||
else if (pid==0) // child
|
||||
{
|
||||
// exec without PATH lookup
|
||||
if (execv(external_midi_argv[0], external_midi_argv) < 0)
|
||||
{
|
||||
perror("execv");
|
||||
_exit(1);
|
||||
}
|
||||
}
|
||||
else // parent
|
||||
{
|
||||
external_midi_pid = pid;
|
||||
}
|
||||
|
||||
return MUSIC_Ok;
|
||||
}
|
||||
|
||||
static void sigchld_handler(int signo)
|
||||
{
|
||||
if (signo==SIGCHLD && external_midi_restart)
|
||||
{
|
||||
int status;
|
||||
|
||||
if (external_midi_pid > 0)
|
||||
{
|
||||
if (waitpid(external_midi_pid, &status, WUNTRACED)==-1)
|
||||
perror("waitpid (3)");
|
||||
|
||||
if (WIFEXITED(status) && WEXITSTATUS(status)==0)
|
||||
{
|
||||
// loop ...
|
||||
playmusic();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Duke3D-specific. --ryan.
|
||||
// void MUSIC_PlayMusic(char *_filename)
|
||||
int32_t MUSIC_PlaySong(char *song, int32_t songsize, int32_t loopflag)
|
||||
{
|
||||
if (external_midi)
|
||||
{
|
||||
buildvfs_FILE fp;
|
||||
|
||||
#if defined FORK_EXEC_MIDI
|
||||
static int32_t sigchld_handler_set = 0;
|
||||
|
||||
if (!sigchld_handler_set)
|
||||
{
|
||||
struct sigaction sa;
|
||||
sa.sa_handler=sigchld_handler;
|
||||
sa.sa_flags=0;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
|
||||
if (sigaction(SIGCHLD, &sa, NULL)==-1)
|
||||
initprintf("%s: sigaction: %s\n", __func__, strerror(errno));
|
||||
|
||||
sigchld_handler_set = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
fp = buildvfs_fopen_write(external_midi_tempfn);
|
||||
if (fp)
|
||||
{
|
||||
buildvfs_fwrite(song, 1, songsize, fp);
|
||||
buildvfs_fclose(fp);
|
||||
|
||||
#if defined FORK_EXEC_MIDI
|
||||
external_midi_restart = loopflag;
|
||||
int32_t retval = playmusic();
|
||||
if (retval != MUSIC_Ok)
|
||||
return retval;
|
||||
#else
|
||||
music_musicchunk = Mix_LoadMUS(external_midi_tempfn);
|
||||
if (!music_musicchunk)
|
||||
{
|
||||
initprintf("Mix_LoadMUS: %s\n", Mix_GetError());
|
||||
return MUSIC_Error;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
initprintf("%s: fopen: %s\n", __func__, strerror(errno));
|
||||
return MUSIC_Error;
|
||||
}
|
||||
}
|
||||
else
|
||||
music_musicchunk = Mix_LoadMUS_RW(SDL_RWFromMem(song, songsize)
|
||||
#if (SDL_MAJOR_VERSION > 1)
|
||||
, SDL_FALSE
|
||||
#endif
|
||||
);
|
||||
|
||||
if (music_musicchunk == NULL)
|
||||
return MUSIC_Error;
|
||||
|
||||
if (Mix_PlayMusic(music_musicchunk, (loopflag == MUSIC_LoopSong)?-1:0) == -1)
|
||||
{
|
||||
initprintf("Mix_PlayMusic: %s\n", Mix_GetError());
|
||||
return MUSIC_Error;
|
||||
}
|
||||
|
||||
return MUSIC_Ok;
|
||||
}
|
||||
|
||||
|
||||
void MUSIC_Update(void)
|
||||
{}
|
|
@ -88,7 +88,3 @@ $(mact_obj)/control.$o: $(mact_src)/control.cpp $(mact_inc)/control.h $(mact_inc
|
|||
$(mact_obj)/keyboard.$o: $(mact_src)/keyboard.cpp $(mact_inc)/keyboard.h $(engine_inc)/compat.h $(engine_inc)/baselayer.h
|
||||
$(mact_obj)/joystick.$o: $(mact_src)/joystick.cpp $(mact_inc)/joystick.h $(engine_inc)/baselayer.h
|
||||
$(mact_obj)/scriplib.$o: $(mact_src)/scriplib.cpp $(mact_inc)/scriplib.h $(mact_src)/_scrplib.h $(engine_inc)/compat.h
|
||||
|
||||
$(rr_obj)/midi.$o: $(rr_src)/midi.cpp $(rr_src)/_midi.h $(rr_src)/midi.h $(audiolib_inc)/music.h
|
||||
$(rr_obj)/mpu401.$o: $(rr_src)/mpu401.cpp $(rr_src)/mpu401.h $(audiolib_inc)/music.h
|
||||
$(rr_obj)/music.$o: $(rr_src)/music.cpp $(rr_src)/midi.h $(rr_src)/mpu401.h $(audiolib_inc)/music.h
|
||||
|
|
|
@ -1,147 +0,0 @@
|
|||
//-------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (C) 2016 EDuke32 developers and contributors
|
||||
|
||||
This file is part of EDuke32.
|
||||
|
||||
EDuke32 is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License version 2
|
||||
as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
#ifndef ___MIDI_H
|
||||
#define ___MIDI_H
|
||||
#include "compat.h"
|
||||
|
||||
#define RELATIVE_BEAT( measure, beat, tick ) \
|
||||
( ( tick ) + ( ( beat ) << 9 ) + ( ( measure ) << 16 ) )
|
||||
|
||||
//Bobby Prince thinks this may be 100
|
||||
//#define GENMIDI_DefaultVolume 100
|
||||
#define GENMIDI_DefaultVolume 90
|
||||
|
||||
#define MAX_FORMAT 1
|
||||
|
||||
#define NUM_MIDI_CHANNELS 16
|
||||
|
||||
#define TIME_PRECISION 16
|
||||
|
||||
#define MIDI_HEADER_SIGNATURE 0x6468544d // "MThd"
|
||||
#define MIDI_TRACK_SIGNATURE 0x6b72544d // "MTrk"
|
||||
|
||||
#define MIDI_VOLUME 7
|
||||
#define MIDI_PAN 10
|
||||
#define MIDI_DETUNE 94
|
||||
#define MIDI_RHYTHM_CHANNEL 9
|
||||
#define MIDI_RPN_MSB 100
|
||||
#define MIDI_RPN_LSB 101
|
||||
#define MIDI_DATAENTRY_MSB 6
|
||||
#define MIDI_DATAENTRY_LSB 38
|
||||
#define MIDI_PITCHBEND_MSB 0
|
||||
#define MIDI_PITCHBEND_LSB 0
|
||||
#define MIDI_RUNNING_STATUS 0x80
|
||||
#define MIDI_NOTE_OFF 0x8
|
||||
#define MIDI_NOTE_ON 0x9
|
||||
#define MIDI_POLY_AFTER_TCH 0xA
|
||||
#define MIDI_CONTROL_CHANGE 0xB
|
||||
#define MIDI_PROGRAM_CHANGE 0xC
|
||||
#define MIDI_AFTER_TOUCH 0xD
|
||||
#define MIDI_PITCH_BEND 0xE
|
||||
#define MIDI_SPECIAL 0xF
|
||||
#define MIDI_SYSEX 0xF0
|
||||
#define MIDI_SYSEX_CONTINUE 0xF7
|
||||
#define MIDI_META_EVENT 0xFF
|
||||
#define MIDI_END_OF_TRACK 0x2F
|
||||
#define MIDI_TEMPO_CHANGE 0x51
|
||||
#define MIDI_TIME_SIGNATURE 0x58
|
||||
#define MIDI_RESET_ALL_CONTROLLERS 0x79
|
||||
#define MIDI_ALL_NOTES_OFF 0x7b
|
||||
#define MIDI_MONO_MODE_ON 0x7E
|
||||
#define MIDI_SYSTEM_RESET 0xFF
|
||||
|
||||
#define GET_NEXT_EVENT( track, data ) do { \
|
||||
( data ) = *( track )->pos; \
|
||||
( track )->pos += 1; \
|
||||
} while (0)
|
||||
|
||||
#define GET_MIDI_CHANNEL( event ) ( ( event ) & 0xf )
|
||||
#define GET_MIDI_COMMAND( event ) ( ( event ) >> 4 )
|
||||
|
||||
#define EMIDI_INFINITE -1
|
||||
#define EMIDI_END_LOOP_VALUE 127
|
||||
#define EMIDI_ALL_CARDS 127
|
||||
#define EMIDI_INCLUDE_TRACK 110
|
||||
#define EMIDI_EXCLUDE_TRACK 111
|
||||
#define EMIDI_PROGRAM_CHANGE 112
|
||||
#define EMIDI_VOLUME_CHANGE 113
|
||||
#define EMIDI_CONTEXT_START 114
|
||||
#define EMIDI_CONTEXT_END 115
|
||||
#define EMIDI_LOOP_START 116
|
||||
#define EMIDI_LOOP_END 117
|
||||
#define EMIDI_SONG_LOOP_START 118
|
||||
#define EMIDI_SONG_LOOP_END 119
|
||||
|
||||
#define EMIDI_GeneralMIDI 0
|
||||
|
||||
#define EMIDI_AffectsCurrentCard(c, type) (((c) == EMIDI_ALL_CARDS) || ((c) == (type)))
|
||||
#define EMIDI_NUM_CONTEXTS 7
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *pos;
|
||||
char *loopstart;
|
||||
int16_t loopcount;
|
||||
int16_t RunningStatus;
|
||||
unsigned time;
|
||||
int32_t FPSecondsPerTick;
|
||||
int16_t tick;
|
||||
int16_t beat;
|
||||
int16_t measure;
|
||||
int16_t BeatsPerMeasure;
|
||||
int16_t TicksPerBeat;
|
||||
int16_t TimeBase;
|
||||
int32_t delay;
|
||||
int16_t active;
|
||||
} songcontext;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *start;
|
||||
char *pos;
|
||||
|
||||
int32_t delay;
|
||||
int16_t active;
|
||||
int16_t RunningStatus;
|
||||
|
||||
int16_t currentcontext;
|
||||
songcontext context[EMIDI_NUM_CONTEXTS];
|
||||
|
||||
char EMIDI_IncludeTrack;
|
||||
char EMIDI_ProgramChange;
|
||||
char EMIDI_VolumeChange;
|
||||
} track;
|
||||
|
||||
static int32_t _MIDI_ReadNumber(void *from, size_t size);
|
||||
static int32_t _MIDI_ReadDelta(track *ptr);
|
||||
static void _MIDI_ResetTracks(void);
|
||||
static void _MIDI_AdvanceTick(void);
|
||||
static void _MIDI_MetaEvent(track *Track);
|
||||
static void _MIDI_SysEx(track *Track);
|
||||
static int32_t _MIDI_InterpretControllerInfo(track *Track, int32_t TimeSet, int32_t channel, int32_t c1, int32_t c2);
|
||||
static int32_t _MIDI_SendControlChange(int32_t channel, int32_t c1, int32_t c2);
|
||||
static void _MIDI_SetChannelVolume(int32_t channel, int32_t volume);
|
||||
static void _MIDI_SendChannelVolumes(void);
|
||||
static void _MIDI_InitEMIDI(void);
|
||||
|
||||
#endif
|
|
@ -1,952 +0,0 @@
|
|||
//-------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (C) 2010 EDuke32 developers and contributors
|
||||
|
||||
This file is part of EDuke32.
|
||||
|
||||
EDuke32 is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License version 2
|
||||
as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/**********************************************************************
|
||||
module: MIDI.C
|
||||
|
||||
author: James R. Dose
|
||||
date: May 25, 1994
|
||||
|
||||
Midi song file playback routines.
|
||||
|
||||
(c) Copyright 1994 James R. Dose. All Rights Reserved.
|
||||
**********************************************************************/
|
||||
|
||||
// This object is shared by all Build games with MIDI playback!
|
||||
|
||||
#include "compat.h"
|
||||
#include "music.h"
|
||||
#include "_midi.h"
|
||||
#include "midi.h"
|
||||
#include "mpu401.h"
|
||||
#include "compat.h"
|
||||
#include "pragmas.h"
|
||||
|
||||
#include "windows_inc.h"
|
||||
|
||||
extern int32_t MUSIC_SoundDevice;
|
||||
|
||||
static const int32_t _MIDI_CommandLengths[ NUM_MIDI_CHANNELS ] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 1, 1, 2, 0
|
||||
};
|
||||
|
||||
static track *_MIDI_TrackPtr = NULL;
|
||||
static int32_t _MIDI_TrackMemSize;
|
||||
static int32_t _MIDI_NumTracks;
|
||||
|
||||
static int32_t _MIDI_SongActive = FALSE;
|
||||
static int32_t _MIDI_SongLoaded = FALSE;
|
||||
static int32_t _MIDI_Loop = FALSE;
|
||||
|
||||
static int32_t _MIDI_Division;
|
||||
static int32_t _MIDI_Tick = 0;
|
||||
static int32_t _MIDI_Beat = 1;
|
||||
static int32_t _MIDI_Measure = 1;
|
||||
static uint32_t _MIDI_Time;
|
||||
static int32_t _MIDI_BeatsPerMeasure;
|
||||
static int32_t _MIDI_TicksPerBeat;
|
||||
static int32_t _MIDI_TimeBase;
|
||||
static int32_t _MIDI_FPSecondsPerTick;
|
||||
static uint32_t _MIDI_TotalTime;
|
||||
static int32_t _MIDI_TotalTicks;
|
||||
static int32_t _MIDI_TotalBeats;
|
||||
static int32_t _MIDI_TotalMeasures;
|
||||
|
||||
uint32_t _MIDI_PositionInTicks;
|
||||
uint32_t _MIDI_GlobalPositionInTicks;
|
||||
|
||||
static int32_t _MIDI_Context;
|
||||
|
||||
static int32_t _MIDI_ActiveTracks;
|
||||
static int32_t _MIDI_TotalVolume = MIDI_MaxVolume;
|
||||
|
||||
static int32_t _MIDI_ChannelVolume[ NUM_MIDI_CHANNELS ];
|
||||
|
||||
static midifuncs *_MIDI_Funcs = NULL;
|
||||
|
||||
static int32_t Reset = FALSE;
|
||||
|
||||
int32_t MIDI_Tempo = 120;
|
||||
|
||||
static int32_t _MIDI_ReadNumber(void *from, size_t size)
|
||||
{
|
||||
if (size > 4)
|
||||
size = 4;
|
||||
|
||||
char *FromPtr = (char *)from;
|
||||
int32_t value = 0;
|
||||
|
||||
while (size--)
|
||||
{
|
||||
value <<= 8;
|
||||
value += *FromPtr++;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static int32_t _MIDI_ReadDelta(track *ptr)
|
||||
{
|
||||
int32_t value;
|
||||
|
||||
GET_NEXT_EVENT(ptr, value);
|
||||
|
||||
if (value & 0x80)
|
||||
{
|
||||
value &= 0x7f;
|
||||
char c;
|
||||
|
||||
do
|
||||
{
|
||||
GET_NEXT_EVENT(ptr, c);
|
||||
value = (value << 7) + (c & 0x7f);
|
||||
}
|
||||
while (c & 0x80);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static void _MIDI_ResetTracks(void)
|
||||
{
|
||||
_MIDI_Tick = 0;
|
||||
_MIDI_Beat = 1;
|
||||
_MIDI_Measure = 1;
|
||||
_MIDI_Time = 0;
|
||||
_MIDI_BeatsPerMeasure = 4;
|
||||
_MIDI_TicksPerBeat = _MIDI_Division;
|
||||
_MIDI_TimeBase = 4;
|
||||
_MIDI_PositionInTicks = 0;
|
||||
_MIDI_ActiveTracks = 0;
|
||||
_MIDI_Context = 0;
|
||||
|
||||
track *ptr = _MIDI_TrackPtr;
|
||||
for (bssize_t i = 0; i < _MIDI_NumTracks; ++i)
|
||||
{
|
||||
ptr->pos = ptr->start;
|
||||
ptr->delay = _MIDI_ReadDelta(ptr);
|
||||
ptr->active = ptr->EMIDI_IncludeTrack;
|
||||
ptr->RunningStatus = 0;
|
||||
ptr->currentcontext = 0;
|
||||
ptr->context[ 0 ].loopstart = ptr->start;
|
||||
ptr->context[ 0 ].loopcount = 0;
|
||||
|
||||
if (ptr->active)
|
||||
_MIDI_ActiveTracks++;
|
||||
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
static void _MIDI_AdvanceTick(void)
|
||||
{
|
||||
_MIDI_PositionInTicks++;
|
||||
_MIDI_Time += _MIDI_FPSecondsPerTick;
|
||||
|
||||
_MIDI_Tick++;
|
||||
while (_MIDI_Tick > _MIDI_TicksPerBeat)
|
||||
{
|
||||
_MIDI_Tick -= _MIDI_TicksPerBeat;
|
||||
_MIDI_Beat++;
|
||||
}
|
||||
while (_MIDI_Beat > _MIDI_BeatsPerMeasure)
|
||||
{
|
||||
_MIDI_Beat -= _MIDI_BeatsPerMeasure;
|
||||
_MIDI_Measure++;
|
||||
}
|
||||
}
|
||||
|
||||
static void _MIDI_SysEx(track *Track)
|
||||
{
|
||||
int32_t length = _MIDI_ReadDelta(Track);
|
||||
Track->pos += length;
|
||||
}
|
||||
|
||||
|
||||
static void _MIDI_MetaEvent(track *Track)
|
||||
{
|
||||
int32_t command;
|
||||
int32_t length;
|
||||
|
||||
GET_NEXT_EVENT(Track, command);
|
||||
GET_NEXT_EVENT(Track, length);
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case MIDI_END_OF_TRACK:
|
||||
Track->active = FALSE;
|
||||
|
||||
_MIDI_ActiveTracks--;
|
||||
break;
|
||||
|
||||
case MIDI_TEMPO_CHANGE:
|
||||
{
|
||||
int32_t tempo = tabledivide32_noinline(60000000L, _MIDI_ReadNumber(Track->pos, 3));
|
||||
MIDI_SetTempo(tempo);
|
||||
break;
|
||||
}
|
||||
|
||||
case MIDI_TIME_SIGNATURE:
|
||||
{
|
||||
if ((_MIDI_Tick > 0) || (_MIDI_Beat > 1))
|
||||
_MIDI_Measure++;
|
||||
|
||||
_MIDI_Tick = 0;
|
||||
_MIDI_Beat = 1;
|
||||
_MIDI_TimeBase = 1;
|
||||
_MIDI_BeatsPerMeasure = (int32_t)*Track->pos;
|
||||
int32_t denominator = (int32_t) * (Track->pos + 1);
|
||||
|
||||
while (denominator > 0)
|
||||
{
|
||||
_MIDI_TimeBase += _MIDI_TimeBase;
|
||||
denominator--;
|
||||
}
|
||||
|
||||
_MIDI_TicksPerBeat = tabledivide32_noinline(_MIDI_Division * 4, _MIDI_TimeBase);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Track->pos += length;
|
||||
}
|
||||
|
||||
static int32_t _MIDI_InterpretControllerInfo(track *Track, int32_t TimeSet, int32_t channel, int32_t c1, int32_t c2)
|
||||
{
|
||||
track *trackptr;
|
||||
int32_t tracknum;
|
||||
int32_t loopcount;
|
||||
|
||||
switch (c1)
|
||||
{
|
||||
case MIDI_MONO_MODE_ON :
|
||||
Track->pos++;
|
||||
break;
|
||||
|
||||
case MIDI_VOLUME :
|
||||
if (!Track->EMIDI_VolumeChange)
|
||||
_MIDI_SetChannelVolume(channel, c2);
|
||||
break;
|
||||
|
||||
case EMIDI_INCLUDE_TRACK :
|
||||
case EMIDI_EXCLUDE_TRACK :
|
||||
break;
|
||||
|
||||
case EMIDI_PROGRAM_CHANGE :
|
||||
if (Track->EMIDI_ProgramChange)
|
||||
_MIDI_Funcs->ProgramChange(channel, c2 & 0x7f);
|
||||
break;
|
||||
|
||||
case EMIDI_VOLUME_CHANGE :
|
||||
if (Track->EMIDI_VolumeChange)
|
||||
_MIDI_SetChannelVolume(channel, c2);
|
||||
break;
|
||||
|
||||
case EMIDI_CONTEXT_START :
|
||||
break;
|
||||
|
||||
case EMIDI_CONTEXT_END :
|
||||
if ((Track->currentcontext == _MIDI_Context) || (_MIDI_Context < 0) ||
|
||||
(Track->context[_MIDI_Context].pos == NULL))
|
||||
break;
|
||||
|
||||
Track->currentcontext = _MIDI_Context;
|
||||
Track->context[ 0 ].loopstart = Track->context[ _MIDI_Context ].loopstart;
|
||||
Track->context[ 0 ].loopcount = Track->context[ _MIDI_Context ].loopcount;
|
||||
Track->pos = Track->context[ _MIDI_Context ].pos;
|
||||
Track->RunningStatus = Track->context[ _MIDI_Context ].RunningStatus;
|
||||
|
||||
if (TimeSet)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
_MIDI_Time = Track->context[ _MIDI_Context ].time;
|
||||
_MIDI_FPSecondsPerTick = Track->context[ _MIDI_Context ].FPSecondsPerTick;
|
||||
_MIDI_Tick = Track->context[ _MIDI_Context ].tick;
|
||||
_MIDI_Beat = Track->context[ _MIDI_Context ].beat;
|
||||
_MIDI_Measure = Track->context[ _MIDI_Context ].measure;
|
||||
_MIDI_BeatsPerMeasure = Track->context[ _MIDI_Context ].BeatsPerMeasure;
|
||||
_MIDI_TicksPerBeat = Track->context[ _MIDI_Context ].TicksPerBeat;
|
||||
_MIDI_TimeBase = Track->context[ _MIDI_Context ].TimeBase;
|
||||
TimeSet = TRUE;
|
||||
break;
|
||||
|
||||
case EMIDI_LOOP_START :
|
||||
case EMIDI_SONG_LOOP_START :
|
||||
loopcount = (c2 == 0) ? EMIDI_INFINITE : c2;
|
||||
|
||||
if (c1 == EMIDI_SONG_LOOP_START)
|
||||
{
|
||||
trackptr = _MIDI_TrackPtr;
|
||||
tracknum = _MIDI_NumTracks;
|
||||
}
|
||||
else
|
||||
{
|
||||
trackptr = Track;
|
||||
tracknum = 1;
|
||||
}
|
||||
|
||||
while (tracknum > 0)
|
||||
{
|
||||
trackptr->context[ 0 ].loopcount = loopcount;
|
||||
trackptr->context[ 0 ].pos = trackptr->pos;
|
||||
trackptr->context[ 0 ].loopstart = trackptr->pos;
|
||||
trackptr->context[ 0 ].RunningStatus = trackptr->RunningStatus;
|
||||
trackptr->context[ 0 ].active = trackptr->active;
|
||||
trackptr->context[ 0 ].delay = trackptr->delay;
|
||||
trackptr->context[ 0 ].time = _MIDI_Time;
|
||||
trackptr->context[ 0 ].FPSecondsPerTick = _MIDI_FPSecondsPerTick;
|
||||
trackptr->context[ 0 ].tick = _MIDI_Tick;
|
||||
trackptr->context[ 0 ].beat = _MIDI_Beat;
|
||||
trackptr->context[ 0 ].measure = _MIDI_Measure;
|
||||
trackptr->context[ 0 ].BeatsPerMeasure = _MIDI_BeatsPerMeasure;
|
||||
trackptr->context[ 0 ].TicksPerBeat = _MIDI_TicksPerBeat;
|
||||
trackptr->context[ 0 ].TimeBase = _MIDI_TimeBase;
|
||||
trackptr++;
|
||||
tracknum--;
|
||||
}
|
||||
break;
|
||||
|
||||
case EMIDI_LOOP_END :
|
||||
case EMIDI_SONG_LOOP_END :
|
||||
if ((c2 != EMIDI_END_LOOP_VALUE) || (Track->context[0].loopstart == NULL) || (Track->context[0].loopcount == 0))
|
||||
break;
|
||||
|
||||
if (c1 == EMIDI_SONG_LOOP_END)
|
||||
{
|
||||
trackptr = _MIDI_TrackPtr;
|
||||
tracknum = _MIDI_NumTracks;
|
||||
_MIDI_ActiveTracks = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
trackptr = Track;
|
||||
tracknum = 1;
|
||||
_MIDI_ActiveTracks--;
|
||||
}
|
||||
|
||||
while (tracknum > 0)
|
||||
{
|
||||
if (trackptr->context[ 0 ].loopcount != EMIDI_INFINITE)
|
||||
{
|
||||
trackptr->context[ 0 ].loopcount--;
|
||||
}
|
||||
|
||||
trackptr->pos = trackptr->context[ 0 ].loopstart;
|
||||
trackptr->RunningStatus = trackptr->context[ 0 ].RunningStatus;
|
||||
trackptr->delay = trackptr->context[ 0 ].delay;
|
||||
trackptr->active = trackptr->context[ 0 ].active;
|
||||
if (trackptr->active)
|
||||
{
|
||||
_MIDI_ActiveTracks++;
|
||||
}
|
||||
|
||||
if (!TimeSet)
|
||||
{
|
||||
_MIDI_Time = trackptr->context[ 0 ].time;
|
||||
_MIDI_FPSecondsPerTick = trackptr->context[ 0 ].FPSecondsPerTick;
|
||||
_MIDI_Tick = trackptr->context[ 0 ].tick;
|
||||
_MIDI_Beat = trackptr->context[ 0 ].beat;
|
||||
_MIDI_Measure = trackptr->context[ 0 ].measure;
|
||||
_MIDI_BeatsPerMeasure = trackptr->context[ 0 ].BeatsPerMeasure;
|
||||
_MIDI_TicksPerBeat = trackptr->context[ 0 ].TicksPerBeat;
|
||||
_MIDI_TimeBase = trackptr->context[ 0 ].TimeBase;
|
||||
TimeSet = TRUE;
|
||||
}
|
||||
|
||||
trackptr++;
|
||||
tracknum--;
|
||||
}
|
||||
break;
|
||||
|
||||
default :
|
||||
if (_MIDI_Funcs->ControlChange)
|
||||
_MIDI_Funcs->ControlChange(channel, c1, c2);
|
||||
}
|
||||
|
||||
return TimeSet;
|
||||
}
|
||||
|
||||
static void _MIDI_ServiceRoutine(void)
|
||||
{
|
||||
if (!_MIDI_SongActive)
|
||||
return;
|
||||
|
||||
track *Track = _MIDI_TrackPtr;
|
||||
int32_t tracknum = 0;
|
||||
int32_t TimeSet = FALSE;
|
||||
int32_t c1 = 0;
|
||||
int32_t c2 = 0;
|
||||
|
||||
while (tracknum < _MIDI_NumTracks)
|
||||
{
|
||||
while ((Track->active) && (Track->delay == 0))
|
||||
{
|
||||
int32_t event;
|
||||
GET_NEXT_EVENT(Track, event);
|
||||
|
||||
if (GET_MIDI_COMMAND(event) == MIDI_SPECIAL)
|
||||
{
|
||||
switch (event)
|
||||
{
|
||||
case MIDI_SYSEX:
|
||||
case MIDI_SYSEX_CONTINUE: _MIDI_SysEx(Track); break;
|
||||
case MIDI_META_EVENT: _MIDI_MetaEvent(Track); break;
|
||||
}
|
||||
|
||||
if (Track->active)
|
||||
Track->delay = _MIDI_ReadDelta(Track);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (event & MIDI_RUNNING_STATUS)
|
||||
Track->RunningStatus = event;
|
||||
else
|
||||
{
|
||||
event = Track->RunningStatus;
|
||||
Track->pos--;
|
||||
}
|
||||
|
||||
int const channel = GET_MIDI_CHANNEL(event);
|
||||
int const command = GET_MIDI_COMMAND(event);
|
||||
|
||||
if (_MIDI_CommandLengths[ command ] > 0)
|
||||
{
|
||||
GET_NEXT_EVENT(Track, c1);
|
||||
if (_MIDI_CommandLengths[ command ] > 1)
|
||||
GET_NEXT_EVENT(Track, c2);
|
||||
}
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case MIDI_NOTE_OFF:
|
||||
if (_MIDI_Funcs->NoteOff)
|
||||
_MIDI_Funcs->NoteOff(channel, c1, c2);
|
||||
break;
|
||||
|
||||
case MIDI_NOTE_ON:
|
||||
if (_MIDI_Funcs->NoteOn)
|
||||
_MIDI_Funcs->NoteOn(channel, c1, c2);
|
||||
break;
|
||||
|
||||
case MIDI_POLY_AFTER_TCH:
|
||||
if (_MIDI_Funcs->PolyAftertouch)
|
||||
_MIDI_Funcs->PolyAftertouch(channel, c1, c2);
|
||||
break;
|
||||
|
||||
case MIDI_CONTROL_CHANGE:
|
||||
TimeSet = _MIDI_InterpretControllerInfo(Track, TimeSet, channel, c1, c2);
|
||||
break;
|
||||
|
||||
case MIDI_PROGRAM_CHANGE:
|
||||
if ((_MIDI_Funcs->ProgramChange) && (!Track->EMIDI_ProgramChange))
|
||||
_MIDI_Funcs->ProgramChange(channel, c1 & 0x7f);
|
||||
break;
|
||||
|
||||
case MIDI_AFTER_TOUCH:
|
||||
if (_MIDI_Funcs->ChannelAftertouch)
|
||||
_MIDI_Funcs->ChannelAftertouch(channel, c1);
|
||||
break;
|
||||
|
||||
case MIDI_PITCH_BEND:
|
||||
if (_MIDI_Funcs->PitchBend)
|
||||
_MIDI_Funcs->PitchBend(channel, c1, c2);
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
Track->delay = _MIDI_ReadDelta(Track);
|
||||
}
|
||||
|
||||
Track->delay--;
|
||||
Track++;
|
||||
tracknum++;
|
||||
|
||||
if (_MIDI_ActiveTracks == 0)
|
||||
{
|
||||
_MIDI_ResetTracks();
|
||||
if (_MIDI_Loop)
|
||||
{
|
||||
tracknum = 0;
|
||||
Track = _MIDI_TrackPtr;
|
||||
}
|
||||
else
|
||||
{
|
||||
_MIDI_SongActive = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_MIDI_AdvanceTick();
|
||||
_MIDI_GlobalPositionInTicks++;
|
||||
}
|
||||
|
||||
static int32_t _MIDI_SendControlChange(int32_t channel, int32_t c1, int32_t c2)
|
||||
{
|
||||
if (_MIDI_Funcs == NULL || _MIDI_Funcs->ControlChange == NULL)
|
||||
return MIDI_Error;
|
||||
|
||||
_MIDI_Funcs->ControlChange(channel, c1, c2);
|
||||
|
||||
return MIDI_Ok;
|
||||
}
|
||||
|
||||
int32_t MIDI_AllNotesOff(void)
|
||||
{
|
||||
for (bssize_t channel = 0; channel < NUM_MIDI_CHANNELS; channel++)
|
||||
{
|
||||
_MIDI_SendControlChange(channel, 0x40, 0);
|
||||
_MIDI_SendControlChange(channel, MIDI_ALL_NOTES_OFF, 0);
|
||||
_MIDI_SendControlChange(channel, 0x78, 0);
|
||||
}
|
||||
|
||||
return MIDI_Ok;
|
||||
}
|
||||
|
||||
static void _MIDI_SetChannelVolume(int32_t channel, int32_t volume)
|
||||
{
|
||||
_MIDI_ChannelVolume[ channel ] = volume;
|
||||
|
||||
if (_MIDI_Funcs == NULL || _MIDI_Funcs->ControlChange == NULL)
|
||||
return;
|
||||
|
||||
volume *= _MIDI_TotalVolume;
|
||||
volume = tabledivide32_noinline(volume, MIDI_MaxVolume);
|
||||
|
||||
_MIDI_Funcs->ControlChange(channel, MIDI_VOLUME, volume);
|
||||
}
|
||||
|
||||
static void _MIDI_SendChannelVolumes(void)
|
||||
{
|
||||
for (bssize_t channel = 0; channel < NUM_MIDI_CHANNELS; channel++)
|
||||
_MIDI_SetChannelVolume(channel, _MIDI_ChannelVolume[channel]);
|
||||
}
|
||||
|
||||
int32_t MIDI_Reset(void)
|
||||
{
|
||||
MIDI_AllNotesOff();
|
||||
|
||||
for (bssize_t channel = 0; channel < NUM_MIDI_CHANNELS; channel++)
|
||||
{
|
||||
_MIDI_SendControlChange(channel, MIDI_RESET_ALL_CONTROLLERS, 0);
|
||||
_MIDI_SendControlChange(channel, MIDI_RPN_MSB, MIDI_PITCHBEND_MSB);
|
||||
_MIDI_SendControlChange(channel, MIDI_RPN_LSB, MIDI_PITCHBEND_LSB);
|
||||
_MIDI_SendControlChange(channel, MIDI_DATAENTRY_MSB, 2); /* Pitch Bend Sensitivity MSB */
|
||||
_MIDI_SendControlChange(channel, MIDI_DATAENTRY_LSB, 0); /* Pitch Bend Sensitivity LSB */
|
||||
_MIDI_ChannelVolume[ channel ] = GENMIDI_DefaultVolume;
|
||||
}
|
||||
|
||||
_MIDI_SendChannelVolumes();
|
||||
|
||||
Reset = TRUE;
|
||||
|
||||
return MIDI_Ok;
|
||||
}
|
||||
|
||||
int32_t MIDI_SetVolume(int32_t volume)
|
||||
{
|
||||
if (_MIDI_Funcs == NULL)
|
||||
return MIDI_NullMidiModule;
|
||||
|
||||
_MIDI_TotalVolume = max(0, min(MIDI_MaxVolume, volume));
|
||||
_MIDI_SendChannelVolumes();
|
||||
|
||||
return MIDI_Ok;
|
||||
}
|
||||
|
||||
int32_t MIDI_GetVolume(void) { return (_MIDI_Funcs == NULL) ? MIDI_NullMidiModule : _MIDI_TotalVolume; }
|
||||
|
||||
void MIDI_SetLoopFlag(int32_t loopflag) { _MIDI_Loop = loopflag; }
|
||||
|
||||
void MIDI_ContinueSong(void)
|
||||
{
|
||||
if (!_MIDI_SongLoaded)
|
||||
return;
|
||||
|
||||
_MIDI_SongActive = TRUE;
|
||||
MPU_Unpause();
|
||||
}
|
||||
|
||||
void MIDI_PauseSong(void)
|
||||
{
|
||||
if (!_MIDI_SongLoaded)
|
||||
return;
|
||||
|
||||
_MIDI_SongActive = FALSE;
|
||||
MIDI_AllNotesOff();
|
||||
MPU_Pause();
|
||||
}
|
||||
|
||||
void MIDI_SetMidiFuncs(midifuncs *funcs) { _MIDI_Funcs = funcs; }
|
||||
|
||||
void MIDI_StopSong(void)
|
||||
{
|
||||
if (!_MIDI_SongLoaded)
|
||||
return;
|
||||
|
||||
_MIDI_SongActive = FALSE;
|
||||
_MIDI_SongLoaded = FALSE;
|
||||
|
||||
MPU_Reset();
|
||||
MPU_Init(MUSIC_SoundDevice);
|
||||
|
||||
MIDI_Reset();
|
||||
_MIDI_ResetTracks();
|
||||
|
||||
DO_FREE_AND_NULL(_MIDI_TrackPtr);
|
||||
|
||||
_MIDI_NumTracks = 0;
|
||||
_MIDI_TrackMemSize = 0;
|
||||
|
||||
_MIDI_TotalTime = 0;
|
||||
_MIDI_TotalTicks = 0;
|
||||
_MIDI_TotalBeats = 0;
|
||||
_MIDI_TotalMeasures = 0;
|
||||
|
||||
}
|
||||
|
||||
int32_t MIDI_PlaySong(char *song, int32_t loopflag)
|
||||
{
|
||||
int32_t numtracks;
|
||||
int32_t format;
|
||||
int32_t headersize;
|
||||
int32_t tracklength;
|
||||
track *CurrentTrack;
|
||||
char *ptr;
|
||||
|
||||
if (_MIDI_Funcs == NULL)
|
||||
return MIDI_NullMidiModule;
|
||||
|
||||
if (B_UNBUF32(song) != MIDI_HEADER_SIGNATURE)
|
||||
return MIDI_InvalidMidiFile;
|
||||
|
||||
song += 4;
|
||||
headersize = _MIDI_ReadNumber(song, 4);
|
||||
song += 4;
|
||||
format = _MIDI_ReadNumber(song, 2);
|
||||
int32_t My_MIDI_NumTracks = _MIDI_ReadNumber(song + 2, 2);
|
||||
int32_t My_MIDI_Division = _MIDI_ReadNumber(song + 4, 2);
|
||||
if (My_MIDI_Division < 0)
|
||||
{
|
||||
// If a SMPTE time division is given, just set to 96 so no errors occur
|
||||
My_MIDI_Division = 96;
|
||||
}
|
||||
|
||||
if (format > MAX_FORMAT)
|
||||
return MIDI_UnknownMidiFormat;
|
||||
|
||||
ptr = song + headersize;
|
||||
|
||||
if (My_MIDI_NumTracks == 0)
|
||||
return MIDI_NoTracks;
|
||||
|
||||
int32_t My_MIDI_TrackMemSize = My_MIDI_NumTracks * sizeof(track);
|
||||
track * My_MIDI_TrackPtr = (track *)Xmalloc(My_MIDI_TrackMemSize);
|
||||
|
||||
CurrentTrack = My_MIDI_TrackPtr;
|
||||
numtracks = My_MIDI_NumTracks;
|
||||
|
||||
while (numtracks--)
|
||||
{
|
||||
if (B_UNBUF32(ptr) != MIDI_TRACK_SIGNATURE)
|
||||
{
|
||||
DO_FREE_AND_NULL(My_MIDI_TrackPtr);
|
||||
|
||||
My_MIDI_TrackMemSize = 0;
|
||||
|
||||
return MIDI_InvalidTrack;
|
||||
}
|
||||
|
||||
tracklength = _MIDI_ReadNumber(ptr + 4, 4);
|
||||
ptr += 8;
|
||||
CurrentTrack->start = ptr;
|
||||
ptr += tracklength;
|
||||
CurrentTrack++;
|
||||
}
|
||||
|
||||
// at this point we know song load is successful
|
||||
|
||||
if (_MIDI_SongLoaded)
|
||||
MIDI_StopSong();
|
||||
|
||||
MPU_Init(MUSIC_SoundDevice);
|
||||
|
||||
_MIDI_Loop = loopflag;
|
||||
_MIDI_NumTracks = My_MIDI_NumTracks;
|
||||
_MIDI_Division = My_MIDI_Division;
|
||||
_MIDI_TrackMemSize = My_MIDI_TrackMemSize;
|
||||
_MIDI_TrackPtr = My_MIDI_TrackPtr;
|
||||
|
||||
_MIDI_InitEMIDI();
|
||||
_MIDI_ResetTracks();
|
||||
|
||||
if (!Reset)
|
||||
MIDI_Reset();
|
||||
|
||||
Reset = FALSE;
|
||||
|
||||
MIDI_SetDivision(_MIDI_Division);
|
||||
//MIDI_SetTempo( 120 );
|
||||
|
||||
_MIDI_SongLoaded = TRUE;
|
||||
_MIDI_SongActive = TRUE;
|
||||
|
||||
while (_MPU_BuffersWaiting < 4) _MIDI_ServiceRoutine();
|
||||
MPU_BeginPlayback();
|
||||
|
||||
return MIDI_Ok;
|
||||
}
|
||||
|
||||
void MIDI_SetTempo(int32_t tempo)
|
||||
{
|
||||
int32_t tickspersecond;
|
||||
|
||||
MIDI_Tempo = tempo;
|
||||
tickspersecond = ((tempo) * _MIDI_Division)/60;
|
||||
_MIDI_FPSecondsPerTick = tabledivide32_noinline(1 << TIME_PRECISION, tickspersecond);
|
||||
MPU_SetTempo(tempo);
|
||||
}
|
||||
|
||||
void MIDI_SetDivision(int32_t division)
|
||||
{
|
||||
MPU_SetDivision(division);
|
||||
}
|
||||
|
||||
int32_t MIDI_GetTempo(void) { return MIDI_Tempo; }
|
||||
|
||||
static void _MIDI_InitEMIDI(void)
|
||||
{
|
||||
int32_t type = EMIDI_GeneralMIDI;
|
||||
|
||||
_MIDI_ResetTracks();
|
||||
|
||||
_MIDI_TotalTime = 0;
|
||||
_MIDI_TotalTicks = 0;
|
||||
_MIDI_TotalBeats = 0;
|
||||
_MIDI_TotalMeasures = 0;
|
||||
|
||||
track *Track = _MIDI_TrackPtr;
|
||||
int32_t tracknum = 0;
|
||||
|
||||
while ((tracknum < _MIDI_NumTracks) && (Track != NULL))
|
||||
{
|
||||
_MIDI_Tick = 0;
|
||||
_MIDI_Beat = 1;
|
||||
_MIDI_Measure = 1;
|
||||
_MIDI_Time = 0;
|
||||
_MIDI_BeatsPerMeasure = 4;
|
||||
_MIDI_TicksPerBeat = _MIDI_Division;
|
||||
_MIDI_TimeBase = 4;
|
||||
|
||||
_MIDI_PositionInTicks = 0;
|
||||
_MIDI_ActiveTracks = 0;
|
||||
_MIDI_Context = -1;
|
||||
|
||||
Track->RunningStatus = 0;
|
||||
Track->active = TRUE;
|
||||
|
||||
Track->EMIDI_ProgramChange = FALSE;
|
||||
Track->EMIDI_VolumeChange = FALSE;
|
||||
Track->EMIDI_IncludeTrack = TRUE;
|
||||
|
||||
memset(Track->context, 0, sizeof(Track->context));
|
||||
|
||||
while (Track->delay > 0)
|
||||
{
|
||||
_MIDI_AdvanceTick();
|
||||
Track->delay--;
|
||||
}
|
||||
|
||||
int32_t IncludeFound = FALSE;
|
||||
|
||||
while (Track->active)
|
||||
{
|
||||
int32_t event;
|
||||
|
||||
GET_NEXT_EVENT(Track, event);
|
||||
|
||||
if (GET_MIDI_COMMAND(event) == MIDI_SPECIAL)
|
||||
{
|
||||
switch (event)
|
||||
{
|
||||
case MIDI_SYSEX:
|
||||
case MIDI_SYSEX_CONTINUE: _MIDI_SysEx(Track); break;
|
||||
case MIDI_META_EVENT: _MIDI_MetaEvent(Track); break;
|
||||
}
|
||||
|
||||
if (Track->active)
|
||||
{
|
||||
Track->delay = _MIDI_ReadDelta(Track);
|
||||
while (Track->delay > 0)
|
||||
{
|
||||
_MIDI_AdvanceTick();
|
||||
Track->delay--;
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (event & MIDI_RUNNING_STATUS)
|
||||
Track->RunningStatus = event;
|
||||
else
|
||||
{
|
||||
event = Track->RunningStatus;
|
||||
Track->pos--;
|
||||
}
|
||||
|
||||
// channel = GET_MIDI_CHANNEL(event);
|
||||
int const command = GET_MIDI_COMMAND(event);
|
||||
int length = _MIDI_CommandLengths[ command ];
|
||||
|
||||
if (command == MIDI_CONTROL_CHANGE)
|
||||
{
|
||||
if (*Track->pos == MIDI_MONO_MODE_ON)
|
||||
length++;
|
||||
|
||||
int32_t c1, c2;
|
||||
GET_NEXT_EVENT(Track, c1);
|
||||
GET_NEXT_EVENT(Track, c2);
|
||||
length -= 2;
|
||||
|
||||
switch (c1)
|
||||
{
|
||||
case EMIDI_LOOP_START :
|
||||
case EMIDI_SONG_LOOP_START :
|
||||
Track->context[ 0 ].loopcount = (c2 == 0) ? EMIDI_INFINITE : c2;
|
||||
Track->context[ 0 ].pos = Track->pos;
|
||||
Track->context[ 0 ].loopstart = Track->pos;
|
||||
Track->context[ 0 ].RunningStatus = Track->RunningStatus;
|
||||
Track->context[ 0 ].time = _MIDI_Time;
|
||||
Track->context[ 0 ].FPSecondsPerTick = _MIDI_FPSecondsPerTick;
|
||||
Track->context[ 0 ].tick = _MIDI_Tick;
|
||||
Track->context[ 0 ].beat = _MIDI_Beat;
|
||||
Track->context[ 0 ].measure = _MIDI_Measure;
|
||||
Track->context[ 0 ].BeatsPerMeasure = _MIDI_BeatsPerMeasure;
|
||||
Track->context[ 0 ].TicksPerBeat = _MIDI_TicksPerBeat;
|
||||
Track->context[ 0 ].TimeBase = _MIDI_TimeBase;
|
||||
break;
|
||||
|
||||
case EMIDI_LOOP_END :
|
||||
case EMIDI_SONG_LOOP_END :
|
||||
if (c2 == EMIDI_END_LOOP_VALUE)
|
||||
{
|
||||
Track->context[ 0 ].loopstart = NULL;
|
||||
Track->context[ 0 ].loopcount = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case EMIDI_INCLUDE_TRACK :
|
||||
if (EMIDI_AffectsCurrentCard(c2, type))
|
||||
{
|
||||
//printf( "Include track %d on card %d\n", tracknum, c2 );
|
||||
IncludeFound = TRUE;
|
||||
Track->EMIDI_IncludeTrack = TRUE;
|
||||
}
|
||||
else if (!IncludeFound)
|
||||
{
|
||||
//printf( "Track excluded %d on card %d\n", tracknum, c2 );
|
||||
IncludeFound = TRUE;
|
||||
Track->EMIDI_IncludeTrack = FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case EMIDI_EXCLUDE_TRACK :
|
||||
if (EMIDI_AffectsCurrentCard(c2, type))
|
||||
{
|
||||
//printf( "Exclude track %d on card %d\n", tracknum, c2 );
|
||||
Track->EMIDI_IncludeTrack = FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case EMIDI_PROGRAM_CHANGE :
|
||||
if (!Track->EMIDI_ProgramChange)
|
||||
//printf( "Program change on track %d\n", tracknum );
|
||||
Track->EMIDI_ProgramChange = TRUE;
|
||||
break;
|
||||
|
||||
case EMIDI_VOLUME_CHANGE :
|
||||
if (!Track->EMIDI_VolumeChange)
|
||||
//printf( "Volume change on track %d\n", tracknum );
|
||||
Track->EMIDI_VolumeChange = TRUE;
|
||||
break;
|
||||
|
||||
case EMIDI_CONTEXT_START :
|
||||
if ((c2 > 0) && (c2 < EMIDI_NUM_CONTEXTS))
|
||||
{
|
||||
Track->context[ c2 ].pos = Track->pos;
|
||||
Track->context[ c2 ].loopstart = Track->context[ 0 ].loopstart;
|
||||
Track->context[ c2 ].loopcount = Track->context[ 0 ].loopcount;
|
||||
Track->context[ c2 ].RunningStatus = Track->RunningStatus;
|
||||
Track->context[ c2 ].time = _MIDI_Time;
|
||||
Track->context[ c2 ].FPSecondsPerTick = _MIDI_FPSecondsPerTick;
|
||||
Track->context[ c2 ].tick = _MIDI_Tick;
|
||||
Track->context[ c2 ].beat = _MIDI_Beat;
|
||||
Track->context[ c2 ].measure = _MIDI_Measure;
|
||||
Track->context[ c2 ].BeatsPerMeasure = _MIDI_BeatsPerMeasure;
|
||||
Track->context[ c2 ].TicksPerBeat = _MIDI_TicksPerBeat;
|
||||
Track->context[ c2 ].TimeBase = _MIDI_TimeBase;
|
||||
}
|
||||
break;
|
||||
|
||||
case EMIDI_CONTEXT_END :
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Track->pos += length;
|
||||
Track->delay = _MIDI_ReadDelta(Track);
|
||||
|
||||
while (Track->delay > 0)
|
||||
{
|
||||
_MIDI_AdvanceTick();
|
||||
Track->delay--;
|
||||
}
|
||||
}
|
||||
|
||||
_MIDI_TotalTime = max(_MIDI_TotalTime, _MIDI_Time);
|
||||
if (RELATIVE_BEAT(_MIDI_Measure, _MIDI_Beat, _MIDI_Tick) >
|
||||
RELATIVE_BEAT(_MIDI_TotalMeasures, _MIDI_TotalBeats, _MIDI_TotalTicks))
|
||||
{
|
||||
_MIDI_TotalTicks = _MIDI_Tick;
|
||||
_MIDI_TotalBeats = _MIDI_Beat;
|
||||
_MIDI_TotalMeasures = _MIDI_Measure;
|
||||
}
|
||||
|
||||
Track++;
|
||||
tracknum++;
|
||||
}
|
||||
|
||||
_MIDI_ResetTracks();
|
||||
}
|
||||
|
||||
|
||||
void MIDI_UpdateMusic(void)
|
||||
{
|
||||
if (!_MIDI_SongLoaded || !_MIDI_SongActive) return;
|
||||
while (_MPU_BuffersWaiting < 4) _MIDI_ServiceRoutine();
|
||||
}
|
||||
|
|
@ -1,87 +0,0 @@
|
|||
//-------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (C) 2016 EDuke32 developers and contributors
|
||||
|
||||
This file is part of EDuke32.
|
||||
|
||||
EDuke32 is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License version 2
|
||||
as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
#ifndef __MIDI_H
|
||||
#define __MIDI_H
|
||||
|
||||
enum MIDI_Errors
|
||||
{
|
||||
MIDI_Warning = -2,
|
||||
MIDI_Error = -1,
|
||||
MIDI_Ok = 0,
|
||||
MIDI_NullMidiModule,
|
||||
MIDI_InvalidMidiFile,
|
||||
MIDI_UnknownMidiFormat,
|
||||
MIDI_NoTracks,
|
||||
MIDI_InvalidTrack,
|
||||
MIDI_NoMemory,
|
||||
MIDI_DPMI_Error
|
||||
};
|
||||
|
||||
|
||||
#define MIDI_PASS_THROUGH 1
|
||||
#define MIDI_DONT_PLAY 0
|
||||
|
||||
#define MIDI_MaxVolume 255
|
||||
|
||||
extern char MIDI_PatchMap[ 128 ];
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void (*NoteOff)(int32_t channel, int32_t key, int32_t velocity);
|
||||
void (*NoteOn)(int32_t channel, int32_t key, int32_t velocity);
|
||||
void (*PolyAftertouch)(int32_t channel, int32_t key, int32_t pressure);
|
||||
void (*ControlChange)(int32_t channel, int32_t number, int32_t value);
|
||||
void (*ProgramChange)(int32_t channel, int32_t program);
|
||||
void (*ChannelAftertouch)(int32_t channel, int32_t pressure);
|
||||
void (*PitchBend)(int32_t channel, int32_t lsb, int32_t msb);
|
||||
void (*FinishBuffer)(void);
|
||||
} midifuncs;
|
||||
|
||||
void MIDI_RerouteMidiChannel( int32_t channel, int32_t ( *function )( int32_t event, int32_t c1, int32_t c2 ) );
|
||||
int32_t MIDI_AllNotesOff( void );
|
||||
void MIDI_SetUserChannelVolume( int32_t channel, int32_t volume );
|
||||
void MIDI_ResetUserChannelVolume( void );
|
||||
int32_t MIDI_Reset( void );
|
||||
int32_t MIDI_SetVolume( int32_t volume );
|
||||
int32_t MIDI_GetVolume( void );
|
||||
void MIDI_SetMidiFuncs( midifuncs *funcs );
|
||||
void MIDI_SetContext( int32_t context );
|
||||
int32_t MIDI_GetContext( void );
|
||||
void MIDI_SetLoopFlag( int32_t loopflag );
|
||||
void MIDI_ContinueSong( void );
|
||||
void MIDI_PauseSong( void );
|
||||
int32_t MIDI_SongPlaying( void );
|
||||
void MIDI_StopSong( void );
|
||||
int32_t MIDI_PlaySong( char *song, int32_t loopflag );
|
||||
void MIDI_SetTempo( int32_t tempo );
|
||||
int32_t MIDI_GetTempo( void );
|
||||
void MIDI_SetSongTick( uint32_t PositionInTicks );
|
||||
void MIDI_SetSongTime( uint32_t milliseconds );
|
||||
void MIDI_SetSongPosition( int32_t measure, int32_t beat, int32_t tick );
|
||||
void MIDI_GetSongPosition( songposition *pos );
|
||||
void MIDI_GetSongLength( songposition *pos );
|
||||
void MIDI_LoadTimbres( void );
|
||||
void MIDI_UpdateMusic(void);
|
||||
void MIDI_SetDivision( int32_t division );
|
||||
|
||||
#endif
|
|
@ -1,496 +0,0 @@
|
|||
//-------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (C) 2010 EDuke32 developers and contributors
|
||||
|
||||
This file is part of EDuke32.
|
||||
|
||||
EDuke32 is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License version 2
|
||||
as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/**********************************************************************
|
||||
module: MPU401.C
|
||||
|
||||
author: James R. Dose
|
||||
date: January 1, 1994
|
||||
|
||||
Low level routines to support sending of MIDI data to MPU401
|
||||
compatible MIDI interfaces.
|
||||
|
||||
(c) Copyright 1994 James R. Dose. All Rights Reserved.
|
||||
**********************************************************************/
|
||||
|
||||
// This object is shared by all Build games with MIDI playback!
|
||||
|
||||
#include "mpu401.h"
|
||||
#include "compat.h"
|
||||
#include "pragmas.h"
|
||||
|
||||
#define NEED_MMSYSTEM_H
|
||||
#include "windows_inc.h"
|
||||
|
||||
static HMIDISTRM hmido = (HMIDISTRM)-1;
|
||||
static MIDIOUTCAPS midicaps;
|
||||
static DWORD mididevice = -1;
|
||||
|
||||
#define PAD(x) ((((x)+3)&(~3)))
|
||||
|
||||
#define BUFFERLEN (32*4*4)
|
||||
#define NUMBUFFERS 6
|
||||
static char eventbuf[NUMBUFFERS][BUFFERLEN];
|
||||
static int32_t eventcnt[NUMBUFFERS];
|
||||
static MIDIHDR bufferheaders[NUMBUFFERS];
|
||||
int32_t _MPU_CurrentBuffer = 0;
|
||||
int32_t _MPU_BuffersWaiting = 0;
|
||||
|
||||
extern uint32_t _MIDI_GlobalPositionInTicks;
|
||||
uint32_t _MPU_LastEvent=0;
|
||||
|
||||
#define MIDI_NOTE_OFF 0x80
|
||||
#define MIDI_NOTE_ON 0x90
|
||||
#define MIDI_POLY_AFTER_TCH 0xA0
|
||||
#define MIDI_CONTROL_CHANGE 0xB0
|
||||
#define MIDI_PROGRAM_CHANGE 0xC0
|
||||
#define MIDI_AFTER_TOUCH 0xD0
|
||||
#define MIDI_PITCH_BEND 0xE0
|
||||
#define MIDI_META_EVENT 0xFF
|
||||
#define MIDI_END_OF_TRACK 0x2F
|
||||
#define MIDI_TEMPO_CHANGE 0x51
|
||||
#define MIDI_MONO_MODE_ON 0x7E
|
||||
#define MIDI_ALL_NOTES_OFF 0x7B
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
|
||||
Memory locked functions:
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
void MPU_FinishBuffer(int32_t buffer)
|
||||
{
|
||||
if (!eventcnt[buffer]) return;
|
||||
ZeroMemory(&bufferheaders[buffer], sizeof(MIDIHDR));
|
||||
bufferheaders[buffer].lpData = eventbuf[buffer];
|
||||
bufferheaders[buffer].dwBufferLength =
|
||||
bufferheaders[buffer].dwBytesRecorded = eventcnt[buffer];
|
||||
midiOutPrepareHeader((HMIDIOUT)hmido, &bufferheaders[buffer], sizeof(MIDIHDR));
|
||||
midiStreamOut(hmido, &bufferheaders[buffer], sizeof(MIDIHDR));
|
||||
// printf("Sending %d bytes (buffer %d)\n",eventcnt[buffer],buffer);
|
||||
_MPU_BuffersWaiting++;
|
||||
}
|
||||
|
||||
void MPU_BeginPlayback(void)
|
||||
{
|
||||
_MPU_LastEvent = _MIDI_GlobalPositionInTicks;
|
||||
if (hmido != (HMIDISTRM)-1) midiStreamRestart(hmido);
|
||||
}
|
||||
|
||||
void MPU_Pause(void)
|
||||
{
|
||||
if (hmido != (HMIDISTRM)-1) midiStreamPause(hmido);
|
||||
}
|
||||
|
||||
void MPU_Unpause(void)
|
||||
{
|
||||
if (hmido != (HMIDISTRM)-1) midiStreamRestart(hmido);
|
||||
}
|
||||
|
||||
|
||||
void CALLBACK MPU_MIDICallback(HMIDIOUT handle, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
|
||||
{
|
||||
int32_t i;
|
||||
|
||||
UNREFERENCED_PARAMETER(dwInstance);
|
||||
UNREFERENCED_PARAMETER(dwParam2);
|
||||
|
||||
switch (uMsg)
|
||||
{
|
||||
case MOM_DONE:
|
||||
midiOutUnprepareHeader((HMIDIOUT)handle, (MIDIHDR *)dwParam1, sizeof(MIDIHDR));
|
||||
for (i=0; i<NUMBUFFERS; i++)
|
||||
{
|
||||
if ((MIDIHDR *)dwParam1 == &bufferheaders[i])
|
||||
{
|
||||
eventcnt[i] = 0; // marks the buffer as free
|
||||
// printf("Finished buffer %d\n",i);
|
||||
_MPU_BuffersWaiting--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
Function: MPU_SendMidi
|
||||
|
||||
Queues a MIDI message to the music device.
|
||||
---------------------------------------------------------------------*/
|
||||
|
||||
int32_t MPU_GetNextBuffer(void)
|
||||
{
|
||||
int32_t i;
|
||||
for (i=0; i<NUMBUFFERS; i++)
|
||||
{
|
||||
if (eventcnt[i] == 0) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void MPU_SendMidi(char *data, int32_t count)
|
||||
{
|
||||
char *p;
|
||||
int32_t padded, nextbuffer;
|
||||
static int32_t masks[3] = { 0x000000ffl, 0x0000ffffl, 0x00ffffffl };
|
||||
|
||||
if (count <= 0) return;
|
||||
if (count <= 3)
|
||||
{
|
||||
if (eventcnt[_MPU_CurrentBuffer] + 12 > BUFFERLEN)
|
||||
{
|
||||
// buffer over-full
|
||||
nextbuffer = MPU_GetNextBuffer();
|
||||
if (nextbuffer < 0)
|
||||
{
|
||||
// printf("All buffers full!\n");
|
||||
return;
|
||||
}
|
||||
MPU_FinishBuffer(_MPU_CurrentBuffer);
|
||||
_MPU_CurrentBuffer = nextbuffer;
|
||||
}
|
||||
|
||||
p = eventbuf[_MPU_CurrentBuffer] + eventcnt[_MPU_CurrentBuffer];
|
||||
((int32_t *)p)[0] = _MIDI_GlobalPositionInTicks - _MPU_LastEvent;
|
||||
((int32_t *)p)[1] = 0;
|
||||
((int32_t *)p)[2] = (MEVT_SHORTMSG << 24) | ((*((int32_t *)data)) & masks[count-1]);
|
||||
eventcnt[_MPU_CurrentBuffer] += 12;
|
||||
}
|
||||
else
|
||||
{
|
||||
padded = PAD(count);
|
||||
if (eventcnt[_MPU_CurrentBuffer] + 12 + padded > BUFFERLEN)
|
||||
{
|
||||
// buffer over-full
|
||||
nextbuffer = MPU_GetNextBuffer();
|
||||
if (nextbuffer < 0)
|
||||
{
|
||||
// printf("All buffers full!\n");
|
||||
return;
|
||||
}
|
||||
MPU_FinishBuffer(_MPU_CurrentBuffer);
|
||||
_MPU_CurrentBuffer = nextbuffer;
|
||||
}
|
||||
|
||||
p = eventbuf[_MPU_CurrentBuffer] + eventcnt[_MPU_CurrentBuffer];
|
||||
((int32_t *)p)[0] = _MIDI_GlobalPositionInTicks - _MPU_LastEvent;
|
||||
((int32_t *)p)[1] = 0;
|
||||
((int32_t *)p)[2] = (MEVT_LONGMSG<<24) | (count & 0xffffffl);
|
||||
p+=12; eventcnt[_MPU_CurrentBuffer] += 12;
|
||||
for (; count>0; count--, padded--, eventcnt[_MPU_CurrentBuffer]++)
|
||||
*(p++) = *(data++);
|
||||
for (; padded>0; padded--, eventcnt[_MPU_CurrentBuffer]++)
|
||||
*(p++) = 0;
|
||||
}
|
||||
_MPU_LastEvent = _MIDI_GlobalPositionInTicks;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
Function: MPU_SendMidiImmediate
|
||||
|
||||
Sends a MIDI message immediately to the the music device.
|
||||
---------------------------------------------------------------------*/
|
||||
void MPU_SendMidiImmediate(char *data, int32_t count)
|
||||
{
|
||||
MIDIHDR mhdr;
|
||||
static int32_t masks[3] = { 0x00ffffffl, 0x0000ffffl, 0x000000ffl };
|
||||
|
||||
if (!count) return;
|
||||
if (count<=3) midiOutShortMsg((HMIDIOUT)hmido, (*((int32_t *)data)) & masks[count-1]);
|
||||
else
|
||||
{
|
||||
ZeroMemory(&mhdr, sizeof(mhdr));
|
||||
mhdr.lpData = data;
|
||||
mhdr.dwBufferLength = count;
|
||||
midiOutPrepareHeader((HMIDIOUT)hmido, &mhdr, sizeof(MIDIHDR));
|
||||
midiOutLongMsg((HMIDIOUT)hmido, &mhdr, sizeof(MIDIHDR));
|
||||
while (!(mhdr.dwFlags & MHDR_DONE)) ;
|
||||
midiOutUnprepareHeader((HMIDIOUT)hmido, &mhdr, sizeof(MIDIHDR));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
Function: MPU_Reset
|
||||
|
||||
Resets the MPU401 card.
|
||||
---------------------------------------------------------------------*/
|
||||
|
||||
int32_t MPU_Reset
|
||||
(
|
||||
void
|
||||
)
|
||||
|
||||
{
|
||||
midiStreamStop(hmido);
|
||||
midiStreamClose(hmido);
|
||||
hmido = (HMIDISTRM)-1;
|
||||
|
||||
return MPU_Ok;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
Function: MPU_Init
|
||||
|
||||
Detects and initializes the MPU401 card.
|
||||
---------------------------------------------------------------------*/
|
||||
|
||||
int32_t MPU_Init
|
||||
(
|
||||
int32_t addr
|
||||
)
|
||||
|
||||
{
|
||||
if (hmido != (HMIDISTRM)-1)
|
||||
return MPU_Ok;
|
||||
|
||||
int32_t i;
|
||||
|
||||
for (i=0; i<NUMBUFFERS; i++) eventcnt[i]=0;
|
||||
|
||||
mididevice = addr;
|
||||
|
||||
if (midiOutGetDevCaps(mididevice, &midicaps, sizeof(MIDIOUTCAPS)) != MMSYSERR_NOERROR) return MPU_Error;
|
||||
|
||||
if (midiStreamOpen(&hmido,(LPUINT)&mididevice,1,(DWORD_PTR)MPU_MIDICallback,0L,CALLBACK_FUNCTION) != MMSYSERR_NOERROR) return MPU_Error;
|
||||
|
||||
return MPU_Ok;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
Function: MPU_NoteOff
|
||||
|
||||
Sends a full MIDI note off event out to the music device.
|
||||
---------------------------------------------------------------------*/
|
||||
|
||||
void MPU_NoteOff
|
||||
(
|
||||
int32_t channel,
|
||||
int32_t key,
|
||||
int32_t velocity
|
||||
)
|
||||
|
||||
{
|
||||
char msg[3];
|
||||
msg[0] = (MIDI_NOTE_OFF | channel);
|
||||
msg[1] = (key);
|
||||
msg[2] = (velocity);
|
||||
MPU_SendMidi(msg, 3);
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
Function: MPU_NoteOn
|
||||
|
||||
Sends a full MIDI note on event out to the music device.
|
||||
---------------------------------------------------------------------*/
|
||||
|
||||
void MPU_NoteOn
|
||||
(
|
||||
int32_t channel,
|
||||
int32_t key,
|
||||
int32_t velocity
|
||||
)
|
||||
|
||||
{
|
||||
char msg[3];
|
||||
msg[0] = (MIDI_NOTE_ON | channel);
|
||||
msg[1] = (key);
|
||||
msg[2] = (velocity);
|
||||
MPU_SendMidi(msg, 3);
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
Function: MPU_PolyAftertouch
|
||||
|
||||
Sends a full MIDI polyphonic aftertouch event out to the music device.
|
||||
---------------------------------------------------------------------*/
|
||||
|
||||
void MPU_PolyAftertouch
|
||||
(
|
||||
int32_t channel,
|
||||
int32_t key,
|
||||
int32_t pressure
|
||||
)
|
||||
|
||||
{
|
||||
char msg[3];
|
||||
msg[0] = (MIDI_POLY_AFTER_TCH | channel);
|
||||
msg[1] = (key);
|
||||
msg[2] = (pressure);
|
||||
MPU_SendMidi(msg, 3);
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
Function: MPU_ControlChange
|
||||
|
||||
Sends a full MIDI control change event out to the music device.
|
||||
---------------------------------------------------------------------*/
|
||||
|
||||
void MPU_ControlChange
|
||||
(
|
||||
int32_t channel,
|
||||
int32_t number,
|
||||
int32_t value
|
||||
)
|
||||
|
||||
{
|
||||
char msg[3];
|
||||
msg[0] = (MIDI_CONTROL_CHANGE | channel);
|
||||
msg[1] = (number);
|
||||
msg[2] = (value);
|
||||
MPU_SendMidi(msg, 3);
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
Function: MPU_ProgramChange
|
||||
|
||||
Sends a full MIDI program change event out to the music device.
|
||||
---------------------------------------------------------------------*/
|
||||
|
||||
void MPU_ProgramChange
|
||||
(
|
||||
int32_t channel,
|
||||
int32_t program
|
||||
)
|
||||
|
||||
{
|
||||
char msg[2];
|
||||
msg[0] = (MIDI_PROGRAM_CHANGE | channel);
|
||||
msg[1] = (program);
|
||||
MPU_SendMidi(msg, 2);
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
Function: MPU_ChannelAftertouch
|
||||
|
||||
Sends a full MIDI channel aftertouch event out to the music device.
|
||||
---------------------------------------------------------------------*/
|
||||
|
||||
void MPU_ChannelAftertouch
|
||||
(
|
||||
int32_t channel,
|
||||
int32_t pressure
|
||||
)
|
||||
|
||||
{
|
||||
char msg[2];
|
||||
msg[0] = (MIDI_AFTER_TOUCH | channel);
|
||||
msg[1] = (pressure);
|
||||
MPU_SendMidi(msg, 2);
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
Function: MPU_PitchBend
|
||||
|
||||
Sends a full MIDI pitch bend event out to the music device.
|
||||
---------------------------------------------------------------------*/
|
||||
|
||||
void MPU_PitchBend
|
||||
(
|
||||
int32_t channel,
|
||||
int32_t lsb,
|
||||
int32_t msb
|
||||
)
|
||||
|
||||
{
|
||||
char msg[3];
|
||||
msg[0] = (MIDI_PITCH_BEND | channel);
|
||||
msg[1] = (lsb);
|
||||
msg[2] = (msb);
|
||||
MPU_SendMidi(msg, 3);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void MPU_SetTempo(int32_t tempo)
|
||||
{
|
||||
MIDIPROPTEMPO prop;
|
||||
prop.cbStruct = sizeof(MIDIPROPTEMPO);
|
||||
prop.dwTempo = tabledivide32_noinline(60000000l, tempo);
|
||||
midiStreamProperty(hmido, (LPBYTE)&prop, MIDIPROP_SET|MIDIPROP_TEMPO);
|
||||
}
|
||||
|
||||
void MPU_SetDivision(int32_t division)
|
||||
{
|
||||
MIDIPROPTIMEDIV prop;
|
||||
prop.cbStruct = sizeof(MIDIPROPTIMEDIV);
|
||||
prop.dwTimeDiv = division;
|
||||
midiStreamProperty(hmido, (LPBYTE)&prop, MIDIPROP_SET|MIDIPROP_TIMEDIV);
|
||||
}
|
||||
|
||||
void MPU_SetVolume(int32_t volume)
|
||||
{
|
||||
/*
|
||||
HMIXER hmixer;
|
||||
int32_t mixerid;
|
||||
MIXERCONTROLDETAILS mxcd;
|
||||
MIXERCONTROLDETAILS_UNSIGNED mxcdu;
|
||||
MMRESULT mme;
|
||||
|
||||
if (mididevice < 0) return;
|
||||
|
||||
mme = mixerOpen(&hmixer, mididevice, 0,0, MIXER_OBJECTF_MIDIOUT);
|
||||
if (mme) {
|
||||
puts("Failed opening mixer");
|
||||
return;
|
||||
}
|
||||
|
||||
mixerGetID(hmixer, &mixerid, MIXER_OBJECTF_HMIXER);
|
||||
printf("mixerid=%d\n",mixerid);
|
||||
|
||||
ZeroMemory(&mxcd,sizeof(mxcd));
|
||||
mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
|
||||
mxcd.dwControlID = MIXERCONTROL_CONTROLTYPE_VOLUME;
|
||||
mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
|
||||
mxcd.paDetails = (LPVOID)&mxcdu;
|
||||
mxcdu.dwValue = (volume << 8) & 0xffff;
|
||||
|
||||
printf("set %d\n",mixerSetControlDetails((HMIXEROBJ)mididevice, &mxcd,
|
||||
MIXER_OBJECTF_MIDIOUT|MIXER_SETCONTROLDETAILSF_VALUE));
|
||||
|
||||
mixerClose(hmixer);
|
||||
*/
|
||||
UNREFERENCED_PARAMETER(volume);
|
||||
}
|
||||
|
||||
int32_t MPU_GetVolume(void)
|
||||
{
|
||||
// if (mididevice < 0) return 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 1994-1995 Apogee Software, Ltd.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
Modifications for JonoF's port by Jonathon Fowler (jf@jonof.id.au)
|
||||
*/
|
||||
#ifndef __MPU401_H
|
||||
#define __MPU401_H
|
||||
|
||||
#include "compat.h"
|
||||
|
||||
#define MPU_DefaultAddress 0x330
|
||||
|
||||
enum MPU_ERRORS
|
||||
{
|
||||
MPU_Warning = -2,
|
||||
MPU_Error = -1,
|
||||
MPU_Ok = 0
|
||||
};
|
||||
|
||||
#define MPU_NotFound -1
|
||||
#define MPU_UARTFailed -2
|
||||
|
||||
#define MPU_ReadyToWrite 0x40
|
||||
#define MPU_ReadyToRead 0x80
|
||||
#define MPU_CmdEnterUART 0x3f
|
||||
#define MPU_CmdReset 0xff
|
||||
#define MPU_CmdAcknowledge 0xfe
|
||||
|
||||
extern int32_t _MPU_CurrentBuffer;
|
||||
extern int32_t _MPU_BuffersWaiting;
|
||||
|
||||
void MPU_SendMidi( char *data, int32_t count );
|
||||
void MPU_SendMidiImmediate( char *data, int32_t count );
|
||||
int32_t MPU_Reset( void );
|
||||
int32_t MPU_Init( int32_t addr );
|
||||
void MPU_NoteOff( int32_t channel, int32_t key, int32_t velocity );
|
||||
void MPU_NoteOn( int32_t channel, int32_t key, int32_t velocity );
|
||||
void MPU_PolyAftertouch( int32_t channel, int32_t key, int32_t pressure );
|
||||
void MPU_ControlChange( int32_t channel, int32_t number, int32_t value );
|
||||
void MPU_ProgramChange( int32_t channel, int32_t program );
|
||||
void MPU_ChannelAftertouch( int32_t channel, int32_t pressure );
|
||||
void MPU_PitchBend( int32_t channel, int32_t lsb, int32_t msb );
|
||||
|
||||
void MPU_SetTempo(int32_t tempo);
|
||||
void MPU_SetDivision(int32_t division);
|
||||
void MPU_SetVolume(int32_t volume);
|
||||
int32_t MPU_GetVolume(void);
|
||||
|
||||
void MPU_BeginPlayback( void );
|
||||
void MPU_Pause(void);
|
||||
void MPU_Unpause(void);
|
||||
|
||||
#endif
|
|
@ -1,125 +0,0 @@
|
|||
//-------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (C) 2016 EDuke32 developers and contributors
|
||||
|
||||
This file is part of EDuke32.
|
||||
|
||||
EDuke32 is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License version 2
|
||||
as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
// This object is shared by all Build games with MIDI playback!
|
||||
|
||||
#include "compat.h"
|
||||
#include "music.h"
|
||||
#include "midi.h"
|
||||
#include "mpu401.h"
|
||||
|
||||
int32_t MUSIC_SoundDevice = -1;
|
||||
int32_t MUSIC_ErrorCode = MUSIC_Ok;
|
||||
|
||||
static midifuncs MUSIC_MidiFunctions;
|
||||
|
||||
int32_t MUSIC_InitMidi(int32_t card, midifuncs *Funcs, int32_t Address);
|
||||
|
||||
#define MUSIC_SetErrorCode(status) MUSIC_ErrorCode = (status);
|
||||
|
||||
const char *MUSIC_ErrorString(int32_t ErrorNumber)
|
||||
{
|
||||
const char *ErrorString;
|
||||
|
||||
switch (ErrorNumber)
|
||||
{
|
||||
case MUSIC_Warning:
|
||||
case MUSIC_Error: ErrorString = MUSIC_ErrorString(MUSIC_ErrorCode); break;
|
||||
case MUSIC_Ok: ErrorString = "Music ok."; break;
|
||||
case MUSIC_MidiError: ErrorString = "Error playing MIDI file."; break;
|
||||
default: ErrorString = "Unknown Music error code."; break;
|
||||
}
|
||||
|
||||
return ErrorString;
|
||||
}
|
||||
|
||||
|
||||
int32_t MUSIC_Init(int32_t SoundCard, int32_t Address)
|
||||
{
|
||||
MUSIC_SoundDevice = SoundCard;
|
||||
|
||||
return MUSIC_InitMidi(SoundCard, &MUSIC_MidiFunctions, Address);
|
||||
}
|
||||
|
||||
|
||||
int32_t MUSIC_Shutdown(void)
|
||||
{
|
||||
MIDI_StopSong();
|
||||
|
||||
return MUSIC_Ok;
|
||||
}
|
||||
|
||||
|
||||
void MUSIC_SetVolume(int32_t volume)
|
||||
{
|
||||
if (MUSIC_SoundDevice != -1)
|
||||
MIDI_SetVolume(min(max(0, volume), 255));
|
||||
}
|
||||
|
||||
|
||||
int32_t MUSIC_GetVolume(void) { return MUSIC_SoundDevice == -1 ? 0 : MIDI_GetVolume(); }
|
||||
void MUSIC_SetLoopFlag(int32_t loopflag) { MIDI_SetLoopFlag(loopflag); }
|
||||
void MUSIC_Continue(void) { MIDI_ContinueSong(); }
|
||||
void MUSIC_Pause(void) { MIDI_PauseSong(); }
|
||||
|
||||
int32_t MUSIC_StopSong(void)
|
||||
{
|
||||
MIDI_StopSong();
|
||||
MUSIC_SetErrorCode(MUSIC_Ok);
|
||||
return MUSIC_Ok;
|
||||
}
|
||||
|
||||
|
||||
int32_t MUSIC_PlaySong(char *song, int32_t songsize, int32_t loopflag)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(songsize);
|
||||
|
||||
MUSIC_SetErrorCode(MUSIC_Ok)
|
||||
|
||||
if (MIDI_PlaySong(song, loopflag) != MIDI_Ok)
|
||||
{
|
||||
MUSIC_SetErrorCode(MUSIC_MidiError);
|
||||
return MUSIC_Warning;
|
||||
}
|
||||
|
||||
return MUSIC_Ok;
|
||||
}
|
||||
|
||||
|
||||
int32_t MUSIC_InitMidi(int32_t card, midifuncs *Funcs, int32_t Address)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(card);
|
||||
UNREFERENCED_PARAMETER(Address);
|
||||
Funcs->NoteOff = MPU_NoteOff;
|
||||
Funcs->NoteOn = MPU_NoteOn;
|
||||
Funcs->PolyAftertouch = MPU_PolyAftertouch;
|
||||
Funcs->ControlChange = MPU_ControlChange;
|
||||
Funcs->ProgramChange = MPU_ProgramChange;
|
||||
Funcs->ChannelAftertouch = MPU_ChannelAftertouch;
|
||||
Funcs->PitchBend = MPU_PitchBend;
|
||||
|
||||
MIDI_SetMidiFuncs(Funcs);
|
||||
|
||||
return MIDI_Ok;
|
||||
}
|
||||
|
||||
void MUSIC_Update(void) { MIDI_UpdateMusic(); }
|
|
@ -1,481 +0,0 @@
|
|||
//-------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (C) 2010 EDuke32 developers and contributors
|
||||
|
||||
This file is part of EDuke32.
|
||||
|
||||
EDuke32 is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License version 2
|
||||
as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* A reimplementation of Jim Dose's FX_MAN routines, using SDL_mixer 1.2.
|
||||
* Whee. FX_MAN is also known as the "Apogee Sound System", or "ASS" for
|
||||
* short. How strangely appropriate that seems.
|
||||
*/
|
||||
|
||||
// This object is shared by all Build games with MIDI playback!
|
||||
|
||||
#define NEED_SDL_MIXER
|
||||
|
||||
#include "compat.h"
|
||||
|
||||
#include "duke3d.h"
|
||||
#include "cache1d.h"
|
||||
|
||||
#include "sdlayer.h"
|
||||
#include "music.h"
|
||||
|
||||
#if !defined _WIN32 && !defined(GEKKO)
|
||||
//# define FORK_EXEC_MIDI 1
|
||||
#endif
|
||||
|
||||
#if defined FORK_EXEC_MIDI // fork/exec based external midi player
|
||||
#include <signal.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/wait.h>
|
||||
static char **external_midi_argv;
|
||||
static pid_t external_midi_pid=-1;
|
||||
static int8_t external_midi_restart=0;
|
||||
#endif
|
||||
|
||||
#ifdef __ANDROID__ //TODO fix
|
||||
static char const *external_midi_tempfn = APPBASENAME "-music.mid";
|
||||
#else
|
||||
static char const *external_midi_tempfn = "/tmp/" APPBASENAME "-music.mid";
|
||||
#endif
|
||||
|
||||
static int32_t external_midi = 0;
|
||||
|
||||
int32_t MUSIC_ErrorCode = MUSIC_Ok;
|
||||
|
||||
static char warningMessage[80];
|
||||
static char errorMessage[80];
|
||||
|
||||
static int32_t music_initialized = 0;
|
||||
static int32_t music_context = 0;
|
||||
static int32_t music_loopflag = MUSIC_PlayOnce;
|
||||
static Mix_Music *music_musicchunk = NULL;
|
||||
|
||||
static void setErrorMessage(const char *msg)
|
||||
{
|
||||
Bstrncpyz(errorMessage, msg, sizeof(errorMessage));
|
||||
}
|
||||
|
||||
// The music functions...
|
||||
|
||||
const char *MUSIC_ErrorString(int32_t ErrorNumber)
|
||||
{
|
||||
switch (ErrorNumber)
|
||||
{
|
||||
case MUSIC_Warning:
|
||||
return warningMessage;
|
||||
|
||||
case MUSIC_Error:
|
||||
return errorMessage;
|
||||
|
||||
case MUSIC_Ok:
|
||||
return "OK; no error.";
|
||||
|
||||
case MUSIC_MidiError:
|
||||
return "MIDI error.";
|
||||
|
||||
default:
|
||||
return "Unknown error.";
|
||||
} // switch
|
||||
|
||||
return NULL;
|
||||
} // MUSIC_ErrorString
|
||||
|
||||
int32_t MUSIC_Init(int32_t SoundCard, int32_t Address)
|
||||
{
|
||||
#ifdef __ANDROID__
|
||||
music_initialized = 1;
|
||||
return MUSIC_Ok;
|
||||
#endif
|
||||
// Use an external MIDI player if the user has specified to do so
|
||||
char *command = getenv("EDUKE32_MUSIC_CMD");
|
||||
const SDL_version *linked = Mix_Linked_Version();
|
||||
|
||||
UNREFERENCED_PARAMETER(SoundCard);
|
||||
UNREFERENCED_PARAMETER(Address);
|
||||
|
||||
if (music_initialized)
|
||||
{
|
||||
setErrorMessage("Music system is already initialized.");
|
||||
return MUSIC_Error;
|
||||
} // if
|
||||
|
||||
if (SDL_VERSIONNUM(linked->major,linked->minor,linked->patch) < MIX_REQUIREDVERSION)
|
||||
{
|
||||
// reject running with SDL_Mixer versions older than what is stated in sdl_inc.h
|
||||
initprintf("You need at least v%d.%d.%d of SDL_mixer for music\n",SDL_MIXER_MIN_X,SDL_MIXER_MIN_Y,SDL_MIXER_MIN_Z);
|
||||
return MUSIC_Error;
|
||||
}
|
||||
|
||||
external_midi = (command != NULL && command[0] != 0);
|
||||
|
||||
if (external_midi)
|
||||
{
|
||||
#if defined FORK_EXEC_MIDI
|
||||
int32_t ws=1, numargs=0, pagesize=sysconf(_SC_PAGE_SIZE);
|
||||
char *c, *cmd;
|
||||
size_t sz;
|
||||
#endif
|
||||
|
||||
initprintf("Setting music command to \"%s\".\n", command);
|
||||
|
||||
#if !defined FORK_EXEC_MIDI
|
||||
if (Mix_SetMusicCMD(command)==-1)
|
||||
{
|
||||
perror("Mix_SetMusicCMD");
|
||||
goto fallback;
|
||||
}
|
||||
#else
|
||||
|
||||
if (pagesize==-1)
|
||||
goto fallback;
|
||||
|
||||
for (c=command; *c; c++)
|
||||
{
|
||||
if (isspace(*c))
|
||||
ws = 1;
|
||||
else if (ws)
|
||||
{
|
||||
ws = 0;
|
||||
numargs++;
|
||||
}
|
||||
}
|
||||
|
||||
if (numargs==0)
|
||||
goto fallback;
|
||||
|
||||
sz = (numargs+2)*sizeof(char *) + (c-command+1);
|
||||
sz = ((sz+pagesize-1)/pagesize)*pagesize;
|
||||
#if defined(__APPLE__) || defined(__ANDROID__)
|
||||
external_midi_argv = Xcalloc(1,sz+pagesize);
|
||||
external_midi_argv = (char **)((intptr_t)external_midi_argv + (pagesize-(((intptr_t)external_midi_argv)&(pagesize-1))));
|
||||
#else
|
||||
if (posix_memalign((void **)&external_midi_argv, pagesize, sz))
|
||||
goto fallback;
|
||||
#endif
|
||||
cmd = (char *)external_midi_argv + (numargs+2)*sizeof(char *);
|
||||
Bmemcpy(cmd, command, c-command+1);
|
||||
|
||||
ws = 1;
|
||||
numargs = 0;
|
||||
for (c=cmd; *c; c++)
|
||||
{
|
||||
if (isspace(*c))
|
||||
{
|
||||
ws = 1;
|
||||
*c = 0;
|
||||
}
|
||||
else if (ws)
|
||||
{
|
||||
ws = 0;
|
||||
external_midi_argv[numargs++] = c;
|
||||
}
|
||||
}
|
||||
external_midi_argv[numargs] = external_midi_tempfn;
|
||||
external_midi_argv[numargs+1] = NULL;
|
||||
|
||||
if (mprotect(external_midi_argv, sz, PROT_READ)==-1) // make argv and command string read-only
|
||||
{
|
||||
perror("MUSIC_Init: mprotect");
|
||||
goto fallback;
|
||||
}
|
||||
# if 0
|
||||
{
|
||||
int i;
|
||||
initprintf("----Music argv:\n");
|
||||
for (i=0; i<numargs+1; i++)
|
||||
initprintf(" %s\n", external_midi_argv[i]);
|
||||
initprintf("----\n");
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
music_initialized = 1;
|
||||
return MUSIC_Ok;
|
||||
|
||||
fallback:
|
||||
initprintf("Error setting music command, falling back to timidity.\n");
|
||||
}
|
||||
|
||||
{
|
||||
static const char *s[] = { "/etc/timidity.cfg", "/etc/timidity/timidity.cfg", "/etc/timidity/freepats.cfg" };
|
||||
FILE *fp;
|
||||
int32_t i;
|
||||
|
||||
for (i = ARRAY_SIZE(s)-1; i>=0; i--)
|
||||
{
|
||||
fp = Bfopen(s[i], "r");
|
||||
if (fp == NULL)
|
||||
{
|
||||
if (i == 0)
|
||||
{
|
||||
initprintf("Error: couldn't open any of the following files:\n");
|
||||
for (i = ARRAY_SIZE(s)-1; i>=0; i--)
|
||||
initprintf("%s\n",s[i]);
|
||||
return MUSIC_Error;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else break;
|
||||
}
|
||||
Bfclose(fp);
|
||||
}
|
||||
|
||||
music_initialized = 1;
|
||||
return MUSIC_Ok;
|
||||
} // MUSIC_Init
|
||||
|
||||
|
||||
int32_t MUSIC_Shutdown(void)
|
||||
{
|
||||
// TODO - make sure this is being called from the menu -- SA
|
||||
#if !defined FORK_EXEC_MIDI
|
||||
if (external_midi)
|
||||
Mix_SetMusicCMD(NULL);
|
||||
#endif
|
||||
|
||||
MUSIC_StopSong();
|
||||
music_context = 0;
|
||||
music_initialized = 0;
|
||||
music_loopflag = MUSIC_PlayOnce;
|
||||
|
||||
return MUSIC_Ok;
|
||||
} // MUSIC_Shutdown
|
||||
|
||||
|
||||
void MUSIC_SetMaxFMMidiChannel(int32_t channel)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(channel);
|
||||
} // MUSIC_SetMaxFMMidiChannel
|
||||
|
||||
|
||||
void MUSIC_SetVolume(int32_t volume)
|
||||
{
|
||||
volume = max(0, volume);
|
||||
volume = min(volume, 255);
|
||||
|
||||
Mix_VolumeMusic(volume >> 1); // convert 0-255 to 0-128.
|
||||
} // MUSIC_SetVolume
|
||||
|
||||
|
||||
int32_t MUSIC_GetVolume(void)
|
||||
{
|
||||
return (Mix_VolumeMusic(-1) << 1); // convert 0-128 to 0-255.
|
||||
} // MUSIC_GetVolume
|
||||
|
||||
|
||||
void MUSIC_SetLoopFlag(int32_t loopflag)
|
||||
{
|
||||
music_loopflag = loopflag;
|
||||
} // MUSIC_SetLoopFlag
|
||||
|
||||
|
||||
void MUSIC_Continue(void)
|
||||
{
|
||||
if (Mix_PausedMusic())
|
||||
Mix_ResumeMusic();
|
||||
} // MUSIC_Continue
|
||||
|
||||
|
||||
void MUSIC_Pause(void)
|
||||
{
|
||||
Mix_PauseMusic();
|
||||
} // MUSIC_Pause
|
||||
|
||||
int32_t MUSIC_StopSong(void)
|
||||
{
|
||||
#if defined FORK_EXEC_MIDI
|
||||
if (external_midi)
|
||||
{
|
||||
if (external_midi_pid > 0)
|
||||
{
|
||||
int32_t ret;
|
||||
struct timespec ts;
|
||||
|
||||
external_midi_restart = 0; // make SIGCHLD handler a no-op
|
||||
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 5000000; // sleep 5ms at most
|
||||
|
||||
kill(external_midi_pid, SIGTERM);
|
||||
nanosleep(&ts, NULL);
|
||||
ret = waitpid(external_midi_pid, NULL, WNOHANG|WUNTRACED);
|
||||
// printf("(%d)", ret);
|
||||
|
||||
if (ret != external_midi_pid)
|
||||
{
|
||||
if (ret==-1)
|
||||
perror("waitpid");
|
||||
else
|
||||
{
|
||||
// we tried to be nice, but no...
|
||||
kill(external_midi_pid, SIGKILL);
|
||||
initprintf("%s: wait for SIGTERM timed out.\n", __func__);
|
||||
if (waitpid(external_midi_pid, NULL, WUNTRACED)==-1)
|
||||
perror("waitpid (2)");
|
||||
}
|
||||
}
|
||||
|
||||
external_midi_pid = -1;
|
||||
}
|
||||
|
||||
return MUSIC_Ok;
|
||||
}
|
||||
#endif
|
||||
|
||||
//if (!fx_initialized)
|
||||
if (!Mix_QuerySpec(NULL, NULL, NULL))
|
||||
{
|
||||
setErrorMessage("Need FX system initialized, too. Sorry.");
|
||||
return MUSIC_Error;
|
||||
} // if
|
||||
|
||||
if ((Mix_PlayingMusic()) || (Mix_PausedMusic()))
|
||||
Mix_HaltMusic();
|
||||
|
||||
if (music_musicchunk)
|
||||
Mix_FreeMusic(music_musicchunk);
|
||||
|
||||
music_musicchunk = NULL;
|
||||
|
||||
return MUSIC_Ok;
|
||||
} // MUSIC_StopSong
|
||||
|
||||
#if defined FORK_EXEC_MIDI
|
||||
static int32_t playmusic()
|
||||
{
|
||||
pid_t pid = vfork();
|
||||
|
||||
if (pid==-1) // error
|
||||
{
|
||||
initprintf("%s: vfork: %s\n", __func__, strerror(errno));
|
||||
return MUSIC_Error;
|
||||
}
|
||||
else if (pid==0) // child
|
||||
{
|
||||
// exec without PATH lookup
|
||||
if (execv(external_midi_argv[0], external_midi_argv) < 0)
|
||||
{
|
||||
perror("execv");
|
||||
_exit(1);
|
||||
}
|
||||
}
|
||||
else // parent
|
||||
{
|
||||
external_midi_pid = pid;
|
||||
}
|
||||
|
||||
return MUSIC_Ok;
|
||||
}
|
||||
|
||||
static void sigchld_handler(int signo)
|
||||
{
|
||||
if (signo==SIGCHLD && external_midi_restart)
|
||||
{
|
||||
int status;
|
||||
|
||||
if (external_midi_pid > 0)
|
||||
{
|
||||
if (waitpid(external_midi_pid, &status, WUNTRACED)==-1)
|
||||
perror("waitpid (3)");
|
||||
|
||||
if (WIFEXITED(status) && WEXITSTATUS(status)==0)
|
||||
{
|
||||
// loop ...
|
||||
playmusic();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Duke3D-specific. --ryan.
|
||||
// void MUSIC_PlayMusic(char *_filename)
|
||||
int32_t MUSIC_PlaySong(char *song, int32_t songsize, int32_t loopflag)
|
||||
{
|
||||
if (external_midi)
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
#if defined FORK_EXEC_MIDI
|
||||
static int32_t sigchld_handler_set = 0;
|
||||
|
||||
if (!sigchld_handler_set)
|
||||
{
|
||||
struct sigaction sa;
|
||||
sa.sa_handler=sigchld_handler;
|
||||
sa.sa_flags=0;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
|
||||
if (sigaction(SIGCHLD, &sa, NULL)==-1)
|
||||
initprintf("%s: sigaction: %s\n", __func__, strerror(errno));
|
||||
|
||||
sigchld_handler_set = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
fp = Bfopen(external_midi_tempfn, "wb");
|
||||
if (fp)
|
||||
{
|
||||
fwrite(song, 1, songsize, fp);
|
||||
Bfclose(fp);
|
||||
|
||||
#if defined FORK_EXEC_MIDI
|
||||
external_midi_restart = loopflag;
|
||||
int32_t retval = playmusic();
|
||||
if (retval != MUSIC_Ok)
|
||||
return retval;
|
||||
#else
|
||||
music_musicchunk = Mix_LoadMUS(external_midi_tempfn);
|
||||
if (!music_musicchunk)
|
||||
{
|
||||
initprintf("Mix_LoadMUS: %s\n", Mix_GetError());
|
||||
return MUSIC_Error;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
initprintf("%s: fopen: %s\n", __func__, strerror(errno));
|
||||
return MUSIC_Error;
|
||||
}
|
||||
}
|
||||
else
|
||||
music_musicchunk = Mix_LoadMUS_RW(SDL_RWFromMem(song, songsize)
|
||||
#if (SDL_MAJOR_VERSION > 1)
|
||||
, SDL_FALSE
|
||||
#endif
|
||||
);
|
||||
|
||||
if (music_musicchunk == NULL)
|
||||
return MUSIC_Error;
|
||||
|
||||
if (Mix_PlayMusic(music_musicchunk, (loopflag == MUSIC_LoopSong)?-1:0) == -1)
|
||||
{
|
||||
initprintf("Mix_PlayMusic: %s\n", Mix_GetError());
|
||||
return MUSIC_Error;
|
||||
}
|
||||
|
||||
return MUSIC_Ok;
|
||||
}
|
||||
|
||||
|
||||
void MUSIC_Update(void)
|
||||
{}
|
Loading…
Reference in a new issue