gosu 0.12.1 → 0.13.0
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.
- checksums.yaml +4 -4
- data/Gosu/Audio.hpp +23 -25
- data/Gosu/Graphics.hpp +16 -12
- data/Gosu/Image.hpp +3 -0
- data/Gosu/Version.hpp +2 -2
- data/lib/gosu.rb +2 -2
- data/lib/gosu/compat.rb +1 -1
- data/lib/gosu/patches.rb +5 -0
- data/lib/gosu/swig_patches.rb +1 -1
- data/rdoc/gosu.rb +10 -10
- data/src/Audio.cpp +93 -228
- data/src/AudioImpl.cpp +94 -0
- data/src/AudioImpl.hpp +33 -0
- data/src/AudioToolboxFile.hpp +14 -18
- data/src/Bitmap.cpp +36 -30
- data/src/BitmapIO.cpp +14 -23
- data/src/BlockAllocator.cpp +7 -10
- data/src/BlockAllocator.hpp +2 -4
- data/src/Channel.cpp +89 -0
- data/src/Color.cpp +4 -9
- data/src/DirectoriesApple.cpp +13 -13
- data/src/DirectoriesUnix.cpp +8 -7
- data/src/DirectoriesWin.cpp +12 -11
- data/src/EmptyImageData.hpp +54 -0
- data/src/FileUnix.cpp +12 -9
- data/src/FileWin.cpp +8 -7
- data/src/Font.cpp +12 -13
- data/src/FormattedString.cpp +237 -0
- data/src/FormattedString.hpp +14 -265
- data/src/GosuViewController.cpp +2 -5
- data/src/Graphics.cpp +38 -39
- data/src/IO.cpp +11 -10
- data/src/Image.cpp +16 -9
- data/src/Input.cpp +16 -15
- data/src/InputUIKit.cpp +8 -7
- data/src/Macro.cpp +11 -11
- data/src/Math.cpp +9 -8
- data/src/RubyGosu.cxx +129 -99
- data/src/TextApple.cpp +19 -13
- data/src/TextInput.cpp +23 -22
- data/src/TextWin.cpp +17 -19
- data/src/Texture.cpp +15 -10
- data/src/Transform.cpp +13 -17
- data/src/Utility.cpp +3 -2
- data/src/UtilityApple.cpp +10 -11
- data/src/UtilityWin.cpp +2 -1
- data/src/Version.cpp +5 -4
- data/src/WinMain.cpp +3 -3
- data/src/WinUtility.cpp +7 -6
- data/src/Window.cpp +11 -10
- data/src/WindowUIKit.cpp +9 -8
- data/src/stb_image.h +782 -480
- data/src/stb_image_write.h +425 -15
- data/src/stb_vorbis.c +82 -32
- metadata +8 -4
- data/src/ALChannelManagement.hpp +0 -119
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 41378387cae1afdcfbfeab14e6adea7ad61aa1e6
|
4
|
+
data.tar.gz: b83153c5f9208a2a201154f012c0135f25238b3e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fccec2f1c9755fe8133d02a4b3f2e31789681938a59a41893a6d247ff29a3fdb68d1c5848390c63dfdb490259b552cd05c2d1833cfdd11533d28d1be07817be2
|
7
|
+
data.tar.gz: 6542882a5ef52f9360444efe0513b3c31b51912c5c21a18be5cc76e6b1bdf223e5981755afe860cdd45383b0db1fd52cd60028f690450ed33ed25d127dfc9049
|
data/Gosu/Audio.hpp
CHANGED
@@ -11,41 +11,36 @@
|
|
11
11
|
|
12
12
|
namespace Gosu
|
13
13
|
{
|
14
|
-
//!
|
15
|
-
//! or to check
|
16
|
-
|
17
|
-
//! as they could accidentally refer to other sounds being played after
|
18
|
-
//! a very long time has passed.
|
19
|
-
class SampleInstance
|
14
|
+
//! Sample::play returns a Channel that represents the sound currently being played.
|
15
|
+
//! This object can be used to stop sounds dynamically, or to check whether they have finished.
|
16
|
+
class Channel
|
20
17
|
{
|
21
|
-
int
|
22
|
-
bool alive() const;
|
18
|
+
mutable int channel, token;
|
23
19
|
|
24
20
|
public:
|
25
|
-
//!
|
26
|
-
|
27
|
-
|
21
|
+
//! For internal use only.
|
22
|
+
Channel(int channel, int token);
|
23
|
+
|
24
|
+
int current_channel() const;
|
25
|
+
|
28
26
|
bool playing() const;
|
29
27
|
bool paused() const;
|
30
|
-
//! Pauses this instance to be resumed afterwards.
|
31
|
-
//! paused.
|
28
|
+
//! Pauses this instance to be resumed afterwards.
|
29
|
+
//! It will still occupy an audio channel while paused.
|
32
30
|
void pause();
|
33
31
|
void resume();
|
34
32
|
//! Stops this instance of a sound being played.
|
35
33
|
//! Calling this twice, or too late, does not do any harm.
|
36
34
|
void stop();
|
37
35
|
|
38
|
-
//! \param volume Can be anything from 0.0 (silence) to 1.0 (full
|
39
|
-
|
40
|
-
void change_volume(double volume);
|
36
|
+
//! \param volume Can be anything from 0.0 (silence) to 1.0 (full volume).
|
37
|
+
void set_volume(double volume);
|
41
38
|
//! \param pan Can be anything from -1.0 (left) to 1.0 (right).
|
42
|
-
void
|
43
|
-
//! \param speed
|
44
|
-
|
45
|
-
//! normal playback speed.
|
46
|
-
void change_speed(double speed);
|
39
|
+
void set_pan(double pan);
|
40
|
+
//! \param speed Use 1.0 for normal playback speed.
|
41
|
+
void set_speed(double speed);
|
47
42
|
};
|
48
|
-
|
43
|
+
|
49
44
|
//! A sample is a short sound that is completely loaded in memory, can be
|
50
45
|
//! played multiple times at once and offers very flexible playback
|
51
46
|
//! parameters. Use samples for everything that's not music.
|
@@ -55,6 +50,9 @@ namespace Gosu
|
|
55
50
|
std::shared_ptr<SampleData> data;
|
56
51
|
|
57
52
|
public:
|
53
|
+
//! Constructs an empty sample that acts as if the song had a length of 0.
|
54
|
+
Sample();
|
55
|
+
|
58
56
|
//! Constructs a sample that can be played on the specified audio
|
59
57
|
//! system and loads the sample from a file.
|
60
58
|
explicit Sample(const std::string& filename);
|
@@ -69,7 +67,7 @@ namespace Gosu
|
|
69
67
|
//! \param speed Playback speed is only limited by the underlying audio library,
|
70
68
|
//! and can accept very high or low values. Use 1.0 for
|
71
69
|
//! normal playback speed.
|
72
|
-
|
70
|
+
Channel play(double volume = 1, double speed = 1, bool looping = false) const;
|
73
71
|
|
74
72
|
//! Plays the sample with panning. Even if pan is 0.0, the sample will
|
75
73
|
//! not be as loud as if it were played by calling play() due to the
|
@@ -80,7 +78,7 @@ namespace Gosu
|
|
80
78
|
//! \param speed Playback speed is only limited by by the underlying audio library,
|
81
79
|
//! and can accept very high
|
82
80
|
//! or low values. Use 1.0 for normal playback speed.
|
83
|
-
|
81
|
+
Channel play_pan(double pan, double volume = 1, double speed = 1,
|
84
82
|
bool looping = false) const;
|
85
83
|
};
|
86
84
|
|
@@ -133,7 +131,7 @@ namespace Gosu
|
|
133
131
|
double volume() const;
|
134
132
|
//! \param volume Can be anything from 0.0 (silence) to 1.0 (full
|
135
133
|
//! volume).
|
136
|
-
void
|
134
|
+
void set_volume(double volume);
|
137
135
|
|
138
136
|
//! Called every tick by Window for management purposes.
|
139
137
|
static void update();
|
data/Gosu/Graphics.hpp
CHANGED
@@ -32,7 +32,7 @@ namespace Gosu
|
|
32
32
|
~Graphics();
|
33
33
|
|
34
34
|
void set_resolution(unsigned logical_width, unsigned logical_height,
|
35
|
-
|
35
|
+
double black_bar_width = 0, double black_bar_height = 0);
|
36
36
|
|
37
37
|
unsigned width() const;
|
38
38
|
unsigned height() const;
|
@@ -75,19 +75,22 @@ namespace Gosu
|
|
75
75
|
//! or end point. Please only use this for debugging purposes. Otherwise, use a quad or
|
76
76
|
//! image to simulate lines, or contribute a better draw_line to Gosu.
|
77
77
|
static void draw_line(double x1, double y1, Color c1,
|
78
|
-
|
79
|
-
|
78
|
+
double x2, double y2, Color c2,
|
79
|
+
ZPos z, AlphaMode mode = AM_DEFAULT);
|
80
80
|
|
81
81
|
static void draw_triangle(double x1, double y1, Color c1,
|
82
|
-
|
83
|
-
|
84
|
-
|
82
|
+
double x2, double y2, Color c2,
|
83
|
+
double x3, double y3, Color c3,
|
84
|
+
ZPos z, AlphaMode mode = AM_DEFAULT);
|
85
85
|
|
86
86
|
static void draw_quad(double x1, double y1, Color c1,
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
87
|
+
double x2, double y2, Color c2,
|
88
|
+
double x3, double y3, Color c3,
|
89
|
+
double x4, double y4, Color c4,
|
90
|
+
ZPos z, AlphaMode mode = AM_DEFAULT);
|
91
|
+
|
92
|
+
static void draw_rect(double x, double y, double width, double height,
|
93
|
+
Color c, ZPos z, AlphaMode mode = AM_DEFAULT);
|
91
94
|
|
92
95
|
//! For internal use only.
|
93
96
|
void set_physical_resolution(unsigned physical_width, unsigned physical_height);
|
@@ -97,7 +100,8 @@ namespace Gosu
|
|
97
100
|
|
98
101
|
//! Turns a portion of a bitmap into something that can be drawn on a Graphics object.
|
99
102
|
static std::unique_ptr<ImageData> create_image(const Bitmap& src,
|
100
|
-
|
101
|
-
|
103
|
+
unsigned src_x, unsigned src_y,
|
104
|
+
unsigned src_width, unsigned src_height,
|
105
|
+
unsigned image_flags);
|
102
106
|
};
|
103
107
|
}
|
data/Gosu/Image.hpp
CHANGED
@@ -17,6 +17,9 @@ namespace Gosu
|
|
17
17
|
std::shared_ptr<ImageData> data_;
|
18
18
|
|
19
19
|
public:
|
20
|
+
//! Creates an empty image. It will have a width and height of 0, and not contain anything.
|
21
|
+
Image();
|
22
|
+
|
20
23
|
//! Loads an image from a given filename.
|
21
24
|
//!
|
22
25
|
//! A color key of #ff00ff is automatically applied to BMP image files.
|
data/Gosu/Version.hpp
CHANGED
data/lib/gosu.rb
CHANGED
@@ -7,14 +7,14 @@ if RUBY_PLATFORM =~ /mswin$|mingw32|mingw64|win32\-|\-win32/
|
|
7
7
|
|
8
8
|
begin
|
9
9
|
# Make DLLs available as shown here:
|
10
|
-
|
10
|
+
# https://github.com/oneclick/rubyinstaller2/wiki/For-gem-developers
|
11
11
|
require 'ruby_installer'
|
12
12
|
RubyInstaller::Runtime.add_dll_directory(binary_path)
|
13
13
|
rescue LoadError
|
14
14
|
# Add this gem to the PATH on Windows so that bundled DLLs can be found.
|
15
15
|
# When running through Ocra on Windows, we need to be careful to preserve the ENV["PATH"]
|
16
16
|
# encoding (see #385).
|
17
|
-
|
17
|
+
path_encoding = ENV["PATH"].encoding
|
18
18
|
ENV["PATH"] = "#{binary_path.encode(path_encoding)};#{ENV["PATH"]}"
|
19
19
|
end
|
20
20
|
|
data/lib/gosu/compat.rb
CHANGED
@@ -143,7 +143,7 @@ class Gosu::Window
|
|
143
143
|
end
|
144
144
|
|
145
145
|
# Instance methods that have been turned into module methods.
|
146
|
-
%w(draw_line draw_triangle draw_quad
|
146
|
+
%w(draw_line draw_triangle draw_quad draw_rect
|
147
147
|
flush gl clip_to record
|
148
148
|
transform translate rotate scale
|
149
149
|
button_id_to_char char_to_button_id button_down?).each do |method|
|
data/lib/gosu/patches.rb
CHANGED
@@ -45,6 +45,11 @@ module Gosu
|
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
48
|
+
module Gosu
|
49
|
+
# Backwards compatibility: Channel was called SampleInstance before Gosu 0.13.0.
|
50
|
+
SampleInstance = Channel
|
51
|
+
end
|
52
|
+
|
48
53
|
class Gosu::Window
|
49
54
|
# Call Thread.pass every tick, which may or may not be necessary for friendly co-existence with
|
50
55
|
# Ruby's Thread class.
|
data/lib/gosu/swig_patches.rb
CHANGED
data/rdoc/gosu.rb
CHANGED
@@ -506,9 +506,9 @@ module Gosu
|
|
506
506
|
##
|
507
507
|
# Plays the sample without panning.
|
508
508
|
#
|
509
|
-
# @return [
|
510
|
-
# @param volume [Float] see {
|
511
|
-
# @param speed [Float] see {
|
509
|
+
# @return [Channel]
|
510
|
+
# @param volume [Float] see {Channel#volume=}
|
511
|
+
# @param speed [Float] see {Channel#speed=}
|
512
512
|
# @param looping [true, false] whether the sample should play in a loop. If you pass true, be sure to store the return value of this method so that you can later stop the looping sound.
|
513
513
|
#
|
514
514
|
# @see #play_pan
|
@@ -517,10 +517,10 @@ module Gosu
|
|
517
517
|
##
|
518
518
|
# Plays the sample with panning.
|
519
519
|
#
|
520
|
-
# @return [
|
521
|
-
# @param pan [Float] see {
|
522
|
-
# @param volume [Float] see {
|
523
|
-
# @param speed [Float] see {
|
520
|
+
# @return [Channel]
|
521
|
+
# @param pan [Float] see {Channel#pan=}
|
522
|
+
# @param volume [Float] see {Channel#volume=}
|
523
|
+
# @param speed [Float] see {Channel#speed=}
|
524
524
|
# @param looping [true, false] whether the sample should play in a loop. If you pass true, be sure to store the return value of this method so that you can later stop the looping sound.
|
525
525
|
#
|
526
526
|
# @see #play
|
@@ -528,10 +528,10 @@ module Gosu
|
|
528
528
|
end
|
529
529
|
|
530
530
|
##
|
531
|
-
#
|
531
|
+
# {Sample#play} returns a Channel that represents the sound currently being played.
|
532
532
|
#
|
533
|
-
#
|
534
|
-
class
|
533
|
+
# This object can be used to stop sounds dynamically, or to check whether they have finished.
|
534
|
+
class Channel
|
535
535
|
##
|
536
536
|
# Sets the playback volume, in the range [0.0; 1.0], where 0 is completely silent and 1 is full volume. Values outside of this range will be clamped to [0.0; 1.0].
|
537
537
|
# @param [Float]
|
data/src/Audio.cpp
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#include "
|
1
|
+
#include "AudioImpl.hpp"
|
2
2
|
#include "OggFile.hpp"
|
3
3
|
#include <Gosu/Audio.hpp>
|
4
4
|
#include <Gosu/Math.hpp>
|
@@ -8,19 +8,12 @@
|
|
8
8
|
#include <cassert>
|
9
9
|
#include <cstdlib>
|
10
10
|
#include <algorithm>
|
11
|
-
#include <memory>
|
12
|
-
#include <stdexcept>
|
13
|
-
#include <vector>
|
14
11
|
|
15
12
|
#ifdef GOSU_IS_MAC
|
16
|
-
#include <OpenAL/al.h>
|
17
|
-
#include <OpenAL/alc.h>
|
18
13
|
#import <Foundation/Foundation.h>
|
19
14
|
#include "AudioToolboxFile.hpp"
|
20
15
|
#define WAVE_FILE AudioToolboxFile
|
21
16
|
#else
|
22
|
-
#include <AL/al.h>
|
23
|
-
#include <AL/alc.h>
|
24
17
|
#include "MPEGFile.hpp"
|
25
18
|
#include "SndFile.hpp"
|
26
19
|
#define WAVE_FILE SndFile
|
@@ -32,116 +25,23 @@
|
|
32
25
|
|
33
26
|
using namespace std;
|
34
27
|
|
35
|
-
|
28
|
+
static bool is_ogg_file(Gosu::Reader reader)
|
36
29
|
{
|
37
|
-
|
38
|
-
{
|
39
|
-
char magic_bytes[4];
|
40
|
-
reader.read(magic_bytes, 4);
|
41
|
-
return magic_bytes[0] == 'O' && magic_bytes[1] == 'g' &&
|
42
|
-
magic_bytes[2] == 'g' && magic_bytes[3] == 'S';
|
43
|
-
}
|
44
|
-
|
45
|
-
bool is_ogg_file(const string& filename)
|
46
|
-
{
|
47
|
-
Gosu::File file(filename);
|
48
|
-
return is_ogg_file(file.front_reader());
|
49
|
-
}
|
50
|
-
|
51
|
-
Gosu::Song* cur_song = nullptr;
|
52
|
-
bool cur_song_looping;
|
53
|
-
}
|
54
|
-
|
55
|
-
#ifdef GOSU_IS_MAC
|
56
|
-
#define CONSTRUCTOR_BEGIN \
|
57
|
-
@autoreleasepool { \
|
58
|
-
if (!al_channel_management.get()) \
|
59
|
-
al_channel_management.reset(new ALChannelManagement)
|
60
|
-
#define CONSTRUCTOR_END \
|
61
|
-
}
|
62
|
-
#else
|
63
|
-
#define CONSTRUCTOR_BEGIN \
|
64
|
-
if (!al_channel_management.get()) \
|
65
|
-
al_channel_management.reset(new ALChannelManagement)
|
66
|
-
#define CONSTRUCTOR_END
|
67
|
-
#endif
|
68
|
-
|
69
|
-
Gosu::SampleInstance::SampleInstance(int handle, int extra)
|
70
|
-
: handle(handle), extra(extra)
|
71
|
-
{
|
72
|
-
}
|
73
|
-
|
74
|
-
bool Gosu::SampleInstance::playing() const
|
75
|
-
{
|
76
|
-
ALuint source = al_channel_management->source_if_still_playing(handle, extra);
|
77
|
-
if (source == ALChannelManagement::NO_SOURCE) return false;
|
30
|
+
if (reader.resource().size() < 4) return false;
|
78
31
|
|
79
|
-
|
80
|
-
|
81
|
-
return
|
32
|
+
char bytes[4];
|
33
|
+
reader.read(bytes, 4);
|
34
|
+
return bytes[0] == 'O' && bytes[1] == 'g' && bytes[2] == 'g' && bytes[3] == 'S';
|
82
35
|
}
|
83
36
|
|
84
|
-
bool
|
37
|
+
static bool is_ogg_file(const string& filename)
|
85
38
|
{
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
ALint state;
|
90
|
-
alGetSourcei(source, AL_SOURCE_STATE, &state);
|
91
|
-
return state == AL_PAUSED;
|
39
|
+
Gosu::File file(filename);
|
40
|
+
return is_ogg_file(file.front_reader());
|
92
41
|
}
|
93
42
|
|
94
|
-
|
95
|
-
|
96
|
-
ALuint source = al_channel_management->source_if_still_playing(handle, extra);
|
97
|
-
if (source == ALChannelManagement::NO_SOURCE) return;
|
98
|
-
|
99
|
-
alSourcePause(source);
|
100
|
-
}
|
101
|
-
|
102
|
-
void Gosu::SampleInstance::resume()
|
103
|
-
{
|
104
|
-
ALuint source = al_channel_management->source_if_still_playing(handle, extra);
|
105
|
-
if (source == ALChannelManagement::NO_SOURCE) return;
|
106
|
-
|
107
|
-
ALint state;
|
108
|
-
alGetSourcei(source, AL_SOURCE_STATE, &state);
|
109
|
-
if (state == AL_PAUSED) {
|
110
|
-
alSourcePlay(source);
|
111
|
-
}
|
112
|
-
}
|
113
|
-
|
114
|
-
void Gosu::SampleInstance::stop()
|
115
|
-
{
|
116
|
-
ALuint source = al_channel_management->source_if_still_playing(handle, extra);
|
117
|
-
if (source == ALChannelManagement::NO_SOURCE) return;
|
118
|
-
|
119
|
-
alSourceStop(source);
|
120
|
-
}
|
121
|
-
|
122
|
-
void Gosu::SampleInstance::change_volume(double volume)
|
123
|
-
{
|
124
|
-
ALuint source = al_channel_management->source_if_still_playing(handle, extra);
|
125
|
-
if (source == ALChannelManagement::NO_SOURCE) return;
|
126
|
-
|
127
|
-
alSourcef(source, AL_GAIN, max(volume, 0.0));
|
128
|
-
}
|
129
|
-
|
130
|
-
void Gosu::SampleInstance::change_pan(double pan)
|
131
|
-
{
|
132
|
-
ALuint source = al_channel_management->source_if_still_playing(handle, extra);
|
133
|
-
if (source == ALChannelManagement::NO_SOURCE) return;
|
134
|
-
|
135
|
-
alSource3f(source, AL_POSITION, pan * 10, 0, 0);
|
136
|
-
}
|
137
|
-
|
138
|
-
void Gosu::SampleInstance::change_speed(double speed)
|
139
|
-
{
|
140
|
-
ALuint source = al_channel_management->source_if_still_playing(handle, extra);
|
141
|
-
if (source == ALChannelManagement::NO_SOURCE) return;
|
142
|
-
|
143
|
-
alSourcef(source, AL_PITCH, speed);
|
144
|
-
}
|
43
|
+
static Gosu::Song* cur_song = nullptr;
|
44
|
+
static bool cur_song_looping;
|
145
45
|
|
146
46
|
struct Gosu::Sample::SampleData
|
147
47
|
{
|
@@ -149,6 +49,7 @@ struct Gosu::Sample::SampleData
|
|
149
49
|
|
150
50
|
SampleData(AudioFile& audio_file)
|
151
51
|
{
|
52
|
+
al_initialize();
|
152
53
|
alGenBuffers(1, &buffer);
|
153
54
|
alBufferData(buffer, audio_file.format(), &audio_file.decoded_data().front(),
|
154
55
|
static_cast<ALsizei>(audio_file.decoded_data().size()),
|
@@ -159,24 +60,20 @@ struct Gosu::Sample::SampleData
|
|
159
60
|
{
|
160
61
|
// It's hard to free things in the right order in Ruby/Gosu.
|
161
62
|
// Make sure buffer isn't deleted after the context/device are shut down.
|
162
|
-
if (!
|
163
|
-
return;
|
164
|
-
}
|
63
|
+
if (!al_initialized()) return;
|
165
64
|
|
166
65
|
alDeleteBuffers(1, &buffer);
|
167
66
|
}
|
168
|
-
|
169
|
-
private:
|
170
|
-
SampleData(const SampleData&);
|
171
|
-
SampleData& operator=(const SampleData&);
|
172
67
|
};
|
173
68
|
|
174
|
-
Gosu::Sample::Sample(
|
69
|
+
Gosu::Sample::Sample()
|
175
70
|
{
|
176
|
-
|
71
|
+
}
|
177
72
|
|
73
|
+
Gosu::Sample::Sample(const string& filename)
|
74
|
+
{
|
178
75
|
if (is_ogg_file(filename)) {
|
179
|
-
|
76
|
+
File file(filename);
|
180
77
|
OggFile ogg_file(file.front_reader());
|
181
78
|
data.reset(new SampleData(ogg_file));
|
182
79
|
}
|
@@ -184,62 +81,54 @@ Gosu::Sample::Sample(const string& filename)
|
|
184
81
|
WAVE_FILE audio_file(filename);
|
185
82
|
data.reset(new SampleData(audio_file));
|
186
83
|
}
|
187
|
-
|
188
|
-
CONSTRUCTOR_END;
|
189
84
|
}
|
190
85
|
|
191
|
-
Gosu::Sample::Sample(Reader reader)
|
86
|
+
Gosu::Sample::Sample(Gosu::Reader reader)
|
192
87
|
{
|
193
|
-
CONSTRUCTOR_BEGIN;
|
194
|
-
|
195
88
|
if (is_ogg_file(reader)) {
|
196
89
|
OggFile ogg_file(reader);
|
197
90
|
data.reset(new SampleData(ogg_file));
|
91
|
+
return;
|
198
92
|
}
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
else
|
211
|
-
#endif
|
212
|
-
throw ex;
|
93
|
+
|
94
|
+
try {
|
95
|
+
WAVE_FILE audio_file(reader);
|
96
|
+
data.reset(new SampleData(audio_file));
|
97
|
+
}
|
98
|
+
catch (const runtime_error& ex) {
|
99
|
+
#ifndef GOSU_IS_MAC
|
100
|
+
if (string(ex.what()).find("unknown format") != string::npos) {
|
101
|
+
MPEGFile mpeg_file(reader);
|
102
|
+
data.reset(new SampleData(mpeg_file));
|
103
|
+
return;
|
213
104
|
}
|
105
|
+
#endif
|
106
|
+
throw ex;
|
214
107
|
}
|
215
|
-
|
216
|
-
CONSTRUCTOR_END;
|
217
108
|
}
|
218
109
|
|
219
|
-
Gosu::
|
110
|
+
Gosu::Channel Gosu::Sample::play(double volume, double speed, bool looping) const
|
220
111
|
{
|
221
112
|
return play_pan(0, volume, speed, looping);
|
222
113
|
}
|
223
114
|
|
224
|
-
Gosu::
|
225
|
-
bool looping) const
|
115
|
+
Gosu::Channel Gosu::Sample::play_pan(double pan, double volume, double speed, bool looping) const
|
226
116
|
{
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
117
|
+
if (!data) return Channel(NO_CHANNEL, 0);
|
118
|
+
|
119
|
+
Channel channel = allocate_channel();
|
120
|
+
|
121
|
+
// Couldn't allocate a free channel.
|
122
|
+
if (channel.current_channel() == NO_CHANNEL) return channel;
|
231
123
|
|
232
|
-
ALuint source =
|
233
|
-
channel_and_token.second);
|
234
|
-
assert (source != ALChannelManagement::NO_SOURCE);
|
124
|
+
ALuint source = al_source_for_channel(channel.current_channel());
|
235
125
|
alSourcei(source, AL_BUFFER, data->buffer);
|
236
126
|
alSource3f(source, AL_POSITION, pan * 10, 0, 0);
|
237
127
|
alSourcef(source, AL_GAIN, max(volume, 0.0));
|
238
128
|
alSourcef(source, AL_PITCH, speed);
|
239
129
|
alSourcei(source, AL_LOOPING, looping ? AL_TRUE : AL_FALSE);
|
240
130
|
alSourcePlay(source);
|
241
|
-
|
242
|
-
return Gosu::SampleInstance(channel_and_token.first, channel_and_token.second);
|
131
|
+
return channel;
|
243
132
|
}
|
244
133
|
|
245
134
|
class Gosu::Song::BaseData
|
@@ -267,7 +156,7 @@ public:
|
|
267
156
|
return volume_;
|
268
157
|
}
|
269
158
|
|
270
|
-
void
|
159
|
+
void set_volume(double volume)
|
271
160
|
{
|
272
161
|
volume_ = clamp(volume, 0.0, 1.0);
|
273
162
|
apply_volume();
|
@@ -336,15 +225,7 @@ class Gosu::Song::StreamData : public BaseData
|
|
336
225
|
|
337
226
|
void apply_volume() override
|
338
227
|
{
|
339
|
-
|
340
|
-
if (source != ALChannelManagement::NO_SOURCE) {
|
341
|
-
alSourcef(source, AL_GAIN, max(volume(), 0.0));
|
342
|
-
}
|
343
|
-
}
|
344
|
-
|
345
|
-
int lookup_source() const
|
346
|
-
{
|
347
|
-
return al_channel_management->source_for_songs();
|
228
|
+
alSourcef(al_source_for_songs(), AL_GAIN, max(volume(), 0.0));
|
348
229
|
}
|
349
230
|
|
350
231
|
bool stream_to_buffer(ALuint buffer)
|
@@ -367,7 +248,7 @@ public:
|
|
367
248
|
StreamData(const string& filename)
|
368
249
|
{
|
369
250
|
if (is_ogg_file(filename)) {
|
370
|
-
|
251
|
+
File source_file(filename);
|
371
252
|
file.reset(new OggFile(source_file.front_reader()));
|
372
253
|
}
|
373
254
|
else {
|
@@ -377,14 +258,16 @@ public:
|
|
377
258
|
catch (const runtime_error& ex) {
|
378
259
|
#ifndef GOSU_IS_MAC
|
379
260
|
if (string(ex.what()).find("unknown format") != string::npos) {
|
380
|
-
|
261
|
+
File source_file(filename);
|
381
262
|
file.reset(new MPEGFile(source_file.front_reader()));
|
382
263
|
}
|
383
264
|
else
|
384
265
|
#endif
|
385
|
-
|
266
|
+
throw ex;
|
386
267
|
}
|
387
268
|
}
|
269
|
+
|
270
|
+
al_initialize();
|
388
271
|
alGenBuffers(2, buffers);
|
389
272
|
}
|
390
273
|
|
@@ -404,88 +287,79 @@ public:
|
|
404
287
|
}
|
405
288
|
else
|
406
289
|
#endif
|
407
|
-
|
290
|
+
throw ex;
|
408
291
|
}
|
409
292
|
}
|
293
|
+
|
294
|
+
al_initialize();
|
410
295
|
alGenBuffers(2, buffers);
|
411
296
|
}
|
412
297
|
|
413
298
|
~StreamData()
|
414
299
|
{
|
415
|
-
|
416
|
-
|
417
|
-
|
300
|
+
// It's hard to free things in the right order in Ruby/Gosu.
|
301
|
+
// Make sure buffers aren't deleted after the context/device are shut down.
|
302
|
+
if (!al_initialized()) return;
|
303
|
+
|
304
|
+
alDeleteBuffers(2, buffers);
|
418
305
|
}
|
419
306
|
|
420
307
|
void play(bool looping) override
|
421
308
|
{
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
alSourcePlay(source);
|
436
|
-
}
|
309
|
+
ALuint source = al_source_for_songs();
|
310
|
+
|
311
|
+
alSource3f(source, AL_POSITION, 0, 0, 0);
|
312
|
+
alSourcef(source, AL_GAIN, max(volume(), 0.0));
|
313
|
+
alSourcef(source, AL_PITCH, 1);
|
314
|
+
alSourcei(source, AL_LOOPING, AL_FALSE); // need to implement this manually...
|
315
|
+
|
316
|
+
stream_to_buffer(buffers[0]);
|
317
|
+
stream_to_buffer(buffers[1]);
|
318
|
+
|
319
|
+
// TODO: Not good for songs with less than two buffers full of data.
|
320
|
+
alSourceQueueBuffers(source, 2, buffers);
|
321
|
+
alSourcePlay(source);
|
437
322
|
}
|
438
323
|
|
439
324
|
void stop() override
|
440
325
|
{
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
alSourceUnqueueBuffers(source, 1, &buffer);
|
454
|
-
}
|
326
|
+
ALuint source = al_source_for_songs();
|
327
|
+
|
328
|
+
alSourceStop(source);
|
329
|
+
|
330
|
+
// Unqueue all buffers for this source.
|
331
|
+
// The number of QUEUED buffers apparently includes the number of PROCESSED ones,
|
332
|
+
// so getting rid of the QUEUED ones is enough.
|
333
|
+
ALuint buffer;
|
334
|
+
int queued;
|
335
|
+
alGetSourcei(source, AL_BUFFERS_QUEUED, &queued);
|
336
|
+
while (queued--) {
|
337
|
+
alSourceUnqueueBuffers(source, 1, &buffer);
|
455
338
|
}
|
339
|
+
|
456
340
|
file->rewind();
|
457
341
|
}
|
458
342
|
|
459
343
|
void pause() override
|
460
344
|
{
|
461
|
-
|
462
|
-
if (source != ALChannelManagement::NO_SOURCE) {
|
463
|
-
alSourcePause(source);
|
464
|
-
}
|
345
|
+
alSourcePause(al_source_for_songs());
|
465
346
|
}
|
466
347
|
|
467
348
|
void resume() override
|
468
349
|
{
|
469
|
-
|
470
|
-
if (source != ALChannelManagement::NO_SOURCE) {
|
471
|
-
alSourcePlay(source);
|
472
|
-
}
|
350
|
+
alSourcePlay(al_source_for_songs());
|
473
351
|
}
|
474
352
|
|
475
353
|
bool paused() const override
|
476
354
|
{
|
477
|
-
int source = lookup_source();
|
478
|
-
if (source == ALChannelManagement::NO_SOURCE) {
|
479
|
-
return false;
|
480
|
-
}
|
481
355
|
ALint state;
|
482
|
-
alGetSourcei(
|
356
|
+
alGetSourcei(al_source_for_songs(), AL_SOURCE_STATE, &state);
|
483
357
|
return state == AL_PAUSED;
|
484
358
|
}
|
485
359
|
|
486
360
|
void update() override
|
487
361
|
{
|
488
|
-
|
362
|
+
ALuint source = al_source_for_songs();
|
489
363
|
|
490
364
|
ALuint buffer;
|
491
365
|
int processed;
|
@@ -495,9 +369,7 @@ public:
|
|
495
369
|
for (int i = 0; i < processed; ++i) {
|
496
370
|
alSourceUnqueueBuffers(source, 1, &buffer);
|
497
371
|
active = stream_to_buffer(buffer);
|
498
|
-
if (active)
|
499
|
-
alSourceQueueBuffers(source, 1, &buffer);
|
500
|
-
}
|
372
|
+
if (active) alSourceQueueBuffers(source, 1, &buffer);
|
501
373
|
}
|
502
374
|
|
503
375
|
ALint state;
|
@@ -528,23 +400,16 @@ Gosu::Song::Song(const string& filename)
|
|
528
400
|
if (has_extension(filename, ".mp3") ||
|
529
401
|
has_extension(filename, ".aac") ||
|
530
402
|
has_extension(filename, ".m4a")) {
|
531
|
-
CONSTRUCTOR_BEGIN;
|
532
403
|
data.reset(new ModuleData(filename));
|
533
|
-
CONSTRUCTOR_END;
|
534
|
-
return;
|
535
404
|
}
|
405
|
+
else
|
536
406
|
#endif
|
537
|
-
|
538
|
-
CONSTRUCTOR_BEGIN;
|
539
407
|
data.reset(new StreamData(filename));
|
540
|
-
CONSTRUCTOR_END;
|
541
408
|
}
|
542
409
|
|
543
410
|
Gosu::Song::Song(Reader reader)
|
544
411
|
{
|
545
|
-
CONSTRUCTOR_BEGIN;
|
546
412
|
data.reset(new StreamData(reader));
|
547
|
-
CONSTRUCTOR_END;
|
548
413
|
}
|
549
414
|
|
550
415
|
Gosu::Song::~Song()
|
@@ -579,7 +444,7 @@ void Gosu::Song::play(bool looping)
|
|
579
444
|
void Gosu::Song::pause()
|
580
445
|
{
|
581
446
|
if (cur_song == this) {
|
582
|
-
data->pause();
|
447
|
+
data->pause();
|
583
448
|
}
|
584
449
|
}
|
585
450
|
|
@@ -606,9 +471,9 @@ double Gosu::Song::volume() const
|
|
606
471
|
return data->volume();
|
607
472
|
}
|
608
473
|
|
609
|
-
void Gosu::Song::
|
474
|
+
void Gosu::Song::set_volume(double volume)
|
610
475
|
{
|
611
|
-
data->
|
476
|
+
data->set_volume(volume);
|
612
477
|
}
|
613
478
|
|
614
479
|
void Gosu::Song::update()
|