11from manim import *
2- import pygments .styles as code_styles
32from manim_voiceover import VoiceoverScene
43
5- from manim_voiceover .services .azure import AzureService
4+ from manim_voiceover .services .gemini import GeminiService
65
7- code_style = code_styles .get_style_by_name ("one-dark" )
6+ code_style = "one-dark"
7+
8+ SCENE_HEADER_LINES = (1 , 2 )
9+ SET_SERVICE_LINE = 3
10+ GEMINI_SERVICE_LINE = 4
11+ GEMINI_VOICE_LINE = 5
12+ GEMINI_AUTH_LINE = 6
13+ SERVICE_CLOSE_LINES = (7 , 8 )
14+ CIRCLE_SETUP_LINES = (9 , 10 )
15+ VOICEOVER_CONTEXT_LINE = 11
16+ VOICEOVER_PLAY_LINE = 12
17+ SHIFT_CONTEXT_LINE = 14
18+ SHIFT_DURATION_LINE = 15
19+
20+
21+ def demo_code_block (code_string ):
22+ return Code (
23+ code_string = code_string ,
24+ add_line_numbers = False ,
25+ formatter_style = code_style ,
26+ background = "window" ,
27+ language = "python" ,
28+ paragraph_config = {"font" : "Menlo" },
29+ )
30+
31+
32+ def code_lines (code_block , start , end = None ):
33+ if end is None :
34+ return code_block .code_lines [start - 1 ]
35+ return code_block .code_lines [start - 1 : end ]
36+
37+
38+ def code_line_range (code_block , line_range ):
39+ return code_lines (code_block , line_range [0 ], line_range [1 ])
840
941
1042class VoiceoverDemo (VoiceoverScene ):
1143 def construct (self ):
12- # Initialize speech synthesis using Azure's TTS API
13- self .set_speech_service (
14- AzureService (
15- voice = "en-US-AriaNeural" ,
16- style = "newscast-casual" , # global_speed=1.15
17- )
18- )
44+ # Initialize speech synthesis using Gemini's TTS API
45+ self .set_speech_service (GeminiService (voice = "Kore" , auth_mode = "adc" ))
1946 banner = ManimBanner ().scale (0.5 )
2047
2148 with self .voiceover (text = "Hey Manim Community!" ):
@@ -31,20 +58,15 @@ def construct(self):
3158 self .wait (tracker .get_remaining_duration (buff = - 1 ))
3259 self .play (FadeOut (banner ))
3360
34- demo_code = Code (
35- code = '''tracker = self.add_voiceover_text(
61+ demo_code = demo_code_block (
62+ '''tracker = self.add_voiceover_text(
3663 """AI generated voices have become realistic
3764 enough for use in most content. Using neural
3865 text-to-speech frees you from the painstaking
3966 process of recording and manually syncing
4067 audio to your video."""
4168)
42- self.play(Write(demo_code), run_time=tracker.duration)''' ,
43- insert_line_no = False ,
44- style = code_style ,
45- background = "window" ,
46- font = "Consolas" ,
47- language = "python" ,
69+ self.play(Write(demo_code), run_time=tracker.duration)'''
4870 ).rescale_to_fit (12 , 0 )
4971
5072 tracker = self .add_voiceover_text (
@@ -80,14 +102,13 @@ def construct(self):
80102 with self .voiceover (text = "I would go on, but you get the idea." ):
81103 self .play (FadeOut (circle ))
82104
83- demo_code2 = Code (
84- code = """class VoiceoverDemo(VoiceoverScene):
105+ demo_code2 = demo_code_block (
106+ """class VoiceoverDemo(VoiceoverScene):
85107 def construct(self):
86108 self.set_speech_service(
87- AzureService(
88- voice="en-US-AriaNeural",
89- style="newscast-casual",
90- global_speed=1.15
109+ GeminiService(
110+ voice="Kore",
111+ auth_mode="adc",
91112 )
92113 )
93114 circle = Circle()
@@ -96,64 +117,51 @@ def construct(self):
96117 self.play(Create(circle))
97118
98119 with self.voiceover(text="Let's shift it to the left 2 units.") as tracker:
99- self.play(circle.animate.shift(2 * LEFT), run_time=tracker.duration)""" ,
100- insert_line_no = False ,
101- style = code_style ,
102- background = "window" ,
103- font = "Consolas" ,
104- language = "python" ,
120+ self.play(circle.animate.shift(2 * LEFT), run_time=tracker.duration)"""
105121 ).rescale_to_fit (12 , 0 )
106122
107123 with self .voiceover (text = "Let's see how the API works!" ):
108- self .play (FadeIn (demo_code2 .background_mobject ))
124+ self .play (FadeIn (demo_code2 .background ))
109125
110- with self .voiceover (
111- text = "First, we create a scene using the Voiceover Scene class from the plugin."
112- ):
113- self .play (FadeIn (demo_code2 .code [:2 ]))
126+ with self .voiceover (text = "First, we create a scene using the Voiceover Scene class from the plugin." ):
127+ self .play (FadeIn (code_line_range (demo_code2 , SCENE_HEADER_LINES )))
114128
115- with self .voiceover (
116- text = "Then, we initialize the voiceover by setting the appropriate speech synthesizer."
117- ):
118- self .play (FadeIn (demo_code2 .code [2 ]))
129+ with self .voiceover (text = "Then, we initialize the voiceover by setting the appropriate speech synthesizer." ):
130+ self .play (FadeIn (code_lines (demo_code2 , SET_SERVICE_LINE )))
119131
120- with self .voiceover (text = "In this example, we use Azure Text -to-speech." ):
121- self .play (FadeIn (demo_code2 . code [ 3 ] ))
132+ with self .voiceover (text = "In this example, we use Gemini text -to-speech." ):
133+ self .play (FadeIn (code_lines ( demo_code2 , GEMINI_SERVICE_LINE ) ))
122134
123- with self .voiceover (
124- text = "We use the English speaking neural voice called Aria."
125- ):
126- self .play (FadeIn (demo_code2 .code [4 ]))
135+ with self .voiceover (text = "We use the prebuilt Gemini voice called Kore." ):
136+ self .play (FadeIn (code_lines (demo_code2 , GEMINI_VOICE_LINE )))
127137
128- with self .voiceover (text = ' We use the style called "newscast casual".' ):
129- self .play (FadeIn (demo_code2 . code [ 5 ] ))
138+ with self .voiceover (text = " We authenticate with Application Default Credentials." ):
139+ self .play (FadeIn (code_lines ( demo_code2 , GEMINI_AUTH_LINE ) ))
130140
131141 with self .voiceover (
132- text = """Finally, we give an option to speed up the voiceover
133- playback fifteen percent, because the default is a bit too slow ."""
142+ text = """Finally, Gemini returns audio that Manim Voiceover stores
143+ in the local voiceover cache for reuse ."""
134144 ):
135- self .play (FadeIn (demo_code2 . code [ 6 : 9 ] ))
145+ self .play (FadeIn (code_line_range ( demo_code2 , SERVICE_CLOSE_LINES ) ))
136146
137- with self .voiceover (
138- text = """With the configuration out of the way, it is time to animate."""
139- ):
147+ with self .voiceover (text = """With the configuration out of the way, it is time to animate.""" ):
140148 pass
141149
142150 with self .voiceover (text = """Let's initialize the circle object.""" ):
143- self .play (FadeIn (demo_code2 . code [ 9 : 11 ] ))
151+ self .play (FadeIn (code_line_range ( demo_code2 , CIRCLE_SETUP_LINES ) ))
144152
145153 with self .voiceover (
146154 text = """Then, we need to tell the scene to start narrating,
147155 by calling the function "self-dot-voiceover"."""
148156 ):
149- self .play (FadeIn (demo_code2 . code [ 11 ] ))
157+ self .play (FadeIn (code_lines ( demo_code2 , VOICEOVER_CONTEXT_LINE ) ))
150158
151159 with self .voiceover (
152160 text = """By wrapping our animation inside a "with-statement",
153161 we ensure that once it finishes playing, it will also wait for
154162 the voiceover playback to finish."""
155163 ):
156- self .play (FadeIn (demo_code2 . code [ 12 ] ))
164+ self .play (FadeIn (code_lines ( demo_code2 , VOICEOVER_PLAY_LINE ) ))
157165
158166 with self .voiceover (
159167 text = """This is extremely convenient, and let's you chain
@@ -164,79 +172,61 @@ def construct(self):
164172 with self .voiceover (
165173 text = """We just need to repeat the same pattern with self-dot-voiceover and with-statements. Here is something cool."""
166174 ):
167- self .play (FadeIn (demo_code2 . code [ 14 ] ))
175+ self .play (FadeIn (code_lines ( demo_code2 , SHIFT_CONTEXT_LINE ) ))
168176
169177 with self .voiceover (
170178 text = """We can retrieve the duration of the generated voiceover programmatically, and then use it to define for how long an animation should play."""
171179 ):
172- self .play (FadeIn (demo_code2 . code [ 15 ] ))
180+ self .play (FadeIn (code_lines ( demo_code2 , SHIFT_DURATION_LINE ) ))
173181
174- demo_code3 = Code (
175- code = """class VoiceoverDemo(VoiceoverScene):
182+ demo_code3 = demo_code_block (
183+ """class VoiceoverDemo(VoiceoverScene):
176184 def construct(self):
177185 self.set_speech_service(
178- AzureService(
179- voice="en-US-AriaNeural",
180- style="newscast-casual",
181- global_speed=1.15
186+ GeminiService(
187+ voice="Kore",
188+ auth_mode="adc",
182189 )
183190 )
184191 # self.set_speech_service(
185192 # StitcherService("my_voice_recording.mp3")
186193 # )
187- """ ,
188- insert_line_no = False ,
189- style = code_style ,
190- background = "window" ,
191- font = "Consolas" ,
192- language = "python" ,
194+ """
193195 ).scale (0.85 )
194196
195197 demo_code4 = (
196- Code (
197- code = """class VoiceoverDemo(VoiceoverScene):
198+ demo_code_block (
199+ """class VoiceoverDemo(VoiceoverScene):
198200 def construct(self):
199201 # self.set_speech_service(
200- # AzureService(
201- # voice="en-US-AriaNeural",
202- # style="newscast-casual",
203- # global_speed=1.15
202+ # GeminiService(
203+ # voice="Kore",
204+ # auth_mode="adc",
204205 # )
205206 # )
206207 # self.set_speech_service(
207208 # StitcherService("my_voice_recording.mp3")
208209 # )
209- """ ,
210- insert_line_no = False ,
211- style = code_style ,
212- background = "window" ,
213- font = "Consolas" ,
214- language = "python" ,
210+ """
215211 )
216212 .scale (0.85 )
217213 .align_to (demo_code3 , LEFT )
218214 )
219215
220216 demo_code5 = (
221- Code (
222- code = """class VoiceoverDemo(VoiceoverScene):
217+ demo_code_block (
218+ """class VoiceoverDemo(VoiceoverScene):
223219 def construct(self):
224220 # self.set_speech_service(
225- # AzureService(
226- # voice="en-US-AriaNeural",
227- # style="newscast-casual",
228- # global_speed=1.15
221+ # GeminiService(
222+ # voice="Kore",
223+ # auth_mode="adc",
229224 # )
230225 # )
231226 self.set_speech_service(
232227 StitcherService("my_voice_recording.mp3")
233228 )
234- """ ,
235- insert_line_no = False ,
236- style = code_style ,
237- background = "window" ,
238- font = "Consolas" ,
239- language = "python" ,
229+ """
240230 )
241231 .scale (0.85 )
242232 .align_to (demo_code3 , LEFT )
@@ -258,31 +248,21 @@ def construct(self):
258248 self .wait ()
259249 self .play (FadeOut (text1 , text2 , arrow ))
260250
261- with self .voiceover (
262- text = "To do that, you record an MP3 of the final text of your video."
263- ):
251+ with self .voiceover (text = "To do that, you record an MP3 of the final text of your video." ):
264252 self .play (FadeIn (demo_code3 ))
265253
266254 with self .voiceover (
267255 text = """Manim-voiceover then splits your audio automatically and replaces the AI generated voice with your real recording."""
268256 ):
269- self .play (FadeOut (demo_code3 .code ), FadeIn (demo_code4 .code ))
270- self .play (FadeOut (demo_code4 .code ), FadeIn (demo_code5 .code ))
257+ self .play (FadeOut (demo_code3 .code_lines ), FadeIn (demo_code4 .code_lines ))
258+ self .play (FadeOut (demo_code4 .code_lines ), FadeIn (demo_code5 .code_lines ))
271259
272260 self .wait (2 )
273261
274- with self .voiceover (
275- text = """Manim-voiceover makes it much easier to do voiceovers for Manim projects."""
276- ):
277- self .play (FadeOut (demo_code5 .code , demo_code3 .background_mobject ))
262+ with self .voiceover (text = """Manim-voiceover makes it much easier to do voiceovers for Manim projects.""" ):
263+ self .play (FadeOut (demo_code5 .code_lines , demo_code3 .background ))
278264
279- with self .voiceover (
280- text = "Visit the GitHub repo to start using it in your project."
281- ):
282- self .play (
283- FadeIn (
284- Tex (r"\texttt{https://github.com/ManimCommunity/manim-voiceover}" )
285- )
286- )
265+ with self .voiceover (text = "Visit the GitHub repo to start using it in your project." ):
266+ self .play (FadeIn (Tex (r"\texttt{https://github.com/ManimCommunity/manim-voiceover}" )))
287267
288268 self .wait (5 )
0 commit comments