0

wavファイルの音量を調整する

音量の小さいwavファイルのボリュームを上げる。上げすぎて音割れしないようにする。

前に作ったWavFile.rbを使ったら簡単にできた


16ビットwavは+-32768、8ビットwavは+-128の範囲の配列で波形が表現されている。
ソースのwavの波形を配列に取り出して、その中で最大の値を取りだし、全体を何倍すれば+-32768の間になるかの倍率を計算して全部かけ算すれば音量を調整できる。

maximizeVolume.rb
#!/usr/bin/env ruby
# -*- coding: utf-8 -*-
# wavの音量を最大に調節する
require File.dirname(__FILE__) + '/WavFile'

if ARGV.size < 2
  puts 'ruby maximizeVolume.rb input.wav output.wav'
  exit 1
end

in_file = ARGV.shift
out_file = ARGV.shift

format, data = WavFile::read open(in_file)

puts format.to_s

bit = 's*' if format.bitPerSample == 16 # int16_t
bit = 'c*' if format.bitPerSample == 8 # signed char
wavs = data.data.unpack(bit)

puts "このwav中の最大音量: #{wavs.max}"

volume_ratio = 32768/wavs.max.to_f if format.bitPerSample == 16
volume_ratio = 128/wavs.max.to_f if format.bitPerSample == 8
puts "補正倍率: #{volume_ratio}"

wavs_fixed = wavs.map{|w|
  (w*volume_ratio).to_i
}
puts "補正されたwav中の最大音量: #{wavs_fixed.max}"

data.data = wavs_fixed.pack(bit)

open(out_file, "w"){|out|
  WavFile::write(out, format, [data])
}


使う
ruby maximizeVolume.rb input.wav out.wav

約24倍されてout.wavに保存された
フォーマットID: 1
チャンネル数: 1
サンプリングレート: 44100 (Hz)
byte per sec: 88200
bit per sample: 16
ブロックサイズ: 2
このwav中の最大音量: 1335
補正倍率: 24.5453183520599
補正されたwav中の最大音量: 32768

0

json_builderを特殊文字のエスケープ、true、false、nullに対応させた

前:橋本商会 C++でmapやvectorをJSON出力するjson_builder.hを作った


ダブルクオートなどを含む文字列を値に保持するためのエスケープ処理にboost::regexを使ったので、libboost_regex-mt.aをコンパイル時に読み込まないとならなくなった → Makefileの例
まさかboost::regex_replaceで頭にバックスラッシュをつけるのに、バックスラッシュ4つで置換するとは思わなかった


こんな風に使う。true, false, nullを入れられるようになった
test.cpp

#include <iostream>
#include <string>
#include <map>
#include <boost/any.hpp>
#include "../json_builder.h"

int main(int argc, char* argv[]){
  std::map<string,boost::any> user;
  user["name"] = std::string("shokai");
  user["fullname"] = std::string("sho hashimoto");
  user["age"] = 25;
  user["test"] = 1.23;
  user["null"] = json_builder::null;
  user["true"] = true;
  user["false"] = false;

  string json = json_builder::toJson(user);
  cout << json << endl;
  return 0;
}


実行結果
{"age":"25","false":false,"fullname":"sho hashimoto","name":"shokai","null":null,"test":"1.23","true":true}



C++でnullを表現するために適当な構造体を定義してしまったけど、こういうので良いんだろうか?
json_builder.h
#include <iostream>
#include <string>
#include <map>
#include <vector>
#include <boost/any.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/format.hpp>
#include <boost/foreach.hpp>
#include <boost/regex.hpp>

using namespace std;
using namespace boost;

#define null json_null()

namespace json_builder{
  struct json_null{};

