なんとかJARファイル内の音源再生に成功

Java Clipをあきらめ、最初に扱ったSourceDataLineを使う方法でいろいろと挑戦した。もともと知識が足りないこともあり、なかなかうまくClipの時と同じような動作をさせることができないまま何日も経った。

一番困ったのは、一度再生を終えると最初に戻すことができない、ということだった。

あちこち見てまわっているうちに、「とりあえずプログラミング」の「JavaでWAVファイルを再生する(2)」という記事を発見。

とすると、どうすればいいかというと、再生位置を先頭に戻すには、一度close()してから再度open()するという処理しかなさそうです。さらに任意の位置に移動させるには、skip()を使うという方法しかないようです。

ということで、skip()を使おうとあれこれ思案したが、これまたなかなかうまくいかない。

次に、「akJとackeyシリーズ 開発日記」の「JavaでWavの部分再生簡単だなー。」という記事を発見。…何をどのように処理しているのかさっぱりわからない。
(T-T)

簡単と書いてあるのにまったくわからない自分の知識と経験のなさを痛感しつつも、もっと簡単にできるのでは、という思いだけは強く、結局まったく同じものを作ろうとすることなく悩み続けることとなった。

Threadの外部からの操作やフラグでの操作など、いろいろと試してみたところ、ふと気づくと、いつの間にかなんとなくでき上がっていた。偶然の産物なので、もっとすっきりさせることができるかもしれないが…。

AudioPlayer.java
import java.io.*;
import javax.sound.sampled.*;

class AudioPlayer {

  AudioInputStream stream;
  AudioFormat format;
  DataLine.Info info;
  SourceDataLine line;
  byte[] buf;
  long nBytesRead;
  boolean playFlag, pauseFlag;
  Thread playThread;
  String filename;

  private AudioPlayer() {
  }

  AudioPlayer(String fn) {
    load(fn);
  }

  public void load(String fn) {
    filename = fn;
    load();
  }

  public void load() {
    playFlag = false;
    pauseFlag = false;
    try {
     stream = AudioSystem.getAudioInputStream(getClass().getResource(filename));
      format = stream.getFormat();
      info = new DataLine.Info(SourceDataLine.class, format);
      line = (SourceDataLine)AudioSystem.getLine(info);
      line.open(format);
      //buf = new byte[line.getBufferSize()]; //大きい数値が入ると停止までに時間がかかる
      buf = new byte[128];
    } catch(Exception e) {
      e.printStackTrace();
    }
  }

  private void makePlayThread() {
    playThread = new Thread() {
      public void run() {
        try {
          int readBytes = 0;
          while(playFlag && readBytes != -1) {
            if(pauseFlag) {
              Thread.sleep(100);
            } else {
              readBytes = stream.read(buf, 0, buf.length);
              if(readBytes >= 0) {
                line.write(buf, 0, readBytes);
              }
            }
          }
          load();
          //line.drain();
        } catch(Exception e) {
          e.printStackTrace();
        }
      }
    };
  }

  public void play() {
    playFlag = true;
    resetFlag = false;
    if(line != null) {
      if(pauseFlag) {
        pauseFlag = false;
      } else {
        makePlayThread();
        line.start();
        playThread.start();
      }
    } else {
      System.out.println("再生するデータがありません。");
    }
  }

  public void pause() {
    pauseFlag = true;
    if(line.getLongFramePosition() == stream.getFrameLength()) {
      try {
        line.close();
        stream.close();
      } catch(Exception e) {
        e.printStackTrace();
      }
      load();
    }
  }

  public long getLength() {
    if(line != null) {
      return stream.getFrameLength();
    } else {
      return 0;
    }
  }

  public long getPosition() {
    if(line != null) {
      return line.getLongFramePosition();
    } else {
      return 0;
    }
  }

}


AudioPlayerTest.java
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

class AudioPlayerTest {

  JButton playButton, stopButton;
  JLabel counterLabel;
  JProgressBar pBar;
  AudioPlayer ap;

  public static void main(String[] args) {
    AudioPlayerTest apt = new AudioPlayerTest();
  }

  AudioPlayerTest() {
    ap = new AudioPlayer("sa00101.wav");
    playButton = new JButton("再生");
    stopButton = new JButton("停止");
    stopButton.setEnabled(false);
    ActionListener al = new ActionListener() {
      public void actionPerformed(ActionEvent ae) {
        playButton.setEnabled(!(playButton.isEnabled()));
        stopButton.setEnabled(!(stopButton.isEnabled()));
        if(ae.getSource() == playButton) {
          ap.play();
        } else {
          ap.pause();
        }
      }
    };
    playButton.addActionListener(al);
    stopButton.addActionListener(al);
    counterLabel = new JLabel("0", JLabel.RIGHT);
    pBar = new JProgressBar(0, (int)ap.getLength());
    JFrame frame = new JFrame(this.getClass().getSimpleName());
    frame.getContentPane().setLayout(new FlowLayout());
    frame.add(playButton);
    frame.add(stopButton);
    frame.add(counterLabel);
    frame.add(pBar);
    frame.setSize(350, 100);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
    long frameLength = ap.getLength();
    while(true) {
      if(ap.getPosition() == 0) {
        playButton.setEnabled(true);
        stopButton.setEnabled(false);
      }
      counterLabel.setText(ap.getPosition() + "/" + frameLength);
      pBar.setValue((int)ap.getPosition());
      try {
        Thread.sleep(200);
      } catch(Exception e ) {
        e.printStackTrace();
      }
    }
  }

}

