"Fossies" - the Fresh Open Source Software Archive

Member "audacious-3.10.1/src/libaudcore/vis-runner.cc" (26 Dec 2018, 6251 Bytes) of package /linux/misc/audacious-3.10.1.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "vis-runner.cc" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 3.9_vs_3.10.

    1 /*
    2  * vis_runner.c
    3  * Copyright 2009-2012 John Lindgren
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions are met:
    7  *
    8  * 1. Redistributions of source code must retain the above copyright notice,
    9  *    this list of conditions, and the following disclaimer.
   10  *
   11  * 2. Redistributions in binary form must reproduce the above copyright notice,
   12  *    this list of conditions, and the following disclaimer in the documentation
   13  *    provided with the distribution.
   14  *
   15  * This software is provided "as is" and without any warranty, express or
   16  * implied. In no event shall the authors be liable for any damages arising from
   17  * the use of this software.
   18  */
   19 
   20 #include "internal.h"
   21 
   22 #include <assert.h>
   23 #include <pthread.h>
   24 #include <stdint.h>
   25 #include <string.h>
   26 
   27 #include "hook.h"
   28 #include "list.h"
   29 #include "mainloop.h"
   30 #include "output.h"
   31 
   32 #define INTERVAL 33 /* milliseconds */
   33 #define FRAMES_PER_NODE 512
   34 
   35 struct VisNode : public ListNode
   36 {
   37     VisNode (int channels, int time) :
   38         channels (channels),
   39         time (time),
   40         data (new float[channels * FRAMES_PER_NODE]) {}
   41 
   42     ~VisNode ()
   43         { delete[] data; }
   44 
   45     const int channels;
   46     int time;
   47     float * data;
   48 };
   49 
   50 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
   51 static bool enabled = false;
   52 static bool playing = false, paused = false;
   53 static VisNode * current_node = nullptr;
   54 static int current_frames;
   55 static List<VisNode> vis_list;
   56 static List<VisNode> vis_pool;
   57 static QueuedFunc queued_clear;
   58 
   59 static void send_audio (void *)
   60 {
   61     /* call before locking mutex to avoid deadlock */
   62     int outputted = output_get_raw_time ();
   63 
   64     pthread_mutex_lock (& mutex);
   65 
   66     if (! enabled || ! playing || paused)
   67     {
   68         pthread_mutex_unlock (& mutex);
   69         return;
   70     }
   71 
   72     VisNode * node = nullptr;
   73     VisNode * next;
   74 
   75     while ((next = vis_list.head ()))
   76     {
   77         /* If we are considering a node, stop searching and use it if it is the
   78          * most recent (that is, the next one is in the future).  Otherwise,
   79          * consider the next node if it is not in the future by more than the
   80          * length of an interval. */
   81         if (next->time > outputted + (node ? 0 : INTERVAL))
   82             break;
   83 
   84         if (node)
   85             vis_pool.prepend (node);
   86 
   87         node = next;
   88         vis_list.remove (node);
   89     }
   90 
   91     pthread_mutex_unlock (& mutex);
   92 
   93     if (! node)
   94         return;
   95 
   96     vis_send_audio (node->data, node->channels);
   97 
   98     pthread_mutex_lock (& mutex);
   99     vis_pool.prepend (node);
  100     pthread_mutex_unlock (& mutex);
  101 }
  102 
  103 static void send_clear (void *)
  104 {
  105     vis_send_clear ();
  106 }
  107 
  108 static void flush_locked ()
  109 {
  110     delete current_node;
  111     current_node = nullptr;
  112 
  113     vis_list.clear ();
  114     vis_pool.clear ();
  115 
  116     if (enabled)
  117         queued_clear.queue (send_clear, nullptr);
  118 }
  119 
  120 void vis_runner_flush ()
  121 {
  122     pthread_mutex_lock (& mutex);
  123     flush_locked ();
  124     pthread_mutex_unlock (& mutex);
  125 }
  126 
  127 static void start_stop_locked (bool new_playing, bool new_paused)
  128 {
  129     playing = new_playing;
  130     paused = new_paused;
  131 
  132     queued_clear.stop ();
  133 
  134     if (! enabled || ! playing)
  135         flush_locked ();
  136 
  137     if (enabled && playing && ! paused)
  138         timer_add (TimerRate::Hz30, send_audio);
  139     else
  140         timer_remove (TimerRate::Hz30, send_audio);
  141 }
  142 
  143 void vis_runner_start_stop (bool new_playing, bool new_paused)
  144 {
  145     pthread_mutex_lock (& mutex);
  146     start_stop_locked (new_playing, new_paused);
  147     pthread_mutex_unlock (& mutex);
  148 }
  149 
  150 void vis_runner_pass_audio (int time, const Index<float> & data, int channels, int rate)
  151 {
  152     pthread_mutex_lock (& mutex);
  153 
  154     if (! enabled || ! playing)
  155     {
  156         pthread_mutex_unlock (& mutex);
  157         return;
  158     }
  159 
  160     /* We can build a single node from multiple calls; we can also build
  161      * multiple nodes from the same call.  If current_node is present, it was
  162      * partly built in the last call and needs to be finished. */
  163 
  164     int at = 0;
  165 
  166     while (1)
  167     {
  168         if (current_node)
  169             assert (current_node->channels == channels);
  170         else
  171         {
  172             int node_time = time;
  173 
  174             /* There is no partly-built node, so start a new one.  Normally
  175              * there will be nodes in the queue already; if so, we want to copy
  176              * audio data from the signal starting at 30 milliseconds after the
  177              * beginning of the most recent node.  If there are no nodes in the
  178              * queue, we are at the beginning of the song or had an underrun,
  179              * and we want to copy the earliest audio data we have. */
  180 
  181             VisNode * tail = vis_list.tail ();
  182             if (tail)
  183                 node_time = tail->time + INTERVAL;
  184 
  185             at = channels * (int) ((int64_t) (node_time - time) * rate / 1000);
  186 
  187             if (at < 0)
  188                 at = 0;
  189             if (at >= data.len ())
  190                 break;
  191 
  192             current_node = vis_pool.head ();
  193 
  194             if (current_node)
  195             {
  196                 assert (current_node->channels == channels);
  197                 vis_pool.remove (current_node);
  198                 current_node->time = node_time;
  199             }
  200             else
  201                 current_node = new VisNode (channels, node_time);
  202 
  203             current_frames = 0;
  204         }
  205 
  206         /* Copy as much data as we can, limited by how much we have and how much
  207          * space is left in the node.  If we cannot fill the node, we return and
  208          * wait for more data to be passed in the next call.  If we do fill the
  209          * node, we loop and start building a new one. */
  210 
  211         int copy = aud::min (data.len () - at, channels * (FRAMES_PER_NODE - current_frames));
  212         memcpy (current_node->data + channels * current_frames, & data[at], sizeof (float) * copy);
  213         current_frames += copy / channels;
  214 
  215         if (current_frames < FRAMES_PER_NODE)
  216             break;
  217 
  218         vis_list.append (current_node);
  219         current_node = nullptr;
  220     }
  221 
  222     pthread_mutex_unlock (& mutex);
  223 }
  224 
  225 void vis_runner_enable (bool enable)
  226 {
  227     pthread_mutex_lock (& mutex);
  228     enabled = enable;
  229     start_stop_locked (playing, paused);
  230     pthread_mutex_unlock (& mutex);
  231 }