Tracker playback via DUMB

This commit is contained in:
eukos 2015-07-30 21:49:42 +02:00
parent 6ad3ae8e9c
commit e7c85e960d
11 changed files with 255 additions and 457 deletions

View file

@ -39,7 +39,7 @@ CC=gcc -m32
BASE_CFLAGS=-Dstricmp=strcasecmp
RELEASE_CFLAGS=$(BASE_CFLAGS)
DEBUG_CFLAGS=$(BASE_CFLAGS) -g
LDFLAGS=-lm -ldl
LDFLAGS=-lm -ldl /usr/local/lib/libdumb.a
XLDFLAGS=-L/usr/X11R6/lib -lX11 -lXext -lXxf86dga
XCFLAGS=-DX11
@ -143,7 +143,8 @@ X11_OBJS = \
$(BUILDDIR)/obj/view.o \
$(BUILDDIR)/obj/wad.o \
$(BUILDDIR)/obj/world.o \
$(BUILDDIR)/obj/cd_linux.o \
$(BUILDDIR)/obj/tracker_linux.o \
$(BUILDDIR)/obj/cd_null.o \
$(BUILDDIR)/obj/sys_linux.o \
$(BUILDDIR)/obj/vid_x.o \
$(BUILDDIR)/obj/snd_dma.o \
@ -376,7 +377,10 @@ $(BUILDDIR)/obj/wad.o : $(MOUNT_DIR)/wad.c
$(BUILDDIR)/obj/world.o : $(MOUNT_DIR)/world.c
$(DO_X11_CC)
$(BUILDDIR)/obj/cd_linux.o : $(MOUNT_DIR)/cd_linux.c
$(BUILDDIR)/obj/tracker_linux.o : $(MOUNT_DIR)/tracker_linux.c
$(DO_X11_CC)
$(BUILDDIR)/obj/cd_null.o : $(MOUNT_DIR)/cd_null.c
$(DO_X11_CC)
$(BUILDDIR)/obj/sys_linux.o :$(MOUNT_DIR)/sys_linux.c

View file

@ -1,5 +0,0 @@
// stupid workaround file for playing back midis.
// BO

View file

@ -140,4 +140,3 @@ LBPatch14:
LBPatch15:
movb %cl,1(%edi)
addl $0x2,%edi

View file