これらのファイルの場所に音源ファイル「sa00101.wav」を置いて以下を実行。

javac *.java
java AudioPlayerTest

無事音がなったので、「mf.txt」を用意。

mf.txt
Main-Class: AudioPlayerTest

そして、以下を実行。

jar cvfm AudioPlayerTest.jar mf.txt *.class
jar uvf AudioPlayerTest.jar sa00101.wav
java -jar AudioPlayerTest.jar

どうやらstop()を使って再生中の音を止めると、その後うまくいかない。さらに、「byte[] buf」の配列を大きくすると、停止ボタンを押してもその配列に収まったデータの再生が完了するまで音は止まらない。そのため小さな値を入れてみたが、今後これが何かしら問題になるかもしれない。

しかし、とりあえず、なんとか自分の思い通りに動くところまできた。今後は音のなるものをいろいろと作ってみたい。…時間が作れれば。

Linux + Java Clipの限界?

これまでになんとかClipを使って音を出すことができるようになったので、いよいよ汎用性を高めようと、音の操作を別のクラスにまとめてみた。

ClipPlayer.java
import java.io.*;
import javax.sound.sampled.*;

class ClipPlayer {

   private Clip clip;

  public ClipPlayer(String filename) {
    try {
      AudioInputStream stream = AudioSystem.getAudioInputStream(getClass().getResource(filename));
      AudioFormat format = stream.getFormat();
      DataLine.Info info = new DataLine.Info(Clip.class, format);
      clip = (Clip)AudioSystem.getLine(info);
      clip.open(stream);
      stream.close();
    } catch(Exception e) {
      e.printStackTrace();
    }
  }

  public void play() {
    if(clip != null) {
      if(getPosition() % (getLength() - 1) == 0) {
        clip.stop();
        clip.setFramePosition(0);
      }
      new Thread() {
        public void run() {
          clip.start();
        }
      }.start();
    } else {
      System.out.println("再生できるデータがありません。");
    }
  }

  public void pause() {
    if(clip != null) {
      clip.stop();
    }
  }

  public int getLength() {
    if(clip != null) {
      return clip.getFrameLength();
    } else {
      return 0;
    }
  }

  public long getPosition() {
    if(clip != null) {
      return clip.getLongFramePosition();
    } else {
      return 0;
    }
  }

}


ClipPlayerTest.java
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

class ClipPlayerTest {

  static JFrame frame;
  static JButton playButton, stopButton;
  static JLabel counterLabel;
  static JProgressBar pBar;
  static ClipPlayer cp;

  public static void main(String[] args) {
    cp = new ClipPlayer("sa00101.wav");
    ClipPlayerTest cpt = new ClipPlayerTest();
    frame.setVisible(true);
    int positionInt = 0;
    int maxLength = cp.getLength() - 1;
    while(true) {
      positionInt = (int)cp.getPosition();
      counterLabel.setText(positionInt + "/" + maxLength);
      pBar.setValue((int)positionInt % (maxLength));
      if(positionInt % (cp.getLength() - 1) == 0) {
        playButton.setEnabled(true);
        stopButton.setEnabled(false);
      }
      try {
        Thread.sleep(500);
      } catch(Exception e) {
        e.printStackTrace();
      }
    }
  }

  ClipPlayerTest() {
    frame = new JFrame(getClass().getSimpleName());
    playButton = new JButton("再生");
    stopButton = new JButton("停止");
    stopButton.setEnabled(false);
    ActionListener al = new ActionListener() {
      public void actionPerformed(ActionEvent ae) {
        playButton.setEnabled(!playButton.isEnabled());
        stopButton.setEnabled(!stopButton.isEnabled());
        if(ae.getSource() == playButton) {
          cp.play();
        } else {
          cp.pause();
        }
      }
    };
    playButton.addActionListener(al);
    stopButton.addActionListener(al);
    counterLabel = new JLabel("0", JLabel.RIGHT);
    pBar = new JProgressBar(0, cp.getLength());
    frame.getContentPane().setLayout(new FlowLayout());
    frame.add(playButton);
    frame.add(stopButton);
    frame.add(counterLabel);
    frame.add(pBar);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setSize(350,100);
    frame.setLocationRelativeTo(null);
  }
}

そして、前回の音源ファイル「sa00101.wav」も同じ場所に用意して、次のように実行。

javac *.java
java ClipPlayerTest

無事成功!