  string toJson(any value){
    if(value.type() == typeid(vector<any>)){
      string result_str;
      vector<any> vec = any_cast<vector<any> >(value);
      for(int i = 0; i < vec.size(); i++){
result_str += toJson(vec[i]);
if(i < vec.size()-1) result_str += ",";
      }
      result_str = str(format("[%s]") % result_str);
      return result_str;
    }
    else if(value.type() == typeid(map<string,any>)){
      string result_str;
      map<string,any> m = any_cast<map<string,any> >(value);
      string key;
      any value;
      int i = 0;
      BOOST_FOREACH(tie(key,value), m){
result_str += str(format("\"%s\":%s") % key % toJson(value));
if(++i < m.size()) result_str += ",";
      }
      result_str = str(format("{%s}") % result_str);
      return result_str;
    }
    else if(value.type() == typeid(json_null)){
      return string("null");
    }
    else if(value.type() == typeid(string)){
      return str(format("\"%s\"") % 
   regex_replace(any_cast<string>(value), regex("[\"\'\\\\/]"), "\\\\$0"));
    }
    else if(value.type() == typeid(bool)){
      if(any_cast<bool>(value)) return string("true");
      return string("false");
    }
    else if(value.type() == typeid(int)){
      return str(format("\"%d\"") % any_cast<int>(value));
    }
    else if(value.type() == typeid(double)){
      return str(format("\"%d\"") % any_cast<double>(value));
    }
  }

}

0

最近作ったYahooPipes

Pipes: 秋月電子 新製品FullFeed
秋月のRSSが無くなったので、新製品ページから取り出した。


Pipes: ストロベリー・リナックス FullFeed
strawberry-linux.comのnews feedがタイトルのみ配信だったので

どちらも商品イメージとデータシートへのリンクと価格を入れてある。

千石は元気の良いblogで新製品を教えてくれる。spark funと液晶工房もblogがある。スイッチサイエンスもフィード作ろうかと思ったけど新製品ページが半年ぐらい更新されてなかったからやめた。マルツもblogあるけど勉強会情報しかなくて、新製品情報はwebで一覧できない。電子工作系はいまだに新製品情報をネットで効率的に収集する手段が乏しいな。


Pipes: twitter list timeline
twitterのlist機能にrssが無いので。list出た時に作ったんだけど、twitterのHTMLが変わっていつのまにか動かなくなってたのを修理した。
ユーザ名とlist名を入れるとRSSを出す。他人の作ったlistをいろいろ購読してみてる。


pipesってソースのHTMLが変わっていつのまにかエラーになってるんだけど、RSSリーダに登録してるだけだと配信されなくなるだけで、「動かなくなった」事に気づけないんだよなあ
なんとかならないものか。1件も出力できなかったら一番上にエラー文を入れるようにすればいいのか?

1

C++でmapやvectorをJSON出力するjson_builder.hを作った

C++でJSONというと、json.orgにもライブラリがたくさん紹介されているとおり色々ある。でも単に出力するだけの物で、ヘッダファイル一つで簡単に使えるのが無かったので作ってみた。
ちょっとstringの連結コストがかかる気もするけど、まあいいか。

今のところ、std::map<string,any>とstd::vector<any>とstringとintとdoubleが入る。つまりkeyはstringのみで、値はboost::anyをかぶせている。もちろんmapやvectorは入れ子にできる。

boost::anyは何でも入れられる便利な型。
参考:boost::any – 橋本詳解


必要なのはこれだけだけど、boost::any、tuple、format、foreachが必要。
json_builder.h最新版はbitbucketからどうぞ

json_builder.h

#include <iostream>
#include <string>
#include <map>
#include <vector>
#include <boost/any.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/format.hpp>
#include <boost/foreach.hpp>

using namespace std;
using namespace boost;