@ -32,7 +32,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define MAX_MAP_PLANES 32767
#define MAX_MAP_NODES 32767 // because negative shorts are contents
#define MAX_MAP_CLIPNODES 65535 //
#define MAX_MAP_CLIPNODES 65535
#define MAX_MAP_LEAFS 32768
#define MAX_MAP_VERTS 65535
#define MAX_MAP_FACES 65535
@ -58,7 +58,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define MAX_MAP_PLANES 32767
#define MAX_MAP_NODES 32767 // because negative shorts are contents
#define MAX_MAP_CLIPNODES 32767 //
#define MAX_MAP_CLIPNODES 32767
#define MAX_MAP_LEAFS 8192
#define MAX_MAP_VERTS 65535
#define MAX_MAP_FACES 32767
@ -165,8 +165,6 @@ typedef struct
int type; // PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate
} dplane_t;
#define CONTENTS_EMPTY -1
#define CONTENTS_SOLID -2
#define CONTENTS_WATER -3
@ -176,20 +174,19 @@ typedef struct
#define CONTENTS_ORIGIN -7 // removed at csg time
#define CONTENTS_CLIP -8 // changed to contents_solid
#define CONTENTS_CURRENT_0 -9
#define CONTENTS_CURRENT_90 -10
#define CONTENTS_CURRENT_0 -9
#define CONTENTS_CURRENT_90 -10
#define CONTENTS_CURRENT_180 -11
#define CONTENTS_CURRENT_270 -12
#define CONTENTS_CURRENT_UP -13
#define CONTENTS_CURRENT_UP -13
#define CONTENTS_CURRENT_DOWN -14
// !!! if this is changed, it must be changed in asm_i386.h too !!!
typedef struct
{
int planenum;
int planenum;
short children[2]; // negative numbers are -(leafs+1), not nodes
short mins[3]; // for sphere culling
short mins[3]; // for sphere culling
short maxs[3];
unsigned short firstface;
unsigned short numfaces; // counting both sides
@ -197,18 +194,18 @@ typedef struct
typedef struct
{
int planenum;
int planenum;
short children[2]; // negative numbers are contents
} dclipnode_t;
typedef struct texinfo_s
{
float vecs[2][4]; // [s/t][xyz offset]
int miptex;
int flags;
float vecs[2][4]; // [s/t][xyz offset]
int miptex;
int flags;
} texinfo_t;
#define TEX_SPECIAL 1 // sky or slime, no lightmap or 256 subdivision
#define TEX_SPECIAL 1 // sky or slime, no lightmap or 256 subdivision
// note that edge 0 is never used, because negative edge nums are used for
// counterclockwise use of the edge in a face
@ -232,21 +229,19 @@ typedef struct
int lightofs; // start of [numstyles*surfsize] samples
} dface_t;
#define AMBIENT_WATER 0
#define AMBIENT_SKY 1
#define AMBIENT_SKY 1
#define AMBIENT_SLIME 2
#define AMBIENT_LAVA 3
#define NUM_AMBIENTS 4 // automatic ambient sounds
#define NUM_AMBIENTS 4 // automatic ambient sounds
// leaf 0 is the generic CONTENTS_SOLID leaf, used for all solid areas
// all other leafs need visibility info
typedef struct
{
int contents;
int visofs; // -1 = no visibility info
int visofs; // -1 = no visibility info
short mins[3]; // for frustum culling
short maxs[3];
@ -265,7 +260,6 @@ typedef struct
#define ANGLE_UP -1
#define ANGLE_DOWN -2
// the utilities get to be lazy and just use large static arrays
extern int nummodels;

View file

@ -1,416 +0,0 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// Quake is a trademark of Id Software, Inc., (c) 1996 Id Software, Inc. All
// rights reserved.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/file.h>
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <linux/cdrom.h>
#include "quakedef.h"
static qboolean cdValid = false;
static qboolean playing = false;
static qboolean wasPlaying = false;
static qboolean initialized = false;
static qboolean enabled = true;
static qboolean playLooping = false;
static float cdvolume;
static byte remap[100];
static byte playTrack;
static byte maxTrack;
static int cdfile = -1;
static char cd_dev[64] = "/dev/cdrom";
static void CDAudio_Eject(void)
{
if (cdfile == -1 || !enabled)
return; // no cd init'd
if ( ioctl(cdfile, CDROMEJECT) == -1 )
Con_DPrintf("ioctl cdromeject failed\n");
}
static void CDAudio_CloseDoor(void)
{
if (cdfile == -1 || !enabled)
return; // no cd init'd
if ( ioctl(cdfile, CDROMCLOSETRAY) == -1 )
Con_DPrintf("ioctl cdromclosetray failed\n");
}
static int CDAudio_GetAudioDiskInfo(void)
{
struct cdrom_tochdr tochdr;
cdValid = false;
if ( ioctl(cdfile, CDROMREADTOCHDR, &tochdr) == -1 )
{
Con_DPrintf("ioctl cdromreadtochdr failed\n");
return -1;
}
if (tochdr.cdth_trk0 < 1)
{
Con_DPrintf("CDAudio: no music tracks\n");
return -1;
}
cdValid = true;
maxTrack = tochdr.cdth_trk1;
return 0;
}
void CDAudio_Play(byte track, qboolean looping)
{
struct cdrom_tocentry entry;
struct cdrom_ti ti;
if (cdfile == -1 || !enabled)
return;
if (!cdValid)
{
CDAudio_GetAudioDiskInfo();
if (!cdValid)
return;
}
track = remap[track];
if (track < 1 || track > maxTrack)
{
Con_DPrintf("CDAudio: Bad track number %u.\n", track);
return;
}
// don't try to play a non-audio track
entry.cdte_track = track;
entry.cdte_format = CDROM_MSF;
if ( ioctl(cdfile, CDROMREADTOCENTRY, &entry) == -1 )
{
Con_DPrintf("ioctl cdromreadtocentry failed\n");
return;
}
if (entry.cdte_ctrl == CDROM_DATA_TRACK)
{
Con_Printf("CDAudio: track %i is not audio\n", track);
return;
}
if (playing)
{
if (playTrack == track)
return;
CDAudio_Stop();
}
ti.cdti_trk0 = track;
ti.cdti_trk1 = track;
ti.cdti_ind0 = 1;
ti.cdti_ind1 = 99;
if ( ioctl(cdfile, CDROMPLAYTRKIND, &ti) == -1 )
{
Con_DPrintf("ioctl cdromplaytrkind failed\n");
return;
}
if ( ioctl(cdfile, CDROMRESUME) == -1 )
Con_DPrintf("ioctl cdromresume failed\n");
playLooping = looping;
playTrack = track;
playing = true;
if (cdvolume == 0.0)
CDAudio_Pause ();
}
void CDAudio_Stop(void)
{
if (cdfile == -1 || !enabled)
return;
if (!playing)
return;
if ( ioctl(cdfile, CDROMSTOP) == -1 )
Con_DPrintf("ioctl cdromstop failed (%d)\n", errno);
wasPlaying = false;
playing = false;
}
void CDAudio_Pause(void)
{
if (cdfile == -1 || !enabled)
return;
if (!playing)
return;
if ( ioctl(cdfile, CDROMPAUSE) == -1 )
Con_DPrintf("ioctl cdrompause failed\n");
wasPlaying = playing;
playing = false;
}
void CDAudio_Resume(void)
{
if (cdfile == -1 || !enabled)
return;
if (!cdValid)
return;
if (!wasPlaying)
return;
if ( ioctl(cdfile, CDROMRESUME) == -1 )
Con_DPrintf("ioctl cdromresume failed\n");
playing = true;
}
static void CD_f (void)
{
char *command;
int ret;
int n;
if (Cmd_Argc() < 2)
return;
command = Cmd_Argv (1);
if (Q_strcasecmp(command, "on") == 0)
{
enabled = true;
return;
}
if (Q_strcasecmp(command, "off") == 0)
{
if (playing)
CDAudio_Stop();
enabled = false;
return;
}
if (Q_strcasecmp(command, "reset") == 0)
{
enabled = true;
if (playing)
CDAudio_Stop();
for (n = 0; n < 100; n++)
remap[n] = n;
CDAudio_GetAudioDiskInfo();
return;
}
if (Q_strcasecmp(command, "remap") == 0)
{
ret = Cmd_Argc() - 2;
if (ret <= 0)
{
for (n = 1; n < 100; n++)
if (remap[n] != n)
Con_Printf(" %u -> %u\n", n, remap[n]);
return;
}
for (n = 1; n <= ret; n++)
remap[n] = Q_atoi(Cmd_Argv (n+1));
return;
}
if (Q_strcasecmp(command, "close") == 0)
{
CDAudio_CloseDoor();
return;
}
if (!cdValid)
{
CDAudio_GetAudioDiskInfo();
if (!cdValid)
{
Con_Printf("No CD in player.\n");
return;
}
}
if (Q_strcasecmp(command, "play") == 0)
{
CDAudio_Play((byte)Q_atoi(Cmd_Argv (2)), false);
return;
}
if (Q_strcasecmp(command, "loop") == 0)
{
CDAudio_Play((byte)Q_atoi(Cmd_Argv (2)), true);
return;
}
if (Q_strcasecmp(command, "stop") == 0)
{
CDAudio_Stop();
return;
}
if (Q_strcasecmp(command, "pause") == 0)
{
CDAudio_Pause();
return;
}
if (Q_strcasecmp(command, "resume") == 0)
{
CDAudio_Resume();
return;
}
if (Q_strcasecmp(command, "eject") == 0)
{
if (playing)
CDAudio_Stop();
CDAudio_Eject();
cdValid = false;
return;
}
if (Q_strcasecmp(command, "info") == 0)
{
Con_Printf("%u tracks\n", maxTrack);
if (playing)
Con_Printf("Currently %s track %u\n", playLooping ? "looping" : "playing", playTrack);
else if (wasPlaying)
Con_Printf("Paused %s track %u\n", playLooping ? "looping" : "playing", playTrack);
Con_Printf("Volume is %f\n", cdvolume);
return;
}
}
void CDAudio_Update(void)
{
struct cdrom_subchnl subchnl;
static time_t lastchk;
if (!enabled)
return;
if (bgmvolume->value != cdvolume)
{
if (cdvolume)
{
Cvar_Set (bgmvolume, "0");
cdvolume = bgmvolume->value;
CDAudio_Pause ();
}
else
{
Cvar_Set (bgmvolume, "1");
cdvolume = bgmvolume->value;
CDAudio_Resume ();
}
}
if (playing && lastchk < time(NULL)) {
lastchk = time(NULL) + 2; //two seconds between chks
subchnl.cdsc_format = CDROM_MSF;
if (ioctl(cdfile, CDROMSUBCHNL, &subchnl) == -1 ) {
Con_DPrintf("ioctl cdromsubchnl failed\n");
playing = false;
return;
}
if (subchnl.cdsc_audiostatus != CDROM_AUDIO_PLAY &&
subchnl.cdsc_audiostatus != CDROM_AUDIO_PAUSED) {
playing = false;
if (playLooping)
CDAudio_Play(playTrack, true);
}
}
}
int CDAudio_Init(void)
{
int i;
if (cls.state == ca_dedicated)
return -1;
if (COM_CheckParm("-nocdaudio"))
return -1;
if ((i = COM_CheckParm("-cddev")) != 0 && i < com_argc - 1) {
strncpy(cd_dev, com_argv[i + 1], sizeof(cd_dev));
cd_dev[sizeof(cd_dev) - 1] = 0;
}
if ((cdfile = open(cd_dev, O_RDONLY)) == -1) {
Con_Printf("CDAudio_Init: open of \"%s\" failed (%i)\n", cd_dev, errno);
cdfile = -1;
return -1;
}
for (i = 0; i < 100; i++)
remap[i] = i;
initialized = true;
enabled = true;
if (CDAudio_GetAudioDiskInfo())
{
Con_Printf("CDAudio_Init: No CD in player.\n");
cdValid = false;
}
Cmd_AddCommand ("cd", CD_f);
Con_Printf("CD Audio Initialized\n");
return 0;
}
void CDAudio_Shutdown(void)
{
if (!initialized)
return;
CDAudio_Stop();
close(cdfile);
cdfile = -1;
}

View file

@ -17,12 +17,6 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifdef DUMB
//typedef struct DUMBFILE DUMBERFILE;
struct DUMBFILE_SYSTEM *duhfile;
struct DUH *duhsong;
//struct DUH *duhgame; // experimental ingame sounding
#endif
int CDAudio_Init(void);
void CDAudio_Play(byte track, qboolean looping);
void CDAudio_Stop(void);

View file

@ -1459,14 +1459,14 @@ void CL_ParseServerMessage (void)
if (cl.paused)
{
CDAudio_Pause ();
Tracker_Pause ();
#ifdef _WIN32
VID_HandlePause (true);
#endif
}
else
{
CDAudio_Resume ();
Tracker_Resume ();
#ifdef _WIN32
VID_HandlePause (false);
#endif
@ -1527,9 +1527,9 @@ void CL_ParseServerMessage (void)
cl.cdtrack = MSG_ReadByte ();
cl.looptrack = MSG_ReadByte ();
if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) )
CDAudio_Play ((byte)cls.forcetrack, true);
Tracker_Play ((byte)cls.forcetrack, true);
else
CDAudio_Play ((byte)cl.cdtrack, true);
Tracker_Play ((byte)cl.cdtrack, true);
break;
#endif