実は、これらの実行ファイルと音源ファイルをJARで一つにまとめて扱うことが目標。そこで、これらのファイルのある場所に「mf.txt」というテキストファイルを用意。

mf.txt
Main-Class: ClipPlayerTest

そして、さらに次のように実行。

jar cvfm ClipPlayerTest.jar mf.txt *.class
jar uvf ClipPlayerTest.jar sa00101.wav
java -jar ClipPlayerTest.jar

…あれ?最初の少しだけ再生され、あとは動いているのに音が止まってしまう。

前回の一つのclass内で再生させたものを同じようにJARでまとめると、なんの問題もなく再生できるのに、汎用性を高めようとClipの操作を別ファイルで行うと、JARでまとめた時には音がならなくなる。

色々調べたがさっぱりわからない。もしかしてうまく読み込めていなくて、「clip.open(stream)」の部分を書き換えたら動くのか?と思い、「clip.open(stream)」を消して次のように書いてみた。

byte[] buf = new byte[stream.available()];
stream.read(buf);
clip.open(format, buf, 0, buf.length);

JARにまとめなければ変更前と同様に音はなるが、JARにまとめるとまたすぐに音が止まってしまった。

Clipは一時停止や繰り返しの機能があって便利そうだったが、よくよく考えれば大きなファイルでは困るようなことが書かれているところもあったし、仕方がないのでもう一方で試してみることにする。

探してはみたものの、Clipで扱えるファイルの大きさの限界がどのくらいなのかはよくわからないまま。わかっているのは、外部のclassでClipを操作する方法ではJARにまとめたときに音がならなくなる、という現状。これもLinux + Javaのせい?

JavaのClipで音再生

前回無事Clipを使った再生ができた。そこで、GUIを使ってコントロールしようと試みたが、これがまたなかなかうまくいかない。

再生ボタンで再生し、停止ボタンをクリックすると一時的に止まり、再生ボタンで続きから再生する。ここまではうまくいったが、一度最後まで再生をすると、その後は再生できない。

いろいろ調べると、「ひでっぷの技術メモ」の「Clipで再生した音声ファイルが途中で途切れる」という記事で、Clipでは再生位置を覚えていて、再生終了時に再生位置を0に戻さなければならないことがわかった。

ところが、この記事のように組んでも動かない。これもLinuxのせい?

とりあえず、LineListenerを追加してupdate()内ではsetFramePosition(0)が実行されないことがわかった。

いろいろと考えて、ボタンをクリックしたタイミングで再生位置を確認し、終了位置ならば再生位置を0に戻すようにした。

また、実際にClipを再生してみると、getLongFramePosition()で得られる位置情報は自分の当初の考えとは異なっていた。

getLongFramePosition()で得られる位置は、1回目が終わり2回目の再生に入ると、1回目の終了位置からさらに数値が増えていく。たとえsetFramePosition(0)を行なっても、getLongFramePosition()で得られる情報は0には戻らないことがわかった。どこが再生されているかわかるように、JLabelとJProgressBarを使って再生位置を表示させてみた。

また、「音の再生」と「再生位置情報の表示」を行うためには、どうしてもThreadを使う必要があった。最初は「再生位置情報の表示」の方をThreadにして実行を試みたがうまく動かなかった。そのため、「音の再生」をThreadで行うとうまくいった。「音の再生」をThreadで行う方法は、「駆け出しプログラマの備忘録」の「JavaでWAVを再生するプログラム」に書かれていた。

ということで、次のようにつくったらうまく動いてくれた。

import java.io.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.sound.sampled.*;

class ClipPlayer2 {
  static Clip clip;
  static JFrame frame;
  static JButton playButton, stopButton;
  static JLabel counterLabel;
  static JProgressBar pBar;
  static int playCount, maxLength;

  public static void main(String[] args) {
    File file = new File("sa00101.wav");
    if(file.exists()) {
      try {
        AudioInputStream stream = AudioSystem.getAudioInputStream(file);
        AudioFormat format = stream.getFormat();
        DataLine.Info info = new DataLine.Info(Clip.class, format);
        clip = (Clip)AudioSystem.getLine(info);
        clip.open(stream);
        maxLength = clip.getFrameLength() - 1;
        clip.addLineListener(new LineListener() {
          public void update(LineEvent le) {
            if(le.getType() == LineEvent.Type.STOP) {
              if(maxLength * playCount == clip.getLongFramePosition()) {
                playButton.setEnabled(true);
                stopButton.setEnabled(false);
              }
            }
          }
        });
        stream.close();
        ClipPlayer2 cp2 = new ClipPlayer2();
        frame.setVisible(true);
        while(true) {
          counterLabel.setText(clip.getLongFramePosition() + "/" + maxLength);
          pBar.setValue((int)clip.getLongFramePosition() % (maxLength + 1));
          try {
            Thread.sleep(500);
          } catch(Exception e) {
            e.printStackTrace();
          }
        }
      } catch(Exception e) {
        e.printStackTrace();
      }
    } else {
      System.out.println("ファイルが見つかりませんでした。");
      System.exit(1);
    }
  }