namespace json_builder{
  string toJson(any value){
    if(value.type() == typeid(vector<any>)){
      string result_str;
      vector<any> vec = any_cast<vector<any> >(value);
      for(int i = 0; i < vec.size(); i++){
result_str += toJson(vec[i]);
if(i < vec.size()-1) result_str += ",";
      }
      result_str = str(format("[%s]") % result_str);
      return result_str;
    }
    else if(value.type() == typeid(map<string,any>)){
      string result_str;
      map<string,any> m = any_cast<map<string,any> >(value);
      string key;
      any value;
      int i = 0;
      BOOST_FOREACH(tie(key,value), m){
result_str += str(format("\"%s\":%s") % key % toJson(value));
if(++i < m.size()) result_str += ",";
      }
      result_str = str(format("{%s}") % result_str);
      return result_str;
    }
    else if(value.type() == typeid(string)){
      return str(format("\"%s\"") % any_cast<string>(value));
    }
    else if(value.type() == typeid(int)){
      return str(format("\"%d\"") % any_cast<int>(value));
    }
    else if(value.type() == typeid(double)){
      return str(format("\"%d\"") % any_cast<double>(value));
    }
  }

}
jsonは要素数不定のただの木なので、再帰でtree walkして要素の型を見て文字列に直して連結し直すだけの関数一つになった。シンプル。
見ての通り、”や’や[や{はescapeしていないので、それらを含む文字列をtoJsonするとparseできないjsonができる。とりあえず今は入れる前にescapeしておいてほしい。
単純にバックスラッシュつければいいだけなのかな? → 対応した


使ってみる。一つのstd::mapをjsonのhashとして標準出力する例
test.cpp
#include <iostream>
#include <string>
#include <map>
#include <boost/any.hpp>
#include "../json_builder.h"

int main(int argc, char* argv[]){
  std::map<string,boost::any> user;
  user["name"] = std::string("shokai"); // string
  user["fullname"] = std::string("sho hashimoto");
  user["age"] = 25; // int
  user["test"] = 1.23; // double

  string json = json_builder::toJson(user);
  cout << json << endl;
  return 0;
}


出力
{"age":"25","fullname":"sho hashimoto","name":"shokai","test":"1.23"}



より複雑に、mapやvectorを入れ子にした例
test2.cpp
#include <iostream>
#include <string>
#include <map>
#include <vector>
#include <boost/any.hpp>
#include "../json_builder.h"

using namespace json_builder;
using namespace std;
using namespace boost;

int main(int argc, char* argv[]){
  map<string,any> obj;
  obj["test"] = string("testtest");

  map<string,any> user;
  user["name"] = string("shokai");
  user["fullname"] = string("sho hashimoto");
  user["age"] = 25;
  user["test"] = 6.78;
  obj["user"] = user;

  std::vector<any> vec;
  vec.push_back(string("aaaa"));
  vec.push_back(1234.56);
  vec.push_back(string("hello work"));
  

  vector<any> vec2;
  vec2.push_back(string("nested std::vector"));
  vec2.push_back(string("bbbbb"));
  vec.push_back(vec2); // std::vecotrの入れ子

  obj["params"] = vec;
  string json = json_builder::toJson(obj);
  cout << json << endl;

  return 0;
}


出力
{"params":["aaaa","1234.56","hello work",["nested std::vector","bbbbb"]],
"test":"testtest","user":{"age":"25","fullname":"sho hashimoto","name":"shokai","test":"6.78"}}


出力したjsonが正しいかどうか、確認するためにrubyのjsonモジュールでrubyのオブジェクトに読み込むコードをtestフォルダに置いておいた。
{"params"=>["aaaa", "1234.56", "hello work", ["nested std::vector", "bbbbb"]],
"user"=>
{"name"=>"shokai", "fullname"=>"sho hashimoto", "test"=>"6.78", "age"=>"25"},
"test"=>"testtest"}
parse success
ちゃんと読み込めた。



BOOST_FOREACHが涙が出るほど便利だった!!

28

scansnapと裁断機を買って本を電子化しまくる

scansnapと裁断機を買った。合計3万6000円ぐらいだったと思う


最近はちょっとした待ち時間に、iPhoneでpdf化したRubyレシピブックをよく読んでいる。
写真 2

漫画なんかも、24インチの液晶に出せばむしろ元の本より大きくなっていい。
あと、中高の頃に毎年度みんなの作文や部活の大会記録がまとめられた200ページぐらいの本が作られていたんだけどそれもスキャンして全部パソコンに入れておいた。OCRもかけてあるので、これで黒歴史を検索できる。どこでもこういう本を見れるのは、友達に会った時とかにネタになって面白い。


買ったのは11月に出たscansnap s1300。サイズはティッシュ箱ぐらい。3,4秒で1枚、裏表まとめて読み込める。普通のフラットヘッドスキャナと違ってプリンタの様に自動でページ送りしてくれるので、500ページの本を20分ちょっとで読み込めた。名刺だとサイズが小さいのでもっと速い。
一冊の本を解体するのに1分、スキャンしてpdf出力に20分(この間、原稿を100枚ずつぐらい入れる)、必要であればスキャン後にOCRをかけるのに10分ぐらいかかる。
webで検索すると一度に20枚程度しかセットできないと書いてあるが、そうでもない。確かに厚さを測るセンサー?か何かが働いていて最初から100枚入れておくと「原稿が読み取れない」というエラーが出るが、最初に20枚ぐらい入れてスキャン開始して、すぐ80枚ぐらい突っ込んでスキャンさせている。

ネットワーク共有すると普通のスキャナとしてしか使えないので、Windows XP homeが入っている古いネットブックにscansnapをつないで、Tight VNC Serverを起動させておいてMac OSXに最初から入っている画面共有で遠隔操作している。


FUJITSU ScanSnap S1300 FI-S1300
富士通 (2009-11-21)
売り上げランキング: 720
おすすめ度の平均: 5.0
5 ストレスフリー


本を解体する為にこの裁断機を買った。14000円ぐらい。
大型ペーパーカッター 裁断機

大型ペーパーカッター 裁断機



まだ必要ないので買ってないけど、替え刃も発見した。
コピー用紙500枚らくらくカット/人気 商品大型ペーパーカッター用『替え刃』

コピー用紙500枚らくらくカット/人気 商品大型ペーパーカッター用『替え刃』


ジャンプぐらいの厚い雑誌でも切れる。このサイズの裁断機では妙に安い(他の半額程度)だが、そのかわり届いた時点で油でぬるぬるしている。
軍手とぞうきんを用意しておいて、よく拭いた。

刃の部分には茶色い油?が付着しているので、試しにいらない本を裁断してみて油の拭き残しが無いか確かめる必要がある。

油がついた。(古本ぐらしは新しいのを持っているので、2003年版を試し切りに使った)
R0013859.JPG


■裁断する
まずスキャンできるように本をバラバラにする。

表紙を外す
R0013860.JPG


しっかり押さえる
R0013861.JPG


切る
R0013862.JPG


切る。裁断機の刃が超鋭いので、あんまり力はいらない。
R0013863.JPG


バラバラにした本をscansnapに入れる
R0013867.JPG


iPhoneアプリのGoodReaderを使って転送して、読める。
写真 1



■OCRをかける
scansnap managerにOCR機能が内蔵されていて、pdfを検索可能な状態にできる。
Windows版はまともだが、Mac版は日本語と英語どちらかしか選べない。日本語でOCRをかけるとローマ字が全角になってしまう。

縦書きの認識はうまくいっていない。自動認識らしいが、横書きだと誤認識してしまう。手動で指定する事も出来ない。


技術書とかは、本の状態よりも検索できた方が便利な事が多い気がする。先に本の内容と流れを把握していれば。
scanしたRubyレシピブック



■スキャンの設定
画質は「スーパーファイン」にしている。ちょっとファイルサイズ大きいけど、ストレージはどんどん大きくなるから別に構わない。

いろいろ試したが、「カラーモードの選択」を「自動」にしていると、例えばこういうページを「グレースケール」ではなく「白黒」として誤認識してしまう事があった。式の部分の背景がグレーの部分がおかしくなってしまう事がある。
写真 1

なので毎回手動でカラーモードは指定している。

「原稿の向きを自動的に補正」も、たまに間違えるのでオフにしている。上側を先にscansnapに入れれば必要ない。
「白紙ページを自動的に削除」はきっちり働くのでオン。
「継続読み取りを有効」はしておいたほうがいい。継続して1つのpdfファイルに追記していける。


■PDFの編集
Windows用のpdf編集ソフトがついている。ページの回転や結合ができて、scansnapの仕上げにはUIがAcrobat Proよりも優れている。
MacではAdobe Acrobat Professional等が必要。


■電子化したくない本
文系の本は、俺はライティングスペースに鉛筆で書き込むので電子化したくない。
あと、やっぱりパラパラ流し見できないので、本の内容と流れが頭に入るまでは電子化したくないな。

文庫で縦書きの小説は電子化してもいいが、ビューアとしてiPhoneの画面サイズだと絶妙に読みにくい。縦書きだと画面からはみだすか、超小さい字になる。


やっぱり技術書と漫画と名刺やはがき、説明書、場所を取るから捨てたいんだけど数年後に確実に見たくなる本(卒業文集とか?)をスキャンすればいいんじゃないだろうか。
あと数年すれば電子化した本を再び製本しなおす方法も整ってくると思うし。