streamvolume.c 6.75 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
/* GStreamer Mixer
 * Copyright (C) 2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

/**
 * SECTION:gststreamvolume
 * @short_description: Interface for elements that provide a stream volume
 *
 * <refsect2>
 * <para>
 * This interface is implemented by elements that provide a stream volume. Examples for
 * such elements are #volume and #playbin2.
 * </para>
 * <para>
 * Applications can use this interface to get or set the current stream volume. For this
 * the "volume" #GObject property can be used or the helper functions gst_stream_volume_set_volume()
 * and gst_stream_volume_get_volume(). This volume is always a linear factor, i.e. 0.0 is muted
 * 1.0 is 100%. For showing the volume in a GUI it might make sense to convert it to
 * a different format by using gst_stream_volume_convert_volume(). Volume sliders should usually
 * use a cubic volume.
 *
 * Separate from the volume the stream can also be muted by the "mute" #GObject property or
 * gst_stream_volume_set_mute() and gst_stream_volume_get_mute().
 * </para>
 * <para>
 * Elements that provide some kind of stream volume should implement the "volume" and
 * "mute" #GObject properties and handle setting and getting of them properly.
 * The volume property is defined to be a linear volume factor.
 * </para>
 * </refsect2>
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "streamvolume.h"
#include <math.h>

55
56
57
58
#ifndef HAVE_CBRT
#define cbrt(x) (pow(abs(x),1.0/3.0))
#endif

59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
static void
gst_stream_volume_class_init (GstStreamVolumeInterface * iface)
{
  g_object_interface_install_property (iface,
      g_param_spec_double ("volume",
          "Volume",
          "Linear volume factor, 1.0=100%",
          0.0, G_MAXDOUBLE, 1.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
  g_object_interface_install_property (iface,
      g_param_spec_boolean ("mute",
          "Mute",
          "Mute the audio channel without changing the volume",
          FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
}

GType
gst_stream_volume_get_type (void)
{
  static volatile gsize type = 0;
  if (g_once_init_enter (&type)) {
    GType tmp;
    static const GTypeInfo info = {
      sizeof (GstStreamVolumeInterface),
      NULL,                     /* base_init */
      NULL,                     /* base_finalize */
      (GClassInitFunc) gst_stream_volume_class_init,    /* class_init */
      NULL,                     /* class_finalize */
      NULL,                     /* class_data */
      0,
      0,                        /* n_preallocs */
      NULL                      /* instance_init */
    };
    tmp = g_type_register_static (G_TYPE_INTERFACE,
        "GstStreamVolume", &info, 0);
    g_type_interface_add_prerequisite (tmp, G_TYPE_OBJECT);

    g_once_init_leave (&type, tmp);
  }
  return type;
}

/**
 * gst_stream_volume_get_volume:
 * @volume: #GstStreamVolume that should be used
 * @format: #GstStreamVolumeFormat which should be returned
 *
 * Returns: The current stream volume as linear factor
 *
 * Since: 0.10.25
 */
gdouble
gst_stream_volume_get_volume (GstStreamVolume * volume,
    GstStreamVolumeFormat format)
{
  gdouble val;

  g_return_val_if_fail (GST_IS_STREAM_VOLUME (volume), 1.0);

  g_object_get (volume, "volume", &val, NULL);
  if (format != GST_STREAM_VOLUME_FORMAT_LINEAR)
    val =
        gst_stream_volume_convert_volume (GST_STREAM_VOLUME_FORMAT_LINEAR,
        format, val);
  return val;
}

/**
 * gst_stream_volume_set_volume:
 * @volume: #GstStreamVolume that should be used
 * @format: #GstStreamVolumeFormat of @val
 * @val: Linear volume factor that should be set
 *
 * Since: 0.10.25
 */
void
gst_stream_volume_set_volume (GstStreamVolume * volume,
    GstStreamVolumeFormat format, gdouble val)
{
  g_return_if_fail (GST_IS_STREAM_VOLUME (volume));

  if (format != GST_STREAM_VOLUME_FORMAT_LINEAR)
    val =
        gst_stream_volume_convert_volume (format,
        GST_STREAM_VOLUME_FORMAT_LINEAR, val);
  g_object_set (volume, "volume", val, NULL);
}

/**
 * gst_stream_volume_get_mute:
 * @volume: #GstStreamVolume that should be used
 *
 * Returns: Returns %TRUE if the stream is muted
 *
 * Since: 0.10.25
 */
gboolean
gst_stream_volume_get_mute (GstStreamVolume * volume)
{
  gboolean val;

  g_return_val_if_fail (GST_IS_STREAM_VOLUME (volume), FALSE);

  g_object_get (volume, "mute", &val, NULL);
  return val;
}

/**
 * gst_stream_volume_set_mute:
 * @volume: #GstStreamVolume that should be used
 * @mute: Mute state that should be set
 *
 * Since: 0.10.25
 */
void
gst_stream_volume_set_mute (GstStreamVolume * volume, gboolean mute)
{
  g_return_if_fail (GST_IS_STREAM_VOLUME (volume));

  g_object_set (volume, "mute", mute, NULL);
}

/**
 * gst_stream_volume_convert_volume:
 * @from: #GstStreamVolumeFormat to convert from
 * @to: #GstStreamVolumeFormat to convert to
 * @val: Volume in @from format that should be converted
 *
 * Returns: the converted volume
 *
 * Since: 0.10.25
 */
gdouble
gst_stream_volume_convert_volume (GstStreamVolumeFormat from,
    GstStreamVolumeFormat to, gdouble val)
{
  switch (from) {
    case GST_STREAM_VOLUME_FORMAT_LINEAR:
      g_return_val_if_fail (val >= 0.0, 0.0);
      switch (to) {
        case GST_STREAM_VOLUME_FORMAT_LINEAR:
          return val;
        case GST_STREAM_VOLUME_FORMAT_CUBIC:
          return cbrt (val);
        case GST_STREAM_VOLUME_FORMAT_DB:
          return 20.0 * log10 (val);
      }
      break;
    case GST_STREAM_VOLUME_FORMAT_CUBIC:
      g_return_val_if_fail (val >= 0.0, 0.0);
      switch (to) {
        case GST_STREAM_VOLUME_FORMAT_LINEAR:
          return val * val * val;
        case GST_STREAM_VOLUME_FORMAT_CUBIC:
          return val;
        case GST_STREAM_VOLUME_FORMAT_DB:
          return 3.0 * 20.0 * log10 (val);
      }
      break;
    case GST_STREAM_VOLUME_FORMAT_DB:
      switch (to) {
        case GST_STREAM_VOLUME_FORMAT_LINEAR:
          return pow (10.0, val / 20.0);
        case GST_STREAM_VOLUME_FORMAT_CUBIC:
          return pow (10.0, val / (3.0 * 20.0));
        case GST_STREAM_VOLUME_FORMAT_DB:
          return val;
      }
      break;
  }
  g_return_val_if_reached (0.0);
}