  ClipPlayer2() {
    frame = new JFrame("ClipPlayer2");
    playCount = 1;
    playButton = new JButton("再生");
    stopButton = new JButton("停止");
    stopButton.setEnabled(false);
    ActionListener al = new ActionListener() {
      public void actionPerformed(ActionEvent ae) {
        if(ae.getSource() == playButton) {
          playButton.setEnabled(false);
          stopButton.setEnabled(true);
          if((long)(clip.getFrameLength() - 1) * playCount == clip.getLongFramePosition()) {
            clip.stop();
            clip.setFramePosition(0);
            playCount++;
          }
          play();
        } else {
          playButton.setEnabled(true);
          stopButton.setEnabled(false);
          clip.stop();
        }
      }
    };
    playButton.addActionListener(al);
    stopButton.addActionListener(al);
    counterLabel = new JLabel("0", JLabel.RIGHT);
    pBar = new JProgressBar(0, maxLength);
    frame.getContentPane().setLayout(new FlowLayout());
    frame.add(playButton);
    frame.add(stopButton);
    frame.add(counterLabel);
    frame.add(pBar);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setSize(350,100);
    frame.setLocationRelativeTo(null);
  }

  public void play() {
    new Thread() {
      public void run() {
        clip.start();
      }
    }.start();
  }

}

ClipPlayer2


「otosozai.com」から音声データ「sa00101.wav」をいただいて実行してみた。再生・停止が無事操作できた。

Linux + Java で音をならす

久しぶりにJavaを勉強しようと思い、Lubuntu13.04にopenjdk-7-jdkを入れたまま放置していたので、JDK8を入れ直すべく「kiy271の日記 インフラエンジニアの備忘録」の「Lubuntu 14.04でOracle JDKのインストール」を参考に操作した。

…という話を書いて、一部を変更しようと思ったら、間違えてきれいさっぱり記事が消えてしまった!思い出しながら、あちこち探しながら書き直すことにする。

どうやら13.04では対応していないようでJDK8はインストールできなかったので、まずはOSのアップグレードを…と思ったが、13.10へのオンラインアップグレードも終了していた。仕方がないので、とりあえずOSはそのまま、openjdk-7-jdkもそのままでお勉強することにする。

なお、新たに用意したLubuntu14.04では、上記のサイトで見た方法でJDK8をインストールすることができた。

sudo add-apt-repository ppa:webupd8team/java
sudo apt-get update
sudo apt-get install oracle-java8-installer


openjdk-7-jdkでも、基本的なプログラムはコンパイル・実行共に問題なかった。しかし、いざ音をならそうとすると「LineUnavailableException」などのエラーが出てうまくいかなかった。

「メモ用紙の裏」の「JavaSound on Linux」という記事を見ていると、どうやらLinuxでは音の再生にアプリケーションを使っているかもしれない、と思い、「aossというコマンドを使うらしい」と書かれているので、LXTerminalを起動して「aoss」と実行してみた。すると、「alsa-oss」をインストールしろと表示された。記事にはPulseAudioについても書かれているので、ついでにこれもインストールすることにした。

sudo apt-get install alsa-oss pulseaudio


さらに、この記事に書かれているままに以下をコピペしてホームディレクトリに.asoundrcとして保存した。

pcm.!default {
 type plug
 slave.pcm "dmixer"
}
#pcm.!plughw {
#  type plug
#  slave.pcm "dmixer"
#}
#pcm.dsp {
#  type plug
#  slave.pcm "dmixer"
#}
#pcm.dsp0 {
# type plug
# slave.pcm "dmixer"
#}
ctl.mixer0 {
 type hw
 card 0
}
pcm.dmixer {
 type dmix
 ipc_key 1024
 slave {
   pcm "hw:0,0"
   period_time 0
   buffer_time 0
   period_size 1024
   buffer_size 8192
   format S32_LE
   channels 2
   rate 44100
 }
 bindings {
   0 0
   1 1
 }
}
ctl.dmixer {
 type hw
 card 0
}


これで、「失言の多いプログラマ」の「JavaでWAVファイルを読む」を参考に以下のようにプログラムを書いてみた。

import javax.sound.sampled.*;
import java.io.*;

public class SoundPlayer {
 public static void main(String[] args) {
   try {
     File file = new File("alarm.wav");
     if(file.exists()) {
       AudioInputStream stream = AudioSystem.getAudioInputStream(file);
       byte[] buf = new byte[stream.available()];
       stream.read(buf, 0, buf.length);
       AudioFormat format = stream.getFormat();
       long nBytesRead = format.getFrameSize()*stream.getFrameLength();
       DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
       SourceDataLine line = (SourceDataLine)AudioSystem.getLine(info);
       line.open(format);
       line.start();
       line.write(buf, 0, (int)nBytesRead);
       line.drain();
       line.close();
     } else {
       System.out.println("ファイルが見つかりませんでした。");
     }
   } catch(Exception e) {
     e.printStackTrace();
   }
   System.exit(0);
 }
}


