1 /*
2     Copyright © 2020, Luna Nielsen
3     Distributed under the 2-Clause BSD License, see LICENSE file.
4     
5     Authors: Luna Nielsen
6 */
7 module engine.audio.astream;
8 import engine.audio.astream.ogg;
9 import std.path;
10 import bindbc.openal;
11 import std.format;
12 import std.range;
13 
14 /**
15     Open an audio file
16 */
17 AudioStream open(string file, bool bit16 = true) {
18     switch(file.extension) {
19         case ".ogg": return new OggStream(file, bit16);
20         default: throw new Exception("Unsupported file type (%s)".format(file.extension));
21     }
22 }
23 
24 
25 /**
26     Information about audio, usually music
27 */
28 struct AudioInfo {
29 
30     /**
31         The file of the audio
32     */
33     string file;
34 
35     /**
36         The title of the audio
37     */
38     string title;
39 
40     /**
41         The artist behind the music
42     */
43     string artist;
44 
45     /**
46         The person performing the music
47     */
48     string performer;
49 
50     /**
51         The person performing the music
52     */
53     string album;
54 
55     /**
56         Date of release, usually year
57     */
58     string date;
59 
60     /**
61         Get the audio info as a string
62     
63         According to Danish law even things CC0 or public domain has to include crediting
64         In the case the music doesn't (eg. the player drags music in to the game's music folder that is pirated)
65         We'll leave a little message for them :)
66     */
67     string toString() {
68         if (artist.empty || title.empty) return "%s\n[Info missing! yarr harr?]".format(file);
69 
70         string base = "%s - %s".format(artist, title);
71         if (!album.empty) base ~= " from %s".format(album);
72         if (!date.empty) base ~= " (%s)".format(date);
73         if (!performer.empty) base ~= "\nPerfomed by %s".format(performer);
74         return base;
75     }
76 }
77 
78 /**
79     Audio format of a stream
80 */
81 enum Format {
82     Mono8 = AL_FORMAT_MONO8,
83     Mono16 = AL_FORMAT_MONO16,
84     Stereo8 = AL_FORMAT_STEREO8,
85     Stereo16 = AL_FORMAT_STEREO16
86 }
87 
88 /**
89     A stream of audio
90 */
91 abstract class AudioStream {
92 public:
93     /**
94         The amount of channels in the audio stream
95     */
96     int channels;
97 
98     /**
99         Audio format of the stream
100     */
101     Format format;
102 
103     /**
104         Read all samples from the stream till the end
105     */
106     final ubyte[] readAll() {
107         ubyte[] data = new ubyte[4096];
108         ubyte[] outData;
109         ptrdiff_t readCount = 0;
110         do {
111             readCount = readSamples(data);
112             outData ~= data[0..readCount];
113         } while(readCount > 0);
114         
115         if (canSeek) seek(0);
116         return outData;
117     }
118 
119 abstract:
120     /**
121         Read samples from the audio stream in to the array
122 
123         Returns the amount of samples read
124         Returns 0 if there's no more samples
125     */
126     ptrdiff_t readSamples(ref ubyte[] toArray);
127     
128     /**
129         Gets whether the file can be seeked
130     */
131     bool canSeek();
132 
133     /**
134         Seek to a PCM location in the stream
135     */
136     void seek(size_t location);
137 
138     /**
139         Get the position in the stream
140     */
141     size_t tell();
142 
143     /**
144         Gets the bitrate of the stream
145     */
146     size_t bitrate();
147 
148     /**
149         Try to get the information about the audio
150 
151         This information is usually only used for music
152     */
153     AudioInfo getInfo();
154 }