diff --git a/src/apu/CMakeLists.txt b/src/apu/CMakeLists.txt index 6767b47..7ca99ba 100644 --- a/src/apu/CMakeLists.txt +++ b/src/apu/CMakeLists.txt @@ -9,6 +9,5 @@ # $HeadURL$ # $Revision$ -add_library(apu SndUnixT.c Sound.c) -#add_library(apu SndAlleg.c Sound.c) +add_library(apu apu.c apu.c) target_link_libraries(apu portaudio_static) diff --git a/src/apu/SndAlleg.c b/src/apu/SndAlleg.c deleted file mode 100755 index 579f2b4..0000000 --- a/src/apu/SndAlleg.c +++ /dev/null @@ -1,434 +0,0 @@ -/* - * Allegro Sound Driver for EMULib Sound system - The peTI-NESulator Project - * SndAlleg.C - * - * Created by Manoel Trapier - * Copyright 2003-2008 986 Corp. All rights reserved. - * - * $LastChangedDate$ - * $Author$ - * $HeadURL$ - * $Revision$ - * - */ -#include - -/* Allegro includes */ -#ifdef __APPLE__ -#define USE_CONSOLE -#include -#else -#define USE_CONSOLE -#include -#endif - -#include - -#include -#include -//#include -//#include -#include -//#include - -#define AUDIO_CONV(A) (128+(A)) - - -AUDIOSTREAM *stream; - -static pthread_t ThreadID; -static int SoundRate = 0; -static int MasterVolume = 64; -static int MasterSwitch = (1<voice); - - if(Verbose) puts("OK"); - return(Rate); -} - -/** DSPLoop() ************************************************/ -/** Main loop of the sound server. **/ -/*************************************************************/ -static void *DSPLoop(void *Arg) -{ - int Wave[SND_BUFSIZE]; - unsigned char *Buf; - register int J,I,K,L,M,N,L1,L2,A1,A2,V; - int FreqCount; - N = L = A2 = 0; - - for(J=0;J>=1) - if(CH[J].Freq&&(V=CH[J].Volume)&&(M&1)) - switch(CH[J].Type) - { - case SND_NOISE: /* White Noise */ - /* For high frequencies, recompute volume */ - if(CH[J].Freq<=SoundRate) K=0x10000*CH[J].Freq/SoundRate; - else { V=V*SoundRate/CH[J].Freq;K=0x10000; } - L1=CH[J].Count; - V<<=7; - for(I=0;I0? (SoundRate<<15)/CH[J].Freq/CH[J].Rate - : (SoundRate<<15)/CH[J].Freq/CH[J].Length; - L1 = CH[J].Pos%CH[J].Length; - L2 = CH[J].Count; - A1 = CH[J].Data[L1]*V; - /* If expecting interpolation... */ - if(L2>15)+1; - N = ((K-(L2&0x7FFF))>>15)+1; - } - /* Add waveform to the buffer */ - for(I=0;I>15)+1; - } - } - /* End counting */ - CH[J].Pos = L1; - CH[J].Count = L2; - break; - - - case SND_QS_DU0: - /* Do not allow frequencies that are too high */ - if(CH[J].Freq>=SoundRate/3) break; - K=0x10000*CH[J].Freq/SoundRate; - L1=CH[J].Count; - V<<=7; - for(I=0;I=SoundRate/3) break; - K=0x10000*CH[J].Freq/SoundRate; - L1=CH[J].Count; - V<<=7; - for(I=0;I=SoundRate/3) break; - K=0x10000*CH[J].Freq/SoundRate; - L1=CH[J].Count; - V<<=7; - for(I=0;I=SoundRate/3) break; - K=0x10000*CH[J].Freq/SoundRate; - L1=CH[J].Count; - V<<=7; - for(I=0;I=SoundRate/3) break; - K=0x10000*CH[J].Freq/SoundRate; - L1=CH[J].Count; - V<<=7; - for(I=0;I>16; - I=I<-128? -128:I>127? 127:I; - Buf[J]=AUDIO_CONV(I); - Wave[J]=0; - } - free_audio_stream_buffer(stream); - } - } - - return(0); -} - -/** InitSound() **********************************************/ -/** Initialize DSP. Returns Rate on success, 0 otherwise. **/ -/** Mode is 0 to skip initialization (will be silent). **/ -/*************************************************************/ -int InitSound(int Rate,int Verbose) -{ - /* If sound was initialized, kill it */ - TrashSound(); - - /* Silence requested */ - if(Rate<=0) return(0); - - /* Synthesis rate should be at least 8kHz */ - if(Rate<8192) Rate=44100; - - /* Initialize things */ - SoundRate = 0; - ThreadID = 0; - Suspended = 0; - - /* Set driver functions */ - SndDriver.SetSound = UnixSetSound; - SndDriver.Drum = UnixDrum; - SndDriver.SetChannels = UnixSetChannels; - SndDriver.Sound = UnixSound; - SndDriver.SetWave = UnixSetWave; - - if (install_sound(DIGI_AUTODETECT, MIDI_NONE, "") != 0) - { - console_printf(Console_Error, "%s!\n", allegro_error); - return 1; - } - - - stream = play_audio_stream(SND_BUFSIZE, 8, FALSE, Rate, 255, 128); - if (!stream) { - console_printf(Console_Error, "Error creating audio stream!\n"); - return 1; - } - - voice_stop(stream->voice); - - /* Open sound device */ - if(Verbose) puts("Starting sound server:"); - if(!(Rate=OpenSoundDevice(Rate,Verbose))) return(0); - - /* Create DSPLoop() thread */ - if(Verbose) console_printf(Console_Default, " Creating thread..."); - if(pthread_create(&ThreadID,0,DSPLoop,0)) - { if(Verbose) puts("FAILED");return(0); } - - /* Detach the thread */ - pthread_detach(ThreadID); - - /* Done */ - SoundRun = 1; - if(Verbose) puts("OK"); - return(SoundRate=Rate); -} - -/** TrashSound() *********************************************/ -/** Shut DSP down. **/ -/*************************************************************/ -void TrashSound(void) -{ - if (SoundRun == 1) - { - StopSound(); - console_printf(Console_Default, "%s: Kill thread...\n", __func__); - if(ThreadID) pthread_cancel(ThreadID); - } - SoundRun = 0; - SoundRate = 0; - ThreadID = 0; -} - -/** UnixSound() **********************************************/ -/** Generate sound of given frequency (Hz) and volume **/ -/** (0..255) via given channel. **/ -/*************************************************************/ -void UnixSound(int Channel,int NewFreq,int NewVolume) -{ - if((Channel<0)||(Channel>=SND_CHANNELS)) return; - if(!NewVolume||!NewFreq) { NewVolume=0;NewFreq=0; } - - CH[Channel].Volume = NewVolume; - CH[Channel].Freq = NewFreq; -} - -/** UnixSetChannels() ****************************************/ -/** Set master volume (0..255) and turn channels on/off. **/ -/** Each bit in Toggle corresponds to a channel (1=on). **/ -/*************************************************************/ -void UnixSetChannels(int MVolume,int MSwitch) -{ - /* Set new MasterSwitch value */ - MasterSwitch = MSwitch; - MasterVolume = MVolume; -} - -/** UnixSetSound() *******************************************/ -/** Set sound type (SND_NOISE/SND_MELODIC) for a given **/ -/** channel. **/ -/*************************************************************/ -void UnixSetSound(int Channel,int NewType) -{ - if((Channel<0)||(Channel>=SND_CHANNELS)) return; - CH[Channel].Type = NewType; -} - - -/** UnixSetWave() ********************************************/ -/** Set waveform for a given channel. The channel will be **/ -/** marked with sound type SND_WAVE. Set Rate=0 if you want **/ -/** waveform to be an instrument or set it to the waveform **/ -/** own playback rate. **/ -/*************************************************************/ -void UnixSetWave(int Channel,const signed char *Data,int Length,int Rate) -{ - if((Channel<0)||(Channel>=SND_CHANNELS)||(Length<=0)) return; - - CH[Channel].Type = SND_WAVE; - CH[Channel].Length = Length; - CH[Channel].Rate = Rate; - CH[Channel].Pos = 0; - CH[Channel].Count = 0; - CH[Channel].Data = Data; -} - -/** UnixDrum() ***********************************************/ -/** Hit a drum of a given type with given force. **/ -/*************************************************************/ -void UnixDrum(int Type,int Force) -{ - /* This function is currently empty */ -} diff --git a/src/apu/SndUnixT.c b/src/apu/SndUnixT.c deleted file mode 100755 index e9280d0..0000000 --- a/src/apu/SndUnixT.c +++ /dev/null @@ -1,556 +0,0 @@ -/** EMULib Emulation Library *********************************/ -/** **/ -/** SndUnix.c **/ -/** **/ -/** This file contains standard sound generation routines **/ -/** for Unix using /dev/dsp and /dev/audio. **/ -/** **/ -/** Copyright (C) Marat Fayzullin 1996-2002 **/ -/** You are not allowed to distribute this software **/ -/** commercially. Please, notify me, if you make any **/ -/** changes to this file. **/ -/*************************************************************/ -//#include "Sound.h" - -#include -#include -#include -#include -#include -#include - -#include -#if 0 -#ifdef SUN_AUDIO - -#include -#include -#include - -#define AUDIO_CONV(A) (ULAW[0xFF&(128+(A))]) - -static unsigned char ULAW[256] = -{ - 31, 31, 31, 32, 32, 32, 32, 33, - 33, 33, 33, 34, 34, 34, 34, 35, - 35, 35, 35, 36, 36, 36, 36, 37, - 37, 37, 37, 38, 38, 38, 38, 39, - 39, 39, 39, 40, 40, 40, 40, 41, - 41, 41, 41, 42, 42, 42, 42, 43, - 43, 43, 43, 44, 44, 44, 44, 45, - 45, 45, 45, 46, 46, 46, 46, 47, - 47, 47, 47, 48, 48, 49, 49, 50, - 50, 51, 51, 52, 52, 53, 53, 54, - 54, 55, 55, 56, 56, 57, 57, 58, - 58, 59, 59, 60, 60, 61, 61, 62, - 62, 63, 63, 64, 65, 66, 67, 68, - 69, 70, 71, 72, 73, 74, 75, 76, - 77, 78, 79, 81, 83, 85, 87, 89, - 91, 93, 95, 99, 103, 107, 111, 119, - 255, 247, 239, 235, 231, 227, 223, 221, - 219, 217, 215, 213, 211, 209, 207, 206, - 205, 204, 203, 202, 201, 200, 199, 198, - 219, 217, 215, 213, 211, 209, 207, 206, - 205, 204, 203, 202, 201, 200, 199, 198, - 197, 196, 195, 194, 193, 192, 191, 191, - 190, 190, 189, 189, 188, 188, 187, 187, - 186, 186, 185, 185, 184, 184, 183, 183, - 182, 182, 181, 181, 180, 180, 179, 179, - 178, 178, 177, 177, 176, 176, 175, 175, - 175, 175, 174, 174, 174, 174, 173, 173, - 173, 173, 172, 172, 172, 172, 171, 171, - 171, 171, 170, 170, 170, 170, 169, 169, - 169, 169, 168, 168, 168, 168, 167, 167, - 167, 167, 166, 166, 166, 166, 165, 165, - 165, 165, 164, 164, 164, 164, 163, 163 -}; - -#else /* SUN_AUDIO */ - -#ifdef __FreeBSD__ -#include -#endif - -#ifdef __NetBSD__ -#include -#endif - -#ifdef __linux__ -#include -#endif - -#define AUDIO_CONV(A) (128+(A)) - -#endif /* SUN_AUDIO */ - -static pthread_t ThreadID; -static int SoundFD; -static int SoundRate = 0; -static int MasterVolume = 64; -static int MasterSwitch = (1<>16)>=1) - if(CH[J].Freq&&(V=CH[J].Volume)&&(M&1)) - switch(CH[J].Type) - { - case SND_NOISE: /* White Noise */ - /* For high frequencies, recompute volume */ - if(CH[J].Freq<=SoundRate) K=0x10000*CH[J].Freq/SoundRate; - else { V=V*SoundRate/CH[J].Freq;K=0x10000; } - L1=CH[J].Count; - V<<=7; - for(I=0;I0? (SoundRate<<15)/CH[J].Freq/CH[J].Rate - : (SoundRate<<15)/CH[J].Freq/CH[J].Length; - L1 = CH[J].Pos%CH[J].Length; - L2 = CH[J].Count; - A1 = CH[J].Data[L1]*V; - /* If expecting interpolation... */ - if(L2>15)+1; - N = ((K-(L2&0x7FFF))>>15)+1; - } - /* Add waveform to the buffer */ - for(I=0;I>15)+1; - } - } - /* End counting */ - CH[J].Pos = L1; - CH[J].Count = L2; - break; - - - case SND_QS_DU0: - /* Do not allow frequencies that are too high */ - if(CH[J].Freq>=SoundRate/3) break; - K=0x10000*CH[J].Freq/SoundRate; - L1=CH[J].Count; - V<<=7; - for(I=0;I=SoundRate/3) break; - K=0x10000*CH[J].Freq/SoundRate; - L1=CH[J].Count; - V<<=7; - for(I=0;I=SoundRate/3) break; - K=0x10000*CH[J].Freq/SoundRate; - L1=CH[J].Count; - V<<=7; - for(I=0;I=SoundRate/3) break; - K=0x10000*CH[J].Freq/SoundRate; - L1=CH[J].Count; - V<<=7; - for(I=0;I=SoundRate/3) break; - K=0x10000*CH[J].Freq/SoundRate; - L1=CH[J].Count; - V<<=7; - for(I=0;I>16; - I=I<-128? -128:I>127? 127:I; - Buf[J]=AUDIO_CONV(I); - Wave[J]=0; - } - - if(SoundFD==-1) sleep(1); - else - { -#ifdef SUN_AUDIO - /* Flush output first, don't care about return status. After this - ** write next buffer of audio data. This method produces a horrible - ** click on each buffer :( Any ideas, how to fix this? - */ - ioctl(SoundFD,AUDIO_DRAIN); - write(SoundFD,Buf,SND_BUFSIZE); -#else - /* We'll block here until next DMA buffer becomes free. It happens - ** once per (1<=SND_CHANNELS)) return; - if(!NewVolume||!NewFreq) { NewVolume=0;NewFreq=0; } - - CH[Channel].Volume = NewVolume; - CH[Channel].Freq = NewFreq; -} - -/** UnixSetChannels() ****************************************/ -/** Set master volume (0..255) and turn channels on/off. **/ -/** Each bit in Toggle corresponds to a channel (1=on). **/ -/*************************************************************/ -void UnixSetChannels(int MVolume,int MSwitch) -{ - /* Set new MasterSwitch value */ - MasterSwitch = MSwitch; - MasterVolume = MVolume; -} - -/** UnixSetSound() *******************************************/ -/** Set sound type (SND_NOISE/SND_MELODIC) for a given **/ -/** channel. **/ -/*************************************************************/ -void UnixSetSound(int Channel,int NewType) -{ - if((Channel<0)||(Channel>=SND_CHANNELS)) return; - CH[Channel].Type = NewType; -} - - -/** UnixSetWave() ********************************************/ -/** Set waveform for a given channel. The channel will be **/ -/** marked with sound type SND_WAVE. Set Rate=0 if you want **/ -/** waveform to be an instrument or set it to the waveform **/ -/** own playback rate. **/ -/*************************************************************/ -void UnixSetWave(int Channel, signed char *Data, int Length, int Freq) -{ - if((Channel<0)||(Channel>=SND_CHANNELS)||(Length<=0)) return; - - CH[Channel].Type = SND_WAVE; - CH[Channel].Length = Length; - CH[Channel].Rate = Freq; - CH[Channel].Pos = 0; - CH[Channel].Count = 0; - CH[Channel].Data = Data; -} - -/** UnixDrum() ***********************************************/ -/** Hit a drum of a given type with given force. **/ -/*************************************************************/ -void UnixDrum(int Type,int Force) -{ - /* This function is currently empty */ -} -#endif \ No newline at end of file diff --git a/src/apu/Sound.c b/src/apu/Sound.c deleted file mode 100644 index cd826a0..0000000 --- a/src/apu/Sound.c +++ /dev/null @@ -1,504 +0,0 @@ -/** EMULib Emulation Library *********************************/ -/** **/ -/** Sound.c **/ -/** **/ -/** This file file implements core part of the sound API **/ -/** and functions needed to log soundtrack into a MIDI **/ -/** file. See Sound.h for declarations. **/ -/** **/ -/** Copyright (C) Marat Fayzullin 1996-2007 **/ -/** You are not allowed to distribute this software **/ -/** commercially. Please, notify me, if you make any **/ -/** changes to this file. **/ -/*************************************************************/ -/* - * $LastChangedDate$ - * $Author$ - * $HeadURL$ - * $Revision$ - */ - -#include "Sound.h" - -#include -#include - -#ifdef UNIX -#include -#endif - -typedef unsigned char byte; -typedef unsigned short word; - -struct SndDriverStruct SndDriver = -{ - (void (*)(int,int))0, - (void (*)(int,int))0, - (void (*)(int,int))0, - (void (*)(int,int,int))0, - (void (*)(int,signed char *,int,int))0, - (const signed char *(*)(int))0 -}; - -static const struct { byte Note;word Wheel; } Freqs[4096] = -{ -#include "MIDIFreq.h" -}; - -static const int Programs[5] = -{ - 80, /* SND_MELODIC/SND_RECTANGLE */ - 80, /* SND_TRIANGLE */ - 122, /* SND_NOISE */ - 122, /* SND_PERIODIC */ - 80 /* SND_WAVE */ -}; - -static struct -{ - int Type; - int Note; - int Pitch; - int Level; -} CH[MIDI_CHANNELS] = -{ - { -1,-1,-1,-1 }, - { -1,-1,-1,-1 }, - { -1,-1,-1,-1 }, - { -1,-1,-1,-1 }, - { -1,-1,-1,-1 }, - { -1,-1,-1,-1 }, - { -1,-1,-1,-1 }, - { -1,-1,-1,-1 }, - { -1,-1,-1,-1 }, - { -1,-1,-1,-1 }, - { -1,-1,-1,-1 }, - { -1,-1,-1,-1 }, - { -1,-1,-1,-1 }, - { -1,-1,-1,-1 }, - { -1,-1,-1,-1 }, - { -1,-1,-1,-1 } -}; - -static const char *LogName = 0; -static int Logging = MIDI_OFF; -static int TickCount = 0; -static int LastMsg = -1; -static int DrumOn = 0; -static FILE *MIDIOut = 0; - -static void MIDISound(int Channel,int Freq,int Volume); -static void MIDISetSound(int Channel,int Type); -static void MIDIDrum(int Type,int Force); -static void MIDIMessage(byte D0,byte D1,byte D2); -static void NoteOn(byte Channel,byte Note,byte Level); -static void NoteOff(byte Channel); -static void WriteDelta(void); -static void WriteTempo(int Freq); - -/** SHIFT() **************************************************/ -/** Make MIDI channel#10 last, as it is normally used for **/ -/** percussion instruments only and doesn't sound nice. **/ -/*************************************************************/ -#define SHIFT(Ch) (Ch==15? 9:Ch>8? Ch+1:Ch) - -/** Sound() **************************************************/ -/** Generate sound of given frequency (Hz) and volume **/ -/** (0..255) via given channel. Setting Freq=0 or Volume=0 **/ -/** turns sound off. **/ -/*************************************************************/ -void Sound(int Channel,int Freq,int Volume) -{ - if(Channel<0) return; - Freq = Freq<0? 0:Freq; - Volume = Volume<0? 0:Volume>255? 255:Volume; - - /* Call sound driver if present */ - if(SndDriver.Sound) (*SndDriver.Sound)(Channel,Freq,Volume); - - /* Log sound to MIDI file */ - MIDISound(Channel,Freq,Volume); -} - -/** Drum() ***************************************************/ -/** Hit a drum of given type with given force (0..255). **/ -/** MIDI drums can be used by ORing their numbers with **/ -/** SND_MIDI. **/ -/*************************************************************/ -void Drum(int Type,int Force) -{ - Force = Force<0? 0:Force>255? 255:Force; - - if(SndDriver.Drum) (*SndDriver.Drum)(Type,Force); - - /* Log drum to MIDI file */ - MIDIDrum(Type,Force); -} - -/** SetSound() ***********************************************/ -/** Set sound type at a given channel. MIDI instruments can **/ -/** be set directly by ORing their numbers with SND_MIDI. **/ -/*************************************************************/ -void SetSound(int Channel,int Type) -{ - if(Channel<0) return; - - if(SndDriver.SetSound) (*SndDriver.SetSound)(Channel,Type); - - /* Log instrument change to MIDI file */ - MIDISetSound(Channel,Type); -} - -/** SetChannels() ********************************************/ -/** Set master volume (0..255) and switch channels on/off. **/ -/** Each channel N has corresponding bit 2^N in Switch. Set **/ -/** or reset this bit to turn the channel on or off. **/ -/*************************************************************/ -void SetChannels(int Volume,int Switch) -{ - Volume = Volume<0? 0:Volume>255? 255:Volume; - - if(SndDriver.SetChannels) (*SndDriver.SetChannels)(Volume,Switch); -} - -/** SetWave() ************************************************/ -/** Set waveform for a given channel. The channel will be **/ -/** marked with sound type SND_WAVE. Set Rate=0 if you want **/ -/** waveform to be an instrument or set it to the waveform **/ -/** own playback rate. **/ -/*************************************************************/ -void SetWave(int Channel,signed char *Data,int Length,int Rate) -{ - if((Channel<0)||(Length<=0)) return; - - if(SndDriver.SetWave) (*SndDriver.SetWave)(Channel,Data,Length,Rate); - - /* Log instrument change to MIDI file */ - MIDISetSound(Channel,Rate? -1:SND_MELODIC); -} - -/** GetWave() ************************************************/ -/** Get current read position for the buffer set with the **/ -/** SetWave() call. Returns 0 if no buffer has been set, or **/ -/** if there is no playrate set (i.e. wave is instrument). **/ -/*************************************************************/ -const signed char *GetWave(int Channel) -{ - return(SndDriver.GetWave? (*SndDriver.GetWave)(Channel):0); -} - -/** InitMIDI() ***********************************************/ -/** Initialize soundtrack logging into MIDI file FileName. **/ -/** Repeated calls to InitMIDI() will close current MIDI **/ -/** file and continue logging into a new one. **/ -/*************************************************************/ -void InitMIDI(const char *FileName) -{ - int WasLogging; - - /* Must pass a name! */ - if(!FileName) return; - - /* Memorize logging status */ - WasLogging=Logging; - - /* If MIDI logging in progress, close current file */ - if(MIDIOut) TrashMIDI(); - - /* Set log file name and ticks/second parameter, no logging yet */ - LogName = FileName; - Logging = MIDI_OFF; - LastMsg = -1; - TickCount = 0; - MIDIOut = 0; - DrumOn = 0; - - /* If was logging, restart */ - if(WasLogging) MIDILogging(MIDI_ON); -} - -/** TrashMIDI() **********************************************/ -/** Finish logging soundtrack and close the MIDI file. **/ -/*************************************************************/ -void TrashMIDI(void) -{ - long Length; - int J; - - /* If not logging, drop out */ - if(!MIDIOut) return; - /* Turn sound off */ - for(J=0;J>24)&0xFF,MIDIOut); - fputc((Length>>16)&0xFF,MIDIOut); - fputc((Length>>8)&0xFF,MIDIOut); - fputc(Length&0xFF,MIDIOut); - - /* Done logging */ - fclose(MIDIOut); - Logging = MIDI_OFF; - LastMsg = -1; - TickCount = 0; - MIDIOut = 0; -} - -/** MIDILogging() ********************************************/ -/** Turn soundtrack logging on/off and return its current **/ -/** status. Possible values of Switch are MIDI_OFF (turn **/ -/** logging off), MIDI_ON (turn logging on), MIDI_TOGGLE **/ -/** (toggle logging), and MIDI_QUERY (just return current **/ -/** state of logging). **/ -/*************************************************************/ -int MIDILogging(int Switch) -{ - static const char MThd[] = "MThd\0\0\0\006\0\0\0\1"; - /* ID DataLen Fmt Trks */ - static const char MTrk[] = "MTrk\0\0\0\0"; - /* ID TrkLen */ - int J,I; - - /* Toggle logging if requested */ - if(Switch==MIDI_TOGGLE) Switch=!Logging; - - if((Switch==MIDI_ON)||(Switch==MIDI_OFF)) - if(Switch^Logging) - { - /* When turning logging off, silence all channels */ - if(!Switch&&MIDIOut) - for(J=0;J>8)&0xFF,MIDIOut); - fputc(MIDI_DIVISIONS&0xFF,MIDIOut); - if(fwrite(MTrk,1,8,MIDIOut)!=8) - { fclose(MIDIOut);MIDIOut=0;return(MIDI_OFF); } - - /* Write out the tempo */ - WriteTempo(MIDI_DIVISIONS); - } - - /* Turn logging off on failure to open MIDIOut */ - if(!MIDIOut) Switch=MIDI_OFF; - - /* Assign new switch value */ - Logging=Switch; - - /* If switching logging on... */ - if(Switch) - { - /* Start logging without a pause */ - TickCount=0; - - /* Write instrument changes */ - for(J=0;J=0)&&(CH[J].Type&0x10000)) - { - I=CH[J].Type&~0x10000; - CH[J].Type=-1; - MIDISetSound(J,I); - } - } - } - - /* Return current logging status */ - return(Logging); -} - -/** MIDITicks() **********************************************/ -/** Log N 1ms MIDI ticks. **/ -/*************************************************************/ -void MIDITicks(int N) -{ - if(Logging&&MIDIOut&&(N>0)) TickCount+=N; -} - -/** MIDISound() **********************************************/ -/** Set sound frequency (Hz) and volume (0..255) for a **/ -/** given channel. **/ -/*************************************************************/ -void MIDISound(int Channel,int Freq,int Volume) -{ - int MIDIVolume,MIDINote,MIDIWheel; - - /* If logging off, file closed, or invalid channel, drop out */ - if(!Logging||!MIDIOut||(Channel>=MIDI_CHANNELS-1)||(Channel<0)) return; - /* Frequency must be in range */ - if((FreqMIDI_MAXFREQ)) Freq=0; - /* Volume must be in range */ - if(Volume<0) Volume=0; else if(Volume>255) Volume=255; - /* Instrument number must be valid */ - if(CH[Channel].Type<0) Freq=0; - - if(!Volume||!Freq) NoteOff(Channel); - else - { - /* SND_TRIANGLE is twice quieter than SND_MELODIC */ - if(CH[Channel].Type==SND_TRIANGLE) Volume=(Volume+1)/2; - /* Compute MIDI note parameters */ - MIDIVolume = (127*Volume+128)/255; - MIDINote = Freqs[Freq/3].Note; - MIDIWheel = Freqs[Freq/3].Wheel; - - /* Play new note */ - NoteOn(Channel,MIDINote,MIDIVolume); - - /* Change pitch */ - if(CH[Channel].Pitch!=MIDIWheel) - { - MIDIMessage(0xE0+SHIFT(Channel),MIDIWheel&0x7F,(MIDIWheel>>7)&0x7F); - CH[Channel].Pitch=MIDIWheel; - } - } -} - -/** MIDISetSound() *******************************************/ -/** Set sound type for a given channel. **/ -/*************************************************************/ -void MIDISetSound(int Channel,int Type) -{ - /* Channel must be valid */ - if((Channel>=MIDI_CHANNELS-1)||(Channel<0)) return; - - /* If instrument changed... */ - if(CH[Channel].Type!=Type) - { - /* If logging off or file closed, drop out */ - if(!Logging||!MIDIOut) CH[Channel].Type=Type|0x10000; - else - { - CH[Channel].Type=Type; - if(Type<0) NoteOff(Channel); - else - { - Type=Type&SND_MIDI? (Type&0x7F):Programs[Type%5]; - MIDIMessage(0xC0+SHIFT(Channel),Type,255); - } - } - } -} - -/** MIDIDrum() ***********************************************/ -/** Hit a drum of a given type with given force. **/ -/*************************************************************/ -void MIDIDrum(int Type,int Force) -{ - /* If logging off or invalid channel, drop out */ - if(!Logging||!MIDIOut) return; - /* The only non-MIDI drum is a click ("Low Wood Block") */ - Type=Type&DRM_MIDI? (Type&0x7F):77; - /* Release previous drum */ - if(DrumOn) MIDIMessage(0x89,DrumOn,127); - /* Hit next drum */ - if(Type) MIDIMessage(0x99,Type,(Force&0xFF)/2); - DrumOn=Type; -} - -/** MIDIMessage() ********************************************/ -/** Write out a MIDI message. **/ -/*************************************************************/ -void MIDIMessage(byte D0,byte D1,byte D2) -{ - /* Write number of ticks that passed */ - WriteDelta(); - - /* Write out the command */ - if(D0!=LastMsg) { LastMsg=D0;fputc(D0,MIDIOut); } - - /* Write out the arguments */ - if(D1<128) - { - fputc(D1,MIDIOut); - if(D2<128) fputc(D2,MIDIOut); - } -} - -/** NoteOn() *************************************************/ -/** Turn on a note on a given channel. **/ -/*************************************************************/ -void NoteOn(byte Channel,byte Note,byte Level) -{ - Note = Note>0x7F? 0x7F:Note; - Level = Level>0x7F? 0x7F:Level; - - if((CH[Channel].Note!=Note)||(CH[Channel].Level!=Level)) - { - if(CH[Channel].Note>=0) NoteOff(Channel); - MIDIMessage(0x90+SHIFT(Channel),Note,Level); - CH[Channel].Note=Note; - CH[Channel].Level=Level; - } -} - -/** NoteOff() ************************************************/ -/** Turn off a note on a given channel. **/ -/*************************************************************/ -void NoteOff(byte Channel) -{ - if(CH[Channel].Note>=0) - { - MIDIMessage(0x80+SHIFT(Channel),CH[Channel].Note,127); - CH[Channel].Note=-1; - } -} - -/** WriteDelta() *********************************************/ -/** Write number of ticks since the last MIDI command and **/ -/** reset the counter. **/ -/*************************************************************/ -void WriteDelta(void) -{ - if(TickCount<128) fputc(TickCount,MIDIOut); - else - { - if(TickCount<128*128) - { - fputc((TickCount>>7)|0x80,MIDIOut); - fputc(TickCount&0x7F,MIDIOut); - } - else - { - fputc(((TickCount>>14)&0x7F)|0x80,MIDIOut); - fputc(((TickCount>>7)&0x7F)|0x80,MIDIOut); - fputc(TickCount&0x7F,MIDIOut); - } - } - - TickCount=0; -} - -/** WriteTempo() *********************************************/ -/** Write out soundtrack tempo (Hz). **/ -/*************************************************************/ -void WriteTempo(int Freq) -{ - int J; - - J=500000*MIDI_DIVISIONS*2/Freq; - WriteDelta(); - fputc(0xFF,MIDIOut); - fputc(0x51,MIDIOut); - fputc(0x03,MIDIOut); - fputc((J>>16)&0xFF,MIDIOut); - fputc((J>>8)&0xFF,MIDIOut); - fputc(J&0xFF,MIDIOut); -} diff --git a/src/apu/apu.c b/src/apu/apu.c new file mode 100644 index 0000000..922f0a4 --- /dev/null +++ b/src/apu/apu.c @@ -0,0 +1,10 @@ +/* + * APU emulation - The peTI-NESulator Project + * apu.c + * + * Created by Manoel TRAPIER. + * Copyright (c) 2003-2018 986-Studio. All rights reserved. + * + */ + +/* Empty, for now */ \ No newline at end of file diff --git a/src/include/apu/apu.h b/src/include/apu/apu.h new file mode 100644 index 0000000..2103175 --- /dev/null +++ b/src/include/apu/apu.h @@ -0,0 +1,14 @@ +/* + * APU emulation - The peTI-NESulator Project + * apu.h + * + * Created by Manoel TRAPIER. + * Copyright (c) 2003-2018 986-Studio. All rights reserved. + * + */ +#ifndef PETI_NESULATOR_APU_H +#define PETI_NESULATOR_APU_H + +/* Empty, for now */ + +#endif /* PETI_NESULATOR_APU_H */ diff --git a/src/main.c b/src/main.c index e7712f4..05a58c7 100755 --- a/src/main.c +++ b/src/main.c @@ -50,10 +50,8 @@ #include #include +#include -#ifdef USE_SOUND -#include -#endif #if ISPAL && !ISNTSC int VBLANK_TIME = 70; @@ -362,7 +360,6 @@ byte Page40[256]; void WrHook4000Multiplexer(byte addr, byte value) { -#ifdef USE_SOUND static byte SQ1V = 0; static byte SQ2V = 0; static byte NOIV = 0; @@ -383,11 +380,10 @@ void WrHook4000Multiplexer(byte addr, byte value) static byte Sq2_reg3 = 0; double SQ = 0.0; -#endif + switch(addr) { -#ifdef USE_SOUND case 0x00: /* DDLE NNNN */ Sq1_reg0 = value; if (Sq1_reg0 & 0x10) @@ -406,49 +402,17 @@ void WrHook4000Multiplexer(byte addr, byte value) break; case 0x02: - /*console_printf(Console_Default, "Sq1 reg0: 0x%02X - duty:0x%X loop:0x%X env:0x%X vol:0x%X\n", - Sq1_reg0, - (Sq1_reg0&0xC0)>>6, - (Sq1_reg0&0x20)>>5, - (Sq1_reg0&0x10)>>4, - Sq1_reg0&0x0F); - console_printf(Console_Default, "Sq1 reg1: 0x%02X - sweep:0x%X period:0x%X neg:0x%X shift:0x%X\n", - Sq1_reg1, - (Sq1_reg1&0x80)>>8, - (Sq1_reg1&0x70)>>4, - (Sq1_reg1&0x08)>>3, - Sq1_reg1&0x07); - console_printf(Console_Default, "Sq1 reg2: 0x%02X\n", value); - console_printf(Console_Default, "Sq1 reg3: 0x%02X\n", Sq1_reg3);*/ SQ1P = value | ((Sq1_reg3&0x7) << 8); - SQ = APU_BASEFREQ * 1000 * 1000 / (SQ1P+1 /*+ - (Sq1_reg1&0x80)?0:( (Sq1_reg1&0x08)?(SQ1P>>(Sq1_reg1&0x07)):(SQ1P<<(Sq1_reg1&0x07)) )*/); - //SetSound(0,SND_MELODIC); - - //console_printf(Console_Default, "SQ1V = %d - SQ = %f - SQ1P = %d\n", SQ1V, SQ, SQ1P); - -#ifdef SOUND_LOG - { FILE *fp = fopen("sound.log", "at"); fprintf(fp, "%d %d %d\n", 0, SQ1P, SQ1V); fclose(fp); } -#endif - Sound(0, (int) SQ/22, (0xFF/0x0F) * SQ1V); - - //console_printf(Console_Default, "40%02X: 0x%02X (SQ1P:%d SQ:%f (%d))\n", addr, value, SQ1P, SQ, (int) SQ); + SQ = APU_BASEFREQ * 1000 * 1000 / (SQ1P+1); Sq1_reg2 = value; break; case 0x03: Sq1_reg3 = value; SQ1P = Sq1_reg2 | ((value&0x7) << 8); - SQ = APU_BASEFREQ * 1000 * 1000 / (SQ1P+1 /*+ - (Sq1_reg1&0x80)?0:( (Sq1_reg1&0x08)?(SQ1P>>(Sq1_reg1&0x07)):(SQ1P<<(Sq1_reg1&0x07)) )*/); -#ifdef SOUND_LOG - { FILE *fp = fopen("sound.log", "at"); fprintf(fp, "%d %d %d\n", 0, SQ1P, SQ1V); fclose(fp); } -#endif - Sound(0, (int) SQ/22, (0xFF/0x0F) * SQ1V); + SQ = APU_BASEFREQ * 1000 * 1000 / (SQ1P+1); break; - - - + case 0x04: Sq2_reg0 = value; if (Sq2_reg0 & 0x10) @@ -467,31 +431,8 @@ void WrHook4000Multiplexer(byte addr, byte value) case 0x06: Sq2_reg2 = value; - SQ2P = Sq2_reg2 | ((Sq2_reg3&0x7) << 8); - - SQ = APU_BASEFREQ * 1000 * 1000 / (SQ2P+1 /*+ - (Sq2_reg1&0x80)?0:( (Sq2_reg1&0x08)?(SQ2P>>(Sq2_reg1&0x07)):(SQ2P<<(Sq2_reg1&0x07)) )*/); - - /* console_printf(Console_Default, "Sq2 reg0: 0x%02X - duty:0x%X loop:0x%X env:0x%X vol:0x%X\n", - Sq2_reg0, - (Sq2_reg0&0xC0)>>6, - (Sq2_reg0&0x20)>>5, - (Sq2_reg0&0x10)>>4, - Sq2_reg0&0x0F); - console_printf(Console_Default, "Sq2 reg1: 0x%02X - sweep:0x%X period:0x%X neg:0x%X shift:0x%X\n", - Sq2_reg1, - (Sq2_reg1&0x80)>>8, - (Sq2_reg1&0x70)>>4, - (Sq2_reg1&0x08)>>3, - Sq2_reg1&0x07); - console_printf(Console_Default, "Sq2 reg2: 0x%02X\n", value); - console_printf(Console_Default, "Sq2 reg3: 0x%02X\n", Sq2_reg3); - console_printf(Console_Default, "SQ2V = %d - SQ = %f - SQ2P = %d\n", SQ2V, SQ, SQ2P);*/ -#ifdef SOUND_LOG - { FILE *fp = fopen("sound.log", "at"); fprintf(fp, "%d %d %d\n", 1, SQ2P, SQ2V); fclose(fp); } -#endif - Sound(1, (int) SQ/22, (0xFF/0x0F) * SQ2V); + SQ = APU_BASEFREQ * 1000 * 1000 / (SQ2P+1); break; case 0x07: @@ -499,65 +440,36 @@ void WrHook4000Multiplexer(byte addr, byte value) SQ2P = Sq2_reg2 | ((Sq2_reg3&0x7) << 8); - SQ = APU_BASEFREQ * 1000 * 1000 / (SQ2P+1 /*+ - (Sq2_reg1&0x80)?0:( (Sq2_reg1&0x08)?(SQ2P>>(Sq2_reg1&0x07)):(SQ2P<<(Sq2_reg1&0x07)) )*/); -#ifdef SOUND_LOG - { FILE *fp = fopen("sound.log", "at"); fprintf(fp, "%d %d %d\n", 1, SQ2P, SQ2V); fclose(fp); } -#endif - Sound(1, (int) SQ/22, (0xFF/0x0F) * SQ2V); + SQ = APU_BASEFREQ * 1000 * 1000 / (SQ2P+1); + break; case 0x0A: TRIP = (TRIP & 0xFF00) | value; SQ = APU_BASEFREQ * 1000 * 1000 / TRIP; -#ifdef SOUND_LOG - { FILE *fp = fopen("sound.log", "at"); fprintf(fp, "%d %d %d\n", 2, TRIP, 127); fclose(fp); } -#endif - Sound(2, (int) SQ/22, 127); break; case 0x0B: TRIP = (TRIP & 0x00FF) | ((value&0x7) << 8);; SQ = APU_BASEFREQ * 1000 * 1000 / TRIP; -#ifdef SOUND_LOG - { FILE *fp = fopen("sound.log", "at"); fprintf(fp, "%d %d %d\n", 2, TRIP, 127); fclose(fp); } -#endif - Sound(2, (int) SQ/22, 127); break; case 0x0C: NOIV = value & 0x0F; -#ifdef SOUND_LOG - { FILE *fp = fopen("sound.log", "at"); fprintf(fp, "%d %d %d\n", 3, NOIP, NOIV); fclose(fp); } -#endif - //SetSound(3, SND_NOISE); - Sound(3, (int) SQ/22, (0xFF/0x0F) * NOIV); break; case 0x0E: NOIP = value & 0x0F; SQ = APU_BASEFREQ * 1000 * 1000 / NOIP; -#ifdef SOUND_LOG - { FILE *fp = fopen("sound.log", "at"); fprintf(fp, "%d %d %d\n", 3, NOIP, NOIV); fclose(fp); } -#endif - //SetSound(3, SND_NOISE); - Sound(3, (int) SQ/22, NOIV); break; + case 0x0F: - break; + case 0x15: /* DMC, Noise, Triangle, Sq 2, Sq 1 */ - //SetChannels(0, (value&0x01)?0x01:0); - /* console_printf(Console_Default, "40%02X: 0x%02X [%c%c%c%c%c]\n", addr, value, - (value&0x10)?'d':'.', - (value&0x08)?'n':'.', - (value&0x04)?'t':'.', - (value&0x02)?'2':'.', - (value&0x01)?'1':'.');*/ - break; -#endif + case 0x14: ppu_fillSprRamDMA(value); break; @@ -577,8 +489,7 @@ void WrHook4000Multiplexer(byte addr, byte value) default: Page40[addr] = value; - // console_printf(Console_Default, "40%02X: 0x%02X\n", addr, value); - // console_printf(Console_Default, "pAPU: 0x%X @ 0x40%X\n", value, addr); + break; } } @@ -598,7 +509,9 @@ byte RdHook4000Multiplexer(byte addr) case 0x15: ret = 0x1F; - default: + break; + + default: ret = 0x42; } return ret;