「SoundPlayer.java」として保存し、「javac SoundPlayer.java」とコンパイルして、同じディレクトリに音声ファイル「alarm.wav」を置いて、「java SoundPlayer」として実行すると、無事音がなった。

なぜ「alsa-oss」と「pulseaudio」を入れるだけで音がなるのだろう?いろいろ疑問が残るが、とりあえず音がなったので今回はOKとする。

ちなみに、Lubuntu14.04 + JDK8では、「alsa-oss」と「pulseaudio」を入れなくても音が再生できた。本当になぜ?まだまだ勉強が必要なようだ。

ここまでが、間違って消してしまったところ。

その後、さらにJavaで音を再生する方法を調べて回った。

Javaでの音の再生には、「TOYATAKU Web」の「音声管理」という記事によると、音を読み込みながら再生する「SourceDataLine」を使う方法と、短い音を事前にメモリ上に読み込んでおいて再生する「Clip」を使う方法の2種類があるらしい。

前回は「SourceDataLine」を使ったので、今回は「Clip」を使ってみることにする。

前回再生実験に用いた「alarm.wav」は、再生さえできればよいと考えてネット上で拾った時計の効果音でありとても短いため、実際の再生には「Clip」の方が向いているようだ。

「Clip」を利用した例はたくさんあったが、なぜかどれもエラーは出ないのに音が再生できなかった。いろいろと調べた結果、「人工知能に関する断創録」の「ClipでWAVE再生」の記事の上部から動作確認用のJARファイル「wave_engine.jar」をゲットすると、1回目だけは再生できた。一時停止したり、音が止まったあとはなぜか操作できなくなるのが気になったが…とにかく、そのJARファイルの中の「WaveEngine.java」と前回書いた「SoundPlayer.java」の2つを元に、以下のように書いたらやっと再生することができた。

import java.io.*;
import javax.sound.sampled.*;

class ClipPlayer {
 public static void main(String[] args) {
   try {
     File file = new File("alarm.wav");
     if(file.exists()) {
       AudioInputStream stream = AudioSystem.getAudioInputStream(file);
       AudioFormat format = stream.getFormat();
       DataLine.Info info = new DataLine.Info(Clip.class, format);
       Clip clip = (Clip)AudioSystem.getLine(info);
       clip.open(stream);
       clip.start();
       clip.drain();
       clip.stop();
       clip.close();
       stream.close();
     } else {
       System.out.println("ファイルが見つかりませんでした。");
     }
   } catch(Exception e) {
     e.printStackTrace();
   }
   System.exit(0);
 }
}


これを「ClipPlayer.java」として保存し、「javac ClipPlayer.java」でコンパイル、「alarm.wav」を同じディレクトリに置いておいて「java ClipPlayer」として実行すれば、無事音がなった。

なぜいろいろ公開している他の例では再生できないのだろう?わからないこと、勉強することはまだまだたっぷりあって、本当にキリがない。

古いPC(PentiumM/PAE非対応)にLubuntu14.04をインストール

最近複数のPCでWindowsXPの動きが悪くなってきた。PAE非対応のCPUではあるが、インストール前に「forcepae」を指定して、Lubuntu14.04をインストールして使うようになってきた。

詳しいインストール方法は「軽量Linuxを試す/Lubuntuのインストール」や「PCメモ lubuntu 14.04 LTSをPentium Mマシンで動かす」に書かれているが、大雑把に書いておく。

1.公式サイトから lubuntu-14.04-desktop-i386.iso を入手してCD-Rを作成。

2.作成したCD-RでPCを起動。

3.言語選択の画面でカーソル移動キーを使って「日本語」に合わせてEnterキーを押す。

4.カーソル移動キー「↓」を押して「Lubuntuをインストール」に合わせる。
 ※ Enterキーを押さない。

5.F6キー・ESCキーの順に押す(ゆっくり順番に押せばよい)。

6.「forcepae」と入力してEnterキーを押す。

7.画面に「WARNING: Forcing PAE in CPU flags」と出た後にインストーラが起動するので、そのまま指示にしたがってOSをインストールし、終了後はCD-Rを抜いて再起動。


OSインストール後の設定は、「Lubuntu 14.04 その1 - 日本語環境の構築と確認・インターネットに接続せずLubuntuをインストールした時は」に詳しく書かれている。

1.再起動後、画面左下の鳥のマークのボタン(Windowsのスタートボタンの位置)をクリック、「設定」に合わせ、「言語サポート」をクリックし、指示に従って言語サポートをインストール。

2.「日本語」が最上段にあることを確認して「システム全体に適用」をクリック。

3.「地域フォーマット」タブを選択し、「日本語」を確認して「システム全体に適用」をクリック。

4.Closeボタンをクリック後、再起動 or 再ログイン。


次に、日本語入力環境を整える。「Ubuntu・フレーバーの日本語化」に従って操作した。

