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