1 /*
2  * DSFML - The Simple and Fast Multimedia Library for D
3  *
4  * Copyright (c) 2013 - 2017 Jeremy DeHaan (dehaan.jeremiah@gmail.com)
5  *
6  * This software is provided 'as-is', without any express or implied warranty.
7  * In no event will the authors be held liable for any damages arising from the
8  * use of this software.
9  *
10  * Permission is granted to anyone to use this software for any purpose,
11  * including commercial applications, and to alter it and redistribute it
12  * freely, subject to the following restrictions:
13  *
14  * 1. The origin of this software must not be misrepresented; you must not claim
15  * that you wrote the original software. If you use this software in a product,
16  * an acknowledgment in the product documentation would be appreciated but is
17  * not required.
18  *
19  * 2. Altered source versions must be plainly marked as such, and must not be
20  * misrepresented as being the original software.
21  *
22  * 3. This notice may not be removed or altered from any source distribution
23  */
24 
25 /**
26  * $(U SoundBufferRecorder) allows to access a recorded sound through a
27  * $(SOUNDBUFFER_LINK), so that it can be played, saved to a file, etc.
28  *
29  * It has the same simple interface as its base class (`start()`, `stop()`) and
30  * adds a function to retrieve the recorded sound buffer (`getBuffer()`).
31  *
32  * As usual, don't forget to call the `isAvailable()` function before using this
33  * class (see $(SOUNDRECORDER_LINK) for more details about this).
34  *
35  * Example:
36  * ---
37  * if (SoundBufferRecorder.isAvailable())
38  * {
39  *     // Record some audio data
40  *     auto recorder = SoundBufferRecorder();
41  *     recorder.start();
42  *     ...
43  *     recorder.stop();
44  *
45  *     // Get the buffer containing the captured audio data
46  *     auto buffer = recorder.getBuffer();
47  *
48  *     // Save it to a file (for example...)
49  *     buffer.saveToFile("my_record.ogg");
50  * }
51  * ---
52  *
53  * See_Also:
54  * $(SOUNDRECORDER_LINK)
55  */
56 module dsfml.audio.soundbufferrecorder;
57 
58 import dsfml.audio.soundrecorder;
59 import dsfml.audio.soundbuffer;
60 
61 
62 /**
63  * Specialized SoundRecorder which stores the captured audio data into a sound
64  * buffer.
65  */
66 class SoundBufferRecorder : SoundRecorder
67 {
68     private
69     {
70         short[] m_samples;
71         SoundBuffer m_buffer;
72     }
73 
74     /// Default constructor.
75     this()
76     {
77         // Constructor code
78         m_buffer = new SoundBuffer();
79     }
80 
81     /// Destructor.
82     ~this()
83     {
84         import dsfml.system.config;
85         mixin(destructorOutput);
86     }
87 
88     /**
89      * Get the sound buffer containing the captured audio data.
90      *
91      * The sound buffer is valid only after the capture has ended. This function
92      * provides a read-only access to the internal sound buffer, but it can be
93      * copied if you need to make any modification to it.
94      *
95      * Returns: Read-only access to the sound buffer.
96      */
97     const(SoundBuffer) getBuffer() const
98     {
99         return m_buffer;
100     }
101 
102     protected
103     {
104         /**
105          * Start capturing audio data.
106          *
107          * Returns: true to start the capture, or false to abort it.
108          */
109         override bool onStart()
110         {
111             m_samples.length = 0;
112             m_buffer = new SoundBuffer();
113 
114             return true;
115         }
116 
117         /**
118          * Process a new chunk of recorded samples.
119          *
120          * Params:
121          *	samples =	Array of the new chunk of recorded samples
122          *
123          * Returns: true to continue the capture, or false to stop it.
124          */
125         override bool onProcessSamples(const(short)[] samples)
126         {
127             m_samples ~= samples;
128 
129             return true;
130         }
131 
132         /**
133          * Stop capturing audio data.
134          */
135         override void onStop()
136         {
137             if(m_samples.length >0)
138             {
139                 m_buffer.loadFromSamples(m_samples,1,sampleRate);
140             }
141         }
142     }
143 }
144 
145 unittest
146 {
147     //When this unit test is run it occasionally throws an error which will vary, and
148     //is obviously in OpenAL. Probably something to do with the way the binding is done. Will be fixed in 2.1.
149     version(DSFML_Unittest_Audio)
150     {
151         import std.stdio;
152         import core.time;
153         import dsfml.window.keyboard;
154         import dsfml.audio.sound;
155         import dsfml.system.clock;
156         import dsfml.system.sleep;
157 
158 
159         writeln("Unit test for SoundBufferRecorder.");
160 
161         assert(SoundRecorder.isAvailable());
162 
163 
164         auto recorder = new SoundBufferRecorder();
165 
166 
167         auto clock = new Clock();
168 
169         writeln("Recording for 5 seconds in...");
170         writeln("3");
171         clock.restart();
172 
173         while(clock.getElapsedTime().total!"seconds" <1)
174         {
175             //wait for a second
176         }
177         writeln("2");
178 
179         clock.restart();
180 
181         while(clock.getElapsedTime().total!"seconds" <1)
182         {
183             //wait for a second
184         }
185         writeln("1");
186 
187         clock.restart();
188 
189         while(clock.getElapsedTime().total!"seconds" <1)
190         {
191             //wait for a second
192         }
193         writeln("Recording!");
194 
195         recorder.start();
196         clock.restart();
197 
198         while(clock.getElapsedTime().total!"seconds" <5)
199         {
200             //wait for a second
201         }
202 
203         writeln("Done!");
204 
205 
206         recorder.stop();
207 
208         auto buffer = recorder.getBuffer();
209 
210         auto recorderDuration = buffer.getDuration();
211 
212         auto recorderSound = new Sound(buffer);
213 
214         clock.restart();
215 
216         recorderSound.play();
217         while(clock.getElapsedTime() < recorderDuration)
218         {
219             //sound playing
220         }
221 
222         writeln();
223     }
224 }