1.画面左下の鳥のマークのボタン(Windowsのスタートボタンの位置)をクリックし、「アクセサリ」に合わせ、「LXTerminal」をクリック。

2.「sudo apt update」と入力し、Enterキーを押してしばらく待つ。

3.「sudo apt install fcitx-mozc」と入力し、Enterキーを押してしばらく待つ。

4.「m-config -n fcitx」と入力してEnterキーを押す。

5.一度ログアウトし、再度ログイン。


各ソフトウェアの更新を行なっておく。

1.画面左下の鳥のマークのボタン(Windowsのスタートボタンの位置)をクリックし、「システムツール」に合わせ、「ソフトウェアの更新」をクリック。

2.パスワード入力など、指示に従って操作した後待つ。

3.再起動


このあたりで概ねOSの準備完了。
あとは、好みで各種アプリケーションソフトウェアをインストール。

いつも、gimp、inkscape、audacity、wine は入れている。
wine以外なら、「LXTerminal」を起動して以下のように入力すれば、一気にインストールしてくれる。

sudo apt-get install gimp inkscape audacity


wineも次のように行えばインストールが開始されるが、途中で質問画面が表示される。

sudo apt-get install wine


どちらもTABキーを押して目的のところに色がついたらEnterキーを押せば良い。

快適。

Windows Vistaで無線LANに接続できなくなった

インターネット接続のサービス内容を変更したため、これまで使用していた機械が変わり、無線LAN親機の機能はこの新たな機械が引き継いだ。

Windows7、Windows8、Lubuntuの各PCで有線は設定不要、無線LAN接続のPCとiPad、Android携帯電話はそれぞれ無線LANの親機の登録をすませればすぐにインターネット接続はOKだった。

しかし、Windows Vistaだけはうまく動かない。なぜか「ローカルのみ」と表示され、インターネット接続ができなかった。有線にすればインターネット接続が可能だが、無線だと「ローカルのみ」なのだ。

検索してみると「Windows Vista ローカルの呪い」など、これまでにも困っていた人は多かったようだ。

あちこちに書かれていたことを次々と試してみたが、一向に改善する気配がない。

ふと、「インターネット接続サービス会社なら何か情報を持っているのでは?」と考えて、契約した会社に電話連絡をしてみた。すると、電話対応してくださった方から素晴らしい一言をいただいた。

「Windows Vistaだと、ドライバが古くて動かないことも考えられるので、パソコンメーカ側に問い合わせてドライバの更新を試していただきたいのですが…。」

ドライバの更新」か!!!!!

デバイスマネージャで見てみると、このPCの無線LANアダプタは「Atheros AR5007EG Wireless Network Adapter」とあるので、このドライバを検索すると、それと思しきサイトを発見。

Drivers for Atheros AR5007EG and Windows Vista」の「Click for Download」をクリックして早速ファイル「vista-7.7.0.498-whql.zip」をダウンロードし、ドライバをインストール後、PCを再起動した。

無事解決!Webブラウザで再びあちこちにアクセスできるようになった。

あれこれ試している途中でファイアウォールを止めていたことを思い出し、再びファイアウォールを動かしてみたが、インターネット接続についてなんら問題ない。

長い戦いがやっと終わった。

さすがWindows。いつもたくさんの学習をさせてくれる。

最新OSに飛びつかず周囲の反応を見て十分予習してから導入を決めろ、ということもこのOSが教えてくれた。

でも、正直言うと、もっと楽させてほしい。

軽量Linux

職場の古いPCを軽快に使えないか、という話になり、軽量Linuxについて調査。

以前、Ubuntuを使い始めたものの重く感じるようになったためLubuntuに変更したが、あれからしばらく経ったのでさらに軽くて使いやすいものを探してみた。

すると、「軽量Linuxを独断と偏見で調べてみたでござる」や「僕が使ってみてこれは良かったと思う軽量Linuxのすべて(追記)」というサイトでたくさんのLinux情報をゲット。

これらによると、linuxBeanPuppy系がよさそう。

Puppy系は、操作方法さえ慣れればそこそこ使える。重くなること覚悟で別のアプリケーションソフトウェア入れるという手もあるが…どうしようか。

CPUがPentiumMということもあり悩んだが、今回は最初から日本語が使えてLTS(Long Term Support)であり、「forcepae」でCD-Rから起動してインストール可能となることから、結局Lubuntu14.04を採用。

THINKPAD X40に直接LUBUNTU 14.04LTSを入れてみた。」を発見できなければ、LubuntuのCD-Rが起動できないままインストールはあきらめていただろう。

今のところはさくさく動いているが、Lubuntuも少しずつ大きくなっている模様。やはり、ゆくゆくはPuppy系…かな?

カウントダウンタイマー

今回はJavaScriptでカウントダウンタイマーを作る。指定時間後に音をならして終了する。

時間設定に文字入力を行うようにすると、入力された字が文字か数値かをチェックする仕組みが必要になるため、プルダウンを使って数値設定をするようにした。

iPadでは、文字入力だと切り替えが面倒で…。

