380 lines
10 KiB
C
Executable File
380 lines
10 KiB
C
Executable File
/* MikMod sound library
|
|
(c) 2004, Raphael Assenat
|
|
(c) 1998, 1999, 2000 Miodrag Vallat and others - see file AUTHORS for
|
|
complete list.
|
|
|
|
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 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 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., 59 Temple Place - Suite 330, Boston, MA
|
|
02111-1307, USA.
|
|
*/
|
|
|
|
/*==============================================================================
|
|
|
|
$Id: drv_aiff.c,v 1.4 2004/02/20 22:08:33 raph Exp $
|
|
|
|
Driver for output to a file called MUSIC.AIFF [or .AIF on Windows].
|
|
|
|
==============================================================================*/
|
|
|
|
/*
|
|
|
|
Written by Axel "awe" Wefers <awe@fruitz-of-dojo.de>
|
|
|
|
|
|
Raphael Assenat: 19 Feb 2004: Command line options documented in the MDRIVER structure,
|
|
and I added #if 0 's around pragmas, since gcc complaines about them.
|
|
Hopefully, the IDE which uses them wont care about that?
|
|
*/
|
|
|
|
/*_______________________________________________________________________________________________iNCLUDES
|
|
*/
|
|
#if 0
|
|
#pragma mark INCLUDES
|
|
#endif
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include "mikmod_internals.h"
|
|
|
|
#ifdef DRV_AIFF
|
|
|
|
#ifdef HAVE_UNISTD_H
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <math.h> /* required for IEEE extended conversion */
|
|
#if 0
|
|
#pragma mark -
|
|
#endif
|
|
/*________________________________________________________________________________________________dEFINES
|
|
*/
|
|
#if 0
|
|
#pragma mark DEFINES
|
|
#endif
|
|
|
|
#define AIFF_BUFFERSIZE 32768
|
|
#if defined(WIN32) || defined(DJGPP)
|
|
#define AIFF_FILENAME "music.aif"
|
|
#else
|
|
#define AIFF_FILENAME "music.aiff"
|
|
#endif /* WIN32 */
|
|
#if 0
|
|
#pragma mark -
|
|
#endif
|
|
/*_________________________________________________________________________________________________mACROS
|
|
*/
|
|
#if 0
|
|
#pragma mark MACROS
|
|
#endif
|
|
|
|
#define AIFF_FLOAT_TO_UNSIGNED(f) ((unsigned long)(((long)(f - 2147483648.0)) + 2147483647L + 1))
|
|
#if 0
|
|
#pragma mark -
|
|
#endif
|
|
/*___________________________________________________________________________________________________vARS
|
|
*/
|
|
#if 0
|
|
#pragma mark VARIABLES
|
|
#endif
|
|
static MWRITER *gAiffOut = NULL;
|
|
static FILE *gAiffFile = NULL;
|
|
static SBYTE *gAiffAudioBuffer = NULL;
|
|
static CHAR *gAiffFileName = NULL;
|
|
static ULONG gAiffDumpSize = 0;
|
|
#if 0
|
|
#pragma mark -
|
|
#endif
|
|
/*____________________________________________________________________________________fUNCTION_pROTOTYPES
|
|
*/
|
|
#if 0
|
|
#pragma mark FUNCTION PROTOTYPES
|
|
#endif
|
|
|
|
#ifdef SUNOS
|
|
extern int fclose(FILE *);
|
|
#endif
|
|
|
|
static void AIFF_ConvertToIeeeExtended (double theValue, char *theBytes);
|
|
static void AIFF_PutHeader (void);
|
|
static void AIFF_CommandLine (CHAR *theCmdLine);
|
|
static BOOL AIFF_IsThere (void);
|
|
static BOOL AIFF_Init (void);
|
|
static void AIFF_Exit (void);
|
|
static void AIFF_Update (void);
|
|
#if 0
|
|
#pragma mark -
|
|
#endif
|
|
/*___________________________________________________________________________AIFF_ConvertToIeeeExtended()
|
|
*/
|
|
|
|
void AIFF_ConvertToIeeeExtended (double theValue, char *theBytes)
|
|
{
|
|
int mySign;
|
|
int myExponent;
|
|
double myFMant, myFsMant;
|
|
unsigned long myHiMant, myLoMant;
|
|
|
|
if (theValue < 0)
|
|
{
|
|
mySign = 0x8000;
|
|
theValue *= -1;
|
|
} else
|
|
{
|
|
mySign = 0;
|
|
}
|
|
|
|
if (theValue == 0)
|
|
{
|
|
myExponent = 0;
|
|
myHiMant = 0;
|
|
myLoMant = 0;
|
|
}
|
|
else
|
|
{
|
|
myFMant = frexp (theValue, &myExponent);
|
|
if ((myExponent > 16384) || !(myFMant < 1))
|
|
{
|
|
myExponent = mySign | 0x7FFF;
|
|
myHiMant = 0;
|
|
myLoMant = 0;
|
|
}
|
|
else
|
|
{
|
|
myExponent += 16382;
|
|
if (myExponent < 0)
|
|
{
|
|
myFMant = ldexp (myFMant, myExponent);
|
|
myExponent = 0;
|
|
}
|
|
myExponent |= mySign;
|
|
myFMant = ldexp (myFMant, 32);
|
|
myFsMant = floor (myFMant);
|
|
myHiMant = AIFF_FLOAT_TO_UNSIGNED (myFsMant);
|
|
myFMant = ldexp (myFMant - myFsMant, 32);
|
|
myFsMant = floor (myFMant);
|
|
myLoMant = AIFF_FLOAT_TO_UNSIGNED (myFsMant);
|
|
}
|
|
}
|
|
|
|
theBytes[0] = myExponent >> 8;
|
|
theBytes[1] = myExponent;
|
|
theBytes[2] = myHiMant >> 24;
|
|
theBytes[3] = myHiMant >> 16;
|
|
theBytes[4] = myHiMant >> 8;
|
|
theBytes[5] = myHiMant;
|
|
theBytes[6] = myLoMant >> 24;
|
|
theBytes[7] = myLoMant >> 16;
|
|
theBytes[8] = myLoMant >> 8;
|
|
theBytes[9] = myLoMant;
|
|
}
|
|
|
|
/*_______________________________________________________________________________________AIFF_PutHeader()
|
|
*/
|
|
|
|
static void AIFF_PutHeader(void)
|
|
{
|
|
ULONG myFrames;
|
|
UBYTE myIEEE[10];
|
|
|
|
myFrames = gAiffDumpSize / (((md_mode&DMODE_STEREO) ? 2 : 1) * ((md_mode & DMODE_16BITS) ? 2 : 1));
|
|
AIFF_ConvertToIeeeExtended ((double) md_mixfreq, myIEEE);
|
|
|
|
_mm_fseek (gAiffOut, 0, SEEK_SET);
|
|
_mm_write_string ("FORM", gAiffOut); /* chunk 'FORM' */
|
|
_mm_write_M_ULONG (gAiffDumpSize + 36, gAiffOut); /* length of the file */
|
|
_mm_write_string ("AIFFCOMM", gAiffOut); /* chunk 'AIFF', 'COMM' */
|
|
_mm_write_M_ULONG (18, gAiffOut); /* length of this AIFF block */
|
|
_mm_write_M_UWORD ((md_mode & DMODE_STEREO) ? 2 : 1, gAiffOut); /* channels */
|
|
_mm_write_M_ULONG (myFrames, gAiffOut); /* frames = freq * secs */
|
|
_mm_write_M_UWORD ((md_mode & DMODE_16BITS) ? 16 : 8, gAiffOut); /* bits per sample */
|
|
_mm_write_UBYTES (myIEEE, 10, gAiffOut); /* frequency [IEEE extended] */
|
|
_mm_write_string ("SSND", gAiffOut); /* data chunk 'SSND' */
|
|
_mm_write_M_ULONG (gAiffDumpSize, gAiffOut); /* data length */
|
|
_mm_write_M_ULONG (0, gAiffOut); /* data offset, always zero */
|
|
_mm_write_M_ULONG (0, gAiffOut); /* data blocksize, always zero */
|
|
}
|
|
|
|
/*_____________________________________________________________________________________AIFF_CommandLine()
|
|
*/
|
|
|
|
static void AIFF_CommandLine (CHAR *theCmdLine)
|
|
{
|
|
CHAR *myFileName = MD_GetAtom ("file", theCmdLine,0);
|
|
|
|
if (myFileName != NULL)
|
|
{
|
|
_mm_free (gAiffFileName);
|
|
gAiffFileName = myFileName;
|
|
}
|
|
}
|
|
|
|
/*_________________________________________________________________________________________AIFF_isThere()
|
|
*/
|
|
|
|
static BOOL AIFF_IsThere (void)
|
|
{
|
|
return (1);
|
|
}
|
|
|
|
/*____________________________________________________________________________________________AIFF_Init()
|
|
*/
|
|
|
|
static BOOL AIFF_Init (void)
|
|
{
|
|
#if defined unix || (defined __APPLE__ && defined __MACH__)
|
|
if (!MD_Access (gAiffFileName ? gAiffFileName : AIFF_FILENAME))
|
|
{
|
|
_mm_errno=MMERR_OPENING_FILE;
|
|
return (1);
|
|
}
|
|
#endif
|
|
|
|
if (!(gAiffFile = fopen (gAiffFileName ? gAiffFileName : AIFF_FILENAME, "wb")))
|
|
{
|
|
_mm_errno = MMERR_OPENING_FILE;
|
|
return (1);
|
|
}
|
|
if (!(gAiffOut =_mm_new_file_writer (gAiffFile)))
|
|
{
|
|
fclose (gAiffFile);
|
|
unlink(gAiffFileName ? gAiffFileName : AIFF_FILENAME);
|
|
gAiffFile = NULL;
|
|
return (1);
|
|
}
|
|
|
|
if (!(gAiffAudioBuffer = (SBYTE*) _mm_malloc (AIFF_BUFFERSIZE)))
|
|
{
|
|
_mm_delete_file_writer (gAiffOut);
|
|
fclose (gAiffFile);
|
|
unlink (gAiffFileName ? gAiffFileName : AIFF_FILENAME);
|
|
gAiffFile = NULL;
|
|
gAiffOut = NULL;
|
|
return 1;
|
|
}
|
|
|
|
md_mode|=DMODE_SOFT_MUSIC|DMODE_SOFT_SNDFX;
|
|
|
|
if (VC_Init ())
|
|
{
|
|
_mm_delete_file_writer (gAiffOut);
|
|
fclose (gAiffFile);
|
|
unlink (gAiffFileName ? gAiffFileName : AIFF_FILENAME);
|
|
gAiffFile = NULL;
|
|
gAiffOut = NULL;
|
|
return 1;
|
|
}
|
|
|
|
gAiffDumpSize = 0;
|
|
AIFF_PutHeader ();
|
|
|
|
return (0);
|
|
}
|
|
|
|
/*____________________________________________________________________________________________AIFF_Exit()
|
|
*/
|
|
|
|
static void AIFF_Exit (void)
|
|
{
|
|
VC_Exit ();
|
|
|
|
/* write in the actual sizes now */
|
|
if (gAiffOut != NULL)
|
|
{
|
|
AIFF_PutHeader ();
|
|
_mm_delete_file_writer (gAiffOut);
|
|
fclose (gAiffFile);
|
|
gAiffFile = NULL;
|
|
gAiffOut = NULL;
|
|
}
|
|
if (gAiffAudioBuffer != NULL)
|
|
{
|
|
free (gAiffAudioBuffer);
|
|
gAiffAudioBuffer = NULL;
|
|
}
|
|
}
|
|
|
|
/*__________________________________________________________________________________________AIFF_Update()
|
|
*/
|
|
|
|
static void AIFF_Update (void)
|
|
{
|
|
ULONG myByteCount;
|
|
|
|
myByteCount = VC_WriteBytes (gAiffAudioBuffer, AIFF_BUFFERSIZE);
|
|
if (md_mode & DMODE_16BITS)
|
|
{
|
|
_mm_write_M_UWORDS ((UWORD *) gAiffAudioBuffer, myByteCount >> 1, gAiffOut);
|
|
}
|
|
else
|
|
{
|
|
ULONG i;
|
|
|
|
for (i = 0; i < myByteCount; i++)
|
|
{
|
|
gAiffAudioBuffer[i] -= 0x80; /* convert to signed PCM */
|
|
}
|
|
_mm_write_UBYTES (gAiffAudioBuffer, myByteCount, gAiffOut);
|
|
}
|
|
gAiffDumpSize += myByteCount;
|
|
}
|
|
|
|
/*________________________________________________________________________________________________drv_osx
|
|
*/
|
|
|
|
MIKMODAPI MDRIVER drv_aiff = {
|
|
NULL,
|
|
"Disk writer (aiff)",
|
|
"AIFF disk writer (music.aiff) v1.1",
|
|
0,255,
|
|
"aif",
|
|
"file:t:music.aiff:Output file name\n",
|
|
AIFF_CommandLine,
|
|
AIFF_IsThere,
|
|
VC_SampleLoad,
|
|
VC_SampleUnload,
|
|
VC_SampleSpace,
|
|
VC_SampleLength,
|
|
AIFF_Init,
|
|
AIFF_Exit,
|
|
NULL,
|
|
VC_SetNumVoices,
|
|
VC_PlayStart,
|
|
VC_PlayStop,
|
|
AIFF_Update,
|
|
NULL,
|
|
VC_VoiceSetVolume,
|
|
VC_VoiceGetVolume,
|
|
VC_VoiceSetFrequency,
|
|
VC_VoiceGetFrequency,
|
|
VC_VoiceSetPanning,
|
|
VC_VoiceGetPanning,
|
|
VC_VoicePlay,
|
|
VC_VoiceStop,
|
|
VC_VoiceStopped,
|
|
VC_VoiceGetPosition,
|
|
VC_VoiceRealVolume
|
|
};
|
|
|
|
#else
|
|
|
|
MISSING(drv_aiff);
|
|
|
|
#endif
|
|
|
|
/*____________________________________________________________________________________________________eOF
|
|
*/
|