mirror of
https://github.com/jorio/Pomme.git
synced 2024-06-03 06:29:31 +00:00
Split SoundFormats/SoundMixer
This commit is contained in:
parent
6f5592fbc3
commit
104c75ad56
|
@ -41,26 +41,29 @@ set(POMME_SOURCES
|
||||||
$<$<BOOL:${WIN32}>:${POMME_SRCDIR}/Platform/Windows/PommeWindows.h>
|
$<$<BOOL:${WIN32}>:${POMME_SRCDIR}/Platform/Windows/PommeWindows.h>
|
||||||
)
|
)
|
||||||
|
|
||||||
if (NOT(POMME_NO_SOUND))
|
if (NOT(POMME_NO_SOUND_FORMATS))
|
||||||
list(APPEND POMME_SOURCES
|
list(APPEND POMME_SOURCES
|
||||||
${POMME_SRCDIR}/Sound/AIFF.cpp
|
${POMME_SRCDIR}/SoundFormats/AIFF.cpp
|
||||||
${POMME_SRCDIR}/Sound/IMA4.cpp
|
${POMME_SRCDIR}/SoundFormats/IMA4.cpp
|
||||||
${POMME_SRCDIR}/Sound/MACE.cpp
|
${POMME_SRCDIR}/SoundFormats/MACE.cpp
|
||||||
${POMME_SRCDIR}/Sound/SoundUtilities.cpp
|
${POMME_SRCDIR}/SoundFormats/Midi.cpp
|
||||||
${POMME_SRCDIR}/Sound/xlaw.cpp
|
${POMME_SRCDIR}/SoundFormats/SoundFormats.cpp
|
||||||
|
${POMME_SRCDIR}/SoundFormats/xlaw.cpp
|
||||||
)
|
)
|
||||||
else()
|
else()
|
||||||
add_compile_definitions(POMME_NO_SOUND)
|
add_compile_definitions(POMME_NO_SOUND_FORMATS)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (NOT(POMME_NO_SOUND_PLAYBACK))
|
if (NOT(POMME_NO_SOUND_MIXER))
|
||||||
list(APPEND POMME_SOURCES
|
list(APPEND POMME_SOURCES
|
||||||
${POMME_SRCDIR}/Sound/cmixer.cpp
|
${POMME_SRCDIR}/SoundMixer/ChannelImpl.cpp
|
||||||
${POMME_SRCDIR}/Sound/cmixer.h
|
${POMME_SRCDIR}/SoundMixer/ChannelImpl.h
|
||||||
${POMME_SRCDIR}/Sound/SoundManager.cpp
|
${POMME_SRCDIR}/SoundMixer/cmixer.cpp
|
||||||
)
|
${POMME_SRCDIR}/SoundMixer/cmixer.h
|
||||||
|
${POMME_SRCDIR}/SoundMixer/SoundManager.cpp
|
||||||
|
)
|
||||||
else()
|
else()
|
||||||
add_compile_definitions(POMME_NO_SOUND_PLAYBACK)
|
add_compile_definitions(POMME_NO_SOUND_MIXER)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (NOT(POMME_NO_GRAPHICS))
|
if (NOT(POMME_NO_GRAPHICS))
|
||||||
|
|
|
@ -53,8 +53,12 @@ void Pomme::Init()
|
||||||
Pomme::Graphics::Init();
|
Pomme::Graphics::Init();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef POMME_NO_SOUND_PLAYBACK
|
#ifndef POMME_NO_SOUND_FORMATS
|
||||||
Pomme::Sound::Init();
|
Pomme::Sound::InitMidiFrequencyTable();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef POMME_NO_SOUND_MIXER
|
||||||
|
Pomme::Sound::InitMixer();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef POMME_NO_INPUT
|
#ifndef POMME_NO_INPUT
|
||||||
|
@ -64,7 +68,7 @@ void Pomme::Init()
|
||||||
|
|
||||||
void Pomme::Shutdown()
|
void Pomme::Shutdown()
|
||||||
{
|
{
|
||||||
#ifndef POMME_NO_SOUND_PLAYBACK
|
#ifndef POMME_NO_SOUND_MIXER
|
||||||
Pomme::Sound::Shutdown();
|
Pomme::Sound::ShutdownMixer();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,13 +6,16 @@
|
||||||
#include <istream>
|
#include <istream>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include "Sound/cmixer.h"
|
|
||||||
|
|
||||||
namespace Pomme::Sound
|
namespace Pomme::Sound
|
||||||
{
|
{
|
||||||
void Init();
|
void InitMidiFrequencyTable();
|
||||||
|
|
||||||
void Shutdown();
|
void InitMixer();
|
||||||
|
void ShutdownMixer();
|
||||||
|
|
||||||
|
double GetMidiNoteFrequency(int note);
|
||||||
|
std::string GetMidiNoteName(int note);
|
||||||
|
|
||||||
struct SampledSoundInfo
|
struct SampledSoundInfo
|
||||||
{
|
{
|
||||||
|
|
55
src/SoundFormats/Midi.cpp
Normal file
55
src/SoundFormats/Midi.cpp
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
#include "PommeSound.h"
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
constexpr int kNumMidiNotes = 128;
|
||||||
|
|
||||||
|
static double gMidiNoteFrequencies[kNumMidiNotes];
|
||||||
|
|
||||||
|
void Pomme::Sound::InitMidiFrequencyTable()
|
||||||
|
{
|
||||||
|
// powers of twelfth root of two
|
||||||
|
double gamme[12];
|
||||||
|
gamme[0] = 1.0;
|
||||||
|
for (int i = 1; i < 12; i++)
|
||||||
|
{
|
||||||
|
gamme[i] = gamme[i - 1] * 1.059630943592952646;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 128; i++)
|
||||||
|
{
|
||||||
|
int octave = 1 + (i + 3) / 12; // A440 and middle C are in octave 7
|
||||||
|
int semitone = (i + 3) % 12; // halfsteps up from A in current octave
|
||||||
|
|
||||||
|
float freq;
|
||||||
|
if (octave < 7)
|
||||||
|
freq = gamme[semitone] * 440.0 / (1 << (7 - octave)); // 440/(2**octaveDiff)
|
||||||
|
else
|
||||||
|
freq = gamme[semitone] * 440.0 * (1 << (octave - 7)); // 440*(2**octaveDiff)
|
||||||
|
|
||||||
|
gMidiNoteFrequencies[i] = freq;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double Pomme::Sound::GetMidiNoteFrequency(int note)
|
||||||
|
{
|
||||||
|
if (note < 0 || note >= kNumMidiNotes)
|
||||||
|
return 440.0;
|
||||||
|
else
|
||||||
|
return gMidiNoteFrequencies[note];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: these names are according to IM:S:2-43.
|
||||||
|
// These names won't match real-world names.
|
||||||
|
// E.g. for note 67 (A 440Hz), this will return "A6", whereas the real-world
|
||||||
|
// convention for that note is "A4".
|
||||||
|
std::string Pomme::Sound::GetMidiNoteName(int note)
|
||||||
|
{
|
||||||
|
static const char* gamme[12] = {"A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"};
|
||||||
|
|
||||||
|
int octave = 1 + (note + 3) / 12;
|
||||||
|
int semitonesFromA = (note + 3) % 12;
|
||||||
|
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << gamme[semitonesFromA] << octave;
|
||||||
|
return ss.str();
|
||||||
|
}
|
126
src/SoundMixer/ChannelImpl.cpp
Normal file
126
src/SoundMixer/ChannelImpl.cpp
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
#include "PommeSound.h"
|
||||||
|
#include "SoundMixer/ChannelImpl.h"
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
namespace Pomme::Sound
|
||||||
|
{
|
||||||
|
extern ChannelImpl* gHeadChan;
|
||||||
|
extern int gNumManagedChans;
|
||||||
|
}
|
||||||
|
|
||||||
|
ChannelImpl::ChannelImpl(SndChannelPtr _macChannel, bool transferMacChannelOwnership)
|
||||||
|
: macChannel(_macChannel)
|
||||||
|
, macChannelStructAllocatedByPomme(transferMacChannelOwnership)
|
||||||
|
, source()
|
||||||
|
, pan(0.0)
|
||||||
|
, gain(1.0)
|
||||||
|
, baseNote(kMiddleC)
|
||||||
|
, playbackNote(kMiddleC)
|
||||||
|
, pitchMult(1.0)
|
||||||
|
, loop(false)
|
||||||
|
, interpolate(false)
|
||||||
|
{
|
||||||
|
macChannel->channelImpl = (Ptr) this;
|
||||||
|
|
||||||
|
Link(); // Link chan into our list of managed chans
|
||||||
|
}
|
||||||
|
|
||||||
|
ChannelImpl::~ChannelImpl()
|
||||||
|
{
|
||||||
|
Unlink();
|
||||||
|
|
||||||
|
macChannel->channelImpl = nullptr;
|
||||||
|
|
||||||
|
if (macChannelStructAllocatedByPomme)
|
||||||
|
{
|
||||||
|
delete macChannel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelImpl::Recycle()
|
||||||
|
{
|
||||||
|
source.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelImpl::SetInitializationParameters(long initBits)
|
||||||
|
{
|
||||||
|
interpolate = !(initBits & initNoInterp);
|
||||||
|
source.SetInterpolation(interpolate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelImpl::ApplyParametersToSource(uint32_t mask, bool evenIfInactive)
|
||||||
|
{
|
||||||
|
if (!evenIfInactive && !source.active)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pitch
|
||||||
|
if (mask & kApplyParameters_Pitch)
|
||||||
|
{
|
||||||
|
double baseFreq = Pomme::Sound::GetMidiNoteFrequency(baseNote);
|
||||||
|
double playbackFreq = Pomme::Sound::GetMidiNoteFrequency(playbackNote);
|
||||||
|
source.SetPitch(pitchMult * playbackFreq / baseFreq);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pan and gain
|
||||||
|
if (mask & kApplyParameters_PanAndGain)
|
||||||
|
{
|
||||||
|
source.SetPan(pan);
|
||||||
|
source.SetGain(gain);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interpolation
|
||||||
|
if (mask & kApplyParameters_Interpolation)
|
||||||
|
{
|
||||||
|
source.SetInterpolation(interpolate);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interpolation
|
||||||
|
if (mask & kApplyParameters_Loop)
|
||||||
|
{
|
||||||
|
source.SetLoop(loop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelImpl::Link()
|
||||||
|
{
|
||||||
|
if (!Pomme::Sound::gHeadChan)
|
||||||
|
{
|
||||||
|
SetNext(nullptr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(nullptr == Pomme::Sound::gHeadChan->GetPrev());
|
||||||
|
Pomme::Sound::gHeadChan->SetPrev(this);
|
||||||
|
SetNext(Pomme::Sound::gHeadChan);
|
||||||
|
}
|
||||||
|
|
||||||
|
Pomme::Sound::gHeadChan = this;
|
||||||
|
SetPrev(nullptr);
|
||||||
|
|
||||||
|
Pomme::Sound::gNumManagedChans++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelImpl::Unlink()
|
||||||
|
{
|
||||||
|
if (Pomme::Sound::gHeadChan == this)
|
||||||
|
{
|
||||||
|
Pomme::Sound::gHeadChan = GetNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nullptr != GetPrev())
|
||||||
|
{
|
||||||
|
GetPrev()->SetNext(GetNext());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nullptr != GetNext())
|
||||||
|
{
|
||||||
|
GetNext()->SetPrev(GetPrev());
|
||||||
|
}
|
||||||
|
|
||||||
|
SetPrev(nullptr);
|
||||||
|
SetNext(nullptr);
|
||||||
|
|
||||||
|
Pomme::Sound::gNumManagedChans--;
|
||||||
|
}
|
73
src/SoundMixer/ChannelImpl.h
Normal file
73
src/SoundMixer/ChannelImpl.h
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Pomme.h"
|
||||||
|
#include "SoundMixer/cmixer.h"
|
||||||
|
|
||||||
|
enum ApplyParametersMask
|
||||||
|
{
|
||||||
|
kApplyParameters_PanAndGain = 1 << 0,
|
||||||
|
kApplyParameters_Pitch = 1 << 1,
|
||||||
|
kApplyParameters_Loop = 1 << 2,
|
||||||
|
kApplyParameters_Interpolation = 1 << 3,
|
||||||
|
kApplyParameters_All = 0xFFFFFFFF
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ChannelImpl
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
ChannelImpl* prev;
|
||||||
|
ChannelImpl* next;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Pointer to application-facing interface
|
||||||
|
SndChannelPtr macChannel;
|
||||||
|
|
||||||
|
bool macChannelStructAllocatedByPomme;
|
||||||
|
cmixer::WavStream source;
|
||||||
|
|
||||||
|
// Parameters coming from Mac sound commands, passed back to cmixer source
|
||||||
|
double pan;
|
||||||
|
double gain;
|
||||||
|
Byte baseNote;
|
||||||
|
Byte playbackNote;
|
||||||
|
double pitchMult;
|
||||||
|
bool loop;
|
||||||
|
bool interpolate;
|
||||||
|
|
||||||
|
bool temporaryPause = false;
|
||||||
|
|
||||||
|
ChannelImpl(SndChannelPtr _macChannel, bool transferMacChannelOwnership);
|
||||||
|
|
||||||
|
~ChannelImpl();
|
||||||
|
|
||||||
|
void Recycle();
|
||||||
|
|
||||||
|
void SetInitializationParameters(long initBits);
|
||||||
|
|
||||||
|
void ApplyParametersToSource(uint32_t mask, bool evenIfInactive = false);
|
||||||
|
|
||||||
|
inline ChannelImpl* GetPrev() const
|
||||||
|
{
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ChannelImpl* GetNext() const
|
||||||
|
{
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void SetPrev(ChannelImpl* newPrev)
|
||||||
|
{
|
||||||
|
prev = newPrev;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void SetNext(ChannelImpl* newNext)
|
||||||
|
{
|
||||||
|
next = newNext;
|
||||||
|
macChannel->nextChan = newNext ? newNext->macChannel : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Link();
|
||||||
|
|
||||||
|
void Unlink();
|
||||||
|
};
|
|
@ -1,7 +1,8 @@
|
||||||
#include "Pomme.h"
|
#include "Pomme.h"
|
||||||
#include "PommeFiles.h"
|
#include "PommeFiles.h"
|
||||||
#include "cmixer.h"
|
|
||||||
#include "PommeSound.h"
|
#include "PommeSound.h"
|
||||||
|
#include "SoundMixer/ChannelImpl.h"
|
||||||
|
#include "SoundMixer/cmixer.h"
|
||||||
#include "Utilities/bigendianstreams.h"
|
#include "Utilities/bigendianstreams.h"
|
||||||
#include "Utilities/IEEEExtended.h"
|
#include "Utilities/IEEEExtended.h"
|
||||||
#include "Utilities/memstream.h"
|
#include "Utilities/memstream.h"
|
||||||
|
@ -15,184 +16,14 @@
|
||||||
#define LOG POMME_GENLOG(POMME_DEBUG_SOUND, "SOUN")
|
#define LOG POMME_GENLOG(POMME_DEBUG_SOUND, "SOUN")
|
||||||
#define LOG_NOPREFIX POMME_GENLOG_NOPREFIX(POMME_DEBUG_SOUND)
|
#define LOG_NOPREFIX POMME_GENLOG_NOPREFIX(POMME_DEBUG_SOUND)
|
||||||
|
|
||||||
static struct ChannelImpl* headChan = nullptr;
|
|
||||||
static int nManagedChans = 0;
|
|
||||||
static double midiNoteFrequencies[128];
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Internal channel info
|
// Internal channel info
|
||||||
|
|
||||||
enum ApplyParametersMask
|
namespace Pomme::Sound
|
||||||
{
|
{
|
||||||
kApplyParameters_PanAndGain = 1 << 0,
|
struct ChannelImpl* gHeadChan = nullptr;
|
||||||
kApplyParameters_Pitch = 1 << 1,
|
int gNumManagedChans = 0;
|
||||||
kApplyParameters_Loop = 1 << 2,
|
}
|
||||||
kApplyParameters_Interpolation = 1 << 3,
|
|
||||||
kApplyParameters_All = 0xFFFFFFFF
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ChannelImpl
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
ChannelImpl* prev;
|
|
||||||
ChannelImpl* next;
|
|
||||||
|
|
||||||
public:
|
|
||||||
// Pointer to application-facing interface
|
|
||||||
SndChannelPtr macChannel;
|
|
||||||
|
|
||||||
bool macChannelStructAllocatedByPomme;
|
|
||||||
cmixer::WavStream source;
|
|
||||||
|
|
||||||
// Parameters coming from Mac sound commands, passed back to cmixer source
|
|
||||||
double pan;
|
|
||||||
double gain;
|
|
||||||
Byte baseNote;
|
|
||||||
Byte playbackNote;
|
|
||||||
double pitchMult;
|
|
||||||
bool loop;
|
|
||||||
bool interpolate;
|
|
||||||
|
|
||||||
bool temporaryPause = false;
|
|
||||||
|
|
||||||
ChannelImpl(SndChannelPtr _macChannel, bool transferMacChannelOwnership)
|
|
||||||
: macChannel(_macChannel)
|
|
||||||
, macChannelStructAllocatedByPomme(transferMacChannelOwnership)
|
|
||||||
, source()
|
|
||||||
, pan(0.0)
|
|
||||||
, gain(1.0)
|
|
||||||
, baseNote(kMiddleC)
|
|
||||||
, playbackNote(kMiddleC)
|
|
||||||
, pitchMult(1.0)
|
|
||||||
, loop(false)
|
|
||||||
, interpolate(false)
|
|
||||||
{
|
|
||||||
macChannel->channelImpl = (Ptr) this;
|
|
||||||
|
|
||||||
Link(); // Link chan into our list of managed chans
|
|
||||||
}
|
|
||||||
|
|
||||||
~ChannelImpl()
|
|
||||||
{
|
|
||||||
Unlink();
|
|
||||||
|
|
||||||
macChannel->channelImpl = nullptr;
|
|
||||||
|
|
||||||
if (macChannelStructAllocatedByPomme)
|
|
||||||
{
|
|
||||||
delete macChannel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Recycle()
|
|
||||||
{
|
|
||||||
source.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetInitializationParameters(long initBits)
|
|
||||||
{
|
|
||||||
interpolate = !(initBits & initNoInterp);
|
|
||||||
source.SetInterpolation(interpolate);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ApplyParametersToSource(uint32_t mask, bool evenIfInactive = false)
|
|
||||||
{
|
|
||||||
if (!evenIfInactive && !source.active)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pitch
|
|
||||||
if (mask & kApplyParameters_Pitch)
|
|
||||||
{
|
|
||||||
double baseFreq = midiNoteFrequencies[baseNote];
|
|
||||||
double playbackFreq = midiNoteFrequencies[playbackNote];
|
|
||||||
source.SetPitch(pitchMult * playbackFreq / baseFreq);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pan and gain
|
|
||||||
if (mask & kApplyParameters_PanAndGain)
|
|
||||||
{
|
|
||||||
source.SetPan(pan);
|
|
||||||
source.SetGain(gain);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Interpolation
|
|
||||||
if (mask & kApplyParameters_Interpolation)
|
|
||||||
{
|
|
||||||
source.SetInterpolation(interpolate);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Interpolation
|
|
||||||
if (mask & kApplyParameters_Loop)
|
|
||||||
{
|
|
||||||
source.SetLoop(loop);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ChannelImpl* GetPrev() const
|
|
||||||
{
|
|
||||||
return prev;
|
|
||||||
}
|
|
||||||
|
|
||||||
ChannelImpl* GetNext() const
|
|
||||||
{
|
|
||||||
return next;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetPrev(ChannelImpl* newPrev)
|
|
||||||
{
|
|
||||||
prev = newPrev;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetNext(ChannelImpl* newNext)
|
|
||||||
{
|
|
||||||
next = newNext;
|
|
||||||
macChannel->nextChan = newNext ? newNext->macChannel : nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Link()
|
|
||||||
{
|
|
||||||
if (!headChan)
|
|
||||||
{
|
|
||||||
SetNext(nullptr);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
assert(nullptr == headChan->GetPrev());
|
|
||||||
headChan->SetPrev(this);
|
|
||||||
SetNext(headChan);
|
|
||||||
}
|
|
||||||
|
|
||||||
headChan = this;
|
|
||||||
SetPrev(nullptr);
|
|
||||||
|
|
||||||
nManagedChans++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Unlink()
|
|
||||||
{
|
|
||||||
if (headChan == this)
|
|
||||||
{
|
|
||||||
headChan = GetNext();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nullptr != GetPrev())
|
|
||||||
{
|
|
||||||
GetPrev()->SetNext(GetNext());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nullptr != GetNext())
|
|
||||||
{
|
|
||||||
GetNext()->SetPrev(GetPrev());
|
|
||||||
}
|
|
||||||
|
|
||||||
SetPrev(nullptr);
|
|
||||||
SetNext(nullptr);
|
|
||||||
|
|
||||||
nManagedChans--;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Internal utilities
|
// Internal utilities
|
||||||
|
@ -202,47 +33,6 @@ static inline ChannelImpl& GetChannelImpl(SndChannelPtr chan)
|
||||||
return *(ChannelImpl*) chan->channelImpl;
|
return *(ChannelImpl*) chan->channelImpl;
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// MIDI note utilities
|
|
||||||
|
|
||||||
// Note: these names are according to IM:S:2-43.
|
|
||||||
// These names won't match real-world names.
|
|
||||||
// E.g. for note 67 (A 440Hz), this will return "A6", whereas the real-world
|
|
||||||
// convention for that note is "A4".
|
|
||||||
static std::string GetMidiNoteName(int i)
|
|
||||||
{
|
|
||||||
static const char* gamme[12] = {"A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"};
|
|
||||||
|
|
||||||
int octave = 1 + (i + 3) / 12;
|
|
||||||
int semitonesFromA = (i + 3) % 12;
|
|
||||||
|
|
||||||
std::stringstream ss;
|
|
||||||
ss << gamme[semitonesFromA] << octave;
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void InitMidiFrequencyTable()
|
|
||||||
{
|
|
||||||
// powers of twelfth root of two
|
|
||||||
double gamme[12];
|
|
||||||
gamme[0] = 1.0;
|
|
||||||
for (int i = 1; i < 12; i++)
|
|
||||||
{
|
|
||||||
gamme[i] = gamme[i - 1] * 1.059630943592952646;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < 128; i++)
|
|
||||||
{
|
|
||||||
int octave = 1 + (i + 3) / 12; // A440 and middle C are in octave 7
|
|
||||||
int semitone = (i + 3) % 12; // halfsteps up from A in current octave
|
|
||||||
if (octave < 7)
|
|
||||||
midiNoteFrequencies[i] = gamme[semitone] * 440.0 / (1 << (7 - octave)); // 440/(2**octaveDiff)
|
|
||||||
else
|
|
||||||
midiNoteFrequencies[i] = gamme[semitone] * 440.0 * (1 << (octave - 7)); // 440*(2**octaveDiff)
|
|
||||||
//LOG << i << "\t" << GetMidiNoteName(i) << "\t" << midiNoteFrequencies[i] << "\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Sound Manager
|
// Sound Manager
|
||||||
|
|
||||||
|
@ -297,7 +87,8 @@ OSErr SndNewChannel(SndChannelPtr* macChanPtr, short synth, long init, SndCallBa
|
||||||
//---------------------------
|
//---------------------------
|
||||||
// Done
|
// Done
|
||||||
|
|
||||||
LOG << "New channel created, init = $" << std::hex << init << std::dec << ", total managed channels = " << nManagedChans << "\n";
|
LOG << "New channel created, init = $" << std::hex << init << std::dec
|
||||||
|
<< ", total managed channels = " << Pomme::Sound::gNumManagedChans << "\n";
|
||||||
|
|
||||||
return noErr;
|
return noErr;
|
||||||
}
|
}
|
||||||
|
@ -440,7 +231,8 @@ OSErr SndDoImmediate(SndChannelPtr chan, const SndCommand* cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
case freqCmd:
|
case freqCmd:
|
||||||
LOG << "freqCmd " << cmd->param2 << " " << GetMidiNoteName(cmd->param2) << " " << midiNoteFrequencies[cmd->param2] << "\n";
|
LOG << "freqCmd " << cmd->param2 << " "
|
||||||
|
<< Pomme::Sound::GetMidiNoteName(cmd->param2) << " " << Pomme::Sound::GetMidiNoteFrequency(cmd->param2) << "\n";
|
||||||
impl.playbackNote = Byte(cmd->param2);
|
impl.playbackNote = Byte(cmd->param2);
|
||||||
impl.ApplyParametersToSource(kApplyParameters_Pitch);
|
impl.ApplyParametersToSource(kApplyParameters_Pitch);
|
||||||
break;
|
break;
|
||||||
|
@ -598,7 +390,7 @@ NumVersion SndSoundManagerVersion()
|
||||||
|
|
||||||
void Pomme_PauseAllChannels(Boolean pause)
|
void Pomme_PauseAllChannels(Boolean pause)
|
||||||
{
|
{
|
||||||
for (auto* chan = headChan; chan; chan = chan->GetNext())
|
for (auto* chan = Pomme::Sound::gHeadChan; chan; chan = chan->GetNext())
|
||||||
{
|
{
|
||||||
auto& source = chan->source;
|
auto& source = chan->source;
|
||||||
if (pause && source.state == cmixer::CM_STATE_PLAYING && !chan->temporaryPause)
|
if (pause && source.state == cmixer::CM_STATE_PLAYING && !chan->temporaryPause)
|
||||||
|
@ -617,17 +409,16 @@ void Pomme_PauseAllChannels(Boolean pause)
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Init Sound Manager
|
// Init Sound Manager
|
||||||
|
|
||||||
void Pomme::Sound::Init()
|
void Pomme::Sound::InitMixer()
|
||||||
{
|
{
|
||||||
InitMidiFrequencyTable();
|
|
||||||
cmixer::InitWithSDL();
|
cmixer::InitWithSDL();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Pomme::Sound::Shutdown()
|
void Pomme::Sound::ShutdownMixer()
|
||||||
{
|
{
|
||||||
cmixer::ShutdownWithSDL();
|
cmixer::ShutdownWithSDL();
|
||||||
while (headChan)
|
while (Pomme::Sound::gHeadChan)
|
||||||
{
|
{
|
||||||
SndDisposeChannel(headChan->macChannel, true);
|
SndDisposeChannel(Pomme::Sound::gHeadChan->macChannel, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user