なお、Windowsではほとんどのブラウザで、TabキーやShiftキー+Tabキーでフォーカスを合わせるとキーボード入力した数値に素早く設定してくれる。

<!DOCTYPE html>
<HTML lang="ja">
<HEAD><TITLE>カウントダウンタイマー</TITLE></HEAD>
<BODY>

<CENTER>

<H1>カウントダウンタイマー</H1>

<AUDIO id="finish">
<SOURCE src="finish.ogg" type="audio/ogg">
<SOURCE src="finish.m4a" type="audio/mpeg">
</AUDIO>

<FORM id="countdownform" name="countdownform">
<SCRIPT>
var cdid;
var audio = document.getElementById("finish");
var idnames = ["hourselect","minselect","secselect"];
var nums = [24,60,60];
for(var i = 0; i < idnames.length; i++) {
  document.write("<SELECT id=¥"" + idnames[i] + "¥" name=¥"" + idnames[i] + "¥">");
  for(var j = 0; j < nums[i]; j++) {
    document.write("<OPTION value = " + j + ">" + setDigit(j, 2) + "</OPTION>");
  }
  document.write("</SELECT>");
  if(i < 2) {
    document.write(":");
  } else {
    document.write(".");
  }
}
document.write("<INPUT id=¥"msectext¥" name=¥"msectext¥" type=¥"text¥" value=¥"000¥" size=¥"3¥" style=¥"text-align: center¥" disabled>");
document.write("<BR><BR>");
document.write("<INPUT id=¥"cdbutton¥" name=¥"cdbutton¥" type=¥"button¥" value=¥"スタート¥" onClick=¥"countdown()¥">");
var button = document.getElementById("cdbutton");
button.addEventListener("click",function() {
  audio.load();
}, false);

function countdown() {
  if(document.countdownform.cdbutton.value == "スタート") {
    document.countdownform.cdbutton.value = "ストップ";
    var hValue = document.countdownform.hourselect.value * 60 * 60;
    var mValue = document.countdownform.minselect.value * 60;
    var sValue = document.countdownform.secselect.value * 1;
    var endTime = Date.now() + (hValue + mValue + sValue) * 1000;
    cdid = setInterval(function() {
      var diff = endTime - Date.now();
      var remainTime = getTimes(diff);
      for(var i = 0; i < idnames.length; i++) {
        var pulldown = document.getElementById(idnames[i]).getElementsByTagName("OPTION");
        for(var j = 0; j < pulldown.length; j++) {
          if(j == remainTime[i]) {
            pulldown[j].selected = true;
          }
        }
      }
      document.countdownform.msectext.value = setDigit(diff % 1000, 3);
      if(diff <= 0) {
        document.countdownform.msectext.value = "000";
        audio.play();
        document.countdownform.cdbutton.value = "スタート";
        clearInterval(cdid);
      }
    }, 10);
  } else {
    document.countdownform.cdbutton.value = "スタート";
    clearInterval(cdid);
  }
}

function setDigit(value, digits) {
  res = value;
  var times = digits - value.toString().length;
  if(times > 0) {
    for(var i = 0; i < times; i++) {
      res = "0" + res;
    }
  }
  return res;
}

function getTimes(msTime) {
  var msec = msTime % 1000;
  msTime = (msTime - msec) / 1000;
  var sec = msTime % 60;
  msTime = (msTime - sec) / 60;
  var min = msTime % 60;
  var hour = (msTime - min) / 60;
  return [hour, min, sec, msec];
}
</SCRIPT>

</FORM>

</CENTER>

</BODY>
</HTML>


結果はこんな感じ。

カウントダウンタイマー



そして、やはりこのページで組み込むとInternet Explorerでは終了の音が出ない。独立したHTMLファイルだと音はなるのに…。

MIDIから各種音声ファイルを作成

ちょっとした音楽をつくるのに、いつもDominoを利用している。操作も分かりやすく、重宝している。

フリーなのに細かなところまで作ることができる…らしいが、正直、残念ながらそこまで使いこなすことができていない。

この前、JavaScriptで音を再生するにあたり、OGGとACC形式のファイルを取得しようとあちこちネット上の素材置き場をまわったが、両方の形式が入手できるのは少なく、どちらかのみであることが多かった。

調べたところ、日頃から同じく愛用しているフリーウェアAudacityでOGGとACCの出力が可能なことが分かった。(ちなみに、いつもはインストール不要のポータブル版Audacity Portableを利用している。)

さらに調べを進めると、「DTM作曲始めましょ 番外編1 MIDI→WAV→MP3」で、Audacityを使ってPCでの再生音を直接録音する方法を見つけた。

ここに書かれていることに従い、画面左上あたりにある「オーディオホスト」を「Windows DirectSound」に、その隣にある「録音デバイス」を「ステレオミキサー」に、「録音チャンネル」を「ステレオ」に、「再生デバイス」を「スピーカー」に、それぞれ変更して録音を開始し、適当なアプリケーションソフトウェアで音を再生する。