View file

@ -954,6 +954,7 @@ void _Host_Frame (float time)
MIDI_Update(); // leilei - update our midi
#endif
CDAudio_Update();
Tracker_Update();
if (host_speeds->value)
{
@ -1439,7 +1440,7 @@ void Host_Init (quakeparms_t *parms)
//TW CDAudio_Init_Cvars(); // 2001-09-18 New cvar system by Maddes (Init)
#ifndef BENCH
CDAudio_Init ();
Tracker_Init ();
Sbar_Init ();
#endif
CL_Init ();
@ -1498,6 +1499,7 @@ void Host_Shutdown(void)
Host_WriteConfiguration ();
#endif
CDAudio_Shutdown ();
Tracker_Shutdown ();
NET_Shutdown ();
S_Shutdown();
IN_Shutdown ();

View file

@ -463,6 +463,7 @@ typedef struct
#include "menu.h"
#include "crc.h"
#include "cdaudio.h"
#include "tracker.h"
#ifdef GLQUAKE
#include "glquake.h"

26
WinQuake/tracker.h Normal file
View file

@ -0,0 +1,26 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
Copyright (C) 2015 Marco "eukara" Hladik
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
int Tracker_Init(void);
void Tracker_Play(byte track, qboolean looping);
void Tracker_Stop(void);
void Tracker_Pause(void);
void Tracker_Resume(void);
void Tracker_Shutdown(void);
void Tracker_Update(void);

199
WinQuake/tracker_linux.c Normal file
View file

@ -0,0 +1,199 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
Copyright (C) 2015 Marco "eukara" Hladik
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "quakedef.h"
#include <dumb.h>
// eukara - added in tracker playback using DUMB - UNIX ONLY!
char name[256];
DUH *trackmod; // The music file ~eukara
DUH_SIGRENDERER *sr; // The DUMB renderer
FILE *oss_device; // output device (by default /dev/dsp for OSS)
// Set up the renderer options
static int depth = 16; // by default 16bit, only affects output not internal 32bit processing
static int unsign = 0;
static int freq = 22050;// 22050 is enough for most music
static int n_channels = 2; // stereo action
static float cdvolume = 0.8f; // default cdvolume...?
static float delay = 0.0f; // You shouldn't need to touch this.
static float delta; // For the speed, combination of frequency
static int bufsize;
static qboolean playing = false;// Is the music playing or not?
union {
short s16[2048]; // was 8192
char s8[4096]; // was twice as the thing above
} buffer;
void Tracker_Play(byte track, qboolean looping)
{
dumb_register_stdfiles(); // Initialize loading files
// Attempt to load every format imaginable, TODO: better method?
sprintf (name, "%s/music/track%d.it", com_gamedir, track);
trackmod = dumb_load_it(name);
if (!trackmod) {
sprintf (name, "%s/music/track%d.xm", com_gamedir, track);
trackmod = dumb_load_xm(name);
if (!trackmod) {
sprintf (name, "%s/music/track%d.s3m", com_gamedir, track);
trackmod = dumb_load_s3m(name);
if (!trackmod) {
sprintf (name, "%s/music/track%d.mod", com_gamedir, track);
trackmod = dumb_load_mod(name);
if (!trackmod) {
fprintf(stderr, "Unable to open %s!\n", name);
return;
}
}
}
}
// Let us know which track you are playing
Con_Printf("Playing %s\n", name);
sr = duh_start_sigrenderer(trackmod, 0, n_channels, 0); // start rendering, action happens in Tracker_Update
if (!sr) { // If it doesn't want to render, stop it before it's too late
unload_duh(trackmod); // Unload the track safely
fprintf(stderr, "Unable to play file!\n");
return;
}
delta = 61536.0f / freq; // This affects the speed
bufsize = depth == 16 ? 2048 : 4096; // Buffer size, small buffer = laggy music; big buff = laggy game
bufsize /= n_channels; // Tell him we are hopefully stereo
playing = true; // Announce that we have a track playing
}
void Tracker_Stop(void)
{
playing = false; // Not playing the song anymore to prevent Tracker_Update
Con_Printf("Stopping %s\n", name); // Just print that we are stopping whatever track
duh_end_sigrenderer(sr); // Stop the renderer safely
unload_duh(trackmod); // Unload the song!
}
void Tracker_Pause(void)
{
playing = false; // Prevent from Tracker_Update from happening
Con_Printf("Paused %s\n", name);
}
void Tracker_Resume(void)
{
// Just making sure we aren't calling Tracker_Update with no song...
if(!trackmod || !sr)
return;
playing = true; // Tracker_Update should now be triggered again
Con_Printf("Resuming %s\n", name);
}
static void Tracker_f (void)
{
char *command;
int ret;
int n;
if (Cmd_Argc() < 2)
return;
command = Cmd_Argv (1);
if (Q_strcasecmp(command, "play") == 0)
{
Tracker_Play((byte)Q_atoi(Cmd_Argv (2)), false);
return;
}
if (Q_strcasecmp(command, "stop") == 0)
{
Tracker_Stop();
return;
}
if (Q_strcasecmp(command, "volume") == 0)
{
cdvolume = (float)Q_atoi(Cmd_Argv (2));
return;
}
if (Q_strcasecmp(command, "frequency") == 0)
{
freq = (int)Q_atoi(Cmd_Argv (2));
return;
}
if (Q_strcasecmp(command, "pause") == 0)
{
Tracker_Pause();
return;
}
if (Q_strcasecmp(command, "resume") == 0)
{
Tracker_Resume();
return;
}
}
void Tracker_Update(void)
{
int i;
// Only update when a song is playing and the renderer works...
if (!sr)
return;
if(playing == false)
return;
// Render the song
int l = duh_render(sr, depth, unsign, cdvolume, delta, bufsize, &buffer);
if (depth == 16) { // On 16 bit, fill the buffer accordingly
for (i = 0; i < l * n_channels; i++) {
short val = buffer.s16[i];
buffer.s8[i*2] = (char)val;
buffer.s8[i*2+1] = (char)(val >> 8);
}
}
// TODO: Write this into the engine's soundbuffer instead for speed!
fwrite(buffer.s8, 1, l * n_channels * (depth >> 3), oss_device); // write it into OSS' device
}
int Tracker_Init(void)
{
oss_device = fopen("/dev/dsp", "wb"); // /dev/dsp is the standard OSS output
if(oss_device == NULL) // just get out if there's none
return 0;
Cmd_AddCommand ("dumb", Tracker_f); // link DUMB
Con_Printf("DUMB Initialized\n"); // Tell them we are ready
return 1; // return that we have successfully initialised
}
void Tracker_Shutdown(void)
{
Tracker_Stop(); // First stop the track
fclose(oss_device); // Close the device
dumb_exit(); // Kill DUMB
}