aboutsummaryrefslogtreecommitdiff
path: root/src/plugins/wav_extractor.c
blob: dae889078f63034abe6a5fd5e2ed46dcb0ee7268 (plain) (blame)
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
55
56
57
58
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
/*
     This file is part of libextractor.
     Copyright (C) 2004, 2009, 2012 Vidyut Samanta and Christian Grothoff

     libextractor is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published
     by the Free Software Foundation; either version 3, or (at your
     option) any later version.

     libextractor 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
     General Public License for more details.

     You should have received a copy of the GNU General Public License
     along with libextractor; see the file COPYING.  If not, write to the
     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     Boston, MA 02110-1301, USA.

     This code was based on bitcollider 0.6.0
     (PD) 2004 The Bitzi Corporation
     http://bitzi.com/
     (PD) 2001 The Bitzi Corporation
     Please see file COPYING or http://bitzi.com/publicdomain
     for more info.
*/
/**
 * @file plugins/wav_extractor.c
 * @brief plugin to support WAV files
 * @author Christian Grothoff
 */

#include "platform.h"
#include "extractor.h"


#if BIG_ENDIAN_HOST
static uint16_t
little_endian_to_host16 (uint16_t in)
{
  unsigned char *ptr = (unsigned char *) ∈

  return ((ptr[1] & 0xFF) << 8) | (ptr[0] & 0xFF);
}


static uint32_t
little_endian_to_host32 (uint32_t in)
{
  unsigned char *ptr = (unsigned char *) &in;

  return ((ptr[3] & 0xFF) << 24) | ((ptr[2] & 0xFF) << 16) |
    ((ptr[1] & 0xFF) << 8) | (ptr[0] & 0xFF);
}
#endif


/**
 * Extract information from WAV files.
 *
 * @param ec extraction context
 *
 * @detail
 * A WAV header looks as follows:
 *
 * Offset  Value    meaning
 * 16      4 bytes  0x00000010     // Length of the fmt data (16 bytes)
 * 20      2 bytes  0x0001         // Format tag: 1 = PCM
 * 22      2 bytes  <channels>     // Channels: 1 = mono, 2 = stereo
 * 24      4 bytes  <sample rate>  // Samples per second: e.g., 44100
 */
void
EXTRACTOR_wav_extract_method (struct EXTRACTOR_ExtractContext *ec)
{
  void *data;
  const unsigned char *buf;
  uint16_t channels;
  uint16_t sample_size;
  uint32_t sample_rate;
  uint32_t data_len;
  uint32_t samples;
  char scratch[256];

  if (44 >
      ec->read (ec->cls,  &data, 44))
    return;
  buf = data;
  if ((buf[0] != 'R' || buf[1] != 'I' ||
       buf[2] != 'F' || buf[3] != 'F' ||
       buf[8] != 'W' || buf[9] != 'A' ||
       buf[10] != 'V' || buf[11] != 'E' ||
       buf[12] != 'f' || buf[13] != 'm' || buf[14] != 't' || buf[15] != ' '))
    return;                /* not a WAV file */

  channels = *((uint16_t *) &buf[22]);
  sample_rate = *((uint32_t *) &buf[24]);
  sample_size = *((uint16_t *) &buf[34]);
  data_len = *((uint32_t *) &buf[40]);

#if BIG_ENDIAN_HOST
  channels = little_endian_to_host16 (channels);
  sample_size = little_endian_to_host16 (sample_size);
  sample_rate = little_endian_to_host32 (sample_rate);
  data_len = little_endian_to_host32 (data_len);
#endif

  if ( (8 != sample_size) &&
       (16 != sample_size) )
    return;                /* invalid sample size found in wav file */
  if (0 == channels)
    return;                /* invalid channels value -- avoid division by 0! */
  if (0 == sample_rate)
    return;                /* invalid sample_rate */
  samples = data_len / (channels * (sample_size >> 3));

  snprintf (scratch,
            sizeof (scratch),
            "%u ms, %d Hz, %s",
            (samples < sample_rate)
            ? (samples * 1000 / sample_rate)
            : (samples / sample_rate) * 1000,
            sample_rate, (1 == channels) ? _("mono") : _("stereo"));
  if (0 != ec->proc (ec->cls,
		     "wav",
		     EXTRACTOR_METATYPE_RESOURCE_TYPE,
		     EXTRACTOR_METAFORMAT_UTF8,
		     "text/plain",
		     scratch,
		     strlen (scratch) + 1))
    return;
  if (0 != ec->proc (ec->cls,
		     "wav",
		     EXTRACTOR_METATYPE_MIMETYPE,
		     EXTRACTOR_METAFORMAT_UTF8,
		     "text/plain",
		     "audio/x-wav",
		     strlen ("audio/x-wav") +1 ))
    return;
}

/* end of wav_extractor.c */