Line data Source code
1 :
2 : /* Copyright (c) 2005-2015, Stefan Eilemann <eile@equalizergraphics.com>
3 : * Cedric Stalder <cedric.stalder@gmail.com>
4 : * Daniel Nachbaur <danielnachbaur@gmail.com>
5 : *
6 : * This library is free software; you can redistribute it and/or modify it under
7 : * the terms of the GNU Lesser General Public License version 2.1 as published
8 : * by the Free Software Foundation.
9 : *
10 : * This library is distributed in the hope that it will be useful, but WITHOUT
11 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 : * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
13 : * details.
14 : *
15 : * You should have received a copy of the GNU Lesser General Public License
16 : * along with this library; if not, write to the Free Software Foundation, Inc.,
17 : * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 : */
19 :
20 : #ifndef EQ_CHANNEL_H
21 : #define EQ_CHANNEL_H
22 :
23 : #include <eq/api.h>
24 : #include <eq/types.h>
25 :
26 : #include <eq/fabric/channel.h> // base class
27 :
28 : namespace eq
29 : {
30 : namespace detail { class Channel; struct RBStat; }
31 :
32 : /**
33 : * A channel represents a two-dimensional viewport within a Window.
34 : *
35 : * The channel is the basic rendering entity. It represents a 2D rendering area
36 : * within a Window. It executes all rendering-relevant tasks, such as clear,
37 : * draw, assemble and readback. Each rendering task is using its own
38 : * RenderContext, which is computed by the server based on the rendering
39 : * description of the current configuration.
40 : *
41 : * @sa fabric::Channel
42 : */
43 : class Channel : public fabric::Channel< Window, Channel >
44 : {
45 : public:
46 : /** Construct a new channel. @version 1.0 */
47 : EQ_API explicit Channel( Window* parent );
48 :
49 : /** Destruct the channel. @version 1.0 */
50 : EQ_API virtual ~Channel();
51 :
52 : /** @name Data Access */
53 : //@{
54 : EQ_API co::CommandQueue* getPipeThreadQueue(); //!< @internal
55 : EQ_API co::CommandQueue* getCommandThreadQueue(); //!< @internal
56 : EQ_API uint32_t getCurrentFrame() const; //!< @internal render thr only
57 :
58 : /** @internal */
59 : bool waitFrameFinished( uint32_t frame, uint32_t timeout ) const;
60 :
61 : /**
62 : * @return true if this channel is stopped, false otherwise.
63 : * @version 1.0
64 : */
65 : EQ_API bool isStopped() const;
66 :
67 : /** @return the parent pipe. @version 1.0 */
68 : EQ_API Pipe* getPipe();
69 :
70 : /** @return the parent pipe. @version 1.0 */
71 : EQ_API const Pipe* getPipe() const;
72 :
73 : /** @return the parent node. @version 1.0 */
74 : EQ_API Node* getNode();
75 :
76 : /** @return the parent node. @version 1.0 */
77 : EQ_API const Node* getNode() const;
78 :
79 : /** @return the parent config. @version 1.0 */
80 : EQ_API Config* getConfig();
81 :
82 : /** @return the parent config. @version 1.0 */
83 : EQ_API const Config* getConfig() const;
84 :
85 : /** @return the parent server. @version 1.0 */
86 : EQ_API ServerPtr getServer();
87 :
88 : /**
89 : * Get the GLEW context for this channel.
90 : *
91 : * The GLEW context is initialized during window initialization, and
92 : * provides access to OpenGL extensions. This function does not follow the
93 : * Equalizer naming conventions, since GLEW uses a function of this name to
94 : * automatically resolve OpenGL function entry points. Therefore, any
95 : * supported GL function can be called directly from an initialized Channel.
96 : *
97 : * @return the extended OpenGL function table for the channel's OpenGL
98 : * context.
99 : * @version 1.0
100 : */
101 : EQ_API const GLEWContext* glewGetContext() const;
102 :
103 : /** @return the window's object manager instance. @version 1.0 */
104 : EQ_API util::ObjectManager& getObjectManager();
105 :
106 : /** @return the channel's drawable config. @version 1.0 */
107 : EQ_API const DrawableConfig& getDrawableConfig() const;
108 :
109 : /**
110 : * Get the channel's native view.
111 : *
112 : * This function always returns the channel's native view, no matter in
113 : * which context it is called. Only destination channels have a native view.
114 : *
115 : * @return the channel's native view, or 0 if it does not have one.
116 : * @sa getView()
117 : * @version 1.0
118 : */
119 : EQ_API View* getNativeView();
120 :
121 : /** const-version of getNativeView() @version 1.0 */
122 : EQ_API const View* getNativeView() const;
123 :
124 : /** @return a fixed unique color for this channel. @version 1.0 */
125 : EQ_API const Vector3ub& getUniqueColor() const;
126 :
127 : /** @internal Add a new statistics event for the current frame. */
128 : EQ_API void addStatistic( Event& event );
129 : //@}
130 :
131 : /**
132 : * @name Context-specific data access.
133 : *
134 : * The data returned by these methods depends on the context (callback) they
135 : * are called from, typically the data for the current rendering task. If
136 : * they are called outside of a frame task method, they return the channel's
137 : * native parameter or a placeholder value for the task decomposition
138 : * parameters.
139 : */
140 : //@{
141 : /**
142 : * @return the jitter vector for the current subpixel decomposition.
143 : * @version 1.0
144 : */
145 : EQ_API virtual Vector2f getJitter() const;
146 :
147 : /**
148 : * Get the channel's current View.
149 : *
150 : * During a frame task method, i.e., in one of the frameFoo functions, the
151 : * view is set to the view of the destination channel, that is, the channel
152 : * for which this channel is executing the rendering task. Outside of a
153 : * frame task method the native view of the channel, or 0, is returned.
154 : *
155 : * @return the channel's view, or 0 if it does not have a view.
156 : * @sa getNativeView()
157 : * @version 1.0
158 : */
159 : EQ_API View* getView();
160 :
161 : /** Const version of getView(). @version 1.0 */
162 : EQ_API const View* getView() const;
163 :
164 : /**
165 : * Returns an orthographic frustum for 2D operations on the view.
166 : *
167 : * One unit of the frustum covers one pixel on screen. The frustum is
168 : * positioned relative to the view.
169 : *
170 : * @return the 2D orthographic frustum.
171 : * @version 1.0
172 : */
173 : EQ_API Frustumf getScreenFrustum() const;
174 : //@}
175 :
176 : /**
177 : * @name Operations
178 : *
179 : * Operations are only meaningful from within certain callbacks. They are
180 : * just convenience wrappers applying context-specific data to the OpenGL
181 : * state using the context-specific data access above.
182 : */
183 : //@{
184 : /**
185 : * Apply the current rendering buffer, including the color mask.
186 : * @sa getReadBuffer() , getDrawBuffer(), getDrawBufferMask()
187 : * @version 1.0
188 : */
189 : EQ_API virtual void applyBuffer();
190 :
191 : /**
192 : * Apply the current color mask.
193 : * @sa applyBuffer(), getDrawBufferMask()
194 : * @version 1.0
195 : */
196 : EQ_API virtual void applyColorMask() const;
197 :
198 : /**
199 : * Apply the OpenGL viewport for the current rendering task.
200 : * @sa getViewport()
201 : * @version 1.0
202 : */
203 : EQ_API virtual void applyViewport() const;
204 :
205 : /**
206 : * Apply the frustum matrix for the current rendering task.
207 : *
208 : * If a sub-pixel decomposition is defined, the frustum is jittered by the
209 : * amount given by getJitter() to implement software
210 : * anti-aliasing. Applications which want to implement a different
211 : * multi-sampling algorithm, e.g., depth-of-field, have to re-implement
212 : * getJitter() or applyFrustum() accordingly.
213 : *
214 : * @sa useOrtho(), getJitter(), getSubPixel()
215 : * @version 1.0
216 : */
217 : EQ_API virtual void applyFrustum() const;
218 :
219 : /**
220 : * Apply the perspective frustum matrix for the current rendering task.
221 : * @version 1.0
222 : */
223 : EQ_API virtual void applyPerspective() const;
224 :
225 : /**
226 : * Apply the orthographic frustum matrix for the current rendering task.
227 : * @version 1.0
228 : */
229 : EQ_API virtual void applyOrtho() const;
230 :
231 : /**
232 : * Apply an orthographic frustum for pixel-based 2D operations.
233 : *
234 : * One unit of the frustum covers one pixel on screen. The frustum is
235 : * positioned relative to the view.
236 : * @version 1.0
237 : */
238 : EQ_API void applyScreenFrustum() const;
239 :
240 : /**
241 : * Apply the transformation to position the view frustum.
242 : * @version 1.0
243 : * @sa useOrtho()
244 : */
245 : EQ_API virtual void applyHeadTransform() const;
246 :
247 : /**
248 : * Apply the transformation to position the perspective view frustum.
249 : * @version 1.0
250 : */
251 : EQ_API virtual void applyPerspectiveTransform() const;
252 :
253 : /**
254 : * Apply the transformation to position the orthographic view frustum.
255 : * @version 1.0
256 : */
257 : EQ_API virtual void applyOrthoTransform() const;
258 :
259 : /**
260 : * Apply the state for pixel-based 2D overlay rendering operations.
261 : * @version 1.11
262 : */
263 : EQ_API void applyOverlayState();
264 :
265 : /**
266 : * Reset the overlay state setup by applyOverlayState()
267 : * @version 1.11
268 : */
269 : EQ_API void resetOverlayState();
270 :
271 : /**
272 : * Rebind the window frame buffer.
273 : * @version 1.0
274 : */
275 : EQ_API void bindFrameBuffer();
276 :
277 : /**
278 : * Rebind the window draw buffer.
279 : * @version 1.9
280 : */
281 : EQ_API void bindDrawFrameBuffer();
282 : //@}
283 :
284 : /** @name Region of Interest. */
285 : //@{
286 : /**
287 : * Reset the declared regions of interest.
288 : *
289 : * Called from frameStart and frameClear to reset the area to be used to
290 : * optimize compositing and load balancing for each frame.
291 : * @version 1.3
292 : */
293 : EQ_API virtual void resetRegions();
294 :
295 : /**
296 : * Declare a region covered by the current draw or assemble operation.
297 : *
298 : * The region is relative to the current pixel viewport. It is clipped
299 : * against the current pixel viewport of the channel. Called with the full
300 : * pixel viewport after frameDraw if no region has been declared.
301 : *
302 : * Declaring a single, empty region causes this channel to not read back any
303 : * pixel data, i.e., if it did not draw anything.
304 : *
305 : * The implementation might merge or split the declared regions.
306 : *
307 : * @version 1.3
308 : */
309 : EQ_API virtual void declareRegion( const eq::PixelViewport& region );
310 :
311 : /**
312 : * Convenience method to declare a region in relative coordinates.
313 : *
314 : * The given viewport is relative to the current pixel viewport.
315 : * @version 1.3
316 : */
317 : EQ_API void declareRegion( const eq::Viewport& vp );
318 :
319 : /** @return a region covering all declared regions. @version 1.3 */
320 : EQ_API PixelViewport getRegion() const;
321 :
322 : /**
323 : * Get the current regions of interest.
324 : *
325 : * The returned regions are guaranteed not to overlap with each
326 : * other. Therefore they may differ in number and size from the declared
327 : * regions. The actual algorithm to create the non-overlapping regions is
328 : * unspecified and may change in the future.
329 : *
330 : * @return current regions of interest.
331 : * @version 1.3
332 : */
333 : EQ_API const PixelViewports& getRegions() const;
334 : //@}
335 :
336 : /** @name Events */
337 : //@{
338 : /**
339 : * Send a channel error event to the application node.
340 : *
341 : * @param error the error code.
342 : * @version 1.7.1
343 : */
344 : EQ_API EventOCommand sendError( const uint32_t error );
345 :
346 : /**
347 : * Process a received event.
348 : *
349 : * The task of this method is to update the channel as necessary, and
350 : * transform the event into a config event to be send to the application
351 : * using Config::sendEvent().
352 : *
353 : * @param event the received event.
354 : * @return true when the event was handled, false if not.
355 : * @version 1.0
356 : */
357 : EQ_API virtual bool processEvent( const Event& event );
358 : //@}
359 :
360 : /** Draw a statistics overlay. @version 1.0 */
361 : EQ_API virtual void drawStatistics();
362 :
363 : /** Outline the current pixel viewport. @version 1.0 */
364 : EQ_API virtual void outlineViewport();
365 :
366 : /**
367 : * @internal
368 : * Change the latency.
369 : *
370 : * @param latency the new latency.
371 : */
372 : void changeLatency( const uint32_t latency );
373 :
374 : /**
375 : * Add a listener that gets notified everytime a new frame was rendered for
376 : * a destination channel.
377 : *
378 : * The channel does not take ownership of the listener. The notification
379 : * always happens in the render thread.
380 : *
381 : * @param listener the new listener to add
382 : * @version 1.9
383 : */
384 : EQ_API void addResultImageListener( ResultImageListener* listener );
385 :
386 : /**
387 : * Remove a result image listener to stop receival of notifications on new
388 : * images.
389 : *
390 : * @param listener the new listener to remove
391 : * @version 1.9
392 : */
393 : EQ_API void removeResultImageListener( ResultImageListener* listener );
394 :
395 : /**
396 : * @return filename for image if SATTR_DUMP_IMAGE,
397 : * default "getCurrentFrame().rgb"
398 : * @version 1.9
399 : */
400 : EQ_API virtual std::string getDumpImageFileName() const;
401 :
402 : protected:
403 : /** @internal */
404 : EQ_API void attach( const uint128_t& id, const uint32_t instanceID );
405 :
406 : /** @name Actions */
407 : //@{
408 : /**
409 : * Start a frame by unlocking all child resources.
410 : *
411 : * @param frameNumber the frame to start.
412 : * @version 1.0
413 : */
414 : EQ_API void startFrame( const uint32_t frameNumber );
415 :
416 : /**
417 : * Signal the completion of a frame to the parent.
418 : *
419 : * @param frameNumber the frame to end.
420 : * @version 1.0
421 : */
422 : EQ_API void releaseFrame( const uint32_t frameNumber );
423 :
424 : /**
425 : * Release the local synchronization of the parent for a frame.
426 : *
427 : * @param frameNumber the frame to release.
428 : * @version 1.0
429 : */
430 : EQ_API void releaseFrameLocal( const uint32_t frameNumber );
431 :
432 : /**
433 : * Setup the OpenGL state for a readback or assemble operation.
434 : *
435 : * The default implementation is very conservative and saves any state
436 : * which is potentially changed by the assembly routines. Applications
437 : * may overwrite this and resetAssemblyState() to optimize performance
438 : * in accordance with their rendering code.
439 : *
440 : * @version 1.0
441 : */
442 : EQ_API virtual void setupAssemblyState();
443 :
444 : /** Reset the OpenGL state after an assembly operation. @version 1.0 */
445 : EQ_API virtual void resetAssemblyState();
446 : //@}
447 :
448 : /**
449 : * @name Task Methods
450 : *
451 : * The task methods (callbacks) are called by Equalizer during rendering
452 : * to execute various rendering tasks. Each task method has a useful
453 : * default implementation, but at least frameDraw() is implemented by an
454 : * application.
455 : */
456 : //@{
457 : /**
458 : * Initialize this channel.
459 : *
460 : * @param initID the init identifier.
461 : * @version 1.0
462 : */
463 : EQ_API virtual bool configInit( const uint128_t& initID );
464 :
465 : /** Exit this channel. @version 1.0 */
466 : EQ_API virtual bool configExit();
467 :
468 : /**
469 : * Start rendering a frame.
470 : *
471 : * Called once at the beginning of each frame, to do per-frame updates
472 : * of channel-specific data. This method has to call startFrame().
473 : *
474 : * @param frameID the per-frame identifier.
475 : * @param frameNumber the frame to start.
476 : * @sa Config::startFrame()
477 : * @version 1.0
478 : */
479 : EQ_API virtual void frameStart( const uint128_t& frameID,
480 : const uint32_t frameNumber );
481 :
482 : /**
483 : * Finish rendering a frame.
484 : *
485 : * Called once at the end of each frame, to do per-frame updates of
486 : * channel-specific data. This method has to call releaseFrame().
487 : *
488 : * @param frameID the per-frame identifier.
489 : * @param frameNumber the frame to finish.
490 : * @version 1.0
491 : */
492 : EQ_API virtual void frameFinish( const uint128_t& frameID,
493 : const uint32_t frameNumber );
494 :
495 : /**
496 : * Finish drawing.
497 : *
498 : * Called once per frame after the last draw operation. Typically
499 : * releases the local node thread synchronization for this frame.
500 : *
501 : * @param frameID the per-frame identifier.
502 : * @param frameNumber the frame to finished with draw.
503 : * @version 1.0
504 : */
505 : EQ_API virtual void frameDrawFinish( const uint128_t& frameID,
506 : const uint32_t frameNumber );
507 :
508 : /**
509 : * Clear the frame buffer.
510 : *
511 : * Called 0 to n times during one frame.
512 : *
513 : * @param frameID the per-frame identifier.
514 : * @version 1.0
515 : */
516 : EQ_API virtual void frameClear( const uint128_t& frameID );
517 :
518 : /**
519 : * Draw the scene.
520 : *
521 : * Called 0 to n times during one frame.
522 : *
523 : * @param frameID the per-frame identifier.
524 : * @version 1.0
525 : */
526 : EQ_API virtual void frameDraw( const uint128_t& frameID );
527 :
528 : /**
529 : * Assemble all input frames.
530 : *
531 : * Called 0 to n times during one frame.
532 : *
533 : * @param frameID the per-frame identifier.
534 : * @param frames the input frames.
535 : * @version 1.7.3
536 : */
537 : EQ_API virtual void frameAssemble( const uint128_t& frameID,
538 : const Frames& frames );
539 :
540 : /**
541 : * Read back the rendered frame buffer into the output frames.
542 : *
543 : * Called 0 to n times during one frame.
544 : *
545 : * @param frameID the per-frame identifier.
546 : * @param frames the output frames.
547 : * @version 1.7.3
548 : * @version 1.0
549 : */
550 : EQ_API virtual void frameReadback( const uint128_t& frameID,
551 : const Frames& frames );
552 :
553 : /**
554 : * Start updating a destination channel.
555 : *
556 : * Called once for each destination channel's eye pass, after frameStart()
557 : * to update a part of a display. Destination channels are the final display
558 : * channels, e.g., channels which are defined by a view/segment
559 : * intersection.
560 : *
561 : * @param frameID the per-frame identifier.
562 : * @version 1.0
563 : */
564 : EQ_API virtual void frameViewStart( const uint128_t& frameID );
565 :
566 : /**
567 : * Finish updating a destination channel.
568 : *
569 : * Called once for each destination channel's eye pass, before frameFinish()
570 : * to update a part of a display. Destination channels are the final display
571 : * channels, e.g., channels which are defined by a view/segment
572 : * intersection.
573 : *
574 : * This is typically used to do operations on the output channel after
575 : * it has been fully updated, e.g., to draw a 2D overlay or to perform
576 : * post-processing on the rendered image.
577 : *
578 : * @param frameID the per-frame identifier.
579 : * @version 1.0
580 : */
581 : EQ_API virtual void frameViewFinish( const uint128_t& frameID );
582 :
583 : /**
584 : * Draw 2D overlay content on a destination channel.
585 : *
586 : * This is called by frameViewFinish().
587 : *
588 : * @param frameID the per-frame identifier.
589 : * @version 1.11
590 : */
591 : EQ_API virtual void frameDrawOverlay( const uint128_t& frameID );
592 : //@}
593 :
594 : /** Start a batch of tile rendering operations. @version 1.1.6 */
595 0 : virtual void frameTilesStart( const uint128_t& /*frameID*/ ) {}
596 :
597 : /** Finish a batch of tile rendering operations. @version 1.1.6 */
598 0 : virtual void frameTilesFinish( const uint128_t& /*frameID*/ ) {}
599 :
600 : /** Notification that parameters influencing the vp/pvp have changed.*/
601 : EQ_API virtual void notifyViewportChanged();
602 :
603 : /**
604 : * Notify interruption of the rendering.
605 : *
606 : * This method is called from the Client command thread, as opposed to the
607 : * rendering thread. Its purpose is to cause the rendering thread to stop
608 : * its operations as soon as possible. Normal rendering shall recommence
609 : * after the given frame.
610 : *
611 : * @param lastFrameNumber stop rendering until this frame has been
612 : * processed.
613 : * @version 1.0
614 : */
615 : EQ_API virtual void notifyStopFrame( const uint32_t lastFrameNumber );
616 :
617 : private:
618 : detail::Channel* const _impl;
619 : friend class fabric::Window< Pipe, Window, Channel, WindowSettings >;
620 :
621 : //-------------------- Methods --------------------
622 : /** Setup the current rendering context. */
623 : void _overrideContext( RenderContext& context );
624 :
625 : /** Initialize the channel's drawable config. */
626 : void _initDrawableConfig();
627 :
628 : /** Tile render loop. */
629 : void _frameTiles( RenderContext& context, const bool isLocal,
630 : const uint128_t& queueID, const uint32_t tasks,
631 : const co::ObjectVersions& frames );
632 :
633 : /** Reference the frame for an async operation. */
634 : void _refFrame( const uint32_t frameNumber );
635 :
636 : /** Check for and send frame finish reply. */
637 : void _unrefFrame( const uint32_t frameNumber );
638 :
639 : /** Transmit one image of a frame to one node. */
640 : void _transmitImage( const co::ObjectVersion& frameDataVersion,
641 : const uint128_t& nodeID,
642 : const co::NodeID& netNodeID,
643 : const uint64_t imageIndex,
644 : const uint32_t frameNumber,
645 : const uint32_t taskID );
646 :
647 : void _frameReadback( const uint128_t& frameID,
648 : const co::ObjectVersions& frames );
649 : void _finishReadback( const co::ObjectVersion& frameDataVersion,
650 : const uint64_t imageIndex,
651 : const uint32_t frameNumber,
652 : const uint32_t taskID,
653 : const std::vector< uint128_t >& nodes,
654 : const co::NodeIDs& netNodes );
655 :
656 : bool _asyncFinishReadback( const std::vector< size_t >& imagePos,
657 : const Frames& frames );
658 :
659 : void _asyncTransmit( FrameDataPtr frame, const uint32_t frameNumber,
660 : const uint64_t image,
661 : const std::vector< uint128_t >& nodes,
662 : const co::NodeIDs& netNodes,
663 : const uint32_t taskID );
664 :
665 : void _setReady( const bool async, detail::RBStat* stat,
666 : const Frames& frames );
667 : void _asyncSetReady( const FrameDataPtr frame, detail::RBStat* stat,
668 : const std::vector< uint128_t >& nodes,
669 : const co::NodeIDs& netNodes );
670 :
671 : void _setReady( FrameDataPtr frame, detail::RBStat* stat,
672 : const std::vector< uint128_t >& nodes,
673 : const co::NodeIDs& netNodes );
674 :
675 : /** Getsthe channel's current input queue. */
676 : co::QueueSlave* _getQueue( const uint128_t& queueID );
677 :
678 : Frames _getFrames( const co::ObjectVersions& frameIDs,
679 : const bool isOutput );
680 :
681 : void _createTransferWindow();
682 : void _deleteTransferWindow();
683 :
684 : /* The command handler functions. */
685 : bool _cmdConfigInit( co::ICommand& command );
686 : bool _cmdConfigExit( co::ICommand& command );
687 : bool _cmdFrameStart( co::ICommand& command );
688 : bool _cmdFrameFinish( co::ICommand& command );
689 : bool _cmdFrameClear( co::ICommand& command );
690 : bool _cmdFrameDraw( co::ICommand& command );
691 : bool _cmdFrameDrawFinish( co::ICommand& command );
692 : bool _cmdFrameAssemble( co::ICommand& command );
693 : bool _cmdFrameReadback( co::ICommand& command );
694 : bool _cmdFinishReadback( co::ICommand& command );
695 : bool _cmdFrameSetReady( co::ICommand& command );
696 : bool _cmdFrameTransmitImage( co::ICommand& command );
697 : bool _cmdFrameSetReadyNode( co::ICommand& command );
698 : bool _cmdFrameViewStart( co::ICommand& command );
699 : bool _cmdFrameViewFinish( co::ICommand& command );
700 : bool _cmdStopFrame( co::ICommand& command );
701 : bool _cmdFrameTiles( co::ICommand& command );
702 : bool _cmdDeleteTransferWindow( co::ICommand& command );
703 :
704 812 : LB_TS_VAR( _pipeThread );
705 : };
706 : }
707 :
708 : #endif // EQ_CHANNEL_H
|