音の再生が終わったところで録音を停止し、前後の無音部分を削除する。

これにより、MIDIでも他の形式でも、PCで音を再生することさえできれば、Audacityで出力可能なファイル形式の音声データを作成することが可能だ。

教えて!goo - iTunesでmidをmp3に変換する方法」でiTunes + QuickTimeによる変換も見つけたが、iPadを独立して使っているのでiTunesは使用しておらず、めったに使わないソフトウェアを入れるのも…と思っていたので、これまでもお世話になってきたAudacityでの録音方法が分かってとてもうれしい。

というこで、「初心者になるための耳コピMIDI講座 #01-10 SMF書き出し」のようにDominoを使ってMIDIファイルを作成し、上記のようにAudacityでOGGやACCなどの形式で出力・保存すればOK。

DominoもAudacity Portableも、適当なフォルダに置いておき、不要になったらフォルダごと削除できるのがとてもうれしい。これまでにもインストール・アンインストールするたびに不安が募っていったので、できるだけフォルダ単位で管理できるアプリケーションソフトウェアを使うことにしている。

フォルダ単位で管理できるもう一つの良い点は、PC引っ越しの際にも簡単であること。1つ1つのアプリケーションソフトウェアをインストールし直す作業が不要で、データ同様バックアップから復元したら終了。そのまますぐに使えるのが良い。

Domino、もっと練習してもっと使って力をつけたい…。

ストップウォッチ(改)

前回の「ストップウォッチを作ってみた」で作ったストップウォッチを使っていたところ、スタートボタンとストップボタンが別々なことに違和感を感じたので、スタートボタンをストップボタンと兼用しようと考えた。

  • スタート・ストップボタンに表示されている文字をチェック

  • 「スタート」ボタンをクリックしたらボタン名を「ストップ」にして時間計測を開始

  • 「ストップ」ボタンをクリックしたらボタン名を「スタート」にして時間計測を終了


  • <!DOCTYPE html>
    <HTML lang="ja">
    <HEAD><TITLE>ストップウォッチ</TITLE></HEAD>
    <BODY>

    <CENTER>

    <H1>ストップウォッチ</H1>

    <FORM name="stopwatch">
    <INPUT type="text" size="20" name="display" value="00:00:00.000" style="text-align: center"><BR><BR>
    <INPUT type="button" name="startstopbutton" value="スタート" onClick="swStartStop()">
    <INPUT type="button" name="resetbutton" value="リセット" onClick="swReset()" disabled>
    </FORM>

    <SCRIPT>
    var swid;

    //スタート・ストップボタンをクリックした時
    function swStartStop() {
      var buttonname = document.stopwatch.startstopbutton.value;
      if(buttonname == "スタート") {
        // ボタン表示が「スタート」の時
        document.stopwatch.startstopbutton.value = "ストップ";
        document.stopwatch.resetbutton.disabled = true;
        var nowValue = document.stopwatch.display.value;
        var hms = nowValue.split(":");
        var secmsec = hms[2].split(".");
        var prevTime = (hms[0] * 60 * 60 + hms[1] * 60 + secmsec[0] * 1) * 1000 + secmsec[1] * 1;
        var startTime = Date.now();
        swid = setInterval(function() {
          var nowTime = Date.now();
          displayTime(nowTime - startTime + prevTime);
        }, 10);
      } else {
        // ボタン表示が「ストップ」の時
        document.stopwatch.startstopbutton.value = "スタート";
        document.stopwatch.resetbutton.disabled = false;
        clearInterval(swid);
      }
    }

    // リセットボタンをクリックした時
    function swReset() {
      document.stopwatch.resetbutton.disabled = true;
      displayTime(0);
    }

    // 数値を指定桁数に変更 例)setDigit(21, 4) => 「0021」を返す
    function setDigit(value, digits) {
      res = value;
      var times = digits - value.toString().length;
      if(times > 0) {
        for(var i = 0; i < times; i++) {
          res = "0" + res;
        }
      }
      return res;
    }

    // ミリ秒 を受け取り 時:分:秒.ミリ秒 の形で表示
    function displayTime(msTime) {
      var msec = msTime % 1000;
      msTime = (msTime - msec) / 1000;
      var sec = msTime % 60;
      msTime = (msTime - sec) / 60;
      var min = msTime % 60;
      var hour = (msTime - min) / 60;
      document.stopwatch.display.value = setDigit(hour, 2) + ":" + setDigit(min, 2) + ":" + setDigit(sec, 2) + "." + setDigit(msec, 3);
    }
    </SCRIPT>

    </CENTER>

    </BODY>
    </HTML>


    これで、スタートボタンとストップボタンを一つのボタンで処理することができた。

    ストップウォッチ





    calendar

    S M T W T F S
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
    << August 2016 >>

    selected entries

    categories

    archives

    links

    profile

    書いた記事数:81 最後に更新した日:2016/07/25

    search this site.

    others

    mobile

    qrcode

    powered

    無料ブログ作成サービス JUGEM