mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-28 06:53:58 +00:00
- fixed Windows version of snd_mididevice.
- removed mus2mis and xmi2mid converters from OPNMidi, because they are not needed. - moved the data file for OPNMidi into gzdoom.pk3.
This commit is contained in:
parent
8aeb6531be
commit
4978d979e8
14 changed files with 14 additions and 6218 deletions
|
@ -872,8 +872,6 @@ set( FASTMATH_SOURCES
|
||||||
sound/opnmidi/opnmidi_midiplay.cpp
|
sound/opnmidi/opnmidi_midiplay.cpp
|
||||||
sound/opnmidi/opnmidi_opn2.cpp
|
sound/opnmidi/opnmidi_opn2.cpp
|
||||||
sound/opnmidi/opnmidi_private.cpp
|
sound/opnmidi/opnmidi_private.cpp
|
||||||
sound/opnmidi/opnmidi_mus2mid.c
|
|
||||||
sound/opnmidi/opnmidi_xmi2mid.c
|
|
||||||
sound/opnmidi/Ym2612_ChipEmu.cpp
|
sound/opnmidi/Ym2612_ChipEmu.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1396,6 +1394,7 @@ install(TARGETS zdoom
|
||||||
|
|
||||||
source_group("Audio Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/sound/.+")
|
source_group("Audio Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/sound/.+")
|
||||||
source_group("Audio Files\\ADL MIDI" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/sound/adlmidi/.+")
|
source_group("Audio Files\\ADL MIDI" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/sound/adlmidi/.+")
|
||||||
|
source_group("Audio Files\\OPN MIDI" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/sound/opnmidi/.+")
|
||||||
source_group("Audio Files\\OPL Synth" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/sound/oplsynth/.+")
|
source_group("Audio Files\\OPL Synth" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/sound/oplsynth/.+")
|
||||||
source_group("Audio Files\\OPL Synth\\DOSBox" FILES sound/oplsynth/dosbox/opl.cpp sound/oplsynth/dosbox/opl.h)
|
source_group("Audio Files\\OPL Synth\\DOSBox" FILES sound/oplsynth/dosbox/opl.cpp sound/oplsynth/dosbox/opl.h)
|
||||||
source_group("Audio Files\\Timidity" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/sound/timidity/.+")
|
source_group("Audio Files\\Timidity" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/sound/timidity/.+")
|
||||||
|
|
|
@ -176,7 +176,7 @@ void ADLMIDIDevice::ComputeOutput(float *buffer, int len)
|
||||||
auto result = adl_generate(Renderer, len*2, &shortbuffer[0]);
|
auto result = adl_generate(Renderer, len*2, &shortbuffer[0]);
|
||||||
for(int i=0; i<result; i++)
|
for(int i=0; i<result; i++)
|
||||||
{
|
{
|
||||||
buffer[i] = shortbuffer[i] * (5.f/32768.f);
|
buffer[i] = shortbuffer[i] * (3.5f/32768.f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,8 +40,8 @@
|
||||||
#include "m_swap.h"
|
#include "m_swap.h"
|
||||||
#include "w_wad.h"
|
#include "w_wad.h"
|
||||||
#include "v_text.h"
|
#include "v_text.h"
|
||||||
|
#include "i_system.h"
|
||||||
#include "opnmidi/opnmidi.h"
|
#include "opnmidi/opnmidi.h"
|
||||||
#include "opnmidi/default_bank/xg_opn_bank.h"
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
enum
|
enum
|
||||||
|
@ -67,7 +67,13 @@ OPNMIDIDevice::OPNMIDIDevice(const char *args)
|
||||||
Renderer = opn2_init(44100); // todo: make it configurable
|
Renderer = opn2_init(44100); // todo: make it configurable
|
||||||
if (Renderer != nullptr)
|
if (Renderer != nullptr)
|
||||||
{
|
{
|
||||||
opn2_openBankData(Renderer, g_gm_opn2_bank, sizeof(g_gm_opn2_bank));
|
int lump = Wads.CheckNumForFullName("xg.wopn");
|
||||||
|
if (lump < 0)
|
||||||
|
{
|
||||||
|
I_Error("No OPL bank found");
|
||||||
|
}
|
||||||
|
FMemLump data = Wads.ReadLump(lump);
|
||||||
|
opn2_openBankData(Renderer, data.GetMem(), data.GetSize());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,7 +175,7 @@ void OPNMIDIDevice::ComputeOutput(float *buffer, int len)
|
||||||
auto result = opn2_generate(Renderer, len*2, &shortbuffer[0]);
|
auto result = opn2_generate(Renderer, len*2, &shortbuffer[0]);
|
||||||
for(int i=0; i<result; i++)
|
for(int i=0; i<result; i++)
|
||||||
{
|
{
|
||||||
buffer[i] = shortbuffer[i] * (5.f/32768.f);
|
buffer[i] = shortbuffer[i] * (1.f/32768.f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -156,6 +156,7 @@ void TimidityMIDIDevice::HandleLongEvent(const uint8_t *data, int len)
|
||||||
void TimidityMIDIDevice::ComputeOutput(float *buffer, int len)
|
void TimidityMIDIDevice::ComputeOutput(float *buffer, int len)
|
||||||
{
|
{
|
||||||
Renderer->ComputeOutput(buffer, len);
|
Renderer->ComputeOutput(buffer, len);
|
||||||
|
for (int i = 0; i < len * 2; i++) buffer[i] *= 0.7f;
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
|
@ -119,7 +119,7 @@ CUSTOM_CVAR (Int, snd_mididevice, DEF_MIDIDEV, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||||
if (!nummididevicesset)
|
if (!nummididevicesset)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if ((self >= (signed)nummididevices) || (self < -7))
|
if ((self >= (signed)nummididevices) || (self < -8))
|
||||||
{
|
{
|
||||||
// Don't do repeated message spam if there is no valid device.
|
// Don't do repeated message spam if there is no valid device.
|
||||||
if (self != 0)
|
if (self != 0)
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
output="xg_opn_bank.h"
|
|
||||||
|
|
||||||
out()
|
|
||||||
{
|
|
||||||
printf "${1}" >> $output
|
|
||||||
}
|
|
||||||
|
|
||||||
truncate -s 0 $output
|
|
||||||
|
|
||||||
out "/*===============================================================*\n"
|
|
||||||
out " This file is automatically generated by wopn2hpp.sh script\n"
|
|
||||||
out " PLEASE DON'T EDIT THIS DIRECTLY. Edit the gm.wonp file first,\n"
|
|
||||||
out " and then run a wopn2hpp.sh script to generate this file again\n"
|
|
||||||
out " *===============================================================*/\n\n"
|
|
||||||
out "static unsigned char g_gm_opn2_bank[] = \n"
|
|
||||||
out "{\n"
|
|
||||||
hexdump -ve '12/1 "0x%02x, " "\n"' xg.wopn >> $output
|
|
||||||
out "0x00\n"
|
|
||||||
out "};\n"
|
|
||||||
out "\n"
|
|
||||||
|
|
||||||
sed -i "s/0x /0x00/g" $output
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -23,9 +23,6 @@
|
||||||
|
|
||||||
#include "opnmidi_private.hpp"
|
#include "opnmidi_private.hpp"
|
||||||
|
|
||||||
#include "opnmidi_mus2mid.h"
|
|
||||||
#include "opnmidi_xmi2mid.h"
|
|
||||||
|
|
||||||
uint64_t OPNMIDIplay::ReadBEint(const void *buffer, size_t nbytes)
|
uint64_t OPNMIDIplay::ReadBEint(const void *buffer, size_t nbytes)
|
||||||
{
|
{
|
||||||
uint64_t result = 0;
|
uint64_t result = 0;
|
||||||
|
@ -370,76 +367,6 @@ riffskip:
|
||||||
fr.seek(7 - static_cast<long>(HeaderSize), SEEK_CUR);
|
fr.seek(7 - static_cast<long>(HeaderSize), SEEK_CUR);
|
||||||
is_GMF = true;
|
is_GMF = true;
|
||||||
}
|
}
|
||||||
else if(std::memcmp(HeaderBuf, "MUS\x1A", 4) == 0)
|
|
||||||
{
|
|
||||||
// MUS/DMX files (Doom)
|
|
||||||
fr.seek(0, SEEK_END);
|
|
||||||
size_t mus_len = fr.tell();
|
|
||||||
fr.seek(0, SEEK_SET);
|
|
||||||
uint8_t *mus = (uint8_t *)malloc(mus_len);
|
|
||||||
if(!mus)
|
|
||||||
{
|
|
||||||
errorStringOut = "Out of memory!";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
fr.read(mus, 1, mus_len);
|
|
||||||
//Close source stream
|
|
||||||
fr.close();
|
|
||||||
|
|
||||||
uint8_t *mid = NULL;
|
|
||||||
uint32_t mid_len = 0;
|
|
||||||
int m2mret = OpnMidi_mus2midi(mus, static_cast<uint32_t>(mus_len),
|
|
||||||
&mid, &mid_len, 0);
|
|
||||||
if(mus) free(mus);
|
|
||||||
if(m2mret < 0)
|
|
||||||
{
|
|
||||||
errorStringOut = "Invalid MUS/DMX data format!";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
cvt_buf.reset(mid);
|
|
||||||
//Open converted MIDI file
|
|
||||||
fr.openData(mid, static_cast<size_t>(mid_len));
|
|
||||||
//Re-Read header again!
|
|
||||||
goto riffskip;
|
|
||||||
}
|
|
||||||
else if(std::memcmp(HeaderBuf, "FORM", 4) == 0)
|
|
||||||
{
|
|
||||||
if(std::memcmp(HeaderBuf + 8, "XDIR", 4) != 0)
|
|
||||||
{
|
|
||||||
fr.close();
|
|
||||||
errorStringOut = fr._fileName + ": Invalid format\n";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
fr.seek(0, SEEK_END);
|
|
||||||
size_t mus_len = fr.tell();
|
|
||||||
fr.seek(0, SEEK_SET);
|
|
||||||
uint8_t *mus = (uint8_t*)malloc(mus_len);
|
|
||||||
if(!mus)
|
|
||||||
{
|
|
||||||
errorStringOut = "Out of memory!";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
fr.read(mus, 1, mus_len);
|
|
||||||
//Close source stream
|
|
||||||
fr.close();
|
|
||||||
|
|
||||||
uint8_t *mid = NULL;
|
|
||||||
uint32_t mid_len = 0;
|
|
||||||
int m2mret = OpnMidi_xmi2midi(mus, static_cast<uint32_t>(mus_len),
|
|
||||||
&mid, &mid_len, XMIDI_CONVERT_NOCONVERSION);
|
|
||||||
if(mus) free(mus);
|
|
||||||
if(m2mret < 0)
|
|
||||||
{
|
|
||||||
errorStringOut = "Invalid XMI data format!";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
cvt_buf.reset(mid);
|
|
||||||
//Open converted MIDI file
|
|
||||||
fr.openData(mid, static_cast<size_t>(mid_len));
|
|
||||||
//Re-Read header again!
|
|
||||||
goto riffskip;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Try to identify RSXX format
|
// Try to identify RSXX format
|
||||||
|
|
|
@ -1,451 +0,0 @@
|
||||||
/*
|
|
||||||
* MUS2MIDI: MUS to MIDI Library
|
|
||||||
*
|
|
||||||
* Copyright (C) 2014 Bret Curtis
|
|
||||||
* Copyright (C) WildMIDI Developers 2015-2016
|
|
||||||
* ADLMIDI Library API: Copyright (c) 2017-2018 Vitaly Novichkov <admin@wohlnet.ru>
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Library General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Library General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Library General Public
|
|
||||||
* License along with this library; if not, write to the
|
|
||||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
|
||||||
* Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "opnmidi_mus2mid.h"
|
|
||||||
|
|
||||||
#define FREQUENCY 140 /* default Hz or BPM */
|
|
||||||
|
|
||||||
#if 0 /* older units: */
|
|
||||||
#define TEMPO 0x001aa309 /* MPQN: 60000000 / 34.37Hz = 1745673 */
|
|
||||||
#define DIVISION 0x0059 /* 89 -- used by many mus2midi converters */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define TEMPO 0x00068A1B /* MPQN: 60000000 / 140BPM (140Hz) = 428571 */
|
|
||||||
/* 0x000D1436 -> MPQN: 60000000 / 70BPM (70Hz) = 857142 */
|
|
||||||
|
|
||||||
#define DIVISION 0x0101 /* 257 for 140Hz files with a 140MPQN */
|
|
||||||
/* 0x0088 -> 136 for 70Hz files with a 140MPQN */
|
|
||||||
/* 0x010B -> 267 for 70hz files with a 70MPQN */
|
|
||||||
/* 0x01F9 -> 505 for 140hz files with a 70MPQN */
|
|
||||||
|
|
||||||
/* New
|
|
||||||
* QLS: MPQN/1000000 = 0.428571
|
|
||||||
* TDPS: QLS/PPQN = 0.428571/136 = 0.003151257
|
|
||||||
* PPQN: 136
|
|
||||||
*
|
|
||||||
* QLS: MPQN/1000000 = 0.428571
|
|
||||||
* TDPS: QLS/PPQN = 0.428571/257 = 0.001667591
|
|
||||||
* PPQN: 257
|
|
||||||
*
|
|
||||||
* QLS: MPQN/1000000 = 0.857142
|
|
||||||
* TDPS: QLS/PPQN = 0.857142/267 = 0.00321027
|
|
||||||
* PPQN: 267
|
|
||||||
*
|
|
||||||
* QLS: MPQN/1000000 = 0.857142
|
|
||||||
* TDPS: QLS/PPQN = 0.857142/505 = 0.001697311
|
|
||||||
* PPQN: 505
|
|
||||||
*
|
|
||||||
* Old
|
|
||||||
* QLS: MPQN/1000000 = 1.745673
|
|
||||||
* TDPS: QLS/PPQN = 1.745673 / 89 = 0.019614303 (seconds per tick)
|
|
||||||
* PPQN: (TDPS = QLS/PPQN) (0.019614303 = 1.745673/PPQN) (0.019614303*PPQN = 1.745673) (PPQN = 89.000001682)
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define MUSEVENT_KEYOFF 0
|
|
||||||
#define MUSEVENT_KEYON 1
|
|
||||||
#define MUSEVENT_PITCHWHEEL 2
|
|
||||||
#define MUSEVENT_CHANNELMODE 3
|
|
||||||
#define MUSEVENT_CONTROLLERCHANGE 4
|
|
||||||
#define MUSEVENT_END 6
|
|
||||||
|
|
||||||
#define MIDI_MAXCHANNELS 16
|
|
||||||
|
|
||||||
static char MUS_ID[] = { 'M', 'U', 'S', 0x1A };
|
|
||||||
|
|
||||||
static uint8_t midimap[] =
|
|
||||||
{/* MIDI Number Description */
|
|
||||||
0, /* 0 program change */
|
|
||||||
0, /* 1 bank selection */
|
|
||||||
0x01, /* 2 Modulation pot (frequency vibrato depth) */
|
|
||||||
0x07, /* 3 Volume: 0-silent, ~100-normal, 127-loud */
|
|
||||||
0x0A, /* 4 Pan (balance) pot: 0-left, 64-center (default), 127-right */
|
|
||||||
0x0B, /* 5 Expression pot */
|
|
||||||
0x5B, /* 6 Reverb depth */
|
|
||||||
0x5D, /* 7 Chorus depth */
|
|
||||||
0x40, /* 8 Sustain pedal */
|
|
||||||
0x43, /* 9 Soft pedal */
|
|
||||||
0x78, /* 10 All sounds off */
|
|
||||||
0x7B, /* 11 All notes off */
|
|
||||||
0x7E, /* 12 Mono (use numchannels + 1) */
|
|
||||||
0x7F, /* 13 Poly */
|
|
||||||
0x79, /* 14 reset all controllers */
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct MUSHeader {
|
|
||||||
char ID[4]; /* identifier: "MUS" 0x1A */
|
|
||||||
uint16_t scoreLen;
|
|
||||||
uint16_t scoreStart;
|
|
||||||
uint16_t channels; /* count of primary channels */
|
|
||||||
uint16_t sec_channels; /* count of secondary channels */
|
|
||||||
uint16_t instrCnt;
|
|
||||||
} MUSHeader ;
|
|
||||||
#define MUS_HEADERSIZE 14
|
|
||||||
|
|
||||||
typedef struct MidiHeaderChunk {
|
|
||||||
char name[4];
|
|
||||||
int32_t length;
|
|
||||||
int16_t format; /* make 0 */
|
|
||||||
int16_t ntracks;/* make 1 */
|
|
||||||
int16_t division; /* 0xe250 ?? */
|
|
||||||
} MidiHeaderChunk;
|
|
||||||
#define MIDI_HEADERSIZE 14
|
|
||||||
|
|
||||||
typedef struct MidiTrackChunk {
|
|
||||||
char name[4];
|
|
||||||
int32_t length;
|
|
||||||
} MidiTrackChunk;
|
|
||||||
#define TRK_CHUNKSIZE 8
|
|
||||||
|
|
||||||
struct mus_ctx {
|
|
||||||
uint8_t *src, *src_ptr;
|
|
||||||
uint32_t srcsize;
|
|
||||||
uint32_t datastart;
|
|
||||||
uint8_t *dst, *dst_ptr;
|
|
||||||
uint32_t dstsize, dstrem;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define DST_CHUNK 8192
|
|
||||||
static void resize_dst(struct mus_ctx *ctx) {
|
|
||||||
uint32_t pos = (uint32_t)(ctx->dst_ptr - ctx->dst);
|
|
||||||
ctx->dst = realloc(ctx->dst, ctx->dstsize + DST_CHUNK);
|
|
||||||
ctx->dstsize += DST_CHUNK;
|
|
||||||
ctx->dstrem += DST_CHUNK;
|
|
||||||
ctx->dst_ptr = ctx->dst + pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void write1(struct mus_ctx *ctx, uint32_t val)
|
|
||||||
{
|
|
||||||
if (ctx->dstrem < 1)
|
|
||||||
resize_dst(ctx);
|
|
||||||
*ctx->dst_ptr++ = val & 0xff;
|
|
||||||
ctx->dstrem--;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void write2(struct mus_ctx *ctx, uint32_t val)
|
|
||||||
{
|
|
||||||
if (ctx->dstrem < 2)
|
|
||||||
resize_dst(ctx);
|
|
||||||
*ctx->dst_ptr++ = (val>>8) & 0xff;
|
|
||||||
*ctx->dst_ptr++ = val & 0xff;
|
|
||||||
ctx->dstrem -= 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void write4(struct mus_ctx *ctx, uint32_t val)
|
|
||||||
{
|
|
||||||
if (ctx->dstrem < 4)
|
|
||||||
resize_dst(ctx);
|
|
||||||
*ctx->dst_ptr++ = (val>>24)&0xff;
|
|
||||||
*ctx->dst_ptr++ = (val>>16)&0xff;
|
|
||||||
*ctx->dst_ptr++ = (val>>8) & 0xff;
|
|
||||||
*ctx->dst_ptr++ = val & 0xff;
|
|
||||||
ctx->dstrem -= 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void seekdst(struct mus_ctx *ctx, uint32_t pos) {
|
|
||||||
ctx->dst_ptr = ctx->dst + pos;
|
|
||||||
while (ctx->dstsize < pos)
|
|
||||||
resize_dst(ctx);
|
|
||||||
ctx->dstrem = ctx->dstsize - pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void skipdst(struct mus_ctx *ctx, int32_t pos) {
|
|
||||||
size_t newpos;
|
|
||||||
ctx->dst_ptr += pos;
|
|
||||||
newpos = ctx->dst_ptr - ctx->dst;
|
|
||||||
while (ctx->dstsize < newpos)
|
|
||||||
resize_dst(ctx);
|
|
||||||
ctx->dstrem = (uint32_t)(ctx->dstsize - newpos);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t getdstpos(struct mus_ctx *ctx) {
|
|
||||||
return (uint32_t)(ctx->dst_ptr - ctx->dst);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* writes a variable length integer to a buffer, and returns bytes written */
|
|
||||||
static int32_t writevarlen(int32_t value, uint8_t *out)
|
|
||||||
{
|
|
||||||
int32_t buffer, count = 0;
|
|
||||||
|
|
||||||
buffer = value & 0x7f;
|
|
||||||
while ((value >>= 7) > 0) {
|
|
||||||
buffer <<= 8;
|
|
||||||
buffer += 0x80;
|
|
||||||
buffer += (value & 0x7f);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
++count;
|
|
||||||
*out = (uint8_t)buffer;
|
|
||||||
++out;
|
|
||||||
if (buffer & 0x80)
|
|
||||||
buffer >>= 8;
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return (count);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define READ_INT16(b) ((b)[0] | ((b)[1] << 8))
|
|
||||||
#define READ_INT32(b) ((b)[0] | ((b)[1] << 8) | ((b)[2] << 16) | ((b)[3] << 24))
|
|
||||||
|
|
||||||
int OpnMidi_mus2midi(uint8_t *in, uint32_t insize,
|
|
||||||
uint8_t **out, uint32_t *outsize,
|
|
||||||
uint16_t frequency) {
|
|
||||||
struct mus_ctx ctx;
|
|
||||||
MUSHeader header;
|
|
||||||
uint8_t *cur, *end;
|
|
||||||
uint32_t track_size_pos, begin_track_pos, current_pos;
|
|
||||||
int32_t delta_time;/* Delta time for midi event */
|
|
||||||
int temp, ret = -1;
|
|
||||||
int channel_volume[MIDI_MAXCHANNELS];
|
|
||||||
int channelMap[MIDI_MAXCHANNELS], currentChannel;
|
|
||||||
|
|
||||||
if (insize < MUS_HEADERSIZE) {
|
|
||||||
/*_WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(too short)", 0);*/
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!frequency)
|
|
||||||
frequency = FREQUENCY;
|
|
||||||
|
|
||||||
/* read the MUS header and set our location */
|
|
||||||
memcpy(header.ID, in, 4);
|
|
||||||
header.scoreLen = READ_INT16(&in[4]);
|
|
||||||
header.scoreStart = READ_INT16(&in[6]);
|
|
||||||
header.channels = READ_INT16(&in[8]);
|
|
||||||
header.sec_channels = READ_INT16(&in[10]);
|
|
||||||
header.instrCnt = READ_INT16(&in[12]);
|
|
||||||
|
|
||||||
if (memcmp(header.ID, MUS_ID, 4)) {
|
|
||||||
/*_WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_MUS, NULL, 0);*/
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
if (insize < (uint32_t)header.scoreLen + (uint32_t)header.scoreStart) {
|
|
||||||
/*_WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(too short)", 0);*/
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
/* channel #15 should be excluded in the numchannels field: */
|
|
||||||
if (header.channels > MIDI_MAXCHANNELS - 1) {
|
|
||||||
/*_WM_GLOBAL_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, NULL, 0);*/
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(&ctx, 0, sizeof(struct mus_ctx));
|
|
||||||
ctx.src = ctx.src_ptr = in;
|
|
||||||
ctx.srcsize = insize;
|
|
||||||
|
|
||||||
ctx.dst = calloc(DST_CHUNK, sizeof(uint8_t));
|
|
||||||
ctx.dst_ptr = ctx.dst;
|
|
||||||
ctx.dstsize = DST_CHUNK;
|
|
||||||
ctx.dstrem = DST_CHUNK;
|
|
||||||
|
|
||||||
/* Map channel 15 to 9 (percussions) */
|
|
||||||
for (temp = 0; temp < MIDI_MAXCHANNELS; ++temp) {
|
|
||||||
channelMap[temp] = -1;
|
|
||||||
channel_volume[temp] = 0x40;
|
|
||||||
}
|
|
||||||
channelMap[15] = 9;
|
|
||||||
|
|
||||||
/* Header is 14 bytes long and add the rest as well */
|
|
||||||
write1(&ctx, 'M');
|
|
||||||
write1(&ctx, 'T');
|
|
||||||
write1(&ctx, 'h');
|
|
||||||
write1(&ctx, 'd');
|
|
||||||
write4(&ctx, 6); /* length of header */
|
|
||||||
write2(&ctx, 0); /* MIDI type (always 0) */
|
|
||||||
write2(&ctx, 1); /* MUS files only have 1 track */
|
|
||||||
write2(&ctx, DIVISION); /* division */
|
|
||||||
|
|
||||||
/* Write out track header and track length position for later */
|
|
||||||
begin_track_pos = getdstpos(&ctx);
|
|
||||||
write1(&ctx, 'M');
|
|
||||||
write1(&ctx, 'T');
|
|
||||||
write1(&ctx, 'r');
|
|
||||||
write1(&ctx, 'k');
|
|
||||||
track_size_pos = getdstpos(&ctx);
|
|
||||||
skipdst(&ctx, 4);
|
|
||||||
|
|
||||||
/* write tempo: microseconds per quarter note */
|
|
||||||
write1(&ctx, 0x00); /* delta time */
|
|
||||||
write1(&ctx, 0xff); /* sys command */
|
|
||||||
write2(&ctx, 0x5103); /* command - set tempo */
|
|
||||||
write1(&ctx, TEMPO & 0x000000ff);
|
|
||||||
write1(&ctx, (TEMPO & 0x0000ff00) >> 8);
|
|
||||||
write1(&ctx, (TEMPO & 0x00ff0000) >> 16);
|
|
||||||
|
|
||||||
/* Percussions channel starts out at full volume */
|
|
||||||
write1(&ctx, 0x00);
|
|
||||||
write1(&ctx, 0xB9);
|
|
||||||
write1(&ctx, 0x07);
|
|
||||||
write1(&ctx, 127);
|
|
||||||
|
|
||||||
/* get current position in source, and end of position */
|
|
||||||
cur = in + header.scoreStart;
|
|
||||||
end = cur + header.scoreLen;
|
|
||||||
|
|
||||||
currentChannel = 0;
|
|
||||||
delta_time = 0;
|
|
||||||
|
|
||||||
/* main loop */
|
|
||||||
while(cur < end){
|
|
||||||
/*printf("LOOP DEBUG: %d\r\n",iterator++);*/
|
|
||||||
uint8_t channel;
|
|
||||||
uint8_t event;
|
|
||||||
uint8_t temp_buffer[32]; /* temp buffer for current iterator */
|
|
||||||
uint8_t *out_local = temp_buffer;
|
|
||||||
uint8_t status, bit1, bit2, bitc = 2;
|
|
||||||
|
|
||||||
/* read in current bit */
|
|
||||||
event = *cur++;
|
|
||||||
channel = (event & 15); /* current channel */
|
|
||||||
|
|
||||||
/* write variable length delta time */
|
|
||||||
out_local += writevarlen(delta_time, out_local);
|
|
||||||
|
|
||||||
/* set all channels to 127 (max) volume */
|
|
||||||
if (channelMap[channel] < 0) {
|
|
||||||
*out_local++ = 0xB0 + currentChannel;
|
|
||||||
*out_local++ = 0x07;
|
|
||||||
*out_local++ = 127;
|
|
||||||
*out_local++ = 0x00;
|
|
||||||
channelMap[channel] = currentChannel++;
|
|
||||||
if (currentChannel == 9)
|
|
||||||
++currentChannel;
|
|
||||||
}
|
|
||||||
status = channelMap[channel];
|
|
||||||
|
|
||||||
/* handle events */
|
|
||||||
switch ((event & 122) >> 4){
|
|
||||||
case MUSEVENT_KEYOFF:
|
|
||||||
status |= 0x80;
|
|
||||||
bit1 = *cur++;
|
|
||||||
bit2 = 0x40;
|
|
||||||
break;
|
|
||||||
case MUSEVENT_KEYON:
|
|
||||||
status |= 0x90;
|
|
||||||
bit1 = *cur & 127;
|
|
||||||
if (*cur++ & 128) /* volume bit? */
|
|
||||||
channel_volume[channelMap[channel]] = *cur++;
|
|
||||||
bit2 = channel_volume[channelMap[channel]];
|
|
||||||
break;
|
|
||||||
case MUSEVENT_PITCHWHEEL:
|
|
||||||
status |= 0xE0;
|
|
||||||
bit1 = (*cur & 1) >> 6;
|
|
||||||
bit2 = (*cur++ >> 1) & 127;
|
|
||||||
break;
|
|
||||||
case MUSEVENT_CHANNELMODE:
|
|
||||||
status |= 0xB0;
|
|
||||||
if (*cur >= sizeof(midimap) / sizeof(midimap[0])) {
|
|
||||||
/*_WM_ERROR_NEW("%s:%i: can't map %u to midi",
|
|
||||||
__FUNCTION__, __LINE__, *cur);*/
|
|
||||||
goto _end;
|
|
||||||
}
|
|
||||||
bit1 = midimap[*cur++];
|
|
||||||
bit2 = (*cur++ == 12) ? header.channels + 1 : 0x00;
|
|
||||||
break;
|
|
||||||
case MUSEVENT_CONTROLLERCHANGE:
|
|
||||||
if (*cur == 0) {
|
|
||||||
cur++;
|
|
||||||
status |= 0xC0;
|
|
||||||
bit1 = *cur++;
|
|
||||||
bit2 = 0;/* silence bogus warnings */
|
|
||||||
bitc = 1;
|
|
||||||
} else {
|
|
||||||
status |= 0xB0;
|
|
||||||
if (*cur >= sizeof(midimap) / sizeof(midimap[0])) {
|
|
||||||
/*_WM_ERROR_NEW("%s:%i: can't map %u to midi",
|
|
||||||
__FUNCTION__, __LINE__, *cur);*/
|
|
||||||
goto _end;
|
|
||||||
}
|
|
||||||
bit1 = midimap[*cur++];
|
|
||||||
bit2 = *cur++;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case MUSEVENT_END: /* End */
|
|
||||||
status = 0xff;
|
|
||||||
bit1 = 0x2f;
|
|
||||||
bit2 = 0x00;
|
|
||||||
if (cur != end) { /* should we error here or report-only? */
|
|
||||||
/*_WM_DEBUG_MSG("%s:%i: MUS buffer off by %ld bytes",
|
|
||||||
__FUNCTION__, __LINE__, (long)(cur - end));*/
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 5:/* Unknown */
|
|
||||||
case 7:/* Unknown */
|
|
||||||
default:/* shouldn't happen */
|
|
||||||
/*_WM_ERROR_NEW("%s:%i: unrecognized event (%u)",
|
|
||||||
__FUNCTION__, __LINE__, event);*/
|
|
||||||
goto _end;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* write it out */
|
|
||||||
*out_local++ = status;
|
|
||||||
*out_local++ = bit1;
|
|
||||||
if (bitc == 2)
|
|
||||||
*out_local++ = bit2;
|
|
||||||
|
|
||||||
/* write out our temp buffer */
|
|
||||||
if (out_local != temp_buffer)
|
|
||||||
{
|
|
||||||
if (ctx.dstrem < sizeof(temp_buffer))
|
|
||||||
resize_dst(&ctx);
|
|
||||||
|
|
||||||
memcpy(ctx.dst_ptr, temp_buffer, out_local - temp_buffer);
|
|
||||||
ctx.dst_ptr += out_local - temp_buffer;
|
|
||||||
ctx.dstrem -= out_local - temp_buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event & 128) {
|
|
||||||
delta_time = 0;
|
|
||||||
do {
|
|
||||||
delta_time = (int32_t)((delta_time * 128 + (*cur & 127)) * (140.0 / (double)frequency));
|
|
||||||
} while ((*cur++ & 128));
|
|
||||||
} else {
|
|
||||||
delta_time = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* write out track length */
|
|
||||||
current_pos = getdstpos(&ctx);
|
|
||||||
seekdst(&ctx, track_size_pos);
|
|
||||||
write4(&ctx, current_pos - begin_track_pos - TRK_CHUNKSIZE);
|
|
||||||
seekdst(&ctx, current_pos); /* reseek to end position */
|
|
||||||
|
|
||||||
*out = ctx.dst;
|
|
||||||
*outsize = ctx.dstsize - ctx.dstrem;
|
|
||||||
ret = 0;
|
|
||||||
|
|
||||||
_end: /* cleanup */
|
|
||||||
if (ret < 0) {
|
|
||||||
free(ctx.dst);
|
|
||||||
*out = NULL;
|
|
||||||
*outsize = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (ret);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,49 +0,0 @@
|
||||||
/*
|
|
||||||
* MUS2MIDI: DMX (DOOM) MUS to MIDI Library Header
|
|
||||||
*
|
|
||||||
* Copyright (C) 2014-2016 Bret Curtis
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Library General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Library General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Library General Public
|
|
||||||
* License along with this library; if not, write to the
|
|
||||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
|
||||||
* Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef MUSLIB_H
|
|
||||||
#define MUSLIB_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#ifdef __DJGPP__
|
|
||||||
typedef signed char int8_t;
|
|
||||||
typedef unsigned char uint8_t;
|
|
||||||
typedef signed short int16_t;
|
|
||||||
typedef unsigned short uint16_t;
|
|
||||||
typedef signed long int32_t;
|
|
||||||
typedef unsigned long uint32_t;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int OpnMidi_mus2midi(uint8_t *in, uint32_t insize,
|
|
||||||
uint8_t **out, uint32_t *outsize,
|
|
||||||
uint16_t frequency);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* MUSLIB_H */
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,60 +0,0 @@
|
||||||
/*
|
|
||||||
* XMIDI: Miles XMIDI to MID Library Header
|
|
||||||
*
|
|
||||||
* Copyright (C) 2001 Ryan Nunn
|
|
||||||
* Copyright (C) 2014-2016 Bret Curtis
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Library General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Library General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Library General Public
|
|
||||||
* License along with this library; if not, write to the
|
|
||||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
|
||||||
* Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* XMIDI Converter */
|
|
||||||
|
|
||||||
#ifndef XMIDILIB_H
|
|
||||||
#define XMIDILIB_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#ifdef __DJGPP__
|
|
||||||
typedef signed char int8_t;
|
|
||||||
typedef unsigned char uint8_t;
|
|
||||||
typedef signed short int16_t;
|
|
||||||
typedef unsigned short uint16_t;
|
|
||||||
typedef signed long int32_t;
|
|
||||||
typedef unsigned long uint32_t;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Conversion types for Midi files */
|
|
||||||
#define XMIDI_CONVERT_NOCONVERSION 0x00
|
|
||||||
#define XMIDI_CONVERT_MT32_TO_GM 0x01
|
|
||||||
#define XMIDI_CONVERT_MT32_TO_GS 0x02
|
|
||||||
#define XMIDI_CONVERT_MT32_TO_GS127 0x03 /* This one is broken, don't use */
|
|
||||||
#define XMIDI_CONVERT_MT32_TO_GS127DRUM 0x04 /* This one is broken, don't use */
|
|
||||||
#define XMIDI_CONVERT_GS127_TO_GS 0x05
|
|
||||||
|
|
||||||
int OpnMidi_xmi2midi(uint8_t *in, uint32_t insize,
|
|
||||||
uint8_t **out, uint32_t *outsize,
|
|
||||||
uint32_t convert_type);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* XMIDILIB_H */
|
|
|
@ -2943,7 +2943,7 @@ void WildMidi_Renderer::ComputeOutput(float *fbuffer, int len)
|
||||||
}
|
}
|
||||||
for (; buffer < newbuf; ++buffer)
|
for (; buffer < newbuf; ++buffer)
|
||||||
{
|
{
|
||||||
*(float *)buffer = (float)*buffer * (2.f / 32768.f); // boost the volume because Wildmidi is far more quiet than the other synths and therefore hard to balance.
|
*(float *)buffer = (float)*buffer * (1.3f / 32768.f); // boost the volume because Wildmidi is far more quiet than the other synths and therefore hard to balance.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue