gosu 0.7.12 → 0.7.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gosu/Audio.hpp +1 -0
- data/Gosu/Bitmap.hpp +4 -4
- data/Gosu/Graphics.hpp +3 -0
- data/Gosu/Input.hpp +10 -0
- data/Gosu/Text.hpp +1 -0
- data/Gosu/Window.hpp +20 -9
- data/GosuImpl/Audio/ALChannelManagement.hpp +72 -0
- data/GosuImpl/Audio/AudioFileMac.hpp +105 -0
- data/GosuImpl/AudioOpenAL.mm +486 -0
- data/GosuImpl/DirectoriesTouch.mm +38 -0
- data/GosuImpl/Graphics/BitmapBMP.cpp +23 -8
- data/GosuImpl/Graphics/BitmapTouch.mm +73 -0
- data/GosuImpl/Graphics/BitmapUtils.cpp +0 -2
- data/GosuImpl/Graphics/BlockAllocator.cpp +15 -4
- data/GosuImpl/Graphics/Common.hpp +21 -0
- data/GosuImpl/Graphics/DrawOp.hpp +53 -10
- data/GosuImpl/Graphics/GosuView.hpp +28 -0
- data/GosuImpl/Graphics/GosuView.mm +159 -0
- data/GosuImpl/Graphics/Graphics.cpp +18 -18
- data/GosuImpl/Graphics/LargeImageData.cpp +3 -0
- data/GosuImpl/Graphics/TexChunk.cpp +3 -2
- data/GosuImpl/Graphics/Text.cpp +85 -20
- data/GosuImpl/Graphics/TextMac.cpp +14 -27
- data/GosuImpl/Graphics/TextTouch.mm +89 -0
- data/GosuImpl/Graphics/Texture.cpp +1 -5
- data/GosuImpl/Iconv.hpp +5 -3
- data/GosuImpl/InputMac.mm +8 -9
- data/GosuImpl/InputTouch.mm +47 -0
- data/GosuImpl/InputWin.cpp +12 -4
- data/GosuImpl/InputX.cpp +3 -1
- data/GosuImpl/MacUtility.hpp +41 -0
- data/GosuImpl/Math.cpp +1 -1
- data/GosuImpl/RubyGosu.swg +17 -6
- data/GosuImpl/RubyGosu_wrap.cxx +950 -549
- data/GosuImpl/RubyGosu_wrap.h +2 -1
- data/GosuImpl/TimingUnix.cpp +15 -17
- data/GosuImpl/UtilityTouch.mm +44 -0
- data/GosuImpl/WindowMac.mm +39 -19
- data/GosuImpl/WindowTouch.mm +154 -0
- data/GosuImpl/WindowWin.cpp +27 -10
- data/GosuImpl/WindowX.cpp +27 -7
- data/linux/extconf.rb +6 -0
- data/mac/Gosu.icns +0 -0
- data/mac/Gosu.xcodeproj/jlnr.pbxuser +562 -788
- data/mac/Gosu.xcodeproj/jlnr.perspectivev3 +113 -103
- data/mac/Gosu.xcodeproj/project.pbxproj +258 -173
- data/reference/Async_8hpp-source.html +1 -1
- data/reference/Audio_8hpp-source.html +91 -90
- data/reference/Audio_8hpp.html +1 -1
- data/reference/AutoLink_8hpp-source.html +1 -1
- data/reference/AutoLink_8hpp.html +1 -1
- data/reference/Bitmap_8hpp-source.html +11 -12
- data/reference/Bitmap_8hpp.html +1 -1
- data/reference/ButtonsMac_8hpp-source.html +1 -1
- data/reference/ButtonsWin_8hpp-source.html +1 -1
- data/reference/ButtonsX_8hpp-source.html +1 -1
- data/reference/Color_8hpp-source.html +1 -1
- data/reference/Color_8hpp.html +1 -1
- data/reference/Directories_8hpp-source.html +1 -1
- data/reference/Directories_8hpp.html +1 -1
- data/reference/Font_8hpp-source.html +1 -1
- data/reference/Font_8hpp.html +1 -1
- data/reference/Fwd_8hpp-source.html +1 -1
- data/reference/Fwd_8hpp.html +1 -1
- data/reference/Gosu_8hpp-source.html +1 -1
- data/reference/Gosu_8hpp.html +1 -1
- data/reference/GraphicsBase_8hpp-source.html +1 -1
- data/reference/GraphicsBase_8hpp.html +1 -1
- data/reference/Graphics_8hpp-source.html +64 -61
- data/reference/Graphics_8hpp.html +8 -1
- data/reference/IO_8hpp-source.html +1 -1
- data/reference/IO_8hpp.html +1 -1
- data/reference/ImageData_8hpp-source.html +1 -1
- data/reference/ImageData_8hpp.html +1 -1
- data/reference/Image_8hpp-source.html +1 -1
- data/reference/Image_8hpp.html +1 -1
- data/reference/Input_8hpp-source.html +81 -71
- data/reference/Input_8hpp.html +7 -1
- data/reference/Math_8hpp-source.html +1 -1
- data/reference/Math_8hpp.html +1 -1
- data/reference/Platform_8hpp-source.html +1 -1
- data/reference/Platform_8hpp.html +1 -1
- data/reference/RotFlip_8hpp-source.html +1 -1
- data/reference/RotFlip_8hpp.html +1 -1
- data/reference/Sockets_8hpp-source.html +1 -1
- data/reference/Sockets_8hpp.html +1 -1
- data/reference/TextInput_8hpp-source.html +1 -1
- data/reference/TextInput_8hpp.html +1 -1
- data/reference/Text_8hpp-source.html +28 -27
- data/reference/Text_8hpp.html +1 -1
- data/reference/Timing_8hpp-source.html +1 -1
- data/reference/Timing_8hpp.html +1 -1
- data/reference/Utility_8hpp-source.html +1 -1
- data/reference/Utility_8hpp.html +1 -1
- data/reference/WinUtility_8hpp-source.html +1 -1
- data/reference/WinUtility_8hpp.html +1 -1
- data/reference/Window_8hpp-source.html +76 -68
- data/reference/Window_8hpp.html +1 -1
- data/reference/annotated.html +1 -1
- data/reference/classGosu_1_1Audio-members.html +1 -1
- data/reference/classGosu_1_1Audio.html +1 -1
- data/reference/classGosu_1_1Bitmap-members.html +3 -2
- data/reference/classGosu_1_1Bitmap.html +9 -6
- data/reference/classGosu_1_1Buffer-members.html +1 -1
- data/reference/classGosu_1_1Buffer.html +1 -1
- data/reference/classGosu_1_1Button-members.html +1 -1
- data/reference/classGosu_1_1Button.html +2 -2
- data/reference/classGosu_1_1Color-members.html +1 -1
- data/reference/classGosu_1_1Color.html +1 -1
- data/reference/classGosu_1_1File-members.html +1 -1
- data/reference/classGosu_1_1File.html +1 -1
- data/reference/classGosu_1_1Font-members.html +1 -1
- data/reference/classGosu_1_1Font.html +1 -1
- data/reference/classGosu_1_1Graphics-members.html +1 -1
- data/reference/classGosu_1_1Graphics.html +1 -1
- data/reference/classGosu_1_1Image-members.html +1 -1
- data/reference/classGosu_1_1Image.html +1 -1
- data/reference/classGosu_1_1ImageData-members.html +1 -1
- data/reference/classGosu_1_1ImageData.html +1 -1
- data/reference/classGosu_1_1Input-members.html +1 -1
- data/reference/classGosu_1_1Input.html +1 -1
- data/reference/classGosu_1_1MessageSocket-members.html +1 -1
- data/reference/classGosu_1_1MessageSocket.html +1 -1
- data/reference/classGosu_1_1Resource-members.html +1 -1
- data/reference/classGosu_1_1Resource.html +1 -1
- data/reference/classGosu_1_1Sample-members.html +1 -1
- data/reference/classGosu_1_1Sample.html +1 -1
- data/reference/classGosu_1_1SampleInstance-members.html +1 -1
- data/reference/classGosu_1_1SampleInstance.html +1 -1
- data/reference/classGosu_1_1Song-members.html +1 -1
- data/reference/classGosu_1_1Song.html +1 -1
- data/reference/classGosu_1_1TextInput-members.html +1 -1
- data/reference/classGosu_1_1TextInput.html +1 -1
- data/reference/classGosu_1_1Window-members.html +3 -3
- data/reference/classGosu_1_1Window.html +27 -9
- data/reference/files.html +1 -1
- data/reference/functions.html +10 -5
- data/reference/functions_enum.html +1 -1
- data/reference/functions_func.html +10 -5
- data/reference/functions_vars.html +1 -1
- data/reference/hierarchy.html +1 -1
- data/reference/index.html +1 -1
- data/reference/namespaceGosu.html +13 -2
- data/reference/namespaceGosu_1_1Colors.html +1 -1
- data/reference/namespaceGosu_1_1Win.html +1 -1
- data/reference/namespacemembers.html +1 -1
- data/reference/namespacemembers_enum.html +1 -1
- data/reference/namespacemembers_eval.html +1 -1
- data/reference/namespacemembers_func.html +1 -1
- data/reference/namespacemembers_type.html +1 -1
- data/reference/namespacemembers_vars.html +1 -1
- data/reference/namespaces.html +1 -1
- data/windows/Gosu.sln +2 -2
- data/windows/Gosu.vcproj +7 -8
- data/windows/RubyGosu.vcproj +5 -5
- metadata +14 -2
data/Gosu/Audio.hpp
CHANGED
data/Gosu/Bitmap.hpp
CHANGED
|
@@ -54,10 +54,10 @@ namespace Gosu
|
|
|
54
54
|
void insert(const Bitmap& source, int x, int y, unsigned srcX,
|
|
55
55
|
unsigned srcY, unsigned srcWidth, unsigned srcHeight);
|
|
56
56
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
const unsigned*
|
|
60
|
-
|
|
57
|
+
//! Direct access to the array of color values. May be useful for optimized
|
|
58
|
+
//! OpenGL operations.
|
|
59
|
+
const unsigned* data() const { return reinterpret_cast<const unsigned*>(&pixels[0]); }
|
|
60
|
+
unsigned* data() { return reinterpret_cast<unsigned*>(&pixels[0]); }
|
|
61
61
|
};
|
|
62
62
|
|
|
63
63
|
//! Loads a Windows or OS/2 BMP file into the given bitmap.
|
data/Gosu/Graphics.hpp
CHANGED
data/Gosu/Input.hpp
CHANGED
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
#include <Gosu/Fwd.hpp>
|
|
28
28
|
#include <boost/function.hpp>
|
|
29
29
|
#include <boost/scoped_ptr.hpp>
|
|
30
|
+
#include <vector>
|
|
30
31
|
|
|
31
32
|
namespace Gosu
|
|
32
33
|
{
|
|
@@ -48,6 +49,11 @@ namespace Gosu
|
|
|
48
49
|
Button(ButtonName name) : id(name) {}
|
|
49
50
|
};
|
|
50
51
|
|
|
52
|
+
// Available even on non-iPhone platforms to make it easier to compile the
|
|
53
|
+
// same source for multiple platforms. To be moved to Input.hpp, though.
|
|
54
|
+
struct Touch { void* id; double x, y; };
|
|
55
|
+
typedef std::vector<Touch> Touches;
|
|
56
|
+
|
|
51
57
|
//! Tests whether two Buttons identify the same physical button.
|
|
52
58
|
inline bool operator==(Button lhs, Button rhs)
|
|
53
59
|
{
|
|
@@ -71,9 +77,13 @@ namespace Gosu
|
|
|
71
77
|
#endif
|
|
72
78
|
|
|
73
79
|
#ifdef GOSU_IS_MAC
|
|
80
|
+
#ifdef GOSU_IS_IPHONE
|
|
81
|
+
Input();
|
|
82
|
+
#else
|
|
74
83
|
Input(void* nswindow);
|
|
75
84
|
bool feedNSEvent(void* event);
|
|
76
85
|
#endif
|
|
86
|
+
#endif
|
|
77
87
|
|
|
78
88
|
#ifdef GOSU_IS_X
|
|
79
89
|
Input(::Display* display, ::Window window);
|
data/Gosu/Text.hpp
CHANGED
data/Gosu/Window.hpp
CHANGED
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
#include <boost/shared_ptr.hpp>
|
|
12
12
|
#include <boost/function.hpp>
|
|
13
13
|
#include <string>
|
|
14
|
-
#include <vector>
|
|
15
14
|
|
|
16
15
|
#ifdef GOSU_IS_WIN
|
|
17
16
|
#include <windows.h>
|
|
@@ -19,11 +18,6 @@
|
|
|
19
18
|
|
|
20
19
|
namespace Gosu
|
|
21
20
|
{
|
|
22
|
-
#ifdef GOSU_IS_IPHONE
|
|
23
|
-
struct Touch { double x, y; };
|
|
24
|
-
typedef std::vector<Touch> Touches;
|
|
25
|
-
#endif
|
|
26
|
-
|
|
27
21
|
//! Convenient all-in-one class that serves as the foundation of a standard
|
|
28
22
|
//! Gosu application. Manages initialization of all of Gosu's core components
|
|
29
23
|
//! and provides timing functionality.
|
|
@@ -42,6 +36,8 @@ namespace Gosu
|
|
|
42
36
|
|
|
43
37
|
std::wstring caption() const;
|
|
44
38
|
void setCaption(const std::wstring& caption);
|
|
39
|
+
|
|
40
|
+
double updateInterval() const;
|
|
45
41
|
|
|
46
42
|
//! Starts the main event loop.
|
|
47
43
|
void show();
|
|
@@ -54,7 +50,12 @@ namespace Gosu
|
|
|
54
50
|
//! Called after every update and when the OS wants the window to
|
|
55
51
|
//! repaint itself. Your application's rendering code goes here.
|
|
56
52
|
virtual void draw() {}
|
|
57
|
-
|
|
53
|
+
|
|
54
|
+
//! Gives the game a chance to say no to being redrawn.
|
|
55
|
+
//! This is not a definitive answer. The operating system can still cause
|
|
56
|
+
//! redraws for one reason or another.
|
|
57
|
+
virtual bool needsRedraw() const { return true; }
|
|
58
|
+
|
|
58
59
|
//! Called before update when the user pressed a button while the
|
|
59
60
|
//! window had the focus.
|
|
60
61
|
virtual void buttonDown(Gosu::Button) {}
|
|
@@ -73,19 +74,29 @@ namespace Gosu
|
|
|
73
74
|
Input& input();
|
|
74
75
|
|
|
75
76
|
#ifdef GOSU_IS_WIN
|
|
76
|
-
// Only on Windows.
|
|
77
|
+
// Only on Windows, used for integrating with GUI toolkits.
|
|
77
78
|
HWND handle() const;
|
|
78
79
|
virtual LRESULT handleMessage(UINT message, WPARAM wparam,
|
|
79
80
|
LPARAM lparam);
|
|
80
|
-
#
|
|
81
|
+
#endif
|
|
82
|
+
|
|
83
|
+
#ifdef GOSU_IS_UNIX
|
|
84
|
+
// Context for creating shared contexts.
|
|
81
85
|
// Only on Unices (so far).
|
|
82
86
|
typedef boost::shared_ptr<boost::function<void()> > SharedContext;
|
|
83
87
|
SharedContext createSharedContext();
|
|
84
88
|
#endif
|
|
89
|
+
|
|
85
90
|
#ifdef GOSU_IS_IPHONE
|
|
91
|
+
// iPhone-only callbacks for touch events.
|
|
92
|
+
// Note that it does not hurt to override them even if you compile
|
|
93
|
+
// for another platform; if you don't specify "virtual" the code
|
|
94
|
+
// should even be stripped away cleanly.
|
|
86
95
|
virtual void touchesBegan(const Touches& touches) {}
|
|
87
96
|
virtual void touchesMoved(const Touches& touches) {}
|
|
88
97
|
virtual void touchesEnded(const Touches& touches) {}
|
|
98
|
+
// Currently known touches.
|
|
99
|
+
const Touches& currentTouches() const;
|
|
89
100
|
#endif
|
|
90
101
|
|
|
91
102
|
#endif
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
#import <OpenAL/al.h>
|
|
2
|
+
#import <OpenAL/alc.h>
|
|
3
|
+
#include <GosuImpl/MacUtility.hpp>
|
|
4
|
+
#include <boost/scoped_ptr.hpp>
|
|
5
|
+
#include <algorithm>
|
|
6
|
+
|
|
7
|
+
namespace Gosu
|
|
8
|
+
{
|
|
9
|
+
class ALChannelManagement : boost::noncopyable
|
|
10
|
+
{
|
|
11
|
+
static ALCdevice* alDevice;
|
|
12
|
+
static ALCcontext* alContext;
|
|
13
|
+
|
|
14
|
+
enum { NUM_SOURCES = 32 }; // This is what the iPhone supports, I hear.
|
|
15
|
+
NSUInteger alSources[NUM_SOURCES];
|
|
16
|
+
NSUInteger currentToken;
|
|
17
|
+
NSUInteger currentTokens[NUM_SOURCES];
|
|
18
|
+
|
|
19
|
+
public:
|
|
20
|
+
enum { NO_TOKEN = -1, NO_SOURCE = -1, NO_FREE_CHANNEL = -1 };
|
|
21
|
+
|
|
22
|
+
ALChannelManagement()
|
|
23
|
+
{
|
|
24
|
+
// Open preferred device
|
|
25
|
+
alDevice = alcOpenDevice(0);
|
|
26
|
+
alContext = alcCreateContext(alDevice, 0);
|
|
27
|
+
alcMakeContextCurrent(alContext);
|
|
28
|
+
alGenSources(NUM_SOURCES, alSources);
|
|
29
|
+
currentToken = 0;
|
|
30
|
+
std::fill(currentTokens, currentTokens + NUM_SOURCES,
|
|
31
|
+
static_cast<NSUInteger>(NO_TOKEN));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
~ALChannelManagement()
|
|
35
|
+
{
|
|
36
|
+
alDeleteSources(NUM_SOURCES, alSources);
|
|
37
|
+
alcMakeContextCurrent(0);
|
|
38
|
+
alcDestroyContext(alContext);
|
|
39
|
+
alcCloseDevice(alDevice);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
std::pair<int, int> reserveChannel()
|
|
43
|
+
{
|
|
44
|
+
int i;
|
|
45
|
+
for (i = 0; i <= NUM_SOURCES; ++i)
|
|
46
|
+
{
|
|
47
|
+
if (i == NUM_SOURCES)
|
|
48
|
+
return std::make_pair<int, int>(NO_FREE_CHANNEL, NO_TOKEN);
|
|
49
|
+
if (currentTokens[i] == NO_TOKEN)
|
|
50
|
+
break;
|
|
51
|
+
ALint state;
|
|
52
|
+
alGetSourcei(alSources[i], AL_SOURCE_STATE, &state);
|
|
53
|
+
if (state != AL_PLAYING && state != AL_PAUSED)
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
++currentToken;
|
|
57
|
+
currentTokens[i] = currentToken;
|
|
58
|
+
return std::make_pair<int, int>(i, currentToken);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
int sourceIfStillPlaying(int channel, int token) const
|
|
62
|
+
{
|
|
63
|
+
if (currentTokens[channel] == token)
|
|
64
|
+
return alSources[channel];
|
|
65
|
+
return NO_SOURCE;
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
ALCdevice* ALChannelManagement::alDevice = 0;
|
|
69
|
+
ALCcontext* ALChannelManagement::alContext = 0;
|
|
70
|
+
|
|
71
|
+
boost::scoped_ptr<ALChannelManagement> alChannelManagement;
|
|
72
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
#ifndef GOSU_AUDIO_AUDIOFILE_MAC_HPP
|
|
2
|
+
#define GOSU_AUDIO_AUDIOFILE_MAC_HPP
|
|
3
|
+
|
|
4
|
+
#include <AudioToolbox/AudioToolbox.h>
|
|
5
|
+
#include <OpenAL/al.h>
|
|
6
|
+
#include <Gosu/IO.hpp>
|
|
7
|
+
#include <GosuImpl/MacUtility.hpp>
|
|
8
|
+
#include <Gosu/Utility.hpp>
|
|
9
|
+
#include <boost/utility.hpp>
|
|
10
|
+
#include <algorithm>
|
|
11
|
+
#include <vector>
|
|
12
|
+
#import <Foundation/Foundation.h>
|
|
13
|
+
|
|
14
|
+
namespace Gosu
|
|
15
|
+
{
|
|
16
|
+
class AudioFile : boost::noncopyable
|
|
17
|
+
{
|
|
18
|
+
AudioFileID fileID;
|
|
19
|
+
mutable std::vector<char> decodedData;
|
|
20
|
+
|
|
21
|
+
static OSStatus AudioFile_ReadProc(void* inClientData, SInt64 inPosition, UInt32 requestCount,
|
|
22
|
+
void* buffer, UInt32* actualCount)
|
|
23
|
+
{
|
|
24
|
+
const Resource& res = *static_cast<Resource*>(inClientData);
|
|
25
|
+
*actualCount = std::min<UInt32>(requestCount, res.size() - inPosition);
|
|
26
|
+
res.read(inPosition, *actualCount, buffer);
|
|
27
|
+
return noErr;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
static SInt64 AudioFile_GetSizeProc(void* inClientData)
|
|
31
|
+
{
|
|
32
|
+
const Resource& res = *static_cast<Resource*>(inClientData);
|
|
33
|
+
return res.size();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
public:
|
|
37
|
+
AudioFile(const std::wstring& filename)
|
|
38
|
+
{
|
|
39
|
+
ObjRef<NSString> utf8Filename([[NSString alloc] initWithUTF8String: wstringToUTF8(filename).c_str()]);
|
|
40
|
+
ObjRef<NSURL> url([[NSURL alloc] initFileURLWithPath: utf8Filename.get()]);
|
|
41
|
+
#ifdef GOSU_IS_IPHONE
|
|
42
|
+
CHECK_OS(AudioFileOpenURL((CFURLRef)url.get(), kAudioFileReadPermission, 0, &fileID));
|
|
43
|
+
#else
|
|
44
|
+
// Use FSRef for compatibility with 10.4 Tiger.
|
|
45
|
+
FSRef fsRef;
|
|
46
|
+
CFURLGetFSRef(reinterpret_cast<CFURLRef>(url.get()), &fsRef);
|
|
47
|
+
CHECK_OS(AudioFileOpen(&fsRef, fsRdPerm, 0, &fileID));
|
|
48
|
+
#endif
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
AudioFile(const Gosu::Resource& resource)
|
|
52
|
+
{
|
|
53
|
+
void* clientData = const_cast<Resource*>(&resource);
|
|
54
|
+
CHECK_OS(AudioFileOpenWithCallbacks(clientData, AudioFile_ReadProc, 0,
|
|
55
|
+
AudioFile_GetSizeProc, 0, 0, &fileID));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
~AudioFile()
|
|
59
|
+
{
|
|
60
|
+
AudioFileClose(fileID);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
UInt32 getSizeOfData() const
|
|
64
|
+
{
|
|
65
|
+
UInt64 sizeOfData = 0;
|
|
66
|
+
UInt32 sizeOfProperty = sizeof sizeOfData;
|
|
67
|
+
CHECK_OS(AudioFileGetProperty(fileID, kAudioFilePropertyAudioDataByteCount, &sizeOfProperty, &sizeOfData));
|
|
68
|
+
return sizeOfData;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
std::pair<ALuint, ALuint> getFormatAndSampleRate() const
|
|
72
|
+
{
|
|
73
|
+
AudioStreamBasicDescription desc;
|
|
74
|
+
UInt32 sizeOfProperty = sizeof desc;
|
|
75
|
+
CHECK_OS(AudioFileGetProperty(fileID, kAudioFilePropertyDataFormat, &sizeOfProperty, &desc));
|
|
76
|
+
std::pair<ALuint, ALuint> formatAndSampleRate = std::make_pair(0, desc.mSampleRate);
|
|
77
|
+
if (desc.mChannelsPerFrame == 1)
|
|
78
|
+
if (desc.mBitsPerChannel == 8)
|
|
79
|
+
formatAndSampleRate.first = AL_FORMAT_MONO8;
|
|
80
|
+
else if (desc.mBitsPerChannel == 16)
|
|
81
|
+
formatAndSampleRate.first = AL_FORMAT_MONO16;
|
|
82
|
+
else if (desc.mChannelsPerFrame == 2)
|
|
83
|
+
if (desc.mBitsPerChannel == 8)
|
|
84
|
+
formatAndSampleRate.first = AL_FORMAT_STEREO8;
|
|
85
|
+
else if (desc.mBitsPerChannel == 16)
|
|
86
|
+
formatAndSampleRate.first = AL_FORMAT_STEREO16;
|
|
87
|
+
if (formatAndSampleRate.first == 0)
|
|
88
|
+
throw std::runtime_error("Invalid sample format");
|
|
89
|
+
return formatAndSampleRate;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const std::vector<char>& getDecodedData() const
|
|
93
|
+
{
|
|
94
|
+
if (decodedData.empty())
|
|
95
|
+
{
|
|
96
|
+
UInt32 sizeOfData = getSizeOfData();
|
|
97
|
+
decodedData.resize(sizeOfData);
|
|
98
|
+
CHECK_OS(AudioFileReadBytes(fileID, false, 0, &sizeOfData, &decodedData[0]));
|
|
99
|
+
}
|
|
100
|
+
return decodedData;
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
#endif
|
|
@@ -0,0 +1,486 @@
|
|
|
1
|
+
#include <GosuImpl/MacUtility.hpp>
|
|
2
|
+
#include <GosuImpl/Audio/AudioFileMac.hpp>
|
|
3
|
+
#include <GosuImpl/Audio/ALChannelManagement.hpp>
|
|
4
|
+
|
|
5
|
+
#include <Gosu/Audio.hpp>
|
|
6
|
+
#include <Gosu/Math.hpp>
|
|
7
|
+
#include <Gosu/IO.hpp>
|
|
8
|
+
#include <Gosu/Utility.hpp>
|
|
9
|
+
#include <Gosu/Platform.hpp>
|
|
10
|
+
|
|
11
|
+
#include <boost/algorithm/string.hpp>
|
|
12
|
+
#include <boost/lexical_cast.hpp>
|
|
13
|
+
|
|
14
|
+
#include <cassert>
|
|
15
|
+
#include <cstdlib>
|
|
16
|
+
#include <algorithm>
|
|
17
|
+
#include <stdexcept>
|
|
18
|
+
#include <vector>
|
|
19
|
+
|
|
20
|
+
#include <OpenAL/al.h>
|
|
21
|
+
#include <OpenAL/alc.h>
|
|
22
|
+
|
|
23
|
+
#if __LP64__ || NS_BUILD_32_LIKE_64
|
|
24
|
+
typedef long NSInteger;
|
|
25
|
+
typedef unsigned long NSUInteger;
|
|
26
|
+
#else
|
|
27
|
+
typedef int NSInteger;
|
|
28
|
+
typedef unsigned int NSUInteger;
|
|
29
|
+
#endif
|
|
30
|
+
|
|
31
|
+
using namespace std;
|
|
32
|
+
|
|
33
|
+
namespace
|
|
34
|
+
{
|
|
35
|
+
using namespace Gosu;
|
|
36
|
+
|
|
37
|
+
/*GOSU_NORETURN void throwLastALError(const char* action)
|
|
38
|
+
{
|
|
39
|
+
string message = "OpenAL error " +
|
|
40
|
+
boost::lexical_cast<string>(alcGetError(alDevice));
|
|
41
|
+
if (action)
|
|
42
|
+
message += " while ", message += action;
|
|
43
|
+
throw runtime_error(message);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
inline void alCheck(const char* action = 0)
|
|
47
|
+
{
|
|
48
|
+
if (alcGetError(alDevice) != ALC_NO_ERROR)
|
|
49
|
+
throwLastALError(action);
|
|
50
|
+
}*/
|
|
51
|
+
|
|
52
|
+
Song* curSong = 0;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
Gosu::Audio::Audio()
|
|
56
|
+
{
|
|
57
|
+
if (alChannelManagement)
|
|
58
|
+
throw std::logic_error("Multiple Gosu::Audio instances not supported");
|
|
59
|
+
alChannelManagement.reset(new ALChannelManagement);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
Gosu::Audio::~Audio()
|
|
63
|
+
{
|
|
64
|
+
alChannelManagement.reset();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
Gosu::SampleInstance::SampleInstance(int handle, int extra)
|
|
68
|
+
: handle(handle), extra(extra)
|
|
69
|
+
{
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
bool Gosu::SampleInstance::playing() const
|
|
73
|
+
{
|
|
74
|
+
NSUInteger source = alChannelManagement->sourceIfStillPlaying(handle, extra);
|
|
75
|
+
if (source == ALChannelManagement::NO_SOURCE)
|
|
76
|
+
return false;
|
|
77
|
+
ALint state;
|
|
78
|
+
alGetSourcei(source, AL_SOURCE_STATE, &state);
|
|
79
|
+
return state == AL_PLAYING;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
bool Gosu::SampleInstance::paused() const
|
|
83
|
+
{
|
|
84
|
+
NSUInteger source = alChannelManagement->sourceIfStillPlaying(handle, extra);
|
|
85
|
+
if (source == ALChannelManagement::NO_SOURCE)
|
|
86
|
+
return false;
|
|
87
|
+
ALint state;
|
|
88
|
+
alGetSourcei(source, AL_SOURCE_STATE, &state);
|
|
89
|
+
return state == AL_PAUSED;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
void Gosu::SampleInstance::pause()
|
|
93
|
+
{
|
|
94
|
+
NSUInteger source = alChannelManagement->sourceIfStillPlaying(handle, extra);
|
|
95
|
+
if (source == ALChannelManagement::NO_SOURCE)
|
|
96
|
+
return;
|
|
97
|
+
alSourcePause(source);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
void Gosu::SampleInstance::resume()
|
|
101
|
+
{
|
|
102
|
+
NSUInteger source = alChannelManagement->sourceIfStillPlaying(handle, extra);
|
|
103
|
+
if (source == ALChannelManagement::NO_SOURCE)
|
|
104
|
+
return;
|
|
105
|
+
ALint state;
|
|
106
|
+
alGetSourcei(source, AL_SOURCE_STATE, &state);
|
|
107
|
+
if (state == AL_PAUSED)
|
|
108
|
+
alSourcePlay(source);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
void Gosu::SampleInstance::stop()
|
|
112
|
+
{
|
|
113
|
+
NSUInteger source = alChannelManagement->sourceIfStillPlaying(handle, extra);
|
|
114
|
+
if (source == ALChannelManagement::NO_SOURCE)
|
|
115
|
+
return;
|
|
116
|
+
alSourceStop(source);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
void Gosu::SampleInstance::changeVolume(double volume)
|
|
120
|
+
{
|
|
121
|
+
NSUInteger source = alChannelManagement->sourceIfStillPlaying(handle, extra);
|
|
122
|
+
if (source == ALChannelManagement::NO_SOURCE)
|
|
123
|
+
return;
|
|
124
|
+
alSourcef(source, AL_GAIN, volume);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
void Gosu::SampleInstance::changePan(double pan)
|
|
128
|
+
{
|
|
129
|
+
NSUInteger source = alChannelManagement->sourceIfStillPlaying(handle, extra);
|
|
130
|
+
if (source == ALChannelManagement::NO_SOURCE)
|
|
131
|
+
return;
|
|
132
|
+
// TODO: This is not the old panning behavior!
|
|
133
|
+
alSource3f(source, AL_POSITION, pan * 10, 0, 0);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
void Gosu::SampleInstance::changeSpeed(double speed)
|
|
137
|
+
{
|
|
138
|
+
NSUInteger source = alChannelManagement->sourceIfStillPlaying(handle, extra);
|
|
139
|
+
if (source == ALChannelManagement::NO_SOURCE)
|
|
140
|
+
return;
|
|
141
|
+
alSourcef(source, AL_PITCH, speed);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
struct Gosu::Sample::SampleData : boost::noncopyable
|
|
145
|
+
{
|
|
146
|
+
NSUInteger buffer, source;
|
|
147
|
+
|
|
148
|
+
SampleData(const AudioFile& audioFile)
|
|
149
|
+
{
|
|
150
|
+
alGenBuffers(1, &buffer);
|
|
151
|
+
alBufferData(buffer,
|
|
152
|
+
audioFile.getFormatAndSampleRate().first,
|
|
153
|
+
&audioFile.getDecodedData().front(),
|
|
154
|
+
audioFile.getDecodedData().size(),
|
|
155
|
+
audioFile.getFormatAndSampleRate().second);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
~SampleData()
|
|
159
|
+
{
|
|
160
|
+
// It's hard to free things in the right order in Ruby/Gosu.
|
|
161
|
+
// Make sure buffer isn't deleted after the context/device are shut down.
|
|
162
|
+
|
|
163
|
+
if (!alChannelManagement)
|
|
164
|
+
return;
|
|
165
|
+
|
|
166
|
+
alDeleteBuffers(1, &buffer);
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
Gosu::Sample::Sample(Audio& audio, const std::wstring& filename)
|
|
171
|
+
{
|
|
172
|
+
AudioFile audioFile(filename);
|
|
173
|
+
data.reset(new SampleData(audioFile));
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
Gosu::Sample::Sample(Audio& audio, Reader reader)
|
|
177
|
+
{
|
|
178
|
+
AudioFile audioFile(reader.resource());
|
|
179
|
+
data.reset(new SampleData(audioFile));
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
Gosu::Sample::~Sample()
|
|
183
|
+
{
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
Gosu::SampleInstance Gosu::Sample::play(double volume, double speed,
|
|
187
|
+
bool looping) const
|
|
188
|
+
{
|
|
189
|
+
return playPan(0, volume, speed, looping);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
Gosu::SampleInstance Gosu::Sample::playPan(double pan, double volume,
|
|
193
|
+
double speed, bool looping) const
|
|
194
|
+
{
|
|
195
|
+
std::pair<int, int> channelAndToken = alChannelManagement->reserveChannel();
|
|
196
|
+
if (channelAndToken.first == ALChannelManagement::NO_FREE_CHANNEL)
|
|
197
|
+
return Gosu::SampleInstance(channelAndToken.first, channelAndToken.second);
|
|
198
|
+
|
|
199
|
+
NSUInteger source = alChannelManagement->sourceIfStillPlaying(channelAndToken.first,
|
|
200
|
+
channelAndToken.second);
|
|
201
|
+
assert(source != ALChannelManagement::NO_SOURCE);
|
|
202
|
+
alSourcei(source, AL_BUFFER, data->buffer);
|
|
203
|
+
// TODO: This is not the old panning behavior!
|
|
204
|
+
alSource3f(source, AL_POSITION, pan * 10, 0, 0);
|
|
205
|
+
alSourcef(source, AL_GAIN, volume);
|
|
206
|
+
alSourcef(source, AL_PITCH, speed);
|
|
207
|
+
alSourcei(source, AL_LOOPING, looping ? AL_TRUE : AL_FALSE);
|
|
208
|
+
alSourcePlay(source);
|
|
209
|
+
|
|
210
|
+
return Gosu::SampleInstance(channelAndToken.first, channelAndToken.second);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
class Gosu::Song::BaseData : boost::noncopyable
|
|
214
|
+
{
|
|
215
|
+
// double volume_;
|
|
216
|
+
//
|
|
217
|
+
//protected:
|
|
218
|
+
// BaseData() : volume_(1) {}
|
|
219
|
+
// virtual void applyVolume() = 0;
|
|
220
|
+
//
|
|
221
|
+
//public:
|
|
222
|
+
// virtual ~BaseData() {}
|
|
223
|
+
//
|
|
224
|
+
// virtual void play(bool looping) = 0;
|
|
225
|
+
// virtual void pause() = 0;
|
|
226
|
+
// virtual bool paused() const = 0;
|
|
227
|
+
// virtual void stop() = 0;
|
|
228
|
+
//
|
|
229
|
+
// double volume() const
|
|
230
|
+
// {
|
|
231
|
+
// return volume_;
|
|
232
|
+
// }
|
|
233
|
+
//
|
|
234
|
+
// void changeVolume(double volume)
|
|
235
|
+
// {
|
|
236
|
+
// volume_ = clamp(volume, 0.0, 1.0);
|
|
237
|
+
// applyVolume();
|
|
238
|
+
// }
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
//class Gosu::Song::StreamData : public BaseData
|
|
242
|
+
//{
|
|
243
|
+
// FSOUND_STREAM* stream;
|
|
244
|
+
// int handle;
|
|
245
|
+
// std::vector<char> buffer;
|
|
246
|
+
//
|
|
247
|
+
// static signed char F_CALLBACKAPI endSongCallback(FSOUND_STREAM*, void*,
|
|
248
|
+
// int, void* self)
|
|
249
|
+
// {
|
|
250
|
+
// curSong = 0;
|
|
251
|
+
// static_cast<StreamData*>(self)->handle = -1;
|
|
252
|
+
// return 0;
|
|
253
|
+
// }
|
|
254
|
+
//
|
|
255
|
+
//public:
|
|
256
|
+
// StreamData(Gosu::Reader reader)
|
|
257
|
+
// : stream(0), handle(-1)
|
|
258
|
+
// {
|
|
259
|
+
// buffer.resize(reader.resource().size() - reader.position());
|
|
260
|
+
// reader.read(&buffer[0], buffer.size());
|
|
261
|
+
//
|
|
262
|
+
//// Disabled for licensing reasons.
|
|
263
|
+
//// If you have a license to play MP3 files, compile with GOSU_ALLOW_MP3.
|
|
264
|
+
//#ifndef GOSU_ALLOW_MP3
|
|
265
|
+
// if (buffer.size() > 2 &&
|
|
266
|
+
// ((buffer[0] == '\xff' && (buffer[1] & 0xfe) == '\xfa') ||
|
|
267
|
+
// (buffer[0] == 'I' && buffer[1] == 'D' && buffer[2] == '3')))
|
|
268
|
+
// {
|
|
269
|
+
// throw std::runtime_error("MP3 file playback not allowed");
|
|
270
|
+
// }
|
|
271
|
+
//#endif
|
|
272
|
+
//
|
|
273
|
+
// stream = FSOUND_Stream_Open(&buffer[0], FSOUND_LOADMEMORY | FSOUND_LOOP_NORMAL,
|
|
274
|
+
// 0, buffer.size());
|
|
275
|
+
// if (stream == 0)
|
|
276
|
+
// throwLastFMODError();
|
|
277
|
+
//
|
|
278
|
+
// FSOUND_Stream_SetEndCallback(stream, endSongCallback, this);
|
|
279
|
+
// }
|
|
280
|
+
//
|
|
281
|
+
// ~StreamData()
|
|
282
|
+
// {
|
|
283
|
+
// // TODO: Should be checked for earlier, as play would crash too.
|
|
284
|
+
// // This is just because Ruby's GC will free objects in a weird
|
|
285
|
+
// // order.
|
|
286
|
+
// if (!fmodInitialized)
|
|
287
|
+
// return;
|
|
288
|
+
//
|
|
289
|
+
// if (stream != 0)
|
|
290
|
+
// FSOUND_Stream_Close(stream);
|
|
291
|
+
// }
|
|
292
|
+
//
|
|
293
|
+
// void play(bool looping)
|
|
294
|
+
// {
|
|
295
|
+
// if (handle == -1)
|
|
296
|
+
// {
|
|
297
|
+
// handle = FSOUND_Stream_Play(FSOUND_FREE, stream);
|
|
298
|
+
// FSOUND_Stream_SetLoopCount(stream, looping ? -1 : 0);
|
|
299
|
+
// }
|
|
300
|
+
// else if (paused())
|
|
301
|
+
// FSOUND_SetPaused(handle, 0);
|
|
302
|
+
// applyVolume();
|
|
303
|
+
// }
|
|
304
|
+
//
|
|
305
|
+
// void pause()
|
|
306
|
+
// {
|
|
307
|
+
// if (handle != -1)
|
|
308
|
+
// FSOUND_SetPaused(handle, 1);
|
|
309
|
+
// }
|
|
310
|
+
//
|
|
311
|
+
// bool paused() const
|
|
312
|
+
// {
|
|
313
|
+
// return handle != -1 && FSOUND_GetPaused(handle);
|
|
314
|
+
// }
|
|
315
|
+
//
|
|
316
|
+
// void stop()
|
|
317
|
+
// {
|
|
318
|
+
// fmodCheck(FSOUND_Stream_Stop(stream));
|
|
319
|
+
// handle = -1; // The end callback is NOT being called!
|
|
320
|
+
// }
|
|
321
|
+
//
|
|
322
|
+
// void applyVolume()
|
|
323
|
+
// {
|
|
324
|
+
// if (handle != -1)
|
|
325
|
+
// FSOUND_SetVolume(handle, static_cast<int>(volume() * 255));
|
|
326
|
+
// }
|
|
327
|
+
//};
|
|
328
|
+
//
|
|
329
|
+
//class Gosu::Song::ModuleData : public Gosu::Song::BaseData
|
|
330
|
+
//{
|
|
331
|
+
// FMUSIC_MODULE* module_;
|
|
332
|
+
//
|
|
333
|
+
//public:
|
|
334
|
+
// ModuleData(Reader reader)
|
|
335
|
+
// : module_(0)
|
|
336
|
+
// {
|
|
337
|
+
// std::vector<char> buffer(reader.resource().size() - reader.position());
|
|
338
|
+
// reader.read(&buffer[0], buffer.size());
|
|
339
|
+
//
|
|
340
|
+
// module_ = FMUSIC_LoadSongEx(&buffer[0], 0, buffer.size(),
|
|
341
|
+
// FSOUND_LOADMEMORY | FSOUND_LOOP_OFF, 0, 0);
|
|
342
|
+
// if (module_ == 0)
|
|
343
|
+
// throwLastFMODError();
|
|
344
|
+
// }
|
|
345
|
+
//
|
|
346
|
+
// ~ModuleData()
|
|
347
|
+
// {
|
|
348
|
+
// // TODO: Should be checked for earlier, as play would crash too.
|
|
349
|
+
// // This is just because Ruby's GC will free objects in a weird
|
|
350
|
+
// // order.
|
|
351
|
+
// if (!fmodInitialized)
|
|
352
|
+
// return;
|
|
353
|
+
//
|
|
354
|
+
// if (module_ != 0)
|
|
355
|
+
// FMUSIC_FreeSong(module_);
|
|
356
|
+
// }
|
|
357
|
+
//
|
|
358
|
+
// void play(bool looping)
|
|
359
|
+
// {
|
|
360
|
+
// if (paused())
|
|
361
|
+
// FMUSIC_SetPaused(module_, 0);
|
|
362
|
+
// else
|
|
363
|
+
// FMUSIC_PlaySong(module_);
|
|
364
|
+
// FMUSIC_SetLooping(module_, looping);
|
|
365
|
+
// applyVolume();
|
|
366
|
+
// }
|
|
367
|
+
//
|
|
368
|
+
// void pause()
|
|
369
|
+
// {
|
|
370
|
+
// FMUSIC_SetPaused(module_, 1);
|
|
371
|
+
// }
|
|
372
|
+
//
|
|
373
|
+
// bool paused() const
|
|
374
|
+
// {
|
|
375
|
+
// return FMUSIC_GetPaused(module_);
|
|
376
|
+
// }
|
|
377
|
+
//
|
|
378
|
+
// void stop()
|
|
379
|
+
// {
|
|
380
|
+
// fmodCheck(FMUSIC_StopSong(module_));
|
|
381
|
+
// FMUSIC_SetPaused(module_, false);
|
|
382
|
+
// }
|
|
383
|
+
//
|
|
384
|
+
// void applyVolume()
|
|
385
|
+
// {
|
|
386
|
+
// // Weird as it may seem, the FMOD doc really says volume can
|
|
387
|
+
// // be 0 to 256, *inclusive*, for this function.
|
|
388
|
+
// FMUSIC_SetMasterVolume(module_, static_cast<int>(volume() * 256.0));
|
|
389
|
+
// }
|
|
390
|
+
//};
|
|
391
|
+
//
|
|
392
|
+
Gosu::Song::Song(Audio& audio, const std::wstring& filename)
|
|
393
|
+
{
|
|
394
|
+
// Buffer buf;
|
|
395
|
+
// loadFile(buf, filename);
|
|
396
|
+
// Type type = stStream;
|
|
397
|
+
//
|
|
398
|
+
// using boost::iends_with;
|
|
399
|
+
// if (iends_with(filename, ".mod") || iends_with(filename, ".mid") ||
|
|
400
|
+
// iends_with(filename, ".s3m") || iends_with(filename, ".it") ||
|
|
401
|
+
// iends_with(filename, ".xm"))
|
|
402
|
+
// {
|
|
403
|
+
// type = stModule;
|
|
404
|
+
// }
|
|
405
|
+
//
|
|
406
|
+
// // Forward.
|
|
407
|
+
// Song(audio, type, buf.frontReader()).data.swap(data);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
Gosu::Song::Song(Audio& audio, Type type, Reader reader)
|
|
411
|
+
{
|
|
412
|
+
// switch (type)
|
|
413
|
+
// {
|
|
414
|
+
// case stStream:
|
|
415
|
+
// data.reset(new StreamData(reader));
|
|
416
|
+
// break;
|
|
417
|
+
//
|
|
418
|
+
// case stModule:
|
|
419
|
+
// data.reset(new ModuleData(reader));
|
|
420
|
+
// break;
|
|
421
|
+
//
|
|
422
|
+
// default:
|
|
423
|
+
// throw std::logic_error("Invalid song type");
|
|
424
|
+
// }
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
Gosu::Song::~Song()
|
|
428
|
+
{
|
|
429
|
+
if (alChannelManagement)
|
|
430
|
+
stop();
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
Gosu::Song* Gosu::Song::currentSong()
|
|
434
|
+
{
|
|
435
|
+
return curSong;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
void Gosu::Song::play(bool looping)
|
|
439
|
+
{
|
|
440
|
+
// if (curSong && curSong != this)
|
|
441
|
+
// {
|
|
442
|
+
// curSong->stop();
|
|
443
|
+
// assert(curSong == 0);
|
|
444
|
+
// }
|
|
445
|
+
//
|
|
446
|
+
// data->play(looping);
|
|
447
|
+
// curSong = this; // may be redundant
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
void Gosu::Song::pause()
|
|
451
|
+
{
|
|
452
|
+
// if (curSong == this)
|
|
453
|
+
// data->pause(); // may be redundant
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
bool Gosu::Song::paused() const
|
|
457
|
+
{
|
|
458
|
+
// return curSong == this && data->paused();
|
|
459
|
+
return false;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
void Gosu::Song::stop()
|
|
463
|
+
{
|
|
464
|
+
// if (curSong == this)
|
|
465
|
+
// {
|
|
466
|
+
// data->stop();
|
|
467
|
+
// curSong = 0;
|
|
468
|
+
// }
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
bool Gosu::Song::playing() const
|
|
472
|
+
{
|
|
473
|
+
// return curSong == this && !data->paused();
|
|
474
|
+
return false;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
double Gosu::Song::volume() const
|
|
478
|
+
{
|
|
479
|
+
// return data->volume();
|
|
480
|
+
return 0;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
void Gosu::Song::changeVolume(double volume)
|
|
484
|
+
{
|
|
485
|
+
// data->changeVolume(volume);
|
|
486
|
+
}
|