dxx-rebirth/common/arch/sdl/rbaudio.cpp

322 lines
6.4 KiB
C++
Raw Normal View History

2014-06-01 17:55:23 +00:00
/*
* This file is part of the DXX-Rebirth project <http://www.dxx-rebirth.com/>.
* It is copyright by its individual contributors, as recorded in the
* project's Git history. See COPYING.txt at the top level for license
* terms and a link to the Git history.
*/
2006-03-20 17:12:09 +00:00
/*
*
* SDL CD Audio functions
*
*
*/
2014-07-13 18:18:17 +00:00
#include <algorithm>
2006-03-20 17:12:09 +00:00
#include <stdio.h>
#include <stdlib.h>
2013-06-30 02:22:56 +00:00
#include <SDL.h>
2006-03-20 17:12:09 +00:00
#ifdef __linux__
#include <sys/ioctl.h>
#include <linux/cdrom.h>
#endif
#include "pstypes.h"
#include "dxxerror.h"
2006-03-20 17:12:09 +00:00
#include "args.h"
#include "rbaudio.h"
#include "console.h"
#include "timer.h"
2014-07-13 18:18:17 +00:00
#include "partial_range.h"
#include "compiler-range_for.h"
2006-03-20 17:12:09 +00:00
#define REDBOOK_VOLUME_SCALE 255
2006-03-20 17:12:09 +00:00
static SDL_CD *s_cd = NULL;
static int initialised = 0;
void RBAExit()
{
if (s_cd)
2006-03-20 17:12:09 +00:00
{
SDL_CDStop(s_cd);
SDL_CDClose(s_cd);
}
}
void RBAInit()
{
int num_cds;
2006-03-20 17:12:09 +00:00
if (initialised) return;
if (SDL_Init(SDL_INIT_CDROM) < 0)
{
Warning("RBAudio: SDL library initialisation failed: %s.",SDL_GetError());
2006-03-20 17:12:09 +00:00
return;
}
num_cds = SDL_CDNumDrives();
if (num_cds < 1)
{
2013-12-07 00:47:27 +00:00
con_printf(CON_NORMAL, "RBAudio: No cdrom drives found!");
#if defined(__APPLE__) || defined(macintosh)
SDL_QuitSubSystem(SDL_INIT_CDROM); // necessary for rescanning CDROMs
#endif
return;
}
for (int i = 0; i < num_cds; i++)
{
if (s_cd)
SDL_CDClose(s_cd);
s_cd = SDL_CDOpen(i);
if (s_cd && CD_INDRIVE(SDL_CDStatus(s_cd)))
{
2014-07-13 18:18:17 +00:00
auto r = partial_range(s_cd->track, static_cast<unsigned>(s_cd->numtracks));
if (std::find_if(r.begin(), r.end(), [](const SDL_CDtrack &t){ return t.type == SDL_AUDIO_TRACK; }) != r.end())
2014-07-19 22:46:26 +00:00
{
initialised = 1;
RBAList();
return; // we've found an audio CD
}
}
else if (s_cd == NULL)
Warning("RBAudio: Could not open cdrom %i for redbook audio:%s\n", i, SDL_GetError());
}
{
2013-12-07 00:47:27 +00:00
con_printf(CON_NORMAL, "RBAudio: No audio CDs found");
if (s_cd) // if there's no audio CD, say that there's no redbook and hence play MIDI instead
{
SDL_CDClose(s_cd);
s_cd = NULL;
}
#if defined(__APPLE__) || defined(macintosh)
SDL_QuitSubSystem(SDL_INIT_CDROM); // necessary for rescanning CDROMs
#endif
return;
}
}
int RBAEnabled()
{
return initialised;
2006-03-20 17:12:09 +00:00
}
int RBAPlayTrack(int a)
{
if (!s_cd) return -1;
2006-03-20 17:12:09 +00:00
if (CD_INDRIVE(SDL_CDStatus(s_cd)) ) {
if (SDL_CDPlayTracks(s_cd, a-1, 0, 0, 0) == 0)
{
2013-12-07 00:47:27 +00:00
con_printf(CON_VERBOSE, "RBAudio: Playing track %i", a);
return a;
}
2006-03-20 17:12:09 +00:00
}
return -1;
2006-03-20 17:12:09 +00:00
}
2013-06-30 20:59:51 +00:00
static void (*redbook_finished_hook)() = NULL;
2006-03-20 17:12:09 +00:00
void RBAStop()
{
if (!s_cd) return;
2006-03-20 17:12:09 +00:00
SDL_CDStop(s_cd);
redbook_finished_hook = NULL; // no calling the finished hook - stopped means stopped here
2013-12-07 00:47:27 +00:00
con_printf(CON_VERBOSE, "RBAudio: Playback stopped");
2006-03-20 17:12:09 +00:00
}
void RBAEjectDisk()
{
if (!s_cd) return;
SDL_CDEject(s_cd); // play nothing until it tries to load a song
#if defined(__APPLE__) || defined(macintosh)
SDL_QuitSubSystem(SDL_INIT_CDROM); // necessary for rescanning CDROMs
#endif
initialised = 0;
}
2015-04-26 20:15:56 +00:00
#ifdef __linux__
2006-03-20 17:12:09 +00:00
void RBASetVolume(int volume)
{
int cdfile, level;
struct cdrom_volctrl volctrl;
if (!s_cd) return;
2006-03-20 17:12:09 +00:00
cdfile = s_cd->id;
level = volume*REDBOOK_VOLUME_SCALE/8;
2006-03-20 17:12:09 +00:00
if ((level<0) || (level>REDBOOK_VOLUME_SCALE)) {
2013-12-07 00:47:27 +00:00
con_printf(CON_CRITICAL, "RBAudio: illegal volume value (allowed values 0-%i)",REDBOOK_VOLUME_SCALE);
2006-03-20 17:12:09 +00:00
return;
}
volctrl.channel0
= volctrl.channel1
= volctrl.channel2
= volctrl.channel3
= level;
if ( ioctl(cdfile, CDROMVOLCTRL, &volctrl) == -1 ) {
2013-12-07 00:47:27 +00:00
con_printf(CON_CRITICAL, "RBAudio: CDROMVOLCTRL ioctl failed");
2006-03-20 17:12:09 +00:00
return;
}
}
2015-04-26 20:15:56 +00:00
#endif
2006-03-20 17:12:09 +00:00
void RBAPause()
{
if (!s_cd) return;
2006-03-20 17:12:09 +00:00
SDL_CDPause(s_cd);
2013-12-07 00:47:27 +00:00
con_printf(CON_VERBOSE, "RBAudio: Playback paused");
2006-03-20 17:12:09 +00:00
}
int RBAResume()
{
if (!s_cd) return -1;
2006-03-20 17:12:09 +00:00
SDL_CDResume(s_cd);
2013-12-07 00:47:27 +00:00
con_printf(CON_VERBOSE, "RBAudio: Playback resumed");
2006-03-20 17:12:09 +00:00
return 1;
}
int RBAPauseResume()
{
if (!s_cd) return 0;
if (SDL_CDStatus(s_cd) == CD_PLAYING)
{
SDL_CDPause(s_cd);
2013-12-07 00:47:27 +00:00
con_printf(CON_VERBOSE, "RBAudio: Toggle Playback pause");
}
else if (SDL_CDStatus(s_cd) == CD_PAUSED)
{
SDL_CDResume(s_cd);
2013-12-07 00:47:27 +00:00
con_printf(CON_VERBOSE, "RBAudio: Toggle Playback resume");
}
else
return 0;
return 1;
}
2006-03-20 17:12:09 +00:00
int RBAGetNumberOfTracks()
{
if (!s_cd) return -1;
2006-03-20 17:12:09 +00:00
SDL_CDStatus(s_cd);
2013-12-07 00:47:27 +00:00
con_printf(CON_VERBOSE, "RBAudio: Found %i tracks on CD", s_cd->numtracks);
2006-03-20 17:12:09 +00:00
return s_cd->numtracks;
}
// check if we need to call the 'finished' hook
// needs to go in all event loops
// a real hook would be ideal, but is currently unsupported by SDL Audio CD
void RBACheckFinishedHook()
{
static fix64 last_check_time = 0;
if (!s_cd) return;
if ((timer_query() - last_check_time) >= F2_0)
{
if ((SDL_CDStatus(s_cd) == CD_STOPPED) && redbook_finished_hook)
{
2013-12-07 00:47:27 +00:00
con_printf(CON_VERBOSE, "RBAudio: Playback done, calling finished-hook");
redbook_finished_hook();
}
last_check_time = timer_query();
}
}
2006-03-20 17:12:09 +00:00
// plays tracks first through last, inclusive
int RBAPlayTracks(int first, int last, void (*hook_finished)(void))
2006-03-20 17:12:09 +00:00
{
if (!s_cd)
2006-03-20 17:12:09 +00:00
return 0;
if (CD_INDRIVE(SDL_CDStatus(s_cd)))
{
redbook_finished_hook = hook_finished;
2013-12-07 00:47:27 +00:00
con_printf(CON_VERBOSE, "RBAudio: Playing tracks %i to %i", first, last);
return SDL_CDPlayTracks(s_cd, first - 1, 0, last - first + 1, 0) == 0;
2006-03-20 17:12:09 +00:00
}
return 0;
2006-03-20 17:12:09 +00:00
}
// return the track number currently playing. Useful if RBAPlayTracks()
// is called. Returns 0 if no track playing, else track number
int RBAGetTrackNum()
{
if (!s_cd)
2006-03-20 17:12:09 +00:00
return 0;
if (SDL_CDStatus(s_cd) != CD_PLAYING)
return 0;
return s_cd->cur_track + 1;
}
int RBAPeekPlayStatus()
{
if (!s_cd)
return 0;
if (SDL_CDStatus(s_cd) == CD_PLAYING)
return 1;
else if (SDL_CDStatus(s_cd) == CD_PAUSED) // hack so it doesn't keep restarting paused music
return -1;
return 0;
2006-03-20 17:12:09 +00:00
}
static int cddb_sum(int n)
{
int ret;
/* For backward compatibility this algorithm must not change */
ret = 0;
while (n > 0) {
ret = ret + (n % 10);
n = n / 10;
}
return (ret);
}
unsigned long RBAGetDiscID()
{
int i, t = 0, n = 0;
if (!s_cd)
2006-03-20 17:12:09 +00:00
return 0;
/* For backward compatibility this algorithm must not change */
i = 0;
while (i < s_cd->numtracks) {
n += cddb_sum(s_cd->track[i].offset / CD_FPS);
i++;
}
t = (s_cd->track[s_cd->numtracks].offset / CD_FPS) -
(s_cd->track[0].offset / CD_FPS);
return ((n % 0xff) << 24 | t << 8 | s_cd->numtracks);
}
void RBAList(void)
{
if (!s_cd)
return;
2014-07-13 18:18:17 +00:00
range_for (auto &i, partial_range(s_cd->track, static_cast<unsigned>(s_cd->numtracks)))
con_printf(CON_VERBOSE, "RBAudio: CD track %d, type %s, length %d, offset %d", i.id, (i.type == SDL_AUDIO_TRACK) ? "audio" : "data", i.length, i.offset);
}