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 dsfml.audio.soundbufferrecorder;
60 
61 import dsfml.audio.soundrecorder;
62 import dsfml.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         short[] m_samples;
73         SoundBuffer m_buffer;
74     }
75 
76     /// Default constructor.
77     this()
78     {
79         // Constructor code
80         m_buffer = new SoundBuffer();
81     }
82 
83     /// Destructor.
84     ~this()
85     {
86         import dsfml.system.config;
87         mixin(destructorOutput);
88     }
89 
90     /**
91      * Get the sound buffer containing the captured audio data.
92      *
93      * The sound buffer is valid only after the capture has ended. This function
94      * provides a read-only access to the internal sound buffer, but it can be
95      * copied if you need to make any modification to it.
96      *
97      * Returns: Read-only access to the sound buffer.
98      */
99     const(SoundBuffer) getBuffer() const
100     {
101         return m_buffer;
102     }
103 
104     protected
105     {
106         /**
107          * Start capturing audio data.
108          *
109          * Returns: true to start the capture, or false to abort it.
110          */
111         override bool onStart()
112         {
113             m_samples.length = 0;
114             m_buffer = new SoundBuffer();
115 
116             return true;
117         }
118 
119         /**
120          * Process a new chunk of recorded samples.
121          *
122          * Params:
123          *	samples =	Array of the new chunk of recorded samples
124          *
125          * Returns: true to continue the capture, or false to stop it.
126          */
127         override bool onProcessSamples(const(short)[] samples)
128         {
129             m_samples ~= samples;
130 
131             return true;
132         }
133 
134         /**
135          * Stop capturing audio data.
136          */
137         override void onStop()
138         {
139             if(m_samples.length >0)
140             {
141                 m_buffer.loadFromSamples(m_samples,1,sampleRate);
142             }
143         }
144     }
145 }
146 
147 unittest
148 {
149     //When this unit test is run it occasionally throws an error which will vary, and
150     //is obviously in OpenAL. Probably something to do with the way the binding is done. Will be fixed in 2.1.
151     version(DSFML_Unittest_Audio)
152     {
153         import std.stdio;
154         import dsfml.window.keyboard;
155         import dsfml.audio.sound;
156         import dsfml.system.clock;
157         import dsfml.system.sleep;
158 
159         writeln("Unit test for SoundBufferRecorder.");
160 
161         assert(SoundRecorder.isAvailable());
162 
163         auto recorder = new SoundBufferRecorder();
164 
165         auto clock = new Clock();
166 
167         writeln("Recording for 5 seconds in...");
168         writeln("3");
169         clock.restart();
170 
171         while(clock.getElapsedTime().asSeconds() <1)
172         {
173             //wait for a second
174         }
175 
176         writeln("2");
177 
178         clock.restart();
179 
180         while(clock.getElapsedTime().asSeconds() <1)
181         {
182             //wait for a second
183         }
184 
185         writeln("1");
186 
187         clock.restart();
188 
189         while(clock.getElapsedTime().asSeconds() <1)
190         {
191             //wait for a second
192         }
193 
194         writeln("Recording!");
195 
196         recorder.start();
197         clock.restart();
198 
199         while(clock.getElapsedTime().asSeconds() <5)
200         {
201             //wait for a second
202         }
203 
204         writeln("Done!");
205 
206         recorder.stop();
207 
208         auto buffer = recorder.getBuffer();
209         auto recorderDuration = buffer.getDuration();
210         auto recorderSound = new Sound(buffer);
211 
212         clock.restart();
213 
214         recorderSound.play();
215         while(clock.getElapsedTime() < recorderDuration)
216         {
217             //sound playing
218         }
219 
220         writeln();
221     }
222 }