1 /*
2  *******************************************************************************************
3  * Dgame (a D game framework) - Copyright (c) Randy Schütt
4  * 
5  * This software is provided 'as-is', without any express or implied warranty.
6  * In no event will the authors be held liable for any damages arising from
7  * the use of this software.
8  * 
9  * Permission is granted to anyone to use this software for any purpose,
10  * including commercial applications, and to alter it and redistribute it
11  * freely, subject to the following restrictions:
12  * 
13  * 1. The origin of this software must not be misrepresented; you must not claim
14  *    that you wrote the original software. If you use this software in a product,
15  *    an acknowledgment in the product documentation would be appreciated but is
16  *    not required.
17  * 
18  * 2. Altered source versions must be plainly marked as such, and must not be
19  *    misrepresented as being the original software.
20  * 
21  * 3. This notice may not be removed or altered from any source distribution.
22  *******************************************************************************************
23  */
24 module Dgame.Audio.VorbisFile;
25 
26 private {
27 	import std..string : toStringz;
28 	
29 	import derelict.ogg.ogg;
30 	import derelict.vorbis.vorbis;
31 	import derelict.vorbis.file;
32 	//import derelict.vorbis.enc;
33 
34 	import Dgame.Internal.Log;
35 	import Dgame.Internal.Unique;
36 	import Dgame.Audio.SoundFile;
37 }
38 
39 /**
40  * An alias for VorbisFile
41  */
42 alias OggFile = VorbisFile;
43 
44 /**
45  * An Ogg/Vorbis implementation of BaseSoundFile
46  * Open an ogg/vorbis file and store the attributes from it's headers.
47  *
48  * Author: rschuett
49  */
50 class VorbisFile : BaseSoundFile {
51 protected:
52 	override void _read(string filename) {
53 		super._filename = filename;
54 		
55 		OggVorbis_File oggFile = void;
56 		scope(exit) ov_clear(&oggFile);
57 		
58 		if (ov_fopen(toStringz(filename), &oggFile) < 0)
59 			Log.error(filename ~ " is no valid Vorbis file.");
60 		
61 		// Get some information about the OGG file
62 		vorbis_info* pInfo = ov_info(&oggFile, -1);
63 		
64 		super._sFile.rate  = pInfo.rate;
65 		super._sFile.bits  = 16;
66 		super._sFile.bytes = 2;
67 		super._sFile.dataSize = cast(uint) ov_pcm_total(&oggFile, -1) * super._sFile.bytes * pInfo.channels;
68 		super._sFile.channels = cast(ubyte) pInfo.channels;
69 		
70 		debug Log.info("Allocate %d memory for Vorbis file %s.", _sFile.dataSize, filename);
71 		super._buffer = new byte[super._sFile.dataSize];
72 		
73 		unique_ptr!(byte) tmpBuf = allocate_unique!(byte)(ushort.max);
74 //		byte[] tmpBuf = new byte[ushort.max];
75 
76 		uint inserted = 0;
77 		while (true) {
78 			// Read up to a buffer's worth of decoded sound data
79 			long bytes = ov_read(&oggFile, &tmpBuf[0], ushort.max, 0, 2, 1, null);
80 			if (bytes <= 0)
81 				break;
82 			// Append to end of buffer
83 			uint bytes_read = cast(uint) bytes;
84 			
85 			super._buffer[inserted .. inserted  + bytes_read] = tmpBuf[0 .. bytes_read];
86 			
87 			inserted += bytes;
88 		}
89 	}
90 	
91 public:
92 	/**
93 	 * CTor
94 	 */
95 	this(string filename) {
96 		super(filename);
97 	}
98 	
99 	/**
100 	 * Returns the music type. In this case: Ogg.
101 	 */
102 	override MusicType getType() const pure nothrow {
103 		return MusicType.Ogg;
104 	}
105 }