gosu 0.12.1 → 0.13.0
Sign up to get free protection for your applications and to get access to all the features.
- 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()
|