hornetseye-alsa 1.1.2 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -7,7 +7,7 @@ require 'rake/loaders/makefile'
7
7
  require 'rbconfig'
8
8
 
9
9
  PKG_NAME = 'hornetseye-alsa'
10
- PKG_VERSION = '1.1.2'
10
+ PKG_VERSION = '1.2.0'
11
11
  CFG = RbConfig::CONFIG
12
12
  CXX = ENV[ 'CXX' ] || 'g++'
13
13
  RB_FILES = FileList[ 'lib/**/*.rb' ]
data/ext/alsainput.cc CHANGED
@@ -1,5 +1,5 @@
1
1
  /* HornetsEye - Computer Vision with Ruby
2
- Copyright (C) 2006, 2007, 2008, 2009, 2010 Jan Wedekind
2
+ Copyright (C) 2012 Jan Wedekind
3
3
 
4
4
  This program is free software: you can redistribute it and/or modify
5
5
  it under the terms of the GNU General Public License as published by
@@ -19,16 +19,17 @@ using namespace std;
19
19
 
20
20
  VALUE AlsaInput::cRubyClass = Qnil;
21
21
 
22
- AlsaInput::AlsaInput( const string &pcmName, unsigned int rate,
23
- unsigned int channels, int periods,
24
- snd_pcm_uframes_t frames ) throw (Error):
25
- m_pcmHandle(NULL), m_pcmName( pcmName ), m_rate( rate ), m_channels( channels )
22
+ AlsaInput::AlsaInput(const string &pcmName, unsigned int rate,
23
+ unsigned int channels) throw (Error):
24
+ m_pcmHandle(NULL), m_pcmName( pcmName ), m_rate( rate ), m_channels( channels ),
25
+ m_periodSize(1024), m_threadInitialised(false), m_start(0), m_count(0),
26
+ m_size(rate)
26
27
  {
27
28
  try {
28
29
  snd_pcm_hw_params_t *hwParams;
29
- snd_pcm_hw_params_alloca( &hwParams );
30
- int err = snd_pcm_open( &m_pcmHandle, m_pcmName.c_str(), SND_PCM_STREAM_CAPTURE,
31
- 0 );
30
+ snd_pcm_hw_params_alloca(&hwParams);
31
+ int err = snd_pcm_open(&m_pcmHandle, m_pcmName.c_str(), SND_PCM_STREAM_CAPTURE,
32
+ 0);
32
33
  ERRORMACRO( err >= 0, Error, , "Error opening PCM device \"" << m_pcmName
33
34
  << "\": " << snd_strerror( err ) );
34
35
  err = snd_pcm_hw_params_any( m_pcmHandle, hwParams );
@@ -48,16 +49,22 @@ AlsaInput::AlsaInput( const string &pcmName, unsigned int rate,
48
49
  err = snd_pcm_hw_params_set_channels( m_pcmHandle, hwParams, channels );
49
50
  ERRORMACRO( err >= 0, Error, , "Error setting number of channels of PCM device \""
50
51
  << m_pcmName << "\" to " << channels << ": " << snd_strerror( err ) );
51
- err = snd_pcm_hw_params_set_periods( m_pcmHandle, hwParams, periods, 0 );
52
- ERRORMACRO( err >= 0, Error, , "Error setting number of periods of PCM device \""
53
- << m_pcmName << "\" to " << periods << ": " << snd_strerror( err ) );
54
- err = snd_pcm_hw_params_set_buffer_size_near( m_pcmHandle, hwParams, &frames );
55
- ERRORMACRO( err >= 0, Error, , "Error setting buffer size of PCM device \""
56
- << m_pcmName << "\" to " << frames << " frames: "
57
- << snd_strerror( err ) );
52
+ unsigned int bufferTime = 500000;
53
+ err = snd_pcm_hw_params_set_buffer_time_near(m_pcmHandle, hwParams, &bufferTime, NULL);
54
+ ERRORMACRO(err >= 0, Error, , "Error setting buffer time of PCM device \""
55
+ << m_pcmName << "\" to " << bufferTime << " us: " << snd_strerror(err));
56
+ unsigned int periods = 16;
57
+ err = snd_pcm_hw_params_set_periods_near(m_pcmHandle, hwParams, &periods, NULL);
58
+ ERRORMACRO(err >= 0, Error, , "Error setting periods of PCM device \""
59
+ << m_pcmName << "\" to " << periods << ": " << snd_strerror(err));
58
60
  err = snd_pcm_hw_params( m_pcmHandle, hwParams );
59
61
  ERRORMACRO( err >= 0, Error, , "Error setting parameters of PCM device \""
60
62
  << m_pcmName << "\": " << snd_strerror( err ) );
63
+ err = snd_pcm_hw_params_get_period_size(hwParams, &m_periodSize, NULL);
64
+ ERRORMACRO( err >= 0, Error, , "Error getting period size of PCM device \""
65
+ << m_pcmName << "\": " << snd_strerror( err ) );
66
+ err = pthread_mutex_init(&m_mutex, NULL);
67
+ ERRORMACRO(err == 0, Error, , "Error initialising mutex: " << strerror(err));
61
68
  } catch ( Error &e ) {
62
69
  close();
63
70
  throw e;
@@ -72,29 +79,59 @@ AlsaInput::~AlsaInput(void)
72
79
  void AlsaInput::close(void)
73
80
  {
74
81
  if ( m_pcmHandle != NULL ) {
75
- // drop();
82
+ drop();
83
+ pthread_mutex_destroy(&m_mutex);
76
84
  snd_pcm_close( m_pcmHandle );
77
85
  m_pcmHandle = NULL;
78
86
  };
79
87
  }
80
88
 
81
- SequencePtr AlsaInput::read( int samples ) throw (Error)
89
+ SequencePtr AlsaInput::read(int samples) throw (Error)
82
90
  {
83
- ERRORMACRO( m_pcmHandle != NULL, Error, , "PCM device \"" << m_pcmName
84
- << "\" is not open. Did you call \"close\" before?" );
85
- SequencePtr frame( new Sequence( (int)( samples * 2 * m_channels ) ) );
86
- int err;
87
- while ( ( err = snd_pcm_readi( m_pcmHandle, (short int *)frame->data(),
88
- samples ) ) < 0 ) {
89
- err = snd_pcm_recover( m_pcmHandle, err, 1 );
90
- ERRORMACRO( err >= 0, Error, , "Error reading audio frames from PCM device \""
91
- << m_pcmName << "\": " << snd_strerror( err ) );
91
+ ERRORMACRO(m_pcmHandle != NULL, Error, , "PCM device \"" << m_pcmName
92
+ << "\" is not open. Did you call \"close\" before?");
93
+ SequencePtr frame(new Sequence((int)(samples * 2 * m_channels)));
94
+ lock();
95
+ if (!m_data.get()) {
96
+ if (m_threadInitialised) pthread_join(m_thread, NULL);
97
+ m_data = boost::shared_array<short int>(new short int[m_size * m_channels]);
98
+ m_start = 0;
99
+ m_count = 0;
100
+ pthread_create(&m_thread, NULL, staticThreadFunc, this);
92
101
  };
93
- ERRORMACRO( samples == err, Error, , "Only managed to read " << err << " of "
94
- << samples << " frames from PCM device \"" << m_pcmName << "\"" );
102
+ int n = samples;
103
+ if (n > m_count) n = m_count;
104
+ if (m_start + n > m_size) {
105
+ memcpy(frame->data(), m_data.get() + m_start * m_channels, (m_size - m_start) * 2 * m_channels);
106
+ memcpy(frame->data() + (m_size - m_start) * 2 * m_channels, m_data.get(), (n + m_start - m_size) * 2 * m_channels);
107
+ } else
108
+ memcpy(frame->data(), m_data.get() + m_start * m_channels, n * 2 * m_channels);
109
+ m_start += n;
110
+ if (m_start >= m_size) m_start -= m_size;
111
+ m_count -= n;
112
+ if (n < samples) {
113
+ try {
114
+ readi((short int *)frame->data() + n * m_channels * 2, samples - n);
115
+ } catch (Error &e) {
116
+ unlock();
117
+ throw e;
118
+ }
119
+ }
120
+ unlock();
95
121
  return frame;
96
122
  }
97
123
 
124
+ void AlsaInput::drop(void) throw (Error)
125
+ {
126
+ ERRORMACRO( m_pcmHandle != NULL, Error, , "PCM device \"" << m_pcmName
127
+ << "\" is not open. Did you call \"close\" before?" );
128
+ lock();
129
+ m_data.reset();
130
+ m_count = 0;
131
+ snd_pcm_drop(m_pcmHandle);
132
+ unlock();
133
+ }
134
+
98
135
  unsigned int AlsaInput::rate(void)
99
136
  {
100
137
  return m_rate;
@@ -109,6 +146,7 @@ int AlsaInput::avail(void) throw (Error)
109
146
  {
110
147
  ERRORMACRO( m_pcmHandle != NULL, Error, , "PCM device \"" << m_pcmName
111
148
  << "\" is not open. Did you call \"close\" before?" );
149
+ lock();
112
150
  snd_pcm_sframes_t frames;
113
151
  int err = 0;
114
152
  while ( ( frames = snd_pcm_avail( m_pcmHandle ) ) < 0 ) {
@@ -117,22 +155,34 @@ int AlsaInput::avail(void) throw (Error)
117
155
  "retrieval from PCM device \"" << m_pcmName << "\": "
118
156
  << snd_strerror( err ) );
119
157
  };
158
+ frames += m_count;
159
+ unlock();
120
160
  return frames;
121
161
  }
122
162
 
123
- int AlsaInput::delay(void) throw (Error)
163
+ void AlsaInput::readi(short int *data, int count)
124
164
  {
125
- ERRORMACRO( m_pcmHandle != NULL, Error, , "PCM device \"" << m_pcmName
126
- << "\" is not open. Did you call \"close\" before?" );
127
- snd_pcm_sframes_t frames;
128
165
  int err;
129
- while ( ( err = snd_pcm_delay( m_pcmHandle, &frames ) ) < 0 ) {
130
- err = snd_pcm_recover( m_pcmHandle, err, 1 );
131
- ERRORMACRO( err >= 0, Error, , "Error querying number of available frames for "
132
- "capture on PCM device \"" << m_pcmName << "\": "
133
- << snd_strerror( err ) );
166
+ while ((err = snd_pcm_readi(m_pcmHandle, data, count)) < 0) {
167
+ if (err == -EBADFD)
168
+ err = snd_pcm_prepare(m_pcmHandle);
169
+ else
170
+ err = snd_pcm_recover(m_pcmHandle, err, 1);
171
+ ERRORMACRO(err >= 0, Error, , "Error reading audio frames from PCM device \""
172
+ << m_pcmName << "\": " << snd_strerror(err));
134
173
  };
135
- return frames;
174
+ ERRORMACRO(count == err, Error, , "Only managed to read " << err << " of "
175
+ << count << " frames from PCM device \"" << m_pcmName << "\"" );
176
+ }
177
+
178
+ void AlsaInput::lock(void)
179
+ {
180
+ pthread_mutex_lock( &m_mutex );
181
+ }
182
+
183
+ void AlsaInput::unlock(void)
184
+ {
185
+ pthread_mutex_unlock( &m_mutex );
136
186
  }
137
187
 
138
188
  void AlsaInput::prepare(void) throw (Error)
@@ -144,17 +194,59 @@ void AlsaInput::prepare(void) throw (Error)
144
194
  << "\": " << snd_strerror( err ) );
145
195
  }
146
196
 
197
+ void AlsaInput::threadFunc(void)
198
+ {
199
+ bool quit = false;
200
+ while (!quit) {
201
+ snd_pcm_wait(m_pcmHandle, 1000);
202
+ try {
203
+ lock();
204
+ if (m_data.get()) {
205
+ int n = m_periodSize;
206
+ if (m_count + n > m_size) {
207
+ int m_size_new = m_size;
208
+ while(m_size_new < m_count + n) m_size_new = 2 * m_size_new;
209
+ boost::shared_array<short int> data(new short int[m_size_new * m_channels]);
210
+ if (m_start + m_count > m_size) {
211
+ memcpy(data.get(), m_data.get() + m_start * m_channels, (m_size - m_start) * 2 * m_channels);
212
+ memcpy(data.get() + (m_size - m_start) * m_channels, m_data.get(), (m_start + m_count - m_size) * 2 * m_channels);
213
+ } else
214
+ memcpy(data.get(), m_data.get() + m_start * m_channels, m_count * 2 * m_channels);
215
+ m_data = data;
216
+ m_start = 0;
217
+ m_size = m_size_new;
218
+ };
219
+ int offset = m_start + m_count;
220
+ if (offset > m_size) offset -= m_size;
221
+ if (offset + n > m_size) n = m_size - offset;
222
+ readi(m_data.get() + offset * m_channels, n);
223
+ m_count += n;
224
+ } else
225
+ quit = true;
226
+ unlock();
227
+ } catch (Error &e) {
228
+ quit = true;
229
+ m_data.reset();
230
+ unlock();
231
+ }
232
+ };
233
+ }
234
+
235
+ void *AlsaInput::staticThreadFunc( void *self )
236
+ {
237
+ ((AlsaInput *)self)->threadFunc();
238
+ return self;
239
+ }
147
240
  VALUE AlsaInput::registerRubyClass( VALUE rbModule )
148
241
  {
149
242
  cRubyClass = rb_define_class_under( rbModule, "AlsaInput", rb_cObject );
150
- rb_define_singleton_method( cRubyClass, "new",
151
- RUBY_METHOD_FUNC( wrapNew ), 5 );
243
+ rb_define_singleton_method(cRubyClass, "new",
244
+ RUBY_METHOD_FUNC(wrapNew), 3);
152
245
  rb_define_method( cRubyClass, "close", RUBY_METHOD_FUNC( wrapClose ), 0 );
153
246
  rb_define_method( cRubyClass, "read", RUBY_METHOD_FUNC( wrapRead ), 1 );
154
247
  rb_define_method( cRubyClass, "rate", RUBY_METHOD_FUNC( wrapRate ), 0 );
155
248
  rb_define_method( cRubyClass, "channels", RUBY_METHOD_FUNC( wrapChannels ), 0 );
156
249
  rb_define_method( cRubyClass, "avail", RUBY_METHOD_FUNC( wrapAvail ), 0 );
157
- rb_define_method( cRubyClass, "delay", RUBY_METHOD_FUNC( wrapDelay ), 0 );
158
250
  rb_define_method( cRubyClass, "prepare", RUBY_METHOD_FUNC( wrapPrepare ), 0 );
159
251
  }
160
252
 
@@ -164,14 +256,13 @@ void AlsaInput::deleteRubyObject( void *ptr )
164
256
  }
165
257
 
166
258
  VALUE AlsaInput::wrapNew( VALUE rbClass, VALUE rbPCMName, VALUE rbRate,
167
- VALUE rbChannels, VALUE rbPeriods, VALUE rbFrames )
259
+ VALUE rbChannels)
168
260
  {
169
261
  VALUE retVal = Qnil;
170
262
  try {
171
263
  rb_check_type( rbPCMName, T_STRING );
172
- AlsaInputPtr ptr( new AlsaInput( StringValuePtr( rbPCMName ),
173
- NUM2UINT( rbRate ), NUM2UINT( rbChannels ),
174
- NUM2INT( rbPeriods ), NUM2INT( rbFrames ) ) );
264
+ AlsaInputPtr ptr(new AlsaInput(StringValuePtr(rbPCMName),
265
+ NUM2UINT(rbRate), NUM2UINT(rbChannels)));
175
266
  retVal = Data_Wrap_Struct( rbClass, 0, deleteRubyObject,
176
267
  new AlsaInputPtr( ptr ) );
177
268
  } catch ( exception &e ) {
@@ -224,18 +315,6 @@ VALUE AlsaInput::wrapAvail( VALUE rbSelf )
224
315
  return rbRetVal;
225
316
  }
226
317
 
227
- VALUE AlsaInput::wrapDelay( VALUE rbSelf )
228
- {
229
- VALUE rbRetVal = Qnil;
230
- try {
231
- AlsaInputPtr *self; Data_Get_Struct( rbSelf, AlsaInputPtr, self );
232
- rbRetVal = INT2NUM( (*self)->delay() );
233
- } catch ( exception &e ) {
234
- rb_raise( rb_eRuntimeError, "%s", e.what() );
235
- };
236
- return rbRetVal;
237
- }
238
-
239
318
  VALUE AlsaInput::wrapPrepare( VALUE rbSelf )
240
319
  {
241
320
  try {
data/ext/alsainput.hh CHANGED
@@ -1,5 +1,5 @@
1
1
  /* HornetsEye - Computer Vision with Ruby
2
- Copyright (C) 2006, 2007, 2008, 2009, 2010 Jan Wedekind
2
+ Copyright (C) 2012 Jan Wedekind
3
3
 
4
4
  This program is free software: you can redistribute it and/or modify
5
5
  it under the terms of the GNU General Public License as published by
@@ -26,33 +26,44 @@ class AlsaInput
26
26
  {
27
27
  public:
28
28
  AlsaInput( const std::string &pcmName = "default:0",
29
- unsigned int rate = 48000, unsigned int channels = 2,
30
- int periods = 16, snd_pcm_uframes_t frames = 1024 ) throw (Error);
29
+ unsigned int rate = 48000, unsigned int channels = 2) throw (Error);
31
30
  virtual ~AlsaInput(void);
32
31
  void close(void);
33
32
  SequencePtr read( int samples ) throw (Error);
33
+ void drop(void) throw (Error);
34
34
  unsigned int rate(void);
35
35
  unsigned int channels(void);
36
36
  int avail(void) throw (Error);
37
- int delay(void) throw (Error);
37
+ void lock(void);
38
+ void unlock(void);
38
39
  void prepare(void) throw (Error);
39
40
  static VALUE cRubyClass;
40
41
  static VALUE registerRubyClass( VALUE rbModule );
41
42
  static void deleteRubyObject( void *ptr );
42
- static VALUE wrapNew( VALUE rbClass, VALUE rbPCMName, VALUE rbRate,
43
- VALUE rbChannels, VALUE rbPeriods, VALUE rbFrames );
43
+ static VALUE wrapNew(VALUE rbClass, VALUE rbPCMName, VALUE rbRate,
44
+ VALUE rbChannels);
44
45
  static VALUE wrapClose( VALUE rbSelf );
45
46
  static VALUE wrapRead( VALUE rbSelf, VALUE rbSamples );
46
47
  static VALUE wrapRate( VALUE rbSelf );
47
48
  static VALUE wrapChannels( VALUE rbSelf );
48
49
  static VALUE wrapAvail( VALUE rbSelf );
49
- static VALUE wrapDelay( VALUE rbSelf );
50
50
  static VALUE wrapPrepare( VALUE rbSelf );
51
51
  protected:
52
+ void readi(short int *data, int count);
53
+ void threadFunc(void);
54
+ static void *staticThreadFunc( void *self );
52
55
  snd_pcm_t *m_pcmHandle;
53
56
  std::string m_pcmName;
54
57
  unsigned int m_rate;
55
58
  unsigned int m_channels;
59
+ snd_pcm_uframes_t m_periodSize;
60
+ bool m_threadInitialised;
61
+ boost::shared_array<short int> m_data;
62
+ int m_start;
63
+ int m_count;
64
+ int m_size;
65
+ pthread_t m_thread;
66
+ pthread_mutex_t m_mutex;
56
67
  };
57
68
 
58
69
  typedef boost::shared_ptr< AlsaInput > AlsaInputPtr;
data/ext/alsaoutput.cc CHANGED
@@ -77,7 +77,7 @@ AlsaOutput::~AlsaOutput(void)
77
77
 
78
78
  void AlsaOutput::close(void)
79
79
  {
80
- if ( m_pcmHandle != NULL ) {
80
+ if (m_pcmHandle != NULL) {
81
81
  drain();
82
82
  pthread_mutex_destroy(&m_mutex);
83
83
  snd_pcm_close( m_pcmHandle );
@@ -113,10 +113,10 @@ void AlsaOutput::write(SequencePtr frame) throw (Error)
113
113
  m_size = m_size_new;
114
114
  };
115
115
  int offset = m_start + m_count;
116
- if (offset > m_size) offset -= m_size;
116
+ if (offset >= m_size) offset -= m_size;
117
117
  if (offset + n > m_size) {
118
118
  memcpy(m_data.get() + offset * m_channels, frame->data(), (m_size - offset) * 2 * m_channels);
119
- memcpy(m_data.get(), frame->data() + (m_size - offset) * m_channels, (n + m_size - offset) * 2 * m_channels);
119
+ memcpy(m_data.get(), frame->data() + (m_size - offset) * 2 * m_channels, (n + offset - m_size) * 2 * m_channels);
120
120
  } else
121
121
  memcpy(m_data.get() + offset * m_channels, frame->data(), n * 2 * m_channels);
122
122
  m_count += n;
@@ -130,8 +130,8 @@ void AlsaOutput::drop(void) throw (Error)
130
130
  lock();
131
131
  m_data.reset();
132
132
  m_count = 0;
133
- unlock();
134
133
  snd_pcm_drop(m_pcmHandle);
134
+ unlock();
135
135
  }
136
136
 
137
137
  void AlsaOutput::drain(void) throw (Error)
@@ -155,19 +155,6 @@ unsigned int AlsaOutput::channels(void)
155
155
  return m_channels;
156
156
  }
157
157
 
158
- int AlsaOutput::avail(void) throw (Error)
159
- {
160
- snd_pcm_sframes_t frames;
161
- int err = 0;
162
- while ( ( frames = snd_pcm_avail( m_pcmHandle ) ) < 0 ) {
163
- err = snd_pcm_recover( m_pcmHandle, frames, 1 );
164
- ERRORMACRO( err >= 0, Error, , "Error querying number of available frames for "
165
- "update of PCM device \"" << m_pcmName << "\": "
166
- << snd_strerror( err ) );
167
- };
168
- return frames;
169
- }
170
-
171
158
  int AlsaOutput::delay(void) throw (Error)
172
159
  {
173
160
  ERRORMACRO(m_pcmHandle != NULL, Error, , "PCM device \"" << m_pcmName
@@ -226,11 +213,8 @@ void AlsaOutput::threadFunc(void)
226
213
  if (m_count <= 0) m_data.reset();
227
214
  if (m_start >= m_size) m_start -= m_size;
228
215
  if (m_data.get()) {
229
- if (m_start + n > m_size) {
230
- writei(m_data.get() + m_start * m_channels, m_size - m_start);
231
- writei(m_data.get(), m_start + n - m_size);
232
- } else
233
- writei(m_data.get() + m_start * m_channels, n);
216
+ if (m_start + n > m_size) n = m_size - m_start;
217
+ writei(m_data.get() + m_start * m_channels, n);
234
218
  m_start += n;
235
219
  m_count -= n;
236
220
  } else
@@ -238,6 +222,7 @@ void AlsaOutput::threadFunc(void)
238
222
  unlock();
239
223
  } catch (Error &e) {
240
224
  quit = true;
225
+ m_data.reset();
241
226
  unlock();
242
227
  }
243
228
  };
data/ext/alsaoutput.hh CHANGED
@@ -50,7 +50,6 @@ public:
50
50
  static VALUE wrapChannels( VALUE rbSelf );
51
51
  static VALUE wrapDelay( VALUE rbSelf );
52
52
  protected:
53
- int avail(void) throw (Error);
54
53
  void writei(short int *data, int count) throw (Error);
55
54
  void threadFunc(void);
56
55
  static void *staticThreadFunc( void *self );
@@ -45,14 +45,11 @@ module Hornetseye
45
45
  # @param [String] pcm_name Name of the PCM device
46
46
  # @param [Integer] rate Desired sampling rate.
47
47
  # @param [Integer] channels Number of channels (1=mono, 2=stereo).
48
- # @param [Integer] periods Number of audio frames of the input buffer.
49
- # @param [Integer] frames Size of the audio frames of the input buffer.
50
48
  # @return [AlsaInput] An object for accessing the microphone.
51
49
  #
52
50
  # @see #rate
53
- def new( pcm_name = 'default', rate = 48000, channels = 2, periods = 8,
54
- frames = 1024 )
55
- orig_new pcm_name, rate, channels, periods, frames
51
+ def new(pcm_name = 'default', rate = 48000, channels = 2)
52
+ orig_new pcm_name, rate, channels
56
53
  end
57
54
 
58
55
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hornetseye-alsa
3
3
  version: !ruby/object:Gem::Version
4
- hash: 23
4
+ hash: 31
5
5
  prerelease:
6
6
  segments:
7
7
  - 1
8
- - 1
9
8
  - 2
10
- version: 1.1.2
9
+ - 0
10
+ version: 1.2.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Jan Wedekind
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-11-14 00:00:00 Z
18
+ date: 2012-11-16 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: malloc