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 }